From f47a8642a2c1b56083cf496c609d031fe0854ea2 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 19 Jan 2026 22:29:12 +0100 Subject: [PATCH 001/207] chore: project setup --- .changeset/config.json | 17 + .editorconfig | 9 + .github/FUNDING.yml | 3 + .github/ISSUE_TEMPLATE/bug_report.yml | 100 + .github/ISSUE_TEMPLATE/config.yml | 11 + .github/pull_request_template.md | 13 + .github/renovate.json | 20 + .github/workflows/autofix.yml | 31 + .github/workflows/pr.yml | 50 + .github/workflows/release.yml | 41 + .gitignore | 63 + .npmrc | 1 + .nvmrc | 1 + .prettierignore | 11 + CODE_OF_CONDUCT.md | 81 + CONTRIBUTING.md | 55 + LICENSE | 21 + README.md | 1 + docs/config.json | 56 + docs/framework/react/adapter.md | 1 + .../react/reference/functions/.gitkeep | 0 docs/framework/react/reference/index.md | 8 + docs/framework/solid/adapter.md | 1 + .../solid/reference/functions/.gitkeep | 0 docs/framework/solid/reference/index.md | 8 + docs/installation.md | 45 + docs/overview.md | 3 + docs/quick-start.md | 13 + docs/reference/classes/.gitkeep | 0 docs/reference/functions/.gitkeep | 0 docs/reference/index.md | 12 + docs/reference/interfaces/.gitkeep | 0 eslint.config.js | 23 + examples/react/basic/index.html | 14 + examples/react/basic/package.json | 24 + examples/react/basic/src/index.tsx | 12 + examples/react/basic/tsconfig.json | 19 + examples/react/basic/vite.config.ts | 6 + examples/react/devtools/index.html | 14 + examples/react/devtools/package.json | 25 + examples/react/devtools/src/index.tsx | 14 + examples/react/devtools/tsconfig.json | 19 + examples/react/devtools/vite.config.ts | 6 + examples/solid/basic/index.html | 14 + examples/solid/basic/package.json | 21 + examples/solid/basic/src/index.tsx | 11 + examples/solid/basic/tsconfig.json | 18 + examples/solid/basic/vite.config.ts | 6 + examples/solid/devtools/index.html | 14 + examples/solid/devtools/package.json | 22 + examples/solid/devtools/src/index.tsx | 14 + examples/solid/devtools/tsconfig.json | 18 + examples/solid/devtools/vite.config.ts | 6 + knip.json | 10 + nx.json | 63 + package.json | 77 + packages/react-time-devtools/README.md | 56 + packages/react-time-devtools/eslint.config.js | 33 + packages/react-time-devtools/package.json | 61 + .../react-time-devtools/src/TimeDevtools.tsx | 6 + packages/react-time-devtools/src/index.ts | 1 + packages/react-time-devtools/tsconfig.json | 8 + packages/react-time-devtools/tsdown.config.ts | 16 + packages/react-time-devtools/vitest.config.ts | 15 + packages/react-time/README.md | 3 + packages/react-time/eslint.config.js | 33 + packages/react-time/package.json | 66 + packages/react-time/src/index.ts | 0 packages/react-time/tests/test-setup.ts | 1 + packages/react-time/tsconfig.docs.json | 9 + packages/react-time/tsconfig.json | 8 + packages/react-time/tsdown.config.ts | 16 + packages/react-time/vitest.config.ts | 15 + packages/solid-time-devtools/README.md | 7 + packages/solid-time-devtools/eslint.config.js | 11 + packages/solid-time-devtools/package.json | 59 + .../solid-time-devtools/src/TimeDevtools.tsx | 4 + packages/solid-time-devtools/src/index.ts | 1 + packages/solid-time-devtools/tsconfig.json | 9 + packages/solid-time-devtools/tsdown.config.ts | 16 + packages/solid-time-devtools/vitest.config.ts | 15 + packages/solid-time/README.md | 7 + packages/solid-time/eslint.config.js | 19 + packages/solid-time/package.json | 60 + packages/solid-time/src/index.ts | 0 packages/solid-time/tests/test-setup.ts | 1 + packages/solid-time/tsconfig.docs.json | 9 + packages/solid-time/tsconfig.json | 9 + packages/solid-time/tsdown.config.ts | 16 + packages/solid-time/vitest.config.ts | 15 + packages/time-devtools/README.md | 7 + packages/time-devtools/eslint.config.js | 11 + packages/time-devtools/package.json | 53 + packages/time-devtools/src/devtools.ts | 5 + packages/time-devtools/src/index.ts | 1 + packages/time-devtools/tsconfig.json | 5 + packages/time-devtools/tsdown.config.ts | 16 + packages/time-devtools/vitest.config.ts | 13 + packages/time/README.md | 7 + packages/time/eslint.config.js | 11 + packages/time/package.json | 56 + packages/time/src/index.ts | 0 packages/time/tests/test-setup.ts | 1 + packages/time/tsconfig.docs.json | 4 + packages/time/tsconfig.json | 5 + packages/time/tsdown.config.ts | 16 + packages/time/vitest.config.ts | 13 + pnpm-lock.yaml | 6712 +++++++++++++++++ pnpm-workspace.yaml | 7 + prettier.config.js | 12 + scripts/generate-docs.ts | 34 + scripts/verify-links.ts | 125 + tsconfig.json | 28 + vitest.workspace.js | 16 + 114 files changed, 8909 insertions(+) create mode 100644 .changeset/config.json create mode 100644 .editorconfig create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/renovate.json create mode 100644 .github/workflows/autofix.yml create mode 100644 .github/workflows/pr.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 .nvmrc create mode 100644 .prettierignore create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 docs/config.json create mode 100644 docs/framework/react/adapter.md create mode 100644 docs/framework/react/reference/functions/.gitkeep create mode 100644 docs/framework/react/reference/index.md create mode 100644 docs/framework/solid/adapter.md create mode 100644 docs/framework/solid/reference/functions/.gitkeep create mode 100644 docs/framework/solid/reference/index.md create mode 100644 docs/installation.md create mode 100644 docs/overview.md create mode 100644 docs/quick-start.md create mode 100644 docs/reference/classes/.gitkeep create mode 100644 docs/reference/functions/.gitkeep create mode 100644 docs/reference/index.md create mode 100644 docs/reference/interfaces/.gitkeep create mode 100644 eslint.config.js create mode 100644 examples/react/basic/index.html create mode 100644 examples/react/basic/package.json create mode 100644 examples/react/basic/src/index.tsx create mode 100644 examples/react/basic/tsconfig.json create mode 100644 examples/react/basic/vite.config.ts create mode 100644 examples/react/devtools/index.html create mode 100644 examples/react/devtools/package.json create mode 100644 examples/react/devtools/src/index.tsx create mode 100644 examples/react/devtools/tsconfig.json create mode 100644 examples/react/devtools/vite.config.ts create mode 100644 examples/solid/basic/index.html create mode 100644 examples/solid/basic/package.json create mode 100644 examples/solid/basic/src/index.tsx create mode 100644 examples/solid/basic/tsconfig.json create mode 100644 examples/solid/basic/vite.config.ts create mode 100644 examples/solid/devtools/index.html create mode 100644 examples/solid/devtools/package.json create mode 100644 examples/solid/devtools/src/index.tsx create mode 100644 examples/solid/devtools/tsconfig.json create mode 100644 examples/solid/devtools/vite.config.ts create mode 100644 knip.json create mode 100644 nx.json create mode 100644 package.json create mode 100644 packages/react-time-devtools/README.md create mode 100644 packages/react-time-devtools/eslint.config.js create mode 100644 packages/react-time-devtools/package.json create mode 100644 packages/react-time-devtools/src/TimeDevtools.tsx create mode 100644 packages/react-time-devtools/src/index.ts create mode 100644 packages/react-time-devtools/tsconfig.json create mode 100644 packages/react-time-devtools/tsdown.config.ts create mode 100644 packages/react-time-devtools/vitest.config.ts create mode 100644 packages/react-time/README.md create mode 100644 packages/react-time/eslint.config.js create mode 100644 packages/react-time/package.json create mode 100644 packages/react-time/src/index.ts create mode 100644 packages/react-time/tests/test-setup.ts create mode 100644 packages/react-time/tsconfig.docs.json create mode 100644 packages/react-time/tsconfig.json create mode 100644 packages/react-time/tsdown.config.ts create mode 100644 packages/react-time/vitest.config.ts create mode 100644 packages/solid-time-devtools/README.md create mode 100644 packages/solid-time-devtools/eslint.config.js create mode 100644 packages/solid-time-devtools/package.json create mode 100644 packages/solid-time-devtools/src/TimeDevtools.tsx create mode 100644 packages/solid-time-devtools/src/index.ts create mode 100644 packages/solid-time-devtools/tsconfig.json create mode 100644 packages/solid-time-devtools/tsdown.config.ts create mode 100644 packages/solid-time-devtools/vitest.config.ts create mode 100644 packages/solid-time/README.md create mode 100644 packages/solid-time/eslint.config.js create mode 100644 packages/solid-time/package.json create mode 100644 packages/solid-time/src/index.ts create mode 100644 packages/solid-time/tests/test-setup.ts create mode 100644 packages/solid-time/tsconfig.docs.json create mode 100644 packages/solid-time/tsconfig.json create mode 100644 packages/solid-time/tsdown.config.ts create mode 100644 packages/solid-time/vitest.config.ts create mode 100644 packages/time-devtools/README.md create mode 100644 packages/time-devtools/eslint.config.js create mode 100644 packages/time-devtools/package.json create mode 100644 packages/time-devtools/src/devtools.ts create mode 100644 packages/time-devtools/src/index.ts create mode 100644 packages/time-devtools/tsconfig.json create mode 100644 packages/time-devtools/tsdown.config.ts create mode 100644 packages/time-devtools/vitest.config.ts create mode 100644 packages/time/README.md create mode 100644 packages/time/eslint.config.js create mode 100644 packages/time/package.json create mode 100644 packages/time/src/index.ts create mode 100644 packages/time/tests/test-setup.ts create mode 100644 packages/time/tsconfig.docs.json create mode 100644 packages/time/tsconfig.json create mode 100644 packages/time/tsdown.config.ts create mode 100644 packages/time/vitest.config.ts create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml create mode 100644 prettier.config.js create mode 100644 scripts/generate-docs.ts create mode 100644 scripts/verify-links.ts create mode 100644 tsconfig.json create mode 100644 vitest.workspace.js diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 00000000..742b8815 --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.1.2/schema.json", + "changelog": [ + "@svitejs/changesets-changelog-github-compact", + { "repo": "TanStack/pacer" } + ], + "commit": false, + "access": "public", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "fixed": [], + "linked": [], + "ignore": [], + "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { + "onlyUpdatePeerDependentsWhenOutOfRange": true + } +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..9d08a1a8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..e2ea8ad3 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: tannerlinsley diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..cb3fd88b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,100 @@ +name: 'šŸ› Bug report' +description: Report a reproducible bug or regression +body: + - type: markdown + attributes: + value: | + Thank you for reporting an issue :pray:. + + This issue tracker is for reporting reproducible bugs or regression's found in [time](https://github.com/tanstack/time) + If you have a question about how to achieve or implement something and are struggling, please post a question + inside of time's [Discussions tab](https://github.com/tanstack/time/discussions) instead of filing an issue. + + Before submitting a new bug/issue, please check the links below to see if there is a solution or question posted there already: + - TanStack time's [Discussions tab](https://github.com/tanstack/time/discussions) + - TanStack time's [Open Issues](https://github.com/tanstack/time/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) + - TanStack time's [Closed Issues](https://github.com/tanstack/time/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aclosed) + + The more information you fill in, the better the community can help you. + + - type: input + id: tanstack-time-version + attributes: + label: TanStack Time version + description: | + - Please let us know the exact version of the TanStack Time framework adapter that you were using when the issue occurred. If you are using an older version, check to see if your bug has already been solved in the latest version. Please don't just put in "latest", as this is subject to change. + - The latest "time" version is + placeholder: | + e.g. v0.0.1 + validations: + required: true + + - type: input + id: framework-library-version + attributes: + label: Framework/Library version + description: Which framework and what version of that framework are you using? + placeholder: | + e.g. React v19.2.3 + validations: + required: true + + - type: textarea + id: description + attributes: + label: Describe the bug and the steps to reproduce it + description: Provide a clear and concise description of the challenge you are running into, and the steps we should take to try to reproduce your bug. + validations: + required: true + + - type: input + id: link + attributes: + label: Your Minimal, Reproducible Example - (Sandbox Highly Recommended) + description: | + Please add a link to a minimal reproduction. + Note: + - Your bug may get fixed much faster if we can run your code and it doesn't have dependencies other than React. + - To create a shareable code example for web, you can use CodeSandbox (https://codesandbox.io/s/new) or Stackblitz (https://stackblitz.com/). + - Please make sure the example is complete and runnable without prior dependencies and free of unnecessary abstractions + - Feel free to fork any of the official CodeSandbox examples to reproduce your issue: https://github.com/tanstack/time/tree/main/examples/ + - For React Native, you can use: https://snack.expo.dev/ + - For TypeScript related issues only, a TypeScript Playground link might be sufficient: https://www.typescriptlang.org/play + - Please read these tips for providing a minimal example: https://stackoverflow.com/help/mcve. + placeholder: | + e.g. Code Sandbox, Stackblitz, TypeScript Playground, etc. + validations: + required: true + + - type: textarea + id: screenshots_or_videos + attributes: + label: Screenshots or Videos (Optional) + description: | + If applicable, add screenshots or a video to help explain your problem. + For more information on the supported file image/file types and the file size limits, please refer + to the following link: https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/attaching-files + placeholder: | + You can drag your video or image files inside of this editor ↓ + + - type: dropdown + attributes: + options: + - No, because I do not know how + - No, because I do not have time to dig into it + - Maybe, I'll investigate and start debugging + - Yes, I think I know how to fix it and will discuss it in the comments of this issue + - Yes, I am also opening a PR that solves the problem along side this issue + label: Do you intend to try to help solve this bug with your own PR? + description: | + If you think you know the cause of the problem, the fastest way to get it fixed is to suggest a fix, or fix it yourself! However, it is ok if you cannot solve this yourself and are just wanting help. + - type: checkboxes + id: agrees-to-terms + attributes: + label: Terms & Code of Conduct + description: By submitting this issue, you agree to follow our Code of Conduct and can verify that you have followed the requirements outlined above to the best of your ability. + options: + - label: I agree to follow this project's Code of Conduct + required: true + - label: I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..9f8eb4ac --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: šŸ¤” Feature Requests & Questions + url: https://github.com/TanStack/pacer/discussions + about: Please ask and answer questions here. + - name: šŸ’¬ Community Chat + url: https://discord.gg/mQd7egN + about: A dedicated discord server hosted by TanStack + - name: šŸ¦‹ TanStack Bluesky + url: https://bsky.app/profile/tanstack.com + about: Stay up to date with new releases of our libraries diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..7351a178 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,13 @@ +## šŸŽÆ Changes + + + +## āœ… Checklist + +- [ ] I have followed the steps in the [Contributing guide](https://github.com/TanStack/pacer/blob/main/CONTRIBUTING.md). +- [ ] I have tested this code locally with `pnpm run test:pr`. + +## šŸš€ Release Impact + +- [ ] This change affects published code, and I have generated a [changeset](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md). +- [ ] This change is docs/CI/dev-only (no release). diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 00000000..fb2083cf --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "configMigration": true, + "extends": [ + "config:recommended", + "group:allNonMajor", + "schedule:weekly", + ":approveMajorUpdates", + ":automergeMinor", + ":disablePeerDependencies", + ":maintainLockFilesMonthly", + ":semanticCommits", + ":semanticCommitTypeAll(chore)" + ], + "ignorePresets": [":ignoreModulesAndTests"], + "labels": ["dependencies"], + "rangeStrategy": "bump", + "postUpdateOptions": ["pnpmDedupe"], + "ignoreDeps": ["@types/node", "node"] +} diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml new file mode 100644 index 00000000..1f48e157 --- /dev/null +++ b/.github/workflows/autofix.yml @@ -0,0 +1,31 @@ +name: autofix.ci # needed to securely identify the workflow + +on: + pull_request: + push: + branches: [main, alpha, beta, rc] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + autofix: + name: autofix + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6.0.1 + - name: Setup Tools + uses: tanstack/config/.github/setup@main + - name: Fix formatting + run: pnpm run format + - name: Regenerate docs + run: pnpm build:all && pnpm generate-docs + - name: Apply fixes + uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27 + with: + commit-message: 'ci: apply automated fixes' diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 00000000..956cea40 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,50 @@ +name: PR + +on: + pull_request: + paths-ignore: + - 'docs/**' + - 'media/**' + - '**/*.md' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.number || github.ref }} + cancel-in-progress: true + +env: + NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} + +permissions: + contents: read + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6.0.1 + with: + fetch-depth: 0 + - name: Setup Tools + uses: tanstack/config/.github/setup@main + - name: Get base and head commits for `nx affected` + uses: nrwl/nx-set-shas@v4.4.0 + with: + main-branch-name: main + - name: Run Checks + run: pnpm run test:pr + preview: + name: Preview + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6.0.1 + with: + fetch-depth: 0 + - name: Setup Tools + uses: tanstack/config/.github/setup@main + - name: Build Packages + run: pnpm run build:all + - name: Publish Previews + run: pnpx pkg-pr-new publish --pnpm './packages/*' --template './examples/*/*' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..dfedf7e4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,41 @@ +name: Release + +on: + push: + # branches: [main, alpha, beta, rc] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.number || github.ref }} + cancel-in-progress: true + +env: + NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} + +permissions: + contents: write + id-token: write + pull-requests: write + +jobs: + release: + name: Release + if: github.repository_owner == 'TanStack' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6.0.1 + with: + fetch-depth: 0 + - name: Setup Tools + uses: tanstack/config/.github/setup@main + - name: Run Tests + run: pnpm run test:ci + - name: Run Changesets (version or publish) + uses: changesets/action@v1.5.3 + with: + version: pnpm run changeset:version + publish: pnpm run changeset:publish + commit: 'ci: Version Packages' + title: 'ci: Version Packages' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3005d7b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules +package-lock.json +yarn.lock + +# builds +build +dist +lib +es +artifacts +.rpt2_cache +coverage +*.tgz + +# misc +.DS_Store +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +.next +.svelte-kit + +# developer-specific VS Code config files +.vscode/tasks.json +.vscode/launch.json + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.history +size-plugin.json +stats-hydration.json +stats-react.json +stats.html +.vscode/settings.json +.idea +.cursor +.claude + +*.log +.DS_Store +.cache +.idea +.pnpm-store + +package-lock.json +yarn.lock +*.tsbuildinfo +*.tsbuildinfo + +.svelte-kit +.nx/cache +.nx/workspace-data +vite.config.js.timestamp-* +vite.config.ts.timestamp-* + +.angular diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..268c392d --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +provenance=true diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..b4040276 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +24.8.0 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..fe4bf24f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +**/.nx/ +**/.nx/cache +**/.svelte-kit +**/build +**/coverage +**/dist +**/docs +**/old-examples +pnpm-lock.yaml + +.angular diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..fa111aa2 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,81 @@ +--- +title: Code of Conduct +id: code-of-conduct +--- + +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at TANNERLINSLEY@GMAIL.COM. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..17da9a1e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +--- +title: Contributing +id: contributing +--- + +# Contributing + +## Questions + +If you have questions about implementation details, help or support, then please use our dedicated community forum at [Github Discussions](https://github.com/tanstack/pacer/discussions) **PLEASE NOTE:** If you choose to instead open an issue for your question, your issue will be immediately closed and redirected to the forum. + +## Reporting Issues + +If you have found what you think is a bug, please [file an issue](https://github.com/tanstack/pacer/issues/new). **PLEASE NOTE:** Issues that are identified as implementation questions or non-issues will be immediately closed and redirected to [Github Discussions](https://github.com/tanstack/pacer/discussions) + +## Suggesting new features + +If you are here to suggest a feature, first create an issue if it does not already exist. From there, we will discuss use-cases for the feature and then finally discuss how it could be implemented. + +## Development + +Before proceeding with development, ensure you match one of the following criteria: + +- Fixing a small bug +- Fixing a larger issue that has been previously discussed and agreed-upon by maintainers +- Adding a new feature that has been previously discussed and agreed-upon by maintainers + +## Development Workflow + +- Fork this repository, we prefer the `feat-*` branch name style +- Ensure you have `pnpm` installed +- Install projects dependencies and linkages by running `pnpm install` +- Auto-build and auto-test files as you edit by running `pnpm dev` +- Implement your changes and tests +- To run examples, follow their individual directions. Usually this includes: + - cd into the example directory + - Do NOT install dependencies again or do any linking. Nx already handles this for you. Only run install from the project root. + - Starting the dev server with `pnpm dev` or `pnpm start` (from the example directory) +- To test in your own projects: + - Build/watch for changes with `pnpm build`/`pnpm dev` +- Document your changes in the appropriate documentation website markdown pages +- Run `pnpm test` to ensure all tests pass before committing +- Create a changeset (changelog entry) for your changes by running `pnpm changeset` +- Commit your work and open a pull request +- Submit PR for review + +## Adding a new example + +- Clone an existing example into the appropriate `examples` directory +- Name it the example name in kebab-case +- Update the new example's package.json to match the new example name and any other details +- Check dependencies for unused packages +- Install any additional packages to the example that you may need +- Update the docs/config.json file to include the new example in the navigation sidebar +- Commit the example eg. `docs: Add example-name` diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..308cb68d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Tanner Linsley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index e3c81954..7ecd7e46 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # time + šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular diff --git a/docs/config.json b/docs/config.json new file mode 100644 index 00000000..07800219 --- /dev/null +++ b/docs/config.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://raw.githubusercontent.com/TanStack/tanstack.com/main/tanstack-docs-config.schema.json", + "docSearch": { + "appId": "", + "apiKey": "", + "indexName": "tanstack-time" + }, + "sections": [ + { + "label": "Getting Started", + "children": [ + { + "label": "Overview", + "to": "overview" + }, + { + "label": "Installation", + "to": "installation" + }, + { + "label": "Quick Start", + "to": "quick-start" + } + ], + "frameworks": [ + { + "label": "react", + "children": [ + { + "label": "React Adapter", + "to": "framework/react/adapter" + } + ] + }, + { + "label": "solid", + "children": [ + { + "label": "Solid Adapter", + "to": "framework/solid/adapter" + } + ] + } + ] + }, + { + "label": "API Reference", + "children": [ + { + "label": "Core API", + "to": "reference" + } + ] + } + ] +} diff --git a/docs/framework/react/adapter.md b/docs/framework/react/adapter.md new file mode 100644 index 00000000..201026e1 --- /dev/null +++ b/docs/framework/react/adapter.md @@ -0,0 +1 @@ +# React Adapter diff --git a/docs/framework/react/reference/functions/.gitkeep b/docs/framework/react/reference/functions/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/framework/react/reference/index.md b/docs/framework/react/reference/index.md new file mode 100644 index 00000000..3727a566 --- /dev/null +++ b/docs/framework/react/reference/index.md @@ -0,0 +1,8 @@ +--- +id: "@tanstack/react-time" +title: "@tanstack/react-time" +--- + +# @tanstack/react-time + +## Functions diff --git a/docs/framework/solid/adapter.md b/docs/framework/solid/adapter.md new file mode 100644 index 00000000..f370e9ec --- /dev/null +++ b/docs/framework/solid/adapter.md @@ -0,0 +1 @@ +# Solid Adapter diff --git a/docs/framework/solid/reference/functions/.gitkeep b/docs/framework/solid/reference/functions/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/framework/solid/reference/index.md b/docs/framework/solid/reference/index.md new file mode 100644 index 00000000..0e2ac4a7 --- /dev/null +++ b/docs/framework/solid/reference/index.md @@ -0,0 +1,8 @@ +--- +id: "@tanstack/solid-time" +title: "@tanstack/solid-time" +--- + +# @tanstack/solid-time + +## Functions diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..c6ec5ddb --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,45 @@ +# Installation + +## Core Package + +```bash +npm install @tanstack/time +# or +pnpm add @tanstack/time +# or +yarn add @tanstack/time +``` + +## React + +```bash +npm install @tanstack/react-time +# or +pnpm add @tanstack/react-time +# or +yarn add @tanstack/react-time +``` + +## Solid + +```bash +npm install @tanstack/solid-time +# or +pnpm add @tanstack/solid-time +# or +yarn add @tanstack/solid-time +``` + +## Devtools + +### React Devtools + +```bash +npm install @tanstack/react-time-devtools +``` + +### Solid Devtools + +```bash +npm install @tanstack/solid-time-devtools +``` diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 00000000..6f387301 --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,3 @@ +# TanStack Time + +šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular diff --git a/docs/quick-start.md b/docs/quick-start.md new file mode 100644 index 00000000..89906578 --- /dev/null +++ b/docs/quick-start.md @@ -0,0 +1,13 @@ +# Quick Start + +## Core Usage + +## React Usage + +## Solid Usage + +## With Devtools + +### React + +### Solid diff --git a/docs/reference/classes/.gitkeep b/docs/reference/classes/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/reference/functions/.gitkeep b/docs/reference/functions/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 00000000..c786a357 --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,12 @@ +--- +id: "@tanstack/time" +title: "@tanstack/time" +--- + +# @tanstack/time + +## Classes + +## Interfaces + +## Functions diff --git a/docs/reference/interfaces/.gitkeep b/docs/reference/interfaces/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..b97eeed3 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,23 @@ +// @ts-check + +// @ts-ignore Needed due to moduleResolution Node vs Bundler +import { tanstackConfig } from '@tanstack/eslint-config' +import unusedImports from 'eslint-plugin-unused-imports' + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...tanstackConfig, + { + name: 'tanstack/temp', + plugins: { + 'unused-imports': unusedImports, + }, + rules: { + 'no-case-declarations': 'off', + 'no-shadow': 'off', + 'unused-imports/no-unused-imports': 'warn', + 'pnpm/enforce-catalog': 'off', + 'pnpm/json-enforce-catalog': 'off', + }, + }, +] diff --git a/examples/react/basic/index.html b/examples/react/basic/index.html new file mode 100644 index 00000000..b68b51ab --- /dev/null +++ b/examples/react/basic/index.html @@ -0,0 +1,14 @@ + + + + + + + TanStack Time - React Basic Example + + + +
+ + + diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json new file mode 100644 index 00000000..704dc2c7 --- /dev/null +++ b/examples/react/basic/package.json @@ -0,0 +1,24 @@ +{ + "name": "@tanstack/time-example-react-basic", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3005", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/react-time": "^0.0.0", + "@tanstack/time": "^0.0.0", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.2", + "typescript": "5.9.3", + "vite": "^7.3.1" + } +} diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx new file mode 100644 index 00000000..16e83d8a --- /dev/null +++ b/examples/react/basic/src/index.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' + +function App() { + return ( +
+

TanStack Time - React Basic Example

+
+ ) +} + +ReactDOM.createRoot(document.getElementById('root')!).render() diff --git a/examples/react/basic/tsconfig.json b/examples/react/basic/tsconfig.json new file mode 100644 index 00000000..a97ff8c1 --- /dev/null +++ b/examples/react/basic/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/react/basic/vite.config.ts b/examples/react/basic/vite.config.ts new file mode 100644 index 00000000..9ffcc675 --- /dev/null +++ b/examples/react/basic/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) diff --git a/examples/react/devtools/index.html b/examples/react/devtools/index.html new file mode 100644 index 00000000..181cb6f4 --- /dev/null +++ b/examples/react/devtools/index.html @@ -0,0 +1,14 @@ + + + + + + + TanStack Time - React Devtools Example + + + +
+ + + diff --git a/examples/react/devtools/package.json b/examples/react/devtools/package.json new file mode 100644 index 00000000..481e18f9 --- /dev/null +++ b/examples/react/devtools/package.json @@ -0,0 +1,25 @@ +{ + "name": "@tanstack/time-example-react-devtools", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3006", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/react-time": "^0.0.0", + "@tanstack/react-time-devtools": "^0.0.0", + "@tanstack/time": "^0.0.0", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.2", + "typescript": "5.9.3", + "vite": "^7.3.1" + } +} diff --git a/examples/react/devtools/src/index.tsx b/examples/react/devtools/src/index.tsx new file mode 100644 index 00000000..0034f294 --- /dev/null +++ b/examples/react/devtools/src/index.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import { TimeDevtools } from '@tanstack/react-time-devtools' + +function App() { + return ( +
+

Devtools:

+ +
+ ) +} + +ReactDOM.createRoot(document.getElementById('root')!).render() diff --git a/examples/react/devtools/tsconfig.json b/examples/react/devtools/tsconfig.json new file mode 100644 index 00000000..a97ff8c1 --- /dev/null +++ b/examples/react/devtools/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/react/devtools/vite.config.ts b/examples/react/devtools/vite.config.ts new file mode 100644 index 00000000..9ffcc675 --- /dev/null +++ b/examples/react/devtools/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) diff --git a/examples/solid/basic/index.html b/examples/solid/basic/index.html new file mode 100644 index 00000000..17f2710e --- /dev/null +++ b/examples/solid/basic/index.html @@ -0,0 +1,14 @@ + + + + + + + TanStack Time - Solid Basic Example + + + +
+ + + diff --git a/examples/solid/basic/package.json b/examples/solid/basic/package.json new file mode 100644 index 00000000..435c077d --- /dev/null +++ b/examples/solid/basic/package.json @@ -0,0 +1,21 @@ +{ + "name": "@tanstack/time-example-solid-basic", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3007", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/solid-time": "^0.0.0", + "@tanstack/time": "^0.0.0", + "solid-js": "^1.9.10" + }, + "devDependencies": { + "typescript": "5.9.3", + "vite": "^7.3.1", + "vite-plugin-solid": "^2.11.10" + } +} diff --git a/examples/solid/basic/src/index.tsx b/examples/solid/basic/src/index.tsx new file mode 100644 index 00000000..8d05d244 --- /dev/null +++ b/examples/solid/basic/src/index.tsx @@ -0,0 +1,11 @@ +import { render } from 'solid-js/web' + +function App() { + return ( +
+

TanStack Time - Solid Basic Example

+
+ ) +} + +render(() => , document.getElementById('root')!) diff --git a/examples/solid/basic/tsconfig.json b/examples/solid/basic/tsconfig.json new file mode 100644 index 00000000..11b0838c --- /dev/null +++ b/examples/solid/basic/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "types": ["vite/client"], + "noEmit": true, + "isolatedModules": true, + "skipLibCheck": true, + "strict": true, + "resolveJsonModule": true + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/solid/basic/vite.config.ts b/examples/solid/basic/vite.config.ts new file mode 100644 index 00000000..d0d72d27 --- /dev/null +++ b/examples/solid/basic/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' + +export default defineConfig({ + plugins: [solid({})], +}) diff --git a/examples/solid/devtools/index.html b/examples/solid/devtools/index.html new file mode 100644 index 00000000..0d3fab34 --- /dev/null +++ b/examples/solid/devtools/index.html @@ -0,0 +1,14 @@ + + + + + + + TanStack Time - Solid Devtools Example + + + +
+ + + diff --git a/examples/solid/devtools/package.json b/examples/solid/devtools/package.json new file mode 100644 index 00000000..251d6a78 --- /dev/null +++ b/examples/solid/devtools/package.json @@ -0,0 +1,22 @@ +{ + "name": "@tanstack/time-example-solid-devtools", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3008", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/solid-time": "^0.0.0", + "@tanstack/solid-time-devtools": "^0.0.0", + "@tanstack/time": "^0.0.0", + "solid-js": "^1.9.10" + }, + "devDependencies": { + "typescript": "5.9.3", + "vite": "^7.3.1", + "vite-plugin-solid": "^2.11.10" + } +} diff --git a/examples/solid/devtools/src/index.tsx b/examples/solid/devtools/src/index.tsx new file mode 100644 index 00000000..cbe1b6e6 --- /dev/null +++ b/examples/solid/devtools/src/index.tsx @@ -0,0 +1,14 @@ +import { render } from 'solid-js/web' +import { TimeDevtools } from '@tanstack/solid-time-devtools' + +function App() { + return ( +
+

TanStack Time - Solid Devtools Example

+

Devtools:

+ +
+ ) +} + +render(() => , document.getElementById('root')!) diff --git a/examples/solid/devtools/tsconfig.json b/examples/solid/devtools/tsconfig.json new file mode 100644 index 00000000..11b0838c --- /dev/null +++ b/examples/solid/devtools/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "types": ["vite/client"], + "noEmit": true, + "isolatedModules": true, + "skipLibCheck": true, + "strict": true, + "resolveJsonModule": true + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/solid/devtools/vite.config.ts b/examples/solid/devtools/vite.config.ts new file mode 100644 index 00000000..d0d72d27 --- /dev/null +++ b/examples/solid/devtools/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' + +export default defineConfig({ + plugins: [solid({})], +}) diff --git a/knip.json b/knip.json new file mode 100644 index 00000000..dfc6c27a --- /dev/null +++ b/knip.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://unpkg.com/knip@5/schema.json", + "ignoreDependencies": ["@faker-js/faker"], + "ignoreWorkspaces": ["examples/**"], + "workspaces": { + "packages/react-pacer": { + "ignore": [] + } + } +} diff --git a/nx.json b/nx.json new file mode 100644 index 00000000..7b9c66d4 --- /dev/null +++ b/nx.json @@ -0,0 +1,63 @@ +{ + "$schema": "./node_modules/nx/schemas/nx-schema.json", + "defaultBase": "main", + "nxCloudId": "6932bc70f7d82526902f62fa", + "useInferencePlugins": false, + "parallel": 5, + "tui": { + "enabled": false + }, + "namedInputs": { + "sharedGlobals": [ + "{workspaceRoot}/.nvmrc", + "{workspaceRoot}/package.json", + "{workspaceRoot}/tsconfig.json" + ], + "default": [ + "sharedGlobals", + "{projectRoot}/**/*", + "!{projectRoot}/**/*.md" + ], + "production": [ + "default", + "!{projectRoot}/tests/**/*", + "!{projectRoot}/eslint.config.js" + ] + }, + "targetDefaults": { + "test:lib": { + "cache": true, + "dependsOn": ["^build"], + "inputs": ["default", "^production"], + "outputs": ["{projectRoot}/coverage"] + }, + "test:eslint": { + "cache": true, + "dependsOn": ["^build"], + "inputs": ["default", "^production", "{workspaceRoot}/eslint.config.js"] + }, + "test:types": { + "cache": true, + "dependsOn": ["^build"], + "inputs": ["default", "^production"] + }, + "build": { + "cache": true, + "dependsOn": ["^build"], + "inputs": ["production", "^production"], + "outputs": ["{projectRoot}/build", "{projectRoot}/dist"] + }, + "test:docs": { + "cache": true, + "inputs": ["{workspaceRoot}/docs/**/*"] + }, + "test:knip": { + "cache": true, + "inputs": ["{workspaceRoot}/**/*"] + }, + "test:sherif": { + "cache": true, + "inputs": ["{workspaceRoot}/**/package.json"] + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..6e81ae1f --- /dev/null +++ b/package.json @@ -0,0 +1,77 @@ +{ + "name": "root", + "private": true, + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/time.git" + }, + "packageManager": "pnpm@10.26.1", + "type": "module", + "scripts": { + "build": "nx affected --skip-nx-cache --targets=build --exclude=examples/**", + "build:all": "nx run-many --targets=build --exclude=examples/**", + "build:core": "nx run-many --targets=build --projects=packages/time", + "changeset": "changeset", + "changeset:publish": "changeset publish", + "changeset:version": "changeset version && pnpm install --no-frozen-lockfile && pnpm format", + "clean": "find . -name 'dist' -type d -prune -exec rm -rf {} +", + "clean:node_modules": "find . -name 'node_modules' -type d -prune -exec rm -rf {} +", + "clean:all": "pnpm run clean && pnpm run clean:node_modules", + "copy:readme": "cp README.md packages/time/README.md && cp README.md packages/time-devtools/README.md && cp README.md packages/react-time/README.md && cp README.md packages/react-time-devtools/README.md && cp README.md packages/solid-time/README.md && cp README.md packages/solid-time-devtools/README.md", + "dev": "pnpm run watch", + "format": "prettier --experimental-cli --ignore-unknown '**/*' --write", + "generate-docs": "node scripts/generate-docs.ts && pnpm run copy:readme", + "lint:fix": "nx affected --target=lint:fix --exclude=examples/**", + "lint:fix:all": "nx run-many --targets=lint --fix", + "test": "pnpm run test:ci", + "test:ci": "nx run-many --targets=test:eslint,test:sherif,test:knip,test:docs,test:lib,test:types,build", + "test:docs": "node scripts/verify-links.ts", + "test:eslint": "nx affected --target=test:eslint --exclude=examples/**", + "test:knip": "knip", + "test:lib": "nx affected --targets=test:lib --exclude=examples/**", + "test:lib:dev": "pnpm test:lib && nx watch --all -- pnpm test:lib", + "test:pr": "nx affected --targets=test:eslint,test:sherif,test:knip,test:docs,test:lib,test:types,build", + "test:sherif": "sherif", + "test:types": "nx affected --targets=test:types --exclude=examples/**", + "watch": "pnpm run build:all && nx watch --all -- pnpm run build:all" + }, + "nx": { + "includedScripts": [ + "test:docs", + "test:knip", + "test:sherif" + ] + }, + "devDependencies": { + "@changesets/cli": "^2.29.8", + "@faker-js/faker": "^10.2.0", + "@svitejs/changesets-changelog-github-compact": "^1.2.0", + "@tanstack/eslint-config": "0.3.4", + "@tanstack/typedoc-config": "0.3.3", + "@testing-library/jest-dom": "^6.9.1", + "@types/node": "^25.0.7", + "eslint": "^9.39.2", + "eslint-plugin-unused-imports": "^4.3.0", + "happy-dom": "^20.1.0", + "knip": "^5.80.2", + "markdown-link-extractor": "^4.0.3", + "nx": "^22.3.3", + "premove": "^4.0.0", + "prettier": "^3.7.4", + "prettier-plugin-svelte": "^3.4.1", + "publint": "^0.3.16", + "sherif": "^1.9.0", + "tinyglobby": "^0.2.15", + "tsdown": "^0.19.0", + "typescript": "5.9.3", + "vitest": "^4.0.17" + }, + "overrides": { + "@tanstack/time": "workspace:*", + "@tanstack/time-devtools": "workspace:*", + "@tanstack/react-time": "workspace:*", + "@tanstack/react-time-devtools": "workspace:*", + "@tanstack/solid-time": "workspace:*", + "@tanstack/solid-time-devtools": "workspace:*" + } +} diff --git a/packages/react-time-devtools/README.md b/packages/react-time-devtools/README.md new file mode 100644 index 00000000..b81652cb --- /dev/null +++ b/packages/react-time-devtools/README.md @@ -0,0 +1,56 @@ +# TanStack Time + +A complete time for creating new TanStack libraries with all the tooling and infrastructure you need. + +## What's Included + +- āœ… Framework-agnostic core package +- āœ… React and Solid adapters (easy to add more) +- āœ… Devtools packages for debugging +- āœ… Full monorepo setup with pnpm + Nx +- āœ… TypeScript configuration +- āœ… Testing setup with Vitest +- āœ… Documentation structure with TypeDoc +- āœ… Example applications +- āœ… GitHub workflows (CI, release, autofix) +- āœ… Changesets for versioning +- āœ… ESLint + Prettier +- āœ… Issue and PR times + +## Getting Started + +1. Clone or copy this time +2. Follow the instructions in time_GUIDE.md +3. Search and replace "time" with your library name +4. Replace placeholder code with your implementation +5. Update documentation +6. Start building! + +## Package Structure + +- `@tanstack/time` - Core library +- `@tanstack/react-time` - React adapter +- `@tanstack/solid-time` - Solid adapter +- `@tanstack/time-devtools` - Base devtools +- `@tanstack/react-time-devtools` - React devtools +- `@tanstack/solid-time-devtools` - Solid devtools + +## Commands + +```bash +pnpm install # Install dependencies +pnpm build:all # Build all packages +pnpm test:lib # Run tests +pnpm test:pr # Run PR checks +pnpm format # Format code +pnpm generate-docs # Generate documentation +pnpm watch # Watch mode +``` + +## Documentation + +See time_GUIDE.md for detailed instructions on customizing this time. + +## License + +MIT diff --git a/packages/react-time-devtools/eslint.config.js b/packages/react-time-devtools/eslint.config.js new file mode 100644 index 00000000..ec5db3c6 --- /dev/null +++ b/packages/react-time-devtools/eslint.config.js @@ -0,0 +1,33 @@ +// @ts-check + +import pluginReact from '@eslint-react/eslint-plugin' +import pluginReactCompiler from 'eslint-plugin-react-compiler' +import pluginReactHooks from 'eslint-plugin-react-hooks' +import rootConfig from '../../eslint.config.js' + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...rootConfig, + { + files: ['**/*.{ts,tsx}'], + ...pluginReact.configs.recommended, + }, + { + plugins: { + 'react-hooks': pluginReactHooks, + 'react-compiler': pluginReactCompiler, + }, + rules: { + '@eslint-react/dom/no-missing-button-type': 'off', + 'react-compiler/react-compiler': 'error', + 'react-hooks/exhaustive-deps': 'error', + 'react-hooks/rules-of-hooks': 'error', + }, + }, + { + files: ['**/__tests__/**'], + rules: { + // 'react-compiler/react-compiler': 'off', + }, + }, +] diff --git a/packages/react-time-devtools/package.json b/packages/react-time-devtools/package.json new file mode 100644 index 00000000..0aaa9efd --- /dev/null +++ b/packages/react-time-devtools/package.json @@ -0,0 +1,61 @@ +{ + "name": "@tanstack/react-time-devtools", + "version": "0.0.0", + "description": "React devtools for TanStack time", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/time.git", + "directory": "packages/react-time-devtools" + }, + "homepage": "https://tanstack.com/time", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "react", + "tanstack", + "time", + "devtools" + ], + "scripts": { + "clean": "premove ./build ./dist", + "test:eslint": "eslint ./src", + "test:lib": "vitest --passWithNoTests", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc", + "build": "tsdown" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.cts", + "exports": { + ".": { + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=18" + }, + "files": [ + "dist", + "src" + ], + "dependencies": { + "@tanstack/time-devtools": "workspace:*" + }, + "devDependencies": { + "@types/react": "^19.2.8", + "react": "^19.2.3" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } +} diff --git a/packages/react-time-devtools/src/TimeDevtools.tsx b/packages/react-time-devtools/src/TimeDevtools.tsx new file mode 100644 index 00000000..6ceb5731 --- /dev/null +++ b/packages/react-time-devtools/src/TimeDevtools.tsx @@ -0,0 +1,6 @@ +import React from 'react' + +export function TimeDevtools() { + console.log('Hello from @tanstack/react-time-devtools!') + return
Time Devtools
+} diff --git a/packages/react-time-devtools/src/index.ts b/packages/react-time-devtools/src/index.ts new file mode 100644 index 00000000..f7114f85 --- /dev/null +++ b/packages/react-time-devtools/src/index.ts @@ -0,0 +1 @@ +export * from './TimeDevtools' diff --git a/packages/react-time-devtools/tsconfig.json b/packages/react-time-devtools/tsconfig.json new file mode 100644 index 00000000..c8d3e73b --- /dev/null +++ b/packages/react-time-devtools/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src", "vitest.config.ts", "tests"], + "exclude": ["eslint.config.js"], + "compilerOptions": { + "jsx": "react" + } +} diff --git a/packages/react-time-devtools/tsdown.config.ts b/packages/react-time-devtools/tsdown.config.ts new file mode 100644 index 00000000..71071cb9 --- /dev/null +++ b/packages/react-time-devtools/tsdown.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'tsdown' + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm', 'cjs'], + unbundle: true, + dts: true, + sourcemap: true, + clean: true, + minify: false, + fixedExtension: false, + exports: true, + publint: { + strict: true, + }, +}) diff --git a/packages/react-time-devtools/vitest.config.ts b/packages/react-time-devtools/vitest.config.ts new file mode 100644 index 00000000..75ff7cb9 --- /dev/null +++ b/packages/react-time-devtools/vitest.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vitest/config' +import react from '@vitejs/plugin-react' +import packageJson from './package.json' with { type: 'json' } + +export default defineConfig({ + plugins: [react()], + test: { + name: packageJson.name, + dir: './', + watch: false, + environment: 'happy-dom', + setupFiles: ['./tests/test-setup.ts'], + globals: true, + }, +}) diff --git a/packages/react-time/README.md b/packages/react-time/README.md new file mode 100644 index 00000000..6f387301 --- /dev/null +++ b/packages/react-time/README.md @@ -0,0 +1,3 @@ +# TanStack Time + +šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular diff --git a/packages/react-time/eslint.config.js b/packages/react-time/eslint.config.js new file mode 100644 index 00000000..ec5db3c6 --- /dev/null +++ b/packages/react-time/eslint.config.js @@ -0,0 +1,33 @@ +// @ts-check + +import pluginReact from '@eslint-react/eslint-plugin' +import pluginReactCompiler from 'eslint-plugin-react-compiler' +import pluginReactHooks from 'eslint-plugin-react-hooks' +import rootConfig from '../../eslint.config.js' + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...rootConfig, + { + files: ['**/*.{ts,tsx}'], + ...pluginReact.configs.recommended, + }, + { + plugins: { + 'react-hooks': pluginReactHooks, + 'react-compiler': pluginReactCompiler, + }, + rules: { + '@eslint-react/dom/no-missing-button-type': 'off', + 'react-compiler/react-compiler': 'error', + 'react-hooks/exhaustive-deps': 'error', + 'react-hooks/rules-of-hooks': 'error', + }, + }, + { + files: ['**/__tests__/**'], + rules: { + // 'react-compiler/react-compiler': 'off', + }, + }, +] diff --git a/packages/react-time/package.json b/packages/react-time/package.json new file mode 100644 index 00000000..ff722615 --- /dev/null +++ b/packages/react-time/package.json @@ -0,0 +1,66 @@ +{ + "name": "@tanstack/react-time", + "version": "0.0.0", + "description": "React adapter for TanStack Time", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/time.git", + "directory": "packages/react-time" + }, + "homepage": "https://tanstack.com/time", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "react", + "tanstack", + "time" + ], + "scripts": { + "clean": "premove ./build ./dist", + "test:eslint": "eslint ./src", + "test:lib": "vitest --passWithNoTests", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc", + "build": "tsdown" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.cts", + "exports": { + ".": { + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=18" + }, + "files": [ + "dist", + "src" + ], + "dependencies": { + "@tanstack/time": "workspace:*", + "@tanstack/react-store": "^0.8.0" + }, + "devDependencies": { + "@eslint-react/eslint-plugin": "^2.5.7", + "@testing-library/react": "^16.1.0", + "@types/react": "^19.2.8", + "@vitejs/plugin-react": "^5.1.2", + "eslint-plugin-react-compiler": "19.1.0-rc.2", + "eslint-plugin-react-hooks": "^7.0.1", + "react": "^19.2.3" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } +} diff --git a/packages/react-time/src/index.ts b/packages/react-time/src/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/react-time/tests/test-setup.ts b/packages/react-time/tests/test-setup.ts new file mode 100644 index 00000000..a9d0dd31 --- /dev/null +++ b/packages/react-time/tests/test-setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/vitest' diff --git a/packages/react-time/tsconfig.docs.json b/packages/react-time/tsconfig.docs.json new file mode 100644 index 00000000..20ccb038 --- /dev/null +++ b/packages/react-time/tsconfig.docs.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "paths": { + "@tanstack/pacer": ["../pacer/src"] + } + }, + "include": ["src"] +} diff --git a/packages/react-time/tsconfig.json b/packages/react-time/tsconfig.json new file mode 100644 index 00000000..98bb38df --- /dev/null +++ b/packages/react-time/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "react" + }, + "include": ["src", "vitest.config.ts", "tests"], + "exclude": ["eslint.config.js"] +} diff --git a/packages/react-time/tsdown.config.ts b/packages/react-time/tsdown.config.ts new file mode 100644 index 00000000..71071cb9 --- /dev/null +++ b/packages/react-time/tsdown.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'tsdown' + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm', 'cjs'], + unbundle: true, + dts: true, + sourcemap: true, + clean: true, + minify: false, + fixedExtension: false, + exports: true, + publint: { + strict: true, + }, +}) diff --git a/packages/react-time/vitest.config.ts b/packages/react-time/vitest.config.ts new file mode 100644 index 00000000..ffea6da6 --- /dev/null +++ b/packages/react-time/vitest.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vitest/config' +import react from '@vitejs/plugin-react' +import packageJson from './package.json' with { type: 'json' } + +export default defineConfig({ + plugins: [react()], + test: { + name: packageJson.name, + dir: './tests', + watch: false, + environment: 'happy-dom', + // setupFiles: ['./tests/test-setup.ts'], + globals: true, + }, +}) diff --git a/packages/solid-time-devtools/README.md b/packages/solid-time-devtools/README.md new file mode 100644 index 00000000..b7017d28 --- /dev/null +++ b/packages/solid-time-devtools/README.md @@ -0,0 +1,7 @@ +# TanStack Time + +šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular + +## License + +MIT diff --git a/packages/solid-time-devtools/eslint.config.js b/packages/solid-time-devtools/eslint.config.js new file mode 100644 index 00000000..c61c24df --- /dev/null +++ b/packages/solid-time-devtools/eslint.config.js @@ -0,0 +1,11 @@ +// @ts-check + +import rootConfig from '../../eslint.config.js' + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...rootConfig, + { + rules: {}, + }, +] diff --git a/packages/solid-time-devtools/package.json b/packages/solid-time-devtools/package.json new file mode 100644 index 00000000..0e80ea67 --- /dev/null +++ b/packages/solid-time-devtools/package.json @@ -0,0 +1,59 @@ +{ + "name": "@tanstack/solid-time-devtools", + "version": "0.0.0", + "description": "Solid devtools for TanStack Time", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/time.git", + "directory": "packages/solid-time-devtools" + }, + "homepage": "https://tanstack.com/time", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "solid", + "tanstack", + "time", + "devtools" + ], + "scripts": { + "clean": "premove ./build ./dist", + "test:eslint": "eslint ./src", + "test:lib": "vitest --passWithNoTests", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc", + "build": "tsdown" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.cts", + "exports": { + ".": { + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=18" + }, + "files": [ + "dist", + "src" + ], + "dependencies": { + "@tanstack/time-devtools": "workspace:*" + }, + "devDependencies": { + "solid-js": "^1.9.5" + }, + "peerDependencies": { + "solid-js": ">=1.9.5" + } +} diff --git a/packages/solid-time-devtools/src/TimeDevtools.tsx b/packages/solid-time-devtools/src/TimeDevtools.tsx new file mode 100644 index 00000000..ea10bf01 --- /dev/null +++ b/packages/solid-time-devtools/src/TimeDevtools.tsx @@ -0,0 +1,4 @@ +export function TimeDevtools() { + console.log('Hello from @tanstack/solid-time-devtools!') + return
Solid Time Devtools
+} diff --git a/packages/solid-time-devtools/src/index.ts b/packages/solid-time-devtools/src/index.ts new file mode 100644 index 00000000..f7114f85 --- /dev/null +++ b/packages/solid-time-devtools/src/index.ts @@ -0,0 +1 @@ +export * from './TimeDevtools' diff --git a/packages/solid-time-devtools/tsconfig.json b/packages/solid-time-devtools/tsconfig.json new file mode 100644 index 00000000..aa58368e --- /dev/null +++ b/packages/solid-time-devtools/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src", "vitest.config.ts", "tests"], + "exclude": ["eslint.config.js"], + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js" + } +} diff --git a/packages/solid-time-devtools/tsdown.config.ts b/packages/solid-time-devtools/tsdown.config.ts new file mode 100644 index 00000000..71071cb9 --- /dev/null +++ b/packages/solid-time-devtools/tsdown.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'tsdown' + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm', 'cjs'], + unbundle: true, + dts: true, + sourcemap: true, + clean: true, + minify: false, + fixedExtension: false, + exports: true, + publint: { + strict: true, + }, +}) diff --git a/packages/solid-time-devtools/vitest.config.ts b/packages/solid-time-devtools/vitest.config.ts new file mode 100644 index 00000000..597cf0ec --- /dev/null +++ b/packages/solid-time-devtools/vitest.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vitest/config' +import solid from 'vite-plugin-solid' +import packageJson from './package.json' with { type: 'json' } + +export default defineConfig({ + plugins: [solid()], + test: { + name: packageJson.name, + dir: './', + watch: false, + environment: 'happy-dom', + setupFiles: ['./tests/test-setup.ts'], + globals: true, + }, +}) diff --git a/packages/solid-time/README.md b/packages/solid-time/README.md new file mode 100644 index 00000000..b7017d28 --- /dev/null +++ b/packages/solid-time/README.md @@ -0,0 +1,7 @@ +# TanStack Time + +šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular + +## License + +MIT diff --git a/packages/solid-time/eslint.config.js b/packages/solid-time/eslint.config.js new file mode 100644 index 00000000..b67a469d --- /dev/null +++ b/packages/solid-time/eslint.config.js @@ -0,0 +1,19 @@ +// @ts-check + +import rootConfig from '../../eslint.config.js' + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...rootConfig, + { + files: ['**/*.{ts,tsx}'], + }, + { + plugins: {}, + rules: {}, + }, + { + files: ['**/__tests__/**'], + rules: {}, + }, +] diff --git a/packages/solid-time/package.json b/packages/solid-time/package.json new file mode 100644 index 00000000..af821937 --- /dev/null +++ b/packages/solid-time/package.json @@ -0,0 +1,60 @@ +{ + "name": "@tanstack/solid-time", + "version": "0.0.0", + "description": "Solid adapter for TanStack Time", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/time.git", + "directory": "packages/solid-time" + }, + "homepage": "https://tanstack.com/time", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "solid", + "tanstack", + "time" + ], + "scripts": { + "clean": "premove ./build ./dist", + "test:eslint": "eslint ./src", + "test:lib": "vitest --passWithNoTests", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc", + "build": "tsdown" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.cts", + "exports": { + ".": { + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=18" + }, + "files": [ + "dist", + "src" + ], + "dependencies": { + "@tanstack/time": "workspace:*", + "@tanstack/solid-store": "^0.8.0" + }, + "devDependencies": { + "@types/node": "^25.0.7", + "solid-js": "^1.9.5" + }, + "peerDependencies": { + "solid-js": ">=1.9.5" + } +} diff --git a/packages/solid-time/src/index.ts b/packages/solid-time/src/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/solid-time/tests/test-setup.ts b/packages/solid-time/tests/test-setup.ts new file mode 100644 index 00000000..a9d0dd31 --- /dev/null +++ b/packages/solid-time/tests/test-setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/vitest' diff --git a/packages/solid-time/tsconfig.docs.json b/packages/solid-time/tsconfig.docs.json new file mode 100644 index 00000000..20ccb038 --- /dev/null +++ b/packages/solid-time/tsconfig.docs.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "paths": { + "@tanstack/pacer": ["../pacer/src"] + } + }, + "include": ["src"] +} diff --git a/packages/solid-time/tsconfig.json b/packages/solid-time/tsconfig.json new file mode 100644 index 00000000..6bb0fd91 --- /dev/null +++ b/packages/solid-time/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js" + }, + "include": ["src", "vitest.config.ts", "tests"], + "exclude": ["eslint.config.js"] +} diff --git a/packages/solid-time/tsdown.config.ts b/packages/solid-time/tsdown.config.ts new file mode 100644 index 00000000..71071cb9 --- /dev/null +++ b/packages/solid-time/tsdown.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'tsdown' + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm', 'cjs'], + unbundle: true, + dts: true, + sourcemap: true, + clean: true, + minify: false, + fixedExtension: false, + exports: true, + publint: { + strict: true, + }, +}) diff --git a/packages/solid-time/vitest.config.ts b/packages/solid-time/vitest.config.ts new file mode 100644 index 00000000..8665d851 --- /dev/null +++ b/packages/solid-time/vitest.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vitest/config' +import solid from 'vite-plugin-solid' +import packageJson from './package.json' with { type: 'json' } + +export default defineConfig({ + plugins: [solid()], + test: { + name: packageJson.name, + dir: './tests', + watch: false, + environment: 'happy-dom', + // setupFiles: ['./tests/test-setup.ts'], + globals: true, + }, +}) diff --git a/packages/time-devtools/README.md b/packages/time-devtools/README.md new file mode 100644 index 00000000..b7017d28 --- /dev/null +++ b/packages/time-devtools/README.md @@ -0,0 +1,7 @@ +# TanStack Time + +šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular + +## License + +MIT diff --git a/packages/time-devtools/eslint.config.js b/packages/time-devtools/eslint.config.js new file mode 100644 index 00000000..c61c24df --- /dev/null +++ b/packages/time-devtools/eslint.config.js @@ -0,0 +1,11 @@ +// @ts-check + +import rootConfig from '../../eslint.config.js' + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...rootConfig, + { + rules: {}, + }, +] diff --git a/packages/time-devtools/package.json b/packages/time-devtools/package.json new file mode 100644 index 00000000..e7e3b422 --- /dev/null +++ b/packages/time-devtools/package.json @@ -0,0 +1,53 @@ +{ + "name": "@tanstack/time-devtools", + "version": "0.0.0", + "description": "Devtools for TanStack Time", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/time.git", + "directory": "packages/time-devtools" + }, + "homepage": "https://tanstack.com/time", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "tanstack", + "time", + "devtools" + ], + "scripts": { + "clean": "premove ./build ./dist", + "lint:fix": "eslint ./src --fix", + "test:eslint": "eslint ./src", + "test:lib": "vitest --passWithNoTests", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc", + "build": "tsdown" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.cts", + "exports": { + ".": { + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=18" + }, + "files": [ + "dist/", + "src" + ], + "dependencies": { + "@tanstack/time": "workspace:*" + } +} diff --git a/packages/time-devtools/src/devtools.ts b/packages/time-devtools/src/devtools.ts new file mode 100644 index 00000000..a5eaa213 --- /dev/null +++ b/packages/time-devtools/src/devtools.ts @@ -0,0 +1,5 @@ +console.log('Hello from @tanstack/time-devtools!') + +export function initTimeDevtools() { + console.log('Time devtools initialized') +} diff --git a/packages/time-devtools/src/index.ts b/packages/time-devtools/src/index.ts new file mode 100644 index 00000000..39356ff2 --- /dev/null +++ b/packages/time-devtools/src/index.ts @@ -0,0 +1 @@ +export * from './devtools' diff --git a/packages/time-devtools/tsconfig.json b/packages/time-devtools/tsconfig.json new file mode 100644 index 00000000..e01806d9 --- /dev/null +++ b/packages/time-devtools/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src", "vite.config.ts", "tests"], + "exclude": ["eslint.config.js"] +} diff --git a/packages/time-devtools/tsdown.config.ts b/packages/time-devtools/tsdown.config.ts new file mode 100644 index 00000000..71071cb9 --- /dev/null +++ b/packages/time-devtools/tsdown.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'tsdown' + +export default defineConfig({ + entry: ['./src/index.ts'], + format: ['esm', 'cjs'], + unbundle: true, + dts: true, + sourcemap: true, + clean: true, + minify: false, + fixedExtension: false, + exports: true, + publint: { + strict: true, + }, +}) diff --git a/packages/time-devtools/vitest.config.ts b/packages/time-devtools/vitest.config.ts new file mode 100644 index 00000000..d3db399a --- /dev/null +++ b/packages/time-devtools/vitest.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vitest/config' +import packageJson from './package.json' with { type: 'json' } + +export default defineConfig({ + test: { + name: packageJson.name, + dir: './', + watch: false, + environment: 'happy-dom', + setupFiles: ['./tests/test-setup.ts'], + globals: true, + }, +}) diff --git a/packages/time/README.md b/packages/time/README.md new file mode 100644 index 00000000..b7017d28 --- /dev/null +++ b/packages/time/README.md @@ -0,0 +1,7 @@ +# TanStack Time + +šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular + +## License + +MIT diff --git a/packages/time/eslint.config.js b/packages/time/eslint.config.js new file mode 100644 index 00000000..c61c24df --- /dev/null +++ b/packages/time/eslint.config.js @@ -0,0 +1,11 @@ +// @ts-check + +import rootConfig from '../../eslint.config.js' + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...rootConfig, + { + rules: {}, + }, +] diff --git a/packages/time/package.json b/packages/time/package.json new file mode 100644 index 00000000..72dd9999 --- /dev/null +++ b/packages/time/package.json @@ -0,0 +1,56 @@ +{ + "name": "@tanstack/time", + "version": "0.0.0", + "description": "Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular", + "author": "Tanner Linsley", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/TanStack/time.git", + "directory": "packages/time" + }, + "homepage": "https://tanstack.com/time", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "keywords": [ + "tanstack", + "time" + ], + "scripts": { + "clean": "premove ./build ./dist", + "lint:fix": "eslint ./src --fix", + "test:eslint": "eslint ./src", + "test:lib": "vitest", + "test:lib:dev": "pnpm test:lib --watch", + "test:types": "tsc", + "build": "tsdown" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.cts", + "exports": { + ".": { + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, + "./types": { + "require": "./dist/types.cjs", + "import": "./dist/types.js" + }, + "./package.json": "./package.json" + }, + "sideEffects": false, + "engines": { + "node": ">=18" + }, + "files": [ + "dist/", + "src" + ], + "dependencies": { + "@tanstack/store": "^0.8.0" + } +} diff --git a/packages/time/src/index.ts b/packages/time/src/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/time/tests/test-setup.ts b/packages/time/tests/test-setup.ts new file mode 100644 index 00000000..a9d0dd31 --- /dev/null +++ b/packages/time/tests/test-setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/vitest' diff --git a/packages/time/tsconfig.docs.json b/packages/time/tsconfig.docs.json new file mode 100644 index 00000000..2880b4df --- /dev/null +++ b/packages/time/tsconfig.docs.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["tests", "src"] +} diff --git a/packages/time/tsconfig.json b/packages/time/tsconfig.json new file mode 100644 index 00000000..e01806d9 --- /dev/null +++ b/packages/time/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src", "vite.config.ts", "tests"], + "exclude": ["eslint.config.js"] +} diff --git a/packages/time/tsdown.config.ts b/packages/time/tsdown.config.ts new file mode 100644 index 00000000..7db992da --- /dev/null +++ b/packages/time/tsdown.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'tsdown' + +export default defineConfig({ + entry: ['./src/index.ts', './src/types.ts'], + format: ['esm', 'cjs'], + unbundle: true, + dts: true, + sourcemap: true, + clean: true, + minify: false, + fixedExtension: false, + exports: true, + publint: { + strict: true, + }, +}) diff --git a/packages/time/vitest.config.ts b/packages/time/vitest.config.ts new file mode 100644 index 00000000..d3db399a --- /dev/null +++ b/packages/time/vitest.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vitest/config' +import packageJson from './package.json' with { type: 'json' } + +export default defineConfig({ + test: { + name: packageJson.name, + dir: './', + watch: false, + environment: 'happy-dom', + setupFiles: ['./tests/test-setup.ts'], + globals: true, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 00000000..a4161bdb --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,6712 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@changesets/cli': + specifier: ^2.29.8 + version: 2.29.8(@types/node@25.0.9) + '@faker-js/faker': + specifier: ^10.2.0 + version: 10.2.0 + '@svitejs/changesets-changelog-github-compact': + specifier: ^1.2.0 + version: 1.2.0 + '@tanstack/eslint-config': + specifier: 0.3.4 + version: 0.3.4(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@tanstack/typedoc-config': + specifier: 0.3.3 + version: 0.3.3(typescript@5.9.3) + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@types/node': + specifier: ^25.0.7 + version: 25.0.9 + eslint: + specifier: ^9.39.2 + version: 9.39.2(jiti@2.6.1) + eslint-plugin-unused-imports: + specifier: ^4.3.0 + version: 4.3.0(@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + happy-dom: + specifier: ^20.1.0 + version: 20.3.1 + knip: + specifier: ^5.80.2 + version: 5.81.0(@types/node@25.0.9)(typescript@5.9.3) + markdown-link-extractor: + specifier: ^4.0.3 + version: 4.0.3 + nx: + specifier: ^22.3.3 + version: 22.3.3 + premove: + specifier: ^4.0.0 + version: 4.0.0 + prettier: + specifier: ^3.7.4 + version: 3.8.0 + prettier-plugin-svelte: + specifier: ^3.4.1 + version: 3.4.1(prettier@3.8.0)(svelte@5.46.4) + publint: + specifier: ^0.3.16 + version: 0.3.16 + sherif: + specifier: ^1.9.0 + version: 1.10.0 + tinyglobby: + specifier: ^0.2.15 + version: 0.2.15 + tsdown: + specifier: ^0.19.0 + version: 0.19.0(oxc-resolver@11.16.3)(publint@0.3.16)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vitest: + specifier: ^4.0.17 + version: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(yaml@2.8.2) + + examples/react/basic: + dependencies: + '@tanstack/react-time': + specifier: ^0.0.0 + version: link:../../../packages/react-time + '@tanstack/time': + specifier: ^0.0.0 + version: link:../../../packages/time + react: + specifier: ^19.2.3 + version: 19.2.3 + react-dom: + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) + devDependencies: + '@types/react': + specifier: ^19.2.8 + version: 19.2.8 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.8) + '@vitejs/plugin-react': + specifier: ^5.1.2 + version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: ^7.3.1 + version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + + examples/react/devtools: + dependencies: + '@tanstack/react-time': + specifier: ^0.0.0 + version: link:../../../packages/react-time + '@tanstack/react-time-devtools': + specifier: ^0.0.0 + version: link:../../../packages/react-time-devtools + '@tanstack/time': + specifier: ^0.0.0 + version: link:../../../packages/time + react: + specifier: ^19.2.3 + version: 19.2.3 + react-dom: + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) + devDependencies: + '@types/react': + specifier: ^19.2.8 + version: 19.2.8 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.8) + '@vitejs/plugin-react': + specifier: ^5.1.2 + version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: ^7.3.1 + version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + + examples/solid/basic: + dependencies: + '@tanstack/solid-time': + specifier: ^0.0.0 + version: link:../../../packages/solid-time + '@tanstack/time': + specifier: ^0.0.0 + version: link:../../../packages/time + solid-js: + specifier: ^1.9.10 + version: 1.9.10 + devDependencies: + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: ^7.3.1 + version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + vite-plugin-solid: + specifier: ^2.11.10 + version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + + examples/solid/devtools: + dependencies: + '@tanstack/solid-time': + specifier: ^0.0.0 + version: link:../../../packages/solid-time + '@tanstack/solid-time-devtools': + specifier: ^0.0.0 + version: link:../../../packages/solid-time-devtools + '@tanstack/time': + specifier: ^0.0.0 + version: link:../../../packages/time + solid-js: + specifier: ^1.9.10 + version: 1.9.10 + devDependencies: + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: ^7.3.1 + version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + vite-plugin-solid: + specifier: ^2.11.10 + version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + + packages/react-time: + dependencies: + '@tanstack/react-store': + specifier: ^0.8.0 + version: 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@tanstack/time': + specifier: workspace:* + version: link:../time + react-dom: + specifier: '>=16.8' + version: 19.2.3(react@19.2.3) + devDependencies: + '@eslint-react/eslint-plugin': + specifier: ^2.5.7 + version: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@testing-library/react': + specifier: ^16.1.0 + version: 16.3.1(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@types/react': + specifier: ^19.2.8 + version: 19.2.8 + '@vitejs/plugin-react': + specifier: ^5.1.2 + version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + eslint-plugin-react-compiler: + specifier: 19.1.0-rc.2 + version: 19.1.0-rc.2(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-react-hooks: + specifier: ^7.0.1 + version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) + react: + specifier: ^19.2.3 + version: 19.2.3 + + packages/react-time-devtools: + dependencies: + '@tanstack/time-devtools': + specifier: workspace:* + version: link:../time-devtools + react-dom: + specifier: '>=16.8' + version: 19.2.3(react@19.2.3) + devDependencies: + '@types/react': + specifier: ^19.2.8 + version: 19.2.8 + react: + specifier: ^19.2.3 + version: 19.2.3 + + packages/solid-time: + dependencies: + '@tanstack/solid-store': + specifier: ^0.8.0 + version: 0.8.0(solid-js@1.9.10) + '@tanstack/time': + specifier: workspace:* + version: link:../time + devDependencies: + '@types/node': + specifier: ^25.0.7 + version: 25.0.9 + solid-js: + specifier: ^1.9.5 + version: 1.9.10 + + packages/solid-time-devtools: + dependencies: + '@tanstack/time-devtools': + specifier: workspace:* + version: link:../time-devtools + devDependencies: + solid-js: + specifier: ^1.9.5 + version: 1.9.10 + + packages/time: + dependencies: + '@tanstack/store': + specifier: ^0.8.0 + version: 0.8.0 + + packages/time-devtools: + dependencies: + '@tanstack/time': + specifier: workspace:* + version: link:../time + +packages: + + '@adobe/css-tools@4.4.4': + resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + + '@babel/code-frame@7.28.6': + resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.6': + resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.6': + resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.6': + resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.18.6': + resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.6': + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-proposal-private-methods@7.18.6': + resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} + engines: {node: '>=6.9.0'} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.6': + resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.6': + resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} + engines: {node: '>=6.9.0'} + + '@changesets/apply-release-plan@7.0.14': + resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} + + '@changesets/assemble-release-plan@6.0.9': + resolution: {integrity: sha512-tPgeeqCHIwNo8sypKlS3gOPmsS3wP0zHt67JDuL20P4QcXiw/O4Hl7oXiuLnP9yg+rXLQ2sScdV1Kkzde61iSQ==} + + '@changesets/changelog-git@0.2.1': + resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} + + '@changesets/cli@2.29.8': + resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==} + hasBin: true + + '@changesets/config@3.1.2': + resolution: {integrity: sha512-CYiRhA4bWKemdYi/uwImjPxqWNpqGPNbEBdX1BdONALFIDK7MCUj6FPkzD+z9gJcvDFUQJn9aDVf4UG7OT6Kog==} + + '@changesets/errors@0.2.0': + resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} + + '@changesets/get-dependents-graph@2.1.3': + resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} + + '@changesets/get-github-info@0.6.0': + resolution: {integrity: sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==} + + '@changesets/get-release-plan@4.0.14': + resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==} + + '@changesets/get-version-range-type@0.4.0': + resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} + + '@changesets/git@3.0.4': + resolution: {integrity: sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==} + + '@changesets/logger@0.1.1': + resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} + + '@changesets/parse@0.4.2': + resolution: {integrity: sha512-Uo5MC5mfg4OM0jU3up66fmSn6/NE9INK+8/Vn/7sMVcdWg46zfbvvUSjD9EMonVqPi9fbrJH9SXHn48Tr1f2yA==} + + '@changesets/pre@2.0.2': + resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} + + '@changesets/read@0.6.6': + resolution: {integrity: sha512-P5QaN9hJSQQKJShzzpBT13FzOSPyHbqdoIBUd2DJdgvnECCyO6LmAOWSV+O8se2TaZJVwSXjL+v9yhb+a9JeJg==} + + '@changesets/should-skip-package@0.1.2': + resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} + + '@changesets/types@4.1.0': + resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} + + '@changesets/types@6.1.0': + resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} + + '@changesets/write@0.4.0': + resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + + '@emnapi/core@1.8.1': + resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} + + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint-react/ast@2.7.2': + resolution: {integrity: sha512-RB8AVNjboN6/md9Da4rUG4WqxLT+DqUR+qXIR6iAD0+xxp6Dtihu541+lKLZ3GCstunbBcDwu7gdhSbz+BHSuQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@eslint-react/core@2.7.2': + resolution: {integrity: sha512-QOYh8OWwUGMYLhuvb8WcmoS2jYXb0SJbpX+Ozk+Ht2G9XGRAahl+8PDy/o2l2lLnFXv5JQGfLrN+m2WPTi104g==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@eslint-react/eff@2.7.2': + resolution: {integrity: sha512-AzQGbidoI8g8izka/1H9xCKW56NR7xWGGPMccBCUZwbCoJZ4wyRKcE10E7ot7LwBv5kBoUQp3GJ9UXCcg/Er0w==} + engines: {node: '>=20.19.0'} + + '@eslint-react/eslint-plugin@2.7.2': + resolution: {integrity: sha512-h9T5cc2TxsKMv/8iO63KKamXyJjHHAmeG2MJVjeIm4FaZdsX0/2Bx254B3Fa8IDqQi4X81AMyJ8ohtbxsn6pOw==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@eslint-react/shared@2.7.2': + resolution: {integrity: sha512-U1H3dLaTj7kvEbyJyJEgn6xX3BmrCH1f9f+tg9gLWlN7askgWT5NF56wfX1l+jtwiEAZD/78W1TfICKkMnZDxQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@eslint-react/var@2.7.2': + resolution: {integrity: sha512-sPnXmikpzmAdIWh6lqqKm4Bu0ypKTCAQ7WxGuR5ejxtrA/HjQQuKMBIyPkBdjHWlF9ADdh9pKuo1j2RQwUWiqA==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.2': + resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@faker-js/faker@10.2.0': + resolution: {integrity: sha512-rTXwAsIxpCqzUnZvrxVh3L0QA0NzToqWBLAhV+zDV3MIIwiQhAZHMdPCIaj5n/yADu/tyk12wIPgL6YHGXJP+g==} + engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} + + '@gerrit0/mini-shiki@3.21.0': + resolution: {integrity: sha512-9PrsT5DjZA+w3lur/aOIx3FlDeHdyCEFlv9U+fmsVyjPZh61G5SYURQ/1ebe2U63KbDmI2V8IhIUegWb8hjOyg==} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + + '@jest/diff-sequences@30.0.1': + resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/get-type@30.1.0': + resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/schemas@30.0.5': + resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@napi-rs/wasm-runtime@0.2.4': + resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} + + '@napi-rs/wasm-runtime@1.1.1': + resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nx/nx-darwin-arm64@22.3.3': + resolution: {integrity: sha512-zBAGFGLal09CxhQkdMpOVwcwa9Y01aFm88jTTn35s/DdIWsfngmPzz0t4mG7u2D05q7TJfGQ31pIf5GkNUjo6g==} + cpu: [arm64] + os: [darwin] + + '@nx/nx-darwin-x64@22.3.3': + resolution: {integrity: sha512-6ZQ6rMqH8NY4Jz+Gc89D5bIH2NxZb5S/vaA4yJ9RrqAfl4QWchNFD5na+aRivSd+UdsYLPKKl6qohet5SE6vOg==} + cpu: [x64] + os: [darwin] + + '@nx/nx-freebsd-x64@22.3.3': + resolution: {integrity: sha512-J/PP5pIOQtR7ZzrFwP6d6h0yfY7r9EravG2m940GsgzGbtZGYIDqnh5Wdt+4uBWPH8VpdNOwFqH0afELtJA3MA==} + cpu: [x64] + os: [freebsd] + + '@nx/nx-linux-arm-gnueabihf@22.3.3': + resolution: {integrity: sha512-/zn0altzM15S7qAgXMaB41vHkEn18HyTVUvRrjmmwaVqk9WfmDmqOQlGWoJ6XCbpvKQ8bh14RyhR9LGw1JJkNA==} + cpu: [arm] + os: [linux] + + '@nx/nx-linux-arm64-gnu@22.3.3': + resolution: {integrity: sha512-NmPeCexWIZHW9RM3lDdFENN9C3WtlQ5L4RSNFESIjreS921rgePhulsszYdGnHdcnKPYlBBJnX/NxVsfioBbnQ==} + cpu: [arm64] + os: [linux] + + '@nx/nx-linux-arm64-musl@22.3.3': + resolution: {integrity: sha512-K02U88Q0dpvCfmSXXvY7KbYQSa1m+mkYeqDBRHp11yHk1GoIqaHp8oEWda7FV4gsriNExPSS5tX1/QGVoLZrCw==} + cpu: [arm64] + os: [linux] + + '@nx/nx-linux-x64-gnu@22.3.3': + resolution: {integrity: sha512-04TEbvgwRaB9ifr39YwJmWh3RuXb4Ry4m84SOJyjNXAfPrepcWgfIQn1VL2ul1Ybq+P023dLO9ME8uqFh6j1YQ==} + cpu: [x64] + os: [linux] + + '@nx/nx-linux-x64-musl@22.3.3': + resolution: {integrity: sha512-uxBXx5q+S5OGatbYDxnamsKXRKlYn+Eq1nrCAHaf8rIfRoHlDiRV2PqtWuF+O2pxR5FWKpvr+/sZtt9rAf7KMw==} + cpu: [x64] + os: [linux] + + '@nx/nx-win32-arm64-msvc@22.3.3': + resolution: {integrity: sha512-aOwlfD6ZA1K6hjZtbhBSp7s1yi3sHbMpLCa4stXzfhCCpKUv46HU/EdiWdE1N8AsyNFemPZFq81k1VTowcACdg==} + cpu: [arm64] + os: [win32] + + '@nx/nx-win32-x64-msvc@22.3.3': + resolution: {integrity: sha512-EDR8BtqeDvVNQ+kPwnfeSfmerYetitU3tDkxOMIybjKJDh69U2JwTB8n9ARwNaZQbNk7sCGNRUSZFTbAAUKvuQ==} + cpu: [x64] + os: [win32] + + '@oxc-project/types@0.107.0': + resolution: {integrity: sha512-QFDRbYfV2LVx8tyqtyiah3jQPUj1mK2+RYwxyFWyGoys6XJnwTdlzO6rdNNHOPorHAu5Uo34oWRKcvNpbJarmQ==} + + '@oxc-project/types@0.108.0': + resolution: {integrity: sha512-7lf13b2IA/kZO6xgnIZA88sq3vwrxWk+2vxf6cc+omwYCRTiA5e63Beqf3fz/v8jEviChWWmFYBwzfSeyrsj7Q==} + + '@oxc-resolver/binding-android-arm-eabi@11.16.3': + resolution: {integrity: sha512-CVyWHu6ACDqDcJxR4nmGiG8vDF4TISJHqRNzac5z/gPQycs/QrP/1pDsJBy0MD7jSw8nVq2E5WqeHQKabBG/Jg==} + cpu: [arm] + os: [android] + + '@oxc-resolver/binding-android-arm64@11.16.3': + resolution: {integrity: sha512-tTIoB7plLeh2o6Ay7NnV5CJb6QUXdxI7Shnsp2ECrLSV81k+oVE3WXYrQSh4ltWL75i0OgU5Bj3bsuyg5SMepw==} + cpu: [arm64] + os: [android] + + '@oxc-resolver/binding-darwin-arm64@11.16.3': + resolution: {integrity: sha512-OXKVH7uwYd3Rbw1s2yJZd6/w+6b01iaokZubYhDAq4tOYArr+YCS+lr81q1hsTPPRZeIsWE+rJLulmf1qHdYZA==} + cpu: [arm64] + os: [darwin] + + '@oxc-resolver/binding-darwin-x64@11.16.3': + resolution: {integrity: sha512-WwjQ4WdnCxVYZYd3e3oY5XbV3JeLy9pPMK+eQQ2m8DtqUtbxnvPpAYC2Knv/2bS6q5JiktqOVJ2Hfia3OSo0/A==} + cpu: [x64] + os: [darwin] + + '@oxc-resolver/binding-freebsd-x64@11.16.3': + resolution: {integrity: sha512-4OHKFGJBBfOnuJnelbCS4eBorI6cj54FUxcZJwEXPeoLc8yzORBoJ2w+fQbwjlQcUUZLEg92uGhKCRiUoqznjg==} + cpu: [x64] + os: [freebsd] + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.16.3': + resolution: {integrity: sha512-OM3W0NLt9u7uKwG/yZbeXABansZC0oZeDF1nKgvcZoRw4/Yak6/l4S0onBfDFeYMY94eYeAt2bl60e30lgsb5A==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm-musleabihf@11.16.3': + resolution: {integrity: sha512-MRs7D7i1t7ACsAdTuP81gLZES918EpBmiUyEl8fu302yQB+4L7L7z0Ui8BWnthUTQd3nAU9dXvENLK/SqRVH8A==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-gnu@11.16.3': + resolution: {integrity: sha512-0eVYZxSceNqGADzhlV4ZRqkHF0fjWxRXQOB7Qwl5y1gN/XYUDvMfip+ngtzj4dM7zQT4U97hUhJ7PUKSy/JIGQ==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-musl@11.16.3': + resolution: {integrity: sha512-B1BvLeZbgDdVN0FvU40l5Q7lej8310WlabCBaouk8jY7H7xbI8phtomTtk3Efmevgfy5hImaQJu6++OmcFb2NQ==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-ppc64-gnu@11.16.3': + resolution: {integrity: sha512-q7khglic3Jqak7uDgA3MFnjDeI7krQT595GDZpvFq785fmFYSx8rlTkoHzmhQtUisYtl4XG7WUscwsoidFUI4w==} + cpu: [ppc64] + os: [linux] + + '@oxc-resolver/binding-linux-riscv64-gnu@11.16.3': + resolution: {integrity: sha512-aFRNmQNPzDgQEbw2s3c8yJYRimacSDI+u9df8rn5nSKzTVitHmbEpZqfxpwNLCKIuLSNmozHR1z1OT+oZVeYqg==} + cpu: [riscv64] + os: [linux] + + '@oxc-resolver/binding-linux-riscv64-musl@11.16.3': + resolution: {integrity: sha512-vZI85SvSMADcEL9G1TIrV0Rlkc1fY5Mup0DdlVC5EHPysZB4hXXHpr+h09pjlK5y+5om5foIzDRxE1baUCaWOA==} + cpu: [riscv64] + os: [linux] + + '@oxc-resolver/binding-linux-s390x-gnu@11.16.3': + resolution: {integrity: sha512-xiLBnaUlddFEzRHiHiSGEMbkg8EwZY6VD8F+3GfnFsiK3xg/4boaUV2bwXd+nUzl3UDQOMW1QcZJ4jJSb0qiJA==} + cpu: [s390x] + os: [linux] + + '@oxc-resolver/binding-linux-x64-gnu@11.16.3': + resolution: {integrity: sha512-6y0b05wIazJJgwu7yU/AYGFswzQQudYJBOb/otDhiDacp1+6ye8egoxx63iVo9lSpDbipL++54AJQFlcOHCB+g==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-linux-x64-musl@11.16.3': + resolution: {integrity: sha512-RmMgwuMa42c9logS7Pjprf5KCp8J1a1bFiuBFtG9/+yMu0BhY2t+0VR/um7pwtkNFvIQqAVh6gDOg/PnoKRcdQ==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-openharmony-arm64@11.16.3': + resolution: {integrity: sha512-/7AYRkjjW7xu1nrHgWUFy99Duj4/ydOBVaHtODie9/M6fFngo+8uQDFFnzmr4q//sd/cchIerISp/8CQ5TsqIA==} + cpu: [arm64] + os: [openharmony] + + '@oxc-resolver/binding-wasm32-wasi@11.16.3': + resolution: {integrity: sha512-urM6aIPbi5di4BSlnpd/TWtDJgG6RD06HvLBuNM+qOYuFtY1/xPbzQ2LanBI2ycpqIoIZwsChyplALwAMdyfCQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-resolver/binding-win32-arm64-msvc@11.16.3': + resolution: {integrity: sha512-QuvLqGKf7frxWHQ5TnrcY0C/hJpANsaez99Q4dAk1hen7lDTD4FBPtBzPnntLFXeaVG3PnSmnVjlv0vMILwU7Q==} + cpu: [arm64] + os: [win32] + + '@oxc-resolver/binding-win32-ia32-msvc@11.16.3': + resolution: {integrity: sha512-QR/witXK6BmYTlEP8CCjC5fxeG5U9A6a50pNpC1nLnhAcJjtzFG8KcQ5etVy/XvCLiDc7fReaAWRNWtCaIhM8Q==} + cpu: [ia32] + os: [win32] + + '@oxc-resolver/binding-win32-x64-msvc@11.16.3': + resolution: {integrity: sha512-bFuJRKOscsDAEZ/a8BezcTMAe2BQ/OBRfuMLFUuINfTR5qGVcm4a3xBIrQVepBaPxFj16SJdRjGe05vDiwZmFw==} + cpu: [x64] + os: [win32] + + '@publint/pack@0.1.2': + resolution: {integrity: sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==} + engines: {node: '>=18'} + + '@quansync/fs@1.0.0': + resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + + '@rolldown/binding-android-arm64@1.0.0-beta.59': + resolution: {integrity: sha512-6yLLgyswYwiCfls9+hoNFY9F8TQdwo15hpXDHzlAR0X/GojeKF+AuNcXjYNbOJ4zjl/5D6lliE8CbpB5t1OWIQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-android-arm64@1.0.0-beta.60': + resolution: {integrity: sha512-hOW6iQXtpG4uCW1zGK56+KhEXGttSkTp2ykncW/nkOIF/jOKTqbM944Q73HVeMXP1mPRvE2cZwNp3xeLIeyIGQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-beta.59': + resolution: {integrity: sha512-hqGXRc162qCCIOAcHN2Cw4eXiVTwYsMFLOhAy1IG2CxY+dwc/l4Ga+dLPkLor3Ikqy5WDn+7kxHbbh6EmshEpQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-arm64@1.0.0-beta.60': + resolution: {integrity: sha512-vyDA4HXY2mP8PPtl5UE17uGPxUNG4m1wkfa3kAkR8JWrFbarV97UmLq22IWrNhtBPa89xqerzLK8KoVmz5JqCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-beta.59': + resolution: {integrity: sha512-ezvvGuhteE15JmMhJW0wS7BaXmhwLy1YHeEwievYaPC1PgGD86wgBKfOpHr9tSKllAXbCe0BeeMvasscWLhKdA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-beta.60': + resolution: {integrity: sha512-WnxyqxAKP2BsxouwGY/RCF5UFw/LA4QOHhJ7VEl+UCelHokiwqNHRbryLAyRy3TE1FZ5eae+vAFcaetAu/kWLw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-beta.59': + resolution: {integrity: sha512-4fhKVJiEYVd5n6no/mrL3LZ9kByfCGwmONOrdtvx8DJGDQhehH/q3RfhG3V/4jGKhpXgbDjpIjkkFdybCTcgew==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-freebsd-x64@1.0.0-beta.60': + resolution: {integrity: sha512-JtyWJ+zXOHof5gOUYwdTWI2kL6b8q9eNwqB/oD4mfUFaC/COEB2+47JMhcq78dey9Ahmec3DZKRDZPRh9hNAMQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.59': + resolution: {integrity: sha512-T3Y52sW6JAhvIqArBw+wtjNU1Ieaz4g0NBxyjSJoW971nZJBZygNlSYx78G4cwkCmo1dYTciTPDOnQygLV23pA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.60': + resolution: {integrity: sha512-LrMoKqpHx+kCaNSk84iSBd4yVOymLIbxJQtvFjDN2CjQraownR+IXcwYDblFcj9ivmS54T3vCboXBbm3s1zbPQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.59': + resolution: {integrity: sha512-NIW40jQDSQap2KDdmm9z3B/4OzWJ6trf8dwx3FD74kcQb3v34ThsBFTtzE5KjDuxnxgUlV+DkAu+XgSMKrgufw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.60': + resolution: {integrity: sha512-sqI+Vdx1gmXJMsXN3Fsewm3wlt7RHvRs1uysSp//NLsCoh9ZFEUr4ZzGhWKOg6Rvf+njNu/vCsz96x7wssLejQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.59': + resolution: {integrity: sha512-CCKEk+H+8c0WGe/8n1E20n85Tq4Pv+HNAbjP1KfUXW+01aCWSMjU56ChNrM2tvHnXicfm7QRNoZyfY8cWh7jLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.60': + resolution: {integrity: sha512-8xlqGLDtTP8sBfYwneTDu8+PRm5reNEHAuI/+6WPy9y350ls0KTFd3EJCOWEXWGW0F35ko9Fn9azmurBTjqOrQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.59': + resolution: {integrity: sha512-VlfwJ/HCskPmQi8R0JuAFndySKVFX7yPhE658o27cjSDWWbXVtGkSbwaxstii7Q+3Rz87ZXN+HLnb1kd4R9Img==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.60': + resolution: {integrity: sha512-iR4nhVouVZK1CiGGGyz+prF5Lw9Lmz30Rl36Hajex+dFVFiegka604zBwzTp5Tl0BZnr50ztnVJ30tGrBhDr8Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.59': + resolution: {integrity: sha512-kuO92hTRyGy0Ts3Nsqll0rfO8eFsEJe9dGQGktkQnZ2hrJrDVN0y419dMgKy/gB2S2o7F2dpWhpfQOBehZPwVA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.60': + resolution: {integrity: sha512-HbfNcqNeqxFjSMf1Kpe8itr2e2lr0Bm6HltD2qXtfU91bSSikVs9EWsa1ThshQ1v2ZvxXckGjlVLtah6IoslPg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.59': + resolution: {integrity: sha512-PXAebvNL4sYfCqi8LdY4qyFRacrRoiPZLo3NoUmiTxm7MPtYYR8CNtBGNokqDmMuZIQIecRaD/jbmFAIDz7DxQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.60': + resolution: {integrity: sha512-BiiamFcgTJ+ZFOUIMO9AHXUo9WXvHVwGfSrJ+Sv0AsTd2w3VN7dJGiH3WRcxKFetljJHWvGbM4fdpY5lf6RIvw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.59': + resolution: {integrity: sha512-yJoklQg7XIZq8nAg0bbkEXcDK6sfpjxQGxpg2Nd6ERNtvg+eOaEBRgPww0BVTrYFQzje1pB5qPwC2VnJHT3koQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.60': + resolution: {integrity: sha512-6roXGbHMdR2ucnxXuwbmQvk8tuYl3VGu0yv13KxspyKBxxBd4RS6iykzLD6mX2gMUHhfX8SVWz7n/62gfyKHow==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.59': + resolution: {integrity: sha512-ljZ4+McmCbIuZwEBaoGtiG8Rq2nJjaXEnLEIx+usWetXn1ECjXY0LAhkELxOV6ytv4ensEmoJJ8nXg47hRMjlw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.60': + resolution: {integrity: sha512-JBOm8/DC/CKnHyMHoJFdvzVHxUixid4dGkiTqGflxOxO43uSJMpl77pSPXvzwZ/VXwqblU2V0/PanyCBcRLowQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.59': + resolution: {integrity: sha512-bMY4tTIwbdZljW+xe/ln1hvs0SRitahQSXfWtvgAtIzgSX9Ar7KqJzU7lRm33YTRFIHLULRi53yNjw9nJGd6uQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.60': + resolution: {integrity: sha512-MKF0B823Efp+Ot8KsbwIuGhKH58pf+2rSM6VcqyNMlNBHheOM0Gf7JmEu+toc1jgN6fqjH7Et+8hAzsLVkIGfA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.53': + resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + + '@rolldown/pluginutils@1.0.0-beta.59': + resolution: {integrity: sha512-aoh6LAJRyhtazs98ydgpNOYstxUlsOV1KJXcpf/0c0vFcUA8uyd/hwKRhqE/AAPNqAho9RliGsvitCoOzREoVA==} + + '@rolldown/pluginutils@1.0.0-beta.60': + resolution: {integrity: sha512-Jz4aqXRPVtqkH1E3jRDzLO5cgN5JwW+WG0wXGE4NiJd25nougv/AHzxmKCzmVQUYnxLmTM0M4wrZp+LlC2FKLg==} + + '@rollup/rollup-android-arm-eabi@4.55.1': + resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.55.1': + resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.55.1': + resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.55.1': + resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.55.1': + resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.55.1': + resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.55.1': + resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.55.1': + resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.55.1': + resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.55.1': + resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.55.1': + resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.55.1': + resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.55.1': + resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.55.1': + resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.55.1': + resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.55.1': + resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.55.1': + resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.55.1': + resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.55.1': + resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.55.1': + resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.55.1': + resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.55.1': + resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.55.1': + resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.55.1': + resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} + cpu: [x64] + os: [win32] + + '@shikijs/engine-oniguruma@3.21.0': + resolution: {integrity: sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==} + + '@shikijs/langs@3.21.0': + resolution: {integrity: sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==} + + '@shikijs/themes@3.21.0': + resolution: {integrity: sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==} + + '@shikijs/types@3.21.0': + resolution: {integrity: sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@sinclair/typebox@0.34.47': + resolution: {integrity: sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@stylistic/eslint-plugin@5.7.0': + resolution: {integrity: sha512-PsSugIf9ip1H/mWKj4bi/BlEoerxXAda9ByRFsYuwsmr6af9NxJL0AaiNXs8Le7R21QR5KMiD/KdxZZ71LjAxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=9.0.0' + + '@sveltejs/acorn-typescript@1.0.8': + resolution: {integrity: sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==} + peerDependencies: + acorn: ^8.9.0 + + '@svitejs/changesets-changelog-github-compact@1.2.0': + resolution: {integrity: sha512-08eKiDAjj4zLug1taXSIJ0kGL5cawjVCyJkBb6EWSg5fEPX6L+Wtr0CH2If4j5KYylz85iaZiFlUItvgJvll5g==} + engines: {node: ^14.13.1 || ^16.0.0 || >=18} + + '@tanstack/eslint-config@0.3.4': + resolution: {integrity: sha512-5Ou1XWJRCTx5G8WoCbT7+6nQ4iNdsISzBAc4lXpFy2fEOO7xioOSPvcPIv+r9V0drPPETou2tr6oLGZZ909FKg==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^8.0.0 || ^9.0.0 + + '@tanstack/react-store@0.8.0': + resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/solid-store@0.8.0': + resolution: {integrity: sha512-JwqTedbxyOGw7mfmdGkB0RGgefRCw/tNauc8tlMcaS1mV5wTFT8c1KIB3LgttuHaanMJEBeqQJ7bc/R0WTP1fA==} + peerDependencies: + solid-js: ^1.6.0 + + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + + '@tanstack/typedoc-config@0.3.3': + resolution: {integrity: sha512-wVT2YfKDSpd+4f7fk6UaPIP3a2J7LSovlyVuFF1PH2yQb7gjqehod5zdFiwFyEXgvI9XGuFvvs1OehkKNYcr6A==} + engines: {node: '>=18'} + + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.3.1': + resolution: {integrity: sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@tybys/wasm-util@0.9.0': + resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + + '@types/node@20.19.30': + resolution: {integrity: sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==} + + '@types/node@25.0.9': + resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.8': + resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/whatwg-mimetype@3.0.2': + resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@typescript-eslint/eslint-plugin@8.53.0': + resolution: {integrity: sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.53.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.53.0': + resolution: {integrity: sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.53.0': + resolution: {integrity: sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.53.0': + resolution: {integrity: sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.53.0': + resolution: {integrity: sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.53.0': + resolution: {integrity: sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.53.0': + resolution: {integrity: sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.53.0': + resolution: {integrity: sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.53.0': + resolution: {integrity: sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.53.0': + resolution: {integrity: sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + '@vitejs/plugin-react@5.1.2': + resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@vitest/expect@4.0.17': + resolution: {integrity: sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==} + + '@vitest/mocker@4.0.17': + resolution: {integrity: sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.0.17': + resolution: {integrity: sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==} + + '@vitest/runner@4.0.17': + resolution: {integrity: sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==} + + '@vitest/snapshot@4.0.17': + resolution: {integrity: sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==} + + '@vitest/spy@4.0.17': + resolution: {integrity: sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==} + + '@vitest/utils@4.0.17': + resolution: {integrity: sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==} + + '@yarnpkg/lockfile@1.1.0': + resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} + + '@yarnpkg/parsers@3.0.2': + resolution: {integrity: sha512-/HcYgtUSiJiot/XWGLOlGxPYUG65+/31V8oqk17vZLW1xlCoR4PampyePljOxY2n8/3jz9+tIFzICsyGujJZoA==} + engines: {node: '>=18.12.0'} + + '@zkochan/js-yaml@0.0.7': + resolution: {integrity: sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==} + hasBin: true + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-kit@2.2.0: + resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} + engines: {node: '>=20.19.0'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.13.2: + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + babel-plugin-jsx-dom-expressions@0.40.3: + resolution: {integrity: sha512-5HOwwt0BYiv/zxl7j8Pf2bGL6rDXfV6nUhLs8ygBX+EFJXzBPHM/euj9j/6deMZ6wa52Wb2PBaAV5U/jKwIY1w==} + peerDependencies: + '@babel/core': ^7.20.12 + + babel-preset-solid@1.9.10: + resolution: {integrity: sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ==} + peerDependencies: + '@babel/core': ^7.0.0 + solid-js: ^1.9.10 + peerDependenciesMeta: + solid-js: + optional: true + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.9.15: + resolution: {integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==} + hasBin: true + + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + + birecord@0.1.1: + resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} + + birpc@4.0.0: + resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001764: + resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.1.2: + resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} + engines: {node: '>=20.18.1'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-spinners@2.6.1: + resolution: {integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==} + engines: {node: '>=6'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + comment-parser@1.4.4: + resolution: {integrity: sha512-0D6qSQ5IkeRrGJFHRClzaMOenMeT0gErz3zIw3AprKMqhRN6LNU2jQOdkPG/FZ+8bCgXE1VidrgSzlBBDZRr8A==} + engines: {node: '>= 12.0.0'} + + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + dataloader@1.4.0: + resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + + devalue@5.6.2: + resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dotenv-expand@11.0.7: + resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} + engines: {node: '>=12'} + + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + dts-resolver@2.1.3: + resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==} + engines: {node: '>=20.19.0'} + peerDependencies: + oxc-resolver: '>=11.0.0' + peerDependenciesMeta: + oxc-resolver: + optional: true + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + enhanced-resolve@5.18.4: + resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + engines: {node: '>=10.13.0'} + + enquirer@2.3.6: + resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} + engines: {node: '>=8.6'} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-compat-utils@0.5.1: + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + + eslint-import-context@0.1.9: + resolution: {integrity: sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + peerDependencies: + unrs-resolver: ^1.0.0 + peerDependenciesMeta: + unrs-resolver: + optional: true + + eslint-plugin-es-x@7.8.0: + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8' + + eslint-plugin-import-x@4.16.1: + resolution: {integrity: sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/utils': ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 + eslint-import-resolver-node: '*' + peerDependenciesMeta: + '@typescript-eslint/utils': + optional: true + eslint-import-resolver-node: + optional: true + + eslint-plugin-n@17.23.2: + resolution: {integrity: sha512-RhWBeb7YVPmNa2eggvJooiuehdL76/bbfj/OJewyoGT80qn5PXdz8zMOTO6YHOsI7byPt7+Ighh/i/4a5/v7hw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.23.0' + + eslint-plugin-react-compiler@19.1.0-rc.2: + resolution: {integrity: sha512-oKalwDGcD+RX9mf3NEO4zOoUMeLvjSvcbbEOpquzmzqEEM2MQdp7/FY/Hx9NzmUwFzH1W9SKTz5fihfMldpEYw==} + engines: {node: ^14.17.0 || ^16.0.0 || >= 18.0.0} + peerDependencies: + eslint: '>=7' + + eslint-plugin-react-dom@2.7.2: + resolution: {integrity: sha512-Qzd4HAFwsxvOJoAycLIRxziOTJwEZ6EGAA6jEFFBSD1BbFVnDlozMvOLp9/+GrZW3cE0FGmAS6QXnjuMf0QYLQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + eslint-plugin-react-hooks-extra@2.7.2: + resolution: {integrity: sha512-wcjQeBO1naCFPV47osw7nnK2p81eudCE2PhasKLtBV+GcAEi34jbt9QGULzQYueP+zd1aW53SmnVrTinY4DC6w==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + eslint-plugin-react-hooks@7.0.1: + resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react-naming-convention@2.7.2: + resolution: {integrity: sha512-T+/RQFEda3AgCzBHguE3isLQetn8KUOZ14SnDBQSOZSWS/GjgQn+gmqHi3EVHX/sDdL+LsIUKRsRR6KmmYWMiw==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + eslint-plugin-react-web-api@2.7.2: + resolution: {integrity: sha512-iA3D8jbwasMeeUfK8XucGkgrjQvZowCTi1+TzA43U7IFsWzyQWQpbN/I9B0BY/g6/JU9falC5b7qv6HB7P5JhA==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + eslint-plugin-react-x@2.7.2: + resolution: {integrity: sha512-0NbYqJhc3tZQVluaFMVCOg6HEFarlNNXe+DHa/JrLAR0PVb9AtJGk8FBEDdxaUZO8ph0sAekUNLB7gymftj4Dw==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + eslint-plugin-unused-imports@4.3.0: + resolution: {integrity: sha512-ZFBmXMGBYfHttdRtOG9nFFpmUvMtbHSjsKrS20vdWdbfiVYsO3yA2SGYy9i9XmZJDfMGBflZGBCm70SEnFQtOA==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 + eslint: ^9.0.0 || ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.0: + resolution: {integrity: sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.2: + resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + esm-env@1.2.2: + resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + espree@11.0.0: + resolution: {integrity: sha512-+gMeWRrIh/NsG+3NaLeWHuyeyk70p2tbvZIWBYcqQ4/7Xvars6GYTZNhF1sIeLcc6Wb11He5ffz3hsHyXFrw5A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrap@2.2.1: + resolution: {integrity: sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + extendable-error@0.1.7: + resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fd-package-json@2.0.0: + resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + formatly@0.3.0: + resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} + engines: {node: '>=18.3.0'} + hasBin: true + + front-matter@4.0.2: + resolution: {integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@15.15.0: + resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + engines: {node: '>=18'} + + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + happy-dom@20.3.1: + resolution: {integrity: sha512-tLvsizNno05Hij0PoB0QN/S8xf0YU2AGvO11/JlJDw5McA/gzyn0Ni1RwbTI1/zteUbOekJH0t6q8HFvjbxsGg==} + engines: {node: '>=20.0.0'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + hookable@6.0.1: + resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} + + html-entities@2.3.3: + resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} + + html-link-extractor@1.0.5: + resolution: {integrity: sha512-ADd49pudM157uWHwHQPUSX4ssMsvR/yHIswOR5CUfBdK9g9ZYGMhVSE6KZVHJ6kCkR0gH4htsfzU6zECDNVwyw==} + + htmlparser2@10.0.0: + resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + + human-id@4.1.3: + resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} + hasBin: true + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-without-cache@0.2.5: + resolution: {integrity: sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==} + engines: {node: '>=20.19.0'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-immutable-type@5.0.1: + resolution: {integrity: sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg==} + peerDependencies: + eslint: '*' + typescript: '>=4.7.4' + + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jest-diff@30.2.0: + resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + knip@5.81.0: + resolution: {integrity: sha512-EM9YdNg6zU2DWMJuc9zD8kPUpj0wvPspa63Qe9DPGygzL956uYThfoUQk5aNpPmMr9hs/k+Xm7FLuWFKERFkrQ==} + engines: {node: '>=18.18.0'} + hasBin: true + peerDependencies: + '@types/node': '>=18' + typescript: '>=5.0.4 <7' + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lines-and-columns@2.0.3: + resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lunr@2.3.9: + resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + markdown-link-extractor@4.0.3: + resolution: {integrity: sha512-aEltJiQ4/oC0h6Jbw/uuATGSHZPkcH8DIunNH1A0e+GSFkvZ6BbBkdvBTVfIV8r6HapCU3yTd0eFdi3ZeM1eAQ==} + + marked@17.0.1: + resolution: {integrity: sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==} + engines: {node: '>= 20'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + merge-anything@5.1.7: + resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} + engines: {node: '>=12.13'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-machine-id@1.1.12: + resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + nx@22.3.3: + resolution: {integrity: sha512-pOxtKWUfvf0oD8Geqs8D89Q2xpstRTaSY+F6Ut/Wd0GnEjUjO32SS1ymAM6WggGPHDZN4qpNrd5cfIxQmAbRLg==} + hasBin: true + peerDependencies: + '@swc-node/register': ^1.8.0 + '@swc/core': ^1.3.85 + peerDependenciesMeta: + '@swc-node/register': + optional: true + '@swc/core': + optional: true + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + ora@5.3.0: + resolution: {integrity: sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==} + engines: {node: '>=10'} + + outdent@0.5.0: + resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + + oxc-resolver@11.16.3: + resolution: {integrity: sha512-goLOJH3x69VouGWGp5CgCIHyksmOZzXr36lsRmQz1APg3SPFORrvV2q7nsUHMzLVa6ZJgNwkgUSJFsbCpAWkCA==} + + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-manager-detector@0.2.11: + resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + premove@4.0.0: + resolution: {integrity: sha512-zim/Hr4+FVdCIM7zL9b9Z0Wfd5Ya3mnKtiuDv7L5lzYzanSq6cOcVJ7EFcgK4I0pt28l8H0jX/x3nyog380XgQ==} + engines: {node: '>=6'} + hasBin: true + + prettier-plugin-svelte@3.4.1: + resolution: {integrity: sha512-xL49LCloMoZRvSwa6IEdN2GV6cq2IqpYGstYtMT+5wmml1/dClEoI0MZR78MiVPpu6BdQFfN0/y73yO6+br5Pg==} + peerDependencies: + prettier: ^3.0.0 + svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + prettier@3.8.0: + resolution: {integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + pretty-format@30.2.0: + resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + publint@0.3.16: + resolution: {integrity: sha512-MFqyfRLAExPVZdTQFwkAQELzA8idyXzROVOytg6nEJ/GEypXBUmMGrVaID8cTuzRS1U5L8yTOdOJtMXgFUJAeA==} + engines: {node: '>=18'} + hasBin: true + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + + quansync@1.0.0: + resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@19.2.3: + resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} + peerDependencies: + react: ^19.2.3 + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react@19.2.3: + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + engines: {node: '>=0.10.0'} + + read-yaml-file@1.1.0: + resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} + engines: {node: '>=6'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rolldown-plugin-dts@0.20.0: + resolution: {integrity: sha512-cLAY1kN2ilTYMfZcFlGWbXnu6Nb+8uwUBsi+Mjbh4uIx7IN8uMOmJ7RxrrRgPsO4H7eSz3E+JwGoL1gyugiyUA==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@ts-macro/tsc': ^0.3.6 + '@typescript/native-preview': '>=7.0.0-dev.20250601.1' + rolldown: ^1.0.0-beta.57 + typescript: ^5.0.0 + vue-tsc: ~3.2.0 + peerDependenciesMeta: + '@ts-macro/tsc': + optional: true + '@typescript/native-preview': + optional: true + typescript: + optional: true + vue-tsc: + optional: true + + rolldown@1.0.0-beta.59: + resolution: {integrity: sha512-Slm000Gd8/AO9z4Kxl4r8mp/iakrbAuJ1L+7ddpkNxgQ+Vf37WPvY63l3oeyZcfuPD1DRrUYBsRPIXSOhvOsmw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rolldown@1.0.0-beta.60: + resolution: {integrity: sha512-YYgpv7MiTp9LdLj1fzGzCtij8Yi2OKEc3HQtfbIxW4yuSgpQz9518I69U72T5ErPA/ATOXqlcisiLrWy+5V9YA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rollup@4.55.1: + resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + seroval-plugins@1.3.3: + resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.3.2: + resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} + engines: {node: '>=10'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + sherif-darwin-arm64@1.10.0: + resolution: {integrity: sha512-fHRg/fgyxHebCH9vuGEhImyGqmwlBq67BVyI8Ugda8GM+W+Ofj1cQnzDX82cYuCHU+KJ7hQFq8iPHkRizXWOrA==} + cpu: [arm64] + os: [darwin] + + sherif-darwin-x64@1.10.0: + resolution: {integrity: sha512-7rhayQ+jlIj3SscnHMi6JVCYR9od/HiqIGIBgOQeux31YRzc/XvfKjE9X+FrCRU+72qz7sqw5ZY7jl7bRxbOUg==} + cpu: [x64] + os: [darwin] + + sherif-linux-arm64-musl@1.10.0: + resolution: {integrity: sha512-TsaQSefkaIJ+oFGGaaPm5BzrjVRnvcquh4q3/e5LB6JdhPTveNPo3o2Pzmq6sKry9dzk3p7sKtzJpLz4q5V/+Q==} + cpu: [arm64] + os: [linux] + + sherif-linux-arm64@1.10.0: + resolution: {integrity: sha512-QtEju3eLPpEb7hv9QRVdsi2J3bhIFEBbRk0vjdnAEKyRb3q9MjyqEhps69JgaCv8olEiBjGcU1hGP7vl5QVG4A==} + cpu: [arm64] + os: [linux] + + sherif-linux-x64-musl@1.10.0: + resolution: {integrity: sha512-iSYRYEFE0xfOJVwPjsUN4o8CoNSEyxJHsSliBDxfEZQubN0rmE9f1hs83HPPAkEozGestI7PxKFKcyTgTxEoXg==} + cpu: [x64] + os: [linux] + + sherif-linux-x64@1.10.0: + resolution: {integrity: sha512-/1ydjgJxXbqnGWViAENHxlX9lEDhATO99qtFcMseUFkPpEAxQ9qFctWf3OB2rciPlHLuPzhphkJAt7ZkX1R5eA==} + cpu: [x64] + os: [linux] + + sherif-windows-arm64@1.10.0: + resolution: {integrity: sha512-CBNys+m7TsWD/1/5WQRJCNjfm08VhmBP9JSmecoHCsfDF+o0vt52NDrzVOOeai/c/yYunCBvAAx9EIFXBmgpHw==} + cpu: [arm64] + os: [win32] + + sherif-windows-x64@1.10.0: + resolution: {integrity: sha512-XRN4SuZQud0X4UKZZxLe4IyVkbo9qa8rvmFhgCoULaRScucNdJJ4r6hnjZ7DR0spl7zSPJNZUNcgnnJmxWfs1Q==} + cpu: [x64] + os: [win32] + + sherif@1.10.0: + resolution: {integrity: sha512-DHg6+Pj7ORhYyC+CaSAr8DeRxqf9GXB90yqLmUILPtY7WhZuJatMir3id2MNjuF5I/1313SbrTTItIDu//G4jg==} + hasBin: true + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + smol-toml@1.6.0: + resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} + engines: {node: '>= 18'} + + solid-js@1.9.10: + resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==} + + solid-refresh@0.6.3: + resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==} + peerDependencies: + solid-js: ^1.3 + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + spawndamnit@3.0.1: + resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stable-hash-x@0.2.0: + resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} + engines: {node: '>=12.0.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + string-ts@2.3.1: + resolution: {integrity: sha512-xSJq+BS52SaFFAVxuStmx6n5aYZU571uYUnUrPXkPFCfdHyZMMlbP2v2Wx5sNBnAVzq/2+0+mcBLBa3Xa5ubYw==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + svelte@5.46.4: + resolution: {integrity: sha512-VJwdXrmv9L8L7ZasJeWcCjoIuMRVbhuxbss0fpVnR8yorMmjNDwcjIH08vS6wmSzzzgAG5CADQ1JuXPS2nwt9w==} + engines: {node: '>=18'} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + term-size@2.2.1: + resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} + engines: {node: '>=8'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-declaration-location@1.0.7: + resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} + peerDependencies: + typescript: '>=4.0.0' + + ts-pattern@5.9.0: + resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} + + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + + tsdown@0.19.0: + resolution: {integrity: sha512-uqg8yzlS7GemFWcM6aCp/sptF4bJiJbWUibuHTRLLCBEsGCgJxuqxPhuVTqyHXqoEkh9ohwAdlyDKli5MEWCyQ==} + engines: {node: '>=20.19.0'} + hasBin: true + peerDependencies: + '@arethetypeswrong/core': ^0.18.1 + '@vitejs/devtools': '*' + publint: ^0.3.0 + typescript: ^5.0.0 + unplugin-lightningcss: ^0.4.0 + unplugin-unused: ^0.5.0 + peerDependenciesMeta: + '@arethetypeswrong/core': + optional: true + '@vitejs/devtools': + optional: true + publint: + optional: true + typescript: + optional: true + unplugin-lightningcss: + optional: true + unplugin-unused: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typedoc-plugin-frontmatter@1.3.0: + resolution: {integrity: sha512-xYQFMAecMlsRUjmf9oM/Sq2FVz4zlgcbIeVFNLdO118CHTN06gIKJNSlyExh9+Xl8sK0YhIvoQwViUURxritWA==} + peerDependencies: + typedoc-plugin-markdown: '>=4.5.0' + + typedoc-plugin-markdown@4.9.0: + resolution: {integrity: sha512-9Uu4WR9L7ZBgAl60N/h+jqmPxxvnC9nQAlnnO/OujtG2ubjnKTVUFY1XDhcMY+pCqlX3N2HsQM2QTYZIU9tJuw==} + engines: {node: '>= 18'} + peerDependencies: + typedoc: 0.28.x + + typedoc@0.28.14: + resolution: {integrity: sha512-ftJYPvpVfQvFzpkoSfHLkJybdA/geDJ8BGQt/ZnkkhnBYoYW6lBgPQXu6vqLxO4X75dA55hX8Af847H5KXlEFA==} + engines: {node: '>= 18', pnpm: '>= 10'} + hasBin: true + peerDependencies: + typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x + + typescript-eslint@8.53.0: + resolution: {integrity: sha512-xHURCQNxZ1dsWn0sdOaOfCSQG0HKeqSj9OexIxrz6ypU6wHYOdX2I3D2b8s8wFSsSOYJb+6q283cLiLlkEsBYw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + unconfig-core@7.4.2: + resolution: {integrity: sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + undici@7.18.2: + resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==} + engines: {node: '>=20.18.1'} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + unrun@0.2.25: + resolution: {integrity: sha512-ZOr5uQL+JlcUT8hZsQbtuUgb1zzcFx3juhXyLSsciaWa3DW1ldMY9r4KSF3+k/LR1Evj2ggAZo1usK4/knBjMQ==} + engines: {node: '>=20.19.0'} + hasBin: true + peerDependencies: + synckit: ^0.11.11 + peerDependenciesMeta: + synckit: + optional: true + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + vite-plugin-solid@2.11.10: + resolution: {integrity: sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw==} + peerDependencies: + '@testing-library/jest-dom': ^5.16.6 || ^5.17.0 || ^6.* + solid-js: ^1.7.2 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + '@testing-library/jest-dom': + optional: true + + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.1: + resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + vite: + optional: true + + vitest@4.0.17: + resolution: {integrity: sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.17 + '@vitest/browser-preview': 4.0.17 + '@vitest/browser-webdriverio': 4.0.17 + '@vitest/ui': 4.0.17 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + vue-eslint-parser@10.2.0: + resolution: {integrity: sha512-CydUvFOQKD928UzZhTp4pr2vWz1L+H99t7Pkln2QSPdvmURT0MoC4wUccfCnuEaihNsu9aYYyk+bep8rlfkUXw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + + walk-up-path@4.0.0: + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} + engines: {node: 20 || >=22} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zimmerframe@1.1.4: + resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} + + zod-validation-error@3.5.4: + resolution: {integrity: sha512-+hEiRIiPobgyuFlEojnqjJnhFvg4r/i3cqgcm67eehZf/WBaK3g6cD02YU9mtdVxZjv8CzCA9n/Rhrs3yAAvAw==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.24.4 + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.3.5: + resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} + +snapshots: + + '@adobe/css-tools@4.4.4': {} + + '@babel/code-frame@7.28.6': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.6': {} + + '@babel/core@7.28.6': + dependencies: + '@babel/code-frame': 7.28.6 + '@babel/generator': 7.28.6 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/template': 7.28.6 + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.6': + dependencies: + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.28.6 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.28.6) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.28.6 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.18.6': + dependencies: + '@babel/types': 7.28.6 + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.28.6 + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-replace-supers@7.28.6(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.28.6 + '@babel/types': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.28.6 + + '@babel/parser@7.28.6': + dependencies: + '@babel/types': 7.28.6 + + '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.28.6) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/runtime@7.28.6': {} + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + + '@babel/traverse@7.28.6': + dependencies: + '@babel/code-frame': 7.28.6 + '@babel/generator': 7.28.6 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.6 + '@babel/template': 7.28.6 + '@babel/types': 7.28.6 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.6': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@changesets/apply-release-plan@7.0.14': + dependencies: + '@changesets/config': 3.1.2 + '@changesets/get-version-range-type': 0.4.0 + '@changesets/git': 3.0.4 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + detect-indent: 6.1.0 + fs-extra: 7.0.1 + lodash.startcase: 4.4.0 + outdent: 0.5.0 + prettier: 2.8.8 + resolve-from: 5.0.0 + semver: 7.7.3 + + '@changesets/assemble-release-plan@6.0.9': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + semver: 7.7.3 + + '@changesets/changelog-git@0.2.1': + dependencies: + '@changesets/types': 6.1.0 + + '@changesets/cli@2.29.8(@types/node@25.0.9)': + dependencies: + '@changesets/apply-release-plan': 7.0.14 + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/changelog-git': 0.2.1 + '@changesets/config': 3.1.2 + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/get-release-plan': 4.0.14 + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.6 + '@changesets/should-skip-package': 0.1.2 + '@changesets/types': 6.1.0 + '@changesets/write': 0.4.0 + '@inquirer/external-editor': 1.0.3(@types/node@25.0.9) + '@manypkg/get-packages': 1.1.3 + ansi-colors: 4.1.3 + ci-info: 3.9.0 + enquirer: 2.4.1 + fs-extra: 7.0.1 + mri: 1.2.0 + p-limit: 2.3.0 + package-manager-detector: 0.2.11 + picocolors: 1.1.1 + resolve-from: 5.0.0 + semver: 7.7.3 + spawndamnit: 3.0.1 + term-size: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@changesets/config@3.1.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/get-dependents-graph': 2.1.3 + '@changesets/logger': 0.1.1 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + micromatch: 4.0.8 + + '@changesets/errors@0.2.0': + dependencies: + extendable-error: 0.1.7 + + '@changesets/get-dependents-graph@2.1.3': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + picocolors: 1.1.1 + semver: 7.7.3 + + '@changesets/get-github-info@0.6.0': + dependencies: + dataloader: 1.4.0 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + '@changesets/get-release-plan@4.0.14': + dependencies: + '@changesets/assemble-release-plan': 6.0.9 + '@changesets/config': 3.1.2 + '@changesets/pre': 2.0.2 + '@changesets/read': 0.6.6 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/get-version-range-type@0.4.0': {} + + '@changesets/git@3.0.4': + dependencies: + '@changesets/errors': 0.2.0 + '@manypkg/get-packages': 1.1.3 + is-subdir: 1.2.0 + micromatch: 4.0.8 + spawndamnit: 3.0.1 + + '@changesets/logger@0.1.1': + dependencies: + picocolors: 1.1.1 + + '@changesets/parse@0.4.2': + dependencies: + '@changesets/types': 6.1.0 + js-yaml: 4.1.1 + + '@changesets/pre@2.0.2': + dependencies: + '@changesets/errors': 0.2.0 + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + fs-extra: 7.0.1 + + '@changesets/read@0.6.6': + dependencies: + '@changesets/git': 3.0.4 + '@changesets/logger': 0.1.1 + '@changesets/parse': 0.4.2 + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + p-filter: 2.1.0 + picocolors: 1.1.1 + + '@changesets/should-skip-package@0.1.2': + dependencies: + '@changesets/types': 6.1.0 + '@manypkg/get-packages': 1.1.3 + + '@changesets/types@4.1.0': {} + + '@changesets/types@6.1.0': {} + + '@changesets/write@0.4.0': + dependencies: + '@changesets/types': 6.1.0 + fs-extra: 7.0.1 + human-id: 4.1.3 + prettier: 2.8.8 + + '@emnapi/core@1.8.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + + '@emnapi/runtime@1.8.1': + dependencies: + tslib: 2.8.1 + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + + '@esbuild/aix-ppc64@0.27.2': + optional: true + + '@esbuild/android-arm64@0.27.2': + optional: true + + '@esbuild/android-arm@0.27.2': + optional: true + + '@esbuild/android-x64@0.27.2': + optional: true + + '@esbuild/darwin-arm64@0.27.2': + optional: true + + '@esbuild/darwin-x64@0.27.2': + optional: true + + '@esbuild/freebsd-arm64@0.27.2': + optional: true + + '@esbuild/freebsd-x64@0.27.2': + optional: true + + '@esbuild/linux-arm64@0.27.2': + optional: true + + '@esbuild/linux-arm@0.27.2': + optional: true + + '@esbuild/linux-ia32@0.27.2': + optional: true + + '@esbuild/linux-loong64@0.27.2': + optional: true + + '@esbuild/linux-mips64el@0.27.2': + optional: true + + '@esbuild/linux-ppc64@0.27.2': + optional: true + + '@esbuild/linux-riscv64@0.27.2': + optional: true + + '@esbuild/linux-s390x@0.27.2': + optional: true + + '@esbuild/linux-x64@0.27.2': + optional: true + + '@esbuild/netbsd-arm64@0.27.2': + optional: true + + '@esbuild/netbsd-x64@0.27.2': + optional: true + + '@esbuild/openbsd-arm64@0.27.2': + optional: true + + '@esbuild/openbsd-x64@0.27.2': + optional: true + + '@esbuild/openharmony-arm64@0.27.2': + optional: true + + '@esbuild/sunos-x64@0.27.2': + optional: true + + '@esbuild/win32-arm64@0.27.2': + optional: true + + '@esbuild/win32-ia32@0.27.2': + optional: true + + '@esbuild/win32-x64@0.27.2': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': + dependencies: + eslint: 9.39.2(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint-react/ast@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-react/eff': 2.7.2 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + string-ts: 2.3.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@eslint-react/core@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.7.2 + '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + birecord: 0.1.1 + eslint: 9.39.2(jiti@2.6.1) + ts-pattern: 5.9.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@eslint-react/eff@2.7.2': {} + + '@eslint-react/eslint-plugin@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-react/eff': 2.7.2 + '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + eslint-plugin-react-dom: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-hooks-extra: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-naming-convention: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-web-api: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-x: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@eslint-react/shared@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-react/eff': 2.7.2 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + ts-pattern: 5.9.0 + typescript: 5.9.3 + zod: 4.3.5 + transitivePeerDependencies: + - supports-color + + '@eslint-react/var@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.7.2 + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + ts-pattern: 5.9.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.3': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.2': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@faker-js/faker@10.2.0': {} + + '@gerrit0/mini-shiki@3.21.0': + dependencies: + '@shikijs/engine-oniguruma': 3.21.0 + '@shikijs/langs': 3.21.0 + '@shikijs/themes': 3.21.0 + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@inquirer/external-editor@1.0.3(@types/node@25.0.9)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 25.0.9 + + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + + '@jest/diff-sequences@30.0.1': {} + + '@jest/get-type@30.1.0': {} + + '@jest/schemas@30.0.5': + dependencies: + '@sinclair/typebox': 0.34.47 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@manypkg/find-root@1.1.0': + dependencies: + '@babel/runtime': 7.28.6 + '@types/node': 12.20.55 + find-up: 4.1.0 + fs-extra: 8.1.0 + + '@manypkg/get-packages@1.1.3': + dependencies: + '@babel/runtime': 7.28.6 + '@changesets/types': 4.1.0 + '@manypkg/find-root': 1.1.0 + fs-extra: 8.1.0 + globby: 11.1.0 + read-yaml-file: 1.1.0 + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@napi-rs/wasm-runtime@0.2.4': + dependencies: + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 + '@tybys/wasm-util': 0.9.0 + + '@napi-rs/wasm-runtime@1.1.1': + dependencies: + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@nx/nx-darwin-arm64@22.3.3': + optional: true + + '@nx/nx-darwin-x64@22.3.3': + optional: true + + '@nx/nx-freebsd-x64@22.3.3': + optional: true + + '@nx/nx-linux-arm-gnueabihf@22.3.3': + optional: true + + '@nx/nx-linux-arm64-gnu@22.3.3': + optional: true + + '@nx/nx-linux-arm64-musl@22.3.3': + optional: true + + '@nx/nx-linux-x64-gnu@22.3.3': + optional: true + + '@nx/nx-linux-x64-musl@22.3.3': + optional: true + + '@nx/nx-win32-arm64-msvc@22.3.3': + optional: true + + '@nx/nx-win32-x64-msvc@22.3.3': + optional: true + + '@oxc-project/types@0.107.0': {} + + '@oxc-project/types@0.108.0': {} + + '@oxc-resolver/binding-android-arm-eabi@11.16.3': + optional: true + + '@oxc-resolver/binding-android-arm64@11.16.3': + optional: true + + '@oxc-resolver/binding-darwin-arm64@11.16.3': + optional: true + + '@oxc-resolver/binding-darwin-x64@11.16.3': + optional: true + + '@oxc-resolver/binding-freebsd-x64@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-arm-musleabihf@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-arm64-gnu@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-arm64-musl@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-ppc64-gnu@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-riscv64-gnu@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-riscv64-musl@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-s390x-gnu@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-x64-gnu@11.16.3': + optional: true + + '@oxc-resolver/binding-linux-x64-musl@11.16.3': + optional: true + + '@oxc-resolver/binding-openharmony-arm64@11.16.3': + optional: true + + '@oxc-resolver/binding-wasm32-wasi@11.16.3': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@oxc-resolver/binding-win32-arm64-msvc@11.16.3': + optional: true + + '@oxc-resolver/binding-win32-ia32-msvc@11.16.3': + optional: true + + '@oxc-resolver/binding-win32-x64-msvc@11.16.3': + optional: true + + '@publint/pack@0.1.2': {} + + '@quansync/fs@1.0.0': + dependencies: + quansync: 1.0.0 + + '@rolldown/binding-android-arm64@1.0.0-beta.59': + optional: true + + '@rolldown/binding-android-arm64@1.0.0-beta.60': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-beta.59': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-beta.60': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-beta.59': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-beta.60': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-beta.59': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-beta.60': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.59': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.60': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.59': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.60': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.59': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.60': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.59': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.60': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.59': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.60': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.59': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.60': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.59': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.60': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.59': + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.60': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.59': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.60': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.53': {} + + '@rolldown/pluginutils@1.0.0-beta.59': {} + + '@rolldown/pluginutils@1.0.0-beta.60': {} + + '@rollup/rollup-android-arm-eabi@4.55.1': + optional: true + + '@rollup/rollup-android-arm64@4.55.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.55.1': + optional: true + + '@rollup/rollup-darwin-x64@4.55.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.55.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.55.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.55.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.55.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.55.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.55.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.55.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.55.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.55.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.55.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.55.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.55.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.55.1': + optional: true + + '@shikijs/engine-oniguruma@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + + '@shikijs/themes@3.21.0': + dependencies: + '@shikijs/types': 3.21.0 + + '@shikijs/types@3.21.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@sinclair/typebox@0.34.47': {} + + '@standard-schema/spec@1.1.0': {} + + '@stylistic/eslint-plugin@5.7.0(eslint@9.39.2(jiti@2.6.1))': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/types': 8.53.0 + eslint: 9.39.2(jiti@2.6.1) + eslint-visitor-keys: 5.0.0 + espree: 11.0.0 + estraverse: 5.3.0 + picomatch: 4.0.3 + + '@sveltejs/acorn-typescript@1.0.8(acorn@8.15.0)': + dependencies: + acorn: 8.15.0 + + '@svitejs/changesets-changelog-github-compact@1.2.0': + dependencies: + '@changesets/get-github-info': 0.6.0 + dotenv: 16.6.1 + transitivePeerDependencies: + - encoding + + '@tanstack/eslint-config@0.3.4(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint/js': 9.39.2 + '@stylistic/eslint-plugin': 5.7.0(eslint@9.39.2(jiti@2.6.1)) + eslint: 9.39.2(jiti@2.6.1) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-n: 17.23.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + globals: 16.5.0 + typescript-eslint: 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) + transitivePeerDependencies: + - '@typescript-eslint/utils' + - eslint-import-resolver-node + - supports-color + - typescript + + '@tanstack/react-store@0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@tanstack/store': 0.8.0 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + use-sync-external-store: 1.6.0(react@19.2.3) + + '@tanstack/solid-store@0.8.0(solid-js@1.9.10)': + dependencies: + '@tanstack/store': 0.8.0 + solid-js: 1.9.10 + + '@tanstack/store@0.8.0': {} + + '@tanstack/typedoc-config@0.3.3(typescript@5.9.3)': + dependencies: + typedoc: 0.28.14(typescript@5.9.3) + typedoc-plugin-frontmatter: 1.3.0(typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3))) + typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.3)) + transitivePeerDependencies: + - typescript + + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.28.6 + '@babel/runtime': 7.28.6 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.4.4 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 + + '@testing-library/react@16.3.1(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.28.6 + '@testing-library/dom': 10.4.1 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@tybys/wasm-util@0.9.0': + dependencies: + tslib: 2.8.1 + + '@types/aria-query@5.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.6 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.6 + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.8': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/node@12.20.55': {} + + '@types/node@20.19.30': + dependencies: + undici-types: 6.21.0 + + '@types/node@25.0.9': + dependencies: + undici-types: 7.16.0 + + '@types/react-dom@19.2.3(@types/react@19.2.8)': + dependencies: + '@types/react': 19.2.8 + + '@types/react@19.2.8': + dependencies: + csstype: 3.2.3 + + '@types/unist@3.0.3': {} + + '@types/whatwg-mimetype@3.0.2': {} + + '@types/ws@8.18.1': + dependencies: + '@types/node': 25.0.9 + + '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.53.0 + eslint: 9.39.2(jiti@2.6.1) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.53.0 + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.53.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.53.0': + dependencies: + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/visitor-keys': 8.53.0 + + '@typescript-eslint/tsconfig-utils@8.53.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.53.0': {} + + '@typescript-eslint/typescript-estree@8.53.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.53.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/visitor-keys': 8.53.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.53.0': + dependencies: + '@typescript-eslint/types': 8.53.0 + eslint-visitor-keys: 4.2.1 + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2))': + dependencies: + '@babel/core': 7.28.6 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.6) + '@rolldown/pluginutils': 1.0.0-beta.53 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@4.0.17': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.0.17 + '@vitest/utils': 4.0.17 + chai: 6.2.2 + tinyrainbow: 3.0.3 + + '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2))': + dependencies: + '@vitest/spy': 4.0.17 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + + '@vitest/pretty-format@4.0.17': + dependencies: + tinyrainbow: 3.0.3 + + '@vitest/runner@4.0.17': + dependencies: + '@vitest/utils': 4.0.17 + pathe: 2.0.3 + + '@vitest/snapshot@4.0.17': + dependencies: + '@vitest/pretty-format': 4.0.17 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.0.17': {} + + '@vitest/utils@4.0.17': + dependencies: + '@vitest/pretty-format': 4.0.17 + tinyrainbow: 3.0.3 + + '@yarnpkg/lockfile@1.1.0': {} + + '@yarnpkg/parsers@3.0.2': + dependencies: + js-yaml: 3.14.2 + tslib: 2.8.1 + + '@zkochan/js-yaml@0.0.7': + dependencies: + argparse: 2.0.1 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansis@4.2.0: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + aria-query@5.3.2: {} + + array-union@2.1.0: {} + + assertion-error@2.0.1: {} + + ast-kit@2.2.0: + dependencies: + '@babel/parser': 7.28.6 + pathe: 2.0.3 + + asynckit@0.4.0: {} + + axios@1.13.2: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + axobject-query@4.1.0: {} + + babel-plugin-jsx-dom-expressions@0.40.3(@babel/core@7.28.6): + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-module-imports': 7.18.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) + '@babel/types': 7.28.6 + html-entities: 2.3.3 + parse5: 7.3.0 + + babel-preset-solid@1.9.10(@babel/core@7.28.6)(solid-js@1.9.10): + dependencies: + '@babel/core': 7.28.6 + babel-plugin-jsx-dom-expressions: 0.40.3(@babel/core@7.28.6) + optionalDependencies: + solid-js: 1.9.10 + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.9.15: {} + + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + + birecord@0.1.1: {} + + birpc@4.0.0: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + boolbase@1.0.0: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.9.15 + caniuse-lite: 1.0.30001764 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001764: {} + + chai@6.2.2: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chardet@2.1.1: {} + + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.1.2: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.0.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.18.2 + whatwg-mimetype: 4.0.0 + + ci-info@3.9.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-spinners@2.6.1: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone@1.0.4: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + comment-parser@1.4.4: {} + + compare-versions@6.1.1: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-what@6.2.2: {} + + css.escape@1.5.1: {} + + csstype@3.2.3: {} + + dataloader@1.4.0: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + define-lazy-prop@2.0.0: {} + + defu@6.1.4: {} + + delayed-stream@1.0.0: {} + + dequal@2.0.3: {} + + detect-indent@6.1.0: {} + + devalue@5.6.2: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dotenv-expand@11.0.7: + dependencies: + dotenv: 16.4.7 + + dotenv@16.4.7: {} + + dotenv@16.6.1: {} + + dts-resolver@2.1.3(oxc-resolver@11.16.3): + optionalDependencies: + oxc-resolver: 11.16.3 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.267: {} + + emoji-regex@8.0.0: {} + + empathic@2.0.0: {} + + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + enhanced-resolve@5.18.4: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + enquirer@2.3.6: + dependencies: + ansi-colors: 4.1.3 + + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + + entities@4.5.0: {} + + entities@6.0.1: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.27.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + eslint-compat-utils@0.5.1(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + semver: 7.7.3 + + eslint-import-context@0.1.9(unrs-resolver@1.11.1): + dependencies: + get-tsconfig: 4.13.0 + stable-hash-x: 0.2.0 + optionalDependencies: + unrs-resolver: 1.11.1 + + eslint-plugin-es-x@7.8.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + eslint: 9.39.2(jiti@2.6.1) + eslint-compat-utils: 0.5.1(eslint@9.39.2(jiti@2.6.1)) + + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@typescript-eslint/types': 8.53.0 + comment-parser: 1.4.4 + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + eslint-import-context: 0.1.9(unrs-resolver@1.11.1) + is-glob: 4.0.3 + minimatch: 10.1.1 + semver: 7.7.3 + stable-hash-x: 0.2.0 + unrs-resolver: 1.11.1 + optionalDependencies: + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + transitivePeerDependencies: + - supports-color + + eslint-plugin-n@17.23.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + enhanced-resolve: 5.18.4 + eslint: 9.39.2(jiti@2.6.1) + eslint-plugin-es-x: 7.8.0(eslint@9.39.2(jiti@2.6.1)) + get-tsconfig: 4.13.0 + globals: 15.15.0 + globrex: 0.1.2 + ignore: 5.3.2 + semver: 7.7.3 + ts-declaration-location: 1.0.7(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@babel/core': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.28.6) + eslint: 9.39.2(jiti@2.6.1) + hermes-parser: 0.25.1 + zod: 3.25.76 + zod-validation-error: 3.5.4(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-dom@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.7.2 + '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + compare-versions: 6.1.1 + eslint: 9.39.2(jiti@2.6.1) + string-ts: 2.3.1 + ts-pattern: 5.9.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-hooks-extra@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.7.2 + '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + string-ts: 2.3.1 + ts-pattern: 5.9.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)): + dependencies: + '@babel/core': 7.28.6 + '@babel/parser': 7.28.6 + eslint: 9.39.2(jiti@2.6.1) + hermes-parser: 0.25.1 + zod: 4.3.5 + zod-validation-error: 4.0.2(zod@4.3.5) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-naming-convention@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.7.2 + '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + compare-versions: 6.1.1 + eslint: 9.39.2(jiti@2.6.1) + string-ts: 2.3.1 + ts-pattern: 5.9.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-web-api@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.7.2 + '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + string-ts: 2.3.1 + ts-pattern: 5.9.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-x@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.7.2 + '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.53.0 + '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + compare-versions: 6.1.1 + eslint: 9.39.2(jiti@2.6.1) + is-immutable-type: 5.0.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + string-ts: 2.3.1 + ts-api-utils: 2.4.0(typescript@5.9.3) + ts-pattern: 5.9.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-unused-imports@4.3.0(@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): + dependencies: + eslint: 9.39.2(jiti@2.6.1) + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.0: {} + + eslint@9.39.2(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.3 + '@eslint/js': 9.39.2 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + esm-env@1.2.2: {} + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + espree@11.0.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 5.0.0 + + esprima@4.0.1: {} + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrap@2.2.1: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + expect-type@1.3.0: {} + + extendable-error@0.1.7: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fd-package-json@2.0.0: + dependencies: + walk-up-path: 4.0.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + figures@3.2.0: + dependencies: + escape-string-regexp: 1.0.5 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flat@5.0.2: {} + + flatted@3.3.3: {} + + follow-redirects@1.15.11: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formatly@0.3.0: + dependencies: + fd-package-json: 2.0.0 + + front-matter@4.0.2: + dependencies: + js-yaml: 3.14.2 + + fs-constants@1.0.0: {} + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globals@15.15.0: {} + + globals@16.5.0: {} + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + globrex@0.1.2: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + happy-dom@20.3.1: + dependencies: + '@types/node': 20.19.30 + '@types/whatwg-mimetype': 3.0.2 + '@types/ws': 8.18.1 + whatwg-mimetype: 3.0.0 + ws: 8.19.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + hookable@6.0.1: {} + + html-entities@2.3.3: {} + + html-link-extractor@1.0.5: + dependencies: + cheerio: 1.1.2 + + htmlparser2@10.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 6.0.1 + + human-id@4.1.3: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-without-cache@0.2.5: {} + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + inherits@2.0.4: {} + + is-docker@2.2.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-immutable-type@5.0.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + ts-api-utils: 2.4.0(typescript@5.9.3) + ts-declaration-location: 1.0.7(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + is-interactive@1.0.0: {} + + is-number@7.0.0: {} + + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + + is-unicode-supported@0.1.0: {} + + is-what@4.1.16: {} + + is-windows@1.0.2: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + isexe@2.0.0: {} + + jest-diff@30.2.0: + dependencies: + '@jest/diff-sequences': 30.0.1 + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + pretty-format: 30.2.0 + + jiti@2.6.1: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + jsonc-parser@3.2.0: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + knip@5.81.0(@types/node@25.0.9)(typescript@5.9.3): + dependencies: + '@nodelib/fs.walk': 1.2.8 + '@types/node': 25.0.9 + fast-glob: 3.3.3 + formatly: 0.3.0 + jiti: 2.6.1 + js-yaml: 4.1.1 + minimist: 1.2.8 + oxc-resolver: 11.16.3 + picocolors: 1.1.1 + picomatch: 4.0.3 + smol-toml: 1.6.0 + strip-json-comments: 5.0.3 + typescript: 5.9.3 + zod: 4.3.5 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lines-and-columns@2.0.3: {} + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + locate-character@3.0.0: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash.startcase@4.4.0: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lunr@2.3.9: {} + + lz-string@1.5.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + markdown-link-extractor@4.0.3: + dependencies: + html-link-extractor: 1.0.5 + marked: 17.0.1 + + marked@17.0.1: {} + + math-intrinsics@1.1.0: {} + + mdurl@2.0.0: {} + + merge-anything@5.1.7: + dependencies: + is-what: 4.1.16 + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@2.1.0: {} + + min-indent@1.0.1: {} + + minimatch@10.1.1: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.3: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + mri@1.2.0: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-machine-id@1.1.12: {} + + node-releases@2.0.27: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + nx@22.3.3: + dependencies: + '@napi-rs/wasm-runtime': 0.2.4 + '@yarnpkg/lockfile': 1.1.0 + '@yarnpkg/parsers': 3.0.2 + '@zkochan/js-yaml': 0.0.7 + axios: 1.13.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.6.1 + cliui: 8.0.1 + dotenv: 16.4.7 + dotenv-expand: 11.0.7 + enquirer: 2.3.6 + figures: 3.2.0 + flat: 5.0.2 + front-matter: 4.0.2 + ignore: 7.0.5 + jest-diff: 30.2.0 + jsonc-parser: 3.2.0 + lines-and-columns: 2.0.3 + minimatch: 9.0.3 + node-machine-id: 1.1.12 + npm-run-path: 4.0.1 + open: 8.4.2 + ora: 5.3.0 + resolve.exports: 2.0.3 + semver: 7.7.3 + string-width: 4.2.3 + tar-stream: 2.2.0 + tmp: 0.2.5 + tree-kill: 1.2.2 + tsconfig-paths: 4.2.0 + tslib: 2.8.1 + yaml: 2.8.2 + yargs: 17.7.2 + yargs-parser: 21.1.1 + optionalDependencies: + '@nx/nx-darwin-arm64': 22.3.3 + '@nx/nx-darwin-x64': 22.3.3 + '@nx/nx-freebsd-x64': 22.3.3 + '@nx/nx-linux-arm-gnueabihf': 22.3.3 + '@nx/nx-linux-arm64-gnu': 22.3.3 + '@nx/nx-linux-arm64-musl': 22.3.3 + '@nx/nx-linux-x64-gnu': 22.3.3 + '@nx/nx-linux-x64-musl': 22.3.3 + '@nx/nx-win32-arm64-msvc': 22.3.3 + '@nx/nx-win32-x64-msvc': 22.3.3 + transitivePeerDependencies: + - debug + + obug@2.1.1: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + ora@5.3.0: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.6.1 + is-interactive: 1.0.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + outdent@0.5.0: {} + + oxc-resolver@11.16.3: + optionalDependencies: + '@oxc-resolver/binding-android-arm-eabi': 11.16.3 + '@oxc-resolver/binding-android-arm64': 11.16.3 + '@oxc-resolver/binding-darwin-arm64': 11.16.3 + '@oxc-resolver/binding-darwin-x64': 11.16.3 + '@oxc-resolver/binding-freebsd-x64': 11.16.3 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.16.3 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.16.3 + '@oxc-resolver/binding-linux-arm64-gnu': 11.16.3 + '@oxc-resolver/binding-linux-arm64-musl': 11.16.3 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.16.3 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.16.3 + '@oxc-resolver/binding-linux-riscv64-musl': 11.16.3 + '@oxc-resolver/binding-linux-s390x-gnu': 11.16.3 + '@oxc-resolver/binding-linux-x64-gnu': 11.16.3 + '@oxc-resolver/binding-linux-x64-musl': 11.16.3 + '@oxc-resolver/binding-openharmony-arm64': 11.16.3 + '@oxc-resolver/binding-wasm32-wasi': 11.16.3 + '@oxc-resolver/binding-win32-arm64-msvc': 11.16.3 + '@oxc-resolver/binding-win32-ia32-msvc': 11.16.3 + '@oxc-resolver/binding-win32-x64-msvc': 11.16.3 + + p-filter@2.1.0: + dependencies: + p-map: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-map@2.1.0: {} + + p-try@2.2.0: {} + + package-manager-detector@0.2.11: + dependencies: + quansync: 0.2.11 + + package-manager-detector@1.6.0: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-type@4.0.0: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pify@4.0.1: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + premove@4.0.0: {} + + prettier-plugin-svelte@3.4.1(prettier@3.8.0)(svelte@5.46.4): + dependencies: + prettier: 3.8.0 + svelte: 5.46.4 + + prettier@2.8.8: {} + + prettier@3.8.0: {} + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + pretty-format@30.2.0: + dependencies: + '@jest/schemas': 30.0.5 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + proxy-from-env@1.1.0: {} + + publint@0.3.16: + dependencies: + '@publint/pack': 0.1.2 + package-manager-detector: 1.6.0 + picocolors: 1.1.1 + sade: 1.8.1 + + punycode.js@2.3.1: {} + + punycode@2.3.1: {} + + quansync@0.2.11: {} + + quansync@1.0.0: {} + + queue-microtask@1.2.3: {} + + react-dom@19.2.3(react@19.2.3): + dependencies: + react: 19.2.3 + scheduler: 0.27.0 + + react-is@17.0.2: {} + + react-is@18.3.1: {} + + react-refresh@0.18.0: {} + + react@19.2.3: {} + + read-yaml-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + js-yaml: 3.14.2 + pify: 4.0.1 + strip-bom: 3.0.0 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + + require-directory@2.1.1: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve.exports@2.0.3: {} + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + reusify@1.1.0: {} + + rolldown-plugin-dts@0.20.0(oxc-resolver@11.16.3)(rolldown@1.0.0-beta.59)(typescript@5.9.3): + dependencies: + '@babel/generator': 7.28.6 + '@babel/parser': 7.28.6 + '@babel/types': 7.28.6 + ast-kit: 2.2.0 + birpc: 4.0.0 + dts-resolver: 2.1.3(oxc-resolver@11.16.3) + get-tsconfig: 4.13.0 + obug: 2.1.1 + rolldown: 1.0.0-beta.59 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - oxc-resolver + + rolldown@1.0.0-beta.59: + dependencies: + '@oxc-project/types': 0.107.0 + '@rolldown/pluginutils': 1.0.0-beta.59 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-beta.59 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.59 + '@rolldown/binding-darwin-x64': 1.0.0-beta.59 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.59 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.59 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.59 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.59 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.59 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.59 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.59 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.59 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.59 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.59 + + rolldown@1.0.0-beta.60: + dependencies: + '@oxc-project/types': 0.108.0 + '@rolldown/pluginutils': 1.0.0-beta.60 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-beta.60 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.60 + '@rolldown/binding-darwin-x64': 1.0.0-beta.60 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.60 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.60 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.60 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.60 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.60 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.60 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.60 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.60 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.60 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.60 + + rollup@4.55.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.55.1 + '@rollup/rollup-android-arm64': 4.55.1 + '@rollup/rollup-darwin-arm64': 4.55.1 + '@rollup/rollup-darwin-x64': 4.55.1 + '@rollup/rollup-freebsd-arm64': 4.55.1 + '@rollup/rollup-freebsd-x64': 4.55.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 + '@rollup/rollup-linux-arm-musleabihf': 4.55.1 + '@rollup/rollup-linux-arm64-gnu': 4.55.1 + '@rollup/rollup-linux-arm64-musl': 4.55.1 + '@rollup/rollup-linux-loong64-gnu': 4.55.1 + '@rollup/rollup-linux-loong64-musl': 4.55.1 + '@rollup/rollup-linux-ppc64-gnu': 4.55.1 + '@rollup/rollup-linux-ppc64-musl': 4.55.1 + '@rollup/rollup-linux-riscv64-gnu': 4.55.1 + '@rollup/rollup-linux-riscv64-musl': 4.55.1 + '@rollup/rollup-linux-s390x-gnu': 4.55.1 + '@rollup/rollup-linux-x64-gnu': 4.55.1 + '@rollup/rollup-linux-x64-musl': 4.55.1 + '@rollup/rollup-openbsd-x64': 4.55.1 + '@rollup/rollup-openharmony-arm64': 4.55.1 + '@rollup/rollup-win32-arm64-msvc': 4.55.1 + '@rollup/rollup-win32-ia32-msvc': 4.55.1 + '@rollup/rollup-win32-x64-gnu': 4.55.1 + '@rollup/rollup-win32-x64-msvc': 4.55.1 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + sade@1.8.1: + dependencies: + mri: 1.2.0 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.7.3: {} + + seroval-plugins@1.3.3(seroval@1.3.2): + dependencies: + seroval: 1.3.2 + + seroval@1.3.2: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + sherif-darwin-arm64@1.10.0: + optional: true + + sherif-darwin-x64@1.10.0: + optional: true + + sherif-linux-arm64-musl@1.10.0: + optional: true + + sherif-linux-arm64@1.10.0: + optional: true + + sherif-linux-x64-musl@1.10.0: + optional: true + + sherif-linux-x64@1.10.0: + optional: true + + sherif-windows-arm64@1.10.0: + optional: true + + sherif-windows-x64@1.10.0: + optional: true + + sherif@1.10.0: + optionalDependencies: + sherif-darwin-arm64: 1.10.0 + sherif-darwin-x64: 1.10.0 + sherif-linux-arm64: 1.10.0 + sherif-linux-arm64-musl: 1.10.0 + sherif-linux-x64: 1.10.0 + sherif-linux-x64-musl: 1.10.0 + sherif-windows-arm64: 1.10.0 + sherif-windows-x64: 1.10.0 + + siginfo@2.0.0: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + smol-toml@1.6.0: {} + + solid-js@1.9.10: + dependencies: + csstype: 3.2.3 + seroval: 1.3.2 + seroval-plugins: 1.3.3(seroval@1.3.2) + + solid-refresh@0.6.3(solid-js@1.9.10): + dependencies: + '@babel/generator': 7.28.6 + '@babel/helper-module-imports': 7.28.6 + '@babel/types': 7.28.6 + solid-js: 1.9.10 + transitivePeerDependencies: + - supports-color + + source-map-js@1.2.1: {} + + spawndamnit@3.0.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + sprintf-js@1.0.3: {} + + stable-hash-x@0.2.0: {} + + stackback@0.0.2: {} + + std-env@3.10.0: {} + + string-ts@2.3.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@3.0.0: {} + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + strip-json-comments@3.1.1: {} + + strip-json-comments@5.0.3: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + svelte@5.46.4: + dependencies: + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) + '@types/estree': 1.0.8 + acorn: 8.15.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + clsx: 2.1.1 + devalue: 5.6.2 + esm-env: 1.2.2 + esrap: 2.2.1 + is-reference: 3.0.3 + locate-character: 3.0.0 + magic-string: 0.30.21 + zimmerframe: 1.1.4 + + tapable@2.3.0: {} + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + term-size@2.2.1: {} + + tinybench@2.9.0: {} + + tinyexec@1.0.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinyrainbow@3.0.3: {} + + tmp@0.2.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tr46@0.0.3: {} + + tree-kill@1.2.2: {} + + ts-api-utils@2.4.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-declaration-location@1.0.7(typescript@5.9.3): + dependencies: + picomatch: 4.0.3 + typescript: 5.9.3 + + ts-pattern@5.9.0: {} + + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tsdown@0.19.0(oxc-resolver@11.16.3)(publint@0.3.16)(typescript@5.9.3): + dependencies: + ansis: 4.2.0 + cac: 6.7.14 + defu: 6.1.4 + empathic: 2.0.0 + hookable: 6.0.1 + import-without-cache: 0.2.5 + obug: 2.1.1 + picomatch: 4.0.3 + rolldown: 1.0.0-beta.59 + rolldown-plugin-dts: 0.20.0(oxc-resolver@11.16.3)(rolldown@1.0.0-beta.59)(typescript@5.9.3) + semver: 7.7.3 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tree-kill: 1.2.2 + unconfig-core: 7.4.2 + unrun: 0.2.25 + optionalDependencies: + publint: 0.3.16 + typescript: 5.9.3 + transitivePeerDependencies: + - '@ts-macro/tsc' + - '@typescript/native-preview' + - oxc-resolver + - synckit + - vue-tsc + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typedoc-plugin-frontmatter@1.3.0(typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3))): + dependencies: + typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.3)) + yaml: 2.8.2 + + typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3)): + dependencies: + typedoc: 0.28.14(typescript@5.9.3) + + typedoc@0.28.14(typescript@5.9.3): + dependencies: + '@gerrit0/mini-shiki': 3.21.0 + lunr: 2.3.9 + markdown-it: 14.1.0 + minimatch: 9.0.5 + typescript: 5.9.3 + yaml: 2.8.2 + + typescript-eslint@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + uc.micro@2.1.0: {} + + unconfig-core@7.4.2: + dependencies: + '@quansync/fs': 1.0.0 + quansync: 1.0.0 + + undici-types@6.21.0: {} + + undici-types@7.16.0: {} + + undici@7.18.2: {} + + universalify@0.1.2: {} + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + unrun@0.2.25: + dependencies: + rolldown: 1.0.0-beta.60 + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-sync-external-store@1.6.0(react@19.2.3): + dependencies: + react: 19.2.3 + + util-deprecate@1.0.2: {} + + vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)): + dependencies: + '@babel/core': 7.28.6 + '@types/babel__core': 7.20.5 + babel-preset-solid: 1.9.10(@babel/core@7.28.6)(solid-js@1.9.10) + merge-anything: 5.1.7 + solid-js: 1.9.10 + solid-refresh: 0.6.3(solid-js@1.9.10) + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + vitefu: 1.1.1(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + optionalDependencies: + '@testing-library/jest-dom': 6.9.1 + transitivePeerDependencies: + - supports-color + + vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2): + dependencies: + esbuild: 0.27.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.55.1 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.0.9 + fsevents: 2.3.3 + jiti: 2.6.1 + yaml: 2.8.2 + + vitefu@1.1.1(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)): + optionalDependencies: + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + + vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(yaml@2.8.2): + dependencies: + '@vitest/expect': 4.0.17 + '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + '@vitest/pretty-format': 4.0.17 + '@vitest/runner': 4.0.17 + '@vitest/snapshot': 4.0.17 + '@vitest/spy': 4.0.17 + '@vitest/utils': 4.0.17 + es-module-lexer: 1.7.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.0.9 + happy-dom: 20.3.1 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + + vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)): + dependencies: + debug: 4.4.3 + eslint: 9.39.2(jiti@2.6.1) + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + semver: 7.7.3 + transitivePeerDependencies: + - supports-color + + walk-up-path@4.0.0: {} + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + webidl-conversions@3.0.1: {} + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@3.0.0: {} + + whatwg-mimetype@4.0.0: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + ws@8.19.0: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yaml@2.8.2: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} + + zimmerframe@1.1.4: {} + + zod-validation-error@3.5.4(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod-validation-error@4.0.2(zod@4.3.5): + dependencies: + zod: 4.3.5 + + zod@3.25.76: {} + + zod@4.3.5: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..5add109e --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,7 @@ +cleanupUnusedCatalogs: true +linkWorkspacePackages: true +preferWorkspacePackages: true + +packages: + - 'examples/**/*' + - 'packages/*' diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 00000000..dbb08b11 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,12 @@ +// @ts-check + +/** @type {import('prettier').Config} */ +const config = { + semi: false, + singleQuote: true, + trailingComma: 'all', + plugins: ['prettier-plugin-svelte'], + overrides: [{ files: '*.svelte', options: { parser: 'svelte' } }], +} + +export default config diff --git a/scripts/generate-docs.ts b/scripts/generate-docs.ts new file mode 100644 index 00000000..99c72999 --- /dev/null +++ b/scripts/generate-docs.ts @@ -0,0 +1,34 @@ +import { resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { generateReferenceDocs } from '@tanstack/typedoc-config' + +const __dirname = fileURLToPath(new URL('.', import.meta.url)) + +await generateReferenceDocs({ + packages: [ + { + name: 'time', + entryPoints: [resolve(__dirname, '../packages/time/src/index.ts')], + tsconfig: resolve(__dirname, '../packages/time/tsconfig.docs.json'), + outputDir: resolve(__dirname, '../docs/reference'), + }, + { + name: 'react-time', + entryPoints: [resolve(__dirname, '../packages/react-time/src/index.ts')], + tsconfig: resolve(__dirname, '../packages/react-time/tsconfig.docs.json'), + outputDir: resolve(__dirname, '../docs/framework/react/reference'), + exclude: ['packages/time/**/*'], + }, + { + name: 'solid-time', + entryPoints: [resolve(__dirname, '../packages/solid-time/src/index.ts')], + tsconfig: resolve(__dirname, '../packages/solid-time/tsconfig.docs.json'), + outputDir: resolve(__dirname, '../docs/framework/solid/reference'), + exclude: ['packages/time/**/*'], + }, + ], +}) + +console.log('\nāœ… All markdown files have been processed!') + +process.exit(0) diff --git a/scripts/verify-links.ts b/scripts/verify-links.ts new file mode 100644 index 00000000..8a1c40dd --- /dev/null +++ b/scripts/verify-links.ts @@ -0,0 +1,125 @@ +import { existsSync, readFileSync, statSync } from 'node:fs' +import { extname, resolve } from 'node:path' +import { glob } from 'tinyglobby' +// @ts-ignore Could not find a declaration file for module 'markdown-link-extractor'. +import markdownLinkExtractor from 'markdown-link-extractor' + +const errors: Array<{ + file: string + link: string + resolvedPath: string + reason: string +}> = [] + +function isRelativeLink(link: string) { + return ( + !link.startsWith('/') && + !link.startsWith('http://') && + !link.startsWith('https://') && + !link.startsWith('//') && + !link.startsWith('#') && + !link.startsWith('mailto:') + ) +} + +/** Remove any trailing .md */ +function stripExtension(p: string): string { + return p.replace(`${extname(p)}`, '') +} + +function relativeLinkExists(link: string, file: string): boolean { + // Remove hash if present + const linkWithoutHash = link.split('#')[0] + // If the link is empty after removing hash, it's not a file + if (!linkWithoutHash) return false + + // Strip the file/link extensions + const filePath = stripExtension(file) + const linkPath = stripExtension(linkWithoutHash) + + // Resolve the path relative to the markdown file's directory + // Nav up a level to simulate how links are resolved on the web + let absPath = resolve(filePath, '..', linkPath) + + // Ensure the resolved path is within /docs + const docsRoot = resolve('docs') + if (!absPath.startsWith(docsRoot)) { + errors.push({ + link, + file, + resolvedPath: absPath, + reason: 'Path outside /docs', + }) + return false + } + + // Check if this is an example path + const isExample = absPath.includes('/examples/') + + let exists = false + + if (isExample) { + // Transform /docs/framework/{framework}/examples/ to /examples/{framework}/ + absPath = absPath.replace( + /\/docs\/framework\/([^/]+)\/examples\//, + '/examples/$1/', + ) + // For examples, we want to check if the directory exists + exists = existsSync(absPath) && statSync(absPath).isDirectory() + } else { + // For non-examples, we want to check if the .md file exists + if (!absPath.endsWith('.md')) { + absPath = `${absPath}.md` + } + exists = existsSync(absPath) + } + + if (!exists) { + errors.push({ + link, + file, + resolvedPath: absPath, + reason: 'Not found', + }) + } + return exists +} + +async function verifyMarkdownLinks() { + // Find all markdown files in docs directory + const markdownFiles = await glob('docs/**/*.md', { + ignore: ['**/node_modules/**'], + }) + + console.log(`Found ${markdownFiles.length} markdown files\n`) + + // Process each file + for (const file of markdownFiles) { + const content = readFileSync(file, 'utf-8') + const links: Array = markdownLinkExtractor(content) + + const relativeLinks = links.filter((link: string) => { + return isRelativeLink(link) + }) + + if (relativeLinks.length > 0) { + relativeLinks.forEach((link) => { + relativeLinkExists(link, file) + }) + } + } + + if (errors.length > 0) { + console.log(`\nāŒ Found ${errors.length} broken links:`) + errors.forEach((err) => { + console.log( + `${err.file}\n link: ${err.link}\n resolved: ${err.resolvedPath}\n why: ${err.reason}\n`, + ) + }) + process.exit(1) + } else { + console.log('\nāœ… No broken links found!') + } +} + +verifyMarkdownLinks().catch(console.error) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..c4e9c3a2 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "checkJs": true, + "declaration": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "module": "ESNext", + "moduleResolution": "Bundler", + "noEmit": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ES2020", + "noErrorTruncation": true + }, + "include": ["scripts", "*.config.*", "vitest.workspace.js"] +} diff --git a/vitest.workspace.js b/vitest.workspace.js new file mode 100644 index 00000000..1cd65719 --- /dev/null +++ b/vitest.workspace.js @@ -0,0 +1,16 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + projects: [ + './packages/pacer/vite.config.ts', + './packages/pacer-lite/vite.config.ts', + './packages/preact-pacer/vitest.config.ts', + './packages/preact-pacer-devtools/vitest.config.ts', + './packages/react-pacer/vite.config.ts', + './packages/react-pacer-devtools/vite.config.ts', + './packages/solid-pacer/vite.config.ts', + './packages/solid-pacer-devtools/vite.config.ts', + ], + }, +}) From cafda9758e8b2f94f3fad77144e1e4b69a4b8c41 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 19 Jan 2026 22:55:04 +0100 Subject: [PATCH 002/207] fix: resolve CI test failures - Fix sherif: sort dependencies alphabetically, align solid-js and @eslint-react/eslint-plugin versions - Add missing devDependencies (@vitejs/plugin-react to react-time-devtools) - Fix solid-time-devtools JSX build by using pre-compiled solid template - Fix vitest configs: remove references to non-existent test-setup.ts files - Fix time package test:lib: add --passWithNoTests flag - Configure react-time-devtools tsdown with jsx: 'automatic' - Update knip.json to ignore intentional template dependencies - Remove unused test-setup.ts files - Remove unused React imports from examples --- examples/react/basic/src/index.tsx | 1 - examples/react/devtools/src/index.tsx | 1 - knip.json | 20 ++++++++++------ packages/react-time-devtools/package.json | 4 ++++ packages/react-time-devtools/tsdown.config.ts | 3 +++ packages/react-time-devtools/vitest.config.ts | 1 - packages/react-time/package.json | 6 ++--- packages/react-time/tests/test-setup.ts | 1 - packages/solid-time-devtools/package.json | 3 ++- .../solid-time-devtools/src/TimeDevtools.tsx | 4 ---- packages/solid-time-devtools/vitest.config.ts | 1 - packages/solid-time/package.json | 7 +++--- packages/solid-time/tests/test-setup.ts | 1 - packages/time-devtools/vitest.config.ts | 1 - packages/time/package.json | 6 +---- packages/time/tests/test-setup.ts | 1 - packages/time/tsdown.config.ts | 2 +- packages/time/vitest.config.ts | 1 - pnpm-lock.yaml | 24 ++++++++++++++++--- 19 files changed, 52 insertions(+), 36 deletions(-) delete mode 100644 packages/react-time/tests/test-setup.ts delete mode 100644 packages/solid-time-devtools/src/TimeDevtools.tsx delete mode 100644 packages/solid-time/tests/test-setup.ts delete mode 100644 packages/time/tests/test-setup.ts diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 16e83d8a..407e3c13 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -1,4 +1,3 @@ -import React from 'react' import ReactDOM from 'react-dom/client' function App() { diff --git a/examples/react/devtools/src/index.tsx b/examples/react/devtools/src/index.tsx index 0034f294..2a6cc9a9 100644 --- a/examples/react/devtools/src/index.tsx +++ b/examples/react/devtools/src/index.tsx @@ -1,4 +1,3 @@ -import React from 'react' import ReactDOM from 'react-dom/client' import { TimeDevtools } from '@tanstack/react-time-devtools' diff --git a/knip.json b/knip.json index dfc6c27a..58066a25 100644 --- a/knip.json +++ b/knip.json @@ -1,10 +1,16 @@ { "$schema": "https://unpkg.com/knip@5/schema.json", - "ignoreDependencies": ["@faker-js/faker"], - "ignoreWorkspaces": ["examples/**"], - "workspaces": { - "packages/react-pacer": { - "ignore": [] - } - } + "ignoreDependencies": [ + "@faker-js/faker", + "@tanstack/store", + "@tanstack/time", + "@tanstack/time-devtools", + "@tanstack/react-store", + "@tanstack/solid-store", + "@testing-library/jest-dom", + "@testing-library/react", + "@types/react", + "react" + ], + "ignoreWorkspaces": ["examples/**"] } diff --git a/packages/react-time-devtools/package.json b/packages/react-time-devtools/package.json index 0aaa9efd..27cf54d2 100644 --- a/packages/react-time-devtools/package.json +++ b/packages/react-time-devtools/package.json @@ -51,7 +51,11 @@ "@tanstack/time-devtools": "workspace:*" }, "devDependencies": { + "@eslint-react/eslint-plugin": "^2.7.2", "@types/react": "^19.2.8", + "@vitejs/plugin-react": "^5.1.2", + "eslint-plugin-react-compiler": "19.1.0-rc.2", + "eslint-plugin-react-hooks": "^7.0.1", "react": "^19.2.3" }, "peerDependencies": { diff --git a/packages/react-time-devtools/tsdown.config.ts b/packages/react-time-devtools/tsdown.config.ts index 71071cb9..deee810d 100644 --- a/packages/react-time-devtools/tsdown.config.ts +++ b/packages/react-time-devtools/tsdown.config.ts @@ -10,6 +10,9 @@ export default defineConfig({ minify: false, fixedExtension: false, exports: true, + esbuild: { + jsx: 'automatic', + }, publint: { strict: true, }, diff --git a/packages/react-time-devtools/vitest.config.ts b/packages/react-time-devtools/vitest.config.ts index 75ff7cb9..c38045f3 100644 --- a/packages/react-time-devtools/vitest.config.ts +++ b/packages/react-time-devtools/vitest.config.ts @@ -9,7 +9,6 @@ export default defineConfig({ dir: './', watch: false, environment: 'happy-dom', - setupFiles: ['./tests/test-setup.ts'], globals: true, }, }) diff --git a/packages/react-time/package.json b/packages/react-time/package.json index ff722615..a124e084 100644 --- a/packages/react-time/package.json +++ b/packages/react-time/package.json @@ -47,11 +47,11 @@ "src" ], "dependencies": { - "@tanstack/time": "workspace:*", - "@tanstack/react-store": "^0.8.0" + "@tanstack/react-store": "^0.8.0", + "@tanstack/time": "workspace:*" }, "devDependencies": { - "@eslint-react/eslint-plugin": "^2.5.7", + "@eslint-react/eslint-plugin": "^2.7.2", "@testing-library/react": "^16.1.0", "@types/react": "^19.2.8", "@vitejs/plugin-react": "^5.1.2", diff --git a/packages/react-time/tests/test-setup.ts b/packages/react-time/tests/test-setup.ts deleted file mode 100644 index a9d0dd31..00000000 --- a/packages/react-time/tests/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom/vitest' diff --git a/packages/solid-time-devtools/package.json b/packages/solid-time-devtools/package.json index 0e80ea67..c289e0d4 100644 --- a/packages/solid-time-devtools/package.json +++ b/packages/solid-time-devtools/package.json @@ -51,7 +51,8 @@ "@tanstack/time-devtools": "workspace:*" }, "devDependencies": { - "solid-js": "^1.9.5" + "solid-js": "^1.9.10", + "vite-plugin-solid": "^2.11.10" }, "peerDependencies": { "solid-js": ">=1.9.5" diff --git a/packages/solid-time-devtools/src/TimeDevtools.tsx b/packages/solid-time-devtools/src/TimeDevtools.tsx deleted file mode 100644 index ea10bf01..00000000 --- a/packages/solid-time-devtools/src/TimeDevtools.tsx +++ /dev/null @@ -1,4 +0,0 @@ -export function TimeDevtools() { - console.log('Hello from @tanstack/solid-time-devtools!') - return
Solid Time Devtools
-} diff --git a/packages/solid-time-devtools/vitest.config.ts b/packages/solid-time-devtools/vitest.config.ts index 597cf0ec..7a911fa1 100644 --- a/packages/solid-time-devtools/vitest.config.ts +++ b/packages/solid-time-devtools/vitest.config.ts @@ -9,7 +9,6 @@ export default defineConfig({ dir: './', watch: false, environment: 'happy-dom', - setupFiles: ['./tests/test-setup.ts'], globals: true, }, }) diff --git a/packages/solid-time/package.json b/packages/solid-time/package.json index af821937..ac6bc489 100644 --- a/packages/solid-time/package.json +++ b/packages/solid-time/package.json @@ -47,12 +47,13 @@ "src" ], "dependencies": { - "@tanstack/time": "workspace:*", - "@tanstack/solid-store": "^0.8.0" + "@tanstack/solid-store": "^0.8.0", + "@tanstack/time": "workspace:*" }, "devDependencies": { "@types/node": "^25.0.7", - "solid-js": "^1.9.5" + "solid-js": "^1.9.10", + "vite-plugin-solid": "^2.11.10" }, "peerDependencies": { "solid-js": ">=1.9.5" diff --git a/packages/solid-time/tests/test-setup.ts b/packages/solid-time/tests/test-setup.ts deleted file mode 100644 index a9d0dd31..00000000 --- a/packages/solid-time/tests/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom/vitest' diff --git a/packages/time-devtools/vitest.config.ts b/packages/time-devtools/vitest.config.ts index d3db399a..72ad1d46 100644 --- a/packages/time-devtools/vitest.config.ts +++ b/packages/time-devtools/vitest.config.ts @@ -7,7 +7,6 @@ export default defineConfig({ dir: './', watch: false, environment: 'happy-dom', - setupFiles: ['./tests/test-setup.ts'], globals: true, }, }) diff --git a/packages/time/package.json b/packages/time/package.json index 72dd9999..e28476cb 100644 --- a/packages/time/package.json +++ b/packages/time/package.json @@ -22,7 +22,7 @@ "clean": "premove ./build ./dist", "lint:fix": "eslint ./src --fix", "test:eslint": "eslint ./src", - "test:lib": "vitest", + "test:lib": "vitest --passWithNoTests", "test:lib:dev": "pnpm test:lib --watch", "test:types": "tsc", "build": "tsdown" @@ -36,10 +36,6 @@ "require": "./dist/index.cjs", "import": "./dist/index.js" }, - "./types": { - "require": "./dist/types.cjs", - "import": "./dist/types.js" - }, "./package.json": "./package.json" }, "sideEffects": false, diff --git a/packages/time/tests/test-setup.ts b/packages/time/tests/test-setup.ts deleted file mode 100644 index a9d0dd31..00000000 --- a/packages/time/tests/test-setup.ts +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom/vitest' diff --git a/packages/time/tsdown.config.ts b/packages/time/tsdown.config.ts index 7db992da..71071cb9 100644 --- a/packages/time/tsdown.config.ts +++ b/packages/time/tsdown.config.ts @@ -1,7 +1,7 @@ import { defineConfig } from 'tsdown' export default defineConfig({ - entry: ['./src/index.ts', './src/types.ts'], + entry: ['./src/index.ts'], format: ['esm', 'cjs'], unbundle: true, dts: true, diff --git a/packages/time/vitest.config.ts b/packages/time/vitest.config.ts index d3db399a..72ad1d46 100644 --- a/packages/time/vitest.config.ts +++ b/packages/time/vitest.config.ts @@ -7,7 +7,6 @@ export default defineConfig({ dir: './', watch: false, environment: 'happy-dom', - setupFiles: ['./tests/test-setup.ts'], globals: true, }, }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4161bdb..9cbc717e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -200,7 +200,7 @@ importers: version: 19.2.3(react@19.2.3) devDependencies: '@eslint-react/eslint-plugin': - specifier: ^2.5.7 + specifier: ^2.7.2 version: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@testing-library/react': specifier: ^16.1.0 @@ -230,9 +230,21 @@ importers: specifier: '>=16.8' version: 19.2.3(react@19.2.3) devDependencies: + '@eslint-react/eslint-plugin': + specifier: ^2.7.2 + version: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@types/react': specifier: ^19.2.8 version: 19.2.8 + '@vitejs/plugin-react': + specifier: ^5.1.2 + version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + eslint-plugin-react-compiler: + specifier: 19.1.0-rc.2 + version: 19.1.0-rc.2(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-react-hooks: + specifier: ^7.0.1 + version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) react: specifier: ^19.2.3 version: 19.2.3 @@ -250,8 +262,11 @@ importers: specifier: ^25.0.7 version: 25.0.9 solid-js: - specifier: ^1.9.5 + specifier: ^1.9.10 version: 1.9.10 + vite-plugin-solid: + specifier: ^2.11.10 + version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) packages/solid-time-devtools: dependencies: @@ -260,8 +275,11 @@ importers: version: link:../time-devtools devDependencies: solid-js: - specifier: ^1.9.5 + specifier: ^1.9.10 version: 1.9.10 + vite-plugin-solid: + specifier: ^2.11.10 + version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) packages/time: dependencies: From 82adbc1749e3c2eff8beb6e3976c6cbbf6cebc21 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 19 Jan 2026 22:57:59 +0100 Subject: [PATCH 003/207] chore: project setup --- examples/react/devtools/index.html | 14 ----------- examples/react/devtools/package.json | 25 ------------------- examples/react/devtools/src/index.tsx | 13 ---------- examples/react/devtools/tsconfig.json | 19 -------------- examples/react/devtools/vite.config.ts | 6 ----- examples/solid/basic/index.html | 14 ----------- examples/solid/basic/package.json | 21 ---------------- examples/solid/basic/src/index.tsx | 11 -------- examples/solid/basic/tsconfig.json | 18 ------------- examples/solid/basic/vite.config.ts | 6 ----- examples/solid/devtools/index.html | 14 ----------- examples/solid/devtools/package.json | 22 ---------------- examples/solid/devtools/src/index.tsx | 14 ----------- examples/solid/devtools/tsconfig.json | 18 ------------- examples/solid/devtools/vite.config.ts | 6 ----- packages/react-time-devtools/eslint.config.js | 2 +- .../react-time-devtools/src/TimeDevtools.tsx | 6 ----- packages/react-time-devtools/src/index.ts | 1 - .../solid-time-devtools/src/TimeDevtools.tsx | 8 ++++++ 19 files changed, 9 insertions(+), 229 deletions(-) delete mode 100644 examples/react/devtools/index.html delete mode 100644 examples/react/devtools/package.json delete mode 100644 examples/react/devtools/src/index.tsx delete mode 100644 examples/react/devtools/tsconfig.json delete mode 100644 examples/react/devtools/vite.config.ts delete mode 100644 examples/solid/basic/index.html delete mode 100644 examples/solid/basic/package.json delete mode 100644 examples/solid/basic/src/index.tsx delete mode 100644 examples/solid/basic/tsconfig.json delete mode 100644 examples/solid/basic/vite.config.ts delete mode 100644 examples/solid/devtools/index.html delete mode 100644 examples/solid/devtools/package.json delete mode 100644 examples/solid/devtools/src/index.tsx delete mode 100644 examples/solid/devtools/tsconfig.json delete mode 100644 examples/solid/devtools/vite.config.ts delete mode 100644 packages/react-time-devtools/src/TimeDevtools.tsx create mode 100644 packages/solid-time-devtools/src/TimeDevtools.tsx diff --git a/examples/react/devtools/index.html b/examples/react/devtools/index.html deleted file mode 100644 index 181cb6f4..00000000 --- a/examples/react/devtools/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - TanStack Time - React Devtools Example - - - -
- - - diff --git a/examples/react/devtools/package.json b/examples/react/devtools/package.json deleted file mode 100644 index 481e18f9..00000000 --- a/examples/react/devtools/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "@tanstack/time-example-react-devtools", - "private": true, - "type": "module", - "scripts": { - "dev": "vite --port=3006", - "build": "vite build", - "preview": "vite preview", - "test:types": "tsc" - }, - "dependencies": { - "@tanstack/react-time": "^0.0.0", - "@tanstack/react-time-devtools": "^0.0.0", - "@tanstack/time": "^0.0.0", - "react": "^19.2.3", - "react-dom": "^19.2.3" - }, - "devDependencies": { - "@types/react": "^19.2.8", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^5.1.2", - "typescript": "5.9.3", - "vite": "^7.3.1" - } -} diff --git a/examples/react/devtools/src/index.tsx b/examples/react/devtools/src/index.tsx deleted file mode 100644 index 2a6cc9a9..00000000 --- a/examples/react/devtools/src/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import ReactDOM from 'react-dom/client' -import { TimeDevtools } from '@tanstack/react-time-devtools' - -function App() { - return ( -
-

Devtools:

- -
- ) -} - -ReactDOM.createRoot(document.getElementById('root')!).render() diff --git a/examples/react/devtools/tsconfig.json b/examples/react/devtools/tsconfig.json deleted file mode 100644 index a97ff8c1..00000000 --- a/examples/react/devtools/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "Bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src", "vite.config.ts"] -} diff --git a/examples/react/devtools/vite.config.ts b/examples/react/devtools/vite.config.ts deleted file mode 100644 index 9ffcc675..00000000 --- a/examples/react/devtools/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -export default defineConfig({ - plugins: [react()], -}) diff --git a/examples/solid/basic/index.html b/examples/solid/basic/index.html deleted file mode 100644 index 17f2710e..00000000 --- a/examples/solid/basic/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - TanStack Time - Solid Basic Example - - - -
- - - diff --git a/examples/solid/basic/package.json b/examples/solid/basic/package.json deleted file mode 100644 index 435c077d..00000000 --- a/examples/solid/basic/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@tanstack/time-example-solid-basic", - "private": true, - "type": "module", - "scripts": { - "dev": "vite --port=3007", - "build": "vite build", - "preview": "vite preview", - "test:types": "tsc" - }, - "dependencies": { - "@tanstack/solid-time": "^0.0.0", - "@tanstack/time": "^0.0.0", - "solid-js": "^1.9.10" - }, - "devDependencies": { - "typescript": "5.9.3", - "vite": "^7.3.1", - "vite-plugin-solid": "^2.11.10" - } -} diff --git a/examples/solid/basic/src/index.tsx b/examples/solid/basic/src/index.tsx deleted file mode 100644 index 8d05d244..00000000 --- a/examples/solid/basic/src/index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { render } from 'solid-js/web' - -function App() { - return ( -
-

TanStack Time - Solid Basic Example

-
- ) -} - -render(() => , document.getElementById('root')!) diff --git a/examples/solid/basic/tsconfig.json b/examples/solid/basic/tsconfig.json deleted file mode 100644 index 11b0838c..00000000 --- a/examples/solid/basic/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Bundler", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - "types": ["vite/client"], - "noEmit": true, - "isolatedModules": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true - }, - "include": ["src", "vite.config.ts"] -} diff --git a/examples/solid/basic/vite.config.ts b/examples/solid/basic/vite.config.ts deleted file mode 100644 index d0d72d27..00000000 --- a/examples/solid/basic/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' - -export default defineConfig({ - plugins: [solid({})], -}) diff --git a/examples/solid/devtools/index.html b/examples/solid/devtools/index.html deleted file mode 100644 index 0d3fab34..00000000 --- a/examples/solid/devtools/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - TanStack Time - Solid Devtools Example - - - -
- - - diff --git a/examples/solid/devtools/package.json b/examples/solid/devtools/package.json deleted file mode 100644 index 251d6a78..00000000 --- a/examples/solid/devtools/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "@tanstack/time-example-solid-devtools", - "private": true, - "type": "module", - "scripts": { - "dev": "vite --port=3008", - "build": "vite build", - "preview": "vite preview", - "test:types": "tsc" - }, - "dependencies": { - "@tanstack/solid-time": "^0.0.0", - "@tanstack/solid-time-devtools": "^0.0.0", - "@tanstack/time": "^0.0.0", - "solid-js": "^1.9.10" - }, - "devDependencies": { - "typescript": "5.9.3", - "vite": "^7.3.1", - "vite-plugin-solid": "^2.11.10" - } -} diff --git a/examples/solid/devtools/src/index.tsx b/examples/solid/devtools/src/index.tsx deleted file mode 100644 index cbe1b6e6..00000000 --- a/examples/solid/devtools/src/index.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { render } from 'solid-js/web' -import { TimeDevtools } from '@tanstack/solid-time-devtools' - -function App() { - return ( -
-

TanStack Time - Solid Devtools Example

-

Devtools:

- -
- ) -} - -render(() => , document.getElementById('root')!) diff --git a/examples/solid/devtools/tsconfig.json b/examples/solid/devtools/tsconfig.json deleted file mode 100644 index 11b0838c..00000000 --- a/examples/solid/devtools/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Bundler", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - "types": ["vite/client"], - "noEmit": true, - "isolatedModules": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true - }, - "include": ["src", "vite.config.ts"] -} diff --git a/examples/solid/devtools/vite.config.ts b/examples/solid/devtools/vite.config.ts deleted file mode 100644 index d0d72d27..00000000 --- a/examples/solid/devtools/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' - -export default defineConfig({ - plugins: [solid({})], -}) diff --git a/packages/react-time-devtools/eslint.config.js b/packages/react-time-devtools/eslint.config.js index ec5db3c6..21ee9b63 100644 --- a/packages/react-time-devtools/eslint.config.js +++ b/packages/react-time-devtools/eslint.config.js @@ -5,7 +5,7 @@ import pluginReactCompiler from 'eslint-plugin-react-compiler' import pluginReactHooks from 'eslint-plugin-react-hooks' import rootConfig from '../../eslint.config.js' -/** @type {import('eslint').Linter.Config[]} */ +/** @type {any[]} */ export default [ ...rootConfig, { diff --git a/packages/react-time-devtools/src/TimeDevtools.tsx b/packages/react-time-devtools/src/TimeDevtools.tsx deleted file mode 100644 index 6ceb5731..00000000 --- a/packages/react-time-devtools/src/TimeDevtools.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react' - -export function TimeDevtools() { - console.log('Hello from @tanstack/react-time-devtools!') - return
Time Devtools
-} diff --git a/packages/react-time-devtools/src/index.ts b/packages/react-time-devtools/src/index.ts index f7114f85..e69de29b 100644 --- a/packages/react-time-devtools/src/index.ts +++ b/packages/react-time-devtools/src/index.ts @@ -1 +0,0 @@ -export * from './TimeDevtools' diff --git a/packages/solid-time-devtools/src/TimeDevtools.tsx b/packages/solid-time-devtools/src/TimeDevtools.tsx new file mode 100644 index 00000000..0d0a71b8 --- /dev/null +++ b/packages/solid-time-devtools/src/TimeDevtools.tsx @@ -0,0 +1,8 @@ +import { template } from 'solid-js/web' + +const _tmpl$ = /* @__PURE__ */ template(`
Solid Time Devtools
`) + +export function TimeDevtools() { + console.log('Hello from @tanstack/solid-time-devtools!') + return _tmpl$() +} From f0f9bace904f1e8c6e1e6f61c79a7354e52a1dbe Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 21:58:51 +0000 Subject: [PATCH 004/207] ci: apply automated fixes --- .../react/reference/functions/.gitkeep | 0 docs/framework/react/reference/index.md | 2 - .../solid/reference/functions/.gitkeep | 0 docs/framework/solid/reference/index.md | 2 - docs/reference/classes/.gitkeep | 0 docs/reference/functions/.gitkeep | 0 docs/reference/index.md | 6 -- docs/reference/interfaces/.gitkeep | 0 packages/react-time-devtools/README.md | 57 +------------------ packages/react-time/README.md | 2 +- packages/solid-time-devtools/README.md | 6 +- packages/solid-time/README.md | 6 +- packages/time-devtools/README.md | 6 +- packages/time/README.md | 6 +- 14 files changed, 7 insertions(+), 86 deletions(-) delete mode 100644 docs/framework/react/reference/functions/.gitkeep delete mode 100644 docs/framework/solid/reference/functions/.gitkeep delete mode 100644 docs/reference/classes/.gitkeep delete mode 100644 docs/reference/functions/.gitkeep delete mode 100644 docs/reference/interfaces/.gitkeep diff --git a/docs/framework/react/reference/functions/.gitkeep b/docs/framework/react/reference/functions/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/framework/react/reference/index.md b/docs/framework/react/reference/index.md index 3727a566..6e5811a0 100644 --- a/docs/framework/react/reference/index.md +++ b/docs/framework/react/reference/index.md @@ -4,5 +4,3 @@ title: "@tanstack/react-time" --- # @tanstack/react-time - -## Functions diff --git a/docs/framework/solid/reference/functions/.gitkeep b/docs/framework/solid/reference/functions/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/framework/solid/reference/index.md b/docs/framework/solid/reference/index.md index 0e2ac4a7..4d2f7063 100644 --- a/docs/framework/solid/reference/index.md +++ b/docs/framework/solid/reference/index.md @@ -4,5 +4,3 @@ title: "@tanstack/solid-time" --- # @tanstack/solid-time - -## Functions diff --git a/docs/reference/classes/.gitkeep b/docs/reference/classes/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/reference/functions/.gitkeep b/docs/reference/functions/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/reference/index.md b/docs/reference/index.md index c786a357..b14fbe49 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -4,9 +4,3 @@ title: "@tanstack/time" --- # @tanstack/time - -## Classes - -## Interfaces - -## Functions diff --git a/docs/reference/interfaces/.gitkeep b/docs/reference/interfaces/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/react-time-devtools/README.md b/packages/react-time-devtools/README.md index b81652cb..7ecd7e46 100644 --- a/packages/react-time-devtools/README.md +++ b/packages/react-time-devtools/README.md @@ -1,56 +1,3 @@ -# TanStack Time +# time -A complete time for creating new TanStack libraries with all the tooling and infrastructure you need. - -## What's Included - -- āœ… Framework-agnostic core package -- āœ… React and Solid adapters (easy to add more) -- āœ… Devtools packages for debugging -- āœ… Full monorepo setup with pnpm + Nx -- āœ… TypeScript configuration -- āœ… Testing setup with Vitest -- āœ… Documentation structure with TypeDoc -- āœ… Example applications -- āœ… GitHub workflows (CI, release, autofix) -- āœ… Changesets for versioning -- āœ… ESLint + Prettier -- āœ… Issue and PR times - -## Getting Started - -1. Clone or copy this time -2. Follow the instructions in time_GUIDE.md -3. Search and replace "time" with your library name -4. Replace placeholder code with your implementation -5. Update documentation -6. Start building! - -## Package Structure - -- `@tanstack/time` - Core library -- `@tanstack/react-time` - React adapter -- `@tanstack/solid-time` - Solid adapter -- `@tanstack/time-devtools` - Base devtools -- `@tanstack/react-time-devtools` - React devtools -- `@tanstack/solid-time-devtools` - Solid devtools - -## Commands - -```bash -pnpm install # Install dependencies -pnpm build:all # Build all packages -pnpm test:lib # Run tests -pnpm test:pr # Run PR checks -pnpm format # Format code -pnpm generate-docs # Generate documentation -pnpm watch # Watch mode -``` - -## Documentation - -See time_GUIDE.md for detailed instructions on customizing this time. - -## License - -MIT +šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular diff --git a/packages/react-time/README.md b/packages/react-time/README.md index 6f387301..7ecd7e46 100644 --- a/packages/react-time/README.md +++ b/packages/react-time/README.md @@ -1,3 +1,3 @@ -# TanStack Time +# time šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular diff --git a/packages/solid-time-devtools/README.md b/packages/solid-time-devtools/README.md index b7017d28..7ecd7e46 100644 --- a/packages/solid-time-devtools/README.md +++ b/packages/solid-time-devtools/README.md @@ -1,7 +1,3 @@ -# TanStack Time +# time šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular - -## License - -MIT diff --git a/packages/solid-time/README.md b/packages/solid-time/README.md index b7017d28..7ecd7e46 100644 --- a/packages/solid-time/README.md +++ b/packages/solid-time/README.md @@ -1,7 +1,3 @@ -# TanStack Time +# time šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular - -## License - -MIT diff --git a/packages/time-devtools/README.md b/packages/time-devtools/README.md index b7017d28..7ecd7e46 100644 --- a/packages/time-devtools/README.md +++ b/packages/time-devtools/README.md @@ -1,7 +1,3 @@ -# TanStack Time +# time šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular - -## License - -MIT diff --git a/packages/time/README.md b/packages/time/README.md index b7017d28..7ecd7e46 100644 --- a/packages/time/README.md +++ b/packages/time/README.md @@ -1,7 +1,3 @@ -# TanStack Time +# time šŸ¤–ā° Headless utilities for building time and calendar components in TS/JS, React, Solid, Vue, Svelte and Angular - -## License - -MIT From b9bdb1b28456c68c5148b0178a4d1cd3e3cbf35b Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 19 Jan 2026 23:18:05 +0100 Subject: [PATCH 005/207] feat: base --- Methodology.md | 152 ++++ Methods.md | 22 + package.json | 3 + packages/time/src/date/dateDefaults.ts | 57 ++ packages/time/src/date/isValidDate/index.ts | 1 + .../time/src/date/isValidDate/isValidDate.ts | 13 + .../isValidDate/tests/isValidDate.test.ts | 16 + packages/time/src/date/parse/index.ts | 1 + packages/time/src/date/parse/parse.ts | 138 ++++ .../time/src/date/parse/tests/parse.test.ts | 157 ++++ packages/time/src/date/parsingDates.md | 82 ++ packages/time/src/date/startOf/index.ts | 1 + packages/time/src/date/startOf/startOf.ts | 0 .../src/date/startOf/tests/startOf.test.ts | 0 packages/time/src/date/validateDate.ts | 27 + .../buildDateFormatter/buildDateFormatter.ts | 40 + .../src/formatter/buildDateFormatter/index.ts | 1 + .../buildDateTimeFormatter.ts | 54 ++ .../formatter/buildDateTimeFormatter/index.ts | 1 + .../buildFinalFormatter.ts | 45 ++ .../formatter/buildFinalFormatter/index.ts | 1 + .../tests/buildFinalFormatter.test.ts | 43 ++ .../buildTimeFormatter/buildTimeFormatter.ts | 40 + .../src/formatter/buildTimeFormatter/index.ts | 1 + .../src/formatter/extractLocaleOptions.ts | 91 +++ packages/time/src/formatter/shared.ts | 60 ++ packages/time/src/polyfills/getWeekInfo.ts | 38 + packages/time/src/polyfills/types.ts | 15 + packages/time/src/polyfills/weekInfoData.ts | 714 ++++++++++++++++++ pnpm-lock.yaml | 98 +-- 30 files changed, 1831 insertions(+), 81 deletions(-) create mode 100644 Methodology.md create mode 100644 Methods.md create mode 100644 packages/time/src/date/dateDefaults.ts create mode 100644 packages/time/src/date/isValidDate/index.ts create mode 100644 packages/time/src/date/isValidDate/isValidDate.ts create mode 100644 packages/time/src/date/isValidDate/tests/isValidDate.test.ts create mode 100644 packages/time/src/date/parse/index.ts create mode 100644 packages/time/src/date/parse/parse.ts create mode 100644 packages/time/src/date/parse/tests/parse.test.ts create mode 100644 packages/time/src/date/parsingDates.md create mode 100644 packages/time/src/date/startOf/index.ts create mode 100644 packages/time/src/date/startOf/startOf.ts create mode 100644 packages/time/src/date/startOf/tests/startOf.test.ts create mode 100644 packages/time/src/date/validateDate.ts create mode 100644 packages/time/src/formatter/buildDateFormatter/buildDateFormatter.ts create mode 100644 packages/time/src/formatter/buildDateFormatter/index.ts create mode 100644 packages/time/src/formatter/buildDateTimeFormatter/buildDateTimeFormatter.ts create mode 100644 packages/time/src/formatter/buildDateTimeFormatter/index.ts create mode 100644 packages/time/src/formatter/buildFinalFormatter/buildFinalFormatter.ts create mode 100644 packages/time/src/formatter/buildFinalFormatter/index.ts create mode 100644 packages/time/src/formatter/buildFinalFormatter/tests/buildFinalFormatter.test.ts create mode 100644 packages/time/src/formatter/buildTimeFormatter/buildTimeFormatter.ts create mode 100644 packages/time/src/formatter/buildTimeFormatter/index.ts create mode 100644 packages/time/src/formatter/extractLocaleOptions.ts create mode 100644 packages/time/src/formatter/shared.ts create mode 100644 packages/time/src/polyfills/getWeekInfo.ts create mode 100644 packages/time/src/polyfills/types.ts create mode 100644 packages/time/src/polyfills/weekInfoData.ts diff --git a/Methodology.md b/Methodology.md new file mode 100644 index 00000000..1369960a --- /dev/null +++ b/Methodology.md @@ -0,0 +1,152 @@ +## Some Givens + +As mentioned in our initial wiki entry, we have a few givens that we are working with: + +- Dates, given to the TanStack Time API, should be in standard Internet Date Time Format [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) (string) format, epoch time (numeric), or already be a Date object. +- Format of dates/times are configurable to base standards set forth by the Intl.DateTimeFormat API. Formats are not designated by string tokens, but rather by parts, and displayed according to locale, calendar and timezone. This ensures consistent display of dates and times when switching between any of these three localization points. +- Until Temporal is ratified and implemented by all major browsers, TanStack Time will [use the polyfill](https://github.com/js-temporal/temporal-polyfill) maintained by the TC39 champions of the Temporal API +- Date objects are mutable, therefore we must take care not to directly revise any Date passed into the API +- Public API methods should return either a Date object or a string. Temporal objects should never be returned by the public API methods. + +## Assumptions of working with true date and time + +Developers, dealing with accurate references to an instance of date/time, require a few things: + +- A reference to the date/time instance, either as an RFC 3339 string or epoch time +- The timezone of the date/time instance +- And, in some instances, the calendar system of the date/time instance + +Why is this important? Because a date/time instance is not a static point in time. It is a reference to a point in time that is relative to the timezone and calendar system in which it is being referenced. This is why it is important to know the timezone and calendar system of the date/time instance. This is the reason the Temporal API is so important. It allows us to work with date/time instances in a way that is more accurate with how we truly interoperate with date/time instances. + +## Defaults + +We can get the browser local defaults for the timezone and calendar system by using the Intl.DateTimeFormat API. This will allow us to set defaults for the timezone and calendar system when the developer does not provide them. That said, we should always allow the developer to override these defaults on a case by case basis. + +## Rethinking In Terms of DX + +When we think about the DX of the TanStack Time API, we need to consider the following: + +- Developers will often be working with date and time values stored in a database +- Developers will often be working with date and time values from user input +- Those values will need to be converted to valid ZonedDateTime objects internally + - This will require the developer to know the timezone of the date/time instance + - This will require the developer to know the calendar system of the date/time instance +- Developers will need to be able to define the representation (return type) of the return value of a method (this excludes formatting methods) + - Do they need an RFC 3339 string? 'standard' (current zulu time standard) or 'long' (with timezone and calendar)? + - Do they need an epoch time? + - Do they need a Date object? + - Do they need a ZonedDateTime object? (this would be for calling multiple methods back to back to back) + +Because the user may use the browser defaults for the timezone and calendar system, it may be necessary to return these options with the 'result' of a method call. This will allow the developer to know what the defaults were when the method was called, where they may need to database the timeZone or calendar. + +```js +// maybe? +const { value: firstOfMonth, options } = startOf({ + date: '2024-03-05T12:34:56.789Z', + unit: 'month', + returnFormat: 'ZonedDateTime', + // These 'options' would be the defaults set by the Intl.DateTimeFormat API + // and could be overridden by the developer + /* options: { + calendar: 'gregory', + timeZone: 'America/New_York' + } */ +}) +const { value: firstCalendarDayOfMarch } = startOf({ + date: firstOfMonth, // as a ZonedDateTime object it won't have to be parsed + unit: 'week', + returnFormat: 'standard', // an ISO 8601 string to send to the database + options, // uses returned options from first method to maintain consistency +}) +// maybe? +const myDate = startOf({ ...options }) +const value = myDate.asDate() +const value2 = myDate.asEpoch() +const tz = myDate.timeZone +const { value, timeZone, calendar } = myDate +``` + +As mentioned in the Temporal documentation, the ISO 8601 and RFC 3339 industry standards for machine-readable serialization of dates and times are considering extension to include the timeZone and calendar as a part of the string. This would allow for a more complete representation of the date/time instance. This is something we should consider when returning a string representation of a date/time instance. (i.e. `2024-03-05T12:34:56.789Z[America/New_York][u-ca=gregory]`). While this may be acceptable for string based representations, where later access to timeZone and calendar may be required. + +## Possible Workflow + +### Workflow 'A' + +One possible way of handling this is for each method to be standalone, requiring basic arguments +and options and returning a result and options. This would allow for a more flexible API, but +may require more boilerplate code to be written by the developer. + +1. Method takes in a date/time value, arguments, and options + a. If value is already a ZonedDateTime, continue + b. If not a ZonedDateTime (i.e. string, epoch time, or Date object), convert to ZonedDateTime +2. Method processes the ZonedDateTime +3. Method returns the result and options + a. Result is in default or specified returnFormat + b. Options include timeZone and calendar + +### Workflow 'B' + +Another possible way of handling this is by utilizing a class that can be instantiated with the options and returnFormat. The class would then hold the 'value' internally, and the return of any method (aside from the `value` getter) would return the class instance, allowing one to chain methods together. + +I'm not sure what this looks like yet, but honestly not a fan. From a DX perspective it gives an initial appearance of ease of use, but seems like in the end it would be more difficult to work with, too difficult to see your progression in the process stack, and hard to identify error boundaries. It would also require a rather large object with a lot of methods, creating a lot of object overhead for simple processes, and make it difficult to treeshake. + +```js +// maybe? +const firstCalendarDayOfMarch = new TanStackTime('2024-03-05T12:34:56.789Z', { + timeZone: 'America/New_York', + calendar: 'gregory', + returnFormat: 'standard', +}) + .startOf({ unit: 'month' }) + .startOf({ unit: 'week' }) + .asDate() +``` + +## Parsing + +When parsing input date/time values, we need to consider the following: + +- If the input is numeric (epoch time), we need to convert it to a valid ZonedDateTime object +- If the input is a string, we need to convert it to a valid ZonedDateTime object? +- If the input is a Date object, we need to convert it to a valid ZonedDateTime object + +### Epoch parsing + +An epoch time is a numeric value that represents the number of milliseconds since the Unix epoch (1970-01-01T00:00:00.000Z). This is a common way of representing a date/time instance in a database. All we require, aside from it's value, is the timezone and calendar system in which it is being referenced. + +```js +const timeZone = 'Asia/Tokyo' +const calendar = 'japanese' +const legacy = new Date(1726515625477) +const zdt = Temporal.ZonedDateTime.from( + `${legacy.toJSON()}[${timeZone}][u-ca=${calendar}]`, +) +``` + +### String parsing + +A string representation must be in the RFC 3339 standard format, or in the ISO 8601 extended format. This is the most common way of representing a date/time instance in a web application. All we require, aside from it's value, is the timezone and calendar system in which it is being referenced. + +```js +const timeZone = 'Asia/Tokyo' +const calendar = 'japanese' +const legacy = '2024-03-05T12:34:56.789Z' +const zdt = Temporal.ZonedDateTime.from( + `${legacy}[${timeZone}][u-ca=${calendar}]`, +) +``` + +This assumes that the timeZone and calendar are not already included in the string. If they are, we can simply pass the string to the Temporal.ZonedDateTime.from() method. + +### Date parsing + +A Date object is a native object in JavaScript that represents a date/time instance. This is a common way of representing a date/time instance in a web application. All we require, aside from it's value, is the timezone and calendar system in which it is being referenced. + +```js +const timeZone = 'Asia/Tokyo' +const calendar = 'japanese' +const legacy = new Date() // this would be passed into a method, but this is just an example +const zdt = Temporal.ZonedDateTime.from( + `${legacy.toJSON()}[${timeZone}][u-ca=${calendar}]`, +) +``` diff --git a/Methods.md b/Methods.md new file mode 100644 index 00000000..55bfd217 --- /dev/null +++ b/Methods.md @@ -0,0 +1,22 @@ +# What API methods do we need? + +[]: # - startOf(ZonedDateTime, unit): ZonedDateTime +[]: # - endOf(ZonedDateTime, unit): ZonedDateTime +[]: # - add(ZonedDateTime, duration): ZonedDateTime +[]: # - subtract(ZonedDateTime, duration): ZonedDateTime +[]: # - until(ZonedDateTime, ZonedDateTime): Duration +[]: # - since(ZonedDateTime, ZonedDateTime): Duration +[]: # - equals(ZonedDateTime, ZonedDateTime, unit): boolean +[]: # - isBefore(ZonedDateTime, ZonedDateTime): boolean +[]: # - isAfter(ZonedDateTime, ZonedDateTime): boolean +[]: # - isSameOrBefore(ZonedDateTime, ZonedDateTime, unit): boolean +[]: # - isSameOrAfter(ZonedDateTime, ZonedDateTime, unit): boolean +[]: # - isBetween(ZonedDateTime, Range): boolean +[]: # - intersects(ZonedDateTime, Range): boolean +[]: # - time(PlainTime): ZonedDateTime (use getter/setter?) +[]: # - timeZone(IANATimeZoneId): ZonedDateTime (use getter/setter?) +[]: # - calendar(Calendar): ZonedDateTime (use getter/setter?) +[]: # - round(unit): ZonedDateTime +[]: # - asEpoch +[]: # - asString +[]: # - asZonedDateTime diff --git a/package.json b/package.json index 6e81ae1f..cea8af33 100644 --- a/package.json +++ b/package.json @@ -73,5 +73,8 @@ "@tanstack/react-time-devtools": "workspace:*", "@tanstack/solid-time": "workspace:*", "@tanstack/solid-time-devtools": "workspace:*" + }, + "dependencies": { + "@js-temporal/polyfill": "^0.5.1" } } diff --git a/packages/time/src/date/dateDefaults.ts b/packages/time/src/date/dateDefaults.ts new file mode 100644 index 00000000..6f962ea5 --- /dev/null +++ b/packages/time/src/date/dateDefaults.ts @@ -0,0 +1,57 @@ +import type { Locale } from '../formatter/shared' + +export interface DateDefaults { + calendar: string + locale: string + timeZone: string +} + +const { + calendar: defaultCalendar, + locale: defaultLocale, + timeZone: defaultTimeZone, +} = new Intl.DateTimeFormat().resolvedOptions() + +/** + * getDateDefaults + * @returns DateDefaults + */ +export function getDateDefaults(): DateDefaults { + return { + calendar: defaultCalendar, + locale: defaultLocale, + timeZone: defaultTimeZone, + } +} + +/** + * getDefaultCalendar + * @returns string - default calendar + */ +export function getDefaultCalendar(): string { + return defaultCalendar +} + +/** + * getDefaultLocale + * @returns string - default locale + */ +export function getDefaultLocale(): Locale { + return defaultLocale +} + +/** + * getDefaultTimeZone + * @returns string - default time zone + */ +export function getDefaultTimeZone(): string { + return defaultTimeZone +} + +export function normalizeLocale(locale: Locale): string | Array { + return Array.isArray(locale) + ? locale.map((loc) => (typeof loc === 'string' ? loc : loc.toString())) + : typeof locale === 'string' + ? locale + : locale.toString() +} diff --git a/packages/time/src/date/isValidDate/index.ts b/packages/time/src/date/isValidDate/index.ts new file mode 100644 index 00000000..3429df3f --- /dev/null +++ b/packages/time/src/date/isValidDate/index.ts @@ -0,0 +1 @@ +export * from './isValidDate' diff --git a/packages/time/src/date/isValidDate/isValidDate.ts b/packages/time/src/date/isValidDate/isValidDate.ts new file mode 100644 index 00000000..b7b28560 --- /dev/null +++ b/packages/time/src/date/isValidDate/isValidDate.ts @@ -0,0 +1,13 @@ +/** + * isValidDate + * Verifies if a date is a JS Date object and is valid + * @param date Date + * @returns boolean + */ +export function isValidDate(date: unknown): date is Date { + if (Object.prototype.toString.call(date) !== '[object Date]') { + return false + } + const dateObj = date as Date + return dateObj.getTime() === dateObj.getTime() +} diff --git a/packages/time/src/date/isValidDate/tests/isValidDate.test.ts b/packages/time/src/date/isValidDate/tests/isValidDate.test.ts new file mode 100644 index 00000000..45d3d692 --- /dev/null +++ b/packages/time/src/date/isValidDate/tests/isValidDate.test.ts @@ -0,0 +1,16 @@ +import {describe, expect, test} from 'vitest'; +import {isValidDate} from '../isValidDate'; + +describe('isValidDate', () => { + test('should return true for a valid date', () => { + expect(isValidDate(new Date())).toBe(true); + }) + + test('should return false for an invalid date', () => { + expect(isValidDate(new Date("invalid"))).toBe(false); + }); + + test("should return false for null", () => { + expect(isValidDate(null)).toBe(false); + }); +}); diff --git a/packages/time/src/date/parse/index.ts b/packages/time/src/date/parse/index.ts new file mode 100644 index 00000000..959e55b4 --- /dev/null +++ b/packages/time/src/date/parse/index.ts @@ -0,0 +1 @@ +export * from './parse' diff --git a/packages/time/src/date/parse/parse.ts b/packages/time/src/date/parse/parse.ts new file mode 100644 index 00000000..c7cabd1c --- /dev/null +++ b/packages/time/src/date/parse/parse.ts @@ -0,0 +1,138 @@ +/** + * rfc3339DateTimeOptionalTimeRegex + * Regular expression to match RFC3339 date/time strings with all optional parts + */ +const rfc3339DateTimeOptionalTimeRegex = + /^(?(?\d{4})(?:-(?0[1-9]|1[0-2])(?:-(?0[1-9]|[12][0-9]|3[01]))))(?:(?:T| )(?(?[01][0-9]|2[0-3])(?::(?[0-5][0-9])(?::(?[0-5][0-9])(?:\.(?\d+))?)?)?)?(?Z|[+-](?:2[0-3]|[01][0-9]:[0-5][0-9]))?)?$/i + +/** + * timeOnlyRegex + * Regular expression to match time-only strings + */ +const timeOnlyRegex = + /^((?(?:2[0-3]|[0-1][0-9]))(?::(?[0-5][0-9])(?::(?[0-5][0-9])(?:\.(?\d+))?)?)?)(?:\s(?(?:AM|PM)))?$/i + +/** + * dateOnlyRegex + * Regular expression to match date-only strings + */ +const dateOnlyRegex = + /^(?\d{4})(-(?0[1-9]|1[0-2]))?(-(?0[1-9]|[12][0-9]|3[01]))?(?T| )?(?Z|[+-](?:2[0-3]|[01][0-9]:[0-5][0-9]))?$/i + +/** + * isValidEpoch + * Verifies if a numeric value is a valid epoch date + * @param {number} value + * @returns boolean + */ +function isValidEpoch(value: number): boolean { + return value >= -8.64e12 && value <= +8.64e12 +} + +/** + * parseEpochDateTime + * Parses a numeric value as a date/time epoch + * @param {number} value + * @returns Date + */ +function parseEpochDateTime(value: number): Date { + // if it's a floating point number, assume it's a unix timestamp + const toParse = Number.isInteger(value) ? value : value * 1000 + // but verify + if (isValidEpoch(toParse)) { + return new Date(toParse) + } + throw new Error(`"${value}" is an invalid epoch date value`) +} + +/** + * parseDateTimeString + * Parses a string as a date/time string + * @param {string} value + * @returns Date + */ +function parseDateTimeString(value: string): Date { + const match = + rfc3339DateTimeOptionalTimeRegex.exec(value) ?? dateOnlyRegex.exec(value) + + if (match?.groups) { + const { + year, + month = '01', + day = '01', + hour = '00', + minute = '00', + second = '00', + millisecond = '000', + timezone = '', + } = match.groups + + return new Date( + `${year}-${month}-${day}T${hour}:${minute}:${second}.${millisecond}${timezone}`, + ) + } + throw new Error(`"${value}" is an invalid RFC339 Internet Date Time string`) +} + +/** + * parseTimeOnlyString + * Parses a string as a time-only string + * @param {string} value + * @returns Date + */ +function parseTimeOnlyString(value: string): Date { + const match = timeOnlyRegex.exec(value) + if (match?.groups) { + const now = new Date() + const { + hour = '00', + minute = '00', + second = '00', + millisecond = '000', + meridiem, + } = match.groups + // convert 12 hour time to 24 + let trueHour = Number(hour) + if (meridiem) { + if (trueHour > 12) { + throw new Error(`"${value}" is an invalid time string`) + } + if (meridiem.toLowerCase() === 'pm' && trueHour < 12) { + trueHour += 12 + } + } + now.setHours(trueHour, Number(minute), Number(second), Number(millisecond)) + return now + } + throw new Error(`"${value}" is an invalid time string`) +} + +/** + * parseDateOrTimeString + * Parses a string as a date/time or time string + * @param {string} value + * @returns Date + */ +function parseDateOrTimeString(value: string): Date { + const match = timeOnlyRegex.exec(value) + if (match) { + return parseTimeOnlyString(value) + } + return parseDateTimeString(value) +} + +/** + * parse + * Parses a string, number or Date object as a Date + * @param {string | number | Date} value + * @returns Date | undefined + */ +export function parse(value: string | number | Date): Date | undefined { + if (!value) return undefined + if (typeof value === 'string') { + return parseDateOrTimeString(value) + } else if (typeof value === 'number') { + return parseEpochDateTime(value) + } + return value +} diff --git a/packages/time/src/date/parse/tests/parse.test.ts b/packages/time/src/date/parse/tests/parse.test.ts new file mode 100644 index 00000000..c5a123d6 --- /dev/null +++ b/packages/time/src/date/parse/tests/parse.test.ts @@ -0,0 +1,157 @@ +import { beforeEach, describe, expect, test, vi } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { parse } from '../parse' + +const dateTimeFormat = new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + timeZoneName: 'short', + timeZone: 'America/New_York', +}) + +const timeOnlyFormat = new Intl.DateTimeFormat('en-US', { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + timeZone: 'America/New_York', +}) + +describe('parse', () => { + const mockDate = new Date('2023-06-15') + const mockDateTime = new Date('2023-06-15T10:00:00') + + beforeEach(() => { + const mockTemporalDate = Temporal.PlainDate.from( + mockDate.toISOString().split('T')[0]!, + ) + const mockTemporalDateTime = Temporal.PlainDateTime.from( + mockDateTime.toISOString().replace('Z', ''), + ) + vi.spyOn(Temporal.Now, 'plainDateISO').mockReturnValue(mockTemporalDate) + vi.spyOn(Temporal.Now, 'plainDateTimeISO').mockReturnValue( + mockTemporalDateTime, + ) + }) + + test('should parse a valid year only date string', () => { + const date = parse('2021') + expect(dateTimeFormat.format(date)).toBe('01/01/2021, 12:00:00 AM EST') + }) + + test('should parse a valid year and month only date string', () => { + const date = parse('2021-03') + expect(dateTimeFormat.format(date)).toBe('03/01/2021, 12:00:00 AM EST') + }) + + test('should parse a valid year, month and day only date string', () => { + const date = parse('2021-03-12') + expect(dateTimeFormat.format(date)).toBe('03/12/2021, 12:00:00 AM EST') + }) + + test('should cast date only string to UTC', () => { + const date = parse('2021-03-12TZ') + expect(dateTimeFormat.format(date)).toBe('03/11/2021, 07:00:00 PM EST') + }) + + test('should cast date only string to offset', () => { + const date = parse('2021-03-12T-07:00') + expect(dateTimeFormat.format(date)).toBe('03/12/2021, 02:00:00 AM EST') + }) + + test('should parse a valid year, month, day and hour only date/time string with separator', () => { + const date = parse('2021-03-12T14') + expect(dateTimeFormat.format(date)).toBe('03/12/2021, 02:00:00 PM EST') + }) + + test('should parse a valid year, month, day and hour only date/time string without separator', () => { + const date = parse('2021-03-12 16') + expect(dateTimeFormat.format(date)).toBe('03/12/2021, 04:00:00 PM EST') + }) + + test('should parse a valid year, month, day, hour and minute only date/time string', () => { + const date = parse('2021-03-12T14:42') + expect(dateTimeFormat.format(date)).toBe('03/12/2021, 02:42:00 PM EST') + }) + + test('should parse a valid year, month, day, hour, minute and seconds only date/time string', () => { + const date = parse('2021-03-12T14:42:12') + expect(dateTimeFormat.format(date)).toBe('03/12/2021, 02:42:12 PM EST') + }) + + test('should parse a valid UTC date/time string', () => { + const date = parse('2021-03-12T14:42:12Z') + expect(dateTimeFormat.format(date)).toBe('03/12/2021, 09:42:12 AM EST') + }) + + test('should parse a valid UTC date/time string with lower case separator and zulu', () => { + const date = parse('2021-03-12t14:42:12z') + expect(dateTimeFormat.format(date)).toBe('03/12/2021, 09:42:12 AM EST') + }) + + test('should parse a valid date/time string with offset', () => { + const date = parse('2021-03-12T14:42:12+09:00') + expect(dateTimeFormat.format(date)).toBe('03/12/2021, 12:42:12 AM EST') + }) + + test('should parse a valid epoch date/time', () => { + const date = parse(1711639239717) + expect(dateTimeFormat.format(date)).toBe('03/28/2024, 11:20:39 AM EDT') + }) + + test('should parse a valid hour and minute time string', () => { + const date = parse('14:00') + expect(timeOnlyFormat.format(date)).toBe('02:00:00 PM') + }) + + test('should parse a valid hour, minute and second time string', () => { + const date = parse('14:14:34') + expect(timeOnlyFormat.format(date)).toBe('02:14:34 PM') + }) + + test('should parse a valid hour, minute and second time string with meridiem', () => { + const date = parse('08:14:34 PM') + expect(timeOnlyFormat.format(date)).toBe('08:14:34 PM') + }) + + test('should throw an error for an invalid date string', () => { + expect(() => parse('2021-15-37')).toThrowError( + '"2021-15-37" is an invalid RFC339 Internet Date Time string', + ) + }) + + test('should throw an error for an invalid time string', () => { + expect(() => parse('27:62')).toThrowError( + '"27:62" is an invalid RFC339 Internet Date Time string', + ) + }) + + test('should throw an error for an invalid time string', () => { + expect(() => parse('14:12 PM')).toThrowError( + '"14:12 PM" is an invalid time string', + ) + }) + + test('should throw an error for an invalid epoch', () => { + // eslint-disable-next-line no-loss-of-precision + expect(() => parse(9274309587123413)).toThrowError( + '"9274309587123412" is an invalid epoch date value', + ) + }) + + /* test('should parse a valid time string', () => { + const date = parse('00:00:00.000Z'); + expect(dateTimeFormat.format(date)).toBe('12/31/2020, 7:00:00 PM EST'); + }); + + test('should throw an error for an invalid date string', () => { + expect(() => parse('2021-01-01T00:00:00.000')).toThrowError('"2021-01-01T00:00:00.000" is an invalid RFC339 Internet Date Time string'); + }); + + test('should throw an error for an invalid time string', () => { + expect(() => parse('00:00:00.000')).toThrowError('"00:00:00.000" is an invalid time string'); + }); */ +}) diff --git a/packages/time/src/date/parsingDates.md b/packages/time/src/date/parsingDates.md new file mode 100644 index 00000000..f127e9e6 --- /dev/null +++ b/packages/time/src/date/parsingDates.md @@ -0,0 +1,82 @@ +# Parsing Dates + +TanStack Time will include a basic parser for parsing dates and times. It will natively parse dates in the following formats: + +- RFC3339 Internet Date/Time Format +- Unix Timestamp (Epoch Time) +- Existing Date object +- a "plain time" string + +If taking an existing Date object, it will just copy it to a new object, as Date objects are mutable. + +A Unix Timestamp (known as an Epoch) is the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, not counting leap seconds. It is used widely in computer systems and is the standard way to represent a date and time in many programming languages. A Unix Timestamp already represents a specific point in time, so it is easily used to create a new Date object. + +Parsing a date from a string is a bit more complex. The RFC3339 Internet Date/Time Format is a profile of the ISO 8601 standard for date and time formats. It is the most accurate way to represent a date and time, and it is the format that TanStack Time will use to parse dates from strings. It is also the format that TanStack Time will use to represent dates as strings. + +## Date/Time Parts + +The RFC3339 standard allows for the following date/time parts: + +> [4 digit year[-2 digit month[-2 digit day]]][separator (t|T|" ")][2 digit hour[:2 digit minute[:2 digit second[.3 digit millisecond]]]][timezone/offset(z|Z|[(+|-)2 digit hour[:2 digit minute]])] + +In accordance with the standard, if 'T' is used as a separator it may be in upper or lower case. If 'Z' is used as a timezone/offset, it may be in upper or lower case. The 'Z' timezone/offset is often referred to as 'Zulu' time, and represents UTC. + +## Deviating From the RFC3339 Standard, and Why + +For developers utilizing a fully qualified RFC3339 Internet Date/Time Format string, including timezone or offset, the parser will parse the string according to standard. However there are some caveats to the standard that the parser should correct. + +There are irregularities in the way a date instance is created from an RFC3339 string, compared to what most developers believe the string to represent. For example, look at the following example: + +```javascript +const formatter = new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + fractionalSecondDigits: 3, + timeZoneName: 'short', +}) +const dateString = '2024-12-14' +const date = new Date(dateString) +// a browser in the Eastern Time Zone will return: +// Fri Dec 13 2024 19:00:00 GMT-0500 (Eastern Standard Time) +formatter.format(date) +// "12/13/2024, 7:00:00 PM EST" +const dateString2 = '2024-12-14T00:00:00' +const date2 = new Date(dateString2) +// a browser in the Eastern Time Zone will return: +// Sat Dec 14 2024 00:00:00 GMT-0500 (Eastern Standard Time) +formatter.format(date2) +// "12/14/2024, 12:00:00 AM EST" +``` + +The valid RFC3339 string of `2024-12-14` is meant to represent "December 14, 2024", however according to the standard all parts are relative to UTC date/time, and later interpreted to the browser local timezone. A developer would consider this to be the beginning of the day, for the timezone of the user, since no time or timezone/offset is specified. However, the Date object will interpret this as "December 13, 2024" at 7:00 PM, for a browser in the Eastern Time Zone. This is because the Date object will interpret the string as a UTC date, and then convert it to the local time zone. This is a major area of confusion for developers, and not the behavior that a developer would expect, and the behavior that the parser should correct. + +A parser should parse an RFC3339 string according to what date parts have been supplied. A valid RFC3339 string considers all date parts to be optional (aside from year), and the parser should interpret the string as such. If a date part is not supplied, the parser should assume the beginning for that part. If a time part is not supplied, the parser should assume the beginning of the day. If a timezone/offset part is not supplied, the parser should assume the local time zone. This is the behavior that the parser will implement. + +There are some caveats: + +- If a day is supplied, month and year are required. +- If a month is supplied, year is required. +- If a time is supplied, a full date (day, month and year) is required. +- If milliseconds are supplied, seconds, minutes and hours are required. +- If seconds are supplied, minutes and hours are required. +- If minutes are supplied, hours are required. + +The RFC3339 standard does not allow for the inclusion of timezone/offset without a time part. However, the parser will allow for that, and assume the beginning of the day, and the given time zone. In this scenario, the timezone/offset must be preceded by the date/time separator. + +## Dealing With Only "Time" + +The Date object does not have facility for "only a time", without a date. However, the parser will allow for a "plain time" string in the format `HH:MM:SS.SSS` (hours, minutes, seconds, milliseconds). The parser will create a Date with the current 'date' of the browser, and the given time. The timezone/offset will always be assumed to be the local time zone. + +This allows for using the Intl.DateTimeFormat to format the time, and the parser to parse the time, without having to worry about the date. + +This also allows for the internal creation of Temporal.PlainTime objects, which will be used in the future for time only manipulation. + +## Parser output + +The parser is used internal to TanStack Time, to interpret the given input for future manipulation and output. While the parser will be publicly available from the API, it is not intended to be used as a general purpose date parser. The public API is available for the creation of other parsers. It is intended to be used to parse dates in the formats that TanStack Time will use to manipulate dates and times. + +All other public API methods will typically return RFC3339 strings representing a date/time instance (UTC), or formatted representations of the date/time instance, according to the formatter configuration. diff --git a/packages/time/src/date/startOf/index.ts b/packages/time/src/date/startOf/index.ts new file mode 100644 index 00000000..23ad55a2 --- /dev/null +++ b/packages/time/src/date/startOf/index.ts @@ -0,0 +1 @@ +export * from './startOf' diff --git a/packages/time/src/date/startOf/startOf.ts b/packages/time/src/date/startOf/startOf.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/time/src/date/startOf/tests/startOf.test.ts b/packages/time/src/date/startOf/tests/startOf.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/time/src/date/validateDate.ts b/packages/time/src/date/validateDate.ts new file mode 100644 index 00000000..b98df219 --- /dev/null +++ b/packages/time/src/date/validateDate.ts @@ -0,0 +1,27 @@ +import { isValidDate } from './isValidDate' +import { parse as parser } from './parse' + +export interface ValidateDateOptions { + date: string | number | Date + parse?: (value: string | number | Date) => Date | undefined + errorMessage?: string +} + +/** + * validateDate + * Verifies if a date is, or can be, a valid JS Date object + * @param {string | number | Date} date - a value that can be converted to a Date object + * @param {string} errorMessage - error message to throw if date is invalid + * @returns Date + */ +export function validateDate({ + date, + parse = parser, + errorMessage = `Invalid Date: "${date}"`, +}: ValidateDateOptions): Date { + const d = parse(date) + if (!isValidDate(d)) { + throw new Error(`${errorMessage}: "${date}"`) + } + return d +} diff --git a/packages/time/src/formatter/buildDateFormatter/buildDateFormatter.ts b/packages/time/src/formatter/buildDateFormatter/buildDateFormatter.ts new file mode 100644 index 00000000..576a6ee7 --- /dev/null +++ b/packages/time/src/formatter/buildDateFormatter/buildDateFormatter.ts @@ -0,0 +1,40 @@ +import { getDefaultLocale, normalizeLocale } from '../../date/dateDefaults' +import { extractLocaleOptions } from '../extractLocaleOptions' +import type { DateFormatterBuildParams, DateFormatterOptions } from '../shared' + +/** + * Function: buildDateFormatter + * This function is used to build a date only formatter, using the Intl.DateTimeFormat constructor. + * The 'locale' named parameter can be a string, an Intl.Locale object, or an array of strings + * or Intl.Locale objects. This is defaulted to the user's browser locale. + * + * The 'options' named parameter can be a string or an object. + * + * If 'options' is a string, it will be used as the 'dateStyle' option. + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#datestyle as reference. + * + * If 'options' is an object, it will use the Intl.DateTimeFormat 'options'. + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options as reference. + * + * You use the 'options' object for finer level of control over the date formatting. + * When using UTC date strings, it is suggested that you use the 'options' object + * to set the 'timeZone' when building the formatter. The 'timeZone' is defaulted + * to the user's browser timezone. + * @param {DateFormatterBuildParams} [param0] + * @returns Intl.DateTimeFormat + */ +export function buildDateFormatter({ + locale = getDefaultLocale(), + options, +}: DateFormatterBuildParams): Intl.DateTimeFormat { + const normalizedLocale = normalizeLocale(locale) + const opts = + typeof options === 'string' ? { dateStyle: options } : (options ?? {}) + const { formatOptions = {}, ...localeOptions } = extractLocaleOptions(opts) + const { dateStyle, ...rest } = formatOptions as DateFormatterOptions + const newOptions = { + ...localeOptions, + ...(dateStyle ? { dateStyle } : rest), + } + return new Intl.DateTimeFormat(normalizedLocale, newOptions) +} diff --git a/packages/time/src/formatter/buildDateFormatter/index.ts b/packages/time/src/formatter/buildDateFormatter/index.ts new file mode 100644 index 00000000..c6394c6c --- /dev/null +++ b/packages/time/src/formatter/buildDateFormatter/index.ts @@ -0,0 +1 @@ +export * from './buildDateFormatter' diff --git a/packages/time/src/formatter/buildDateTimeFormatter/buildDateTimeFormatter.ts b/packages/time/src/formatter/buildDateTimeFormatter/buildDateTimeFormatter.ts new file mode 100644 index 00000000..11be878d --- /dev/null +++ b/packages/time/src/formatter/buildDateTimeFormatter/buildDateTimeFormatter.ts @@ -0,0 +1,54 @@ +import { getDefaultLocale, normalizeLocale } from '../../date/dateDefaults' +import { extractLocaleOptions } from '../extractLocaleOptions' +import type { + DateTimeFormatterBuildParams, + DateTimeFormatterOptions, +} from '../shared' + +/** + * @typedef {string | Intl.Locale | string[] | Intl.Locale[]} Locale + * + * @typedef {Object} DateTimeFormatterOptions + * @property {Locale} [locale] + * @property {string | DateFormatterOptions} [options] + */ + +/** + * Function: buildDateTimeFormatter + * This function is used to build a date and time formatter, using the Intl.DateTimeFormat constructor. + * The 'locale' named parameter can be a string, an Intl.Locale object, or an array of strings + * or Intl.Locale objects. This is defaulted to the user's browser locale. + * + * The 'options' named parameter can be a string or an object. + * + * If 'options' is a string, it will be used as the 'dateStyle' and 'timeStyle' options. + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#datestyle and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#timestyle as reference. + * + * If 'options' is an object, it will use the Intl.DateTimeFormat 'options'. + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options as reference. + * + * You use the 'options' object for finer level of control over the time formatting. + * When using UTC date strings, it is suggested that you use the 'options' object + * to set the 'timeZone' when building the formatter. The 'timeZone' is defaulted + * to the user's browser timezone. + * @param {DateTimeFormatterBuildParams} [param0] + * @returns Intl.DateTimeFormat + */ +export function buildDateTimeFormatter({ + locale = getDefaultLocale(), + options, +}: DateTimeFormatterBuildParams): Intl.DateTimeFormat { + const normalizedLocale = normalizeLocale(locale) + const opts = + typeof options === 'string' + ? { dateStyle: options, timeStyle: options } + : (options ?? {}) + const { formatOptions = {}, ...localeOptions } = extractLocaleOptions(opts) + const { dateStyle, timeStyle, ...rest } = + formatOptions as DateTimeFormatterOptions + const newOptions = { + ...localeOptions, + ...(dateStyle && timeStyle ? { dateStyle, timeStyle } : rest), + } + return new Intl.DateTimeFormat(normalizedLocale, newOptions) +} diff --git a/packages/time/src/formatter/buildDateTimeFormatter/index.ts b/packages/time/src/formatter/buildDateTimeFormatter/index.ts new file mode 100644 index 00000000..e178416c --- /dev/null +++ b/packages/time/src/formatter/buildDateTimeFormatter/index.ts @@ -0,0 +1 @@ +export * from './buildDateTimeFormatter' diff --git a/packages/time/src/formatter/buildFinalFormatter/buildFinalFormatter.ts b/packages/time/src/formatter/buildFinalFormatter/buildFinalFormatter.ts new file mode 100644 index 00000000..d843b6bd --- /dev/null +++ b/packages/time/src/formatter/buildFinalFormatter/buildFinalFormatter.ts @@ -0,0 +1,45 @@ +import { validateDate } from '../../date/validateDate' +import { parse as parser } from '../../date/parse' + +export interface BuildFinalFormatterOptions { + formatter: Intl.DateTimeFormat + formatterName: string + parse?: (value: string | number | Date) => Date | undefined + forRange?: boolean +} + +/** + * buildFinalFormatter - takes an Intl.DateTimeFormat object and returns a + * basic format function. When calling the format function, it will validate + * the given input date(s) and return the formatted date string. + */ +export function buildFinalFormatter({ + formatter, + formatterName, + parse = parser, + forRange = false, +}: BuildFinalFormatterOptions): ( + date: string | number | Date, + date2?: string | number | Date, +) => string { + return ( + date: string | number | Date, + date2?: string | number | Date, + ): string => { + if (!date) return '' + const trueDate = validateDate({ + date, + parse, + errorMessage: `[${formatterName}] date "${date}" is Invalid.`, + }) + if (!forRange || !date2) { + return formatter.format(trueDate) + } + const endDate = validateDate({ + date: date2, + parse, + errorMessage: `[${formatterName}] second date "${date2}" is Invalid.`, + }) + return formatter.formatRange(trueDate, endDate) + } +} diff --git a/packages/time/src/formatter/buildFinalFormatter/index.ts b/packages/time/src/formatter/buildFinalFormatter/index.ts new file mode 100644 index 00000000..be621692 --- /dev/null +++ b/packages/time/src/formatter/buildFinalFormatter/index.ts @@ -0,0 +1 @@ +export * from './buildFinalFormatter' diff --git a/packages/time/src/formatter/buildFinalFormatter/tests/buildFinalFormatter.test.ts b/packages/time/src/formatter/buildFinalFormatter/tests/buildFinalFormatter.test.ts new file mode 100644 index 00000000..b71a5144 --- /dev/null +++ b/packages/time/src/formatter/buildFinalFormatter/tests/buildFinalFormatter.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, test } from 'vitest' +import { buildFinalFormatter } from '../buildFinalFormatter' + +const dateTimeFormat = new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + timeZoneName: 'short', + timeZone: 'America/New_York', +}) + +const timeOnlyFormat = new Intl.DateTimeFormat('en-US', { + hour: '2-digit', + minute: '2-digit', + // second: '2-digit', + // timeZoneName: 'short', + timeZone: 'America/New_York', +}) + +describe('buildFinalFormatter', () => { + test('should format a date string', () => { + const format = buildFinalFormatter({ + formatter: dateTimeFormat, + formatterName: 'dateTimeFormat', + }) + expect(format('2021-03-12T14:42')).toBe('03/12/2021, 02:42:00 PM EST') + }) + + test('should format a time string range', () => { + const timeFormat = buildFinalFormatter({ + formatter: timeOnlyFormat, + formatterName: 'timeOnlyFormat', + forRange: true, + }) + // output does not show 2-digit hour in range due to a bug in Intl.DateTimeFormat.formatRange + expect(timeFormat('2021-03-12T14:42', '2021-03-12T15:42')).toBe( + '2:42 – 3:42 PM', + ) + }) +}) diff --git a/packages/time/src/formatter/buildTimeFormatter/buildTimeFormatter.ts b/packages/time/src/formatter/buildTimeFormatter/buildTimeFormatter.ts new file mode 100644 index 00000000..605a28ba --- /dev/null +++ b/packages/time/src/formatter/buildTimeFormatter/buildTimeFormatter.ts @@ -0,0 +1,40 @@ +import { getDefaultLocale, normalizeLocale } from '../../date/dateDefaults' +import { extractLocaleOptions } from '../extractLocaleOptions' +import type { TimeFormatterBuildParams, TimeFormatterOptions } from '../shared' + +/** + * Function: buildTimeFormatter + * This function is used to build a time only formatter, using the Intl.DateTimeFormat constructor. + * The 'locale' named parameter can be a string, an Intl.Locale object, or an array of strings + * or Intl.Locale objects. This is defaulted to the user's browser locale. + * + * The 'options' named parameter can be a string or an object. + * + * If 'options' is a string, it will be used as the 'timeStyle' option. + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#timestyle as reference. + * + * If 'options' is an object, it will use the Intl.DateTimeFormat 'options'. + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options as reference. + * + * You use the 'options' object for finer level of control over the time formatting. + * When using UTC date strings, it is suggested that you use the 'options' object + * to set the 'timeZone' when building the formatter. The 'timeZone' is defaulted + * to the user's browser timezone. + * @param {TimeFormatterBuildParams} [param0] + * @returns Intl.DateTimeFormat + */ +export function buildTimeFormatter({ + locale = getDefaultLocale(), + options, +}: TimeFormatterBuildParams): Intl.DateTimeFormat { + const normalizedLocale = normalizeLocale(locale) + const opts = + typeof options === 'string' ? { dateStyle: options } : (options ?? {}) + const { formatOptions = {}, ...localeOptions } = extractLocaleOptions(opts) + const { timeStyle, ...rest } = formatOptions as TimeFormatterOptions + const newOptions = { + ...localeOptions, + ...(timeStyle ? { timeStyle } : rest), + } + return new Intl.DateTimeFormat(normalizedLocale, newOptions) +} diff --git a/packages/time/src/formatter/buildTimeFormatter/index.ts b/packages/time/src/formatter/buildTimeFormatter/index.ts new file mode 100644 index 00000000..2d212871 --- /dev/null +++ b/packages/time/src/formatter/buildTimeFormatter/index.ts @@ -0,0 +1 @@ +export * from './buildTimeFormatter' diff --git a/packages/time/src/formatter/extractLocaleOptions.ts b/packages/time/src/formatter/extractLocaleOptions.ts new file mode 100644 index 00000000..1478f454 --- /dev/null +++ b/packages/time/src/formatter/extractLocaleOptions.ts @@ -0,0 +1,91 @@ +import { getDefaultCalendar, getDefaultTimeZone } from '../date/dateDefaults' +import type { + DateFormatterOptions, + DateTimeFormatterOptions, + TimeFormatterOptions, +} from './shared' + +/** + * @typedef {Object} DateFormatterOptions + * @property {string} [localeMatcher] + * @property {string} [calendar] + * @property {string} [numberingSystem] + * @property {boolean} [hour12] + * @property {string} [hourCycle] + * @property {string} [timeZone] + * @property {string} [formatMatcher] + * @property {string} [weekday] + * @property {string} [era] + * @property {string} [year] + * @property {string} [month] + * @property {string} [day] + * @property {string} [dateStyle] + * + * @typedef {Object} TimeFormatterOptions + * @property {string} [localeMatcher] + * @property {string} [calendar] + * @property {string} [numberingSystem] + * @property {boolean} [hour12] + * @property {string} [hourCycle] + * @property {string} [timeZone] + * @property {string} [formatMatcher] + * @property {string} [dayPeriod] + * @property {string} [hour] + * @property {string} [minute] + * @property {string} [second] + * @property {number} [fractionalSecondDigits] + * @property {string} [timeZoneName] + * @property {string} [timeStyle] + * + * @typedef {Object} DateTimeFormatterOptions + * @property {string} [localeMatcher] + * @property {string} [calendar] + * @property {string} [numberingSystem] + * @property {boolean} [hour12] + * @property {string} [hourCycle] + * @property {string} [timeZone] + * @property {string} [formatMatcher] + * @property {string} [weekday] + * @property {string} [era] + * @property {string} [year] + * @property {string} [month] + * @property {string} [day] + * @property {string} [dateStyle] + * @property {string} [dayPeriod] + * @property {string} [hour] + * @property {string} [minute] + * @property {string} [second] + * @property {number} [fractionalSecondDigits] + * @property {string} [timeZoneName] + * @property {string} [timeStyle] + */ + +/** + * Function: extractLocaleOptions + * This function is used to extract the locale options from the 'options' parameter of the various + * formatter 'build' functions. + * + * If 'calender' or 'timeZone' are not provided, the default values provided by the + * Intl.DateTimeFormat().resolvedOptions() are used. + * @param {DateFormatterOptions | DateTimeFormatterOptions | TimeFormatterOptions} param0 + * @returns + */ +export function extractLocaleOptions({ + localeMatcher, + calendar = getDefaultCalendar(), + numberingSystem, + hour12, + hourCycle, + timeZone = getDefaultTimeZone(), + ...formatOptions +}: DateFormatterOptions | DateTimeFormatterOptions | TimeFormatterOptions) { + return { + localeMatcher, + calendar, + numberingSystem, + hour12, + hourCycle, + timeZone, + formatOptions, + } +} diff --git a/packages/time/src/formatter/shared.ts b/packages/time/src/formatter/shared.ts new file mode 100644 index 00000000..122f6f05 --- /dev/null +++ b/packages/time/src/formatter/shared.ts @@ -0,0 +1,60 @@ +export interface LocaleFormatterOptions { + localeMatcher?: 'lookup' | 'best fit' + calendar?: string + numberingSystem?: string + hour12?: boolean + hourCycle?: 'h11' | 'h12' | 'h23' | 'h24' + timeZone?: string +} + +type FormatStyle = 'full' | 'long' | 'medium' | 'short' + +export type Locale = string | Intl.Locale | Array | Array + +export interface DateFormatterOptions extends LocaleFormatterOptions { + formatMatcher?: 'basic' | 'best fit' + weekday?: 'narrow' | 'short' | 'long' + era?: 'narrow' | 'short' | 'long' + year?: '2-digit' | 'numeric' + month?: '2-digit' | 'numeric' | 'narrow' | 'short' | 'long' + day?: '2-digit' | 'numeric' + // style shortcuts + dateStyle?: FormatStyle +} + +export interface TimeFormatterOptions extends LocaleFormatterOptions { + formatMatcher?: 'basic' | 'best fit' + dayPeriod?: 'narrow' | 'short' | 'long' + hour?: '2-digit' | 'numeric' + minute?: '2-digit' | 'numeric' + second?: '2-digit' | 'numeric' + fractionalSecondDigits?: 1 | 2 | 3 + timeZoneName?: + | 'short' + | 'long' + | 'shortOffset' + | 'longOffset' + | 'shortGeneric' + | 'longGeneric' + // style shortcuts + timeStyle?: FormatStyle +} + +export interface DateTimeFormatterOptions + extends DateFormatterOptions, + TimeFormatterOptions {} + +export interface DateFormatterBuildParams { + locale?: Locale + options?: FormatStyle | DateFormatterOptions +} + +export interface TimeFormatterBuildParams { + locale?: Locale + options?: FormatStyle | TimeFormatterOptions +} + +export interface DateTimeFormatterBuildParams { + locale?: Locale + options?: FormatStyle | DateTimeFormatterOptions +} diff --git a/packages/time/src/polyfills/getWeekInfo.ts b/packages/time/src/polyfills/getWeekInfo.ts new file mode 100644 index 00000000..c9df49e8 --- /dev/null +++ b/packages/time/src/polyfills/getWeekInfo.ts @@ -0,0 +1,38 @@ +import type { WeekInfo } from "./types"; + +const normalizeLocale = (loc: string) => { + const [lang, region] = loc.split('-') + return region ? `${lang?.toLowerCase()}-${region.toUpperCase()}` : lang?.toLowerCase() +} + +;(function () { + if ('weekInfo' in Intl.Locale.prototype && typeof Intl.Locale.prototype.getWeekInfo !== 'function') { + Intl.Locale.prototype.getWeekInfo = function () { + return this.weekInfo + } + } + + if (typeof Intl.Locale.prototype.getWeekInfo !== 'function') { + import('./weekInfoData').then(({ weekInfoData }) => { + Intl.Locale.prototype.getWeekInfo = function () { + const locale = this.toString() + const normalizedLocale = normalizeLocale(locale) + + let match: WeekInfo | undefined = weekInfoData[normalizedLocale ?? ''] + + if (!match) { + const mainLanguage = normalizedLocale?.split('-')[0] + match = weekInfoData[mainLanguage ?? ''] + } + + if (!match) { + match = Object.entries(weekInfoData).find(([key]) => + normalizeLocale(key) === normalizedLocale + )?.[1] + } + + return match + } + }) + } +})() \ No newline at end of file diff --git a/packages/time/src/polyfills/types.ts b/packages/time/src/polyfills/types.ts new file mode 100644 index 00000000..0f9a20a1 --- /dev/null +++ b/packages/time/src/polyfills/types.ts @@ -0,0 +1,15 @@ +export interface WeekInfo { + firstDay: number + weekend: Array + minimalDays: number +} + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Intl { + interface Locale { + getWeekInfo: () => WeekInfo + weekInfo?: WeekInfo + } + } +} diff --git a/packages/time/src/polyfills/weekInfoData.ts b/packages/time/src/polyfills/weekInfoData.ts new file mode 100644 index 00000000..59f77021 --- /dev/null +++ b/packages/time/src/polyfills/weekInfoData.ts @@ -0,0 +1,714 @@ +import type { WeekInfo } from "./types"; + +export const weekInfoData: Record = { + aa: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "aa-DJ": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + "aa-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ab: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + af: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "af-NA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + agq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ak: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + am: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + an: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ann: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + apc: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + ar: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-AE": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + "ar-BH": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-DJ": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + "ar-DZ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-EG": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-EH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-IL": { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + "ar-IQ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-JO": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-KM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-KW": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-LB": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-LY": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-MA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-MR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-OM": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-PS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-QA": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-SA": { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + "ar-SD": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-SO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-SS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-SY": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ar-TD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-TN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ar-YE": { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + arn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + as: { firstDay: 7, weekend: [7], minimalDays: 1 }, + asa: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ast: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + az: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "az-Arab": { firstDay: 6, weekend: [5], minimalDays: 1 }, + "az-Arab-IQ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "az-Arab-TR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "az-Cyrl": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "az-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ba: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + bal: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "bal-Arab": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "bal-Latn": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + bas: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + be: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "be-tarask": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bem: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bew: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + bez: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bg: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + bgc: { firstDay: 7, weekend: [7], minimalDays: 1 }, + bgn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "bgn-AE": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + "bgn-AF": { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, + "bgn-IR": { firstDay: 6, weekend: [5], minimalDays: 1 }, + "bgn-OM": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + bho: { firstDay: 7, weekend: [7], minimalDays: 1 }, + blo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + blt: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bm: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "bm-Nkoo": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "bn-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, + bo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "bo-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, + br: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + brx: { firstDay: 7, weekend: [7], minimalDays: 1 }, + bs: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "bs-Cyrl": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "bs-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bss: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + byn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ca: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "ca-AD": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "ca-ES-valencia": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "ca-FR": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "ca-IT": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + cad: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + cch: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ccp: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "ccp-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, + ce: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ceb: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + cgg: { firstDay: 1, weekend: [7], minimalDays: 1 }, + cho: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + chr: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + cic: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ckb: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ckb-IR": { firstDay: 6, weekend: [5], minimalDays: 1 }, + co: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + cs: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + csw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + cu: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + cv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + cy: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + da: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "da-GL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + dav: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + de: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "de-AT": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "de-BE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "de-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "de-IT": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "de-LI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "de-LU": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + dje: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + doi: { firstDay: 7, weekend: [7], minimalDays: 1 }, + dsb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + dua: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + dv: { firstDay: 5, weekend: [6, 7], minimalDays: 1 }, + dyo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + dz: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ebu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ee: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ee-TG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + el: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "el-CY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "el-polyton": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + en: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-001": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-150": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-AE": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + "en-AG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-AI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-AS": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-AT": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-AU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-BB": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-BE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-BI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-BM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-BS": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-BW": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-BZ": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-CA": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-CC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-CK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-CM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-CX": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-CY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-DE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-DG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-DK": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-DM": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-Dsrt": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-FI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-FJ": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-FK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-FM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-GB": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-GD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-GG": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-GH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-GI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-GM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-GU": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-GY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-HK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-ID": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-IE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-IL": { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + "en-IM": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, + "en-IO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-JE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-JM": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-KI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-KN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-KY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-LC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-LR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-LS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-MG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-MH": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-MO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-MP": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-MS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-MT": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-MU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-MV": { firstDay: 5, weekend: [6, 7], minimalDays: 1 }, + "en-MW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-MY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-NA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-NF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-NG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-NL": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-NR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-NU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-NZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-PG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-PH": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-PK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-PN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-PR": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-PW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-RW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-SB": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-SC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-SD": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "en-SE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-SG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-SH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-SI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-SL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-SS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-SX": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-SZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-Shaw": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "en-TC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-TK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-TO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-TT": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-TV": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-TZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-UG": { firstDay: 1, weekend: [7], minimalDays: 1 }, + "en-UM": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-VC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-VG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-VI": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-VU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-WS": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-ZA": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "en-ZM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "en-ZW": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + eo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + es: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "es-419": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-AR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-BO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-BR": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-BZ": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-CL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-CO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-CR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-CU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-DO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-EA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-EC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-GQ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-GT": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-HN": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-IC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-MX": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-NI": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-PA": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-PE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-PH": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-PR": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-PY": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-SV": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-US": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "es-UY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "es-VE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + et: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + eu: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ewo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + fa: { firstDay: 6, weekend: [5], minimalDays: 1 }, + "fa-AF": { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, + ff: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-BF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-CM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-GH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-GM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-GW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-LR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-MR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-NE": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-NG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-SL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Adlm-SN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-BF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-CM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-GH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-GM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-GN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-GW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-LR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-MR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-NE": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-NG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ff-Latn-SL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + fi: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + fil: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + fo: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fo-DK": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + fr: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fr-BE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fr-BF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-BI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-BJ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-BL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-CA": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "fr-CD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-CF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-CG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fr-CI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-CM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-DJ": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + "fr-DZ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "fr-GA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-GF": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fr-GN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-GP": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fr-GQ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-HT": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-KM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-LU": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fr-MA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-MC": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fr-MF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-MG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-ML": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-MQ": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fr-MR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-MU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-NC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-NE": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-PF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-PM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-RE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "fr-RW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-SC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-SN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-SY": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "fr-TD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-TG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-TN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-VU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-WF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "fr-YT": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + frr: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + fur: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + fy: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ga: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "ga-GB": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + gaa: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + gd: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + gez: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "gez-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + gl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + gn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + gsw: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "gsw-FR": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "gsw-LI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + gu: { firstDay: 7, weekend: [7], minimalDays: 1 }, + guz: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + gv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ha: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ha-Arab": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ha-Arab-SD": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "ha-GH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ha-NE": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + haw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + he: { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + hi: { firstDay: 7, weekend: [7], minimalDays: 1 }, + "hi-Latn": { firstDay: 7, weekend: [7], minimalDays: 1 }, + hnj: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "hnj-Hmnp": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + hr: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "hr-BA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + hsb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + hu: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + hy: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ia: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + id: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ie: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ig: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ii: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + io: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + is: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + it: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "it-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "it-SM": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "it-VA": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + iu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "iu-Latn": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ja: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + jbo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + jgo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + jmc: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + jv: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ka: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kab: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + kaj: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kam: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + kcg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kde: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kea: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ken: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kgp: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + khq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ki: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + kk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kkj: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kl: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kln: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + km: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + kn: { firstDay: 7, weekend: [7], minimalDays: 1 }, + ko: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "ko-CN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ko-KP": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kok: { firstDay: 7, weekend: [7], minimalDays: 1 }, + kpe: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "kpe-GN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ks: { firstDay: 7, weekend: [7], minimalDays: 1 }, + "ks-Arab": { firstDay: 7, weekend: [7], minimalDays: 1 }, + "ks-Deva": { firstDay: 7, weekend: [7], minimalDays: 1 }, + ksb: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ksf: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ksh: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ku: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kw: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + kxv: { firstDay: 7, weekend: [7], minimalDays: 1 }, + "kxv-Deva": { firstDay: 7, weekend: [7], minimalDays: 1 }, + "kxv-Latn": { firstDay: 7, weekend: [7], minimalDays: 1 }, + "kxv-Orya": { firstDay: 7, weekend: [7], minimalDays: 1 }, + "kxv-Telu": { firstDay: 7, weekend: [7], minimalDays: 1 }, + ky: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + la: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + lag: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + lb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + lg: { firstDay: 1, weekend: [7], minimalDays: 1 }, + lij: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + lkt: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + lmo: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ln: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ln-AO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ln-CF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ln-CG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + lo: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + lrc: { firstDay: 6, weekend: [5], minimalDays: 1 }, + "lrc-IQ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + lt: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + lu: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + luo: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + luy: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + lv: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mai: { firstDay: 7, weekend: [7], minimalDays: 1 }, + mas: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "mas-TZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mdf: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + mer: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mfe: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mgh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mgo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mic: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ml: { firstDay: 7, weekend: [7], minimalDays: 1 }, + mn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "mn-Mong": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "mn-Mong-MN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mni: { firstDay: 7, weekend: [7], minimalDays: 1 }, + "mni-Beng": { firstDay: 7, weekend: [7], minimalDays: 1 }, + "mni-Mtei": { firstDay: 7, weekend: [7], minimalDays: 1 }, + moh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mr: { firstDay: 7, weekend: [7], minimalDays: 1 }, + ms: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ms-Arab": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ms-Arab-BN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ms-BN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ms-ID": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "ms-SG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mt: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mua: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mus: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + my: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + myv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + mzn: { firstDay: 6, weekend: [5], minimalDays: 1 }, + naq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "nb-SJ": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + nd: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + nds: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "nds-NL": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ne: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "ne-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, + nl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "nl-AW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "nl-BE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "nl-BQ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "nl-CW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "nl-SR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "nl-SX": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nmg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nn: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + nnh: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + no: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + nqo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nr: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + nso: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + nus: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nv: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ny: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nyn: { firstDay: 1, weekend: [7], minimalDays: 1 }, + oc: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "oc-ES": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + om: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "om-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + or: { firstDay: 7, weekend: [7], minimalDays: 1 }, + os: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "os-RU": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + osa: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + pa: { firstDay: 7, weekend: [7], minimalDays: 1 }, + "pa-Arab": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "pa-Guru": { firstDay: 7, weekend: [7], minimalDays: 1 }, + pap: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "pap-AW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + pcm: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + pis: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + pl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + prg: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ps: { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, + "ps-PK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + pt: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "pt-AO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "pt-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "pt-CV": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "pt-GQ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "pt-GW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "pt-LU": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "pt-MO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "pt-MZ": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "pt-PT": { firstDay: 7, weekend: [6, 7], minimalDays: 4 }, + "pt-ST": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "pt-TL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + qu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "qu-BO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "qu-EC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + quc: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + raj: { firstDay: 7, weekend: [7], minimalDays: 1 }, + rhg: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "rhg-Rohg": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "rhg-Rohg-BD": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + rif: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + rm: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + rn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ro: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ro-MD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + rof: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ru: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "ru-BY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ru-KG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ru-KZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ru-MD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ru-UA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + rw: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + rwk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sa: { firstDay: 7, weekend: [7], minimalDays: 1 }, + sah: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + saq: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sat: { firstDay: 7, weekend: [7], minimalDays: 1 }, + "sat-Deva": { firstDay: 7, weekend: [7], minimalDays: 1 }, + "sat-Olck": { firstDay: 7, weekend: [7], minimalDays: 1 }, + sbp: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sc: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + scn: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + sd: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "sd-Arab": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "sd-Deva": { firstDay: 7, weekend: [7], minimalDays: 1 }, + sdh: { firstDay: 6, weekend: [5], minimalDays: 1 }, + "sdh-IQ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + se: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "se-FI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "se-SE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + seh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ses: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + shi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "shi-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "shi-Tfng": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + shn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "shn-TH": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + si: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sid: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sk: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + skr: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sl: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sma: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "sma-NO": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + smj: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "smj-NO": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + smn: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + sms: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + sn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + so: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "so-DJ": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + "so-ET": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "so-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sq-MK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sq-XK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sr: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sr-Cyrl": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sr-Cyrl-BA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sr-Cyrl-ME": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sr-Cyrl-XK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sr-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sr-Latn-BA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sr-Latn-ME": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sr-Latn-XK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ss: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "ss-SZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ssy: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + st: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "st-LS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + su: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "su-Latn": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "sv-AX": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + "sv-FI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + sw: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sw-CD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "sw-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "sw-UG": { firstDay: 1, weekend: [7], minimalDays: 1 }, + syr: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + "syr-SY": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + szl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ta: { firstDay: 7, weekend: [7], minimalDays: 1 }, + "ta-LK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ta-MY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "ta-SG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + te: { firstDay: 7, weekend: [7], minimalDays: 1 }, + teo: { firstDay: 1, weekend: [7], minimalDays: 1 }, + "teo-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + tg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + th: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ti: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "ti-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tig: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "tn-BW": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + to: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tok: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tpi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tr: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "tr-CY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + trv: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + trw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ts: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + tt: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + twq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tyv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + tzm: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ug: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + uk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + und: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ur: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "ur-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, + uz: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "uz-Arab": { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, + "uz-Cyrl": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "uz-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + vai: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "vai-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "vai-Vaii": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ve: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + vec: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + vi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + vmw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + vo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + vun: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + wa: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + wae: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + wal: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + wbp: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + wo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + xh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + xnr: { firstDay: 7, weekend: [7], minimalDays: 1 }, + xog: { firstDay: 1, weekend: [7], minimalDays: 1 }, + yav: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + yi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + yo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "yo-BJ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + yrl: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "yrl-CO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "yrl-VE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + yue: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "yue-Hans": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "yue-Hant": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + za: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + zgh: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + zh: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "zh-Hans": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + "zh-Hans-HK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "zh-Hans-MO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "zh-Hans-SG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "zh-Hant": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "zh-Hant-HK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + "zh-Hant-MO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + zu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, +}; \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9cbc717e..ec318d2f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,10 @@ settings: importers: .: + dependencies: + '@js-temporal/polyfill': + specifier: ^0.5.1 + version: 0.5.1 devDependencies: '@changesets/cli': specifier: ^2.29.8 @@ -106,87 +110,6 @@ importers: specifier: ^7.3.1 version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) - examples/react/devtools: - dependencies: - '@tanstack/react-time': - specifier: ^0.0.0 - version: link:../../../packages/react-time - '@tanstack/react-time-devtools': - specifier: ^0.0.0 - version: link:../../../packages/react-time-devtools - '@tanstack/time': - specifier: ^0.0.0 - version: link:../../../packages/time - react: - specifier: ^19.2.3 - version: 19.2.3 - react-dom: - specifier: ^19.2.3 - version: 19.2.3(react@19.2.3) - devDependencies: - '@types/react': - specifier: ^19.2.8 - version: 19.2.8 - '@types/react-dom': - specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.8) - '@vitejs/plugin-react': - specifier: ^5.1.2 - version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) - typescript: - specifier: 5.9.3 - version: 5.9.3 - vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) - - examples/solid/basic: - dependencies: - '@tanstack/solid-time': - specifier: ^0.0.0 - version: link:../../../packages/solid-time - '@tanstack/time': - specifier: ^0.0.0 - version: link:../../../packages/time - solid-js: - specifier: ^1.9.10 - version: 1.9.10 - devDependencies: - typescript: - specifier: 5.9.3 - version: 5.9.3 - vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) - vite-plugin-solid: - specifier: ^2.11.10 - version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) - - examples/solid/devtools: - dependencies: - '@tanstack/solid-time': - specifier: ^0.0.0 - version: link:../../../packages/solid-time - '@tanstack/solid-time-devtools': - specifier: ^0.0.0 - version: link:../../../packages/solid-time-devtools - '@tanstack/time': - specifier: ^0.0.0 - version: link:../../../packages/time - solid-js: - specifier: ^1.9.10 - version: 1.9.10 - devDependencies: - typescript: - specifier: 5.9.3 - version: 5.9.3 - vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) - vite-plugin-solid: - specifier: ^2.11.10 - version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) - packages/react-time: dependencies: '@tanstack/react-store': @@ -798,6 +721,10 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@js-temporal/polyfill@0.5.1': + resolution: {integrity: sha512-hloP58zRVCRSpgDxmqCWJNlizAlUgJFqG2ypq79DCvyv9tHjRYMDOcPFjzfl/A1/YxDvRCZz8wvZvmapQnKwFQ==} + engines: {node: '>=12'} + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} @@ -2480,6 +2407,9 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jsbi@4.3.2: + resolution: {integrity: sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==} + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -4085,6 +4015,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@js-temporal/polyfill@0.5.1': + dependencies: + jsbi: 4.3.2 + '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.28.6 @@ -5721,6 +5655,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsbi@4.3.2: {} + jsesc@3.1.0: {} json-buffer@3.0.1: {} From 450aae7df915b7f724340ca355c66107d61fdd13 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 22:18:54 +0000 Subject: [PATCH 006/207] ci: apply automated fixes --- docs/reference/index.md | 6 - .../isValidDate/tests/isValidDate.test.ts | 18 +- packages/time/src/formatter/shared.ts | 3 +- packages/time/src/polyfills/getWeekInfo.ts | 17 +- packages/time/src/polyfills/weekInfoData.ts | 1424 ++++++++--------- 5 files changed, 733 insertions(+), 735 deletions(-) delete mode 100644 docs/reference/index.md diff --git a/docs/reference/index.md b/docs/reference/index.md deleted file mode 100644 index b14fbe49..00000000 --- a/docs/reference/index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -id: "@tanstack/time" -title: "@tanstack/time" ---- - -# @tanstack/time diff --git a/packages/time/src/date/isValidDate/tests/isValidDate.test.ts b/packages/time/src/date/isValidDate/tests/isValidDate.test.ts index 45d3d692..50778777 100644 --- a/packages/time/src/date/isValidDate/tests/isValidDate.test.ts +++ b/packages/time/src/date/isValidDate/tests/isValidDate.test.ts @@ -1,16 +1,16 @@ -import {describe, expect, test} from 'vitest'; -import {isValidDate} from '../isValidDate'; +import { describe, expect, test } from 'vitest' +import { isValidDate } from '../isValidDate' describe('isValidDate', () => { test('should return true for a valid date', () => { - expect(isValidDate(new Date())).toBe(true); + expect(isValidDate(new Date())).toBe(true) }) test('should return false for an invalid date', () => { - expect(isValidDate(new Date("invalid"))).toBe(false); - }); + expect(isValidDate(new Date('invalid'))).toBe(false) + }) - test("should return false for null", () => { - expect(isValidDate(null)).toBe(false); - }); -}); + test('should return false for null', () => { + expect(isValidDate(null)).toBe(false) + }) +}) diff --git a/packages/time/src/formatter/shared.ts b/packages/time/src/formatter/shared.ts index 122f6f05..70a7c4c7 100644 --- a/packages/time/src/formatter/shared.ts +++ b/packages/time/src/formatter/shared.ts @@ -41,8 +41,7 @@ export interface TimeFormatterOptions extends LocaleFormatterOptions { } export interface DateTimeFormatterOptions - extends DateFormatterOptions, - TimeFormatterOptions {} + extends DateFormatterOptions, TimeFormatterOptions {} export interface DateFormatterBuildParams { locale?: Locale diff --git a/packages/time/src/polyfills/getWeekInfo.ts b/packages/time/src/polyfills/getWeekInfo.ts index c9df49e8..8bd7dd55 100644 --- a/packages/time/src/polyfills/getWeekInfo.ts +++ b/packages/time/src/polyfills/getWeekInfo.ts @@ -1,12 +1,17 @@ -import type { WeekInfo } from "./types"; +import type { WeekInfo } from './types' const normalizeLocale = (loc: string) => { const [lang, region] = loc.split('-') - return region ? `${lang?.toLowerCase()}-${region.toUpperCase()}` : lang?.toLowerCase() + return region + ? `${lang?.toLowerCase()}-${region.toUpperCase()}` + : lang?.toLowerCase() } ;(function () { - if ('weekInfo' in Intl.Locale.prototype && typeof Intl.Locale.prototype.getWeekInfo !== 'function') { + if ( + 'weekInfo' in Intl.Locale.prototype && + typeof Intl.Locale.prototype.getWeekInfo !== 'function' + ) { Intl.Locale.prototype.getWeekInfo = function () { return this.weekInfo } @@ -26,8 +31,8 @@ const normalizeLocale = (loc: string) => { } if (!match) { - match = Object.entries(weekInfoData).find(([key]) => - normalizeLocale(key) === normalizedLocale + match = Object.entries(weekInfoData).find( + ([key]) => normalizeLocale(key) === normalizedLocale, )?.[1] } @@ -35,4 +40,4 @@ const normalizeLocale = (loc: string) => { } }) } -})() \ No newline at end of file +})() diff --git a/packages/time/src/polyfills/weekInfoData.ts b/packages/time/src/polyfills/weekInfoData.ts index 59f77021..39d39de6 100644 --- a/packages/time/src/polyfills/weekInfoData.ts +++ b/packages/time/src/polyfills/weekInfoData.ts @@ -1,714 +1,714 @@ -import type { WeekInfo } from "./types"; +import type { WeekInfo } from './types' export const weekInfoData: Record = { - aa: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "aa-DJ": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, - "aa-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ab: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - af: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "af-NA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - agq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ak: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - am: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - an: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ann: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - apc: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - ar: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-AE": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, - "ar-BH": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-DJ": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, - "ar-DZ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-EG": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-EH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-IL": { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, - "ar-IQ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-JO": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-KM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-KW": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-LB": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-LY": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-MA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-MR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-OM": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-PS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-QA": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-SA": { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, - "ar-SD": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-SO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-SS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-SY": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ar-TD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-TN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ar-YE": { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, - arn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - as: { firstDay: 7, weekend: [7], minimalDays: 1 }, - asa: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ast: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - az: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "az-Arab": { firstDay: 6, weekend: [5], minimalDays: 1 }, - "az-Arab-IQ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "az-Arab-TR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "az-Cyrl": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "az-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ba: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - bal: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "bal-Arab": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "bal-Latn": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - bas: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - be: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "be-tarask": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - bem: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - bew: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - bez: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - bg: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - bgc: { firstDay: 7, weekend: [7], minimalDays: 1 }, - bgn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "bgn-AE": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, - "bgn-AF": { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, - "bgn-IR": { firstDay: 6, weekend: [5], minimalDays: 1 }, - "bgn-OM": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - bho: { firstDay: 7, weekend: [7], minimalDays: 1 }, - blo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - blt: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - bm: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "bm-Nkoo": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - bn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "bn-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, - bo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "bo-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, - br: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - brx: { firstDay: 7, weekend: [7], minimalDays: 1 }, - bs: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "bs-Cyrl": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "bs-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - bss: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - byn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ca: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "ca-AD": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "ca-ES-valencia": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "ca-FR": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "ca-IT": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - cad: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - cch: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ccp: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "ccp-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, - ce: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ceb: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - cgg: { firstDay: 1, weekend: [7], minimalDays: 1 }, - cho: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - chr: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - cic: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ckb: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ckb-IR": { firstDay: 6, weekend: [5], minimalDays: 1 }, - co: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - cs: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - csw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - cu: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - cv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - cy: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - da: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "da-GL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - dav: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - de: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "de-AT": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "de-BE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "de-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "de-IT": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "de-LI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "de-LU": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - dje: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - doi: { firstDay: 7, weekend: [7], minimalDays: 1 }, - dsb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - dua: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - dv: { firstDay: 5, weekend: [6, 7], minimalDays: 1 }, - dyo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - dz: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ebu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ee: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ee-TG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - el: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "el-CY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "el-polyton": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - en: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-001": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-150": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-AE": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, - "en-AG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-AI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-AS": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-AT": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-AU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-BB": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-BE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-BI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-BM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-BS": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-BW": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-BZ": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-CA": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-CC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-CK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-CM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-CX": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-CY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-DE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-DG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-DK": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-DM": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-Dsrt": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-FI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-FJ": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-FK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-FM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-GB": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-GD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-GG": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-GH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-GI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-GM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-GU": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-GY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-HK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-ID": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-IE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-IL": { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, - "en-IM": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, - "en-IO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-JE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-JM": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-KI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-KN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-KY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-LC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-LR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-LS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-MG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-MH": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-MO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-MP": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-MS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-MT": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-MU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-MV": { firstDay: 5, weekend: [6, 7], minimalDays: 1 }, - "en-MW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-MY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-NA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-NF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-NG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-NL": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-NR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-NU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-NZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-PG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-PH": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-PK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-PN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-PR": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-PW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-RW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-SB": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-SC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-SD": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "en-SE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-SG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-SH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-SI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-SL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-SS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-SX": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-SZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-Shaw": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "en-TC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-TK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-TO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-TT": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-TV": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-TZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-UG": { firstDay: 1, weekend: [7], minimalDays: 1 }, - "en-UM": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-VC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-VG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-VI": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-VU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-WS": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-ZA": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "en-ZM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "en-ZW": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - eo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - es: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "es-419": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-AR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-BO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-BR": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-BZ": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-CL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-CO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-CR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-CU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-DO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-EA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-EC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-GQ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-GT": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-HN": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-IC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-MX": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-NI": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-PA": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-PE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-PH": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-PR": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-PY": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-SV": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-US": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "es-UY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "es-VE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - et: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - eu: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ewo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - fa: { firstDay: 6, weekend: [5], minimalDays: 1 }, - "fa-AF": { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, - ff: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-BF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-CM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-GH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-GM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-GW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-LR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-MR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-NE": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-NG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-SL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Adlm-SN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-BF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-CM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-GH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-GM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-GN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-GW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-LR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-MR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-NE": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-NG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ff-Latn-SL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - fi: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - fil: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - fo: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fo-DK": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - fr: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fr-BE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fr-BF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-BI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-BJ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-BL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-CA": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "fr-CD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-CF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-CG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fr-CI": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-CM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-DJ": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, - "fr-DZ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "fr-GA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-GF": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fr-GN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-GP": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fr-GQ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-HT": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-KM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-LU": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fr-MA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-MC": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fr-MF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-MG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-ML": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-MQ": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fr-MR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-MU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-NC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-NE": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-PF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-PM": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-RE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "fr-RW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-SC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-SN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-SY": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "fr-TD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-TG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-TN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-VU": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-WF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "fr-YT": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - frr: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - fur: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - fy: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ga: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "ga-GB": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - gaa: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - gd: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - gez: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "gez-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - gl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - gn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - gsw: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "gsw-FR": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "gsw-LI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - gu: { firstDay: 7, weekend: [7], minimalDays: 1 }, - guz: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - gv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ha: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ha-Arab": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ha-Arab-SD": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "ha-GH": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ha-NE": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - haw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - he: { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, - hi: { firstDay: 7, weekend: [7], minimalDays: 1 }, - "hi-Latn": { firstDay: 7, weekend: [7], minimalDays: 1 }, - hnj: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "hnj-Hmnp": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - hr: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "hr-BA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - hsb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - hu: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - hy: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ia: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - id: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ie: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ig: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ii: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - io: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - is: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - it: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "it-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "it-SM": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "it-VA": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - iu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "iu-Latn": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ja: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - jbo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - jgo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - jmc: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - jv: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ka: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kab: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - kaj: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kam: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - kcg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kde: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kea: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ken: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kgp: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - khq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ki: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - kk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kkj: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kl: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kln: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - km: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - kn: { firstDay: 7, weekend: [7], minimalDays: 1 }, - ko: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "ko-CN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ko-KP": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kok: { firstDay: 7, weekend: [7], minimalDays: 1 }, - kpe: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "kpe-GN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ks: { firstDay: 7, weekend: [7], minimalDays: 1 }, - "ks-Arab": { firstDay: 7, weekend: [7], minimalDays: 1 }, - "ks-Deva": { firstDay: 7, weekend: [7], minimalDays: 1 }, - ksb: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ksf: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ksh: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ku: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - kw: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - kxv: { firstDay: 7, weekend: [7], minimalDays: 1 }, - "kxv-Deva": { firstDay: 7, weekend: [7], minimalDays: 1 }, - "kxv-Latn": { firstDay: 7, weekend: [7], minimalDays: 1 }, - "kxv-Orya": { firstDay: 7, weekend: [7], minimalDays: 1 }, - "kxv-Telu": { firstDay: 7, weekend: [7], minimalDays: 1 }, - ky: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - la: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - lag: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - lb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - lg: { firstDay: 1, weekend: [7], minimalDays: 1 }, - lij: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - lkt: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - lmo: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ln: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ln-AO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ln-CF": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ln-CG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - lo: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - lrc: { firstDay: 6, weekend: [5], minimalDays: 1 }, - "lrc-IQ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - lt: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - lu: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - luo: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - luy: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - lv: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - mai: { firstDay: 7, weekend: [7], minimalDays: 1 }, - mas: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "mas-TZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - mdf: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - mer: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - mfe: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - mg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - mgh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - mgo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - mi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - mic: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - mk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ml: { firstDay: 7, weekend: [7], minimalDays: 1 }, - mn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "mn-Mong": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "mn-Mong-MN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - mni: { firstDay: 7, weekend: [7], minimalDays: 1 }, - "mni-Beng": { firstDay: 7, weekend: [7], minimalDays: 1 }, - "mni-Mtei": { firstDay: 7, weekend: [7], minimalDays: 1 }, - moh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - mr: { firstDay: 7, weekend: [7], minimalDays: 1 }, - ms: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ms-Arab": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ms-Arab-BN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ms-BN": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ms-ID": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "ms-SG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - mt: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - mua: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - mus: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - my: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - myv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - mzn: { firstDay: 6, weekend: [5], minimalDays: 1 }, - naq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - nb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "nb-SJ": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - nd: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - nds: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "nds-NL": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ne: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "ne-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, - nl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "nl-AW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "nl-BE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "nl-BQ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "nl-CW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "nl-SR": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "nl-SX": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - nmg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - nn: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - nnh: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - no: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - nqo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - nr: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - nso: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - nus: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - nv: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ny: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - nyn: { firstDay: 1, weekend: [7], minimalDays: 1 }, - oc: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "oc-ES": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - om: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "om-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - or: { firstDay: 7, weekend: [7], minimalDays: 1 }, - os: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "os-RU": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - osa: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - pa: { firstDay: 7, weekend: [7], minimalDays: 1 }, - "pa-Arab": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "pa-Guru": { firstDay: 7, weekend: [7], minimalDays: 1 }, - pap: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "pap-AW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - pcm: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - pis: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - pl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - prg: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ps: { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, - "ps-PK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - pt: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "pt-AO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "pt-CH": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "pt-CV": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "pt-GQ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "pt-GW": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "pt-LU": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "pt-MO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "pt-MZ": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "pt-PT": { firstDay: 7, weekend: [6, 7], minimalDays: 4 }, - "pt-ST": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "pt-TL": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - qu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "qu-BO": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "qu-EC": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - quc: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - raj: { firstDay: 7, weekend: [7], minimalDays: 1 }, - rhg: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "rhg-Rohg": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "rhg-Rohg-BD": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - rif: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - rm: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - rn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ro: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ro-MD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - rof: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ru: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "ru-BY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ru-KG": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ru-KZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ru-MD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ru-UA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - rw: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - rwk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - sa: { firstDay: 7, weekend: [7], minimalDays: 1 }, - sah: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - saq: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - sat: { firstDay: 7, weekend: [7], minimalDays: 1 }, - "sat-Deva": { firstDay: 7, weekend: [7], minimalDays: 1 }, - "sat-Olck": { firstDay: 7, weekend: [7], minimalDays: 1 }, - sbp: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - sc: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - scn: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - sd: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "sd-Arab": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "sd-Deva": { firstDay: 7, weekend: [7], minimalDays: 1 }, - sdh: { firstDay: 6, weekend: [5], minimalDays: 1 }, - "sdh-IQ": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - se: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "se-FI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "se-SE": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - seh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ses: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - sg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - shi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "shi-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "shi-Tfng": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - shn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "shn-TH": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - si: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - sid: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - sk: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - skr: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - sl: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - sma: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "sma-NO": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - smj: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "smj-NO": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - smn: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - sms: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - sn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - so: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "so-DJ": { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, - "so-ET": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "so-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - sq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sq-MK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sq-XK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - sr: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sr-Cyrl": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sr-Cyrl-BA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sr-Cyrl-ME": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sr-Cyrl-XK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sr-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sr-Latn-BA": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sr-Latn-ME": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sr-Latn-XK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ss: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "ss-SZ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ssy: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - st: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "st-LS": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - su: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "su-Latn": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - sv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "sv-AX": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - "sv-FI": { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - sw: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sw-CD": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "sw-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "sw-UG": { firstDay: 1, weekend: [7], minimalDays: 1 }, - syr: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - "syr-SY": { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, - szl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - ta: { firstDay: 7, weekend: [7], minimalDays: 1 }, - "ta-LK": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ta-MY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "ta-SG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - te: { firstDay: 7, weekend: [7], minimalDays: 1 }, - teo: { firstDay: 1, weekend: [7], minimalDays: 1 }, - "teo-KE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - tg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - th: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ti: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "ti-ER": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - tig: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - tk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - tn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "tn-BW": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - to: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - tok: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - tpi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - tr: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "tr-CY": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - trv: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - trw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ts: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - tt: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - twq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - tyv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - tzm: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ug: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - uk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - und: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - ur: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "ur-IN": { firstDay: 7, weekend: [7], minimalDays: 1 }, - uz: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "uz-Arab": { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, - "uz-Cyrl": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "uz-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - vai: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "vai-Latn": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "vai-Vaii": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - ve: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - vec: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - vi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - vmw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - vo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - vun: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - wa: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - wae: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, - wal: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - wbp: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - wo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - xh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - xnr: { firstDay: 7, weekend: [7], minimalDays: 1 }, - xog: { firstDay: 1, weekend: [7], minimalDays: 1 }, - yav: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - yi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - yo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "yo-BJ": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - yrl: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "yrl-CO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "yrl-VE": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - yue: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "yue-Hans": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "yue-Hant": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - za: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - zgh: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - zh: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "zh-Hans": { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, - "zh-Hans-HK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "zh-Hans-MO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "zh-Hans-SG": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "zh-Hant": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "zh-Hant-HK": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - "zh-Hant-MO": { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, - zu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, -}; \ No newline at end of file + aa: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'aa-DJ': { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + 'aa-ER': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ab: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + af: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'af-NA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + agq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ak: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + am: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + an: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ann: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + apc: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + ar: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-AE': { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + 'ar-BH': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-DJ': { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + 'ar-DZ': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-EG': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-EH': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-ER': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-IL': { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + 'ar-IQ': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-JO': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-KM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-KW': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-LB': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-LY': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-MA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-MR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-OM': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-PS': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-QA': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-SA': { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + 'ar-SD': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-SO': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-SS': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-SY': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ar-TD': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-TN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ar-YE': { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + arn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + as: { firstDay: 7, weekend: [7], minimalDays: 1 }, + asa: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ast: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + az: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'az-Arab': { firstDay: 6, weekend: [5], minimalDays: 1 }, + 'az-Arab-IQ': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'az-Arab-TR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'az-Cyrl': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'az-Latn': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ba: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + bal: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'bal-Arab': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'bal-Latn': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + bas: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + be: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'be-tarask': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bem: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bew: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + bez: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bg: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + bgc: { firstDay: 7, weekend: [7], minimalDays: 1 }, + bgn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'bgn-AE': { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + 'bgn-AF': { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, + 'bgn-IR': { firstDay: 6, weekend: [5], minimalDays: 1 }, + 'bgn-OM': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + bho: { firstDay: 7, weekend: [7], minimalDays: 1 }, + blo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + blt: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bm: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'bm-Nkoo': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'bn-IN': { firstDay: 7, weekend: [7], minimalDays: 1 }, + bo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'bo-IN': { firstDay: 7, weekend: [7], minimalDays: 1 }, + br: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + brx: { firstDay: 7, weekend: [7], minimalDays: 1 }, + bs: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'bs-Cyrl': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'bs-Latn': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + bss: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + byn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ca: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'ca-AD': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'ca-ES-valencia': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'ca-FR': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'ca-IT': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + cad: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + cch: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ccp: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'ccp-IN': { firstDay: 7, weekend: [7], minimalDays: 1 }, + ce: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ceb: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + cgg: { firstDay: 1, weekend: [7], minimalDays: 1 }, + cho: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + chr: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + cic: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ckb: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ckb-IR': { firstDay: 6, weekend: [5], minimalDays: 1 }, + co: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + cs: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + csw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + cu: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + cv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + cy: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + da: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'da-GL': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + dav: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + de: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'de-AT': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'de-BE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'de-CH': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'de-IT': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'de-LI': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'de-LU': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + dje: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + doi: { firstDay: 7, weekend: [7], minimalDays: 1 }, + dsb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + dua: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + dv: { firstDay: 5, weekend: [6, 7], minimalDays: 1 }, + dyo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + dz: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ebu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ee: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ee-TG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + el: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'el-CY': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'el-polyton': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + en: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-001': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-150': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-AE': { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + 'en-AG': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-AI': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-AS': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-AT': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-AU': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-BB': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-BE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-BI': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-BM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-BS': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-BW': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-BZ': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-CA': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-CC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-CH': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-CK': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-CM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-CX': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-CY': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-DE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-DG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-DK': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-DM': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-Dsrt': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-ER': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-FI': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-FJ': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-FK': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-FM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-GB': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-GD': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-GG': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-GH': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-GI': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-GM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-GU': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-GY': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-HK': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-ID': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-IE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-IL': { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + 'en-IM': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-IN': { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'en-IO': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-JE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-JM': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-KE': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-KI': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-KN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-KY': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-LC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-LR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-LS': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-MG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-MH': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-MO': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-MP': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-MS': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-MT': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-MU': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-MV': { firstDay: 5, weekend: [6, 7], minimalDays: 1 }, + 'en-MW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-MY': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-NA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-NF': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-NG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-NL': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-NR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-NU': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-NZ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-PG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-PH': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-PK': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-PN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-PR': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-PW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-RW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-SB': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-SC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-SD': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'en-SE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-SG': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-SH': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-SI': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-SL': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-SS': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-SX': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-SZ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-Shaw': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'en-TC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-TK': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-TO': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-TT': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-TV': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-TZ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-UG': { firstDay: 1, weekend: [7], minimalDays: 1 }, + 'en-UM': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-VC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-VG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-VI': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-VU': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-WS': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-ZA': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'en-ZM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'en-ZW': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + eo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + es: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'es-419': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-AR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-BO': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-BR': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-BZ': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-CL': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-CO': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-CR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-CU': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-DO': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-EA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-EC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-GQ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-GT': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-HN': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-IC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-MX': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-NI': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-PA': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-PE': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-PH': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-PR': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-PY': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-SV': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-US': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'es-UY': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'es-VE': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + et: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + eu: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ewo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + fa: { firstDay: 6, weekend: [5], minimalDays: 1 }, + 'fa-AF': { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, + ff: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-BF': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-CM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-GH': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-GM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-GW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-LR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-MR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-NE': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-NG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-SL': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Adlm-SN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-BF': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-CM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-GH': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-GM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-GN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-GW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-LR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-MR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-NE': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-NG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ff-Latn-SL': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + fi: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + fil: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + fo: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fo-DK': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + fr: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fr-BE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fr-BF': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-BI': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-BJ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-BL': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-CA': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'fr-CD': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-CF': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-CG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-CH': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fr-CI': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-CM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-DJ': { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + 'fr-DZ': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'fr-GA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-GF': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fr-GN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-GP': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fr-GQ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-HT': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-KM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-LU': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fr-MA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-MC': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fr-MF': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-MG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-ML': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-MQ': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fr-MR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-MU': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-NC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-NE': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-PF': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-PM': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-RE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'fr-RW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-SC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-SN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-SY': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'fr-TD': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-TG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-TN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-VU': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-WF': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'fr-YT': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + frr: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + fur: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + fy: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ga: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'ga-GB': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + gaa: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + gd: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + gez: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'gez-ER': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + gl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + gn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + gsw: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'gsw-FR': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'gsw-LI': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + gu: { firstDay: 7, weekend: [7], minimalDays: 1 }, + guz: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + gv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ha: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ha-Arab': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ha-Arab-SD': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'ha-GH': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ha-NE': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + haw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + he: { firstDay: 7, weekend: [5, 6], minimalDays: 1 }, + hi: { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'hi-Latn': { firstDay: 7, weekend: [7], minimalDays: 1 }, + hnj: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'hnj-Hmnp': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + hr: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'hr-BA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + hsb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + hu: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + hy: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ia: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + id: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ie: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ig: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ii: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + io: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + is: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + it: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'it-CH': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'it-SM': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'it-VA': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + iu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'iu-Latn': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ja: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + jbo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + jgo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + jmc: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + jv: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ka: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kab: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + kaj: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kam: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + kcg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kde: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kea: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ken: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kgp: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + khq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ki: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + kk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kkj: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kl: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kln: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + km: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + kn: { firstDay: 7, weekend: [7], minimalDays: 1 }, + ko: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'ko-CN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ko-KP': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kok: { firstDay: 7, weekend: [7], minimalDays: 1 }, + kpe: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'kpe-GN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ks: { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'ks-Arab': { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'ks-Deva': { firstDay: 7, weekend: [7], minimalDays: 1 }, + ksb: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ksf: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ksh: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ku: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + kw: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + kxv: { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'kxv-Deva': { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'kxv-Latn': { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'kxv-Orya': { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'kxv-Telu': { firstDay: 7, weekend: [7], minimalDays: 1 }, + ky: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + la: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + lag: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + lb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + lg: { firstDay: 1, weekend: [7], minimalDays: 1 }, + lij: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + lkt: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + lmo: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ln: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ln-AO': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ln-CF': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ln-CG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + lo: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + lrc: { firstDay: 6, weekend: [5], minimalDays: 1 }, + 'lrc-IQ': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + lt: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + lu: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + luo: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + luy: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + lv: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mai: { firstDay: 7, weekend: [7], minimalDays: 1 }, + mas: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'mas-TZ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mdf: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + mer: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mfe: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mgh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mgo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mic: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ml: { firstDay: 7, weekend: [7], minimalDays: 1 }, + mn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'mn-Mong': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'mn-Mong-MN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mni: { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'mni-Beng': { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'mni-Mtei': { firstDay: 7, weekend: [7], minimalDays: 1 }, + moh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mr: { firstDay: 7, weekend: [7], minimalDays: 1 }, + ms: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ms-Arab': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ms-Arab-BN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ms-BN': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ms-ID': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'ms-SG': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mt: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + mua: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + mus: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + my: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + myv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + mzn: { firstDay: 6, weekend: [5], minimalDays: 1 }, + naq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nb: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'nb-SJ': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + nd: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + nds: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'nds-NL': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ne: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'ne-IN': { firstDay: 7, weekend: [7], minimalDays: 1 }, + nl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'nl-AW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'nl-BE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'nl-BQ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'nl-CW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'nl-SR': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'nl-SX': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nmg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nn: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + nnh: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + no: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + nqo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nr: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + nso: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + nus: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nv: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ny: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + nyn: { firstDay: 1, weekend: [7], minimalDays: 1 }, + oc: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'oc-ES': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + om: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'om-KE': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + or: { firstDay: 7, weekend: [7], minimalDays: 1 }, + os: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'os-RU': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + osa: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + pa: { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'pa-Arab': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'pa-Guru': { firstDay: 7, weekend: [7], minimalDays: 1 }, + pap: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'pap-AW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + pcm: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + pis: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + pl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + prg: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ps: { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, + 'ps-PK': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + pt: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'pt-AO': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'pt-CH': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'pt-CV': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'pt-GQ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'pt-GW': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'pt-LU': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'pt-MO': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'pt-MZ': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'pt-PT': { firstDay: 7, weekend: [6, 7], minimalDays: 4 }, + 'pt-ST': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'pt-TL': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + qu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'qu-BO': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'qu-EC': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + quc: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + raj: { firstDay: 7, weekend: [7], minimalDays: 1 }, + rhg: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'rhg-Rohg': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'rhg-Rohg-BD': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + rif: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + rm: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + rn: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ro: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ro-MD': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + rof: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ru: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'ru-BY': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ru-KG': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ru-KZ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ru-MD': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ru-UA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + rw: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + rwk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sa: { firstDay: 7, weekend: [7], minimalDays: 1 }, + sah: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + saq: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sat: { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'sat-Deva': { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'sat-Olck': { firstDay: 7, weekend: [7], minimalDays: 1 }, + sbp: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sc: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + scn: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + sd: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'sd-Arab': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'sd-Deva': { firstDay: 7, weekend: [7], minimalDays: 1 }, + sdh: { firstDay: 6, weekend: [5], minimalDays: 1 }, + 'sdh-IQ': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + se: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'se-FI': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'se-SE': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + seh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ses: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + shi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'shi-Latn': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'shi-Tfng': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + shn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'shn-TH': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + si: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sid: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sk: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + skr: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sl: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sma: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'sma-NO': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + smj: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'smj-NO': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + smn: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + sms: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + sn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + so: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'so-DJ': { firstDay: 6, weekend: [6, 7], minimalDays: 1 }, + 'so-ET': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'so-KE': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sq-MK': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sq-XK': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + sr: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sr-Cyrl': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sr-Cyrl-BA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sr-Cyrl-ME': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sr-Cyrl-XK': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sr-Latn': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sr-Latn-BA': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sr-Latn-ME': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sr-Latn-XK': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ss: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'ss-SZ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ssy: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + st: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'st-LS': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + su: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'su-Latn': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + sv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'sv-AX': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + 'sv-FI': { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + sw: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sw-CD': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'sw-KE': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'sw-UG': { firstDay: 1, weekend: [7], minimalDays: 1 }, + syr: { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + 'syr-SY': { firstDay: 6, weekend: [5, 6], minimalDays: 1 }, + szl: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + ta: { firstDay: 7, weekend: [7], minimalDays: 1 }, + 'ta-LK': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ta-MY': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'ta-SG': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + te: { firstDay: 7, weekend: [7], minimalDays: 1 }, + teo: { firstDay: 1, weekend: [7], minimalDays: 1 }, + 'teo-KE': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + tg: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + th: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ti: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'ti-ER': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tig: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tn: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'tn-BW': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + to: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tok: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tpi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tr: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'tr-CY': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + trv: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + trw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ts: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + tt: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + twq: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + tyv: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + tzm: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ug: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + uk: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + und: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + ur: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'ur-IN': { firstDay: 7, weekend: [7], minimalDays: 1 }, + uz: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'uz-Arab': { firstDay: 6, weekend: [4, 5], minimalDays: 1 }, + 'uz-Cyrl': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'uz-Latn': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + vai: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'vai-Latn': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'vai-Vaii': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + ve: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + vec: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + vi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + vmw: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + vo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + vun: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + wa: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + wae: { firstDay: 1, weekend: [6, 7], minimalDays: 4 }, + wal: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + wbp: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + wo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + xh: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + xnr: { firstDay: 7, weekend: [7], minimalDays: 1 }, + xog: { firstDay: 1, weekend: [7], minimalDays: 1 }, + yav: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + yi: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + yo: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'yo-BJ': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + yrl: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'yrl-CO': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'yrl-VE': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + yue: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'yue-Hans': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'yue-Hant': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + za: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + zgh: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + zh: { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'zh-Hans': { firstDay: 1, weekend: [6, 7], minimalDays: 1 }, + 'zh-Hans-HK': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'zh-Hans-MO': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'zh-Hans-SG': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'zh-Hant': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'zh-Hant-HK': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + 'zh-Hant-MO': { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, + zu: { firstDay: 7, weekend: [6, 7], minimalDays: 1 }, +} From 6a75f09748e0751dcd7f9b085971ff24cab81951 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 19 Jan 2026 23:27:11 +0100 Subject: [PATCH 007/207] feat: parse --- packages/time/src/date/parse/parse.ts | 37 ++++++++++++++++--- .../time/src/date/parse/tests/parse.test.ts | 20 +++------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/packages/time/src/date/parse/parse.ts b/packages/time/src/date/parse/parse.ts index c7cabd1c..8c963a47 100644 --- a/packages/time/src/date/parse/parse.ts +++ b/packages/time/src/date/parse/parse.ts @@ -67,8 +67,25 @@ function parseDateTimeString(value: string): Date { timezone = '', } = match.groups + // If timezone is specified, use ISO string format (will be parsed as UTC/offset) + if (timezone) { + const millisecondStr = millisecond || '000' + return new Date( + `${year}-${month}-${day}T${hour}:${minute}:${second}.${millisecondStr.padEnd(3, '0').substring(0, 3)}${timezone}`, + ) + } + + // For dates without timezone, use Date constructor with individual components + // This creates a date in the system's local timezone + const millisecondStr = (millisecond || '000').padEnd(3, '0').substring(0, 3) return new Date( - `${year}-${month}-${day}T${hour}:${minute}:${second}.${millisecond}${timezone}`, + Number(year), + Number(month) - 1, // Month is 0-indexed + Number(day), + Number(hour), + Number(minute), + Number(second), + Number(millisecondStr), ) } throw new Error(`"${value}" is an invalid RFC339 Internet Date Time string`) @@ -94,14 +111,24 @@ function parseTimeOnlyString(value: string): Date { // convert 12 hour time to 24 let trueHour = Number(hour) if (meridiem) { - if (trueHour > 12) { + if (trueHour > 12 || trueHour === 0) { throw new Error(`"${value}" is an invalid time string`) } - if (meridiem.toLowerCase() === 'pm' && trueHour < 12) { - trueHour += 12 + if (meridiem.toLowerCase() === 'pm') { + if (trueHour < 12) { + trueHour += 12 + } + // If hour is 12 PM, keep it as 12 (noon) + } else { + // AM + if (trueHour === 12) { + trueHour = 0 // 12 AM is midnight + } } } - now.setHours(trueHour, Number(minute), Number(second), Number(millisecond)) + // If no meridiem, assume 24-hour format (hour can be 00-23) + const millisecondStr = (millisecond || '000').padEnd(3, '0').substring(0, 3) + now.setHours(trueHour, Number(minute), Number(second), Number(millisecondStr)) return now } throw new Error(`"${value}" is an invalid time string`) diff --git a/packages/time/src/date/parse/tests/parse.test.ts b/packages/time/src/date/parse/tests/parse.test.ts index c5a123d6..5997dd65 100644 --- a/packages/time/src/date/parse/tests/parse.test.ts +++ b/packages/time/src/date/parse/tests/parse.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { Temporal } from '@js-temporal/polyfill' import { parse } from '../parse' @@ -21,20 +21,12 @@ const timeOnlyFormat = new Intl.DateTimeFormat('en-US', { }) describe('parse', () => { - const mockDate = new Date('2023-06-15') - const mockDateTime = new Date('2023-06-15T10:00:00') - beforeEach(() => { - const mockTemporalDate = Temporal.PlainDate.from( - mockDate.toISOString().split('T')[0]!, - ) - const mockTemporalDateTime = Temporal.PlainDateTime.from( - mockDateTime.toISOString().replace('Z', ''), - ) - vi.spyOn(Temporal.Now, 'plainDateISO').mockReturnValue(mockTemporalDate) - vi.spyOn(Temporal.Now, 'plainDateTimeISO').mockReturnValue( - mockTemporalDateTime, - ) + vi.stubEnv('TZ', 'America/New_York') + }) + + afterEach(() => { + vi.unstubAllEnvs() }) test('should parse a valid year only date string', () => { From 757a9361db373f8d5341e8b9c0b9f00a3728936e Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 20 Jan 2026 00:07:10 +0100 Subject: [PATCH 008/207] feat: withDateOperation HOF and startOf util --- .../time/src/date/parse/tests/parse.test.ts | 1 - packages/time/src/date/startOf/startOf.ts | 57 ++++++ .../src/date/startOf/tests/startOf.test.ts | 103 +++++++++++ .../time/src/date/withDateOperation.test.ts | 167 ++++++++++++++++++ packages/time/src/date/withDateOperation.ts | 112 ++++++++++++ 5 files changed, 439 insertions(+), 1 deletion(-) create mode 100644 packages/time/src/date/withDateOperation.test.ts create mode 100644 packages/time/src/date/withDateOperation.ts diff --git a/packages/time/src/date/parse/tests/parse.test.ts b/packages/time/src/date/parse/tests/parse.test.ts index 5997dd65..8cd9be82 100644 --- a/packages/time/src/date/parse/tests/parse.test.ts +++ b/packages/time/src/date/parse/tests/parse.test.ts @@ -1,5 +1,4 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' -import { Temporal } from '@js-temporal/polyfill' import { parse } from '../parse' const dateTimeFormat = new Intl.DateTimeFormat('en-US', { diff --git a/packages/time/src/date/startOf/startOf.ts b/packages/time/src/date/startOf/startOf.ts index e69de29b..fdc4a4ad 100644 --- a/packages/time/src/date/startOf/startOf.ts +++ b/packages/time/src/date/startOf/startOf.ts @@ -0,0 +1,57 @@ +import { withDateOperation } from '../withDateOperation' +import type { + DateInput, + DateOperationOptions, + DateOperationResult, +} from '../withDateOperation' + +export type StartOfUnit = + | 'year' + | 'month' + | 'week' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'millisecond' + +export interface StartOfArgs extends Record { + unit: StartOfUnit +} + +/** + * startOf + * Returns the start of a given unit for a date/time instance + */ +export function startOf( + input: DateInput, + args: StartOfArgs, + options?: DateOperationOptions, +): DateOperationResult { + return withDateOperation((zdt, { unit }) => { + switch (unit) { + case 'year': + return zdt.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + case 'month': + return zdt.with({ day: 1, hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + case 'week': { + const dayOfWeek = zdt.dayOfWeek + const firstDayOfWeek = 1 + const daysToSubtract = (dayOfWeek - firstDayOfWeek + 7) % 7 + return zdt.subtract({ days: daysToSubtract }) + } + case 'day': + return zdt.with({ hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + case 'hour': + return zdt.with({ minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + case 'minute': + return zdt.with({ second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + case 'second': + return zdt.with({ millisecond: 0, microsecond: 0, nanosecond: 0 }) + case 'millisecond': + return zdt.with({ microsecond: 0, nanosecond: 0 }) + default: + return zdt + } + })(input, args, options) +} diff --git a/packages/time/src/date/startOf/tests/startOf.test.ts b/packages/time/src/date/startOf/tests/startOf.test.ts index e69de29b..726f0fb8 100644 --- a/packages/time/src/date/startOf/tests/startOf.test.ts +++ b/packages/time/src/date/startOf/tests/startOf.test.ts @@ -0,0 +1,103 @@ +import { describe, expect, test } from 'vitest' +import { startOf } from '../startOf' + +describe('startOf', () => { + describe('with string input', () => { + test('should return start of year', () => { + const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'year' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-01-01T00:00:00Z') + expect(result.options.timeZone).toBe('UTC') + expect(result.options.calendar).toBeDefined() + }) + + test('should return start of month', () => { + const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'month' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-01T00:00:00Z') + }) + + test('should return start of day', () => { + const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'day' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T00:00:00Z') + }) + + test('should return start of hour', () => { + const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'hour' }) + expect(result.value).toContain('2024-03-15T14:00:00') + }) + + test('should return start of minute', () => { + const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'minute' }) + expect(result.value).toContain('2024-03-15T14:42:00') + }) + + test('should return start of second', () => { + const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'second' }) + expect(result.value).toContain('2024-03-15T14:42:12') + }) + + test('should return start of millisecond', () => { + const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'millisecond' }) + expect(result.value).toContain('2024-03-15T14:42:12.789') + }) + }) + + + describe('week calculation', () => { + test('should return start of week (Monday)', () => { + // 2024-03-15 is a Friday (day 5), so start of week should be Monday (2024-03-11) + const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'week' }) + const resultDate = new Date(result.value as unknown as string) + expect(resultDate.getDay()).toBe(1) // Monday + }) + + test('should return start of week for Sunday', () => { + // 2024-03-17 is a Sunday (day 7), so start of week should be Monday (2024-03-11) + const result = startOf('2024-03-17T14:42:12.789Z', { unit: 'week' }) + const resultDate = new Date(result.value as unknown as string) + expect(resultDate.getDay()).toBe(1) // Monday + }) + + test('should return start of week for Monday', () => { + // 2024-03-11 is a Monday (day 1), so start of week should be itself + const result = startOf('2024-03-11T14:42:12.789Z', { unit: 'week' }) + const resultDate = new Date(result.value as unknown as string) + expect(resultDate.getDay()).toBe(1) // Monday + expect(resultDate.toISOString()).toContain('2024-03-11') + }) + }) + + + describe('edge cases', () => { + test('should handle start of year for January 1st', () => { + const result = startOf('2024-01-01T00:00:00Z', { unit: 'year' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-01-01T00:00:00Z') + }) + + test('should handle start of month for first day', () => { + const result = startOf('2024-03-01T00:00:00Z', { unit: 'month' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-01T00:00:00Z') + }) + + test('should handle start of day at midnight', () => { + const result = startOf('2024-03-15T00:00:00Z', { unit: 'day' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T00:00:00Z') + }) + + test('should handle start of hour at 00:00', () => { + const result = startOf('2024-03-15T14:00:00Z', { unit: 'hour' }) + expect(result.value).toContain('2024-03-15T14:00:00') + }) + }) +}) diff --git a/packages/time/src/date/withDateOperation.test.ts b/packages/time/src/date/withDateOperation.test.ts new file mode 100644 index 00000000..dd16ee4d --- /dev/null +++ b/packages/time/src/date/withDateOperation.test.ts @@ -0,0 +1,167 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { withDateOperation } from './withDateOperation' + +describe('withDateOperation', () => { + const mockOperation = withDateOperation((zdt) => zdt) + + describe('timezone handling', () => { + test('should use default timezone when not provided', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }) + expect(result.options.timeZone).toBeDefined() + expect(typeof result.options.timeZone).toBe('string') + }) + + test('should use custom timezone', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'Asia/Tokyo', + }) + expect(result.options.timeZone).toBe('Asia/Tokyo') + }) + + test('should return timezone in options', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'Europe/London', + }) + expect(result.options.timeZone).toBe('Europe/London') + }) + }) + + describe('calendar handling', () => { + test('should use default calendar when not provided', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }) + expect(result.options.calendar).toBeDefined() + expect(typeof result.options.calendar).toBe('string') + }) + + test('should use custom calendar', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + calendar: 'japanese', + }) + expect(result.options.calendar).toBe('japanese') + }) + + test('should return calendar in options', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + calendar: 'islamic', + }) + expect(result.options.calendar).toBe('islamic') + }) + }) + + describe('conversion methods', () => { + test('should have asDate method', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'UTC', + }) + const date = result.asDate() + expect(date).toBeInstanceOf(Date) + expect(date.toISOString()).toContain('2024-03-15') + }) + + test('should have asEpoch method', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'UTC', + }) + const epoch = result.asEpoch() + expect(typeof epoch).toBe('number') + expect(new Date(epoch).toISOString()).toContain('2024-03-15') + }) + + test('should have asString method', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'UTC', + }) + const str = result.asString() + expect(typeof str).toBe('string') + expect(str).toContain('2024-03-15') + }) + + test('should have asLong method', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'America/New_York', + calendar: 'gregory', + }) + const long = result.asLong() + expect(typeof long).toBe('string') + expect(long).toContain('2024-03-15') + expect(long).toContain('[America/New_York]') + expect(long).toContain('[u-ca=gregory]') + }) + + test('should have asZonedDateTime method', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'UTC', + }) + const zdt = result.asZonedDateTime() + expect(zdt).toBeInstanceOf(Temporal.ZonedDateTime) + expect(zdt.toInstant().toString()).toContain('2024-03-15') + }) + }) + + describe('result properties', () => { + test('should have value property as string', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'UTC', + }) + expect(typeof result.value).toBe('string') + expect(result.value).toContain('2024-03-15') + }) + + test('should have options property', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }) + expect(result.options).toHaveProperty('timeZone') + expect(result.options).toHaveProperty('calendar') + expect(typeof result.options.timeZone).toBe('string') + expect(typeof result.options.calendar).toBe('string') + }) + + test('should have timeZone property', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'Asia/Tokyo', + }) + expect(result.timeZone).toBe('Asia/Tokyo') + }) + + test('should have calendar property', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + calendar: 'japanese', + }) + expect(result.calendar).toBe('japanese') + }) + + test('should support destructuring', () => { + const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { + timeZone: 'UTC', + calendar: 'gregory', + }) + const { value, timeZone, calendar } = result + expect(typeof value).toBe('string') + expect(timeZone).toBe('UTC') + expect(calendar).toBe('gregory') + }) + }) + + describe('operation execution', () => { + test('should execute the provided operation function', () => { + const addDayOperation = withDateOperation<{ days: number }>((zdt, { days }) => { + return zdt.add({ days }) + }) + const result = addDayOperation('2024-03-15T00:00:00Z', { days: 1 }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-16T00:00:00Z') + }) + + test('should pass args to the operation function', () => { + const customOperation = withDateOperation<{ multiplier: number }>((zdt, { multiplier }) => { + const days = zdt.day * multiplier + return zdt.with({ day: days }) + }) + const result = customOperation('2024-03-15T00:00:00Z', { multiplier: 2 }, { + timeZone: 'UTC', + }) + expect(result.value).toContain('2024-03-30') + }) + }) +}) diff --git a/packages/time/src/date/withDateOperation.ts b/packages/time/src/date/withDateOperation.ts new file mode 100644 index 00000000..5cafeda8 --- /dev/null +++ b/packages/time/src/date/withDateOperation.ts @@ -0,0 +1,112 @@ +import { Temporal } from '@js-temporal/polyfill' +import { parse } from './parse/parse' +import { getDateDefaults } from './dateDefaults' + +export type DateInput = string | number | Date | Temporal.ZonedDateTime + +export interface DateOptions { + calendar?: string + timeZone?: string +} + +export interface DateOperationOptions extends DateOptions {} + +export interface DateOperationResult { + value: string + options: Required + asDate: () => Date + asEpoch: () => number + asString: () => string + asLong: () => string + asZonedDateTime: () => Temporal.ZonedDateTime + timeZone: string + calendar: string +} + +function createDateOperationResult( + zdt: Temporal.ZonedDateTime, + options: Required, +): DateOperationResult { + return { + value: zdt.toInstant().toString(), + options, + asDate: () => { + return new Date(Number(zdt.epochNanoseconds / 1_000_000n)) + }, + asEpoch: () => { + return Number(zdt.epochNanoseconds / 1_000_000n) + }, + asString: () => { + return zdt.toInstant().toString() + }, + asLong: () => { + return `${zdt.toInstant().toString()}[${zdt.timeZoneId}][u-ca=${zdt.calendarId}]` + }, + asZonedDateTime: () => { + return zdt + }, + timeZone: options.timeZone, + calendar: options.calendar, + } +} + +/** + * Converts various date inputs to a Temporal.ZonedDateTime + */ +function toZonedDateTime( + input: DateInput, + timeZone: string, + calendar: string, +): Temporal.ZonedDateTime { + if (input instanceof Temporal.ZonedDateTime) { + return input + } + + let dateString: string + + if (typeof input === 'string') { + if (input.includes('[') && input.includes(']')) { + return Temporal.ZonedDateTime.from(input) + } + dateString = input + } else if (typeof input === 'number') { + const date = parse(input) + if (!date) { + throw new Error(`"${input}" is an invalid date value`) + } + dateString = date.toISOString() + } else if (input instanceof Date) { + dateString = input.toISOString() + } else { + throw new Error(`Invalid date input type: ${typeof input}`) + } + + const zonedDateTimeString = `${dateString}[${timeZone}][u-ca=${calendar}]` + return Temporal.ZonedDateTime.from(zonedDateTimeString) +} + +/** + * Higher-order function that provides common parsing, defaults, and formatting logic + * for date utility functions like startOf, endOf, etc. + */ +export function withDateOperation>( + fn: (zdt: Temporal.ZonedDateTime, args: TArgs) => Temporal.ZonedDateTime, +) { + return ( + input: DateInput, + args: TArgs, + options?: DateOperationOptions, + ): DateOperationResult => { + const defaults = getDateDefaults() + const timeZone = options?.timeZone ?? defaults.timeZone + const calendar = options?.calendar ?? defaults.calendar + + const inputZdt = toZonedDateTime(input, timeZone, calendar) + const resultZdt = fn(inputZdt, args) + + return createDateOperationResult(resultZdt, { + timeZone, + calendar, + }) + } +} From 7ba3389f22f321a6776674cf589a32265b396e35 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 23:08:16 +0000 Subject: [PATCH 009/207] ci: apply automated fixes --- docs/reference/index.md | 6 + packages/time/src/date/parse/parse.ts | 7 +- packages/time/src/date/startOf/startOf.ts | 45 ++++- .../src/date/startOf/tests/startOf.test.ts | 66 ++++--- .../time/src/date/withDateOperation.test.ts | 172 ++++++++++++------ 5 files changed, 215 insertions(+), 81 deletions(-) create mode 100644 docs/reference/index.md diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 00000000..b14fbe49 --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,6 @@ +--- +id: "@tanstack/time" +title: "@tanstack/time" +--- + +# @tanstack/time diff --git a/packages/time/src/date/parse/parse.ts b/packages/time/src/date/parse/parse.ts index 8c963a47..3624a68e 100644 --- a/packages/time/src/date/parse/parse.ts +++ b/packages/time/src/date/parse/parse.ts @@ -128,7 +128,12 @@ function parseTimeOnlyString(value: string): Date { } // If no meridiem, assume 24-hour format (hour can be 00-23) const millisecondStr = (millisecond || '000').padEnd(3, '0').substring(0, 3) - now.setHours(trueHour, Number(minute), Number(second), Number(millisecondStr)) + now.setHours( + trueHour, + Number(minute), + Number(second), + Number(millisecondStr), + ) return now } throw new Error(`"${value}" is an invalid time string`) diff --git a/packages/time/src/date/startOf/startOf.ts b/packages/time/src/date/startOf/startOf.ts index fdc4a4ad..58e3b4f3 100644 --- a/packages/time/src/date/startOf/startOf.ts +++ b/packages/time/src/date/startOf/startOf.ts @@ -31,9 +31,26 @@ export function startOf( return withDateOperation((zdt, { unit }) => { switch (unit) { case 'year': - return zdt.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + month: 1, + day: 1, + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + }) case 'month': - return zdt.with({ day: 1, hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + day: 1, + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + }) case 'week': { const dayOfWeek = zdt.dayOfWeek const firstDayOfWeek = 1 @@ -41,11 +58,29 @@ export function startOf( return zdt.subtract({ days: daysToSubtract }) } case 'day': - return zdt.with({ hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + }) case 'hour': - return zdt.with({ minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + }) case 'minute': - return zdt.with({ second: 0, millisecond: 0, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + }) case 'second': return zdt.with({ millisecond: 0, microsecond: 0, nanosecond: 0 }) case 'millisecond': diff --git a/packages/time/src/date/startOf/tests/startOf.test.ts b/packages/time/src/date/startOf/tests/startOf.test.ts index 726f0fb8..e9abb4d9 100644 --- a/packages/time/src/date/startOf/tests/startOf.test.ts +++ b/packages/time/src/date/startOf/tests/startOf.test.ts @@ -4,25 +4,37 @@ import { startOf } from '../startOf' describe('startOf', () => { describe('with string input', () => { test('should return start of year', () => { - const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'year' }, { - timeZone: 'UTC', - }) + const result = startOf( + '2024-03-15T14:42:12.789Z', + { unit: 'year' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-01-01T00:00:00Z') expect(result.options.timeZone).toBe('UTC') expect(result.options.calendar).toBeDefined() }) test('should return start of month', () => { - const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'month' }, { - timeZone: 'UTC', - }) + const result = startOf( + '2024-03-15T14:42:12.789Z', + { unit: 'month' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-03-01T00:00:00Z') }) test('should return start of day', () => { - const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'day' }, { - timeZone: 'UTC', - }) + const result = startOf( + '2024-03-15T14:42:12.789Z', + { unit: 'day' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-03-15T00:00:00Z') }) @@ -42,12 +54,13 @@ describe('startOf', () => { }) test('should return start of millisecond', () => { - const result = startOf('2024-03-15T14:42:12.789Z', { unit: 'millisecond' }) + const result = startOf('2024-03-15T14:42:12.789Z', { + unit: 'millisecond', + }) expect(result.value).toContain('2024-03-15T14:42:12.789') }) }) - describe('week calculation', () => { test('should return start of week (Monday)', () => { // 2024-03-15 is a Friday (day 5), so start of week should be Monday (2024-03-11) @@ -72,26 +85,37 @@ describe('startOf', () => { }) }) - describe('edge cases', () => { test('should handle start of year for January 1st', () => { - const result = startOf('2024-01-01T00:00:00Z', { unit: 'year' }, { - timeZone: 'UTC', - }) + const result = startOf( + '2024-01-01T00:00:00Z', + { unit: 'year' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-01-01T00:00:00Z') }) test('should handle start of month for first day', () => { - const result = startOf('2024-03-01T00:00:00Z', { unit: 'month' }, { - timeZone: 'UTC', - }) + const result = startOf( + '2024-03-01T00:00:00Z', + { unit: 'month' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-03-01T00:00:00Z') }) test('should handle start of day at midnight', () => { - const result = startOf('2024-03-15T00:00:00Z', { unit: 'day' }, { - timeZone: 'UTC', - }) + const result = startOf( + '2024-03-15T00:00:00Z', + { unit: 'day' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-03-15T00:00:00Z') }) diff --git a/packages/time/src/date/withDateOperation.test.ts b/packages/time/src/date/withDateOperation.test.ts index dd16ee4d..a26a0f58 100644 --- a/packages/time/src/date/withDateOperation.test.ts +++ b/packages/time/src/date/withDateOperation.test.ts @@ -13,16 +13,24 @@ describe('withDateOperation', () => { }) test('should use custom timezone', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'Asia/Tokyo', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'Asia/Tokyo', + }, + ) expect(result.options.timeZone).toBe('Asia/Tokyo') }) test('should return timezone in options', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'Europe/London', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'Europe/London', + }, + ) expect(result.options.timeZone).toBe('Europe/London') }) }) @@ -35,53 +43,77 @@ describe('withDateOperation', () => { }) test('should use custom calendar', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - calendar: 'japanese', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + calendar: 'japanese', + }, + ) expect(result.options.calendar).toBe('japanese') }) test('should return calendar in options', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - calendar: 'islamic', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + calendar: 'islamic', + }, + ) expect(result.options.calendar).toBe('islamic') }) }) describe('conversion methods', () => { test('should have asDate method', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'UTC', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'UTC', + }, + ) const date = result.asDate() expect(date).toBeInstanceOf(Date) expect(date.toISOString()).toContain('2024-03-15') }) test('should have asEpoch method', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'UTC', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'UTC', + }, + ) const epoch = result.asEpoch() expect(typeof epoch).toBe('number') expect(new Date(epoch).toISOString()).toContain('2024-03-15') }) test('should have asString method', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'UTC', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'UTC', + }, + ) const str = result.asString() expect(typeof str).toBe('string') expect(str).toContain('2024-03-15') }) test('should have asLong method', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'America/New_York', - calendar: 'gregory', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'America/New_York', + calendar: 'gregory', + }, + ) const long = result.asLong() expect(typeof long).toBe('string') expect(long).toContain('2024-03-15') @@ -90,9 +122,13 @@ describe('withDateOperation', () => { }) test('should have asZonedDateTime method', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'UTC', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'UTC', + }, + ) const zdt = result.asZonedDateTime() expect(zdt).toBeInstanceOf(Temporal.ZonedDateTime) expect(zdt.toInstant().toString()).toContain('2024-03-15') @@ -101,9 +137,13 @@ describe('withDateOperation', () => { describe('result properties', () => { test('should have value property as string', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'UTC', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'UTC', + }, + ) expect(typeof result.value).toBe('string') expect(result.value).toContain('2024-03-15') }) @@ -117,24 +157,36 @@ describe('withDateOperation', () => { }) test('should have timeZone property', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'Asia/Tokyo', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'Asia/Tokyo', + }, + ) expect(result.timeZone).toBe('Asia/Tokyo') }) test('should have calendar property', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - calendar: 'japanese', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + calendar: 'japanese', + }, + ) expect(result.calendar).toBe('japanese') }) test('should support destructuring', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test' }, { - timeZone: 'UTC', - calendar: 'gregory', - }) + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'UTC', + calendar: 'gregory', + }, + ) const { value, timeZone, calendar } = result expect(typeof value).toBe('string') expect(timeZone).toBe('UTC') @@ -144,23 +196,35 @@ describe('withDateOperation', () => { describe('operation execution', () => { test('should execute the provided operation function', () => { - const addDayOperation = withDateOperation<{ days: number }>((zdt, { days }) => { - return zdt.add({ days }) - }) - const result = addDayOperation('2024-03-15T00:00:00Z', { days: 1 }, { - timeZone: 'UTC', - }) + const addDayOperation = withDateOperation<{ days: number }>( + (zdt, { days }) => { + return zdt.add({ days }) + }, + ) + const result = addDayOperation( + '2024-03-15T00:00:00Z', + { days: 1 }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-03-16T00:00:00Z') }) test('should pass args to the operation function', () => { - const customOperation = withDateOperation<{ multiplier: number }>((zdt, { multiplier }) => { - const days = zdt.day * multiplier - return zdt.with({ day: days }) - }) - const result = customOperation('2024-03-15T00:00:00Z', { multiplier: 2 }, { - timeZone: 'UTC', - }) + const customOperation = withDateOperation<{ multiplier: number }>( + (zdt, { multiplier }) => { + const days = zdt.day * multiplier + return zdt.with({ day: days }) + }, + ) + const result = customOperation( + '2024-03-15T00:00:00Z', + { multiplier: 2 }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toContain('2024-03-30') }) }) From 017176d59509990657ad0e670d8dafb55ff18691 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 20 Jan 2026 00:39:03 +0100 Subject: [PATCH 010/207] feat: endOf util --- packages/time/src/date/endOf/endOf.ts | 59 +++++++++ packages/time/src/date/endOf/index.ts | 1 + .../time/src/date/endOf/tests/endOf.test.ts | 123 ++++++++++++++++++ packages/time/src/date/withDateOperation.ts | 13 +- 4 files changed, 189 insertions(+), 7 deletions(-) create mode 100644 packages/time/src/date/endOf/endOf.ts create mode 100644 packages/time/src/date/endOf/index.ts create mode 100644 packages/time/src/date/endOf/tests/endOf.test.ts diff --git a/packages/time/src/date/endOf/endOf.ts b/packages/time/src/date/endOf/endOf.ts new file mode 100644 index 00000000..f4955f55 --- /dev/null +++ b/packages/time/src/date/endOf/endOf.ts @@ -0,0 +1,59 @@ +import { withDateOperation } from '../withDateOperation' +import type { + DateInput, + DateOperationOptions, + DateOperationResult, +} from '../withDateOperation' + +export type EndOfUnit = + | 'year' + | 'month' + | 'week' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'millisecond' + +export interface EndOfArgs extends Record { + unit: EndOfUnit +} + +/** + * endOf + * Returns the end of a given unit for a date/time instance + */ +export function endOf( + input: DateInput, + args: EndOfArgs, + options?: DateOperationOptions, +): DateOperationResult { + return withDateOperation((zdt, { unit }) => { + switch (unit) { + case 'year': + return zdt.with({ month: 12, day: 31, hour: 23, minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + case 'month': { + const daysInMonth = zdt.daysInMonth + return zdt.with({ day: daysInMonth, hour: 23, minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + } + case 'week': { + const dayOfWeek = zdt.dayOfWeek + const daysToAdd = dayOfWeek === 7 ? 0 : 7 - dayOfWeek + const endOfWeekDay = daysToAdd === 0 ? zdt : zdt.add({ days: daysToAdd }) + return endOfWeekDay.with({ hour: 23, minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + } + case 'day': + return zdt.with({ hour: 23, minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + case 'hour': + return zdt.with({ minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + case 'minute': + return zdt.with({ second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + case 'second': + return zdt.with({ millisecond: 999, microsecond: 0, nanosecond: 0 }) + case 'millisecond': + return zdt.with({ microsecond: 999, nanosecond: 0 }) + default: + return zdt + } + })(input, args, options) +} diff --git a/packages/time/src/date/endOf/index.ts b/packages/time/src/date/endOf/index.ts new file mode 100644 index 00000000..ee08e133 --- /dev/null +++ b/packages/time/src/date/endOf/index.ts @@ -0,0 +1 @@ +export * from './endOf' diff --git a/packages/time/src/date/endOf/tests/endOf.test.ts b/packages/time/src/date/endOf/tests/endOf.test.ts new file mode 100644 index 00000000..85eb943c --- /dev/null +++ b/packages/time/src/date/endOf/tests/endOf.test.ts @@ -0,0 +1,123 @@ +import { describe, expect, test } from 'vitest' +import { endOf } from '../endOf' + +describe('endOf', () => { + describe('with string input', () => { + test('should return end of year', () => { + const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'year' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-12-31T23:59:59.999Z') + }) + + test('should return end of month', () => { + const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'month' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-31T23:59:59.999Z') + }) + + test('should return end of day', () => { + const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'day' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T23:59:59.999Z') + }) + + test('should return end of hour', () => { + const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'hour' }) + expect(result.value).toContain('2024-03-15T14:59:59.999') + }) + + test('should return end of minute', () => { + const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'minute' }) + expect(result.value).toContain('2024-03-15T14:42:59.999') + }) + + test('should return end of second', () => { + const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'second' }) + expect(result.value).toContain('2024-03-15T14:42:12.999') + }) + + test('should return end of millisecond', () => { + const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'millisecond' }) + expect(result.value).toContain('2024-03-15T14:42:12.789') + }) + }) + + describe('week calculation', () => { + test('should return end of week (Sunday)', () => { + // 2024-03-15 is a Friday (day 5), so end of week should be Sunday (2024-03-17) + const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'week' }, { + timeZone: 'UTC', + }) + const resultDate = new Date(result.value) + expect(resultDate.getUTCDay()).toBe(0) // Sunday + expect(result.value).toContain('2024-03-17') + expect(result.value).toContain('23:59:59.999') + }) + + test('should return end of week for Sunday', () => { + // 2024-03-17 is a Sunday (day 7), so end of week should be itself + const result = endOf('2024-03-17T14:42:12.789Z', { unit: 'week' }, { + timeZone: 'UTC', + }) + const resultDate = new Date(result.value) + expect(resultDate.getUTCDay()).toBe(0) // Sunday + expect(result.value).toContain('2024-03-17') + expect(result.value).toContain('23:59:59.999') + }) + + test('should return end of week for Monday', () => { + // 2024-03-11 is a Monday (day 1), so end of week should be Sunday (2024-03-17) + const result = endOf('2024-03-11T14:42:12.789Z', { unit: 'week' }, { + timeZone: 'UTC', + }) + const resultDate = new Date(result.value) + expect(resultDate.getUTCDay()).toBe(0) // Sunday + expect(result.value).toContain('2024-03-17') + }) + }) + + describe('edge cases', () => { + test('should handle end of year for December 31st', () => { + const result = endOf('2024-12-31T00:00:00Z', { unit: 'year' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-12-31T23:59:59.999Z') + }) + + test('should handle end of month for last day', () => { + const result = endOf('2024-03-31T00:00:00Z', { unit: 'month' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-31T23:59:59.999Z') + }) + + test('should handle end of month for February in leap year', () => { + const result = endOf('2024-02-15T00:00:00Z', { unit: 'month' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-02-29T23:59:59.999Z') + }) + + test('should handle end of month for February in non-leap year', () => { + const result = endOf('2023-02-15T00:00:00Z', { unit: 'month' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2023-02-28T23:59:59.999Z') + }) + + test('should handle end of day at 23:59:59', () => { + const result = endOf('2024-03-15T23:59:59Z', { unit: 'day' }, { + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T23:59:59.999Z') + }) + + test('should handle end of hour at 59:59', () => { + const result = endOf('2024-03-15T14:59:59Z', { unit: 'hour' }) + expect(result.value).toContain('2024-03-15T14:59:59.999') + }) + }) +}) diff --git a/packages/time/src/date/withDateOperation.ts b/packages/time/src/date/withDateOperation.ts index 5cafeda8..9ccac187 100644 --- a/packages/time/src/date/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation.ts @@ -1,5 +1,5 @@ import { Temporal } from '@js-temporal/polyfill' -import { parse } from './parse/parse' +import { validateDate } from './validateDate' import { getDateDefaults } from './dateDefaults' export type DateInput = string | number | Date | Temporal.ZonedDateTime @@ -68,15 +68,14 @@ function toZonedDateTime( if (input.includes('[') && input.includes(']')) { return Temporal.ZonedDateTime.from(input) } - dateString = input + const date = validateDate({ date: input }) + dateString = date.toISOString() } else if (typeof input === 'number') { - const date = parse(input) - if (!date) { - throw new Error(`"${input}" is an invalid date value`) - } + const date = validateDate({ date: input }) dateString = date.toISOString() } else if (input instanceof Date) { - dateString = input.toISOString() + const date = validateDate({ date: input }) + dateString = date.toISOString() } else { throw new Error(`Invalid date input type: ${typeof input}`) } From 7dfbee855b9988c53a556ee93dbbcdb3f83fad85 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 19 Jan 2026 23:39:54 +0000 Subject: [PATCH 011/207] ci: apply automated fixes --- packages/time/src/date/endOf/endOf.ts | 57 +++++++-- .../time/src/date/endOf/tests/endOf.test.ts | 110 ++++++++++++------ 2 files changed, 127 insertions(+), 40 deletions(-) diff --git a/packages/time/src/date/endOf/endOf.ts b/packages/time/src/date/endOf/endOf.ts index f4955f55..f74f56e6 100644 --- a/packages/time/src/date/endOf/endOf.ts +++ b/packages/time/src/date/endOf/endOf.ts @@ -31,23 +31,66 @@ export function endOf( return withDateOperation((zdt, { unit }) => { switch (unit) { case 'year': - return zdt.with({ month: 12, day: 31, hour: 23, minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + month: 12, + day: 31, + hour: 23, + minute: 59, + second: 59, + millisecond: 999, + microsecond: 0, + nanosecond: 0, + }) case 'month': { const daysInMonth = zdt.daysInMonth - return zdt.with({ day: daysInMonth, hour: 23, minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + day: daysInMonth, + hour: 23, + minute: 59, + second: 59, + millisecond: 999, + microsecond: 0, + nanosecond: 0, + }) } case 'week': { const dayOfWeek = zdt.dayOfWeek const daysToAdd = dayOfWeek === 7 ? 0 : 7 - dayOfWeek - const endOfWeekDay = daysToAdd === 0 ? zdt : zdt.add({ days: daysToAdd }) - return endOfWeekDay.with({ hour: 23, minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + const endOfWeekDay = + daysToAdd === 0 ? zdt : zdt.add({ days: daysToAdd }) + return endOfWeekDay.with({ + hour: 23, + minute: 59, + second: 59, + millisecond: 999, + microsecond: 0, + nanosecond: 0, + }) } case 'day': - return zdt.with({ hour: 23, minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + hour: 23, + minute: 59, + second: 59, + millisecond: 999, + microsecond: 0, + nanosecond: 0, + }) case 'hour': - return zdt.with({ minute: 59, second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + minute: 59, + second: 59, + millisecond: 999, + microsecond: 0, + nanosecond: 0, + }) case 'minute': - return zdt.with({ second: 59, millisecond: 999, microsecond: 0, nanosecond: 0 }) + return zdt.with({ + second: 59, + millisecond: 999, + microsecond: 0, + nanosecond: 0, + }) case 'second': return zdt.with({ millisecond: 999, microsecond: 0, nanosecond: 0 }) case 'millisecond': diff --git a/packages/time/src/date/endOf/tests/endOf.test.ts b/packages/time/src/date/endOf/tests/endOf.test.ts index 85eb943c..45229b84 100644 --- a/packages/time/src/date/endOf/tests/endOf.test.ts +++ b/packages/time/src/date/endOf/tests/endOf.test.ts @@ -4,23 +4,35 @@ import { endOf } from '../endOf' describe('endOf', () => { describe('with string input', () => { test('should return end of year', () => { - const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'year' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-03-15T14:42:12.789Z', + { unit: 'year' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-12-31T23:59:59.999Z') }) test('should return end of month', () => { - const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'month' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-03-15T14:42:12.789Z', + { unit: 'month' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-03-31T23:59:59.999Z') }) test('should return end of day', () => { - const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'day' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-03-15T14:42:12.789Z', + { unit: 'day' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-03-15T23:59:59.999Z') }) @@ -48,9 +60,13 @@ describe('endOf', () => { describe('week calculation', () => { test('should return end of week (Sunday)', () => { // 2024-03-15 is a Friday (day 5), so end of week should be Sunday (2024-03-17) - const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'week' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-03-15T14:42:12.789Z', + { unit: 'week' }, + { + timeZone: 'UTC', + }, + ) const resultDate = new Date(result.value) expect(resultDate.getUTCDay()).toBe(0) // Sunday expect(result.value).toContain('2024-03-17') @@ -59,9 +75,13 @@ describe('endOf', () => { test('should return end of week for Sunday', () => { // 2024-03-17 is a Sunday (day 7), so end of week should be itself - const result = endOf('2024-03-17T14:42:12.789Z', { unit: 'week' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-03-17T14:42:12.789Z', + { unit: 'week' }, + { + timeZone: 'UTC', + }, + ) const resultDate = new Date(result.value) expect(resultDate.getUTCDay()).toBe(0) // Sunday expect(result.value).toContain('2024-03-17') @@ -70,9 +90,13 @@ describe('endOf', () => { test('should return end of week for Monday', () => { // 2024-03-11 is a Monday (day 1), so end of week should be Sunday (2024-03-17) - const result = endOf('2024-03-11T14:42:12.789Z', { unit: 'week' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-03-11T14:42:12.789Z', + { unit: 'week' }, + { + timeZone: 'UTC', + }, + ) const resultDate = new Date(result.value) expect(resultDate.getUTCDay()).toBe(0) // Sunday expect(result.value).toContain('2024-03-17') @@ -81,37 +105,57 @@ describe('endOf', () => { describe('edge cases', () => { test('should handle end of year for December 31st', () => { - const result = endOf('2024-12-31T00:00:00Z', { unit: 'year' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-12-31T00:00:00Z', + { unit: 'year' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-12-31T23:59:59.999Z') }) test('should handle end of month for last day', () => { - const result = endOf('2024-03-31T00:00:00Z', { unit: 'month' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-03-31T00:00:00Z', + { unit: 'month' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-03-31T23:59:59.999Z') }) test('should handle end of month for February in leap year', () => { - const result = endOf('2024-02-15T00:00:00Z', { unit: 'month' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-02-15T00:00:00Z', + { unit: 'month' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-02-29T23:59:59.999Z') }) test('should handle end of month for February in non-leap year', () => { - const result = endOf('2023-02-15T00:00:00Z', { unit: 'month' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2023-02-15T00:00:00Z', + { unit: 'month' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2023-02-28T23:59:59.999Z') }) test('should handle end of day at 23:59:59', () => { - const result = endOf('2024-03-15T23:59:59Z', { unit: 'day' }, { - timeZone: 'UTC', - }) + const result = endOf( + '2024-03-15T23:59:59Z', + { unit: 'day' }, + { + timeZone: 'UTC', + }, + ) expect(result.value).toBe('2024-03-15T23:59:59.999Z') }) From cf4708023c298d490fcf62eaf93716707a5e8f97 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 20 Jan 2026 10:05:36 +0100 Subject: [PATCH 012/207] feat: returnFormat option --- .../time/src/date/endOf/tests/endOf.test.ts | 16 ++--- .../time/src/date/withDateOperation/index.ts | 1 + .../withDateOperation.test.ts | 62 +++++++++++++++++-- .../withDateOperation.ts | 31 ++++++++-- .../tests/buildFinalFormatter.test.ts | 12 +++- 5 files changed, 101 insertions(+), 21 deletions(-) create mode 100644 packages/time/src/date/withDateOperation/index.ts rename packages/time/src/date/{ => withDateOperation}/withDateOperation.test.ts (76%) rename packages/time/src/date/{ => withDateOperation}/withDateOperation.ts (77%) diff --git a/packages/time/src/date/endOf/tests/endOf.test.ts b/packages/time/src/date/endOf/tests/endOf.test.ts index 85eb943c..d481a5de 100644 --- a/packages/time/src/date/endOf/tests/endOf.test.ts +++ b/packages/time/src/date/endOf/tests/endOf.test.ts @@ -51,10 +51,10 @@ describe('endOf', () => { const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'week' }, { timeZone: 'UTC', }) - const resultDate = new Date(result.value) + const resultDate = new Date(result.asString()) expect(resultDate.getUTCDay()).toBe(0) // Sunday - expect(result.value).toContain('2024-03-17') - expect(result.value).toContain('23:59:59.999') + expect(result.asString()).toContain('2024-03-17') + expect(result.asString()).toContain('23:59:59.999') }) test('should return end of week for Sunday', () => { @@ -62,10 +62,10 @@ describe('endOf', () => { const result = endOf('2024-03-17T14:42:12.789Z', { unit: 'week' }, { timeZone: 'UTC', }) - const resultDate = new Date(result.value) + const resultDate = new Date(result.asString()) expect(resultDate.getUTCDay()).toBe(0) // Sunday - expect(result.value).toContain('2024-03-17') - expect(result.value).toContain('23:59:59.999') + expect(result.asString()).toContain('2024-03-17') + expect(result.asString()).toContain('23:59:59.999') }) test('should return end of week for Monday', () => { @@ -73,9 +73,9 @@ describe('endOf', () => { const result = endOf('2024-03-11T14:42:12.789Z', { unit: 'week' }, { timeZone: 'UTC', }) - const resultDate = new Date(result.value) + const resultDate = new Date(result.asString()) expect(resultDate.getUTCDay()).toBe(0) // Sunday - expect(result.value).toContain('2024-03-17') + expect(result.asString()).toContain('2024-03-17') }) }) diff --git a/packages/time/src/date/withDateOperation/index.ts b/packages/time/src/date/withDateOperation/index.ts new file mode 100644 index 00000000..94e6b468 --- /dev/null +++ b/packages/time/src/date/withDateOperation/index.ts @@ -0,0 +1 @@ +export * from './withDateOperation' diff --git a/packages/time/src/date/withDateOperation.test.ts b/packages/time/src/date/withDateOperation/withDateOperation.test.ts similarity index 76% rename from packages/time/src/date/withDateOperation.test.ts rename to packages/time/src/date/withDateOperation/withDateOperation.test.ts index a26a0f58..615b569d 100644 --- a/packages/time/src/date/withDateOperation.test.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.test.ts @@ -136,7 +136,7 @@ describe('withDateOperation', () => { }) describe('result properties', () => { - test('should have value property as string', () => { + test('should have value property (defaults to string)', () => { const result = mockOperation( '2024-03-15T14:42:12.789Z', { unit: 'test' }, @@ -145,7 +145,8 @@ describe('withDateOperation', () => { }, ) expect(typeof result.value).toBe('string') - expect(result.value).toContain('2024-03-15') + const valueStr = result.value as string + expect(valueStr).toContain('2024-03-15') }) test('should have options property', () => { @@ -187,10 +188,62 @@ describe('withDateOperation', () => { calendar: 'gregory', }, ) - const { value, timeZone, calendar } = result + const { value, timeZone, calendar, returnFormat } = result expect(typeof value).toBe('string') expect(timeZone).toBe('UTC') expect(calendar).toBe('gregory') + expect(returnFormat).toBe('standard') + }) + }) + + describe('returnFormat', () => { + test('should default to standard format', () => { + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'UTC', + }, + ) + expect(result.returnFormat).toBe('standard') + expect(typeof result.value).toBe('string') + expect(result.value).toContain('2024-03-15') + expect(result.value).not.toContain('[') + }) + + test('should return standard format (RFC 3339 string)', () => { + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'UTC', + returnFormat: 'standard', + }, + ) + expect(result.returnFormat).toBe('standard') + expect(typeof result.value).toBe('string') + const valueStr = result.value as string + expect(valueStr).toContain('2024-03-15') + expect(valueStr).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/) + expect(valueStr).not.toContain('[') + }) + + test('should return long format (with timezone and calendar)', () => { + const result = mockOperation( + '2024-03-15T14:42:12.789Z', + { unit: 'test' }, + { + timeZone: 'America/New_York', + calendar: 'gregory', + returnFormat: 'long', + }, + ) + expect(result.returnFormat).toBe('long') + expect(typeof result.value).toBe('string') + const valueStr = result.value as string + expect(valueStr).toContain('2024-03-15') + expect(valueStr).toContain('[America/New_York]') + expect(valueStr).toContain('[u-ca=gregory]') }) }) @@ -225,7 +278,8 @@ describe('withDateOperation', () => { timeZone: 'UTC', }, ) - expect(result.value).toContain('2024-03-30') + const valueStr = result.value as string + expect(valueStr).toContain('2024-03-30') }) }) }) diff --git a/packages/time/src/date/withDateOperation.ts b/packages/time/src/date/withDateOperation/withDateOperation.ts similarity index 77% rename from packages/time/src/date/withDateOperation.ts rename to packages/time/src/date/withDateOperation/withDateOperation.ts index 9ccac187..1c12d3d4 100644 --- a/packages/time/src/date/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.ts @@ -1,6 +1,6 @@ import { Temporal } from '@js-temporal/polyfill' -import { validateDate } from './validateDate' -import { getDateDefaults } from './dateDefaults' +import { validateDate } from '../validateDate' +import { getDateDefaults } from '../dateDefaults' export type DateInput = string | number | Date | Temporal.ZonedDateTime @@ -9,11 +9,16 @@ export interface DateOptions { timeZone?: string } -export interface DateOperationOptions extends DateOptions {} +export type ReturnFormat = 'standard' | 'long' + +export interface DateOperationOptions extends DateOptions { + returnFormat?: ReturnFormat +} export interface DateOperationResult { - value: string + value: string | number | Date | Temporal.ZonedDateTime options: Required + returnFormat: ReturnFormat asDate: () => Date asEpoch: () => number asString: () => string @@ -26,10 +31,23 @@ export interface DateOperationResult { function createDateOperationResult( zdt: Temporal.ZonedDateTime, options: Required, + returnFormat: ReturnFormat = 'standard', ): DateOperationResult { + const getValue = (): string | number | Date | Temporal.ZonedDateTime => { + switch (returnFormat) { + case 'standard': + return zdt.toInstant().toString() + case 'long': + return `${zdt.toInstant().toString()}[${zdt.timeZoneId}][u-ca=${zdt.calendarId}]` + default: + return zdt.toInstant().toString() + } + } + return { - value: zdt.toInstant().toString(), + value: getValue(), options, + returnFormat, asDate: () => { return new Date(Number(zdt.epochNanoseconds / 1_000_000n)) }, @@ -99,6 +117,7 @@ export function withDateOperation>( const defaults = getDateDefaults() const timeZone = options?.timeZone ?? defaults.timeZone const calendar = options?.calendar ?? defaults.calendar + const returnFormat = options?.returnFormat ?? 'standard' const inputZdt = toZonedDateTime(input, timeZone, calendar) const resultZdt = fn(inputZdt, args) @@ -106,6 +125,6 @@ export function withDateOperation>( return createDateOperationResult(resultZdt, { timeZone, calendar, - }) + }, returnFormat) } } diff --git a/packages/time/src/formatter/buildFinalFormatter/tests/buildFinalFormatter.test.ts b/packages/time/src/formatter/buildFinalFormatter/tests/buildFinalFormatter.test.ts index b71a5144..5b91c204 100644 --- a/packages/time/src/formatter/buildFinalFormatter/tests/buildFinalFormatter.test.ts +++ b/packages/time/src/formatter/buildFinalFormatter/tests/buildFinalFormatter.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, test } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { buildFinalFormatter } from '../buildFinalFormatter' const dateTimeFormat = new Intl.DateTimeFormat('en-US', { @@ -15,12 +15,18 @@ const dateTimeFormat = new Intl.DateTimeFormat('en-US', { const timeOnlyFormat = new Intl.DateTimeFormat('en-US', { hour: '2-digit', minute: '2-digit', - // second: '2-digit', - // timeZoneName: 'short', timeZone: 'America/New_York', }) describe('buildFinalFormatter', () => { + beforeEach(() => { + vi.stubEnv('TZ', 'America/New_York') + }) + + afterEach(() => { + vi.unstubAllEnvs() + }) + test('should format a date string', () => { const format = buildFinalFormatter({ formatter: dateTimeFormat, From bb3ba6d463e2c9c173bc4e78d6e4cfd660c6671d Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 20 Jan 2026 11:49:56 +0100 Subject: [PATCH 013/207] feat: utils --- packages/time/src/date/add/add.ts | 34 +++ packages/time/src/date/add/index.ts | 1 + packages/time/src/date/add/tests/add.test.ts | 252 ++++++++++++++++ packages/time/src/date/endOf/endOf.ts | 9 +- .../time/src/date/endOf/tests/endOf.test.ts | 16 +- packages/time/src/date/startOf/startOf.ts | 9 +- packages/time/src/date/subtract/index.ts | 1 + packages/time/src/date/subtract/subtract.ts | 34 +++ .../src/date/subtract/tests/subtract.test.ts | 274 ++++++++++++++++++ packages/time/src/date/types.ts | 8 + packages/time/src/date/until/index.ts | 1 + .../time/src/date/until/tests/until.test.ts | 262 +++++++++++++++++ packages/time/src/date/until/until.ts | 64 ++++ .../withDateOperation/withDateOperation.ts | 27 +- 14 files changed, 949 insertions(+), 43 deletions(-) create mode 100644 packages/time/src/date/add/add.ts create mode 100644 packages/time/src/date/add/index.ts create mode 100644 packages/time/src/date/add/tests/add.test.ts create mode 100644 packages/time/src/date/subtract/index.ts create mode 100644 packages/time/src/date/subtract/subtract.ts create mode 100644 packages/time/src/date/subtract/tests/subtract.test.ts create mode 100644 packages/time/src/date/types.ts create mode 100644 packages/time/src/date/until/index.ts create mode 100644 packages/time/src/date/until/tests/until.test.ts create mode 100644 packages/time/src/date/until/until.ts diff --git a/packages/time/src/date/add/add.ts b/packages/time/src/date/add/add.ts new file mode 100644 index 00000000..76bec52a --- /dev/null +++ b/packages/time/src/date/add/add.ts @@ -0,0 +1,34 @@ +import { withDateOperation } from '../withDateOperation' +import type { DateOperationOptions } from '../withDateOperation' +import type { DateInput } from '../types' + +export interface DurationLike { + years?: number + months?: number + weeks?: number + days?: number + hours?: number + minutes?: number + seconds?: number + milliseconds?: number + microseconds?: number + nanoseconds?: number +} + +export interface AddArgs extends Record { + duration: DurationLike +} + +/** + * add + * Adds a duration to a date/time instance + */ +export function add( + input: DateInput, + args: AddArgs, + options?: DateOperationOptions, +) { + return withDateOperation((zdt, { duration }) => { + return zdt.add(duration) + })(input, args, options) +} diff --git a/packages/time/src/date/add/index.ts b/packages/time/src/date/add/index.ts new file mode 100644 index 00000000..2bed2c4c --- /dev/null +++ b/packages/time/src/date/add/index.ts @@ -0,0 +1 @@ +export * from './add' diff --git a/packages/time/src/date/add/tests/add.test.ts b/packages/time/src/date/add/tests/add.test.ts new file mode 100644 index 00000000..5a8d7d51 --- /dev/null +++ b/packages/time/src/date/add/tests/add.test.ts @@ -0,0 +1,252 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { add } from '../add' + +describe('add', () => { + describe('with string input', () => { + test('should add days', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { days: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-16T14:42:12.789Z') + }) + + test('should add multiple days', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { days: 7 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-22T14:42:12.789Z') + }) + + test('should add hours', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { hours: 2 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T16:42:12.789Z') + }) + + test('should add minutes', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { minutes: 30 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T15:12:12.789Z') + }) + + test('should add seconds', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { seconds: 45 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T14:42:57.789Z') + }) + + test('should add milliseconds', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { milliseconds: 100 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T14:42:12.889Z') + }) + + test('should add months', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { months: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-04-15T14:42:12.789Z') + }) + + test('should add years', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { years: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2025-03-15T14:42:12.789Z') + }) + + test('should add weeks', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { weeks: 2 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-29T14:42:12.789Z') + }) + }) + + describe('with complex duration', () => { + test('should add multiple duration units', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { days: 1, hours: 2, minutes: 30 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-16T17:12:12.789Z') + }) + + test('should handle year and month addition', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { years: 1, months: 2 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2025-05-15T14:42:12.789Z') + }) + }) + + describe('edge cases', () => { + test('should handle month end correctly', () => { + const result = add( + '2024-01-31T00:00:00Z', + { duration: { months: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-02-29T00:00:00Z') + }) + + test('should handle leap year correctly', () => { + const result = add( + '2024-02-29T00:00:00Z', + { duration: { years: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2025-02-28T00:00:00Z') + }) + + test('should handle negative duration (subtraction)', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { days: -1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-14T14:42:12.789Z') + }) + + test('should handle zero duration', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { days: 0 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T14:42:12.789Z') + }) + }) + + describe('with different input types', () => { + test('should work with Date object', () => { + const date = new Date('2024-03-15T14:42:12.789Z') + const result = add( + date, + { duration: { days: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-16T14:42:12.789Z') + }) + + test('should work with epoch time', () => { + const epoch = new Date('2024-03-15T14:42:12.789Z').getTime() + const result = add( + epoch, + { duration: { days: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-16T14:42:12.789Z') + }) + + test('should work with ZonedDateTime', () => { + const zdt = Temporal.ZonedDateTime.from('2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]') + const result = add( + zdt, + { duration: { days: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-16T14:42:12.789Z') + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { hours: 1 } }, + { + timeZone: 'America/New_York', + }, + ) + expect(result.options.timeZone).toBe('America/New_York') + expect(result.value).toContain('2024-03-15') + }) + + test('should return timezone in options', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { days: 1 } }, + { + timeZone: 'Asia/Tokyo', + }, + ) + expect(result.options.timeZone).toBe('Asia/Tokyo') + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = add( + '2024-03-15T14:42:12.789Z', + { duration: { days: 1 } }, + { + calendar: 'japanese', + }, + ) + expect(result.options.calendar).toBe('japanese') + }) + }) +}) diff --git a/packages/time/src/date/endOf/endOf.ts b/packages/time/src/date/endOf/endOf.ts index f4955f55..318c106a 100644 --- a/packages/time/src/date/endOf/endOf.ts +++ b/packages/time/src/date/endOf/endOf.ts @@ -1,9 +1,6 @@ import { withDateOperation } from '../withDateOperation' -import type { - DateInput, - DateOperationOptions, - DateOperationResult, -} from '../withDateOperation' +import type { DateOperationOptions } from '../withDateOperation' +import type { DateInput } from '../types' export type EndOfUnit = | 'year' @@ -27,7 +24,7 @@ export function endOf( input: DateInput, args: EndOfArgs, options?: DateOperationOptions, -): DateOperationResult { +) { return withDateOperation((zdt, { unit }) => { switch (unit) { case 'year': diff --git a/packages/time/src/date/endOf/tests/endOf.test.ts b/packages/time/src/date/endOf/tests/endOf.test.ts index d481a5de..85eb943c 100644 --- a/packages/time/src/date/endOf/tests/endOf.test.ts +++ b/packages/time/src/date/endOf/tests/endOf.test.ts @@ -51,10 +51,10 @@ describe('endOf', () => { const result = endOf('2024-03-15T14:42:12.789Z', { unit: 'week' }, { timeZone: 'UTC', }) - const resultDate = new Date(result.asString()) + const resultDate = new Date(result.value) expect(resultDate.getUTCDay()).toBe(0) // Sunday - expect(result.asString()).toContain('2024-03-17') - expect(result.asString()).toContain('23:59:59.999') + expect(result.value).toContain('2024-03-17') + expect(result.value).toContain('23:59:59.999') }) test('should return end of week for Sunday', () => { @@ -62,10 +62,10 @@ describe('endOf', () => { const result = endOf('2024-03-17T14:42:12.789Z', { unit: 'week' }, { timeZone: 'UTC', }) - const resultDate = new Date(result.asString()) + const resultDate = new Date(result.value) expect(resultDate.getUTCDay()).toBe(0) // Sunday - expect(result.asString()).toContain('2024-03-17') - expect(result.asString()).toContain('23:59:59.999') + expect(result.value).toContain('2024-03-17') + expect(result.value).toContain('23:59:59.999') }) test('should return end of week for Monday', () => { @@ -73,9 +73,9 @@ describe('endOf', () => { const result = endOf('2024-03-11T14:42:12.789Z', { unit: 'week' }, { timeZone: 'UTC', }) - const resultDate = new Date(result.asString()) + const resultDate = new Date(result.value) expect(resultDate.getUTCDay()).toBe(0) // Sunday - expect(result.asString()).toContain('2024-03-17') + expect(result.value).toContain('2024-03-17') }) }) diff --git a/packages/time/src/date/startOf/startOf.ts b/packages/time/src/date/startOf/startOf.ts index 58e3b4f3..69968344 100644 --- a/packages/time/src/date/startOf/startOf.ts +++ b/packages/time/src/date/startOf/startOf.ts @@ -1,9 +1,6 @@ import { withDateOperation } from '../withDateOperation' -import type { - DateInput, - DateOperationOptions, - DateOperationResult, -} from '../withDateOperation' +import type { DateOperationOptions } from '../withDateOperation' +import type { DateInput } from '../types' export type StartOfUnit = | 'year' @@ -27,7 +24,7 @@ export function startOf( input: DateInput, args: StartOfArgs, options?: DateOperationOptions, -): DateOperationResult { +) { return withDateOperation((zdt, { unit }) => { switch (unit) { case 'year': diff --git a/packages/time/src/date/subtract/index.ts b/packages/time/src/date/subtract/index.ts new file mode 100644 index 00000000..8f081bbd --- /dev/null +++ b/packages/time/src/date/subtract/index.ts @@ -0,0 +1 @@ +export * from './subtract' diff --git a/packages/time/src/date/subtract/subtract.ts b/packages/time/src/date/subtract/subtract.ts new file mode 100644 index 00000000..29db5cc1 --- /dev/null +++ b/packages/time/src/date/subtract/subtract.ts @@ -0,0 +1,34 @@ +import { withDateOperation } from '../withDateOperation' +import type { DateOperationOptions } from '../withDateOperation' +import type { DateInput } from '../types' + +export interface DurationLike { + years?: number + months?: number + weeks?: number + days?: number + hours?: number + minutes?: number + seconds?: number + milliseconds?: number + microseconds?: number + nanoseconds?: number +} + +export interface SubtractArgs extends Record { + duration: DurationLike +} + +/** + * subtract + * Subtracts a duration from a date/time instance + */ +export function subtract( + input: DateInput, + args: SubtractArgs, + options?: DateOperationOptions, +) { + return withDateOperation((zdt, { duration }) => { + return zdt.subtract(duration) + })(input, args, options) +} diff --git a/packages/time/src/date/subtract/tests/subtract.test.ts b/packages/time/src/date/subtract/tests/subtract.test.ts new file mode 100644 index 00000000..c559b05c --- /dev/null +++ b/packages/time/src/date/subtract/tests/subtract.test.ts @@ -0,0 +1,274 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { subtract } from '../subtract' + +describe('subtract', () => { + describe('with string input', () => { + test('should subtract days', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { days: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-14T14:42:12.789Z') + }) + + test('should subtract multiple days', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { days: 7 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-08T14:42:12.789Z') + }) + + test('should subtract hours', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { hours: 2 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T12:42:12.789Z') + }) + + test('should subtract minutes', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { minutes: 30 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T14:12:12.789Z') + }) + + test('should subtract seconds', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { seconds: 45 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T14:41:27.789Z') + }) + + test('should subtract milliseconds', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { milliseconds: 100 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T14:42:12.689Z') + }) + + test('should subtract months', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { months: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-02-15T14:42:12.789Z') + }) + + test('should subtract years', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { years: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2023-03-15T14:42:12.789Z') + }) + + test('should subtract weeks', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { weeks: 2 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-01T14:42:12.789Z') + }) + }) + + describe('with complex duration', () => { + test('should subtract multiple duration units', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { days: 1, hours: 2, minutes: 30 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-14T12:12:12.789Z') + }) + + test('should handle year and month subtraction', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { years: 1, months: 2 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2023-01-15T14:42:12.789Z') + }) + }) + + describe('edge cases', () => { + test('should handle month start correctly', () => { + const result = subtract( + '2024-03-01T00:00:00Z', + { duration: { months: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-02-01T00:00:00Z') + }) + + test('should handle leap year correctly', () => { + const result = subtract( + '2024-02-29T00:00:00Z', + { duration: { years: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2023-02-28T00:00:00Z') + }) + + test('should handle negative duration (addition)', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { days: -1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-16T14:42:12.789Z') + }) + + test('should handle zero duration', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { days: 0 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-15T14:42:12.789Z') + }) + + test('should handle crossing year boundary', () => { + const result = subtract( + '2024-01-15T14:42:12.789Z', + { duration: { months: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2023-12-15T14:42:12.789Z') + }) + + test('should handle subtracting more than available', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { days: 100 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2023-12-06T14:42:12.789Z') + }) + }) + + describe('with different input types', () => { + test('should work with Date object', () => { + const date = new Date('2024-03-15T14:42:12.789Z') + const result = subtract( + date, + { duration: { days: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-14T14:42:12.789Z') + }) + + test('should work with epoch time', () => { + const epoch = new Date('2024-03-15T14:42:12.789Z').getTime() + const result = subtract( + epoch, + { duration: { days: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-14T14:42:12.789Z') + }) + + test('should work with ZonedDateTime', () => { + const zdt = Temporal.ZonedDateTime.from('2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]') + const result = subtract( + zdt, + { duration: { days: 1 } }, + { + timeZone: 'UTC', + }, + ) + expect(result.value).toBe('2024-03-14T14:42:12.789Z') + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { hours: 1 } }, + { + timeZone: 'America/New_York', + }, + ) + expect(result.options.timeZone).toBe('America/New_York') + expect(result.value).toContain('2024-03-15') + }) + + test('should return timezone in options', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { days: 1 } }, + { + timeZone: 'Asia/Tokyo', + }, + ) + expect(result.options.timeZone).toBe('Asia/Tokyo') + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = subtract( + '2024-03-15T14:42:12.789Z', + { duration: { days: 1 } }, + { + calendar: 'japanese', + }, + ) + expect(result.options.calendar).toBe('japanese') + }) + }) +}) diff --git a/packages/time/src/date/types.ts b/packages/time/src/date/types.ts new file mode 100644 index 00000000..a1ffbcac --- /dev/null +++ b/packages/time/src/date/types.ts @@ -0,0 +1,8 @@ +import type { Temporal } from "@js-temporal/polyfill" + +export type DateInput = string | number | Date | Temporal.ZonedDateTime + +export interface DateOptions { + calendar?: string + timeZone?: string +} diff --git a/packages/time/src/date/until/index.ts b/packages/time/src/date/until/index.ts new file mode 100644 index 00000000..e6e9d6b3 --- /dev/null +++ b/packages/time/src/date/until/index.ts @@ -0,0 +1 @@ +export * from './until' diff --git a/packages/time/src/date/until/tests/until.test.ts b/packages/time/src/date/until/tests/until.test.ts new file mode 100644 index 00000000..ba7fb4b8 --- /dev/null +++ b/packages/time/src/date/until/tests/until.test.ts @@ -0,0 +1,262 @@ +import { describe, expect, test } from 'vitest' +import { until } from '../until' + +describe('until', () => { + describe('with string inputs', () => { + test('should calculate duration in days', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(1) + }) + + test('should calculate duration in hours', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-03-15T16:42:12.789Z', + { + timeZone: 'UTC', + unit: 'hour', + }, + ) + expect(duration).toBe(2) + }) + + test('should calculate duration in minutes', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:44:12.789Z', + { + timeZone: 'UTC', + unit: 'minute', + }, + ) + expect(duration).toBe(2) + }) + + test('should calculate duration in seconds', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:57.789Z', + { + timeZone: 'UTC', + unit: 'second', + }, + ) + expect(duration).toBe(45) + }) + + test('should calculate duration in milliseconds', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.889Z', + { + timeZone: 'UTC', + unit: 'millisecond', + }, + ) + expect(duration).toBe(100) + }) + + test('should calculate complex duration', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-03-16T17:12:12.789Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBeCloseTo(1.104, 2) + }) + + test('should calculate duration in months', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-04-15T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'month', + }, + ) + expect(duration).toBe(1) + }) + + test('should calculate duration in years', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2025-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'year', + }, + ) + expect(duration).toBe(1) + }) + + test('should calculate duration in weeks', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-03-29T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'week', + }, + ) + expect(duration).toBe(2) + }) + }) + + describe('with negative duration', () => { + test('should return negative duration when end is before start', () => { + const duration = until( + '2024-03-16T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(-1) + }) + + test('should return zero duration when dates are equal', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(0) + }) + }) + + describe('edge cases', () => { + test('should handle month boundaries', () => { + const duration = until( + '2024-03-31T00:00:00Z', + '2024-04-01T00:00:00Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(1) + }) + + test('should handle year boundaries', () => { + const duration = until( + '2024-12-31T00:00:00Z', + '2025-01-01T00:00:00Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(1) + }) + + test('should handle leap years', () => { + const duration = until( + '2024-02-28T00:00:00Z', + '2024-02-29T00:00:00Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(1) + }) + + test('should handle non-leap years', () => { + const duration = until( + '2023-02-28T00:00:00Z', + '2023-03-01T00:00:00Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(1) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const start = new Date('2024-03-15T14:42:12.789Z') + const end = new Date('2024-03-16T14:42:12.789Z') + const duration = until(start, end, { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + + test('should work with epoch time', () => { + const start = new Date('2024-03-15T14:42:12.789Z').getTime() + const end = new Date('2024-03-16T14:42:12.789Z').getTime() + const duration = until(start, end, { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + + test('should work with mixed input types', () => { + const start = '2024-03-15T14:42:12.789Z' + const end = new Date('2024-03-16T14:42:12.789Z') + const duration = until(start, end, { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const duration = until( + '2024-03-15T14:00:00Z', + '2024-03-15T15:00:00Z', + { + timeZone: 'America/New_York', + unit: 'hour', + }, + ) + expect(duration).toBe(1) + }) + + test('should handle different timezones correctly', () => { + const duration = until( + '2024-03-15T00:00:00Z', + '2024-03-15T01:00:00Z', + { + timeZone: 'UTC', + unit: 'hour', + }, + ) + expect(duration).toBe(1) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const duration = until( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + { + calendar: 'japanese', + unit: 'day', + }, + ) + expect(duration).toBe(1) + }) + }) +}) diff --git a/packages/time/src/date/until/until.ts b/packages/time/src/date/until/until.ts new file mode 100644 index 00000000..2cbd3577 --- /dev/null +++ b/packages/time/src/date/until/until.ts @@ -0,0 +1,64 @@ +import { Temporal } from '@js-temporal/polyfill' +import { validateDate } from '../validateDate' +import { getDateDefaults } from '../dateDefaults' +import type { DateInput, DateOptions } from '../types' + +export interface UntilOptions extends DateOptions { + unit: Temporal.DateTimeUnit +} + +function toZonedDateTime( + input: DateInput, + timeZone: string, + calendar: string, +): Temporal.ZonedDateTime { + if (input instanceof Temporal.ZonedDateTime) { + return input + } + + let dateString: string + + if (typeof input === 'string') { + if (input.includes('[') && input.includes(']')) { + return Temporal.ZonedDateTime.from(input) + } + const date = validateDate({ date: input }) + dateString = date.toISOString() + } else if (typeof input === 'number') { + const date = validateDate({ date: input }) + dateString = date.toISOString() + } else if (input instanceof Date) { + const date = validateDate({ date: input }) + dateString = date.toISOString() + } else { + throw new Error(`Invalid date input type: ${typeof input}`) + } + + const zonedDateTimeString = `${dateString}[${timeZone}][u-ca=${calendar}]` + return Temporal.ZonedDateTime.from(zonedDateTimeString) +} + +/** + * until + * Returns the duration from the first date/time instance until the second date/time instance + */ +export function until( + start: DateInput, + end: DateInput, + options: UntilOptions, +) { + const defaults = getDateDefaults() + const timeZone = options.timeZone ?? defaults.timeZone + const calendar = options.calendar ?? defaults.calendar + + const startZdt = toZonedDateTime(start, timeZone, calendar) + const endZdt = toZonedDateTime(end, timeZone, calendar) + + const duration = startZdt.until(endZdt) + const unit = options.unit + + return duration.total({ + unit, + relativeTo: startZdt, + }) +} diff --git a/packages/time/src/date/withDateOperation/withDateOperation.ts b/packages/time/src/date/withDateOperation/withDateOperation.ts index 1c12d3d4..8ecfe6f6 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.ts @@ -1,13 +1,7 @@ import { Temporal } from '@js-temporal/polyfill' import { validateDate } from '../validateDate' import { getDateDefaults } from '../dateDefaults' - -export type DateInput = string | number | Date | Temporal.ZonedDateTime - -export interface DateOptions { - calendar?: string - timeZone?: string -} +import type { DateInput, DateOptions } from '../types' export type ReturnFormat = 'standard' | 'long' @@ -15,25 +9,12 @@ export interface DateOperationOptions extends DateOptions { returnFormat?: ReturnFormat } -export interface DateOperationResult { - value: string | number | Date | Temporal.ZonedDateTime - options: Required - returnFormat: ReturnFormat - asDate: () => Date - asEpoch: () => number - asString: () => string - asLong: () => string - asZonedDateTime: () => Temporal.ZonedDateTime - timeZone: string - calendar: string -} - function createDateOperationResult( zdt: Temporal.ZonedDateTime, options: Required, returnFormat: ReturnFormat = 'standard', -): DateOperationResult { - const getValue = (): string | number | Date | Temporal.ZonedDateTime => { +) { + const getValue = (): string => { switch (returnFormat) { case 'standard': return zdt.toInstant().toString() @@ -113,7 +94,7 @@ export function withDateOperation>( input: DateInput, args: TArgs, options?: DateOperationOptions, - ): DateOperationResult => { + ) => { const defaults = getDateDefaults() const timeZone = options?.timeZone ?? defaults.timeZone const calendar = options?.calendar ?? defaults.calendar From 37e74a4579f6c7be08a532e74124630633376320 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 10:50:54 +0000 Subject: [PATCH 014/207] ci: apply automated fixes --- packages/time/src/date/add/tests/add.test.ts | 4 +- .../src/date/subtract/tests/subtract.test.ts | 4 +- packages/time/src/date/types.ts | 2 +- .../time/src/date/until/tests/until.test.ts | 72 +++++++------------ packages/time/src/date/until/until.ts | 6 +- .../withDateOperation/withDateOperation.ts | 18 ++--- 6 files changed, 41 insertions(+), 65 deletions(-) diff --git a/packages/time/src/date/add/tests/add.test.ts b/packages/time/src/date/add/tests/add.test.ts index 5a8d7d51..7aefd52c 100644 --- a/packages/time/src/date/add/tests/add.test.ts +++ b/packages/time/src/date/add/tests/add.test.ts @@ -200,7 +200,9 @@ describe('add', () => { }) test('should work with ZonedDateTime', () => { - const zdt = Temporal.ZonedDateTime.from('2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]') + const zdt = Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', + ) const result = add( zdt, { duration: { days: 1 } }, diff --git a/packages/time/src/date/subtract/tests/subtract.test.ts b/packages/time/src/date/subtract/tests/subtract.test.ts index c559b05c..db481571 100644 --- a/packages/time/src/date/subtract/tests/subtract.test.ts +++ b/packages/time/src/date/subtract/tests/subtract.test.ts @@ -222,7 +222,9 @@ describe('subtract', () => { }) test('should work with ZonedDateTime', () => { - const zdt = Temporal.ZonedDateTime.from('2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]') + const zdt = Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', + ) const result = subtract( zdt, { duration: { days: 1 } }, diff --git a/packages/time/src/date/types.ts b/packages/time/src/date/types.ts index a1ffbcac..0894fa5b 100644 --- a/packages/time/src/date/types.ts +++ b/packages/time/src/date/types.ts @@ -1,4 +1,4 @@ -import type { Temporal } from "@js-temporal/polyfill" +import type { Temporal } from '@js-temporal/polyfill' export type DateInput = string | number | Date | Temporal.ZonedDateTime diff --git a/packages/time/src/date/until/tests/until.test.ts b/packages/time/src/date/until/tests/until.test.ts index ba7fb4b8..2c6385ed 100644 --- a/packages/time/src/date/until/tests/until.test.ts +++ b/packages/time/src/date/until/tests/until.test.ts @@ -140,50 +140,34 @@ describe('until', () => { describe('edge cases', () => { test('should handle month boundaries', () => { - const duration = until( - '2024-03-31T00:00:00Z', - '2024-04-01T00:00:00Z', - { - timeZone: 'UTC', - unit: 'day', - }, - ) + const duration = until('2024-03-31T00:00:00Z', '2024-04-01T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) expect(duration).toBe(1) }) test('should handle year boundaries', () => { - const duration = until( - '2024-12-31T00:00:00Z', - '2025-01-01T00:00:00Z', - { - timeZone: 'UTC', - unit: 'day', - }, - ) + const duration = until('2024-12-31T00:00:00Z', '2025-01-01T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) expect(duration).toBe(1) }) test('should handle leap years', () => { - const duration = until( - '2024-02-28T00:00:00Z', - '2024-02-29T00:00:00Z', - { - timeZone: 'UTC', - unit: 'day', - }, - ) + const duration = until('2024-02-28T00:00:00Z', '2024-02-29T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) expect(duration).toBe(1) }) test('should handle non-leap years', () => { - const duration = until( - '2023-02-28T00:00:00Z', - '2023-03-01T00:00:00Z', - { - timeZone: 'UTC', - unit: 'day', - }, - ) + const duration = until('2023-02-28T00:00:00Z', '2023-03-01T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) expect(duration).toBe(1) }) }) @@ -222,26 +206,18 @@ describe('until', () => { describe('timezone handling', () => { test('should respect timezone', () => { - const duration = until( - '2024-03-15T14:00:00Z', - '2024-03-15T15:00:00Z', - { - timeZone: 'America/New_York', - unit: 'hour', - }, - ) + const duration = until('2024-03-15T14:00:00Z', '2024-03-15T15:00:00Z', { + timeZone: 'America/New_York', + unit: 'hour', + }) expect(duration).toBe(1) }) test('should handle different timezones correctly', () => { - const duration = until( - '2024-03-15T00:00:00Z', - '2024-03-15T01:00:00Z', - { - timeZone: 'UTC', - unit: 'hour', - }, - ) + const duration = until('2024-03-15T00:00:00Z', '2024-03-15T01:00:00Z', { + timeZone: 'UTC', + unit: 'hour', + }) expect(duration).toBe(1) }) }) diff --git a/packages/time/src/date/until/until.ts b/packages/time/src/date/until/until.ts index 2cbd3577..a75278c2 100644 --- a/packages/time/src/date/until/until.ts +++ b/packages/time/src/date/until/until.ts @@ -42,11 +42,7 @@ function toZonedDateTime( * until * Returns the duration from the first date/time instance until the second date/time instance */ -export function until( - start: DateInput, - end: DateInput, - options: UntilOptions, -) { +export function until(start: DateInput, end: DateInput, options: UntilOptions) { const defaults = getDateDefaults() const timeZone = options.timeZone ?? defaults.timeZone const calendar = options.calendar ?? defaults.calendar diff --git a/packages/time/src/date/withDateOperation/withDateOperation.ts b/packages/time/src/date/withDateOperation/withDateOperation.ts index 8ecfe6f6..b755f722 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.ts @@ -90,11 +90,7 @@ function toZonedDateTime( export function withDateOperation>( fn: (zdt: Temporal.ZonedDateTime, args: TArgs) => Temporal.ZonedDateTime, ) { - return ( - input: DateInput, - args: TArgs, - options?: DateOperationOptions, - ) => { + return (input: DateInput, args: TArgs, options?: DateOperationOptions) => { const defaults = getDateDefaults() const timeZone = options?.timeZone ?? defaults.timeZone const calendar = options?.calendar ?? defaults.calendar @@ -103,9 +99,13 @@ export function withDateOperation>( const inputZdt = toZonedDateTime(input, timeZone, calendar) const resultZdt = fn(inputZdt, args) - return createDateOperationResult(resultZdt, { - timeZone, - calendar, - }, returnFormat) + return createDateOperationResult( + resultZdt, + { + timeZone, + calendar, + }, + returnFormat, + ) } } From c3a958aa4e33dd77dd0750ebee5e26e47c24597f Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 20 Jan 2026 12:14:40 +0100 Subject: [PATCH 015/207] feat: utils --- packages/time/src/date/add/add.ts | 12 +- packages/time/src/date/add/tests/add.test.ts | 233 +++++-------- packages/time/src/date/endOf/endOf.ts | 12 +- .../time/src/date/endOf/tests/endOf.test.ts | 121 +++---- packages/time/src/date/equals/equals.ts | 61 ++++ packages/time/src/date/equals/index.ts | 1 + .../time/src/date/equals/tests/equals.test.ts | 317 ++++++++++++++++++ packages/time/src/date/since/index.ts | 1 + packages/time/src/date/since/since.ts | 61 ++++ .../time/src/date/since/tests/since.test.ts | 255 ++++++++++++++ packages/time/src/date/startOf/startOf.ts | 12 +- .../src/date/startOf/tests/startOf.test.ts | 66 ++-- packages/time/src/date/subtract/subtract.ts | 12 +- .../src/date/subtract/tests/subtract.test.ts | 255 ++++++-------- packages/time/src/date/types.ts | 2 +- .../time/src/date/until/tests/until.test.ts | 72 ++-- packages/time/src/date/until/until.ts | 6 +- .../withDateOperation.test.ts | 218 +++++------- .../withDateOperation/withDateOperation.ts | 28 +- 19 files changed, 1082 insertions(+), 663 deletions(-) create mode 100644 packages/time/src/date/equals/equals.ts create mode 100644 packages/time/src/date/equals/index.ts create mode 100644 packages/time/src/date/equals/tests/equals.test.ts create mode 100644 packages/time/src/date/since/index.ts create mode 100644 packages/time/src/date/since/since.ts create mode 100644 packages/time/src/date/since/tests/since.test.ts diff --git a/packages/time/src/date/add/add.ts b/packages/time/src/date/add/add.ts index 76bec52a..9a18285c 100644 --- a/packages/time/src/date/add/add.ts +++ b/packages/time/src/date/add/add.ts @@ -15,7 +15,7 @@ export interface DurationLike { nanoseconds?: number } -export interface AddArgs extends Record { +export interface AddOptions extends DateOperationOptions { duration: DurationLike } @@ -23,12 +23,8 @@ export interface AddArgs extends Record { * add * Adds a duration to a date/time instance */ -export function add( - input: DateInput, - args: AddArgs, - options?: DateOperationOptions, -) { - return withDateOperation((zdt, { duration }) => { +export function add(input: DateInput, options: AddOptions) { + return withDateOperation((zdt, { duration }) => { return zdt.add(duration) - })(input, args, options) + })(input, options) } diff --git a/packages/time/src/date/add/tests/add.test.ts b/packages/time/src/date/add/tests/add.test.ts index 5a8d7d51..63fd7984 100644 --- a/packages/time/src/date/add/tests/add.test.ts +++ b/packages/time/src/date/add/tests/add.test.ts @@ -5,171 +5,126 @@ import { add } from '../add' describe('add', () => { describe('with string input', () => { test('should add days', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { days: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { days: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-16T14:42:12.789Z') }) test('should add multiple days', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { days: 7 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { days: 7 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-22T14:42:12.789Z') }) test('should add hours', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { hours: 2 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { hours: 2 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T16:42:12.789Z') }) test('should add minutes', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { minutes: 30 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { minutes: 30 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T15:12:12.789Z') }) test('should add seconds', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { seconds: 45 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { seconds: 45 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T14:42:57.789Z') }) test('should add milliseconds', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { milliseconds: 100 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { milliseconds: 100 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T14:42:12.889Z') }) test('should add months', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { months: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { months: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-04-15T14:42:12.789Z') }) test('should add years', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { years: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { years: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2025-03-15T14:42:12.789Z') }) test('should add weeks', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { weeks: 2 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { weeks: 2 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-29T14:42:12.789Z') }) }) describe('with complex duration', () => { test('should add multiple duration units', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { days: 1, hours: 2, minutes: 30 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { days: 1, hours: 2, minutes: 30 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-16T17:12:12.789Z') }) test('should handle year and month addition', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { years: 1, months: 2 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { years: 1, months: 2 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2025-05-15T14:42:12.789Z') }) }) describe('edge cases', () => { test('should handle month end correctly', () => { - const result = add( - '2024-01-31T00:00:00Z', - { duration: { months: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-01-31T00:00:00Z', { + duration: { months: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-02-29T00:00:00Z') }) test('should handle leap year correctly', () => { - const result = add( - '2024-02-29T00:00:00Z', - { duration: { years: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-02-29T00:00:00Z', { + duration: { years: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2025-02-28T00:00:00Z') }) test('should handle negative duration (subtraction)', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { days: -1 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { days: -1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-14T14:42:12.789Z') }) test('should handle zero duration', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { days: 0 } }, - { - timeZone: 'UTC', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { days: 0 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T14:42:12.789Z') }) }) @@ -177,75 +132,59 @@ describe('add', () => { describe('with different input types', () => { test('should work with Date object', () => { const date = new Date('2024-03-15T14:42:12.789Z') - const result = add( - date, - { duration: { days: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = add(date, { + duration: { days: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-16T14:42:12.789Z') }) test('should work with epoch time', () => { const epoch = new Date('2024-03-15T14:42:12.789Z').getTime() - const result = add( - epoch, - { duration: { days: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = add(epoch, { + duration: { days: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-16T14:42:12.789Z') }) test('should work with ZonedDateTime', () => { - const zdt = Temporal.ZonedDateTime.from('2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]') - const result = add( - zdt, - { duration: { days: 1 } }, - { - timeZone: 'UTC', - }, + const zdt = Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', ) + const result = add(zdt, { + duration: { days: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-16T14:42:12.789Z') }) }) describe('timezone handling', () => { test('should respect timezone', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { hours: 1 } }, - { - timeZone: 'America/New_York', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { hours: 1 }, + timeZone: 'America/New_York', + }) expect(result.options.timeZone).toBe('America/New_York') expect(result.value).toContain('2024-03-15') }) test('should return timezone in options', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { days: 1 } }, - { - timeZone: 'Asia/Tokyo', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { days: 1 }, + timeZone: 'Asia/Tokyo', + }) expect(result.options.timeZone).toBe('Asia/Tokyo') }) }) describe('calendar handling', () => { test('should respect calendar', () => { - const result = add( - '2024-03-15T14:42:12.789Z', - { duration: { days: 1 } }, - { - calendar: 'japanese', - }, - ) + const result = add('2024-03-15T14:42:12.789Z', { + duration: { days: 1 }, + calendar: 'japanese', + }) expect(result.options.calendar).toBe('japanese') }) }) diff --git a/packages/time/src/date/endOf/endOf.ts b/packages/time/src/date/endOf/endOf.ts index 07302aba..b469992f 100644 --- a/packages/time/src/date/endOf/endOf.ts +++ b/packages/time/src/date/endOf/endOf.ts @@ -12,7 +12,7 @@ export type EndOfUnit = | 'second' | 'millisecond' -export interface EndOfArgs extends Record { +export interface EndOfOptions extends DateOperationOptions { unit: EndOfUnit } @@ -20,12 +20,8 @@ export interface EndOfArgs extends Record { * endOf * Returns the end of a given unit for a date/time instance */ -export function endOf( - input: DateInput, - args: EndOfArgs, - options?: DateOperationOptions, -) { - return withDateOperation((zdt, { unit }) => { +export function endOf(input: DateInput, options: EndOfOptions) { + return withDateOperation((zdt, { unit }) => { switch (unit) { case 'year': return zdt.with({ @@ -95,5 +91,5 @@ export function endOf( default: return zdt } - })(input, args, options) + })(input, options) } diff --git a/packages/time/src/date/endOf/tests/endOf.test.ts b/packages/time/src/date/endOf/tests/endOf.test.ts index 45229b84..fce14379 100644 --- a/packages/time/src/date/endOf/tests/endOf.test.ts +++ b/packages/time/src/date/endOf/tests/endOf.test.ts @@ -4,35 +4,26 @@ import { endOf } from '../endOf' describe('endOf', () => { describe('with string input', () => { test('should return end of year', () => { - const result = endOf( - '2024-03-15T14:42:12.789Z', - { unit: 'year' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-03-15T14:42:12.789Z', { + unit: 'year', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-12-31T23:59:59.999Z') }) test('should return end of month', () => { - const result = endOf( - '2024-03-15T14:42:12.789Z', - { unit: 'month' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-03-15T14:42:12.789Z', { + unit: 'month', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-31T23:59:59.999Z') }) test('should return end of day', () => { - const result = endOf( - '2024-03-15T14:42:12.789Z', - { unit: 'day' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-03-15T14:42:12.789Z', { + unit: 'day', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T23:59:59.999Z') }) @@ -60,13 +51,10 @@ describe('endOf', () => { describe('week calculation', () => { test('should return end of week (Sunday)', () => { // 2024-03-15 is a Friday (day 5), so end of week should be Sunday (2024-03-17) - const result = endOf( - '2024-03-15T14:42:12.789Z', - { unit: 'week' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-03-15T14:42:12.789Z', { + unit: 'week', + timeZone: 'UTC', + }) const resultDate = new Date(result.value) expect(resultDate.getUTCDay()).toBe(0) // Sunday expect(result.value).toContain('2024-03-17') @@ -75,13 +63,10 @@ describe('endOf', () => { test('should return end of week for Sunday', () => { // 2024-03-17 is a Sunday (day 7), so end of week should be itself - const result = endOf( - '2024-03-17T14:42:12.789Z', - { unit: 'week' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-03-17T14:42:12.789Z', { + unit: 'week', + timeZone: 'UTC', + }) const resultDate = new Date(result.value) expect(resultDate.getUTCDay()).toBe(0) // Sunday expect(result.value).toContain('2024-03-17') @@ -90,13 +75,10 @@ describe('endOf', () => { test('should return end of week for Monday', () => { // 2024-03-11 is a Monday (day 1), so end of week should be Sunday (2024-03-17) - const result = endOf( - '2024-03-11T14:42:12.789Z', - { unit: 'week' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-03-11T14:42:12.789Z', { + unit: 'week', + timeZone: 'UTC', + }) const resultDate = new Date(result.value) expect(resultDate.getUTCDay()).toBe(0) // Sunday expect(result.value).toContain('2024-03-17') @@ -105,57 +87,42 @@ describe('endOf', () => { describe('edge cases', () => { test('should handle end of year for December 31st', () => { - const result = endOf( - '2024-12-31T00:00:00Z', - { unit: 'year' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-12-31T00:00:00Z', { + unit: 'year', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-12-31T23:59:59.999Z') }) test('should handle end of month for last day', () => { - const result = endOf( - '2024-03-31T00:00:00Z', - { unit: 'month' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-03-31T00:00:00Z', { + unit: 'month', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-31T23:59:59.999Z') }) test('should handle end of month for February in leap year', () => { - const result = endOf( - '2024-02-15T00:00:00Z', - { unit: 'month' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-02-15T00:00:00Z', { + unit: 'month', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-02-29T23:59:59.999Z') }) test('should handle end of month for February in non-leap year', () => { - const result = endOf( - '2023-02-15T00:00:00Z', - { unit: 'month' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2023-02-15T00:00:00Z', { + unit: 'month', + timeZone: 'UTC', + }) expect(result.value).toBe('2023-02-28T23:59:59.999Z') }) test('should handle end of day at 23:59:59', () => { - const result = endOf( - '2024-03-15T23:59:59Z', - { unit: 'day' }, - { - timeZone: 'UTC', - }, - ) + const result = endOf('2024-03-15T23:59:59Z', { + unit: 'day', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T23:59:59.999Z') }) diff --git a/packages/time/src/date/equals/equals.ts b/packages/time/src/date/equals/equals.ts new file mode 100644 index 00000000..05b65d55 --- /dev/null +++ b/packages/time/src/date/equals/equals.ts @@ -0,0 +1,61 @@ +import { getDateDefaults } from '../dateDefaults' +import { startOf } from '../startOf/startOf' +import type { DateInput, DateOptions } from '../types' + +export type EqualsUnit = + | 'year' + | 'month' + | 'week' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'millisecond' + +export interface EqualsOptions extends DateOptions {} + +/** + * equals + * Returns true if two date/time instances are equal at the specified unit level + */ +export function equals( + date1: DateInput, + date2: DateInput, + unit: EqualsUnit, + options?: EqualsOptions, +): boolean { + const defaults = getDateDefaults() + const timeZone = options?.timeZone ?? defaults.timeZone + const calendar = options?.calendar ?? defaults.calendar + + const startOf1 = startOf(date1, { unit, timeZone, calendar }) + const startOf2 = startOf(date2, { unit, timeZone, calendar }) + + const zdt1 = startOf1.asZonedDateTime() + const zdt2 = startOf2.asZonedDateTime() + + if (unit === 'week') { + const normalized1 = zdt1.with({ + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + }) + const normalized2 = zdt2.with({ + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + }) + return ( + normalized1.toInstant().epochNanoseconds === + normalized2.toInstant().epochNanoseconds + ) + } + + return zdt1.toInstant().epochNanoseconds === zdt2.toInstant().epochNanoseconds +} diff --git a/packages/time/src/date/equals/index.ts b/packages/time/src/date/equals/index.ts new file mode 100644 index 00000000..cf0ebec5 --- /dev/null +++ b/packages/time/src/date/equals/index.ts @@ -0,0 +1 @@ +export * from './equals' diff --git a/packages/time/src/date/equals/tests/equals.test.ts b/packages/time/src/date/equals/tests/equals.test.ts new file mode 100644 index 00000000..d2fd395c --- /dev/null +++ b/packages/time/src/date/equals/tests/equals.test.ts @@ -0,0 +1,317 @@ +import { describe, expect, test } from 'vitest' +import { equals } from '../equals' + +describe('equals', () => { + describe('with string inputs', () => { + test('should return true for same year', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-12-31T23:59:59.999Z', + 'year', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false for different years', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2025-03-15T14:42:12.789Z', + 'year', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should return true for same month', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-31T23:59:59.999Z', + 'month', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false for different months', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-04-15T14:42:12.789Z', + 'month', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should return true for same week', () => { + const result = equals( + '2024-03-11T00:00:00Z', + '2024-03-17T23:59:59.999Z', + 'week', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false for different weeks', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-18T14:42:12.789Z', + 'week', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should return true for same day', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T23:59:59.999Z', + 'day', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false for different days', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + 'day', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should return true for same hour', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:59:59.999Z', + 'hour', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false for different hours', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T15:42:12.789Z', + 'hour', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should return true for same minute', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:59.999Z', + 'minute', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false for different minutes', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:43:12.789Z', + 'minute', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should return true for same second', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.999Z', + 'second', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false for different seconds', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:13.789Z', + 'second', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should return true for same millisecond', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + 'millisecond', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false for different milliseconds', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.790Z', + 'millisecond', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + }) + + describe('edge cases', () => { + test('should handle year boundaries', () => { + const result = equals( + '2024-12-31T23:59:59.999Z', + '2025-01-01T00:00:00.000Z', + 'year', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should handle month boundaries', () => { + const result = equals( + '2024-03-31T23:59:59.999Z', + '2024-04-01T00:00:00.000Z', + 'month', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should handle leap years', () => { + const result = equals( + '2024-02-28T00:00:00Z', + '2024-02-29T00:00:00Z', + 'month', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle non-leap years', () => { + const result = equals( + '2023-02-28T00:00:00Z', + '2023-03-01T00:00:00Z', + 'month', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const date1 = new Date('2024-03-15T14:42:12.789Z') + const date2 = new Date('2024-03-15T23:59:59.999Z') + const result = equals(date1, date2, 'day', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const date1 = new Date('2024-03-15T14:42:12.789Z').getTime() + const date2 = new Date('2024-03-15T23:59:59.999Z').getTime() + const result = equals(date1, date2, 'day', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with mixed input types', () => { + const date1 = '2024-03-15T14:42:12.789Z' + const date2 = new Date('2024-03-15T23:59:59.999Z') + const result = equals(date1, date2, 'day', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = equals( + '2024-03-15T14:00:00Z', + '2024-03-15T19:00:00Z', + 'day', + { + timeZone: 'America/New_York', + }, + ) + expect(result).toBe(true) + }) + + test('should handle different timezones correctly', () => { + const result = equals( + '2024-03-15T00:00:00Z', + '2024-03-16T00:00:00Z', + 'day', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = equals( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + 'day', + { + calendar: 'japanese', + }, + ) + expect(result).toBe(true) + }) + }) +}) diff --git a/packages/time/src/date/since/index.ts b/packages/time/src/date/since/index.ts new file mode 100644 index 00000000..f84080e9 --- /dev/null +++ b/packages/time/src/date/since/index.ts @@ -0,0 +1 @@ +export * from './since' diff --git a/packages/time/src/date/since/since.ts b/packages/time/src/date/since/since.ts new file mode 100644 index 00000000..f07e34e4 --- /dev/null +++ b/packages/time/src/date/since/since.ts @@ -0,0 +1,61 @@ +import { Temporal } from '@js-temporal/polyfill' +import { validateDate } from '../validateDate' +import { getDateDefaults } from '../dateDefaults' +import type { DateInput, DateOptions } from '../types' + +export interface SinceOptions extends DateOptions { + unit: Temporal.DateTimeUnit +} + +function toZonedDateTime( + input: DateInput, + timeZone: string, + calendar: string, +): Temporal.ZonedDateTime { + if (input instanceof Temporal.ZonedDateTime) { + return input + } + + let dateString: string + + if (typeof input === 'string') { + if (input.includes('[') && input.includes(']')) { + return Temporal.ZonedDateTime.from(input) + } + const date = validateDate({ date: input }) + dateString = date.toISOString() + } else if (typeof input === 'number') { + const date = validateDate({ date: input }) + dateString = date.toISOString() + } else if (input instanceof Date) { + const date = validateDate({ date: input }) + dateString = date.toISOString() + } else { + throw new Error(`Invalid date input type: ${typeof input}`) + } + + const zonedDateTimeString = `${dateString}[${timeZone}][u-ca=${calendar}]` + return Temporal.ZonedDateTime.from(zonedDateTimeString) +} + +/** + * since + * Returns the duration from the first date/time instance since the second date/time instance + * (equivalent to: how long has it been since the second date, from the first date's perspective) + */ +export function since(start: DateInput, end: DateInput, options: SinceOptions) { + const defaults = getDateDefaults() + const timeZone = options.timeZone ?? defaults.timeZone + const calendar = options.calendar ?? defaults.calendar + + const startZdt = toZonedDateTime(start, timeZone, calendar) + const endZdt = toZonedDateTime(end, timeZone, calendar) + + const duration = endZdt.since(startZdt) + const unit = options.unit + + return duration.total({ + unit, + relativeTo: startZdt, + }) +} diff --git a/packages/time/src/date/since/tests/since.test.ts b/packages/time/src/date/since/tests/since.test.ts new file mode 100644 index 00000000..ce38ae07 --- /dev/null +++ b/packages/time/src/date/since/tests/since.test.ts @@ -0,0 +1,255 @@ +import { describe, expect, test } from 'vitest' +import { since } from '../since' +import { until } from '../../until/until' + +describe('since', () => { + describe('with string inputs', () => { + test('should calculate duration in days', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(1) + }) + + test('should calculate duration in hours', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-03-15T16:42:12.789Z', + { + timeZone: 'UTC', + unit: 'hour', + }, + ) + expect(duration).toBe(2) + }) + + test('should calculate duration in minutes', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:44:12.789Z', + { + timeZone: 'UTC', + unit: 'minute', + }, + ) + expect(duration).toBe(2) + }) + + test('should calculate duration in seconds', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:57.789Z', + { + timeZone: 'UTC', + unit: 'second', + }, + ) + expect(duration).toBe(45) + }) + + test('should calculate duration in milliseconds', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.889Z', + { + timeZone: 'UTC', + unit: 'millisecond', + }, + ) + expect(duration).toBe(100) + }) + + test('should calculate complex duration', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-03-16T17:12:12.789Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBeCloseTo(1.104, 2) + }) + + test('should calculate duration in months', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-04-15T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'month', + }, + ) + expect(duration).toBe(1) + }) + + test('should calculate duration in years', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2025-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'year', + }, + ) + expect(duration).toBe(1) + }) + + test('should calculate duration in weeks', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-03-29T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'week', + }, + ) + expect(duration).toBe(2) + }) + }) + + describe('with negative duration', () => { + test('should return negative duration when end is before start', () => { + const duration = since( + '2024-03-16T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(-1) + }) + + test('should return zero duration when dates are equal', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + unit: 'day', + }, + ) + expect(duration).toBe(0) + }) + }) + + describe('edge cases', () => { + test('should handle month boundaries', () => { + const duration = since('2024-03-31T00:00:00Z', '2024-04-01T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + + test('should handle year boundaries', () => { + const duration = since('2024-12-31T00:00:00Z', '2025-01-01T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + + test('should handle leap years', () => { + const duration = since('2024-02-28T00:00:00Z', '2024-02-29T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + + test('should handle non-leap years', () => { + const duration = since('2023-02-28T00:00:00Z', '2023-03-01T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const start = new Date('2024-03-15T14:42:12.789Z') + const end = new Date('2024-03-16T14:42:12.789Z') + const duration = since(start, end, { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + + test('should work with epoch time', () => { + const start = new Date('2024-03-15T14:42:12.789Z').getTime() + const end = new Date('2024-03-16T14:42:12.789Z').getTime() + const duration = since(start, end, { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + + test('should work with mixed input types', () => { + const start = '2024-03-15T14:42:12.789Z' + const end = new Date('2024-03-16T14:42:12.789Z') + const duration = since(start, end, { + timeZone: 'UTC', + unit: 'day', + }) + expect(duration).toBe(1) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const duration = since('2024-03-15T14:00:00Z', '2024-03-15T15:00:00Z', { + timeZone: 'America/New_York', + unit: 'hour', + }) + expect(duration).toBe(1) + }) + + test('should handle different timezones correctly', () => { + const duration = since('2024-03-15T00:00:00Z', '2024-03-15T01:00:00Z', { + timeZone: 'UTC', + unit: 'hour', + }) + expect(duration).toBe(1) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const duration = since( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + { + calendar: 'japanese', + unit: 'day', + }, + ) + expect(duration).toBe(1) + }) + }) + + describe('comparison with until', () => { + test('should return same result as until', () => { + const start = '2024-03-15T14:42:12.789Z' + const end = '2024-03-16T14:42:12.789Z' + const options = { + timeZone: 'UTC' as const, + unit: 'day' as const, + } + + const sinceResult = since(start, end, options) + const untilResult = until(start, end, options) + + expect(sinceResult).toBe(untilResult) + }) + }) +}) diff --git a/packages/time/src/date/startOf/startOf.ts b/packages/time/src/date/startOf/startOf.ts index 69968344..d88c0e97 100644 --- a/packages/time/src/date/startOf/startOf.ts +++ b/packages/time/src/date/startOf/startOf.ts @@ -12,7 +12,7 @@ export type StartOfUnit = | 'second' | 'millisecond' -export interface StartOfArgs extends Record { +export interface StartOfOptions extends DateOperationOptions { unit: StartOfUnit } @@ -20,12 +20,8 @@ export interface StartOfArgs extends Record { * startOf * Returns the start of a given unit for a date/time instance */ -export function startOf( - input: DateInput, - args: StartOfArgs, - options?: DateOperationOptions, -) { - return withDateOperation((zdt, { unit }) => { +export function startOf(input: DateInput, options: StartOfOptions) { + return withDateOperation((zdt, { unit }) => { switch (unit) { case 'year': return zdt.with({ @@ -85,5 +81,5 @@ export function startOf( default: return zdt } - })(input, args, options) + })(input, options) } diff --git a/packages/time/src/date/startOf/tests/startOf.test.ts b/packages/time/src/date/startOf/tests/startOf.test.ts index e9abb4d9..b557936d 100644 --- a/packages/time/src/date/startOf/tests/startOf.test.ts +++ b/packages/time/src/date/startOf/tests/startOf.test.ts @@ -4,37 +4,28 @@ import { startOf } from '../startOf' describe('startOf', () => { describe('with string input', () => { test('should return start of year', () => { - const result = startOf( - '2024-03-15T14:42:12.789Z', - { unit: 'year' }, - { - timeZone: 'UTC', - }, - ) + const result = startOf('2024-03-15T14:42:12.789Z', { + unit: 'year', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-01-01T00:00:00Z') expect(result.options.timeZone).toBe('UTC') expect(result.options.calendar).toBeDefined() }) test('should return start of month', () => { - const result = startOf( - '2024-03-15T14:42:12.789Z', - { unit: 'month' }, - { - timeZone: 'UTC', - }, - ) + const result = startOf('2024-03-15T14:42:12.789Z', { + unit: 'month', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-01T00:00:00Z') }) test('should return start of day', () => { - const result = startOf( - '2024-03-15T14:42:12.789Z', - { unit: 'day' }, - { - timeZone: 'UTC', - }, - ) + const result = startOf('2024-03-15T14:42:12.789Z', { + unit: 'day', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T00:00:00Z') }) @@ -87,35 +78,26 @@ describe('startOf', () => { describe('edge cases', () => { test('should handle start of year for January 1st', () => { - const result = startOf( - '2024-01-01T00:00:00Z', - { unit: 'year' }, - { - timeZone: 'UTC', - }, - ) + const result = startOf('2024-01-01T00:00:00Z', { + unit: 'year', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-01-01T00:00:00Z') }) test('should handle start of month for first day', () => { - const result = startOf( - '2024-03-01T00:00:00Z', - { unit: 'month' }, - { - timeZone: 'UTC', - }, - ) + const result = startOf('2024-03-01T00:00:00Z', { + unit: 'month', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-01T00:00:00Z') }) test('should handle start of day at midnight', () => { - const result = startOf( - '2024-03-15T00:00:00Z', - { unit: 'day' }, - { - timeZone: 'UTC', - }, - ) + const result = startOf('2024-03-15T00:00:00Z', { + unit: 'day', + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T00:00:00Z') }) diff --git a/packages/time/src/date/subtract/subtract.ts b/packages/time/src/date/subtract/subtract.ts index 29db5cc1..977cd064 100644 --- a/packages/time/src/date/subtract/subtract.ts +++ b/packages/time/src/date/subtract/subtract.ts @@ -15,7 +15,7 @@ export interface DurationLike { nanoseconds?: number } -export interface SubtractArgs extends Record { +export interface SubtractOptions extends DateOperationOptions { duration: DurationLike } @@ -23,12 +23,8 @@ export interface SubtractArgs extends Record { * subtract * Subtracts a duration from a date/time instance */ -export function subtract( - input: DateInput, - args: SubtractArgs, - options?: DateOperationOptions, -) { - return withDateOperation((zdt, { duration }) => { +export function subtract(input: DateInput, options: SubtractOptions) { + return withDateOperation((zdt, { duration }) => { return zdt.subtract(duration) - })(input, args, options) + })(input, options) } diff --git a/packages/time/src/date/subtract/tests/subtract.test.ts b/packages/time/src/date/subtract/tests/subtract.test.ts index c559b05c..55d17f5b 100644 --- a/packages/time/src/date/subtract/tests/subtract.test.ts +++ b/packages/time/src/date/subtract/tests/subtract.test.ts @@ -5,193 +5,142 @@ import { subtract } from '../subtract' describe('subtract', () => { describe('with string input', () => { test('should subtract days', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { days: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { days: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-14T14:42:12.789Z') }) test('should subtract multiple days', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { days: 7 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { days: 7 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-08T14:42:12.789Z') }) test('should subtract hours', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { hours: 2 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { hours: 2 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T12:42:12.789Z') }) test('should subtract minutes', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { minutes: 30 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { minutes: 30 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T14:12:12.789Z') }) test('should subtract seconds', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { seconds: 45 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { seconds: 45 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T14:41:27.789Z') }) test('should subtract milliseconds', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { milliseconds: 100 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { milliseconds: 100 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T14:42:12.689Z') }) test('should subtract months', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { months: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { months: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-02-15T14:42:12.789Z') }) test('should subtract years', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { years: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { years: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2023-03-15T14:42:12.789Z') }) test('should subtract weeks', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { weeks: 2 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { weeks: 2 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-01T14:42:12.789Z') }) }) describe('with complex duration', () => { test('should subtract multiple duration units', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { days: 1, hours: 2, minutes: 30 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { days: 1, hours: 2, minutes: 30 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-14T12:12:12.789Z') }) test('should handle year and month subtraction', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { years: 1, months: 2 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { years: 1, months: 2 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2023-01-15T14:42:12.789Z') }) }) describe('edge cases', () => { test('should handle month start correctly', () => { - const result = subtract( - '2024-03-01T00:00:00Z', - { duration: { months: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-01T00:00:00Z', { + duration: { months: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-02-01T00:00:00Z') }) test('should handle leap year correctly', () => { - const result = subtract( - '2024-02-29T00:00:00Z', - { duration: { years: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-02-29T00:00:00Z', { + duration: { years: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2023-02-28T00:00:00Z') }) test('should handle negative duration (addition)', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { days: -1 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { days: -1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-16T14:42:12.789Z') }) test('should handle zero duration', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { days: 0 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { days: 0 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-15T14:42:12.789Z') }) test('should handle crossing year boundary', () => { - const result = subtract( - '2024-01-15T14:42:12.789Z', - { duration: { months: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-01-15T14:42:12.789Z', { + duration: { months: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2023-12-15T14:42:12.789Z') }) test('should handle subtracting more than available', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { days: 100 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { days: 100 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2023-12-06T14:42:12.789Z') }) }) @@ -199,75 +148,59 @@ describe('subtract', () => { describe('with different input types', () => { test('should work with Date object', () => { const date = new Date('2024-03-15T14:42:12.789Z') - const result = subtract( - date, - { duration: { days: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract(date, { + duration: { days: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-14T14:42:12.789Z') }) test('should work with epoch time', () => { const epoch = new Date('2024-03-15T14:42:12.789Z').getTime() - const result = subtract( - epoch, - { duration: { days: 1 } }, - { - timeZone: 'UTC', - }, - ) + const result = subtract(epoch, { + duration: { days: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-14T14:42:12.789Z') }) test('should work with ZonedDateTime', () => { - const zdt = Temporal.ZonedDateTime.from('2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]') - const result = subtract( - zdt, - { duration: { days: 1 } }, - { - timeZone: 'UTC', - }, + const zdt = Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', ) + const result = subtract(zdt, { + duration: { days: 1 }, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-14T14:42:12.789Z') }) }) describe('timezone handling', () => { test('should respect timezone', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { hours: 1 } }, - { - timeZone: 'America/New_York', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { hours: 1 }, + timeZone: 'America/New_York', + }) expect(result.options.timeZone).toBe('America/New_York') expect(result.value).toContain('2024-03-15') }) test('should return timezone in options', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { days: 1 } }, - { - timeZone: 'Asia/Tokyo', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { days: 1 }, + timeZone: 'Asia/Tokyo', + }) expect(result.options.timeZone).toBe('Asia/Tokyo') }) }) describe('calendar handling', () => { test('should respect calendar', () => { - const result = subtract( - '2024-03-15T14:42:12.789Z', - { duration: { days: 1 } }, - { - calendar: 'japanese', - }, - ) + const result = subtract('2024-03-15T14:42:12.789Z', { + duration: { days: 1 }, + calendar: 'japanese', + }) expect(result.options.calendar).toBe('japanese') }) }) diff --git a/packages/time/src/date/types.ts b/packages/time/src/date/types.ts index a1ffbcac..0894fa5b 100644 --- a/packages/time/src/date/types.ts +++ b/packages/time/src/date/types.ts @@ -1,4 +1,4 @@ -import type { Temporal } from "@js-temporal/polyfill" +import type { Temporal } from '@js-temporal/polyfill' export type DateInput = string | number | Date | Temporal.ZonedDateTime diff --git a/packages/time/src/date/until/tests/until.test.ts b/packages/time/src/date/until/tests/until.test.ts index ba7fb4b8..2c6385ed 100644 --- a/packages/time/src/date/until/tests/until.test.ts +++ b/packages/time/src/date/until/tests/until.test.ts @@ -140,50 +140,34 @@ describe('until', () => { describe('edge cases', () => { test('should handle month boundaries', () => { - const duration = until( - '2024-03-31T00:00:00Z', - '2024-04-01T00:00:00Z', - { - timeZone: 'UTC', - unit: 'day', - }, - ) + const duration = until('2024-03-31T00:00:00Z', '2024-04-01T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) expect(duration).toBe(1) }) test('should handle year boundaries', () => { - const duration = until( - '2024-12-31T00:00:00Z', - '2025-01-01T00:00:00Z', - { - timeZone: 'UTC', - unit: 'day', - }, - ) + const duration = until('2024-12-31T00:00:00Z', '2025-01-01T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) expect(duration).toBe(1) }) test('should handle leap years', () => { - const duration = until( - '2024-02-28T00:00:00Z', - '2024-02-29T00:00:00Z', - { - timeZone: 'UTC', - unit: 'day', - }, - ) + const duration = until('2024-02-28T00:00:00Z', '2024-02-29T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) expect(duration).toBe(1) }) test('should handle non-leap years', () => { - const duration = until( - '2023-02-28T00:00:00Z', - '2023-03-01T00:00:00Z', - { - timeZone: 'UTC', - unit: 'day', - }, - ) + const duration = until('2023-02-28T00:00:00Z', '2023-03-01T00:00:00Z', { + timeZone: 'UTC', + unit: 'day', + }) expect(duration).toBe(1) }) }) @@ -222,26 +206,18 @@ describe('until', () => { describe('timezone handling', () => { test('should respect timezone', () => { - const duration = until( - '2024-03-15T14:00:00Z', - '2024-03-15T15:00:00Z', - { - timeZone: 'America/New_York', - unit: 'hour', - }, - ) + const duration = until('2024-03-15T14:00:00Z', '2024-03-15T15:00:00Z', { + timeZone: 'America/New_York', + unit: 'hour', + }) expect(duration).toBe(1) }) test('should handle different timezones correctly', () => { - const duration = until( - '2024-03-15T00:00:00Z', - '2024-03-15T01:00:00Z', - { - timeZone: 'UTC', - unit: 'hour', - }, - ) + const duration = until('2024-03-15T00:00:00Z', '2024-03-15T01:00:00Z', { + timeZone: 'UTC', + unit: 'hour', + }) expect(duration).toBe(1) }) }) diff --git a/packages/time/src/date/until/until.ts b/packages/time/src/date/until/until.ts index 2cbd3577..a75278c2 100644 --- a/packages/time/src/date/until/until.ts +++ b/packages/time/src/date/until/until.ts @@ -42,11 +42,7 @@ function toZonedDateTime( * until * Returns the duration from the first date/time instance until the second date/time instance */ -export function until( - start: DateInput, - end: DateInput, - options: UntilOptions, -) { +export function until(start: DateInput, end: DateInput, options: UntilOptions) { const defaults = getDateDefaults() const timeZone = options.timeZone ?? defaults.timeZone const calendar = options.calendar ?? defaults.calendar diff --git a/packages/time/src/date/withDateOperation/withDateOperation.test.ts b/packages/time/src/date/withDateOperation/withDateOperation.test.ts index 615b569d..feb988a0 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.test.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.test.ts @@ -3,7 +3,7 @@ import { Temporal } from '@js-temporal/polyfill' import { withDateOperation } from './withDateOperation' describe('withDateOperation', () => { - const mockOperation = withDateOperation((zdt) => zdt) + const mockOperation = withDateOperation((zdt, _args: { unit: string }) => zdt) describe('timezone handling', () => { test('should use default timezone when not provided', () => { @@ -13,24 +13,18 @@ describe('withDateOperation', () => { }) test('should use custom timezone', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'Asia/Tokyo', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'Asia/Tokyo', + }) expect(result.options.timeZone).toBe('Asia/Tokyo') }) test('should return timezone in options', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'Europe/London', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'Europe/London', + }) expect(result.options.timeZone).toBe('Europe/London') }) }) @@ -43,77 +37,59 @@ describe('withDateOperation', () => { }) test('should use custom calendar', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - calendar: 'japanese', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + calendar: 'japanese', + }) expect(result.options.calendar).toBe('japanese') }) test('should return calendar in options', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - calendar: 'islamic', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + calendar: 'islamic', + }) expect(result.options.calendar).toBe('islamic') }) }) describe('conversion methods', () => { test('should have asDate method', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'UTC', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'UTC', + }) const date = result.asDate() expect(date).toBeInstanceOf(Date) expect(date.toISOString()).toContain('2024-03-15') }) test('should have asEpoch method', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'UTC', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'UTC', + }) const epoch = result.asEpoch() expect(typeof epoch).toBe('number') expect(new Date(epoch).toISOString()).toContain('2024-03-15') }) test('should have asString method', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'UTC', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'UTC', + }) const str = result.asString() expect(typeof str).toBe('string') expect(str).toContain('2024-03-15') }) test('should have asLong method', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'America/New_York', - calendar: 'gregory', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'America/New_York', + calendar: 'gregory', + }) const long = result.asLong() expect(typeof long).toBe('string') expect(long).toContain('2024-03-15') @@ -122,13 +98,10 @@ describe('withDateOperation', () => { }) test('should have asZonedDateTime method', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'UTC', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'UTC', + }) const zdt = result.asZonedDateTime() expect(zdt).toBeInstanceOf(Temporal.ZonedDateTime) expect(zdt.toInstant().toString()).toContain('2024-03-15') @@ -137,13 +110,10 @@ describe('withDateOperation', () => { describe('result properties', () => { test('should have value property (defaults to string)', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'UTC', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'UTC', + }) expect(typeof result.value).toBe('string') const valueStr = result.value as string expect(valueStr).toContain('2024-03-15') @@ -158,36 +128,27 @@ describe('withDateOperation', () => { }) test('should have timeZone property', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'Asia/Tokyo', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'Asia/Tokyo', + }) expect(result.timeZone).toBe('Asia/Tokyo') }) test('should have calendar property', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - calendar: 'japanese', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + calendar: 'japanese', + }) expect(result.calendar).toBe('japanese') }) test('should support destructuring', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'UTC', - calendar: 'gregory', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'UTC', + calendar: 'gregory', + }) const { value, timeZone, calendar, returnFormat } = result expect(typeof value).toBe('string') expect(timeZone).toBe('UTC') @@ -198,13 +159,10 @@ describe('withDateOperation', () => { describe('returnFormat', () => { test('should default to standard format', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'UTC', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'UTC', + }) expect(result.returnFormat).toBe('standard') expect(typeof result.value).toBe('string') expect(result.value).toContain('2024-03-15') @@ -212,14 +170,11 @@ describe('withDateOperation', () => { }) test('should return standard format (RFC 3339 string)', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'UTC', - returnFormat: 'standard', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'UTC', + returnFormat: 'standard', + }) expect(result.returnFormat).toBe('standard') expect(typeof result.value).toBe('string') const valueStr = result.value as string @@ -229,15 +184,12 @@ describe('withDateOperation', () => { }) test('should return long format (with timezone and calendar)', () => { - const result = mockOperation( - '2024-03-15T14:42:12.789Z', - { unit: 'test' }, - { - timeZone: 'America/New_York', - calendar: 'gregory', - returnFormat: 'long', - }, - ) + const result = mockOperation('2024-03-15T14:42:12.789Z', { + unit: 'test', + timeZone: 'America/New_York', + calendar: 'gregory', + returnFormat: 'long', + }) expect(result.returnFormat).toBe('long') expect(typeof result.value).toBe('string') const valueStr = result.value as string @@ -249,35 +201,29 @@ describe('withDateOperation', () => { describe('operation execution', () => { test('should execute the provided operation function', () => { - const addDayOperation = withDateOperation<{ days: number }>( - (zdt, { days }) => { + const addDayOperation = withDateOperation( + (zdt, { days }: { days: number }) => { return zdt.add({ days }) }, ) - const result = addDayOperation( - '2024-03-15T00:00:00Z', - { days: 1 }, - { - timeZone: 'UTC', - }, - ) + const result = addDayOperation('2024-03-15T00:00:00Z', { + days: 1, + timeZone: 'UTC', + }) expect(result.value).toBe('2024-03-16T00:00:00Z') }) test('should pass args to the operation function', () => { - const customOperation = withDateOperation<{ multiplier: number }>( - (zdt, { multiplier }) => { + const customOperation = withDateOperation( + (zdt, { multiplier }: { multiplier: number }) => { const days = zdt.day * multiplier return zdt.with({ day: days }) }, ) - const result = customOperation( - '2024-03-15T00:00:00Z', - { multiplier: 2 }, - { - timeZone: 'UTC', - }, - ) + const result = customOperation('2024-03-15T00:00:00Z', { + multiplier: 2, + timeZone: 'UTC', + }) const valueStr = result.value as string expect(valueStr).toContain('2024-03-30') }) diff --git a/packages/time/src/date/withDateOperation/withDateOperation.ts b/packages/time/src/date/withDateOperation/withDateOperation.ts index 8ecfe6f6..fdc2530b 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.ts @@ -87,25 +87,25 @@ function toZonedDateTime( * Higher-order function that provides common parsing, defaults, and formatting logic * for date utility functions like startOf, endOf, etc. */ -export function withDateOperation>( +export function withDateOperation( fn: (zdt: Temporal.ZonedDateTime, args: TArgs) => Temporal.ZonedDateTime, ) { - return ( - input: DateInput, - args: TArgs, - options?: DateOperationOptions, - ) => { + return (input: DateInput, options: DateOperationOptions & TArgs) => { const defaults = getDateDefaults() - const timeZone = options?.timeZone ?? defaults.timeZone - const calendar = options?.calendar ?? defaults.calendar - const returnFormat = options?.returnFormat ?? 'standard' + const timeZone = options.timeZone ?? defaults.timeZone + const calendar = options.calendar ?? defaults.calendar + const returnFormat = options.returnFormat ?? 'standard' const inputZdt = toZonedDateTime(input, timeZone, calendar) - const resultZdt = fn(inputZdt, args) + const resultZdt = fn(inputZdt, options) - return createDateOperationResult(resultZdt, { - timeZone, - calendar, - }, returnFormat) + return createDateOperationResult( + resultZdt, + { + timeZone, + calendar, + }, + returnFormat, + ) } } From 35e7ec8314b1cecbd8a89f565a7b9d153d868839 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:16:17 +0000 Subject: [PATCH 016/207] ci: apply automated fixes --- docs/reference/index.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 docs/reference/index.md diff --git a/docs/reference/index.md b/docs/reference/index.md deleted file mode 100644 index b14fbe49..00000000 --- a/docs/reference/index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -id: "@tanstack/time" -title: "@tanstack/time" ---- - -# @tanstack/time From 68abe5069446b2ed47de6b550cce87a50096d3ba Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 20 Jan 2026 12:52:17 +0100 Subject: [PATCH 017/207] feat: date comparition utils --- Methods.md | 22 +-- packages/time/src/date/add/add.ts | 15 +- packages/time/src/date/equals/equals.ts | 19 +- packages/time/src/date/helpers/index.ts | 2 + .../time/src/date/helpers/normalizeWeek.ts | 18 ++ .../time/src/date/helpers/toZonedDateTime.ts | 34 ++++ packages/time/src/date/index.ts | 11 ++ packages/time/src/date/isAfter/index.ts | 2 + packages/time/src/date/isAfter/isAfter.ts | 25 +++ .../src/date/isAfter/tests/isAfter.test.ts | 178 +++++++++++++++++ packages/time/src/date/isBefore/index.ts | 2 + packages/time/src/date/isBefore/isBefore.ts | 25 +++ .../src/date/isBefore/tests/isBefore.test.ts | 178 +++++++++++++++++ packages/time/src/date/isSameOrAfter/index.ts | 2 + .../src/date/isSameOrAfter/isSameOrAfter.ts | 47 +++++ .../isSameOrAfter/tests/isSameOrAfter.test.ts | 181 ++++++++++++++++++ .../time/src/date/isSameOrBefore/index.ts | 5 + .../src/date/isSameOrBefore/isSameOrBefore.ts | 47 +++++ .../tests/isSameOrBefore.test.ts | 181 ++++++++++++++++++ packages/time/src/date/since/since.ts | 35 +--- packages/time/src/date/subtract/subtract.ts | 17 +- packages/time/src/date/types.ts | 13 ++ packages/time/src/date/until/until.ts | 35 +--- .../withDateOperation.test.ts | 8 +- .../withDateOperation/withDateOperation.ts | 38 +--- packages/time/src/index.ts | 1 + 26 files changed, 979 insertions(+), 162 deletions(-) create mode 100644 packages/time/src/date/helpers/index.ts create mode 100644 packages/time/src/date/helpers/normalizeWeek.ts create mode 100644 packages/time/src/date/helpers/toZonedDateTime.ts create mode 100644 packages/time/src/date/index.ts create mode 100644 packages/time/src/date/isAfter/index.ts create mode 100644 packages/time/src/date/isAfter/isAfter.ts create mode 100644 packages/time/src/date/isAfter/tests/isAfter.test.ts create mode 100644 packages/time/src/date/isBefore/index.ts create mode 100644 packages/time/src/date/isBefore/isBefore.ts create mode 100644 packages/time/src/date/isBefore/tests/isBefore.test.ts create mode 100644 packages/time/src/date/isSameOrAfter/index.ts create mode 100644 packages/time/src/date/isSameOrAfter/isSameOrAfter.ts create mode 100644 packages/time/src/date/isSameOrAfter/tests/isSameOrAfter.test.ts create mode 100644 packages/time/src/date/isSameOrBefore/index.ts create mode 100644 packages/time/src/date/isSameOrBefore/isSameOrBefore.ts create mode 100644 packages/time/src/date/isSameOrBefore/tests/isSameOrBefore.test.ts diff --git a/Methods.md b/Methods.md index 55bfd217..7688e213 100644 --- a/Methods.md +++ b/Methods.md @@ -1,16 +1,16 @@ # What API methods do we need? -[]: # - startOf(ZonedDateTime, unit): ZonedDateTime -[]: # - endOf(ZonedDateTime, unit): ZonedDateTime -[]: # - add(ZonedDateTime, duration): ZonedDateTime -[]: # - subtract(ZonedDateTime, duration): ZonedDateTime -[]: # - until(ZonedDateTime, ZonedDateTime): Duration -[]: # - since(ZonedDateTime, ZonedDateTime): Duration -[]: # - equals(ZonedDateTime, ZonedDateTime, unit): boolean -[]: # - isBefore(ZonedDateTime, ZonedDateTime): boolean -[]: # - isAfter(ZonedDateTime, ZonedDateTime): boolean -[]: # - isSameOrBefore(ZonedDateTime, ZonedDateTime, unit): boolean -[]: # - isSameOrAfter(ZonedDateTime, ZonedDateTime, unit): boolean +[]: # - startOf(ZonedDateTime, unit): ZonedDateTime āœ… +[]: # - endOf(ZonedDateTime, unit): ZonedDateTime āœ… +[]: # - add(ZonedDateTime, duration): ZonedDateTime āœ… +[]: # - subtract(ZonedDateTime, duration): ZonedDateTime āœ… +[]: # - until(ZonedDateTime, ZonedDateTime): Duration āœ… +[]: # - since(ZonedDateTime, ZonedDateTime): Duration āœ… +[]: # - equals(ZonedDateTime, ZonedDateTime, unit): boolean āœ… +[]: # - isBefore(ZonedDateTime, ZonedDateTime): boolean āœ… +[]: # - isAfter(ZonedDateTime, ZonedDateTime): boolean āœ… +[]: # - isSameOrBefore(ZonedDateTime, ZonedDateTime, unit): boolean āœ… +[]: # - isSameOrAfter(ZonedDateTime, ZonedDateTime, unit): boolean āœ… []: # - isBetween(ZonedDateTime, Range): boolean []: # - intersects(ZonedDateTime, Range): boolean []: # - time(PlainTime): ZonedDateTime (use getter/setter?) diff --git a/packages/time/src/date/add/add.ts b/packages/time/src/date/add/add.ts index 9a18285c..e5761364 100644 --- a/packages/time/src/date/add/add.ts +++ b/packages/time/src/date/add/add.ts @@ -1,19 +1,6 @@ import { withDateOperation } from '../withDateOperation' import type { DateOperationOptions } from '../withDateOperation' -import type { DateInput } from '../types' - -export interface DurationLike { - years?: number - months?: number - weeks?: number - days?: number - hours?: number - minutes?: number - seconds?: number - milliseconds?: number - microseconds?: number - nanoseconds?: number -} +import type { DateInput, DurationLike } from '../types' export interface AddOptions extends DateOperationOptions { duration: DurationLike diff --git a/packages/time/src/date/equals/equals.ts b/packages/time/src/date/equals/equals.ts index 05b65d55..5fa6bf05 100644 --- a/packages/time/src/date/equals/equals.ts +++ b/packages/time/src/date/equals/equals.ts @@ -1,4 +1,5 @@ import { getDateDefaults } from '../dateDefaults' +import { normalizeWeek } from '../helpers' import { startOf } from '../startOf/startOf' import type { DateInput, DateOptions } from '../types' @@ -35,22 +36,8 @@ export function equals( const zdt2 = startOf2.asZonedDateTime() if (unit === 'week') { - const normalized1 = zdt1.with({ - hour: 0, - minute: 0, - second: 0, - millisecond: 0, - microsecond: 0, - nanosecond: 0, - }) - const normalized2 = zdt2.with({ - hour: 0, - minute: 0, - second: 0, - millisecond: 0, - microsecond: 0, - nanosecond: 0, - }) + const normalized1 = normalizeWeek(zdt1) + const normalized2 = normalizeWeek(zdt2) return ( normalized1.toInstant().epochNanoseconds === normalized2.toInstant().epochNanoseconds diff --git a/packages/time/src/date/helpers/index.ts b/packages/time/src/date/helpers/index.ts new file mode 100644 index 00000000..ba4da1e5 --- /dev/null +++ b/packages/time/src/date/helpers/index.ts @@ -0,0 +1,2 @@ +export * from './toZonedDateTime' +export * from './normalizeWeek' diff --git a/packages/time/src/date/helpers/normalizeWeek.ts b/packages/time/src/date/helpers/normalizeWeek.ts new file mode 100644 index 00000000..b0c1695f --- /dev/null +++ b/packages/time/src/date/helpers/normalizeWeek.ts @@ -0,0 +1,18 @@ +import type { Temporal } from '@js-temporal/polyfill' + +/** + * Normalizes a ZonedDateTime to midnight for week-level comparisons + * This is needed because startOf('week') only adjusts the day but preserves time components + */ +export function normalizeWeek( + zdt: Temporal.ZonedDateTime, +): Temporal.ZonedDateTime { + return zdt.with({ + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + microsecond: 0, + nanosecond: 0, + }) +} diff --git a/packages/time/src/date/helpers/toZonedDateTime.ts b/packages/time/src/date/helpers/toZonedDateTime.ts new file mode 100644 index 00000000..9edc0ddd --- /dev/null +++ b/packages/time/src/date/helpers/toZonedDateTime.ts @@ -0,0 +1,34 @@ +import { Temporal } from '@js-temporal/polyfill' +import { validateDate } from '../validateDate' +import type { DateInput } from '../types' + +export function toZonedDateTime( + input: DateInput, + timeZone: string, + calendar: string, +): Temporal.ZonedDateTime { + if (input instanceof Temporal.ZonedDateTime) { + return input + } + + let dateString: string + + if (typeof input === 'string') { + if (input.includes('[') && input.includes(']')) { + return Temporal.ZonedDateTime.from(input) + } + const date = validateDate({ date: input }) + dateString = date.toISOString() + } else if (typeof input === 'number') { + const date = validateDate({ date: input }) + dateString = date.toISOString() + } else if (input instanceof Date) { + const date = validateDate({ date: input }) + dateString = date.toISOString() + } else { + throw new Error(`Invalid date input type: ${typeof input}`) + } + + const zonedDateTimeString = `${dateString}[${timeZone}][u-ca=${calendar}]` + return Temporal.ZonedDateTime.from(zonedDateTimeString) +} diff --git a/packages/time/src/date/index.ts b/packages/time/src/date/index.ts new file mode 100644 index 00000000..9b6e3398 --- /dev/null +++ b/packages/time/src/date/index.ts @@ -0,0 +1,11 @@ +export * from './add' +export * from './subtract' +export * from './since' +export * from './until' +export * from './startOf' +export * from './endOf' +export * from './isBefore' +export * from './isAfter' +export * from './equals' +export * from './isSameOrBefore' +export * from './isSameOrAfter' diff --git a/packages/time/src/date/isAfter/index.ts b/packages/time/src/date/isAfter/index.ts new file mode 100644 index 00000000..48eabef4 --- /dev/null +++ b/packages/time/src/date/isAfter/index.ts @@ -0,0 +1,2 @@ +export { isAfter } from './isAfter' +export type { IsAfterOptions } from './isAfter' diff --git a/packages/time/src/date/isAfter/isAfter.ts b/packages/time/src/date/isAfter/isAfter.ts new file mode 100644 index 00000000..8ddc1c5e --- /dev/null +++ b/packages/time/src/date/isAfter/isAfter.ts @@ -0,0 +1,25 @@ +import { Temporal } from '@js-temporal/polyfill' +import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { DateInput, DateOptions } from '../types' + +export interface IsAfterOptions extends DateOptions {} + +/** + * isAfter + * Returns true if the first date/time instance is after the second date/time instance + */ +export function isAfter( + date1: DateInput, + date2: DateInput, + options?: IsAfterOptions, +): boolean { + const defaults = getDateDefaults() + const timeZone = options?.timeZone ?? defaults.timeZone + const calendar = options?.calendar ?? defaults.calendar + + const zdt1 = toZonedDateTime(date1, timeZone, calendar) + const zdt2 = toZonedDateTime(date2, timeZone, calendar) + + return Temporal.ZonedDateTime.compare(zdt1, zdt2) > 0 +} diff --git a/packages/time/src/date/isAfter/tests/isAfter.test.ts b/packages/time/src/date/isAfter/tests/isAfter.test.ts new file mode 100644 index 00000000..8f151634 --- /dev/null +++ b/packages/time/src/date/isAfter/tests/isAfter.test.ts @@ -0,0 +1,178 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { isAfter } from '../isAfter' + +describe('isAfter', () => { + describe('with string inputs', () => { + test('should return true when first date is after second date', () => { + const result = isAfter( + '2024-03-16T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false when first date is before second date', () => { + const result = isAfter( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should return false when dates are equal', () => { + const result = isAfter( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should handle different times on same day', () => { + const result = isAfter('2024-03-15T15:00:00Z', '2024-03-15T10:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle different days', () => { + const result = isAfter( + '2024-03-16T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle different months', () => { + const result = isAfter( + '2024-03-15T14:42:12.789Z', + '2024-02-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle different years', () => { + const result = isAfter( + '2024-03-15T14:42:12.789Z', + '2023-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const date1 = new Date('2024-03-16T14:42:12.789Z') + const date2 = new Date('2024-03-15T14:42:12.789Z') + const result = isAfter(date1, date2, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const date1 = new Date('2024-03-16T14:42:12.789Z').getTime() + const date2 = new Date('2024-03-15T14:42:12.789Z').getTime() + const result = isAfter(date1, date2, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with ZonedDateTime', () => { + const zdt1 = Temporal.ZonedDateTime.from( + '2024-03-16T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const zdt2 = Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const result = isAfter(zdt1, zdt2, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with mixed input types', () => { + const date1 = '2024-03-16T14:42:12.789Z' + const date2 = new Date('2024-03-15T14:42:12.789Z') + const result = isAfter(date1, date2, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = isAfter('2024-03-15T19:00:00Z', '2024-03-15T14:00:00Z', { + timeZone: 'America/New_York', + }) + expect(result).toBe(true) + }) + + test('should handle different timezones correctly', () => { + const result = isAfter('2024-03-16T00:00:00Z', '2024-03-15T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = isAfter( + '2024-03-16T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + calendar: 'japanese', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('edge cases', () => { + test('should handle milliseconds precision', () => { + const result = isAfter( + '2024-03-15T14:42:12.790Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle leap year dates', () => { + const result = isAfter('2024-02-29T00:00:00Z', '2024-02-28T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle year boundaries', () => { + const result = isAfter('2024-01-01T00:00:00Z', '2023-12-31T23:59:59Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) +}) diff --git a/packages/time/src/date/isBefore/index.ts b/packages/time/src/date/isBefore/index.ts new file mode 100644 index 00000000..9d1e7079 --- /dev/null +++ b/packages/time/src/date/isBefore/index.ts @@ -0,0 +1,2 @@ +export { isBefore } from './isBefore' +export type { IsBeforeOptions } from './isBefore' diff --git a/packages/time/src/date/isBefore/isBefore.ts b/packages/time/src/date/isBefore/isBefore.ts new file mode 100644 index 00000000..936892e7 --- /dev/null +++ b/packages/time/src/date/isBefore/isBefore.ts @@ -0,0 +1,25 @@ +import { Temporal } from '@js-temporal/polyfill' +import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { DateInput, DateOptions } from '../types' + +export interface IsBeforeOptions extends DateOptions {} + +/** + * isBefore + * Returns true if the first date/time instance is before the second date/time instance + */ +export function isBefore( + date1: DateInput, + date2: DateInput, + options?: IsBeforeOptions, +): boolean { + const defaults = getDateDefaults() + const timeZone = options?.timeZone ?? defaults.timeZone + const calendar = options?.calendar ?? defaults.calendar + + const zdt1 = toZonedDateTime(date1, timeZone, calendar) + const zdt2 = toZonedDateTime(date2, timeZone, calendar) + + return Temporal.ZonedDateTime.compare(zdt1, zdt2) < 0 +} diff --git a/packages/time/src/date/isBefore/tests/isBefore.test.ts b/packages/time/src/date/isBefore/tests/isBefore.test.ts new file mode 100644 index 00000000..1b3a9302 --- /dev/null +++ b/packages/time/src/date/isBefore/tests/isBefore.test.ts @@ -0,0 +1,178 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { isBefore } from '../isBefore' + +describe('isBefore', () => { + describe('with string inputs', () => { + test('should return true when first date is before second date', () => { + const result = isBefore( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false when first date is after second date', () => { + const result = isBefore( + '2024-03-16T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should return false when dates are equal', () => { + const result = isBefore( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should handle different times on same day', () => { + const result = isBefore('2024-03-15T10:00:00Z', '2024-03-15T15:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle different days', () => { + const result = isBefore( + '2024-03-14T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle different months', () => { + const result = isBefore( + '2024-02-15T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle different years', () => { + const result = isBefore( + '2023-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const date1 = new Date('2024-03-15T14:42:12.789Z') + const date2 = new Date('2024-03-16T14:42:12.789Z') + const result = isBefore(date1, date2, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const date1 = new Date('2024-03-15T14:42:12.789Z').getTime() + const date2 = new Date('2024-03-16T14:42:12.789Z').getTime() + const result = isBefore(date1, date2, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with ZonedDateTime', () => { + const zdt1 = Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const zdt2 = Temporal.ZonedDateTime.from( + '2024-03-16T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const result = isBefore(zdt1, zdt2, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with mixed input types', () => { + const date1 = '2024-03-15T14:42:12.789Z' + const date2 = new Date('2024-03-16T14:42:12.789Z') + const result = isBefore(date1, date2, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = isBefore('2024-03-15T14:00:00Z', '2024-03-15T19:00:00Z', { + timeZone: 'America/New_York', + }) + expect(result).toBe(true) + }) + + test('should handle different timezones correctly', () => { + const result = isBefore('2024-03-15T00:00:00Z', '2024-03-16T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = isBefore( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + { + calendar: 'japanese', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('edge cases', () => { + test('should handle milliseconds precision', () => { + const result = isBefore( + '2024-03-15T14:42:12.789Z', + '2024-03-15T14:42:12.790Z', + { + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle leap year dates', () => { + const result = isBefore('2024-02-28T00:00:00Z', '2024-02-29T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle year boundaries', () => { + const result = isBefore('2023-12-31T23:59:59Z', '2024-01-01T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) +}) diff --git a/packages/time/src/date/isSameOrAfter/index.ts b/packages/time/src/date/isSameOrAfter/index.ts new file mode 100644 index 00000000..82fb41dd --- /dev/null +++ b/packages/time/src/date/isSameOrAfter/index.ts @@ -0,0 +1,2 @@ +export { isSameOrAfter } from './isSameOrAfter' +export type { IsSameOrAfterOptions, IsSameOrAfterUnit } from './isSameOrAfter' diff --git a/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts b/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts new file mode 100644 index 00000000..45da3026 --- /dev/null +++ b/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts @@ -0,0 +1,47 @@ +import { Temporal } from '@js-temporal/polyfill' +import { getDateDefaults } from '../dateDefaults' +import { normalizeWeek } from '../helpers' +import { startOf } from '../startOf/startOf' +import type { DateInput, DateOptions } from '../types' + +export type IsSameOrAfterUnit = + | 'year' + | 'month' + | 'week' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'millisecond' + +export interface IsSameOrAfterOptions extends DateOptions { + unit: IsSameOrAfterUnit +} + +/** + * isSameOrAfter + * Returns true if the first date/time instance is the same as or after the second date/time instance at the specified unit level + */ +export function isSameOrAfter( + date1: DateInput, + date2: DateInput, + options: IsSameOrAfterOptions, +): boolean { + const defaults = getDateDefaults() + const timeZone = options.timeZone ?? defaults.timeZone + const calendar = options.calendar ?? defaults.calendar + + const startOf1 = startOf(date1, { unit: options.unit, timeZone, calendar }) + const startOf2 = startOf(date2, { unit: options.unit, timeZone, calendar }) + + const zdt1 = startOf1.asZonedDateTime() + const zdt2 = startOf2.asZonedDateTime() + + if (options.unit === 'week') { + const normalized1 = normalizeWeek(zdt1) + const normalized2 = normalizeWeek(zdt2) + return Temporal.ZonedDateTime.compare(normalized1, normalized2) >= 0 + } + + return Temporal.ZonedDateTime.compare(zdt1, zdt2) >= 0 +} diff --git a/packages/time/src/date/isSameOrAfter/tests/isSameOrAfter.test.ts b/packages/time/src/date/isSameOrAfter/tests/isSameOrAfter.test.ts new file mode 100644 index 00000000..45689244 --- /dev/null +++ b/packages/time/src/date/isSameOrAfter/tests/isSameOrAfter.test.ts @@ -0,0 +1,181 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { isSameOrAfter } from '../isSameOrAfter' + +describe('isSameOrAfter', () => { + describe('with string inputs', () => { + test('should return true when first date is after second date at day level', () => { + const result = isSameOrAfter( + '2024-03-16T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + unit: 'day', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return true when dates are equal at day level', () => { + const result = isSameOrAfter( + '2024-03-15T23:59:59Z', + '2024-03-15T10:00:00Z', + { + unit: 'day', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false when first date is before second date at day level', () => { + const result = isSameOrAfter( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + { + unit: 'day', + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should handle year level comparison', () => { + const result = isSameOrAfter( + '2024-12-31T23:59:59Z', + '2024-01-01T00:00:00Z', + { + unit: 'year', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle month level comparison', () => { + const result = isSameOrAfter( + '2024-03-31T23:59:59Z', + '2024-03-01T00:00:00Z', + { + unit: 'month', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle week level comparison', () => { + const result = isSameOrAfter( + '2024-03-17T23:59:59Z', + '2024-03-11T00:00:00Z', + { + unit: 'week', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle hour level comparison', () => { + const result = isSameOrAfter( + '2024-03-15T14:59:59Z', + '2024-03-15T14:00:00Z', + { + unit: 'hour', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const date1 = new Date('2024-03-15T23:59:59Z') + const date2 = new Date('2024-03-15T10:00:00Z') + const result = isSameOrAfter(date1, date2, { + unit: 'day', + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const date1 = new Date('2024-03-15T23:59:59Z').getTime() + const date2 = new Date('2024-03-15T10:00:00Z').getTime() + const result = isSameOrAfter(date1, date2, { + unit: 'day', + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with ZonedDateTime', () => { + const zdt1 = Temporal.ZonedDateTime.from( + '2024-03-15T23:59:59Z[UTC][u-ca=gregory]', + ) + const zdt2 = Temporal.ZonedDateTime.from( + '2024-03-15T10:00:00Z[UTC][u-ca=gregory]', + ) + const result = isSameOrAfter(zdt1, zdt2, { + unit: 'day', + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = isSameOrAfter( + '2024-03-15T19:00:00Z', + '2024-03-15T14:00:00Z', + { + unit: 'day', + timeZone: 'America/New_York', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = isSameOrAfter( + '2024-03-15T23:59:59Z', + '2024-03-15T10:00:00Z', + { + unit: 'day', + calendar: 'japanese', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('edge cases', () => { + test('should handle different years correctly', () => { + const result = isSameOrAfter( + '2024-01-01T00:00:00Z', + '2023-12-31T23:59:59Z', + { + unit: 'year', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle leap year dates', () => { + const result = isSameOrAfter( + '2024-02-29T00:00:00Z', + '2024-02-28T00:00:00Z', + { + unit: 'day', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + }) +}) diff --git a/packages/time/src/date/isSameOrBefore/index.ts b/packages/time/src/date/isSameOrBefore/index.ts new file mode 100644 index 00000000..a77c2ffc --- /dev/null +++ b/packages/time/src/date/isSameOrBefore/index.ts @@ -0,0 +1,5 @@ +export { isSameOrBefore } from './isSameOrBefore' +export type { + IsSameOrBeforeOptions, + IsSameOrBeforeUnit, +} from './isSameOrBefore' diff --git a/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts b/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts new file mode 100644 index 00000000..bd789cdb --- /dev/null +++ b/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts @@ -0,0 +1,47 @@ +import { Temporal } from '@js-temporal/polyfill' +import { getDateDefaults } from '../dateDefaults' +import { normalizeWeek } from '../helpers' +import { startOf } from '../startOf/startOf' +import type { DateInput, DateOptions } from '../types' + +export type IsSameOrBeforeUnit = + | 'year' + | 'month' + | 'week' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'millisecond' + +export interface IsSameOrBeforeOptions extends DateOptions { + unit: IsSameOrBeforeUnit +} + +/** + * isSameOrBefore + * Returns true if the first date/time instance is the same as or before the second date/time instance at the specified unit level + */ +export function isSameOrBefore( + date1: DateInput, + date2: DateInput, + options: IsSameOrBeforeOptions, +): boolean { + const defaults = getDateDefaults() + const timeZone = options.timeZone ?? defaults.timeZone + const calendar = options.calendar ?? defaults.calendar + + const startOf1 = startOf(date1, { unit: options.unit, timeZone, calendar }) + const startOf2 = startOf(date2, { unit: options.unit, timeZone, calendar }) + + const zdt1 = startOf1.asZonedDateTime() + const zdt2 = startOf2.asZonedDateTime() + + if (options.unit === 'week') { + const normalized1 = normalizeWeek(zdt1) + const normalized2 = normalizeWeek(zdt2) + return Temporal.ZonedDateTime.compare(normalized1, normalized2) <= 0 + } + + return Temporal.ZonedDateTime.compare(zdt1, zdt2) <= 0 +} diff --git a/packages/time/src/date/isSameOrBefore/tests/isSameOrBefore.test.ts b/packages/time/src/date/isSameOrBefore/tests/isSameOrBefore.test.ts new file mode 100644 index 00000000..b3891531 --- /dev/null +++ b/packages/time/src/date/isSameOrBefore/tests/isSameOrBefore.test.ts @@ -0,0 +1,181 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { isSameOrBefore } from '../isSameOrBefore' + +describe('isSameOrBefore', () => { + describe('with string inputs', () => { + test('should return true when first date is before second date at day level', () => { + const result = isSameOrBefore( + '2024-03-15T14:42:12.789Z', + '2024-03-16T14:42:12.789Z', + { + unit: 'day', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return true when dates are equal at day level', () => { + const result = isSameOrBefore( + '2024-03-15T10:00:00Z', + '2024-03-15T23:59:59Z', + { + unit: 'day', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should return false when first date is after second date at day level', () => { + const result = isSameOrBefore( + '2024-03-16T14:42:12.789Z', + '2024-03-15T14:42:12.789Z', + { + unit: 'day', + timeZone: 'UTC', + }, + ) + expect(result).toBe(false) + }) + + test('should handle year level comparison', () => { + const result = isSameOrBefore( + '2024-03-15T14:42:12.789Z', + '2024-12-31T23:59:59Z', + { + unit: 'year', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle month level comparison', () => { + const result = isSameOrBefore( + '2024-03-01T00:00:00Z', + '2024-03-31T23:59:59Z', + { + unit: 'month', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle week level comparison', () => { + const result = isSameOrBefore( + '2024-03-11T00:00:00Z', + '2024-03-17T23:59:59Z', + { + unit: 'week', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle hour level comparison', () => { + const result = isSameOrBefore( + '2024-03-15T14:00:00Z', + '2024-03-15T14:59:59Z', + { + unit: 'hour', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const date1 = new Date('2024-03-15T10:00:00Z') + const date2 = new Date('2024-03-15T23:59:59Z') + const result = isSameOrBefore(date1, date2, { + unit: 'day', + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const date1 = new Date('2024-03-15T10:00:00Z').getTime() + const date2 = new Date('2024-03-15T23:59:59Z').getTime() + const result = isSameOrBefore(date1, date2, { + unit: 'day', + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with ZonedDateTime', () => { + const zdt1 = Temporal.ZonedDateTime.from( + '2024-03-15T10:00:00Z[UTC][u-ca=gregory]', + ) + const zdt2 = Temporal.ZonedDateTime.from( + '2024-03-15T23:59:59Z[UTC][u-ca=gregory]', + ) + const result = isSameOrBefore(zdt1, zdt2, { + unit: 'day', + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = isSameOrBefore( + '2024-03-15T14:00:00Z', + '2024-03-15T19:00:00Z', + { + unit: 'day', + timeZone: 'America/New_York', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = isSameOrBefore( + '2024-03-15T10:00:00Z', + '2024-03-15T23:59:59Z', + { + unit: 'day', + calendar: 'japanese', + }, + ) + expect(result).toBe(true) + }) + }) + + describe('edge cases', () => { + test('should handle different years correctly', () => { + const result = isSameOrBefore( + '2023-12-31T23:59:59Z', + '2024-01-01T00:00:00Z', + { + unit: 'year', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + + test('should handle leap year dates', () => { + const result = isSameOrBefore( + '2024-02-28T00:00:00Z', + '2024-02-29T00:00:00Z', + { + unit: 'day', + timeZone: 'UTC', + }, + ) + expect(result).toBe(true) + }) + }) +}) diff --git a/packages/time/src/date/since/since.ts b/packages/time/src/date/since/since.ts index f07e34e4..7a4eb81c 100644 --- a/packages/time/src/date/since/since.ts +++ b/packages/time/src/date/since/since.ts @@ -1,43 +1,12 @@ -import { Temporal } from '@js-temporal/polyfill' -import { validateDate } from '../validateDate' import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { Temporal } from '@js-temporal/polyfill' import type { DateInput, DateOptions } from '../types' export interface SinceOptions extends DateOptions { unit: Temporal.DateTimeUnit } -function toZonedDateTime( - input: DateInput, - timeZone: string, - calendar: string, -): Temporal.ZonedDateTime { - if (input instanceof Temporal.ZonedDateTime) { - return input - } - - let dateString: string - - if (typeof input === 'string') { - if (input.includes('[') && input.includes(']')) { - return Temporal.ZonedDateTime.from(input) - } - const date = validateDate({ date: input }) - dateString = date.toISOString() - } else if (typeof input === 'number') { - const date = validateDate({ date: input }) - dateString = date.toISOString() - } else if (input instanceof Date) { - const date = validateDate({ date: input }) - dateString = date.toISOString() - } else { - throw new Error(`Invalid date input type: ${typeof input}`) - } - - const zonedDateTimeString = `${dateString}[${timeZone}][u-ca=${calendar}]` - return Temporal.ZonedDateTime.from(zonedDateTimeString) -} - /** * since * Returns the duration from the first date/time instance since the second date/time instance diff --git a/packages/time/src/date/subtract/subtract.ts b/packages/time/src/date/subtract/subtract.ts index 977cd064..f1d226ef 100644 --- a/packages/time/src/date/subtract/subtract.ts +++ b/packages/time/src/date/subtract/subtract.ts @@ -1,19 +1,6 @@ import { withDateOperation } from '../withDateOperation' import type { DateOperationOptions } from '../withDateOperation' -import type { DateInput } from '../types' - -export interface DurationLike { - years?: number - months?: number - weeks?: number - days?: number - hours?: number - minutes?: number - seconds?: number - milliseconds?: number - microseconds?: number - nanoseconds?: number -} +import type { DateInput, DurationLike } from '../types' export interface SubtractOptions extends DateOperationOptions { duration: DurationLike @@ -24,7 +11,7 @@ export interface SubtractOptions extends DateOperationOptions { * Subtracts a duration from a date/time instance */ export function subtract(input: DateInput, options: SubtractOptions) { - return withDateOperation((zdt, { duration }) => { + return withDateOperation((zdt, { duration }) => { return zdt.subtract(duration) })(input, options) } diff --git a/packages/time/src/date/types.ts b/packages/time/src/date/types.ts index 0894fa5b..6fabaa44 100644 --- a/packages/time/src/date/types.ts +++ b/packages/time/src/date/types.ts @@ -6,3 +6,16 @@ export interface DateOptions { calendar?: string timeZone?: string } + +export interface DurationLike { + years?: number + months?: number + weeks?: number + days?: number + hours?: number + minutes?: number + seconds?: number + milliseconds?: number + microseconds?: number + nanoseconds?: number +} diff --git a/packages/time/src/date/until/until.ts b/packages/time/src/date/until/until.ts index a75278c2..bf74f6e8 100644 --- a/packages/time/src/date/until/until.ts +++ b/packages/time/src/date/until/until.ts @@ -1,43 +1,12 @@ -import { Temporal } from '@js-temporal/polyfill' -import { validateDate } from '../validateDate' import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { Temporal } from '@js-temporal/polyfill' import type { DateInput, DateOptions } from '../types' export interface UntilOptions extends DateOptions { unit: Temporal.DateTimeUnit } -function toZonedDateTime( - input: DateInput, - timeZone: string, - calendar: string, -): Temporal.ZonedDateTime { - if (input instanceof Temporal.ZonedDateTime) { - return input - } - - let dateString: string - - if (typeof input === 'string') { - if (input.includes('[') && input.includes(']')) { - return Temporal.ZonedDateTime.from(input) - } - const date = validateDate({ date: input }) - dateString = date.toISOString() - } else if (typeof input === 'number') { - const date = validateDate({ date: input }) - dateString = date.toISOString() - } else if (input instanceof Date) { - const date = validateDate({ date: input }) - dateString = date.toISOString() - } else { - throw new Error(`Invalid date input type: ${typeof input}`) - } - - const zonedDateTimeString = `${dateString}[${timeZone}][u-ca=${calendar}]` - return Temporal.ZonedDateTime.from(zonedDateTimeString) -} - /** * until * Returns the duration from the first date/time instance until the second date/time instance diff --git a/packages/time/src/date/withDateOperation/withDateOperation.test.ts b/packages/time/src/date/withDateOperation/withDateOperation.test.ts index feb988a0..59c51c39 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.test.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.test.ts @@ -115,7 +115,7 @@ describe('withDateOperation', () => { timeZone: 'UTC', }) expect(typeof result.value).toBe('string') - const valueStr = result.value as string + const valueStr = result.value expect(valueStr).toContain('2024-03-15') }) @@ -177,7 +177,7 @@ describe('withDateOperation', () => { }) expect(result.returnFormat).toBe('standard') expect(typeof result.value).toBe('string') - const valueStr = result.value as string + const valueStr = result.value expect(valueStr).toContain('2024-03-15') expect(valueStr).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/) expect(valueStr).not.toContain('[') @@ -192,7 +192,7 @@ describe('withDateOperation', () => { }) expect(result.returnFormat).toBe('long') expect(typeof result.value).toBe('string') - const valueStr = result.value as string + const valueStr = result.value expect(valueStr).toContain('2024-03-15') expect(valueStr).toContain('[America/New_York]') expect(valueStr).toContain('[u-ca=gregory]') @@ -224,7 +224,7 @@ describe('withDateOperation', () => { multiplier: 2, timeZone: 'UTC', }) - const valueStr = result.value as string + const valueStr = result.value expect(valueStr).toContain('2024-03-30') }) }) diff --git a/packages/time/src/date/withDateOperation/withDateOperation.ts b/packages/time/src/date/withDateOperation/withDateOperation.ts index fdc2530b..52adf3d0 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.ts @@ -1,6 +1,6 @@ -import { Temporal } from '@js-temporal/polyfill' -import { validateDate } from '../validateDate' import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { Temporal } from '@js-temporal/polyfill' import type { DateInput, DateOptions } from '../types' export type ReturnFormat = 'standard' | 'long' @@ -49,40 +49,6 @@ function createDateOperationResult( } } -/** - * Converts various date inputs to a Temporal.ZonedDateTime - */ -function toZonedDateTime( - input: DateInput, - timeZone: string, - calendar: string, -): Temporal.ZonedDateTime { - if (input instanceof Temporal.ZonedDateTime) { - return input - } - - let dateString: string - - if (typeof input === 'string') { - if (input.includes('[') && input.includes(']')) { - return Temporal.ZonedDateTime.from(input) - } - const date = validateDate({ date: input }) - dateString = date.toISOString() - } else if (typeof input === 'number') { - const date = validateDate({ date: input }) - dateString = date.toISOString() - } else if (input instanceof Date) { - const date = validateDate({ date: input }) - dateString = date.toISOString() - } else { - throw new Error(`Invalid date input type: ${typeof input}`) - } - - const zonedDateTimeString = `${dateString}[${timeZone}][u-ca=${calendar}]` - return Temporal.ZonedDateTime.from(zonedDateTimeString) -} - /** * Higher-order function that provides common parsing, defaults, and formatting logic * for date utility functions like startOf, endOf, etc. diff --git a/packages/time/src/index.ts b/packages/time/src/index.ts index e69de29b..edf1e3ce 100644 --- a/packages/time/src/index.ts +++ b/packages/time/src/index.ts @@ -0,0 +1 @@ +export * from './date' From e56eab837c531e74d036120ebc39354d720eee27 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:53:02 +0000 Subject: [PATCH 018/207] ci: apply automated fixes --- docs/reference/functions/add.md | 109 ++++++++++++++++++ docs/reference/functions/endOf.md | 109 ++++++++++++++++++ docs/reference/functions/equals.md | 41 +++++++ docs/reference/functions/isAfter.md | 36 ++++++ docs/reference/functions/isBefore.md | 36 ++++++ docs/reference/functions/isSameOrAfter.md | 36 ++++++ docs/reference/functions/isSameOrBefore.md | 36 ++++++ docs/reference/functions/since.md | 37 ++++++ docs/reference/functions/startOf.md | 109 ++++++++++++++++++ docs/reference/functions/subtract.md | 109 ++++++++++++++++++ docs/reference/functions/until.md | 36 ++++++ docs/reference/index.md | 42 +++++++ docs/reference/interfaces/AddOptions.md | 70 +++++++++++ docs/reference/interfaces/EndOfOptions.md | 70 +++++++++++ docs/reference/interfaces/EqualsOptions.md | 44 +++++++ docs/reference/interfaces/IsAfterOptions.md | 44 +++++++ docs/reference/interfaces/IsBeforeOptions.md | 44 +++++++ .../interfaces/IsSameOrAfterOptions.md | 54 +++++++++ .../interfaces/IsSameOrBeforeOptions.md | 54 +++++++++ docs/reference/interfaces/SinceOptions.md | 54 +++++++++ docs/reference/interfaces/StartOfOptions.md | 70 +++++++++++ docs/reference/interfaces/SubtractOptions.md | 70 +++++++++++ docs/reference/interfaces/UntilOptions.md | 54 +++++++++ docs/reference/type-aliases/EndOfUnit.md | 20 ++++ docs/reference/type-aliases/EqualsUnit.md | 20 ++++ .../type-aliases/IsSameOrAfterUnit.md | 20 ++++ .../type-aliases/IsSameOrBeforeUnit.md | 20 ++++ docs/reference/type-aliases/StartOfUnit.md | 20 ++++ 28 files changed, 1464 insertions(+) create mode 100644 docs/reference/functions/add.md create mode 100644 docs/reference/functions/endOf.md create mode 100644 docs/reference/functions/equals.md create mode 100644 docs/reference/functions/isAfter.md create mode 100644 docs/reference/functions/isBefore.md create mode 100644 docs/reference/functions/isSameOrAfter.md create mode 100644 docs/reference/functions/isSameOrBefore.md create mode 100644 docs/reference/functions/since.md create mode 100644 docs/reference/functions/startOf.md create mode 100644 docs/reference/functions/subtract.md create mode 100644 docs/reference/functions/until.md create mode 100644 docs/reference/index.md create mode 100644 docs/reference/interfaces/AddOptions.md create mode 100644 docs/reference/interfaces/EndOfOptions.md create mode 100644 docs/reference/interfaces/EqualsOptions.md create mode 100644 docs/reference/interfaces/IsAfterOptions.md create mode 100644 docs/reference/interfaces/IsBeforeOptions.md create mode 100644 docs/reference/interfaces/IsSameOrAfterOptions.md create mode 100644 docs/reference/interfaces/IsSameOrBeforeOptions.md create mode 100644 docs/reference/interfaces/SinceOptions.md create mode 100644 docs/reference/interfaces/StartOfOptions.md create mode 100644 docs/reference/interfaces/SubtractOptions.md create mode 100644 docs/reference/interfaces/UntilOptions.md create mode 100644 docs/reference/type-aliases/EndOfUnit.md create mode 100644 docs/reference/type-aliases/EqualsUnit.md create mode 100644 docs/reference/type-aliases/IsSameOrAfterUnit.md create mode 100644 docs/reference/type-aliases/IsSameOrBeforeUnit.md create mode 100644 docs/reference/type-aliases/StartOfUnit.md diff --git a/docs/reference/functions/add.md b/docs/reference/functions/add.md new file mode 100644 index 00000000..17e7aa1a --- /dev/null +++ b/docs/reference/functions/add.md @@ -0,0 +1,109 @@ +--- +id: add +title: add +--- + +# Function: add() + +```ts +function add(input, options): object; +``` + +Defined in: [add/add.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L13) + +add +Adds a duration to a date/time instance + +## Parameters + +### input + +`DateInput` + +### options + +[`AddOptions`](../interfaces/AddOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asLong() + +```ts +asLong: () => string; +``` + +#### Returns + +`string` + +### asString() + +```ts +asString: () => string; +``` + +#### Returns + +`string` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: Required; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/functions/endOf.md b/docs/reference/functions/endOf.md new file mode 100644 index 00000000..6a3c3c07 --- /dev/null +++ b/docs/reference/functions/endOf.md @@ -0,0 +1,109 @@ +--- +id: endOf +title: endOf +--- + +# Function: endOf() + +```ts +function endOf(input, options): object; +``` + +Defined in: [endOf/endOf.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L23) + +endOf +Returns the end of a given unit for a date/time instance + +## Parameters + +### input + +`DateInput` + +### options + +[`EndOfOptions`](../interfaces/EndOfOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asLong() + +```ts +asLong: () => string; +``` + +#### Returns + +`string` + +### asString() + +```ts +asString: () => string; +``` + +#### Returns + +`string` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: Required; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/functions/equals.md b/docs/reference/functions/equals.md new file mode 100644 index 00000000..12950ac6 --- /dev/null +++ b/docs/reference/functions/equals.md @@ -0,0 +1,41 @@ +--- +id: equals +title: equals +--- + +# Function: equals() + +```ts +function equals( + date1, + date2, + unit, + options?): boolean; +``` + +Defined in: [equals/equals.ts:22](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L22) + +equals +Returns true if two date/time instances are equal at the specified unit level + +## Parameters + +### date1 + +`DateInput` + +### date2 + +`DateInput` + +### unit + +[`EqualsUnit`](../type-aliases/EqualsUnit.md) + +### options? + +[`EqualsOptions`](../interfaces/EqualsOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isAfter.md b/docs/reference/functions/isAfter.md new file mode 100644 index 00000000..15207507 --- /dev/null +++ b/docs/reference/functions/isAfter.md @@ -0,0 +1,36 @@ +--- +id: isAfter +title: isAfter +--- + +# Function: isAfter() + +```ts +function isAfter( + date1, + date2, + options?): boolean; +``` + +Defined in: [isAfter/isAfter.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/isAfter/isAfter.ts#L12) + +isAfter +Returns true if the first date/time instance is after the second date/time instance + +## Parameters + +### date1 + +`DateInput` + +### date2 + +`DateInput` + +### options? + +[`IsAfterOptions`](../interfaces/IsAfterOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isBefore.md b/docs/reference/functions/isBefore.md new file mode 100644 index 00000000..926ee6eb --- /dev/null +++ b/docs/reference/functions/isBefore.md @@ -0,0 +1,36 @@ +--- +id: isBefore +title: isBefore +--- + +# Function: isBefore() + +```ts +function isBefore( + date1, + date2, + options?): boolean; +``` + +Defined in: [isBefore/isBefore.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBefore/isBefore.ts#L12) + +isBefore +Returns true if the first date/time instance is before the second date/time instance + +## Parameters + +### date1 + +`DateInput` + +### date2 + +`DateInput` + +### options? + +[`IsBeforeOptions`](../interfaces/IsBeforeOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isSameOrAfter.md b/docs/reference/functions/isSameOrAfter.md new file mode 100644 index 00000000..e9da696a --- /dev/null +++ b/docs/reference/functions/isSameOrAfter.md @@ -0,0 +1,36 @@ +--- +id: isSameOrAfter +title: isSameOrAfter +--- + +# Function: isSameOrAfter() + +```ts +function isSameOrAfter( + date1, + date2, + options): boolean; +``` + +Defined in: [isSameOrAfter/isSameOrAfter.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L25) + +isSameOrAfter +Returns true if the first date/time instance is the same as or after the second date/time instance at the specified unit level + +## Parameters + +### date1 + +`DateInput` + +### date2 + +`DateInput` + +### options + +[`IsSameOrAfterOptions`](../interfaces/IsSameOrAfterOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isSameOrBefore.md b/docs/reference/functions/isSameOrBefore.md new file mode 100644 index 00000000..7fa72ce2 --- /dev/null +++ b/docs/reference/functions/isSameOrBefore.md @@ -0,0 +1,36 @@ +--- +id: isSameOrBefore +title: isSameOrBefore +--- + +# Function: isSameOrBefore() + +```ts +function isSameOrBefore( + date1, + date2, + options): boolean; +``` + +Defined in: [isSameOrBefore/isSameOrBefore.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L25) + +isSameOrBefore +Returns true if the first date/time instance is the same as or before the second date/time instance at the specified unit level + +## Parameters + +### date1 + +`DateInput` + +### date2 + +`DateInput` + +### options + +[`IsSameOrBeforeOptions`](../interfaces/IsSameOrBeforeOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/since.md b/docs/reference/functions/since.md new file mode 100644 index 00000000..20c2f9c9 --- /dev/null +++ b/docs/reference/functions/since.md @@ -0,0 +1,37 @@ +--- +id: since +title: since +--- + +# Function: since() + +```ts +function since( + start, + end, + options): number; +``` + +Defined in: [since/since.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L15) + +since +Returns the duration from the first date/time instance since the second date/time instance +(equivalent to: how long has it been since the second date, from the first date's perspective) + +## Parameters + +### start + +`DateInput` + +### end + +`DateInput` + +### options + +[`SinceOptions`](../interfaces/SinceOptions.md) + +## Returns + +`number` diff --git a/docs/reference/functions/startOf.md b/docs/reference/functions/startOf.md new file mode 100644 index 00000000..f9718629 --- /dev/null +++ b/docs/reference/functions/startOf.md @@ -0,0 +1,109 @@ +--- +id: startOf +title: startOf +--- + +# Function: startOf() + +```ts +function startOf(input, options): object; +``` + +Defined in: [startOf/startOf.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L23) + +startOf +Returns the start of a given unit for a date/time instance + +## Parameters + +### input + +`DateInput` + +### options + +[`StartOfOptions`](../interfaces/StartOfOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asLong() + +```ts +asLong: () => string; +``` + +#### Returns + +`string` + +### asString() + +```ts +asString: () => string; +``` + +#### Returns + +`string` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: Required; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/functions/subtract.md b/docs/reference/functions/subtract.md new file mode 100644 index 00000000..8777ddb8 --- /dev/null +++ b/docs/reference/functions/subtract.md @@ -0,0 +1,109 @@ +--- +id: subtract +title: subtract +--- + +# Function: subtract() + +```ts +function subtract(input, options): object; +``` + +Defined in: [subtract/subtract.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L13) + +subtract +Subtracts a duration from a date/time instance + +## Parameters + +### input + +`DateInput` + +### options + +[`SubtractOptions`](../interfaces/SubtractOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asLong() + +```ts +asLong: () => string; +``` + +#### Returns + +`string` + +### asString() + +```ts +asString: () => string; +``` + +#### Returns + +`string` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: Required; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/functions/until.md b/docs/reference/functions/until.md new file mode 100644 index 00000000..98786af6 --- /dev/null +++ b/docs/reference/functions/until.md @@ -0,0 +1,36 @@ +--- +id: until +title: until +--- + +# Function: until() + +```ts +function until( + start, + end, + options): number; +``` + +Defined in: [until/until.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L14) + +until +Returns the duration from the first date/time instance until the second date/time instance + +## Parameters + +### start + +`DateInput` + +### end + +`DateInput` + +### options + +[`UntilOptions`](../interfaces/UntilOptions.md) + +## Returns + +`number` diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 00000000..d90b9e1c --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,42 @@ +--- +id: "@tanstack/time" +title: "@tanstack/time" +--- + +# @tanstack/time + +## Interfaces + +- [AddOptions](interfaces/AddOptions.md) +- [EndOfOptions](interfaces/EndOfOptions.md) +- [EqualsOptions](interfaces/EqualsOptions.md) +- [IsAfterOptions](interfaces/IsAfterOptions.md) +- [IsBeforeOptions](interfaces/IsBeforeOptions.md) +- [IsSameOrAfterOptions](interfaces/IsSameOrAfterOptions.md) +- [IsSameOrBeforeOptions](interfaces/IsSameOrBeforeOptions.md) +- [SinceOptions](interfaces/SinceOptions.md) +- [StartOfOptions](interfaces/StartOfOptions.md) +- [SubtractOptions](interfaces/SubtractOptions.md) +- [UntilOptions](interfaces/UntilOptions.md) + +## Type Aliases + +- [EndOfUnit](type-aliases/EndOfUnit.md) +- [EqualsUnit](type-aliases/EqualsUnit.md) +- [IsSameOrAfterUnit](type-aliases/IsSameOrAfterUnit.md) +- [IsSameOrBeforeUnit](type-aliases/IsSameOrBeforeUnit.md) +- [StartOfUnit](type-aliases/StartOfUnit.md) + +## Functions + +- [add](functions/add.md) +- [endOf](functions/endOf.md) +- [equals](functions/equals.md) +- [isAfter](functions/isAfter.md) +- [isBefore](functions/isBefore.md) +- [isSameOrAfter](functions/isSameOrAfter.md) +- [isSameOrBefore](functions/isSameOrBefore.md) +- [since](functions/since.md) +- [startOf](functions/startOf.md) +- [subtract](functions/subtract.md) +- [until](functions/until.md) diff --git a/docs/reference/interfaces/AddOptions.md b/docs/reference/interfaces/AddOptions.md new file mode 100644 index 00000000..d82c3f82 --- /dev/null +++ b/docs/reference/interfaces/AddOptions.md @@ -0,0 +1,70 @@ +--- +id: AddOptions +title: AddOptions +--- + +# Interface: AddOptions + +Defined in: [add/add.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L5) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### duration + +```ts +duration: DurationLike; +``` + +Defined in: [add/add.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L6) + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` diff --git a/docs/reference/interfaces/EndOfOptions.md b/docs/reference/interfaces/EndOfOptions.md new file mode 100644 index 00000000..7d962107 --- /dev/null +++ b/docs/reference/interfaces/EndOfOptions.md @@ -0,0 +1,70 @@ +--- +id: EndOfOptions +title: EndOfOptions +--- + +# Interface: EndOfOptions + +Defined in: [endOf/endOf.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L15) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` + +*** + +### unit + +```ts +unit: EndOfUnit; +``` + +Defined in: [endOf/endOf.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L16) diff --git a/docs/reference/interfaces/EqualsOptions.md b/docs/reference/interfaces/EqualsOptions.md new file mode 100644 index 00000000..42db5762 --- /dev/null +++ b/docs/reference/interfaces/EqualsOptions.md @@ -0,0 +1,44 @@ +--- +id: EqualsOptions +title: EqualsOptions +--- + +# Interface: EqualsOptions + +Defined in: [equals/equals.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L16) + +## Extends + +- `DateOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOptions.calendar +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOptions.timeZone +``` diff --git a/docs/reference/interfaces/IsAfterOptions.md b/docs/reference/interfaces/IsAfterOptions.md new file mode 100644 index 00000000..7101bacc --- /dev/null +++ b/docs/reference/interfaces/IsAfterOptions.md @@ -0,0 +1,44 @@ +--- +id: IsAfterOptions +title: IsAfterOptions +--- + +# Interface: IsAfterOptions + +Defined in: [isAfter/isAfter.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isAfter/isAfter.ts#L6) + +## Extends + +- `DateOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOptions.calendar +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOptions.timeZone +``` diff --git a/docs/reference/interfaces/IsBeforeOptions.md b/docs/reference/interfaces/IsBeforeOptions.md new file mode 100644 index 00000000..4217c8b4 --- /dev/null +++ b/docs/reference/interfaces/IsBeforeOptions.md @@ -0,0 +1,44 @@ +--- +id: IsBeforeOptions +title: IsBeforeOptions +--- + +# Interface: IsBeforeOptions + +Defined in: [isBefore/isBefore.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBefore/isBefore.ts#L6) + +## Extends + +- `DateOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOptions.calendar +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOptions.timeZone +``` diff --git a/docs/reference/interfaces/IsSameOrAfterOptions.md b/docs/reference/interfaces/IsSameOrAfterOptions.md new file mode 100644 index 00000000..a3e45792 --- /dev/null +++ b/docs/reference/interfaces/IsSameOrAfterOptions.md @@ -0,0 +1,54 @@ +--- +id: IsSameOrAfterOptions +title: IsSameOrAfterOptions +--- + +# Interface: IsSameOrAfterOptions + +Defined in: [isSameOrAfter/isSameOrAfter.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L17) + +## Extends + +- `DateOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOptions.calendar +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOptions.timeZone +``` + +*** + +### unit + +```ts +unit: IsSameOrAfterUnit; +``` + +Defined in: [isSameOrAfter/isSameOrAfter.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L18) diff --git a/docs/reference/interfaces/IsSameOrBeforeOptions.md b/docs/reference/interfaces/IsSameOrBeforeOptions.md new file mode 100644 index 00000000..7b4facf4 --- /dev/null +++ b/docs/reference/interfaces/IsSameOrBeforeOptions.md @@ -0,0 +1,54 @@ +--- +id: IsSameOrBeforeOptions +title: IsSameOrBeforeOptions +--- + +# Interface: IsSameOrBeforeOptions + +Defined in: [isSameOrBefore/isSameOrBefore.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L17) + +## Extends + +- `DateOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOptions.calendar +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOptions.timeZone +``` + +*** + +### unit + +```ts +unit: IsSameOrBeforeUnit; +``` + +Defined in: [isSameOrBefore/isSameOrBefore.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L18) diff --git a/docs/reference/interfaces/SinceOptions.md b/docs/reference/interfaces/SinceOptions.md new file mode 100644 index 00000000..ca44c2f7 --- /dev/null +++ b/docs/reference/interfaces/SinceOptions.md @@ -0,0 +1,54 @@ +--- +id: SinceOptions +title: SinceOptions +--- + +# Interface: SinceOptions + +Defined in: [since/since.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L6) + +## Extends + +- `DateOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOptions.calendar +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOptions.timeZone +``` + +*** + +### unit + +```ts +unit: DateTimeUnit; +``` + +Defined in: [since/since.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L7) diff --git a/docs/reference/interfaces/StartOfOptions.md b/docs/reference/interfaces/StartOfOptions.md new file mode 100644 index 00000000..4a3b2330 --- /dev/null +++ b/docs/reference/interfaces/StartOfOptions.md @@ -0,0 +1,70 @@ +--- +id: StartOfOptions +title: StartOfOptions +--- + +# Interface: StartOfOptions + +Defined in: [startOf/startOf.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L15) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` + +*** + +### unit + +```ts +unit: StartOfUnit; +``` + +Defined in: [startOf/startOf.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L16) diff --git a/docs/reference/interfaces/SubtractOptions.md b/docs/reference/interfaces/SubtractOptions.md new file mode 100644 index 00000000..ad2a1eef --- /dev/null +++ b/docs/reference/interfaces/SubtractOptions.md @@ -0,0 +1,70 @@ +--- +id: SubtractOptions +title: SubtractOptions +--- + +# Interface: SubtractOptions + +Defined in: [subtract/subtract.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L5) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### duration + +```ts +duration: DurationLike; +``` + +Defined in: [subtract/subtract.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L6) + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` diff --git a/docs/reference/interfaces/UntilOptions.md b/docs/reference/interfaces/UntilOptions.md new file mode 100644 index 00000000..76a090a2 --- /dev/null +++ b/docs/reference/interfaces/UntilOptions.md @@ -0,0 +1,54 @@ +--- +id: UntilOptions +title: UntilOptions +--- + +# Interface: UntilOptions + +Defined in: [until/until.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L6) + +## Extends + +- `DateOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOptions.calendar +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOptions.timeZone +``` + +*** + +### unit + +```ts +unit: DateTimeUnit; +``` + +Defined in: [until/until.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L7) diff --git a/docs/reference/type-aliases/EndOfUnit.md b/docs/reference/type-aliases/EndOfUnit.md new file mode 100644 index 00000000..9e9d7bd5 --- /dev/null +++ b/docs/reference/type-aliases/EndOfUnit.md @@ -0,0 +1,20 @@ +--- +id: EndOfUnit +title: EndOfUnit +--- + +# Type Alias: EndOfUnit + +```ts +type EndOfUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [endOf/endOf.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L5) diff --git a/docs/reference/type-aliases/EqualsUnit.md b/docs/reference/type-aliases/EqualsUnit.md new file mode 100644 index 00000000..f8d3eb8a --- /dev/null +++ b/docs/reference/type-aliases/EqualsUnit.md @@ -0,0 +1,20 @@ +--- +id: EqualsUnit +title: EqualsUnit +--- + +# Type Alias: EqualsUnit + +```ts +type EqualsUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [equals/equals.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L6) diff --git a/docs/reference/type-aliases/IsSameOrAfterUnit.md b/docs/reference/type-aliases/IsSameOrAfterUnit.md new file mode 100644 index 00000000..ef6acd42 --- /dev/null +++ b/docs/reference/type-aliases/IsSameOrAfterUnit.md @@ -0,0 +1,20 @@ +--- +id: IsSameOrAfterUnit +title: IsSameOrAfterUnit +--- + +# Type Alias: IsSameOrAfterUnit + +```ts +type IsSameOrAfterUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [isSameOrAfter/isSameOrAfter.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L7) diff --git a/docs/reference/type-aliases/IsSameOrBeforeUnit.md b/docs/reference/type-aliases/IsSameOrBeforeUnit.md new file mode 100644 index 00000000..60ca08ff --- /dev/null +++ b/docs/reference/type-aliases/IsSameOrBeforeUnit.md @@ -0,0 +1,20 @@ +--- +id: IsSameOrBeforeUnit +title: IsSameOrBeforeUnit +--- + +# Type Alias: IsSameOrBeforeUnit + +```ts +type IsSameOrBeforeUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [isSameOrBefore/isSameOrBefore.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L7) diff --git a/docs/reference/type-aliases/StartOfUnit.md b/docs/reference/type-aliases/StartOfUnit.md new file mode 100644 index 00000000..e1840ec5 --- /dev/null +++ b/docs/reference/type-aliases/StartOfUnit.md @@ -0,0 +1,20 @@ +--- +id: StartOfUnit +title: StartOfUnit +--- + +# Type Alias: StartOfUnit + +```ts +type StartOfUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [startOf/startOf.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L5) From b13de3bb33863f24319de001d454437d015c57d3 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 20 Jan 2026 14:21:44 +0100 Subject: [PATCH 019/207] feat: date comparition utils --- Methods.md | 40 +-- packages/time/src/date/index.ts | 4 + packages/time/src/date/intersects/index.ts | 2 + .../time/src/date/intersects/intersects.ts | 35 +++ .../date/intersects/tests/intersects.test.ts | 178 ++++++++++++ packages/time/src/date/isBetween/index.ts | 2 + packages/time/src/date/isBetween/isBetween.ts | 42 +++ .../date/isBetween/tests/isBetween.test.ts | 268 ++++++++++++++++++ .../time/src/date/{ => parse}/parsingDates.md | 0 packages/time/src/date/round/index.ts | 2 + packages/time/src/date/round/round.ts | 108 +++++++ .../time/src/date/round/tests/round.test.ts | 255 +++++++++++++++++ packages/time/src/date/types.ts | 5 + 13 files changed, 921 insertions(+), 20 deletions(-) create mode 100644 packages/time/src/date/intersects/index.ts create mode 100644 packages/time/src/date/intersects/intersects.ts create mode 100644 packages/time/src/date/intersects/tests/intersects.test.ts create mode 100644 packages/time/src/date/isBetween/index.ts create mode 100644 packages/time/src/date/isBetween/isBetween.ts create mode 100644 packages/time/src/date/isBetween/tests/isBetween.test.ts rename packages/time/src/date/{ => parse}/parsingDates.md (100%) create mode 100644 packages/time/src/date/round/index.ts create mode 100644 packages/time/src/date/round/round.ts create mode 100644 packages/time/src/date/round/tests/round.test.ts diff --git a/Methods.md b/Methods.md index 7688e213..42beb37b 100644 --- a/Methods.md +++ b/Methods.md @@ -1,22 +1,22 @@ # What API methods do we need? -[]: # - startOf(ZonedDateTime, unit): ZonedDateTime āœ… -[]: # - endOf(ZonedDateTime, unit): ZonedDateTime āœ… -[]: # - add(ZonedDateTime, duration): ZonedDateTime āœ… -[]: # - subtract(ZonedDateTime, duration): ZonedDateTime āœ… -[]: # - until(ZonedDateTime, ZonedDateTime): Duration āœ… -[]: # - since(ZonedDateTime, ZonedDateTime): Duration āœ… -[]: # - equals(ZonedDateTime, ZonedDateTime, unit): boolean āœ… -[]: # - isBefore(ZonedDateTime, ZonedDateTime): boolean āœ… -[]: # - isAfter(ZonedDateTime, ZonedDateTime): boolean āœ… -[]: # - isSameOrBefore(ZonedDateTime, ZonedDateTime, unit): boolean āœ… -[]: # - isSameOrAfter(ZonedDateTime, ZonedDateTime, unit): boolean āœ… -[]: # - isBetween(ZonedDateTime, Range): boolean -[]: # - intersects(ZonedDateTime, Range): boolean -[]: # - time(PlainTime): ZonedDateTime (use getter/setter?) -[]: # - timeZone(IANATimeZoneId): ZonedDateTime (use getter/setter?) -[]: # - calendar(Calendar): ZonedDateTime (use getter/setter?) -[]: # - round(unit): ZonedDateTime -[]: # - asEpoch -[]: # - asString -[]: # - asZonedDateTime +[x] startOf(ZonedDateTime, unit): ZonedDateTime āœ… +[x] endOf(ZonedDateTime, unit): ZonedDateTime āœ… +[x] add(ZonedDateTime, duration): ZonedDateTime āœ… +[x] subtract(ZonedDateTime, duration): ZonedDateTime āœ… +[x] until(ZonedDateTime, ZonedDateTime): Duration āœ… +[x] since(ZonedDateTime, ZonedDateTime): Duration āœ… +[x] equals(ZonedDateTime, ZonedDateTime, unit): boolean āœ… +[x] isBefore(ZonedDateTime, ZonedDateTime): boolean āœ… +[x] isAfter(ZonedDateTime, ZonedDateTime): boolean āœ… +[x] round(unit): ZonedDateTime āœ… +[x] isSameOrBefore(ZonedDateTime, ZonedDateTime, unit): boolean āœ… +[x] isSameOrAfter(ZonedDateTime, ZonedDateTime, unit): boolean āœ… +[x] isBetween(ZonedDateTime, Range): boolean āœ… +[x] intersects(ZonedDateTime, Range): boolean āœ… +[ ] time(PlainTime): ZonedDateTime (use getter/setter?) +[x] timeZone(IANATimeZoneId): ZonedDateTime (use getter/setter?) āœ… +[x] calendar(Calendar): ZonedDateTime (use getter/setter?) āœ… +[x] asEpoch āœ… +[x] asString āœ… +[x] asZonedDateTime āœ… diff --git a/packages/time/src/date/index.ts b/packages/time/src/date/index.ts index 9b6e3398..0040c9ba 100644 --- a/packages/time/src/date/index.ts +++ b/packages/time/src/date/index.ts @@ -4,8 +4,12 @@ export * from './since' export * from './until' export * from './startOf' export * from './endOf' +export * from './round' export * from './isBefore' export * from './isAfter' export * from './equals' export * from './isSameOrBefore' export * from './isSameOrAfter' +export * from './isBetween' +export * from './intersects' +export type { Range } from './types' diff --git a/packages/time/src/date/intersects/index.ts b/packages/time/src/date/intersects/index.ts new file mode 100644 index 00000000..7a96d852 --- /dev/null +++ b/packages/time/src/date/intersects/index.ts @@ -0,0 +1,2 @@ +export { intersects } from './intersects' +export type { IntersectsOptions } from './intersects' diff --git a/packages/time/src/date/intersects/intersects.ts b/packages/time/src/date/intersects/intersects.ts new file mode 100644 index 00000000..a93c14f9 --- /dev/null +++ b/packages/time/src/date/intersects/intersects.ts @@ -0,0 +1,35 @@ +import { Temporal } from '@js-temporal/polyfill' +import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { DateInput, DateOptions, Range } from '../types' + +export interface IntersectsOptions extends DateOptions { + range: Range +} + +/** + * intersects + * Returns true if the date/time instance intersects with the range (i.e., is within or equal to the range boundaries) + * @param date - The date to check + * @param options - Options including range, timeZone and calendar + */ +export function intersects( + date: DateInput, + options: IntersectsOptions, +): boolean { + const defaults = getDateDefaults() + const { + range: { start, end }, + timeZone = defaults.timeZone, + calendar = defaults.calendar, + } = options + + const zdt = toZonedDateTime(date, timeZone, calendar) + const zdtStart = toZonedDateTime(start, timeZone, calendar) + const zdtEnd = toZonedDateTime(end, timeZone, calendar) + + const compareStart = Temporal.ZonedDateTime.compare(zdt, zdtStart) + const compareEnd = Temporal.ZonedDateTime.compare(zdt, zdtEnd) + + return compareStart >= 0 && compareEnd <= 0 +} diff --git a/packages/time/src/date/intersects/tests/intersects.test.ts b/packages/time/src/date/intersects/tests/intersects.test.ts new file mode 100644 index 00000000..f9bdabcc --- /dev/null +++ b/packages/time/src/date/intersects/tests/intersects.test.ts @@ -0,0 +1,178 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { intersects } from '../intersects' + +describe('intersects', () => { + describe('basic functionality', () => { + test('should return true when date is between start and end', () => { + const result = intersects('2024-03-16T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true when date equals start', () => { + const result = intersects('2024-03-15T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true when date equals end', () => { + const result = intersects('2024-03-17T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return false when date is before start', () => { + const result = intersects('2024-03-14T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false when date is after end', () => { + const result = intersects('2024-03-18T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const date = new Date('2024-03-16T14:42:12.789Z') + const result = intersects(date, { + range: { + start: new Date('2024-03-15T14:42:12.789Z'), + end: new Date('2024-03-17T14:42:12.789Z'), + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const date = new Date('2024-03-16T14:42:12.789Z').getTime() + const result = intersects(date, { + range: { + start: new Date('2024-03-15T14:42:12.789Z').getTime(), + end: new Date('2024-03-17T14:42:12.789Z').getTime(), + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with ZonedDateTime', () => { + const zdt = Temporal.ZonedDateTime.from( + '2024-03-16T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const result = intersects(zdt, { + range: { + start: Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', + ), + end: Temporal.ZonedDateTime.from( + '2024-03-17T14:42:12.789Z[UTC][u-ca=gregory]', + ), + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with mixed input types', () => { + const result = intersects('2024-03-16T14:42:12.789Z', { + range: { + start: new Date('2024-03-15T14:42:12.789Z'), + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = intersects('2024-03-16T14:00:00Z', { + range: { + start: '2024-03-15T14:00:00Z', + end: '2024-03-17T14:00:00Z', + }, + timeZone: 'America/New_York', + }) + expect(result).toBe(true) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = intersects('2024-03-16T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + calendar: 'japanese', + }) + expect(result).toBe(true) + }) + }) + + describe('edge cases', () => { + test('should handle milliseconds precision', () => { + const result = intersects('2024-03-15T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.788Z', + end: '2024-03-15T14:42:12.790Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle same start and end date', () => { + const result = intersects('2024-03-15T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-15T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle reversed range (start after end)', () => { + const result = intersects('2024-03-16T14:42:12.789Z', { + range: { + start: '2024-03-17T14:42:12.789Z', + end: '2024-03-15T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + }) +}) diff --git a/packages/time/src/date/isBetween/index.ts b/packages/time/src/date/isBetween/index.ts new file mode 100644 index 00000000..76c75e46 --- /dev/null +++ b/packages/time/src/date/isBetween/index.ts @@ -0,0 +1,2 @@ +export { isBetween } from './isBetween' +export type { IsBetweenOptions } from './isBetween' diff --git a/packages/time/src/date/isBetween/isBetween.ts b/packages/time/src/date/isBetween/isBetween.ts new file mode 100644 index 00000000..43ec1908 --- /dev/null +++ b/packages/time/src/date/isBetween/isBetween.ts @@ -0,0 +1,42 @@ +import { Temporal } from '@js-temporal/polyfill' +import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { DateInput, DateOptions, Range } from '../types' + +export interface IsBetweenOptions extends DateOptions { + inclusive?: boolean | 'start' | 'end' + range: Range +} + +/** + * isBetween + * Returns true if the date/time instance is between the start and end of the range + * @param date - The date to check + * @param range - The range with start and end dates + * @param options - Options including timeZone, calendar, and inclusivity + */ +export function isBetween(date: DateInput, options: IsBetweenOptions): boolean { + const defaults = getDateDefaults() + const { + range: { start, end }, + timeZone = defaults.timeZone, + calendar = defaults.calendar, + inclusive = true, + } = options + const zdt = toZonedDateTime(date, timeZone, calendar) + const zdtStart = toZonedDateTime(start, timeZone, calendar) + const zdtEnd = toZonedDateTime(end, timeZone, calendar) + + const compareStart = Temporal.ZonedDateTime.compare(zdt, zdtStart) + const compareEnd = Temporal.ZonedDateTime.compare(zdt, zdtEnd) + + if (inclusive === true) { + return compareStart >= 0 && compareEnd <= 0 + } else if (inclusive === 'start') { + return compareStart >= 0 && compareEnd < 0 + } else if (inclusive === 'end') { + return compareStart > 0 && compareEnd <= 0 + } else { + return compareStart > 0 && compareEnd < 0 + } +} diff --git a/packages/time/src/date/isBetween/tests/isBetween.test.ts b/packages/time/src/date/isBetween/tests/isBetween.test.ts new file mode 100644 index 00000000..8f48a5bc --- /dev/null +++ b/packages/time/src/date/isBetween/tests/isBetween.test.ts @@ -0,0 +1,268 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { isBetween } from '../isBetween' + +describe('isBetween', () => { + describe('with inclusive range (default)', () => { + test('should return true when date is between start and end', () => { + const result = isBetween('2024-03-16T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true when date equals start', () => { + const result = isBetween('2024-03-15T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true when date equals end', () => { + const result = isBetween('2024-03-17T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return false when date is before start', () => { + const result = isBetween('2024-03-14T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false when date is after end', () => { + const result = isBetween('2024-03-18T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + }) + + describe('with exclusive range', () => { + test('should return true when date is strictly between start and end', () => { + const result = isBetween('2024-03-16T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + inclusive: false, + }) + expect(result).toBe(true) + }) + + test('should return false when date equals start', () => { + const result = isBetween('2024-03-15T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + inclusive: false, + }) + expect(result).toBe(false) + }) + + test('should return false when date equals end', () => { + const result = isBetween('2024-03-17T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + inclusive: false, + }) + expect(result).toBe(false) + }) + }) + + describe('with inclusive start only', () => { + test('should return true when date equals start', () => { + const result = isBetween('2024-03-15T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + inclusive: 'start', + }) + expect(result).toBe(true) + }) + + test('should return false when date equals end', () => { + const result = isBetween('2024-03-17T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + inclusive: 'start', + }) + expect(result).toBe(false) + }) + }) + + describe('with inclusive end only', () => { + test('should return true when date equals end', () => { + const result = isBetween('2024-03-17T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + inclusive: 'end', + }) + expect(result).toBe(true) + }) + + test('should return false when date equals start', () => { + const result = isBetween('2024-03-15T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + inclusive: 'end', + }) + expect(result).toBe(false) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const date = new Date('2024-03-16T14:42:12.789Z') + const result = isBetween(date, { + range: { + start: new Date('2024-03-15T14:42:12.789Z'), + end: new Date('2024-03-17T14:42:12.789Z'), + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const date = new Date('2024-03-16T14:42:12.789Z').getTime() + const result = isBetween(date, { + range: { + start: new Date('2024-03-15T14:42:12.789Z').getTime(), + end: new Date('2024-03-17T14:42:12.789Z').getTime(), + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with ZonedDateTime', () => { + const zdt = Temporal.ZonedDateTime.from( + '2024-03-16T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const result = isBetween(zdt, { + range: { + start: Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', + ), + end: Temporal.ZonedDateTime.from( + '2024-03-17T14:42:12.789Z[UTC][u-ca=gregory]', + ), + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with mixed input types', () => { + const result = isBetween('2024-03-16T14:42:12.789Z', { + range: { + start: new Date('2024-03-15T14:42:12.789Z'), + end: '2024-03-17T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = isBetween('2024-03-16T14:00:00Z', { + range: { + start: '2024-03-15T14:00:00Z', + end: '2024-03-17T14:00:00Z', + }, + timeZone: 'America/New_York', + }) + expect(result).toBe(true) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = isBetween('2024-03-16T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-17T14:42:12.789Z', + }, + calendar: 'japanese', + }) + expect(result).toBe(true) + }) + }) + + describe('edge cases', () => { + test('should handle milliseconds precision', () => { + const result = isBetween('2024-03-15T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.788Z', + end: '2024-03-15T14:42:12.790Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle same start and end date', () => { + const result = isBetween('2024-03-15T14:42:12.789Z', { + range: { + start: '2024-03-15T14:42:12.789Z', + end: '2024-03-15T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle reversed range (start after end)', () => { + const result = isBetween('2024-03-16T14:42:12.789Z', { + range: { + start: '2024-03-17T14:42:12.789Z', + end: '2024-03-15T14:42:12.789Z', + }, + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + }) +}) diff --git a/packages/time/src/date/parsingDates.md b/packages/time/src/date/parse/parsingDates.md similarity index 100% rename from packages/time/src/date/parsingDates.md rename to packages/time/src/date/parse/parsingDates.md diff --git a/packages/time/src/date/round/index.ts b/packages/time/src/date/round/index.ts new file mode 100644 index 00000000..e48fba4f --- /dev/null +++ b/packages/time/src/date/round/index.ts @@ -0,0 +1,2 @@ +export { round } from './round' +export type { RoundOptions, RoundUnit } from './round' diff --git a/packages/time/src/date/round/round.ts b/packages/time/src/date/round/round.ts new file mode 100644 index 00000000..e9f912dc --- /dev/null +++ b/packages/time/src/date/round/round.ts @@ -0,0 +1,108 @@ +import { Temporal } from '@js-temporal/polyfill' +import { withDateOperation } from '../withDateOperation' +import type { DateOperationOptions } from '../withDateOperation' +import type { DateInput } from '../types' +import { startOf } from '../startOf/startOf' + +export type RoundUnit = + | 'year' + | 'month' + | 'week' + | 'day' + | 'hour' + | 'minute' + | 'second' + | 'millisecond' + +export interface RoundOptions extends DateOperationOptions { + unit: RoundUnit +} + +/** + * round + * Returns the date/time instance rounded to the nearest unit + */ +export function round(input: DateInput, options: RoundOptions) { + return withDateOperation((zdt, { unit }) => { + switch (unit) { + case 'year': { + const yearStart = startOf(zdt, { + unit: 'year', + timeZone: zdt.timeZoneId, + calendar: zdt.calendarId, + }).asZonedDateTime() + const nextYearStart = startOf(zdt.add({ years: 1 }), { + unit: 'year', + timeZone: zdt.timeZoneId, + calendar: zdt.calendarId, + }).asZonedDateTime() + const midpoint = yearStart.add({ months: 6 }) + return Temporal.ZonedDateTime.compare(zdt, midpoint) >= 0 + ? nextYearStart + : yearStart + } + case 'month': { + const monthStart = startOf(zdt, { + unit: 'month', + timeZone: zdt.timeZoneId, + calendar: zdt.calendarId, + }).asZonedDateTime() + const nextMonthStart = startOf(zdt.add({ months: 1 }), { + unit: 'month', + timeZone: zdt.timeZoneId, + calendar: zdt.calendarId, + }).asZonedDateTime() + const daysInMonth = zdt.daysInMonth + const midpoint = monthStart.add({ days: Math.floor(daysInMonth / 2) }) + return Temporal.ZonedDateTime.compare(zdt, midpoint) >= 0 + ? nextMonthStart + : monthStart + } + case 'week': { + const weekStart = startOf(zdt, { + unit: 'week', + timeZone: zdt.timeZoneId, + calendar: zdt.calendarId, + }).asZonedDateTime() + const nextWeekStart = startOf(zdt.add({ weeks: 1 }), { + unit: 'week', + timeZone: zdt.timeZoneId, + calendar: zdt.calendarId, + }).asZonedDateTime() + const midpoint = weekStart.add({ days: 3, hours: 12 }) + return Temporal.ZonedDateTime.compare(zdt, midpoint) >= 0 + ? nextWeekStart + : weekStart + } + case 'day': { + const dayStart = startOf(zdt, { + unit: 'day', + timeZone: zdt.timeZoneId, + calendar: zdt.calendarId, + }).asZonedDateTime() + const nextDayStart = startOf(zdt.add({ days: 1 }), { + unit: 'day', + timeZone: zdt.timeZoneId, + calendar: zdt.calendarId, + }).asZonedDateTime() + const midpoint = dayStart.add({ hours: 12 }) + return Temporal.ZonedDateTime.compare(zdt, midpoint) >= 0 + ? nextDayStart + : dayStart + } + case 'hour': + return zdt.round({ smallestUnit: 'hour', roundingMode: 'halfExpand' }) + case 'minute': + return zdt.round({ smallestUnit: 'minute', roundingMode: 'halfExpand' }) + case 'second': + return zdt.round({ smallestUnit: 'second', roundingMode: 'halfExpand' }) + case 'millisecond': + return zdt.round({ + smallestUnit: 'millisecond', + roundingMode: 'halfExpand', + }) + default: + return zdt + } + })(input, options) +} diff --git a/packages/time/src/date/round/tests/round.test.ts b/packages/time/src/date/round/tests/round.test.ts new file mode 100644 index 00000000..da79a48f --- /dev/null +++ b/packages/time/src/date/round/tests/round.test.ts @@ -0,0 +1,255 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { round } from '../round' + +describe('round', () => { + describe('rounding to year', () => { + test('should round down when before midpoint of year', () => { + const result = round('2024-06-15T14:42:12.789Z', { + unit: 'year', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-01-01T00:00:00Z') + }) + + test('should round up when at or after midpoint of year', () => { + const result = round('2024-07-15T14:42:12.789Z', { + unit: 'year', + timeZone: 'UTC', + }) + expect(result.value).toBe('2025-01-01T00:00:00Z') + }) + + test('should round down when exactly at start of year', () => { + const result = round('2024-01-01T00:00:00Z', { + unit: 'year', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-01-01T00:00:00Z') + }) + }) + + describe('rounding to month', () => { + test('should round down when before midpoint of month', () => { + const result = round('2024-03-10T14:42:12.789Z', { + unit: 'month', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-01T00:00:00Z') + }) + + test('should round up when at or after midpoint of month', () => { + const result = round('2024-03-20T14:42:12.789Z', { + unit: 'month', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-04-01T00:00:00Z') + }) + + test('should handle February correctly', () => { + const result = round('2024-02-15T14:42:12.789Z', { + unit: 'month', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-01T00:00:00Z') + }) + }) + + describe('rounding to week', () => { + test('should round down when before midpoint of week', () => { + const result = round('2024-03-13T10:00:00Z', { + unit: 'week', + timeZone: 'UTC', + }) + const weekStart = result.asZonedDateTime() + expect(weekStart.dayOfWeek).toBe(1) + }) + + test('should round up when at or after midpoint of week', () => { + const result = round('2024-03-16T18:00:00Z', { + unit: 'week', + timeZone: 'UTC', + }) + const weekStart = result.asZonedDateTime() + expect(weekStart.dayOfWeek).toBe(1) + }) + }) + + describe('rounding to day', () => { + test('should round down when before noon', () => { + const result = round('2024-03-15T10:00:00Z', { + unit: 'day', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T00:00:00Z') + }) + + test('should round up when at or after noon', () => { + const result = round('2024-03-15T14:00:00Z', { + unit: 'day', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-16T00:00:00Z') + }) + + test('should round down when exactly at midnight', () => { + const result = round('2024-03-15T00:00:00Z', { + unit: 'day', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T00:00:00Z') + }) + }) + + describe('rounding to hour', () => { + test('should round down when before 30 minutes', () => { + const result = round('2024-03-15T14:20:00Z', { + unit: 'hour', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T14:00:00Z') + }) + + test('should round up when at or after 30 minutes', () => { + const result = round('2024-03-15T14:30:00Z', { + unit: 'hour', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T15:00:00Z') + }) + + test('should round up when exactly at 30 minutes', () => { + const result = round('2024-03-15T14:30:00.000Z', { + unit: 'hour', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T15:00:00Z') + }) + }) + + describe('rounding to minute', () => { + test('should round down when before 30 seconds', () => { + const result = round('2024-03-15T14:42:20Z', { + unit: 'minute', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T14:42:00Z') + }) + + test('should round up when at or after 30 seconds', () => { + const result = round('2024-03-15T14:42:30Z', { + unit: 'minute', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T14:43:00Z') + }) + }) + + describe('rounding to second', () => { + test('should round down when before 500 milliseconds', () => { + const result = round('2024-03-15T14:42:12.400Z', { + unit: 'second', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T14:42:12Z') + }) + + test('should round up when at or after 500 milliseconds', () => { + const result = round('2024-03-15T14:42:12.500Z', { + unit: 'second', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T14:42:13Z') + }) + }) + + describe('rounding to millisecond', () => { + test('should round to nearest millisecond', () => { + const result = round('2024-03-15T14:42:12.789456Z', { + unit: 'millisecond', + timeZone: 'UTC', + }) + const rounded = result.asZonedDateTime() + expect(rounded.millisecond).toBe(789) + expect(rounded.microsecond).toBe(0) + expect(rounded.nanosecond).toBe(0) + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const date = new Date('2024-03-15T14:30:00Z') + const result = round(date, { + unit: 'hour', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T15:00:00Z') + }) + + test('should work with epoch time', () => { + const date = new Date('2024-03-15T14:30:00Z').getTime() + const result = round(date, { + unit: 'hour', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T15:00:00Z') + }) + + test('should work with ZonedDateTime', () => { + const zdt = Temporal.ZonedDateTime.from( + '2024-03-15T14:30:00Z[UTC][u-ca=gregory]', + ) + const result = round(zdt, { + unit: 'hour', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-15T15:00:00Z') + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = round('2024-03-15T14:30:00Z', { + unit: 'hour', + timeZone: 'America/New_York', + }) + expect(result.timeZone).toBe('America/New_York') + }) + }) + + describe('calendar handling', () => { + test('should respect calendar', () => { + const result = round('2024-03-15T14:30:00Z', { + unit: 'hour', + calendar: 'japanese', + }) + expect(result.calendar).toBe('japanese') + }) + }) + + describe('edge cases', () => { + test('should handle year boundary correctly', () => { + const result = round('2023-12-31T18:00:00Z', { + unit: 'day', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-01-01T00:00:00Z') + }) + + test('should handle month boundary correctly', () => { + const result = round('2024-02-29T18:00:00Z', { + unit: 'day', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-01T00:00:00Z') + }) + + test('should handle leap year correctly', () => { + const result = round('2024-02-15T12:00:00Z', { + unit: 'month', + timeZone: 'UTC', + }) + expect(result.value).toBe('2024-03-01T00:00:00Z') + }) + }) +}) diff --git a/packages/time/src/date/types.ts b/packages/time/src/date/types.ts index 6fabaa44..ed63c483 100644 --- a/packages/time/src/date/types.ts +++ b/packages/time/src/date/types.ts @@ -19,3 +19,8 @@ export interface DurationLike { microseconds?: number nanoseconds?: number } + +export interface Range { + start: DateInput + end: DateInput +} From 843002bdf949fca934cd996e5814f84848d55cc7 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:22:38 +0000 Subject: [PATCH 020/207] ci: apply automated fixes --- docs/reference/functions/intersects.md | 33 ++++++ docs/reference/functions/isBetween.md | 33 ++++++ docs/reference/functions/round.md | 109 ++++++++++++++++++ docs/reference/index.md | 8 ++ .../reference/interfaces/IntersectsOptions.md | 54 +++++++++ docs/reference/interfaces/IsBetweenOptions.md | 64 ++++++++++ docs/reference/interfaces/Range.md | 28 +++++ docs/reference/interfaces/RoundOptions.md | 70 +++++++++++ docs/reference/type-aliases/RoundUnit.md | 20 ++++ 9 files changed, 419 insertions(+) create mode 100644 docs/reference/functions/intersects.md create mode 100644 docs/reference/functions/isBetween.md create mode 100644 docs/reference/functions/round.md create mode 100644 docs/reference/interfaces/IntersectsOptions.md create mode 100644 docs/reference/interfaces/IsBetweenOptions.md create mode 100644 docs/reference/interfaces/Range.md create mode 100644 docs/reference/interfaces/RoundOptions.md create mode 100644 docs/reference/type-aliases/RoundUnit.md diff --git a/docs/reference/functions/intersects.md b/docs/reference/functions/intersects.md new file mode 100644 index 00000000..eeddb7e0 --- /dev/null +++ b/docs/reference/functions/intersects.md @@ -0,0 +1,33 @@ +--- +id: intersects +title: intersects +--- + +# Function: intersects() + +```ts +function intersects(date, options): boolean; +``` + +Defined in: [intersects/intersects.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L16) + +intersects +Returns true if the date/time instance intersects with the range (i.e., is within or equal to the range boundaries) + +## Parameters + +### date + +`DateInput` + +The date to check + +### options + +[`IntersectsOptions`](../interfaces/IntersectsOptions.md) + +Options including range, timeZone and calendar + +## Returns + +`boolean` diff --git a/docs/reference/functions/isBetween.md b/docs/reference/functions/isBetween.md new file mode 100644 index 00000000..751f5aea --- /dev/null +++ b/docs/reference/functions/isBetween.md @@ -0,0 +1,33 @@ +--- +id: isBetween +title: isBetween +--- + +# Function: isBetween() + +```ts +function isBetween(date, options): boolean; +``` + +Defined in: [isBetween/isBetween.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L18) + +isBetween +Returns true if the date/time instance is between the start and end of the range + +## Parameters + +### date + +`DateInput` + +The date to check + +### options + +[`IsBetweenOptions`](../interfaces/IsBetweenOptions.md) + +Options including timeZone, calendar, and inclusivity + +## Returns + +`boolean` diff --git a/docs/reference/functions/round.md b/docs/reference/functions/round.md new file mode 100644 index 00000000..f09ffbfa --- /dev/null +++ b/docs/reference/functions/round.md @@ -0,0 +1,109 @@ +--- +id: round +title: round +--- + +# Function: round() + +```ts +function round(input, options): object; +``` + +Defined in: [round/round.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L25) + +round +Returns the date/time instance rounded to the nearest unit + +## Parameters + +### input + +`DateInput` + +### options + +[`RoundOptions`](../interfaces/RoundOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asLong() + +```ts +asLong: () => string; +``` + +#### Returns + +`string` + +### asString() + +```ts +asString: () => string; +``` + +#### Returns + +`string` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: Required; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/index.md b/docs/reference/index.md index d90b9e1c..aeedc313 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -10,10 +10,14 @@ title: "@tanstack/time" - [AddOptions](interfaces/AddOptions.md) - [EndOfOptions](interfaces/EndOfOptions.md) - [EqualsOptions](interfaces/EqualsOptions.md) +- [IntersectsOptions](interfaces/IntersectsOptions.md) - [IsAfterOptions](interfaces/IsAfterOptions.md) - [IsBeforeOptions](interfaces/IsBeforeOptions.md) +- [IsBetweenOptions](interfaces/IsBetweenOptions.md) - [IsSameOrAfterOptions](interfaces/IsSameOrAfterOptions.md) - [IsSameOrBeforeOptions](interfaces/IsSameOrBeforeOptions.md) +- [Range](interfaces/Range.md) +- [RoundOptions](interfaces/RoundOptions.md) - [SinceOptions](interfaces/SinceOptions.md) - [StartOfOptions](interfaces/StartOfOptions.md) - [SubtractOptions](interfaces/SubtractOptions.md) @@ -25,6 +29,7 @@ title: "@tanstack/time" - [EqualsUnit](type-aliases/EqualsUnit.md) - [IsSameOrAfterUnit](type-aliases/IsSameOrAfterUnit.md) - [IsSameOrBeforeUnit](type-aliases/IsSameOrBeforeUnit.md) +- [RoundUnit](type-aliases/RoundUnit.md) - [StartOfUnit](type-aliases/StartOfUnit.md) ## Functions @@ -32,10 +37,13 @@ title: "@tanstack/time" - [add](functions/add.md) - [endOf](functions/endOf.md) - [equals](functions/equals.md) +- [intersects](functions/intersects.md) - [isAfter](functions/isAfter.md) - [isBefore](functions/isBefore.md) +- [isBetween](functions/isBetween.md) - [isSameOrAfter](functions/isSameOrAfter.md) - [isSameOrBefore](functions/isSameOrBefore.md) +- [round](functions/round.md) - [since](functions/since.md) - [startOf](functions/startOf.md) - [subtract](functions/subtract.md) diff --git a/docs/reference/interfaces/IntersectsOptions.md b/docs/reference/interfaces/IntersectsOptions.md new file mode 100644 index 00000000..0d86af84 --- /dev/null +++ b/docs/reference/interfaces/IntersectsOptions.md @@ -0,0 +1,54 @@ +--- +id: IntersectsOptions +title: IntersectsOptions +--- + +# Interface: IntersectsOptions + +Defined in: [intersects/intersects.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L6) + +## Extends + +- `DateOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOptions.calendar +``` + +*** + +### range + +```ts +range: Range; +``` + +Defined in: [intersects/intersects.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L7) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOptions.timeZone +``` diff --git a/docs/reference/interfaces/IsBetweenOptions.md b/docs/reference/interfaces/IsBetweenOptions.md new file mode 100644 index 00000000..82b28f71 --- /dev/null +++ b/docs/reference/interfaces/IsBetweenOptions.md @@ -0,0 +1,64 @@ +--- +id: IsBetweenOptions +title: IsBetweenOptions +--- + +# Interface: IsBetweenOptions + +Defined in: [isBetween/isBetween.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L6) + +## Extends + +- `DateOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOptions.calendar +``` + +*** + +### inclusive? + +```ts +optional inclusive: boolean | "start" | "end"; +``` + +Defined in: [isBetween/isBetween.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L7) + +*** + +### range + +```ts +range: Range; +``` + +Defined in: [isBetween/isBetween.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L8) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOptions.timeZone +``` diff --git a/docs/reference/interfaces/Range.md b/docs/reference/interfaces/Range.md new file mode 100644 index 00000000..83ff45d3 --- /dev/null +++ b/docs/reference/interfaces/Range.md @@ -0,0 +1,28 @@ +--- +id: Range +title: Range +--- + +# Interface: Range + +Defined in: [types.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L23) + +## Properties + +### end + +```ts +end: DateInput; +``` + +Defined in: [types.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L25) + +*** + +### start + +```ts +start: DateInput; +``` + +Defined in: [types.ts:24](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L24) diff --git a/docs/reference/interfaces/RoundOptions.md b/docs/reference/interfaces/RoundOptions.md new file mode 100644 index 00000000..8b705b6a --- /dev/null +++ b/docs/reference/interfaces/RoundOptions.md @@ -0,0 +1,70 @@ +--- +id: RoundOptions +title: RoundOptions +--- + +# Interface: RoundOptions + +Defined in: [round/round.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L17) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` + +*** + +### unit + +```ts +unit: RoundUnit; +``` + +Defined in: [round/round.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L18) diff --git a/docs/reference/type-aliases/RoundUnit.md b/docs/reference/type-aliases/RoundUnit.md new file mode 100644 index 00000000..2d49aafd --- /dev/null +++ b/docs/reference/type-aliases/RoundUnit.md @@ -0,0 +1,20 @@ +--- +id: RoundUnit +title: RoundUnit +--- + +# Type Alias: RoundUnit + +```ts +type RoundUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [round/round.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L7) From c468624938f4039bfd6750d95d6f4097d9e20b46 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 20 Jan 2026 14:26:22 +0100 Subject: [PATCH 021/207] refactor: date comparition utils --- packages/time/src/date/equals/equals.ts | 4 ++-- packages/time/src/date/isAfter/isAfter.ts | 4 ++-- packages/time/src/date/isBefore/isBefore.ts | 4 ++-- packages/time/src/date/isSameOrAfter/isSameOrAfter.ts | 4 +--- .../time/src/date/isSameOrBefore/isSameOrBefore.ts | 8 +++----- packages/time/src/date/since/since.ts | 11 ++--------- packages/time/src/date/until/until.ts | 3 +-- .../src/date/withDateOperation/withDateOperation.ts | 8 +++++--- 8 files changed, 18 insertions(+), 28 deletions(-) diff --git a/packages/time/src/date/equals/equals.ts b/packages/time/src/date/equals/equals.ts index 5fa6bf05..d1da0e78 100644 --- a/packages/time/src/date/equals/equals.ts +++ b/packages/time/src/date/equals/equals.ts @@ -26,8 +26,8 @@ export function equals( options?: EqualsOptions, ): boolean { const defaults = getDateDefaults() - const timeZone = options?.timeZone ?? defaults.timeZone - const calendar = options?.calendar ?? defaults.calendar + const { timeZone = defaults.timeZone, calendar = defaults.calendar } = + options ?? {} const startOf1 = startOf(date1, { unit, timeZone, calendar }) const startOf2 = startOf(date2, { unit, timeZone, calendar }) diff --git a/packages/time/src/date/isAfter/isAfter.ts b/packages/time/src/date/isAfter/isAfter.ts index 8ddc1c5e..03d6463b 100644 --- a/packages/time/src/date/isAfter/isAfter.ts +++ b/packages/time/src/date/isAfter/isAfter.ts @@ -15,8 +15,8 @@ export function isAfter( options?: IsAfterOptions, ): boolean { const defaults = getDateDefaults() - const timeZone = options?.timeZone ?? defaults.timeZone - const calendar = options?.calendar ?? defaults.calendar + const { timeZone = defaults.timeZone, calendar = defaults.calendar } = + options ?? {} const zdt1 = toZonedDateTime(date1, timeZone, calendar) const zdt2 = toZonedDateTime(date2, timeZone, calendar) diff --git a/packages/time/src/date/isBefore/isBefore.ts b/packages/time/src/date/isBefore/isBefore.ts index 936892e7..6dc1e1fc 100644 --- a/packages/time/src/date/isBefore/isBefore.ts +++ b/packages/time/src/date/isBefore/isBefore.ts @@ -15,8 +15,8 @@ export function isBefore( options?: IsBeforeOptions, ): boolean { const defaults = getDateDefaults() - const timeZone = options?.timeZone ?? defaults.timeZone - const calendar = options?.calendar ?? defaults.calendar + const { timeZone = defaults.timeZone, calendar = defaults.calendar } = + options ?? {} const zdt1 = toZonedDateTime(date1, timeZone, calendar) const zdt2 = toZonedDateTime(date2, timeZone, calendar) diff --git a/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts b/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts index 45da3026..8ee3eda5 100644 --- a/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts +++ b/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts @@ -28,12 +28,10 @@ export function isSameOrAfter( options: IsSameOrAfterOptions, ): boolean { const defaults = getDateDefaults() - const timeZone = options.timeZone ?? defaults.timeZone - const calendar = options.calendar ?? defaults.calendar + const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options const startOf1 = startOf(date1, { unit: options.unit, timeZone, calendar }) const startOf2 = startOf(date2, { unit: options.unit, timeZone, calendar }) - const zdt1 = startOf1.asZonedDateTime() const zdt2 = startOf2.asZonedDateTime() diff --git a/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts b/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts index bd789cdb..2763c5d6 100644 --- a/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts +++ b/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts @@ -28,20 +28,18 @@ export function isSameOrBefore( options: IsSameOrBeforeOptions, ): boolean { const defaults = getDateDefaults() - const timeZone = options.timeZone ?? defaults.timeZone - const calendar = options.calendar ?? defaults.calendar + const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options const startOf1 = startOf(date1, { unit: options.unit, timeZone, calendar }) const startOf2 = startOf(date2, { unit: options.unit, timeZone, calendar }) - const zdt1 = startOf1.asZonedDateTime() const zdt2 = startOf2.asZonedDateTime() if (options.unit === 'week') { const normalized1 = normalizeWeek(zdt1) const normalized2 = normalizeWeek(zdt2) - return Temporal.ZonedDateTime.compare(normalized1, normalized2) <= 0 + return Temporal.ZonedDateTime.compare(normalized1, normalized2) >= 0 } - return Temporal.ZonedDateTime.compare(zdt1, zdt2) <= 0 + return Temporal.ZonedDateTime.compare(zdt1, zdt2) >= 0 } diff --git a/packages/time/src/date/since/since.ts b/packages/time/src/date/since/since.ts index 7a4eb81c..a437833e 100644 --- a/packages/time/src/date/since/since.ts +++ b/packages/time/src/date/since/since.ts @@ -14,17 +14,10 @@ export interface SinceOptions extends DateOptions { */ export function since(start: DateInput, end: DateInput, options: SinceOptions) { const defaults = getDateDefaults() - const timeZone = options.timeZone ?? defaults.timeZone - const calendar = options.calendar ?? defaults.calendar + const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options const startZdt = toZonedDateTime(start, timeZone, calendar) const endZdt = toZonedDateTime(end, timeZone, calendar) - const duration = endZdt.since(startZdt) - const unit = options.unit - - return duration.total({ - unit, - relativeTo: startZdt, - }) + return duration.total({ unit: options.unit, relativeTo: startZdt }) } diff --git a/packages/time/src/date/until/until.ts b/packages/time/src/date/until/until.ts index bf74f6e8..fddf3e89 100644 --- a/packages/time/src/date/until/until.ts +++ b/packages/time/src/date/until/until.ts @@ -13,8 +13,7 @@ export interface UntilOptions extends DateOptions { */ export function until(start: DateInput, end: DateInput, options: UntilOptions) { const defaults = getDateDefaults() - const timeZone = options.timeZone ?? defaults.timeZone - const calendar = options.calendar ?? defaults.calendar + const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options const startZdt = toZonedDateTime(start, timeZone, calendar) const endZdt = toZonedDateTime(end, timeZone, calendar) diff --git a/packages/time/src/date/withDateOperation/withDateOperation.ts b/packages/time/src/date/withDateOperation/withDateOperation.ts index 52adf3d0..9b3207dd 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.ts @@ -58,9 +58,11 @@ export function withDateOperation( ) { return (input: DateInput, options: DateOperationOptions & TArgs) => { const defaults = getDateDefaults() - const timeZone = options.timeZone ?? defaults.timeZone - const calendar = options.calendar ?? defaults.calendar - const returnFormat = options.returnFormat ?? 'standard' + const { + timeZone = defaults.timeZone, + calendar = defaults.calendar, + returnFormat = 'standard', + } = options const inputZdt = toZonedDateTime(input, timeZone, calendar) const resultZdt = fn(inputZdt, options) From 808726b87f66426635d33b9c4403db43d03d6f2a Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 20 Jan 2026 14:51:42 +0100 Subject: [PATCH 022/207] refactor: date comparition utils --- Methods.md | 57 ++++++++++++------- .../src/date/isSameOrBefore/isSameOrBefore.ts | 4 +- packages/time/src/date/round/round.ts | 4 +- .../withDateOperation.test.ts | 23 -------- .../withDateOperation/withDateOperation.ts | 21 ++----- 5 files changed, 47 insertions(+), 62 deletions(-) diff --git a/Methods.md b/Methods.md index 42beb37b..4874fed9 100644 --- a/Methods.md +++ b/Methods.md @@ -1,22 +1,39 @@ # What API methods do we need? -[x] startOf(ZonedDateTime, unit): ZonedDateTime āœ… -[x] endOf(ZonedDateTime, unit): ZonedDateTime āœ… -[x] add(ZonedDateTime, duration): ZonedDateTime āœ… -[x] subtract(ZonedDateTime, duration): ZonedDateTime āœ… -[x] until(ZonedDateTime, ZonedDateTime): Duration āœ… -[x] since(ZonedDateTime, ZonedDateTime): Duration āœ… -[x] equals(ZonedDateTime, ZonedDateTime, unit): boolean āœ… -[x] isBefore(ZonedDateTime, ZonedDateTime): boolean āœ… -[x] isAfter(ZonedDateTime, ZonedDateTime): boolean āœ… -[x] round(unit): ZonedDateTime āœ… -[x] isSameOrBefore(ZonedDateTime, ZonedDateTime, unit): boolean āœ… -[x] isSameOrAfter(ZonedDateTime, ZonedDateTime, unit): boolean āœ… -[x] isBetween(ZonedDateTime, Range): boolean āœ… -[x] intersects(ZonedDateTime, Range): boolean āœ… -[ ] time(PlainTime): ZonedDateTime (use getter/setter?) -[x] timeZone(IANATimeZoneId): ZonedDateTime (use getter/setter?) āœ… -[x] calendar(Calendar): ZonedDateTime (use getter/setter?) āœ… -[x] asEpoch āœ… -[x] asString āœ… -[x] asZonedDateTime āœ… +## Date Operations + +- [x] `startOf(input: DateInput, options: StartOfOptions): DateOperationResult` āœ… +- [x] `endOf(input: DateInput, options: EndOfOptions): DateOperationResult` āœ… +- [x] `add(input: DateInput, options: AddOptions): DateOperationResult` āœ… +- [x] `subtract(input: DateInput, options: SubtractOptions): DateOperationResult` āœ… +- [x] `round(input: DateInput, options: RoundOptions): DateOperationResult` āœ… + +## Duration Calculations + +- [x] `until(start: DateInput, end: DateInput, options: UntilOptions): number` āœ… +- [x] `since(start: DateInput, end: DateInput, options: SinceOptions): number` āœ… + +## Comparisons + +- [x] `equals(date1: DateInput, date2: DateInput, options: EqualsOptions): boolean` āœ… +- [x] `isBefore(date1: DateInput, date2: DateInput, options?: IsBeforeOptions): boolean` āœ… +- [x] `isAfter(date1: DateInput, date2: DateInput, options?: IsAfterOptions): boolean` āœ… +- [x] `isSameOrBefore(date1: DateInput, date2: DateInput, options: IsSameOrBeforeOptions): boolean` āœ… +- [x] `isSameOrAfter(date1: DateInput, date2: DateInput, options: IsSameOrAfterOptions): boolean` āœ… + +## Range Operations + +- [x] `isBetween(date: DateInput, options: IsBetweenOptions): boolean` āœ… +- [x] `intersects(date: DateInput, options: IntersectsOptions): boolean` āœ… + +## Type Definitions + +- `DateInput = string | number | Date | Temporal.ZonedDateTime` +- `DateOperationResult` - Object with `value`, `asDate()`, `asEpoch()`, `asString()`, `asZonedDateTime()`, etc. +- `Range = { start: DateInput, end: DateInput }` + +## Future Considerations + +- [ ] `time(PlainTime): ZonedDateTime` (use getter/setter?) +- [x] `timeZone(IANATimeZoneId): ZonedDateTime` (use getter/setter?) āœ… +- [x] `calendar(Calendar): ZonedDateTime` (use getter/setter?) āœ… diff --git a/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts b/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts index 2763c5d6..01003331 100644 --- a/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts +++ b/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts @@ -38,8 +38,8 @@ export function isSameOrBefore( if (options.unit === 'week') { const normalized1 = normalizeWeek(zdt1) const normalized2 = normalizeWeek(zdt2) - return Temporal.ZonedDateTime.compare(normalized1, normalized2) >= 0 + return Temporal.ZonedDateTime.compare(normalized1, normalized2) <= 0 } - return Temporal.ZonedDateTime.compare(zdt1, zdt2) >= 0 + return Temporal.ZonedDateTime.compare(zdt1, zdt2) <= 0 } diff --git a/packages/time/src/date/round/round.ts b/packages/time/src/date/round/round.ts index e9f912dc..1b4a711c 100644 --- a/packages/time/src/date/round/round.ts +++ b/packages/time/src/date/round/round.ts @@ -1,8 +1,8 @@ import { Temporal } from '@js-temporal/polyfill' +import { startOf } from '../startOf/startOf' import { withDateOperation } from '../withDateOperation' -import type { DateOperationOptions } from '../withDateOperation' import type { DateInput } from '../types' -import { startOf } from '../startOf/startOf' +import type { DateOperationOptions } from '../withDateOperation' export type RoundUnit = | 'year' diff --git a/packages/time/src/date/withDateOperation/withDateOperation.test.ts b/packages/time/src/date/withDateOperation/withDateOperation.test.ts index 59c51c39..598b0c09 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.test.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.test.ts @@ -74,29 +74,6 @@ describe('withDateOperation', () => { expect(new Date(epoch).toISOString()).toContain('2024-03-15') }) - test('should have asString method', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { - unit: 'test', - timeZone: 'UTC', - }) - const str = result.asString() - expect(typeof str).toBe('string') - expect(str).toContain('2024-03-15') - }) - - test('should have asLong method', () => { - const result = mockOperation('2024-03-15T14:42:12.789Z', { - unit: 'test', - timeZone: 'America/New_York', - calendar: 'gregory', - }) - const long = result.asLong() - expect(typeof long).toBe('string') - expect(long).toContain('2024-03-15') - expect(long).toContain('[America/New_York]') - expect(long).toContain('[u-ca=gregory]') - }) - test('should have asZonedDateTime method', () => { const result = mockOperation('2024-03-15T14:42:12.789Z', { unit: 'test', diff --git a/packages/time/src/date/withDateOperation/withDateOperation.ts b/packages/time/src/date/withDateOperation/withDateOperation.ts index 9b3207dd..ca6d9406 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.ts @@ -11,9 +11,9 @@ export interface DateOperationOptions extends DateOptions { function createDateOperationResult( zdt: Temporal.ZonedDateTime, - options: Required, - returnFormat: ReturnFormat = 'standard', + options: DateOperationOptions, ) { + const { returnFormat } = options const getValue = (): string => { switch (returnFormat) { case 'standard': @@ -35,12 +35,6 @@ function createDateOperationResult( asEpoch: () => { return Number(zdt.epochNanoseconds / 1_000_000n) }, - asString: () => { - return zdt.toInstant().toString() - }, - asLong: () => { - return `${zdt.toInstant().toString()}[${zdt.timeZoneId}][u-ca=${zdt.calendarId}]` - }, asZonedDateTime: () => { return zdt }, @@ -67,13 +61,10 @@ export function withDateOperation( const inputZdt = toZonedDateTime(input, timeZone, calendar) const resultZdt = fn(inputZdt, options) - return createDateOperationResult( - resultZdt, - { - timeZone, - calendar, - }, + return createDateOperationResult(resultZdt, { + timeZone, + calendar, returnFormat, - ) + }) } } From 4ae20c4bd7bda55dd10013969b65bd8cd8092e4f Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 20 Jan 2026 13:52:41 +0000 Subject: [PATCH 023/207] ci: apply automated fixes --- docs/reference/functions/add.md | 28 ++++------------------------ docs/reference/functions/endOf.md | 28 ++++------------------------ docs/reference/functions/round.md | 28 ++++------------------------ docs/reference/functions/startOf.md | 28 ++++------------------------ docs/reference/functions/subtract.md | 28 ++++------------------------ 5 files changed, 20 insertions(+), 120 deletions(-) diff --git a/docs/reference/functions/add.md b/docs/reference/functions/add.md index 17e7aa1a..4d459c35 100644 --- a/docs/reference/functions/add.md +++ b/docs/reference/functions/add.md @@ -48,26 +48,6 @@ asEpoch: () => number; `number` -### asLong() - -```ts -asLong: () => string; -``` - -#### Returns - -`string` - -### asString() - -```ts -asString: () => string; -``` - -#### Returns - -`string` - ### asZonedDateTime() ```ts @@ -81,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string = options.calendar; +calendar: string | undefined = options.calendar; ``` ### options ```ts -options: Required; +options: DateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat; +returnFormat: ReturnFormat | undefined; ``` ### timeZone ```ts -timeZone: string = options.timeZone; +timeZone: string | undefined = options.timeZone; ``` ### value diff --git a/docs/reference/functions/endOf.md b/docs/reference/functions/endOf.md index 6a3c3c07..e2dff876 100644 --- a/docs/reference/functions/endOf.md +++ b/docs/reference/functions/endOf.md @@ -48,26 +48,6 @@ asEpoch: () => number; `number` -### asLong() - -```ts -asLong: () => string; -``` - -#### Returns - -`string` - -### asString() - -```ts -asString: () => string; -``` - -#### Returns - -`string` - ### asZonedDateTime() ```ts @@ -81,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string = options.calendar; +calendar: string | undefined = options.calendar; ``` ### options ```ts -options: Required; +options: DateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat; +returnFormat: ReturnFormat | undefined; ``` ### timeZone ```ts -timeZone: string = options.timeZone; +timeZone: string | undefined = options.timeZone; ``` ### value diff --git a/docs/reference/functions/round.md b/docs/reference/functions/round.md index f09ffbfa..efa471d6 100644 --- a/docs/reference/functions/round.md +++ b/docs/reference/functions/round.md @@ -48,26 +48,6 @@ asEpoch: () => number; `number` -### asLong() - -```ts -asLong: () => string; -``` - -#### Returns - -`string` - -### asString() - -```ts -asString: () => string; -``` - -#### Returns - -`string` - ### asZonedDateTime() ```ts @@ -81,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string = options.calendar; +calendar: string | undefined = options.calendar; ``` ### options ```ts -options: Required; +options: DateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat; +returnFormat: ReturnFormat | undefined; ``` ### timeZone ```ts -timeZone: string = options.timeZone; +timeZone: string | undefined = options.timeZone; ``` ### value diff --git a/docs/reference/functions/startOf.md b/docs/reference/functions/startOf.md index f9718629..e7bb94dc 100644 --- a/docs/reference/functions/startOf.md +++ b/docs/reference/functions/startOf.md @@ -48,26 +48,6 @@ asEpoch: () => number; `number` -### asLong() - -```ts -asLong: () => string; -``` - -#### Returns - -`string` - -### asString() - -```ts -asString: () => string; -``` - -#### Returns - -`string` - ### asZonedDateTime() ```ts @@ -81,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string = options.calendar; +calendar: string | undefined = options.calendar; ``` ### options ```ts -options: Required; +options: DateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat; +returnFormat: ReturnFormat | undefined; ``` ### timeZone ```ts -timeZone: string = options.timeZone; +timeZone: string | undefined = options.timeZone; ``` ### value diff --git a/docs/reference/functions/subtract.md b/docs/reference/functions/subtract.md index 8777ddb8..8d67b8aa 100644 --- a/docs/reference/functions/subtract.md +++ b/docs/reference/functions/subtract.md @@ -48,26 +48,6 @@ asEpoch: () => number; `number` -### asLong() - -```ts -asLong: () => string; -``` - -#### Returns - -`string` - -### asString() - -```ts -asString: () => string; -``` - -#### Returns - -`string` - ### asZonedDateTime() ```ts @@ -81,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string = options.calendar; +calendar: string | undefined = options.calendar; ``` ### options ```ts -options: Required; +options: DateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat; +returnFormat: ReturnFormat | undefined; ``` ### timeZone ```ts -timeZone: string = options.timeZone; +timeZone: string | undefined = options.timeZone; ``` ### value From 12998a37465e01d0141244e3d2d060a03d395eec Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Wed, 21 Jan 2026 08:14:24 +0100 Subject: [PATCH 024/207] feat: format util --- Methods.md | 39 --- packages/time/src/date/format/format.ts | 87 ++++++ packages/time/src/date/format/index.ts | 2 + .../time/src/date/format/tests/format.test.ts | 275 ++++++++++++++++++ packages/time/src/date/index.ts | 3 +- 5 files changed, 366 insertions(+), 40 deletions(-) delete mode 100644 Methods.md create mode 100644 packages/time/src/date/format/format.ts create mode 100644 packages/time/src/date/format/index.ts create mode 100644 packages/time/src/date/format/tests/format.test.ts diff --git a/Methods.md b/Methods.md deleted file mode 100644 index 4874fed9..00000000 --- a/Methods.md +++ /dev/null @@ -1,39 +0,0 @@ -# What API methods do we need? - -## Date Operations - -- [x] `startOf(input: DateInput, options: StartOfOptions): DateOperationResult` āœ… -- [x] `endOf(input: DateInput, options: EndOfOptions): DateOperationResult` āœ… -- [x] `add(input: DateInput, options: AddOptions): DateOperationResult` āœ… -- [x] `subtract(input: DateInput, options: SubtractOptions): DateOperationResult` āœ… -- [x] `round(input: DateInput, options: RoundOptions): DateOperationResult` āœ… - -## Duration Calculations - -- [x] `until(start: DateInput, end: DateInput, options: UntilOptions): number` āœ… -- [x] `since(start: DateInput, end: DateInput, options: SinceOptions): number` āœ… - -## Comparisons - -- [x] `equals(date1: DateInput, date2: DateInput, options: EqualsOptions): boolean` āœ… -- [x] `isBefore(date1: DateInput, date2: DateInput, options?: IsBeforeOptions): boolean` āœ… -- [x] `isAfter(date1: DateInput, date2: DateInput, options?: IsAfterOptions): boolean` āœ… -- [x] `isSameOrBefore(date1: DateInput, date2: DateInput, options: IsSameOrBeforeOptions): boolean` āœ… -- [x] `isSameOrAfter(date1: DateInput, date2: DateInput, options: IsSameOrAfterOptions): boolean` āœ… - -## Range Operations - -- [x] `isBetween(date: DateInput, options: IsBetweenOptions): boolean` āœ… -- [x] `intersects(date: DateInput, options: IntersectsOptions): boolean` āœ… - -## Type Definitions - -- `DateInput = string | number | Date | Temporal.ZonedDateTime` -- `DateOperationResult` - Object with `value`, `asDate()`, `asEpoch()`, `asString()`, `asZonedDateTime()`, etc. -- `Range = { start: DateInput, end: DateInput }` - -## Future Considerations - -- [ ] `time(PlainTime): ZonedDateTime` (use getter/setter?) -- [x] `timeZone(IANATimeZoneId): ZonedDateTime` (use getter/setter?) āœ… -- [x] `calendar(Calendar): ZonedDateTime` (use getter/setter?) āœ… diff --git a/packages/time/src/date/format/format.ts b/packages/time/src/date/format/format.ts new file mode 100644 index 00000000..f7c6f7a1 --- /dev/null +++ b/packages/time/src/date/format/format.ts @@ -0,0 +1,87 @@ +import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import { buildFinalFormatter } from '../../formatter/buildFinalFormatter' +import { buildDateFormatter } from '../../formatter/buildDateFormatter' +import { buildTimeFormatter } from '../../formatter/buildTimeFormatter' +import { buildDateTimeFormatter } from '../../formatter/buildDateTimeFormatter' +import type { DateInput, DateOptions } from '../types' +import type { + DateFormatterBuildParams, + DateTimeFormatterBuildParams, + TimeFormatterBuildParams, +} from '../../formatter/shared' + +export type FormatType = 'date' | 'time' | 'datetime' + +export interface FormatDateOptions extends DateOptions { + type?: FormatType + locale?: string | Intl.Locale | Array | Array + options?: + | string + | DateFormatterBuildParams['options'] + | TimeFormatterBuildParams['options'] + | DateTimeFormatterBuildParams['options'] +} + +/** + * format + * Formats a date/time instance using Intl.DateTimeFormat + * @param date - The date to format + * @param formatOptions - Formatting options including type, locale, and Intl.DateTimeFormat options + */ +export function format( + date: DateInput, + formatOptions?: FormatDateOptions, +): string { + const defaults = getDateDefaults() + const { + type = 'datetime', + locale = defaults.locale, + timeZone = defaults.timeZone, + calendar = defaults.calendar, + options, + } = formatOptions ?? {} + + const zdt = toZonedDateTime(date, timeZone, calendar) + const dateObj = new Date(Number(zdt.epochNanoseconds / 1_000_000n)) + + const mergedOptions = + typeof options === 'string' + ? options + : { + ...options, + timeZone, + calendar, + } + + let formatter: Intl.DateTimeFormat + + switch (type) { + case 'date': + formatter = buildDateFormatter({ + locale, + options: mergedOptions as DateFormatterBuildParams['options'], + }) + break + case 'time': + formatter = buildTimeFormatter({ + locale, + options: mergedOptions as TimeFormatterBuildParams['options'], + }) + break + case 'datetime': + default: + formatter = buildDateTimeFormatter({ + locale, + options: mergedOptions as DateTimeFormatterBuildParams['options'], + }) + break + } + + const formatFn = buildFinalFormatter({ + formatter, + formatterName: 'format', + }) + + return formatFn(dateObj) +} diff --git a/packages/time/src/date/format/index.ts b/packages/time/src/date/format/index.ts new file mode 100644 index 00000000..ba9e8a49 --- /dev/null +++ b/packages/time/src/date/format/index.ts @@ -0,0 +1,2 @@ +export { format } from './format' +export type { FormatDateOptions, FormatType } from './format' diff --git a/packages/time/src/date/format/tests/format.test.ts b/packages/time/src/date/format/tests/format.test.ts new file mode 100644 index 00000000..007081eb --- /dev/null +++ b/packages/time/src/date/format/tests/format.test.ts @@ -0,0 +1,275 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { format } from '../format' + +describe('format', () => { + describe('with default datetime format', () => { + test('should format date with string input', () => { + const result = format('2024-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format date with Date input', () => { + const date = new Date('2024-03-15T14:42:12.789Z') + const result = format(date, { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format date with epoch time input', () => { + const epoch = new Date('2024-03-15T14:42:12.789Z').getTime() + const result = format(epoch, { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format date with ZonedDateTime input', () => { + const zdt = Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const result = format(zdt, { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + }) + + describe('with date type', () => { + test('should format date only', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'date', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format date with dateStyle option', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'date', + options: 'full', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format date with object options', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'date', + options: { + year: 'numeric', + month: 'long', + day: 'numeric', + }, + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + }) + + describe('with time type', () => { + test('should format time only', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'time', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format time with timeStyle option', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'time', + options: 'full', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format time with object options', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'time', + options: { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }, + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + }) + + describe('with datetime type', () => { + test('should format date and time', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'datetime', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format datetime with style option', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'datetime', + options: 'full', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format datetime with object options', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'datetime', + options: { + year: 'numeric', + month: 'long', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + }, + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + }) + + describe('locale handling', () => { + test('should format with different locale', () => { + const result = format('2024-03-15T14:42:12.789Z', { + locale: 'en-US', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format with French locale', () => { + const result = format('2024-03-15T14:42:12.789Z', { + locale: 'fr-FR', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format with Japanese locale', () => { + const result = format('2024-03-15T14:42:12.789Z', { + locale: 'ja-JP', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + }) + + describe('timezone handling', () => { + test('should format with UTC timezone', () => { + const result = format('2024-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format with America/New_York timezone', () => { + const result = format('2024-03-15T14:42:12.789Z', { + timeZone: 'America/New_York', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format with Asia/Tokyo timezone', () => { + const result = format('2024-03-15T14:42:12.789Z', { + timeZone: 'Asia/Tokyo', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + }) + + describe('calendar handling', () => { + test('should format with default calendar', () => { + const result = format('2024-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format with japanese calendar', () => { + const result = format('2024-03-15T14:42:12.789Z', { + calendar: 'japanese', + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + }) + + describe('edge cases', () => { + test('should handle year boundary', () => { + const result = format('2023-12-31T23:59:59.999Z', { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should handle leap year date', () => { + const result = format('2024-02-29T12:00:00Z', { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should handle midnight', () => { + const result = format('2024-03-15T00:00:00Z', { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should handle end of day', () => { + const result = format('2024-03-15T23:59:59.999Z', { + timeZone: 'UTC', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + }) + + describe('with minimal options', () => { + test('should format with no options', () => { + const result = format('2024-03-15T14:42:12.789Z') + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + + test('should format with only type option', () => { + const result = format('2024-03-15T14:42:12.789Z', { + type: 'date', + }) + expect(typeof result).toBe('string') + expect(result.length).toBeGreaterThan(0) + }) + }) +}) diff --git a/packages/time/src/date/index.ts b/packages/time/src/date/index.ts index 0040c9ba..3996a22d 100644 --- a/packages/time/src/date/index.ts +++ b/packages/time/src/date/index.ts @@ -1,3 +1,4 @@ +export type * from './types' export * from './add' export * from './subtract' export * from './since' @@ -12,4 +13,4 @@ export * from './isSameOrBefore' export * from './isSameOrAfter' export * from './isBetween' export * from './intersects' -export type { Range } from './types' +export * from './formatDate' From f3a70ee490f7eab77313fbff02979daae695d46c Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Wed, 21 Jan 2026 08:14:46 +0100 Subject: [PATCH 025/207] feat: format util --- packages/time/src/date/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/time/src/date/index.ts b/packages/time/src/date/index.ts index 3996a22d..ebc39446 100644 --- a/packages/time/src/date/index.ts +++ b/packages/time/src/date/index.ts @@ -13,4 +13,4 @@ export * from './isSameOrBefore' export * from './isSameOrAfter' export * from './isBetween' export * from './intersects' -export * from './formatDate' +export * from './format' From deb652e32241d55361acb7796f31cc5f6d9ddb22 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 07:15:38 +0000 Subject: [PATCH 026/207] ci: apply automated fixes --- docs/reference/functions/add.md | 2 +- docs/reference/functions/endOf.md | 2 +- docs/reference/functions/equals.md | 4 +- docs/reference/functions/format.md | 33 ++++++ docs/reference/functions/intersects.md | 2 +- docs/reference/functions/isAfter.md | 4 +- docs/reference/functions/isBefore.md | 4 +- docs/reference/functions/isBetween.md | 2 +- docs/reference/functions/isSameOrAfter.md | 4 +- docs/reference/functions/isSameOrBefore.md | 4 +- docs/reference/functions/round.md | 2 +- docs/reference/functions/since.md | 4 +- docs/reference/functions/startOf.md | 2 +- docs/reference/functions/subtract.md | 2 +- docs/reference/functions/until.md | 4 +- docs/reference/index.md | 6 + docs/reference/interfaces/DateOptions.md | 41 +++++++ docs/reference/interfaces/DurationLike.md | 108 ++++++++++++++++++ docs/reference/interfaces/EqualsOptions.md | 10 +- .../reference/interfaces/FormatDateOptions.md | 74 ++++++++++++ .../reference/interfaces/IntersectsOptions.md | 10 +- docs/reference/interfaces/IsAfterOptions.md | 10 +- docs/reference/interfaces/IsBeforeOptions.md | 10 +- docs/reference/interfaces/IsBetweenOptions.md | 10 +- .../interfaces/IsSameOrAfterOptions.md | 10 +- .../interfaces/IsSameOrBeforeOptions.md | 10 +- docs/reference/interfaces/SinceOptions.md | 10 +- docs/reference/interfaces/UntilOptions.md | 10 +- docs/reference/type-aliases/DateInput.md | 12 ++ docs/reference/type-aliases/FormatType.md | 12 ++ 30 files changed, 334 insertions(+), 84 deletions(-) create mode 100644 docs/reference/functions/format.md create mode 100644 docs/reference/interfaces/DateOptions.md create mode 100644 docs/reference/interfaces/DurationLike.md create mode 100644 docs/reference/interfaces/FormatDateOptions.md create mode 100644 docs/reference/type-aliases/DateInput.md create mode 100644 docs/reference/type-aliases/FormatType.md diff --git a/docs/reference/functions/add.md b/docs/reference/functions/add.md index 4d459c35..d9d3a05e 100644 --- a/docs/reference/functions/add.md +++ b/docs/reference/functions/add.md @@ -18,7 +18,7 @@ Adds a duration to a date/time instance ### input -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options diff --git a/docs/reference/functions/endOf.md b/docs/reference/functions/endOf.md index e2dff876..a45e48fb 100644 --- a/docs/reference/functions/endOf.md +++ b/docs/reference/functions/endOf.md @@ -18,7 +18,7 @@ Returns the end of a given unit for a date/time instance ### input -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options diff --git a/docs/reference/functions/equals.md b/docs/reference/functions/equals.md index 12950ac6..fd9a786b 100644 --- a/docs/reference/functions/equals.md +++ b/docs/reference/functions/equals.md @@ -22,11 +22,11 @@ Returns true if two date/time instances are equal at the specified unit level ### date1 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### date2 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### unit diff --git a/docs/reference/functions/format.md b/docs/reference/functions/format.md new file mode 100644 index 00000000..f7ca6174 --- /dev/null +++ b/docs/reference/functions/format.md @@ -0,0 +1,33 @@ +--- +id: format +title: format +--- + +# Function: format() + +```ts +function format(date, formatOptions?): string; +``` + +Defined in: [format/format.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L32) + +format +Formats a date/time instance using Intl.DateTimeFormat + +## Parameters + +### date + +[`DateInput`](../type-aliases/DateInput.md) + +The date to format + +### formatOptions? + +[`FormatDateOptions`](../interfaces/FormatDateOptions.md) + +Formatting options including type, locale, and Intl.DateTimeFormat options + +## Returns + +`string` diff --git a/docs/reference/functions/intersects.md b/docs/reference/functions/intersects.md index eeddb7e0..824c8bbc 100644 --- a/docs/reference/functions/intersects.md +++ b/docs/reference/functions/intersects.md @@ -18,7 +18,7 @@ Returns true if the date/time instance intersects with the range (i.e., is withi ### date -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) The date to check diff --git a/docs/reference/functions/isAfter.md b/docs/reference/functions/isAfter.md index 15207507..f39f9d47 100644 --- a/docs/reference/functions/isAfter.md +++ b/docs/reference/functions/isAfter.md @@ -21,11 +21,11 @@ Returns true if the first date/time instance is after the second date/time insta ### date1 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### date2 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options? diff --git a/docs/reference/functions/isBefore.md b/docs/reference/functions/isBefore.md index 926ee6eb..b31cdcbf 100644 --- a/docs/reference/functions/isBefore.md +++ b/docs/reference/functions/isBefore.md @@ -21,11 +21,11 @@ Returns true if the first date/time instance is before the second date/time inst ### date1 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### date2 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options? diff --git a/docs/reference/functions/isBetween.md b/docs/reference/functions/isBetween.md index 751f5aea..1c89b65e 100644 --- a/docs/reference/functions/isBetween.md +++ b/docs/reference/functions/isBetween.md @@ -18,7 +18,7 @@ Returns true if the date/time instance is between the start and end of the range ### date -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) The date to check diff --git a/docs/reference/functions/isSameOrAfter.md b/docs/reference/functions/isSameOrAfter.md index e9da696a..b3495511 100644 --- a/docs/reference/functions/isSameOrAfter.md +++ b/docs/reference/functions/isSameOrAfter.md @@ -21,11 +21,11 @@ Returns true if the first date/time instance is the same as or after the second ### date1 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### date2 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options diff --git a/docs/reference/functions/isSameOrBefore.md b/docs/reference/functions/isSameOrBefore.md index 7fa72ce2..2bc2a75e 100644 --- a/docs/reference/functions/isSameOrBefore.md +++ b/docs/reference/functions/isSameOrBefore.md @@ -21,11 +21,11 @@ Returns true if the first date/time instance is the same as or before the second ### date1 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### date2 -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options diff --git a/docs/reference/functions/round.md b/docs/reference/functions/round.md index efa471d6..6a09beff 100644 --- a/docs/reference/functions/round.md +++ b/docs/reference/functions/round.md @@ -18,7 +18,7 @@ Returns the date/time instance rounded to the nearest unit ### input -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options diff --git a/docs/reference/functions/since.md b/docs/reference/functions/since.md index 20c2f9c9..78ece940 100644 --- a/docs/reference/functions/since.md +++ b/docs/reference/functions/since.md @@ -22,11 +22,11 @@ Returns the duration from the first date/time instance since the second date/tim ### start -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### end -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options diff --git a/docs/reference/functions/startOf.md b/docs/reference/functions/startOf.md index e7bb94dc..bc7c1506 100644 --- a/docs/reference/functions/startOf.md +++ b/docs/reference/functions/startOf.md @@ -18,7 +18,7 @@ Returns the start of a given unit for a date/time instance ### input -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options diff --git a/docs/reference/functions/subtract.md b/docs/reference/functions/subtract.md index 8d67b8aa..f6b19beb 100644 --- a/docs/reference/functions/subtract.md +++ b/docs/reference/functions/subtract.md @@ -18,7 +18,7 @@ Subtracts a duration from a date/time instance ### input -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options diff --git a/docs/reference/functions/until.md b/docs/reference/functions/until.md index 98786af6..ff727d9c 100644 --- a/docs/reference/functions/until.md +++ b/docs/reference/functions/until.md @@ -21,11 +21,11 @@ Returns the duration from the first date/time instance until the second date/tim ### start -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### end -`DateInput` +[`DateInput`](../type-aliases/DateInput.md) ### options diff --git a/docs/reference/index.md b/docs/reference/index.md index aeedc313..bf0836c3 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -8,8 +8,11 @@ title: "@tanstack/time" ## Interfaces - [AddOptions](interfaces/AddOptions.md) +- [DateOptions](interfaces/DateOptions.md) +- [DurationLike](interfaces/DurationLike.md) - [EndOfOptions](interfaces/EndOfOptions.md) - [EqualsOptions](interfaces/EqualsOptions.md) +- [FormatDateOptions](interfaces/FormatDateOptions.md) - [IntersectsOptions](interfaces/IntersectsOptions.md) - [IsAfterOptions](interfaces/IsAfterOptions.md) - [IsBeforeOptions](interfaces/IsBeforeOptions.md) @@ -25,8 +28,10 @@ title: "@tanstack/time" ## Type Aliases +- [DateInput](type-aliases/DateInput.md) - [EndOfUnit](type-aliases/EndOfUnit.md) - [EqualsUnit](type-aliases/EqualsUnit.md) +- [FormatType](type-aliases/FormatType.md) - [IsSameOrAfterUnit](type-aliases/IsSameOrAfterUnit.md) - [IsSameOrBeforeUnit](type-aliases/IsSameOrBeforeUnit.md) - [RoundUnit](type-aliases/RoundUnit.md) @@ -37,6 +42,7 @@ title: "@tanstack/time" - [add](functions/add.md) - [endOf](functions/endOf.md) - [equals](functions/equals.md) +- [format](functions/format.md) - [intersects](functions/intersects.md) - [isAfter](functions/isAfter.md) - [isBefore](functions/isBefore.md) diff --git a/docs/reference/interfaces/DateOptions.md b/docs/reference/interfaces/DateOptions.md new file mode 100644 index 00000000..d4e29a3d --- /dev/null +++ b/docs/reference/interfaces/DateOptions.md @@ -0,0 +1,41 @@ +--- +id: DateOptions +title: DateOptions +--- + +# Interface: DateOptions + +Defined in: [types.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L5) + +## Extended by + +- [`SinceOptions`](SinceOptions.md) +- [`UntilOptions`](UntilOptions.md) +- [`EqualsOptions`](EqualsOptions.md) +- [`IsBeforeOptions`](IsBeforeOptions.md) +- [`IsAfterOptions`](IsAfterOptions.md) +- [`IsSameOrBeforeOptions`](IsSameOrBeforeOptions.md) +- [`IsSameOrAfterOptions`](IsSameOrAfterOptions.md) +- [`IsBetweenOptions`](IsBetweenOptions.md) +- [`IntersectsOptions`](IntersectsOptions.md) +- [`FormatDateOptions`](FormatDateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) diff --git a/docs/reference/interfaces/DurationLike.md b/docs/reference/interfaces/DurationLike.md new file mode 100644 index 00000000..024fc98e --- /dev/null +++ b/docs/reference/interfaces/DurationLike.md @@ -0,0 +1,108 @@ +--- +id: DurationLike +title: DurationLike +--- + +# Interface: DurationLike + +Defined in: [types.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L10) + +## Properties + +### days? + +```ts +optional days: number; +``` + +Defined in: [types.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L14) + +*** + +### hours? + +```ts +optional hours: number; +``` + +Defined in: [types.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L15) + +*** + +### microseconds? + +```ts +optional microseconds: number; +``` + +Defined in: [types.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L19) + +*** + +### milliseconds? + +```ts +optional milliseconds: number; +``` + +Defined in: [types.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L18) + +*** + +### minutes? + +```ts +optional minutes: number; +``` + +Defined in: [types.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L16) + +*** + +### months? + +```ts +optional months: number; +``` + +Defined in: [types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +*** + +### nanoseconds? + +```ts +optional nanoseconds: number; +``` + +Defined in: [types.ts:20](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L20) + +*** + +### seconds? + +```ts +optional seconds: number; +``` + +Defined in: [types.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L17) + +*** + +### weeks? + +```ts +optional weeks: number; +``` + +Defined in: [types.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L13) + +*** + +### years? + +```ts +optional years: number; +``` + +Defined in: [types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) diff --git a/docs/reference/interfaces/EqualsOptions.md b/docs/reference/interfaces/EqualsOptions.md index 42db5762..b29ec885 100644 --- a/docs/reference/interfaces/EqualsOptions.md +++ b/docs/reference/interfaces/EqualsOptions.md @@ -9,7 +9,7 @@ Defined in: [equals/equals.ts:16](https://github.com/TanStack/time/blob/main/pac ## Extends -- `DateOptions` +- [`DateOptions`](DateOptions.md) ## Properties @@ -23,9 +23,7 @@ Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.calendar -``` +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) *** @@ -39,6 +37,4 @@ Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.timeZone -``` +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/FormatDateOptions.md b/docs/reference/interfaces/FormatDateOptions.md new file mode 100644 index 00000000..3656cdd4 --- /dev/null +++ b/docs/reference/interfaces/FormatDateOptions.md @@ -0,0 +1,74 @@ +--- +id: FormatDateOptions +title: FormatDateOptions +--- + +# Interface: FormatDateOptions + +Defined in: [format/format.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L16) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### locale? + +```ts +optional locale: string | Locale | string[] | Locale[]; +``` + +Defined in: [format/format.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L18) + +*** + +### options? + +```ts +optional options: + | string + | DateFormatterOptions + | TimeFormatterOptions + | DateTimeFormatterOptions; +``` + +Defined in: [format/format.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L19) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) + +*** + +### type? + +```ts +optional type: FormatType; +``` + +Defined in: [format/format.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L17) diff --git a/docs/reference/interfaces/IntersectsOptions.md b/docs/reference/interfaces/IntersectsOptions.md index 0d86af84..fbcb1bed 100644 --- a/docs/reference/interfaces/IntersectsOptions.md +++ b/docs/reference/interfaces/IntersectsOptions.md @@ -9,7 +9,7 @@ Defined in: [intersects/intersects.ts:6](https://github.com/TanStack/time/blob/m ## Extends -- `DateOptions` +- [`DateOptions`](DateOptions.md) ## Properties @@ -23,9 +23,7 @@ Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.calendar -``` +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) *** @@ -49,6 +47,4 @@ Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.timeZone -``` +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsAfterOptions.md b/docs/reference/interfaces/IsAfterOptions.md index 7101bacc..b9b2c323 100644 --- a/docs/reference/interfaces/IsAfterOptions.md +++ b/docs/reference/interfaces/IsAfterOptions.md @@ -9,7 +9,7 @@ Defined in: [isAfter/isAfter.ts:6](https://github.com/TanStack/time/blob/main/pa ## Extends -- `DateOptions` +- [`DateOptions`](DateOptions.md) ## Properties @@ -23,9 +23,7 @@ Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.calendar -``` +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) *** @@ -39,6 +37,4 @@ Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.timeZone -``` +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsBeforeOptions.md b/docs/reference/interfaces/IsBeforeOptions.md index 4217c8b4..17e05ed1 100644 --- a/docs/reference/interfaces/IsBeforeOptions.md +++ b/docs/reference/interfaces/IsBeforeOptions.md @@ -9,7 +9,7 @@ Defined in: [isBefore/isBefore.ts:6](https://github.com/TanStack/time/blob/main/ ## Extends -- `DateOptions` +- [`DateOptions`](DateOptions.md) ## Properties @@ -23,9 +23,7 @@ Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.calendar -``` +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) *** @@ -39,6 +37,4 @@ Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.timeZone -``` +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsBetweenOptions.md b/docs/reference/interfaces/IsBetweenOptions.md index 82b28f71..01282b14 100644 --- a/docs/reference/interfaces/IsBetweenOptions.md +++ b/docs/reference/interfaces/IsBetweenOptions.md @@ -9,7 +9,7 @@ Defined in: [isBetween/isBetween.ts:6](https://github.com/TanStack/time/blob/mai ## Extends -- `DateOptions` +- [`DateOptions`](DateOptions.md) ## Properties @@ -23,9 +23,7 @@ Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.calendar -``` +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) *** @@ -59,6 +57,4 @@ Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.timeZone -``` +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsSameOrAfterOptions.md b/docs/reference/interfaces/IsSameOrAfterOptions.md index a3e45792..29efc3e3 100644 --- a/docs/reference/interfaces/IsSameOrAfterOptions.md +++ b/docs/reference/interfaces/IsSameOrAfterOptions.md @@ -9,7 +9,7 @@ Defined in: [isSameOrAfter/isSameOrAfter.ts:17](https://github.com/TanStack/time ## Extends -- `DateOptions` +- [`DateOptions`](DateOptions.md) ## Properties @@ -23,9 +23,7 @@ Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.calendar -``` +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) *** @@ -39,9 +37,7 @@ Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.timeZone -``` +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) *** diff --git a/docs/reference/interfaces/IsSameOrBeforeOptions.md b/docs/reference/interfaces/IsSameOrBeforeOptions.md index 7b4facf4..60d6fb76 100644 --- a/docs/reference/interfaces/IsSameOrBeforeOptions.md +++ b/docs/reference/interfaces/IsSameOrBeforeOptions.md @@ -9,7 +9,7 @@ Defined in: [isSameOrBefore/isSameOrBefore.ts:17](https://github.com/TanStack/ti ## Extends -- `DateOptions` +- [`DateOptions`](DateOptions.md) ## Properties @@ -23,9 +23,7 @@ Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.calendar -``` +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) *** @@ -39,9 +37,7 @@ Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.timeZone -``` +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) *** diff --git a/docs/reference/interfaces/SinceOptions.md b/docs/reference/interfaces/SinceOptions.md index ca44c2f7..1a89c322 100644 --- a/docs/reference/interfaces/SinceOptions.md +++ b/docs/reference/interfaces/SinceOptions.md @@ -9,7 +9,7 @@ Defined in: [since/since.ts:6](https://github.com/TanStack/time/blob/main/packag ## Extends -- `DateOptions` +- [`DateOptions`](DateOptions.md) ## Properties @@ -23,9 +23,7 @@ Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.calendar -``` +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) *** @@ -39,9 +37,7 @@ Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.timeZone -``` +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) *** diff --git a/docs/reference/interfaces/UntilOptions.md b/docs/reference/interfaces/UntilOptions.md index 76a090a2..57ccccb7 100644 --- a/docs/reference/interfaces/UntilOptions.md +++ b/docs/reference/interfaces/UntilOptions.md @@ -9,7 +9,7 @@ Defined in: [until/until.ts:6](https://github.com/TanStack/time/blob/main/packag ## Extends -- `DateOptions` +- [`DateOptions`](DateOptions.md) ## Properties @@ -23,9 +23,7 @@ Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.calendar -``` +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) *** @@ -39,9 +37,7 @@ Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/tim #### Inherited from -```ts -DateOptions.timeZone -``` +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) *** diff --git a/docs/reference/type-aliases/DateInput.md b/docs/reference/type-aliases/DateInput.md new file mode 100644 index 00000000..c66a40c4 --- /dev/null +++ b/docs/reference/type-aliases/DateInput.md @@ -0,0 +1,12 @@ +--- +id: DateInput +title: DateInput +--- + +# Type Alias: DateInput + +```ts +type DateInput = string | number | Date | Temporal.ZonedDateTime; +``` + +Defined in: [types.ts:3](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L3) diff --git a/docs/reference/type-aliases/FormatType.md b/docs/reference/type-aliases/FormatType.md new file mode 100644 index 00000000..dfced255 --- /dev/null +++ b/docs/reference/type-aliases/FormatType.md @@ -0,0 +1,12 @@ +--- +id: FormatType +title: FormatType +--- + +# Type Alias: FormatType + +```ts +type FormatType = "date" | "time" | "datetime"; +``` + +Defined in: [format/format.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L14) From b19c47d3ec2e7e58cca3afe7340c849f3225ef6a Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Wed, 21 Jan 2026 16:09:09 +0100 Subject: [PATCH 027/207] feat: isLeapYear, isWeekend and isWeekday utils --- UTILITY_RESEARCH.md | 221 ++++++++++++++++ packages/time/src/date/index.ts | 3 + packages/time/src/date/isLeapYear/index.ts | 1 + .../time/src/date/isLeapYear/isLeapYear.ts | 16 ++ .../date/isLeapYear/tests/isLeapYear.test.ts | 169 +++++++++++++ packages/time/src/date/isWeekday/index.ts | 1 + packages/time/src/date/isWeekday/isWeekday.ts | 28 ++ .../date/isWeekday/tests/isWeekday.test.ts | 239 ++++++++++++++++++ packages/time/src/date/isWeekend/index.ts | 1 + packages/time/src/date/isWeekend/isWeekend.ts | 29 +++ .../date/isWeekend/tests/isWeekend.test.ts | 221 ++++++++++++++++ packages/time/src/date/round/round.ts | 96 +------ .../time/src/date/round/tests/round.test.ts | 80 ------ 13 files changed, 939 insertions(+), 166 deletions(-) create mode 100644 UTILITY_RESEARCH.md create mode 100644 packages/time/src/date/isLeapYear/index.ts create mode 100644 packages/time/src/date/isLeapYear/isLeapYear.ts create mode 100644 packages/time/src/date/isLeapYear/tests/isLeapYear.test.ts create mode 100644 packages/time/src/date/isWeekday/index.ts create mode 100644 packages/time/src/date/isWeekday/isWeekday.ts create mode 100644 packages/time/src/date/isWeekday/tests/isWeekday.test.ts create mode 100644 packages/time/src/date/isWeekend/index.ts create mode 100644 packages/time/src/date/isWeekend/isWeekend.ts create mode 100644 packages/time/src/date/isWeekend/tests/isWeekend.test.ts diff --git a/UTILITY_RESEARCH.md b/UTILITY_RESEARCH.md new file mode 100644 index 00000000..f7346da1 --- /dev/null +++ b/UTILITY_RESEARCH.md @@ -0,0 +1,221 @@ +# Utility Research: d3-time & date-fns + +## Already Implemented āœ… + +- `startOf` / `endOf` - Start/end of units +- `add` / `subtract` - Date arithmetic +- `round` - Round to nearest unit +- `isBefore` / `isAfter` - Comparisons +- `equals` - Equality with unit +- `isSameOrBefore` / `isSameOrAfter` - Comparison with unit +- `isBetween` / `intersects` - Range operations +- `since` / `until` - Duration calculations +- `format` - Date formatting + +## Recommended Additions + +### 1. Rounding & Boundaries (from d3-time) + +#### `ceil(date, unit)` - Round up to nearest unit āœ… + +- **Use case**: "Next Monday", "Next hour", "Next month" +- **Example**: `ceil('2024-03-15T14:30:00Z', { unit: 'hour' })` → `'2024-03-15T15:00:00Z'` +- **Status**: High priority - complements `round` and `startOf` + +#### `floor(date, unit)` - Round down to nearest unit āœ… + +- **Use case**: Similar to `startOf` but more explicit naming +- **Note**: Could be alias for `startOf` or separate implementation +- **Status**: Medium priority - `startOf` already covers this + +### 2. Range Generation (from d3-time & date-fns) + +#### `range(start, end, unit, step?)` - Generate array of dates + +- **Use case**: Generate dates for calendars, charts, time series +- **Example**: `range('2024-03-01', '2024-03-31', { unit: 'day' })` → array of all days in March +- **Example**: `range('2024-03-01T00:00:00Z', '2024-03-01T23:00:00Z', { unit: 'hour', step: 2 })` → every 2 hours +- **Status**: High priority - very useful for UI components + +#### `eachDayOfInterval(range)` - Generate days in range + +- **Use case**: Calendar views, date pickers +- **Status**: Medium priority - can use `range` with `unit: 'day'` + +#### `eachWeekOfInterval(range)` - Generate weeks in range + +- **Use case**: Week-based views +- **Status**: Medium priority - can use `range` with `unit: 'week'` + +### 3. Interval Counting (from d3-time) + +#### `count(start, end, unit)` - Count intervals between dates + +- **Use case**: "How many days/months/weeks between two dates?" +- **Example**: `count('2024-03-01', '2024-03-31', { unit: 'day' })` → `30` +- **Note**: Different from `until` which returns duration - this counts discrete intervals +- **Status**: High priority - common use case + +### 4. Date Clamping (from date-fns) + +#### `clamp(date, range)` - Ensure date is within range + +- **Use case**: Date picker min/max constraints, validation +- **Example**: `clamp('2024-05-01', { start: '2024-03-01', end: '2024-04-30' })` → `'2024-04-30'` +- **Status**: High priority - essential for date pickers + +### 5. Relative Time Checks (from date-fns) + +#### `isToday(date)` - Check if date is today + +- **Use case**: UI highlighting, relative formatting +- **Status**: Medium priority - convenience function + +#### `isYesterday(date)` / `isTomorrow(date)` - Relative day checks + +- **Use case**: Relative date formatting ("yesterday", "tomorrow") +- **Status**: Low priority - can be built with `isSameDay` + date arithmetic + +#### `isPast(date)` / `isFuture(date)` - Relative to now + +- **Use case**: Validation, conditional rendering +- **Status**: Medium priority - common use case + +### 6. Day/Week Helpers (from date-fns) + +#### `isWeekend(date)` / `isWeekday(date)` - Day type checks + +- **Use case**: Business logic, calendar highlighting +- **Status**: Medium priority - useful utility + +#### `isSameDay(date1, date2)` / `isSameMonth(date1, date2)` / `isSameYear(date1, date2)` + +- **Use case**: Convenience wrappers around `equals` with specific units +- **Status**: Low priority - `equals` with unit already covers this + +### 7. Getters (from date-fns) + +#### `getDayOfYear(date)` - Get day of year (1-365/366) + +- **Use case**: Analytics, progress tracking +- **Status**: Medium priority - niche but useful + +#### `getWeek(date)` - Get ISO week number + +- **Use case**: Week-based reporting, ISO 8601 compliance +- **Status**: Medium priority - depends on week calculation needs + +#### `getWeeksInMonth(date)` - Count weeks in month + +- **Use case**: Calendar layout calculations +- **Status**: Low priority - can be calculated + +### 8. Setters (from date-fns) + +#### `set(date, { year?, month?, day?, hour?, ... })` - Set date components + +- **Use case**: Date manipulation, form inputs +- **Example**: `set('2024-03-15T14:00:00Z', { month: 5, day: 1 })` → `'2024-06-01T14:00:00Z'` +- **Status**: High priority - very useful for date manipulation + +#### `setDate(date, day)` / `setMonth(date, month)` / `setYear(date, year)` - Individual setters + +- **Use case**: Convenience setters +- **Status**: Medium priority - can use `set` with single property + +### 9. Min/Max Operations (from date-fns) + +#### `min(dates[])` - Find earliest date + +- **Use case**: Finding earliest date in array +- **Status**: Medium priority - useful utility + +#### `max(dates[])` - Find latest date + +- **Use case**: Finding latest date in array +- **Status**: Medium priority - useful utility + +### 10. Calendar Differences (from date-fns) + +#### `differenceInCalendarDays(date1, date2)` - Calendar day difference + +- **Use case**: "How many calendar days apart?" vs duration +- **Note**: Different from `until` - counts calendar boundaries, not duration +- **Status**: Medium priority - useful distinction from duration + +#### `differenceInCalendarMonths(date1, date2)` / `differenceInCalendarYears(date1, date2)` + +- **Use case**: Calendar-based differences +- **Status**: Medium priority - similar to calendar days + +### 11. Offset/Step Operations (from d3-time) + +#### `offset(date, unit, step)` - Advance by step intervals + +- **Use case**: "Next 3 Mondays", "Every 15 minutes" +- **Example**: `offset('2024-03-15T14:00:00Z', { unit: 'day', step: 7 })` → next week same time +- **Status**: Medium priority - can use `add` with duration + +#### `every(unit, step)` - Create filtered interval + +- **Use case**: "Every 15 minutes", "Every 2 weeks" +- **Status**: Low priority - advanced use case + +### 12. Conversion Helpers (from date-fns) + +#### `toDate(dateInput)` - Convert to Date object + +- **Use case**: Interop with Date-based libraries +- **Status**: Low priority - `asDate()` already exists on results + +#### `fromUnixTime(timestamp)` - Create date from Unix timestamp + +- **Use case**: API responses, database timestamps +- **Status**: Medium priority - common conversion + +#### `getUnixTime(date)` - Get Unix timestamp + +- **Use case**: API requests, database storage +- **Status**: Medium priority - common conversion + +## Priority Recommendations + +### High Priority (Implement Soon) + +1. **`ceil`** - Round up to nearest unit (complements `round`) +2. **`range`** - Generate date arrays (essential for calendars/charts) +3. **`count`** - Count intervals between dates (common use case) +4. **`clamp`** - Date clamping (essential for date pickers) +5. **`set`** - Set date components (very useful for manipulation) + +### Medium Priority (Consider Adding) + +1. **`isPast` / `isFuture`** - Relative time checks +2. **`isWeekend` / `isWeekday`** - Day type checks +3. **`min` / `max`** - Array operations +4. **`differenceInCalendarDays`** - Calendar differences +5. **`fromUnixTime` / `getUnixTime`** - Unix timestamp conversion +6. **`getDayOfYear`** - Day of year getter +7. **`getWeek`** - ISO week number + +### Low Priority (Nice to Have) + +1. **`isToday` / `isYesterday` / `isTomorrow`** - Can be built from existing functions +2. **`isSameDay` / `isSameMonth`** - Convenience wrappers around `equals` +3. **`eachDayOfInterval`** - Can use `range` with `unit: 'day'` +4. **`setDate` / `setMonth`** - Can use `set` with single property +5. **`every`** - Advanced interval filtering + +## Implementation Notes + +- All functions should follow existing patterns: + - Accept `DateInput` (string | number | Date | ZonedDateTime) + - Support `DateOptions` (timeZone, calendar) + - Use Temporal API internally + - Return appropriate types (boolean, number, array, etc.) + +- Consider creating a `range` function that's flexible enough to replace multiple "each\*" functions + +- `ceil` should mirror `round` but always round up instead of nearest + +- `clamp` should work with the existing `Range` type diff --git a/packages/time/src/date/index.ts b/packages/time/src/date/index.ts index ebc39446..19c5b504 100644 --- a/packages/time/src/date/index.ts +++ b/packages/time/src/date/index.ts @@ -14,3 +14,6 @@ export * from './isSameOrAfter' export * from './isBetween' export * from './intersects' export * from './format' +export * from './isLeapYear' +export * from './isWeekend' +export * from './isWeekday' diff --git a/packages/time/src/date/isLeapYear/index.ts b/packages/time/src/date/isLeapYear/index.ts new file mode 100644 index 00000000..bda4faf1 --- /dev/null +++ b/packages/time/src/date/isLeapYear/index.ts @@ -0,0 +1 @@ +export * from './isLeapYear' diff --git a/packages/time/src/date/isLeapYear/isLeapYear.ts b/packages/time/src/date/isLeapYear/isLeapYear.ts new file mode 100644 index 00000000..492cd4bd --- /dev/null +++ b/packages/time/src/date/isLeapYear/isLeapYear.ts @@ -0,0 +1,16 @@ +import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { DateInput, DateOptions } from '../types' + +export interface IsLeapYearOptions extends DateOptions {} + +/** + * isLeapYear + * Returns true if the year of the given date is a leap year + */ +export function isLeapYear(date: DateInput, options?: IsLeapYearOptions): boolean { + const defaults = getDateDefaults() + const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options ?? {} + + return toZonedDateTime(date, timeZone, calendar).inLeapYear +} diff --git a/packages/time/src/date/isLeapYear/tests/isLeapYear.test.ts b/packages/time/src/date/isLeapYear/tests/isLeapYear.test.ts new file mode 100644 index 00000000..7f2d1323 --- /dev/null +++ b/packages/time/src/date/isLeapYear/tests/isLeapYear.test.ts @@ -0,0 +1,169 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { isLeapYear } from '../isLeapYear' + +describe('isLeapYear', () => { + describe('leap years', () => { + test('should return true for 2024 (divisible by 4)', () => { + const result = isLeapYear('2024-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for 2000 (divisible by 400)', () => { + const result = isLeapYear('2000-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for 2020 (divisible by 4)', () => { + const result = isLeapYear('2020-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for 2016 (divisible by 4)', () => { + const result = isLeapYear('2016-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true when date is February 29 of leap year', () => { + const result = isLeapYear('2024-02-29T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('non-leap years', () => { + test('should return false for 2023 (not divisible by 4)', () => { + const result = isLeapYear('2023-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false for 2025 (not divisible by 4)', () => { + const result = isLeapYear('2025-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false for 1900 (divisible by 100 but not 400)', () => { + const result = isLeapYear('1900-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false for 2100 (divisible by 100 but not 400)', () => { + const result = isLeapYear('2100-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + }) + + describe('with different input types', () => { + test('should work with Date object', () => { + const date = new Date('2024-03-15T14:42:12.789Z') + const result = isLeapYear(date, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const epoch = new Date('2024-03-15T14:42:12.789Z').getTime() + const result = isLeapYear(epoch, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with ZonedDateTime', () => { + const zdt = Temporal.ZonedDateTime.from( + '2024-03-15T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const result = isLeapYear(zdt, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with date string', () => { + const result = isLeapYear('2024-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timeZone option', () => { + const result = isLeapYear('2024-03-15T14:42:12.789Z', { + timeZone: 'America/New_York', + }) + expect(result).toBe(true) + }) + + test('should use default timeZone when not provided', () => { + const result = isLeapYear('2024-03-15T14:42:12.789Z') + expect(result).toBe(true) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar option', () => { + const result = isLeapYear('2024-03-15T14:42:12.789Z', { + calendar: 'japanese', + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should use default calendar when not provided', () => { + const result = isLeapYear('2024-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('edge cases', () => { + test('should handle year boundaries correctly', () => { + const result = isLeapYear('2024-12-31T23:59:59Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle January 1st correctly', () => { + const result = isLeapYear('2024-01-01T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle different months correctly', () => { + const result1 = isLeapYear('2024-01-15T00:00:00Z', { + timeZone: 'UTC', + }) + const result2 = isLeapYear('2024-06-15T00:00:00Z', { + timeZone: 'UTC', + }) + const result3 = isLeapYear('2024-12-15T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result1).toBe(true) + expect(result2).toBe(true) + expect(result3).toBe(true) + }) + }) +}) diff --git a/packages/time/src/date/isWeekday/index.ts b/packages/time/src/date/isWeekday/index.ts new file mode 100644 index 00000000..33af9578 --- /dev/null +++ b/packages/time/src/date/isWeekday/index.ts @@ -0,0 +1 @@ +export * from './isWeekday' diff --git a/packages/time/src/date/isWeekday/isWeekday.ts b/packages/time/src/date/isWeekday/isWeekday.ts new file mode 100644 index 00000000..8b7cd36f --- /dev/null +++ b/packages/time/src/date/isWeekday/isWeekday.ts @@ -0,0 +1,28 @@ +import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { DateInput, DateOptions } from '../types' + +export interface IsWeekdayOptions extends DateOptions { + locale?: string | Intl.Locale +} + +/** + * isWeekday + * Returns true if the date falls on a weekday based on locale-specific week info + */ +export function isWeekday(date: DateInput, options?: IsWeekdayOptions): boolean { + const defaults = getDateDefaults() + const { + timeZone = defaults.timeZone, + calendar = defaults.calendar, + locale = defaults.locale, + } = options ?? {} + + const zdt = toZonedDateTime(date, timeZone, calendar) + const dayOfWeek = zdt.dayOfWeek + + const localeObj = typeof locale === 'string' ? new Intl.Locale(locale) : locale + + const weekInfo = localeObj.getWeekInfo() + return !weekInfo.weekend.includes(dayOfWeek) +} diff --git a/packages/time/src/date/isWeekday/tests/isWeekday.test.ts b/packages/time/src/date/isWeekday/tests/isWeekday.test.ts new file mode 100644 index 00000000..ce3507e1 --- /dev/null +++ b/packages/time/src/date/isWeekday/tests/isWeekday.test.ts @@ -0,0 +1,239 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { isWeekday } from '../isWeekday' + +describe('isWeekday', () => { + describe('weekday days', () => { + test('should return true for Monday', () => { + const result = isWeekday('2024-03-18T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for Tuesday', () => { + const result = isWeekday('2024-03-19T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for Wednesday', () => { + const result = isWeekday('2024-03-20T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for Thursday', () => { + const result = isWeekday('2024-03-21T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for Friday', () => { + const result = isWeekday('2024-03-22T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for Monday at midnight', () => { + const result = isWeekday('2024-03-18T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for Friday at end of day', () => { + const result = isWeekday('2024-03-22T23:59:59Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('weekend days', () => { + test('should return false for Saturday', () => { + const result = isWeekday('2024-03-16T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false for Sunday', () => { + const result = isWeekday('2024-03-17T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + }) + + describe('with different input types', () => { + test('should work with Date object', () => { + const date = new Date('2024-03-18T14:42:12.789Z') + const result = isWeekday(date, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const epoch = new Date('2024-03-18T14:42:12.789Z').getTime() + const result = isWeekday(epoch, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with ZonedDateTime', () => { + const zdt = Temporal.ZonedDateTime.from( + '2024-03-18T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const result = isWeekday(zdt, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with date string', () => { + const result = isWeekday('2024-03-18T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timeZone option', () => { + const result = isWeekday('2024-03-18T14:42:12.789Z', { + timeZone: 'America/New_York', + }) + expect(result).toBe(true) + }) + + test('should use default timeZone when not provided', () => { + const result = isWeekday('2024-03-18T14:42:12.789Z') + expect(result).toBe(true) + }) + + test('should handle timezone differences correctly', () => { + const mondayUTC = '2024-03-18T23:00:00Z' + const result1 = isWeekday(mondayUTC, { + timeZone: 'UTC', + }) + const result2 = isWeekday(mondayUTC, { + timeZone: 'America/New_York', + }) + expect(result1).toBe(true) + expect(result2).toBe(true) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar option', () => { + const result = isWeekday('2024-03-18T14:42:12.789Z', { + calendar: 'japanese', + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should use default calendar when not provided', () => { + const result = isWeekday('2024-03-18T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('edge cases', () => { + test('should handle year boundaries correctly', () => { + const result = isWeekday('2024-01-01T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle leap year dates correctly', () => { + const result = isWeekday('2024-02-29T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle all days of the week correctly', () => { + const monday = isWeekday('2024-03-18T00:00:00Z', { timeZone: 'UTC' }) + const tuesday = isWeekday('2024-03-19T00:00:00Z', { timeZone: 'UTC' }) + const wednesday = isWeekday('2024-03-20T00:00:00Z', { timeZone: 'UTC' }) + const thursday = isWeekday('2024-03-21T00:00:00Z', { timeZone: 'UTC' }) + const friday = isWeekday('2024-03-22T00:00:00Z', { timeZone: 'UTC' }) + const saturday = isWeekday('2024-03-23T00:00:00Z', { timeZone: 'UTC' }) + const sunday = isWeekday('2024-03-24T00:00:00Z', { timeZone: 'UTC' }) + + expect(monday).toBe(true) + expect(tuesday).toBe(true) + expect(wednesday).toBe(true) + expect(thursday).toBe(true) + expect(friday).toBe(true) + expect(saturday).toBe(false) + expect(sunday).toBe(false) + }) + }) + + describe('locale-specific weekday handling', () => { + test('should respect Arabic locale (Friday-Saturday weekend)', () => { + const thursday = isWeekday('2024-03-14T14:42:12.789Z', { + locale: 'ar-SA', + timeZone: 'UTC', + }) + const friday = isWeekday('2024-03-15T14:42:12.789Z', { + locale: 'ar-SA', + timeZone: 'UTC', + }) + const saturday = isWeekday('2024-03-16T14:42:12.789Z', { + locale: 'ar-SA', + timeZone: 'UTC', + }) + const sunday = isWeekday('2024-03-17T14:42:12.789Z', { + locale: 'ar-SA', + timeZone: 'UTC', + }) + + expect(thursday).toBe(true) + expect(friday).toBe(false) + expect(saturday).toBe(false) + expect(sunday).toBe(true) + }) + + test('should respect default locale (Saturday-Sunday weekend)', () => { + const friday = isWeekday('2024-03-15T14:42:12.789Z', { + timeZone: 'UTC', + }) + const saturday = isWeekday('2024-03-16T14:42:12.789Z', { + timeZone: 'UTC', + }) + const sunday = isWeekday('2024-03-17T14:42:12.789Z', { + timeZone: 'UTC', + }) + const monday = isWeekday('2024-03-18T14:42:12.789Z', { + timeZone: 'UTC', + }) + + expect(friday).toBe(true) + expect(saturday).toBe(false) + expect(sunday).toBe(false) + expect(monday).toBe(true) + }) + + test('should work with Intl.Locale object', () => { + const locale = new Intl.Locale('ar-SA') + const thursday = isWeekday('2024-03-14T14:42:12.789Z', { + locale, + timeZone: 'UTC', + }) + expect(thursday).toBe(true) + }) + }) +}) diff --git a/packages/time/src/date/isWeekend/index.ts b/packages/time/src/date/isWeekend/index.ts new file mode 100644 index 00000000..2c905cb8 --- /dev/null +++ b/packages/time/src/date/isWeekend/index.ts @@ -0,0 +1 @@ +export * from './isWeekend' diff --git a/packages/time/src/date/isWeekend/isWeekend.ts b/packages/time/src/date/isWeekend/isWeekend.ts new file mode 100644 index 00000000..15b9433f --- /dev/null +++ b/packages/time/src/date/isWeekend/isWeekend.ts @@ -0,0 +1,29 @@ +import '../../polyfills/getWeekInfo' +import { getDateDefaults } from '../dateDefaults' +import { toZonedDateTime } from '../helpers' +import type { DateInput, DateOptions } from '../types' + +export interface IsWeekendOptions extends DateOptions { + locale?: string +} + +/** + * isWeekend + * Returns true if the date falls on a weekend based on locale-specific week info + */ +export function isWeekend(date: DateInput, options?: IsWeekendOptions): boolean { + const defaults = getDateDefaults() + const { + timeZone = defaults.timeZone, + calendar = defaults.calendar, + locale = defaults.locale, + } = options ?? {} + + const zdt = toZonedDateTime(date, timeZone, calendar) + const dayOfWeek = zdt.dayOfWeek + + const localeObj = new Intl.Locale(locale) + const weekInfo = localeObj.getWeekInfo() + + return weekInfo.weekend.includes(dayOfWeek) +} diff --git a/packages/time/src/date/isWeekend/tests/isWeekend.test.ts b/packages/time/src/date/isWeekend/tests/isWeekend.test.ts new file mode 100644 index 00000000..603c72e8 --- /dev/null +++ b/packages/time/src/date/isWeekend/tests/isWeekend.test.ts @@ -0,0 +1,221 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { isWeekend } from '../isWeekend' + +describe('isWeekend', () => { + describe('weekend days', () => { + test('should return true for Saturday', () => { + const result = isWeekend('2024-03-16T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for Sunday', () => { + const result = isWeekend('2024-03-17T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for Saturday at midnight', () => { + const result = isWeekend('2024-03-16T00:00:00Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should return true for Sunday at end of day', () => { + const result = isWeekend('2024-03-17T23:59:59Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('weekday days', () => { + test('should return false for Monday', () => { + const result = isWeekend('2024-03-18T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false for Tuesday', () => { + const result = isWeekend('2024-03-19T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false for Wednesday', () => { + const result = isWeekend('2024-03-20T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false for Thursday', () => { + const result = isWeekend('2024-03-21T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should return false for Friday', () => { + const result = isWeekend('2024-03-22T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + }) + + describe('with different input types', () => { + test('should work with Date object', () => { + const date = new Date('2024-03-16T14:42:12.789Z') + const result = isWeekend(date, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with epoch time', () => { + const epoch = new Date('2024-03-16T14:42:12.789Z').getTime() + const result = isWeekend(epoch, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with ZonedDateTime', () => { + const zdt = Temporal.ZonedDateTime.from( + '2024-03-16T14:42:12.789Z[UTC][u-ca=gregory]', + ) + const result = isWeekend(zdt, { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should work with date string', () => { + const result = isWeekend('2024-03-16T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('timezone handling', () => { + test('should respect timeZone option', () => { + const result = isWeekend('2024-03-16T14:42:12.789Z', { + timeZone: 'America/New_York', + }) + expect(result).toBe(true) + }) + + test('should use default timeZone when not provided', () => { + const result = isWeekend('2024-03-16T14:42:12.789Z') + expect(result).toBe(true) + }) + + test('should handle timezone differences correctly', () => { + const saturdayUTC = '2024-03-16T23:00:00Z' + const result1 = isWeekend(saturdayUTC, { + timeZone: 'UTC', + }) + const result2 = isWeekend(saturdayUTC, { + timeZone: 'America/New_York', + }) + expect(result1).toBe(true) + expect(result2).toBe(true) + }) + }) + + describe('calendar handling', () => { + test('should respect calendar option', () => { + const result = isWeekend('2024-03-16T14:42:12.789Z', { + calendar: 'japanese', + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should use default calendar when not provided', () => { + const result = isWeekend('2024-03-16T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + }) + + describe('edge cases', () => { + test('should handle year boundaries correctly', () => { + const result = isWeekend('2023-12-31T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(true) + }) + + test('should handle leap year dates correctly', () => { + const result = isWeekend('2024-02-29T14:42:12.789Z', { + timeZone: 'UTC', + }) + expect(result).toBe(false) + }) + + test('should handle all days of the week correctly', () => { + const monday = isWeekend('2024-03-18T00:00:00Z', { timeZone: 'UTC' }) + const tuesday = isWeekend('2024-03-19T00:00:00Z', { timeZone: 'UTC' }) + const wednesday = isWeekend('2024-03-20T00:00:00Z', { timeZone: 'UTC' }) + const thursday = isWeekend('2024-03-21T00:00:00Z', { timeZone: 'UTC' }) + const friday = isWeekend('2024-03-22T00:00:00Z', { timeZone: 'UTC' }) + const saturday = isWeekend('2024-03-23T00:00:00Z', { timeZone: 'UTC' }) + const sunday = isWeekend('2024-03-24T00:00:00Z', { timeZone: 'UTC' }) + + expect(monday).toBe(false) + expect(tuesday).toBe(false) + expect(wednesday).toBe(false) + expect(thursday).toBe(false) + expect(friday).toBe(false) + expect(saturday).toBe(true) + expect(sunday).toBe(true) + }) + }) + + describe('locale-specific weekend handling', () => { + test('should respect Arabic locale (Friday-Saturday weekend)', () => { + const friday = isWeekend('2024-03-15T14:42:12.789Z', { + locale: 'ar-SA', + timeZone: 'UTC', + }) + const saturday = isWeekend('2024-03-16T14:42:12.789Z', { + locale: 'ar-SA', + timeZone: 'UTC', + }) + const sunday = isWeekend('2024-03-17T14:42:12.789Z', { + locale: 'ar-SA', + timeZone: 'UTC', + }) + + expect(friday).toBe(true) + expect(saturday).toBe(true) + expect(sunday).toBe(false) + }) + + test('should respect default locale (Saturday-Sunday weekend)', () => { + const saturday = isWeekend('2024-03-16T14:42:12.789Z', { + timeZone: 'UTC', + }) + const sunday = isWeekend('2024-03-17T14:42:12.789Z', { + timeZone: 'UTC', + }) + const monday = isWeekend('2024-03-18T14:42:12.789Z', { + timeZone: 'UTC', + }) + + expect(saturday).toBe(true) + expect(sunday).toBe(true) + expect(monday).toBe(false) + }) + }) +}) diff --git a/packages/time/src/date/round/round.ts b/packages/time/src/date/round/round.ts index 1b4a711c..8fd3665a 100644 --- a/packages/time/src/date/round/round.ts +++ b/packages/time/src/date/round/round.ts @@ -1,21 +1,23 @@ -import { Temporal } from '@js-temporal/polyfill' -import { startOf } from '../startOf/startOf' import { withDateOperation } from '../withDateOperation' import type { DateInput } from '../types' import type { DateOperationOptions } from '../withDateOperation' +import type { Temporal } from '@js-temporal/polyfill' export type RoundUnit = - | 'year' - | 'month' - | 'week' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond' + | 'microsecond' + | 'nanosecond' + +export type RoundingMode = Temporal.RoundingMode export interface RoundOptions extends DateOperationOptions { unit: RoundUnit + roundingMode?: RoundingMode + roundingIncrement?: number } /** @@ -23,86 +25,8 @@ export interface RoundOptions extends DateOperationOptions { * Returns the date/time instance rounded to the nearest unit */ export function round(input: DateInput, options: RoundOptions) { - return withDateOperation((zdt, { unit }) => { - switch (unit) { - case 'year': { - const yearStart = startOf(zdt, { - unit: 'year', - timeZone: zdt.timeZoneId, - calendar: zdt.calendarId, - }).asZonedDateTime() - const nextYearStart = startOf(zdt.add({ years: 1 }), { - unit: 'year', - timeZone: zdt.timeZoneId, - calendar: zdt.calendarId, - }).asZonedDateTime() - const midpoint = yearStart.add({ months: 6 }) - return Temporal.ZonedDateTime.compare(zdt, midpoint) >= 0 - ? nextYearStart - : yearStart - } - case 'month': { - const monthStart = startOf(zdt, { - unit: 'month', - timeZone: zdt.timeZoneId, - calendar: zdt.calendarId, - }).asZonedDateTime() - const nextMonthStart = startOf(zdt.add({ months: 1 }), { - unit: 'month', - timeZone: zdt.timeZoneId, - calendar: zdt.calendarId, - }).asZonedDateTime() - const daysInMonth = zdt.daysInMonth - const midpoint = monthStart.add({ days: Math.floor(daysInMonth / 2) }) - return Temporal.ZonedDateTime.compare(zdt, midpoint) >= 0 - ? nextMonthStart - : monthStart - } - case 'week': { - const weekStart = startOf(zdt, { - unit: 'week', - timeZone: zdt.timeZoneId, - calendar: zdt.calendarId, - }).asZonedDateTime() - const nextWeekStart = startOf(zdt.add({ weeks: 1 }), { - unit: 'week', - timeZone: zdt.timeZoneId, - calendar: zdt.calendarId, - }).asZonedDateTime() - const midpoint = weekStart.add({ days: 3, hours: 12 }) - return Temporal.ZonedDateTime.compare(zdt, midpoint) >= 0 - ? nextWeekStart - : weekStart - } - case 'day': { - const dayStart = startOf(zdt, { - unit: 'day', - timeZone: zdt.timeZoneId, - calendar: zdt.calendarId, - }).asZonedDateTime() - const nextDayStart = startOf(zdt.add({ days: 1 }), { - unit: 'day', - timeZone: zdt.timeZoneId, - calendar: zdt.calendarId, - }).asZonedDateTime() - const midpoint = dayStart.add({ hours: 12 }) - return Temporal.ZonedDateTime.compare(zdt, midpoint) >= 0 - ? nextDayStart - : dayStart - } - case 'hour': - return zdt.round({ smallestUnit: 'hour', roundingMode: 'halfExpand' }) - case 'minute': - return zdt.round({ smallestUnit: 'minute', roundingMode: 'halfExpand' }) - case 'second': - return zdt.round({ smallestUnit: 'second', roundingMode: 'halfExpand' }) - case 'millisecond': - return zdt.round({ - smallestUnit: 'millisecond', - roundingMode: 'halfExpand', - }) - default: - return zdt - } + return withDateOperation((zdt, options) => { + const { unit, roundingMode = 'halfExpand', roundingIncrement } = options + return zdt.round({ smallestUnit: unit, roundingMode, roundingIncrement }) })(input, options) } diff --git a/packages/time/src/date/round/tests/round.test.ts b/packages/time/src/date/round/tests/round.test.ts index da79a48f..901539ac 100644 --- a/packages/time/src/date/round/tests/round.test.ts +++ b/packages/time/src/date/round/tests/round.test.ts @@ -3,78 +3,6 @@ import { Temporal } from '@js-temporal/polyfill' import { round } from '../round' describe('round', () => { - describe('rounding to year', () => { - test('should round down when before midpoint of year', () => { - const result = round('2024-06-15T14:42:12.789Z', { - unit: 'year', - timeZone: 'UTC', - }) - expect(result.value).toBe('2024-01-01T00:00:00Z') - }) - - test('should round up when at or after midpoint of year', () => { - const result = round('2024-07-15T14:42:12.789Z', { - unit: 'year', - timeZone: 'UTC', - }) - expect(result.value).toBe('2025-01-01T00:00:00Z') - }) - - test('should round down when exactly at start of year', () => { - const result = round('2024-01-01T00:00:00Z', { - unit: 'year', - timeZone: 'UTC', - }) - expect(result.value).toBe('2024-01-01T00:00:00Z') - }) - }) - - describe('rounding to month', () => { - test('should round down when before midpoint of month', () => { - const result = round('2024-03-10T14:42:12.789Z', { - unit: 'month', - timeZone: 'UTC', - }) - expect(result.value).toBe('2024-03-01T00:00:00Z') - }) - - test('should round up when at or after midpoint of month', () => { - const result = round('2024-03-20T14:42:12.789Z', { - unit: 'month', - timeZone: 'UTC', - }) - expect(result.value).toBe('2024-04-01T00:00:00Z') - }) - - test('should handle February correctly', () => { - const result = round('2024-02-15T14:42:12.789Z', { - unit: 'month', - timeZone: 'UTC', - }) - expect(result.value).toBe('2024-03-01T00:00:00Z') - }) - }) - - describe('rounding to week', () => { - test('should round down when before midpoint of week', () => { - const result = round('2024-03-13T10:00:00Z', { - unit: 'week', - timeZone: 'UTC', - }) - const weekStart = result.asZonedDateTime() - expect(weekStart.dayOfWeek).toBe(1) - }) - - test('should round up when at or after midpoint of week', () => { - const result = round('2024-03-16T18:00:00Z', { - unit: 'week', - timeZone: 'UTC', - }) - const weekStart = result.asZonedDateTime() - expect(weekStart.dayOfWeek).toBe(1) - }) - }) - describe('rounding to day', () => { test('should round down when before noon', () => { const result = round('2024-03-15T10:00:00Z', { @@ -243,13 +171,5 @@ describe('round', () => { }) expect(result.value).toBe('2024-03-01T00:00:00Z') }) - - test('should handle leap year correctly', () => { - const result = round('2024-02-15T12:00:00Z', { - unit: 'month', - timeZone: 'UTC', - }) - expect(result.value).toBe('2024-03-01T00:00:00Z') - }) }) }) From 1e63887e228bb51c4964d9fc9134b07f6a0bb757 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Wed, 21 Jan 2026 16:09:25 +0100 Subject: [PATCH 028/207] feat: isLeapYear, isWeekend and isWeekday utils --- packages/time/src/date/isLeapYear/isLeapYear.ts | 8 ++++++-- packages/time/src/date/isWeekday/isWeekday.ts | 8 ++++++-- packages/time/src/date/isWeekend/isWeekend.ts | 5 ++++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/time/src/date/isLeapYear/isLeapYear.ts b/packages/time/src/date/isLeapYear/isLeapYear.ts index 492cd4bd..f81a91e2 100644 --- a/packages/time/src/date/isLeapYear/isLeapYear.ts +++ b/packages/time/src/date/isLeapYear/isLeapYear.ts @@ -8,9 +8,13 @@ export interface IsLeapYearOptions extends DateOptions {} * isLeapYear * Returns true if the year of the given date is a leap year */ -export function isLeapYear(date: DateInput, options?: IsLeapYearOptions): boolean { +export function isLeapYear( + date: DateInput, + options?: IsLeapYearOptions, +): boolean { const defaults = getDateDefaults() - const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options ?? {} + const { timeZone = defaults.timeZone, calendar = defaults.calendar } = + options ?? {} return toZonedDateTime(date, timeZone, calendar).inLeapYear } diff --git a/packages/time/src/date/isWeekday/isWeekday.ts b/packages/time/src/date/isWeekday/isWeekday.ts index 8b7cd36f..b743cedc 100644 --- a/packages/time/src/date/isWeekday/isWeekday.ts +++ b/packages/time/src/date/isWeekday/isWeekday.ts @@ -10,7 +10,10 @@ export interface IsWeekdayOptions extends DateOptions { * isWeekday * Returns true if the date falls on a weekday based on locale-specific week info */ -export function isWeekday(date: DateInput, options?: IsWeekdayOptions): boolean { +export function isWeekday( + date: DateInput, + options?: IsWeekdayOptions, +): boolean { const defaults = getDateDefaults() const { timeZone = defaults.timeZone, @@ -21,7 +24,8 @@ export function isWeekday(date: DateInput, options?: IsWeekdayOptions): boolean const zdt = toZonedDateTime(date, timeZone, calendar) const dayOfWeek = zdt.dayOfWeek - const localeObj = typeof locale === 'string' ? new Intl.Locale(locale) : locale + const localeObj = + typeof locale === 'string' ? new Intl.Locale(locale) : locale const weekInfo = localeObj.getWeekInfo() return !weekInfo.weekend.includes(dayOfWeek) diff --git a/packages/time/src/date/isWeekend/isWeekend.ts b/packages/time/src/date/isWeekend/isWeekend.ts index 15b9433f..12d0abb1 100644 --- a/packages/time/src/date/isWeekend/isWeekend.ts +++ b/packages/time/src/date/isWeekend/isWeekend.ts @@ -11,7 +11,10 @@ export interface IsWeekendOptions extends DateOptions { * isWeekend * Returns true if the date falls on a weekend based on locale-specific week info */ -export function isWeekend(date: DateInput, options?: IsWeekendOptions): boolean { +export function isWeekend( + date: DateInput, + options?: IsWeekendOptions, +): boolean { const defaults = getDateDefaults() const { timeZone = defaults.timeZone, From 584c93f9a8d0764ea28136937ad8bbbe4a1f3374 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 15:10:17 +0000 Subject: [PATCH 029/207] ci: apply automated fixes --- docs/reference/functions/isLeapYear.md | 29 +++++++++++ docs/reference/functions/isWeekday.md | 29 +++++++++++ docs/reference/functions/isWeekend.md | 29 +++++++++++ docs/reference/functions/round.md | 2 +- docs/reference/index.md | 6 +++ docs/reference/interfaces/DateOptions.md | 3 ++ .../reference/interfaces/IsLeapYearOptions.md | 40 +++++++++++++++ docs/reference/interfaces/IsWeekdayOptions.md | 50 +++++++++++++++++++ docs/reference/interfaces/IsWeekendOptions.md | 50 +++++++++++++++++++ docs/reference/interfaces/RoundOptions.md | 20 ++++++++ docs/reference/type-aliases/RoundUnit.md | 9 ++-- 11 files changed, 261 insertions(+), 6 deletions(-) create mode 100644 docs/reference/functions/isLeapYear.md create mode 100644 docs/reference/functions/isWeekday.md create mode 100644 docs/reference/functions/isWeekend.md create mode 100644 docs/reference/interfaces/IsLeapYearOptions.md create mode 100644 docs/reference/interfaces/IsWeekdayOptions.md create mode 100644 docs/reference/interfaces/IsWeekendOptions.md diff --git a/docs/reference/functions/isLeapYear.md b/docs/reference/functions/isLeapYear.md new file mode 100644 index 00000000..559a24b4 --- /dev/null +++ b/docs/reference/functions/isLeapYear.md @@ -0,0 +1,29 @@ +--- +id: isLeapYear +title: isLeapYear +--- + +# Function: isLeapYear() + +```ts +function isLeapYear(date, options?): boolean; +``` + +Defined in: [isLeapYear/isLeapYear.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/isLeapYear/isLeapYear.ts#L11) + +isLeapYear +Returns true if the year of the given date is a leap year + +## Parameters + +### date + +[`DateInput`](../type-aliases/DateInput.md) + +### options? + +[`IsLeapYearOptions`](../interfaces/IsLeapYearOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isWeekday.md b/docs/reference/functions/isWeekday.md new file mode 100644 index 00000000..10f85958 --- /dev/null +++ b/docs/reference/functions/isWeekday.md @@ -0,0 +1,29 @@ +--- +id: isWeekday +title: isWeekday +--- + +# Function: isWeekday() + +```ts +function isWeekday(date, options?): boolean; +``` + +Defined in: [isWeekday/isWeekday.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekday/isWeekday.ts#L13) + +isWeekday +Returns true if the date falls on a weekday based on locale-specific week info + +## Parameters + +### date + +[`DateInput`](../type-aliases/DateInput.md) + +### options? + +[`IsWeekdayOptions`](../interfaces/IsWeekdayOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isWeekend.md b/docs/reference/functions/isWeekend.md new file mode 100644 index 00000000..57f9d80f --- /dev/null +++ b/docs/reference/functions/isWeekend.md @@ -0,0 +1,29 @@ +--- +id: isWeekend +title: isWeekend +--- + +# Function: isWeekend() + +```ts +function isWeekend(date, options?): boolean; +``` + +Defined in: [isWeekend/isWeekend.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L14) + +isWeekend +Returns true if the date falls on a weekend based on locale-specific week info + +## Parameters + +### date + +[`DateInput`](../type-aliases/DateInput.md) + +### options? + +[`IsWeekendOptions`](../interfaces/IsWeekendOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/round.md b/docs/reference/functions/round.md index 6a09beff..8f464e64 100644 --- a/docs/reference/functions/round.md +++ b/docs/reference/functions/round.md @@ -9,7 +9,7 @@ title: round function round(input, options): object; ``` -Defined in: [round/round.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L25) +Defined in: [round/round.ts:27](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L27) round Returns the date/time instance rounded to the nearest unit diff --git a/docs/reference/index.md b/docs/reference/index.md index bf0836c3..1036b1e1 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -17,8 +17,11 @@ title: "@tanstack/time" - [IsAfterOptions](interfaces/IsAfterOptions.md) - [IsBeforeOptions](interfaces/IsBeforeOptions.md) - [IsBetweenOptions](interfaces/IsBetweenOptions.md) +- [IsLeapYearOptions](interfaces/IsLeapYearOptions.md) - [IsSameOrAfterOptions](interfaces/IsSameOrAfterOptions.md) - [IsSameOrBeforeOptions](interfaces/IsSameOrBeforeOptions.md) +- [IsWeekdayOptions](interfaces/IsWeekdayOptions.md) +- [IsWeekendOptions](interfaces/IsWeekendOptions.md) - [Range](interfaces/Range.md) - [RoundOptions](interfaces/RoundOptions.md) - [SinceOptions](interfaces/SinceOptions.md) @@ -47,8 +50,11 @@ title: "@tanstack/time" - [isAfter](functions/isAfter.md) - [isBefore](functions/isBefore.md) - [isBetween](functions/isBetween.md) +- [isLeapYear](functions/isLeapYear.md) - [isSameOrAfter](functions/isSameOrAfter.md) - [isSameOrBefore](functions/isSameOrBefore.md) +- [isWeekday](functions/isWeekday.md) +- [isWeekend](functions/isWeekend.md) - [round](functions/round.md) - [since](functions/since.md) - [startOf](functions/startOf.md) diff --git a/docs/reference/interfaces/DateOptions.md b/docs/reference/interfaces/DateOptions.md index d4e29a3d..db4013b2 100644 --- a/docs/reference/interfaces/DateOptions.md +++ b/docs/reference/interfaces/DateOptions.md @@ -12,6 +12,9 @@ Defined in: [types.ts:5](https://github.com/TanStack/time/blob/main/packages/tim - [`SinceOptions`](SinceOptions.md) - [`UntilOptions`](UntilOptions.md) - [`EqualsOptions`](EqualsOptions.md) +- [`IsLeapYearOptions`](IsLeapYearOptions.md) +- [`IsWeekendOptions`](IsWeekendOptions.md) +- [`IsWeekdayOptions`](IsWeekdayOptions.md) - [`IsBeforeOptions`](IsBeforeOptions.md) - [`IsAfterOptions`](IsAfterOptions.md) - [`IsSameOrBeforeOptions`](IsSameOrBeforeOptions.md) diff --git a/docs/reference/interfaces/IsLeapYearOptions.md b/docs/reference/interfaces/IsLeapYearOptions.md new file mode 100644 index 00000000..bd1bf8c1 --- /dev/null +++ b/docs/reference/interfaces/IsLeapYearOptions.md @@ -0,0 +1,40 @@ +--- +id: IsLeapYearOptions +title: IsLeapYearOptions +--- + +# Interface: IsLeapYearOptions + +Defined in: [isLeapYear/isLeapYear.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/isLeapYear/isLeapYear.ts#L5) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsWeekdayOptions.md b/docs/reference/interfaces/IsWeekdayOptions.md new file mode 100644 index 00000000..6c1b710b --- /dev/null +++ b/docs/reference/interfaces/IsWeekdayOptions.md @@ -0,0 +1,50 @@ +--- +id: IsWeekdayOptions +title: IsWeekdayOptions +--- + +# Interface: IsWeekdayOptions + +Defined in: [isWeekday/isWeekday.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekday/isWeekday.ts#L5) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### locale? + +```ts +optional locale: string | Locale; +``` + +Defined in: [isWeekday/isWeekday.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekday/isWeekday.ts#L6) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsWeekendOptions.md b/docs/reference/interfaces/IsWeekendOptions.md new file mode 100644 index 00000000..da724639 --- /dev/null +++ b/docs/reference/interfaces/IsWeekendOptions.md @@ -0,0 +1,50 @@ +--- +id: IsWeekendOptions +title: IsWeekendOptions +--- + +# Interface: IsWeekendOptions + +Defined in: [isWeekend/isWeekend.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L6) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### locale? + +```ts +optional locale: string; +``` + +Defined in: [isWeekend/isWeekend.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L7) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/RoundOptions.md b/docs/reference/interfaces/RoundOptions.md index 8b705b6a..bd6267a5 100644 --- a/docs/reference/interfaces/RoundOptions.md +++ b/docs/reference/interfaces/RoundOptions.md @@ -45,6 +45,26 @@ DateOperationOptions.returnFormat *** +### roundingIncrement? + +```ts +optional roundingIncrement: number; +``` + +Defined in: [round/round.ts:20](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L20) + +*** + +### roundingMode? + +```ts +optional roundingMode: RoundingMode; +``` + +Defined in: [round/round.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L19) + +*** + ### timeZone? ```ts diff --git a/docs/reference/type-aliases/RoundUnit.md b/docs/reference/type-aliases/RoundUnit.md index 2d49aafd..a5dd3dc6 100644 --- a/docs/reference/type-aliases/RoundUnit.md +++ b/docs/reference/type-aliases/RoundUnit.md @@ -7,14 +7,13 @@ title: RoundUnit ```ts type RoundUnit = - | "year" - | "month" - | "week" | "day" | "hour" | "minute" | "second" - | "millisecond"; + | "millisecond" + | "microsecond" + | "nanosecond"; ``` -Defined in: [round/round.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L7) +Defined in: [round/round.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L6) From ad806504f8e31b17fb75d9e9ad2a2e810437de26 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Wed, 21 Jan 2026 19:14:56 +0100 Subject: [PATCH 030/207] feat: range util --- packages/time/src/date/index.ts | 2 +- packages/time/src/date/isWeekday/index.ts | 1 - packages/time/src/date/isWeekday/isWeekday.ts | 32 -- .../date/isWeekday/tests/isWeekday.test.ts | 239 ------------ packages/time/src/date/range/index.ts | 1 + packages/time/src/date/range/range.ts | 50 +++ .../time/src/date/range/tests/range.test.ts | 350 ++++++++++++++++++ packages/time/src/date/types.ts | 13 +- .../withDateOperation/withDateOperation.ts | 41 +- 9 files changed, 429 insertions(+), 300 deletions(-) delete mode 100644 packages/time/src/date/isWeekday/index.ts delete mode 100644 packages/time/src/date/isWeekday/isWeekday.ts delete mode 100644 packages/time/src/date/isWeekday/tests/isWeekday.test.ts create mode 100644 packages/time/src/date/range/index.ts create mode 100644 packages/time/src/date/range/range.ts create mode 100644 packages/time/src/date/range/tests/range.test.ts diff --git a/packages/time/src/date/index.ts b/packages/time/src/date/index.ts index 19c5b504..039ea922 100644 --- a/packages/time/src/date/index.ts +++ b/packages/time/src/date/index.ts @@ -16,4 +16,4 @@ export * from './intersects' export * from './format' export * from './isLeapYear' export * from './isWeekend' -export * from './isWeekday' +export * from './range' diff --git a/packages/time/src/date/isWeekday/index.ts b/packages/time/src/date/isWeekday/index.ts deleted file mode 100644 index 33af9578..00000000 --- a/packages/time/src/date/isWeekday/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './isWeekday' diff --git a/packages/time/src/date/isWeekday/isWeekday.ts b/packages/time/src/date/isWeekday/isWeekday.ts deleted file mode 100644 index b743cedc..00000000 --- a/packages/time/src/date/isWeekday/isWeekday.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { getDateDefaults } from '../dateDefaults' -import { toZonedDateTime } from '../helpers' -import type { DateInput, DateOptions } from '../types' - -export interface IsWeekdayOptions extends DateOptions { - locale?: string | Intl.Locale -} - -/** - * isWeekday - * Returns true if the date falls on a weekday based on locale-specific week info - */ -export function isWeekday( - date: DateInput, - options?: IsWeekdayOptions, -): boolean { - const defaults = getDateDefaults() - const { - timeZone = defaults.timeZone, - calendar = defaults.calendar, - locale = defaults.locale, - } = options ?? {} - - const zdt = toZonedDateTime(date, timeZone, calendar) - const dayOfWeek = zdt.dayOfWeek - - const localeObj = - typeof locale === 'string' ? new Intl.Locale(locale) : locale - - const weekInfo = localeObj.getWeekInfo() - return !weekInfo.weekend.includes(dayOfWeek) -} diff --git a/packages/time/src/date/isWeekday/tests/isWeekday.test.ts b/packages/time/src/date/isWeekday/tests/isWeekday.test.ts deleted file mode 100644 index ce3507e1..00000000 --- a/packages/time/src/date/isWeekday/tests/isWeekday.test.ts +++ /dev/null @@ -1,239 +0,0 @@ -import { describe, expect, test } from 'vitest' -import { Temporal } from '@js-temporal/polyfill' -import { isWeekday } from '../isWeekday' - -describe('isWeekday', () => { - describe('weekday days', () => { - test('should return true for Monday', () => { - const result = isWeekday('2024-03-18T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should return true for Tuesday', () => { - const result = isWeekday('2024-03-19T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should return true for Wednesday', () => { - const result = isWeekday('2024-03-20T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should return true for Thursday', () => { - const result = isWeekday('2024-03-21T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should return true for Friday', () => { - const result = isWeekday('2024-03-22T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should return true for Monday at midnight', () => { - const result = isWeekday('2024-03-18T00:00:00Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should return true for Friday at end of day', () => { - const result = isWeekday('2024-03-22T23:59:59Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - }) - - describe('weekend days', () => { - test('should return false for Saturday', () => { - const result = isWeekday('2024-03-16T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(false) - }) - - test('should return false for Sunday', () => { - const result = isWeekday('2024-03-17T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(false) - }) - }) - - describe('with different input types', () => { - test('should work with Date object', () => { - const date = new Date('2024-03-18T14:42:12.789Z') - const result = isWeekday(date, { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should work with epoch time', () => { - const epoch = new Date('2024-03-18T14:42:12.789Z').getTime() - const result = isWeekday(epoch, { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should work with ZonedDateTime', () => { - const zdt = Temporal.ZonedDateTime.from( - '2024-03-18T14:42:12.789Z[UTC][u-ca=gregory]', - ) - const result = isWeekday(zdt, { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should work with date string', () => { - const result = isWeekday('2024-03-18T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - }) - - describe('timezone handling', () => { - test('should respect timeZone option', () => { - const result = isWeekday('2024-03-18T14:42:12.789Z', { - timeZone: 'America/New_York', - }) - expect(result).toBe(true) - }) - - test('should use default timeZone when not provided', () => { - const result = isWeekday('2024-03-18T14:42:12.789Z') - expect(result).toBe(true) - }) - - test('should handle timezone differences correctly', () => { - const mondayUTC = '2024-03-18T23:00:00Z' - const result1 = isWeekday(mondayUTC, { - timeZone: 'UTC', - }) - const result2 = isWeekday(mondayUTC, { - timeZone: 'America/New_York', - }) - expect(result1).toBe(true) - expect(result2).toBe(true) - }) - }) - - describe('calendar handling', () => { - test('should respect calendar option', () => { - const result = isWeekday('2024-03-18T14:42:12.789Z', { - calendar: 'japanese', - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should use default calendar when not provided', () => { - const result = isWeekday('2024-03-18T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - }) - - describe('edge cases', () => { - test('should handle year boundaries correctly', () => { - const result = isWeekday('2024-01-01T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should handle leap year dates correctly', () => { - const result = isWeekday('2024-02-29T14:42:12.789Z', { - timeZone: 'UTC', - }) - expect(result).toBe(true) - }) - - test('should handle all days of the week correctly', () => { - const monday = isWeekday('2024-03-18T00:00:00Z', { timeZone: 'UTC' }) - const tuesday = isWeekday('2024-03-19T00:00:00Z', { timeZone: 'UTC' }) - const wednesday = isWeekday('2024-03-20T00:00:00Z', { timeZone: 'UTC' }) - const thursday = isWeekday('2024-03-21T00:00:00Z', { timeZone: 'UTC' }) - const friday = isWeekday('2024-03-22T00:00:00Z', { timeZone: 'UTC' }) - const saturday = isWeekday('2024-03-23T00:00:00Z', { timeZone: 'UTC' }) - const sunday = isWeekday('2024-03-24T00:00:00Z', { timeZone: 'UTC' }) - - expect(monday).toBe(true) - expect(tuesday).toBe(true) - expect(wednesday).toBe(true) - expect(thursday).toBe(true) - expect(friday).toBe(true) - expect(saturday).toBe(false) - expect(sunday).toBe(false) - }) - }) - - describe('locale-specific weekday handling', () => { - test('should respect Arabic locale (Friday-Saturday weekend)', () => { - const thursday = isWeekday('2024-03-14T14:42:12.789Z', { - locale: 'ar-SA', - timeZone: 'UTC', - }) - const friday = isWeekday('2024-03-15T14:42:12.789Z', { - locale: 'ar-SA', - timeZone: 'UTC', - }) - const saturday = isWeekday('2024-03-16T14:42:12.789Z', { - locale: 'ar-SA', - timeZone: 'UTC', - }) - const sunday = isWeekday('2024-03-17T14:42:12.789Z', { - locale: 'ar-SA', - timeZone: 'UTC', - }) - - expect(thursday).toBe(true) - expect(friday).toBe(false) - expect(saturday).toBe(false) - expect(sunday).toBe(true) - }) - - test('should respect default locale (Saturday-Sunday weekend)', () => { - const friday = isWeekday('2024-03-15T14:42:12.789Z', { - timeZone: 'UTC', - }) - const saturday = isWeekday('2024-03-16T14:42:12.789Z', { - timeZone: 'UTC', - }) - const sunday = isWeekday('2024-03-17T14:42:12.789Z', { - timeZone: 'UTC', - }) - const monday = isWeekday('2024-03-18T14:42:12.789Z', { - timeZone: 'UTC', - }) - - expect(friday).toBe(true) - expect(saturday).toBe(false) - expect(sunday).toBe(false) - expect(monday).toBe(true) - }) - - test('should work with Intl.Locale object', () => { - const locale = new Intl.Locale('ar-SA') - const thursday = isWeekday('2024-03-14T14:42:12.789Z', { - locale, - timeZone: 'UTC', - }) - expect(thursday).toBe(true) - }) - }) -}) diff --git a/packages/time/src/date/range/index.ts b/packages/time/src/date/range/index.ts new file mode 100644 index 00000000..29e028ca --- /dev/null +++ b/packages/time/src/date/range/index.ts @@ -0,0 +1 @@ +export * from './range' diff --git a/packages/time/src/date/range/range.ts b/packages/time/src/date/range/range.ts new file mode 100644 index 00000000..d7982606 --- /dev/null +++ b/packages/time/src/date/range/range.ts @@ -0,0 +1,50 @@ +import { Temporal } from '@js-temporal/polyfill' +import { toZonedDateTime } from '../helpers' +import { createDateOperationResult, resolveOptions } from '../withDateOperation' +import type { DateOperationOptions } from '../withDateOperation' +import type { DateInput, DurationLike } from '../types' + +export interface RangeOptions extends DateOperationOptions { + start: DateInput + end: DateInput + step: DurationLike +} + +/** + * range + * Generates an array of dates from start to end at the specified step interval. + * The range is inclusive of both start and end (if end falls exactly on a step). + */ +export function range(options: RangeOptions) { + const { start, end, step } = options + const resolved = resolveOptions(options) + const duration = Temporal.Duration.from(step) + + if (duration.blank) { + throw new Error('Step duration cannot be zero') + } + + const startZdt = toZonedDateTime(start, resolved.timeZone, resolved.calendar) + const endZdt = toZonedDateTime(end, resolved.timeZone, resolved.calendar) + + const isForward = Temporal.ZonedDateTime.compare(startZdt, endZdt) <= 0 + const isPositiveStep = duration.sign === 1 + + if (isForward !== isPositiveStep) { + throw new Error( + isForward + ? 'Step must be positive when start is before or equal to end' + : 'Step must be negative when start is after end', + ) + } + + const result: Array> = [] + let current = startZdt + + while (duration.sign * Temporal.ZonedDateTime.compare(current, endZdt) <= 0) { + result.push(createDateOperationResult(current, resolved)) + current = current.add(duration) + } + + return result +} diff --git a/packages/time/src/date/range/tests/range.test.ts b/packages/time/src/date/range/tests/range.test.ts new file mode 100644 index 00000000..4416ba7a --- /dev/null +++ b/packages/time/src/date/range/tests/range.test.ts @@ -0,0 +1,350 @@ +import { describe, expect, test } from 'vitest' +import { Temporal } from '@js-temporal/polyfill' +import { range } from '../range' + +describe('range', () => { + describe('with day intervals', () => { + test('should generate daily range', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-05T00:00:00Z', + step: { days: 1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(5) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + expect(result[1]!.value).toBe('2024-03-02T00:00:00Z') + expect(result[2]!.value).toBe('2024-03-03T00:00:00Z') + expect(result[3]!.value).toBe('2024-03-04T00:00:00Z') + expect(result[4]!.value).toBe('2024-03-05T00:00:00Z') + }) + + test('should generate range with 2-day intervals', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-07T00:00:00Z', + step: { days: 2 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(4) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + expect(result[1]!.value).toBe('2024-03-03T00:00:00Z') + expect(result[2]!.value).toBe('2024-03-05T00:00:00Z') + expect(result[3]!.value).toBe('2024-03-07T00:00:00Z') + }) + }) + + describe('with hour intervals', () => { + test('should generate hourly range', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-01T03:00:00Z', + step: { hours: 1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(4) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + expect(result[1]!.value).toBe('2024-03-01T01:00:00Z') + expect(result[2]!.value).toBe('2024-03-01T02:00:00Z') + expect(result[3]!.value).toBe('2024-03-01T03:00:00Z') + }) + + test('should generate range with 6-hour intervals', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-02T00:00:00Z', + step: { hours: 6 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(5) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + expect(result[1]!.value).toBe('2024-03-01T06:00:00Z') + expect(result[2]!.value).toBe('2024-03-01T12:00:00Z') + expect(result[3]!.value).toBe('2024-03-01T18:00:00Z') + expect(result[4]!.value).toBe('2024-03-02T00:00:00Z') + }) + }) + + describe('with week intervals', () => { + test('should generate weekly range', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-29T00:00:00Z', + step: { weeks: 1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(5) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + expect(result[1]!.value).toBe('2024-03-08T00:00:00Z') + expect(result[2]!.value).toBe('2024-03-15T00:00:00Z') + expect(result[3]!.value).toBe('2024-03-22T00:00:00Z') + expect(result[4]!.value).toBe('2024-03-29T00:00:00Z') + }) + }) + + describe('with month intervals', () => { + test('should generate monthly range', () => { + const result = range({ + start: '2024-01-15T00:00:00Z', + end: '2024-05-15T00:00:00Z', + step: { months: 1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(5) + expect(result[0]!.value).toBe('2024-01-15T00:00:00Z') + expect(result[1]!.value).toBe('2024-02-15T00:00:00Z') + expect(result[2]!.value).toBe('2024-03-15T00:00:00Z') + expect(result[3]!.value).toBe('2024-04-15T00:00:00Z') + expect(result[4]!.value).toBe('2024-05-15T00:00:00Z') + }) + }) + + describe('with minute intervals', () => { + test('should generate range with 15-minute intervals', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-01T01:00:00Z', + step: { minutes: 15 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(5) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + expect(result[1]!.value).toBe('2024-03-01T00:15:00Z') + expect(result[2]!.value).toBe('2024-03-01T00:30:00Z') + expect(result[3]!.value).toBe('2024-03-01T00:45:00Z') + expect(result[4]!.value).toBe('2024-03-01T01:00:00Z') + }) + }) + + describe('with combined intervals', () => { + test('should generate range with days and hours', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-03T12:00:00Z', + step: { days: 1, hours: 6 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(3) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + expect(result[1]!.value).toBe('2024-03-02T06:00:00Z') + expect(result[2]!.value).toBe('2024-03-03T12:00:00Z') + }) + }) + + describe('backward ranges', () => { + test('should generate backward daily range', () => { + const result = range({ + start: '2024-03-05T00:00:00Z', + end: '2024-03-01T00:00:00Z', + step: { days: -1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(5) + expect(result[0]!.value).toBe('2024-03-05T00:00:00Z') + expect(result[1]!.value).toBe('2024-03-04T00:00:00Z') + expect(result[2]!.value).toBe('2024-03-03T00:00:00Z') + expect(result[3]!.value).toBe('2024-03-02T00:00:00Z') + expect(result[4]!.value).toBe('2024-03-01T00:00:00Z') + }) + + test('should generate backward hourly range', () => { + const result = range({ + start: '2024-03-01T03:00:00Z', + end: '2024-03-01T00:00:00Z', + step: { hours: -1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(4) + expect(result[0]!.value).toBe('2024-03-01T03:00:00Z') + expect(result[1]!.value).toBe('2024-03-01T02:00:00Z') + expect(result[2]!.value).toBe('2024-03-01T01:00:00Z') + expect(result[3]!.value).toBe('2024-03-01T00:00:00Z') + }) + }) + + describe('edge cases', () => { + test('should return single item when start equals end', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-01T00:00:00Z', + step: { days: 1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(1) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + }) + + test('should throw error for zero step', () => { + expect(() => + range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-05T00:00:00Z', + step: { days: 0 }, + timeZone: 'UTC', + }), + ).toThrow('Step duration cannot be zero') + }) + + test('should throw error for negative step with forward range', () => { + expect(() => + range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-05T00:00:00Z', + step: { days: -1 }, + timeZone: 'UTC', + }), + ).toThrow('Step must be positive when start is before or equal to end') + }) + + test('should throw error for positive step with backward range', () => { + expect(() => + range({ + start: '2024-03-05T00:00:00Z', + end: '2024-03-01T00:00:00Z', + step: { days: 1 }, + timeZone: 'UTC', + }), + ).toThrow('Step must be negative when start is after end') + }) + + test('should handle range that does not land exactly on end', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-04T12:00:00Z', + step: { days: 1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(4) + expect(result[3]!.value).toBe('2024-03-04T00:00:00Z') + }) + }) + + describe('with different input types', () => { + test('should work with Date objects', () => { + const result = range({ + start: new Date('2024-03-01T00:00:00Z'), + end: new Date('2024-03-03T00:00:00Z'), + step: { days: 1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(3) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + }) + + test('should work with epoch timestamps', () => { + const startEpoch = new Date('2024-03-01T00:00:00Z').getTime() + const endEpoch = new Date('2024-03-03T00:00:00Z').getTime() + + const result = range({ + start: startEpoch, + end: endEpoch, + step: { days: 1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(3) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + }) + + test('should work with ZonedDateTime', () => { + const startZdt = Temporal.ZonedDateTime.from( + '2024-03-01T00:00:00Z[UTC][u-ca=gregory]', + ) + const endZdt = Temporal.ZonedDateTime.from( + '2024-03-03T00:00:00Z[UTC][u-ca=gregory]', + ) + + const result = range({ + start: startZdt, + end: endZdt, + step: { days: 1 }, + timeZone: 'UTC', + }) + + expect(result).toHaveLength(3) + expect(result[0]!.value).toBe('2024-03-01T00:00:00Z') + }) + }) + + describe('output methods', () => { + test('asDate should return Date objects', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-02T00:00:00Z', + step: { days: 1 }, + timeZone: 'UTC', + }) + + const date = result[0]!.asDate() + expect(date).toBeInstanceOf(Date) + expect(date.toISOString()).toBe('2024-03-01T00:00:00.000Z') + }) + + test('asEpoch should return epoch timestamps', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-02T00:00:00Z', + step: { days: 1 }, + timeZone: 'UTC', + }) + + const epoch = result[0]!.asEpoch() + expect(typeof epoch).toBe('number') + expect(epoch).toBe(new Date('2024-03-01T00:00:00Z').getTime()) + }) + + test('asZonedDateTime should return ZonedDateTime instances', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-02T00:00:00Z', + step: { days: 1 }, + timeZone: 'UTC', + }) + + const zdt = result[0]!.asZonedDateTime() + expect(zdt).toBeInstanceOf(Temporal.ZonedDateTime) + }) + }) + + describe('timezone handling', () => { + test('should respect timezone', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-03T00:00:00Z', + step: { days: 1 }, + timeZone: 'America/New_York', + }) + + expect(result).toHaveLength(3) + }) + }) + + describe('returnFormat', () => { + test('should return long format when specified', () => { + const result = range({ + start: '2024-03-01T00:00:00Z', + end: '2024-03-02T00:00:00Z', + step: { days: 1 }, + timeZone: 'UTC', + calendar: 'gregory', + returnFormat: 'long', + }) + + expect(result[0]!.value).toContain('[UTC]') + expect(result[0]!.value).toContain('[u-ca=gregory]') + }) + }) +}) diff --git a/packages/time/src/date/types.ts b/packages/time/src/date/types.ts index ed63c483..074835d3 100644 --- a/packages/time/src/date/types.ts +++ b/packages/time/src/date/types.ts @@ -7,18 +7,7 @@ export interface DateOptions { timeZone?: string } -export interface DurationLike { - years?: number - months?: number - weeks?: number - days?: number - hours?: number - minutes?: number - seconds?: number - milliseconds?: number - microseconds?: number - nanoseconds?: number -} +export type DurationLike = Temporal.DurationLike export interface Range { start: DateInput diff --git a/packages/time/src/date/withDateOperation/withDateOperation.ts b/packages/time/src/date/withDateOperation/withDateOperation.ts index ca6d9406..06c72d4e 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.ts @@ -9,9 +9,26 @@ export interface DateOperationOptions extends DateOptions { returnFormat?: ReturnFormat } -function createDateOperationResult( - zdt: Temporal.ZonedDateTime, +export interface ResolvedDateOperationOptions { + timeZone: string + calendar: string + returnFormat: ReturnFormat +} + +export function resolveOptions( options: DateOperationOptions, +): ResolvedDateOperationOptions { + const defaults = getDateDefaults() + return { + timeZone: options.timeZone ?? defaults.timeZone, + calendar: options.calendar ?? defaults.calendar, + returnFormat: options.returnFormat ?? 'standard', + } +} + +export function createDateOperationResult( + zdt: Temporal.ZonedDateTime, + options: ResolvedDateOperationOptions, ) { const { returnFormat } = options const getValue = (): string => { @@ -51,20 +68,14 @@ export function withDateOperation( fn: (zdt: Temporal.ZonedDateTime, args: TArgs) => Temporal.ZonedDateTime, ) { return (input: DateInput, options: DateOperationOptions & TArgs) => { - const defaults = getDateDefaults() - const { - timeZone = defaults.timeZone, - calendar = defaults.calendar, - returnFormat = 'standard', - } = options - - const inputZdt = toZonedDateTime(input, timeZone, calendar) + const resolved = resolveOptions(options) + const inputZdt = toZonedDateTime( + input, + resolved.timeZone, + resolved.calendar, + ) const resultZdt = fn(inputZdt, options) - return createDateOperationResult(resultZdt, { - timeZone, - calendar, - returnFormat, - }) + return createDateOperationResult(resultZdt, resolved) } } From 1c12f572f31cc0f06ed71eb26cf1f3e0ee3adb42 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 18:16:51 +0000 Subject: [PATCH 031/207] ci: apply automated fixes --- docs/reference/functions/add.md | 8 +- docs/reference/functions/endOf.md | 8 +- docs/reference/functions/isWeekday.md | 29 ----- docs/reference/functions/range.md | 26 +++++ docs/reference/functions/round.md | 8 +- docs/reference/functions/startOf.md | 8 +- docs/reference/functions/subtract.md | 8 +- docs/reference/index.md | 6 +- docs/reference/interfaces/DateOptions.md | 1 - docs/reference/interfaces/DurationLike.md | 108 ------------------ docs/reference/interfaces/IsWeekdayOptions.md | 50 -------- docs/reference/interfaces/Range.md | 6 +- docs/reference/interfaces/RangeOptions.md | 90 +++++++++++++++ docs/reference/type-aliases/DurationLike.md | 12 ++ 14 files changed, 154 insertions(+), 214 deletions(-) delete mode 100644 docs/reference/functions/isWeekday.md create mode 100644 docs/reference/functions/range.md delete mode 100644 docs/reference/interfaces/DurationLike.md delete mode 100644 docs/reference/interfaces/IsWeekdayOptions.md create mode 100644 docs/reference/interfaces/RangeOptions.md create mode 100644 docs/reference/type-aliases/DurationLike.md diff --git a/docs/reference/functions/add.md b/docs/reference/functions/add.md index d9d3a05e..3f054550 100644 --- a/docs/reference/functions/add.md +++ b/docs/reference/functions/add.md @@ -61,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string | undefined = options.calendar; +calendar: string = options.calendar; ``` ### options ```ts -options: DateOperationOptions; +options: ResolvedDateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat | undefined; +returnFormat: ReturnFormat; ``` ### timeZone ```ts -timeZone: string | undefined = options.timeZone; +timeZone: string = options.timeZone; ``` ### value diff --git a/docs/reference/functions/endOf.md b/docs/reference/functions/endOf.md index a45e48fb..2f73487b 100644 --- a/docs/reference/functions/endOf.md +++ b/docs/reference/functions/endOf.md @@ -61,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string | undefined = options.calendar; +calendar: string = options.calendar; ``` ### options ```ts -options: DateOperationOptions; +options: ResolvedDateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat | undefined; +returnFormat: ReturnFormat; ``` ### timeZone ```ts -timeZone: string | undefined = options.timeZone; +timeZone: string = options.timeZone; ``` ### value diff --git a/docs/reference/functions/isWeekday.md b/docs/reference/functions/isWeekday.md deleted file mode 100644 index 10f85958..00000000 --- a/docs/reference/functions/isWeekday.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -id: isWeekday -title: isWeekday ---- - -# Function: isWeekday() - -```ts -function isWeekday(date, options?): boolean; -``` - -Defined in: [isWeekday/isWeekday.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekday/isWeekday.ts#L13) - -isWeekday -Returns true if the date falls on a weekday based on locale-specific week info - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -### options? - -[`IsWeekdayOptions`](../interfaces/IsWeekdayOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/range.md b/docs/reference/functions/range.md new file mode 100644 index 00000000..357bf089 --- /dev/null +++ b/docs/reference/functions/range.md @@ -0,0 +1,26 @@ +--- +id: range +title: range +--- + +# Function: range() + +```ts +function range(options): object[]; +``` + +Defined in: [range/range.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L18) + +range +Generates an array of dates from start to end at the specified step interval. +The range is inclusive of both start and end (if end falls exactly on a step). + +## Parameters + +### options + +[`RangeOptions`](../interfaces/RangeOptions.md) + +## Returns + +`object`[] diff --git a/docs/reference/functions/round.md b/docs/reference/functions/round.md index 8f464e64..472c445b 100644 --- a/docs/reference/functions/round.md +++ b/docs/reference/functions/round.md @@ -61,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string | undefined = options.calendar; +calendar: string = options.calendar; ``` ### options ```ts -options: DateOperationOptions; +options: ResolvedDateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat | undefined; +returnFormat: ReturnFormat; ``` ### timeZone ```ts -timeZone: string | undefined = options.timeZone; +timeZone: string = options.timeZone; ``` ### value diff --git a/docs/reference/functions/startOf.md b/docs/reference/functions/startOf.md index bc7c1506..06e7b469 100644 --- a/docs/reference/functions/startOf.md +++ b/docs/reference/functions/startOf.md @@ -61,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string | undefined = options.calendar; +calendar: string = options.calendar; ``` ### options ```ts -options: DateOperationOptions; +options: ResolvedDateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat | undefined; +returnFormat: ReturnFormat; ``` ### timeZone ```ts -timeZone: string | undefined = options.timeZone; +timeZone: string = options.timeZone; ``` ### value diff --git a/docs/reference/functions/subtract.md b/docs/reference/functions/subtract.md index f6b19beb..976c0a37 100644 --- a/docs/reference/functions/subtract.md +++ b/docs/reference/functions/subtract.md @@ -61,25 +61,25 @@ asZonedDateTime: () => ZonedDateTime; ### calendar ```ts -calendar: string | undefined = options.calendar; +calendar: string = options.calendar; ``` ### options ```ts -options: DateOperationOptions; +options: ResolvedDateOperationOptions; ``` ### returnFormat ```ts -returnFormat: ReturnFormat | undefined; +returnFormat: ReturnFormat; ``` ### timeZone ```ts -timeZone: string | undefined = options.timeZone; +timeZone: string = options.timeZone; ``` ### value diff --git a/docs/reference/index.md b/docs/reference/index.md index 1036b1e1..fc521c54 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -9,7 +9,6 @@ title: "@tanstack/time" - [AddOptions](interfaces/AddOptions.md) - [DateOptions](interfaces/DateOptions.md) -- [DurationLike](interfaces/DurationLike.md) - [EndOfOptions](interfaces/EndOfOptions.md) - [EqualsOptions](interfaces/EqualsOptions.md) - [FormatDateOptions](interfaces/FormatDateOptions.md) @@ -20,9 +19,9 @@ title: "@tanstack/time" - [IsLeapYearOptions](interfaces/IsLeapYearOptions.md) - [IsSameOrAfterOptions](interfaces/IsSameOrAfterOptions.md) - [IsSameOrBeforeOptions](interfaces/IsSameOrBeforeOptions.md) -- [IsWeekdayOptions](interfaces/IsWeekdayOptions.md) - [IsWeekendOptions](interfaces/IsWeekendOptions.md) - [Range](interfaces/Range.md) +- [RangeOptions](interfaces/RangeOptions.md) - [RoundOptions](interfaces/RoundOptions.md) - [SinceOptions](interfaces/SinceOptions.md) - [StartOfOptions](interfaces/StartOfOptions.md) @@ -32,6 +31,7 @@ title: "@tanstack/time" ## Type Aliases - [DateInput](type-aliases/DateInput.md) +- [DurationLike](type-aliases/DurationLike.md) - [EndOfUnit](type-aliases/EndOfUnit.md) - [EqualsUnit](type-aliases/EqualsUnit.md) - [FormatType](type-aliases/FormatType.md) @@ -53,8 +53,8 @@ title: "@tanstack/time" - [isLeapYear](functions/isLeapYear.md) - [isSameOrAfter](functions/isSameOrAfter.md) - [isSameOrBefore](functions/isSameOrBefore.md) -- [isWeekday](functions/isWeekday.md) - [isWeekend](functions/isWeekend.md) +- [range](functions/range.md) - [round](functions/round.md) - [since](functions/since.md) - [startOf](functions/startOf.md) diff --git a/docs/reference/interfaces/DateOptions.md b/docs/reference/interfaces/DateOptions.md index db4013b2..65af3b1c 100644 --- a/docs/reference/interfaces/DateOptions.md +++ b/docs/reference/interfaces/DateOptions.md @@ -14,7 +14,6 @@ Defined in: [types.ts:5](https://github.com/TanStack/time/blob/main/packages/tim - [`EqualsOptions`](EqualsOptions.md) - [`IsLeapYearOptions`](IsLeapYearOptions.md) - [`IsWeekendOptions`](IsWeekendOptions.md) -- [`IsWeekdayOptions`](IsWeekdayOptions.md) - [`IsBeforeOptions`](IsBeforeOptions.md) - [`IsAfterOptions`](IsAfterOptions.md) - [`IsSameOrBeforeOptions`](IsSameOrBeforeOptions.md) diff --git a/docs/reference/interfaces/DurationLike.md b/docs/reference/interfaces/DurationLike.md deleted file mode 100644 index 024fc98e..00000000 --- a/docs/reference/interfaces/DurationLike.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -id: DurationLike -title: DurationLike ---- - -# Interface: DurationLike - -Defined in: [types.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L10) - -## Properties - -### days? - -```ts -optional days: number; -``` - -Defined in: [types.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L14) - -*** - -### hours? - -```ts -optional hours: number; -``` - -Defined in: [types.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L15) - -*** - -### microseconds? - -```ts -optional microseconds: number; -``` - -Defined in: [types.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L19) - -*** - -### milliseconds? - -```ts -optional milliseconds: number; -``` - -Defined in: [types.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L18) - -*** - -### minutes? - -```ts -optional minutes: number; -``` - -Defined in: [types.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L16) - -*** - -### months? - -```ts -optional months: number; -``` - -Defined in: [types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -*** - -### nanoseconds? - -```ts -optional nanoseconds: number; -``` - -Defined in: [types.ts:20](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L20) - -*** - -### seconds? - -```ts -optional seconds: number; -``` - -Defined in: [types.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L17) - -*** - -### weeks? - -```ts -optional weeks: number; -``` - -Defined in: [types.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L13) - -*** - -### years? - -```ts -optional years: number; -``` - -Defined in: [types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) diff --git a/docs/reference/interfaces/IsWeekdayOptions.md b/docs/reference/interfaces/IsWeekdayOptions.md deleted file mode 100644 index 6c1b710b..00000000 --- a/docs/reference/interfaces/IsWeekdayOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: IsWeekdayOptions -title: IsWeekdayOptions ---- - -# Interface: IsWeekdayOptions - -Defined in: [isWeekday/isWeekday.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekday/isWeekday.ts#L5) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### locale? - -```ts -optional locale: string | Locale; -``` - -Defined in: [isWeekday/isWeekday.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekday/isWeekday.ts#L6) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/Range.md b/docs/reference/interfaces/Range.md index 83ff45d3..16447e97 100644 --- a/docs/reference/interfaces/Range.md +++ b/docs/reference/interfaces/Range.md @@ -5,7 +5,7 @@ title: Range # Interface: Range -Defined in: [types.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L23) +Defined in: [types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) ## Properties @@ -15,7 +15,7 @@ Defined in: [types.ts:23](https://github.com/TanStack/time/blob/main/packages/ti end: DateInput; ``` -Defined in: [types.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L25) +Defined in: [types.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L14) *** @@ -25,4 +25,4 @@ Defined in: [types.ts:25](https://github.com/TanStack/time/blob/main/packages/ti start: DateInput; ``` -Defined in: [types.ts:24](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L24) +Defined in: [types.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L13) diff --git a/docs/reference/interfaces/RangeOptions.md b/docs/reference/interfaces/RangeOptions.md new file mode 100644 index 00000000..20f65b56 --- /dev/null +++ b/docs/reference/interfaces/RangeOptions.md @@ -0,0 +1,90 @@ +--- +id: RangeOptions +title: RangeOptions +--- + +# Interface: RangeOptions + +Defined in: [range/range.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L7) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### end + +```ts +end: DateInput; +``` + +Defined in: [range/range.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L9) + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### start + +```ts +start: DateInput; +``` + +Defined in: [range/range.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L8) + +*** + +### step + +```ts +step: DurationLike; +``` + +Defined in: [range/range.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L10) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` diff --git a/docs/reference/type-aliases/DurationLike.md b/docs/reference/type-aliases/DurationLike.md new file mode 100644 index 00000000..f9fef337 --- /dev/null +++ b/docs/reference/type-aliases/DurationLike.md @@ -0,0 +1,12 @@ +--- +id: DurationLike +title: DurationLike +--- + +# Type Alias: DurationLike + +```ts +type DurationLike = Temporal.DurationLike; +``` + +Defined in: [types.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L10) From 4d5f75e3bf2d0a2ec6eab3a4fab893bea1e770ea Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Wed, 21 Jan 2026 23:57:49 +0100 Subject: [PATCH 032/207] refactor: date utils --- packages/time/src/date/dateDefaults.ts | 57 ----------- packages/time/src/date/equals/equals.ts | 9 +- packages/time/src/date/format/format.ts | 24 +++-- packages/time/src/date/helpers/index.ts | 1 + .../time/src/date/helpers/normalizeLocale.ts | 9 ++ .../time/src/date/intersects/intersects.ts | 9 +- packages/time/src/date/isAfter/isAfter.ts | 7 +- packages/time/src/date/isBefore/isBefore.ts | 7 +- packages/time/src/date/isBetween/isBetween.ts | 9 +- .../time/src/date/isLeapYear/isLeapYear.ts | 7 +- .../src/date/isSameOrAfter/isSameOrAfter.ts | 11 ++- .../src/date/isSameOrBefore/isSameOrBefore.ts | 11 ++- packages/time/src/date/isWeekend/isWeekend.ts | 16 ++-- packages/time/src/date/since/since.ts | 9 +- packages/time/src/date/types.ts | 7 +- packages/time/src/date/until/until.ts | 9 +- .../withDateOperation/withDateOperation.ts | 12 ++- .../buildDateFormatter/buildDateFormatter.ts | 7 +- .../buildDateTimeFormatter.ts | 7 +- .../buildTimeFormatter/buildTimeFormatter.ts | 7 +- .../src/formatter/extractLocaleOptions.ts | 6 +- packages/time/src/utils/dateDefaults.ts | 1 + packages/time/src/utils/dateRange.ts | 96 +++++++++++++++++++ packages/time/src/utils/dateTimeDefaults.ts | 15 +++ packages/time/src/utils/index.ts | 3 + packages/time/src/utils/weekUtils.ts | 30 ++++++ packages/time/tsconfig.json | 8 +- 27 files changed, 263 insertions(+), 131 deletions(-) delete mode 100644 packages/time/src/date/dateDefaults.ts create mode 100644 packages/time/src/date/helpers/normalizeLocale.ts create mode 100644 packages/time/src/utils/dateDefaults.ts create mode 100644 packages/time/src/utils/dateRange.ts create mode 100644 packages/time/src/utils/dateTimeDefaults.ts create mode 100644 packages/time/src/utils/index.ts create mode 100644 packages/time/src/utils/weekUtils.ts diff --git a/packages/time/src/date/dateDefaults.ts b/packages/time/src/date/dateDefaults.ts deleted file mode 100644 index 6f962ea5..00000000 --- a/packages/time/src/date/dateDefaults.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { Locale } from '../formatter/shared' - -export interface DateDefaults { - calendar: string - locale: string - timeZone: string -} - -const { - calendar: defaultCalendar, - locale: defaultLocale, - timeZone: defaultTimeZone, -} = new Intl.DateTimeFormat().resolvedOptions() - -/** - * getDateDefaults - * @returns DateDefaults - */ -export function getDateDefaults(): DateDefaults { - return { - calendar: defaultCalendar, - locale: defaultLocale, - timeZone: defaultTimeZone, - } -} - -/** - * getDefaultCalendar - * @returns string - default calendar - */ -export function getDefaultCalendar(): string { - return defaultCalendar -} - -/** - * getDefaultLocale - * @returns string - default locale - */ -export function getDefaultLocale(): Locale { - return defaultLocale -} - -/** - * getDefaultTimeZone - * @returns string - default time zone - */ -export function getDefaultTimeZone(): string { - return defaultTimeZone -} - -export function normalizeLocale(locale: Locale): string | Array { - return Array.isArray(locale) - ? locale.map((loc) => (typeof loc === 'string' ? loc : loc.toString())) - : typeof locale === 'string' - ? locale - : locale.toString() -} diff --git a/packages/time/src/date/equals/equals.ts b/packages/time/src/date/equals/equals.ts index d1da0e78..880a6b9c 100644 --- a/packages/time/src/date/equals/equals.ts +++ b/packages/time/src/date/equals/equals.ts @@ -1,7 +1,7 @@ -import { getDateDefaults } from '../dateDefaults' import { normalizeWeek } from '../helpers' -import { startOf } from '../startOf/startOf' +import { startOf } from '../startOf' import type { DateInput, DateOptions } from '../types' +import { getDateTimeDefaults } from '~/utils' export type EqualsUnit = | 'year' @@ -25,8 +25,9 @@ export function equals( unit: EqualsUnit, options?: EqualsOptions, ): boolean { - const defaults = getDateDefaults() - const { timeZone = defaults.timeZone, calendar = defaults.calendar } = + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() + const { timeZone = defaultTimeZone, calendar = defaultCalendar } = options ?? {} const startOf1 = startOf(date1, { unit, timeZone, calendar }) diff --git a/packages/time/src/date/format/format.ts b/packages/time/src/date/format/format.ts index f7c6f7a1..4c15aa59 100644 --- a/packages/time/src/date/format/format.ts +++ b/packages/time/src/date/format/format.ts @@ -1,15 +1,15 @@ -import { getDateDefaults } from '../dateDefaults' import { toZonedDateTime } from '../helpers' -import { buildFinalFormatter } from '../../formatter/buildFinalFormatter' -import { buildDateFormatter } from '../../formatter/buildDateFormatter' -import { buildTimeFormatter } from '../../formatter/buildTimeFormatter' -import { buildDateTimeFormatter } from '../../formatter/buildDateTimeFormatter' import type { DateInput, DateOptions } from '../types' import type { DateFormatterBuildParams, DateTimeFormatterBuildParams, TimeFormatterBuildParams, -} from '../../formatter/shared' +} from '~/formatter/shared' +import { getDateTimeDefaults } from '~/utils' +import { buildFinalFormatter } from '~/formatter/buildFinalFormatter' +import { buildDateFormatter } from '~/formatter/buildDateFormatter' +import { buildTimeFormatter } from '~/formatter/buildTimeFormatter' +import { buildDateTimeFormatter } from '~/formatter/buildDateTimeFormatter' export type FormatType = 'date' | 'time' | 'datetime' @@ -33,12 +33,16 @@ export function format( date: DateInput, formatOptions?: FormatDateOptions, ): string { - const defaults = getDateDefaults() + const { + locale: defaultLocale, + timeZone: defaultTimeZone, + calendar: defaultCalendar, + } = getDateTimeDefaults() const { type = 'datetime', - locale = defaults.locale, - timeZone = defaults.timeZone, - calendar = defaults.calendar, + locale = defaultLocale, + timeZone = defaultTimeZone, + calendar = defaultCalendar, options, } = formatOptions ?? {} diff --git a/packages/time/src/date/helpers/index.ts b/packages/time/src/date/helpers/index.ts index ba4da1e5..9c9cec67 100644 --- a/packages/time/src/date/helpers/index.ts +++ b/packages/time/src/date/helpers/index.ts @@ -1,2 +1,3 @@ export * from './toZonedDateTime' export * from './normalizeWeek' +export * from './normalizeLocale' diff --git a/packages/time/src/date/helpers/normalizeLocale.ts b/packages/time/src/date/helpers/normalizeLocale.ts new file mode 100644 index 00000000..859be9e8 --- /dev/null +++ b/packages/time/src/date/helpers/normalizeLocale.ts @@ -0,0 +1,9 @@ +import type { Locale } from '~/formatter/shared' + +export function normalizeLocale(locale: Locale): string | Array { + return Array.isArray(locale) + ? locale.map((loc) => (typeof loc === 'string' ? loc : loc.toString())) + : typeof locale === 'string' + ? locale + : locale.toString() +} diff --git a/packages/time/src/date/intersects/intersects.ts b/packages/time/src/date/intersects/intersects.ts index a93c14f9..40d36b66 100644 --- a/packages/time/src/date/intersects/intersects.ts +++ b/packages/time/src/date/intersects/intersects.ts @@ -1,7 +1,7 @@ import { Temporal } from '@js-temporal/polyfill' -import { getDateDefaults } from '../dateDefaults' import { toZonedDateTime } from '../helpers' import type { DateInput, DateOptions, Range } from '../types' +import { getDateTimeDefaults } from '~/utils' export interface IntersectsOptions extends DateOptions { range: Range @@ -17,11 +17,12 @@ export function intersects( date: DateInput, options: IntersectsOptions, ): boolean { - const defaults = getDateDefaults() + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() const { range: { start, end }, - timeZone = defaults.timeZone, - calendar = defaults.calendar, + timeZone = defaultTimeZone, + calendar = defaultCalendar, } = options const zdt = toZonedDateTime(date, timeZone, calendar) diff --git a/packages/time/src/date/isAfter/isAfter.ts b/packages/time/src/date/isAfter/isAfter.ts index 03d6463b..2e9ddef7 100644 --- a/packages/time/src/date/isAfter/isAfter.ts +++ b/packages/time/src/date/isAfter/isAfter.ts @@ -1,7 +1,7 @@ import { Temporal } from '@js-temporal/polyfill' -import { getDateDefaults } from '../dateDefaults' import { toZonedDateTime } from '../helpers' import type { DateInput, DateOptions } from '../types' +import { getDateTimeDefaults } from '~/utils' export interface IsAfterOptions extends DateOptions {} @@ -14,8 +14,9 @@ export function isAfter( date2: DateInput, options?: IsAfterOptions, ): boolean { - const defaults = getDateDefaults() - const { timeZone = defaults.timeZone, calendar = defaults.calendar } = + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() + const { timeZone = defaultTimeZone, calendar = defaultCalendar } = options ?? {} const zdt1 = toZonedDateTime(date1, timeZone, calendar) diff --git a/packages/time/src/date/isBefore/isBefore.ts b/packages/time/src/date/isBefore/isBefore.ts index 6dc1e1fc..1d604f5c 100644 --- a/packages/time/src/date/isBefore/isBefore.ts +++ b/packages/time/src/date/isBefore/isBefore.ts @@ -1,7 +1,7 @@ import { Temporal } from '@js-temporal/polyfill' -import { getDateDefaults } from '../dateDefaults' import { toZonedDateTime } from '../helpers' import type { DateInput, DateOptions } from '../types' +import { getDateTimeDefaults } from '~/utils' export interface IsBeforeOptions extends DateOptions {} @@ -14,8 +14,9 @@ export function isBefore( date2: DateInput, options?: IsBeforeOptions, ): boolean { - const defaults = getDateDefaults() - const { timeZone = defaults.timeZone, calendar = defaults.calendar } = + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() + const { timeZone = defaultTimeZone, calendar = defaultCalendar } = options ?? {} const zdt1 = toZonedDateTime(date1, timeZone, calendar) diff --git a/packages/time/src/date/isBetween/isBetween.ts b/packages/time/src/date/isBetween/isBetween.ts index 43ec1908..7641761d 100644 --- a/packages/time/src/date/isBetween/isBetween.ts +++ b/packages/time/src/date/isBetween/isBetween.ts @@ -1,7 +1,7 @@ import { Temporal } from '@js-temporal/polyfill' -import { getDateDefaults } from '../dateDefaults' import { toZonedDateTime } from '../helpers' import type { DateInput, DateOptions, Range } from '../types' +import { getDateTimeDefaults } from '~/utils' export interface IsBetweenOptions extends DateOptions { inclusive?: boolean | 'start' | 'end' @@ -16,11 +16,12 @@ export interface IsBetweenOptions extends DateOptions { * @param options - Options including timeZone, calendar, and inclusivity */ export function isBetween(date: DateInput, options: IsBetweenOptions): boolean { - const defaults = getDateDefaults() + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() const { range: { start, end }, - timeZone = defaults.timeZone, - calendar = defaults.calendar, + timeZone = defaultTimeZone, + calendar = defaultCalendar, inclusive = true, } = options const zdt = toZonedDateTime(date, timeZone, calendar) diff --git a/packages/time/src/date/isLeapYear/isLeapYear.ts b/packages/time/src/date/isLeapYear/isLeapYear.ts index f81a91e2..febd81c0 100644 --- a/packages/time/src/date/isLeapYear/isLeapYear.ts +++ b/packages/time/src/date/isLeapYear/isLeapYear.ts @@ -1,6 +1,6 @@ -import { getDateDefaults } from '../dateDefaults' import { toZonedDateTime } from '../helpers' import type { DateInput, DateOptions } from '../types' +import { getDateTimeDefaults } from '~/utils' export interface IsLeapYearOptions extends DateOptions {} @@ -12,8 +12,9 @@ export function isLeapYear( date: DateInput, options?: IsLeapYearOptions, ): boolean { - const defaults = getDateDefaults() - const { timeZone = defaults.timeZone, calendar = defaults.calendar } = + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() + const { timeZone = defaultTimeZone, calendar = defaultCalendar } = options ?? {} return toZonedDateTime(date, timeZone, calendar).inLeapYear diff --git a/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts b/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts index 8ee3eda5..17407a32 100644 --- a/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts +++ b/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts @@ -1,8 +1,8 @@ import { Temporal } from '@js-temporal/polyfill' -import { getDateDefaults } from '../dateDefaults' -import { normalizeWeek } from '../helpers' -import { startOf } from '../startOf/startOf' import type { DateInput, DateOptions } from '../types' +import { getDateTimeDefaults } from '~/utils' +import { normalizeWeek } from '~/date/helpers' +import { startOf } from '~/date/startOf/startOf' export type IsSameOrAfterUnit = | 'year' @@ -27,8 +27,9 @@ export function isSameOrAfter( date2: DateInput, options: IsSameOrAfterOptions, ): boolean { - const defaults = getDateDefaults() - const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() + const { timeZone = defaultTimeZone, calendar = defaultCalendar } = options const startOf1 = startOf(date1, { unit: options.unit, timeZone, calendar }) const startOf2 = startOf(date2, { unit: options.unit, timeZone, calendar }) diff --git a/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts b/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts index 01003331..fac1ef3c 100644 --- a/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts +++ b/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts @@ -1,8 +1,8 @@ import { Temporal } from '@js-temporal/polyfill' -import { getDateDefaults } from '../dateDefaults' -import { normalizeWeek } from '../helpers' -import { startOf } from '../startOf/startOf' import type { DateInput, DateOptions } from '../types' +import { getDateTimeDefaults } from '~/utils' +import { normalizeWeek } from '~/date/helpers' +import { startOf } from '~/date/startOf/startOf' export type IsSameOrBeforeUnit = | 'year' @@ -27,8 +27,9 @@ export function isSameOrBefore( date2: DateInput, options: IsSameOrBeforeOptions, ): boolean { - const defaults = getDateDefaults() - const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() + const { timeZone = defaultTimeZone, calendar = defaultCalendar } = options const startOf1 = startOf(date1, { unit: options.unit, timeZone, calendar }) const startOf2 = startOf(date2, { unit: options.unit, timeZone, calendar }) diff --git a/packages/time/src/date/isWeekend/isWeekend.ts b/packages/time/src/date/isWeekend/isWeekend.ts index 12d0abb1..0807b9bd 100644 --- a/packages/time/src/date/isWeekend/isWeekend.ts +++ b/packages/time/src/date/isWeekend/isWeekend.ts @@ -1,7 +1,7 @@ import '../../polyfills/getWeekInfo' -import { getDateDefaults } from '../dateDefaults' -import { toZonedDateTime } from '../helpers' import type { DateInput, DateOptions } from '../types' +import { toZonedDateTime } from '~/date/helpers' +import { getDateTimeDefaults } from '~/utils' export interface IsWeekendOptions extends DateOptions { locale?: string @@ -15,11 +15,15 @@ export function isWeekend( date: DateInput, options?: IsWeekendOptions, ): boolean { - const defaults = getDateDefaults() const { - timeZone = defaults.timeZone, - calendar = defaults.calendar, - locale = defaults.locale, + timeZone: defaultTimeZone, + calendar: defaultCalendar, + locale: defaultLocale, + } = getDateTimeDefaults() + const { + timeZone = defaultTimeZone, + calendar = defaultCalendar, + locale = defaultLocale, } = options ?? {} const zdt = toZonedDateTime(date, timeZone, calendar) diff --git a/packages/time/src/date/since/since.ts b/packages/time/src/date/since/since.ts index a437833e..4c02acc0 100644 --- a/packages/time/src/date/since/since.ts +++ b/packages/time/src/date/since/since.ts @@ -1,7 +1,7 @@ -import { getDateDefaults } from '../dateDefaults' -import { toZonedDateTime } from '../helpers' import type { Temporal } from '@js-temporal/polyfill' import type { DateInput, DateOptions } from '../types' +import { toZonedDateTime } from '~/date/helpers' +import { getDateTimeDefaults } from '~/utils' export interface SinceOptions extends DateOptions { unit: Temporal.DateTimeUnit @@ -13,8 +13,9 @@ export interface SinceOptions extends DateOptions { * (equivalent to: how long has it been since the second date, from the first date's perspective) */ export function since(start: DateInput, end: DateInput, options: SinceOptions) { - const defaults = getDateDefaults() - const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() + const { timeZone = defaultTimeZone, calendar = defaultCalendar } = options const startZdt = toZonedDateTime(start, timeZone, calendar) const endZdt = toZonedDateTime(end, timeZone, calendar) diff --git a/packages/time/src/date/types.ts b/packages/time/src/date/types.ts index 074835d3..e05be641 100644 --- a/packages/time/src/date/types.ts +++ b/packages/time/src/date/types.ts @@ -1,6 +1,11 @@ import type { Temporal } from '@js-temporal/polyfill' -export type DateInput = string | number | Date | Temporal.ZonedDateTime +export type DateInput = + | string + | number + | Date + | Temporal.ZonedDateTime + | Temporal.PlainDate export interface DateOptions { calendar?: string diff --git a/packages/time/src/date/until/until.ts b/packages/time/src/date/until/until.ts index fddf3e89..29a563a9 100644 --- a/packages/time/src/date/until/until.ts +++ b/packages/time/src/date/until/until.ts @@ -1,7 +1,7 @@ -import { getDateDefaults } from '../dateDefaults' -import { toZonedDateTime } from '../helpers' import type { Temporal } from '@js-temporal/polyfill' import type { DateInput, DateOptions } from '../types' +import { toZonedDateTime } from '~/date/helpers' +import { getDateTimeDefaults } from '~/utils' export interface UntilOptions extends DateOptions { unit: Temporal.DateTimeUnit @@ -12,8 +12,9 @@ export interface UntilOptions extends DateOptions { * Returns the duration from the first date/time instance until the second date/time instance */ export function until(start: DateInput, end: DateInput, options: UntilOptions) { - const defaults = getDateDefaults() - const { timeZone = defaults.timeZone, calendar = defaults.calendar } = options + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() + const { timeZone = defaultTimeZone, calendar = defaultCalendar } = options const startZdt = toZonedDateTime(start, timeZone, calendar) const endZdt = toZonedDateTime(end, timeZone, calendar) diff --git a/packages/time/src/date/withDateOperation/withDateOperation.ts b/packages/time/src/date/withDateOperation/withDateOperation.ts index 06c72d4e..a9f8de54 100644 --- a/packages/time/src/date/withDateOperation/withDateOperation.ts +++ b/packages/time/src/date/withDateOperation/withDateOperation.ts @@ -1,7 +1,7 @@ -import { getDateDefaults } from '../dateDefaults' -import { toZonedDateTime } from '../helpers' import type { Temporal } from '@js-temporal/polyfill' import type { DateInput, DateOptions } from '../types' +import { getDateTimeDefaults } from '~/utils' +import { toZonedDateTime } from '~/date/helpers' export type ReturnFormat = 'standard' | 'long' @@ -18,10 +18,12 @@ export interface ResolvedDateOperationOptions { export function resolveOptions( options: DateOperationOptions, ): ResolvedDateOperationOptions { - const defaults = getDateDefaults() + const { timeZone: defaultTimeZone, calendar: defaultCalendar } = + getDateTimeDefaults() + const { timeZone = defaultTimeZone, calendar = defaultCalendar } = options return { - timeZone: options.timeZone ?? defaults.timeZone, - calendar: options.calendar ?? defaults.calendar, + timeZone, + calendar, returnFormat: options.returnFormat ?? 'standard', } } diff --git a/packages/time/src/formatter/buildDateFormatter/buildDateFormatter.ts b/packages/time/src/formatter/buildDateFormatter/buildDateFormatter.ts index 576a6ee7..b62ee931 100644 --- a/packages/time/src/formatter/buildDateFormatter/buildDateFormatter.ts +++ b/packages/time/src/formatter/buildDateFormatter/buildDateFormatter.ts @@ -1,6 +1,7 @@ -import { getDefaultLocale, normalizeLocale } from '../../date/dateDefaults' -import { extractLocaleOptions } from '../extractLocaleOptions' import type { DateFormatterBuildParams, DateFormatterOptions } from '../shared' +import { normalizeLocale } from '~/date/helpers' +import { getDateTimeDefaults } from '~/utils' +import { extractLocaleOptions } from '~/formatter/extractLocaleOptions' /** * Function: buildDateFormatter @@ -24,7 +25,7 @@ import type { DateFormatterBuildParams, DateFormatterOptions } from '../shared' * @returns Intl.DateTimeFormat */ export function buildDateFormatter({ - locale = getDefaultLocale(), + locale = getDateTimeDefaults().locale, options, }: DateFormatterBuildParams): Intl.DateTimeFormat { const normalizedLocale = normalizeLocale(locale) diff --git a/packages/time/src/formatter/buildDateTimeFormatter/buildDateTimeFormatter.ts b/packages/time/src/formatter/buildDateTimeFormatter/buildDateTimeFormatter.ts index 11be878d..0352296e 100644 --- a/packages/time/src/formatter/buildDateTimeFormatter/buildDateTimeFormatter.ts +++ b/packages/time/src/formatter/buildDateTimeFormatter/buildDateTimeFormatter.ts @@ -1,9 +1,10 @@ -import { getDefaultLocale, normalizeLocale } from '../../date/dateDefaults' -import { extractLocaleOptions } from '../extractLocaleOptions' import type { DateTimeFormatterBuildParams, DateTimeFormatterOptions, } from '../shared' +import { getDateTimeDefaults } from '~/utils' +import { normalizeLocale } from '~/date/helpers' +import { extractLocaleOptions } from '~/formatter/extractLocaleOptions' /** * @typedef {string | Intl.Locale | string[] | Intl.Locale[]} Locale @@ -35,7 +36,7 @@ import type { * @returns Intl.DateTimeFormat */ export function buildDateTimeFormatter({ - locale = getDefaultLocale(), + locale = getDateTimeDefaults().locale, options, }: DateTimeFormatterBuildParams): Intl.DateTimeFormat { const normalizedLocale = normalizeLocale(locale) diff --git a/packages/time/src/formatter/buildTimeFormatter/buildTimeFormatter.ts b/packages/time/src/formatter/buildTimeFormatter/buildTimeFormatter.ts index 605a28ba..ec0f7a68 100644 --- a/packages/time/src/formatter/buildTimeFormatter/buildTimeFormatter.ts +++ b/packages/time/src/formatter/buildTimeFormatter/buildTimeFormatter.ts @@ -1,6 +1,7 @@ -import { getDefaultLocale, normalizeLocale } from '../../date/dateDefaults' -import { extractLocaleOptions } from '../extractLocaleOptions' import type { TimeFormatterBuildParams, TimeFormatterOptions } from '../shared' +import { getDateTimeDefaults } from '~/utils' +import { normalizeLocale } from '~/date/helpers' +import { extractLocaleOptions } from '~/formatter/extractLocaleOptions' /** * Function: buildTimeFormatter @@ -24,7 +25,7 @@ import type { TimeFormatterBuildParams, TimeFormatterOptions } from '../shared' * @returns Intl.DateTimeFormat */ export function buildTimeFormatter({ - locale = getDefaultLocale(), + locale = getDateTimeDefaults().locale, options, }: TimeFormatterBuildParams): Intl.DateTimeFormat { const normalizedLocale = normalizeLocale(locale) diff --git a/packages/time/src/formatter/extractLocaleOptions.ts b/packages/time/src/formatter/extractLocaleOptions.ts index 1478f454..037a7fff 100644 --- a/packages/time/src/formatter/extractLocaleOptions.ts +++ b/packages/time/src/formatter/extractLocaleOptions.ts @@ -1,9 +1,9 @@ -import { getDefaultCalendar, getDefaultTimeZone } from '../date/dateDefaults' import type { DateFormatterOptions, DateTimeFormatterOptions, TimeFormatterOptions, } from './shared' +import { getDateTimeDefaults } from '~/utils' /** * @typedef {Object} DateFormatterOptions @@ -72,11 +72,11 @@ import type { */ export function extractLocaleOptions({ localeMatcher, - calendar = getDefaultCalendar(), + calendar = getDateTimeDefaults().calendar, + timeZone = getDateTimeDefaults().timeZone, numberingSystem, hour12, hourCycle, - timeZone = getDefaultTimeZone(), ...formatOptions }: DateFormatterOptions | DateTimeFormatterOptions | TimeFormatterOptions) { return { diff --git a/packages/time/src/utils/dateDefaults.ts b/packages/time/src/utils/dateDefaults.ts new file mode 100644 index 00000000..b9c252f8 --- /dev/null +++ b/packages/time/src/utils/dateDefaults.ts @@ -0,0 +1 @@ +export * from '~/utils/dateTimeDefaults' diff --git a/packages/time/src/utils/dateRange.ts b/packages/time/src/utils/dateRange.ts new file mode 100644 index 00000000..7de79feb --- /dev/null +++ b/packages/time/src/utils/dateRange.ts @@ -0,0 +1,96 @@ +import { Temporal } from '@js-temporal/polyfill' +import type { DateRange } from '../date/calendar/types' +import type { DateInput } from '../date/types' + +export interface ParsedDateRange { + start: Temporal.PlainDate | null + end: Temporal.PlainDate | null +} + +function toPlainDate( + input: DateInput, + calendar: Temporal.CalendarLike, +): Temporal.PlainDate { + if (input instanceof Temporal.PlainDate) { + return input.withCalendar(calendar) + } + if (input instanceof Temporal.ZonedDateTime) { + return input.toPlainDate().withCalendar(calendar) + } + if (input instanceof Date) { + return Temporal.PlainDate.from({ + year: input.getFullYear(), + month: input.getMonth() + 1, + day: input.getDate(), + }).withCalendar(calendar) + } + if (typeof input === 'number') { + const date = new Date(input) + return Temporal.PlainDate.from({ + year: date.getFullYear(), + month: date.getMonth() + 1, + day: date.getDate(), + }).withCalendar(calendar) + } + return Temporal.PlainDate.from(input).withCalendar(calendar) +} + +export interface ParseDateRangeOptions { + range?: DateRange + calendar: Temporal.CalendarLike +} + +export function parseDateRange({ + range, + calendar, +}: ParseDateRangeOptions): ParsedDateRange { + if (!range) { + return { start: null, end: null } + } + + return { + start: range.start ? toPlainDate(range.start, calendar) : null, + end: range.end ? toPlainDate(range.end, calendar) : null, + } +} + +export interface IsDateInRangeOptions { + date: Temporal.PlainDate + range: ParsedDateRange +} + +export function isDateInRange({ date, range }: IsDateInRangeOptions): boolean { + const { start, end } = range + + if (start && Temporal.PlainDate.compare(date, start) < 0) { + return false + } + + if (end && Temporal.PlainDate.compare(date, end) > 0) { + return false + } + + return true +} + +export interface ConstrainDateToRangeOptions { + date: Temporal.PlainDate + range: ParsedDateRange +} + +export function constrainDateToRange({ + date, + range, +}: ConstrainDateToRangeOptions): Temporal.PlainDate { + const { start, end } = range + + if (start && Temporal.PlainDate.compare(date, start) < 0) { + return start + } + + if (end && Temporal.PlainDate.compare(date, end) > 0) { + return end + } + + return date +} diff --git a/packages/time/src/utils/dateTimeDefaults.ts b/packages/time/src/utils/dateTimeDefaults.ts new file mode 100644 index 00000000..6f562da9 --- /dev/null +++ b/packages/time/src/utils/dateTimeDefaults.ts @@ -0,0 +1,15 @@ +import type { Locale } from '../formatter/shared' + +const defaults = new Intl.DateTimeFormat().resolvedOptions() + +export function getDateTimeDefaults() { + return defaults +} + +export function normalizeLocale(locale: Locale): string | Array { + return Array.isArray(locale) + ? locale.map((loc) => (typeof loc === 'string' ? loc : loc.toString())) + : typeof locale === 'string' + ? locale + : locale.toString() +} diff --git a/packages/time/src/utils/index.ts b/packages/time/src/utils/index.ts new file mode 100644 index 00000000..83e45017 --- /dev/null +++ b/packages/time/src/utils/index.ts @@ -0,0 +1,3 @@ +export * from './dateRange' +export * from './weekUtils' +export * from './dateTimeDefaults' diff --git a/packages/time/src/utils/weekUtils.ts b/packages/time/src/utils/weekUtils.ts new file mode 100644 index 00000000..3eff39fd --- /dev/null +++ b/packages/time/src/utils/weekUtils.ts @@ -0,0 +1,30 @@ +import { Temporal } from '@js-temporal/polyfill' +import '@bart-krakowski/get-week-info-polyfill' + +/** + * Get the first day of the month for a given year-month string + */ +export function getFirstDayOfMonth(yearMonth: string): Temporal.PlainDate { + const [year, month] = yearMonth.split('-').map(Number) + if (!year || !month) { + throw new Error(`Invalid yearMonth format: ${yearMonth}. Expected YYYY-MM`) + } + return Temporal.PlainDate.from({ year, month, day: 1 }) +} + +/** + * Get the first day of the week for a given date string and locale + */ +export function getFirstDayOfWeek( + dateString: string, + locale: string, +): Temporal.PlainDate { + const date = Temporal.PlainDate.from(dateString) + const weekInfo = new Intl.Locale(locale).getWeekInfo() + const firstDayOfWeek = weekInfo.firstDay + + const dayOfWeek = date.dayOfWeek + const daysToSubtract = (dayOfWeek - firstDayOfWeek + 7) % 7 + + return date.subtract({ days: daysToSubtract }) +} diff --git a/packages/time/tsconfig.json b/packages/time/tsconfig.json index e01806d9..bfb655a4 100644 --- a/packages/time/tsconfig.json +++ b/packages/time/tsconfig.json @@ -1,5 +1,11 @@ { "extends": "../../tsconfig.json", "include": ["src", "vite.config.ts", "tests"], - "exclude": ["eslint.config.js"] + "exclude": ["eslint.config.js"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "~/*": ["./src/*"] + } + } } From 5d6de77bac02a91366b4c06e83a04a313b9f852e Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 21 Jan 2026 22:58:37 +0000 Subject: [PATCH 033/207] ci: apply automated fixes --- docs/reference/functions/add.md | 89 ------------------ docs/reference/functions/endOf.md | 89 ------------------ docs/reference/functions/equals.md | 41 --------- docs/reference/functions/format.md | 33 ------- docs/reference/functions/intersects.md | 33 ------- docs/reference/functions/isAfter.md | 36 -------- docs/reference/functions/isBefore.md | 36 -------- docs/reference/functions/isBetween.md | 33 ------- docs/reference/functions/isLeapYear.md | 29 ------ docs/reference/functions/isSameOrAfter.md | 36 -------- docs/reference/functions/isSameOrBefore.md | 36 -------- docs/reference/functions/isWeekend.md | 29 ------ docs/reference/functions/range.md | 26 ------ docs/reference/functions/round.md | 89 ------------------ docs/reference/functions/since.md | 37 -------- docs/reference/functions/startOf.md | 89 ------------------ docs/reference/functions/subtract.md | 89 ------------------ docs/reference/functions/until.md | 36 -------- docs/reference/index.md | 62 ------------- docs/reference/interfaces/AddOptions.md | 70 --------------- docs/reference/interfaces/DateOptions.md | 43 --------- docs/reference/interfaces/EndOfOptions.md | 70 --------------- docs/reference/interfaces/EqualsOptions.md | 40 --------- .../reference/interfaces/FormatDateOptions.md | 74 --------------- .../reference/interfaces/IntersectsOptions.md | 50 ----------- docs/reference/interfaces/IsAfterOptions.md | 40 --------- docs/reference/interfaces/IsBeforeOptions.md | 40 --------- docs/reference/interfaces/IsBetweenOptions.md | 60 ------------- .../reference/interfaces/IsLeapYearOptions.md | 40 --------- .../interfaces/IsSameOrAfterOptions.md | 50 ----------- .../interfaces/IsSameOrBeforeOptions.md | 50 ----------- docs/reference/interfaces/IsWeekendOptions.md | 50 ----------- docs/reference/interfaces/Range.md | 28 ------ docs/reference/interfaces/RangeOptions.md | 90 ------------------- docs/reference/interfaces/RoundOptions.md | 90 ------------------- docs/reference/interfaces/SinceOptions.md | 50 ----------- docs/reference/interfaces/StartOfOptions.md | 70 --------------- docs/reference/interfaces/SubtractOptions.md | 70 --------------- docs/reference/interfaces/UntilOptions.md | 50 ----------- docs/reference/type-aliases/DateInput.md | 12 --- docs/reference/type-aliases/DurationLike.md | 12 --- docs/reference/type-aliases/EndOfUnit.md | 20 ----- docs/reference/type-aliases/EqualsUnit.md | 20 ----- docs/reference/type-aliases/FormatType.md | 12 --- .../type-aliases/IsSameOrAfterUnit.md | 20 ----- .../type-aliases/IsSameOrBeforeUnit.md | 20 ----- docs/reference/type-aliases/RoundUnit.md | 19 ---- docs/reference/type-aliases/StartOfUnit.md | 20 ----- 48 files changed, 2228 deletions(-) delete mode 100644 docs/reference/functions/add.md delete mode 100644 docs/reference/functions/endOf.md delete mode 100644 docs/reference/functions/equals.md delete mode 100644 docs/reference/functions/format.md delete mode 100644 docs/reference/functions/intersects.md delete mode 100644 docs/reference/functions/isAfter.md delete mode 100644 docs/reference/functions/isBefore.md delete mode 100644 docs/reference/functions/isBetween.md delete mode 100644 docs/reference/functions/isLeapYear.md delete mode 100644 docs/reference/functions/isSameOrAfter.md delete mode 100644 docs/reference/functions/isSameOrBefore.md delete mode 100644 docs/reference/functions/isWeekend.md delete mode 100644 docs/reference/functions/range.md delete mode 100644 docs/reference/functions/round.md delete mode 100644 docs/reference/functions/since.md delete mode 100644 docs/reference/functions/startOf.md delete mode 100644 docs/reference/functions/subtract.md delete mode 100644 docs/reference/functions/until.md delete mode 100644 docs/reference/index.md delete mode 100644 docs/reference/interfaces/AddOptions.md delete mode 100644 docs/reference/interfaces/DateOptions.md delete mode 100644 docs/reference/interfaces/EndOfOptions.md delete mode 100644 docs/reference/interfaces/EqualsOptions.md delete mode 100644 docs/reference/interfaces/FormatDateOptions.md delete mode 100644 docs/reference/interfaces/IntersectsOptions.md delete mode 100644 docs/reference/interfaces/IsAfterOptions.md delete mode 100644 docs/reference/interfaces/IsBeforeOptions.md delete mode 100644 docs/reference/interfaces/IsBetweenOptions.md delete mode 100644 docs/reference/interfaces/IsLeapYearOptions.md delete mode 100644 docs/reference/interfaces/IsSameOrAfterOptions.md delete mode 100644 docs/reference/interfaces/IsSameOrBeforeOptions.md delete mode 100644 docs/reference/interfaces/IsWeekendOptions.md delete mode 100644 docs/reference/interfaces/Range.md delete mode 100644 docs/reference/interfaces/RangeOptions.md delete mode 100644 docs/reference/interfaces/RoundOptions.md delete mode 100644 docs/reference/interfaces/SinceOptions.md delete mode 100644 docs/reference/interfaces/StartOfOptions.md delete mode 100644 docs/reference/interfaces/SubtractOptions.md delete mode 100644 docs/reference/interfaces/UntilOptions.md delete mode 100644 docs/reference/type-aliases/DateInput.md delete mode 100644 docs/reference/type-aliases/DurationLike.md delete mode 100644 docs/reference/type-aliases/EndOfUnit.md delete mode 100644 docs/reference/type-aliases/EqualsUnit.md delete mode 100644 docs/reference/type-aliases/FormatType.md delete mode 100644 docs/reference/type-aliases/IsSameOrAfterUnit.md delete mode 100644 docs/reference/type-aliases/IsSameOrBeforeUnit.md delete mode 100644 docs/reference/type-aliases/RoundUnit.md delete mode 100644 docs/reference/type-aliases/StartOfUnit.md diff --git a/docs/reference/functions/add.md b/docs/reference/functions/add.md deleted file mode 100644 index 3f054550..00000000 --- a/docs/reference/functions/add.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: add -title: add ---- - -# Function: add() - -```ts -function add(input, options): object; -``` - -Defined in: [add/add.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L13) - -add -Adds a duration to a date/time instance - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`AddOptions`](../interfaces/AddOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/endOf.md b/docs/reference/functions/endOf.md deleted file mode 100644 index 2f73487b..00000000 --- a/docs/reference/functions/endOf.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: endOf -title: endOf ---- - -# Function: endOf() - -```ts -function endOf(input, options): object; -``` - -Defined in: [endOf/endOf.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L23) - -endOf -Returns the end of a given unit for a date/time instance - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`EndOfOptions`](../interfaces/EndOfOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/equals.md b/docs/reference/functions/equals.md deleted file mode 100644 index fd9a786b..00000000 --- a/docs/reference/functions/equals.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -id: equals -title: equals ---- - -# Function: equals() - -```ts -function equals( - date1, - date2, - unit, - options?): boolean; -``` - -Defined in: [equals/equals.ts:22](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L22) - -equals -Returns true if two date/time instances are equal at the specified unit level - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### unit - -[`EqualsUnit`](../type-aliases/EqualsUnit.md) - -### options? - -[`EqualsOptions`](../interfaces/EqualsOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/format.md b/docs/reference/functions/format.md deleted file mode 100644 index f7ca6174..00000000 --- a/docs/reference/functions/format.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: format -title: format ---- - -# Function: format() - -```ts -function format(date, formatOptions?): string; -``` - -Defined in: [format/format.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L32) - -format -Formats a date/time instance using Intl.DateTimeFormat - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -The date to format - -### formatOptions? - -[`FormatDateOptions`](../interfaces/FormatDateOptions.md) - -Formatting options including type, locale, and Intl.DateTimeFormat options - -## Returns - -`string` diff --git a/docs/reference/functions/intersects.md b/docs/reference/functions/intersects.md deleted file mode 100644 index 824c8bbc..00000000 --- a/docs/reference/functions/intersects.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: intersects -title: intersects ---- - -# Function: intersects() - -```ts -function intersects(date, options): boolean; -``` - -Defined in: [intersects/intersects.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L16) - -intersects -Returns true if the date/time instance intersects with the range (i.e., is within or equal to the range boundaries) - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -The date to check - -### options - -[`IntersectsOptions`](../interfaces/IntersectsOptions.md) - -Options including range, timeZone and calendar - -## Returns - -`boolean` diff --git a/docs/reference/functions/isAfter.md b/docs/reference/functions/isAfter.md deleted file mode 100644 index f39f9d47..00000000 --- a/docs/reference/functions/isAfter.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: isAfter -title: isAfter ---- - -# Function: isAfter() - -```ts -function isAfter( - date1, - date2, - options?): boolean; -``` - -Defined in: [isAfter/isAfter.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/isAfter/isAfter.ts#L12) - -isAfter -Returns true if the first date/time instance is after the second date/time instance - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### options? - -[`IsAfterOptions`](../interfaces/IsAfterOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isBefore.md b/docs/reference/functions/isBefore.md deleted file mode 100644 index b31cdcbf..00000000 --- a/docs/reference/functions/isBefore.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: isBefore -title: isBefore ---- - -# Function: isBefore() - -```ts -function isBefore( - date1, - date2, - options?): boolean; -``` - -Defined in: [isBefore/isBefore.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBefore/isBefore.ts#L12) - -isBefore -Returns true if the first date/time instance is before the second date/time instance - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### options? - -[`IsBeforeOptions`](../interfaces/IsBeforeOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isBetween.md b/docs/reference/functions/isBetween.md deleted file mode 100644 index 1c89b65e..00000000 --- a/docs/reference/functions/isBetween.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: isBetween -title: isBetween ---- - -# Function: isBetween() - -```ts -function isBetween(date, options): boolean; -``` - -Defined in: [isBetween/isBetween.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L18) - -isBetween -Returns true if the date/time instance is between the start and end of the range - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -The date to check - -### options - -[`IsBetweenOptions`](../interfaces/IsBetweenOptions.md) - -Options including timeZone, calendar, and inclusivity - -## Returns - -`boolean` diff --git a/docs/reference/functions/isLeapYear.md b/docs/reference/functions/isLeapYear.md deleted file mode 100644 index 559a24b4..00000000 --- a/docs/reference/functions/isLeapYear.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -id: isLeapYear -title: isLeapYear ---- - -# Function: isLeapYear() - -```ts -function isLeapYear(date, options?): boolean; -``` - -Defined in: [isLeapYear/isLeapYear.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/isLeapYear/isLeapYear.ts#L11) - -isLeapYear -Returns true if the year of the given date is a leap year - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -### options? - -[`IsLeapYearOptions`](../interfaces/IsLeapYearOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isSameOrAfter.md b/docs/reference/functions/isSameOrAfter.md deleted file mode 100644 index b3495511..00000000 --- a/docs/reference/functions/isSameOrAfter.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: isSameOrAfter -title: isSameOrAfter ---- - -# Function: isSameOrAfter() - -```ts -function isSameOrAfter( - date1, - date2, - options): boolean; -``` - -Defined in: [isSameOrAfter/isSameOrAfter.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L25) - -isSameOrAfter -Returns true if the first date/time instance is the same as or after the second date/time instance at the specified unit level - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`IsSameOrAfterOptions`](../interfaces/IsSameOrAfterOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isSameOrBefore.md b/docs/reference/functions/isSameOrBefore.md deleted file mode 100644 index 2bc2a75e..00000000 --- a/docs/reference/functions/isSameOrBefore.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: isSameOrBefore -title: isSameOrBefore ---- - -# Function: isSameOrBefore() - -```ts -function isSameOrBefore( - date1, - date2, - options): boolean; -``` - -Defined in: [isSameOrBefore/isSameOrBefore.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L25) - -isSameOrBefore -Returns true if the first date/time instance is the same as or before the second date/time instance at the specified unit level - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`IsSameOrBeforeOptions`](../interfaces/IsSameOrBeforeOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isWeekend.md b/docs/reference/functions/isWeekend.md deleted file mode 100644 index 57f9d80f..00000000 --- a/docs/reference/functions/isWeekend.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -id: isWeekend -title: isWeekend ---- - -# Function: isWeekend() - -```ts -function isWeekend(date, options?): boolean; -``` - -Defined in: [isWeekend/isWeekend.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L14) - -isWeekend -Returns true if the date falls on a weekend based on locale-specific week info - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -### options? - -[`IsWeekendOptions`](../interfaces/IsWeekendOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/range.md b/docs/reference/functions/range.md deleted file mode 100644 index 357bf089..00000000 --- a/docs/reference/functions/range.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -id: range -title: range ---- - -# Function: range() - -```ts -function range(options): object[]; -``` - -Defined in: [range/range.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L18) - -range -Generates an array of dates from start to end at the specified step interval. -The range is inclusive of both start and end (if end falls exactly on a step). - -## Parameters - -### options - -[`RangeOptions`](../interfaces/RangeOptions.md) - -## Returns - -`object`[] diff --git a/docs/reference/functions/round.md b/docs/reference/functions/round.md deleted file mode 100644 index 472c445b..00000000 --- a/docs/reference/functions/round.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: round -title: round ---- - -# Function: round() - -```ts -function round(input, options): object; -``` - -Defined in: [round/round.ts:27](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L27) - -round -Returns the date/time instance rounded to the nearest unit - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`RoundOptions`](../interfaces/RoundOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/since.md b/docs/reference/functions/since.md deleted file mode 100644 index 78ece940..00000000 --- a/docs/reference/functions/since.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -id: since -title: since ---- - -# Function: since() - -```ts -function since( - start, - end, - options): number; -``` - -Defined in: [since/since.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L15) - -since -Returns the duration from the first date/time instance since the second date/time instance -(equivalent to: how long has it been since the second date, from the first date's perspective) - -## Parameters - -### start - -[`DateInput`](../type-aliases/DateInput.md) - -### end - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`SinceOptions`](../interfaces/SinceOptions.md) - -## Returns - -`number` diff --git a/docs/reference/functions/startOf.md b/docs/reference/functions/startOf.md deleted file mode 100644 index 06e7b469..00000000 --- a/docs/reference/functions/startOf.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: startOf -title: startOf ---- - -# Function: startOf() - -```ts -function startOf(input, options): object; -``` - -Defined in: [startOf/startOf.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L23) - -startOf -Returns the start of a given unit for a date/time instance - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`StartOfOptions`](../interfaces/StartOfOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/subtract.md b/docs/reference/functions/subtract.md deleted file mode 100644 index 976c0a37..00000000 --- a/docs/reference/functions/subtract.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: subtract -title: subtract ---- - -# Function: subtract() - -```ts -function subtract(input, options): object; -``` - -Defined in: [subtract/subtract.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L13) - -subtract -Subtracts a duration from a date/time instance - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`SubtractOptions`](../interfaces/SubtractOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/until.md b/docs/reference/functions/until.md deleted file mode 100644 index ff727d9c..00000000 --- a/docs/reference/functions/until.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: until -title: until ---- - -# Function: until() - -```ts -function until( - start, - end, - options): number; -``` - -Defined in: [until/until.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L14) - -until -Returns the duration from the first date/time instance until the second date/time instance - -## Parameters - -### start - -[`DateInput`](../type-aliases/DateInput.md) - -### end - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`UntilOptions`](../interfaces/UntilOptions.md) - -## Returns - -`number` diff --git a/docs/reference/index.md b/docs/reference/index.md deleted file mode 100644 index fc521c54..00000000 --- a/docs/reference/index.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -id: "@tanstack/time" -title: "@tanstack/time" ---- - -# @tanstack/time - -## Interfaces - -- [AddOptions](interfaces/AddOptions.md) -- [DateOptions](interfaces/DateOptions.md) -- [EndOfOptions](interfaces/EndOfOptions.md) -- [EqualsOptions](interfaces/EqualsOptions.md) -- [FormatDateOptions](interfaces/FormatDateOptions.md) -- [IntersectsOptions](interfaces/IntersectsOptions.md) -- [IsAfterOptions](interfaces/IsAfterOptions.md) -- [IsBeforeOptions](interfaces/IsBeforeOptions.md) -- [IsBetweenOptions](interfaces/IsBetweenOptions.md) -- [IsLeapYearOptions](interfaces/IsLeapYearOptions.md) -- [IsSameOrAfterOptions](interfaces/IsSameOrAfterOptions.md) -- [IsSameOrBeforeOptions](interfaces/IsSameOrBeforeOptions.md) -- [IsWeekendOptions](interfaces/IsWeekendOptions.md) -- [Range](interfaces/Range.md) -- [RangeOptions](interfaces/RangeOptions.md) -- [RoundOptions](interfaces/RoundOptions.md) -- [SinceOptions](interfaces/SinceOptions.md) -- [StartOfOptions](interfaces/StartOfOptions.md) -- [SubtractOptions](interfaces/SubtractOptions.md) -- [UntilOptions](interfaces/UntilOptions.md) - -## Type Aliases - -- [DateInput](type-aliases/DateInput.md) -- [DurationLike](type-aliases/DurationLike.md) -- [EndOfUnit](type-aliases/EndOfUnit.md) -- [EqualsUnit](type-aliases/EqualsUnit.md) -- [FormatType](type-aliases/FormatType.md) -- [IsSameOrAfterUnit](type-aliases/IsSameOrAfterUnit.md) -- [IsSameOrBeforeUnit](type-aliases/IsSameOrBeforeUnit.md) -- [RoundUnit](type-aliases/RoundUnit.md) -- [StartOfUnit](type-aliases/StartOfUnit.md) - -## Functions - -- [add](functions/add.md) -- [endOf](functions/endOf.md) -- [equals](functions/equals.md) -- [format](functions/format.md) -- [intersects](functions/intersects.md) -- [isAfter](functions/isAfter.md) -- [isBefore](functions/isBefore.md) -- [isBetween](functions/isBetween.md) -- [isLeapYear](functions/isLeapYear.md) -- [isSameOrAfter](functions/isSameOrAfter.md) -- [isSameOrBefore](functions/isSameOrBefore.md) -- [isWeekend](functions/isWeekend.md) -- [range](functions/range.md) -- [round](functions/round.md) -- [since](functions/since.md) -- [startOf](functions/startOf.md) -- [subtract](functions/subtract.md) -- [until](functions/until.md) diff --git a/docs/reference/interfaces/AddOptions.md b/docs/reference/interfaces/AddOptions.md deleted file mode 100644 index d82c3f82..00000000 --- a/docs/reference/interfaces/AddOptions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: AddOptions -title: AddOptions ---- - -# Interface: AddOptions - -Defined in: [add/add.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L5) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### duration - -```ts -duration: DurationLike; -``` - -Defined in: [add/add.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L6) - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` diff --git a/docs/reference/interfaces/DateOptions.md b/docs/reference/interfaces/DateOptions.md deleted file mode 100644 index 65af3b1c..00000000 --- a/docs/reference/interfaces/DateOptions.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -id: DateOptions -title: DateOptions ---- - -# Interface: DateOptions - -Defined in: [types.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L5) - -## Extended by - -- [`SinceOptions`](SinceOptions.md) -- [`UntilOptions`](UntilOptions.md) -- [`EqualsOptions`](EqualsOptions.md) -- [`IsLeapYearOptions`](IsLeapYearOptions.md) -- [`IsWeekendOptions`](IsWeekendOptions.md) -- [`IsBeforeOptions`](IsBeforeOptions.md) -- [`IsAfterOptions`](IsAfterOptions.md) -- [`IsSameOrBeforeOptions`](IsSameOrBeforeOptions.md) -- [`IsSameOrAfterOptions`](IsSameOrAfterOptions.md) -- [`IsBetweenOptions`](IsBetweenOptions.md) -- [`IntersectsOptions`](IntersectsOptions.md) -- [`FormatDateOptions`](FormatDateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) diff --git a/docs/reference/interfaces/EndOfOptions.md b/docs/reference/interfaces/EndOfOptions.md deleted file mode 100644 index 7d962107..00000000 --- a/docs/reference/interfaces/EndOfOptions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: EndOfOptions -title: EndOfOptions ---- - -# Interface: EndOfOptions - -Defined in: [endOf/endOf.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L15) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` - -*** - -### unit - -```ts -unit: EndOfUnit; -``` - -Defined in: [endOf/endOf.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L16) diff --git a/docs/reference/interfaces/EqualsOptions.md b/docs/reference/interfaces/EqualsOptions.md deleted file mode 100644 index b29ec885..00000000 --- a/docs/reference/interfaces/EqualsOptions.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: EqualsOptions -title: EqualsOptions ---- - -# Interface: EqualsOptions - -Defined in: [equals/equals.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L16) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/FormatDateOptions.md b/docs/reference/interfaces/FormatDateOptions.md deleted file mode 100644 index 3656cdd4..00000000 --- a/docs/reference/interfaces/FormatDateOptions.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -id: FormatDateOptions -title: FormatDateOptions ---- - -# Interface: FormatDateOptions - -Defined in: [format/format.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L16) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### locale? - -```ts -optional locale: string | Locale | string[] | Locale[]; -``` - -Defined in: [format/format.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L18) - -*** - -### options? - -```ts -optional options: - | string - | DateFormatterOptions - | TimeFormatterOptions - | DateTimeFormatterOptions; -``` - -Defined in: [format/format.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L19) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### type? - -```ts -optional type: FormatType; -``` - -Defined in: [format/format.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L17) diff --git a/docs/reference/interfaces/IntersectsOptions.md b/docs/reference/interfaces/IntersectsOptions.md deleted file mode 100644 index fbcb1bed..00000000 --- a/docs/reference/interfaces/IntersectsOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: IntersectsOptions -title: IntersectsOptions ---- - -# Interface: IntersectsOptions - -Defined in: [intersects/intersects.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### range - -```ts -range: Range; -``` - -Defined in: [intersects/intersects.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L7) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsAfterOptions.md b/docs/reference/interfaces/IsAfterOptions.md deleted file mode 100644 index b9b2c323..00000000 --- a/docs/reference/interfaces/IsAfterOptions.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: IsAfterOptions -title: IsAfterOptions ---- - -# Interface: IsAfterOptions - -Defined in: [isAfter/isAfter.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isAfter/isAfter.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsBeforeOptions.md b/docs/reference/interfaces/IsBeforeOptions.md deleted file mode 100644 index 17e05ed1..00000000 --- a/docs/reference/interfaces/IsBeforeOptions.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: IsBeforeOptions -title: IsBeforeOptions ---- - -# Interface: IsBeforeOptions - -Defined in: [isBefore/isBefore.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBefore/isBefore.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsBetweenOptions.md b/docs/reference/interfaces/IsBetweenOptions.md deleted file mode 100644 index 01282b14..00000000 --- a/docs/reference/interfaces/IsBetweenOptions.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: IsBetweenOptions -title: IsBetweenOptions ---- - -# Interface: IsBetweenOptions - -Defined in: [isBetween/isBetween.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### inclusive? - -```ts -optional inclusive: boolean | "start" | "end"; -``` - -Defined in: [isBetween/isBetween.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L7) - -*** - -### range - -```ts -range: Range; -``` - -Defined in: [isBetween/isBetween.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L8) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsLeapYearOptions.md b/docs/reference/interfaces/IsLeapYearOptions.md deleted file mode 100644 index bd1bf8c1..00000000 --- a/docs/reference/interfaces/IsLeapYearOptions.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: IsLeapYearOptions -title: IsLeapYearOptions ---- - -# Interface: IsLeapYearOptions - -Defined in: [isLeapYear/isLeapYear.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/isLeapYear/isLeapYear.ts#L5) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsSameOrAfterOptions.md b/docs/reference/interfaces/IsSameOrAfterOptions.md deleted file mode 100644 index 29efc3e3..00000000 --- a/docs/reference/interfaces/IsSameOrAfterOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: IsSameOrAfterOptions -title: IsSameOrAfterOptions ---- - -# Interface: IsSameOrAfterOptions - -Defined in: [isSameOrAfter/isSameOrAfter.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L17) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### unit - -```ts -unit: IsSameOrAfterUnit; -``` - -Defined in: [isSameOrAfter/isSameOrAfter.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L18) diff --git a/docs/reference/interfaces/IsSameOrBeforeOptions.md b/docs/reference/interfaces/IsSameOrBeforeOptions.md deleted file mode 100644 index 60d6fb76..00000000 --- a/docs/reference/interfaces/IsSameOrBeforeOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: IsSameOrBeforeOptions -title: IsSameOrBeforeOptions ---- - -# Interface: IsSameOrBeforeOptions - -Defined in: [isSameOrBefore/isSameOrBefore.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L17) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### unit - -```ts -unit: IsSameOrBeforeUnit; -``` - -Defined in: [isSameOrBefore/isSameOrBefore.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L18) diff --git a/docs/reference/interfaces/IsWeekendOptions.md b/docs/reference/interfaces/IsWeekendOptions.md deleted file mode 100644 index da724639..00000000 --- a/docs/reference/interfaces/IsWeekendOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: IsWeekendOptions -title: IsWeekendOptions ---- - -# Interface: IsWeekendOptions - -Defined in: [isWeekend/isWeekend.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### locale? - -```ts -optional locale: string; -``` - -Defined in: [isWeekend/isWeekend.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L7) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/Range.md b/docs/reference/interfaces/Range.md deleted file mode 100644 index 16447e97..00000000 --- a/docs/reference/interfaces/Range.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -id: Range -title: Range ---- - -# Interface: Range - -Defined in: [types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -## Properties - -### end - -```ts -end: DateInput; -``` - -Defined in: [types.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L14) - -*** - -### start - -```ts -start: DateInput; -``` - -Defined in: [types.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L13) diff --git a/docs/reference/interfaces/RangeOptions.md b/docs/reference/interfaces/RangeOptions.md deleted file mode 100644 index 20f65b56..00000000 --- a/docs/reference/interfaces/RangeOptions.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -id: RangeOptions -title: RangeOptions ---- - -# Interface: RangeOptions - -Defined in: [range/range.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L7) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### end - -```ts -end: DateInput; -``` - -Defined in: [range/range.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L9) - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### start - -```ts -start: DateInput; -``` - -Defined in: [range/range.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L8) - -*** - -### step - -```ts -step: DurationLike; -``` - -Defined in: [range/range.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L10) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` diff --git a/docs/reference/interfaces/RoundOptions.md b/docs/reference/interfaces/RoundOptions.md deleted file mode 100644 index bd6267a5..00000000 --- a/docs/reference/interfaces/RoundOptions.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -id: RoundOptions -title: RoundOptions ---- - -# Interface: RoundOptions - -Defined in: [round/round.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L17) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### roundingIncrement? - -```ts -optional roundingIncrement: number; -``` - -Defined in: [round/round.ts:20](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L20) - -*** - -### roundingMode? - -```ts -optional roundingMode: RoundingMode; -``` - -Defined in: [round/round.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L19) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` - -*** - -### unit - -```ts -unit: RoundUnit; -``` - -Defined in: [round/round.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L18) diff --git a/docs/reference/interfaces/SinceOptions.md b/docs/reference/interfaces/SinceOptions.md deleted file mode 100644 index 1a89c322..00000000 --- a/docs/reference/interfaces/SinceOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: SinceOptions -title: SinceOptions ---- - -# Interface: SinceOptions - -Defined in: [since/since.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### unit - -```ts -unit: DateTimeUnit; -``` - -Defined in: [since/since.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L7) diff --git a/docs/reference/interfaces/StartOfOptions.md b/docs/reference/interfaces/StartOfOptions.md deleted file mode 100644 index 4a3b2330..00000000 --- a/docs/reference/interfaces/StartOfOptions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: StartOfOptions -title: StartOfOptions ---- - -# Interface: StartOfOptions - -Defined in: [startOf/startOf.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L15) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` - -*** - -### unit - -```ts -unit: StartOfUnit; -``` - -Defined in: [startOf/startOf.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L16) diff --git a/docs/reference/interfaces/SubtractOptions.md b/docs/reference/interfaces/SubtractOptions.md deleted file mode 100644 index ad2a1eef..00000000 --- a/docs/reference/interfaces/SubtractOptions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: SubtractOptions -title: SubtractOptions ---- - -# Interface: SubtractOptions - -Defined in: [subtract/subtract.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L5) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### duration - -```ts -duration: DurationLike; -``` - -Defined in: [subtract/subtract.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L6) - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` diff --git a/docs/reference/interfaces/UntilOptions.md b/docs/reference/interfaces/UntilOptions.md deleted file mode 100644 index 57ccccb7..00000000 --- a/docs/reference/interfaces/UntilOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: UntilOptions -title: UntilOptions ---- - -# Interface: UntilOptions - -Defined in: [until/until.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L6) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [types.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L7) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### unit - -```ts -unit: DateTimeUnit; -``` - -Defined in: [until/until.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L7) diff --git a/docs/reference/type-aliases/DateInput.md b/docs/reference/type-aliases/DateInput.md deleted file mode 100644 index c66a40c4..00000000 --- a/docs/reference/type-aliases/DateInput.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: DateInput -title: DateInput ---- - -# Type Alias: DateInput - -```ts -type DateInput = string | number | Date | Temporal.ZonedDateTime; -``` - -Defined in: [types.ts:3](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L3) diff --git a/docs/reference/type-aliases/DurationLike.md b/docs/reference/type-aliases/DurationLike.md deleted file mode 100644 index f9fef337..00000000 --- a/docs/reference/type-aliases/DurationLike.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: DurationLike -title: DurationLike ---- - -# Type Alias: DurationLike - -```ts -type DurationLike = Temporal.DurationLike; -``` - -Defined in: [types.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L10) diff --git a/docs/reference/type-aliases/EndOfUnit.md b/docs/reference/type-aliases/EndOfUnit.md deleted file mode 100644 index 9e9d7bd5..00000000 --- a/docs/reference/type-aliases/EndOfUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: EndOfUnit -title: EndOfUnit ---- - -# Type Alias: EndOfUnit - -```ts -type EndOfUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [endOf/endOf.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L5) diff --git a/docs/reference/type-aliases/EqualsUnit.md b/docs/reference/type-aliases/EqualsUnit.md deleted file mode 100644 index f8d3eb8a..00000000 --- a/docs/reference/type-aliases/EqualsUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: EqualsUnit -title: EqualsUnit ---- - -# Type Alias: EqualsUnit - -```ts -type EqualsUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [equals/equals.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L6) diff --git a/docs/reference/type-aliases/FormatType.md b/docs/reference/type-aliases/FormatType.md deleted file mode 100644 index dfced255..00000000 --- a/docs/reference/type-aliases/FormatType.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: FormatType -title: FormatType ---- - -# Type Alias: FormatType - -```ts -type FormatType = "date" | "time" | "datetime"; -``` - -Defined in: [format/format.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L14) diff --git a/docs/reference/type-aliases/IsSameOrAfterUnit.md b/docs/reference/type-aliases/IsSameOrAfterUnit.md deleted file mode 100644 index ef6acd42..00000000 --- a/docs/reference/type-aliases/IsSameOrAfterUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: IsSameOrAfterUnit -title: IsSameOrAfterUnit ---- - -# Type Alias: IsSameOrAfterUnit - -```ts -type IsSameOrAfterUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [isSameOrAfter/isSameOrAfter.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L7) diff --git a/docs/reference/type-aliases/IsSameOrBeforeUnit.md b/docs/reference/type-aliases/IsSameOrBeforeUnit.md deleted file mode 100644 index 60ca08ff..00000000 --- a/docs/reference/type-aliases/IsSameOrBeforeUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: IsSameOrBeforeUnit -title: IsSameOrBeforeUnit ---- - -# Type Alias: IsSameOrBeforeUnit - -```ts -type IsSameOrBeforeUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [isSameOrBefore/isSameOrBefore.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L7) diff --git a/docs/reference/type-aliases/RoundUnit.md b/docs/reference/type-aliases/RoundUnit.md deleted file mode 100644 index a5dd3dc6..00000000 --- a/docs/reference/type-aliases/RoundUnit.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -id: RoundUnit -title: RoundUnit ---- - -# Type Alias: RoundUnit - -```ts -type RoundUnit = - | "day" - | "hour" - | "minute" - | "second" - | "millisecond" - | "microsecond" - | "nanosecond"; -``` - -Defined in: [round/round.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L6) diff --git a/docs/reference/type-aliases/StartOfUnit.md b/docs/reference/type-aliases/StartOfUnit.md deleted file mode 100644 index e1840ec5..00000000 --- a/docs/reference/type-aliases/StartOfUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: StartOfUnit -title: StartOfUnit ---- - -# Type Alias: StartOfUnit - -```ts -type StartOfUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [startOf/startOf.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L5) From 3ab5235d78298e0eda87e4d0675b258e90e61698 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Sun, 25 Jan 2026 22:14:17 +0100 Subject: [PATCH 034/207] feat: calendar --- examples/react/basic/package.json | 3 + examples/react/basic/postcss.config.js | 6 + examples/react/basic/src/index.css | 3 + examples/react/basic/src/index.tsx | 375 ++++++++++++++- examples/react/basic/tailwind.config.js | 8 + packages/react-time/src/index.ts | 1 + packages/react-time/src/useCalendar/index.ts | 1 + .../react-time/src/useCalendar/useCalendar.ts | 118 +++++ packages/time/src/calendar/calendar.ts | 224 +++++++++ packages/time/src/calendar/date-core.ts | 431 ++++++++++++++++++ .../time/src/calendar/generateDateRange.ts | 16 + packages/time/src/calendar/getEventProps.ts | 46 ++ packages/time/src/calendar/getTimeSlots.ts | 52 +++ packages/time/src/calendar/groupDaysBy.ts | 171 +++++++ packages/time/src/calendar/index.ts | 7 + .../time/src/calendar/splitMultiDayEvents.ts | 44 ++ packages/time/src/calendar/types.ts | 47 ++ packages/time/src/date/isWeekend/isWeekend.ts | 2 +- packages/time/src/index.ts | 1 + packages/time/src/utils/dateRange.ts | 2 +- packages/time/src/utils/weekUtils.ts | 3 +- pnpm-lock.yaml | 388 +++++++++++++++- 22 files changed, 1941 insertions(+), 8 deletions(-) create mode 100644 examples/react/basic/postcss.config.js create mode 100644 examples/react/basic/src/index.css create mode 100644 examples/react/basic/tailwind.config.js create mode 100644 packages/react-time/src/useCalendar/index.ts create mode 100644 packages/react-time/src/useCalendar/useCalendar.ts create mode 100644 packages/time/src/calendar/calendar.ts create mode 100644 packages/time/src/calendar/date-core.ts create mode 100644 packages/time/src/calendar/generateDateRange.ts create mode 100644 packages/time/src/calendar/getEventProps.ts create mode 100644 packages/time/src/calendar/getTimeSlots.ts create mode 100644 packages/time/src/calendar/groupDaysBy.ts create mode 100644 packages/time/src/calendar/index.ts create mode 100644 packages/time/src/calendar/splitMultiDayEvents.ts create mode 100644 packages/time/src/calendar/types.ts diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json index 704dc2c7..ad3f5ff6 100644 --- a/examples/react/basic/package.json +++ b/examples/react/basic/package.json @@ -18,6 +18,9 @@ "@types/react": "^19.2.8", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.2", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.17", "typescript": "5.9.3", "vite": "^7.3.1" } diff --git a/examples/react/basic/postcss.config.js b/examples/react/basic/postcss.config.js new file mode 100644 index 00000000..2e7af2b7 --- /dev/null +++ b/examples/react/basic/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/examples/react/basic/src/index.css b/examples/react/basic/src/index.css new file mode 100644 index 00000000..b5c61c95 --- /dev/null +++ b/examples/react/basic/src/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 407e3c13..b2371c27 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -1,11 +1,380 @@ +import { useCalendar } from '@tanstack/react-time' import ReactDOM from 'react-dom/client' +import type { Day, Event, Resource } from '@tanstack/time' +import './index.css' + +function formatPeriodDate(dateString: string): string { + const datePart = dateString.split('[')[0] + if (!datePart) return dateString + + const [year, month, day] = datePart.split('-').map(Number) + const date = new Date(year, month - 1, day) + + const formatter = new Intl.DateTimeFormat(undefined, { + month: 'long', + year: 'numeric', + }) + + return formatter.format(date) +} + +function formatDateToISO(date: Date): string { + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + return `${year}-${month}-${day}` +} + +function getSampleEvents(): Array> { + const today = new Date() + const tomorrow = new Date(today) + tomorrow.setDate(today.getDate() + 1) + + const dayAfterTomorrow = new Date(today) + dayAfterTomorrow.setDate(today.getDate() + 2) + + const threeDaysLater = new Date(today) + threeDaysLater.setDate(today.getDate() + 3) + + const fourDaysLater = new Date(today) + fourDaysLater.setDate(today.getDate() + 4) + + return [ + { + id: '1', + title: 'Team Meeting', + start: `${formatDateToISO(tomorrow)}T10:00:00`, + end: `${formatDateToISO(tomorrow)}T11:00:00`, + }, + { + id: '2', + title: 'Project Review', + start: `${formatDateToISO(dayAfterTomorrow)}T14:00:00`, + end: `${formatDateToISO(dayAfterTomorrow)}T15:30:00`, + }, + { + id: '3', + title: 'Multi-day Conference', + start: `${formatDateToISO(threeDaysLater)}T09:00:00`, + end: `${formatDateToISO(fourDaysLater)}T17:00:00`, + }, + { + id: '4', + title: 'Lunch Break', + start: `${formatDateToISO(threeDaysLater)}T12:00:00`, + end: `${formatDateToISO(threeDaysLater)}T13:00:00`, + }, + ] +} + +const sampleEvents = getSampleEvents() + +function parseEventTime(event: Event): { hour: number; minute: number } { + const [_datePart, timePart] = event.start.split('T') + if (!timePart) return { hour: 0, minute: 0 } + const [hour, minute] = timePart.split(':').map(Number) + return { hour, minute } +} + +function parseEventDuration(event: Event): number { + const start = new Date(event.start) + const end = new Date(event.end) + return (end.getTime() - start.getTime()) / (1000 * 60) +} + +function ScheduleView({ + calendar, + days, +}: { + calendar: ReturnType>> + days: Array>> +}) { + const timeSlots = calendar.getTimeSlots({ startHour: 0, endHour: 24, interval: 60 }) + const slotHeight = 60 + + const getEventPosition = (event: Event) => { + const { hour, minute } = parseEventTime(event) + const duration = parseEventDuration(event) + const top = (hour * 60 + minute) * (slotHeight / 60) + const height = duration * (slotHeight / 60) + return { top, height } + } + + return ( +
+
+
+ {timeSlots.map((slot) => ( +
+ {slot.label} +
+ ))} +
+
+
+
+ {days.map((day) => { + const dayName = new Intl.DateTimeFormat('en-US', { weekday: 'short' }).format( + new Date(day.date.year, day.date.month - 1, day.date.day) + ) + return ( +
+
+
+ {dayName} +
+
{day.date.day}
+
+
+ {day.events.map((event) => { + const { top, height } = getEventPosition(event) + return ( +
+
{event.title}
+ {height > 30 && ( +
+ {new Date(event.start).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit', + })} + {' - '} + {new Date(event.end).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit', + })} +
+ )} +
+ ) + })} +
+
+ ) + })} +
+
+
+
+ ) +} + +function CalendarView() { + + const calendar = useCalendar>({ + viewMode: { value: 1, unit: 'month' }, + events: sampleEvents, + + timeZone: 'UTC', + }) + + const dayNames = calendar.getDaysNames('short') + const groupedDays = calendar.groupDaysBy({ + days: calendar.days, + unit: 'week', + fillMissingDays: true, + }) + + const isScheduleView = calendar.viewMode.unit === 'week' || calendar.viewMode.unit === 'day' + const scheduleDays: Array>> = isScheduleView + ? calendar.viewMode.unit === 'day' + ? calendar.days.filter((day) => { + const currentDateStr = calendar.currentPeriod.split('[')[0] + return day.date.toString({ calendarName: 'never' }) === currentDateStr + }) + : calendar.days + : [] -function App() { return ( -
-

TanStack Time - React Basic Example

+
+
+

+ TanStack Time - Calendar Example +

+ +
+ + + + + + +
+ + + +
+
+ +
+ {formatPeriodDate(calendar.currentPeriod)} +
+
+ + {isScheduleView ? ( + + ) : ( +
+
+ {dayNames.map((dayName: string, index: number) => ( +
+ {dayName} +
+ ))} +
+ +
+ {groupedDays.map((week: Array> | null>, weekIndex: number) => + week.map((day, dayIndex) => { + if (!day) { + return ( +
+ ) + } + + const isToday = day.isToday + const isInCurrentPeriod = day.isInCurrentPeriod + + return ( +
+
+ {day.date.day} +
+
+ {day.events.map((event) => ( +
+ {event.title} +
+ ))} +
+
+ ) + }), + )} +
+
+ )} + + {calendar.isPending && ( +
+ Loading... +
+ )}
) } +function App() { + return +} + ReactDOM.createRoot(document.getElementById('root')!).render() diff --git a/examples/react/basic/tailwind.config.js b/examples/react/basic/tailwind.config.js new file mode 100644 index 00000000..7141e452 --- /dev/null +++ b/examples/react/basic/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], + theme: { + extend: {}, + }, + plugins: [], +} diff --git a/packages/react-time/src/index.ts b/packages/react-time/src/index.ts index e69de29b..5ba2e09d 100644 --- a/packages/react-time/src/index.ts +++ b/packages/react-time/src/index.ts @@ -0,0 +1 @@ +export { useCalendar } from './useCalendar' diff --git a/packages/react-time/src/useCalendar/index.ts b/packages/react-time/src/useCalendar/index.ts new file mode 100644 index 00000000..0b95ae99 --- /dev/null +++ b/packages/react-time/src/useCalendar/index.ts @@ -0,0 +1 @@ +export { useCalendar } from './useCalendar'; diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts new file mode 100644 index 00000000..5fd2db9d --- /dev/null +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -0,0 +1,118 @@ +import { useCallback, useState, useTransition } from 'react' +import { useStore } from '@tanstack/react-store' +import { CalendarCore } from '@tanstack/time' +import type { + CalendarApi, + CalendarCoreOptions, + Event, + Resource, +} from '@tanstack/time' + +export const useCalendar = < + TResource extends Resource, + TEvent extends Event = Event, +>( + options: CalendarCoreOptions, +): CalendarApi & { isPending: boolean } => { + const [calendarCore] = useState( + () => new CalendarCore(options), + ) + const state = useStore(calendarCore.store) + const [isPending, startTransition] = useTransition() + + const goToPreviousPeriod = useCallback< + typeof calendarCore.goToPreviousPeriod + >(() => { + startTransition(() => { + calendarCore.goToPreviousPeriod() + }) + }, [calendarCore, startTransition]) + + const goToNextPeriod = useCallback(() => { + startTransition(() => { + calendarCore.goToNextPeriod() + }) + }, [calendarCore, startTransition]) + + const goToCurrentPeriod = useCallback< + typeof calendarCore.goToCurrentPeriod + >(() => { + startTransition(() => { + calendarCore.goToCurrentPeriod() + }) + }, [calendarCore, startTransition]) + + const goToSpecificPeriod = useCallback< + typeof calendarCore.goToSpecificPeriod + >( + (date) => { + startTransition(() => { + calendarCore.goToSpecificPeriod(date) + }) + }, + [calendarCore, startTransition], + ) + + const changeViewMode = useCallback( + (newViewMode) => { + startTransition(() => { + calendarCore.changeViewMode(newViewMode) + }) + }, + [calendarCore, startTransition], + ) + + const getEventProps = useCallback( + (id) => calendarCore.getEventProps(id), + [calendarCore], + ) + + const groupDaysBy = useCallback( + (props) => calendarCore.groupDaysBy(props), + [calendarCore], + ) + + const getDaysNames = useCallback( + (props) => calendarCore.getDaysNames(props), + [calendarCore], + ) + + const getTimeSlots = useCallback( + (options) => calendarCore.getTimeSlots(options), + [calendarCore], + ) + + const getEventsByDate = useCallback( + (date) => calendarCore.getEventsByDate(date), + [calendarCore], + ) + + const canGoPreviousPeriod = useCallback< + typeof calendarCore.canGoPreviousPeriod + >(() => calendarCore.canGoPreviousPeriod(), [calendarCore]) + + const canGoNextPeriod = useCallback( + () => calendarCore.canGoNextPeriod(), + [calendarCore], + ) + + return { + activeDate: state.activeDate.toString(), + currentPeriod: state.currentPeriod.toString(), + viewMode: state.viewMode, + days: calendarCore.getDaysWithEvents(), + getDaysNames, + getTimeSlots, + getEventsByDate, + goToPreviousPeriod, + goToNextPeriod, + goToCurrentPeriod, + goToSpecificPeriod, + canGoPreviousPeriod, + canGoNextPeriod, + changeViewMode, + getEventProps, + isPending, + groupDaysBy, + } +} diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts new file mode 100644 index 00000000..047f7837 --- /dev/null +++ b/packages/time/src/calendar/calendar.ts @@ -0,0 +1,224 @@ +import { Temporal } from '@js-temporal/polyfill' +import { splitMultiDayEvents } from './splitMultiDayEvents' +import { getEventProps } from './getEventProps' +import { groupDaysBy } from './groupDaysBy' +import { getTimeSlots } from './getTimeSlots' +import { DateCore } from './date-core' +import type {DateCoreOptions, ParsedDateCoreOptions} from './date-core'; +import type { GroupDaysByProps } from './groupDaysBy' +import type { + Day, + Event, + Resource, + TimeSlot, + ViewMode, +} from './types' + +export type * from './types' +export * from './date-core' + +interface CalendarStore { + currentPeriod: Temporal.PlainDate + activeDate: Temporal.PlainDate + viewMode: ViewMode +} + +/** + * Configuration options for initializing a CalendarCore instance, allowing customization + * of events, locale, time zone, and the calendar system. + * @template TEvent - Specifies the event type, extending a base Event type. + */ +export interface CalendarCoreOptions< + TResource extends Resource, + TEvent extends Event, +> extends DateCoreOptions { + /** An optional array of events to be handled by the calendar. */ + events?: Array | null + /** Optional resources to be used in the calendar. */ + resources?: Array | null +} + +/** + * The API surface provided by CalendarCore, allowing interaction with the calendar's state + * and manipulation of its settings and data. + * @template TEvent - The type of events handled by the calendar. + */ +interface CalendarActions< + TResource extends Resource, + TEvent extends Event, +> { + /** Navigates to the previous period according to the current view mode. */ + goToPreviousPeriod: () => void + /** Navigates to the next period according to the current view mode. */ + goToNextPeriod: () => void + /** Resets the view to the current period based on today's date. */ + goToCurrentPeriod: () => void + /** Navigates to a specific date. */ + goToSpecificPeriod: (date: string) => void + /** Checks if navigation to the previous period is allowed within the range. */ + canGoPreviousPeriod: () => boolean + /** Checks if navigation to the next period is allowed within the range. */ + canGoNextPeriod: () => boolean + /** Changes the current view mode of the calendar. */ + changeViewMode: (newViewMode: CalendarStore['viewMode']) => void + /** Retrieves styling properties for a specific event, identified by ID. */ + getEventProps: (id: Event['id']) => { + isSplitEvent: boolean + overlappingEvents: Array + } | null + /** Retrieves the names of the days of the week, based on the current locale. */ + getDaysNames: (weekday?: 'long' | 'short') => Array + /** Groups days by a specified unit. */ + groupDaysBy: ( + props: Omit, 'weekStartsOn' | 'locale'>, + ) => Array | null>> + /** Retrieves time slots for day view with configurable intervals. */ + getTimeSlots: (options?: Parameters[1]) => Array + /** Retrieves events for a specific date. */ + getEventsByDate: (date: string) => Array +} + +interface CalendarState< + TResource extends Resource, + TEvent extends Event, +> { + /** The currently focused date period in the calendar. */ + currentPeriod: CalendarStore['currentPeriod'] + /** The current view mode of the calendar. */ + viewMode: CalendarStore['viewMode'] + /** An array of days, each potentially containing events. */ + days: Array> + /** The currently active date in the calendar. */ + activeDate: CalendarStore['activeDate'] +} + +type ConvertTemporalToString = { + [K in keyof T]: T[K] extends Temporal.PlainDate ? string : T[K] +} + +export interface CalendarApi< + TResource extends Resource, + TEvent extends Event, +> extends CalendarActions, + ConvertTemporalToString> {} + +/** + * Core functionality for a calendar system, managing the state and operations of the calendar, + * such as navigating through time periods, handling events, and adjusting settings. + * @template TEvent - The type of events managed by the calendar. + */ +type ParsedCalendarCoreOptions< + TResource extends Resource, + TEvent extends Event, +> = ParsedDateCoreOptions & { + events: Array | null + resources: Array | null +} + +export class CalendarCore< + TResource extends Resource, + TEvent extends Event, + > + extends DateCore + implements CalendarActions +{ + declare options: ParsedCalendarCoreOptions + + constructor(options: CalendarCoreOptions) { + super(options) + Object.assign(this.options, { + events: options.events || null, + resources: options.resources || null, + }) + } + + protected getCalendarDays() { + return super.getCalendarDays() + } + + private getEventMap() { + const map = new Map>() + this.options.events?.forEach((event) => { + const eventStartDate = Temporal.PlainDateTime.from( + event.start, + ).toZonedDateTime(this.options.timeZone) + const eventEndDate = Temporal.PlainDateTime.from( + event.end, + ).toZonedDateTime(this.options.timeZone) + const startPlainDate = eventStartDate.toPlainDate() + const endPlainDate = eventEndDate.toPlainDate() + + if (Temporal.PlainDate.compare(startPlainDate, endPlainDate) !== 0) { + const splitEvents = splitMultiDayEvents( + event, + this.options.timeZone, + ) + splitEvents.forEach((splitEvent) => { + const dateKey = Temporal.ZonedDateTime.from(splitEvent.start).toPlainDate().toString({ calendarName: 'never' }) + if (!map.has(dateKey)) map.set(dateKey, []) + map.get(dateKey)?.push(splitEvent) + }) + } else { + const dateKey = startPlainDate.toString({ calendarName: 'never' }) + if (!map.has(dateKey)) map.set(dateKey, []) + map.get(dateKey)?.push(event) + } + }) + return map + } + + getDaysWithEvents() { + const calendarDays = this.getCalendarDays() + const eventMap = this.getEventMap() + return calendarDays.map((day) => { + const dayKey = day.toString({ calendarName: 'never' }) + const dailyEvents = eventMap.get(dayKey) ?? [] + const currentMonthRange = Array.from( + { length: this.store.state.viewMode.value }, + (_, i) => this.store.state.currentPeriod.add({ months: i }).month, + ) + const isInCurrentPeriod = currentMonthRange.includes(day.month) + return { + date: day, + events: dailyEvents, + isToday: + Temporal.PlainDate.compare(day, Temporal.Now.plainDateISO()) === 0, + isInCurrentPeriod, + } + }) + } + + getEventProps(id: Event['id']) { + return getEventProps( + this.getEventMap(), + id, + this.store.state, + ) as ReturnType['getEventProps']> + } + + groupDaysBy({ + days, + unit, + fillMissingDays = true, + }: Omit, 'weekStartsOn' | 'locale'>) { + return groupDaysBy({ + days, + unit, + fillMissingDays, + weekStartsOn: this.getWeekStartsOn(), + locale: this.options.locale, + }) + } + + getTimeSlots(options?: Parameters[1]): Array { + return getTimeSlots(this.options.locale, options) + } + + getEventsByDate(date: string): Array { + const targetDate = Temporal.PlainDate.from(date).toString({ + calendarName: 'never', + }) + const eventMap = this.getEventMap() + return eventMap.get(targetDate) ?? [] + } +} diff --git a/packages/time/src/calendar/date-core.ts b/packages/time/src/calendar/date-core.ts new file mode 100644 index 00000000..de1fa3ac --- /dev/null +++ b/packages/time/src/calendar/date-core.ts @@ -0,0 +1,431 @@ +import { Store } from '@tanstack/store' +import { Temporal } from '@js-temporal/polyfill' +import { + constrainDateToRange, + getFirstDayOfMonth, + getFirstDayOfWeek, + isDateInRange, + parseDateRange, +} from '../utils' +import { getDateTimeDefaults } from '../utils/dateDefaults' +import { buildDateFormatter } from '../formatter/buildDateFormatter' +import { buildDateTimeFormatter } from '../formatter/buildDateTimeFormatter' +import { buildTimeFormatter } from '../formatter/buildTimeFormatter' +import { generateDateRange } from './generateDateRange' +import type { ParsedDateRange } from '../utils/dateRange' +import type { DateRange, ViewMode } from './types' +import type { DateInput } from '~/date' + +function toTemporalPlainDateString(date: DateInput): string { + if (date instanceof Temporal.PlainDate) { + return date.toString({ calendarName: 'never' }) + } + if (date instanceof Temporal.ZonedDateTime) { + return date.toPlainDate().toString({ calendarName: 'never' }) + } + if (date instanceof Date) { + return date.toISOString().split('T')[0]! + } + if (typeof date === 'number') { + return new Date(date).toISOString().split('T')[0]! + } + return date +} + +function toDate(date: DateInput): Date { + if (date instanceof Date) { + return date + } + if (date instanceof Temporal.ZonedDateTime) { + return new Date(date.toPlainDate().toString({ calendarName: 'auto' })) + } + if (date instanceof Temporal.PlainDate) { + return new Date(date.year, date.month - 1, date.day) + } + return new Date(date) +} + +/** + * Base options interface for date-related core classes. + */ +export interface DateCoreOptions { + /** The initial view mode configuration. */ + viewMode: ViewMode + /** Optional locale for date formatting. Uses a BCP 47 language tag. */ + locale?: Intl.UnicodeBCP47LocaleIdentifier + /** Optional time zone specification. */ + timeZone?: Temporal.TimeZoneLike + /** Optional calendar system to be used. */ + calendar?: Temporal.CalendarLike + /** Optional range of dates to be used. */ + range?: DateRange + /** Optional date formatter. */ + dateFormatter?: Intl.DateTimeFormat + /** Optional time formatter. */ + timeFormatter?: Intl.DateTimeFormat + /** Optional date time formatter. */ + dateTimeFormatter?: Intl.DateTimeFormat +} + +export interface ParsedDateCoreOptions + extends Omit< + Required, + 'range' | 'dateFormatter' | 'timeFormatter' | 'dateTimeFormatter' + > { + range: ParsedDateRange +} + +export abstract class DateCore { + store: Store<{ + currentPeriod: Temporal.PlainDate + activeDate: Temporal.PlainDate + viewMode: ViewMode + }> + options: ParsedDateCoreOptions + formatters: { + date: Intl.DateTimeFormat + time: Intl.DateTimeFormat + dateTime: Intl.DateTimeFormat + } + + constructor(options: DateCoreOptions) { + const defaults = getDateTimeDefaults() + const parsedRange = parseDateRange({ + range: options.range, + calendar: defaults.calendar, + }) + + this.options = { + ...defaults, + ...options, + range: parsedRange, + } + + this.formatters = { + date: + options.dateFormatter ?? + buildDateFormatter({ + locale: this.options.locale, + }), + time: + options.timeFormatter ?? + buildTimeFormatter({ + locale: this.options.locale, + }), + dateTime: + options.dateTimeFormatter ?? + buildDateTimeFormatter({ + locale: this.options.locale, + }), + } + + const now = Temporal.Now.plainDateISO().withCalendar(this.options.calendar) + const initialDate = constrainDateToRange({ + date: now, + range: this.options.range, + }) + + this.store = new Store({ + currentPeriod: initialDate, + activeDate: initialDate, + viewMode: options.viewMode, + }) + } + + formatDate(date: DateInput) { + return this.formatters.date.format(toDate(date)) + } + + formatTime(date: DateInput) { + return this.formatters.time.format(toDate(date)) + } + + formatDateTime(date: DateInput) { + return this.formatters.dateTime.format(toDate(date)) + } + + protected getFirstDayOfMonth() { + return getFirstDayOfMonth( + this.store.state.currentPeriod + .toString({ calendarName: 'auto' }) + .substring(0, 7), + ) + } + + protected getFirstDayOfWeek() { + return getFirstDayOfWeek( + this.store.state.currentPeriod.toString(), + this.options.locale, + ) + } + + getWeekStartsOn() { + return this.getFirstDayOfWeek().dayOfWeek + } + + protected getCalendarDays() { + const start = + this.store.state.viewMode.unit === 'month' + ? this.getFirstDayOfMonth().subtract({ + days: + (this.getFirstDayOfMonth().dayOfWeek - + (this.getFirstDayOfWeek().dayOfWeek + 1) + + 7) % + 7, + }) + : this.store.state.currentPeriod + + let end: Temporal.PlainDate + switch (this.store.state.viewMode.unit) { + case 'month': { + const lastDayOfMonth = this.getFirstDayOfMonth() + .add({ months: this.store.state.viewMode.value }) + .subtract({ days: 1 }) + const lastDayOfMonthWeekDay = + (lastDayOfMonth.dayOfWeek - + (this.getFirstDayOfWeek().dayOfWeek + 1) + + 7) % + 7 + end = lastDayOfMonth.add({ days: 6 - lastDayOfMonthWeekDay }) + break + } + case 'week': { + end = this.getFirstDayOfWeek().add({ + days: 7 * this.store.state.viewMode.value - 1, + }) + break + } + case 'day': { + end = this.store.state.currentPeriod.add({ + days: this.store.state.viewMode.value - 1, + }) + break + } + case 'workWeek': { + end = start.add({ days: 4 }) + break + } + } + + const allDays = generateDateRange(start.toString(), end.toString()) + const startMonthDate = this.store.state.currentPeriod.with({ day: 1 }) + const endMonthDate = this.store.state.currentPeriod + .add({ + months: this.store.state.viewMode.value - 1, + }) + .with({ + day: Temporal.PlainDate.from( + this.store.state.currentPeriod.toString({ calendarName: 'auto' }), + ).daysInMonth, + }) + + const filteredDays = allDays.filter( + (day) => + Temporal.PlainDate.compare(day, startMonthDate) >= 0 && + Temporal.PlainDate.compare(day, endMonthDate) <= 0, + ) + + if (this.options.range.start || this.options.range.end) { + return filteredDays.filter((day) => + isDateInRange({ date: day, range: this.options.range }), + ) + } + + return filteredDays + } + + getDaysNames(weekday: 'long' | 'short' = 'short') { + const baseDate = Temporal.PlainDate.from('2024-01-01') + const firstDayOfWeek = this.getFirstDayOfWeek().dayOfWeek + + return Array.from({ length: 7 }).map((_, i) => + baseDate + .add({ days: (i + (firstDayOfWeek - 1)) % 7 }) + .toLocaleString(this.options.locale, { weekday: weekday }), + ) + } + + changeViewMode(newViewMode: ViewMode) { + this.store.setState((prev) => ({ + ...prev, + viewMode: newViewMode, + })) + } + + goToPreviousPeriod() { + let newActiveDate: Temporal.PlainDate + + switch (this.store.state.viewMode.unit) { + case 'month': { + newActiveDate = this.store.state.activeDate.subtract({ + months: this.store.state.viewMode.value, + }) + break + } + + case 'week': { + newActiveDate = this.store.state.activeDate.subtract({ + weeks: this.store.state.viewMode.value, + }) + break + } + + case 'day': { + newActiveDate = this.store.state.activeDate.subtract({ + days: this.store.state.viewMode.value, + }) + break + } + case 'workWeek': { + newActiveDate = this.store.state.activeDate.subtract({ + days: 5, + }) + break + } + } + + const constrainedDate = constrainDateToRange({ + date: newActiveDate, + range: this.options.range, + }) + this.store.setState((prev) => ({ + ...prev, + activeDate: constrainedDate, + currentPeriod: constrainedDate, + })) + } + + goToNextPeriod() { + let newActiveDate: Temporal.PlainDate + + switch (this.store.state.viewMode.unit) { + case 'month': { + newActiveDate = this.store.state.activeDate.add({ + months: this.store.state.viewMode.value, + }) + break + } + + case 'week': { + newActiveDate = this.store.state.activeDate.add({ + weeks: this.store.state.viewMode.value, + }) + break + } + + case 'day': { + newActiveDate = this.store.state.activeDate.add({ + days: this.store.state.viewMode.value, + }) + break + } + case 'workWeek': { + newActiveDate = this.store.state.activeDate.add({ + days: 5, + }) + break + } + } + + const constrainedDate = constrainDateToRange({ + date: newActiveDate, + range: this.options.range, + }) + this.store.setState((prev) => ({ + ...prev, + activeDate: constrainedDate, + currentPeriod: constrainedDate, + })) + } + + goToCurrentPeriod() { + const now = Temporal.Now.plainDateISO().withCalendar(this.options.calendar) + const constrainedDate = constrainDateToRange({ + date: now, + range: this.options.range, + }) + this.store.setState((prev) => ({ + ...prev, + activeDate: constrainedDate, + currentPeriod: constrainedDate, + })) + } + + goToSpecificPeriod(date: DateInput) { + const dateStr = toTemporalPlainDateString(date) + const targetDate = Temporal.PlainDate.from(dateStr).withCalendar( + this.options.calendar, + ) + const constrainedDate = constrainDateToRange({ + date: targetDate, + range: this.options.range, + }) + this.store.setState((prev) => ({ + ...prev, + activeDate: constrainedDate, + currentPeriod: constrainedDate, + })) + } + + canGoPreviousPeriod(): boolean { + let previousDate: Temporal.PlainDate + + switch (this.store.state.viewMode.unit) { + case 'month': { + previousDate = this.store.state.activeDate.subtract({ + months: this.store.state.viewMode.value, + }) + break + } + case 'week': { + previousDate = this.store.state.activeDate.subtract({ + weeks: this.store.state.viewMode.value, + }) + break + } + case 'day': { + previousDate = this.store.state.activeDate.subtract({ + days: this.store.state.viewMode.value, + }) + break + } + case 'workWeek': { + previousDate = this.store.state.activeDate.subtract({ days: 5 }) + break + } + } + + return isDateInRange({ date: previousDate, range: this.options.range }) + } + + canGoNextPeriod(): boolean { + let nextDate: Temporal.PlainDate + + switch (this.store.state.viewMode.unit) { + case 'month': { + nextDate = this.store.state.activeDate.add({ + months: this.store.state.viewMode.value, + }) + break + } + case 'week': { + nextDate = this.store.state.activeDate.add({ + weeks: this.store.state.viewMode.value, + }) + break + } + case 'day': { + nextDate = this.store.state.activeDate.add({ + days: this.store.state.viewMode.value, + }) + break + } + case 'workWeek': { + nextDate = this.store.state.activeDate.add({ days: 5 }) + break + } + } + + return isDateInRange({ date: nextDate, range: this.options.range }) + } +} diff --git a/packages/time/src/calendar/generateDateRange.ts b/packages/time/src/calendar/generateDateRange.ts new file mode 100644 index 00000000..9315b34b --- /dev/null +++ b/packages/time/src/calendar/generateDateRange.ts @@ -0,0 +1,16 @@ +import { Temporal } from '@js-temporal/polyfill' + +export const generateDateRange = ( + start: string, + end: string, +): Array => { + const startDate = Temporal.PlainDate.from(start) + const endDate = Temporal.PlainDate.from(end) + const dates: Array = [] + let current = startDate + while (Temporal.PlainDate.compare(current, endDate) <= 0) { + dates.push(current) + current = current.add({ days: 1 }) + } + return dates +} diff --git a/packages/time/src/calendar/getEventProps.ts b/packages/time/src/calendar/getEventProps.ts new file mode 100644 index 00000000..c867977d --- /dev/null +++ b/packages/time/src/calendar/getEventProps.ts @@ -0,0 +1,46 @@ +import { Temporal } from '@js-temporal/polyfill' +import type { CalendarStore, Event } from './types' + +export const getEventProps = ( + eventMap: Map>, + id: Event['id'], + state: CalendarStore, +) => { + const event = [...eventMap.values()] + .flat() + .find((currEvent) => currEvent.id === id) + if (!event) return null + + const eventStartDate = Temporal.ZonedDateTime.from(event.start) + const eventEndDate = Temporal.ZonedDateTime.from(event.end) + const isSplitEvent = + Temporal.PlainDate.compare( + eventStartDate.toPlainDate(), + eventEndDate.toPlainDate(), + ) !== 0 + + const overlappingEvents = [...eventMap.values()].flat().filter((e) => { + const eStartDate = Temporal.ZonedDateTime.from(e.start) + const eEndDate = Temporal.ZonedDateTime.from(e.end) + return ( + e.id !== id && + ((Temporal.ZonedDateTime.compare(eventStartDate, eStartDate) >= 0 && + Temporal.ZonedDateTime.compare(eventStartDate, eEndDate) <= 0) || + (Temporal.ZonedDateTime.compare(eventEndDate, eStartDate) >= 0 && + Temporal.ZonedDateTime.compare(eventEndDate, eEndDate) <= 0) || + (Temporal.ZonedDateTime.compare(eStartDate, eventStartDate) >= 0 && + Temporal.ZonedDateTime.compare(eStartDate, eventEndDate) <= 0) || + (Temporal.ZonedDateTime.compare(eEndDate, eventStartDate) >= 0 && + Temporal.ZonedDateTime.compare(eEndDate, eventEndDate) <= 0)) + ) + }) + + if (state.viewMode.unit === 'week' || state.viewMode.unit === 'day') { + return { + isSplitEvent, + overlappingEvents, + } + } + + return null +} diff --git a/packages/time/src/calendar/getTimeSlots.ts b/packages/time/src/calendar/getTimeSlots.ts new file mode 100644 index 00000000..2cf54413 --- /dev/null +++ b/packages/time/src/calendar/getTimeSlots.ts @@ -0,0 +1,52 @@ +import type { TimeSlot } from './types' + +interface TimeSlotOptions { + /** Start hour (0-23). Default: 0 */ + startHour?: number + /** End hour (0-24). Default: 24 */ + endHour?: number + /** Interval in minutes. Default: 60 */ + interval?: number +} +/** + * Generates time slots for calendar day views. + * Returns an array of time slots with labels formatted according to the locale. + * + * @param locale - The locale to use for formatting time labels (BCP 47 format) + * @param options - Configuration options for time slots + * @returns Array of time slots with hour, minute, and formatted label + */ +export function getTimeSlots( + locale: Intl.UnicodeBCP47LocaleIdentifier, + options?: TimeSlotOptions, +): Array { + const { startHour = 0, endHour = 24, interval = 60 } = options ?? {} + + const slots: Array = [] + const totalMinutes = (endHour - startHour) * 60 + const numSlots = Math.floor(totalMinutes / interval) + + const formatter = new Intl.DateTimeFormat(locale, { + hour: 'numeric', + minute: '2-digit', + }) + + for (let i = 0; i < numSlots; i++) { + const totalMinutesFromStart = startHour * 60 + i * interval + const hour = Math.floor(totalMinutesFromStart / 60) + const minute = totalMinutesFromStart % 60 + + if (hour >= 24) break + + const date = new Date(2024, 0, 1, hour, minute) + const label = formatter.format(date) + + slots.push({ + hour, + minute, + label, + }) + } + + return slots +} diff --git a/packages/time/src/calendar/groupDaysBy.ts b/packages/time/src/calendar/groupDaysBy.ts new file mode 100644 index 00000000..1fe9fb49 --- /dev/null +++ b/packages/time/src/calendar/groupDaysBy.ts @@ -0,0 +1,171 @@ +import { Temporal } from '@js-temporal/polyfill' +import type { Day, Event, Resource } from './types' + +interface GroupDaysByBaseProps< + TResource extends Resource, + TEvent extends Event = Event, +> { + days: Array | null> + weekStartsOn: number + locale: string +} + +type GroupDaysByMonthProps< + TResource extends Resource, + TEvent extends Event = Event, +> = GroupDaysByBaseProps & { + unit: 'month' + fillMissingDays?: never +} + +type GroupDaysByWeekProps< + TResource extends Resource, + TEvent extends Event = Event, +> = GroupDaysByBaseProps & { + unit: 'week' | 'workWeek' + fillMissingDays?: boolean +} + +export type GroupDaysByProps< + TResource extends Resource, + TEvent extends Event = Event, +> = + | GroupDaysByMonthProps + | GroupDaysByWeekProps + +export const groupDaysBy = < + TResource extends Resource, + TEvent extends Event = Event, +>({ + days, + unit, + fillMissingDays = true, + weekStartsOn, + locale, +}: GroupDaysByProps): Array | null>> => { + const groups: Array | null>> = [] + const loc = new Intl.Locale(locale) + const { weekend } = loc.getWeekInfo() + + switch (unit) { + case 'week': { + const weeks: Array | null>> = [] + let currentWeek: Array | null> = [] + + days.forEach((day) => { + if (currentWeek.length === 0 && day?.date.dayOfWeek !== weekStartsOn) { + if (day) { + const dayOfWeek = (day.date.dayOfWeek - weekStartsOn + 7) % 7 + for (let i = 0; i < dayOfWeek; i++) { + currentWeek.push( + fillMissingDays + ? { + date: day.date.subtract({ days: dayOfWeek - i }), + events: [], + isToday: false, + isInCurrentPeriod: false, + } + : null, + ) + } + } + } + currentWeek.push(day) + if (currentWeek.length === 7) { + weeks.push(currentWeek) + currentWeek = [] + } + }) + + if (currentWeek.length > 0) { + while (currentWeek.length < 7) { + const lastDate = + currentWeek[currentWeek.length - 1]?.date ?? + Temporal.PlainDate.from('2024-01-01') + currentWeek.push( + fillMissingDays + ? { + date: lastDate.add({ days: 1 }), + events: [], + isToday: false, + isInCurrentPeriod: false, + } + : null, + ) + } + weeks.push(currentWeek) + } + + return weeks + } + + case 'workWeek': { + const workWeeks: Array | null>> = [] + let currentWorkWeek: Array | null> = [] + + days.forEach((day) => { + if ( + currentWorkWeek.length === 0 && + day?.date.dayOfWeek !== weekStartsOn + ) { + if (day) { + const dayOfWeek = (day.date.dayOfWeek - weekStartsOn + 7) % 7 + for (let i = 0; i < dayOfWeek; i++) { + const newDay = day.date.subtract({ days: dayOfWeek - i }) + if (!weekend.includes(newDay.dayOfWeek)) { + currentWorkWeek.push( + fillMissingDays + ? { + date: newDay, + events: [], + isToday: false, + isInCurrentPeriod: false, + } + : null, + ) + } + } + } + } + if (day && !weekend.includes(day.date.dayOfWeek)) { + currentWorkWeek.push(day) + } + if (currentWorkWeek.length === 5) { + workWeeks.push(currentWorkWeek) + currentWorkWeek = [] + } + }) + + if (currentWorkWeek.length > 0) { + while (currentWorkWeek.length < 5) { + const lastDate = + currentWorkWeek[currentWorkWeek.length - 1]?.date ?? + Temporal.PlainDate.from('2024-01-01') + const nextDate = lastDate.add({ days: 1 }) + if (!weekend.includes(nextDate.dayOfWeek)) { + currentWorkWeek.push( + fillMissingDays + ? { + date: nextDate, + events: [], + isToday: false, + isInCurrentPeriod: false, + } + : null, + ) + } + } + workWeeks.push(currentWorkWeek) + } + + return workWeeks + } + + default: + break + } + return groups +} diff --git a/packages/time/src/calendar/index.ts b/packages/time/src/calendar/index.ts new file mode 100644 index 00000000..ad8807f3 --- /dev/null +++ b/packages/time/src/calendar/index.ts @@ -0,0 +1,7 @@ +export * from './types' +export * from './splitMultiDayEvents' +export * from './generateDateRange' +export * from './getEventProps' +export * from './groupDaysBy' +export * from './getTimeSlots' +export * from './calendar' diff --git a/packages/time/src/calendar/splitMultiDayEvents.ts b/packages/time/src/calendar/splitMultiDayEvents.ts new file mode 100644 index 00000000..d4c2516a --- /dev/null +++ b/packages/time/src/calendar/splitMultiDayEvents.ts @@ -0,0 +1,44 @@ +import { Temporal } from '@js-temporal/polyfill' +import type { Event, Resource } from './types' +import { endOf, startOf } from '~/date' + +export const splitMultiDayEvents = < + TResource extends Resource = Resource, + TEvent extends Event = Event, +>( + event: TEvent, + timeZone: Temporal.TimeZoneLike, +): Array => { + const startDate = Temporal.PlainDateTime.from(event.start).toZonedDateTime( + timeZone, + ) + const endDate = Temporal.PlainDateTime.from(event.end).toZonedDateTime( + timeZone, + ) + const events: Array = [] + + let currentDay = startDate + while (Temporal.ZonedDateTime.compare(currentDay, endDate) < 0) { + const startOfDay = startOf(currentDay, { unit: 'day' }).asZonedDateTime() + const endOfDay = endOf(currentDay, { unit: 'day' }).asZonedDateTime() + + const eventStart = + Temporal.ZonedDateTime.compare(currentDay, startDate) === 0 + ? startDate + : startOfDay + const eventEnd = + Temporal.ZonedDateTime.compare(endDate, endOfDay) < 0 + ? endDate + : endOfDay + + events.push({ + ...event, + start: eventStart.toString(), + end: eventEnd.toString(), + }) + + currentDay = startOfDay.add({ days: 1 }) + } + + return events +} diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts new file mode 100644 index 00000000..943b57b4 --- /dev/null +++ b/packages/time/src/calendar/types.ts @@ -0,0 +1,47 @@ +import type { Temporal } from '@js-temporal/polyfill' +import type { DateInput } from '~/date' + +export interface Resource { + id: string + label: string +} + +/** + * Represents the configuration for the current viewing mode of a calendar, + * specifying the scale and unit of time. + */ +export interface ViewMode { + /** The number of units for the view mode. */ + value: number + /** The unit of time that the calendar view should display (month, week, workWeek or day). */ + unit: 'month' | 'week' | 'day' | 'workWeek' +} + +export interface Event { + id: string + start: string + end: string + title: string + resources?: Array +} + +export type Day< + TResource extends Resource = Resource, + TEvent extends Event = Event, +> = { + date: Temporal.PlainDate + events: Array + isToday: boolean + isInCurrentPeriod: boolean +} + +export interface DateRange { + start: DateInput | null + end: DateInput | null +} + +export interface TimeSlot { + hour: number + minute: number + label: string +} diff --git a/packages/time/src/date/isWeekend/isWeekend.ts b/packages/time/src/date/isWeekend/isWeekend.ts index 0807b9bd..79eac65d 100644 --- a/packages/time/src/date/isWeekend/isWeekend.ts +++ b/packages/time/src/date/isWeekend/isWeekend.ts @@ -1,4 +1,4 @@ -import '../../polyfills/getWeekInfo' + import type { DateInput, DateOptions } from '../types' import { toZonedDateTime } from '~/date/helpers' import { getDateTimeDefaults } from '~/utils' diff --git a/packages/time/src/index.ts b/packages/time/src/index.ts index edf1e3ce..61005c71 100644 --- a/packages/time/src/index.ts +++ b/packages/time/src/index.ts @@ -1 +1,2 @@ export * from './date' +export * from './calendar' diff --git a/packages/time/src/utils/dateRange.ts b/packages/time/src/utils/dateRange.ts index 7de79feb..6361964e 100644 --- a/packages/time/src/utils/dateRange.ts +++ b/packages/time/src/utils/dateRange.ts @@ -1,6 +1,6 @@ import { Temporal } from '@js-temporal/polyfill' -import type { DateRange } from '../date/calendar/types' import type { DateInput } from '../date/types' +import type { DateRange } from '../calendar/types' export interface ParsedDateRange { start: Temporal.PlainDate | null diff --git a/packages/time/src/utils/weekUtils.ts b/packages/time/src/utils/weekUtils.ts index 3eff39fd..1ca081ab 100644 --- a/packages/time/src/utils/weekUtils.ts +++ b/packages/time/src/utils/weekUtils.ts @@ -1,5 +1,4 @@ import { Temporal } from '@js-temporal/polyfill' -import '@bart-krakowski/get-week-info-polyfill' /** * Get the first day of the month for a given year-month string @@ -23,6 +22,8 @@ export function getFirstDayOfWeek( const weekInfo = new Intl.Locale(locale).getWeekInfo() const firstDayOfWeek = weekInfo.firstDay + console.log('locale', locale) + const dayOfWeek = date.dayOfWeek const daysToSubtract = (dayOfWeek - firstDayOfWeek + 7) % 7 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ec318d2f..63e4ec60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,13 +102,22 @@ importers: version: 19.2.3(@types/react@19.2.8) '@vitejs/plugin-react': specifier: ^5.1.2 - version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2)) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.23(postcss@8.5.6) + postcss: + specifier: ^8.4.49 + version: 8.5.6 + tailwindcss: + specifier: ^3.4.17 + version: 3.4.19(yaml@2.8.2) typescript: specifier: 5.9.3 version: 5.9.3 vite: specifier: ^7.3.1 - version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + version: 7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2) packages/react-time: dependencies: @@ -221,6 +230,10 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@babel/code-frame@7.28.6': resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} engines: {node: '>=6.9.0'} @@ -1581,6 +1594,16 @@ packages: resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} engines: {node: '>=14'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -1609,6 +1632,13 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.4.23: + resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + axios@1.13.2: resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} @@ -1644,6 +1674,10 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + birecord@0.1.1: resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} @@ -1686,6 +1720,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + caniuse-lite@1.0.30001764: resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} @@ -1707,6 +1745,10 @@ packages: resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} engines: {node: '>=20.18.1'} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -1742,6 +1784,10 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + comment-parser@1.4.4: resolution: {integrity: sha512-0D6qSQ5IkeRrGJFHRClzaMOenMeT0gErz3zIw3AprKMqhRN6LNU2jQOdkPG/FZ+8bCgXE1VidrgSzlBBDZRr8A==} engines: {node: '>= 12.0.0'} @@ -1769,6 +1815,11 @@ packages: css.escape@1.5.1: resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -1812,10 +1863,16 @@ packages: devalue@5.6.2: resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -2176,6 +2233,9 @@ packages: engines: {node: '>=18.3.0'} hasBin: true + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + front-matter@4.0.2: resolution: {integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==} @@ -2331,6 +2391,14 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -2392,6 +2460,10 @@ packages: resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -2450,6 +2522,13 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lines-and-columns@2.0.3: resolution: {integrity: sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2563,6 +2642,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -2591,6 +2673,10 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -2610,6 +2696,14 @@ packages: '@swc/core': optional: true + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} @@ -2693,6 +2787,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -2711,10 +2808,61 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -2796,6 +2944,9 @@ packages: resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} engines: {node: '>=0.10.0'} + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} @@ -2804,6 +2955,10 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -2827,6 +2982,11 @@ packages: resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} engines: {node: '>=10'} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -3032,14 +3192,28 @@ packages: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + svelte@5.46.4: resolution: {integrity: sha512-VJwdXrmv9L8L7ZasJeWcCjoIuMRVbhuxbss0fpVnR8yorMmjNDwcjIH08vS6wmSzzzgAG5CADQ1JuXPS2nwt9w==} engines: {node: '>=18'} + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} + engines: {node: '>=14.0.0'} + hasBin: true + tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} @@ -3052,6 +3226,13 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -3093,6 +3274,9 @@ packages: peerDependencies: typescript: '>=4.0.0' + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-pattern@5.9.0: resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} @@ -3418,6 +3602,8 @@ snapshots: '@adobe/css-tools@4.4.4': {} + '@alloc/quick-lru@5.2.0': {} + '@babel/code-frame@7.28.6': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -4668,6 +4854,18 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2))': + dependencies: + '@babel/core': 7.28.6 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.6) + '@rolldown/pluginutils': 1.0.0-beta.53 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2))': dependencies: '@babel/core': 7.28.6 @@ -4755,6 +4953,15 @@ snapshots: ansis@4.2.0: {} + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 @@ -4778,6 +4985,15 @@ snapshots: asynckit@0.4.0: {} + autoprefixer@10.4.23(postcss@8.5.6): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001764 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + axios@1.13.2: dependencies: follow-redirects: 1.15.11 @@ -4814,6 +5030,8 @@ snapshots: dependencies: is-windows: 1.0.2 + binary-extensions@2.3.0: {} + birecord@0.1.1: {} birpc@4.0.0: {} @@ -4861,6 +5079,8 @@ snapshots: callsites@3.1.0: {} + camelcase-css@2.0.1: {} + caniuse-lite@1.0.30001764: {} chai@6.2.2: {} @@ -4895,6 +5115,18 @@ snapshots: undici: 7.18.2 whatwg-mimetype: 4.0.0 + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + ci-info@3.9.0: {} cli-cursor@3.1.0: @@ -4923,6 +5155,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + commander@4.1.1: {} + comment-parser@1.4.4: {} compare-versions@6.1.1: {} @@ -4949,6 +5183,8 @@ snapshots: css.escape@1.5.1: {} + cssesc@3.0.0: {} + csstype@3.2.3: {} dataloader@1.4.0: {} @@ -4975,10 +5211,14 @@ snapshots: devalue@5.6.2: {} + didyoumean@1.2.2: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 + dlv@1.1.3: {} + dom-accessibility-api@0.5.16: {} dom-accessibility-api@0.6.3: {} @@ -5440,6 +5680,8 @@ snapshots: dependencies: fd-package-json: 2.0.0 + fraction.js@5.3.4: {} + front-matter@4.0.2: dependencies: js-yaml: 3.14.2 @@ -5591,6 +5833,14 @@ snapshots: inherits@2.0.4: {} + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + is-docker@2.2.1: {} is-extglob@2.1.1: {} @@ -5642,6 +5892,8 @@ snapshots: chalk: 4.1.2 pretty-format: 30.2.0 + jiti@1.21.7: {} + jiti@2.6.1: {} js-tokens@4.0.0: {} @@ -5699,6 +5951,10 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + lines-and-columns@2.0.3: {} linkify-it@5.0.0: @@ -5799,6 +6055,12 @@ snapshots: ms@2.1.3: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nanoid@3.3.11: {} napi-postinstall@0.3.4: {} @@ -5813,6 +6075,8 @@ snapshots: node-releases@2.0.27: {} + normalize-path@3.0.0: {} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 @@ -5872,6 +6136,10 @@ snapshots: transitivePeerDependencies: - debug + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + obug@2.1.1: {} once@1.4.0: @@ -5984,6 +6252,8 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + path-type@4.0.0: {} pathe@2.0.3: {} @@ -5994,8 +6264,44 @@ snapshots: picomatch@4.0.3: {} + pify@2.3.0: {} + pify@4.0.1: {} + pirates@4.0.7: {} + + postcss-import@15.1.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.11 + + postcss-js@4.1.0(postcss@8.5.6): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.6 + + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 1.21.7 + postcss: 8.5.6 + yaml: 2.8.2 + + postcss-nested@6.2.0(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 6.1.2 + + postcss-selector-parser@6.1.2: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -6059,6 +6365,10 @@ snapshots: react@19.2.3: {} + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 @@ -6072,6 +6382,10 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -6087,6 +6401,12 @@ snapshots: resolve.exports@2.0.3: {} + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -6310,10 +6630,22 @@ snapshots: strip-json-comments@5.0.3: {} + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.15 + ts-interface-checker: 0.1.13 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + svelte@5.46.4: dependencies: '@jridgewell/remapping': 2.3.5 @@ -6332,6 +6664,34 @@ snapshots: magic-string: 0.30.21 zimmerframe: 1.1.4 + tailwindcss@3.4.19(yaml@2.8.2): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-import: 15.1.0(postcss@8.5.6) + postcss-js: 4.1.0(postcss@8.5.6) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.8.2) + postcss-nested: 6.2.0(postcss@8.5.6) + postcss-selector-parser: 6.1.2 + resolve: 1.22.11 + sucrase: 3.35.1 + transitivePeerDependencies: + - tsx + - yaml + tapable@2.3.0: {} tar-stream@2.2.0: @@ -6344,6 +6704,14 @@ snapshots: term-size@2.2.1: {} + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + tinybench@2.9.0: {} tinyexec@1.0.2: {} @@ -6374,6 +6742,8 @@ snapshots: picomatch: 4.0.3 typescript: 5.9.3 + ts-interface-checker@0.1.13: {} + ts-pattern@5.9.0: {} tsconfig-paths@4.2.0: @@ -6521,6 +6891,20 @@ snapshots: transitivePeerDependencies: - supports-color + vite@7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2): + dependencies: + esbuild: 0.27.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.55.1 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.0.9 + fsevents: 2.3.3 + jiti: 1.21.7 + yaml: 2.8.2 + vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2): dependencies: esbuild: 0.27.2 From 00186b8419b4b40fdfd92c3210ea13b050305227 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 25 Jan 2026 21:15:10 +0000 Subject: [PATCH 035/207] ci: apply automated fixes --- .../react/reference/functions/useCalendar.md | 32 +++ docs/framework/react/reference/index.md | 4 + examples/react/basic/src/index.tsx | 235 ++++++++++-------- packages/react-time/src/useCalendar/index.ts | 2 +- packages/time/src/calendar/calendar.ts | 28 +-- packages/time/src/calendar/date-core.ts | 9 +- packages/time/src/calendar/groupDaysBy.ts | 7 +- .../time/src/calendar/splitMultiDayEvents.ts | 4 +- packages/time/src/date/isWeekend/isWeekend.ts | 1 - 9 files changed, 196 insertions(+), 126 deletions(-) create mode 100644 docs/framework/react/reference/functions/useCalendar.md diff --git a/docs/framework/react/reference/functions/useCalendar.md b/docs/framework/react/reference/functions/useCalendar.md new file mode 100644 index 00000000..6eea9c71 --- /dev/null +++ b/docs/framework/react/reference/functions/useCalendar.md @@ -0,0 +1,32 @@ +--- +id: useCalendar +title: useCalendar +--- + +# Function: useCalendar() + +```ts +function useCalendar(options): CalendarApi & object; +``` + +Defined in: [useCalendar.ts:11](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L11) + +## Type Parameters + +### TResource + +`TResource` *extends* `Resource` + +### TEvent + +`TEvent` *extends* `Event`\<`TResource`\> = `Event`\<`TResource`\> + +## Parameters + +### options + +`CalendarCoreOptions`\<`TResource`, `TEvent`\> + +## Returns + +`CalendarApi`\<`TResource`, `TEvent`\> & `object` diff --git a/docs/framework/react/reference/index.md b/docs/framework/react/reference/index.md index 6e5811a0..51ff3a03 100644 --- a/docs/framework/react/reference/index.md +++ b/docs/framework/react/reference/index.md @@ -4,3 +4,7 @@ title: "@tanstack/react-time" --- # @tanstack/react-time + +## Functions + +- [useCalendar](functions/useCalendar.md) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index b2371c27..db4f16fa 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -69,7 +69,10 @@ function getSampleEvents(): Array> { const sampleEvents = getSampleEvents() -function parseEventTime(event: Event): { hour: number; minute: number } { +function parseEventTime(event: Event): { + hour: number + minute: number +} { const [_datePart, timePart] = event.start.split('T') if (!timePart) return { hour: 0, minute: 0 } const [hour, minute] = timePart.split(':').map(Number) @@ -89,7 +92,11 @@ function ScheduleView({ calendar: ReturnType>> days: Array>> }) { - const timeSlots = calendar.getTimeSlots({ startHour: 0, endHour: 24, interval: 60 }) + const timeSlots = calendar.getTimeSlots({ + startHour: 0, + endHour: 24, + interval: 60, + }) const slotHeight = 60 const getEventPosition = (event: Event) => { @@ -114,53 +121,67 @@ function ScheduleView({ ))}
-
+
{days.map((day) => { - const dayName = new Intl.DateTimeFormat('en-US', { weekday: 'short' }).format( - new Date(day.date.year, day.date.month - 1, day.date.day) + const dayName = new Intl.DateTimeFormat('en-US', { + weekday: 'short', + }).format( + new Date(day.date.year, day.date.month - 1, day.date.day), ) return ( -
-
-
- {dayName} +
+
+
+ {dayName} +
+
{day.date.day}
+
+
+ {day.events.map((event) => { + const { top, height } = getEventPosition(event) + return ( +
+
{event.title}
+ {height > 30 && ( +
+ {new Date(event.start).toLocaleTimeString( + 'en-US', + { + hour: 'numeric', + minute: '2-digit', + }, + )} + {' - '} + {new Date(event.end).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit', + })} +
+ )} +
+ ) + })}
-
{day.date.day}
-
-
- {day.events.map((event) => { - const { top, height } = getEventPosition(event) - return ( -
-
{event.title}
- {height > 30 && ( -
- {new Date(event.start).toLocaleTimeString('en-US', { - hour: 'numeric', - minute: '2-digit', - })} - {' - '} - {new Date(event.end).toLocaleTimeString('en-US', { - hour: 'numeric', - minute: '2-digit', - })} -
- )} -
- ) - })}
-
) })}
@@ -171,7 +192,6 @@ function ScheduleView({ } function CalendarView() { - const calendar = useCalendar>({ viewMode: { value: 1, unit: 'month' }, events: sampleEvents, @@ -186,7 +206,8 @@ function CalendarView() { fillMissingDays: true, }) - const isScheduleView = calendar.viewMode.unit === 'week' || calendar.viewMode.unit === 'day' + const isScheduleView = + calendar.viewMode.unit === 'week' || calendar.viewMode.unit === 'day' const scheduleDays: Array>> = isScheduleView ? calendar.viewMode.unit === 'day' ? calendar.days.filter((day) => { @@ -220,7 +241,9 @@ function CalendarView() { onClick={calendar.goToCurrentPeriod} disabled={calendar.isPending} className={`px-4 py-2 border border-gray-300 rounded-md bg-white ${ - calendar.isPending ? 'cursor-not-allowed opacity-50' : 'cursor-pointer opacity-100' + calendar.isPending + ? 'cursor-not-allowed opacity-50' + : 'cursor-pointer opacity-100' }`} > Today @@ -240,7 +263,9 @@ function CalendarView() {
+ )} +
+
+ + +
+
+ +
+
+ ) +} + function ScheduleView({ calendar, days, + onEventClick, }: { calendar: ReturnType>> days: Array>> + onEventClick: (event: Event) => void }) { const timeSlots = calendar.getTimeSlots() @@ -122,9 +284,10 @@ function ScheduleView({ return (
onEventClick(event)} >
{event.title}
{style && parseFloat(style.height) > 2 && ( @@ -161,10 +324,20 @@ function ScheduleView({ } function CalendarView() { + const [modalState, setModalState] = useState<{ + isOpen: boolean + mode: 'add' | 'edit' + eventId?: string + initialData: EventFormData + }>({ + isOpen: false, + mode: 'add', + initialData: emptyFormData, + }) + const calendar = useCalendar>({ viewMode: { value: 1, unit: 'month' }, events: sampleEvents, - timeZone: 'UTC', }) @@ -186,6 +359,58 @@ function CalendarView() { : calendar.days : [] + const openAddModal = () => { + setModalState({ + isOpen: true, + mode: 'add', + initialData: emptyFormData, + }) + } + + const openEditModal = (event: Event) => { + const eventProps = calendar.getEventProps(event) + const startDate = new Date(eventProps.start) + const endDate = new Date(eventProps.end) + + setModalState({ + isOpen: true, + mode: 'edit', + eventId: event.id, + initialData: { + title: event.title, + startDate: formatDateToISO(startDate), + startTime: startDate.toTimeString().slice(0, 5), + endDate: formatDateToISO(endDate), + endTime: endDate.toTimeString().slice(0, 5), + }, + }) + } + + const closeModal = () => { + setModalState((prev) => ({ ...prev, isOpen: false })) + } + + const handleSave = (data: EventFormData) => { + const eventData = { + title: data.title, + start: `${data.startDate}T${data.startTime}:00`, + end: `${data.endDate}T${data.endTime}:00`, + } + + if (modalState.mode === 'add') { + const newId = String(Date.now()) + calendar.addEvent({ id: newId, ...eventData }) + } else if (modalState.eventId) { + calendar.updateEvent(modalState.eventId, eventData) + } + } + + const handleDelete = () => { + if (modalState.eventId) { + calendar.removeEvent(modalState.eventId) + } + } + return (
@@ -230,6 +455,13 @@ function CalendarView() { Next → + +
{isScheduleView ? ( - + ) : (
(
openEditModal(event)} > {event.title}
@@ -377,6 +614,15 @@ function CalendarView() { Loading...
)} + +
) } diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 5fd2db9d..178b64e4 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -96,6 +96,21 @@ export const useCalendar = < [calendarCore], ) + const addEvent = useCallback( + (event) => calendarCore.addEvent(event), + [calendarCore], + ) + + const updateEvent = useCallback( + (id, updates) => calendarCore.updateEvent(id, updates), + [calendarCore], + ) + + const removeEvent = useCallback( + (id) => calendarCore.removeEvent(id), + [calendarCore], + ) + return { activeDate: state.activeDate.toString(), currentPeriod: state.currentPeriod.toString(), @@ -112,6 +127,9 @@ export const useCalendar = < canGoNextPeriod, changeViewMode, getEventProps, + addEvent, + updateEvent, + removeEvent, isPending, groupDaysBy, } diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index 58955690..eedd3bc0 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -81,6 +81,12 @@ interface CalendarActions< ) => Array /** Retrieves events for a specific date. */ getEventsByDate: (date: string) => Array + /** Adds a new event to the calendar. */ + addEvent: (event: TEvent) => void + /** Updates an existing event by ID. */ + updateEvent: (id: Event['id'], updates: Partial>) => void + /** Removes an event by ID. */ + removeEvent: (id: Event['id']) => void } interface CalendarState< @@ -232,4 +238,30 @@ export class CalendarCore< const eventMap = this.getEventMap() return eventMap.get(targetDate) ?? [] } + + addEvent(event: TEvent): void { + if (!this.options.events) { + this.options.events = [] + } + this.options.events.push(event) + } + + updateEvent(id: Event['id'], updates: Partial>): void { + if (!this.options.events) return + + const index = this.options.events.findIndex((e) => e.id === id) + if (index === -1) return + + const existingEvent = this.options.events[index] + this.options.events[index] = { ...existingEvent, ...updates } as TEvent + } + + removeEvent(id: Event['id']): void { + if (!this.options.events) return + + const index = this.options.events.findIndex((e) => e.id === id) + if (index === -1) return + + this.options.events.splice(index, 1) + } } diff --git a/packages/time/src/calendar/date-core.ts b/packages/time/src/calendar/date-core.ts index ee74ece6..4b806e39 100644 --- a/packages/time/src/calendar/date-core.ts +++ b/packages/time/src/calendar/date-core.ts @@ -203,30 +203,41 @@ export abstract class DateCore { } const allDays = generateDateRange(start.toString(), end.toString()) - const startMonthDate = this.store.state.currentPeriod.with({ day: 1 }) - const endMonthDate = this.store.state.currentPeriod - .add({ - months: this.store.state.viewMode.value - 1, - }) - .with({ - day: Temporal.PlainDate.from( - this.store.state.currentPeriod.toString({ calendarName: 'auto' }), - ).daysInMonth, - }) - - const filteredDays = allDays.filter( - (day) => - Temporal.PlainDate.compare(day, startMonthDate) >= 0 && - Temporal.PlainDate.compare(day, endMonthDate) <= 0, - ) + + if (this.store.state.viewMode.unit === 'month') { + const startMonthDate = this.store.state.currentPeriod.with({ day: 1 }) + const endMonthDate = this.store.state.currentPeriod + .add({ + months: this.store.state.viewMode.value - 1, + }) + .with({ + day: Temporal.PlainDate.from( + this.store.state.currentPeriod.toString({ calendarName: 'auto' }), + ).daysInMonth, + }) + + const filteredDays = allDays.filter( + (day) => + Temporal.PlainDate.compare(day, startMonthDate) >= 0 && + Temporal.PlainDate.compare(day, endMonthDate) <= 0, + ) + + if (this.options.range.start || this.options.range.end) { + return filteredDays.filter((day) => + isDateInRange({ date: day, range: this.options.range }), + ) + } + + return filteredDays + } if (this.options.range.start || this.options.range.end) { - return filteredDays.filter((day) => + return allDays.filter((day) => isDateInRange({ date: day, range: this.options.range }), ) } - return filteredDays + return allDays } getDaysNames(weekday: 'long' | 'short' = 'short') { diff --git a/packages/time/src/calendar/getEventProps.ts b/packages/time/src/calendar/getEventProps.ts index 8fb7779c..bd3b7c2a 100644 --- a/packages/time/src/calendar/getEventProps.ts +++ b/packages/time/src/calendar/getEventProps.ts @@ -92,13 +92,15 @@ export const getEventProps = ( const eventIndex = overlappingCount > 0 - ? overlappingEvents.filter( - (e) => - Temporal.ZonedDateTime.compare( - toZonedDateTime(e.start, timeZone), - segmentStart, - ) < 0, - ).length + ? overlappingEvents.filter((e) => { + const eStart = toZonedDateTime(e.start, timeZone) + const comparison = Temporal.ZonedDateTime.compare( + eStart, + segmentStart, + ) + if (comparison !== 0) return comparison < 0 + return e.id < event.id + }).length : 0 return { From 3f223b330c1f6eb7fc54df8f4fd87c7f5490d9e7 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 09:30:10 +0000 Subject: [PATCH 039/207] ci: apply automated fixes --- docs/reference/classes/CalendarCore.md | 742 ++++++++++++++++++ docs/reference/classes/DateCore.md | 326 ++++++++ docs/reference/functions/add.md | 89 +++ docs/reference/functions/endOf.md | 89 +++ docs/reference/functions/equals.md | 41 + docs/reference/functions/format.md | 33 + docs/reference/functions/generateDateRange.md | 26 + docs/reference/functions/getEventProps.md | 73 ++ docs/reference/functions/getTimeSlots.md | 35 + docs/reference/functions/groupDaysBy.md | 32 + docs/reference/functions/intersects.md | 33 + docs/reference/functions/isAfter.md | 36 + docs/reference/functions/isBefore.md | 36 + docs/reference/functions/isBetween.md | 33 + docs/reference/functions/isLeapYear.md | 29 + docs/reference/functions/isSameOrAfter.md | 36 + docs/reference/functions/isSameOrBefore.md | 36 + docs/reference/functions/isWeekend.md | 29 + docs/reference/functions/range.md | 26 + docs/reference/functions/round.md | 89 +++ docs/reference/functions/since.md | 37 + .../functions/splitMultiDayEvents.md | 36 + docs/reference/functions/startOf.md | 89 +++ docs/reference/functions/subtract.md | 89 +++ docs/reference/functions/until.md | 36 + docs/reference/index.md | 84 ++ docs/reference/interfaces/AddOptions.md | 70 ++ docs/reference/interfaces/CalendarApi.md | 552 +++++++++++++ .../interfaces/CalendarCoreOptions.md | 179 +++++ docs/reference/interfaces/CalendarStore.md | 38 + docs/reference/interfaces/DateCoreOptions.md | 110 +++ docs/reference/interfaces/DateOptions.md | 43 + docs/reference/interfaces/DateRange.md | 28 + docs/reference/interfaces/EndOfOptions.md | 70 ++ docs/reference/interfaces/EqualsOptions.md | 40 + docs/reference/interfaces/Event.md | 64 ++ .../reference/interfaces/FormatDateOptions.md | 74 ++ .../reference/interfaces/IntersectsOptions.md | 50 ++ docs/reference/interfaces/IsAfterOptions.md | 40 + docs/reference/interfaces/IsBeforeOptions.md | 40 + docs/reference/interfaces/IsBetweenOptions.md | 60 ++ .../reference/interfaces/IsLeapYearOptions.md | 40 + .../interfaces/IsSameOrAfterOptions.md | 50 ++ .../interfaces/IsSameOrBeforeOptions.md | 50 ++ docs/reference/interfaces/IsWeekendOptions.md | 50 ++ .../interfaces/ParsedDateCoreOptions.md | 86 ++ docs/reference/interfaces/Range.md | 28 + docs/reference/interfaces/RangeOptions.md | 90 +++ docs/reference/interfaces/Resource.md | 28 + docs/reference/interfaces/RoundOptions.md | 90 +++ docs/reference/interfaces/SinceOptions.md | 50 ++ docs/reference/interfaces/StartOfOptions.md | 70 ++ docs/reference/interfaces/SubtractOptions.md | 70 ++ docs/reference/interfaces/TimeSlot.md | 38 + docs/reference/interfaces/UntilOptions.md | 50 ++ docs/reference/interfaces/ViewMode.md | 35 + docs/reference/type-aliases/DateInput.md | 12 + docs/reference/type-aliases/Day.md | 62 ++ docs/reference/type-aliases/DurationLike.md | 12 + docs/reference/type-aliases/EndOfUnit.md | 20 + docs/reference/type-aliases/EqualsUnit.md | 20 + docs/reference/type-aliases/FormatType.md | 12 + .../type-aliases/GroupDaysByProps.md | 24 + .../type-aliases/IsSameOrAfterUnit.md | 20 + .../type-aliases/IsSameOrBeforeUnit.md | 20 + docs/reference/type-aliases/RoundUnit.md | 19 + docs/reference/type-aliases/StartOfUnit.md | 20 + 67 files changed, 4764 insertions(+) create mode 100644 docs/reference/classes/CalendarCore.md create mode 100644 docs/reference/classes/DateCore.md create mode 100644 docs/reference/functions/add.md create mode 100644 docs/reference/functions/endOf.md create mode 100644 docs/reference/functions/equals.md create mode 100644 docs/reference/functions/format.md create mode 100644 docs/reference/functions/generateDateRange.md create mode 100644 docs/reference/functions/getEventProps.md create mode 100644 docs/reference/functions/getTimeSlots.md create mode 100644 docs/reference/functions/groupDaysBy.md create mode 100644 docs/reference/functions/intersects.md create mode 100644 docs/reference/functions/isAfter.md create mode 100644 docs/reference/functions/isBefore.md create mode 100644 docs/reference/functions/isBetween.md create mode 100644 docs/reference/functions/isLeapYear.md create mode 100644 docs/reference/functions/isSameOrAfter.md create mode 100644 docs/reference/functions/isSameOrBefore.md create mode 100644 docs/reference/functions/isWeekend.md create mode 100644 docs/reference/functions/range.md create mode 100644 docs/reference/functions/round.md create mode 100644 docs/reference/functions/since.md create mode 100644 docs/reference/functions/splitMultiDayEvents.md create mode 100644 docs/reference/functions/startOf.md create mode 100644 docs/reference/functions/subtract.md create mode 100644 docs/reference/functions/until.md create mode 100644 docs/reference/index.md create mode 100644 docs/reference/interfaces/AddOptions.md create mode 100644 docs/reference/interfaces/CalendarApi.md create mode 100644 docs/reference/interfaces/CalendarCoreOptions.md create mode 100644 docs/reference/interfaces/CalendarStore.md create mode 100644 docs/reference/interfaces/DateCoreOptions.md create mode 100644 docs/reference/interfaces/DateOptions.md create mode 100644 docs/reference/interfaces/DateRange.md create mode 100644 docs/reference/interfaces/EndOfOptions.md create mode 100644 docs/reference/interfaces/EqualsOptions.md create mode 100644 docs/reference/interfaces/Event.md create mode 100644 docs/reference/interfaces/FormatDateOptions.md create mode 100644 docs/reference/interfaces/IntersectsOptions.md create mode 100644 docs/reference/interfaces/IsAfterOptions.md create mode 100644 docs/reference/interfaces/IsBeforeOptions.md create mode 100644 docs/reference/interfaces/IsBetweenOptions.md create mode 100644 docs/reference/interfaces/IsLeapYearOptions.md create mode 100644 docs/reference/interfaces/IsSameOrAfterOptions.md create mode 100644 docs/reference/interfaces/IsSameOrBeforeOptions.md create mode 100644 docs/reference/interfaces/IsWeekendOptions.md create mode 100644 docs/reference/interfaces/ParsedDateCoreOptions.md create mode 100644 docs/reference/interfaces/Range.md create mode 100644 docs/reference/interfaces/RangeOptions.md create mode 100644 docs/reference/interfaces/Resource.md create mode 100644 docs/reference/interfaces/RoundOptions.md create mode 100644 docs/reference/interfaces/SinceOptions.md create mode 100644 docs/reference/interfaces/StartOfOptions.md create mode 100644 docs/reference/interfaces/SubtractOptions.md create mode 100644 docs/reference/interfaces/TimeSlot.md create mode 100644 docs/reference/interfaces/UntilOptions.md create mode 100644 docs/reference/interfaces/ViewMode.md create mode 100644 docs/reference/type-aliases/DateInput.md create mode 100644 docs/reference/type-aliases/Day.md create mode 100644 docs/reference/type-aliases/DurationLike.md create mode 100644 docs/reference/type-aliases/EndOfUnit.md create mode 100644 docs/reference/type-aliases/EqualsUnit.md create mode 100644 docs/reference/type-aliases/FormatType.md create mode 100644 docs/reference/type-aliases/GroupDaysByProps.md create mode 100644 docs/reference/type-aliases/IsSameOrAfterUnit.md create mode 100644 docs/reference/type-aliases/IsSameOrBeforeUnit.md create mode 100644 docs/reference/type-aliases/RoundUnit.md create mode 100644 docs/reference/type-aliases/StartOfUnit.md diff --git a/docs/reference/classes/CalendarCore.md b/docs/reference/classes/CalendarCore.md new file mode 100644 index 00000000..724b4d54 --- /dev/null +++ b/docs/reference/classes/CalendarCore.md @@ -0,0 +1,742 @@ +--- +id: CalendarCore +title: CalendarCore +--- + +# Class: CalendarCore\ + +Defined in: [calendar/calendar.ts:131](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L131) + +## Extends + +- [`DateCore`](DateCore.md) + +## Type Parameters + +### TResource + +`TResource` *extends* [`Resource`](../interfaces/Resource.md) + +### TEvent + +`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> + +## Implements + +- `CalendarActions`\<`TResource`, `TEvent`\> + +## Constructors + +### Constructor + +```ts +new CalendarCore(options): CalendarCore; +``` + +Defined in: [calendar/calendar.ts:140](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L140) + +#### Parameters + +##### options + +[`CalendarCoreOptions`](../interfaces/CalendarCoreOptions.md)\<`TResource`, `TEvent`\> + +#### Returns + +`CalendarCore`\<`TResource`, `TEvent`\> + +#### Overrides + +[`DateCore`](DateCore.md).[`constructor`](DateCore.md#constructor) + +## Properties + +### formatters + +```ts +formatters: object; +``` + +Defined in: [calendar/date-core.ts:80](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L80) + +#### date + +```ts +date: DateTimeFormat; +``` + +#### dateTime + +```ts +dateTime: DateTimeFormat; +``` + +#### time + +```ts +time: DateTimeFormat; +``` + +#### Inherited from + +[`DateCore`](DateCore.md).[`formatters`](DateCore.md#formatters) + +*** + +### options + +```ts +options: ParsedCalendarCoreOptions; +``` + +Defined in: [calendar/calendar.ts:138](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L138) + +#### Overrides + +[`DateCore`](DateCore.md).[`options`](DateCore.md#options) + +*** + +### store + +```ts +store: Store; +``` + +Defined in: [calendar/date-core.ts:78](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L78) + +#### Inherited from + +[`DateCore`](DateCore.md).[`store`](DateCore.md#store) + +## Methods + +### addEvent() + +```ts +addEvent(event): void; +``` + +Defined in: [calendar/calendar.ts:242](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L242) + +Adds a new event to the calendar. + +#### Parameters + +##### event + +`TEvent` + +#### Returns + +`void` + +#### Implementation of + +```ts +CalendarActions.addEvent +``` + +*** + +### canGoNextPeriod() + +```ts +canGoNextPeriod(): boolean; +``` + +Defined in: [calendar/date-core.ts:407](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L407) + +#### Returns + +`boolean` + +#### Implementation of + +```ts +CalendarActions.canGoNextPeriod +``` + +#### Inherited from + +[`DateCore`](DateCore.md).[`canGoNextPeriod`](DateCore.md#cangonextperiod) + +*** + +### canGoPreviousPeriod() + +```ts +canGoPreviousPeriod(): boolean; +``` + +Defined in: [calendar/date-core.ts:376](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L376) + +#### Returns + +`boolean` + +#### Implementation of + +```ts +CalendarActions.canGoPreviousPeriod +``` + +#### Inherited from + +[`DateCore`](DateCore.md).[`canGoPreviousPeriod`](DateCore.md#cangopreviousperiod) + +*** + +### changeViewMode() + +```ts +changeViewMode(newViewMode): void; +``` + +Defined in: [calendar/date-core.ts:254](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L254) + +#### Parameters + +##### newViewMode + +[`ViewMode`](../interfaces/ViewMode.md) + +#### Returns + +`void` + +#### Implementation of + +```ts +CalendarActions.changeViewMode +``` + +#### Inherited from + +[`DateCore`](DateCore.md).[`changeViewMode`](DateCore.md#changeviewmode) + +*** + +### formatDate() + +```ts +formatDate(date): string; +``` + +Defined in: [calendar/date-core.ts:130](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L130) + +#### Parameters + +##### date + +[`DateInput`](../type-aliases/DateInput.md) + +#### Returns + +`string` + +#### Inherited from + +[`DateCore`](DateCore.md).[`formatDate`](DateCore.md#formatdate) + +*** + +### formatDateTime() + +```ts +formatDateTime(date): string; +``` + +Defined in: [calendar/date-core.ts:138](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L138) + +#### Parameters + +##### date + +[`DateInput`](../type-aliases/DateInput.md) + +#### Returns + +`string` + +#### Inherited from + +[`DateCore`](DateCore.md).[`formatDateTime`](DateCore.md#formatdatetime) + +*** + +### formatTime() + +```ts +formatTime(date): string; +``` + +Defined in: [calendar/date-core.ts:134](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L134) + +#### Parameters + +##### date + +[`DateInput`](../type-aliases/DateInput.md) + +#### Returns + +`string` + +#### Inherited from + +[`DateCore`](DateCore.md).[`formatTime`](DateCore.md#formattime) + +*** + +### getCalendarDays() + +```ts +protected getCalendarDays(): PlainDate[]; +``` + +Defined in: [calendar/calendar.ts:148](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L148) + +#### Returns + +`PlainDate`[] + +#### Overrides + +[`DateCore`](DateCore.md).[`getCalendarDays`](DateCore.md#getcalendardays) + +*** + +### getDaysNames() + +```ts +getDaysNames(weekday): string[]; +``` + +Defined in: [calendar/date-core.ts:243](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L243) + +#### Parameters + +##### weekday + +`"long"` | `"short"` + +#### Returns + +`string`[] + +#### Implementation of + +```ts +CalendarActions.getDaysNames +``` + +#### Inherited from + +[`DateCore`](DateCore.md).[`getDaysNames`](DateCore.md#getdaysnames) + +*** + +### getDaysWithEvents() + +```ts +getDaysWithEvents(): object[]; +``` + +Defined in: [calendar/calendar.ts:185](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L185) + +#### Returns + +`object`[] + +*** + +### getEventProps() + +```ts +getEventProps(event): object; +``` + +Defined in: [calendar/calendar.ts:206](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L206) + +Retrieves styling properties for a specific event. + +#### Parameters + +##### event + +`TEvent` + +#### Returns + +`object` + +##### end + +```ts +end: string; +``` + +##### isSplitEvent + +```ts +isSplitEvent: boolean; +``` + +##### overlappingEvents + +```ts +overlappingEvents: TEvent[]; +``` + +##### start + +```ts +start: string; +``` + +##### style? + +```ts +optional style: object; +``` + +###### style.height + +```ts +height: string; +``` + +###### style.left + +```ts +left: string; +``` + +###### style.top + +```ts +top: string; +``` + +###### style.width + +```ts +width: string; +``` + +#### Implementation of + +```ts +CalendarActions.getEventProps +``` + +*** + +### getEventsByDate() + +```ts +getEventsByDate(date): TEvent[]; +``` + +Defined in: [calendar/calendar.ts:234](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L234) + +Retrieves events for a specific date. + +#### Parameters + +##### date + +`string` + +#### Returns + +`TEvent`[] + +#### Implementation of + +```ts +CalendarActions.getEventsByDate +``` + +*** + +### getFirstDayOfMonth() + +```ts +protected getFirstDayOfMonth(): PlainDate; +``` + +Defined in: [calendar/date-core.ts:142](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L142) + +#### Returns + +`PlainDate` + +#### Inherited from + +[`DateCore`](DateCore.md).[`getFirstDayOfMonth`](DateCore.md#getfirstdayofmonth) + +*** + +### getFirstDayOfWeek() + +```ts +protected getFirstDayOfWeek(): PlainDate; +``` + +Defined in: [calendar/date-core.ts:150](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L150) + +#### Returns + +`PlainDate` + +#### Inherited from + +[`DateCore`](DateCore.md).[`getFirstDayOfWeek`](DateCore.md#getfirstdayofweek) + +*** + +### getTimeSlots() + +```ts +getTimeSlots(options?): TimeSlot[]; +``` + +Defined in: [calendar/calendar.ts:230](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L230) + +Retrieves time slots for day view with configurable intervals. + +#### Parameters + +##### options? + +`TimeSlotOptions` + +#### Returns + +[`TimeSlot`](../interfaces/TimeSlot.md)[] + +#### Implementation of + +```ts +CalendarActions.getTimeSlots +``` + +*** + +### getWeekStartsOn() + +```ts +getWeekStartsOn(): number; +``` + +Defined in: [calendar/date-core.ts:157](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L157) + +#### Returns + +`number` + +#### Inherited from + +[`DateCore`](DateCore.md).[`getWeekStartsOn`](DateCore.md#getweekstartson) + +*** + +### goToCurrentPeriod() + +```ts +goToCurrentPeriod(): void; +``` + +Defined in: [calendar/date-core.ts:347](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L347) + +#### Returns + +`void` + +#### Implementation of + +```ts +CalendarActions.goToCurrentPeriod +``` + +#### Inherited from + +[`DateCore`](DateCore.md).[`goToCurrentPeriod`](DateCore.md#gotocurrentperiod) + +*** + +### goToNextPeriod() + +```ts +goToNextPeriod(): void; +``` + +Defined in: [calendar/date-core.ts:304](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L304) + +#### Returns + +`void` + +#### Implementation of + +```ts +CalendarActions.goToNextPeriod +``` + +#### Inherited from + +[`DateCore`](DateCore.md).[`goToNextPeriod`](DateCore.md#gotonextperiod) + +*** + +### goToPreviousPeriod() + +```ts +goToPreviousPeriod(): void; +``` + +Defined in: [calendar/date-core.ts:261](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L261) + +#### Returns + +`void` + +#### Implementation of + +```ts +CalendarActions.goToPreviousPeriod +``` + +#### Inherited from + +[`DateCore`](DateCore.md).[`goToPreviousPeriod`](DateCore.md#gotopreviousperiod) + +*** + +### goToSpecificPeriod() + +```ts +goToSpecificPeriod(date): void; +``` + +Defined in: [calendar/date-core.ts:360](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L360) + +#### Parameters + +##### date + +[`DateInput`](../type-aliases/DateInput.md) + +#### Returns + +`void` + +#### Implementation of + +```ts +CalendarActions.goToSpecificPeriod +``` + +#### Inherited from + +[`DateCore`](DateCore.md).[`goToSpecificPeriod`](DateCore.md#gotospecificperiod) + +*** + +### groupDaysBy() + +```ts +groupDaysBy(__namedParameters): (Day | null)[][]; +``` + +Defined in: [calendar/calendar.ts:212](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L212) + +Groups days by a specified unit. + +#### Parameters + +##### \_\_namedParameters + +###### days + +([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[] + +###### fillMissingDays? + +`boolean` = `true` + +###### unit + +`"week"` \| `"workWeek"` + +#### Returns + +([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[][] + +#### Implementation of + +```ts +CalendarActions.groupDaysBy +``` + +*** + +### removeEvent() + +```ts +removeEvent(id): void; +``` + +Defined in: [calendar/calendar.ts:259](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L259) + +Removes an event by ID. + +#### Parameters + +##### id + +`string` + +#### Returns + +`void` + +#### Implementation of + +```ts +CalendarActions.removeEvent +``` + +*** + +### updateEvent() + +```ts +updateEvent(id, updates): void; +``` + +Defined in: [calendar/calendar.ts:249](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L249) + +Updates an existing event by ID. + +#### Parameters + +##### id + +`string` + +##### updates + +`Partial`\<`Omit`\<`TEvent`, `"id"`\>\> + +#### Returns + +`void` + +#### Implementation of + +```ts +CalendarActions.updateEvent +``` diff --git a/docs/reference/classes/DateCore.md b/docs/reference/classes/DateCore.md new file mode 100644 index 00000000..79c899e5 --- /dev/null +++ b/docs/reference/classes/DateCore.md @@ -0,0 +1,326 @@ +--- +id: DateCore +title: DateCore +--- + +# Abstract Class: DateCore + +Defined in: [calendar/date-core.ts:77](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L77) + +## Extended by + +- [`CalendarCore`](CalendarCore.md) + +## Constructors + +### Constructor + +```ts +new DateCore(options): DateCore; +``` + +Defined in: [calendar/date-core.ts:86](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L86) + +#### Parameters + +##### options + +[`DateCoreOptions`](../interfaces/DateCoreOptions.md) + +#### Returns + +`DateCore` + +## Properties + +### formatters + +```ts +formatters: object; +``` + +Defined in: [calendar/date-core.ts:80](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L80) + +#### date + +```ts +date: DateTimeFormat; +``` + +#### dateTime + +```ts +dateTime: DateTimeFormat; +``` + +#### time + +```ts +time: DateTimeFormat; +``` + +*** + +### options + +```ts +options: ParsedDateCoreOptions; +``` + +Defined in: [calendar/date-core.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L79) + +*** + +### store + +```ts +store: Store; +``` + +Defined in: [calendar/date-core.ts:78](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L78) + +## Methods + +### canGoNextPeriod() + +```ts +canGoNextPeriod(): boolean; +``` + +Defined in: [calendar/date-core.ts:407](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L407) + +#### Returns + +`boolean` + +*** + +### canGoPreviousPeriod() + +```ts +canGoPreviousPeriod(): boolean; +``` + +Defined in: [calendar/date-core.ts:376](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L376) + +#### Returns + +`boolean` + +*** + +### changeViewMode() + +```ts +changeViewMode(newViewMode): void; +``` + +Defined in: [calendar/date-core.ts:254](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L254) + +#### Parameters + +##### newViewMode + +[`ViewMode`](../interfaces/ViewMode.md) + +#### Returns + +`void` + +*** + +### formatDate() + +```ts +formatDate(date): string; +``` + +Defined in: [calendar/date-core.ts:130](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L130) + +#### Parameters + +##### date + +[`DateInput`](../type-aliases/DateInput.md) + +#### Returns + +`string` + +*** + +### formatDateTime() + +```ts +formatDateTime(date): string; +``` + +Defined in: [calendar/date-core.ts:138](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L138) + +#### Parameters + +##### date + +[`DateInput`](../type-aliases/DateInput.md) + +#### Returns + +`string` + +*** + +### formatTime() + +```ts +formatTime(date): string; +``` + +Defined in: [calendar/date-core.ts:134](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L134) + +#### Parameters + +##### date + +[`DateInput`](../type-aliases/DateInput.md) + +#### Returns + +`string` + +*** + +### getCalendarDays() + +```ts +protected getCalendarDays(): PlainDate[]; +``` + +Defined in: [calendar/date-core.ts:161](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L161) + +#### Returns + +`PlainDate`[] + +*** + +### getDaysNames() + +```ts +getDaysNames(weekday): string[]; +``` + +Defined in: [calendar/date-core.ts:243](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L243) + +#### Parameters + +##### weekday + +`"long"` | `"short"` + +#### Returns + +`string`[] + +*** + +### getFirstDayOfMonth() + +```ts +protected getFirstDayOfMonth(): PlainDate; +``` + +Defined in: [calendar/date-core.ts:142](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L142) + +#### Returns + +`PlainDate` + +*** + +### getFirstDayOfWeek() + +```ts +protected getFirstDayOfWeek(): PlainDate; +``` + +Defined in: [calendar/date-core.ts:150](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L150) + +#### Returns + +`PlainDate` + +*** + +### getWeekStartsOn() + +```ts +getWeekStartsOn(): number; +``` + +Defined in: [calendar/date-core.ts:157](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L157) + +#### Returns + +`number` + +*** + +### goToCurrentPeriod() + +```ts +goToCurrentPeriod(): void; +``` + +Defined in: [calendar/date-core.ts:347](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L347) + +#### Returns + +`void` + +*** + +### goToNextPeriod() + +```ts +goToNextPeriod(): void; +``` + +Defined in: [calendar/date-core.ts:304](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L304) + +#### Returns + +`void` + +*** + +### goToPreviousPeriod() + +```ts +goToPreviousPeriod(): void; +``` + +Defined in: [calendar/date-core.ts:261](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L261) + +#### Returns + +`void` + +*** + +### goToSpecificPeriod() + +```ts +goToSpecificPeriod(date): void; +``` + +Defined in: [calendar/date-core.ts:360](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L360) + +#### Parameters + +##### date + +[`DateInput`](../type-aliases/DateInput.md) + +#### Returns + +`void` diff --git a/docs/reference/functions/add.md b/docs/reference/functions/add.md new file mode 100644 index 00000000..b3b99a48 --- /dev/null +++ b/docs/reference/functions/add.md @@ -0,0 +1,89 @@ +--- +id: add +title: add +--- + +# Function: add() + +```ts +function add(input, options): object; +``` + +Defined in: [date/add/add.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L13) + +add +Adds a duration to a date/time instance + +## Parameters + +### input + +[`DateInput`](../type-aliases/DateInput.md) + +### options + +[`AddOptions`](../interfaces/AddOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: ResolvedDateOperationOptions; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/functions/endOf.md b/docs/reference/functions/endOf.md new file mode 100644 index 00000000..6f8e8077 --- /dev/null +++ b/docs/reference/functions/endOf.md @@ -0,0 +1,89 @@ +--- +id: endOf +title: endOf +--- + +# Function: endOf() + +```ts +function endOf(input, options): object; +``` + +Defined in: [date/endOf/endOf.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L23) + +endOf +Returns the end of a given unit for a date/time instance + +## Parameters + +### input + +[`DateInput`](../type-aliases/DateInput.md) + +### options + +[`EndOfOptions`](../interfaces/EndOfOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: ResolvedDateOperationOptions; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/functions/equals.md b/docs/reference/functions/equals.md new file mode 100644 index 00000000..7e9724aa --- /dev/null +++ b/docs/reference/functions/equals.md @@ -0,0 +1,41 @@ +--- +id: equals +title: equals +--- + +# Function: equals() + +```ts +function equals( + date1, + date2, + unit, + options?): boolean; +``` + +Defined in: [date/equals/equals.ts:22](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L22) + +equals +Returns true if two date/time instances are equal at the specified unit level + +## Parameters + +### date1 + +[`DateInput`](../type-aliases/DateInput.md) + +### date2 + +[`DateInput`](../type-aliases/DateInput.md) + +### unit + +[`EqualsUnit`](../type-aliases/EqualsUnit.md) + +### options? + +[`EqualsOptions`](../interfaces/EqualsOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/format.md b/docs/reference/functions/format.md new file mode 100644 index 00000000..1c20d4a2 --- /dev/null +++ b/docs/reference/functions/format.md @@ -0,0 +1,33 @@ +--- +id: format +title: format +--- + +# Function: format() + +```ts +function format(date, formatOptions?): string; +``` + +Defined in: [date/format/format.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L32) + +format +Formats a date/time instance using Intl.DateTimeFormat + +## Parameters + +### date + +[`DateInput`](../type-aliases/DateInput.md) + +The date to format + +### formatOptions? + +[`FormatDateOptions`](../interfaces/FormatDateOptions.md) + +Formatting options including type, locale, and Intl.DateTimeFormat options + +## Returns + +`string` diff --git a/docs/reference/functions/generateDateRange.md b/docs/reference/functions/generateDateRange.md new file mode 100644 index 00000000..8780d59c --- /dev/null +++ b/docs/reference/functions/generateDateRange.md @@ -0,0 +1,26 @@ +--- +id: generateDateRange +title: generateDateRange +--- + +# Function: generateDateRange() + +```ts +function generateDateRange(start, end): PlainDate[]; +``` + +Defined in: [calendar/generateDateRange.ts:3](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/generateDateRange.ts#L3) + +## Parameters + +### start + +`string` + +### end + +`string` + +## Returns + +`PlainDate`[] diff --git a/docs/reference/functions/getEventProps.md b/docs/reference/functions/getEventProps.md new file mode 100644 index 00000000..904d9f77 --- /dev/null +++ b/docs/reference/functions/getEventProps.md @@ -0,0 +1,73 @@ +--- +id: getEventProps +title: getEventProps +--- + +# Function: getEventProps() + +```ts +function getEventProps( + eventMap, + event, + state, + options): + | { + end: string; + isSplitEvent: boolean; + overlappingEvents: Event[]; + start: string; +} + | { + end: string; + isSplitEvent: boolean; + overlappingEvents: Event[]; + start: string; + style: { + height: string; + left: string; + top: string; + width: string; + }; +}; +``` + +Defined in: [calendar/getEventProps.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getEventProps.ts#L54) + +## Parameters + +### eventMap + +`Map`\<`string`, [`Event`](../interfaces/Event.md)\<[`Resource`](../interfaces/Resource.md)\>[]\> + +### event + +[`Event`](../interfaces/Event.md) + +### state + +[`CalendarStore`](../interfaces/CalendarStore.md) + +### options + +`GetEventPropsOptions` + +## Returns + + \| \{ + `end`: `string`; + `isSplitEvent`: `boolean`; + `overlappingEvents`: [`Event`](../interfaces/Event.md)\<[`Resource`](../interfaces/Resource.md)\>[]; + `start`: `string`; +\} + \| \{ + `end`: `string`; + `isSplitEvent`: `boolean`; + `overlappingEvents`: [`Event`](../interfaces/Event.md)\<[`Resource`](../interfaces/Resource.md)\>[]; + `start`: `string`; + `style`: \{ + `height`: `string`; + `left`: `string`; + `top`: `string`; + `width`: `string`; + \}; +\} diff --git a/docs/reference/functions/getTimeSlots.md b/docs/reference/functions/getTimeSlots.md new file mode 100644 index 00000000..f88c1fc4 --- /dev/null +++ b/docs/reference/functions/getTimeSlots.md @@ -0,0 +1,35 @@ +--- +id: getTimeSlots +title: getTimeSlots +--- + +# Function: getTimeSlots() + +```ts +function getTimeSlots(locale, options?): TimeSlot[]; +``` + +Defined in: [calendar/getTimeSlots.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getTimeSlots.ts#L19) + +Generates time slots for calendar day views. +Returns an array of time slots with labels formatted according to the locale. + +## Parameters + +### locale + +`string` + +The locale to use for formatting time labels (BCP 47 format) + +### options? + +`TimeSlotOptions` + +Configuration options for time slots + +## Returns + +[`TimeSlot`](../interfaces/TimeSlot.md)[] + +Array of time slots with hour, minute, and formatted label diff --git a/docs/reference/functions/groupDaysBy.md b/docs/reference/functions/groupDaysBy.md new file mode 100644 index 00000000..1a8edc1e --- /dev/null +++ b/docs/reference/functions/groupDaysBy.md @@ -0,0 +1,32 @@ +--- +id: groupDaysBy +title: groupDaysBy +--- + +# Function: groupDaysBy() + +```ts +function groupDaysBy(__namedParameters): (Day | null)[][]; +``` + +Defined in: [calendar/groupDaysBy.ts:36](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/groupDaysBy.ts#L36) + +## Type Parameters + +### TResource + +`TResource` *extends* [`Resource`](../interfaces/Resource.md) + +### TEvent + +`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> = [`Event`](../interfaces/Event.md)\<`TResource`\> + +## Parameters + +### \_\_namedParameters + +[`GroupDaysByProps`](../type-aliases/GroupDaysByProps.md)\<`TResource`, `TEvent`\> + +## Returns + +([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[][] diff --git a/docs/reference/functions/intersects.md b/docs/reference/functions/intersects.md new file mode 100644 index 00000000..bdec851b --- /dev/null +++ b/docs/reference/functions/intersects.md @@ -0,0 +1,33 @@ +--- +id: intersects +title: intersects +--- + +# Function: intersects() + +```ts +function intersects(date, options): boolean; +``` + +Defined in: [date/intersects/intersects.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L16) + +intersects +Returns true if the date/time instance intersects with the range (i.e., is within or equal to the range boundaries) + +## Parameters + +### date + +[`DateInput`](../type-aliases/DateInput.md) + +The date to check + +### options + +[`IntersectsOptions`](../interfaces/IntersectsOptions.md) + +Options including range, timeZone and calendar + +## Returns + +`boolean` diff --git a/docs/reference/functions/isAfter.md b/docs/reference/functions/isAfter.md new file mode 100644 index 00000000..c1c06abe --- /dev/null +++ b/docs/reference/functions/isAfter.md @@ -0,0 +1,36 @@ +--- +id: isAfter +title: isAfter +--- + +# Function: isAfter() + +```ts +function isAfter( + date1, + date2, + options?): boolean; +``` + +Defined in: [date/isAfter/isAfter.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/isAfter/isAfter.ts#L12) + +isAfter +Returns true if the first date/time instance is after the second date/time instance + +## Parameters + +### date1 + +[`DateInput`](../type-aliases/DateInput.md) + +### date2 + +[`DateInput`](../type-aliases/DateInput.md) + +### options? + +[`IsAfterOptions`](../interfaces/IsAfterOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isBefore.md b/docs/reference/functions/isBefore.md new file mode 100644 index 00000000..796f97f1 --- /dev/null +++ b/docs/reference/functions/isBefore.md @@ -0,0 +1,36 @@ +--- +id: isBefore +title: isBefore +--- + +# Function: isBefore() + +```ts +function isBefore( + date1, + date2, + options?): boolean; +``` + +Defined in: [date/isBefore/isBefore.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBefore/isBefore.ts#L12) + +isBefore +Returns true if the first date/time instance is before the second date/time instance + +## Parameters + +### date1 + +[`DateInput`](../type-aliases/DateInput.md) + +### date2 + +[`DateInput`](../type-aliases/DateInput.md) + +### options? + +[`IsBeforeOptions`](../interfaces/IsBeforeOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isBetween.md b/docs/reference/functions/isBetween.md new file mode 100644 index 00000000..880bfb4a --- /dev/null +++ b/docs/reference/functions/isBetween.md @@ -0,0 +1,33 @@ +--- +id: isBetween +title: isBetween +--- + +# Function: isBetween() + +```ts +function isBetween(date, options): boolean; +``` + +Defined in: [date/isBetween/isBetween.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L18) + +isBetween +Returns true if the date/time instance is between the start and end of the range + +## Parameters + +### date + +[`DateInput`](../type-aliases/DateInput.md) + +The date to check + +### options + +[`IsBetweenOptions`](../interfaces/IsBetweenOptions.md) + +Options including timeZone, calendar, and inclusivity + +## Returns + +`boolean` diff --git a/docs/reference/functions/isLeapYear.md b/docs/reference/functions/isLeapYear.md new file mode 100644 index 00000000..0665af2b --- /dev/null +++ b/docs/reference/functions/isLeapYear.md @@ -0,0 +1,29 @@ +--- +id: isLeapYear +title: isLeapYear +--- + +# Function: isLeapYear() + +```ts +function isLeapYear(date, options?): boolean; +``` + +Defined in: [date/isLeapYear/isLeapYear.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/isLeapYear/isLeapYear.ts#L11) + +isLeapYear +Returns true if the year of the given date is a leap year + +## Parameters + +### date + +[`DateInput`](../type-aliases/DateInput.md) + +### options? + +[`IsLeapYearOptions`](../interfaces/IsLeapYearOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isSameOrAfter.md b/docs/reference/functions/isSameOrAfter.md new file mode 100644 index 00000000..1ff85269 --- /dev/null +++ b/docs/reference/functions/isSameOrAfter.md @@ -0,0 +1,36 @@ +--- +id: isSameOrAfter +title: isSameOrAfter +--- + +# Function: isSameOrAfter() + +```ts +function isSameOrAfter( + date1, + date2, + options): boolean; +``` + +Defined in: [date/isSameOrAfter/isSameOrAfter.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L25) + +isSameOrAfter +Returns true if the first date/time instance is the same as or after the second date/time instance at the specified unit level + +## Parameters + +### date1 + +[`DateInput`](../type-aliases/DateInput.md) + +### date2 + +[`DateInput`](../type-aliases/DateInput.md) + +### options + +[`IsSameOrAfterOptions`](../interfaces/IsSameOrAfterOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isSameOrBefore.md b/docs/reference/functions/isSameOrBefore.md new file mode 100644 index 00000000..352fc993 --- /dev/null +++ b/docs/reference/functions/isSameOrBefore.md @@ -0,0 +1,36 @@ +--- +id: isSameOrBefore +title: isSameOrBefore +--- + +# Function: isSameOrBefore() + +```ts +function isSameOrBefore( + date1, + date2, + options): boolean; +``` + +Defined in: [date/isSameOrBefore/isSameOrBefore.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L25) + +isSameOrBefore +Returns true if the first date/time instance is the same as or before the second date/time instance at the specified unit level + +## Parameters + +### date1 + +[`DateInput`](../type-aliases/DateInput.md) + +### date2 + +[`DateInput`](../type-aliases/DateInput.md) + +### options + +[`IsSameOrBeforeOptions`](../interfaces/IsSameOrBeforeOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/isWeekend.md b/docs/reference/functions/isWeekend.md new file mode 100644 index 00000000..ef5c58fd --- /dev/null +++ b/docs/reference/functions/isWeekend.md @@ -0,0 +1,29 @@ +--- +id: isWeekend +title: isWeekend +--- + +# Function: isWeekend() + +```ts +function isWeekend(date, options?): boolean; +``` + +Defined in: [date/isWeekend/isWeekend.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L13) + +isWeekend +Returns true if the date falls on a weekend based on locale-specific week info + +## Parameters + +### date + +[`DateInput`](../type-aliases/DateInput.md) + +### options? + +[`IsWeekendOptions`](../interfaces/IsWeekendOptions.md) + +## Returns + +`boolean` diff --git a/docs/reference/functions/range.md b/docs/reference/functions/range.md new file mode 100644 index 00000000..ed18d0a0 --- /dev/null +++ b/docs/reference/functions/range.md @@ -0,0 +1,26 @@ +--- +id: range +title: range +--- + +# Function: range() + +```ts +function range(options): object[]; +``` + +Defined in: [date/range/range.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L18) + +range +Generates an array of dates from start to end at the specified step interval. +The range is inclusive of both start and end (if end falls exactly on a step). + +## Parameters + +### options + +[`RangeOptions`](../interfaces/RangeOptions.md) + +## Returns + +`object`[] diff --git a/docs/reference/functions/round.md b/docs/reference/functions/round.md new file mode 100644 index 00000000..6156d618 --- /dev/null +++ b/docs/reference/functions/round.md @@ -0,0 +1,89 @@ +--- +id: round +title: round +--- + +# Function: round() + +```ts +function round(input, options): object; +``` + +Defined in: [date/round/round.ts:27](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L27) + +round +Returns the date/time instance rounded to the nearest unit + +## Parameters + +### input + +[`DateInput`](../type-aliases/DateInput.md) + +### options + +[`RoundOptions`](../interfaces/RoundOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: ResolvedDateOperationOptions; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/functions/since.md b/docs/reference/functions/since.md new file mode 100644 index 00000000..3e051bea --- /dev/null +++ b/docs/reference/functions/since.md @@ -0,0 +1,37 @@ +--- +id: since +title: since +--- + +# Function: since() + +```ts +function since( + start, + end, + options): number; +``` + +Defined in: [date/since/since.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L15) + +since +Returns the duration from the first date/time instance since the second date/time instance +(equivalent to: how long has it been since the second date, from the first date's perspective) + +## Parameters + +### start + +[`DateInput`](../type-aliases/DateInput.md) + +### end + +[`DateInput`](../type-aliases/DateInput.md) + +### options + +[`SinceOptions`](../interfaces/SinceOptions.md) + +## Returns + +`number` diff --git a/docs/reference/functions/splitMultiDayEvents.md b/docs/reference/functions/splitMultiDayEvents.md new file mode 100644 index 00000000..60d9dbf4 --- /dev/null +++ b/docs/reference/functions/splitMultiDayEvents.md @@ -0,0 +1,36 @@ +--- +id: splitMultiDayEvents +title: splitMultiDayEvents +--- + +# Function: splitMultiDayEvents() + +```ts +function splitMultiDayEvents(event, timeZone): TEvent[]; +``` + +Defined in: [calendar/splitMultiDayEvents.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/splitMultiDayEvents.ts#L5) + +## Type Parameters + +### TResource + +`TResource` *extends* [`Resource`](../interfaces/Resource.md) = [`Resource`](../interfaces/Resource.md) + +### TEvent + +`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> = [`Event`](../interfaces/Event.md)\<`TResource`\> + +## Parameters + +### event + +`TEvent` + +### timeZone + +`TimeZoneLike` + +## Returns + +`TEvent`[] diff --git a/docs/reference/functions/startOf.md b/docs/reference/functions/startOf.md new file mode 100644 index 00000000..d0d5e8af --- /dev/null +++ b/docs/reference/functions/startOf.md @@ -0,0 +1,89 @@ +--- +id: startOf +title: startOf +--- + +# Function: startOf() + +```ts +function startOf(input, options): object; +``` + +Defined in: [date/startOf/startOf.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L23) + +startOf +Returns the start of a given unit for a date/time instance + +## Parameters + +### input + +[`DateInput`](../type-aliases/DateInput.md) + +### options + +[`StartOfOptions`](../interfaces/StartOfOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: ResolvedDateOperationOptions; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/functions/subtract.md b/docs/reference/functions/subtract.md new file mode 100644 index 00000000..2beb5399 --- /dev/null +++ b/docs/reference/functions/subtract.md @@ -0,0 +1,89 @@ +--- +id: subtract +title: subtract +--- + +# Function: subtract() + +```ts +function subtract(input, options): object; +``` + +Defined in: [date/subtract/subtract.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L13) + +subtract +Subtracts a duration from a date/time instance + +## Parameters + +### input + +[`DateInput`](../type-aliases/DateInput.md) + +### options + +[`SubtractOptions`](../interfaces/SubtractOptions.md) + +## Returns + +`object` + +### asDate() + +```ts +asDate: () => Date; +``` + +#### Returns + +`Date` + +### asEpoch() + +```ts +asEpoch: () => number; +``` + +#### Returns + +`number` + +### asZonedDateTime() + +```ts +asZonedDateTime: () => ZonedDateTime; +``` + +#### Returns + +`ZonedDateTime` + +### calendar + +```ts +calendar: string = options.calendar; +``` + +### options + +```ts +options: ResolvedDateOperationOptions; +``` + +### returnFormat + +```ts +returnFormat: ReturnFormat; +``` + +### timeZone + +```ts +timeZone: string = options.timeZone; +``` + +### value + +```ts +value: string; +``` diff --git a/docs/reference/functions/until.md b/docs/reference/functions/until.md new file mode 100644 index 00000000..298e3e3e --- /dev/null +++ b/docs/reference/functions/until.md @@ -0,0 +1,36 @@ +--- +id: until +title: until +--- + +# Function: until() + +```ts +function until( + start, + end, + options): number; +``` + +Defined in: [date/until/until.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L14) + +until +Returns the duration from the first date/time instance until the second date/time instance + +## Parameters + +### start + +[`DateInput`](../type-aliases/DateInput.md) + +### end + +[`DateInput`](../type-aliases/DateInput.md) + +### options + +[`UntilOptions`](../interfaces/UntilOptions.md) + +## Returns + +`number` diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 00000000..e0b5468f --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,84 @@ +--- +id: "@tanstack/time" +title: "@tanstack/time" +--- + +# @tanstack/time + +## Classes + +- [CalendarCore](classes/CalendarCore.md) +- [DateCore](classes/DateCore.md) + +## Interfaces + +- [AddOptions](interfaces/AddOptions.md) +- [CalendarApi](interfaces/CalendarApi.md) +- [CalendarCoreOptions](interfaces/CalendarCoreOptions.md) +- [CalendarStore](interfaces/CalendarStore.md) +- [DateCoreOptions](interfaces/DateCoreOptions.md) +- [DateOptions](interfaces/DateOptions.md) +- [DateRange](interfaces/DateRange.md) +- [EndOfOptions](interfaces/EndOfOptions.md) +- [EqualsOptions](interfaces/EqualsOptions.md) +- [Event](interfaces/Event.md) +- [FormatDateOptions](interfaces/FormatDateOptions.md) +- [IntersectsOptions](interfaces/IntersectsOptions.md) +- [IsAfterOptions](interfaces/IsAfterOptions.md) +- [IsBeforeOptions](interfaces/IsBeforeOptions.md) +- [IsBetweenOptions](interfaces/IsBetweenOptions.md) +- [IsLeapYearOptions](interfaces/IsLeapYearOptions.md) +- [IsSameOrAfterOptions](interfaces/IsSameOrAfterOptions.md) +- [IsSameOrBeforeOptions](interfaces/IsSameOrBeforeOptions.md) +- [IsWeekendOptions](interfaces/IsWeekendOptions.md) +- [ParsedDateCoreOptions](interfaces/ParsedDateCoreOptions.md) +- [Range](interfaces/Range.md) +- [RangeOptions](interfaces/RangeOptions.md) +- [Resource](interfaces/Resource.md) +- [RoundOptions](interfaces/RoundOptions.md) +- [SinceOptions](interfaces/SinceOptions.md) +- [StartOfOptions](interfaces/StartOfOptions.md) +- [SubtractOptions](interfaces/SubtractOptions.md) +- [TimeSlot](interfaces/TimeSlot.md) +- [UntilOptions](interfaces/UntilOptions.md) +- [ViewMode](interfaces/ViewMode.md) + +## Type Aliases + +- [DateInput](type-aliases/DateInput.md) +- [Day](type-aliases/Day.md) +- [DurationLike](type-aliases/DurationLike.md) +- [EndOfUnit](type-aliases/EndOfUnit.md) +- [EqualsUnit](type-aliases/EqualsUnit.md) +- [FormatType](type-aliases/FormatType.md) +- [GroupDaysByProps](type-aliases/GroupDaysByProps.md) +- [IsSameOrAfterUnit](type-aliases/IsSameOrAfterUnit.md) +- [IsSameOrBeforeUnit](type-aliases/IsSameOrBeforeUnit.md) +- [RoundUnit](type-aliases/RoundUnit.md) +- [StartOfUnit](type-aliases/StartOfUnit.md) + +## Functions + +- [add](functions/add.md) +- [endOf](functions/endOf.md) +- [equals](functions/equals.md) +- [format](functions/format.md) +- [generateDateRange](functions/generateDateRange.md) +- [getEventProps](functions/getEventProps.md) +- [getTimeSlots](functions/getTimeSlots.md) +- [groupDaysBy](functions/groupDaysBy.md) +- [intersects](functions/intersects.md) +- [isAfter](functions/isAfter.md) +- [isBefore](functions/isBefore.md) +- [isBetween](functions/isBetween.md) +- [isLeapYear](functions/isLeapYear.md) +- [isSameOrAfter](functions/isSameOrAfter.md) +- [isSameOrBefore](functions/isSameOrBefore.md) +- [isWeekend](functions/isWeekend.md) +- [range](functions/range.md) +- [round](functions/round.md) +- [since](functions/since.md) +- [splitMultiDayEvents](functions/splitMultiDayEvents.md) +- [startOf](functions/startOf.md) +- [subtract](functions/subtract.md) +- [until](functions/until.md) diff --git a/docs/reference/interfaces/AddOptions.md b/docs/reference/interfaces/AddOptions.md new file mode 100644 index 00000000..250d3345 --- /dev/null +++ b/docs/reference/interfaces/AddOptions.md @@ -0,0 +1,70 @@ +--- +id: AddOptions +title: AddOptions +--- + +# Interface: AddOptions + +Defined in: [date/add/add.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L5) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### duration + +```ts +duration: DurationLike; +``` + +Defined in: [date/add/add.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L6) + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` diff --git a/docs/reference/interfaces/CalendarApi.md b/docs/reference/interfaces/CalendarApi.md new file mode 100644 index 00000000..dddfd41f --- /dev/null +++ b/docs/reference/interfaces/CalendarApi.md @@ -0,0 +1,552 @@ +--- +id: CalendarApi +title: CalendarApi +--- + +# Interface: CalendarApi\ + +Defined in: [calendar/calendar.ts:110](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L110) + +## Extends + +- `CalendarActions`\<`TResource`, `TEvent`\>.`ConvertTemporalToString`\<`CalendarState`\<`TResource`, `TEvent`\>\> + +## Type Parameters + +### TResource + +`TResource` *extends* [`Resource`](Resource.md) + +### TEvent + +`TEvent` *extends* [`Event`](Event.md)\<`TResource`\> + +## Properties + +### activeDate + +```ts +activeDate: string; +``` + +Defined in: [calendar/calendar.ts:103](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L103) + +The currently active date in the calendar. + +#### Inherited from + +```ts +ConvertTemporalToString.activeDate +``` + +*** + +### addEvent() + +```ts +addEvent: (event) => void; +``` + +Defined in: [calendar/calendar.ts:85](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L85) + +Adds a new event to the calendar. + +#### Parameters + +##### event + +`TEvent` + +#### Returns + +`void` + +#### Inherited from + +```ts +CalendarActions.addEvent +``` + +*** + +### canGoNextPeriod() + +```ts +canGoNextPeriod: () => boolean; +``` + +Defined in: [calendar/calendar.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L54) + +Checks if navigation to the next period is allowed within the range. + +#### Returns + +`boolean` + +#### Inherited from + +```ts +CalendarActions.canGoNextPeriod +``` + +*** + +### canGoPreviousPeriod() + +```ts +canGoPreviousPeriod: () => boolean; +``` + +Defined in: [calendar/calendar.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L52) + +Checks if navigation to the previous period is allowed within the range. + +#### Returns + +`boolean` + +#### Inherited from + +```ts +CalendarActions.canGoPreviousPeriod +``` + +*** + +### changeViewMode() + +```ts +changeViewMode: (newViewMode) => void; +``` + +Defined in: [calendar/calendar.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L56) + +Changes the current view mode of the calendar. + +#### Parameters + +##### newViewMode + +[`ViewMode`](ViewMode.md) + +#### Returns + +`void` + +#### Inherited from + +```ts +CalendarActions.changeViewMode +``` + +*** + +### currentPeriod + +```ts +currentPeriod: string; +``` + +Defined in: [calendar/calendar.ts:97](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L97) + +The currently focused date period in the calendar. + +#### Inherited from + +```ts +ConvertTemporalToString.currentPeriod +``` + +*** + +### days + +```ts +days: Day[]; +``` + +Defined in: [calendar/calendar.ts:101](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L101) + +An array of days, each potentially containing events. + +#### Inherited from + +```ts +ConvertTemporalToString.days +``` + +*** + +### getDaysNames() + +```ts +getDaysNames: (weekday?) => string[]; +``` + +Defined in: [calendar/calendar.ts:71](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L71) + +Retrieves the names of the days of the week, based on the current locale. + +#### Parameters + +##### weekday? + +`"long"` | `"short"` + +#### Returns + +`string`[] + +#### Inherited from + +```ts +CalendarActions.getDaysNames +``` + +*** + +### getEventProps() + +```ts +getEventProps: (event) => object; +``` + +Defined in: [calendar/calendar.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L58) + +Retrieves styling properties for a specific event. + +#### Parameters + +##### event + +`TEvent` + +#### Returns + +`object` + +##### end + +```ts +end: string; +``` + +##### isSplitEvent + +```ts +isSplitEvent: boolean; +``` + +##### overlappingEvents + +```ts +overlappingEvents: TEvent[]; +``` + +##### start + +```ts +start: string; +``` + +##### style? + +```ts +optional style: object; +``` + +###### style.height + +```ts +height: string; +``` + +###### style.left + +```ts +left: string; +``` + +###### style.top + +```ts +top: string; +``` + +###### style.width + +```ts +width: string; +``` + +#### Inherited from + +```ts +CalendarActions.getEventProps +``` + +*** + +### getEventsByDate() + +```ts +getEventsByDate: (date) => TEvent[]; +``` + +Defined in: [calendar/calendar.ts:83](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L83) + +Retrieves events for a specific date. + +#### Parameters + +##### date + +`string` + +#### Returns + +`TEvent`[] + +#### Inherited from + +```ts +CalendarActions.getEventsByDate +``` + +*** + +### getTimeSlots() + +```ts +getTimeSlots: (options?) => TimeSlot[]; +``` + +Defined in: [calendar/calendar.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L79) + +Retrieves time slots for day view with configurable intervals. + +#### Parameters + +##### options? + +`TimeSlotOptions` + +#### Returns + +[`TimeSlot`](TimeSlot.md)[] + +#### Inherited from + +```ts +CalendarActions.getTimeSlots +``` + +*** + +### goToCurrentPeriod() + +```ts +goToCurrentPeriod: () => void; +``` + +Defined in: [calendar/calendar.ts:48](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L48) + +Resets the view to the current period based on today's date. + +#### Returns + +`void` + +#### Inherited from + +```ts +CalendarActions.goToCurrentPeriod +``` + +*** + +### goToNextPeriod() + +```ts +goToNextPeriod: () => void; +``` + +Defined in: [calendar/calendar.ts:46](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L46) + +Navigates to the next period according to the current view mode. + +#### Returns + +`void` + +#### Inherited from + +```ts +CalendarActions.goToNextPeriod +``` + +*** + +### goToPreviousPeriod() + +```ts +goToPreviousPeriod: () => void; +``` + +Defined in: [calendar/calendar.ts:44](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L44) + +Navigates to the previous period according to the current view mode. + +#### Returns + +`void` + +#### Inherited from + +```ts +CalendarActions.goToPreviousPeriod +``` + +*** + +### goToSpecificPeriod() + +```ts +goToSpecificPeriod: (date) => void; +``` + +Defined in: [calendar/calendar.ts:50](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L50) + +Navigates to a specific date. + +#### Parameters + +##### date + +`string` + +#### Returns + +`void` + +#### Inherited from + +```ts +CalendarActions.goToSpecificPeriod +``` + +*** + +### groupDaysBy() + +```ts +groupDaysBy: (props) => (Day | null)[][]; +``` + +Defined in: [calendar/calendar.ts:73](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L73) + +Groups days by a specified unit. + +#### Parameters + +##### props + +###### days + +([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[] + +###### fillMissingDays? + +`boolean` + +###### unit + +`"week"` \| `"workWeek"` + +#### Returns + +([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[][] + +#### Inherited from + +```ts +CalendarActions.groupDaysBy +``` + +*** + +### removeEvent() + +```ts +removeEvent: (id) => void; +``` + +Defined in: [calendar/calendar.ts:89](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L89) + +Removes an event by ID. + +#### Parameters + +##### id + +`string` + +#### Returns + +`void` + +#### Inherited from + +```ts +CalendarActions.removeEvent +``` + +*** + +### updateEvent() + +```ts +updateEvent: (id, updates) => void; +``` + +Defined in: [calendar/calendar.ts:87](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L87) + +Updates an existing event by ID. + +#### Parameters + +##### id + +`string` + +##### updates + +`Partial`\<`Omit`\<`TEvent`, `"id"`\>\> + +#### Returns + +`void` + +#### Inherited from + +```ts +CalendarActions.updateEvent +``` + +*** + +### viewMode + +```ts +viewMode: ViewMode; +``` + +Defined in: [calendar/calendar.ts:99](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L99) + +The current view mode of the calendar. + +#### Inherited from + +```ts +ConvertTemporalToString.viewMode +``` diff --git a/docs/reference/interfaces/CalendarCoreOptions.md b/docs/reference/interfaces/CalendarCoreOptions.md new file mode 100644 index 00000000..4a4efd9e --- /dev/null +++ b/docs/reference/interfaces/CalendarCoreOptions.md @@ -0,0 +1,179 @@ +--- +id: CalendarCoreOptions +title: CalendarCoreOptions +--- + +# Interface: CalendarCoreOptions\ + +Defined in: [calendar/calendar.ts:24](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L24) + +Configuration options for initializing a CalendarCore instance, allowing customization +of events, locale, time zone, and the calendar system. + +## Extends + +- [`DateCoreOptions`](DateCoreOptions.md) + +## Type Parameters + +### TResource + +`TResource` *extends* [`Resource`](Resource.md) + +### TEvent + +`TEvent` *extends* [`Event`](Event.md)\<`TResource`\> + +Specifies the event type, extending a base Event type. + +## Properties + +### calendar? + +```ts +optional calendar: CalendarLike; +``` + +Defined in: [calendar/date-core.ts:59](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L59) + +Optional calendar system to be used. + +#### Inherited from + +[`DateCoreOptions`](DateCoreOptions.md).[`calendar`](DateCoreOptions.md#calendar) + +*** + +### dateFormatter? + +```ts +optional dateFormatter: DateTimeFormat; +``` + +Defined in: [calendar/date-core.ts:63](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L63) + +Optional date formatter. + +#### Inherited from + +[`DateCoreOptions`](DateCoreOptions.md).[`dateFormatter`](DateCoreOptions.md#dateformatter) + +*** + +### dateTimeFormatter? + +```ts +optional dateTimeFormatter: DateTimeFormat; +``` + +Defined in: [calendar/date-core.ts:67](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L67) + +Optional date time formatter. + +#### Inherited from + +[`DateCoreOptions`](DateCoreOptions.md).[`dateTimeFormatter`](DateCoreOptions.md#datetimeformatter) + +*** + +### events? + +```ts +optional events: TEvent[] | null; +``` + +Defined in: [calendar/calendar.ts:29](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L29) + +An optional array of events to be handled by the calendar. + +*** + +### locale? + +```ts +optional locale: string; +``` + +Defined in: [calendar/date-core.ts:55](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L55) + +Optional locale for date formatting. Uses a BCP 47 language tag. + +#### Inherited from + +[`DateCoreOptions`](DateCoreOptions.md).[`locale`](DateCoreOptions.md#locale) + +*** + +### range? + +```ts +optional range: DateRange; +``` + +Defined in: [calendar/date-core.ts:61](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L61) + +Optional range of dates to be used. + +#### Inherited from + +[`DateCoreOptions`](DateCoreOptions.md).[`range`](DateCoreOptions.md#range) + +*** + +### resources? + +```ts +optional resources: TResource[] | null; +``` + +Defined in: [calendar/calendar.ts:31](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L31) + +Optional resources to be used in the calendar. + +*** + +### timeFormatter? + +```ts +optional timeFormatter: DateTimeFormat; +``` + +Defined in: [calendar/date-core.ts:65](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L65) + +Optional time formatter. + +#### Inherited from + +[`DateCoreOptions`](DateCoreOptions.md).[`timeFormatter`](DateCoreOptions.md#timeformatter) + +*** + +### timeZone? + +```ts +optional timeZone: TimeZoneLike; +``` + +Defined in: [calendar/date-core.ts:57](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L57) + +Optional time zone specification. + +#### Inherited from + +[`DateCoreOptions`](DateCoreOptions.md).[`timeZone`](DateCoreOptions.md#timezone) + +*** + +### viewMode + +```ts +viewMode: ViewMode; +``` + +Defined in: [calendar/date-core.ts:53](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L53) + +The initial view mode configuration. + +#### Inherited from + +[`DateCoreOptions`](DateCoreOptions.md).[`viewMode`](DateCoreOptions.md#viewmode) diff --git a/docs/reference/interfaces/CalendarStore.md b/docs/reference/interfaces/CalendarStore.md new file mode 100644 index 00000000..150c7148 --- /dev/null +++ b/docs/reference/interfaces/CalendarStore.md @@ -0,0 +1,38 @@ +--- +id: CalendarStore +title: CalendarStore +--- + +# Interface: CalendarStore + +Defined in: [calendar/types.ts:49](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L49) + +## Properties + +### activeDate + +```ts +activeDate: PlainDate; +``` + +Defined in: [calendar/types.ts:51](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L51) + +*** + +### currentPeriod + +```ts +currentPeriod: PlainDate; +``` + +Defined in: [calendar/types.ts:50](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L50) + +*** + +### viewMode + +```ts +viewMode: ViewMode; +``` + +Defined in: [calendar/types.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L52) diff --git a/docs/reference/interfaces/DateCoreOptions.md b/docs/reference/interfaces/DateCoreOptions.md new file mode 100644 index 00000000..689222cf --- /dev/null +++ b/docs/reference/interfaces/DateCoreOptions.md @@ -0,0 +1,110 @@ +--- +id: DateCoreOptions +title: DateCoreOptions +--- + +# Interface: DateCoreOptions + +Defined in: [calendar/date-core.ts:51](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L51) + +Base options interface for date-related core classes. + +## Extended by + +- [`CalendarCoreOptions`](CalendarCoreOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: CalendarLike; +``` + +Defined in: [calendar/date-core.ts:59](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L59) + +Optional calendar system to be used. + +*** + +### dateFormatter? + +```ts +optional dateFormatter: DateTimeFormat; +``` + +Defined in: [calendar/date-core.ts:63](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L63) + +Optional date formatter. + +*** + +### dateTimeFormatter? + +```ts +optional dateTimeFormatter: DateTimeFormat; +``` + +Defined in: [calendar/date-core.ts:67](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L67) + +Optional date time formatter. + +*** + +### locale? + +```ts +optional locale: string; +``` + +Defined in: [calendar/date-core.ts:55](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L55) + +Optional locale for date formatting. Uses a BCP 47 language tag. + +*** + +### range? + +```ts +optional range: DateRange; +``` + +Defined in: [calendar/date-core.ts:61](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L61) + +Optional range of dates to be used. + +*** + +### timeFormatter? + +```ts +optional timeFormatter: DateTimeFormat; +``` + +Defined in: [calendar/date-core.ts:65](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L65) + +Optional time formatter. + +*** + +### timeZone? + +```ts +optional timeZone: TimeZoneLike; +``` + +Defined in: [calendar/date-core.ts:57](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L57) + +Optional time zone specification. + +*** + +### viewMode + +```ts +viewMode: ViewMode; +``` + +Defined in: [calendar/date-core.ts:53](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L53) + +The initial view mode configuration. diff --git a/docs/reference/interfaces/DateOptions.md b/docs/reference/interfaces/DateOptions.md new file mode 100644 index 00000000..90b07152 --- /dev/null +++ b/docs/reference/interfaces/DateOptions.md @@ -0,0 +1,43 @@ +--- +id: DateOptions +title: DateOptions +--- + +# Interface: DateOptions + +Defined in: [date/types.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L10) + +## Extended by + +- [`SinceOptions`](SinceOptions.md) +- [`UntilOptions`](UntilOptions.md) +- [`EqualsOptions`](EqualsOptions.md) +- [`IsLeapYearOptions`](IsLeapYearOptions.md) +- [`IsWeekendOptions`](IsWeekendOptions.md) +- [`IsBeforeOptions`](IsBeforeOptions.md) +- [`IsAfterOptions`](IsAfterOptions.md) +- [`IsSameOrBeforeOptions`](IsSameOrBeforeOptions.md) +- [`IsSameOrAfterOptions`](IsSameOrAfterOptions.md) +- [`IsBetweenOptions`](IsBetweenOptions.md) +- [`IntersectsOptions`](IntersectsOptions.md) +- [`FormatDateOptions`](FormatDateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) diff --git a/docs/reference/interfaces/DateRange.md b/docs/reference/interfaces/DateRange.md new file mode 100644 index 00000000..9440465e --- /dev/null +++ b/docs/reference/interfaces/DateRange.md @@ -0,0 +1,28 @@ +--- +id: DateRange +title: DateRange +--- + +# Interface: DateRange + +Defined in: [calendar/types.ts:38](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L38) + +## Properties + +### end + +```ts +end: DateInput | null; +``` + +Defined in: [calendar/types.ts:40](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L40) + +*** + +### start + +```ts +start: DateInput | null; +``` + +Defined in: [calendar/types.ts:39](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L39) diff --git a/docs/reference/interfaces/EndOfOptions.md b/docs/reference/interfaces/EndOfOptions.md new file mode 100644 index 00000000..7f3c282c --- /dev/null +++ b/docs/reference/interfaces/EndOfOptions.md @@ -0,0 +1,70 @@ +--- +id: EndOfOptions +title: EndOfOptions +--- + +# Interface: EndOfOptions + +Defined in: [date/endOf/endOf.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L15) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` + +*** + +### unit + +```ts +unit: EndOfUnit; +``` + +Defined in: [date/endOf/endOf.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L16) diff --git a/docs/reference/interfaces/EqualsOptions.md b/docs/reference/interfaces/EqualsOptions.md new file mode 100644 index 00000000..530e281b --- /dev/null +++ b/docs/reference/interfaces/EqualsOptions.md @@ -0,0 +1,40 @@ +--- +id: EqualsOptions +title: EqualsOptions +--- + +# Interface: EqualsOptions + +Defined in: [date/equals/equals.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L16) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/Event.md b/docs/reference/interfaces/Event.md new file mode 100644 index 00000000..e7504655 --- /dev/null +++ b/docs/reference/interfaces/Event.md @@ -0,0 +1,64 @@ +--- +id: Event +title: Event +--- + +# Interface: Event\ + +Defined in: [calendar/types.ts:20](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L20) + +## Type Parameters + +### TResource + +`TResource` *extends* [`Resource`](Resource.md) = [`Resource`](Resource.md) + +## Properties + +### end + +```ts +end: string; +``` + +Defined in: [calendar/types.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L23) + +*** + +### id + +```ts +id: string; +``` + +Defined in: [calendar/types.ts:21](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L21) + +*** + +### resources? + +```ts +optional resources: TResource[]; +``` + +Defined in: [calendar/types.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L25) + +*** + +### start + +```ts +start: string; +``` + +Defined in: [calendar/types.ts:22](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L22) + +*** + +### title + +```ts +title: string; +``` + +Defined in: [calendar/types.ts:24](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L24) diff --git a/docs/reference/interfaces/FormatDateOptions.md b/docs/reference/interfaces/FormatDateOptions.md new file mode 100644 index 00000000..cb4727cd --- /dev/null +++ b/docs/reference/interfaces/FormatDateOptions.md @@ -0,0 +1,74 @@ +--- +id: FormatDateOptions +title: FormatDateOptions +--- + +# Interface: FormatDateOptions + +Defined in: [date/format/format.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L16) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### locale? + +```ts +optional locale: string | string[] | Locale | Locale[]; +``` + +Defined in: [date/format/format.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L18) + +*** + +### options? + +```ts +optional options: + | string + | DateFormatterOptions + | TimeFormatterOptions + | DateTimeFormatterOptions; +``` + +Defined in: [date/format/format.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L19) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) + +*** + +### type? + +```ts +optional type: FormatType; +``` + +Defined in: [date/format/format.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L17) diff --git a/docs/reference/interfaces/IntersectsOptions.md b/docs/reference/interfaces/IntersectsOptions.md new file mode 100644 index 00000000..431b4865 --- /dev/null +++ b/docs/reference/interfaces/IntersectsOptions.md @@ -0,0 +1,50 @@ +--- +id: IntersectsOptions +title: IntersectsOptions +--- + +# Interface: IntersectsOptions + +Defined in: [date/intersects/intersects.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L6) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### range + +```ts +range: Range; +``` + +Defined in: [date/intersects/intersects.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L7) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsAfterOptions.md b/docs/reference/interfaces/IsAfterOptions.md new file mode 100644 index 00000000..fb772548 --- /dev/null +++ b/docs/reference/interfaces/IsAfterOptions.md @@ -0,0 +1,40 @@ +--- +id: IsAfterOptions +title: IsAfterOptions +--- + +# Interface: IsAfterOptions + +Defined in: [date/isAfter/isAfter.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isAfter/isAfter.ts#L6) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsBeforeOptions.md b/docs/reference/interfaces/IsBeforeOptions.md new file mode 100644 index 00000000..3c06573c --- /dev/null +++ b/docs/reference/interfaces/IsBeforeOptions.md @@ -0,0 +1,40 @@ +--- +id: IsBeforeOptions +title: IsBeforeOptions +--- + +# Interface: IsBeforeOptions + +Defined in: [date/isBefore/isBefore.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBefore/isBefore.ts#L6) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsBetweenOptions.md b/docs/reference/interfaces/IsBetweenOptions.md new file mode 100644 index 00000000..48e5ca62 --- /dev/null +++ b/docs/reference/interfaces/IsBetweenOptions.md @@ -0,0 +1,60 @@ +--- +id: IsBetweenOptions +title: IsBetweenOptions +--- + +# Interface: IsBetweenOptions + +Defined in: [date/isBetween/isBetween.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L6) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### inclusive? + +```ts +optional inclusive: boolean | "start" | "end"; +``` + +Defined in: [date/isBetween/isBetween.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L7) + +*** + +### range + +```ts +range: Range; +``` + +Defined in: [date/isBetween/isBetween.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L8) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsLeapYearOptions.md b/docs/reference/interfaces/IsLeapYearOptions.md new file mode 100644 index 00000000..dcdcc9f2 --- /dev/null +++ b/docs/reference/interfaces/IsLeapYearOptions.md @@ -0,0 +1,40 @@ +--- +id: IsLeapYearOptions +title: IsLeapYearOptions +--- + +# Interface: IsLeapYearOptions + +Defined in: [date/isLeapYear/isLeapYear.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/isLeapYear/isLeapYear.ts#L5) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsSameOrAfterOptions.md b/docs/reference/interfaces/IsSameOrAfterOptions.md new file mode 100644 index 00000000..92f0e03c --- /dev/null +++ b/docs/reference/interfaces/IsSameOrAfterOptions.md @@ -0,0 +1,50 @@ +--- +id: IsSameOrAfterOptions +title: IsSameOrAfterOptions +--- + +# Interface: IsSameOrAfterOptions + +Defined in: [date/isSameOrAfter/isSameOrAfter.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L17) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) + +*** + +### unit + +```ts +unit: IsSameOrAfterUnit; +``` + +Defined in: [date/isSameOrAfter/isSameOrAfter.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L18) diff --git a/docs/reference/interfaces/IsSameOrBeforeOptions.md b/docs/reference/interfaces/IsSameOrBeforeOptions.md new file mode 100644 index 00000000..e818e578 --- /dev/null +++ b/docs/reference/interfaces/IsSameOrBeforeOptions.md @@ -0,0 +1,50 @@ +--- +id: IsSameOrBeforeOptions +title: IsSameOrBeforeOptions +--- + +# Interface: IsSameOrBeforeOptions + +Defined in: [date/isSameOrBefore/isSameOrBefore.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L17) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) + +*** + +### unit + +```ts +unit: IsSameOrBeforeUnit; +``` + +Defined in: [date/isSameOrBefore/isSameOrBefore.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L18) diff --git a/docs/reference/interfaces/IsWeekendOptions.md b/docs/reference/interfaces/IsWeekendOptions.md new file mode 100644 index 00000000..1b492741 --- /dev/null +++ b/docs/reference/interfaces/IsWeekendOptions.md @@ -0,0 +1,50 @@ +--- +id: IsWeekendOptions +title: IsWeekendOptions +--- + +# Interface: IsWeekendOptions + +Defined in: [date/isWeekend/isWeekend.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L5) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### locale? + +```ts +optional locale: string; +``` + +Defined in: [date/isWeekend/isWeekend.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L6) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/ParsedDateCoreOptions.md b/docs/reference/interfaces/ParsedDateCoreOptions.md new file mode 100644 index 00000000..417916f8 --- /dev/null +++ b/docs/reference/interfaces/ParsedDateCoreOptions.md @@ -0,0 +1,86 @@ +--- +id: ParsedDateCoreOptions +title: ParsedDateCoreOptions +--- + +# Interface: ParsedDateCoreOptions + +Defined in: [calendar/date-core.ts:70](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L70) + +## Extends + +- `Omit`\<`Required`\<[`DateCoreOptions`](DateCoreOptions.md)\>, `"range"` \| `"dateFormatter"` \| `"timeFormatter"` \| `"dateTimeFormatter"`\> + +## Properties + +### calendar + +```ts +calendar: CalendarLike; +``` + +Defined in: [calendar/date-core.ts:59](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L59) + +Optional calendar system to be used. + +#### Inherited from + +[`CalendarCoreOptions`](CalendarCoreOptions.md).[`calendar`](CalendarCoreOptions.md#calendar) + +*** + +### locale + +```ts +locale: string; +``` + +Defined in: [calendar/date-core.ts:55](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L55) + +Optional locale for date formatting. Uses a BCP 47 language tag. + +#### Inherited from + +[`CalendarCoreOptions`](CalendarCoreOptions.md).[`locale`](CalendarCoreOptions.md#locale) + +*** + +### range + +```ts +range: ParsedDateRange; +``` + +Defined in: [calendar/date-core.ts:74](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L74) + +*** + +### timeZone + +```ts +timeZone: TimeZoneLike; +``` + +Defined in: [calendar/date-core.ts:57](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L57) + +Optional time zone specification. + +#### Inherited from + +[`CalendarCoreOptions`](CalendarCoreOptions.md).[`timeZone`](CalendarCoreOptions.md#timezone) + +*** + +### viewMode + +```ts +viewMode: ViewMode; +``` + +Defined in: [calendar/date-core.ts:53](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L53) + +The initial view mode configuration. + +#### Inherited from + +[`CalendarCoreOptions`](CalendarCoreOptions.md).[`viewMode`](CalendarCoreOptions.md#viewmode) diff --git a/docs/reference/interfaces/Range.md b/docs/reference/interfaces/Range.md new file mode 100644 index 00000000..47d83f53 --- /dev/null +++ b/docs/reference/interfaces/Range.md @@ -0,0 +1,28 @@ +--- +id: Range +title: Range +--- + +# Interface: Range + +Defined in: [date/types.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L17) + +## Properties + +### end + +```ts +end: DateInput; +``` + +Defined in: [date/types.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L19) + +*** + +### start + +```ts +start: DateInput; +``` + +Defined in: [date/types.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L18) diff --git a/docs/reference/interfaces/RangeOptions.md b/docs/reference/interfaces/RangeOptions.md new file mode 100644 index 00000000..86eaaf67 --- /dev/null +++ b/docs/reference/interfaces/RangeOptions.md @@ -0,0 +1,90 @@ +--- +id: RangeOptions +title: RangeOptions +--- + +# Interface: RangeOptions + +Defined in: [date/range/range.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L7) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### end + +```ts +end: DateInput; +``` + +Defined in: [date/range/range.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L9) + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### start + +```ts +start: DateInput; +``` + +Defined in: [date/range/range.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L8) + +*** + +### step + +```ts +step: DurationLike; +``` + +Defined in: [date/range/range.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L10) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` diff --git a/docs/reference/interfaces/Resource.md b/docs/reference/interfaces/Resource.md new file mode 100644 index 00000000..d5e2dcbc --- /dev/null +++ b/docs/reference/interfaces/Resource.md @@ -0,0 +1,28 @@ +--- +id: Resource +title: Resource +--- + +# Interface: Resource + +Defined in: [calendar/types.ts:4](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L4) + +## Properties + +### id + +```ts +id: string; +``` + +Defined in: [calendar/types.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L5) + +*** + +### label + +```ts +label: string; +``` + +Defined in: [calendar/types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L6) diff --git a/docs/reference/interfaces/RoundOptions.md b/docs/reference/interfaces/RoundOptions.md new file mode 100644 index 00000000..005206c6 --- /dev/null +++ b/docs/reference/interfaces/RoundOptions.md @@ -0,0 +1,90 @@ +--- +id: RoundOptions +title: RoundOptions +--- + +# Interface: RoundOptions + +Defined in: [date/round/round.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L17) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### roundingIncrement? + +```ts +optional roundingIncrement: number; +``` + +Defined in: [date/round/round.ts:20](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L20) + +*** + +### roundingMode? + +```ts +optional roundingMode: RoundingMode; +``` + +Defined in: [date/round/round.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L19) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` + +*** + +### unit + +```ts +unit: RoundUnit; +``` + +Defined in: [date/round/round.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L18) diff --git a/docs/reference/interfaces/SinceOptions.md b/docs/reference/interfaces/SinceOptions.md new file mode 100644 index 00000000..1d186d23 --- /dev/null +++ b/docs/reference/interfaces/SinceOptions.md @@ -0,0 +1,50 @@ +--- +id: SinceOptions +title: SinceOptions +--- + +# Interface: SinceOptions + +Defined in: [date/since/since.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L6) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) + +*** + +### unit + +```ts +unit: DateTimeUnit; +``` + +Defined in: [date/since/since.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L7) diff --git a/docs/reference/interfaces/StartOfOptions.md b/docs/reference/interfaces/StartOfOptions.md new file mode 100644 index 00000000..ad444e38 --- /dev/null +++ b/docs/reference/interfaces/StartOfOptions.md @@ -0,0 +1,70 @@ +--- +id: StartOfOptions +title: StartOfOptions +--- + +# Interface: StartOfOptions + +Defined in: [date/startOf/startOf.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L15) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` + +*** + +### unit + +```ts +unit: StartOfUnit; +``` + +Defined in: [date/startOf/startOf.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L16) diff --git a/docs/reference/interfaces/SubtractOptions.md b/docs/reference/interfaces/SubtractOptions.md new file mode 100644 index 00000000..06f82129 --- /dev/null +++ b/docs/reference/interfaces/SubtractOptions.md @@ -0,0 +1,70 @@ +--- +id: SubtractOptions +title: SubtractOptions +--- + +# Interface: SubtractOptions + +Defined in: [date/subtract/subtract.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L5) + +## Extends + +- `DateOperationOptions` + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +```ts +DateOperationOptions.calendar +``` + +*** + +### duration + +```ts +duration: DurationLike; +``` + +Defined in: [date/subtract/subtract.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L6) + +*** + +### returnFormat? + +```ts +optional returnFormat: ReturnFormat; +``` + +Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) + +#### Inherited from + +```ts +DateOperationOptions.returnFormat +``` + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +```ts +DateOperationOptions.timeZone +``` diff --git a/docs/reference/interfaces/TimeSlot.md b/docs/reference/interfaces/TimeSlot.md new file mode 100644 index 00000000..562220b9 --- /dev/null +++ b/docs/reference/interfaces/TimeSlot.md @@ -0,0 +1,38 @@ +--- +id: TimeSlot +title: TimeSlot +--- + +# Interface: TimeSlot + +Defined in: [calendar/types.ts:43](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L43) + +## Properties + +### hour + +```ts +hour: number; +``` + +Defined in: [calendar/types.ts:44](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L44) + +*** + +### label + +```ts +label: string; +``` + +Defined in: [calendar/types.ts:46](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L46) + +*** + +### minute + +```ts +minute: number; +``` + +Defined in: [calendar/types.ts:45](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L45) diff --git a/docs/reference/interfaces/UntilOptions.md b/docs/reference/interfaces/UntilOptions.md new file mode 100644 index 00000000..6eb7aa61 --- /dev/null +++ b/docs/reference/interfaces/UntilOptions.md @@ -0,0 +1,50 @@ +--- +id: UntilOptions +title: UntilOptions +--- + +# Interface: UntilOptions + +Defined in: [date/until/until.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L6) + +## Extends + +- [`DateOptions`](DateOptions.md) + +## Properties + +### calendar? + +```ts +optional calendar: string; +``` + +Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) + +*** + +### timeZone? + +```ts +optional timeZone: string; +``` + +Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) + +#### Inherited from + +[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) + +*** + +### unit + +```ts +unit: DateTimeUnit; +``` + +Defined in: [date/until/until.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L7) diff --git a/docs/reference/interfaces/ViewMode.md b/docs/reference/interfaces/ViewMode.md new file mode 100644 index 00000000..cf5d5fae --- /dev/null +++ b/docs/reference/interfaces/ViewMode.md @@ -0,0 +1,35 @@ +--- +id: ViewMode +title: ViewMode +--- + +# Interface: ViewMode + +Defined in: [calendar/types.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L13) + +Represents the configuration for the current viewing mode of a calendar, +specifying the scale and unit of time. + +## Properties + +### unit + +```ts +unit: "month" | "week" | "day" | "workWeek"; +``` + +Defined in: [calendar/types.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L17) + +The unit of time that the calendar view should display (month, week, workWeek or day). + +*** + +### value + +```ts +value: number; +``` + +Defined in: [calendar/types.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L15) + +The number of units for the view mode. diff --git a/docs/reference/type-aliases/DateInput.md b/docs/reference/type-aliases/DateInput.md new file mode 100644 index 00000000..a62d63b6 --- /dev/null +++ b/docs/reference/type-aliases/DateInput.md @@ -0,0 +1,12 @@ +--- +id: DateInput +title: DateInput +--- + +# Type Alias: DateInput + +```ts +type DateInput = string | number | Date | Temporal.ZonedDateTime | Temporal.PlainDate; +``` + +Defined in: [date/types.ts:3](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L3) diff --git a/docs/reference/type-aliases/Day.md b/docs/reference/type-aliases/Day.md new file mode 100644 index 00000000..77228cad --- /dev/null +++ b/docs/reference/type-aliases/Day.md @@ -0,0 +1,62 @@ +--- +id: Day +title: Day +--- + +# Type Alias: Day\ + +```ts +type Day = object; +``` + +Defined in: [calendar/types.ts:28](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L28) + +## Type Parameters + +### TResource + +`TResource` *extends* [`Resource`](../interfaces/Resource.md) = [`Resource`](../interfaces/Resource.md) + +### TEvent + +`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> = [`Event`](../interfaces/Event.md)\<`TResource`\> + +## Properties + +### date + +```ts +date: Temporal.PlainDate; +``` + +Defined in: [calendar/types.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L32) + +*** + +### events + +```ts +events: TEvent[]; +``` + +Defined in: [calendar/types.ts:33](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L33) + +*** + +### isInCurrentPeriod + +```ts +isInCurrentPeriod: boolean; +``` + +Defined in: [calendar/types.ts:35](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L35) + +*** + +### isToday + +```ts +isToday: boolean; +``` + +Defined in: [calendar/types.ts:34](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L34) diff --git a/docs/reference/type-aliases/DurationLike.md b/docs/reference/type-aliases/DurationLike.md new file mode 100644 index 00000000..ecdccc6f --- /dev/null +++ b/docs/reference/type-aliases/DurationLike.md @@ -0,0 +1,12 @@ +--- +id: DurationLike +title: DurationLike +--- + +# Type Alias: DurationLike + +```ts +type DurationLike = Temporal.DurationLike; +``` + +Defined in: [date/types.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L15) diff --git a/docs/reference/type-aliases/EndOfUnit.md b/docs/reference/type-aliases/EndOfUnit.md new file mode 100644 index 00000000..56e11564 --- /dev/null +++ b/docs/reference/type-aliases/EndOfUnit.md @@ -0,0 +1,20 @@ +--- +id: EndOfUnit +title: EndOfUnit +--- + +# Type Alias: EndOfUnit + +```ts +type EndOfUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [date/endOf/endOf.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L5) diff --git a/docs/reference/type-aliases/EqualsUnit.md b/docs/reference/type-aliases/EqualsUnit.md new file mode 100644 index 00000000..57c99027 --- /dev/null +++ b/docs/reference/type-aliases/EqualsUnit.md @@ -0,0 +1,20 @@ +--- +id: EqualsUnit +title: EqualsUnit +--- + +# Type Alias: EqualsUnit + +```ts +type EqualsUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [date/equals/equals.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L6) diff --git a/docs/reference/type-aliases/FormatType.md b/docs/reference/type-aliases/FormatType.md new file mode 100644 index 00000000..3d72d75f --- /dev/null +++ b/docs/reference/type-aliases/FormatType.md @@ -0,0 +1,12 @@ +--- +id: FormatType +title: FormatType +--- + +# Type Alias: FormatType + +```ts +type FormatType = "date" | "time" | "datetime"; +``` + +Defined in: [date/format/format.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L14) diff --git a/docs/reference/type-aliases/GroupDaysByProps.md b/docs/reference/type-aliases/GroupDaysByProps.md new file mode 100644 index 00000000..4e5336ac --- /dev/null +++ b/docs/reference/type-aliases/GroupDaysByProps.md @@ -0,0 +1,24 @@ +--- +id: GroupDaysByProps +title: GroupDaysByProps +--- + +# Type Alias: GroupDaysByProps\ + +```ts +type GroupDaysByProps = + | GroupDaysByMonthProps +| GroupDaysByWeekProps; +``` + +Defined in: [calendar/groupDaysBy.ts:29](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/groupDaysBy.ts#L29) + +## Type Parameters + +### TResource + +`TResource` *extends* [`Resource`](../interfaces/Resource.md) + +### TEvent + +`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> = [`Event`](../interfaces/Event.md)\<`TResource`\> diff --git a/docs/reference/type-aliases/IsSameOrAfterUnit.md b/docs/reference/type-aliases/IsSameOrAfterUnit.md new file mode 100644 index 00000000..3c795455 --- /dev/null +++ b/docs/reference/type-aliases/IsSameOrAfterUnit.md @@ -0,0 +1,20 @@ +--- +id: IsSameOrAfterUnit +title: IsSameOrAfterUnit +--- + +# Type Alias: IsSameOrAfterUnit + +```ts +type IsSameOrAfterUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [date/isSameOrAfter/isSameOrAfter.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L7) diff --git a/docs/reference/type-aliases/IsSameOrBeforeUnit.md b/docs/reference/type-aliases/IsSameOrBeforeUnit.md new file mode 100644 index 00000000..7552ceb0 --- /dev/null +++ b/docs/reference/type-aliases/IsSameOrBeforeUnit.md @@ -0,0 +1,20 @@ +--- +id: IsSameOrBeforeUnit +title: IsSameOrBeforeUnit +--- + +# Type Alias: IsSameOrBeforeUnit + +```ts +type IsSameOrBeforeUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [date/isSameOrBefore/isSameOrBefore.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L7) diff --git a/docs/reference/type-aliases/RoundUnit.md b/docs/reference/type-aliases/RoundUnit.md new file mode 100644 index 00000000..c6f6620b --- /dev/null +++ b/docs/reference/type-aliases/RoundUnit.md @@ -0,0 +1,19 @@ +--- +id: RoundUnit +title: RoundUnit +--- + +# Type Alias: RoundUnit + +```ts +type RoundUnit = + | "day" + | "hour" + | "minute" + | "second" + | "millisecond" + | "microsecond" + | "nanosecond"; +``` + +Defined in: [date/round/round.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L6) diff --git a/docs/reference/type-aliases/StartOfUnit.md b/docs/reference/type-aliases/StartOfUnit.md new file mode 100644 index 00000000..50b40116 --- /dev/null +++ b/docs/reference/type-aliases/StartOfUnit.md @@ -0,0 +1,20 @@ +--- +id: StartOfUnit +title: StartOfUnit +--- + +# Type Alias: StartOfUnit + +```ts +type StartOfUnit = + | "year" + | "month" + | "week" + | "day" + | "hour" + | "minute" + | "second" + | "millisecond"; +``` + +Defined in: [date/startOf/startOf.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L5) From 9dffe0e6d41ad37bf54c84f7cfe09a1a4d09da00 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Thu, 29 Jan 2026 18:24:03 +0100 Subject: [PATCH 040/207] feat: event resize --- examples/react/basic/src/index.tsx | 452 +++++++++++++++++- packages/react-time/src/index.ts | 5 + packages/react-time/src/useCalendar/index.ts | 5 + .../react-time/src/useCalendar/useCalendar.ts | 254 +++++++++- packages/time/src/calendar/calendar.ts | 12 + packages/time/src/calendar/date-core.ts | 31 +- packages/time/src/calendar/getResizeProps.ts | 115 +++++ packages/time/src/calendar/index.ts | 1 + packages/time/src/calendar/types.ts | 1 + packages/time/src/utils/weekUtils.ts | 3 - 10 files changed, 840 insertions(+), 39 deletions(-) create mode 100644 packages/time/src/calendar/getResizeProps.ts diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index e831a198..70a7b09c 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -229,6 +229,185 @@ function EventModal({ ) } +const MINUTES_IN_DAY = 24 * 60 + +interface ResizeHandleProps { + edge: 'top' | 'bottom' + onMouseDown: (e: React.MouseEvent) => void +} + +function ResizeHandle({ edge, onMouseDown }: ResizeHandleProps) { + return ( +
{ + // Prevent event click from firing when clicking resize handle + e.stopPropagation() + }} + style={{ touchAction: 'none' }} + > +
+
+ ) +} + +function calculatePreviewStyleForSegment( + previewStart: string, + previewEnd: string, + segmentStart: string, + segmentEnd: string, + edge: 'top' | 'bottom' | null, +): { top: string; height: string } | null { + const previewStartDate = new Date(previewStart) + const previewEndDate = new Date(previewEnd) + const segmentStartDate = new Date(segmentStart) + const segmentEndDate = new Date(segmentEnd) + + // Get the date part (YYYY-MM-DD) for comparison + const segmentDate = segmentStart.split('T')[0] + const previewStartDateStr = previewStart.split('T')[0] + const previewEndDateStr = previewEnd.split('T')[0] + + let effectiveStart: Date + let effectiveEnd: Date + + if (edge === 'top') { + // For top edge resize, check if preview start is on the same day as segment + if (previewStartDateStr !== segmentDate) { + // Preview start is on a different day, use segment start + effectiveStart = segmentStartDate + } else { + effectiveStart = previewStartDate + } + effectiveEnd = segmentEndDate + } else if (edge === 'bottom') { + // For bottom edge resize, check if preview end is on the same day as segment + effectiveStart = segmentStartDate + if (previewEndDateStr !== segmentDate) { + // Preview end is on a different day, use segment end (end of day) + effectiveEnd = new Date(segmentDate + 'T23:59:59') + } else { + effectiveEnd = previewEndDate + } + } else { + // For both edges or no edge specified, check if preview spans this segment's day + if (previewStartDateStr === segmentDate && previewEndDateStr === segmentDate) { + // Both preview times are on the same day as segment + effectiveStart = previewStartDate + effectiveEnd = previewEndDate + } else if (previewStartDateStr === segmentDate) { + // Only start is on this day + effectiveStart = previewStartDate + effectiveEnd = new Date(segmentDate + 'T23:59:59') + } else if (previewEndDateStr === segmentDate) { + // Only end is on this day + effectiveStart = new Date(segmentDate + 'T00:00:00') + effectiveEnd = previewEndDate + } else { + // Preview doesn't span this day at all + return null + } + } + + const startMinutes = effectiveStart.getHours() * 60 + effectiveStart.getMinutes() + const endMinutes = effectiveEnd.getHours() * 60 + effectiveEnd.getMinutes() + const durationMinutes = endMinutes - startMinutes + + if (durationMinutes <= 0) return null + + const topPercent = (startMinutes / MINUTES_IN_DAY) * 100 + const heightPercent = (durationMinutes / MINUTES_IN_DAY) * 100 + + return { + top: `${topPercent}%`, + height: `${Math.max(heightPercent, (30 / MINUTES_IN_DAY) * 100)}%`, + } +} + +// Calculate style for original segment when resizing spans multiple days +function calculateOriginalSegmentStyleForMultiDay( + originalStart: string, + originalEnd: string, + edge: 'top' | 'bottom' | null, + isSpanningMultipleDays: boolean, +): { top: string; height: string } | null { + if (!isSpanningMultipleDays) return null + + const startDate = new Date(originalStart) + const endDate = new Date(originalEnd) + + let startMinutes: number + let endMinutes: number + + if (edge === 'bottom') { + // Resizing bottom to next day: original shows from start to end of day + startMinutes = startDate.getHours() * 60 + startDate.getMinutes() + endMinutes = MINUTES_IN_DAY // 23:59 (end of day) + } else if (edge === 'top') { + // Resizing top to previous day: original shows from start of day to end + startMinutes = 0 // 00:00 (start of day) + endMinutes = endDate.getHours() * 60 + endDate.getMinutes() + } else { + return null + } + + const durationMinutes = endMinutes - startMinutes + if (durationMinutes <= 0) return null + + const topPercent = (startMinutes / MINUTES_IN_DAY) * 100 + const heightPercent = (durationMinutes / MINUTES_IN_DAY) * 100 + + return { + top: `${topPercent}%`, + height: `${Math.max(heightPercent, (30 / MINUTES_IN_DAY) * 100)}%`, + } +} + +// Calculate style for ghost preview on target day +function calculateGhostPreviewStyle( + previewStart: string, + previewEnd: string, + edge: 'top' | 'bottom' | null, +): { top: string; height: string } | null { + const previewStartDate = new Date(previewStart) + const previewEndDate = new Date(previewEnd) + + let startMinutes: number + let endMinutes: number + + if (edge === 'bottom') { + // Resizing bottom to next day: ghost starts at 00:00 and ends at preview end time + startMinutes = 0 + endMinutes = previewEndDate.getHours() * 60 + previewEndDate.getMinutes() + } else if (edge === 'top') { + // Resizing top to previous day: ghost starts at preview start time and ends at 23:59 + startMinutes = previewStartDate.getHours() * 60 + previewStartDate.getMinutes() + endMinutes = MINUTES_IN_DAY + } else { + startMinutes = previewStartDate.getHours() * 60 + previewStartDate.getMinutes() + endMinutes = previewEndDate.getHours() * 60 + previewEndDate.getMinutes() + } + + const durationMinutes = endMinutes - startMinutes + if (durationMinutes <= 0) return null + + const topPercent = (startMinutes / MINUTES_IN_DAY) * 100 + const heightPercent = (durationMinutes / MINUTES_IN_DAY) * 100 + + return { + top: `${topPercent}%`, + height: `${Math.max(heightPercent, (30 / MINUTES_IN_DAY) * 100)}%`, + } +} + function ScheduleView({ calendar, days, @@ -239,6 +418,7 @@ function ScheduleView({ onEventClick: (event: Event) => void }) { const timeSlots = calendar.getTimeSlots() + const { resizeState, getResizeHandleProps } = calendar return (
@@ -260,6 +440,7 @@ function ScheduleView({ >
{days.map((day) => { + const dayDate = `${day.date.year}-${String(day.date.month).padStart(2, '0')}-${String(day.date.day).padStart(2, '0')}` const dayName = new Intl.DateTimeFormat('en-US', { weekday: 'short', }).format( @@ -269,6 +450,7 @@ function ScheduleView({
@@ -279,39 +461,259 @@ function ScheduleView({
{day.events.map((event, eventIndex) => { const eventProps = calendar.getEventProps(event) - if (!eventProps) return null - const { style } = eventProps + const { style, isSplitEvent } = eventProps + + const eventStartDate = event.start.split('T')[0] + const eventEndDate = event.end.split('T')[0] + const segmentStartDate = eventProps.start.split('T')[0] + const segmentEndDate = eventProps.end.split('T')[0] + + // First segment: event starts on this day (exact match or same date) + const isFirstSegment = + event.start === eventProps.start || + eventStartDate === segmentStartDate + + // Last segment: event ends on this day + // For multi-day events, check if this segment's date matches the event's end date + const isLastSegment = + event.end === eventProps.end || + eventEndDate === segmentEndDate || + eventEndDate === segmentStartDate + + const isBeingResized = + resizeState.isResizing && resizeState.eventId === event.id + + // Check if this event is being resized + const isThisSegmentBeingResized = + isBeingResized && + ((resizeState.edge === 'top' && isFirstSegment) || + (resizeState.edge === 'bottom' && isLastSegment)) + + // Check if resize is spanning multiple days + const segmentDate = eventProps.start.split('T')[0] + const isSpanningMultipleDays = + isThisSegmentBeingResized && + resizeState.targetDayDate !== null && + resizeState.targetDayDate !== segmentDate + + // Calculate display style based on resize state + let previewStyle: { top: string; height: string } | null = null + let shouldHideSegment = false + + if (isBeingResized && resizeState.previewStart && resizeState.previewEnd) { + const previewStartDateStr = resizeState.previewStart.split('T')[0] + const previewEndDateStr = resizeState.previewEnd.split('T')[0] + + // Check if this segment's day is within the preview range + const previewAffectsThisDay = + previewStartDateStr === dayDate || + previewEndDateStr === dayDate || + (previewStartDateStr < dayDate && previewEndDateStr > dayDate) + + // Check if this segment is being shrunk away (not in preview range anymore) + const isBeingShrunkAway = + isThisSegmentBeingResized && !previewAffectsThisDay + + if (isBeingShrunkAway) { + // This segment is being removed by the resize, hide it + shouldHideSegment = true + } else if (isThisSegmentBeingResized && isSpanningMultipleDays && previewAffectsThisDay) { + // Extending to another day - use multi-day style + previewStyle = calculateOriginalSegmentStyleForMultiDay( + eventProps.start, + eventProps.end, + resizeState.edge, + true, + ) + } else if (isThisSegmentBeingResized && !isSpanningMultipleDays) { + // Normal resize within same day + previewStyle = calculatePreviewStyleForSegment( + resizeState.previewStart, + resizeState.previewEnd, + eventProps.start, + eventProps.end, + resizeState.edge, + ) + } else if (!isThisSegmentBeingResized && previewAffectsThisDay) { + // This segment is newly affected by the resize (e.g., shrinking to this day) + // Check if this is the new "last segment" for bottom resize + const isNewLastSegment = + resizeState.edge === 'bottom' && previewEndDateStr === dayDate + const isNewFirstSegment = + resizeState.edge === 'top' && previewStartDateStr === dayDate + + if (isNewLastSegment || isNewFirstSegment) { + previewStyle = calculatePreviewStyleForSegment( + resizeState.previewStart, + resizeState.previewEnd, + eventProps.start, + eventProps.end, + resizeState.edge, + ) + } + } + } + + // Skip rendering if segment is being shrunk away + if (shouldHideSegment) { + return null + } + + const displayStyle = previewStyle + ? { ...style, ...previewStyle } + : style + + // Calculate display times based on preview + let displayStart = eventProps.start + let displayEnd = eventProps.end + + if (isBeingResized && resizeState.previewStart && resizeState.previewEnd) { + const previewEndDateStr = resizeState.previewEnd.split('T')[0] + const previewStartDateStr = resizeState.previewStart.split('T')[0] + + if (resizeState.edge === 'top') { + // For top edge resize, update start if this is the new first segment + if (previewStartDateStr === dayDate) { + displayStart = resizeState.previewStart + } + } else if (resizeState.edge === 'bottom') { + // For bottom edge resize, update end if this is the new last segment + if (previewEndDateStr === dayDate) { + displayEnd = resizeState.previewEnd + } else if (isThisSegmentBeingResized && previewEndDateStr !== segmentDate) { + // Extending to next day - show end of day for current segment + displayEnd = `${segmentDate}T23:59:00` + } + } + } + + // For multi-day events, show handles on first/last segments + // For single-day events, show both handles + const showTopHandle = !isSplitEvent || isFirstSegment + + // Show bottom handle if: + // 1. Not a split event (single day), OR + // 2. This segment's date matches the event's end date (last segment) + // Check if the event ends on this day by comparing the dayDate with eventEndDate + const showBottomHandle = + !isSplitEvent || + dayDate === eventEndDate || + eventEndDate === segmentStartDate || + eventEndDate === segmentEndDate + + // Check if this segment is being actively resized (original or new target) + const isActivelyResized = isBeingResized && previewStyle !== null + return (
onEventClick(event)} + style={displayStyle} + onClick={(e) => { + // Don't trigger event click if clicking on resize handle + if ( + !resizeState.isResizing && + !(e.target as HTMLElement).closest('[data-resize-handle]') + ) { + onEventClick(event) + } + }} > -
{event.title}
- {style && parseFloat(style.height) > 2 && ( -
- {new Date(eventProps.start).toLocaleTimeString( - 'en-US', - { - hour: 'numeric', - minute: '2-digit', - }, + {showTopHandle && ( + + )} +
{event.title}
+ {displayStyle && parseFloat(displayStyle.height) > 2 && ( +
+ {new Date(displayStart).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit', + })} {' - '} - {new Date(eventProps.end).toLocaleTimeString( - 'en-US', - { - hour: 'numeric', - minute: '2-digit', - }, - )} + {new Date(displayEnd).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit', + })}
)} + {showBottomHandle && ( + + )}
) })} + {/* Ghost preview on target day when resizing across days */} + {resizeState.isResizing && + resizeState.targetDayDate === dayDate && + resizeState.previewStart && + resizeState.previewEnd && + (() => { + const previewStartDate = resizeState.previewStart.split('T')[0] + const previewEndDate = resizeState.previewEnd.split('T')[0] + + const eventOnThisDay = day.events.some( + (e) => e.id === resizeState.eventId, + ) + const isDayInPreviewRange = + dayDate >= previewStartDate && dayDate <= previewEndDate + + if (!eventOnThisDay && isDayInPreviewRange) { + const ghostStyle = calculateGhostPreviewStyle( + resizeState.previewStart, + resizeState.previewEnd, + resizeState.edge, + ) + + if (!ghostStyle) return null + + // Calculate display times for the ghost + const ghostStartTime = resizeState.edge === 'bottom' + ? '00:00' + : new Date(resizeState.previewStart).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit', + }) + const ghostEndTime = resizeState.edge === 'top' + ? '11:59 PM' + : new Date(resizeState.previewEnd).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit', + }) + + return ( +
+
+ {ghostStartTime} - {ghostEndTime} +
+
+ ) + } + return null + })()}
) @@ -339,6 +741,14 @@ function CalendarView() { viewMode: { value: 1, unit: 'month' }, events: sampleEvents, timeZone: 'UTC', + resize: { + enabled: true, + containerHeight: 1440, + constraints: { + minDurationMinutes: 15, + snapToMinutes: 15, + }, + }, }) const dayNames = calendar.getDaysNames('short') diff --git a/packages/react-time/src/index.ts b/packages/react-time/src/index.ts index 5ba2e09d..9fb4d791 100644 --- a/packages/react-time/src/index.ts +++ b/packages/react-time/src/index.ts @@ -1 +1,6 @@ export { useCalendar } from './useCalendar' +export type { + ResizeState, + ResizeOptions, + UseCalendarOptions, +} from './useCalendar' \ No newline at end of file diff --git a/packages/react-time/src/useCalendar/index.ts b/packages/react-time/src/useCalendar/index.ts index 5ba2e09d..14b46416 100644 --- a/packages/react-time/src/useCalendar/index.ts +++ b/packages/react-time/src/useCalendar/index.ts @@ -1 +1,6 @@ export { useCalendar } from './useCalendar' +export type { + ResizeState, + ResizeOptions, + UseCalendarOptions, +} from './useCalendar' diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 178b64e4..020b2bcf 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -1,25 +1,261 @@ -import { useCallback, useState, useTransition } from 'react' +import { + useCallback, + useMemo, + useRef, + useState, + useSyncExternalStore, + useTransition, +} from 'react' import { useStore } from '@tanstack/react-store' -import { CalendarCore } from '@tanstack/time' +import { + CalendarCore, + calculateDeltaMinutesFromPixels, + calculateResizedEvent, +} from '@tanstack/time' import type { CalendarApi, CalendarCoreOptions, Event, + ResizeConstraints, + ResizeEdge, Resource, } from '@tanstack/time' +export interface ResizeState { + isResizing: boolean + eventId: string | null + edge: ResizeEdge | null + previewStart: string | null + previewEnd: string | null + targetDayDate: string | null +} + +export interface ResizeOptions { + enabled?: boolean + containerHeight?: number + constraints?: ResizeConstraints + onResizeStart?: (eventId: string, edge: ResizeEdge) => void + onResizeEnd?: (eventId: string, newStart: string, newEnd: string) => void +} + +interface ResizeHandleHandlers { + onMouseDown: (e: React.MouseEvent) => void +} + +export interface UseCalendarOptions< + TResource extends Resource, + TEvent extends Event, +> extends CalendarCoreOptions { + resize?: ResizeOptions +} + +const initialResizeState: ResizeState = { + isResizing: false, + eventId: null, + edge: null, + previewStart: null, + previewEnd: null, + targetDayDate: null, +} + +const DEFAULT_CONTAINER_HEIGHT = 1440 + export const useCalendar = < TResource extends Resource, TEvent extends Event = Event, >( - options: CalendarCoreOptions, -): CalendarApi & { isPending: boolean } => { + options: UseCalendarOptions, +): CalendarApi & { + isPending: boolean + resizeState: ResizeState + getResizeHandleProps: ( + eventId: string, + edge: ResizeEdge, + originalStart: string, + originalEnd: string, + ) => ResizeHandleHandlers +} => { + const { resize, ...calendarOptions } = options + const resizeEnabled = resize?.enabled ?? true + const containerHeight = resize?.containerHeight ?? DEFAULT_CONTAINER_HEIGHT + const constraints = resize?.constraints + const [calendarCore] = useState( - () => new CalendarCore(options), + () => new CalendarCore(calendarOptions), ) const state = useStore(calendarCore.store) const [isPending, startTransition] = useTransition() + const resizeStateRef = useRef(initialResizeState) + const resizeListenersRef = useRef void>>(new Set()) + const originalEventRef = useRef<{ + id: string + start: string + end: string + edge: ResizeEdge + startY: number + originalDayDate: string + currentDayDate: string + } | null>(null) + + const subscribeResize = useCallback((listener: () => void) => { + resizeListenersRef.current.add(listener) + return () => resizeListenersRef.current.delete(listener) + }, []) + + const getResizeSnapshot = useCallback(() => resizeStateRef.current, []) + + const notifyResizeListeners = useCallback(() => { + resizeListenersRef.current.forEach((listener) => listener()) + }, []) + + const updateResizeState = useCallback( + (newState: Partial) => { + resizeStateRef.current = { ...resizeStateRef.current, ...newState } + notifyResizeListeners() + }, + [notifyResizeListeners], + ) + + const resizeState = useSyncExternalStore( + subscribeResize, + getResizeSnapshot, + getResizeSnapshot, + ) + + const handleMouseMove = useCallback( + (e: MouseEvent) => { + if (!originalEventRef.current) return + + const { id, start, end, edge, startY, originalDayDate } = + originalEventRef.current + const deltaY = e.clientY - startY + + const deltaMinutes = calculateDeltaMinutesFromPixels( + deltaY, + containerHeight, + ) + + // Detect which day column the mouse is over + const dayColumns = document.querySelectorAll('[data-day-date]') + let targetDayDate: string | null = null + + for (const column of dayColumns) { + const rect = column.getBoundingClientRect() + if (e.clientX >= rect.left && e.clientX <= rect.right) { + targetDayDate = column.getAttribute('data-day-date') + break + } + } + + // Calculate day offset if moved to a different day + let dayOffsetMinutes = 0 + if (targetDayDate && targetDayDate !== originalDayDate) { + const originalDate = new Date(originalDayDate + 'T00:00:00') + const targetDate = new Date(targetDayDate + 'T00:00:00') + const dayDiff = Math.round( + (targetDate.getTime() - originalDate.getTime()) / + (1000 * 60 * 60 * 24), + ) + + // Apply day offset in both directions for flexible resizing + dayOffsetMinutes = dayDiff * 24 * 60 + originalEventRef.current.currentDayDate = targetDayDate + } + + const totalDeltaMinutes = deltaMinutes + dayOffsetMinutes + + const result = calculateResizedEvent({ + originalStart: start, + originalEnd: end, + edge, + deltaMinutes: totalDeltaMinutes, + timeZone: calendarOptions.timeZone ?? 'UTC', + constraints, + }) + + updateResizeState({ + eventId: id, + previewStart: result.start, + previewEnd: result.end, + targetDayDate, + }) + }, + [containerHeight, calendarOptions.timeZone, constraints, updateResizeState], + ) + + const handleMouseUp = useCallback(() => { + const currentState = resizeStateRef.current + if ( + currentState.eventId && + currentState.previewStart && + currentState.previewEnd + ) { + calendarCore.updateEvent(currentState.eventId, { + start: currentState.previewStart, + end: currentState.previewEnd, + } as Partial>) + resize?.onResizeEnd?.( + currentState.eventId, + currentState.previewStart, + currentState.previewEnd, + ) + } + + originalEventRef.current = null + updateResizeState(initialResizeState) + + document.removeEventListener('mousemove', handleMouseMove) + document.removeEventListener('mouseup', handleMouseUp) + }, [calendarCore, handleMouseMove, resize, updateResizeState]) + + const getResizeHandleProps = useCallback( + ( + eventId: string, + edge: ResizeEdge, + originalStart: string, + originalEnd: string, + ): ResizeHandleHandlers => ({ + onMouseDown: (e: React.MouseEvent) => { + if (!resizeEnabled) return + + e.preventDefault() + e.stopPropagation() + + // Find the day column this event is in + const dayColumn = (e.target as HTMLElement).closest('[data-day-date]') + const dayDate = dayColumn?.getAttribute('data-day-date') ?? '' + + originalEventRef.current = { + id: eventId, + start: originalStart, + end: originalEnd, + edge, + startY: e.clientY, + originalDayDate: dayDate, + currentDayDate: dayDate, + } + + updateResizeState({ + isResizing: true, + eventId, + edge, + previewStart: originalStart, + previewEnd: originalEnd, + targetDayDate: dayDate, + }) + + resize?.onResizeStart?.(eventId, edge) + + document.addEventListener('mousemove', handleMouseMove) + document.addEventListener('mouseup', handleMouseUp) + document.body.style.cursor = 'ns-resize' + document.body.style.userSelect = 'none' + }, + }), + [resizeEnabled, handleMouseMove, handleMouseUp, resize, updateResizeState], + ) + const goToPreviousPeriod = useCallback< typeof calendarCore.goToPreviousPeriod >(() => { @@ -111,6 +347,12 @@ export const useCalendar = < [calendarCore], ) + const days = useMemo(() => { + // state dependency triggers recalculation when calendar state changes + void state + return calendarCore.getDaysWithEvents() + }, [calendarCore, state]) + return { activeDate: state.activeDate.toString(), currentPeriod: state.currentPeriod.toString(), @@ -132,5 +374,7 @@ export const useCalendar = < removeEvent, isPending, groupDaysBy, + resizeState, + getResizeHandleProps, } } diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index eedd3bc0..983458a4 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -244,6 +244,10 @@ export class CalendarCore< this.options.events = [] } this.options.events.push(event) + this.store.setState((prev) => ({ + ...prev, + eventsVersion: prev.eventsVersion + 1, + })) } updateEvent(id: Event['id'], updates: Partial>): void { @@ -254,6 +258,10 @@ export class CalendarCore< const existingEvent = this.options.events[index] this.options.events[index] = { ...existingEvent, ...updates } as TEvent + this.store.setState((prev) => ({ + ...prev, + eventsVersion: prev.eventsVersion + 1, + })) } removeEvent(id: Event['id']): void { @@ -263,5 +271,9 @@ export class CalendarCore< if (index === -1) return this.options.events.splice(index, 1) + this.store.setState((prev) => ({ + ...prev, + eventsVersion: prev.eventsVersion + 1, + })) } } diff --git a/packages/time/src/calendar/date-core.ts b/packages/time/src/calendar/date-core.ts index 4b806e39..42dfa196 100644 --- a/packages/time/src/calendar/date-core.ts +++ b/packages/time/src/calendar/date-core.ts @@ -124,6 +124,7 @@ export abstract class DateCore { currentPeriod: initialDate, activeDate: initialDate, viewMode: options.viewMode, + eventsVersion: 0, }) } @@ -159,16 +160,26 @@ export abstract class DateCore { } protected getCalendarDays() { - const start = - this.store.state.viewMode.unit === 'month' - ? this.getFirstDayOfMonth().subtract({ - days: - (this.getFirstDayOfMonth().dayOfWeek - - (this.getFirstDayOfWeek().dayOfWeek + 1) + - 7) % - 7, - }) - : this.store.state.currentPeriod + let start: Temporal.PlainDate + switch (this.store.state.viewMode.unit) { + case 'month': + start = this.getFirstDayOfMonth().subtract({ + days: + (this.getFirstDayOfMonth().dayOfWeek - + (this.getFirstDayOfWeek().dayOfWeek + 1) + + 7) % + 7, + }) + break + case 'week': + case 'workWeek': + start = this.getFirstDayOfWeek() + break + case 'day': + default: + start = this.store.state.currentPeriod + break + } let end: Temporal.PlainDate switch (this.store.state.viewMode.unit) { diff --git a/packages/time/src/calendar/getResizeProps.ts b/packages/time/src/calendar/getResizeProps.ts new file mode 100644 index 00000000..b1613f94 --- /dev/null +++ b/packages/time/src/calendar/getResizeProps.ts @@ -0,0 +1,115 @@ +import { Temporal } from '@js-temporal/polyfill' + +export type ResizeEdge = 'top' | 'bottom' + +export interface ResizeConstraints { + minDurationMinutes?: number + snapToMinutes?: number +} + +interface CalculateResizedEventOptions { + originalStart: string + originalEnd: string + edge: ResizeEdge + deltaMinutes: number + timeZone: Temporal.TimeZoneLike + constraints?: ResizeConstraints +} + +interface ResizedEventResult { + start: string + end: string + durationMinutes: number +} + +const DEFAULT_MIN_DURATION_MINUTES = 15 +const DEFAULT_SNAP_TO_MINUTES = 15 + +const roundToNearestInterval = (minutes: number, interval: number): number => + Math.round(minutes / interval) * interval + +export function calculateResizedEvent( + options: CalculateResizedEventOptions, +): ResizedEventResult { + const { + originalStart, + originalEnd, + edge, + deltaMinutes, + timeZone, + constraints = {}, + } = options + + const { + minDurationMinutes = DEFAULT_MIN_DURATION_MINUTES, + snapToMinutes = DEFAULT_SNAP_TO_MINUTES, + } = constraints + + const startZdt = + Temporal.PlainDateTime.from(originalStart).toZonedDateTime(timeZone) + const endZdt = + Temporal.PlainDateTime.from(originalEnd).toZonedDateTime(timeZone) + + const snappedDelta = roundToNearestInterval(deltaMinutes, snapToMinutes) + + let newStartZdt = startZdt + let newEndZdt = endZdt + + if (edge === 'top') { + newStartZdt = startZdt.add({ minutes: snappedDelta }) + const maxStartZdt = endZdt.subtract({ minutes: minDurationMinutes }) + if (Temporal.ZonedDateTime.compare(newStartZdt, maxStartZdt) > 0) { + newStartZdt = maxStartZdt + } + } else { + newEndZdt = endZdt.add({ minutes: snappedDelta }) + const minEndZdt = startZdt.add({ minutes: minDurationMinutes }) + if (Temporal.ZonedDateTime.compare(newEndZdt, minEndZdt) < 0) { + newEndZdt = minEndZdt + } + } + + const durationMs = newEndZdt.epochMilliseconds - newStartZdt.epochMilliseconds + const durationMinutes = Math.floor(durationMs / (1000 * 60)) + + return { + start: newStartZdt.toPlainDateTime().toString(), + end: newEndZdt.toPlainDateTime().toString(), + durationMinutes, + } +} + +export function calculateDeltaMinutesFromPixels( + deltaPixels: number, + containerHeight: number, + minutesInDay: number = 24 * 60, +): number { + return (deltaPixels / containerHeight) * minutesInDay +} + +export interface ResizeHandleStyle { + position: 'absolute' + left: number + right: number + height: string + cursor: 'ns-resize' + zIndex: number + top?: number + bottom?: number +} + +export function getResizeHandleStyle(edge: ResizeEdge): ResizeHandleStyle { + const baseStyle: ResizeHandleStyle = { + position: 'absolute', + left: 0, + right: 0, + height: '8px', + cursor: 'ns-resize', + zIndex: 10, + } + + if (edge === 'top') { + return { ...baseStyle, top: 0 } + } + return { ...baseStyle, bottom: 0 } +} diff --git a/packages/time/src/calendar/index.ts b/packages/time/src/calendar/index.ts index ad8807f3..cc13a7a6 100644 --- a/packages/time/src/calendar/index.ts +++ b/packages/time/src/calendar/index.ts @@ -4,4 +4,5 @@ export * from './generateDateRange' export * from './getEventProps' export * from './groupDaysBy' export * from './getTimeSlots' +export * from './getResizeProps' export * from './calendar' diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index 03e708ce..27c6b365 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -50,4 +50,5 @@ export interface CalendarStore { currentPeriod: Temporal.PlainDate activeDate: Temporal.PlainDate viewMode: ViewMode + eventsVersion: number } diff --git a/packages/time/src/utils/weekUtils.ts b/packages/time/src/utils/weekUtils.ts index 1ca081ab..82f33054 100644 --- a/packages/time/src/utils/weekUtils.ts +++ b/packages/time/src/utils/weekUtils.ts @@ -21,9 +21,6 @@ export function getFirstDayOfWeek( const date = Temporal.PlainDate.from(dateString) const weekInfo = new Intl.Locale(locale).getWeekInfo() const firstDayOfWeek = weekInfo.firstDay - - console.log('locale', locale) - const dayOfWeek = date.dayOfWeek const daysToSubtract = (dayOfWeek - firstDayOfWeek + 7) % 7 From d84752348da0e19581e56054afa055da53759883 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Thu, 29 Jan 2026 22:24:56 +0100 Subject: [PATCH 041/207] feat: event resize --- examples/react/basic/src/index.tsx | 37 ++++++++----------- .../time/src/calendar/splitMultiDayEvents.ts | 2 + packages/time/src/calendar/types.ts | 4 ++ 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 70a7b09c..c2683acc 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -463,22 +463,20 @@ function ScheduleView({ const eventProps = calendar.getEventProps(event) const { style, isSplitEvent } = eventProps - const eventStartDate = event.start.split('T')[0] - const eventEndDate = event.end.split('T')[0] + const originalStart = event._originalStart ?? event.start + const originalEnd = event._originalEnd ?? event.end + const originalStartDate = originalStart.split('T')[0] + const originalEndDate = originalEnd.split('T')[0] const segmentStartDate = eventProps.start.split('T')[0] const segmentEndDate = eventProps.end.split('T')[0] - // First segment: event starts on this day (exact match or same date) - const isFirstSegment = - event.start === eventProps.start || - eventStartDate === segmentStartDate + // First segment: this segment's start date matches the original event's start date + const isFirstSegment = originalStartDate === segmentStartDate - // Last segment: event ends on this day - // For multi-day events, check if this segment's date matches the event's end date + // Last segment: this segment's date matches the original event's end date const isLastSegment = - event.end === eventProps.end || - eventEndDate === segmentEndDate || - eventEndDate === segmentStartDate + originalEndDate === segmentEndDate || + originalEndDate === segmentStartDate const isBeingResized = resizeState.isResizing && resizeState.eventId === event.id @@ -593,13 +591,8 @@ function ScheduleView({ // Show bottom handle if: // 1. Not a split event (single day), OR - // 2. This segment's date matches the event's end date (last segment) - // Check if the event ends on this day by comparing the dayDate with eventEndDate - const showBottomHandle = - !isSplitEvent || - dayDate === eventEndDate || - eventEndDate === segmentStartDate || - eventEndDate === segmentEndDate + // 2. This is the last segment (matches original event's end date) + const showBottomHandle = !isSplitEvent || isLastSegment // Check if this segment is being actively resized (original or new target) const isActivelyResized = isBeingResized && previewStyle !== null @@ -630,8 +623,8 @@ function ScheduleView({ {...getResizeHandleProps( event.id, 'top', - event.start, - event.end, + event._originalStart ?? event.start, + event._originalEnd ?? event.end, )} /> )} @@ -655,8 +648,8 @@ function ScheduleView({ {...getResizeHandleProps( event.id, 'bottom', - event.start, - event.end, + event._originalStart ?? event.start, + event._originalEnd ?? event.end, )} /> )} diff --git a/packages/time/src/calendar/splitMultiDayEvents.ts b/packages/time/src/calendar/splitMultiDayEvents.ts index 541d70fe..f0e1d167 100644 --- a/packages/time/src/calendar/splitMultiDayEvents.ts +++ b/packages/time/src/calendar/splitMultiDayEvents.ts @@ -33,6 +33,8 @@ export const splitMultiDayEvents = < ...event, start: eventStart.toPlainDateTime().toString(), end: eventEnd.toPlainDateTime().toString(), + _originalStart: event.start, + _originalEnd: event.end, }) currentDay = startOfDay.add({ days: 1 }) diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index 27c6b365..9385179b 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -23,6 +23,10 @@ export interface Event { end: string title: string resources?: Array + /** Original start time before splitting (only set on split segments of multi-day events) */ + _originalStart?: string + /** Original end time before splitting (only set on split segments of multi-day events) */ + _originalEnd?: string } export type Day< From d8e6c6da2996cc171671e99d21c35f8643734bd0 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Thu, 29 Jan 2026 22:37:09 +0100 Subject: [PATCH 042/207] feat: event resize --- examples/react/basic/src/index.tsx | 67 +++++++++++++++++++----------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index c2683acc..a8b3fbf6 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -463,20 +463,24 @@ function ScheduleView({ const eventProps = calendar.getEventProps(event) const { style, isSplitEvent } = eventProps + // Original event times (for resize calculations) const originalStart = event._originalStart ?? event.start const originalEnd = event._originalEnd ?? event.end const originalStartDate = originalStart.split('T')[0] const originalEndDate = originalEnd.split('T')[0] - const segmentStartDate = eventProps.start.split('T')[0] - const segmentEndDate = eventProps.end.split('T')[0] + + // Segment times (the actual bounds of THIS day's portion) + // Note: event.start/end are segment bounds, eventProps.start/end are full event bounds + const segmentStart = event.start + const segmentEnd = event.end + const segmentStartDate = segmentStart.split('T')[0] + const segmentEndDate = segmentEnd.split('T')[0] // First segment: this segment's start date matches the original event's start date const isFirstSegment = originalStartDate === segmentStartDate // Last segment: this segment's date matches the original event's end date - const isLastSegment = - originalEndDate === segmentEndDate || - originalEndDate === segmentStartDate + const isLastSegment = originalEndDate === segmentStartDate || originalEndDate === segmentEndDate const isBeingResized = resizeState.isResizing && resizeState.eventId === event.id @@ -487,12 +491,11 @@ function ScheduleView({ ((resizeState.edge === 'top' && isFirstSegment) || (resizeState.edge === 'bottom' && isLastSegment)) - // Check if resize is spanning multiple days - const segmentDate = eventProps.start.split('T')[0] + // Check if resize is spanning multiple days (mouse moved to a different day than segment) const isSpanningMultipleDays = isThisSegmentBeingResized && resizeState.targetDayDate !== null && - resizeState.targetDayDate !== segmentDate + resizeState.targetDayDate !== segmentStartDate // Calculate display style based on resize state let previewStyle: { top: string; height: string } | null = null @@ -512,27 +515,41 @@ function ScheduleView({ const isBeingShrunkAway = isThisSegmentBeingResized && !previewAffectsThisDay + // Check if the preview has actually changed from the original event bounds + const hasPreviewChanged = + resizeState.previewStart !== originalStart || + resizeState.previewEnd !== originalEnd + if (isBeingShrunkAway) { // This segment is being removed by the resize, hide it shouldHideSegment = true } else if (isThisSegmentBeingResized && isSpanningMultipleDays && previewAffectsThisDay) { - // Extending to another day - use multi-day style + // Extending to another day - use multi-day style with SEGMENT bounds previewStyle = calculateOriginalSegmentStyleForMultiDay( - eventProps.start, - eventProps.end, + segmentStart, + segmentEnd, resizeState.edge, true, ) - } else if (isThisSegmentBeingResized && !isSpanningMultipleDays) { - // Normal resize within same day + } else if (isThisSegmentBeingResized && !isSpanningMultipleDays && hasPreviewChanged) { + // Normal resize within same day - only apply if preview actually changed + // For multi-day events, the segment always starts at midnight (for non-first segments) + // and ends at end of day (for non-last segments), except for the actual boundaries + const effectivePreviewStart = resizeState.edge === 'top' && previewStartDateStr === dayDate + ? resizeState.previewStart + : segmentStart + const effectivePreviewEnd = resizeState.edge === 'bottom' && previewEndDateStr === dayDate + ? resizeState.previewEnd + : segmentEnd + previewStyle = calculatePreviewStyleForSegment( - resizeState.previewStart, - resizeState.previewEnd, - eventProps.start, - eventProps.end, + effectivePreviewStart, + effectivePreviewEnd, + segmentStart, + segmentEnd, resizeState.edge, ) - } else if (!isThisSegmentBeingResized && previewAffectsThisDay) { + } else if (!isThisSegmentBeingResized && previewAffectsThisDay && hasPreviewChanged) { // This segment is newly affected by the resize (e.g., shrinking to this day) // Check if this is the new "last segment" for bottom resize const isNewLastSegment = @@ -544,8 +561,8 @@ function ScheduleView({ previewStyle = calculatePreviewStyleForSegment( resizeState.previewStart, resizeState.previewEnd, - eventProps.start, - eventProps.end, + segmentStart, + segmentEnd, resizeState.edge, ) } @@ -561,9 +578,9 @@ function ScheduleView({ ? { ...style, ...previewStyle } : style - // Calculate display times based on preview - let displayStart = eventProps.start - let displayEnd = eventProps.end + // Calculate display times based on preview (use segment times as base) + let displayStart = segmentStart + let displayEnd = segmentEnd if (isBeingResized && resizeState.previewStart && resizeState.previewEnd) { const previewEndDateStr = resizeState.previewEnd.split('T')[0] @@ -578,9 +595,9 @@ function ScheduleView({ // For bottom edge resize, update end if this is the new last segment if (previewEndDateStr === dayDate) { displayEnd = resizeState.previewEnd - } else if (isThisSegmentBeingResized && previewEndDateStr !== segmentDate) { + } else if (isThisSegmentBeingResized && previewEndDateStr !== segmentStartDate) { // Extending to next day - show end of day for current segment - displayEnd = `${segmentDate}T23:59:00` + displayEnd = `${segmentStartDate}T23:59:00` } } } From 144d940e0bf9b9c12fc594134bfc812e92728bef Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Thu, 29 Jan 2026 22:42:13 +0100 Subject: [PATCH 043/207] feat: event resize --- examples/react/basic/src/index.tsx | 174 +++++++++++++++++------------ 1 file changed, 103 insertions(+), 71 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index a8b3fbf6..895292c3 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -507,13 +507,11 @@ function ScheduleView({ // Check if this segment's day is within the preview range const previewAffectsThisDay = - previewStartDateStr === dayDate || - previewEndDateStr === dayDate || - (previewStartDateStr < dayDate && previewEndDateStr > dayDate) + dayDate >= previewStartDateStr && dayDate <= previewEndDateStr - // Check if this segment is being shrunk away (not in preview range anymore) - const isBeingShrunkAway = - isThisSegmentBeingResized && !previewAffectsThisDay + // Check if this segment should be hidden (not in preview range anymore) + // This applies to ANY segment of the event being resized, not just the edge being resized + const isBeingShrunkAway = !previewAffectsThisDay // Check if the preview has actually changed from the original event bounds const hasPreviewChanged = @@ -523,48 +521,46 @@ function ScheduleView({ if (isBeingShrunkAway) { // This segment is being removed by the resize, hide it shouldHideSegment = true - } else if (isThisSegmentBeingResized && isSpanningMultipleDays && previewAffectsThisDay) { - // Extending to another day - use multi-day style with SEGMENT bounds - previewStyle = calculateOriginalSegmentStyleForMultiDay( - segmentStart, - segmentEnd, - resizeState.edge, - true, - ) - } else if (isThisSegmentBeingResized && !isSpanningMultipleDays && hasPreviewChanged) { - // Normal resize within same day - only apply if preview actually changed - // For multi-day events, the segment always starts at midnight (for non-first segments) - // and ends at end of day (for non-last segments), except for the actual boundaries - const effectivePreviewStart = resizeState.edge === 'top' && previewStartDateStr === dayDate - ? resizeState.previewStart - : segmentStart - const effectivePreviewEnd = resizeState.edge === 'bottom' && previewEndDateStr === dayDate - ? resizeState.previewEnd - : segmentEnd - - previewStyle = calculatePreviewStyleForSegment( - effectivePreviewStart, - effectivePreviewEnd, - segmentStart, - segmentEnd, - resizeState.edge, - ) - } else if (!isThisSegmentBeingResized && previewAffectsThisDay && hasPreviewChanged) { - // This segment is newly affected by the resize (e.g., shrinking to this day) - // Check if this is the new "last segment" for bottom resize - const isNewLastSegment = - resizeState.edge === 'bottom' && previewEndDateStr === dayDate - const isNewFirstSegment = - resizeState.edge === 'top' && previewStartDateStr === dayDate - - if (isNewLastSegment || isNewFirstSegment) { - previewStyle = calculatePreviewStyleForSegment( - resizeState.previewStart, - resizeState.previewEnd, - segmentStart, - segmentEnd, - resizeState.edge, - ) + } else if (previewAffectsThisDay && hasPreviewChanged) { + // This segment is within the preview range - calculate its new bounds + const isPreviewFirstDay = previewStartDateStr === dayDate + const isPreviewLastDay = previewEndDateStr === dayDate + + // Calculate the effective start and end for this segment in the preview + let effectiveStart: string + let effectiveEnd: string + + if (isPreviewFirstDay && isPreviewLastDay) { + // Single day event - use exact preview times + effectiveStart = resizeState.previewStart + effectiveEnd = resizeState.previewEnd + } else if (isPreviewFirstDay) { + // First day of multi-day - start at preview start, end at end of day + effectiveStart = resizeState.previewStart + effectiveEnd = `${dayDate}T23:59:59` + } else if (isPreviewLastDay) { + // Last day of multi-day - start at beginning of day, end at preview end + effectiveStart = `${dayDate}T00:00:00` + effectiveEnd = resizeState.previewEnd + } else { + // Middle day - full day + effectiveStart = `${dayDate}T00:00:00` + effectiveEnd = `${dayDate}T23:59:59` + } + + // Calculate preview style from effective times + const startDate = new Date(effectiveStart) + const endDate = new Date(effectiveEnd) + const startMinutes = startDate.getHours() * 60 + startDate.getMinutes() + const endMinutes = endDate.getHours() * 60 + endDate.getMinutes() || MINUTES_IN_DAY + const topPercent = (startMinutes / MINUTES_IN_DAY) * 100 + const heightPercent = ((endMinutes - startMinutes) / MINUTES_IN_DAY) * 100 + + if (heightPercent > 0) { + previewStyle = { + top: `${topPercent}%`, + height: `${Math.max(heightPercent, (30 / MINUTES_IN_DAY) * 100)}%`, + } } } } @@ -585,19 +581,23 @@ function ScheduleView({ if (isBeingResized && resizeState.previewStart && resizeState.previewEnd) { const previewEndDateStr = resizeState.previewEnd.split('T')[0] const previewStartDateStr = resizeState.previewStart.split('T')[0] + const previewAffectsThisDay = dayDate >= previewStartDateStr && dayDate <= previewEndDateStr + + if (previewAffectsThisDay) { + const isPreviewFirstDay = previewStartDateStr === dayDate + const isPreviewLastDay = previewEndDateStr === dayDate - if (resizeState.edge === 'top') { - // For top edge resize, update start if this is the new first segment - if (previewStartDateStr === dayDate) { + // Update display times based on position in preview range + if (isPreviewFirstDay) { displayStart = resizeState.previewStart + } else { + displayStart = `${dayDate}T00:00:00` } - } else if (resizeState.edge === 'bottom') { - // For bottom edge resize, update end if this is the new last segment - if (previewEndDateStr === dayDate) { + + if (isPreviewLastDay) { displayEnd = resizeState.previewEnd - } else if (isThisSegmentBeingResized && previewEndDateStr !== segmentStartDate) { - // Extending to next day - show end of day for current segment - displayEnd = `${segmentStartDate}T23:59:00` + } else { + displayEnd = `${dayDate}T23:59:00` } } } @@ -673,43 +673,75 @@ function ScheduleView({
) })} - {/* Ghost preview on target day when resizing across days */} + {/* Ghost preview on ALL days in preview range when resizing across days */} {resizeState.isResizing && - resizeState.targetDayDate === dayDate && resizeState.previewStart && resizeState.previewEnd && (() => { const previewStartDate = resizeState.previewStart.split('T')[0] const previewEndDate = resizeState.previewEnd.split('T')[0] + // Check if this day already has a segment of the event being resized const eventOnThisDay = day.events.some( (e) => e.id === resizeState.eventId, ) + + // Check if this day is within the new preview range const isDayInPreviewRange = dayDate >= previewStartDate && dayDate <= previewEndDate + // Show ghost on days that are in the preview range but don't have an existing segment if (!eventOnThisDay && isDayInPreviewRange) { - const ghostStyle = calculateGhostPreviewStyle( - resizeState.previewStart, - resizeState.previewEnd, - resizeState.edge, - ) + // Calculate ghost style based on position in the range + const isFirstDay = dayDate === previewStartDate + const isLastDay = dayDate === previewEndDate + + let ghostTop: number + let ghostBottom: number + + if (isFirstDay && isLastDay) { + // Single day - use actual times + const startDate = new Date(resizeState.previewStart) + const endDate = new Date(resizeState.previewEnd) + ghostTop = (startDate.getHours() * 60 + startDate.getMinutes()) / MINUTES_IN_DAY * 100 + ghostBottom = (endDate.getHours() * 60 + endDate.getMinutes()) / MINUTES_IN_DAY * 100 + } else if (isFirstDay) { + // First day of multi-day range + const startDate = new Date(resizeState.previewStart) + ghostTop = (startDate.getHours() * 60 + startDate.getMinutes()) / MINUTES_IN_DAY * 100 + ghostBottom = 100 // End of day + } else if (isLastDay) { + // Last day of multi-day range + const endDate = new Date(resizeState.previewEnd) + ghostTop = 0 // Start of day + ghostBottom = (endDate.getHours() * 60 + endDate.getMinutes()) / MINUTES_IN_DAY * 100 + } else { + // Middle day - full day + ghostTop = 0 + ghostBottom = 100 + } + + const ghostHeight = ghostBottom - ghostTop + if (ghostHeight <= 0) return null - if (!ghostStyle) return null + const ghostStyle = { + top: `${ghostTop}%`, + height: `${Math.max(ghostHeight, (30 / MINUTES_IN_DAY) * 100)}%`, + } // Calculate display times for the ghost - const ghostStartTime = resizeState.edge === 'bottom' - ? '00:00' - : new Date(resizeState.previewStart).toLocaleTimeString('en-US', { + const ghostStartTime = isFirstDay + ? new Date(resizeState.previewStart).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', }) - const ghostEndTime = resizeState.edge === 'top' - ? '11:59 PM' - : new Date(resizeState.previewEnd).toLocaleTimeString('en-US', { + : '12:00 AM' + const ghostEndTime = isLastDay + ? new Date(resizeState.previewEnd).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', }) + : '11:59 PM' return (
Date: Thu, 29 Jan 2026 22:42:34 +0100 Subject: [PATCH 044/207] feat: event resize --- examples/react/basic/src/index.tsx | 148 ----------------------------- 1 file changed, 148 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 895292c3..0f022ba2 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -259,154 +259,10 @@ function ResizeHandle({ edge, onMouseDown }: ResizeHandleProps) { ) } -function calculatePreviewStyleForSegment( - previewStart: string, - previewEnd: string, - segmentStart: string, - segmentEnd: string, - edge: 'top' | 'bottom' | null, -): { top: string; height: string } | null { - const previewStartDate = new Date(previewStart) - const previewEndDate = new Date(previewEnd) - const segmentStartDate = new Date(segmentStart) - const segmentEndDate = new Date(segmentEnd) - - // Get the date part (YYYY-MM-DD) for comparison - const segmentDate = segmentStart.split('T')[0] - const previewStartDateStr = previewStart.split('T')[0] - const previewEndDateStr = previewEnd.split('T')[0] - - let effectiveStart: Date - let effectiveEnd: Date - - if (edge === 'top') { - // For top edge resize, check if preview start is on the same day as segment - if (previewStartDateStr !== segmentDate) { - // Preview start is on a different day, use segment start - effectiveStart = segmentStartDate - } else { - effectiveStart = previewStartDate - } - effectiveEnd = segmentEndDate - } else if (edge === 'bottom') { - // For bottom edge resize, check if preview end is on the same day as segment - effectiveStart = segmentStartDate - if (previewEndDateStr !== segmentDate) { - // Preview end is on a different day, use segment end (end of day) - effectiveEnd = new Date(segmentDate + 'T23:59:59') - } else { - effectiveEnd = previewEndDate - } - } else { - // For both edges or no edge specified, check if preview spans this segment's day - if (previewStartDateStr === segmentDate && previewEndDateStr === segmentDate) { - // Both preview times are on the same day as segment - effectiveStart = previewStartDate - effectiveEnd = previewEndDate - } else if (previewStartDateStr === segmentDate) { - // Only start is on this day - effectiveStart = previewStartDate - effectiveEnd = new Date(segmentDate + 'T23:59:59') - } else if (previewEndDateStr === segmentDate) { - // Only end is on this day - effectiveStart = new Date(segmentDate + 'T00:00:00') - effectiveEnd = previewEndDate - } else { - // Preview doesn't span this day at all - return null - } - } - - const startMinutes = effectiveStart.getHours() * 60 + effectiveStart.getMinutes() - const endMinutes = effectiveEnd.getHours() * 60 + effectiveEnd.getMinutes() - const durationMinutes = endMinutes - startMinutes - - if (durationMinutes <= 0) return null - - const topPercent = (startMinutes / MINUTES_IN_DAY) * 100 - const heightPercent = (durationMinutes / MINUTES_IN_DAY) * 100 - - return { - top: `${topPercent}%`, - height: `${Math.max(heightPercent, (30 / MINUTES_IN_DAY) * 100)}%`, - } -} // Calculate style for original segment when resizing spans multiple days -function calculateOriginalSegmentStyleForMultiDay( - originalStart: string, - originalEnd: string, - edge: 'top' | 'bottom' | null, - isSpanningMultipleDays: boolean, -): { top: string; height: string } | null { - if (!isSpanningMultipleDays) return null - - const startDate = new Date(originalStart) - const endDate = new Date(originalEnd) - - let startMinutes: number - let endMinutes: number - - if (edge === 'bottom') { - // Resizing bottom to next day: original shows from start to end of day - startMinutes = startDate.getHours() * 60 + startDate.getMinutes() - endMinutes = MINUTES_IN_DAY // 23:59 (end of day) - } else if (edge === 'top') { - // Resizing top to previous day: original shows from start of day to end - startMinutes = 0 // 00:00 (start of day) - endMinutes = endDate.getHours() * 60 + endDate.getMinutes() - } else { - return null - } - - const durationMinutes = endMinutes - startMinutes - if (durationMinutes <= 0) return null - - const topPercent = (startMinutes / MINUTES_IN_DAY) * 100 - const heightPercent = (durationMinutes / MINUTES_IN_DAY) * 100 - - return { - top: `${topPercent}%`, - height: `${Math.max(heightPercent, (30 / MINUTES_IN_DAY) * 100)}%`, - } -} // Calculate style for ghost preview on target day -function calculateGhostPreviewStyle( - previewStart: string, - previewEnd: string, - edge: 'top' | 'bottom' | null, -): { top: string; height: string } | null { - const previewStartDate = new Date(previewStart) - const previewEndDate = new Date(previewEnd) - - let startMinutes: number - let endMinutes: number - - if (edge === 'bottom') { - // Resizing bottom to next day: ghost starts at 00:00 and ends at preview end time - startMinutes = 0 - endMinutes = previewEndDate.getHours() * 60 + previewEndDate.getMinutes() - } else if (edge === 'top') { - // Resizing top to previous day: ghost starts at preview start time and ends at 23:59 - startMinutes = previewStartDate.getHours() * 60 + previewStartDate.getMinutes() - endMinutes = MINUTES_IN_DAY - } else { - startMinutes = previewStartDate.getHours() * 60 + previewStartDate.getMinutes() - endMinutes = previewEndDate.getHours() * 60 + previewEndDate.getMinutes() - } - - const durationMinutes = endMinutes - startMinutes - if (durationMinutes <= 0) return null - - const topPercent = (startMinutes / MINUTES_IN_DAY) * 100 - const heightPercent = (durationMinutes / MINUTES_IN_DAY) * 100 - - return { - top: `${topPercent}%`, - height: `${Math.max(heightPercent, (30 / MINUTES_IN_DAY) * 100)}%`, - } -} function ScheduleView({ calendar, @@ -492,10 +348,6 @@ function ScheduleView({ (resizeState.edge === 'bottom' && isLastSegment)) // Check if resize is spanning multiple days (mouse moved to a different day than segment) - const isSpanningMultipleDays = - isThisSegmentBeingResized && - resizeState.targetDayDate !== null && - resizeState.targetDayDate !== segmentStartDate // Calculate display style based on resize state let previewStyle: { top: string; height: string } | null = null From 191d8186c4db1d386230f4dd35512b957d49395b Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Thu, 29 Jan 2026 22:52:18 +0100 Subject: [PATCH 045/207] feat: event resize --- examples/react/basic/src/index.tsx | 91 ++++++++++++------------------ 1 file changed, 36 insertions(+), 55 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 0f022ba2..af1628a1 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -426,34 +426,6 @@ function ScheduleView({ ? { ...style, ...previewStyle } : style - // Calculate display times based on preview (use segment times as base) - let displayStart = segmentStart - let displayEnd = segmentEnd - - if (isBeingResized && resizeState.previewStart && resizeState.previewEnd) { - const previewEndDateStr = resizeState.previewEnd.split('T')[0] - const previewStartDateStr = resizeState.previewStart.split('T')[0] - const previewAffectsThisDay = dayDate >= previewStartDateStr && dayDate <= previewEndDateStr - - if (previewAffectsThisDay) { - const isPreviewFirstDay = previewStartDateStr === dayDate - const isPreviewLastDay = previewEndDateStr === dayDate - - // Update display times based on position in preview range - if (isPreviewFirstDay) { - displayStart = resizeState.previewStart - } else { - displayStart = `${dayDate}T00:00:00` - } - - if (isPreviewLastDay) { - displayEnd = resizeState.previewEnd - } else { - displayEnd = `${dayDate}T23:59:00` - } - } - } - // For multi-day events, show handles on first/last segments // For single-day events, show both handles const showTopHandle = !isSplitEvent || isFirstSegment @@ -498,19 +470,30 @@ function ScheduleView({ /> )}
{event.title}
- {displayStyle && parseFloat(displayStyle.height) > 2 && ( -
- {new Date(displayStart).toLocaleTimeString('en-US', { - hour: 'numeric', - minute: '2-digit', - })} - {' - '} - {new Date(displayEnd).toLocaleTimeString('en-US', { - hour: 'numeric', - minute: '2-digit', - })} -
- )} + {displayStyle && parseFloat(displayStyle.height) > 2 && (() => { + const startDt = new Date(isBeingResized ? resizeState.previewStart! : originalStart) + const endDt = new Date(isBeingResized ? resizeState.previewEnd! : originalEnd) + const isMultiDay = startDt.toDateString() !== endDt.toDateString() + + if (isMultiDay) { + return ( +
+ {startDt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}{' '} + {startDt.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })} + {' - '} + {endDt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}{' '} + {endDt.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })} +
+ ) + } + return ( +
+ {startDt.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })} + {' - '} + {endDt.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })} +
+ ) + })()} {showBottomHandle && (
- {ghostStartTime} - {ghostEndTime} + {ghostStart} - {ghostEnd}
) From 475b1826b9d8802ebca83739d2418ee1790d457c Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Thu, 29 Jan 2026 23:34:50 +0100 Subject: [PATCH 046/207] feat: event resize --- examples/react/basic/src/index.tsx | 8 +------- packages/react-time/src/useCalendar/useCalendar.ts | 5 +---- packages/time/src/calendar/calendar.ts | 1 + 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index af1628a1..5b1602b1 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -341,12 +341,6 @@ function ScheduleView({ const isBeingResized = resizeState.isResizing && resizeState.eventId === event.id - // Check if this event is being resized - const isThisSegmentBeingResized = - isBeingResized && - ((resizeState.edge === 'top' && isFirstSegment) || - (resizeState.edge === 'bottom' && isLastSegment)) - // Check if resize is spanning multiple days (mouse moved to a different day than segment) // Calculate display style based on resize state @@ -373,7 +367,7 @@ function ScheduleView({ if (isBeingShrunkAway) { // This segment is being removed by the resize, hide it shouldHideSegment = true - } else if (previewAffectsThisDay && hasPreviewChanged) { + } else if (hasPreviewChanged) { // This segment is within the preview range - calculate its new bounds const isPreviewFirstDay = previewStartDateStr === dayDate const isPreviewLastDay = previewEndDateStr === dayDate diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 020b2bcf..12d42eb9 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -249,8 +249,6 @@ export const useCalendar = < document.addEventListener('mousemove', handleMouseMove) document.addEventListener('mouseup', handleMouseUp) - document.body.style.cursor = 'ns-resize' - document.body.style.userSelect = 'none' }, }), [resizeEnabled, handleMouseMove, handleMouseUp, resize, updateResizeState], @@ -348,7 +346,6 @@ export const useCalendar = < ) const days = useMemo(() => { - // state dependency triggers recalculation when calendar state changes void state return calendarCore.getDaysWithEvents() }, [calendarCore, state]) @@ -357,7 +354,7 @@ export const useCalendar = < activeDate: state.activeDate.toString(), currentPeriod: state.currentPeriod.toString(), viewMode: state.viewMode, - days: calendarCore.getDaysWithEvents(), + days, getDaysNames, getTimeSlots, getEventsByDate, diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index 983458a4..74fa716b 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -183,6 +183,7 @@ export class CalendarCore< } getDaysWithEvents() { + console.log('getDaysWithEvents') const calendarDays = this.getCalendarDays() const eventMap = this.getEventMap() return calendarDays.map((day) => { From d4e34dd7deead4a86cad20e479a63235105f47a7 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Sat, 31 Jan 2026 22:51:58 +0100 Subject: [PATCH 047/207] feat: calendar --- examples/react/basic/src/index.tsx | 267 ++++---------- packages/react-time/src/index.ts | 22 +- .../react-time/src/useCalendar/useCalendar.ts | 81 ++++- packages/time/src/calendar/getResizeProps.ts | 343 ++++++++++++++++++ 4 files changed, 486 insertions(+), 227 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 5b1602b1..a75ee4fd 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -1,4 +1,10 @@ -import { useCalendar } from '@tanstack/react-time' +import { + calculateGhostPreviewStyle, + calculateSegmentResizePreview, + formatEventTimeRange, + getSegmentInfo, + useCalendar, +} from '@tanstack/react-time' import ReactDOM from 'react-dom/client' import { useState } from 'react' import type { Day, Event, Resource } from '@tanstack/time' @@ -229,8 +235,6 @@ function EventModal({ ) } -const MINUTES_IN_DAY = 24 * 60 - interface ResizeHandleProps { edge: 'top' | 'bottom' onMouseDown: (e: React.MouseEvent) => void @@ -274,7 +278,7 @@ function ScheduleView({ onEventClick: (event: Event) => void }) { const timeSlots = calendar.getTimeSlots() - const { resizeState, getResizeHandleProps } = calendar + const { resizeState, getResizeHandleProps, getDayColumnProps } = calendar return (
@@ -306,7 +310,7 @@ function ScheduleView({
@@ -319,118 +323,40 @@ function ScheduleView({ const eventProps = calendar.getEventProps(event) const { style, isSplitEvent } = eventProps - // Original event times (for resize calculations) - const originalStart = event._originalStart ?? event.start - const originalEnd = event._originalEnd ?? event.end - const originalStartDate = originalStart.split('T')[0] - const originalEndDate = originalEnd.split('T')[0] - - // Segment times (the actual bounds of THIS day's portion) - // Note: event.start/end are segment bounds, eventProps.start/end are full event bounds - const segmentStart = event.start - const segmentEnd = event.end - const segmentStartDate = segmentStart.split('T')[0] - const segmentEndDate = segmentEnd.split('T')[0] - - // First segment: this segment's start date matches the original event's start date - const isFirstSegment = originalStartDate === segmentStartDate - - // Last segment: this segment's date matches the original event's end date - const isLastSegment = originalEndDate === segmentStartDate || originalEndDate === segmentEndDate + const segmentInfo = getSegmentInfo(event) + const { isFirstSegment, isLastSegment, originalStart, originalEnd } = segmentInfo const isBeingResized = resizeState.isResizing && resizeState.eventId === event.id - // Check if resize is spanning multiple days (mouse moved to a different day than segment) - - // Calculate display style based on resize state - let previewStyle: { top: string; height: string } | null = null - let shouldHideSegment = false - - if (isBeingResized && resizeState.previewStart && resizeState.previewEnd) { - const previewStartDateStr = resizeState.previewStart.split('T')[0] - const previewEndDateStr = resizeState.previewEnd.split('T')[0] - - // Check if this segment's day is within the preview range - const previewAffectsThisDay = - dayDate >= previewStartDateStr && dayDate <= previewEndDateStr - - // Check if this segment should be hidden (not in preview range anymore) - // This applies to ANY segment of the event being resized, not just the edge being resized - const isBeingShrunkAway = !previewAffectsThisDay - - // Check if the preview has actually changed from the original event bounds - const hasPreviewChanged = - resizeState.previewStart !== originalStart || - resizeState.previewEnd !== originalEnd - - if (isBeingShrunkAway) { - // This segment is being removed by the resize, hide it - shouldHideSegment = true - } else if (hasPreviewChanged) { - // This segment is within the preview range - calculate its new bounds - const isPreviewFirstDay = previewStartDateStr === dayDate - const isPreviewLastDay = previewEndDateStr === dayDate - - // Calculate the effective start and end for this segment in the preview - let effectiveStart: string - let effectiveEnd: string - - if (isPreviewFirstDay && isPreviewLastDay) { - // Single day event - use exact preview times - effectiveStart = resizeState.previewStart - effectiveEnd = resizeState.previewEnd - } else if (isPreviewFirstDay) { - // First day of multi-day - start at preview start, end at end of day - effectiveStart = resizeState.previewStart - effectiveEnd = `${dayDate}T23:59:59` - } else if (isPreviewLastDay) { - // Last day of multi-day - start at beginning of day, end at preview end - effectiveStart = `${dayDate}T00:00:00` - effectiveEnd = resizeState.previewEnd - } else { - // Middle day - full day - effectiveStart = `${dayDate}T00:00:00` - effectiveEnd = `${dayDate}T23:59:59` - } - - // Calculate preview style from effective times - const startDate = new Date(effectiveStart) - const endDate = new Date(effectiveEnd) - const startMinutes = startDate.getHours() * 60 + startDate.getMinutes() - const endMinutes = endDate.getHours() * 60 + endDate.getMinutes() || MINUTES_IN_DAY - const topPercent = (startMinutes / MINUTES_IN_DAY) * 100 - const heightPercent = ((endMinutes - startMinutes) / MINUTES_IN_DAY) * 100 - - if (heightPercent > 0) { - previewStyle = { - top: `${topPercent}%`, - height: `${Math.max(heightPercent, (30 / MINUTES_IN_DAY) * 100)}%`, - } - } - } - } - - // Skip rendering if segment is being shrunk away - if (shouldHideSegment) { + // Calculate preview state using library function + const resizePreview = isBeingResized && resizeState.previewStart && resizeState.previewEnd + ? calculateSegmentResizePreview({ + dayDate, + originalStart, + originalEnd, + previewStart: resizeState.previewStart, + previewEnd: resizeState.previewEnd, + }) + : null + + if (resizePreview?.shouldHide) { return null } - const displayStyle = previewStyle - ? { ...style, ...previewStyle } + const displayStyle = resizePreview?.previewStyle + ? { ...style, ...resizePreview.previewStyle } : style - // For multi-day events, show handles on first/last segments - // For single-day events, show both handles const showTopHandle = !isSplitEvent || isFirstSegment - - // Show bottom handle if: - // 1. Not a split event (single day), OR - // 2. This is the last segment (matches original event's end date) const showBottomHandle = !isSplitEvent || isLastSegment + const isActivelyResized = isBeingResized && resizePreview?.previewStyle !== null - // Check if this segment is being actively resized (original or new target) - const isActivelyResized = isBeingResized && previewStyle !== null + // Format time display using library function + const timeRange = formatEventTimeRange( + isBeingResized && resizeState.previewStart ? resizeState.previewStart : originalStart, + isBeingResized && resizeState.previewEnd ? resizeState.previewEnd : originalEnd, + ) return (
{ - // Don't trigger event click if clicking on resize handle if ( !resizeState.isResizing && !(e.target as HTMLElement).closest('[data-resize-handle]') @@ -458,130 +383,60 @@ function ScheduleView({ {...getResizeHandleProps( event.id, 'top', - event._originalStart ?? event.start, - event._originalEnd ?? event.end, + originalStart, + originalEnd, )} /> )}
{event.title}
- {displayStyle && parseFloat(displayStyle.height) > 2 && (() => { - const startDt = new Date(isBeingResized ? resizeState.previewStart! : originalStart) - const endDt = new Date(isBeingResized ? resizeState.previewEnd! : originalEnd) - const isMultiDay = startDt.toDateString() !== endDt.toDateString() - - if (isMultiDay) { - return ( -
- {startDt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}{' '} - {startDt.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })} - {' - '} - {endDt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}{' '} - {endDt.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })} -
- ) - } - return ( -
- {startDt.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })} - {' - '} - {endDt.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })} -
- ) - })()} + {displayStyle && parseFloat(displayStyle.height) > 2 && ( +
+ {timeRange.rangeFormatted} +
+ )} {showBottomHandle && ( )}
) })} - {/* Ghost preview on ALL days in preview range when resizing across days */} + {/* Ghost preview on days without existing segments */} {resizeState.isResizing && resizeState.previewStart && resizeState.previewEnd && + !day.events.some((e) => e.id === resizeState.eventId) && (() => { - const previewStartDate = resizeState.previewStart.split('T')[0] - const previewEndDate = resizeState.previewEnd.split('T')[0] + const ghostStyle = calculateGhostPreviewStyle({ + dayDate, + previewStart: resizeState.previewStart, + previewEnd: resizeState.previewEnd, + }) - // Check if this day already has a segment of the event being resized - const eventOnThisDay = day.events.some( - (e) => e.id === resizeState.eventId, + if (!ghostStyle) return null + + const timeRange = formatEventTimeRange( + resizeState.previewStart, + resizeState.previewEnd, ) - // Check if this day is within the new preview range - const isDayInPreviewRange = - dayDate >= previewStartDate && dayDate <= previewEndDate - - // Show ghost on days that are in the preview range but don't have an existing segment - if (!eventOnThisDay && isDayInPreviewRange) { - // Calculate ghost style based on position in the range - const isFirstDay = dayDate === previewStartDate - const isLastDay = dayDate === previewEndDate - - let ghostTop: number - let ghostBottom: number - - if (isFirstDay && isLastDay) { - // Single day - use actual times - const startDate = new Date(resizeState.previewStart) - const endDate = new Date(resizeState.previewEnd) - ghostTop = (startDate.getHours() * 60 + startDate.getMinutes()) / MINUTES_IN_DAY * 100 - ghostBottom = (endDate.getHours() * 60 + endDate.getMinutes()) / MINUTES_IN_DAY * 100 - } else if (isFirstDay) { - // First day of multi-day range - const startDate = new Date(resizeState.previewStart) - ghostTop = (startDate.getHours() * 60 + startDate.getMinutes()) / MINUTES_IN_DAY * 100 - ghostBottom = 100 // End of day - } else if (isLastDay) { - // Last day of multi-day range - const endDate = new Date(resizeState.previewEnd) - ghostTop = 0 // Start of day - ghostBottom = (endDate.getHours() * 60 + endDate.getMinutes()) / MINUTES_IN_DAY * 100 - } else { - // Middle day - full day - ghostTop = 0 - ghostBottom = 100 - } - - const ghostHeight = ghostBottom - ghostTop - if (ghostHeight <= 0) return null - - const ghostStyle = { - top: `${ghostTop}%`, - height: `${Math.max(ghostHeight, (30 / MINUTES_IN_DAY) * 100)}%`, - } - - // Display the full event date and time (only dates for multi-day) - const startDateTime = new Date(resizeState.previewStart) - const endDateTime = new Date(resizeState.previewEnd) - const isMultiDay = startDateTime.toDateString() !== endDateTime.toDateString() - - const ghostStart = isMultiDay - ? `${startDateTime.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} ${startDateTime.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}` - : startDateTime.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' }) - const ghostEnd = isMultiDay - ? `${endDateTime.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} ${endDateTime.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}` - : endDateTime.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' }) - - return ( -
-
- {ghostStart} - {ghostEnd} -
+ return ( +
+
+ {timeRange.rangeFormatted}
- ) - } - return null +
+ ) })()}
diff --git a/packages/react-time/src/index.ts b/packages/react-time/src/index.ts index 9fb4d791..ff52acbe 100644 --- a/packages/react-time/src/index.ts +++ b/packages/react-time/src/index.ts @@ -3,4 +3,24 @@ export type { ResizeState, ResizeOptions, UseCalendarOptions, -} from './useCalendar' \ No newline at end of file +} from './useCalendar' + +export { + calculateGhostPreviewStyle, + calculateSegmentResizePreview, + formatEventTimeRange, + getEventDisplayTimeRange, + getSegmentInfo, + isMultiDayEvent, +} from '@tanstack/time' + +export type { + EventTimeRange, + FormatEventTimeOptions, + FormattedEventTime, + GhostPreviewOptions, + PositionStyle, + ResizePreviewOptions, + SegmentInfo, + SegmentResizePreview, +} from '@tanstack/time' diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 12d42eb9..62b5b014 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -42,6 +42,10 @@ interface ResizeHandleHandlers { onMouseDown: (e: React.MouseEvent) => void } +interface DayColumnProps { + ref: (element: HTMLElement | null) => void +} + export interface UseCalendarOptions< TResource extends Resource, TEvent extends Event, @@ -58,8 +62,6 @@ const initialResizeState: ResizeState = { targetDayDate: null, } -const DEFAULT_CONTAINER_HEIGHT = 1440 - export const useCalendar = < TResource extends Resource, TEvent extends Event = Event, @@ -74,10 +76,11 @@ export const useCalendar = < originalStart: string, originalEnd: string, ) => ResizeHandleHandlers + getDayColumnProps: (dayDate: string) => DayColumnProps } => { const { resize, ...calendarOptions } = options const resizeEnabled = resize?.enabled ?? true - const containerHeight = resize?.containerHeight ?? DEFAULT_CONTAINER_HEIGHT + const containerHeight = resize?.containerHeight ?? 0 const constraints = resize?.constraints const [calendarCore] = useState( @@ -88,6 +91,7 @@ export const useCalendar = < const resizeStateRef = useRef(initialResizeState) const resizeListenersRef = useRef void>>(new Set()) + const dayColumnRefsRef = useRef>(new Map()) const originalEventRef = useRef<{ id: string start: string @@ -123,6 +127,16 @@ export const useCalendar = < getResizeSnapshot, ) + const getDayFromPoint = useCallback((x: number): string | null => { + for (const [dayDate, element] of dayColumnRefsRef.current) { + const rect = element.getBoundingClientRect() + if (x >= rect.left && x <= rect.right) { + return dayDate + } + } + return null + }, []) + const handleMouseMove = useCallback( (e: MouseEvent) => { if (!originalEventRef.current) return @@ -136,17 +150,7 @@ export const useCalendar = < containerHeight, ) - // Detect which day column the mouse is over - const dayColumns = document.querySelectorAll('[data-day-date]') - let targetDayDate: string | null = null - - for (const column of dayColumns) { - const rect = column.getBoundingClientRect() - if (e.clientX >= rect.left && e.clientX <= rect.right) { - targetDayDate = column.getAttribute('data-day-date') - break - } - } + const targetDayDate = getDayFromPoint(e.clientX) ?? originalDayDate // Calculate day offset if moved to a different day let dayOffsetMinutes = 0 @@ -158,7 +162,6 @@ export const useCalendar = < (1000 * 60 * 60 * 24), ) - // Apply day offset in both directions for flexible resizing dayOffsetMinutes = dayDiff * 24 * 60 originalEventRef.current.currentDayDate = targetDayDate } @@ -181,7 +184,13 @@ export const useCalendar = < targetDayDate, }) }, - [containerHeight, calendarOptions.timeZone, constraints, updateResizeState], + [ + containerHeight, + calendarOptions.timeZone, + constraints, + getDayFromPoint, + updateResizeState, + ], ) const handleMouseUp = useCallback(() => { @@ -209,6 +218,18 @@ export const useCalendar = < document.removeEventListener('mouseup', handleMouseUp) }, [calendarCore, handleMouseMove, resize, updateResizeState]) + const getDayFromElement = useCallback( + (element: HTMLElement): string | null => { + for (const [dayDate, dayElement] of dayColumnRefsRef.current) { + if (dayElement.contains(element)) { + return dayDate + } + } + return null + }, + [], + ) + const getResizeHandleProps = useCallback( ( eventId: string, @@ -222,9 +243,8 @@ export const useCalendar = < e.preventDefault() e.stopPropagation() - // Find the day column this event is in - const dayColumn = (e.target as HTMLElement).closest('[data-day-date]') - const dayDate = dayColumn?.getAttribute('data-day-date') ?? '' + const dayDate = getDayFromElement(e.target as HTMLElement) + if (!dayDate) return originalEventRef.current = { id: eventId, @@ -251,7 +271,27 @@ export const useCalendar = < document.addEventListener('mouseup', handleMouseUp) }, }), - [resizeEnabled, handleMouseMove, handleMouseUp, resize, updateResizeState], + [ + resizeEnabled, + getDayFromElement, + handleMouseMove, + handleMouseUp, + resize, + updateResizeState, + ], + ) + + const getDayColumnProps = useCallback( + (dayDate: string): DayColumnProps => ({ + ref: (element: HTMLElement | null) => { + if (element) { + dayColumnRefsRef.current.set(dayDate, element) + } else { + dayColumnRefsRef.current.delete(dayDate) + } + }, + }), + [], ) const goToPreviousPeriod = useCallback< @@ -373,5 +413,6 @@ export const useCalendar = < groupDaysBy, resizeState, getResizeHandleProps, + getDayColumnProps, } } diff --git a/packages/time/src/calendar/getResizeProps.ts b/packages/time/src/calendar/getResizeProps.ts index b1613f94..fd53aa0f 100644 --- a/packages/time/src/calendar/getResizeProps.ts +++ b/packages/time/src/calendar/getResizeProps.ts @@ -7,6 +7,11 @@ export interface ResizeConstraints { snapToMinutes?: number } +const MINUTES_IN_DAY = 24 * 60 + +const extractDateFromDateTime = (dateTime: string): string => + dateTime.split('T')[0] ?? dateTime + interface CalculateResizedEventOptions { originalStart: string originalEnd: string @@ -113,3 +118,341 @@ export function getResizeHandleStyle(edge: ResizeEdge): ResizeHandleStyle { } return { ...baseStyle, bottom: 0 } } + +/** + * Information about a segment's position within a multi-day event + */ +export interface SegmentInfo { + /** Whether this is the first segment of a multi-day event */ + isFirstSegment: boolean + /** Whether this is the last segment of a multi-day event */ + isLastSegment: boolean + /** Whether this segment is part of a split multi-day event */ + isSplitEvent: boolean + /** The original event start (before splitting) */ + originalStart: string + /** The original event end (before splitting) */ + originalEnd: string + /** The segment's start time */ + segmentStart: string + /** The segment's end time */ + segmentEnd: string +} + +/** + * Analyzes a segment to determine its position within a multi-day event + */ +export function getSegmentInfo(event: { + start: string + end: string + _originalStart?: string + _originalEnd?: string +}): SegmentInfo { + const originalStart = event._originalStart ?? event.start + const originalEnd = event._originalEnd ?? event.end + const originalStartDate = extractDateFromDateTime(originalStart) + const originalEndDate = extractDateFromDateTime(originalEnd) + + const segmentStart = event.start + const segmentEnd = event.end + const segmentStartDate = extractDateFromDateTime(segmentStart) + const segmentEndDate = extractDateFromDateTime(segmentEnd) + + const isSplitEvent = + event._originalStart !== undefined || event._originalEnd !== undefined + const isFirstSegment = originalStartDate === segmentStartDate + const isLastSegment = + originalEndDate === segmentStartDate || originalEndDate === segmentEndDate + + return { + isFirstSegment, + isLastSegment, + isSplitEvent, + originalStart, + originalEnd, + segmentStart, + segmentEnd, + } +} + +/** + * Style for positioned elements (events, ghosts) + */ +export interface PositionStyle { + top: string + height: string +} + +/** + * Result of resize preview calculation for a segment + */ +export interface SegmentResizePreview { + /** Whether the segment should be hidden (shrunk away) */ + shouldHide: boolean + /** The preview style to apply, if any */ + previewStyle: PositionStyle | null + /** Whether the preview has changed from the original */ + hasChanged: boolean +} + +export interface ResizePreviewOptions { + /** The date string of the day being rendered (YYYY-MM-DD) */ + dayDate: string + /** The original start of the event (before resize) */ + originalStart: string + /** The original end of the event (before resize) */ + originalEnd: string + /** The preview start during resize */ + previewStart: string + /** The preview end during resize */ + previewEnd: string +} + +/** + * Calculates the resize preview state for a segment on a specific day + */ +export function calculateSegmentResizePreview( + options: ResizePreviewOptions, +): SegmentResizePreview { + const { dayDate, originalStart, originalEnd, previewStart, previewEnd } = + options + + const previewStartDate = extractDateFromDateTime(previewStart) + const previewEndDate = extractDateFromDateTime(previewEnd) + + const previewAffectsThisDay = + dayDate >= previewStartDate && dayDate <= previewEndDate + + const hasChanged = + previewStart !== originalStart || previewEnd !== originalEnd + + if (!previewAffectsThisDay) { + return { shouldHide: true, previewStyle: null, hasChanged } + } + + if (!hasChanged) { + return { shouldHide: false, previewStyle: null, hasChanged: false } + } + + const isPreviewFirstDay = previewStartDate === dayDate + const isPreviewLastDay = previewEndDate === dayDate + + let effectiveStart: string + let effectiveEnd: string + + if (isPreviewFirstDay && isPreviewLastDay) { + effectiveStart = previewStart + effectiveEnd = previewEnd + } else if (isPreviewFirstDay) { + effectiveStart = previewStart + effectiveEnd = `${dayDate}T23:59:59` + } else if (isPreviewLastDay) { + effectiveStart = `${dayDate}T00:00:00` + effectiveEnd = previewEnd + } else { + effectiveStart = `${dayDate}T00:00:00` + effectiveEnd = `${dayDate}T23:59:59` + } + + const startDate = new Date(effectiveStart) + const endDate = new Date(effectiveEnd) + const startMinutes = startDate.getHours() * 60 + startDate.getMinutes() + const endMinutes = + endDate.getHours() * 60 + endDate.getMinutes() || MINUTES_IN_DAY + + const topPercent = (startMinutes / MINUTES_IN_DAY) * 100 + const heightPercent = ((endMinutes - startMinutes) / MINUTES_IN_DAY) * 100 + + if (heightPercent <= 0) { + return { shouldHide: true, previewStyle: null, hasChanged } + } + + const minHeightPercent = (30 / MINUTES_IN_DAY) * 100 + + return { + shouldHide: false, + previewStyle: { + top: `${topPercent}%`, + height: `${Math.max(heightPercent, minHeightPercent)}%`, + }, + hasChanged, + } +} + +export interface GhostPreviewOptions { + /** The date string of the day being rendered (YYYY-MM-DD) */ + dayDate: string + /** The preview start during resize */ + previewStart: string + /** The preview end during resize */ + previewEnd: string +} + +/** + * Calculates the ghost preview style for a day that doesn't have an existing segment + */ +export function calculateGhostPreviewStyle( + options: GhostPreviewOptions, +): PositionStyle | null { + const { dayDate, previewStart, previewEnd } = options + + const previewStartDate = extractDateFromDateTime(previewStart) + const previewEndDate = extractDateFromDateTime(previewEnd) + + const isDayInPreviewRange = + dayDate >= previewStartDate && dayDate <= previewEndDate + + if (!isDayInPreviewRange) { + return null + } + + const isFirstDay = dayDate === previewStartDate + const isLastDay = dayDate === previewEndDate + + let ghostTop: number + let ghostBottom: number + + if (isFirstDay && isLastDay) { + const startDate = new Date(previewStart) + const endDate = new Date(previewEnd) + ghostTop = + ((startDate.getHours() * 60 + startDate.getMinutes()) / MINUTES_IN_DAY) * + 100 + ghostBottom = + ((endDate.getHours() * 60 + endDate.getMinutes()) / MINUTES_IN_DAY) * 100 + } else if (isFirstDay) { + const startDate = new Date(previewStart) + ghostTop = + ((startDate.getHours() * 60 + startDate.getMinutes()) / MINUTES_IN_DAY) * + 100 + ghostBottom = 100 + } else if (isLastDay) { + const endDate = new Date(previewEnd) + ghostTop = 0 + ghostBottom = + ((endDate.getHours() * 60 + endDate.getMinutes()) / MINUTES_IN_DAY) * 100 + } else { + ghostTop = 0 + ghostBottom = 100 + } + + const ghostHeight = ghostBottom - ghostTop + if (ghostHeight <= 0) { + return null + } + + const minHeightPercent = (30 / MINUTES_IN_DAY) * 100 + + return { + top: `${ghostTop}%`, + height: `${Math.max(ghostHeight, minHeightPercent)}%`, + } +} + +/** + * Checks if an event spans multiple days + */ +export function isMultiDayEvent(start: string, end: string): boolean { + const startDate = new Date(start) + const endDate = new Date(end) + return startDate.toDateString() !== endDate.toDateString() +} + +export interface EventTimeRange { + start: string + end: string + isMultiDay: boolean +} + +/** + * Gets the time range to display for an event, considering resize state + */ +export function getEventDisplayTimeRange(options: { + originalStart: string + originalEnd: string + isBeingResized?: boolean + previewStart?: string + previewEnd?: string +}): EventTimeRange { + const { + originalStart, + originalEnd, + isBeingResized, + previewStart, + previewEnd, + } = options + + const displayStart = + isBeingResized && previewStart ? previewStart : originalStart + const displayEnd = isBeingResized && previewEnd ? previewEnd : originalEnd + + return { + start: displayStart, + end: displayEnd, + isMultiDay: isMultiDayEvent(displayStart, displayEnd), + } +} + +export interface FormatEventTimeOptions { + /** Locale for formatting (e.g., 'en-US') */ + locale?: string + /** Whether to include date for single-day events */ + alwaysShowDate?: boolean +} + +export interface FormattedEventTime { + /** Formatted start string */ + startFormatted: string + /** Formatted end string */ + endFormatted: string + /** Full formatted range string */ + rangeFormatted: string + /** Whether this is a multi-day event */ + isMultiDay: boolean +} + +/** + * Formats an event's time range for display + * For multi-day events: includes date and time + * For single-day events: includes only time (unless alwaysShowDate is true) + */ +export function formatEventTimeRange( + start: string, + end: string, + options: FormatEventTimeOptions = {}, +): FormattedEventTime { + const { locale = 'en-US', alwaysShowDate = false } = options + + const startDate = new Date(start) + const endDate = new Date(end) + const isMultiDay = startDate.toDateString() !== endDate.toDateString() + + const timeOptions: Intl.DateTimeFormatOptions = { + hour: 'numeric', + minute: '2-digit', + } + + const dateTimeOptions: Intl.DateTimeFormatOptions = { + month: 'short', + day: 'numeric', + hour: 'numeric', + minute: '2-digit', + } + + const showDate = isMultiDay || alwaysShowDate + + const startFormatted = showDate + ? startDate.toLocaleString(locale, dateTimeOptions) + : startDate.toLocaleTimeString(locale, timeOptions) + + const endFormatted = showDate + ? endDate.toLocaleString(locale, dateTimeOptions) + : endDate.toLocaleTimeString(locale, timeOptions) + + return { + startFormatted, + endFormatted, + rangeFormatted: `${startFormatted} - ${endFormatted}`, + isMultiDay, + } +} From e9ddc6dbc335091a0ed9db4dd85292b6f9a3fbcc Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Sat, 31 Jan 2026 22:57:02 +0100 Subject: [PATCH 048/207] feat: calendar example --- examples/react/basic/index.html | 2 +- examples/react/basic/src/index.css | 6 ++ examples/react/basic/src/index.tsx | 151 ++++++++++++++--------------- 3 files changed, 79 insertions(+), 80 deletions(-) diff --git a/examples/react/basic/index.html b/examples/react/basic/index.html index b68b51ab..4615473f 100644 --- a/examples/react/basic/index.html +++ b/examples/react/basic/index.html @@ -3,7 +3,7 @@ - + TanStack Time - React Basic Example diff --git a/examples/react/basic/src/index.css b/examples/react/basic/src/index.css index b5c61c95..b892ad29 100644 --- a/examples/react/basic/src/index.css +++ b/examples/react/basic/src/index.css @@ -1,3 +1,9 @@ @tailwind base; @tailwind components; @tailwind utilities; + +@layer base { + body { + @apply bg-black text-neutral-200 antialiased; + } +} diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index a75ee4fd..af9d172b 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -118,14 +118,14 @@ function EventModal({ } return ( -
-
-

+
+
+

{mode === 'add' ? 'Add Event' : 'Edit Event'}

-
-
-
-
-
@@ -207,7 +207,7 @@ function EventModal({ onDelete() onClose() }} - className="px-4 py-2 text-red-600 hover:bg-red-50 rounded-md" + className="px-4 py-2 text-red-400 hover:text-red-300 rounded-md" > Delete @@ -217,13 +217,13 @@ function EventModal({ @@ -244,18 +244,17 @@ function ResizeHandle({ edge, onMouseDown }: ResizeHandleProps) { return (
{ - // Prevent event click from firing when clicking resize handle e.stopPropagation() }} style={{ touchAction: 'none' }} >
@@ -264,10 +263,6 @@ function ResizeHandle({ edge, onMouseDown }: ResizeHandleProps) { } -// Calculate style for original segment when resizing spans multiple days - -// Calculate style for ghost preview on target day - function ScheduleView({ calendar, days, @@ -281,13 +276,13 @@ function ScheduleView({ const { resizeState, getResizeHandleProps, getDayColumnProps } = calendar return ( -
-
-
+
+
+
{timeSlots.map((slot) => (
{slot.label}
@@ -309,16 +304,16 @@ function ScheduleView({ return (
-
-
+
+
{dayName}
-
{day.date.day}
+
{day.date.day}
-
+
{day.events.map((event, eventIndex) => { const eventProps = calendar.getEventProps(event) const { style, isSplitEvent } = eventProps @@ -361,10 +356,10 @@ function ScheduleView({ return (
-
+
{timeRange.rangeFormatted}
@@ -546,20 +541,20 @@ function CalendarView() { } return ( -
+
-

- TanStack Time - Calendar Example +

+ TanStack Time

-
+
@@ -601,10 +594,10 @@ function CalendarView() { onClick={() => calendar.changeViewMode({ value: 1, unit: 'month' }) } - className={`px-3 py-1.5 rounded-md cursor-pointer ${ + className={`px-3 py-1.5 rounded-md border ${ calendar.viewMode.unit === 'month' - ? 'border-2 border-blue-500 bg-blue-50' - : 'border border-gray-300 bg-white' + ? 'border-neutral-500 bg-neutral-800 text-white' + : 'border-neutral-700 text-neutral-400 hover:text-neutral-200 hover:border-neutral-600' }`} > Month @@ -613,20 +606,20 @@ function CalendarView() { onClick={() => calendar.changeViewMode({ value: 1, unit: 'week' }) } - className={`px-3 py-1.5 rounded-md cursor-pointer ${ + className={`px-3 py-1.5 rounded-md border ${ calendar.viewMode.unit === 'week' - ? 'border-2 border-blue-500 bg-blue-50' - : 'border border-gray-300 bg-white' + ? 'border-neutral-500 bg-neutral-800 text-white' + : 'border-neutral-700 text-neutral-400 hover:text-neutral-200 hover:border-neutral-600' }`} > Week
-
+
{formatPeriodDate(calendar.currentPeriod)}
@@ -646,16 +639,16 @@ function CalendarView() { onEventClick={openEditModal} /> ) : ( -
+
{dayNames.map((dayName: string, index: number) => (
{dayName} @@ -677,13 +670,13 @@ function CalendarView() { return (
@@ -698,27 +691,27 @@ function CalendarView() { key={day.date.toString()} className={`min-h-[120px] p-2 relative ${ dayIndex < dayNames.length - 1 - ? 'border-r border-gray-200' + ? 'border-r border-neutral-800' : '' } ${ weekIndex < groupedDays.length - 1 - ? 'border-b border-gray-200' + ? 'border-b border-neutral-800' : '' } ${ isToday - ? 'bg-blue-50' + ? 'bg-neutral-900' : isInCurrentPeriod - ? 'bg-white' - : 'bg-gray-50' + ? 'bg-black' + : 'bg-neutral-950/50' }`} >
{day.date.day} @@ -727,7 +720,7 @@ function CalendarView() { {day.events.map((event) => (
openEditModal(event)} > @@ -744,7 +737,7 @@ function CalendarView() { )} {calendar.isPending && ( -
+
Loading...
)} From 72e9f89906f3884cbb23932d9bc346d70125dc3b Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 2 Feb 2026 13:09:48 +0100 Subject: [PATCH 049/207] feat: calendar example --- examples/react/basic/src/index.tsx | 70 ++++++++++++------- packages/time/src/calendar/groupDaysBy.ts | 4 +- packages/time/src/date/isWeekend/isWeekend.ts | 5 +- packages/time/src/polyfills/getWeekInfo.ts | 67 +++++++++++------- packages/time/src/utils/weekUtils.ts | 3 +- 5 files changed, 92 insertions(+), 57 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index af9d172b..7eff78d0 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -262,7 +262,6 @@ function ResizeHandle({ edge, onMouseDown }: ResizeHandleProps) { ) } - function ScheduleView({ calendar, days, @@ -311,7 +310,9 @@ function ScheduleView({
{dayName}
-
{day.date.day}
+
+ {day.date.day} +
{day.events.map((event, eventIndex) => { @@ -319,21 +320,30 @@ function ScheduleView({ const { style, isSplitEvent } = eventProps const segmentInfo = getSegmentInfo(event) - const { isFirstSegment, isLastSegment, originalStart, originalEnd } = segmentInfo + const { + isFirstSegment, + isLastSegment, + originalStart, + originalEnd, + } = segmentInfo const isBeingResized = - resizeState.isResizing && resizeState.eventId === event.id + resizeState.isResizing && + resizeState.eventId === event.id // Calculate preview state using library function - const resizePreview = isBeingResized && resizeState.previewStart && resizeState.previewEnd - ? calculateSegmentResizePreview({ - dayDate, - originalStart, - originalEnd, - previewStart: resizeState.previewStart, - previewEnd: resizeState.previewEnd, - }) - : null + const resizePreview = + isBeingResized && + resizeState.previewStart && + resizeState.previewEnd + ? calculateSegmentResizePreview({ + dayDate, + originalStart, + originalEnd, + previewStart: resizeState.previewStart, + previewEnd: resizeState.previewEnd, + }) + : null if (resizePreview?.shouldHide) { return null @@ -345,12 +355,17 @@ function ScheduleView({ const showTopHandle = !isSplitEvent || isFirstSegment const showBottomHandle = !isSplitEvent || isLastSegment - const isActivelyResized = isBeingResized && resizePreview?.previewStyle !== null + const isActivelyResized = + isBeingResized && resizePreview?.previewStyle !== null // Format time display using library function const timeRange = formatEventTimeRange( - isBeingResized && resizeState.previewStart ? resizeState.previewStart : originalStart, - isBeingResized && resizeState.previewEnd ? resizeState.previewEnd : originalEnd, + isBeingResized && resizeState.previewStart + ? resizeState.previewStart + : originalStart, + isBeingResized && resizeState.previewEnd + ? resizeState.previewEnd + : originalEnd, ) return ( @@ -366,7 +381,9 @@ function ScheduleView({ onClick={(e) => { if ( !resizeState.isResizing && - !(e.target as HTMLElement).closest('[data-resize-handle]') + !(e.target as HTMLElement).closest( + '[data-resize-handle]', + ) ) { onEventClick(event) } @@ -383,12 +400,15 @@ function ScheduleView({ )} /> )} -
{event.title}
- {displayStyle && parseFloat(displayStyle.height) > 2 && ( -
- {timeRange.rangeFormatted} -
- )} +
+ {event.title} +
+ {displayStyle && + parseFloat(displayStyle.height) > 2 && ( +
+ {timeRange.rangeFormatted} +
+ )} {showBottomHandle && ( {dayName} diff --git a/packages/time/src/calendar/groupDaysBy.ts b/packages/time/src/calendar/groupDaysBy.ts index caa1ed98..10da3650 100644 --- a/packages/time/src/calendar/groupDaysBy.ts +++ b/packages/time/src/calendar/groupDaysBy.ts @@ -1,4 +1,5 @@ import { Temporal } from '@js-temporal/polyfill' +import { getWeekInfo } from '../polyfills/getWeekInfo' import type { Day, Event, Resource } from './types' interface GroupDaysByBaseProps< @@ -46,8 +47,7 @@ export const groupDaysBy = < Array | null> > => { const groups: Array | null>> = [] - const loc = new Intl.Locale(locale) - const { weekend } = loc.getWeekInfo() + const { weekend } = getWeekInfo(locale) switch (unit) { case 'week': { diff --git a/packages/time/src/date/isWeekend/isWeekend.ts b/packages/time/src/date/isWeekend/isWeekend.ts index e6948c79..21aeb57b 100644 --- a/packages/time/src/date/isWeekend/isWeekend.ts +++ b/packages/time/src/date/isWeekend/isWeekend.ts @@ -1,6 +1,7 @@ import type { DateInput, DateOptions } from '../types' import { toZonedDateTime } from '~/date/helpers' import { getDateTimeDefaults } from '~/utils' +import { getWeekInfo } from '../../polyfills/getWeekInfo' export interface IsWeekendOptions extends DateOptions { locale?: string @@ -27,9 +28,7 @@ export function isWeekend( const zdt = toZonedDateTime(date, timeZone, calendar) const dayOfWeek = zdt.dayOfWeek - - const localeObj = new Intl.Locale(locale) - const weekInfo = localeObj.getWeekInfo() + const weekInfo = getWeekInfo(locale) return weekInfo.weekend.includes(dayOfWeek) } diff --git a/packages/time/src/polyfills/getWeekInfo.ts b/packages/time/src/polyfills/getWeekInfo.ts index 8bd7dd55..6a972f7d 100644 --- a/packages/time/src/polyfills/getWeekInfo.ts +++ b/packages/time/src/polyfills/getWeekInfo.ts @@ -1,3 +1,4 @@ +import { weekInfoData } from './weekInfoData' import type { WeekInfo } from './types' const normalizeLocale = (loc: string) => { @@ -7,37 +8,49 @@ const normalizeLocale = (loc: string) => { : lang?.toLowerCase() } -;(function () { - if ( - 'weekInfo' in Intl.Locale.prototype && - typeof Intl.Locale.prototype.getWeekInfo !== 'function' - ) { - Intl.Locale.prototype.getWeekInfo = function () { - return this.weekInfo - } +const DEFAULT_WEEK_INFO: WeekInfo = { + firstDay: 7, + weekend: [6, 7], + minimalDays: 1, +} + +function lookupWeekInfo(localeString: string): WeekInfo { + const normalizedLocale = normalizeLocale(localeString) + + let match: WeekInfo | undefined = weekInfoData[normalizedLocale ?? ''] + + if (!match) { + const mainLanguage = normalizedLocale?.split('-')[0] + match = weekInfoData[mainLanguage ?? ''] } - if (typeof Intl.Locale.prototype.getWeekInfo !== 'function') { - import('./weekInfoData').then(({ weekInfoData }) => { - Intl.Locale.prototype.getWeekInfo = function () { - const locale = this.toString() - const normalizedLocale = normalizeLocale(locale) + if (!match) { + match = Object.entries(weekInfoData).find( + ([key]) => normalizeLocale(key) === normalizedLocale, + )?.[1] + } - let match: WeekInfo | undefined = weekInfoData[normalizedLocale ?? ''] + if (!match) { + match = weekInfoData.en ?? weekInfoData['en-US'] ?? DEFAULT_WEEK_INFO + } - if (!match) { - const mainLanguage = normalizedLocale?.split('-')[0] - match = weekInfoData[mainLanguage ?? ''] - } + return match +} - if (!match) { - match = Object.entries(weekInfoData).find( - ([key]) => normalizeLocale(key) === normalizedLocale, - )?.[1] - } +export function getWeekInfo(locale: string | Intl.Locale): WeekInfo { + const localeString = typeof locale === 'string' ? locale : locale.toString() + return lookupWeekInfo(localeString) +} - return match - } - }) +if (typeof Intl !== 'undefined') { + const { prototype } = Intl.Locale + if ('weekInfo' in prototype && typeof prototype.getWeekInfo !== 'function') { + prototype.getWeekInfo = function () { + return this.weekInfo + } + } else if (typeof prototype.getWeekInfo !== 'function') { + prototype.getWeekInfo = function () { + return lookupWeekInfo(this.toString()) + } } -})() +} diff --git a/packages/time/src/utils/weekUtils.ts b/packages/time/src/utils/weekUtils.ts index 82f33054..7bd05cc5 100644 --- a/packages/time/src/utils/weekUtils.ts +++ b/packages/time/src/utils/weekUtils.ts @@ -1,4 +1,5 @@ import { Temporal } from '@js-temporal/polyfill' +import { getWeekInfo } from '../polyfills/getWeekInfo' /** * Get the first day of the month for a given year-month string @@ -19,7 +20,7 @@ export function getFirstDayOfWeek( locale: string, ): Temporal.PlainDate { const date = Temporal.PlainDate.from(dateString) - const weekInfo = new Intl.Locale(locale).getWeekInfo() + const weekInfo = getWeekInfo(locale) const firstDayOfWeek = weekInfo.firstDay const dayOfWeek = date.dayOfWeek const daysToSubtract = (dayOfWeek - firstDayOfWeek + 7) % 7 From f5e72988306876b6cee0400c2a74388ad22a4f23 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 2 Feb 2026 13:44:28 +0100 Subject: [PATCH 050/207] feat: calendar example --- packages/time/src/polyfills/getWeekInfo.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/time/src/polyfills/getWeekInfo.ts b/packages/time/src/polyfills/getWeekInfo.ts index 6a972f7d..a63d0cb9 100644 --- a/packages/time/src/polyfills/getWeekInfo.ts +++ b/packages/time/src/polyfills/getWeekInfo.ts @@ -1,3 +1,4 @@ +import { getDateTimeDefaults } from '../utils/dateTimeDefaults' import { weekInfoData } from './weekInfoData' import type { WeekInfo } from './types' @@ -37,8 +38,13 @@ function lookupWeekInfo(localeString: string): WeekInfo { return match } -export function getWeekInfo(locale: string | Intl.Locale): WeekInfo { - const localeString = typeof locale === 'string' ? locale : locale.toString() +export function getWeekInfo(locale?: string | Intl.Locale): WeekInfo { + const localeString = + locale == null + ? getDateTimeDefaults().locale + : typeof locale === 'string' + ? locale + : locale.toString() return lookupWeekInfo(localeString) } From 5169c0f443461aa489ae70883be243bd92c62cd6 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 2 Feb 2026 23:29:01 +0100 Subject: [PATCH 051/207] feat: availability rules --- examples/react/basic/src/index.tsx | 42 +++++- .../react-time/src/useCalendar/useCalendar.ts | 12 ++ packages/time/src/calendar/calendar.ts | 125 +++++++++++++++++- packages/time/src/calendar/types.ts | 22 +++ 4 files changed, 198 insertions(+), 3 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 7eff78d0..ff072ceb 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -272,7 +272,12 @@ function ScheduleView({ onEventClick: (event: Event) => void }) { const timeSlots = calendar.getTimeSlots() - const { resizeState, getResizeHandleProps, getDayColumnProps } = calendar + const { + resizeState, + getResizeHandleProps, + getDayColumnProps, + getUnavailableRanges, + } = calendar return (
@@ -315,6 +320,19 @@ function ScheduleView({
+ {getUnavailableRanges(dayDate, { resourceIds: ['1'] }).map( + (range, idx) => ( +
+ ), + )} {day.events.map((event, eventIndex) => { const eventProps = calendar.getEventProps(event) const { style, isSplitEvent } = eventProps @@ -371,7 +389,7 @@ function ScheduleView({ return (
= [ + { + id: '1', + label: 'Resource 1', + availability: [ + { + weekdays: [1, 2, 3, 4, 5], + startTime: '08:00', + endTime: '17:00', + }, + { + weekdays: [6, 7], + startTime: '10:00', + endTime: '15:00', + }, + ], + }, + ] + const calendar = useCalendar>({ viewMode: { value: 1, unit: 'month' }, events: sampleEvents, + resources, timeZone: 'UTC', resize: { enabled: true, diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 62b5b014..97a37443 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -385,6 +385,17 @@ export const useCalendar = < [calendarCore], ) + const getUnavailableRanges = useCallback< + typeof calendarCore.getUnavailableRanges + >( + (date, options) => + calendarCore.getUnavailableRanges(date, { + containerHeight: options?.containerHeight ?? containerHeight, + resourceIds: options?.resourceIds, + }), + [calendarCore, containerHeight], + ) + const days = useMemo(() => { void state return calendarCore.getDaysWithEvents() @@ -414,5 +425,6 @@ export const useCalendar = < resizeState, getResizeHandleProps, getDayColumnProps, + getUnavailableRanges, } } diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index 74fa716b..8c7ebf3c 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -5,7 +5,14 @@ import { groupDaysBy } from './groupDaysBy' import { getTimeSlots } from './getTimeSlots' import { DateCore } from './date-core' import type { DateCoreOptions, ParsedDateCoreOptions } from './date-core' -import type { Day, Event, Resource, TimeSlot, ViewMode } from './types' +import type { + Day, + Event, + Resource, + TimeSlot, + UnavailableRange, + ViewMode, +} from './types' export type * from './types' export * from './date-core' @@ -87,6 +94,14 @@ interface CalendarActions< updateEvent: (id: Event['id'], updates: Partial>) => void /** Removes an event by ID. */ removeEvent: (id: Event['id']) => void + /** Retrieves unavailable time ranges for a specific date based on resource availability. */ + getUnavailableRanges: ( + date: string, + options?: { + containerHeight?: number + resourceIds?: Array + }, + ) => Array } interface CalendarState< @@ -277,4 +292,112 @@ export class CalendarCore< eventsVersion: prev.eventsVersion + 1, })) } + + getUnavailableRanges( + date: string, + options?: { + containerHeight?: number + resourceIds?: Array + }, + ): Array { + const containerHeight = options?.containerHeight ?? 1440 + const resources = options?.resourceIds + ? this.options.resources?.filter((resource) => + options.resourceIds?.includes(resource.id), + ) + : this.options.resources + if (!resources || resources.length === 0) { + return [] + } + + const plainDate = Temporal.PlainDate.from(date) + const weekday = plainDate.dayOfWeek + + const availableRanges: Array<{ startMinutes: number; endMinutes: number }> = + [] + + for (const resource of resources) { + if (!resource.availability) continue + + for (const slot of resource.availability) { + if (!slot.weekdays.includes(weekday)) continue + + const startParts = slot.startTime.split(':').map(Number) + const endParts = slot.endTime.split(':').map(Number) + const startHour = startParts[0] ?? 0 + const startMin = startParts[1] ?? 0 + const endHour = endParts[0] ?? 0 + const endMin = endParts[1] ?? 0 + + const startMinutes = startHour * 60 + startMin + const endMinutes = endHour * 60 + endMin + + availableRanges.push({ startMinutes, endMinutes }) + } + } + + if (availableRanges.length === 0) { + return [ + { + top: 0, + height: containerHeight, + startTime: '00:00', + endTime: '24:00', + }, + ] + } + + availableRanges.sort((a, b) => a.startMinutes - b.startMinutes) + + const mergedAvailable: Array<{ startMinutes: number; endMinutes: number }> = + [] + for (const range of availableRanges) { + const last = mergedAvailable[mergedAvailable.length - 1] + if (last && range.startMinutes <= last.endMinutes) { + last.endMinutes = Math.max(last.endMinutes, range.endMinutes) + } else { + mergedAvailable.push({ ...range }) + } + } + + const unavailableRanges: Array<{ + startMinutes: number + endMinutes: number + }> = [] + let currentMinute = 0 + const dayEndMinutes = 24 * 60 + + for (const available of mergedAvailable) { + if (currentMinute < available.startMinutes) { + unavailableRanges.push({ + startMinutes: currentMinute, + endMinutes: available.startMinutes, + }) + } + currentMinute = available.endMinutes + } + + if (currentMinute < dayEndMinutes) { + unavailableRanges.push({ + startMinutes: currentMinute, + endMinutes: dayEndMinutes, + }) + } + + const minutesToPixels = (minutes: number) => + (minutes / dayEndMinutes) * containerHeight + + const formatTime = (minutes: number): string => { + const hours = Math.floor(minutes / 60) + const mins = minutes % 60 + return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}` + } + + return unavailableRanges.map((range) => ({ + top: minutesToPixels(range.startMinutes), + height: minutesToPixels(range.endMinutes - range.startMinutes), + startTime: formatTime(range.startMinutes), + endTime: formatTime(range.endMinutes), + })) + } } diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index 9385179b..ce9651fa 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -1,9 +1,20 @@ import type { Temporal } from '@js-temporal/polyfill' import type { DateInput } from '~/date' +export interface Availability { + /** Days of the week when available (ISO weekday: 1 = Monday, ..., 7 = Sunday) */ + weekdays: Array + /** Start time in HH:mm format */ + startTime: string + /** End time in HH:mm format */ + endTime: string +} + export interface Resource { id: string label: string + /** Optional availability schedule for this resource */ + availability?: Array } /** @@ -50,6 +61,17 @@ export interface TimeSlot { label: string } +export interface UnavailableRange { + /** Top position in pixels */ + top: number + /** Height in pixels */ + height: number + /** Start time as HH:mm string */ + startTime: string + /** End time as HH:mm string */ + endTime: string +} + export interface CalendarStore { currentPeriod: Temporal.PlainDate activeDate: Temporal.PlainDate From 049aa154bf4e42cd7c1802d587b37273e620c3aa Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 3 Feb 2026 11:14:42 +0100 Subject: [PATCH 052/207] feat: availability rules --- examples/react/basic/src/index.tsx | 52 ++++---- .../react-time/src/useCalendar/useCalendar.ts | 113 +++++++++++++++++- packages/time/src/calendar/getResizeProps.ts | 80 ++++++++++++- 3 files changed, 213 insertions(+), 32 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index ff072ceb..9fcd3ad3 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -32,6 +32,30 @@ function formatDateToISO(date: Date): string { return `${year}-${month}-${day}` } +const sampleResources: Array = [ + { + id: '1', + label: 'Resource 1', + availability: [ + { + weekdays: [1, 2, 3], + startTime: '08:00', + endTime: '17:00', + }, + { + weekdays: [4, 5], + startTime: '00:00', + endTime: '24:00', + }, + { + weekdays: [6, 7], + startTime: '10:00', + endTime: '15:00', + }, + ], + }, +] + function getSampleEvents(): Array> { const today = new Date() const tomorrow = new Date(today) @@ -52,24 +76,28 @@ function getSampleEvents(): Array> { title: 'Team Meeting', start: `${formatDateToISO(tomorrow)}T10:00:00`, end: `${formatDateToISO(tomorrow)}T11:00:00`, + resources: sampleResources, }, { id: '2', title: 'Project Review', start: `${formatDateToISO(dayAfterTomorrow)}T14:00:00`, end: `${formatDateToISO(dayAfterTomorrow)}T15:30:00`, + resources: sampleResources, }, { id: '3', title: 'Multi-day Conference', start: `${formatDateToISO(threeDaysLater)}T09:00:00`, end: `${formatDateToISO(fourDaysLater)}T17:00:00`, + resources: sampleResources, }, { id: '4', title: 'Lunch Break', start: `${formatDateToISO(threeDaysLater)}T12:00:00`, end: `${formatDateToISO(threeDaysLater)}T13:00:00`, + resources: sampleResources, }, ] } @@ -349,7 +377,6 @@ function ScheduleView({ resizeState.isResizing && resizeState.eventId === event.id - // Calculate preview state using library function const resizePreview = isBeingResized && resizeState.previewStart && @@ -376,7 +403,6 @@ function ScheduleView({ const isActivelyResized = isBeingResized && resizePreview?.previewStyle !== null - // Format time display using library function const timeRange = formatEventTimeRange( isBeingResized && resizeState.previewStart ? resizeState.previewStart @@ -441,7 +467,6 @@ function ScheduleView({
) })} - {/* Ghost preview on days without existing segments */} {resizeState.isResizing && resizeState.previewStart && resizeState.previewEnd && @@ -494,29 +519,10 @@ function CalendarView() { initialData: emptyFormData, }) - const resources: Array = [ - { - id: '1', - label: 'Resource 1', - availability: [ - { - weekdays: [1, 2, 3, 4, 5], - startTime: '08:00', - endTime: '17:00', - }, - { - weekdays: [6, 7], - startTime: '10:00', - endTime: '15:00', - }, - ], - }, - ] - const calendar = useCalendar>({ viewMode: { value: 1, unit: 'month' }, events: sampleEvents, - resources, + resources: sampleResources, timeZone: 'UTC', resize: { enabled: true, diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 97a37443..853a89f9 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -81,7 +81,7 @@ export const useCalendar = < const { resize, ...calendarOptions } = options const resizeEnabled = resize?.enabled ?? true const containerHeight = resize?.containerHeight ?? 0 - const constraints = resize?.constraints + const resizeConstraints = resize?.constraints const [calendarCore] = useState( () => new CalendarCore(calendarOptions), @@ -152,7 +152,6 @@ export const useCalendar = < const targetDayDate = getDayFromPoint(e.clientX) ?? originalDayDate - // Calculate day offset if moved to a different day let dayOffsetMinutes = 0 if (targetDayDate && targetDayDate !== originalDayDate) { const originalDate = new Date(originalDayDate + 'T00:00:00') @@ -168,26 +167,128 @@ export const useCalendar = < const totalDeltaMinutes = deltaMinutes + dayOffsetMinutes + const event = calendarOptions.events?.find((ev) => ev.id === id) + const resourceIds = event?.resources?.map((r) => r.id) + + const getUnavailableMinutesForDay = (dayDate: string) => { + const rawRanges = resourceIds?.length + ? calendarCore.getUnavailableRanges(dayDate, { + containerHeight: 1440, + resourceIds, + }) + : [] + return rawRanges.map((range) => { + const startParts = range.startTime.split(':').map(Number) + const endParts = range.endTime.split(':').map(Number) + return { + startMinutes: (startParts[0] ?? 0) * 60 + (startParts[1] ?? 0), + endMinutes: (endParts[0] ?? 0) * 60 + (endParts[1] ?? 0), + } + }) + } + + const unavailableRanges = getUnavailableMinutesForDay(targetDayDate) + + const originalStartDate = start.split('T')[0] ?? '' + const originalEndDate = end.split('T')[0] ?? '' + + let shouldBlockResize = false + + if (edge === 'top' && targetDayDate < originalStartDate) { + const rawStartMinutes = + new Date(start).getHours() * 60 + + new Date(start).getMinutes() + + totalDeltaMinutes + const targetStartMinutes = ((rawStartMinutes % 1440) + 1440) % 1440 + const currentStartMinutes = + new Date(start).getHours() * 60 + new Date(start).getMinutes() + + for (const range of unavailableRanges) { + if ( + targetStartMinutes < range.endMinutes && + range.startMinutes < 1440 + ) { + shouldBlockResize = true + break + } + } + + if (!shouldBlockResize) { + const sourceUnavailableRanges = + getUnavailableMinutesForDay(originalStartDate) + for (const range of sourceUnavailableRanges) { + if ( + 0 < range.endMinutes && + range.startMinutes < currentStartMinutes + ) { + shouldBlockResize = true + break + } + } + } + } else if (edge === 'bottom' && targetDayDate > originalEndDate) { + const rawEndMinutes = + new Date(end).getHours() * 60 + + new Date(end).getMinutes() + + totalDeltaMinutes + const targetEndMinutes = ((rawEndMinutes % 1440) + 1440) % 1440 + const currentEndMinutes = + new Date(end).getHours() * 60 + new Date(end).getMinutes() + + const sourceUnavailableRanges = + getUnavailableMinutesForDay(originalEndDate) + for (const range of sourceUnavailableRanges) { + if ( + currentEndMinutes < range.endMinutes && + range.startMinutes < 1440 + ) { + shouldBlockResize = true + break + } + } + + if (!shouldBlockResize) { + for (const range of unavailableRanges) { + if (0 < range.endMinutes && range.startMinutes < targetEndMinutes) { + shouldBlockResize = true + break + } + } + } + } + + const effectiveDeltaMinutes = shouldBlockResize + ? deltaMinutes + : totalDeltaMinutes + const effectiveUnavailableRanges = shouldBlockResize + ? getUnavailableMinutesForDay(originalDayDate) + : unavailableRanges + const result = calculateResizedEvent({ originalStart: start, originalEnd: end, edge, - deltaMinutes: totalDeltaMinutes, + deltaMinutes: effectiveDeltaMinutes, timeZone: calendarOptions.timeZone ?? 'UTC', - constraints, + constraints: { + ...resizeConstraints, + unavailableRanges: effectiveUnavailableRanges, + }, }) updateResizeState({ eventId: id, previewStart: result.start, previewEnd: result.end, - targetDayDate, + targetDayDate: shouldBlockResize ? originalDayDate : targetDayDate, }) }, [ containerHeight, calendarOptions.timeZone, - constraints, + calendarOptions.events, + calendarCore, + resizeConstraints, getDayFromPoint, updateResizeState, ], diff --git a/packages/time/src/calendar/getResizeProps.ts b/packages/time/src/calendar/getResizeProps.ts index fd53aa0f..bb78cc47 100644 --- a/packages/time/src/calendar/getResizeProps.ts +++ b/packages/time/src/calendar/getResizeProps.ts @@ -2,9 +2,18 @@ import { Temporal } from '@js-temporal/polyfill' export type ResizeEdge = 'top' | 'bottom' +export interface UnavailableTimeRange { + /** Start time in minutes from midnight (0-1440) */ + startMinutes: number + /** End time in minutes from midnight (0-1440) */ + endMinutes: number +} + export interface ResizeConstraints { minDurationMinutes?: number snapToMinutes?: number + /** Unavailable time ranges that the event cannot be resized into */ + unavailableRanges?: Array } const MINUTES_IN_DAY = 24 * 60 @@ -33,6 +42,19 @@ const DEFAULT_SNAP_TO_MINUTES = 15 const roundToNearestInterval = (minutes: number, interval: number): number => Math.round(minutes / interval) * interval +const getMinutesFromMidnight = (zdt: Temporal.ZonedDateTime): number => + zdt.hour * 60 + zdt.minute + +const setMinutesFromMidnight = ( + zdt: Temporal.ZonedDateTime, + minutes: number, +): Temporal.ZonedDateTime => { + const clampedMinutes = Math.max(0, Math.min(minutes, MINUTES_IN_DAY - 1)) + const hours = Math.floor(clampedMinutes / 60) + const mins = clampedMinutes % 60 + return zdt.with({ hour: hours, minute: mins, second: 0, millisecond: 0 }) +} + export function calculateResizedEvent( options: CalculateResizedEventOptions, ): ResizedEventResult { @@ -48,6 +70,7 @@ export function calculateResizedEvent( const { minDurationMinutes = DEFAULT_MIN_DURATION_MINUTES, snapToMinutes = DEFAULT_SNAP_TO_MINUTES, + unavailableRanges = [], } = constraints const startZdt = @@ -60,18 +83,72 @@ export function calculateResizedEvent( let newStartZdt = startZdt let newEndZdt = endZdt + const isEntireDayUnavailable = unavailableRanges.some( + (range) => range.startMinutes === 0 && range.endMinutes >= MINUTES_IN_DAY, + ) + if (edge === 'top') { newStartZdt = startZdt.add({ minutes: snappedDelta }) const maxStartZdt = endZdt.subtract({ minutes: minDurationMinutes }) if (Temporal.ZonedDateTime.compare(newStartZdt, maxStartZdt) > 0) { newStartZdt = maxStartZdt } + + if (isEntireDayUnavailable) { + const originalStartMinutes = getMinutesFromMidnight(startZdt) + newStartZdt = setMinutesFromMidnight(newStartZdt, originalStartMinutes) + } else { + let newStartMinutes = getMinutesFromMidnight(newStartZdt) + + for (const range of unavailableRanges) { + if ( + newStartMinutes >= range.startMinutes && + newStartMinutes < range.endMinutes + ) { + if (range.endMinutes < MINUTES_IN_DAY) { + newStartZdt = setMinutesFromMidnight(newStartZdt, range.endMinutes) + newStartMinutes = range.endMinutes + } else if (range.startMinutes > 0) { + const validTime = range.startMinutes - snapToMinutes + if (validTime >= 0) { + newStartZdt = setMinutesFromMidnight(newStartZdt, validTime) + newStartMinutes = validTime + } + } + } + } + } } else { newEndZdt = endZdt.add({ minutes: snappedDelta }) const minEndZdt = startZdt.add({ minutes: minDurationMinutes }) if (Temporal.ZonedDateTime.compare(newEndZdt, minEndZdt) < 0) { newEndZdt = minEndZdt } + + if (isEntireDayUnavailable) { + const originalEndMinutes = getMinutesFromMidnight(endZdt) + newEndZdt = setMinutesFromMidnight(newEndZdt, originalEndMinutes) + } else { + let newEndMinutes = getMinutesFromMidnight(newEndZdt) + + for (const range of unavailableRanges) { + if ( + newEndMinutes > range.startMinutes && + newEndMinutes <= range.endMinutes + ) { + if (range.startMinutes > 0) { + newEndZdt = setMinutesFromMidnight(newEndZdt, range.startMinutes) + newEndMinutes = range.startMinutes + } else if (range.endMinutes < MINUTES_IN_DAY) { + const validTime = range.endMinutes + snapToMinutes + if (validTime <= MINUTES_IN_DAY) { + newEndZdt = setMinutesFromMidnight(newEndZdt, validTime) + newEndMinutes = validTime + } + } + } + } + } } const durationMs = newEndZdt.epochMilliseconds - newStartZdt.epochMilliseconds @@ -139,9 +216,6 @@ export interface SegmentInfo { segmentEnd: string } -/** - * Analyzes a segment to determine its position within a multi-day event - */ export function getSegmentInfo(event: { start: string end: string From 614327693422428e6c105e2d07415e3584db85d0 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Wed, 4 Feb 2026 10:15:01 +0100 Subject: [PATCH 053/207] feat: resources --- examples/react/basic/src/index.tsx | 81 +++++++++++++++++++++++++---- packages/time/src/calendar/types.ts | 6 ++- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 9fcd3ad3..1df4bce3 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -36,6 +36,7 @@ const sampleResources: Array = [ { id: '1', label: 'Resource 1', + capacity: 1, availability: [ { weekdays: [1, 2, 3], @@ -54,6 +55,23 @@ const sampleResources: Array = [ }, ], }, + { + id: '2', + label: 'Resource 2', + capacity: 1, + availability: [ + { + weekdays: [1, 2, 3, 4, 5], + startTime: '12:00', + endTime: '18:00', + }, + { + weekdays: [6, 7], + startTime: '00:00', + endTime: '24:00', + }, + ], + }, ] function getSampleEvents(): Array> { @@ -308,9 +326,40 @@ function ScheduleView({ } = calendar return ( -
-
-
+
+
+
+ {sampleResources.map((resource, idx) => { + const colors = ['#0049af75', '#00af3475'] + const color = colors[idx % colors.length] + return ( +
+
+ + {resource.label} + + {resource.capacity !== undefined && ( + + (Capacity: {resource.capacity}) + + )} +
+ ) + })} +
+
+
+
+
{timeSlots.map((slot) => (
- {getUnavailableRanges(dayDate, { resourceIds: ['1'] }).map( - (range, idx) => ( + {sampleResources.map((resource, resourceIdx) => { + const resourceRanges = getUnavailableRanges(dayDate, { + resourceIds: [resource.id], + }) + const colors = [ + '#0049af75', + '#00af3475', + + ] + const color = colors[resourceIdx % colors.length] + + return resourceRanges.map((range, rangeIdx) => (
- ), - )} + )) + })} {day.events.map((event, eventIndex) => { const eventProps = calendar.getEventProps(event) const { style, isSplitEvent } = eventProps @@ -503,6 +563,7 @@ function ScheduleView({
+
) } diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index ce9651fa..bb2736b7 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -13,8 +13,12 @@ export interface Availability { export interface Resource { id: string label: string - /** Optional availability schedule for this resource */ availability?: Array + capacity?: number + buffer?: { + before?: number + after?: number + } } /** From 63b149b7d7daaec83b71742afdfdfbfbda50a65a Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 9 Feb 2026 09:45:02 +0100 Subject: [PATCH 054/207] feat: devtools setup --- examples/react/basic/package.json | 2 + examples/react/basic/src/index.tsx | 379 +++++++++--------- packages/react-time-devtools/package.json | 4 +- .../react-time-devtools/src/TimeDevtools.tsx | 33 ++ packages/react-time-devtools/src/index.ts | 19 + packages/react-time-devtools/src/plugin.tsx | 11 + .../react-time-devtools/src/production.ts | 7 + packages/solid-time-devtools/package.json | 1 + .../solid-time-devtools/src/TimeDevtools.tsx | 14 +- packages/solid-time-devtools/src/index.ts | 15 +- packages/solid-time-devtools/src/plugin.tsx | 11 + .../solid-time-devtools/src/production.ts | 5 + packages/time-devtools/package.json | 9 +- .../time-devtools/src/components/Shell.tsx | 26 ++ packages/time-devtools/src/core.tsx | 10 + packages/time-devtools/src/devtools.ts | 5 - packages/time-devtools/src/index.ts | 9 +- packages/time-devtools/src/production.ts | 3 + .../time-devtools/src/store/time-context.tsx | 36 ++ packages/time-devtools/src/styles/tokens.ts | 305 ++++++++++++++ .../time-devtools/src/styles/use-styles.ts | 28 ++ packages/time-devtools/tsconfig.json | 6 +- packages/time-devtools/tsdown.config.ts | 2 + pnpm-lock.yaml | 294 ++++++++++++++ 24 files changed, 1029 insertions(+), 205 deletions(-) create mode 100644 packages/react-time-devtools/src/TimeDevtools.tsx create mode 100644 packages/react-time-devtools/src/plugin.tsx create mode 100644 packages/react-time-devtools/src/production.ts create mode 100644 packages/solid-time-devtools/src/plugin.tsx create mode 100644 packages/solid-time-devtools/src/production.ts create mode 100644 packages/time-devtools/src/components/Shell.tsx create mode 100644 packages/time-devtools/src/core.tsx delete mode 100644 packages/time-devtools/src/devtools.ts create mode 100644 packages/time-devtools/src/production.ts create mode 100644 packages/time-devtools/src/store/time-context.tsx create mode 100644 packages/time-devtools/src/styles/tokens.ts create mode 100644 packages/time-devtools/src/styles/use-styles.ts diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json index ad3f5ff6..29645168 100644 --- a/examples/react/basic/package.json +++ b/examples/react/basic/package.json @@ -9,7 +9,9 @@ "test:types": "tsc" }, "dependencies": { + "@tanstack/react-devtools": "^0.9.5", "@tanstack/react-time": "^0.0.0", + "@tanstack/react-time-devtools": "^0.0.0", "@tanstack/time": "^0.0.0", "react": "^19.2.3", "react-dom": "^19.2.3" diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 1df4bce3..c04228cf 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -7,7 +7,10 @@ import { } from '@tanstack/react-time' import ReactDOM from 'react-dom/client' import { useState } from 'react' +import { TanStackDevtools } from '@tanstack/react-devtools' +import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' import type { Day, Event, Resource } from '@tanstack/time' + import './index.css' function formatPeriodDate(dateString: string): string { @@ -333,10 +336,7 @@ function ScheduleView({ const colors = ['#0049af75', '#00af3475'] const color = colors[idx % colors.length] return ( -
+
- {timeSlots.map((slot) => ( + {timeSlots.map((slot) => ( +
+ {slot.label} +
+ ))} +
+
- {slot.label} -
- ))} -
-
-
-
- {days.map((day) => { - const dayDate = `${day.date.year}-${String(day.date.month).padStart(2, '0')}-${String(day.date.day).padStart(2, '0')}` - const dayName = new Intl.DateTimeFormat('en-US', { - weekday: 'short', - }).format( - new Date(day.date.year, day.date.month - 1, day.date.day), - ) - return ( -
-
-
- {dayName} -
-
- {day.date.day} +
+ {days.map((day) => { + const dayDate = `${day.date.year}-${String(day.date.month).padStart(2, '0')}-${String(day.date.day).padStart(2, '0')}` + const dayName = new Intl.DateTimeFormat('en-US', { + weekday: 'short', + }).format( + new Date(day.date.year, day.date.month - 1, day.date.day), + ) + return ( +
+
+
+ {dayName} +
+
+ {day.date.day} +
-
-
- {sampleResources.map((resource, resourceIdx) => { - const resourceRanges = getUnavailableRanges(dayDate, { - resourceIds: [resource.id], - }) - const colors = [ - '#0049af75', - '#00af3475', - - ] - const color = colors[resourceIdx % colors.length] - - return resourceRanges.map((range, rangeIdx) => ( -
- )) - })} - {day.events.map((event, eventIndex) => { - const eventProps = calendar.getEventProps(event) - const { style, isSplitEvent } = eventProps - - const segmentInfo = getSegmentInfo(event) - const { - isFirstSegment, - isLastSegment, - originalStart, - originalEnd, - } = segmentInfo - - const isBeingResized = - resizeState.isResizing && - resizeState.eventId === event.id - - const resizePreview = - isBeingResized && - resizeState.previewStart && - resizeState.previewEnd - ? calculateSegmentResizePreview({ - dayDate, - originalStart, - originalEnd, - previewStart: resizeState.previewStart, - previewEnd: resizeState.previewEnd, - }) - : null - - if (resizePreview?.shouldHide) { - return null - } - - const displayStyle = resizePreview?.previewStyle - ? { ...style, ...resizePreview.previewStyle } - : style - - const showTopHandle = !isSplitEvent || isFirstSegment - const showBottomHandle = !isSplitEvent || isLastSegment - const isActivelyResized = - isBeingResized && resizePreview?.previewStyle !== null - - const timeRange = formatEventTimeRange( - isBeingResized && resizeState.previewStart - ? resizeState.previewStart - : originalStart, - isBeingResized && resizeState.previewEnd - ? resizeState.previewEnd - : originalEnd, - ) - - return ( -
{ - if ( - !resizeState.isResizing && - !(e.target as HTMLElement).closest( - '[data-resize-handle]', - ) - ) { - onEventClick(event) - } - }} - > - {showTopHandle && ( - - )} -
- {event.title} -
- {displayStyle && - parseFloat(displayStyle.height) > 2 && ( -
- {timeRange.rangeFormatted} -
- )} - {showBottomHandle && ( - + {sampleResources.map((resource, resourceIdx) => { + const resourceRanges = getUnavailableRanges(dayDate, { + resourceIds: [resource.id], + }) + const colors = ['#0049af75', '#00af3475'] + const color = colors[resourceIdx % colors.length] + + return resourceRanges.map((range, rangeIdx) => ( +
+ )) + })} + {day.events.map((event, eventIndex) => { + const eventProps = calendar.getEventProps(event) + const { style, isSplitEvent } = eventProps + + const segmentInfo = getSegmentInfo(event) + const { + isFirstSegment, + isLastSegment, + originalStart, + originalEnd, + } = segmentInfo + + const isBeingResized = + resizeState.isResizing && + resizeState.eventId === event.id + + const resizePreview = + isBeingResized && + resizeState.previewStart && + resizeState.previewEnd + ? calculateSegmentResizePreview({ + dayDate, originalStart, originalEnd, - )} - /> - )} -
- ) - })} - {resizeState.isResizing && - resizeState.previewStart && - resizeState.previewEnd && - !day.events.some((e) => e.id === resizeState.eventId) && - (() => { - const ghostStyle = calculateGhostPreviewStyle({ - dayDate, - previewStart: resizeState.previewStart, - previewEnd: resizeState.previewEnd, - }) + previewStart: resizeState.previewStart, + previewEnd: resizeState.previewEnd, + }) + : null + + if (resizePreview?.shouldHide) { + return null + } + + const displayStyle = resizePreview?.previewStyle + ? { ...style, ...resizePreview.previewStyle } + : style - if (!ghostStyle) return null + const showTopHandle = !isSplitEvent || isFirstSegment + const showBottomHandle = !isSplitEvent || isLastSegment + const isActivelyResized = + isBeingResized && resizePreview?.previewStyle !== null const timeRange = formatEventTimeRange( - resizeState.previewStart, - resizeState.previewEnd, + isBeingResized && resizeState.previewStart + ? resizeState.previewStart + : originalStart, + isBeingResized && resizeState.previewEnd + ? resizeState.previewEnd + : originalEnd, ) return (
{ + if ( + !resizeState.isResizing && + !(e.target as HTMLElement).closest( + '[data-resize-handle]', + ) + ) { + onEventClick(event) + } + }} > -
- {timeRange.rangeFormatted} + {showTopHandle && ( + + )} +
+ {event.title}
+ {displayStyle && + parseFloat(displayStyle.height) > 2 && ( +
+ {timeRange.rangeFormatted} +
+ )} + {showBottomHandle && ( + + )}
) - })()} + })} + {resizeState.isResizing && + resizeState.previewStart && + resizeState.previewEnd && + !day.events.some((e) => e.id === resizeState.eventId) && + (() => { + const ghostStyle = calculateGhostPreviewStyle({ + dayDate, + previewStart: resizeState.previewStart, + previewEnd: resizeState.previewEnd, + }) + + if (!ghostStyle) return null + + const timeRange = formatEventTimeRange( + resizeState.previewStart, + resizeState.previewEnd, + ) + + return ( +
+
+ {timeRange.rangeFormatted} +
+
+ ) + })()} +
-
- ) - })} + ) + })} +
-
) } @@ -882,7 +878,12 @@ function CalendarView() { } function App() { - return + return ( + <> + + + + ) } ReactDOM.createRoot(document.getElementById('root')!).render() diff --git a/packages/react-time-devtools/package.json b/packages/react-time-devtools/package.json index 27cf54d2..cc8c2425 100644 --- a/packages/react-time-devtools/package.json +++ b/packages/react-time-devtools/package.json @@ -48,6 +48,7 @@ "src" ], "dependencies": { + "@tanstack/devtools-utils": "^0.3.0", "@tanstack/time-devtools": "workspace:*" }, "devDependencies": { @@ -56,7 +57,8 @@ "@vitejs/plugin-react": "^5.1.2", "eslint-plugin-react-compiler": "19.1.0-rc.2", "eslint-plugin-react-hooks": "^7.0.1", - "react": "^19.2.3" + "react": "^19.2.3", + "solid-js": "^1.9.10" }, "peerDependencies": { "react": ">=16.8", diff --git a/packages/react-time-devtools/src/TimeDevtools.tsx b/packages/react-time-devtools/src/TimeDevtools.tsx new file mode 100644 index 00000000..4fe0d008 --- /dev/null +++ b/packages/react-time-devtools/src/TimeDevtools.tsx @@ -0,0 +1,33 @@ +import React, { useEffect, useRef } from 'react' +import { TimeDevtoolsCore } from '@tanstack/time-devtools' +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/react' + +export interface TimeDevtoolsReactInit extends DevtoolsPanelProps {} + +function TimeDevtoolsPanel(props: TimeDevtoolsReactInit) { + const containerRef = useRef(null) + const devtoolsRef = useRef | null>(null) + + useEffect(() => { + if (containerRef.current && !devtoolsRef.current) { + const devtools = new TimeDevtoolsCore() + devtoolsRef.current = devtools + devtools.mount(containerRef.current, props.theme ?? 'dark') + } + + return () => { + if (devtoolsRef.current) { + devtoolsRef.current.unmount() + devtoolsRef.current = null + } + } + }, [props.theme]) + + return
+} + +function TimeDevtoolsPanelNoOp(_props: TimeDevtoolsReactInit) { + return null +} + +export { TimeDevtoolsPanel, TimeDevtoolsPanelNoOp } diff --git a/packages/react-time-devtools/src/index.ts b/packages/react-time-devtools/src/index.ts index e69de29b..3e243364 100644 --- a/packages/react-time-devtools/src/index.ts +++ b/packages/react-time-devtools/src/index.ts @@ -0,0 +1,19 @@ +'use client' + +import type { createSolidPanel } from '@tanstack/devtools-utils/solid' +import * as Devtools from './TimeDevtools' +import * as plugin from './plugin' + +type SolidPanelComponent = ReturnType[0] + +export const TimeDevtoolsPanel: SolidPanelComponent = + process.env.NODE_ENV !== 'development' + ? Devtools.TimeDevtoolsPanelNoOp + : Devtools.TimeDevtoolsPanel + +export const timeDevtoolsPlugin = + process.env.NODE_ENV !== 'development' + ? plugin.timeDevtoolsNoOpPlugin + : plugin.timeDevtoolsPlugin + +export type { TimeDevtoolsReactInit } from './TimeDevtools' diff --git a/packages/react-time-devtools/src/plugin.tsx b/packages/react-time-devtools/src/plugin.tsx new file mode 100644 index 00000000..e72c459b --- /dev/null +++ b/packages/react-time-devtools/src/plugin.tsx @@ -0,0 +1,11 @@ +import { createReactPlugin } from '@tanstack/devtools-utils/react' +import { TimeDevtoolsPanel } from './TimeDevtools' + +const [timeDevtoolsPlugin, timeDevtoolsNoOpPlugin] = createReactPlugin({ + Component: TimeDevtoolsPanel, + name: 'TanStack Time', + id: 'tanstack-time', + defaultOpen: true, +}) + +export { timeDevtoolsPlugin, timeDevtoolsNoOpPlugin } diff --git a/packages/react-time-devtools/src/production.ts b/packages/react-time-devtools/src/production.ts new file mode 100644 index 00000000..2d89b9fb --- /dev/null +++ b/packages/react-time-devtools/src/production.ts @@ -0,0 +1,7 @@ +'use client' + +export { TimeDevtoolsPanel } from './TimeDevtools' + +export type { TimeDevtoolsReactInit } from './TimeDevtools' + +export { TimeDevtoolsPlugin } from './plugin' diff --git a/packages/solid-time-devtools/package.json b/packages/solid-time-devtools/package.json index c289e0d4..98e8ecfc 100644 --- a/packages/solid-time-devtools/package.json +++ b/packages/solid-time-devtools/package.json @@ -48,6 +48,7 @@ "src" ], "dependencies": { + "@tanstack/devtools-utils": "^0.3.0", "@tanstack/time-devtools": "workspace:*" }, "devDependencies": { diff --git a/packages/solid-time-devtools/src/TimeDevtools.tsx b/packages/solid-time-devtools/src/TimeDevtools.tsx index 0d0a71b8..114cb714 100644 --- a/packages/solid-time-devtools/src/TimeDevtools.tsx +++ b/packages/solid-time-devtools/src/TimeDevtools.tsx @@ -1,8 +1,10 @@ -import { template } from 'solid-js/web' +import { createSolidPanel } from '@tanstack/devtools-utils/solid' +import { TimeDevtoolsCore } from '@tanstack/time-devtools' +import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/solid' -const _tmpl$ = /* @__PURE__ */ template(`
Solid Time Devtools
`) +const [TimeDevtoolsPanel, TimeDevtoolsPanelNoOp] = + createSolidPanel(TimeDevtoolsCore) -export function TimeDevtools() { - console.log('Hello from @tanstack/solid-time-devtools!') - return _tmpl$() -} +export interface TimeDevtoolsSolidInit extends DevtoolsPanelProps {} + +export { TimeDevtoolsPanel, TimeDevtoolsPanelNoOp } diff --git a/packages/solid-time-devtools/src/index.ts b/packages/solid-time-devtools/src/index.ts index f7114f85..3e76650f 100644 --- a/packages/solid-time-devtools/src/index.ts +++ b/packages/solid-time-devtools/src/index.ts @@ -1 +1,14 @@ -export * from './TimeDevtools' +import * as Devtools from './TimeDevtools' +import * as plugin from './plugin' + +export const TimeDevtools = + process.env.NODE_ENV !== 'development' + ? Devtools.TimeDevtoolsPanelNoOp + : Devtools.TimeDevtoolsPanel + +export const timeDevtoolsPlugin = + process.env.NODE_ENV !== 'development' + ? plugin.timeDevtoolsNoOpPlugin + : plugin.timeDevtoolsPlugin + +export type { TimeDevtoolsSolidInit } from './TimeDevtools' diff --git a/packages/solid-time-devtools/src/plugin.tsx b/packages/solid-time-devtools/src/plugin.tsx new file mode 100644 index 00000000..21b1d91f --- /dev/null +++ b/packages/solid-time-devtools/src/plugin.tsx @@ -0,0 +1,11 @@ +import { createSolidPlugin } from '@tanstack/devtools-utils/solid' +import { TimeDevtoolsPanel } from './TimeDevtools' + +const [timeDevtoolsPlugin, timeDevtoolsNoOpPlugin] = createSolidPlugin({ + Component: TimeDevtoolsPanel, + name: 'TanStack Time', + id: 'tanstack-time', + defaultOpen: true, +}) + +export { timeDevtoolsPlugin, timeDevtoolsNoOpPlugin } diff --git a/packages/solid-time-devtools/src/production.ts b/packages/solid-time-devtools/src/production.ts new file mode 100644 index 00000000..50304211 --- /dev/null +++ b/packages/solid-time-devtools/src/production.ts @@ -0,0 +1,5 @@ +export { TimeDevtoolsPanel } from './TimeDevtools' + +export type { TimeDevtoolsSolidInit } from './TimeDevtools' + +export { timeDevtoolsPlugin } from './plugin' diff --git a/packages/time-devtools/package.json b/packages/time-devtools/package.json index e7e3b422..0d95b4c4 100644 --- a/packages/time-devtools/package.json +++ b/packages/time-devtools/package.json @@ -48,6 +48,13 @@ "src" ], "dependencies": { - "@tanstack/time": "workspace:*" + "@tanstack/devtools-ui": "^0.4.4", + "@tanstack/devtools-utils": "^0.3.0", + "@tanstack/time": "workspace:*", + "goober": "^2.1.18", + "solid-js": "^1.9.10" + }, + "devDependencies": { + "rolldown-plugin-solid": "^0.2.1" } } diff --git a/packages/time-devtools/src/components/Shell.tsx b/packages/time-devtools/src/components/Shell.tsx new file mode 100644 index 00000000..2883b692 --- /dev/null +++ b/packages/time-devtools/src/components/Shell.tsx @@ -0,0 +1,26 @@ +import { Header, HeaderLogo, MainPanel } from '@tanstack/devtools-ui' +import { useStyles } from '../styles/use-styles' +import { TimeProvider } from '../store/time-context' + +export default function Devtools() { + return ( + + + + ) +} + +function DevtoolsContent() { + const styles = useStyles() + return ( + +
+ + TanStack Time + +
+ +
+
+ ) +} diff --git a/packages/time-devtools/src/core.tsx b/packages/time-devtools/src/core.tsx new file mode 100644 index 00000000..e780280c --- /dev/null +++ b/packages/time-devtools/src/core.tsx @@ -0,0 +1,10 @@ +import { lazy } from 'solid-js' +import { constructCoreClass } from '@tanstack/devtools-utils/solid' + +const Component = lazy(() => import('./components/Shell')) + +export interface TimeDevtoolsInit {} + +const [TimeDevtoolsCore, TimeDevtoolsCoreNoOp] = constructCoreClass(Component) + +export { TimeDevtoolsCore, TimeDevtoolsCoreNoOp } diff --git a/packages/time-devtools/src/devtools.ts b/packages/time-devtools/src/devtools.ts deleted file mode 100644 index a5eaa213..00000000 --- a/packages/time-devtools/src/devtools.ts +++ /dev/null @@ -1,5 +0,0 @@ -console.log('Hello from @tanstack/time-devtools!') - -export function initTimeDevtools() { - console.log('Time devtools initialized') -} diff --git a/packages/time-devtools/src/index.ts b/packages/time-devtools/src/index.ts index 39356ff2..b8527488 100644 --- a/packages/time-devtools/src/index.ts +++ b/packages/time-devtools/src/index.ts @@ -1 +1,8 @@ -export * from './devtools' +import * as Devtools from './core' + +export const TimeDevtoolsCore = + process.env.NODE_ENV !== 'development' + ? Devtools.TimeDevtoolsCoreNoOp + : Devtools.TimeDevtoolsCore + +export type { TimeDevtoolsInit } from './core' diff --git a/packages/time-devtools/src/production.ts b/packages/time-devtools/src/production.ts new file mode 100644 index 00000000..bdba1cc8 --- /dev/null +++ b/packages/time-devtools/src/production.ts @@ -0,0 +1,3 @@ +export { TimeDevtoolsCore } from './core' + +export type { TimeDevtoolsInit } from './core' diff --git a/packages/time-devtools/src/store/time-context.tsx b/packages/time-devtools/src/store/time-context.tsx new file mode 100644 index 00000000..45b855c3 --- /dev/null +++ b/packages/time-devtools/src/store/time-context.tsx @@ -0,0 +1,36 @@ +import { createContext, useContext } from 'solid-js' +import { createStore } from 'solid-js/store' +import type { ParentComponent } from 'solid-js' + +interface TimeStoreState {} + +interface TimeContextValue { + state: TimeStoreState +} + +const TimeContext = createContext() + +export function useTimeStore(): TimeContextValue { + const context = useContext(TimeContext) + if (!context) { + throw new Error('useTimeStore must be used within an TimeProvider') + } + return context +} + +export const TimeProvider: ParentComponent = (props) => { + const [state, setState] = createStore({ + conversations: {}, + activeConversationId: null, + }) + + const contextValue: TimeContextValue = { + state, + } + + return ( + + {props.children} + + ) +} diff --git a/packages/time-devtools/src/styles/tokens.ts b/packages/time-devtools/src/styles/tokens.ts new file mode 100644 index 00000000..9d247cf1 --- /dev/null +++ b/packages/time-devtools/src/styles/tokens.ts @@ -0,0 +1,305 @@ +export const tokens = { + colors: { + inherit: 'inherit', + current: 'currentColor', + transparent: 'transparent', + black: '#000000', + white: '#ffffff', + neutral: { + 50: '#f9fafb', + 100: '#f2f4f7', + 200: '#eaecf0', + 300: '#d0d5dd', + 400: '#98a2b3', + 500: '#667085', + 600: '#475467', + 700: '#344054', + 800: '#1d2939', + 900: '#101828', + }, + darkGray: { + 50: '#525c7a', + 100: '#49536e', + 200: '#414962', + 300: '#394056', + 400: '#313749', + 500: '#292e3d', + 600: '#212530', + 700: '#191c24', + 800: '#111318', + 900: '#0b0d10', + }, + gray: { + 50: '#f9fafb', + 100: '#f2f4f7', + 200: '#eaecf0', + 300: '#d0d5dd', + 400: '#98a2b3', + 500: '#667085', + 600: '#475467', + 700: '#344054', + 800: '#1d2939', + 900: '#101828', + }, + blue: { + 25: '#F5FAFF', + 50: '#EFF8FF', + 100: '#D1E9FF', + 200: '#B2DDFF', + 300: '#84CAFF', + 400: '#53B1FD', + 500: '#2E90FA', + 600: '#1570EF', + 700: '#175CD3', + 800: '#1849A9', + 900: '#194185', + }, + green: { + 25: '#F6FEF9', + 50: '#ECFDF3', + 100: '#D1FADF', + 200: '#A6F4C5', + 300: '#6CE9A6', + 400: '#32D583', + 500: '#12B76A', + 600: '#039855', + 700: '#027A48', + 800: '#05603A', + 900: '#054F31', + }, + red: { + 50: '#fef2f2', + 100: '#fee2e2', + 200: '#fecaca', + 300: '#fca5a5', + 400: '#f87171', + 500: '#ef4444', + 600: '#dc2626', + 700: '#b91c1c', + 800: '#991b1b', + 900: '#7f1d1d', + 950: '#450a0a', + }, + yellow: { + 25: '#FFFCF5', + 50: '#FFFAEB', + 100: '#FEF0C7', + 200: '#FEDF89', + 300: '#FEC84B', + 400: '#FDB022', + 500: '#F79009', + 600: '#DC6803', + 700: '#B54708', + 800: '#93370D', + 900: '#7A2E0E', + }, + purple: { + 25: '#FAFAFF', + 50: '#F4F3FF', + 100: '#EBE9FE', + 200: '#D9D6FE', + 300: '#BDB4FE', + 400: '#9B8AFB', + 500: '#7A5AF8', + 600: '#6938EF', + 700: '#5925DC', + 800: '#4A1FB8', + 900: '#3E1C96', + }, + teal: { + 25: '#F6FEFC', + 50: '#F0FDF9', + 100: '#CCFBEF', + 200: '#99F6E0', + 300: '#5FE9D0', + 400: '#2ED3B7', + 500: '#15B79E', + 600: '#0E9384', + 700: '#107569', + 800: '#125D56', + 900: '#134E48', + }, + pink: { + 25: '#fdf2f8', + 50: '#fce7f3', + 100: '#fbcfe8', + 200: '#f9a8d4', + 300: '#f472b6', + 400: '#ec4899', + 500: '#db2777', + 600: '#be185d', + 700: '#9d174d', + 800: '#831843', + 900: '#500724', + }, + cyan: { + 25: '#ecfeff', + 50: '#cffafe', + 100: '#a5f3fc', + 200: '#67e8f9', + 300: '#22d3ee', + 400: '#06b6d4', + 500: '#0891b2', + 600: '#0e7490', + 700: '#155e75', + 800: '#164e63', + 900: '#083344', + }, + }, + alpha: { + 100: 'ff', + 90: 'e5', + 80: 'cc', + 70: 'b3', + 60: '99', + 50: '80', + 40: '66', + 30: '4d', + 20: '33', + 10: '1a', + 0: '00', + }, + font: { + size: { + '2xs': 'calc(var(--tsrd-font-size) * 0.625)', + xs: 'calc(var(--tsrd-font-size) * 0.75)', + sm: 'calc(var(--tsrd-font-size) * 0.875)', + md: 'var(--tsrd-font-size)', + lg: 'calc(var(--tsrd-font-size) * 1.125)', + xl: 'calc(var(--tsrd-font-size) * 1.25)', + '2xl': 'calc(var(--tsrd-font-size) * 1.5)', + '3xl': 'calc(var(--tsrd-font-size) * 1.875)', + '4xl': 'calc(var(--tsrd-font-size) * 2.25)', + '5xl': 'calc(var(--tsrd-font-size) * 3)', + '6xl': 'calc(var(--tsrd-font-size) * 3.75)', + '7xl': 'calc(var(--tsrd-font-size) * 4.5)', + '8xl': 'calc(var(--tsrd-font-size) * 6)', + '9xl': 'calc(var(--tsrd-font-size) * 8)', + }, + lineHeight: { + '3xs': 'calc(var(--tsrd-font-size) * 0.75)', + '2xs': 'calc(var(--tsrd-font-size) * 0.875)', + xs: 'calc(var(--tsrd-font-size) * 1)', + sm: 'calc(var(--tsrd-font-size) * 1.25)', + md: 'calc(var(--tsrd-font-size) * 1.5)', + lg: 'calc(var(--tsrd-font-size) * 1.75)', + xl: 'calc(var(--tsrd-font-size) * 2)', + '2xl': 'calc(var(--tsrd-font-size) * 2.25)', + '3xl': 'calc(var(--tsrd-font-size) * 2.5)', + '4xl': 'calc(var(--tsrd-font-size) * 2.75)', + '5xl': 'calc(var(--tsrd-font-size) * 3)', + '6xl': 'calc(var(--tsrd-font-size) * 3.25)', + '7xl': 'calc(var(--tsrd-font-size) * 3.5)', + '8xl': 'calc(var(--tsrd-font-size) * 3.75)', + '9xl': 'calc(var(--tsrd-font-size) * 4)', + }, + weight: { + thin: '100', + extralight: '200', + light: '300', + normal: '400', + medium: '500', + semibold: '600', + bold: '700', + extrabold: '800', + black: '900', + }, + fontFamily: { + sans: 'ui-sans-serif, Inter, system-ui, sans-serif, sans-serif', + mono: `ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace`, + }, + }, + breakpoints: { + xs: '320px', + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + border: { + radius: { + none: '0px', + xs: 'calc(var(--tsrd-font-size) * 0.125)', + sm: 'calc(var(--tsrd-font-size) * 0.25)', + md: 'calc(var(--tsrd-font-size) * 0.375)', + lg: 'calc(var(--tsrd-font-size) * 0.5)', + xl: 'calc(var(--tsrd-font-size) * 0.75)', + '2xl': 'calc(var(--tsrd-font-size) * 1)', + '3xl': 'calc(var(--tsrd-font-size) * 1.5)', + full: '9999px', + }, + }, + size: { + 0: '0px', + 0.25: 'calc(var(--tsrd-font-size) * 0.0625)', + 0.5: 'calc(var(--tsrd-font-size) * 0.125)', + 1: 'calc(var(--tsrd-font-size) * 0.25)', + 1.5: 'calc(var(--tsrd-font-size) * 0.375)', + 2: 'calc(var(--tsrd-font-size) * 0.5)', + 2.5: 'calc(var(--tsrd-font-size) * 0.625)', + 3: 'calc(var(--tsrd-font-size) * 0.75)', + 3.5: 'calc(var(--tsrd-font-size) * 0.875)', + 4: 'calc(var(--tsrd-font-size) * 1)', + 4.5: 'calc(var(--tsrd-font-size) * 1.125)', + 5: 'calc(var(--tsrd-font-size) * 1.25)', + 5.5: 'calc(var(--tsrd-font-size) * 1.375)', + 6: 'calc(var(--tsrd-font-size) * 1.5)', + 6.5: 'calc(var(--tsrd-font-size) * 1.625)', + 7: 'calc(var(--tsrd-font-size) * 1.75)', + 8: 'calc(var(--tsrd-font-size) * 2)', + 9: 'calc(var(--tsrd-font-size) * 2.25)', + 10: 'calc(var(--tsrd-font-size) * 2.5)', + 11: 'calc(var(--tsrd-font-size) * 2.75)', + 12: 'calc(var(--tsrd-font-size) * 3)', + 14: 'calc(var(--tsrd-font-size) * 3.5)', + 16: 'calc(var(--tsrd-font-size) * 4)', + 20: 'calc(var(--tsrd-font-size) * 5)', + 24: 'calc(var(--tsrd-font-size) * 6)', + 28: 'calc(var(--tsrd-font-size) * 7)', + 32: 'calc(var(--tsrd-font-size) * 8)', + 36: 'calc(var(--tsrd-font-size) * 9)', + 40: 'calc(var(--tsrd-font-size) * 10)', + 44: 'calc(var(--tsrd-font-size) * 11)', + 48: 'calc(var(--tsrd-font-size) * 12)', + 52: 'calc(var(--tsrd-font-size) * 13)', + 56: 'calc(var(--tsrd-font-size) * 14)', + 60: 'calc(var(--tsrd-font-size) * 15)', + 64: 'calc(var(--tsrd-font-size) * 16)', + 72: 'calc(var(--tsrd-font-size) * 18)', + 80: 'calc(var(--tsrd-font-size) * 20)', + 96: 'calc(var(--tsrd-font-size) * 24)', + }, + shadow: { + xs: (_: string = 'rgb(0 0 0 / 0.1)') => + `0 1px 2px 0 rgb(0 0 0 / 0.05)` as const, + sm: (color: string = 'rgb(0 0 0 / 0.1)') => + `0 1px 3px 0 ${color}, 0 1px 2px -1px ${color}` as const, + md: (color: string = 'rgb(0 0 0 / 0.1)') => + `0 4px 6px -1px ${color}, 0 2px 4px -2px ${color}` as const, + lg: (color: string = 'rgb(0 0 0 / 0.1)') => + `0 10px 15px -3px ${color}, 0 4px 6px -4px ${color}` as const, + xl: (color: string = 'rgb(0 0 0 / 0.1)') => + `0 20px 25px -5px ${color}, 0 8px 10px -6px ${color}` as const, + '2xl': (color: string = 'rgb(0 0 0 / 0.25)') => + `0 25px 50px -12px ${color}` as const, + inner: (color: string = 'rgb(0 0 0 / 0.05)') => + `inset 0 2px 4px 0 ${color}` as const, + none: () => `none` as const, + }, + zIndices: { + hide: -1, + auto: 'auto', + base: 0, + docked: 10, + dropdown: 1000, + sticky: 1100, + banner: 1200, + overlay: 1300, + modal: 1400, + popover: 1500, + skipLink: 1600, + toast: 1700, + tooltip: 1800, + }, +} as const diff --git a/packages/time-devtools/src/styles/use-styles.ts b/packages/time-devtools/src/styles/use-styles.ts new file mode 100644 index 00000000..3b01e72f --- /dev/null +++ b/packages/time-devtools/src/styles/use-styles.ts @@ -0,0 +1,28 @@ +import * as goober from 'goober' +import { createEffect, createSignal } from 'solid-js' +import { useTheme } from '@tanstack/devtools-ui' +import { tokens } from './tokens' + +const stylesFactory = () => { + const { font, size } = tokens + const css = goober.css + + return { + mainContainer: css` + display: flex; + flex: 1; + min-height: 80%; + overflow: hidden; + padding: ${size[2]}; + `, + } +} + +export function useStyles() { + const { theme } = useTheme() + const [styles, setStyles] = createSignal(stylesFactory()) + createEffect(() => { + setStyles(stylesFactory()) + }) + return styles +} diff --git a/packages/time-devtools/tsconfig.json b/packages/time-devtools/tsconfig.json index e01806d9..91883231 100644 --- a/packages/time-devtools/tsconfig.json +++ b/packages/time-devtools/tsconfig.json @@ -1,5 +1,9 @@ { "extends": "../../tsconfig.json", "include": ["src", "vite.config.ts", "tests"], - "exclude": ["eslint.config.js"] + "exclude": ["eslint.config.js"], + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js" + } } diff --git a/packages/time-devtools/tsdown.config.ts b/packages/time-devtools/tsdown.config.ts index 71071cb9..a72a8faa 100644 --- a/packages/time-devtools/tsdown.config.ts +++ b/packages/time-devtools/tsdown.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from 'tsdown' +import solid from 'rolldown-plugin-solid' export default defineConfig({ entry: ['./src/index.ts'], @@ -13,4 +14,5 @@ export default defineConfig({ publint: { strict: true, }, + plugins: [solid()], }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 63e4ec60..705ed8eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,9 +81,15 @@ importers: examples/react/basic: dependencies: + '@tanstack/react-devtools': + specifier: ^0.9.5 + version: 0.9.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10) '@tanstack/react-time': specifier: ^0.0.0 version: link:../../../packages/react-time + '@tanstack/react-time-devtools': + specifier: ^0.0.0 + version: link:../../../packages/react-time-devtools '@tanstack/time': specifier: ^0.0.0 version: link:../../../packages/time @@ -155,6 +161,9 @@ importers: packages/react-time-devtools: dependencies: + '@tanstack/devtools-utils': + specifier: ^0.3.0 + version: 0.3.0(@types/react@19.2.8)(csstype@3.2.3)(react@19.2.3)(solid-js@1.9.10) '@tanstack/time-devtools': specifier: workspace:* version: link:../time-devtools @@ -180,6 +189,9 @@ importers: react: specifier: ^19.2.3 version: 19.2.3 + solid-js: + specifier: ^1.9.10 + version: 1.9.10 packages/solid-time: dependencies: @@ -202,6 +214,9 @@ importers: packages/solid-time-devtools: dependencies: + '@tanstack/devtools-utils': + specifier: ^0.3.0 + version: 0.3.0(@types/react@19.2.8)(csstype@3.2.3)(react@19.2.3)(solid-js@1.9.10) '@tanstack/time-devtools': specifier: workspace:* version: link:../time-devtools @@ -221,9 +236,25 @@ importers: packages/time-devtools: dependencies: + '@tanstack/devtools-ui': + specifier: ^0.4.4 + version: 0.4.4(csstype@3.2.3)(solid-js@1.9.10) + '@tanstack/devtools-utils': + specifier: ^0.3.0 + version: 0.3.0(@types/react@19.2.8)(csstype@3.2.3)(react@19.2.3)(solid-js@1.9.10) '@tanstack/time': specifier: workspace:* version: link:../time + goober: + specifier: ^2.1.18 + version: 2.1.18(csstype@3.2.3) + solid-js: + specifier: ^1.9.10 + version: 1.9.10 + devDependencies: + rolldown-plugin-solid: + specifier: ^0.2.1 + version: 0.2.1(rolldown@1.0.0-beta.60)(solid-js@1.9.10) packages: @@ -338,6 +369,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.28.6': + resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} @@ -350,6 +393,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.28.6': resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} @@ -1234,6 +1289,36 @@ packages: '@sinclair/typebox@0.34.47': resolution: {integrity: sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==} + '@solid-primitives/event-listener@2.4.3': + resolution: {integrity: sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/keyboard@1.3.3': + resolution: {integrity: sha512-9dQHTTgLBqyAI7aavtO+HnpTVJgWQA1ghBSrmLtMu1SMxLPDuLfuNr+Tk5udb4AL4Ojg7h9JrKOGEEDqsJXWJA==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/resize-observer@2.1.3': + resolution: {integrity: sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/rootless@1.5.2': + resolution: {integrity: sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/static-store@0.1.2': + resolution: {integrity: sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw==} + peerDependencies: + solid-js: ^1.6.12 + + '@solid-primitives/utils@6.3.2': + resolution: {integrity: sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ==} + peerDependencies: + solid-js: ^1.6.12 + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -1252,12 +1337,66 @@ packages: resolution: {integrity: sha512-08eKiDAjj4zLug1taXSIJ0kGL5cawjVCyJkBb6EWSg5fEPX6L+Wtr0CH2If4j5KYylz85iaZiFlUItvgJvll5g==} engines: {node: ^14.13.1 || ^16.0.0 || >=18} + '@tanstack/devtools-client@0.0.5': + resolution: {integrity: sha512-hsNDE3iu4frt9cC2ppn1mNRnLKo2uc1/1hXAyY9z4UYb+o40M2clFAhiFoo4HngjfGJDV3x18KVVIq7W4Un+zA==} + engines: {node: '>=18'} + + '@tanstack/devtools-event-bus@0.4.1': + resolution: {integrity: sha512-cNnJ89Q021Zf883rlbBTfsaxTfi2r73/qejGtyTa7ksErF3hyDyAq1aTbo5crK9dAL7zSHh9viKY1BtMls1QOA==} + engines: {node: '>=18'} + + '@tanstack/devtools-event-client@0.4.0': + resolution: {integrity: sha512-RPfGuk2bDZgcu9bAJodvO2lnZeHuz4/71HjZ0bGb/SPg8+lyTA+RLSKQvo7fSmPSi8/vcH3aKQ8EM9ywf1olaw==} + engines: {node: '>=18'} + + '@tanstack/devtools-ui@0.4.4': + resolution: {integrity: sha512-5xHXFyX3nom0UaNfiOM92o6ziaHjGo3mcSGe2HD5Xs8dWRZNpdZ0Smd0B9ddEhy0oB+gXyMzZgUJb9DmrZV0Mg==} + engines: {node: '>=18'} + peerDependencies: + solid-js: '>=1.9.7' + + '@tanstack/devtools-utils@0.3.0': + resolution: {integrity: sha512-JgApXVrgtgSLIPrm/QWHx0u6c9Ji0MNMDWhwujapj8eMzux5aOfi+2Ycwzj0A0qITXA12SEPYV3HC568mDtYmQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/react': '>=17.0.0' + preact: '>=10.0.0' + react: '>=17.0.0' + solid-js: '>=1.9.7' + vue: '>=3.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + preact: + optional: true + react: + optional: true + solid-js: + optional: true + vue: + optional: true + + '@tanstack/devtools@0.10.6': + resolution: {integrity: sha512-STB3pS49gPoe7UHgDshOMkWPXPZmezsQBLkCrh6l+mcsRs+/Jk1OvfVF8HspiMA1RTuNRkTeGXZDA8LoGWmxyQ==} + engines: {node: '>=18'} + peerDependencies: + solid-js: '>=1.9.7' + '@tanstack/eslint-config@0.3.4': resolution: {integrity: sha512-5Ou1XWJRCTx5G8WoCbT7+6nQ4iNdsISzBAc4lXpFy2fEOO7xioOSPvcPIv+r9V0drPPETou2tr6oLGZZ909FKg==} engines: {node: '>=18'} peerDependencies: eslint: ^8.0.0 || ^9.0.0 + '@tanstack/react-devtools@0.9.5': + resolution: {integrity: sha512-/YsSSobbWfSZ0khLZ5n4cz/isa8Ac21PAVdgrX0qOEkPkS6J63JTEgFR0Ch2n2ka511dm2pIEuTvCsL7WVu1XQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/react': '>=16.8' + '@types/react-dom': '>=16.8' + react: '>=16.8' + react-dom: '>=16.8' + '@tanstack/react-store@0.8.0': resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} peerDependencies: @@ -2304,6 +2443,11 @@ packages: globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + goober@2.1.18: + resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} + peerDependencies: + csstype: ^3.0.10 + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -3014,6 +3158,13 @@ packages: vue-tsc: optional: true + rolldown-plugin-solid@0.2.1: + resolution: {integrity: sha512-vRMsRf4psuWEXZbx+pwp1UYg0YrC9PWPrjGXwFLkVZPtH08sFSMhZpLwMUaLcKoqUvoWlvCPhbFDeSks7os6qQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + rolldown: '>=0.15.0' + solid-js: '>=1.8.0' + rolldown@1.0.0-beta.59: resolution: {integrity: sha512-Slm000Gd8/AO9z4Kxl4r8mp/iakrbAuJ1L+7ddpkNxgQ+Vf37WPvY63l3oeyZcfuPD1DRrUYBsRPIXSOhvOsmw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3744,6 +3895,19 @@ snapshots: '@babel/core': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.6)': dependencies: '@babel/core': 7.28.6 @@ -3754,6 +3918,28 @@ snapshots: '@babel/core': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.28.6) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.28.5(@babel/core@7.28.6)': + dependencies: + '@babel/core': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.28.6) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.28.6) + transitivePeerDependencies: + - supports-color + '@babel/runtime@7.28.6': {} '@babel/template@7.28.6': @@ -4540,6 +4726,40 @@ snapshots: '@sinclair/typebox@0.34.47': {} + '@solid-primitives/event-listener@2.4.3(solid-js@1.9.10)': + dependencies: + '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) + solid-js: 1.9.10 + + '@solid-primitives/keyboard@1.3.3(solid-js@1.9.10)': + dependencies: + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.10) + '@solid-primitives/rootless': 1.5.2(solid-js@1.9.10) + '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) + solid-js: 1.9.10 + + '@solid-primitives/resize-observer@2.1.3(solid-js@1.9.10)': + dependencies: + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.10) + '@solid-primitives/rootless': 1.5.2(solid-js@1.9.10) + '@solid-primitives/static-store': 0.1.2(solid-js@1.9.10) + '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) + solid-js: 1.9.10 + + '@solid-primitives/rootless@1.5.2(solid-js@1.9.10)': + dependencies: + '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) + solid-js: 1.9.10 + + '@solid-primitives/static-store@0.1.2(solid-js@1.9.10)': + dependencies: + '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) + solid-js: 1.9.10 + + '@solid-primitives/utils@6.3.2(solid-js@1.9.10)': + dependencies: + solid-js: 1.9.10 + '@standard-schema/spec@1.1.0': {} '@stylistic/eslint-plugin@5.7.0(eslint@9.39.2(jiti@2.6.1))': @@ -4563,6 +4783,53 @@ snapshots: transitivePeerDependencies: - encoding + '@tanstack/devtools-client@0.0.5': + dependencies: + '@tanstack/devtools-event-client': 0.4.0 + + '@tanstack/devtools-event-bus@0.4.1': + dependencies: + ws: 8.19.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@tanstack/devtools-event-client@0.4.0': {} + + '@tanstack/devtools-ui@0.4.4(csstype@3.2.3)(solid-js@1.9.10)': + dependencies: + clsx: 2.1.1 + goober: 2.1.18(csstype@3.2.3) + solid-js: 1.9.10 + transitivePeerDependencies: + - csstype + + '@tanstack/devtools-utils@0.3.0(@types/react@19.2.8)(csstype@3.2.3)(react@19.2.3)(solid-js@1.9.10)': + dependencies: + '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.10) + optionalDependencies: + '@types/react': 19.2.8 + react: 19.2.3 + solid-js: 1.9.10 + transitivePeerDependencies: + - csstype + + '@tanstack/devtools@0.10.6(csstype@3.2.3)(solid-js@1.9.10)': + dependencies: + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.10) + '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.10) + '@solid-primitives/resize-observer': 2.1.3(solid-js@1.9.10) + '@tanstack/devtools-client': 0.0.5 + '@tanstack/devtools-event-bus': 0.4.1 + '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.10) + clsx: 2.1.1 + goober: 2.1.18(csstype@3.2.3) + solid-js: 1.9.10 + transitivePeerDependencies: + - bufferutil + - csstype + - utf-8-validate + '@tanstack/eslint-config@0.3.4(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint/js': 9.39.2 @@ -4579,6 +4846,19 @@ snapshots: - supports-color - typescript + '@tanstack/react-devtools@0.9.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)': + dependencies: + '@tanstack/devtools': 0.10.6(csstype@3.2.3)(solid-js@1.9.10) + '@types/react': 19.2.8 + '@types/react-dom': 19.2.3(@types/react@19.2.8) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + transitivePeerDependencies: + - bufferutil + - csstype + - solid-js + - utf-8-validate + '@tanstack/react-store@0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@tanstack/store': 0.8.0 @@ -5756,6 +6036,10 @@ snapshots: globrex@0.1.2: {} + goober@2.1.18(csstype@3.2.3): + dependencies: + csstype: 3.2.3 + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -6430,6 +6714,16 @@ snapshots: transitivePeerDependencies: - oxc-resolver + rolldown-plugin-solid@0.2.1(rolldown@1.0.0-beta.60)(solid-js@1.9.10): + dependencies: + '@babel/core': 7.28.6 + '@babel/preset-typescript': 7.28.5(@babel/core@7.28.6) + babel-preset-solid: 1.9.10(@babel/core@7.28.6)(solid-js@1.9.10) + rolldown: 1.0.0-beta.60 + solid-js: 1.9.10 + transitivePeerDependencies: + - supports-color + rolldown@1.0.0-beta.59: dependencies: '@oxc-project/types': 0.107.0 From 5375009099761ef266654ba4082f17053acc183e Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Tue, 10 Feb 2026 09:34:40 +0100 Subject: [PATCH 055/207] feat: devtools --- examples/react/basic/src/index.tsx | 78 +- packages/react-time/src/index.ts | 3 + packages/react-time/src/useCalendar/index.ts | 1 + .../react-time/src/useCalendar/useCalendar.ts | 138 +- .../time-devtools/src/components/Shell.tsx | 122 +- .../time-devtools/src/store/time-context.tsx | 53 +- .../time-devtools/src/styles/use-styles.ts | 66 +- packages/time/package.json | 3 +- packages/time/src/calendar/calendar.ts | 29 + packages/time/src/calendar/date-core.ts | 29 +- packages/time/src/calendar/types.ts | 41 + packages/time/src/client/TimeClient.ts | 87 + packages/time/src/client/index.ts | 1 + packages/time/src/index.ts | 1 + pnpm-lock.yaml | 2236 ++++++++--------- 15 files changed, 1748 insertions(+), 1140 deletions(-) create mode 100644 packages/time/src/client/TimeClient.ts create mode 100644 packages/time/src/client/index.ts diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index c04228cf..bf5417d4 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -6,10 +6,10 @@ import { useCalendar, } from '@tanstack/react-time' import ReactDOM from 'react-dom/client' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { TanStackDevtools } from '@tanstack/react-devtools' import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' -import type { Day, Event, Resource } from '@tanstack/time' +import type { Day, Event, Resource, ResizeError } from '@tanstack/time' import './index.css' @@ -564,6 +564,68 @@ function ScheduleView({ ) } +function ResizeErrorToast({ + error, + onDismiss, +}: { + error: ResizeError + onDismiss: () => void +}) { + useEffect(() => { + const timer = setTimeout(onDismiss, 5000) + return () => clearTimeout(timer) + }, [onDismiss]) + + return ( +
+
+
+
⚠
+
+
+ Cannot Resize Event +
+
{error.message}
+ {error.conflicts && error.conflicts.length > 0 && ( +
+
+ Conflicts: +
+ {error.conflicts.map((conflict, idx) => ( +
+
+ {conflict.date} +
+
+ {conflict.conflictRange.start} -{' '} + {conflict.conflictRange.end} +
+
+ {conflict.description} +
+
+ ))} +
+ )} +
+ {error.eventTitle} +
+
+ +
+
+
+ ) +} + function CalendarView() { const [modalState, setModalState] = useState<{ isOpen: boolean @@ -576,6 +638,8 @@ function CalendarView() { initialData: emptyFormData, }) + const [resizeError, setResizeError] = useState(null) + const calendar = useCalendar>({ viewMode: { value: 1, unit: 'month' }, events: sampleEvents, @@ -588,6 +652,9 @@ function CalendarView() { minDurationMinutes: 15, snapToMinutes: 15, }, + onResizeError: (error) => { + setResizeError(error) + }, }, }) @@ -873,6 +940,13 @@ function CalendarView() { initialData={modalState.initialData} mode={modalState.mode} /> + + {resizeError && ( + setResizeError(null)} + /> + )}
) } diff --git a/packages/react-time/src/index.ts b/packages/react-time/src/index.ts index ff52acbe..a4358d60 100644 --- a/packages/react-time/src/index.ts +++ b/packages/react-time/src/index.ts @@ -5,6 +5,9 @@ export type { UseCalendarOptions, } from './useCalendar' +// Re-export ResizeError and AvailabilityConflict from core package +export type { ResizeError, AvailabilityConflict } from '@tanstack/time' + export { calculateGhostPreviewStyle, calculateSegmentResizePreview, diff --git a/packages/react-time/src/useCalendar/index.ts b/packages/react-time/src/useCalendar/index.ts index 14b46416..2f96372e 100644 --- a/packages/react-time/src/useCalendar/index.ts +++ b/packages/react-time/src/useCalendar/index.ts @@ -4,3 +4,4 @@ export type { ResizeOptions, UseCalendarOptions, } from './useCalendar' +export type { ResizeError } from '@tanstack/time' diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 853a89f9..93937146 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -11,13 +11,16 @@ import { CalendarCore, calculateDeltaMinutesFromPixels, calculateResizedEvent, + getTimeClient, } from '@tanstack/time' import type { + AvailabilityConflict, CalendarApi, CalendarCoreOptions, Event, ResizeConstraints, ResizeEdge, + ResizeError, Resource, } from '@tanstack/time' @@ -36,6 +39,7 @@ export interface ResizeOptions { constraints?: ResizeConstraints onResizeStart?: (eventId: string, edge: ResizeEdge) => void onResizeEnd?: (eventId: string, newStart: string, newEnd: string) => void + onResizeError?: (error: ResizeError) => void } interface ResizeHandleHandlers { @@ -101,6 +105,11 @@ export const useCalendar = < originalDayDate: string currentDayDate: string } | null>(null) + const lastEmittedErrorRef = useRef<{ + eventId: string + message: string + timestamp: number + } | null>(null) const subscribeResize = useCallback((listener: () => void) => { resizeListenersRef.current.add(listener) @@ -193,6 +202,21 @@ export const useCalendar = < const originalEndDate = end.split('T')[0] ?? '' let shouldBlockResize = false + let blockReason: ResizeError['reason'] = 'blocked' + let blockMessage = 'Resize blocked' + const conflicts: Array = [] + + const formatMinutesToTime = (minutes: number): string => { + const hours = Math.floor(minutes / 60) + const mins = minutes % 60 + return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}` + } + + const snapToMinutes = resizeConstraints?.snapToMinutes ?? 1 + const snapMinutes = (minutes: number): number => { + if (snapToMinutes <= 1) return minutes + return Math.round(minutes / snapToMinutes) * snapToMinutes + } if (edge === 'top' && targetDayDate < originalStartDate) { const rawStartMinutes = @@ -200,15 +224,30 @@ export const useCalendar = < new Date(start).getMinutes() + totalDeltaMinutes const targetStartMinutes = ((rawStartMinutes % 1440) + 1440) % 1440 + // Snap to grid before checking conflicts + const snappedTargetStartMinutes = snapMinutes(targetStartMinutes) const currentStartMinutes = new Date(start).getHours() * 60 + new Date(start).getMinutes() for (const range of unavailableRanges) { if ( - targetStartMinutes < range.endMinutes && + snappedTargetStartMinutes < range.endMinutes && range.startMinutes < 1440 ) { shouldBlockResize = true + blockReason = 'unavailable-time' + blockMessage = `Cannot resize: Event would start at ${formatMinutesToTime(snappedTargetStartMinutes)} which is during unavailable time (${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)})` + conflicts.push({ + date: targetDayDate, + conflictRange: { + start: formatMinutesToTime( + Math.max(snappedTargetStartMinutes, range.startMinutes), + ), + end: formatMinutesToTime(range.endMinutes), + }, + resourceIds: resourceIds ?? [], + description: `Target time ${formatMinutesToTime(snappedTargetStartMinutes)} conflicts with unavailable period ${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)}`, + }) break } } @@ -222,6 +261,19 @@ export const useCalendar = < range.startMinutes < currentStartMinutes ) { shouldBlockResize = true + blockReason = 'unavailable-time' + blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalStartDate} (${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)})` + conflicts.push({ + date: originalStartDate, + conflictRange: { + start: formatMinutesToTime(range.startMinutes), + end: formatMinutesToTime( + Math.min(range.endMinutes, currentStartMinutes), + ), + }, + resourceIds: resourceIds ?? [], + description: `Must pass through unavailable period ${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)}`, + }) break } } @@ -232,6 +284,8 @@ export const useCalendar = < new Date(end).getMinutes() + totalDeltaMinutes const targetEndMinutes = ((rawEndMinutes % 1440) + 1440) % 1440 + // Snap to grid before checking conflicts + const snappedTargetEndMinutes = snapMinutes(targetEndMinutes) const currentEndMinutes = new Date(end).getHours() * 60 + new Date(end).getMinutes() @@ -243,20 +297,99 @@ export const useCalendar = < range.startMinutes < 1440 ) { shouldBlockResize = true + blockReason = 'unavailable-time' + blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalEndDate} (${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)})` + conflicts.push({ + date: originalEndDate, + conflictRange: { + start: formatMinutesToTime( + Math.max(range.startMinutes, currentEndMinutes), + ), + end: formatMinutesToTime(range.endMinutes), + }, + resourceIds: resourceIds ?? [], + description: `Must pass through unavailable period ${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)}`, + }) break } } if (!shouldBlockResize) { for (const range of unavailableRanges) { - if (0 < range.endMinutes && range.startMinutes < targetEndMinutes) { + if ( + 0 < range.endMinutes && + range.startMinutes < snappedTargetEndMinutes + ) { shouldBlockResize = true + blockReason = 'unavailable-time' + blockMessage = `Cannot resize: Event would end at ${formatMinutesToTime(snappedTargetEndMinutes)} which is during unavailable time (${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)})` + conflicts.push({ + date: targetDayDate, + conflictRange: { + start: formatMinutesToTime(range.startMinutes), + end: formatMinutesToTime( + Math.min(snappedTargetEndMinutes, range.endMinutes), + ), + }, + resourceIds: resourceIds ?? [], + description: `Target time ${formatMinutesToTime(snappedTargetEndMinutes)} conflicts with unavailable period ${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)}`, + }) break } } } } + // Emit error if resize is blocked (throttle to avoid emitting on every mouse move) + if (shouldBlockResize) { + const event = calendarOptions.events?.find((ev) => ev.id === id) + const now = Date.now() + const lastError = lastEmittedErrorRef.current + + // Only emit if this is a different error or it's been more than 500ms + const shouldEmitError = + !lastError || + lastError.eventId !== id || + lastError.message !== blockMessage || + now - lastError.timestamp > 500 + + if (shouldEmitError) { + const resizeError: ResizeError = { + eventId: id, + eventTitle: event?.title ?? 'Unknown Event', + reason: blockReason, + message: blockMessage, + originalStart: start, + originalEnd: end, + conflicts: conflicts.length > 0 ? conflicts : undefined, + } + + // Emit to TimeClient for devtools + getTimeClient().emit('event:resize:error', { + eventId: id, + eventTitle: event?.title ?? 'Unknown Event', + reason: blockReason, + message: blockMessage, + originalStart: start, + originalEnd: end, + conflicts: conflicts.length > 0 ? conflicts : undefined, + }) + + // Call user-provided error handler + resize?.onResizeError?.(resizeError) + + // Track this error emission + lastEmittedErrorRef.current = { + eventId: id, + message: blockMessage, + timestamp: now, + } + } + } else { + // Clear last error when resize is no longer blocked + lastEmittedErrorRef.current = null + } + const effectiveDeltaMinutes = shouldBlockResize ? deltaMinutes : totalDeltaMinutes @@ -313,6 +446,7 @@ export const useCalendar = < } originalEventRef.current = null + lastEmittedErrorRef.current = null updateResizeState(initialResizeState) document.removeEventListener('mousemove', handleMouseMove) diff --git a/packages/time-devtools/src/components/Shell.tsx b/packages/time-devtools/src/components/Shell.tsx index 2883b692..f18badd3 100644 --- a/packages/time-devtools/src/components/Shell.tsx +++ b/packages/time-devtools/src/components/Shell.tsx @@ -1,6 +1,16 @@ -import { Header, HeaderLogo, MainPanel } from '@tanstack/devtools-ui' +import { For, Show } from 'solid-js' +import { + Button, + Header, + HeaderLogo, + MainPanel, + Section, + SectionTitle, + Tag, +} from '@tanstack/devtools-ui' import { useStyles } from '../styles/use-styles' -import { TimeProvider } from '../store/time-context' +import { TimeProvider, useTimeStore } from '../store/time-context' +import type { ActivityLogEntry } from '../store/time-context' export default function Devtools() { return ( @@ -10,17 +20,121 @@ export default function Devtools() { ) } +const formatTime = (timestamp: number) => { + const date = new Date(timestamp) + return date.toLocaleTimeString('en-US', { + hour12: false, + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }) +} + +const getEventTypeLabel = ( + type: string, +): { + text: string + color: 'green' | 'blue' | 'red' | 'yellow' | 'purple' | 'pink' | 'gray' +} => { + switch (type) { + case 'time:event:added': + return { text: 'Added', color: 'green' } + case 'time:event:updated': + return { text: 'Updated', color: 'blue' } + case 'time:event:removed': + return { text: 'Removed', color: 'red' } + case 'time:event:resized': + return { text: 'Resized', color: 'yellow' } + case 'time:event:resize:error': + return { text: 'Resize Error', color: 'red' } + case 'time:calendar:navigate': + return { text: 'Navigate', color: 'purple' } + case 'time:calendar:viewMode:changed': + return { text: 'View Mode', color: 'pink' } + default: + return { text: type, color: 'gray' } + } +} + +const getEventDescription = (entry: ActivityLogEntry): string => { + const { type, details } = entry + + switch (type) { + case 'time:event:added': + return `${details.eventTitle || 'Event'} (ID: ${String(details.eventId).slice(0, 8)}...)` + case 'time:event:updated': + return `${details.eventTitle || 'Event'} - ${Object.keys(details.updates || {}).join(', ')}` + case 'time:event:removed': + return `${details.eventTitle || 'Event'}` + case 'time:event:resized': + return `Resized to ${String(details.start)} - ${String(details.end)}` + case 'time:event:resize:error': + return `${details.eventTitle || 'Event'} - ${String(details.message)}` + case 'time:calendar:navigate': + return `${String(details.direction)} → ${String(details.targetDate)}` + case 'time:calendar:viewMode:changed': + const viewMode = details.viewMode as + | { value?: number; unit?: string } + | undefined + return `${viewMode?.value || ''} ${viewMode?.unit || ''}` + default: + return '' + } +} + function DevtoolsContent() { + const { state, clearLog } = useTimeStore() const styles = useStyles() return (
- + TanStack Time + + + + Connected + +
-
+
+
+ Activity Log + +
+ + 0} + fallback={ +
+ No activity yet. Start interacting with the calendar! +
+ } + > +
+ + {(entry) => { + const label = getEventTypeLabel(entry.type) + return ( +
+ + {formatTime(entry.timestamp)} + + + + {getEventDescription(entry)} + +
+ ) + }} +
+
+
+
) } diff --git a/packages/time-devtools/src/store/time-context.tsx b/packages/time-devtools/src/store/time-context.tsx index 45b855c3..e45a53b6 100644 --- a/packages/time-devtools/src/store/time-context.tsx +++ b/packages/time-devtools/src/store/time-context.tsx @@ -1,11 +1,23 @@ -import { createContext, useContext } from 'solid-js' +import { createContext, useContext, onMount, onCleanup } from 'solid-js' import { createStore } from 'solid-js/store' import type { ParentComponent } from 'solid-js' +import { getTimeClient, type TimeEventMap } from '@tanstack/time' -interface TimeStoreState {} +export interface ActivityLogEntry { + id: string + timestamp: number + type: keyof TimeEventMap + details: Record +} + +interface TimeStoreState { + activityLog: Array + isConnected: boolean +} interface TimeContextValue { state: TimeStoreState + clearLog: () => void } const TimeContext = createContext() @@ -18,14 +30,47 @@ export function useTimeStore(): TimeContextValue { return context } +function generateId(): string { + return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}` +} + export const TimeProvider: ParentComponent = (props) => { const [state, setState] = createStore({ - conversations: {}, - activeConversationId: null, + activityLog: [], + isConnected: false, + }) + + const clearLog = () => { + setState('activityLog', []) + } + + onMount(() => { + const client = getTimeClient() + + // Mark as connected + setState('isConnected', true) + + // Subscribe to all time events using onAllPluginEvents + const unsubscribe = client.onAllPluginEvents((event) => { + const entry: ActivityLogEntry = { + id: generateId(), + timestamp: Date.now(), + type: event.type, + details: event.payload as unknown as Record, + } + + setState('activityLog', (prev) => [entry, ...prev].slice(0, 100)) + }) + + onCleanup(() => { + unsubscribe() + setState('isConnected', false) + }) }) const contextValue: TimeContextValue = { state, + clearLog, } return ( diff --git a/packages/time-devtools/src/styles/use-styles.ts b/packages/time-devtools/src/styles/use-styles.ts index 3b01e72f..b3c6e881 100644 --- a/packages/time-devtools/src/styles/use-styles.ts +++ b/packages/time-devtools/src/styles/use-styles.ts @@ -1,25 +1,75 @@ import * as goober from 'goober' import { createEffect, createSignal } from 'solid-js' -import { useTheme } from '@tanstack/devtools-ui' -import { tokens } from './tokens' const stylesFactory = () => { - const { font, size } = tokens const css = goober.css return { - mainContainer: css` + connectedStatus: css` + font-size: 12px; + color: #22c55e; display: flex; - flex: 1; - min-height: 80%; + align-items: center; + gap: 6px; + `, + + connectedDot: css` + width: 8px; + height: 8px; + border-radius: 50%; + background-color: #22c55e; + `, + + sectionHeader: css` + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; + `, + + emptyState: css` + text-align: center; + color: #6b7280; + padding: 20px; + font-size: 13px; + `, + + activityList: css` + display: flex; + flex-direction: column; + gap: 8px; + max-height: 300px; + overflow-y: auto; + `, + + activityEntry: css` + display: flex; + align-items: center; + gap: 10px; + padding: 8px 10px; + background-color: #1f2937; + border-radius: 6px; + font-size: 12px; + `, + + timestamp: css` + font-family: monospace; + color: #9ca3af; + font-size: 11px; + min-width: 70px; + `, + + description: css` + color: #e5e7eb; + flex-grow: 1; overflow: hidden; - padding: ${size[2]}; + text-overflow: ellipsis; + white-space: nowrap; `, } } export function useStyles() { - const { theme } = useTheme() const [styles, setStyles] = createSignal(stylesFactory()) createEffect(() => { setStyles(stylesFactory()) diff --git a/packages/time/package.json b/packages/time/package.json index e28476cb..53610f97 100644 --- a/packages/time/package.json +++ b/packages/time/package.json @@ -47,6 +47,7 @@ "src" ], "dependencies": { - "@tanstack/store": "^0.8.0" + "@tanstack/store": "^0.8.0", + "@tanstack/devtools-event-client": "^0.4.0" } } diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index 8c7ebf3c..ed1ea1b8 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -1,4 +1,5 @@ import { Temporal } from '@js-temporal/polyfill' +import { getTimeClient } from '../client' import { splitMultiDayEvents } from './splitMultiDayEvents' import { getEventProps } from './getEventProps' import { groupDaysBy } from './groupDaysBy' @@ -264,6 +265,13 @@ export class CalendarCore< ...prev, eventsVersion: prev.eventsVersion + 1, })) + + getTimeClient().emit('event:added', { + eventId: event.id, + eventTitle: event.title, + start: event.start, + end: event.end, + }) } updateEvent(id: Event['id'], updates: Partial>): void { @@ -278,6 +286,17 @@ export class CalendarCore< ...prev, eventsVersion: prev.eventsVersion + 1, })) + + // Emit event to TimeClient + if (existingEvent) { + getTimeClient().emit('event:updated', { + eventId: id, + eventTitle: existingEvent.title, + start: this.options.events[index].start, + end: this.options.events[index].end, + updates: updates as Record, + }) + } } removeEvent(id: Event['id']): void { @@ -286,11 +305,21 @@ export class CalendarCore< const index = this.options.events.findIndex((e) => e.id === id) if (index === -1) return + const removedEvent = this.options.events[index] this.options.events.splice(index, 1) this.store.setState((prev) => ({ ...prev, eventsVersion: prev.eventsVersion + 1, })) + + if (removedEvent) { + getTimeClient().emit('event:removed', { + eventId: id, + eventTitle: removedEvent.title, + start: removedEvent.start, + end: removedEvent.end, + }) + } } getUnavailableRanges( diff --git a/packages/time/src/calendar/date-core.ts b/packages/time/src/calendar/date-core.ts index 42dfa196..4de82064 100644 --- a/packages/time/src/calendar/date-core.ts +++ b/packages/time/src/calendar/date-core.ts @@ -11,6 +11,7 @@ import { getDateTimeDefaults } from '../utils/dateDefaults' import { buildDateFormatter } from '../formatter/buildDateFormatter' import { buildDateTimeFormatter } from '../formatter/buildDateTimeFormatter' import { buildTimeFormatter } from '../formatter/buildTimeFormatter' +import { getTimeClient } from '../client' import { generateDateRange } from './generateDateRange' import type { ParsedDateRange } from '../utils/dateRange' import type { CalendarStore, DateRange, ViewMode } from './types' @@ -82,7 +83,6 @@ export abstract class DateCore { time: Intl.DateTimeFormat dateTime: Intl.DateTimeFormat } - constructor(options: DateCoreOptions) { const defaults = getDateTimeDefaults() const parsedRange = parseDateRange({ @@ -267,6 +267,13 @@ export abstract class DateCore { ...prev, viewMode: newViewMode, })) + + getTimeClient().emit('calendar:viewMode:changed', { + viewMode: { + value: newViewMode.value, + unit: newViewMode.unit, + }, + }) } goToPreviousPeriod() { @@ -310,6 +317,11 @@ export abstract class DateCore { activeDate: constrainedDate, currentPeriod: constrainedDate, })) + + getTimeClient().emit('calendar:navigate', { + direction: 'previous', + targetDate: constrainedDate.toString({ calendarName: 'never' }), + }) } goToNextPeriod() { @@ -353,6 +365,11 @@ export abstract class DateCore { activeDate: constrainedDate, currentPeriod: constrainedDate, })) + + getTimeClient().emit('calendar:navigate', { + direction: 'next', + targetDate: constrainedDate.toString({ calendarName: 'never' }), + }) } goToCurrentPeriod() { @@ -366,6 +383,11 @@ export abstract class DateCore { activeDate: constrainedDate, currentPeriod: constrainedDate, })) + + getTimeClient().emit('calendar:navigate', { + direction: 'current', + targetDate: constrainedDate.toString({ calendarName: 'never' }), + }) } goToSpecificPeriod(date: DateInput) { @@ -382,6 +404,11 @@ export abstract class DateCore { activeDate: constrainedDate, currentPeriod: constrainedDate, })) + + getTimeClient().emit('calendar:navigate', { + direction: 'specific', + targetDate: constrainedDate.toString({ calendarName: 'never' }), + }) } canGoPreviousPeriod(): boolean { diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index bb2736b7..676e966e 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -82,3 +82,44 @@ export interface CalendarStore { viewMode: ViewMode eventsVersion: number } + +/** + * Information about a specific availability conflict + */ +export interface AvailabilityConflict { + /** The date where the conflict occurred (YYYY-MM-DD) */ + date: string + /** Time range that conflicts with availability */ + conflictRange: { + start: string + end: string + } + /** The resource(s) whose availability is being violated */ + resourceIds: Array + /** Human-readable description of the conflict */ + description: string +} + +/** + * Error information when a resize operation is blocked + */ +export interface ResizeError { + eventId: string + eventTitle: string + reason: 'unavailable-time' | 'invalid-time' | 'min-duration' | 'blocked' + message: string + originalStart: string + originalEnd: string + attemptedStart?: string + attemptedEnd?: string + /** Specific availability conflicts that prevented the resize */ + conflicts?: Array +} + +/** + * Result of checking if a resize is valid + */ +export interface ResizeValidationResult { + valid: boolean + error?: ResizeError +} diff --git a/packages/time/src/client/TimeClient.ts b/packages/time/src/client/TimeClient.ts new file mode 100644 index 00000000..de19f9bc --- /dev/null +++ b/packages/time/src/client/TimeClient.ts @@ -0,0 +1,87 @@ +import { EventClient } from '@tanstack/devtools-event-client' +import type { AvailabilityConflict } from '../calendar/types' + +/** + * Event map for TimeClient events + */ +export interface TimeEventMap { + 'time:event:added': { + eventId: string + eventTitle: string + start: string + end: string + } + 'time:event:updated': { + eventId: string + eventTitle: string + start: string + end: string + updates: Record + } + 'time:event:removed': { + eventId: string + eventTitle: string + start: string + end: string + } + 'time:event:resized': { + eventId: string + eventTitle: string + start: string + end: string + } + 'time:event:resize:error': { + eventId: string + eventTitle: string + reason: 'unavailable-time' | 'invalid-time' | 'min-duration' | 'blocked' + message: string + originalStart: string + originalEnd: string + attemptedStart?: string + attemptedEnd?: string + conflicts?: Array + } + 'time:calendar:navigate': { + direction: 'previous' | 'next' | 'current' | 'specific' + targetDate: string + } + 'time:calendar:viewMode:changed': { + viewMode: { + value: number + unit: string + } + } +} + +/** + * TimeClient extends EventClient to provide typed events for calendar operations + * Used by devtools to monitor and display activity + */ +class TimeClient extends EventClient { + private static instance: TimeClient | null = null + + private constructor() { + super({ + pluginId: 'time', + }) + } + + /** + * Get the singleton instance + */ + static getInstance(): TimeClient { + if (!TimeClient.instance) { + TimeClient.instance = new TimeClient() + } + return TimeClient.instance + } +} + +/** + * Get the global TimeClient instance + */ +export function getTimeClient(): TimeClient { + return TimeClient.getInstance() +} + +export type { AvailabilityConflict } diff --git a/packages/time/src/client/index.ts b/packages/time/src/client/index.ts new file mode 100644 index 00000000..10cef5e5 --- /dev/null +++ b/packages/time/src/client/index.ts @@ -0,0 +1 @@ +export * from './TimeClient' diff --git a/packages/time/src/index.ts b/packages/time/src/index.ts index 61005c71..d7284f31 100644 --- a/packages/time/src/index.ts +++ b/packages/time/src/index.ts @@ -1,2 +1,3 @@ export * from './date' export * from './calendar' +export * from './client' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 705ed8eb..a9ece014 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,16 +14,16 @@ importers: devDependencies: '@changesets/cli': specifier: ^2.29.8 - version: 2.29.8(@types/node@25.0.9) + version: 2.29.8(@types/node@25.2.2) '@faker-js/faker': specifier: ^10.2.0 - version: 10.2.0 + version: 10.3.0 '@svitejs/changesets-changelog-github-compact': specifier: ^1.2.0 version: 1.2.0 '@tanstack/eslint-config': specifier: 0.3.4 - version: 0.3.4(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 0.3.4(@typescript-eslint/utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@tanstack/typedoc-config': specifier: 0.3.3 version: 0.3.3(typescript@5.9.3) @@ -32,37 +32,37 @@ importers: version: 6.9.1 '@types/node': specifier: ^25.0.7 - version: 25.0.9 + version: 25.2.2 eslint: specifier: ^9.39.2 version: 9.39.2(jiti@2.6.1) eslint-plugin-unused-imports: specifier: ^4.3.0 - version: 4.3.0(@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + version: 4.4.1(@typescript-eslint/eslint-plugin@8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) happy-dom: specifier: ^20.1.0 - version: 20.3.1 + version: 20.5.3 knip: specifier: ^5.80.2 - version: 5.81.0(@types/node@25.0.9)(typescript@5.9.3) + version: 5.83.1(@types/node@25.2.2)(typescript@5.9.3) markdown-link-extractor: specifier: ^4.0.3 version: 4.0.3 nx: specifier: ^22.3.3 - version: 22.3.3 + version: 22.4.5 premove: specifier: ^4.0.0 version: 4.0.0 prettier: specifier: ^3.7.4 - version: 3.8.0 + version: 3.8.1 prettier-plugin-svelte: specifier: ^3.4.1 - version: 3.4.1(prettier@3.8.0)(svelte@5.46.4) + version: 3.4.1(prettier@3.8.1)(svelte@5.50.0) publint: specifier: ^0.3.16 - version: 0.3.16 + version: 0.3.17 sherif: specifier: ^1.9.0 version: 1.10.0 @@ -71,19 +71,19 @@ importers: version: 0.2.15 tsdown: specifier: ^0.19.0 - version: 0.19.0(oxc-resolver@11.16.3)(publint@0.3.16)(typescript@5.9.3) + version: 0.19.0(oxc-resolver@11.17.1)(publint@0.3.17)(typescript@5.9.3) typescript: specifier: 5.9.3 version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(yaml@2.8.2) + version: 4.0.18(@types/node@25.2.2)(happy-dom@20.5.3)(jiti@2.6.1)(yaml@2.8.2) examples/react/basic: dependencies: '@tanstack/react-devtools': specifier: ^0.9.5 - version: 0.9.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10) + version: 0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) '@tanstack/react-time': specifier: ^0.0.0 version: link:../../../packages/react-time @@ -95,23 +95,23 @@ importers: version: link:../../../packages/time react: specifier: ^19.2.3 - version: 19.2.3 + version: 19.2.4 react-dom: specifier: ^19.2.3 - version: 19.2.3(react@19.2.3) + version: 19.2.4(react@19.2.4) devDependencies: '@types/react': specifier: ^19.2.8 - version: 19.2.8 + version: 19.2.13 '@types/react-dom': specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.8) + version: 19.2.3(@types/react@19.2.13) '@vitejs/plugin-react': specifier: ^5.1.2 - version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2)) + version: 5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2)) autoprefixer: specifier: ^10.4.20 - version: 10.4.23(postcss@8.5.6) + version: 10.4.24(postcss@8.5.6) postcss: specifier: ^8.4.49 version: 8.5.6 @@ -123,32 +123,32 @@ importers: version: 5.9.3 vite: specifier: ^7.3.1 - version: 7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2) + version: 7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2) packages/react-time: dependencies: '@tanstack/react-store': specifier: ^0.8.0 - version: 0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/time': specifier: workspace:* version: link:../time react-dom: specifier: '>=16.8' - version: 19.2.3(react@19.2.3) + version: 19.2.4(react@19.2.4) devDependencies: '@eslint-react/eslint-plugin': specifier: ^2.7.2 - version: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@testing-library/react': specifier: ^16.1.0 - version: 16.3.1(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/react': specifier: ^19.2.8 - version: 19.2.8 + version: 19.2.13 '@vitejs/plugin-react': specifier: ^5.1.2 - version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + version: 5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) eslint-plugin-react-compiler: specifier: 19.1.0-rc.2 version: 19.1.0-rc.2(eslint@9.39.2(jiti@2.6.1)) @@ -157,29 +157,29 @@ importers: version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) react: specifier: ^19.2.3 - version: 19.2.3 + version: 19.2.4 packages/react-time-devtools: dependencies: '@tanstack/devtools-utils': specifier: ^0.3.0 - version: 0.3.0(@types/react@19.2.8)(csstype@3.2.3)(react@19.2.3)(solid-js@1.9.10) + version: 0.3.0(@types/react@19.2.13)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) '@tanstack/time-devtools': specifier: workspace:* version: link:../time-devtools react-dom: specifier: '>=16.8' - version: 19.2.3(react@19.2.3) + version: 19.2.4(react@19.2.4) devDependencies: '@eslint-react/eslint-plugin': specifier: ^2.7.2 - version: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + version: 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@types/react': specifier: ^19.2.8 - version: 19.2.8 + version: 19.2.13 '@vitejs/plugin-react': specifier: ^5.1.2 - version: 5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + version: 5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) eslint-plugin-react-compiler: specifier: 19.1.0-rc.2 version: 19.1.0-rc.2(eslint@9.39.2(jiti@2.6.1)) @@ -188,48 +188,51 @@ importers: version: 7.0.1(eslint@9.39.2(jiti@2.6.1)) react: specifier: ^19.2.3 - version: 19.2.3 + version: 19.2.4 solid-js: specifier: ^1.9.10 - version: 1.9.10 + version: 1.9.11 packages/solid-time: dependencies: '@tanstack/solid-store': specifier: ^0.8.0 - version: 0.8.0(solid-js@1.9.10) + version: 0.8.0(solid-js@1.9.11) '@tanstack/time': specifier: workspace:* version: link:../time devDependencies: '@types/node': specifier: ^25.0.7 - version: 25.0.9 + version: 25.2.2 solid-js: specifier: ^1.9.10 - version: 1.9.10 + version: 1.9.11 vite-plugin-solid: specifier: ^2.11.10 - version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) packages/solid-time-devtools: dependencies: '@tanstack/devtools-utils': specifier: ^0.3.0 - version: 0.3.0(@types/react@19.2.8)(csstype@3.2.3)(react@19.2.3)(solid-js@1.9.10) + version: 0.3.0(@types/react@19.2.13)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) '@tanstack/time-devtools': specifier: workspace:* version: link:../time-devtools devDependencies: solid-js: specifier: ^1.9.10 - version: 1.9.10 + version: 1.9.11 vite-plugin-solid: specifier: ^2.11.10 - version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + version: 2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) packages/time: dependencies: + '@tanstack/devtools-event-client': + specifier: ^0.4.0 + version: 0.4.0 '@tanstack/store': specifier: ^0.8.0 version: 0.8.0 @@ -238,10 +241,10 @@ importers: dependencies: '@tanstack/devtools-ui': specifier: ^0.4.4 - version: 0.4.4(csstype@3.2.3)(solid-js@1.9.10) + version: 0.4.4(csstype@3.2.3)(solid-js@1.9.11) '@tanstack/devtools-utils': specifier: ^0.3.0 - version: 0.3.0(@types/react@19.2.8)(csstype@3.2.3)(react@19.2.3)(solid-js@1.9.10) + version: 0.3.0(@types/react@19.2.13)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) '@tanstack/time': specifier: workspace:* version: link:../time @@ -250,11 +253,11 @@ importers: version: 2.1.18(csstype@3.2.3) solid-js: specifier: ^1.9.10 - version: 1.9.10 + version: 1.9.11 devDependencies: rolldown-plugin-solid: specifier: ^0.2.1 - version: 0.2.1(rolldown@1.0.0-beta.60)(solid-js@1.9.10) + version: 0.2.1(rolldown@1.0.0-rc.3)(solid-js@1.9.11) packages: @@ -265,20 +268,20 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@babel/code-frame@7.28.6': - resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.6': - resolution: {integrity: sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.6': - resolution: {integrity: sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.6': - resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} '@babel/helper-annotate-as-pure@7.27.3': @@ -351,8 +354,8 @@ packages: resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.6': - resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} engines: {node: '>=6.0.0'} hasBin: true @@ -413,12 +416,12 @@ packages: resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.6': - resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.6': - resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} '@changesets/apply-release-plan@7.0.14': @@ -488,158 +491,158 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@esbuild/aix-ppc64@0.27.2': - resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.2': - resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.2': - resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.2': - resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.2': - resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.2': - resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.2': - resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.2': - resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.2': - resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.2': - resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.2': - resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.2': - resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.2': - resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.2': - resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.2': - resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.2': - resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.2': - resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.2': - resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.2': - resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.2': - resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.2': - resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.2': - resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.2': - resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.2': - resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.2': - resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.2': - resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -654,43 +657,43 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint-react/ast@2.7.2': - resolution: {integrity: sha512-RB8AVNjboN6/md9Da4rUG4WqxLT+DqUR+qXIR6iAD0+xxp6Dtihu541+lKLZ3GCstunbBcDwu7gdhSbz+BHSuQ==} + '@eslint-react/ast@2.12.2': + resolution: {integrity: sha512-OMpEIJguhDOaMDr6U4/qmoSQCjNcqCteiv4okA6a0p5ACX9s1uulmK2tcm7sep4RR+nPYkZUag3sXOi3R0oFmw==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@eslint-react/core@2.7.2': - resolution: {integrity: sha512-QOYh8OWwUGMYLhuvb8WcmoS2jYXb0SJbpX+Ozk+Ht2G9XGRAahl+8PDy/o2l2lLnFXv5JQGfLrN+m2WPTi104g==} + '@eslint-react/core@2.12.2': + resolution: {integrity: sha512-lS2a1I3G7JXjFfdlOWXJoid8kPstcgMyL3rVQFcZVJF569JwF/VRZ7DDdH7JKrnFPAu1CtkLl8Acqy6Q8+mbdA==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@eslint-react/eff@2.7.2': - resolution: {integrity: sha512-AzQGbidoI8g8izka/1H9xCKW56NR7xWGGPMccBCUZwbCoJZ4wyRKcE10E7ot7LwBv5kBoUQp3GJ9UXCcg/Er0w==} + '@eslint-react/eff@2.12.2': + resolution: {integrity: sha512-UWN/mtvu8gPVwZzg77h3zV0GEnKHjN/2yAI++UGGlVQ9x6en4/LFbn/9J2aM61lwyU4CvPUKpQ1KcYTTwJeJ0A==} engines: {node: '>=20.19.0'} - '@eslint-react/eslint-plugin@2.7.2': - resolution: {integrity: sha512-h9T5cc2TxsKMv/8iO63KKamXyJjHHAmeG2MJVjeIm4FaZdsX0/2Bx254B3Fa8IDqQi4X81AMyJ8ohtbxsn6pOw==} + '@eslint-react/eslint-plugin@2.12.2': + resolution: {integrity: sha512-7P2cGKwfTABeBnTac6PpLupE30+TmEbF3jTnGaziMwCzpPS1WAJtyvZw27RDSzb7pfx6GjTNBBHGg3dwfK+nhg==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@eslint-react/shared@2.7.2': - resolution: {integrity: sha512-U1H3dLaTj7kvEbyJyJEgn6xX3BmrCH1f9f+tg9gLWlN7askgWT5NF56wfX1l+jtwiEAZD/78W1TfICKkMnZDxQ==} + '@eslint-react/shared@2.12.2': + resolution: {integrity: sha512-/40s8neS142nMN9l7SDzwncqh/PNSzeYJ0Gc3h/eacQcUrjLx1NWWvPs1CNA3EbtqJRCvS2gflvzkzM2w6HURA==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@eslint-react/var@2.7.2': - resolution: {integrity: sha512-sPnXmikpzmAdIWh6lqqKm4Bu0ypKTCAQ7WxGuR5ejxtrA/HjQQuKMBIyPkBdjHWlF9ADdh9pKuo1j2RQwUWiqA==} + '@eslint-react/var@2.12.2': + resolution: {integrity: sha512-d+s6G1HAghVA25io3Vtj8237mQZUGozH+3UwEboNl+8XE3oTJMYv0T3X9U96GbxrV2S1BPFSYQEMwl6Z0RYgmA==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' '@eslint/config-array@0.21.1': @@ -721,12 +724,12 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@faker-js/faker@10.2.0': - resolution: {integrity: sha512-rTXwAsIxpCqzUnZvrxVh3L0QA0NzToqWBLAhV+zDV3MIIwiQhAZHMdPCIaj5n/yADu/tyk12wIPgL6YHGXJP+g==} + '@faker-js/faker@10.3.0': + resolution: {integrity: sha512-It0Sne6P3szg7JIi6CgKbvTZoMjxBZhcv91ZrqrNuaZQfB5WoqYYbzCUOq89YR+VY8juY9M1vDWmDDa2TzfXCw==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} - '@gerrit0/mini-shiki@3.21.0': - resolution: {integrity: sha512-9PrsT5DjZA+w3lur/aOIx3FlDeHdyCEFlv9U+fmsVyjPZh61G5SYURQ/1ebe2U63KbDmI2V8IhIUegWb8hjOyg==} + '@gerrit0/mini-shiki@3.22.0': + resolution: {integrity: sha512-jMpciqEVUBKE1QwU64S4saNMzpsSza6diNCk4MWAeCxO2+LFi2FIFmL2S0VDLzEJCxuvCbU783xi8Hp/gkM5CQ==} '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} @@ -757,8 +760,8 @@ packages: resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + '@isaacs/brace-expansion@5.0.1': + resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} engines: {node: 20 || >=22} '@jest/diff-sequences@30.0.1': @@ -820,164 +823,164 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@nx/nx-darwin-arm64@22.3.3': - resolution: {integrity: sha512-zBAGFGLal09CxhQkdMpOVwcwa9Y01aFm88jTTn35s/DdIWsfngmPzz0t4mG7u2D05q7TJfGQ31pIf5GkNUjo6g==} + '@nx/nx-darwin-arm64@22.4.5': + resolution: {integrity: sha512-zdRHZv1AMvzgp+5g2VZNXXuqk0/n1wOFksOeZ6BRyKg6hC2YkjGyn5xle/UK668MDAwe9KKm4jizvztK/LlPuA==} cpu: [arm64] os: [darwin] - '@nx/nx-darwin-x64@22.3.3': - resolution: {integrity: sha512-6ZQ6rMqH8NY4Jz+Gc89D5bIH2NxZb5S/vaA4yJ9RrqAfl4QWchNFD5na+aRivSd+UdsYLPKKl6qohet5SE6vOg==} + '@nx/nx-darwin-x64@22.4.5': + resolution: {integrity: sha512-1NVWaSgpa8yawi2UILX4NE9UcMuNzAAGh95JSV2yJovRfKxFQgQSB6hj0gpJu+TLLVCroTqy4woSQ2a0SPodeQ==} cpu: [x64] os: [darwin] - '@nx/nx-freebsd-x64@22.3.3': - resolution: {integrity: sha512-J/PP5pIOQtR7ZzrFwP6d6h0yfY7r9EravG2m940GsgzGbtZGYIDqnh5Wdt+4uBWPH8VpdNOwFqH0afELtJA3MA==} + '@nx/nx-freebsd-x64@22.4.5': + resolution: {integrity: sha512-baaLz53wr/HsVfSJ7ZgIFCPAb/OtP7yPPasb3eIu65oVhSswGfgvz9+YINhuInUgW7x7STmRnhGeR8pj6iqFqw==} cpu: [x64] os: [freebsd] - '@nx/nx-linux-arm-gnueabihf@22.3.3': - resolution: {integrity: sha512-/zn0altzM15S7qAgXMaB41vHkEn18HyTVUvRrjmmwaVqk9WfmDmqOQlGWoJ6XCbpvKQ8bh14RyhR9LGw1JJkNA==} + '@nx/nx-linux-arm-gnueabihf@22.4.5': + resolution: {integrity: sha512-wRBPv/l39tz+sQjZUH4hygCsd/DoUXUbDYkR6lnNXWHAVyPUh48/27JozM8hD3o/G3O2Vd8PFQasIXtvy2GS0Q==} cpu: [arm] os: [linux] - '@nx/nx-linux-arm64-gnu@22.3.3': - resolution: {integrity: sha512-NmPeCexWIZHW9RM3lDdFENN9C3WtlQ5L4RSNFESIjreS921rgePhulsszYdGnHdcnKPYlBBJnX/NxVsfioBbnQ==} + '@nx/nx-linux-arm64-gnu@22.4.5': + resolution: {integrity: sha512-6B/yCFiqjvV2Bkz6MKUtfFWjwtiF53DN07K1BFksMpQef+h2yE1IrGaG/OCl6VaVl4VRzQgLOluqP96M1yhDgg==} cpu: [arm64] os: [linux] - '@nx/nx-linux-arm64-musl@22.3.3': - resolution: {integrity: sha512-K02U88Q0dpvCfmSXXvY7KbYQSa1m+mkYeqDBRHp11yHk1GoIqaHp8oEWda7FV4gsriNExPSS5tX1/QGVoLZrCw==} + '@nx/nx-linux-arm64-musl@22.4.5': + resolution: {integrity: sha512-n0v60vRYn7BDHWB588snPZntLO2XC8/pvLd+QunneM2VGEPf51n5llX5U3AwTt/ybaZHWhbuHv0sJBIbT4I0GA==} cpu: [arm64] os: [linux] - '@nx/nx-linux-x64-gnu@22.3.3': - resolution: {integrity: sha512-04TEbvgwRaB9ifr39YwJmWh3RuXb4Ry4m84SOJyjNXAfPrepcWgfIQn1VL2ul1Ybq+P023dLO9ME8uqFh6j1YQ==} + '@nx/nx-linux-x64-gnu@22.4.5': + resolution: {integrity: sha512-zT7nb1PRE3NcW/HFnbgKJ9ZPtCOeVDpbJ5J4ZhHj36ZAUWZVXFEIPq9VTIZFy5+0pioLUIClQQY7OUfwnV/Zig==} cpu: [x64] os: [linux] - '@nx/nx-linux-x64-musl@22.3.3': - resolution: {integrity: sha512-uxBXx5q+S5OGatbYDxnamsKXRKlYn+Eq1nrCAHaf8rIfRoHlDiRV2PqtWuF+O2pxR5FWKpvr+/sZtt9rAf7KMw==} + '@nx/nx-linux-x64-musl@22.4.5': + resolution: {integrity: sha512-r8Rls5BS7lGQbUNX1Z1S370XrOacOU1bQ/dxY8i7qahFQKnMwpFo0W8odhgzjk+vrC/WLf9jOgz5/JPzehQBIw==} cpu: [x64] os: [linux] - '@nx/nx-win32-arm64-msvc@22.3.3': - resolution: {integrity: sha512-aOwlfD6ZA1K6hjZtbhBSp7s1yi3sHbMpLCa4stXzfhCCpKUv46HU/EdiWdE1N8AsyNFemPZFq81k1VTowcACdg==} + '@nx/nx-win32-arm64-msvc@22.4.5': + resolution: {integrity: sha512-Lv81LTnG6sSvBOq2vDSeyfzpF9X0cTGlJdzJOJzPZXCZGFhTV1ig9TdLiij/GM2JwV4Kvq5Co6YzA5dxtGUphQ==} cpu: [arm64] os: [win32] - '@nx/nx-win32-x64-msvc@22.3.3': - resolution: {integrity: sha512-EDR8BtqeDvVNQ+kPwnfeSfmerYetitU3tDkxOMIybjKJDh69U2JwTB8n9ARwNaZQbNk7sCGNRUSZFTbAAUKvuQ==} + '@nx/nx-win32-x64-msvc@22.4.5': + resolution: {integrity: sha512-52RfBcq9PXt76soCAZAJcNmCYrdsg6BvhBmjf0IFTMZ8IaeqZ9ktxAy1TZf/gCkOaM3ly4htbYMStiZ4MHX7Eg==} cpu: [x64] os: [win32] '@oxc-project/types@0.107.0': resolution: {integrity: sha512-QFDRbYfV2LVx8tyqtyiah3jQPUj1mK2+RYwxyFWyGoys6XJnwTdlzO6rdNNHOPorHAu5Uo34oWRKcvNpbJarmQ==} - '@oxc-project/types@0.108.0': - resolution: {integrity: sha512-7lf13b2IA/kZO6xgnIZA88sq3vwrxWk+2vxf6cc+omwYCRTiA5e63Beqf3fz/v8jEviChWWmFYBwzfSeyrsj7Q==} + '@oxc-project/types@0.112.0': + resolution: {integrity: sha512-m6RebKHIRsax2iCwVpYW2ErQwa4ywHJrE4sCK3/8JK8ZZAWOKXaRJFl/uP51gaVyyXlaS4+chU1nSCdzYf6QqQ==} - '@oxc-resolver/binding-android-arm-eabi@11.16.3': - resolution: {integrity: sha512-CVyWHu6ACDqDcJxR4nmGiG8vDF4TISJHqRNzac5z/gPQycs/QrP/1pDsJBy0MD7jSw8nVq2E5WqeHQKabBG/Jg==} + '@oxc-resolver/binding-android-arm-eabi@11.17.1': + resolution: {integrity: sha512-+VuZyMYYaap5uDAU1xDU3Kul0FekLqpBS8kI5JozlWfYQKnc/HsZg2gHPkQrj0SC9lt74WMNCfOzZZJlYXSdEQ==} cpu: [arm] os: [android] - '@oxc-resolver/binding-android-arm64@11.16.3': - resolution: {integrity: sha512-tTIoB7plLeh2o6Ay7NnV5CJb6QUXdxI7Shnsp2ECrLSV81k+oVE3WXYrQSh4ltWL75i0OgU5Bj3bsuyg5SMepw==} + '@oxc-resolver/binding-android-arm64@11.17.1': + resolution: {integrity: sha512-YlDDTjvOEKhom/cRSVsXsMVeXVIAM9PJ/x2mfe08rfuS0iIEfJd8PngKbEIhG72WPxleUa+vkEZj9ncmC14z3Q==} cpu: [arm64] os: [android] - '@oxc-resolver/binding-darwin-arm64@11.16.3': - resolution: {integrity: sha512-OXKVH7uwYd3Rbw1s2yJZd6/w+6b01iaokZubYhDAq4tOYArr+YCS+lr81q1hsTPPRZeIsWE+rJLulmf1qHdYZA==} + '@oxc-resolver/binding-darwin-arm64@11.17.1': + resolution: {integrity: sha512-HOYYLSY4JDk14YkXaz/ApgJYhgDP4KsG8EZpgpOxdszGW9HmIMMY/vXqVKYW74dSH+GQkIXYxBrEh3nv+XODVg==} cpu: [arm64] os: [darwin] - '@oxc-resolver/binding-darwin-x64@11.16.3': - resolution: {integrity: sha512-WwjQ4WdnCxVYZYd3e3oY5XbV3JeLy9pPMK+eQQ2m8DtqUtbxnvPpAYC2Knv/2bS6q5JiktqOVJ2Hfia3OSo0/A==} + '@oxc-resolver/binding-darwin-x64@11.17.1': + resolution: {integrity: sha512-JHPJbsa5HvPq2/RIdtGlqfaG9zV2WmgvHrKTYmlW0L5esqtKCBuetFudXTBzkNcyD69kSZLzH92AzTr6vFHMFg==} cpu: [x64] os: [darwin] - '@oxc-resolver/binding-freebsd-x64@11.16.3': - resolution: {integrity: sha512-4OHKFGJBBfOnuJnelbCS4eBorI6cj54FUxcZJwEXPeoLc8yzORBoJ2w+fQbwjlQcUUZLEg92uGhKCRiUoqznjg==} + '@oxc-resolver/binding-freebsd-x64@11.17.1': + resolution: {integrity: sha512-UD1FRC8j8xZstFXYsXwQkNmmg7vUbee006IqxokwDUUA+xEgKZDpLhBEiVKM08Urb+bn7Q0gn6M1pyNR0ng5mg==} cpu: [x64] os: [freebsd] - '@oxc-resolver/binding-linux-arm-gnueabihf@11.16.3': - resolution: {integrity: sha512-OM3W0NLt9u7uKwG/yZbeXABansZC0oZeDF1nKgvcZoRw4/Yak6/l4S0onBfDFeYMY94eYeAt2bl60e30lgsb5A==} + '@oxc-resolver/binding-linux-arm-gnueabihf@11.17.1': + resolution: {integrity: sha512-wFWC1wyf2ROFWTxK5x0Enm++DSof3EBQ/ypyAesMDLiYxOOASDoMOZG1ylWUnlKaCt5W7eNOWOzABpdfFf/ssA==} cpu: [arm] os: [linux] - '@oxc-resolver/binding-linux-arm-musleabihf@11.16.3': - resolution: {integrity: sha512-MRs7D7i1t7ACsAdTuP81gLZES918EpBmiUyEl8fu302yQB+4L7L7z0Ui8BWnthUTQd3nAU9dXvENLK/SqRVH8A==} + '@oxc-resolver/binding-linux-arm-musleabihf@11.17.1': + resolution: {integrity: sha512-k/hUif0GEBk/csSqCfTPXb8AAVs1NNWCa/skBghvNbTtORcWfOVqJ3mM+2pE189+enRm4UnryLREu5ysI0kXEQ==} cpu: [arm] os: [linux] - '@oxc-resolver/binding-linux-arm64-gnu@11.16.3': - resolution: {integrity: sha512-0eVYZxSceNqGADzhlV4ZRqkHF0fjWxRXQOB7Qwl5y1gN/XYUDvMfip+ngtzj4dM7zQT4U97hUhJ7PUKSy/JIGQ==} + '@oxc-resolver/binding-linux-arm64-gnu@11.17.1': + resolution: {integrity: sha512-Cwm6A071ww60QouJ9LoHAwBgEoZzHQ0Qaqk2E7WLfBdiQN9mLXIDhnrpn04hlRElRPhLiu/dtg+o5PPLvaINXQ==} cpu: [arm64] os: [linux] - '@oxc-resolver/binding-linux-arm64-musl@11.16.3': - resolution: {integrity: sha512-B1BvLeZbgDdVN0FvU40l5Q7lej8310WlabCBaouk8jY7H7xbI8phtomTtk3Efmevgfy5hImaQJu6++OmcFb2NQ==} + '@oxc-resolver/binding-linux-arm64-musl@11.17.1': + resolution: {integrity: sha512-+hwlE2v3m0r3sk93SchJL1uyaKcPjf+NGO/TD2DZUDo+chXx7FfaEj0nUMewigSt7oZ2sQN9Z4NJOtUa75HE5Q==} cpu: [arm64] os: [linux] - '@oxc-resolver/binding-linux-ppc64-gnu@11.16.3': - resolution: {integrity: sha512-q7khglic3Jqak7uDgA3MFnjDeI7krQT595GDZpvFq785fmFYSx8rlTkoHzmhQtUisYtl4XG7WUscwsoidFUI4w==} + '@oxc-resolver/binding-linux-ppc64-gnu@11.17.1': + resolution: {integrity: sha512-bO+rsaE5Ox8cFyeL5Ct5tzot1TnQpFa/Wmu5k+hqBYSH2dNVDGoi0NizBN5QV8kOIC6O5MZr81UG4yW/2FyDTA==} cpu: [ppc64] os: [linux] - '@oxc-resolver/binding-linux-riscv64-gnu@11.16.3': - resolution: {integrity: sha512-aFRNmQNPzDgQEbw2s3c8yJYRimacSDI+u9df8rn5nSKzTVitHmbEpZqfxpwNLCKIuLSNmozHR1z1OT+oZVeYqg==} + '@oxc-resolver/binding-linux-riscv64-gnu@11.17.1': + resolution: {integrity: sha512-B/P+hxKQ1oX4YstI9Lyh4PGzqB87Ddqj/A4iyRBbPdXTcxa+WW3oRLx1CsJKLmHPdDk461Hmbghq1Bm3pl+8Aw==} cpu: [riscv64] os: [linux] - '@oxc-resolver/binding-linux-riscv64-musl@11.16.3': - resolution: {integrity: sha512-vZI85SvSMADcEL9G1TIrV0Rlkc1fY5Mup0DdlVC5EHPysZB4hXXHpr+h09pjlK5y+5om5foIzDRxE1baUCaWOA==} + '@oxc-resolver/binding-linux-riscv64-musl@11.17.1': + resolution: {integrity: sha512-ulp2H3bFXzd/th2maH+QNKj5qgOhJ3v9Yspdf1svTw3CDOuuTl6sRKsWQ7MUw0vnkSNvQndtflBwVXgzZvURsQ==} cpu: [riscv64] os: [linux] - '@oxc-resolver/binding-linux-s390x-gnu@11.16.3': - resolution: {integrity: sha512-xiLBnaUlddFEzRHiHiSGEMbkg8EwZY6VD8F+3GfnFsiK3xg/4boaUV2bwXd+nUzl3UDQOMW1QcZJ4jJSb0qiJA==} + '@oxc-resolver/binding-linux-s390x-gnu@11.17.1': + resolution: {integrity: sha512-LAXYVe3rKk09Zo9YKF2ZLBcH8sz8Oj+JIyiUxiHtq0hiYLMsN6dOpCf2hzQEjPAmsSEA/hdC1PVKeXo+oma8mQ==} cpu: [s390x] os: [linux] - '@oxc-resolver/binding-linux-x64-gnu@11.16.3': - resolution: {integrity: sha512-6y0b05wIazJJgwu7yU/AYGFswzQQudYJBOb/otDhiDacp1+6ye8egoxx63iVo9lSpDbipL++54AJQFlcOHCB+g==} + '@oxc-resolver/binding-linux-x64-gnu@11.17.1': + resolution: {integrity: sha512-3RAhxipMKE8RCSPn7O//sj440i+cYTgYbapLeOoDvQEt6R1QcJjTsFgI4iz99FhVj3YbPxlZmcLB5VW+ipyRTA==} cpu: [x64] os: [linux] - '@oxc-resolver/binding-linux-x64-musl@11.16.3': - resolution: {integrity: sha512-RmMgwuMa42c9logS7Pjprf5KCp8J1a1bFiuBFtG9/+yMu0BhY2t+0VR/um7pwtkNFvIQqAVh6gDOg/PnoKRcdQ==} + '@oxc-resolver/binding-linux-x64-musl@11.17.1': + resolution: {integrity: sha512-wpjMEubGU8r9VjZTLdZR3aPHaBqTl8Jl8F4DBbgNoZ+yhkhQD1/MGvY70v2TLnAI6kAHSvcqgfvaqKDa2iWsPQ==} cpu: [x64] os: [linux] - '@oxc-resolver/binding-openharmony-arm64@11.16.3': - resolution: {integrity: sha512-/7AYRkjjW7xu1nrHgWUFy99Duj4/ydOBVaHtODie9/M6fFngo+8uQDFFnzmr4q//sd/cchIerISp/8CQ5TsqIA==} + '@oxc-resolver/binding-openharmony-arm64@11.17.1': + resolution: {integrity: sha512-XIE4w17RYAVIgx+9Gs3deTREq5tsmalbatYOOBGNdH7n0DfTE600c7wYXsp7ANc3BPDXsInnOzXDEPCvO1F6cg==} cpu: [arm64] os: [openharmony] - '@oxc-resolver/binding-wasm32-wasi@11.16.3': - resolution: {integrity: sha512-urM6aIPbi5di4BSlnpd/TWtDJgG6RD06HvLBuNM+qOYuFtY1/xPbzQ2LanBI2ycpqIoIZwsChyplALwAMdyfCQ==} + '@oxc-resolver/binding-wasm32-wasi@11.17.1': + resolution: {integrity: sha512-Lqi5BlHX3zS4bpSOkIbOKVf7DIk6Gvmdifr2OuOI58eUUyP944M8/OyaB09cNpPy9Vukj7nmmhOzj8pwLgAkIg==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@oxc-resolver/binding-win32-arm64-msvc@11.16.3': - resolution: {integrity: sha512-QuvLqGKf7frxWHQ5TnrcY0C/hJpANsaez99Q4dAk1hen7lDTD4FBPtBzPnntLFXeaVG3PnSmnVjlv0vMILwU7Q==} + '@oxc-resolver/binding-win32-arm64-msvc@11.17.1': + resolution: {integrity: sha512-l6lTcLBQVj1HNquFpXSsrkCIM8X5Hlng5YNQJrg00z/KyovvDV5l3OFhoRyZ+aLBQ74zUnMRaJZC7xcBnHyeNg==} cpu: [arm64] os: [win32] - '@oxc-resolver/binding-win32-ia32-msvc@11.16.3': - resolution: {integrity: sha512-QR/witXK6BmYTlEP8CCjC5fxeG5U9A6a50pNpC1nLnhAcJjtzFG8KcQ5etVy/XvCLiDc7fReaAWRNWtCaIhM8Q==} + '@oxc-resolver/binding-win32-ia32-msvc@11.17.1': + resolution: {integrity: sha512-VTzVtfnCCsU/6GgvursWoyZrhe3Gj/RyXzDWmh4/U1Y3IW0u1FZbp+hCIlBL16pRPbDc5YvXVtCOnA41QOrOoQ==} cpu: [ia32] os: [win32] - '@oxc-resolver/binding-win32-x64-msvc@11.16.3': - resolution: {integrity: sha512-bFuJRKOscsDAEZ/a8BezcTMAe2BQ/OBRfuMLFUuINfTR5qGVcm4a3xBIrQVepBaPxFj16SJdRjGe05vDiwZmFw==} + '@oxc-resolver/binding-win32-x64-msvc@11.17.1': + resolution: {integrity: sha512-jRPVU+6/12baj87q2+UGRh30FBVBzqKdJ7rP/mSqiL1kpNQB9yZ1j0+m3sru1m+C8hiFK7lBFwjUtYUBI7+UpQ==} cpu: [x64] os: [win32] - '@publint/pack@0.1.2': - resolution: {integrity: sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==} + '@publint/pack@0.1.4': + resolution: {integrity: sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ==} engines: {node: '>=18'} '@quansync/fs@1.0.0': @@ -989,8 +992,8 @@ packages: cpu: [arm64] os: [android] - '@rolldown/binding-android-arm64@1.0.0-beta.60': - resolution: {integrity: sha512-hOW6iQXtpG4uCW1zGK56+KhEXGttSkTp2ykncW/nkOIF/jOKTqbM944Q73HVeMXP1mPRvE2cZwNp3xeLIeyIGQ==} + '@rolldown/binding-android-arm64@1.0.0-rc.3': + resolution: {integrity: sha512-0T1k9FinuBZ/t7rZ8jN6OpUKPnUjNdYHoj/cESWrQ3ZraAJ4OMm6z7QjSfCxqj8mOp9kTKc1zHK3kGz5vMu+nQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] @@ -1001,8 +1004,8 @@ packages: cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-arm64@1.0.0-beta.60': - resolution: {integrity: sha512-vyDA4HXY2mP8PPtl5UE17uGPxUNG4m1wkfa3kAkR8JWrFbarV97UmLq22IWrNhtBPa89xqerzLK8KoVmz5JqCQ==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.3': + resolution: {integrity: sha512-JWWLzvcmc/3pe7qdJqPpuPk91SoE/N+f3PcWx/6ZwuyDVyungAEJPvKm/eEldiDdwTmaEzWfIR+HORxYWrCi1A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] @@ -1013,8 +1016,8 @@ packages: cpu: [x64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.60': - resolution: {integrity: sha512-WnxyqxAKP2BsxouwGY/RCF5UFw/LA4QOHhJ7VEl+UCelHokiwqNHRbryLAyRy3TE1FZ5eae+vAFcaetAu/kWLw==} + '@rolldown/binding-darwin-x64@1.0.0-rc.3': + resolution: {integrity: sha512-MTakBxfx3tde5WSmbHxuqlDsIW0EzQym+PJYGF4P6lG2NmKzi128OGynoFUqoD5ryCySEY85dug4v+LWGBElIw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] @@ -1025,8 +1028,8 @@ packages: cpu: [x64] os: [freebsd] - '@rolldown/binding-freebsd-x64@1.0.0-beta.60': - resolution: {integrity: sha512-JtyWJ+zXOHof5gOUYwdTWI2kL6b8q9eNwqB/oD4mfUFaC/COEB2+47JMhcq78dey9Ahmec3DZKRDZPRh9hNAMQ==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.3': + resolution: {integrity: sha512-jje3oopyOLs7IwfvXoS6Lxnmie5JJO7vW29fdGFu5YGY1EDbVDhD+P9vDihqS5X6fFiqL3ZQZCMBg6jyHkSVww==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] @@ -1037,8 +1040,8 @@ packages: cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.60': - resolution: {integrity: sha512-LrMoKqpHx+kCaNSk84iSBd4yVOymLIbxJQtvFjDN2CjQraownR+IXcwYDblFcj9ivmS54T3vCboXBbm3s1zbPQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3': + resolution: {integrity: sha512-A0n8P3hdLAaqzSFrQoA42p23ZKBYQOw+8EH5r15Sa9X1kD9/JXe0YT2gph2QTWvdr0CVK2BOXiK6ENfy6DXOag==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] @@ -1049,8 +1052,8 @@ packages: cpu: [arm64] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.60': - resolution: {integrity: sha512-sqI+Vdx1gmXJMsXN3Fsewm3wlt7RHvRs1uysSp//NLsCoh9ZFEUr4ZzGhWKOg6Rvf+njNu/vCsz96x7wssLejQ==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3': + resolution: {integrity: sha512-kWXkoxxarYISBJ4bLNf5vFkEbb4JvccOwxWDxuK9yee8lg5XA7OpvlTptfRuwEvYcOZf+7VS69Uenpmpyo5Bjw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -1061,8 +1064,8 @@ packages: cpu: [arm64] os: [linux] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.60': - resolution: {integrity: sha512-8xlqGLDtTP8sBfYwneTDu8+PRm5reNEHAuI/+6WPy9y350ls0KTFd3EJCOWEXWGW0F35ko9Fn9azmurBTjqOrQ==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.3': + resolution: {integrity: sha512-Z03/wrqau9Bicfgb3Dbs6SYTHliELk2PM2LpG2nFd+cGupTMF5kanLEcj2vuuJLLhptNyS61rtk7SOZ+lPsTUA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -1073,8 +1076,8 @@ packages: cpu: [x64] os: [linux] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.60': - resolution: {integrity: sha512-iR4nhVouVZK1CiGGGyz+prF5Lw9Lmz30Rl36Hajex+dFVFiegka604zBwzTp5Tl0BZnr50ztnVJ30tGrBhDr8Q==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.3': + resolution: {integrity: sha512-iSXXZsQp08CSilff/DCTFZHSVEpEwdicV3W8idHyrByrcsRDVh9sGC3sev6d8BygSGj3vt8GvUKBPCoyMA4tgQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -1085,8 +1088,8 @@ packages: cpu: [x64] os: [linux] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.60': - resolution: {integrity: sha512-HbfNcqNeqxFjSMf1Kpe8itr2e2lr0Bm6HltD2qXtfU91bSSikVs9EWsa1ThshQ1v2ZvxXckGjlVLtah6IoslPg==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.3': + resolution: {integrity: sha512-qaj+MFudtdCv9xZo9znFvkgoajLdc+vwf0Kz5N44g+LU5XMe+IsACgn3UG7uTRlCCvhMAGXm1XlpEA5bZBrOcw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -1097,8 +1100,8 @@ packages: cpu: [arm64] os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.60': - resolution: {integrity: sha512-BiiamFcgTJ+ZFOUIMO9AHXUo9WXvHVwGfSrJ+Sv0AsTd2w3VN7dJGiH3WRcxKFetljJHWvGbM4fdpY5lf6RIvw==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.3': + resolution: {integrity: sha512-U662UnMETyjT65gFmG9ma+XziENrs7BBnENi/27swZPYagubfHRirXHG2oMl+pEax2WvO7Kb9gHZmMakpYqBHQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] @@ -1108,8 +1111,8 @@ packages: engines: {node: '>=14.0.0'} cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.0.0-beta.60': - resolution: {integrity: sha512-6roXGbHMdR2ucnxXuwbmQvk8tuYl3VGu0yv13KxspyKBxxBd4RS6iykzLD6mX2gMUHhfX8SVWz7n/62gfyKHow==} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.3': + resolution: {integrity: sha512-gekrQ3Q2HiC1T5njGyuUJoGpK/l6B/TNXKed3fZXNf9YRTJn3L5MOZsFBn4bN2+UX+8+7hgdlTcEsexX988G4g==} engines: {node: '>=14.0.0'} cpu: [wasm32] @@ -1119,8 +1122,8 @@ packages: cpu: [arm64] os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.60': - resolution: {integrity: sha512-JBOm8/DC/CKnHyMHoJFdvzVHxUixid4dGkiTqGflxOxO43uSJMpl77pSPXvzwZ/VXwqblU2V0/PanyCBcRLowQ==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3': + resolution: {integrity: sha512-85y5JifyMgs8m5K2XzR/VDsapKbiFiohl7s5lEj7nmNGO0pkTXE7q6TQScei96BNAsoK7JC3pA7ukA8WRHVJpg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] @@ -1131,163 +1134,163 @@ packages: cpu: [x64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.60': - resolution: {integrity: sha512-MKF0B823Efp+Ot8KsbwIuGhKH58pf+2rSM6VcqyNMlNBHheOM0Gf7JmEu+toc1jgN6fqjH7Et+8hAzsLVkIGfA==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.3': + resolution: {integrity: sha512-a4VUQZH7LxGbUJ3qJ/TzQG8HxdHvf+jOnqf7B7oFx1TEBm+j2KNL2zr5SQ7wHkNAcaPevF6gf9tQnVBnC4mD+A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-beta.53': - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} - '@rolldown/pluginutils@1.0.0-beta.59': resolution: {integrity: sha512-aoh6LAJRyhtazs98ydgpNOYstxUlsOV1KJXcpf/0c0vFcUA8uyd/hwKRhqE/AAPNqAho9RliGsvitCoOzREoVA==} - '@rolldown/pluginutils@1.0.0-beta.60': - resolution: {integrity: sha512-Jz4aqXRPVtqkH1E3jRDzLO5cgN5JwW+WG0wXGE4NiJd25nougv/AHzxmKCzmVQUYnxLmTM0M4wrZp+LlC2FKLg==} + '@rolldown/pluginutils@1.0.0-rc.2': + resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} - '@rollup/rollup-android-arm-eabi@4.55.1': - resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==} + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + + '@rollup/rollup-android-arm-eabi@4.57.1': + resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.55.1': - resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==} + '@rollup/rollup-android-arm64@4.57.1': + resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.55.1': - resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==} + '@rollup/rollup-darwin-arm64@4.57.1': + resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.55.1': - resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==} + '@rollup/rollup-darwin-x64@4.57.1': + resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.55.1': - resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==} + '@rollup/rollup-freebsd-arm64@4.57.1': + resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.55.1': - resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==} + '@rollup/rollup-freebsd-x64@4.57.1': + resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.55.1': - resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': + resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.55.1': - resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} + '@rollup/rollup-linux-arm-musleabihf@4.57.1': + resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.55.1': - resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} + '@rollup/rollup-linux-arm64-gnu@4.57.1': + resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.55.1': - resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} + '@rollup/rollup-linux-arm64-musl@4.57.1': + resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.55.1': - resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} + '@rollup/rollup-linux-loong64-gnu@4.57.1': + resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-loong64-musl@4.55.1': - resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} + '@rollup/rollup-linux-loong64-musl@4.57.1': + resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.55.1': - resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} + '@rollup/rollup-linux-ppc64-gnu@4.57.1': + resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-ppc64-musl@4.55.1': - resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} + '@rollup/rollup-linux-ppc64-musl@4.57.1': + resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.55.1': - resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} + '@rollup/rollup-linux-riscv64-gnu@4.57.1': + resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.55.1': - resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} + '@rollup/rollup-linux-riscv64-musl@4.57.1': + resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.55.1': - resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} + '@rollup/rollup-linux-s390x-gnu@4.57.1': + resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.55.1': - resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} + '@rollup/rollup-linux-x64-gnu@4.57.1': + resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.55.1': - resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} + '@rollup/rollup-linux-x64-musl@4.57.1': + resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] - '@rollup/rollup-openbsd-x64@4.55.1': - resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} + '@rollup/rollup-openbsd-x64@4.57.1': + resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.55.1': - resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==} + '@rollup/rollup-openharmony-arm64@4.57.1': + resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.55.1': - resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==} + '@rollup/rollup-win32-arm64-msvc@4.57.1': + resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.55.1': - resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==} + '@rollup/rollup-win32-ia32-msvc@4.57.1': + resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.55.1': - resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==} + '@rollup/rollup-win32-x64-gnu@4.57.1': + resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.55.1': - resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==} + '@rollup/rollup-win32-x64-msvc@4.57.1': + resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} cpu: [x64] os: [win32] - '@shikijs/engine-oniguruma@3.21.0': - resolution: {integrity: sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==} + '@shikijs/engine-oniguruma@3.22.0': + resolution: {integrity: sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==} - '@shikijs/langs@3.21.0': - resolution: {integrity: sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==} + '@shikijs/langs@3.22.0': + resolution: {integrity: sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==} - '@shikijs/themes@3.21.0': - resolution: {integrity: sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==} + '@shikijs/themes@3.22.0': + resolution: {integrity: sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==} - '@shikijs/types@3.21.0': - resolution: {integrity: sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==} + '@shikijs/types@3.22.0': + resolution: {integrity: sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - '@sinclair/typebox@0.34.47': - resolution: {integrity: sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==} + '@sinclair/typebox@0.34.48': + resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} '@solid-primitives/event-listener@2.4.3': resolution: {integrity: sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg==} @@ -1322,8 +1325,8 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@stylistic/eslint-plugin@5.7.0': - resolution: {integrity: sha512-PsSugIf9ip1H/mWKj4bi/BlEoerxXAda9ByRFsYuwsmr6af9NxJL0AaiNXs8Le7R21QR5KMiD/KdxZZ71LjAxQ==} + '@stylistic/eslint-plugin@5.8.0': + resolution: {integrity: sha512-WNPVF/FfBAjyi3OA7gok8swRiImNLKI4dmV3iK/GC/0xSJR7eCzBFsw9hLZVgb1+MYNLy7aDsjohxN1hA/FIfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: '>=9.0.0' @@ -1423,8 +1426,8 @@ packages: resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - '@testing-library/react@16.3.1': - resolution: {integrity: sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw==} + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} engines: {node: '>=18'} peerDependencies: '@testing-library/dom': ^10.0.0 @@ -1477,19 +1480,16 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@20.19.30': - resolution: {integrity: sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==} - - '@types/node@25.0.9': - resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==} + '@types/node@25.2.2': + resolution: {integrity: sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ==} '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.8': - resolution: {integrity: sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==} + '@types/react@19.2.13': + resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -1500,63 +1500,63 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/eslint-plugin@8.53.0': - resolution: {integrity: sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==} + '@typescript-eslint/eslint-plugin@8.55.0': + resolution: {integrity: sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.53.0 + '@typescript-eslint/parser': ^8.55.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.53.0': - resolution: {integrity: sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==} + '@typescript-eslint/parser@8.55.0': + resolution: {integrity: sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.53.0': - resolution: {integrity: sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg==} + '@typescript-eslint/project-service@8.55.0': + resolution: {integrity: sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.53.0': - resolution: {integrity: sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g==} + '@typescript-eslint/scope-manager@8.55.0': + resolution: {integrity: sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.53.0': - resolution: {integrity: sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA==} + '@typescript-eslint/tsconfig-utils@8.55.0': + resolution: {integrity: sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.53.0': - resolution: {integrity: sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw==} + '@typescript-eslint/type-utils@8.55.0': + resolution: {integrity: sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.53.0': - resolution: {integrity: sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ==} + '@typescript-eslint/types@8.55.0': + resolution: {integrity: sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.53.0': - resolution: {integrity: sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw==} + '@typescript-eslint/typescript-estree@8.55.0': + resolution: {integrity: sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.53.0': - resolution: {integrity: sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA==} + '@typescript-eslint/utils@8.55.0': + resolution: {integrity: sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.53.0': - resolution: {integrity: sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw==} + '@typescript-eslint/visitor-keys@8.55.0': + resolution: {integrity: sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -1654,17 +1654,17 @@ packages: cpu: [x64] os: [win32] - '@vitejs/plugin-react@5.1.2': - resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} + '@vitejs/plugin-react@5.1.3': + resolution: {integrity: sha512-NVUnA6gQCl8jfoYqKqQU5Clv0aPw14KkZYCsX6T9Lfu9slI0LOU10OTwFHS/WmptsMMpshNd/1tuWsHQ2Uk+cg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - '@vitest/expect@4.0.17': - resolution: {integrity: sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==} + '@vitest/expect@4.0.18': + resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - '@vitest/mocker@4.0.17': - resolution: {integrity: sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==} + '@vitest/mocker@4.0.18': + resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0-0 @@ -1674,20 +1674,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.17': - resolution: {integrity: sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==} + '@vitest/pretty-format@4.0.18': + resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} - '@vitest/runner@4.0.17': - resolution: {integrity: sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==} + '@vitest/runner@4.0.18': + resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} - '@vitest/snapshot@4.0.17': - resolution: {integrity: sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==} + '@vitest/snapshot@4.0.18': + resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} - '@vitest/spy@4.0.17': - resolution: {integrity: sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==} + '@vitest/spy@4.0.18': + resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} - '@vitest/utils@4.0.17': - resolution: {integrity: sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==} + '@vitest/utils@4.0.18': + resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} @@ -1771,15 +1771,15 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - autoprefixer@10.4.23: - resolution: {integrity: sha512-YYTXSFulfwytnjAPlw8QHncHJmlvFKtczb8InXaAx9Q0LbfDnfEYDE55omerIJKihhmU61Ft+cAOSzQVaBUmeA==} + autoprefixer@10.4.24: + resolution: {integrity: sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: postcss: ^8.1.0 - axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + axios@1.13.5: + resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} @@ -1805,8 +1805,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.9.15: - resolution: {integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==} + baseline-browser-mapping@2.9.19: + resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} hasBin: true better-path-resolve@1.0.0: @@ -1863,8 +1863,8 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - caniuse-lite@1.0.30001764: - resolution: {integrity: sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==} + caniuse-lite@1.0.30001769: + resolution: {integrity: sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==} chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} @@ -1880,8 +1880,8 @@ packages: cheerio-select@2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} - cheerio@1.1.2: - resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} + cheerio@1.2.0: + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} engines: {node: '>=20.18.1'} chokidar@3.6.0: @@ -1927,8 +1927,8 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - comment-parser@1.4.4: - resolution: {integrity: sha512-0D6qSQ5IkeRrGJFHRClzaMOenMeT0gErz3zIw3AprKMqhRN6LNU2jQOdkPG/FZ+8bCgXE1VidrgSzlBBDZRr8A==} + comment-parser@1.4.5: + resolution: {integrity: sha512-aRDkn3uyIlCFfk5NUA+VdwMmMsh8JGhc4hapfV4yxymHGQ3BVskMQfoXGpCo5IoBuQ9tS5iiVKhCpTcB4pW4qw==} engines: {node: '>= 12.0.0'} compare-versions@6.1.1: @@ -2056,8 +2056,8 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.267: - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + electron-to-chromium@1.5.286: + resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2072,8 +2072,8 @@ packages: end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - enhanced-resolve@5.18.4: - resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + enhanced-resolve@5.19.0: + resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} engines: {node: '>=10.13.0'} enquirer@2.3.6: @@ -2092,6 +2092,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -2111,8 +2115,8 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - esbuild@0.27.2: - resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} hasBin: true @@ -2174,18 +2178,18 @@ packages: peerDependencies: eslint: '>=7' - eslint-plugin-react-dom@2.7.2: - resolution: {integrity: sha512-Qzd4HAFwsxvOJoAycLIRxziOTJwEZ6EGAA6jEFFBSD1BbFVnDlozMvOLp9/+GrZW3cE0FGmAS6QXnjuMf0QYLQ==} + eslint-plugin-react-dom@2.12.2: + resolution: {integrity: sha512-Tvz+YETB0MQiPHR3KYhkwCioGfXQ6aUXpNOFpgZ70wx5/QuU1lemTWdmXuxgAPifsl150OOZmM2MJ0ElkwBUOw==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - eslint-plugin-react-hooks-extra@2.7.2: - resolution: {integrity: sha512-wcjQeBO1naCFPV47osw7nnK2p81eudCE2PhasKLtBV+GcAEi34jbt9QGULzQYueP+zd1aW53SmnVrTinY4DC6w==} + eslint-plugin-react-hooks-extra@2.12.2: + resolution: {integrity: sha512-I3L/iVgyMRbbmMxRZNIxlxMrXUnV74ZHOsmSfzB/ue9hivdd5yN8JhMe+I5PNOw9L0gJHUCo2mgkKV6lMEE5DA==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' eslint-plugin-react-hooks@7.0.1: @@ -2194,32 +2198,39 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react-naming-convention@2.7.2: - resolution: {integrity: sha512-T+/RQFEda3AgCzBHguE3isLQetn8KUOZ14SnDBQSOZSWS/GjgQn+gmqHi3EVHX/sDdL+LsIUKRsRR6KmmYWMiw==} + eslint-plugin-react-naming-convention@2.12.2: + resolution: {integrity: sha512-IsPmSs+AZo11uR47UoSRv9tVntUDL9Ah5F8Zj4HVC4HTxJlFZHC0gbm43q36Xw6c65J0LqA75oDA2h6jvhqSQQ==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - eslint-plugin-react-web-api@2.7.2: - resolution: {integrity: sha512-iA3D8jbwasMeeUfK8XucGkgrjQvZowCTi1+TzA43U7IFsWzyQWQpbN/I9B0BY/g6/JU9falC5b7qv6HB7P5JhA==} + eslint-plugin-react-rsc@2.12.2: + resolution: {integrity: sha512-37Z4u6bBddO2wz8wrelYapOoDHhdEyF2pt8pbzFs0nW2USOxoA34/Gv73Dos0Kb6Ul4fFuwEHH2Tu8hZoki5jQ==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - eslint-plugin-react-x@2.7.2: - resolution: {integrity: sha512-0NbYqJhc3tZQVluaFMVCOg6HEFarlNNXe+DHa/JrLAR0PVb9AtJGk8FBEDdxaUZO8ph0sAekUNLB7gymftj4Dw==} + eslint-plugin-react-web-api@2.12.2: + resolution: {integrity: sha512-bnpobQ6pjGdo4sJpd/PDlVM/wTqHt29fsW3uExuB+9ta6LSJjJo0/nXhV/o7q/MU/04QZB8WOw+k9ws8HU1sPQ==} engines: {node: '>=20.19.0'} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - eslint-plugin-unused-imports@4.3.0: - resolution: {integrity: sha512-ZFBmXMGBYfHttdRtOG9nFFpmUvMtbHSjsKrS20vdWdbfiVYsO3yA2SGYy9i9XmZJDfMGBflZGBCm70SEnFQtOA==} + eslint-plugin-react-x@2.12.2: + resolution: {integrity: sha512-0zA48OyHKHePa3mhV/tRxT26LvEhRC7ROQ02sdwoyv/JOYgLX+5Z9o85sneFB7SmkZul4TubxUf+EvHTXdUmVg==} + engines: {node: '>=20.19.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + eslint-plugin-unused-imports@4.4.1: + resolution: {integrity: sha512-oZGYUz1X3sRMGUB+0cZyK2VcvRX5lm/vB56PgNNcU+7ficUCKm66oZWKUubXWnOuPjQ8PvmXtCViXBMONPe7tQ==} peerDependencies: '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 - eslint: ^9.0.0 || ^8.0.0 + eslint: ^10.0.0 || ^9.0.0 || ^8.0.0 peerDependenciesMeta: '@typescript-eslint/eslint-plugin': optional: true @@ -2236,10 +2247,6 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint-visitor-keys@5.0.0: - resolution: {integrity: sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@9.39.2: resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2257,10 +2264,6 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - espree@11.0.0: - resolution: {integrity: sha512-+gMeWRrIh/NsG+3NaLeWHuyeyk70p2tbvZIWBYcqQ4/7Xvars6GYTZNhF1sIeLcc6Wb11He5ffz3hsHyXFrw5A==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -2270,8 +2273,8 @@ packages: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} - esrap@2.2.1: - resolution: {integrity: sha512-GiYWG34AN/4CUyaWAgunGt0Rxvr1PTMlGC0vvEov/uOQYWne2bpN03Um+k8jT+q3op33mKouP2zeJ6OlM+qeUg==} + esrap@2.2.3: + resolution: {integrity: sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==} esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} @@ -2413,8 +2416,8 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.13.6: + resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -2455,8 +2458,8 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - happy-dom@20.3.1: - resolution: {integrity: sha512-tLvsizNno05Hij0PoB0QN/S8xf0YU2AGvO11/JlJDw5McA/gzyn0Ni1RwbTI1/zteUbOekJH0t6q8HFvjbxsGg==} + happy-dom@20.5.3: + resolution: {integrity: sha512-xqAxGnkRU0KNhheHpxb3uScqg/aehqUiVto/a9ApWMyNvnH9CAqHYq9dEPAovM6bOGbLstmTfGIln5ZIezEU0g==} engines: {node: '>=20.0.0'} has-flag@4.0.0: @@ -2490,8 +2493,8 @@ packages: html-link-extractor@1.0.5: resolution: {integrity: sha512-ADd49pudM157uWHwHQPUSX4ssMsvR/yHIswOR5CUfBdK9g9ZYGMhVSE6KZVHJ6kCkR0gH4htsfzU6zECDNVwyw==} - htmlparser2@10.0.0: - resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} human-id@4.1.3: resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} @@ -2654,8 +2657,8 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - knip@5.81.0: - resolution: {integrity: sha512-EM9YdNg6zU2DWMJuc9zD8kPUpj0wvPspa63Qe9DPGygzL956uYThfoUQk5aNpPmMr9hs/k+Xm7FLuWFKERFkrQ==} + knip@5.83.1: + resolution: {integrity: sha512-av3ZG/Nui6S/BNL8Tmj12yGxYfTnwWnslouW97m40him7o8MwiMjZBY9TPvlEWUci45aVId0/HbgTwSKIDGpMw==} engines: {node: '>=18.18.0'} hasBin: true peerDependencies: @@ -2765,13 +2768,13 @@ packages: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} + minimatch@10.1.2: + resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -2828,8 +2831,8 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nx@22.3.3: - resolution: {integrity: sha512-pOxtKWUfvf0oD8Geqs8D89Q2xpstRTaSY+F6Ut/Wd0GnEjUjO32SS1ymAM6WggGPHDZN4qpNrd5cfIxQmAbRLg==} + nx@22.4.5: + resolution: {integrity: sha512-l68kzhnemXXGCDS9/W8eccZ7Bzse9pw1oJ466pzDM89MbA6hEaOQ0p+eDXZI++iWl0T+lYJ56EDhO23syKzt9g==} hasBin: true peerDependencies: '@swc-node/register': ^1.8.0 @@ -2873,8 +2876,8 @@ packages: outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} - oxc-resolver@11.16.3: - resolution: {integrity: sha512-goLOJH3x69VouGWGp5CgCIHyksmOZzXr36lsRmQz1APg3SPFORrvV2q7nsUHMzLVa6ZJgNwkgUSJFsbCpAWkCA==} + oxc-resolver@11.17.1: + resolution: {integrity: sha512-pyRXK9kH81zKlirHufkFhOFBZRks8iAMLwPH8gU7lvKFiuzUH9L8MxDEllazwOb8fjXMcWjY1PMDfMJ2/yh5cw==} p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} @@ -3031,8 +3034,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.8.0: - resolution: {integrity: sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==} + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} engines: {node: '>=14'} hasBin: true @@ -3047,8 +3050,8 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - publint@0.3.16: - resolution: {integrity: sha512-MFqyfRLAExPVZdTQFwkAQELzA8idyXzROVOytg6nEJ/GEypXBUmMGrVaID8cTuzRS1U5L8yTOdOJtMXgFUJAeA==} + publint@0.3.17: + resolution: {integrity: sha512-Q3NLegA9XM6usW+dYQRG1g9uEHiYUzcCVBJDJ7yMcWRqVU9LYZUWdqbwMZfmTCFC5PZLQpLAmhvRcQRl3exqkw==} engines: {node: '>=18'} hasBin: true @@ -3069,10 +3072,10 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - react-dom@19.2.3: - resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: - react: ^19.2.3 + react: ^19.2.4 react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -3084,8 +3087,8 @@ packages: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} - react@19.2.3: - resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} read-cache@1.0.0: @@ -3170,13 +3173,13 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rolldown@1.0.0-beta.60: - resolution: {integrity: sha512-YYgpv7MiTp9LdLj1fzGzCtij8Yi2OKEc3HQtfbIxW4yuSgpQz9518I69U72T5ErPA/ATOXqlcisiLrWy+5V9YA==} + rolldown@1.0.0-rc.3: + resolution: {integrity: sha512-Po/YZECDOqVXjIXrtC5h++a5NLvKAQNrd9ggrIG3sbDfGO5BqTUsrI6l8zdniKRp3r5Tp/2JTrXqx4GIguFCMw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.55.1: - resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==} + rollup@4.57.1: + resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -3200,19 +3203,19 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true - seroval-plugins@1.3.3: - resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} + seroval-plugins@1.5.0: + resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 - seroval@1.3.2: - resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} + seroval@1.5.0: + resolution: {integrity: sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==} engines: {node: '>=10'} shebang-command@2.0.0: @@ -3285,8 +3288,8 @@ packages: resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} engines: {node: '>= 18'} - solid-js@1.9.10: - resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==} + solid-js@1.9.11: + resolution: {integrity: sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q==} solid-refresh@0.6.3: resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==} @@ -3356,8 +3359,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svelte@5.46.4: - resolution: {integrity: sha512-VJwdXrmv9L8L7ZasJeWcCjoIuMRVbhuxbss0fpVnR8yorMmjNDwcjIH08vS6wmSzzzgAG5CADQ1JuXPS2nwt9w==} + svelte@5.50.0: + resolution: {integrity: sha512-FR9kTLmX5i0oyeQ5j/+w8DuagIkQ7MWMuPpPVioW2zx9Dw77q+1ufLzF1IqNtcTXPRnIIio4PlasliVn43OnbQ==} engines: {node: '>=18'} tailwindcss@3.4.19: @@ -3485,8 +3488,8 @@ packages: peerDependencies: typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x - typescript-eslint@8.53.0: - resolution: {integrity: sha512-xHURCQNxZ1dsWn0sdOaOfCSQG0HKeqSj9OexIxrz6ypU6wHYOdX2I3D2b8s8wFSsSOYJb+6q283cLiLlkEsBYw==} + typescript-eslint@8.55.0: + resolution: {integrity: sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -3503,14 +3506,11 @@ packages: unconfig-core@7.4.2: resolution: {integrity: sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@7.18.2: - resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==} + undici@7.21.0: + resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==} engines: {node: '>=20.18.1'} universalify@0.1.2: @@ -3520,8 +3520,8 @@ packages: unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} - unrun@0.2.25: - resolution: {integrity: sha512-ZOr5uQL+JlcUT8hZsQbtuUgb1zzcFx3juhXyLSsciaWa3DW1ldMY9r4KSF3+k/LR1Evj2ggAZo1usK4/knBjMQ==} + unrun@0.2.27: + resolution: {integrity: sha512-Mmur1UJpIbfxasLOhPRvox/QS4xBiDii71hMP7smfRthGcwFL2OAmYRgduLANOAU4LUkvVamuP+02U+c90jlrw==} engines: {node: '>=20.19.0'} hasBin: true peerDependencies: @@ -3605,18 +3605,18 @@ packages: vite: optional: true - vitest@4.0.17: - resolution: {integrity: sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==} + vitest@4.0.18: + resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.17 - '@vitest/browser-preview': 4.0.17 - '@vitest/browser-webdriverio': 4.0.17 - '@vitest/ui': 4.0.17 + '@vitest/browser-playwright': 4.0.18 + '@vitest/browser-preview': 4.0.18 + '@vitest/browser-webdriverio': 4.0.18 + '@vitest/ui': 4.0.18 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -3746,8 +3746,8 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.3.5: - resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} snapshots: @@ -3755,25 +3755,25 @@ snapshots: '@alloc/quick-lru@5.2.0': {} - '@babel/code-frame@7.28.6': + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.6': {} + '@babel/compat-data@7.29.0': {} - '@babel/core@7.28.6': + '@babel/core@7.29.0': dependencies: - '@babel/code-frame': 7.28.6 - '@babel/generator': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6) + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) '@babel/helpers': 7.28.6 - '@babel/parser': 7.28.6 + '@babel/parser': 7.29.0 '@babel/template': 7.28.6 - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -3783,35 +3783,35 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.6': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.6 + '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.28.6)': + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.28.6) + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.6 + '@babel/traverse': 7.29.0 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -3820,50 +3820,50 @@ snapshots: '@babel/helper-member-expression-to-functions@7.28.5': dependencies: - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.18.6': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.28.6)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-module-imports': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@babel/helper-plugin-utils@7.28.6': {} - '@babel/helper-replace-supers@7.28.6(@babel/core@7.28.6)': + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.6 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.28.6 - '@babel/types': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color @@ -3876,67 +3876,67 @@ snapshots: '@babel/helpers@7.28.6': dependencies: '@babel/template': 7.28.6 - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 - '@babel/parser@7.28.6': + '@babel/parser@7.29.0': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 - '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.28.6)': + '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.28.6) + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.28.6)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.28.6)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.28.6)': + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.28.6) + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) '@babel/helper-plugin-utils': 7.28.6 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.6)': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.6)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.28.6)': + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.28.6) + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.28.6) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.28.5(@babel/core@7.28.6)': + '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.28.6) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.28.6) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) transitivePeerDependencies: - supports-color @@ -3944,23 +3944,23 @@ snapshots: '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 - '@babel/traverse@7.28.6': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.28.6 - '@babel/generator': 7.28.6 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.6 + '@babel/parser': 7.29.0 '@babel/template': 7.28.6 - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.6': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 @@ -3979,7 +3979,7 @@ snapshots: outdent: 0.5.0 prettier: 2.8.8 resolve-from: 5.0.0 - semver: 7.7.3 + semver: 7.7.4 '@changesets/assemble-release-plan@6.0.9': dependencies: @@ -3988,13 +3988,13 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 - semver: 7.7.3 + semver: 7.7.4 '@changesets/changelog-git@0.2.1': dependencies: '@changesets/types': 6.1.0 - '@changesets/cli@2.29.8(@types/node@25.0.9)': + '@changesets/cli@2.29.8(@types/node@25.2.2)': dependencies: '@changesets/apply-release-plan': 7.0.14 '@changesets/assemble-release-plan': 6.0.9 @@ -4010,7 +4010,7 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.3(@types/node@25.0.9) + '@inquirer/external-editor': 1.0.3(@types/node@25.2.2) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 ci-info: 3.9.0 @@ -4021,7 +4021,7 @@ snapshots: package-manager-detector: 0.2.11 picocolors: 1.1.1 resolve-from: 5.0.0 - semver: 7.7.3 + semver: 7.7.4 spawndamnit: 3.0.1 term-size: 2.2.1 transitivePeerDependencies: @@ -4046,7 +4046,7 @@ snapshots: '@changesets/types': 6.1.0 '@manypkg/get-packages': 1.1.3 picocolors: 1.1.1 - semver: 7.7.3 + semver: 7.7.4 '@changesets/get-github-info@0.6.0': dependencies: @@ -4129,82 +4129,82 @@ snapshots: dependencies: tslib: 2.8.1 - '@esbuild/aix-ppc64@0.27.2': + '@esbuild/aix-ppc64@0.27.3': optional: true - '@esbuild/android-arm64@0.27.2': + '@esbuild/android-arm64@0.27.3': optional: true - '@esbuild/android-arm@0.27.2': + '@esbuild/android-arm@0.27.3': optional: true - '@esbuild/android-x64@0.27.2': + '@esbuild/android-x64@0.27.3': optional: true - '@esbuild/darwin-arm64@0.27.2': + '@esbuild/darwin-arm64@0.27.3': optional: true - '@esbuild/darwin-x64@0.27.2': + '@esbuild/darwin-x64@0.27.3': optional: true - '@esbuild/freebsd-arm64@0.27.2': + '@esbuild/freebsd-arm64@0.27.3': optional: true - '@esbuild/freebsd-x64@0.27.2': + '@esbuild/freebsd-x64@0.27.3': optional: true - '@esbuild/linux-arm64@0.27.2': + '@esbuild/linux-arm64@0.27.3': optional: true - '@esbuild/linux-arm@0.27.2': + '@esbuild/linux-arm@0.27.3': optional: true - '@esbuild/linux-ia32@0.27.2': + '@esbuild/linux-ia32@0.27.3': optional: true - '@esbuild/linux-loong64@0.27.2': + '@esbuild/linux-loong64@0.27.3': optional: true - '@esbuild/linux-mips64el@0.27.2': + '@esbuild/linux-mips64el@0.27.3': optional: true - '@esbuild/linux-ppc64@0.27.2': + '@esbuild/linux-ppc64@0.27.3': optional: true - '@esbuild/linux-riscv64@0.27.2': + '@esbuild/linux-riscv64@0.27.3': optional: true - '@esbuild/linux-s390x@0.27.2': + '@esbuild/linux-s390x@0.27.3': optional: true - '@esbuild/linux-x64@0.27.2': + '@esbuild/linux-x64@0.27.3': optional: true - '@esbuild/netbsd-arm64@0.27.2': + '@esbuild/netbsd-arm64@0.27.3': optional: true - '@esbuild/netbsd-x64@0.27.2': + '@esbuild/netbsd-x64@0.27.3': optional: true - '@esbuild/openbsd-arm64@0.27.2': + '@esbuild/openbsd-arm64@0.27.3': optional: true - '@esbuild/openbsd-x64@0.27.2': + '@esbuild/openbsd-x64@0.27.3': optional: true - '@esbuild/openharmony-arm64@0.27.2': + '@esbuild/openharmony-arm64@0.27.3': optional: true - '@esbuild/sunos-x64@0.27.2': + '@esbuild/sunos-x64@0.27.3': optional: true - '@esbuild/win32-arm64@0.27.2': + '@esbuild/win32-arm64@0.27.3': optional: true - '@esbuild/win32-ia32@0.27.2': + '@esbuild/win32-ia32@0.27.3': optional: true - '@esbuild/win32-x64@0.27.2': + '@esbuild/win32-x64@0.27.3': optional: true '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': @@ -4214,73 +4214,74 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint-react/ast@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@eslint-react/ast@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-react/eff': 2.7.2 - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) string-ts: 2.3.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@eslint-react/core@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@eslint-react/core@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - birecord: 0.1.1 + '@eslint-react/ast': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@eslint-react/shared': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) ts-pattern: 5.9.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@eslint-react/eff@2.7.2': {} + '@eslint-react/eff@2.12.2': {} - '@eslint-react/eslint-plugin@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@eslint-react/eslint-plugin@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@eslint-react/shared': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/type-utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-react-dom: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-hooks-extra: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-naming-convention: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-web-api: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-react-x: 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-dom: 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-hooks-extra: 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-naming-convention: 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-rsc: 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-web-api: 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-x: 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@eslint-react/shared@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@eslint-react/shared@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-react/eff': 2.7.2 - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) ts-pattern: 5.9.0 typescript: 5.9.3 - zod: 4.3.5 + zod: 4.3.6 transitivePeerDependencies: - supports-color - '@eslint-react/var@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@eslint-react/var@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/ast': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@eslint-react/shared': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) ts-pattern: 5.9.0 typescript: 5.9.3 @@ -4326,14 +4327,14 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@faker-js/faker@10.2.0': {} + '@faker-js/faker@10.3.0': {} - '@gerrit0/mini-shiki@3.21.0': + '@gerrit0/mini-shiki@3.22.0': dependencies: - '@shikijs/engine-oniguruma': 3.21.0 - '@shikijs/langs': 3.21.0 - '@shikijs/themes': 3.21.0 - '@shikijs/types': 3.21.0 + '@shikijs/engine-oniguruma': 3.22.0 + '@shikijs/langs': 3.22.0 + '@shikijs/themes': 3.22.0 + '@shikijs/types': 3.22.0 '@shikijs/vscode-textmate': 10.0.2 '@humanfs/core@0.19.1': {} @@ -4347,16 +4348,16 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inquirer/external-editor@1.0.3(@types/node@25.0.9)': + '@inquirer/external-editor@1.0.3(@types/node@25.2.2)': dependencies: chardet: 2.1.1 iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 25.0.9 + '@types/node': 25.2.2 '@isaacs/balanced-match@4.0.1': {} - '@isaacs/brace-expansion@5.0.0': + '@isaacs/brace-expansion@5.0.1': dependencies: '@isaacs/balanced-match': 4.0.1 @@ -4366,7 +4367,7 @@ snapshots: '@jest/schemas@30.0.5': dependencies: - '@sinclair/typebox': 0.34.47 + '@sinclair/typebox': 0.34.48 '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -4439,103 +4440,103 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 - '@nx/nx-darwin-arm64@22.3.3': + '@nx/nx-darwin-arm64@22.4.5': optional: true - '@nx/nx-darwin-x64@22.3.3': + '@nx/nx-darwin-x64@22.4.5': optional: true - '@nx/nx-freebsd-x64@22.3.3': + '@nx/nx-freebsd-x64@22.4.5': optional: true - '@nx/nx-linux-arm-gnueabihf@22.3.3': + '@nx/nx-linux-arm-gnueabihf@22.4.5': optional: true - '@nx/nx-linux-arm64-gnu@22.3.3': + '@nx/nx-linux-arm64-gnu@22.4.5': optional: true - '@nx/nx-linux-arm64-musl@22.3.3': + '@nx/nx-linux-arm64-musl@22.4.5': optional: true - '@nx/nx-linux-x64-gnu@22.3.3': + '@nx/nx-linux-x64-gnu@22.4.5': optional: true - '@nx/nx-linux-x64-musl@22.3.3': + '@nx/nx-linux-x64-musl@22.4.5': optional: true - '@nx/nx-win32-arm64-msvc@22.3.3': + '@nx/nx-win32-arm64-msvc@22.4.5': optional: true - '@nx/nx-win32-x64-msvc@22.3.3': + '@nx/nx-win32-x64-msvc@22.4.5': optional: true '@oxc-project/types@0.107.0': {} - '@oxc-project/types@0.108.0': {} + '@oxc-project/types@0.112.0': {} - '@oxc-resolver/binding-android-arm-eabi@11.16.3': + '@oxc-resolver/binding-android-arm-eabi@11.17.1': optional: true - '@oxc-resolver/binding-android-arm64@11.16.3': + '@oxc-resolver/binding-android-arm64@11.17.1': optional: true - '@oxc-resolver/binding-darwin-arm64@11.16.3': + '@oxc-resolver/binding-darwin-arm64@11.17.1': optional: true - '@oxc-resolver/binding-darwin-x64@11.16.3': + '@oxc-resolver/binding-darwin-x64@11.17.1': optional: true - '@oxc-resolver/binding-freebsd-x64@11.16.3': + '@oxc-resolver/binding-freebsd-x64@11.17.1': optional: true - '@oxc-resolver/binding-linux-arm-gnueabihf@11.16.3': + '@oxc-resolver/binding-linux-arm-gnueabihf@11.17.1': optional: true - '@oxc-resolver/binding-linux-arm-musleabihf@11.16.3': + '@oxc-resolver/binding-linux-arm-musleabihf@11.17.1': optional: true - '@oxc-resolver/binding-linux-arm64-gnu@11.16.3': + '@oxc-resolver/binding-linux-arm64-gnu@11.17.1': optional: true - '@oxc-resolver/binding-linux-arm64-musl@11.16.3': + '@oxc-resolver/binding-linux-arm64-musl@11.17.1': optional: true - '@oxc-resolver/binding-linux-ppc64-gnu@11.16.3': + '@oxc-resolver/binding-linux-ppc64-gnu@11.17.1': optional: true - '@oxc-resolver/binding-linux-riscv64-gnu@11.16.3': + '@oxc-resolver/binding-linux-riscv64-gnu@11.17.1': optional: true - '@oxc-resolver/binding-linux-riscv64-musl@11.16.3': + '@oxc-resolver/binding-linux-riscv64-musl@11.17.1': optional: true - '@oxc-resolver/binding-linux-s390x-gnu@11.16.3': + '@oxc-resolver/binding-linux-s390x-gnu@11.17.1': optional: true - '@oxc-resolver/binding-linux-x64-gnu@11.16.3': + '@oxc-resolver/binding-linux-x64-gnu@11.17.1': optional: true - '@oxc-resolver/binding-linux-x64-musl@11.16.3': + '@oxc-resolver/binding-linux-x64-musl@11.17.1': optional: true - '@oxc-resolver/binding-openharmony-arm64@11.16.3': + '@oxc-resolver/binding-openharmony-arm64@11.17.1': optional: true - '@oxc-resolver/binding-wasm32-wasi@11.16.3': + '@oxc-resolver/binding-wasm32-wasi@11.17.1': dependencies: '@napi-rs/wasm-runtime': 1.1.1 optional: true - '@oxc-resolver/binding-win32-arm64-msvc@11.16.3': + '@oxc-resolver/binding-win32-arm64-msvc@11.17.1': optional: true - '@oxc-resolver/binding-win32-ia32-msvc@11.16.3': + '@oxc-resolver/binding-win32-ia32-msvc@11.17.1': optional: true - '@oxc-resolver/binding-win32-x64-msvc@11.16.3': + '@oxc-resolver/binding-win32-x64-msvc@11.17.1': optional: true - '@publint/pack@0.1.2': {} + '@publint/pack@0.1.4': {} '@quansync/fs@1.0.0': dependencies: @@ -4544,61 +4545,61 @@ snapshots: '@rolldown/binding-android-arm64@1.0.0-beta.59': optional: true - '@rolldown/binding-android-arm64@1.0.0-beta.60': + '@rolldown/binding-android-arm64@1.0.0-rc.3': optional: true '@rolldown/binding-darwin-arm64@1.0.0-beta.59': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-beta.60': + '@rolldown/binding-darwin-arm64@1.0.0-rc.3': optional: true '@rolldown/binding-darwin-x64@1.0.0-beta.59': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.60': + '@rolldown/binding-darwin-x64@1.0.0-rc.3': optional: true '@rolldown/binding-freebsd-x64@1.0.0-beta.59': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.60': + '@rolldown/binding-freebsd-x64@1.0.0-rc.3': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.59': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.60': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.3': optional: true '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.59': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.60': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.3': optional: true '@rolldown/binding-linux-arm64-musl@1.0.0-beta.59': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.60': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.3': optional: true '@rolldown/binding-linux-x64-gnu@1.0.0-beta.59': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.60': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.3': optional: true '@rolldown/binding-linux-x64-musl@1.0.0-beta.59': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.60': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.3': optional: true '@rolldown/binding-openharmony-arm64@1.0.0-beta.59': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.60': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.3': optional: true '@rolldown/binding-wasm32-wasi@1.0.0-beta.59': @@ -4606,7 +4607,7 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.1 optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.60': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.3': dependencies: '@napi-rs/wasm-runtime': 1.1.1 optional: true @@ -4614,161 +4615,161 @@ snapshots: '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.59': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.60': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.3': optional: true '@rolldown/binding-win32-x64-msvc@1.0.0-beta.59': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.60': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.3': optional: true - '@rolldown/pluginutils@1.0.0-beta.53': {} - '@rolldown/pluginutils@1.0.0-beta.59': {} - '@rolldown/pluginutils@1.0.0-beta.60': {} + '@rolldown/pluginutils@1.0.0-rc.2': {} - '@rollup/rollup-android-arm-eabi@4.55.1': + '@rolldown/pluginutils@1.0.0-rc.3': {} + + '@rollup/rollup-android-arm-eabi@4.57.1': optional: true - '@rollup/rollup-android-arm64@4.55.1': + '@rollup/rollup-android-arm64@4.57.1': optional: true - '@rollup/rollup-darwin-arm64@4.55.1': + '@rollup/rollup-darwin-arm64@4.57.1': optional: true - '@rollup/rollup-darwin-x64@4.55.1': + '@rollup/rollup-darwin-x64@4.57.1': optional: true - '@rollup/rollup-freebsd-arm64@4.55.1': + '@rollup/rollup-freebsd-arm64@4.57.1': optional: true - '@rollup/rollup-freebsd-x64@4.55.1': + '@rollup/rollup-freebsd-x64@4.57.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.55.1': + '@rollup/rollup-linux-arm-gnueabihf@4.57.1': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.55.1': + '@rollup/rollup-linux-arm-musleabihf@4.57.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.55.1': + '@rollup/rollup-linux-arm64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.55.1': + '@rollup/rollup-linux-arm64-musl@4.57.1': optional: true - '@rollup/rollup-linux-loong64-gnu@4.55.1': + '@rollup/rollup-linux-loong64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-loong64-musl@4.55.1': + '@rollup/rollup-linux-loong64-musl@4.57.1': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.55.1': + '@rollup/rollup-linux-ppc64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-ppc64-musl@4.55.1': + '@rollup/rollup-linux-ppc64-musl@4.57.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.55.1': + '@rollup/rollup-linux-riscv64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-riscv64-musl@4.55.1': + '@rollup/rollup-linux-riscv64-musl@4.57.1': optional: true - '@rollup/rollup-linux-s390x-gnu@4.55.1': + '@rollup/rollup-linux-s390x-gnu@4.57.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.55.1': + '@rollup/rollup-linux-x64-gnu@4.57.1': optional: true - '@rollup/rollup-linux-x64-musl@4.55.1': + '@rollup/rollup-linux-x64-musl@4.57.1': optional: true - '@rollup/rollup-openbsd-x64@4.55.1': + '@rollup/rollup-openbsd-x64@4.57.1': optional: true - '@rollup/rollup-openharmony-arm64@4.55.1': + '@rollup/rollup-openharmony-arm64@4.57.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.55.1': + '@rollup/rollup-win32-arm64-msvc@4.57.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.55.1': + '@rollup/rollup-win32-ia32-msvc@4.57.1': optional: true - '@rollup/rollup-win32-x64-gnu@4.55.1': + '@rollup/rollup-win32-x64-gnu@4.57.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.55.1': + '@rollup/rollup-win32-x64-msvc@4.57.1': optional: true - '@shikijs/engine-oniguruma@3.21.0': + '@shikijs/engine-oniguruma@3.22.0': dependencies: - '@shikijs/types': 3.21.0 + '@shikijs/types': 3.22.0 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.21.0': + '@shikijs/langs@3.22.0': dependencies: - '@shikijs/types': 3.21.0 + '@shikijs/types': 3.22.0 - '@shikijs/themes@3.21.0': + '@shikijs/themes@3.22.0': dependencies: - '@shikijs/types': 3.21.0 + '@shikijs/types': 3.22.0 - '@shikijs/types@3.21.0': + '@shikijs/types@3.22.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 '@shikijs/vscode-textmate@10.0.2': {} - '@sinclair/typebox@0.34.47': {} + '@sinclair/typebox@0.34.48': {} - '@solid-primitives/event-listener@2.4.3(solid-js@1.9.10)': + '@solid-primitives/event-listener@2.4.3(solid-js@1.9.11)': dependencies: - '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) - solid-js: 1.9.10 + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 - '@solid-primitives/keyboard@1.3.3(solid-js@1.9.10)': + '@solid-primitives/keyboard@1.3.3(solid-js@1.9.11)': dependencies: - '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.10) - '@solid-primitives/rootless': 1.5.2(solid-js@1.9.10) - '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) - solid-js: 1.9.10 + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) + '@solid-primitives/rootless': 1.5.2(solid-js@1.9.11) + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 - '@solid-primitives/resize-observer@2.1.3(solid-js@1.9.10)': + '@solid-primitives/resize-observer@2.1.3(solid-js@1.9.11)': dependencies: - '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.10) - '@solid-primitives/rootless': 1.5.2(solid-js@1.9.10) - '@solid-primitives/static-store': 0.1.2(solid-js@1.9.10) - '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) - solid-js: 1.9.10 + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) + '@solid-primitives/rootless': 1.5.2(solid-js@1.9.11) + '@solid-primitives/static-store': 0.1.2(solid-js@1.9.11) + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 - '@solid-primitives/rootless@1.5.2(solid-js@1.9.10)': + '@solid-primitives/rootless@1.5.2(solid-js@1.9.11)': dependencies: - '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) - solid-js: 1.9.10 + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 - '@solid-primitives/static-store@0.1.2(solid-js@1.9.10)': + '@solid-primitives/static-store@0.1.2(solid-js@1.9.11)': dependencies: - '@solid-primitives/utils': 6.3.2(solid-js@1.9.10) - solid-js: 1.9.10 + '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) + solid-js: 1.9.11 - '@solid-primitives/utils@6.3.2(solid-js@1.9.10)': + '@solid-primitives/utils@6.3.2(solid-js@1.9.11)': dependencies: - solid-js: 1.9.10 + solid-js: 1.9.11 '@standard-schema/spec@1.1.0': {} - '@stylistic/eslint-plugin@5.7.0(eslint@9.39.2(jiti@2.6.1))': + '@stylistic/eslint-plugin@5.8.0(eslint@9.39.2(jiti@2.6.1))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/types': 8.55.0 eslint: 9.39.2(jiti@2.6.1) - eslint-visitor-keys: 5.0.0 - espree: 11.0.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.3 @@ -4796,49 +4797,49 @@ snapshots: '@tanstack/devtools-event-client@0.4.0': {} - '@tanstack/devtools-ui@0.4.4(csstype@3.2.3)(solid-js@1.9.10)': + '@tanstack/devtools-ui@0.4.4(csstype@3.2.3)(solid-js@1.9.11)': dependencies: clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.10 + solid-js: 1.9.11 transitivePeerDependencies: - csstype - '@tanstack/devtools-utils@0.3.0(@types/react@19.2.8)(csstype@3.2.3)(react@19.2.3)(solid-js@1.9.10)': + '@tanstack/devtools-utils@0.3.0(@types/react@19.2.13)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11)': dependencies: - '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.10) + '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.11) optionalDependencies: - '@types/react': 19.2.8 - react: 19.2.3 - solid-js: 1.9.10 + '@types/react': 19.2.13 + react: 19.2.4 + solid-js: 1.9.11 transitivePeerDependencies: - csstype - '@tanstack/devtools@0.10.6(csstype@3.2.3)(solid-js@1.9.10)': + '@tanstack/devtools@0.10.6(csstype@3.2.3)(solid-js@1.9.11)': dependencies: - '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.10) - '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.10) - '@solid-primitives/resize-observer': 2.1.3(solid-js@1.9.10) + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) + '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.11) + '@solid-primitives/resize-observer': 2.1.3(solid-js@1.9.11) '@tanstack/devtools-client': 0.0.5 '@tanstack/devtools-event-bus': 0.4.1 - '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.10) + '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.11) clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.10 + solid-js: 1.9.11 transitivePeerDependencies: - bufferutil - csstype - utf-8-validate - '@tanstack/eslint-config@0.3.4(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@tanstack/eslint-config@0.3.4(@typescript-eslint/utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint/js': 9.39.2 - '@stylistic/eslint-plugin': 5.7.0(eslint@9.39.2(jiti@2.6.1)) + '@stylistic/eslint-plugin': 5.8.0(eslint@9.39.2(jiti@2.6.1)) eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-n: 17.23.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) globals: 16.5.0 - typescript-eslint: 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + typescript-eslint: 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - '@typescript-eslint/utils' @@ -4846,30 +4847,30 @@ snapshots: - supports-color - typescript - '@tanstack/react-devtools@0.9.5(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(csstype@3.2.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.10)': + '@tanstack/react-devtools@0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11)': dependencies: - '@tanstack/devtools': 0.10.6(csstype@3.2.3)(solid-js@1.9.10) - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@tanstack/devtools': 0.10.6(csstype@3.2.3)(solid-js@1.9.11) + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - bufferutil - csstype - solid-js - utf-8-validate - '@tanstack/react-store@0.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@tanstack/react-store@0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/store': 0.8.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - use-sync-external-store: 1.6.0(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) - '@tanstack/solid-store@0.8.0(solid-js@1.9.10)': + '@tanstack/solid-store@0.8.0(solid-js@1.9.11)': dependencies: '@tanstack/store': 0.8.0 - solid-js: 1.9.10 + solid-js: 1.9.11 '@tanstack/store@0.8.0': {} @@ -4883,7 +4884,7 @@ snapshots: '@testing-library/dom@10.4.1': dependencies: - '@babel/code-frame': 7.28.6 + '@babel/code-frame': 7.29.0 '@babel/runtime': 7.28.6 '@types/aria-query': 5.0.4 aria-query: 5.3.0 @@ -4901,15 +4902,15 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.1(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.8))(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 '@testing-library/dom': 10.4.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) optionalDependencies: - '@types/react': 19.2.8 - '@types/react-dom': 19.2.3(@types/react@19.2.8) + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) '@tybys/wasm-util@0.10.1': dependencies: @@ -4924,24 +4925,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.6 + '@babel/types': 7.29.0 '@types/chai@5.2.3': dependencies: @@ -4960,19 +4961,15 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@20.19.30': - dependencies: - undici-types: 6.21.0 - - '@types/node@25.0.9': + '@types/node@25.2.2': dependencies: undici-types: 7.16.0 - '@types/react-dom@19.2.3(@types/react@19.2.8)': + '@types/react-dom@19.2.3(@types/react@19.2.13)': dependencies: - '@types/react': 19.2.8 + '@types/react': 19.2.13 - '@types/react@19.2.8': + '@types/react@19.2.13': dependencies: csstype: 3.2.3 @@ -4982,16 +4979,16 @@ snapshots: '@types/ws@8.18.1': dependencies: - '@types/node': 25.0.9 + '@types/node': 25.2.2 - '@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.53.0 + '@typescript-eslint/parser': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/type-utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.55.0 eslint: 9.39.2(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 @@ -5000,41 +4997,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.53.0 + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.55.0 debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.53.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.55.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) - '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.53.0': + '@typescript-eslint/scope-manager@8.55.0': dependencies: - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/visitor-keys': 8.53.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/visitor-keys': 8.55.0 - '@typescript-eslint/tsconfig-utils@8.53.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.55.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) ts-api-utils: 2.4.0(typescript@5.9.3) @@ -5042,37 +5039,37 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.53.0': {} + '@typescript-eslint/types@8.55.0': {} - '@typescript-eslint/typescript-estree@8.53.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.55.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.53.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.53.0(typescript@5.9.3) - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/visitor-keys': 8.53.0 + '@typescript-eslint/project-service': 8.55.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.55.0(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/visitor-keys': 8.55.0 debug: 4.4.3 minimatch: 9.0.5 - semver: 7.7.3 + semver: 7.7.4 tinyglobby: 0.2.15 ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.53.0': + '@typescript-eslint/visitor-keys@8.55.0': dependencies: - '@typescript-eslint/types': 8.53.0 + '@typescript-eslint/types': 8.55.0 eslint-visitor-keys: 4.2.1 '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -5134,67 +5131,67 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2))': + '@vitejs/plugin-react@5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2))': dependencies: - '@babel/core': 7.28.6 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.6) - '@rolldown/pluginutils': 1.0.0-beta.53 + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.2 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2))': + '@vitejs/plugin-react@5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2))': dependencies: - '@babel/core': 7.28.6 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.6) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.6) - '@rolldown/pluginutils': 1.0.0-beta.53 + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.2 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/expect@4.0.17': + '@vitest/expect@4.0.18': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.17 - '@vitest/utils': 4.0.17 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2))': + '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2))': dependencies: - '@vitest/spy': 4.0.17 + '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) - '@vitest/pretty-format@4.0.17': + '@vitest/pretty-format@4.0.18': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.17': + '@vitest/runner@4.0.18': dependencies: - '@vitest/utils': 4.0.17 + '@vitest/utils': 4.0.18 pathe: 2.0.3 - '@vitest/snapshot@4.0.17': + '@vitest/snapshot@4.0.18': dependencies: - '@vitest/pretty-format': 4.0.17 + '@vitest/pretty-format': 4.0.18 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.17': {} + '@vitest/spy@4.0.18': {} - '@vitest/utils@4.0.17': + '@vitest/utils@4.0.18': dependencies: - '@vitest/pretty-format': 4.0.17 + '@vitest/pretty-format': 4.0.18 tinyrainbow: 3.0.3 '@yarnpkg/lockfile@1.1.0': {} @@ -5260,21 +5257,21 @@ snapshots: ast-kit@2.2.0: dependencies: - '@babel/parser': 7.28.6 + '@babel/parser': 7.29.0 pathe: 2.0.3 asynckit@0.4.0: {} - autoprefixer@10.4.23(postcss@8.5.6): + autoprefixer@10.4.24(postcss@8.5.6): dependencies: browserslist: 4.28.1 - caniuse-lite: 1.0.30001764 + caniuse-lite: 1.0.30001769 fraction.js: 5.3.4 picocolors: 1.1.1 postcss: 8.5.6 postcss-value-parser: 4.2.0 - axios@1.13.2: + axios@1.13.5: dependencies: follow-redirects: 1.15.11 form-data: 4.0.5 @@ -5284,27 +5281,27 @@ snapshots: axobject-query@4.1.0: {} - babel-plugin-jsx-dom-expressions@0.40.3(@babel/core@7.28.6): + babel-plugin-jsx-dom-expressions@0.40.3(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@babel/helper-module-imports': 7.18.6 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.28.6) - '@babel/types': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 html-entities: 2.3.3 parse5: 7.3.0 - babel-preset-solid@1.9.10(@babel/core@7.28.6)(solid-js@1.9.10): + babel-preset-solid@1.9.10(@babel/core@7.29.0)(solid-js@1.9.11): dependencies: - '@babel/core': 7.28.6 - babel-plugin-jsx-dom-expressions: 0.40.3(@babel/core@7.28.6) + '@babel/core': 7.29.0 + babel-plugin-jsx-dom-expressions: 0.40.3(@babel/core@7.29.0) optionalDependencies: - solid-js: 1.9.10 + solid-js: 1.9.11 balanced-match@1.0.2: {} base64-js@1.5.1: {} - baseline-browser-mapping@2.9.15: {} + baseline-browser-mapping@2.9.19: {} better-path-resolve@1.0.0: dependencies: @@ -5339,9 +5336,9 @@ snapshots: browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.9.15 - caniuse-lite: 1.0.30001764 - electron-to-chromium: 1.5.267 + baseline-browser-mapping: 2.9.19 + caniuse-lite: 1.0.30001769 + electron-to-chromium: 1.5.286 node-releases: 2.0.27 update-browserslist-db: 1.2.3(browserslist@4.28.1) @@ -5361,7 +5358,7 @@ snapshots: camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001764: {} + caniuse-lite@1.0.30001769: {} chai@6.2.2: {} @@ -5381,18 +5378,18 @@ snapshots: domhandler: 5.0.3 domutils: 3.2.2 - cheerio@1.1.2: + cheerio@1.2.0: dependencies: cheerio-select: 2.1.0 dom-serializer: 2.0.0 domhandler: 5.0.3 domutils: 3.2.2 encoding-sniffer: 0.2.1 - htmlparser2: 10.0.0 + htmlparser2: 10.1.0 parse5: 7.3.0 parse5-htmlparser2-tree-adapter: 7.1.0 parse5-parser-stream: 7.1.2 - undici: 7.18.2 + undici: 7.21.0 whatwg-mimetype: 4.0.0 chokidar@3.6.0: @@ -5437,7 +5434,7 @@ snapshots: commander@4.1.1: {} - comment-parser@1.4.4: {} + comment-parser@1.4.5: {} compare-versions@6.1.1: {} @@ -5529,9 +5526,9 @@ snapshots: dotenv@16.6.1: {} - dts-resolver@2.1.3(oxc-resolver@11.16.3): + dts-resolver@2.1.3(oxc-resolver@11.17.1): optionalDependencies: - oxc-resolver: 11.16.3 + oxc-resolver: 11.17.1 dunder-proto@1.0.1: dependencies: @@ -5539,7 +5536,7 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.267: {} + electron-to-chromium@1.5.286: {} emoji-regex@8.0.0: {} @@ -5554,7 +5551,7 @@ snapshots: dependencies: once: 1.4.0 - enhanced-resolve@5.18.4: + enhanced-resolve@5.19.0: dependencies: graceful-fs: 4.2.11 tapable: 2.3.0 @@ -5572,6 +5569,8 @@ snapshots: entities@6.0.1: {} + entities@7.0.1: {} + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -5589,34 +5588,34 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - esbuild@0.27.2: + esbuild@0.27.3: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.2 - '@esbuild/android-arm': 0.27.2 - '@esbuild/android-arm64': 0.27.2 - '@esbuild/android-x64': 0.27.2 - '@esbuild/darwin-arm64': 0.27.2 - '@esbuild/darwin-x64': 0.27.2 - '@esbuild/freebsd-arm64': 0.27.2 - '@esbuild/freebsd-x64': 0.27.2 - '@esbuild/linux-arm': 0.27.2 - '@esbuild/linux-arm64': 0.27.2 - '@esbuild/linux-ia32': 0.27.2 - '@esbuild/linux-loong64': 0.27.2 - '@esbuild/linux-mips64el': 0.27.2 - '@esbuild/linux-ppc64': 0.27.2 - '@esbuild/linux-riscv64': 0.27.2 - '@esbuild/linux-s390x': 0.27.2 - '@esbuild/linux-x64': 0.27.2 - '@esbuild/netbsd-arm64': 0.27.2 - '@esbuild/netbsd-x64': 0.27.2 - '@esbuild/openbsd-arm64': 0.27.2 - '@esbuild/openbsd-x64': 0.27.2 - '@esbuild/openharmony-arm64': 0.27.2 - '@esbuild/sunos-x64': 0.27.2 - '@esbuild/win32-arm64': 0.27.2 - '@esbuild/win32-ia32': 0.27.2 - '@esbuild/win32-x64': 0.27.2 + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 escalade@3.2.0: {} @@ -5627,11 +5626,11 @@ snapshots: eslint-compat-utils@0.5.1(eslint@9.39.2(jiti@2.6.1)): dependencies: eslint: 9.39.2(jiti@2.6.1) - semver: 7.7.3 + semver: 7.7.4 eslint-import-context@0.1.9(unrs-resolver@1.11.1): dependencies: - get-tsconfig: 4.13.0 + get-tsconfig: 4.13.6 stable-hash-x: 0.2.0 optionalDependencies: unrs-resolver: 1.11.1 @@ -5643,43 +5642,43 @@ snapshots: eslint: 9.39.2(jiti@2.6.1) eslint-compat-utils: 0.5.1(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@typescript-eslint/types': 8.53.0 - comment-parser: 1.4.4 + '@typescript-eslint/types': 8.55.0 + comment-parser: 1.4.5 debug: 4.4.3 eslint: 9.39.2(jiti@2.6.1) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 - minimatch: 10.1.1 - semver: 7.7.3 + minimatch: 10.1.2 + semver: 7.7.4 stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - supports-color eslint-plugin-n@17.23.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - enhanced-resolve: 5.18.4 + enhanced-resolve: 5.19.0 eslint: 9.39.2(jiti@2.6.1) eslint-plugin-es-x: 7.8.0(eslint@9.39.2(jiti@2.6.1)) - get-tsconfig: 4.13.0 + get-tsconfig: 4.13.6 globals: 15.15.0 globrex: 0.1.2 ignore: 5.3.2 - semver: 7.7.3 + semver: 7.7.4 ts-declaration-location: 1.0.7(typescript@5.9.3) transitivePeerDependencies: - typescript eslint-plugin-react-compiler@19.1.0-rc.2(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@babel/core': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.28.6) + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.29.0) eslint: 9.39.2(jiti@2.6.1) hermes-parser: 0.25.1 zod: 3.25.76 @@ -5687,37 +5686,35 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-react-dom@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-react-dom@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/ast': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@eslint-react/shared': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) compare-versions: 6.1.1 eslint: 9.39.2(jiti@2.6.1) - string-ts: 2.3.1 ts-pattern: 5.9.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-hooks-extra@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-hooks-extra@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-react/ast': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@eslint-react/shared': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/type-utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) - string-ts: 2.3.1 ts-pattern: 5.9.0 typescript: 5.9.3 transitivePeerDependencies: @@ -5725,26 +5722,26 @@ snapshots: eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@babel/core': 7.28.6 - '@babel/parser': 7.28.6 + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 eslint: 9.39.2(jiti@2.6.1) hermes-parser: 0.25.1 - zod: 4.3.5 - zod-validation-error: 4.0.2(zod@4.3.5) + zod: 4.3.6 + zod-validation-error: 4.0.2(zod@4.3.6) transitivePeerDependencies: - supports-color - eslint-plugin-react-naming-convention@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-naming-convention@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-react/ast': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@eslint-react/shared': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/type-utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) compare-versions: 6.1.1 eslint: 9.39.2(jiti@2.6.1) string-ts: 2.3.1 @@ -5753,49 +5750,61 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-react-web-api@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-react-rsc@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/ast': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/shared': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + ts-pattern: 5.9.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-web-api@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-react/ast': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@eslint-react/shared': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + birecord: 0.1.1 eslint: 9.39.2(jiti@2.6.1) - string-ts: 2.3.1 ts-pattern: 5.9.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-react-x@2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@eslint-react/ast': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/core': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/eff': 2.7.2 - '@eslint-react/shared': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@eslint-react/var': 2.7.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.53.0 - '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/types': 8.53.0 - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint-plugin-react-x@2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@eslint-react/ast': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/core': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/eff': 2.12.2 + '@eslint-react/shared': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@eslint-react/var': 2.12.2(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.55.0 + '@typescript-eslint/type-utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.55.0 + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) compare-versions: 6.1.1 eslint: 9.39.2(jiti@2.6.1) is-immutable-type: 5.0.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - string-ts: 2.3.1 ts-api-utils: 2.4.0(typescript@5.9.3) ts-pattern: 5.9.0 typescript: 5.9.3 transitivePeerDependencies: - supports-color - eslint-plugin-unused-imports@4.3.0(@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): dependencies: eslint: 9.39.2(jiti@2.6.1) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint-scope@8.4.0: dependencies: @@ -5806,8 +5815,6 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint-visitor-keys@5.0.0: {} - eslint@9.39.2(jiti@2.6.1): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) @@ -5857,19 +5864,13 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 - espree@11.0.0: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 5.0.0 - esprima@4.0.1: {} esquery@1.7.0: dependencies: estraverse: 5.3.0 - esrap@2.2.1: + esrap@2.2.3: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -6007,7 +6008,7 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-tsconfig@4.13.0: + get-tsconfig@4.13.6: dependencies: resolve-pkg-maps: 1.0.0 @@ -6044,11 +6045,12 @@ snapshots: graceful-fs@4.2.11: {} - happy-dom@20.3.1: + happy-dom@20.5.3: dependencies: - '@types/node': 20.19.30 + '@types/node': 25.2.2 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 + entities: 6.0.1 whatwg-mimetype: 3.0.0 ws: 8.19.0 transitivePeerDependencies: @@ -6079,14 +6081,14 @@ snapshots: html-link-extractor@1.0.5: dependencies: - cheerio: 1.1.2 + cheerio: 1.2.0 - htmlparser2@10.0.0: + htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 domhandler: 5.0.3 domutils: 3.2.2 - entities: 6.0.1 + entities: 7.0.1 human-id@4.1.3: {} @@ -6137,7 +6139,7 @@ snapshots: is-immutable-type@5.0.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/type-utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) ts-api-utils: 2.4.0(typescript@5.9.3) ts-declaration-location: 1.0.7(typescript@5.9.3) @@ -6213,22 +6215,22 @@ snapshots: dependencies: json-buffer: 3.0.1 - knip@5.81.0(@types/node@25.0.9)(typescript@5.9.3): + knip@5.83.1(@types/node@25.2.2)(typescript@5.9.3): dependencies: '@nodelib/fs.walk': 1.2.8 - '@types/node': 25.0.9 + '@types/node': 25.2.2 fast-glob: 3.3.3 formatly: 0.3.0 jiti: 2.6.1 js-yaml: 4.1.1 minimist: 1.2.8 - oxc-resolver: 11.16.3 + oxc-resolver: 11.17.1 picocolors: 1.1.1 picomatch: 4.0.3 smol-toml: 1.6.0 strip-json-comments: 5.0.3 typescript: 5.9.3 - zod: 4.3.5 + zod: 4.3.6 levn@0.4.1: dependencies: @@ -6319,15 +6321,15 @@ snapshots: minimatch@10.1.1: dependencies: - '@isaacs/brace-expansion': 5.0.0 + '@isaacs/brace-expansion': 5.0.1 - minimatch@3.1.2: + minimatch@10.1.2: dependencies: - brace-expansion: 1.1.12 + '@isaacs/brace-expansion': 5.0.1 - minimatch@9.0.3: + minimatch@3.1.2: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 1.1.12 minimatch@9.0.5: dependencies: @@ -6369,13 +6371,13 @@ snapshots: dependencies: boolbase: 1.0.0 - nx@22.3.3: + nx@22.4.5: dependencies: '@napi-rs/wasm-runtime': 0.2.4 '@yarnpkg/lockfile': 1.1.0 '@yarnpkg/parsers': 3.0.2 '@zkochan/js-yaml': 0.0.7 - axios: 1.13.2 + axios: 1.13.5 chalk: 4.1.2 cli-cursor: 3.1.0 cli-spinners: 2.6.1 @@ -6390,13 +6392,13 @@ snapshots: jest-diff: 30.2.0 jsonc-parser: 3.2.0 lines-and-columns: 2.0.3 - minimatch: 9.0.3 + minimatch: 10.1.1 node-machine-id: 1.1.12 npm-run-path: 4.0.1 open: 8.4.2 ora: 5.3.0 resolve.exports: 2.0.3 - semver: 7.7.3 + semver: 7.7.4 string-width: 4.2.3 tar-stream: 2.2.0 tmp: 0.2.5 @@ -6407,16 +6409,16 @@ snapshots: yargs: 17.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@nx/nx-darwin-arm64': 22.3.3 - '@nx/nx-darwin-x64': 22.3.3 - '@nx/nx-freebsd-x64': 22.3.3 - '@nx/nx-linux-arm-gnueabihf': 22.3.3 - '@nx/nx-linux-arm64-gnu': 22.3.3 - '@nx/nx-linux-arm64-musl': 22.3.3 - '@nx/nx-linux-x64-gnu': 22.3.3 - '@nx/nx-linux-x64-musl': 22.3.3 - '@nx/nx-win32-arm64-msvc': 22.3.3 - '@nx/nx-win32-x64-msvc': 22.3.3 + '@nx/nx-darwin-arm64': 22.4.5 + '@nx/nx-darwin-x64': 22.4.5 + '@nx/nx-freebsd-x64': 22.4.5 + '@nx/nx-linux-arm-gnueabihf': 22.4.5 + '@nx/nx-linux-arm64-gnu': 22.4.5 + '@nx/nx-linux-arm64-musl': 22.4.5 + '@nx/nx-linux-x64-gnu': 22.4.5 + '@nx/nx-linux-x64-musl': 22.4.5 + '@nx/nx-win32-arm64-msvc': 22.4.5 + '@nx/nx-win32-x64-msvc': 22.4.5 transitivePeerDependencies: - debug @@ -6462,28 +6464,28 @@ snapshots: outdent@0.5.0: {} - oxc-resolver@11.16.3: + oxc-resolver@11.17.1: optionalDependencies: - '@oxc-resolver/binding-android-arm-eabi': 11.16.3 - '@oxc-resolver/binding-android-arm64': 11.16.3 - '@oxc-resolver/binding-darwin-arm64': 11.16.3 - '@oxc-resolver/binding-darwin-x64': 11.16.3 - '@oxc-resolver/binding-freebsd-x64': 11.16.3 - '@oxc-resolver/binding-linux-arm-gnueabihf': 11.16.3 - '@oxc-resolver/binding-linux-arm-musleabihf': 11.16.3 - '@oxc-resolver/binding-linux-arm64-gnu': 11.16.3 - '@oxc-resolver/binding-linux-arm64-musl': 11.16.3 - '@oxc-resolver/binding-linux-ppc64-gnu': 11.16.3 - '@oxc-resolver/binding-linux-riscv64-gnu': 11.16.3 - '@oxc-resolver/binding-linux-riscv64-musl': 11.16.3 - '@oxc-resolver/binding-linux-s390x-gnu': 11.16.3 - '@oxc-resolver/binding-linux-x64-gnu': 11.16.3 - '@oxc-resolver/binding-linux-x64-musl': 11.16.3 - '@oxc-resolver/binding-openharmony-arm64': 11.16.3 - '@oxc-resolver/binding-wasm32-wasi': 11.16.3 - '@oxc-resolver/binding-win32-arm64-msvc': 11.16.3 - '@oxc-resolver/binding-win32-ia32-msvc': 11.16.3 - '@oxc-resolver/binding-win32-x64-msvc': 11.16.3 + '@oxc-resolver/binding-android-arm-eabi': 11.17.1 + '@oxc-resolver/binding-android-arm64': 11.17.1 + '@oxc-resolver/binding-darwin-arm64': 11.17.1 + '@oxc-resolver/binding-darwin-x64': 11.17.1 + '@oxc-resolver/binding-freebsd-x64': 11.17.1 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.17.1 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.17.1 + '@oxc-resolver/binding-linux-arm64-gnu': 11.17.1 + '@oxc-resolver/binding-linux-arm64-musl': 11.17.1 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.17.1 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.17.1 + '@oxc-resolver/binding-linux-riscv64-musl': 11.17.1 + '@oxc-resolver/binding-linux-s390x-gnu': 11.17.1 + '@oxc-resolver/binding-linux-x64-gnu': 11.17.1 + '@oxc-resolver/binding-linux-x64-musl': 11.17.1 + '@oxc-resolver/binding-openharmony-arm64': 11.17.1 + '@oxc-resolver/binding-wasm32-wasi': 11.17.1 + '@oxc-resolver/binding-win32-arm64-msvc': 11.17.1 + '@oxc-resolver/binding-win32-ia32-msvc': 11.17.1 + '@oxc-resolver/binding-win32-x64-msvc': 11.17.1 p-filter@2.1.0: dependencies: @@ -6596,14 +6598,14 @@ snapshots: premove@4.0.0: {} - prettier-plugin-svelte@3.4.1(prettier@3.8.0)(svelte@5.46.4): + prettier-plugin-svelte@3.4.1(prettier@3.8.1)(svelte@5.50.0): dependencies: - prettier: 3.8.0 - svelte: 5.46.4 + prettier: 3.8.1 + svelte: 5.50.0 prettier@2.8.8: {} - prettier@3.8.0: {} + prettier@3.8.1: {} pretty-format@27.5.1: dependencies: @@ -6619,9 +6621,9 @@ snapshots: proxy-from-env@1.1.0: {} - publint@0.3.16: + publint@0.3.17: dependencies: - '@publint/pack': 0.1.2 + '@publint/pack': 0.1.4 package-manager-detector: 1.6.0 picocolors: 1.1.1 sade: 1.8.1 @@ -6636,9 +6638,9 @@ snapshots: queue-microtask@1.2.3: {} - react-dom@19.2.3(react@19.2.3): + react-dom@19.2.4(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 scheduler: 0.27.0 react-is@17.0.2: {} @@ -6647,7 +6649,7 @@ snapshots: react-refresh@0.18.0: {} - react@19.2.3: {} + react@19.2.4: {} read-cache@1.0.0: dependencies: @@ -6698,15 +6700,15 @@ snapshots: reusify@1.1.0: {} - rolldown-plugin-dts@0.20.0(oxc-resolver@11.16.3)(rolldown@1.0.0-beta.59)(typescript@5.9.3): + rolldown-plugin-dts@0.20.0(oxc-resolver@11.17.1)(rolldown@1.0.0-beta.59)(typescript@5.9.3): dependencies: - '@babel/generator': 7.28.6 - '@babel/parser': 7.28.6 - '@babel/types': 7.28.6 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 ast-kit: 2.2.0 birpc: 4.0.0 - dts-resolver: 2.1.3(oxc-resolver@11.16.3) - get-tsconfig: 4.13.0 + dts-resolver: 2.1.3(oxc-resolver@11.17.1) + get-tsconfig: 4.13.6 obug: 2.1.1 rolldown: 1.0.0-beta.59 optionalDependencies: @@ -6714,13 +6716,13 @@ snapshots: transitivePeerDependencies: - oxc-resolver - rolldown-plugin-solid@0.2.1(rolldown@1.0.0-beta.60)(solid-js@1.9.10): + rolldown-plugin-solid@0.2.1(rolldown@1.0.0-rc.3)(solid-js@1.9.11): dependencies: - '@babel/core': 7.28.6 - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.6) - babel-preset-solid: 1.9.10(@babel/core@7.28.6)(solid-js@1.9.10) - rolldown: 1.0.0-beta.60 - solid-js: 1.9.10 + '@babel/core': 7.29.0 + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + babel-preset-solid: 1.9.10(@babel/core@7.29.0)(solid-js@1.9.11) + rolldown: 1.0.0-rc.3 + solid-js: 1.9.11 transitivePeerDependencies: - supports-color @@ -6743,54 +6745,54 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.59 '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.59 - rolldown@1.0.0-beta.60: + rolldown@1.0.0-rc.3: dependencies: - '@oxc-project/types': 0.108.0 - '@rolldown/pluginutils': 1.0.0-beta.60 + '@oxc-project/types': 0.112.0 + '@rolldown/pluginutils': 1.0.0-rc.3 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.60 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.60 - '@rolldown/binding-darwin-x64': 1.0.0-beta.60 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.60 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.60 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.60 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.60 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.60 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.60 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.60 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.60 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.60 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.60 - - rollup@4.55.1: + '@rolldown/binding-android-arm64': 1.0.0-rc.3 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.3 + '@rolldown/binding-darwin-x64': 1.0.0-rc.3 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.3 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.3 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.3 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.3 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.3 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.3 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.3 + + rollup@4.57.1: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.55.1 - '@rollup/rollup-android-arm64': 4.55.1 - '@rollup/rollup-darwin-arm64': 4.55.1 - '@rollup/rollup-darwin-x64': 4.55.1 - '@rollup/rollup-freebsd-arm64': 4.55.1 - '@rollup/rollup-freebsd-x64': 4.55.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.55.1 - '@rollup/rollup-linux-arm-musleabihf': 4.55.1 - '@rollup/rollup-linux-arm64-gnu': 4.55.1 - '@rollup/rollup-linux-arm64-musl': 4.55.1 - '@rollup/rollup-linux-loong64-gnu': 4.55.1 - '@rollup/rollup-linux-loong64-musl': 4.55.1 - '@rollup/rollup-linux-ppc64-gnu': 4.55.1 - '@rollup/rollup-linux-ppc64-musl': 4.55.1 - '@rollup/rollup-linux-riscv64-gnu': 4.55.1 - '@rollup/rollup-linux-riscv64-musl': 4.55.1 - '@rollup/rollup-linux-s390x-gnu': 4.55.1 - '@rollup/rollup-linux-x64-gnu': 4.55.1 - '@rollup/rollup-linux-x64-musl': 4.55.1 - '@rollup/rollup-openbsd-x64': 4.55.1 - '@rollup/rollup-openharmony-arm64': 4.55.1 - '@rollup/rollup-win32-arm64-msvc': 4.55.1 - '@rollup/rollup-win32-ia32-msvc': 4.55.1 - '@rollup/rollup-win32-x64-gnu': 4.55.1 - '@rollup/rollup-win32-x64-msvc': 4.55.1 + '@rollup/rollup-android-arm-eabi': 4.57.1 + '@rollup/rollup-android-arm64': 4.57.1 + '@rollup/rollup-darwin-arm64': 4.57.1 + '@rollup/rollup-darwin-x64': 4.57.1 + '@rollup/rollup-freebsd-arm64': 4.57.1 + '@rollup/rollup-freebsd-x64': 4.57.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 + '@rollup/rollup-linux-arm-musleabihf': 4.57.1 + '@rollup/rollup-linux-arm64-gnu': 4.57.1 + '@rollup/rollup-linux-arm64-musl': 4.57.1 + '@rollup/rollup-linux-loong64-gnu': 4.57.1 + '@rollup/rollup-linux-loong64-musl': 4.57.1 + '@rollup/rollup-linux-ppc64-gnu': 4.57.1 + '@rollup/rollup-linux-ppc64-musl': 4.57.1 + '@rollup/rollup-linux-riscv64-gnu': 4.57.1 + '@rollup/rollup-linux-riscv64-musl': 4.57.1 + '@rollup/rollup-linux-s390x-gnu': 4.57.1 + '@rollup/rollup-linux-x64-gnu': 4.57.1 + '@rollup/rollup-linux-x64-musl': 4.57.1 + '@rollup/rollup-openbsd-x64': 4.57.1 + '@rollup/rollup-openharmony-arm64': 4.57.1 + '@rollup/rollup-win32-arm64-msvc': 4.57.1 + '@rollup/rollup-win32-ia32-msvc': 4.57.1 + '@rollup/rollup-win32-x64-gnu': 4.57.1 + '@rollup/rollup-win32-x64-msvc': 4.57.1 fsevents: 2.3.3 run-parallel@1.2.0: @@ -6809,13 +6811,13 @@ snapshots: semver@6.3.1: {} - semver@7.7.3: {} + semver@7.7.4: {} - seroval-plugins@1.3.3(seroval@1.3.2): + seroval-plugins@1.5.0(seroval@1.5.0): dependencies: - seroval: 1.3.2 + seroval: 1.5.0 - seroval@1.3.2: {} + seroval@1.5.0: {} shebang-command@2.0.0: dependencies: @@ -6868,18 +6870,18 @@ snapshots: smol-toml@1.6.0: {} - solid-js@1.9.10: + solid-js@1.9.11: dependencies: csstype: 3.2.3 - seroval: 1.3.2 - seroval-plugins: 1.3.3(seroval@1.3.2) + seroval: 1.5.0 + seroval-plugins: 1.5.0(seroval@1.5.0) - solid-refresh@0.6.3(solid-js@1.9.10): + solid-refresh@0.6.3(solid-js@1.9.11): dependencies: - '@babel/generator': 7.28.6 + '@babel/generator': 7.29.1 '@babel/helper-module-imports': 7.28.6 - '@babel/types': 7.28.6 - solid-js: 1.9.10 + '@babel/types': 7.29.0 + solid-js: 1.9.11 transitivePeerDependencies: - supports-color @@ -6940,7 +6942,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte@5.46.4: + svelte@5.50.0: dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 @@ -6952,7 +6954,7 @@ snapshots: clsx: 2.1.1 devalue: 5.6.2 esm-env: 1.2.2 - esrap: 2.2.1 + esrap: 2.2.3 is-reference: 3.0.3 locate-character: 3.0.0 magic-string: 0.30.21 @@ -7046,7 +7048,7 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tsdown@0.19.0(oxc-resolver@11.16.3)(publint@0.3.16)(typescript@5.9.3): + tsdown@0.19.0(oxc-resolver@11.17.1)(publint@0.3.17)(typescript@5.9.3): dependencies: ansis: 4.2.0 cac: 6.7.14 @@ -7057,15 +7059,15 @@ snapshots: obug: 2.1.1 picomatch: 4.0.3 rolldown: 1.0.0-beta.59 - rolldown-plugin-dts: 0.20.0(oxc-resolver@11.16.3)(rolldown@1.0.0-beta.59)(typescript@5.9.3) - semver: 7.7.3 + rolldown-plugin-dts: 0.20.0(oxc-resolver@11.17.1)(rolldown@1.0.0-beta.59)(typescript@5.9.3) + semver: 7.7.4 tinyexec: 1.0.2 tinyglobby: 0.2.15 tree-kill: 1.2.2 unconfig-core: 7.4.2 - unrun: 0.2.25 + unrun: 0.2.27 optionalDependencies: - publint: 0.3.16 + publint: 0.3.17 typescript: 5.9.3 transitivePeerDependencies: - '@ts-macro/tsc' @@ -7091,19 +7093,19 @@ snapshots: typedoc@0.28.14(typescript@5.9.3): dependencies: - '@gerrit0/mini-shiki': 3.21.0 + '@gerrit0/mini-shiki': 3.22.0 lunr: 2.3.9 markdown-it: 14.1.0 minimatch: 9.0.5 typescript: 5.9.3 yaml: 2.8.2 - typescript-eslint@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.53.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.55.0(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.55.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -7118,11 +7120,9 @@ snapshots: '@quansync/fs': 1.0.0 quansync: 1.0.0 - undici-types@6.21.0: {} - undici-types@7.16.0: {} - undici@7.18.2: {} + undici@7.21.0: {} universalify@0.1.2: {} @@ -7150,9 +7150,9 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - unrun@0.2.25: + unrun@0.2.27: dependencies: - rolldown: 1.0.0-beta.60 + rolldown: 1.0.0-rc.3 update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: @@ -7164,68 +7164,68 @@ snapshots: dependencies: punycode: 2.3.1 - use-sync-external-store@1.6.0(react@19.2.3): + use-sync-external-store@1.6.0(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 util-deprecate@1.0.2: {} - vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.10)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)): + vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)): dependencies: - '@babel/core': 7.28.6 + '@babel/core': 7.29.0 '@types/babel__core': 7.20.5 - babel-preset-solid: 1.9.10(@babel/core@7.28.6)(solid-js@1.9.10) + babel-preset-solid: 1.9.10(@babel/core@7.29.0)(solid-js@1.9.11) merge-anything: 5.1.7 - solid-js: 1.9.10 - solid-refresh: 0.6.3(solid-js@1.9.10) - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) - vitefu: 1.1.1(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) + solid-js: 1.9.11 + solid-refresh: 0.6.3(solid-js@1.9.11) + vite: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) + vitefu: 1.1.1(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) optionalDependencies: '@testing-library/jest-dom': 6.9.1 transitivePeerDependencies: - supports-color - vite@7.3.1(@types/node@25.0.9)(jiti@1.21.7)(yaml@2.8.2): + vite@7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2): dependencies: - esbuild: 0.27.2 + esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.55.1 + rollup: 4.57.1 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.0.9 + '@types/node': 25.2.2 fsevents: 2.3.3 jiti: 1.21.7 yaml: 2.8.2 - vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2): + vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2): dependencies: - esbuild: 0.27.2 + esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.55.1 + rollup: 4.57.1 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.0.9 + '@types/node': 25.2.2 fsevents: 2.3.3 jiti: 2.6.1 yaml: 2.8.2 - vitefu@1.1.1(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)): + vitefu@1.1.1(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)): optionalDependencies: - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) - vitest@4.0.17(@types/node@25.0.9)(happy-dom@20.3.1)(jiti@2.6.1)(yaml@2.8.2): + vitest@4.0.18(@types/node@25.2.2)(happy-dom@20.5.3)(jiti@2.6.1)(yaml@2.8.2): dependencies: - '@vitest/expect': 4.0.17 - '@vitest/mocker': 4.0.17(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.17 - '@vitest/runner': 4.0.17 - '@vitest/snapshot': 4.0.17 - '@vitest/spy': 4.0.17 - '@vitest/utils': 4.0.17 + '@vitest/expect': 4.0.18 + '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) + '@vitest/pretty-format': 4.0.18 + '@vitest/runner': 4.0.18 + '@vitest/snapshot': 4.0.18 + '@vitest/spy': 4.0.18 + '@vitest/utils': 4.0.18 es-module-lexer: 1.7.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -7237,11 +7237,11 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(yaml@2.8.2) + vite: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 25.0.9 - happy-dom: 20.3.1 + '@types/node': 25.2.2 + happy-dom: 20.5.3 transitivePeerDependencies: - jiti - less @@ -7263,7 +7263,7 @@ snapshots: eslint-visitor-keys: 4.2.1 espree: 10.4.0 esquery: 1.7.0 - semver: 7.7.3 + semver: 7.7.4 transitivePeerDependencies: - supports-color @@ -7335,10 +7335,10 @@ snapshots: dependencies: zod: 3.25.76 - zod-validation-error@4.0.2(zod@4.3.5): + zod-validation-error@4.0.2(zod@4.3.6): dependencies: - zod: 4.3.5 + zod: 4.3.6 zod@3.25.76: {} - zod@4.3.5: {} + zod@4.3.6: {} From dbd77706f3648f93dced7ddd2efd75f86096985e Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Fri, 13 Feb 2026 21:34:10 +0100 Subject: [PATCH 056/207] feat: calendar --- packages/react-time/src/index.ts | 6 +- .../react-time/src/useCalendar/useCalendar.ts | 419 ++++++++++++++---- packages/time/src/calendar/calendar.ts | 104 +++++ packages/time/src/calendar/types.ts | 22 + packages/time/src/client/TimeClient.ts | 7 +- 5 files changed, 473 insertions(+), 85 deletions(-) diff --git a/packages/react-time/src/index.ts b/packages/react-time/src/index.ts index a4358d60..ff363e82 100644 --- a/packages/react-time/src/index.ts +++ b/packages/react-time/src/index.ts @@ -6,7 +6,11 @@ export type { } from './useCalendar' // Re-export ResizeError and AvailabilityConflict from core package -export type { ResizeError, AvailabilityConflict } from '@tanstack/time' +export type { + ResizeError, + AvailabilityConflict, + UnavailabilityReason, +} from '@tanstack/time' export { calculateGhostPreviewStyle, diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 93937146..33899aac 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -218,64 +218,216 @@ export const useCalendar = < return Math.round(minutes / snapToMinutes) * snapToMinutes } + const getDetailedConflicts = ( + dayDate: string, + startMins: number, + endMins: number, + ): Array => { + if (!resourceIds?.length) return [] + + const conflicts: Array = [] + + const details = calendarCore.getUnavailabilityDetails( + dayDate, + startMins, + endMins, + { + resourceIds, + }, + ) + + const unavailableRangesForDay = getUnavailableMinutesForDay(dayDate) + + for (const range of unavailableRangesForDay) { + if (startMins < range.endMinutes && endMins > range.startMinutes) { + const overlappingDetails = details.filter((d) => { + const resource = calendarCore.options.resources?.find( + (r) => r.id === d.resourceId, + ) + if (!resource) return false + + const resourceAvailableSlots = + resource.availability?.filter((slot) => { + const slotWeekday = new Date(dayDate).getDay() || 7 + return slot.weekdays.includes(slotWeekday) + }) || [] + + if (resourceAvailableSlots.length === 0) return true + + return !resourceAvailableSlots.some((slot) => { + const slotStartParts = slot.startTime.split(':').map(Number) + const slotEndParts = slot.endTime.split(':').map(Number) + const slotStart = + (slotStartParts[0] ?? 0) * 60 + (slotStartParts[1] ?? 0) + const slotEnd = + (slotEndParts[0] ?? 0) * 60 + (slotEndParts[1] ?? 0) + + return !( + range.endMinutes <= slotStart || range.startMinutes >= slotEnd + ) + }) + }) + + if (overlappingDetails.length > 0) { + conflicts.push({ + date: dayDate, + conflictRange: { + start: formatMinutesToTime( + Math.max(startMins, range.startMinutes), + ), + end: formatMinutesToTime(Math.min(endMins, range.endMinutes)), + }, + resourceIds: overlappingDetails.map((d) => d.resourceId), + resourceDetails: overlappingDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: overlappingDetails + .map((d) => d.description) + .join('; '), + }) + } + } + } + + const eventsOnDay = calendarCore.getEventsByDate(dayDate) + const currentEventId = id + + for (const resourceId of resourceIds) { + const resource = calendarCore.options.resources?.find( + (r) => r.id === resourceId, + ) + if (!resource || !resource.capacity) continue + + const overlappingEvents = eventsOnDay.filter((e) => { + if (e.id === currentEventId) return false + + const eventResourceIds = e.resources?.map((r) => r.id) || [] + if (!eventResourceIds.includes(resourceId)) return false + + const eventStart = new Date(e.start) + const eventEnd = new Date(e.end) + const eventStartMins = + eventStart.getHours() * 60 + eventStart.getMinutes() + const eventEndMins = + eventEnd.getHours() * 60 + eventEnd.getMinutes() + + return startMins < eventEndMins && endMins > eventStartMins + }) + + const currentUsage = overlappingEvents.length + const maxCapacity = resource.capacity + + if (currentUsage >= maxCapacity) { + conflicts.push({ + date: dayDate, + conflictRange: { + start: formatMinutesToTime(startMins), + end: formatMinutesToTime(endMins), + }, + resourceIds: [resourceId], + resourceDetails: [ + { + resourceId: resource.id, + resourceLabel: resource.label, + reason: 'capacity', + description: `${resource.label}: Capacity exceeded (${currentUsage}/${maxCapacity} slots used)`, + capacityInfo: { + max: maxCapacity, + used: currentUsage, + remaining: 0, + }, + }, + ], + description: `${resource.label}: Capacity exceeded (${currentUsage}/${maxCapacity} slots used)`, + }) + } + } + + return conflicts + } + if (edge === 'top' && targetDayDate < originalStartDate) { const rawStartMinutes = new Date(start).getHours() * 60 + new Date(start).getMinutes() + totalDeltaMinutes const targetStartMinutes = ((rawStartMinutes % 1440) + 1440) % 1440 - // Snap to grid before checking conflicts const snappedTargetStartMinutes = snapMinutes(targetStartMinutes) const currentStartMinutes = new Date(start).getHours() * 60 + new Date(start).getMinutes() - for (const range of unavailableRanges) { - if ( - snappedTargetStartMinutes < range.endMinutes && - range.startMinutes < 1440 - ) { + if (resourceIds?.length) { + const unavailabilityDetails = calendarCore.getUnavailabilityDetails( + targetDayDate, + snappedTargetStartMinutes, + 1440, + { resourceIds }, + ) + + if (unavailabilityDetails.length > 0) { shouldBlockResize = true blockReason = 'unavailable-time' - blockMessage = `Cannot resize: Event would start at ${formatMinutesToTime(snappedTargetStartMinutes)} which is during unavailable time (${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)})` + const detailsText = unavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Unavailable: Event at ${formatMinutesToTime(snappedTargetStartMinutes)} conflicts with ${detailsText}` conflicts.push({ date: targetDayDate, conflictRange: { - start: formatMinutesToTime( - Math.max(snappedTargetStartMinutes, range.startMinutes), - ), - end: formatMinutesToTime(range.endMinutes), + start: formatMinutesToTime(snappedTargetStartMinutes), + end: formatMinutesToTime(1440), }, - resourceIds: resourceIds ?? [], - description: `Target time ${formatMinutesToTime(snappedTargetStartMinutes)} conflicts with unavailable period ${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)}`, + resourceIds: unavailabilityDetails.map((d) => d.resourceId), + resourceDetails: unavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: unavailabilityDetails + .map((d) => d.description) + .join('; '), }) - break } } - if (!shouldBlockResize) { - const sourceUnavailableRanges = - getUnavailableMinutesForDay(originalStartDate) - for (const range of sourceUnavailableRanges) { - if ( - 0 < range.endMinutes && - range.startMinutes < currentStartMinutes - ) { - shouldBlockResize = true - blockReason = 'unavailable-time' - blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalStartDate} (${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)})` - conflicts.push({ - date: originalStartDate, - conflictRange: { - start: formatMinutesToTime(range.startMinutes), - end: formatMinutesToTime( - Math.min(range.endMinutes, currentStartMinutes), - ), - }, - resourceIds: resourceIds ?? [], - description: `Must pass through unavailable period ${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)}`, - }) - break - } + // Check if we would need to pass through unavailable time on the source day + if (!shouldBlockResize && resourceIds?.length) { + const sourceUnavailabilityDetails = + calendarCore.getUnavailabilityDetails( + originalStartDate, + 0, + currentStartMinutes, + { resourceIds }, + ) + + if (sourceUnavailabilityDetails.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const detailsText = sourceUnavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalStartDate} - ${detailsText}` + conflicts.push({ + date: originalStartDate, + conflictRange: { + start: formatMinutesToTime(0), + end: formatMinutesToTime(currentStartMinutes), + }, + resourceIds: sourceUnavailabilityDetails.map((d) => d.resourceId), + resourceDetails: sourceUnavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: sourceUnavailabilityDetails + .map((d) => d.description) + .join('; '), + }) } } } else if (edge === 'bottom' && targetDayDate > originalEndDate) { @@ -284,58 +436,166 @@ export const useCalendar = < new Date(end).getMinutes() + totalDeltaMinutes const targetEndMinutes = ((rawEndMinutes % 1440) + 1440) % 1440 - // Snap to grid before checking conflicts const snappedTargetEndMinutes = snapMinutes(targetEndMinutes) const currentEndMinutes = new Date(end).getHours() * 60 + new Date(end).getMinutes() - const sourceUnavailableRanges = - getUnavailableMinutesForDay(originalEndDate) - for (const range of sourceUnavailableRanges) { - if ( - currentEndMinutes < range.endMinutes && - range.startMinutes < 1440 - ) { + // Check if any resource is unavailable at the target time on the target day + if (resourceIds?.length) { + const unavailabilityDetails = calendarCore.getUnavailabilityDetails( + targetDayDate, + 0, // Check from start of day to end time + snappedTargetEndMinutes, + { resourceIds }, + ) + + if (unavailabilityDetails.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const detailsText = unavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Unavailable: Event ending at ${formatMinutesToTime(snappedTargetEndMinutes)} conflicts with ${detailsText}` + conflicts.push({ + date: targetDayDate, + conflictRange: { + start: formatMinutesToTime(0), + end: formatMinutesToTime(snappedTargetEndMinutes), + }, + resourceIds: unavailabilityDetails.map((d) => d.resourceId), + resourceDetails: unavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: unavailabilityDetails + .map((d) => d.description) + .join('; '), + }) + } + } + + // Check if we would need to pass through unavailable time on the source day + if (!shouldBlockResize && resourceIds?.length) { + const sourceUnavailabilityDetails = + calendarCore.getUnavailabilityDetails( + originalEndDate, + currentEndMinutes, + 1440, + { resourceIds }, + ) + + if (sourceUnavailabilityDetails.length > 0) { shouldBlockResize = true blockReason = 'unavailable-time' - blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalEndDate} (${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)})` + const detailsText = sourceUnavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalEndDate} - ${detailsText}` conflicts.push({ date: originalEndDate, conflictRange: { - start: formatMinutesToTime( - Math.max(range.startMinutes, currentEndMinutes), - ), - end: formatMinutesToTime(range.endMinutes), + start: formatMinutesToTime(currentEndMinutes), + end: formatMinutesToTime(1440), }, - resourceIds: resourceIds ?? [], - description: `Must pass through unavailable period ${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)}`, + resourceIds: sourceUnavailabilityDetails.map((d) => d.resourceId), + resourceDetails: sourceUnavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: sourceUnavailabilityDetails + .map((d) => d.description) + .join('; '), }) - break } } + } + + // Also check for conflicts when resizing within the same day + if ( + !shouldBlockResize && + targetDayDate === originalStartDate && + targetDayDate === originalEndDate + ) { + // Calculate the new time range based on the resize + const rawStartMinutes = + new Date(start).getHours() * 60 + + new Date(start).getMinutes() + + (edge === 'top' ? totalDeltaMinutes : 0) + const rawEndMinutes = + new Date(end).getHours() * 60 + + new Date(end).getMinutes() + + (edge === 'bottom' ? totalDeltaMinutes : 0) + const snappedStartMinutes = snapMinutes( + ((rawStartMinutes % 1440) + 1440) % 1440, + ) + const snappedEndMinutes = snapMinutes( + ((rawEndMinutes % 1440) + 1440) % 1440, + ) + + // Directly check if any resource is unavailable for the new time range + // This is more reliable than using getUnavailableRanges which merges availability + if (resourceIds?.length) { + const unavailabilityDetails = calendarCore.getUnavailabilityDetails( + targetDayDate, + snappedStartMinutes, + snappedEndMinutes, + { resourceIds }, + ) + + if (unavailabilityDetails.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const detailsText = unavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Unavailable: Event at ${formatMinutesToTime(snappedStartMinutes)}-${formatMinutesToTime(snappedEndMinutes)} conflicts with ${detailsText}` + conflicts.push({ + date: targetDayDate, + conflictRange: { + start: formatMinutesToTime(snappedStartMinutes), + end: formatMinutesToTime(snappedEndMinutes), + }, + resourceIds: unavailabilityDetails.map((d) => d.resourceId), + resourceDetails: unavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: unavailabilityDetails + .map((d) => d.description) + .join('; '), + }) + } + } + + // Also check capacity constraints if not already blocked if (!shouldBlockResize) { - for (const range of unavailableRanges) { - if ( - 0 < range.endMinutes && - range.startMinutes < snappedTargetEndMinutes - ) { - shouldBlockResize = true - blockReason = 'unavailable-time' - blockMessage = `Cannot resize: Event would end at ${formatMinutesToTime(snappedTargetEndMinutes)} which is during unavailable time (${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)})` - conflicts.push({ - date: targetDayDate, - conflictRange: { - start: formatMinutesToTime(range.startMinutes), - end: formatMinutesToTime( - Math.min(snappedTargetEndMinutes, range.endMinutes), - ), - }, - resourceIds: resourceIds ?? [], - description: `Target time ${formatMinutesToTime(snappedTargetEndMinutes)} conflicts with unavailable period ${formatMinutesToTime(range.startMinutes)} - ${formatMinutesToTime(range.endMinutes)}`, - }) - break - } + const detailedConflicts = getDetailedConflicts( + targetDayDate, + snappedStartMinutes, + snappedEndMinutes, + ) + + // Filter to only capacity conflicts (availability already checked above) + const capacityConflicts = detailedConflicts.filter((c) => + c.resourceDetails.some((d) => d.reason === 'capacity'), + ) + + if (capacityConflicts.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const conflict = capacityConflicts[0]! + const detailsText = conflict.resourceDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Unavailable: Event at ${formatMinutesToTime(snappedStartMinutes)}-${formatMinutesToTime(snappedEndMinutes)} conflicts with ${detailsText}` + conflicts.push(...capacityConflicts) } } } @@ -390,12 +650,7 @@ export const useCalendar = < lastEmittedErrorRef.current = null } - const effectiveDeltaMinutes = shouldBlockResize - ? deltaMinutes - : totalDeltaMinutes - const effectiveUnavailableRanges = shouldBlockResize - ? getUnavailableMinutesForDay(originalDayDate) - : unavailableRanges + const effectiveDeltaMinutes = shouldBlockResize ? 0 : totalDeltaMinutes const result = calculateResizedEvent({ originalStart: start, @@ -405,7 +660,7 @@ export const useCalendar = < timeZone: calendarOptions.timeZone ?? 'UTC', constraints: { ...resizeConstraints, - unavailableRanges: effectiveUnavailableRanges, + unavailableRanges: shouldBlockResize ? [] : unavailableRanges, }, }) diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index ed1ea1b8..585b4a8b 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -429,4 +429,108 @@ export class CalendarCore< endTime: formatTime(range.endMinutes), })) } + + /** + * Get detailed unavailability information for a specific time range on a date + * Returns which resources are unavailable and why + */ + getUnavailabilityDetails( + date: string, + startMinutes: number, + endMinutes: number, + options?: { + resourceIds?: Array + }, + ): Array<{ + resourceId: string + resourceLabel: string + reason: 'outside-hours' | 'capacity' | 'no-availability' + description: string + }> { + const resources = options?.resourceIds + ? this.options.resources?.filter((resource) => + options.resourceIds?.includes(resource.id), + ) + : this.options.resources + + if (!resources || resources.length === 0) { + return [] + } + + const plainDate = Temporal.PlainDate.from(date) + const weekday = plainDate.dayOfWeek + + const details: Array<{ + resourceId: string + resourceLabel: string + reason: 'outside-hours' | 'capacity' | 'no-availability' + description: string + }> = [] + + for (const resource of resources) { + if (!resource.availability || resource.availability.length === 0) { + details.push({ + resourceId: resource.id, + resourceLabel: resource.label, + reason: 'no-availability', + description: `${resource.label}: No availability configured`, + }) + continue + } + + const availableSlots = resource.availability.filter((slot) => + slot.weekdays.includes(weekday), + ) + + if (availableSlots.length === 0) { + details.push({ + resourceId: resource.id, + resourceLabel: resource.label, + reason: 'outside-hours', + description: `${resource.label}: Not available on this day`, + }) + continue + } + + const isWithinAvailability = availableSlots.some((slot) => { + const slotStartParts = slot.startTime.split(':').map(Number) + const slotEndParts = slot.endTime.split(':').map(Number) + const slotStartMinutes = + (slotStartParts[0] ?? 0) * 60 + (slotStartParts[1] ?? 0) + const slotEndMinutes = + (slotEndParts[0] ?? 0) * 60 + (slotEndParts[1] ?? 0) + + return startMinutes >= slotStartMinutes && endMinutes <= slotEndMinutes + }) + + if (!isWithinAvailability) { + const timeRanges = availableSlots + .map((slot) => { + const slotStartParts = slot.startTime.split(':').map(Number) + const slotEndParts = slot.endTime.split(':').map(Number) + return { + start: (slotStartParts[0] ?? 0) * 60 + (slotStartParts[1] ?? 0), + end: (slotEndParts[0] ?? 0) * 60 + (slotEndParts[1] ?? 0), + } + }) + .sort((a, b) => a.start - b.start) + + const formatTime = (mins: number) => + `${String(Math.floor(mins / 60)).padStart(2, '0')}:${String(mins % 60).padStart(2, '0')}` + + const availabilityWindow = timeRanges + .map((r) => `${formatTime(r.start)}-${formatTime(r.end)}`) + .join(', ') + + details.push({ + resourceId: resource.id, + resourceLabel: resource.label, + reason: 'outside-hours', + description: `${resource.label}: Available ${availabilityWindow}, but event is ${formatTime(startMinutes)}-${formatTime(endMinutes)}`, + }) + } + } + + return details + } } diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index 676e966e..44d8483e 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -83,6 +83,26 @@ export interface CalendarStore { eventsVersion: number } +/** + * Information about why a resource is unavailable + */ +export interface UnavailabilityReason { + /** Resource ID */ + resourceId: string + /** Resource label/name */ + resourceLabel: string + /** Why the resource is unavailable */ + reason: 'outside-hours' | 'capacity' | 'no-availability' + /** Human-readable explanation */ + description: string + /** Current capacity usage if applicable */ + capacityInfo?: { + max: number + used: number + remaining: number + } +} + /** * Information about a specific availability conflict */ @@ -96,6 +116,8 @@ export interface AvailabilityConflict { } /** The resource(s) whose availability is being violated */ resourceIds: Array + /** Detailed reasons for each resource */ + resourceDetails: Array /** Human-readable description of the conflict */ description: string } diff --git a/packages/time/src/client/TimeClient.ts b/packages/time/src/client/TimeClient.ts index de19f9bc..8fdc859d 100644 --- a/packages/time/src/client/TimeClient.ts +++ b/packages/time/src/client/TimeClient.ts @@ -1,5 +1,8 @@ import { EventClient } from '@tanstack/devtools-event-client' -import type { AvailabilityConflict } from '../calendar/types' +import type { + AvailabilityConflict, + UnavailabilityReason, +} from '../calendar/types' /** * Event map for TimeClient events @@ -84,4 +87,4 @@ export function getTimeClient(): TimeClient { return TimeClient.getInstance() } -export type { AvailabilityConflict } +export type { AvailabilityConflict, UnavailabilityReason } From c12fc201426f9dee210ad925d1684b2cf5938428 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 21:30:21 +0000 Subject: [PATCH 057/207] ci: apply automated fixes --- .../react/reference/functions/useCalendar.md | 4 +- docs/framework/react/reference/index.md | 6 + .../reference/interfaces/ResizeOptions.md | 110 ++++++++ .../react/reference/interfaces/ResizeState.md | 68 +++++ .../interfaces/UseCalendarOptions.md | 32 +++ docs/reference/classes/CalendarCore.md | 135 +++++++-- docs/reference/classes/DateCore.md | 38 +-- .../calculateDeltaMinutesFromPixels.md | 33 +++ .../functions/calculateGhostPreviewStyle.md | 24 ++ .../functions/calculateResizedEvent.md | 22 ++ .../calculateSegmentResizePreview.md | 24 ++ .../functions/formatEventTimeRange.md | 37 +++ .../functions/getEventDisplayTimeRange.md | 42 +++ .../functions/getResizeHandleStyle.md | 22 ++ docs/reference/functions/getSegmentInfo.md | 36 +++ docs/reference/functions/getTimeClient.md | 18 ++ docs/reference/functions/groupDaysBy.md | 2 +- docs/reference/functions/isMultiDayEvent.md | 28 ++ docs/reference/functions/isWeekend.md | 2 +- docs/reference/index.md | 29 ++ docs/reference/interfaces/Availability.md | 44 +++ .../interfaces/AvailabilityConflict.md | 82 ++++++ docs/reference/interfaces/CalendarApi.md | 78 +++-- .../interfaces/CalendarCoreOptions.md | 22 +- docs/reference/interfaces/CalendarStore.md | 18 +- docs/reference/interfaces/DateCoreOptions.md | 18 +- docs/reference/interfaces/DateRange.md | 6 +- docs/reference/interfaces/Event.md | 36 ++- docs/reference/interfaces/EventTimeRange.md | 38 +++ .../interfaces/FormatEventTimeOptions.md | 32 +++ .../interfaces/FormattedEventTime.md | 56 ++++ .../interfaces/GhostPreviewOptions.md | 44 +++ docs/reference/interfaces/IsWeekendOptions.md | 4 +- .../interfaces/ParsedDateCoreOptions.md | 12 +- docs/reference/interfaces/PositionStyle.md | 30 ++ .../reference/interfaces/ResizeConstraints.md | 40 +++ docs/reference/interfaces/ResizeError.md | 102 +++++++ .../reference/interfaces/ResizeHandleStyle.md | 88 ++++++ .../interfaces/ResizePreviewOptions.md | 68 +++++ .../interfaces/ResizeValidationResult.md | 30 ++ docs/reference/interfaces/Resource.md | 48 +++- docs/reference/interfaces/SegmentInfo.md | 94 +++++++ .../interfaces/SegmentResizePreview.md | 46 +++ docs/reference/interfaces/TimeEventMap.md | 266 ++++++++++++++++++ docs/reference/interfaces/TimeSlot.md | 8 +- .../interfaces/UnavailabilityReason.md | 88 ++++++ docs/reference/interfaces/UnavailableRange.md | 56 ++++ .../interfaces/UnavailableTimeRange.md | 32 +++ docs/reference/interfaces/ViewMode.md | 6 +- docs/reference/type-aliases/Day.md | 10 +- .../type-aliases/GroupDaysByProps.md | 2 +- docs/reference/type-aliases/ResizeEdge.md | 12 + 52 files changed, 2100 insertions(+), 128 deletions(-) create mode 100644 docs/framework/react/reference/interfaces/ResizeOptions.md create mode 100644 docs/framework/react/reference/interfaces/ResizeState.md create mode 100644 docs/framework/react/reference/interfaces/UseCalendarOptions.md create mode 100644 docs/reference/functions/calculateDeltaMinutesFromPixels.md create mode 100644 docs/reference/functions/calculateGhostPreviewStyle.md create mode 100644 docs/reference/functions/calculateResizedEvent.md create mode 100644 docs/reference/functions/calculateSegmentResizePreview.md create mode 100644 docs/reference/functions/formatEventTimeRange.md create mode 100644 docs/reference/functions/getEventDisplayTimeRange.md create mode 100644 docs/reference/functions/getResizeHandleStyle.md create mode 100644 docs/reference/functions/getSegmentInfo.md create mode 100644 docs/reference/functions/getTimeClient.md create mode 100644 docs/reference/functions/isMultiDayEvent.md create mode 100644 docs/reference/interfaces/Availability.md create mode 100644 docs/reference/interfaces/AvailabilityConflict.md create mode 100644 docs/reference/interfaces/EventTimeRange.md create mode 100644 docs/reference/interfaces/FormatEventTimeOptions.md create mode 100644 docs/reference/interfaces/FormattedEventTime.md create mode 100644 docs/reference/interfaces/GhostPreviewOptions.md create mode 100644 docs/reference/interfaces/PositionStyle.md create mode 100644 docs/reference/interfaces/ResizeConstraints.md create mode 100644 docs/reference/interfaces/ResizeError.md create mode 100644 docs/reference/interfaces/ResizeHandleStyle.md create mode 100644 docs/reference/interfaces/ResizePreviewOptions.md create mode 100644 docs/reference/interfaces/ResizeValidationResult.md create mode 100644 docs/reference/interfaces/SegmentInfo.md create mode 100644 docs/reference/interfaces/SegmentResizePreview.md create mode 100644 docs/reference/interfaces/TimeEventMap.md create mode 100644 docs/reference/interfaces/UnavailabilityReason.md create mode 100644 docs/reference/interfaces/UnavailableRange.md create mode 100644 docs/reference/interfaces/UnavailableTimeRange.md create mode 100644 docs/reference/type-aliases/ResizeEdge.md diff --git a/docs/framework/react/reference/functions/useCalendar.md b/docs/framework/react/reference/functions/useCalendar.md index 6eea9c71..d3241b81 100644 --- a/docs/framework/react/reference/functions/useCalendar.md +++ b/docs/framework/react/reference/functions/useCalendar.md @@ -9,7 +9,7 @@ title: useCalendar function useCalendar(options): CalendarApi & object; ``` -Defined in: [useCalendar.ts:11](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L11) +Defined in: [useCalendar.ts:69](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L69) ## Type Parameters @@ -25,7 +25,7 @@ Defined in: [useCalendar.ts:11](https://github.com/TanStack/time/blob/main/packa ### options -`CalendarCoreOptions`\<`TResource`, `TEvent`\> +[`UseCalendarOptions`](../interfaces/UseCalendarOptions.md)\<`TResource`, `TEvent`\> ## Returns diff --git a/docs/framework/react/reference/index.md b/docs/framework/react/reference/index.md index 51ff3a03..dbd4f97e 100644 --- a/docs/framework/react/reference/index.md +++ b/docs/framework/react/reference/index.md @@ -5,6 +5,12 @@ title: "@tanstack/react-time" # @tanstack/react-time +## Interfaces + +- [ResizeOptions](interfaces/ResizeOptions.md) +- [ResizeState](interfaces/ResizeState.md) +- [UseCalendarOptions](interfaces/UseCalendarOptions.md) + ## Functions - [useCalendar](functions/useCalendar.md) diff --git a/docs/framework/react/reference/interfaces/ResizeOptions.md b/docs/framework/react/reference/interfaces/ResizeOptions.md new file mode 100644 index 00000000..f00669e7 --- /dev/null +++ b/docs/framework/react/reference/interfaces/ResizeOptions.md @@ -0,0 +1,110 @@ +--- +id: ResizeOptions +title: ResizeOptions +--- + +# Interface: ResizeOptions + +Defined in: [useCalendar.ts:36](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L36) + +## Properties + +### constraints? + +```ts +optional constraints: ResizeConstraints; +``` + +Defined in: [useCalendar.ts:39](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L39) + +*** + +### containerHeight? + +```ts +optional containerHeight: number; +``` + +Defined in: [useCalendar.ts:38](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L38) + +*** + +### enabled? + +```ts +optional enabled: boolean; +``` + +Defined in: [useCalendar.ts:37](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L37) + +*** + +### onResizeEnd()? + +```ts +optional onResizeEnd: (eventId, newStart, newEnd) => void; +``` + +Defined in: [useCalendar.ts:41](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L41) + +#### Parameters + +##### eventId + +`string` + +##### newStart + +`string` + +##### newEnd + +`string` + +#### Returns + +`void` + +*** + +### onResizeError()? + +```ts +optional onResizeError: (error) => void; +``` + +Defined in: [useCalendar.ts:42](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L42) + +#### Parameters + +##### error + +`ResizeError` + +#### Returns + +`void` + +*** + +### onResizeStart()? + +```ts +optional onResizeStart: (eventId, edge) => void; +``` + +Defined in: [useCalendar.ts:40](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L40) + +#### Parameters + +##### eventId + +`string` + +##### edge + +`ResizeEdge` + +#### Returns + +`void` diff --git a/docs/framework/react/reference/interfaces/ResizeState.md b/docs/framework/react/reference/interfaces/ResizeState.md new file mode 100644 index 00000000..e1d4a00a --- /dev/null +++ b/docs/framework/react/reference/interfaces/ResizeState.md @@ -0,0 +1,68 @@ +--- +id: ResizeState +title: ResizeState +--- + +# Interface: ResizeState + +Defined in: [useCalendar.ts:27](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L27) + +## Properties + +### edge + +```ts +edge: ResizeEdge | null; +``` + +Defined in: [useCalendar.ts:30](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L30) + +*** + +### eventId + +```ts +eventId: string | null; +``` + +Defined in: [useCalendar.ts:29](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L29) + +*** + +### isResizing + +```ts +isResizing: boolean; +``` + +Defined in: [useCalendar.ts:28](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L28) + +*** + +### previewEnd + +```ts +previewEnd: string | null; +``` + +Defined in: [useCalendar.ts:32](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L32) + +*** + +### previewStart + +```ts +previewStart: string | null; +``` + +Defined in: [useCalendar.ts:31](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L31) + +*** + +### targetDayDate + +```ts +targetDayDate: string | null; +``` + +Defined in: [useCalendar.ts:33](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L33) diff --git a/docs/framework/react/reference/interfaces/UseCalendarOptions.md b/docs/framework/react/reference/interfaces/UseCalendarOptions.md new file mode 100644 index 00000000..e3d87648 --- /dev/null +++ b/docs/framework/react/reference/interfaces/UseCalendarOptions.md @@ -0,0 +1,32 @@ +--- +id: UseCalendarOptions +title: UseCalendarOptions +--- + +# Interface: UseCalendarOptions\ + +Defined in: [useCalendar.ts:53](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L53) + +## Extends + +- `CalendarCoreOptions`\<`TResource`, `TEvent`\> + +## Type Parameters + +### TResource + +`TResource` *extends* `Resource` + +### TEvent + +`TEvent` *extends* `Event`\<`TResource`\> + +## Properties + +### resize? + +```ts +optional resize: ResizeOptions; +``` + +Defined in: [useCalendar.ts:57](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L57) diff --git a/docs/reference/classes/CalendarCore.md b/docs/reference/classes/CalendarCore.md index 724b4d54..5a356179 100644 --- a/docs/reference/classes/CalendarCore.md +++ b/docs/reference/classes/CalendarCore.md @@ -5,7 +5,7 @@ title: CalendarCore # Class: CalendarCore\ -Defined in: [calendar/calendar.ts:131](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L131) +Defined in: [calendar/calendar.ts:147](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L147) ## Extends @@ -33,7 +33,7 @@ Defined in: [calendar/calendar.ts:131](https://github.com/TanStack/time/blob/mai new CalendarCore(options): CalendarCore; ``` -Defined in: [calendar/calendar.ts:140](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L140) +Defined in: [calendar/calendar.ts:156](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L156) #### Parameters @@ -57,7 +57,7 @@ Defined in: [calendar/calendar.ts:140](https://github.com/TanStack/time/blob/mai formatters: object; ``` -Defined in: [calendar/date-core.ts:80](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L80) +Defined in: [calendar/date-core.ts:81](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L81) #### date @@ -89,7 +89,7 @@ time: DateTimeFormat; options: ParsedCalendarCoreOptions; ``` -Defined in: [calendar/calendar.ts:138](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L138) +Defined in: [calendar/calendar.ts:154](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L154) #### Overrides @@ -103,7 +103,7 @@ Defined in: [calendar/calendar.ts:138](https://github.com/TanStack/time/blob/mai store: Store; ``` -Defined in: [calendar/date-core.ts:78](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L78) +Defined in: [calendar/date-core.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L79) #### Inherited from @@ -117,7 +117,7 @@ Defined in: [calendar/date-core.ts:78](https://github.com/TanStack/time/blob/mai addEvent(event): void; ``` -Defined in: [calendar/calendar.ts:242](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L242) +Defined in: [calendar/calendar.ts:259](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L259) Adds a new event to the calendar. @@ -145,7 +145,7 @@ CalendarActions.addEvent canGoNextPeriod(): boolean; ``` -Defined in: [calendar/date-core.ts:407](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L407) +Defined in: [calendar/date-core.ts:445](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L445) #### Returns @@ -169,7 +169,7 @@ CalendarActions.canGoNextPeriod canGoPreviousPeriod(): boolean; ``` -Defined in: [calendar/date-core.ts:376](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L376) +Defined in: [calendar/date-core.ts:414](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L414) #### Returns @@ -193,7 +193,7 @@ CalendarActions.canGoPreviousPeriod changeViewMode(newViewMode): void; ``` -Defined in: [calendar/date-core.ts:254](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L254) +Defined in: [calendar/date-core.ts:265](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L265) #### Parameters @@ -223,7 +223,7 @@ CalendarActions.changeViewMode formatDate(date): string; ``` -Defined in: [calendar/date-core.ts:130](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L130) +Defined in: [calendar/date-core.ts:131](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L131) #### Parameters @@ -247,7 +247,7 @@ Defined in: [calendar/date-core.ts:130](https://github.com/TanStack/time/blob/ma formatDateTime(date): string; ``` -Defined in: [calendar/date-core.ts:138](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L138) +Defined in: [calendar/date-core.ts:139](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L139) #### Parameters @@ -271,7 +271,7 @@ Defined in: [calendar/date-core.ts:138](https://github.com/TanStack/time/blob/ma formatTime(date): string; ``` -Defined in: [calendar/date-core.ts:134](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L134) +Defined in: [calendar/date-core.ts:135](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L135) #### Parameters @@ -295,7 +295,7 @@ Defined in: [calendar/date-core.ts:134](https://github.com/TanStack/time/blob/ma protected getCalendarDays(): PlainDate[]; ``` -Defined in: [calendar/calendar.ts:148](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L148) +Defined in: [calendar/calendar.ts:164](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L164) #### Returns @@ -313,7 +313,7 @@ Defined in: [calendar/calendar.ts:148](https://github.com/TanStack/time/blob/mai getDaysNames(weekday): string[]; ``` -Defined in: [calendar/date-core.ts:243](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L243) +Defined in: [calendar/date-core.ts:254](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L254) #### Parameters @@ -343,7 +343,7 @@ CalendarActions.getDaysNames getDaysWithEvents(): object[]; ``` -Defined in: [calendar/calendar.ts:185](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L185) +Defined in: [calendar/calendar.ts:201](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L201) #### Returns @@ -357,7 +357,7 @@ Defined in: [calendar/calendar.ts:185](https://github.com/TanStack/time/blob/mai getEventProps(event): object; ``` -Defined in: [calendar/calendar.ts:206](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L206) +Defined in: [calendar/calendar.ts:223](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L223) Retrieves styling properties for a specific event. @@ -439,7 +439,7 @@ CalendarActions.getEventProps getEventsByDate(date): TEvent[]; ``` -Defined in: [calendar/calendar.ts:234](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L234) +Defined in: [calendar/calendar.ts:251](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L251) Retrieves events for a specific date. @@ -467,7 +467,7 @@ CalendarActions.getEventsByDate protected getFirstDayOfMonth(): PlainDate; ``` -Defined in: [calendar/date-core.ts:142](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L142) +Defined in: [calendar/date-core.ts:143](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L143) #### Returns @@ -485,7 +485,7 @@ Defined in: [calendar/date-core.ts:142](https://github.com/TanStack/time/blob/ma protected getFirstDayOfWeek(): PlainDate; ``` -Defined in: [calendar/date-core.ts:150](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L150) +Defined in: [calendar/date-core.ts:151](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L151) #### Returns @@ -503,7 +503,7 @@ Defined in: [calendar/date-core.ts:150](https://github.com/TanStack/time/blob/ma getTimeSlots(options?): TimeSlot[]; ``` -Defined in: [calendar/calendar.ts:230](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L230) +Defined in: [calendar/calendar.ts:247](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L247) Retrieves time slots for day view with configurable intervals. @@ -525,13 +525,92 @@ CalendarActions.getTimeSlots *** +### getUnavailabilityDetails() + +```ts +getUnavailabilityDetails( + date, + startMinutes, + endMinutes, + options?): object[]; +``` + +Defined in: [calendar/calendar.ts:437](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L437) + +Get detailed unavailability information for a specific time range on a date +Returns which resources are unavailable and why + +#### Parameters + +##### date + +`string` + +##### startMinutes + +`number` + +##### endMinutes + +`number` + +##### options? + +###### resourceIds? + +`TResource`\[`"id"`\][] + +#### Returns + +`object`[] + +*** + +### getUnavailableRanges() + +```ts +getUnavailableRanges(date, options?): UnavailableRange[]; +``` + +Defined in: [calendar/calendar.ts:325](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L325) + +Retrieves unavailable time ranges for a specific date based on resource availability. + +#### Parameters + +##### date + +`string` + +##### options? + +###### containerHeight? + +`number` + +###### resourceIds? + +`TResource`\[`"id"`\][] + +#### Returns + +[`UnavailableRange`](../interfaces/UnavailableRange.md)[] + +#### Implementation of + +```ts +CalendarActions.getUnavailableRanges +``` + +*** + ### getWeekStartsOn() ```ts getWeekStartsOn(): number; ``` -Defined in: [calendar/date-core.ts:157](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L157) +Defined in: [calendar/date-core.ts:158](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L158) #### Returns @@ -549,7 +628,7 @@ Defined in: [calendar/date-core.ts:157](https://github.com/TanStack/time/blob/ma goToCurrentPeriod(): void; ``` -Defined in: [calendar/date-core.ts:347](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L347) +Defined in: [calendar/date-core.ts:375](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L375) #### Returns @@ -573,7 +652,7 @@ CalendarActions.goToCurrentPeriod goToNextPeriod(): void; ``` -Defined in: [calendar/date-core.ts:304](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L304) +Defined in: [calendar/date-core.ts:327](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L327) #### Returns @@ -597,7 +676,7 @@ CalendarActions.goToNextPeriod goToPreviousPeriod(): void; ``` -Defined in: [calendar/date-core.ts:261](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L261) +Defined in: [calendar/date-core.ts:279](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L279) #### Returns @@ -621,7 +700,7 @@ CalendarActions.goToPreviousPeriod goToSpecificPeriod(date): void; ``` -Defined in: [calendar/date-core.ts:360](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L360) +Defined in: [calendar/date-core.ts:393](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L393) #### Parameters @@ -651,7 +730,7 @@ CalendarActions.goToSpecificPeriod groupDaysBy(__namedParameters): (Day | null)[][]; ``` -Defined in: [calendar/calendar.ts:212](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L212) +Defined in: [calendar/calendar.ts:229](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L229) Groups days by a specified unit. @@ -689,7 +768,7 @@ CalendarActions.groupDaysBy removeEvent(id): void; ``` -Defined in: [calendar/calendar.ts:259](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L259) +Defined in: [calendar/calendar.ts:302](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L302) Removes an event by ID. @@ -717,7 +796,7 @@ CalendarActions.removeEvent updateEvent(id, updates): void; ``` -Defined in: [calendar/calendar.ts:249](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L249) +Defined in: [calendar/calendar.ts:277](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L277) Updates an existing event by ID. diff --git a/docs/reference/classes/DateCore.md b/docs/reference/classes/DateCore.md index 79c899e5..f791e635 100644 --- a/docs/reference/classes/DateCore.md +++ b/docs/reference/classes/DateCore.md @@ -5,7 +5,7 @@ title: DateCore # Abstract Class: DateCore -Defined in: [calendar/date-core.ts:77](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L77) +Defined in: [calendar/date-core.ts:78](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L78) ## Extended by @@ -39,7 +39,7 @@ Defined in: [calendar/date-core.ts:86](https://github.com/TanStack/time/blob/mai formatters: object; ``` -Defined in: [calendar/date-core.ts:80](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L80) +Defined in: [calendar/date-core.ts:81](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L81) #### date @@ -67,7 +67,7 @@ time: DateTimeFormat; options: ParsedDateCoreOptions; ``` -Defined in: [calendar/date-core.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L79) +Defined in: [calendar/date-core.ts:80](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L80) *** @@ -77,7 +77,7 @@ Defined in: [calendar/date-core.ts:79](https://github.com/TanStack/time/blob/mai store: Store; ``` -Defined in: [calendar/date-core.ts:78](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L78) +Defined in: [calendar/date-core.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L79) ## Methods @@ -87,7 +87,7 @@ Defined in: [calendar/date-core.ts:78](https://github.com/TanStack/time/blob/mai canGoNextPeriod(): boolean; ``` -Defined in: [calendar/date-core.ts:407](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L407) +Defined in: [calendar/date-core.ts:445](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L445) #### Returns @@ -101,7 +101,7 @@ Defined in: [calendar/date-core.ts:407](https://github.com/TanStack/time/blob/ma canGoPreviousPeriod(): boolean; ``` -Defined in: [calendar/date-core.ts:376](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L376) +Defined in: [calendar/date-core.ts:414](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L414) #### Returns @@ -115,7 +115,7 @@ Defined in: [calendar/date-core.ts:376](https://github.com/TanStack/time/blob/ma changeViewMode(newViewMode): void; ``` -Defined in: [calendar/date-core.ts:254](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L254) +Defined in: [calendar/date-core.ts:265](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L265) #### Parameters @@ -135,7 +135,7 @@ Defined in: [calendar/date-core.ts:254](https://github.com/TanStack/time/blob/ma formatDate(date): string; ``` -Defined in: [calendar/date-core.ts:130](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L130) +Defined in: [calendar/date-core.ts:131](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L131) #### Parameters @@ -155,7 +155,7 @@ Defined in: [calendar/date-core.ts:130](https://github.com/TanStack/time/blob/ma formatDateTime(date): string; ``` -Defined in: [calendar/date-core.ts:138](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L138) +Defined in: [calendar/date-core.ts:139](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L139) #### Parameters @@ -175,7 +175,7 @@ Defined in: [calendar/date-core.ts:138](https://github.com/TanStack/time/blob/ma formatTime(date): string; ``` -Defined in: [calendar/date-core.ts:134](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L134) +Defined in: [calendar/date-core.ts:135](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L135) #### Parameters @@ -195,7 +195,7 @@ Defined in: [calendar/date-core.ts:134](https://github.com/TanStack/time/blob/ma protected getCalendarDays(): PlainDate[]; ``` -Defined in: [calendar/date-core.ts:161](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L161) +Defined in: [calendar/date-core.ts:162](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L162) #### Returns @@ -209,7 +209,7 @@ Defined in: [calendar/date-core.ts:161](https://github.com/TanStack/time/blob/ma getDaysNames(weekday): string[]; ``` -Defined in: [calendar/date-core.ts:243](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L243) +Defined in: [calendar/date-core.ts:254](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L254) #### Parameters @@ -229,7 +229,7 @@ Defined in: [calendar/date-core.ts:243](https://github.com/TanStack/time/blob/ma protected getFirstDayOfMonth(): PlainDate; ``` -Defined in: [calendar/date-core.ts:142](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L142) +Defined in: [calendar/date-core.ts:143](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L143) #### Returns @@ -243,7 +243,7 @@ Defined in: [calendar/date-core.ts:142](https://github.com/TanStack/time/blob/ma protected getFirstDayOfWeek(): PlainDate; ``` -Defined in: [calendar/date-core.ts:150](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L150) +Defined in: [calendar/date-core.ts:151](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L151) #### Returns @@ -257,7 +257,7 @@ Defined in: [calendar/date-core.ts:150](https://github.com/TanStack/time/blob/ma getWeekStartsOn(): number; ``` -Defined in: [calendar/date-core.ts:157](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L157) +Defined in: [calendar/date-core.ts:158](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L158) #### Returns @@ -271,7 +271,7 @@ Defined in: [calendar/date-core.ts:157](https://github.com/TanStack/time/blob/ma goToCurrentPeriod(): void; ``` -Defined in: [calendar/date-core.ts:347](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L347) +Defined in: [calendar/date-core.ts:375](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L375) #### Returns @@ -285,7 +285,7 @@ Defined in: [calendar/date-core.ts:347](https://github.com/TanStack/time/blob/ma goToNextPeriod(): void; ``` -Defined in: [calendar/date-core.ts:304](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L304) +Defined in: [calendar/date-core.ts:327](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L327) #### Returns @@ -299,7 +299,7 @@ Defined in: [calendar/date-core.ts:304](https://github.com/TanStack/time/blob/ma goToPreviousPeriod(): void; ``` -Defined in: [calendar/date-core.ts:261](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L261) +Defined in: [calendar/date-core.ts:279](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L279) #### Returns @@ -313,7 +313,7 @@ Defined in: [calendar/date-core.ts:261](https://github.com/TanStack/time/blob/ma goToSpecificPeriod(date): void; ``` -Defined in: [calendar/date-core.ts:360](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L360) +Defined in: [calendar/date-core.ts:393](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L393) #### Parameters diff --git a/docs/reference/functions/calculateDeltaMinutesFromPixels.md b/docs/reference/functions/calculateDeltaMinutesFromPixels.md new file mode 100644 index 00000000..aff7522d --- /dev/null +++ b/docs/reference/functions/calculateDeltaMinutesFromPixels.md @@ -0,0 +1,33 @@ +--- +id: calculateDeltaMinutesFromPixels +title: calculateDeltaMinutesFromPixels +--- + +# Function: calculateDeltaMinutesFromPixels() + +```ts +function calculateDeltaMinutesFromPixels( + deltaPixels, + containerHeight, + minutesInDay): number; +``` + +Defined in: [calendar/getResizeProps.ts:164](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L164) + +## Parameters + +### deltaPixels + +`number` + +### containerHeight + +`number` + +### minutesInDay + +`number` = `...` + +## Returns + +`number` diff --git a/docs/reference/functions/calculateGhostPreviewStyle.md b/docs/reference/functions/calculateGhostPreviewStyle.md new file mode 100644 index 00000000..64389403 --- /dev/null +++ b/docs/reference/functions/calculateGhostPreviewStyle.md @@ -0,0 +1,24 @@ +--- +id: calculateGhostPreviewStyle +title: calculateGhostPreviewStyle +--- + +# Function: calculateGhostPreviewStyle() + +```ts +function calculateGhostPreviewStyle(options): PositionStyle | null; +``` + +Defined in: [calendar/getResizeProps.ts:368](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L368) + +Calculates the ghost preview style for a day that doesn't have an existing segment + +## Parameters + +### options + +[`GhostPreviewOptions`](../interfaces/GhostPreviewOptions.md) + +## Returns + +[`PositionStyle`](../interfaces/PositionStyle.md) \| `null` diff --git a/docs/reference/functions/calculateResizedEvent.md b/docs/reference/functions/calculateResizedEvent.md new file mode 100644 index 00000000..174368fc --- /dev/null +++ b/docs/reference/functions/calculateResizedEvent.md @@ -0,0 +1,22 @@ +--- +id: calculateResizedEvent +title: calculateResizedEvent +--- + +# Function: calculateResizedEvent() + +```ts +function calculateResizedEvent(options): ResizedEventResult; +``` + +Defined in: [calendar/getResizeProps.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L58) + +## Parameters + +### options + +`CalculateResizedEventOptions` + +## Returns + +`ResizedEventResult` diff --git a/docs/reference/functions/calculateSegmentResizePreview.md b/docs/reference/functions/calculateSegmentResizePreview.md new file mode 100644 index 00000000..f72c89a9 --- /dev/null +++ b/docs/reference/functions/calculateSegmentResizePreview.md @@ -0,0 +1,24 @@ +--- +id: calculateSegmentResizePreview +title: calculateSegmentResizePreview +--- + +# Function: calculateSegmentResizePreview() + +```ts +function calculateSegmentResizePreview(options): SegmentResizePreview; +``` + +Defined in: [calendar/getResizeProps.ts:288](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L288) + +Calculates the resize preview state for a segment on a specific day + +## Parameters + +### options + +[`ResizePreviewOptions`](../interfaces/ResizePreviewOptions.md) + +## Returns + +[`SegmentResizePreview`](../interfaces/SegmentResizePreview.md) diff --git a/docs/reference/functions/formatEventTimeRange.md b/docs/reference/functions/formatEventTimeRange.md new file mode 100644 index 00000000..89fc1f90 --- /dev/null +++ b/docs/reference/functions/formatEventTimeRange.md @@ -0,0 +1,37 @@ +--- +id: formatEventTimeRange +title: formatEventTimeRange +--- + +# Function: formatEventTimeRange() + +```ts +function formatEventTimeRange( + start, + end, + options): FormattedEventTime; +``` + +Defined in: [calendar/getResizeProps.ts:493](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L493) + +Formats an event's time range for display +For multi-day events: includes date and time +For single-day events: includes only time (unless alwaysShowDate is true) + +## Parameters + +### start + +`string` + +### end + +`string` + +### options + +[`FormatEventTimeOptions`](../interfaces/FormatEventTimeOptions.md) = `{}` + +## Returns + +[`FormattedEventTime`](../interfaces/FormattedEventTime.md) diff --git a/docs/reference/functions/getEventDisplayTimeRange.md b/docs/reference/functions/getEventDisplayTimeRange.md new file mode 100644 index 00000000..ae349ea1 --- /dev/null +++ b/docs/reference/functions/getEventDisplayTimeRange.md @@ -0,0 +1,42 @@ +--- +id: getEventDisplayTimeRange +title: getEventDisplayTimeRange +--- + +# Function: getEventDisplayTimeRange() + +```ts +function getEventDisplayTimeRange(options): EventTimeRange; +``` + +Defined in: [calendar/getResizeProps.ts:444](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L444) + +Gets the time range to display for an event, considering resize state + +## Parameters + +### options + +#### isBeingResized? + +`boolean` + +#### originalEnd + +`string` + +#### originalStart + +`string` + +#### previewEnd? + +`string` + +#### previewStart? + +`string` + +## Returns + +[`EventTimeRange`](../interfaces/EventTimeRange.md) diff --git a/docs/reference/functions/getResizeHandleStyle.md b/docs/reference/functions/getResizeHandleStyle.md new file mode 100644 index 00000000..0807e264 --- /dev/null +++ b/docs/reference/functions/getResizeHandleStyle.md @@ -0,0 +1,22 @@ +--- +id: getResizeHandleStyle +title: getResizeHandleStyle +--- + +# Function: getResizeHandleStyle() + +```ts +function getResizeHandleStyle(edge): ResizeHandleStyle; +``` + +Defined in: [calendar/getResizeProps.ts:183](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L183) + +## Parameters + +### edge + +[`ResizeEdge`](../type-aliases/ResizeEdge.md) + +## Returns + +[`ResizeHandleStyle`](../interfaces/ResizeHandleStyle.md) diff --git a/docs/reference/functions/getSegmentInfo.md b/docs/reference/functions/getSegmentInfo.md new file mode 100644 index 00000000..55347ea7 --- /dev/null +++ b/docs/reference/functions/getSegmentInfo.md @@ -0,0 +1,36 @@ +--- +id: getSegmentInfo +title: getSegmentInfo +--- + +# Function: getSegmentInfo() + +```ts +function getSegmentInfo(event): SegmentInfo; +``` + +Defined in: [calendar/getResizeProps.ts:219](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L219) + +## Parameters + +### event + +#### _originalEnd? + +`string` + +#### _originalStart? + +`string` + +#### end + +`string` + +#### start + +`string` + +## Returns + +[`SegmentInfo`](../interfaces/SegmentInfo.md) diff --git a/docs/reference/functions/getTimeClient.md b/docs/reference/functions/getTimeClient.md new file mode 100644 index 00000000..f76050b5 --- /dev/null +++ b/docs/reference/functions/getTimeClient.md @@ -0,0 +1,18 @@ +--- +id: getTimeClient +title: getTimeClient +--- + +# Function: getTimeClient() + +```ts +function getTimeClient(): TimeClient; +``` + +Defined in: [client/TimeClient.ts:86](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L86) + +Get the global TimeClient instance + +## Returns + +`TimeClient` diff --git a/docs/reference/functions/groupDaysBy.md b/docs/reference/functions/groupDaysBy.md index 1a8edc1e..85f7a639 100644 --- a/docs/reference/functions/groupDaysBy.md +++ b/docs/reference/functions/groupDaysBy.md @@ -9,7 +9,7 @@ title: groupDaysBy function groupDaysBy(__namedParameters): (Day | null)[][]; ``` -Defined in: [calendar/groupDaysBy.ts:36](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/groupDaysBy.ts#L36) +Defined in: [calendar/groupDaysBy.ts:37](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/groupDaysBy.ts#L37) ## Type Parameters diff --git a/docs/reference/functions/isMultiDayEvent.md b/docs/reference/functions/isMultiDayEvent.md new file mode 100644 index 00000000..1c0b4cb5 --- /dev/null +++ b/docs/reference/functions/isMultiDayEvent.md @@ -0,0 +1,28 @@ +--- +id: isMultiDayEvent +title: isMultiDayEvent +--- + +# Function: isMultiDayEvent() + +```ts +function isMultiDayEvent(start, end): boolean; +``` + +Defined in: [calendar/getResizeProps.ts:429](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L429) + +Checks if an event spans multiple days + +## Parameters + +### start + +`string` + +### end + +`string` + +## Returns + +`boolean` diff --git a/docs/reference/functions/isWeekend.md b/docs/reference/functions/isWeekend.md index ef5c58fd..152c2758 100644 --- a/docs/reference/functions/isWeekend.md +++ b/docs/reference/functions/isWeekend.md @@ -9,7 +9,7 @@ title: isWeekend function isWeekend(date, options?): boolean; ``` -Defined in: [date/isWeekend/isWeekend.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L13) +Defined in: [date/isWeekend/isWeekend.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L14) isWeekend Returns true if the date falls on a weekend based on locale-specific week info diff --git a/docs/reference/index.md b/docs/reference/index.md index e0b5468f..808f66d9 100644 --- a/docs/reference/index.md +++ b/docs/reference/index.md @@ -13,6 +13,8 @@ title: "@tanstack/time" ## Interfaces - [AddOptions](interfaces/AddOptions.md) +- [Availability](interfaces/Availability.md) +- [AvailabilityConflict](interfaces/AvailabilityConflict.md) - [CalendarApi](interfaces/CalendarApi.md) - [CalendarCoreOptions](interfaces/CalendarCoreOptions.md) - [CalendarStore](interfaces/CalendarStore.md) @@ -22,7 +24,11 @@ title: "@tanstack/time" - [EndOfOptions](interfaces/EndOfOptions.md) - [EqualsOptions](interfaces/EqualsOptions.md) - [Event](interfaces/Event.md) +- [EventTimeRange](interfaces/EventTimeRange.md) - [FormatDateOptions](interfaces/FormatDateOptions.md) +- [FormatEventTimeOptions](interfaces/FormatEventTimeOptions.md) +- [FormattedEventTime](interfaces/FormattedEventTime.md) +- [GhostPreviewOptions](interfaces/GhostPreviewOptions.md) - [IntersectsOptions](interfaces/IntersectsOptions.md) - [IsAfterOptions](interfaces/IsAfterOptions.md) - [IsBeforeOptions](interfaces/IsBeforeOptions.md) @@ -32,14 +38,26 @@ title: "@tanstack/time" - [IsSameOrBeforeOptions](interfaces/IsSameOrBeforeOptions.md) - [IsWeekendOptions](interfaces/IsWeekendOptions.md) - [ParsedDateCoreOptions](interfaces/ParsedDateCoreOptions.md) +- [PositionStyle](interfaces/PositionStyle.md) - [Range](interfaces/Range.md) - [RangeOptions](interfaces/RangeOptions.md) +- [ResizeConstraints](interfaces/ResizeConstraints.md) +- [ResizeError](interfaces/ResizeError.md) +- [ResizeHandleStyle](interfaces/ResizeHandleStyle.md) +- [ResizePreviewOptions](interfaces/ResizePreviewOptions.md) +- [ResizeValidationResult](interfaces/ResizeValidationResult.md) - [Resource](interfaces/Resource.md) - [RoundOptions](interfaces/RoundOptions.md) +- [SegmentInfo](interfaces/SegmentInfo.md) +- [SegmentResizePreview](interfaces/SegmentResizePreview.md) - [SinceOptions](interfaces/SinceOptions.md) - [StartOfOptions](interfaces/StartOfOptions.md) - [SubtractOptions](interfaces/SubtractOptions.md) +- [TimeEventMap](interfaces/TimeEventMap.md) - [TimeSlot](interfaces/TimeSlot.md) +- [UnavailabilityReason](interfaces/UnavailabilityReason.md) +- [UnavailableRange](interfaces/UnavailableRange.md) +- [UnavailableTimeRange](interfaces/UnavailableTimeRange.md) - [UntilOptions](interfaces/UntilOptions.md) - [ViewMode](interfaces/ViewMode.md) @@ -54,17 +72,27 @@ title: "@tanstack/time" - [GroupDaysByProps](type-aliases/GroupDaysByProps.md) - [IsSameOrAfterUnit](type-aliases/IsSameOrAfterUnit.md) - [IsSameOrBeforeUnit](type-aliases/IsSameOrBeforeUnit.md) +- [ResizeEdge](type-aliases/ResizeEdge.md) - [RoundUnit](type-aliases/RoundUnit.md) - [StartOfUnit](type-aliases/StartOfUnit.md) ## Functions - [add](functions/add.md) +- [calculateDeltaMinutesFromPixels](functions/calculateDeltaMinutesFromPixels.md) +- [calculateGhostPreviewStyle](functions/calculateGhostPreviewStyle.md) +- [calculateResizedEvent](functions/calculateResizedEvent.md) +- [calculateSegmentResizePreview](functions/calculateSegmentResizePreview.md) - [endOf](functions/endOf.md) - [equals](functions/equals.md) - [format](functions/format.md) +- [formatEventTimeRange](functions/formatEventTimeRange.md) - [generateDateRange](functions/generateDateRange.md) +- [getEventDisplayTimeRange](functions/getEventDisplayTimeRange.md) - [getEventProps](functions/getEventProps.md) +- [getResizeHandleStyle](functions/getResizeHandleStyle.md) +- [getSegmentInfo](functions/getSegmentInfo.md) +- [getTimeClient](functions/getTimeClient.md) - [getTimeSlots](functions/getTimeSlots.md) - [groupDaysBy](functions/groupDaysBy.md) - [intersects](functions/intersects.md) @@ -72,6 +100,7 @@ title: "@tanstack/time" - [isBefore](functions/isBefore.md) - [isBetween](functions/isBetween.md) - [isLeapYear](functions/isLeapYear.md) +- [isMultiDayEvent](functions/isMultiDayEvent.md) - [isSameOrAfter](functions/isSameOrAfter.md) - [isSameOrBefore](functions/isSameOrBefore.md) - [isWeekend](functions/isWeekend.md) diff --git a/docs/reference/interfaces/Availability.md b/docs/reference/interfaces/Availability.md new file mode 100644 index 00000000..1d9c4376 --- /dev/null +++ b/docs/reference/interfaces/Availability.md @@ -0,0 +1,44 @@ +--- +id: Availability +title: Availability +--- + +# Interface: Availability + +Defined in: [calendar/types.ts:4](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L4) + +## Properties + +### endTime + +```ts +endTime: string; +``` + +Defined in: [calendar/types.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L10) + +End time in HH:mm format + +*** + +### startTime + +```ts +startTime: string; +``` + +Defined in: [calendar/types.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L8) + +Start time in HH:mm format + +*** + +### weekdays + +```ts +weekdays: number[]; +``` + +Defined in: [calendar/types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L6) + +Days of the week when available (ISO weekday: 1 = Monday, ..., 7 = Sunday) diff --git a/docs/reference/interfaces/AvailabilityConflict.md b/docs/reference/interfaces/AvailabilityConflict.md new file mode 100644 index 00000000..0c4f5619 --- /dev/null +++ b/docs/reference/interfaces/AvailabilityConflict.md @@ -0,0 +1,82 @@ +--- +id: AvailabilityConflict +title: AvailabilityConflict +--- + +# Interface: AvailabilityConflict + +Defined in: [calendar/types.ts:109](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L109) + +Information about a specific availability conflict + +## Properties + +### conflictRange + +```ts +conflictRange: object; +``` + +Defined in: [calendar/types.ts:113](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L113) + +Time range that conflicts with availability + +#### end + +```ts +end: string; +``` + +#### start + +```ts +start: string; +``` + +*** + +### date + +```ts +date: string; +``` + +Defined in: [calendar/types.ts:111](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L111) + +The date where the conflict occurred (YYYY-MM-DD) + +*** + +### description + +```ts +description: string; +``` + +Defined in: [calendar/types.ts:122](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L122) + +Human-readable description of the conflict + +*** + +### resourceDetails + +```ts +resourceDetails: UnavailabilityReason[]; +``` + +Defined in: [calendar/types.ts:120](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L120) + +Detailed reasons for each resource + +*** + +### resourceIds + +```ts +resourceIds: string[]; +``` + +Defined in: [calendar/types.ts:118](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L118) + +The resource(s) whose availability is being violated diff --git a/docs/reference/interfaces/CalendarApi.md b/docs/reference/interfaces/CalendarApi.md index dddfd41f..f9b12cae 100644 --- a/docs/reference/interfaces/CalendarApi.md +++ b/docs/reference/interfaces/CalendarApi.md @@ -5,7 +5,7 @@ title: CalendarApi # Interface: CalendarApi\ -Defined in: [calendar/calendar.ts:110](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L110) +Defined in: [calendar/calendar.ts:126](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L126) ## Extends @@ -29,7 +29,7 @@ Defined in: [calendar/calendar.ts:110](https://github.com/TanStack/time/blob/mai activeDate: string; ``` -Defined in: [calendar/calendar.ts:103](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L103) +Defined in: [calendar/calendar.ts:119](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L119) The currently active date in the calendar. @@ -47,7 +47,7 @@ ConvertTemporalToString.activeDate addEvent: (event) => void; ``` -Defined in: [calendar/calendar.ts:85](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L85) +Defined in: [calendar/calendar.ts:93](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L93) Adds a new event to the calendar. @@ -75,7 +75,7 @@ CalendarActions.addEvent canGoNextPeriod: () => boolean; ``` -Defined in: [calendar/calendar.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L54) +Defined in: [calendar/calendar.ts:62](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L62) Checks if navigation to the next period is allowed within the range. @@ -97,7 +97,7 @@ CalendarActions.canGoNextPeriod canGoPreviousPeriod: () => boolean; ``` -Defined in: [calendar/calendar.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L52) +Defined in: [calendar/calendar.ts:60](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L60) Checks if navigation to the previous period is allowed within the range. @@ -119,7 +119,7 @@ CalendarActions.canGoPreviousPeriod changeViewMode: (newViewMode) => void; ``` -Defined in: [calendar/calendar.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L56) +Defined in: [calendar/calendar.ts:64](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L64) Changes the current view mode of the calendar. @@ -147,7 +147,7 @@ CalendarActions.changeViewMode currentPeriod: string; ``` -Defined in: [calendar/calendar.ts:97](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L97) +Defined in: [calendar/calendar.ts:113](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L113) The currently focused date period in the calendar. @@ -165,7 +165,7 @@ ConvertTemporalToString.currentPeriod days: Day[]; ``` -Defined in: [calendar/calendar.ts:101](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L101) +Defined in: [calendar/calendar.ts:117](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L117) An array of days, each potentially containing events. @@ -183,7 +183,7 @@ ConvertTemporalToString.days getDaysNames: (weekday?) => string[]; ``` -Defined in: [calendar/calendar.ts:71](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L71) +Defined in: [calendar/calendar.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L79) Retrieves the names of the days of the week, based on the current locale. @@ -211,7 +211,7 @@ CalendarActions.getDaysNames getEventProps: (event) => object; ``` -Defined in: [calendar/calendar.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L58) +Defined in: [calendar/calendar.ts:66](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L66) Retrieves styling properties for a specific event. @@ -293,7 +293,7 @@ CalendarActions.getEventProps getEventsByDate: (date) => TEvent[]; ``` -Defined in: [calendar/calendar.ts:83](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L83) +Defined in: [calendar/calendar.ts:91](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L91) Retrieves events for a specific date. @@ -321,7 +321,7 @@ CalendarActions.getEventsByDate getTimeSlots: (options?) => TimeSlot[]; ``` -Defined in: [calendar/calendar.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L79) +Defined in: [calendar/calendar.ts:87](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L87) Retrieves time slots for day view with configurable intervals. @@ -343,13 +343,51 @@ CalendarActions.getTimeSlots *** +### getUnavailableRanges() + +```ts +getUnavailableRanges: (date, options?) => UnavailableRange[]; +``` + +Defined in: [calendar/calendar.ts:99](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L99) + +Retrieves unavailable time ranges for a specific date based on resource availability. + +#### Parameters + +##### date + +`string` + +##### options? + +###### containerHeight? + +`number` + +###### resourceIds? + +`TResource`\[`"id"`\][] + +#### Returns + +[`UnavailableRange`](UnavailableRange.md)[] + +#### Inherited from + +```ts +CalendarActions.getUnavailableRanges +``` + +*** + ### goToCurrentPeriod() ```ts goToCurrentPeriod: () => void; ``` -Defined in: [calendar/calendar.ts:48](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L48) +Defined in: [calendar/calendar.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L56) Resets the view to the current period based on today's date. @@ -371,7 +409,7 @@ CalendarActions.goToCurrentPeriod goToNextPeriod: () => void; ``` -Defined in: [calendar/calendar.ts:46](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L46) +Defined in: [calendar/calendar.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L54) Navigates to the next period according to the current view mode. @@ -393,7 +431,7 @@ CalendarActions.goToNextPeriod goToPreviousPeriod: () => void; ``` -Defined in: [calendar/calendar.ts:44](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L44) +Defined in: [calendar/calendar.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L52) Navigates to the previous period according to the current view mode. @@ -415,7 +453,7 @@ CalendarActions.goToPreviousPeriod goToSpecificPeriod: (date) => void; ``` -Defined in: [calendar/calendar.ts:50](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L50) +Defined in: [calendar/calendar.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L58) Navigates to a specific date. @@ -443,7 +481,7 @@ CalendarActions.goToSpecificPeriod groupDaysBy: (props) => (Day | null)[][]; ``` -Defined in: [calendar/calendar.ts:73](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L73) +Defined in: [calendar/calendar.ts:81](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L81) Groups days by a specified unit. @@ -481,7 +519,7 @@ CalendarActions.groupDaysBy removeEvent: (id) => void; ``` -Defined in: [calendar/calendar.ts:89](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L89) +Defined in: [calendar/calendar.ts:97](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L97) Removes an event by ID. @@ -509,7 +547,7 @@ CalendarActions.removeEvent updateEvent: (id, updates) => void; ``` -Defined in: [calendar/calendar.ts:87](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L87) +Defined in: [calendar/calendar.ts:95](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L95) Updates an existing event by ID. @@ -541,7 +579,7 @@ CalendarActions.updateEvent viewMode: ViewMode; ``` -Defined in: [calendar/calendar.ts:99](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L99) +Defined in: [calendar/calendar.ts:115](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L115) The current view mode of the calendar. diff --git a/docs/reference/interfaces/CalendarCoreOptions.md b/docs/reference/interfaces/CalendarCoreOptions.md index 4a4efd9e..3b65ec9b 100644 --- a/docs/reference/interfaces/CalendarCoreOptions.md +++ b/docs/reference/interfaces/CalendarCoreOptions.md @@ -5,7 +5,7 @@ title: CalendarCoreOptions # Interface: CalendarCoreOptions\ -Defined in: [calendar/calendar.ts:24](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L24) +Defined in: [calendar/calendar.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L32) Configuration options for initializing a CalendarCore instance, allowing customization of events, locale, time zone, and the calendar system. @@ -34,7 +34,7 @@ Specifies the event type, extending a base Event type. optional calendar: CalendarLike; ``` -Defined in: [calendar/date-core.ts:59](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L59) +Defined in: [calendar/date-core.ts:60](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L60) Optional calendar system to be used. @@ -50,7 +50,7 @@ Optional calendar system to be used. optional dateFormatter: DateTimeFormat; ``` -Defined in: [calendar/date-core.ts:63](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L63) +Defined in: [calendar/date-core.ts:64](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L64) Optional date formatter. @@ -66,7 +66,7 @@ Optional date formatter. optional dateTimeFormatter: DateTimeFormat; ``` -Defined in: [calendar/date-core.ts:67](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L67) +Defined in: [calendar/date-core.ts:68](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L68) Optional date time formatter. @@ -82,7 +82,7 @@ Optional date time formatter. optional events: TEvent[] | null; ``` -Defined in: [calendar/calendar.ts:29](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L29) +Defined in: [calendar/calendar.ts:37](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L37) An optional array of events to be handled by the calendar. @@ -94,7 +94,7 @@ An optional array of events to be handled by the calendar. optional locale: string; ``` -Defined in: [calendar/date-core.ts:55](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L55) +Defined in: [calendar/date-core.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L56) Optional locale for date formatting. Uses a BCP 47 language tag. @@ -110,7 +110,7 @@ Optional locale for date formatting. Uses a BCP 47 language tag. optional range: DateRange; ``` -Defined in: [calendar/date-core.ts:61](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L61) +Defined in: [calendar/date-core.ts:62](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L62) Optional range of dates to be used. @@ -126,7 +126,7 @@ Optional range of dates to be used. optional resources: TResource[] | null; ``` -Defined in: [calendar/calendar.ts:31](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L31) +Defined in: [calendar/calendar.ts:39](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L39) Optional resources to be used in the calendar. @@ -138,7 +138,7 @@ Optional resources to be used in the calendar. optional timeFormatter: DateTimeFormat; ``` -Defined in: [calendar/date-core.ts:65](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L65) +Defined in: [calendar/date-core.ts:66](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L66) Optional time formatter. @@ -154,7 +154,7 @@ Optional time formatter. optional timeZone: TimeZoneLike; ``` -Defined in: [calendar/date-core.ts:57](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L57) +Defined in: [calendar/date-core.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L58) Optional time zone specification. @@ -170,7 +170,7 @@ Optional time zone specification. viewMode: ViewMode; ``` -Defined in: [calendar/date-core.ts:53](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L53) +Defined in: [calendar/date-core.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L54) The initial view mode configuration. diff --git a/docs/reference/interfaces/CalendarStore.md b/docs/reference/interfaces/CalendarStore.md index 150c7148..87a2dbaa 100644 --- a/docs/reference/interfaces/CalendarStore.md +++ b/docs/reference/interfaces/CalendarStore.md @@ -5,7 +5,7 @@ title: CalendarStore # Interface: CalendarStore -Defined in: [calendar/types.ts:49](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L49) +Defined in: [calendar/types.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L79) ## Properties @@ -15,7 +15,7 @@ Defined in: [calendar/types.ts:49](https://github.com/TanStack/time/blob/main/pa activeDate: PlainDate; ``` -Defined in: [calendar/types.ts:51](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L51) +Defined in: [calendar/types.ts:81](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L81) *** @@ -25,7 +25,17 @@ Defined in: [calendar/types.ts:51](https://github.com/TanStack/time/blob/main/pa currentPeriod: PlainDate; ``` -Defined in: [calendar/types.ts:50](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L50) +Defined in: [calendar/types.ts:80](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L80) + +*** + +### eventsVersion + +```ts +eventsVersion: number; +``` + +Defined in: [calendar/types.ts:83](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L83) *** @@ -35,4 +45,4 @@ Defined in: [calendar/types.ts:50](https://github.com/TanStack/time/blob/main/pa viewMode: ViewMode; ``` -Defined in: [calendar/types.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L52) +Defined in: [calendar/types.ts:82](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L82) diff --git a/docs/reference/interfaces/DateCoreOptions.md b/docs/reference/interfaces/DateCoreOptions.md index 689222cf..267fd3e3 100644 --- a/docs/reference/interfaces/DateCoreOptions.md +++ b/docs/reference/interfaces/DateCoreOptions.md @@ -5,7 +5,7 @@ title: DateCoreOptions # Interface: DateCoreOptions -Defined in: [calendar/date-core.ts:51](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L51) +Defined in: [calendar/date-core.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L52) Base options interface for date-related core classes. @@ -21,7 +21,7 @@ Base options interface for date-related core classes. optional calendar: CalendarLike; ``` -Defined in: [calendar/date-core.ts:59](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L59) +Defined in: [calendar/date-core.ts:60](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L60) Optional calendar system to be used. @@ -33,7 +33,7 @@ Optional calendar system to be used. optional dateFormatter: DateTimeFormat; ``` -Defined in: [calendar/date-core.ts:63](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L63) +Defined in: [calendar/date-core.ts:64](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L64) Optional date formatter. @@ -45,7 +45,7 @@ Optional date formatter. optional dateTimeFormatter: DateTimeFormat; ``` -Defined in: [calendar/date-core.ts:67](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L67) +Defined in: [calendar/date-core.ts:68](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L68) Optional date time formatter. @@ -57,7 +57,7 @@ Optional date time formatter. optional locale: string; ``` -Defined in: [calendar/date-core.ts:55](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L55) +Defined in: [calendar/date-core.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L56) Optional locale for date formatting. Uses a BCP 47 language tag. @@ -69,7 +69,7 @@ Optional locale for date formatting. Uses a BCP 47 language tag. optional range: DateRange; ``` -Defined in: [calendar/date-core.ts:61](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L61) +Defined in: [calendar/date-core.ts:62](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L62) Optional range of dates to be used. @@ -81,7 +81,7 @@ Optional range of dates to be used. optional timeFormatter: DateTimeFormat; ``` -Defined in: [calendar/date-core.ts:65](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L65) +Defined in: [calendar/date-core.ts:66](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L66) Optional time formatter. @@ -93,7 +93,7 @@ Optional time formatter. optional timeZone: TimeZoneLike; ``` -Defined in: [calendar/date-core.ts:57](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L57) +Defined in: [calendar/date-core.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L58) Optional time zone specification. @@ -105,6 +105,6 @@ Optional time zone specification. viewMode: ViewMode; ``` -Defined in: [calendar/date-core.ts:53](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L53) +Defined in: [calendar/date-core.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L54) The initial view mode configuration. diff --git a/docs/reference/interfaces/DateRange.md b/docs/reference/interfaces/DateRange.md index 9440465e..a88b8032 100644 --- a/docs/reference/interfaces/DateRange.md +++ b/docs/reference/interfaces/DateRange.md @@ -5,7 +5,7 @@ title: DateRange # Interface: DateRange -Defined in: [calendar/types.ts:38](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L38) +Defined in: [calendar/types.ts:57](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L57) ## Properties @@ -15,7 +15,7 @@ Defined in: [calendar/types.ts:38](https://github.com/TanStack/time/blob/main/pa end: DateInput | null; ``` -Defined in: [calendar/types.ts:40](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L40) +Defined in: [calendar/types.ts:59](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L59) *** @@ -25,4 +25,4 @@ Defined in: [calendar/types.ts:40](https://github.com/TanStack/time/blob/main/pa start: DateInput | null; ``` -Defined in: [calendar/types.ts:39](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L39) +Defined in: [calendar/types.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L58) diff --git a/docs/reference/interfaces/Event.md b/docs/reference/interfaces/Event.md index e7504655..41589484 100644 --- a/docs/reference/interfaces/Event.md +++ b/docs/reference/interfaces/Event.md @@ -5,7 +5,7 @@ title: Event # Interface: Event\ -Defined in: [calendar/types.ts:20](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L20) +Defined in: [calendar/types.ts:35](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L35) ## Type Parameters @@ -15,13 +15,37 @@ Defined in: [calendar/types.ts:20](https://github.com/TanStack/time/blob/main/pa ## Properties +### \_originalEnd? + +```ts +optional _originalEnd: string; +``` + +Defined in: [calendar/types.ts:44](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L44) + +Original end time before splitting (only set on split segments of multi-day events) + +*** + +### \_originalStart? + +```ts +optional _originalStart: string; +``` + +Defined in: [calendar/types.ts:42](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L42) + +Original start time before splitting (only set on split segments of multi-day events) + +*** + ### end ```ts end: string; ``` -Defined in: [calendar/types.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L23) +Defined in: [calendar/types.ts:38](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L38) *** @@ -31,7 +55,7 @@ Defined in: [calendar/types.ts:23](https://github.com/TanStack/time/blob/main/pa id: string; ``` -Defined in: [calendar/types.ts:21](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L21) +Defined in: [calendar/types.ts:36](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L36) *** @@ -41,7 +65,7 @@ Defined in: [calendar/types.ts:21](https://github.com/TanStack/time/blob/main/pa optional resources: TResource[]; ``` -Defined in: [calendar/types.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L25) +Defined in: [calendar/types.ts:40](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L40) *** @@ -51,7 +75,7 @@ Defined in: [calendar/types.ts:25](https://github.com/TanStack/time/blob/main/pa start: string; ``` -Defined in: [calendar/types.ts:22](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L22) +Defined in: [calendar/types.ts:37](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L37) *** @@ -61,4 +85,4 @@ Defined in: [calendar/types.ts:22](https://github.com/TanStack/time/blob/main/pa title: string; ``` -Defined in: [calendar/types.ts:24](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L24) +Defined in: [calendar/types.ts:39](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L39) diff --git a/docs/reference/interfaces/EventTimeRange.md b/docs/reference/interfaces/EventTimeRange.md new file mode 100644 index 00000000..953ca2b2 --- /dev/null +++ b/docs/reference/interfaces/EventTimeRange.md @@ -0,0 +1,38 @@ +--- +id: EventTimeRange +title: EventTimeRange +--- + +# Interface: EventTimeRange + +Defined in: [calendar/getResizeProps.ts:435](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L435) + +## Properties + +### end + +```ts +end: string; +``` + +Defined in: [calendar/getResizeProps.ts:437](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L437) + +*** + +### isMultiDay + +```ts +isMultiDay: boolean; +``` + +Defined in: [calendar/getResizeProps.ts:438](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L438) + +*** + +### start + +```ts +start: string; +``` + +Defined in: [calendar/getResizeProps.ts:436](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L436) diff --git a/docs/reference/interfaces/FormatEventTimeOptions.md b/docs/reference/interfaces/FormatEventTimeOptions.md new file mode 100644 index 00000000..93c3277b --- /dev/null +++ b/docs/reference/interfaces/FormatEventTimeOptions.md @@ -0,0 +1,32 @@ +--- +id: FormatEventTimeOptions +title: FormatEventTimeOptions +--- + +# Interface: FormatEventTimeOptions + +Defined in: [calendar/getResizeProps.ts:470](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L470) + +## Properties + +### alwaysShowDate? + +```ts +optional alwaysShowDate: boolean; +``` + +Defined in: [calendar/getResizeProps.ts:474](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L474) + +Whether to include date for single-day events + +*** + +### locale? + +```ts +optional locale: string; +``` + +Defined in: [calendar/getResizeProps.ts:472](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L472) + +Locale for formatting (e.g., 'en-US') diff --git a/docs/reference/interfaces/FormattedEventTime.md b/docs/reference/interfaces/FormattedEventTime.md new file mode 100644 index 00000000..15e98376 --- /dev/null +++ b/docs/reference/interfaces/FormattedEventTime.md @@ -0,0 +1,56 @@ +--- +id: FormattedEventTime +title: FormattedEventTime +--- + +# Interface: FormattedEventTime + +Defined in: [calendar/getResizeProps.ts:477](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L477) + +## Properties + +### endFormatted + +```ts +endFormatted: string; +``` + +Defined in: [calendar/getResizeProps.ts:481](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L481) + +Formatted end string + +*** + +### isMultiDay + +```ts +isMultiDay: boolean; +``` + +Defined in: [calendar/getResizeProps.ts:485](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L485) + +Whether this is a multi-day event + +*** + +### rangeFormatted + +```ts +rangeFormatted: string; +``` + +Defined in: [calendar/getResizeProps.ts:483](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L483) + +Full formatted range string + +*** + +### startFormatted + +```ts +startFormatted: string; +``` + +Defined in: [calendar/getResizeProps.ts:479](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L479) + +Formatted start string diff --git a/docs/reference/interfaces/GhostPreviewOptions.md b/docs/reference/interfaces/GhostPreviewOptions.md new file mode 100644 index 00000000..21d5b53b --- /dev/null +++ b/docs/reference/interfaces/GhostPreviewOptions.md @@ -0,0 +1,44 @@ +--- +id: GhostPreviewOptions +title: GhostPreviewOptions +--- + +# Interface: GhostPreviewOptions + +Defined in: [calendar/getResizeProps.ts:356](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L356) + +## Properties + +### dayDate + +```ts +dayDate: string; +``` + +Defined in: [calendar/getResizeProps.ts:358](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L358) + +The date string of the day being rendered (YYYY-MM-DD) + +*** + +### previewEnd + +```ts +previewEnd: string; +``` + +Defined in: [calendar/getResizeProps.ts:362](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L362) + +The preview end during resize + +*** + +### previewStart + +```ts +previewStart: string; +``` + +Defined in: [calendar/getResizeProps.ts:360](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L360) + +The preview start during resize diff --git a/docs/reference/interfaces/IsWeekendOptions.md b/docs/reference/interfaces/IsWeekendOptions.md index 1b492741..f1bc1c23 100644 --- a/docs/reference/interfaces/IsWeekendOptions.md +++ b/docs/reference/interfaces/IsWeekendOptions.md @@ -5,7 +5,7 @@ title: IsWeekendOptions # Interface: IsWeekendOptions -Defined in: [date/isWeekend/isWeekend.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L5) +Defined in: [date/isWeekend/isWeekend.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L6) ## Extends @@ -33,7 +33,7 @@ Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packag optional locale: string; ``` -Defined in: [date/isWeekend/isWeekend.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L6) +Defined in: [date/isWeekend/isWeekend.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L7) *** diff --git a/docs/reference/interfaces/ParsedDateCoreOptions.md b/docs/reference/interfaces/ParsedDateCoreOptions.md index 417916f8..5e694cf3 100644 --- a/docs/reference/interfaces/ParsedDateCoreOptions.md +++ b/docs/reference/interfaces/ParsedDateCoreOptions.md @@ -5,7 +5,7 @@ title: ParsedDateCoreOptions # Interface: ParsedDateCoreOptions -Defined in: [calendar/date-core.ts:70](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L70) +Defined in: [calendar/date-core.ts:71](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L71) ## Extends @@ -19,7 +19,7 @@ Defined in: [calendar/date-core.ts:70](https://github.com/TanStack/time/blob/mai calendar: CalendarLike; ``` -Defined in: [calendar/date-core.ts:59](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L59) +Defined in: [calendar/date-core.ts:60](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L60) Optional calendar system to be used. @@ -35,7 +35,7 @@ Optional calendar system to be used. locale: string; ``` -Defined in: [calendar/date-core.ts:55](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L55) +Defined in: [calendar/date-core.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L56) Optional locale for date formatting. Uses a BCP 47 language tag. @@ -51,7 +51,7 @@ Optional locale for date formatting. Uses a BCP 47 language tag. range: ParsedDateRange; ``` -Defined in: [calendar/date-core.ts:74](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L74) +Defined in: [calendar/date-core.ts:75](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L75) *** @@ -61,7 +61,7 @@ Defined in: [calendar/date-core.ts:74](https://github.com/TanStack/time/blob/mai timeZone: TimeZoneLike; ``` -Defined in: [calendar/date-core.ts:57](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L57) +Defined in: [calendar/date-core.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L58) Optional time zone specification. @@ -77,7 +77,7 @@ Optional time zone specification. viewMode: ViewMode; ``` -Defined in: [calendar/date-core.ts:53](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L53) +Defined in: [calendar/date-core.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L54) The initial view mode configuration. diff --git a/docs/reference/interfaces/PositionStyle.md b/docs/reference/interfaces/PositionStyle.md new file mode 100644 index 00000000..a3057e32 --- /dev/null +++ b/docs/reference/interfaces/PositionStyle.md @@ -0,0 +1,30 @@ +--- +id: PositionStyle +title: PositionStyle +--- + +# Interface: PositionStyle + +Defined in: [calendar/getResizeProps.ts:255](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L255) + +Style for positioned elements (events, ghosts) + +## Properties + +### height + +```ts +height: string; +``` + +Defined in: [calendar/getResizeProps.ts:257](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L257) + +*** + +### top + +```ts +top: string; +``` + +Defined in: [calendar/getResizeProps.ts:256](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L256) diff --git a/docs/reference/interfaces/ResizeConstraints.md b/docs/reference/interfaces/ResizeConstraints.md new file mode 100644 index 00000000..7da83e72 --- /dev/null +++ b/docs/reference/interfaces/ResizeConstraints.md @@ -0,0 +1,40 @@ +--- +id: ResizeConstraints +title: ResizeConstraints +--- + +# Interface: ResizeConstraints + +Defined in: [calendar/getResizeProps.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L12) + +## Properties + +### minDurationMinutes? + +```ts +optional minDurationMinutes: number; +``` + +Defined in: [calendar/getResizeProps.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L13) + +*** + +### snapToMinutes? + +```ts +optional snapToMinutes: number; +``` + +Defined in: [calendar/getResizeProps.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L14) + +*** + +### unavailableRanges? + +```ts +optional unavailableRanges: UnavailableTimeRange[]; +``` + +Defined in: [calendar/getResizeProps.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L16) + +Unavailable time ranges that the event cannot be resized into diff --git a/docs/reference/interfaces/ResizeError.md b/docs/reference/interfaces/ResizeError.md new file mode 100644 index 00000000..9a78d786 --- /dev/null +++ b/docs/reference/interfaces/ResizeError.md @@ -0,0 +1,102 @@ +--- +id: ResizeError +title: ResizeError +--- + +# Interface: ResizeError + +Defined in: [calendar/types.ts:128](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L128) + +Error information when a resize operation is blocked + +## Properties + +### attemptedEnd? + +```ts +optional attemptedEnd: string; +``` + +Defined in: [calendar/types.ts:136](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L136) + +*** + +### attemptedStart? + +```ts +optional attemptedStart: string; +``` + +Defined in: [calendar/types.ts:135](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L135) + +*** + +### conflicts? + +```ts +optional conflicts: AvailabilityConflict[]; +``` + +Defined in: [calendar/types.ts:138](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L138) + +Specific availability conflicts that prevented the resize + +*** + +### eventId + +```ts +eventId: string; +``` + +Defined in: [calendar/types.ts:129](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L129) + +*** + +### eventTitle + +```ts +eventTitle: string; +``` + +Defined in: [calendar/types.ts:130](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L130) + +*** + +### message + +```ts +message: string; +``` + +Defined in: [calendar/types.ts:132](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L132) + +*** + +### originalEnd + +```ts +originalEnd: string; +``` + +Defined in: [calendar/types.ts:134](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L134) + +*** + +### originalStart + +```ts +originalStart: string; +``` + +Defined in: [calendar/types.ts:133](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L133) + +*** + +### reason + +```ts +reason: "unavailable-time" | "invalid-time" | "min-duration" | "blocked"; +``` + +Defined in: [calendar/types.ts:131](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L131) diff --git a/docs/reference/interfaces/ResizeHandleStyle.md b/docs/reference/interfaces/ResizeHandleStyle.md new file mode 100644 index 00000000..8a224faf --- /dev/null +++ b/docs/reference/interfaces/ResizeHandleStyle.md @@ -0,0 +1,88 @@ +--- +id: ResizeHandleStyle +title: ResizeHandleStyle +--- + +# Interface: ResizeHandleStyle + +Defined in: [calendar/getResizeProps.ts:172](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L172) + +## Properties + +### bottom? + +```ts +optional bottom: number; +``` + +Defined in: [calendar/getResizeProps.ts:180](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L180) + +*** + +### cursor + +```ts +cursor: "ns-resize"; +``` + +Defined in: [calendar/getResizeProps.ts:177](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L177) + +*** + +### height + +```ts +height: string; +``` + +Defined in: [calendar/getResizeProps.ts:176](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L176) + +*** + +### left + +```ts +left: number; +``` + +Defined in: [calendar/getResizeProps.ts:174](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L174) + +*** + +### position + +```ts +position: "absolute"; +``` + +Defined in: [calendar/getResizeProps.ts:173](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L173) + +*** + +### right + +```ts +right: number; +``` + +Defined in: [calendar/getResizeProps.ts:175](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L175) + +*** + +### top? + +```ts +optional top: number; +``` + +Defined in: [calendar/getResizeProps.ts:179](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L179) + +*** + +### zIndex + +```ts +zIndex: number; +``` + +Defined in: [calendar/getResizeProps.ts:178](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L178) diff --git a/docs/reference/interfaces/ResizePreviewOptions.md b/docs/reference/interfaces/ResizePreviewOptions.md new file mode 100644 index 00000000..dc729825 --- /dev/null +++ b/docs/reference/interfaces/ResizePreviewOptions.md @@ -0,0 +1,68 @@ +--- +id: ResizePreviewOptions +title: ResizePreviewOptions +--- + +# Interface: ResizePreviewOptions + +Defined in: [calendar/getResizeProps.ts:272](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L272) + +## Properties + +### dayDate + +```ts +dayDate: string; +``` + +Defined in: [calendar/getResizeProps.ts:274](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L274) + +The date string of the day being rendered (YYYY-MM-DD) + +*** + +### originalEnd + +```ts +originalEnd: string; +``` + +Defined in: [calendar/getResizeProps.ts:278](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L278) + +The original end of the event (before resize) + +*** + +### originalStart + +```ts +originalStart: string; +``` + +Defined in: [calendar/getResizeProps.ts:276](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L276) + +The original start of the event (before resize) + +*** + +### previewEnd + +```ts +previewEnd: string; +``` + +Defined in: [calendar/getResizeProps.ts:282](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L282) + +The preview end during resize + +*** + +### previewStart + +```ts +previewStart: string; +``` + +Defined in: [calendar/getResizeProps.ts:280](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L280) + +The preview start during resize diff --git a/docs/reference/interfaces/ResizeValidationResult.md b/docs/reference/interfaces/ResizeValidationResult.md new file mode 100644 index 00000000..a5334a57 --- /dev/null +++ b/docs/reference/interfaces/ResizeValidationResult.md @@ -0,0 +1,30 @@ +--- +id: ResizeValidationResult +title: ResizeValidationResult +--- + +# Interface: ResizeValidationResult + +Defined in: [calendar/types.ts:144](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L144) + +Result of checking if a resize is valid + +## Properties + +### error? + +```ts +optional error: ResizeError; +``` + +Defined in: [calendar/types.ts:146](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L146) + +*** + +### valid + +```ts +valid: boolean; +``` + +Defined in: [calendar/types.ts:145](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L145) diff --git a/docs/reference/interfaces/Resource.md b/docs/reference/interfaces/Resource.md index d5e2dcbc..5e7c6ef0 100644 --- a/docs/reference/interfaces/Resource.md +++ b/docs/reference/interfaces/Resource.md @@ -5,17 +5,59 @@ title: Resource # Interface: Resource -Defined in: [calendar/types.ts:4](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L4) +Defined in: [calendar/types.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L13) ## Properties +### availability? + +```ts +optional availability: Availability[]; +``` + +Defined in: [calendar/types.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L16) + +*** + +### buffer? + +```ts +optional buffer: object; +``` + +Defined in: [calendar/types.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L18) + +#### after? + +```ts +optional after: number; +``` + +#### before? + +```ts +optional before: number; +``` + +*** + +### capacity? + +```ts +optional capacity: number; +``` + +Defined in: [calendar/types.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L17) + +*** + ### id ```ts id: string; ``` -Defined in: [calendar/types.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L5) +Defined in: [calendar/types.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L14) *** @@ -25,4 +67,4 @@ Defined in: [calendar/types.ts:5](https://github.com/TanStack/time/blob/main/pac label: string; ``` -Defined in: [calendar/types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L6) +Defined in: [calendar/types.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L15) diff --git a/docs/reference/interfaces/SegmentInfo.md b/docs/reference/interfaces/SegmentInfo.md new file mode 100644 index 00000000..5f9ba92e --- /dev/null +++ b/docs/reference/interfaces/SegmentInfo.md @@ -0,0 +1,94 @@ +--- +id: SegmentInfo +title: SegmentInfo +--- + +# Interface: SegmentInfo + +Defined in: [calendar/getResizeProps.ts:202](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L202) + +Information about a segment's position within a multi-day event + +## Properties + +### isFirstSegment + +```ts +isFirstSegment: boolean; +``` + +Defined in: [calendar/getResizeProps.ts:204](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L204) + +Whether this is the first segment of a multi-day event + +*** + +### isLastSegment + +```ts +isLastSegment: boolean; +``` + +Defined in: [calendar/getResizeProps.ts:206](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L206) + +Whether this is the last segment of a multi-day event + +*** + +### isSplitEvent + +```ts +isSplitEvent: boolean; +``` + +Defined in: [calendar/getResizeProps.ts:208](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L208) + +Whether this segment is part of a split multi-day event + +*** + +### originalEnd + +```ts +originalEnd: string; +``` + +Defined in: [calendar/getResizeProps.ts:212](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L212) + +The original event end (before splitting) + +*** + +### originalStart + +```ts +originalStart: string; +``` + +Defined in: [calendar/getResizeProps.ts:210](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L210) + +The original event start (before splitting) + +*** + +### segmentEnd + +```ts +segmentEnd: string; +``` + +Defined in: [calendar/getResizeProps.ts:216](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L216) + +The segment's end time + +*** + +### segmentStart + +```ts +segmentStart: string; +``` + +Defined in: [calendar/getResizeProps.ts:214](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L214) + +The segment's start time diff --git a/docs/reference/interfaces/SegmentResizePreview.md b/docs/reference/interfaces/SegmentResizePreview.md new file mode 100644 index 00000000..0385d37b --- /dev/null +++ b/docs/reference/interfaces/SegmentResizePreview.md @@ -0,0 +1,46 @@ +--- +id: SegmentResizePreview +title: SegmentResizePreview +--- + +# Interface: SegmentResizePreview + +Defined in: [calendar/getResizeProps.ts:263](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L263) + +Result of resize preview calculation for a segment + +## Properties + +### hasChanged + +```ts +hasChanged: boolean; +``` + +Defined in: [calendar/getResizeProps.ts:269](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L269) + +Whether the preview has changed from the original + +*** + +### previewStyle + +```ts +previewStyle: PositionStyle | null; +``` + +Defined in: [calendar/getResizeProps.ts:267](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L267) + +The preview style to apply, if any + +*** + +### shouldHide + +```ts +shouldHide: boolean; +``` + +Defined in: [calendar/getResizeProps.ts:265](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L265) + +Whether the segment should be hidden (shrunk away) diff --git a/docs/reference/interfaces/TimeEventMap.md b/docs/reference/interfaces/TimeEventMap.md new file mode 100644 index 00000000..318be9db --- /dev/null +++ b/docs/reference/interfaces/TimeEventMap.md @@ -0,0 +1,266 @@ +--- +id: TimeEventMap +title: TimeEventMap +--- + +# Interface: TimeEventMap + +Defined in: [client/TimeClient.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L10) + +Event map for TimeClient events + +## Properties + +### time:calendar:navigate + +```ts +time:calendar:navigate: object; +``` + +Defined in: [client/TimeClient.ts:47](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L47) + +#### direction + +```ts +direction: "previous" | "next" | "current" | "specific"; +``` + +#### targetDate + +```ts +targetDate: string; +``` + +*** + +### time:calendar:viewMode:changed + +```ts +time:calendar:viewMode:changed: object; +``` + +Defined in: [client/TimeClient.ts:51](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L51) + +#### viewMode + +```ts +viewMode: object; +``` + +##### viewMode.unit + +```ts +unit: string; +``` + +##### viewMode.value + +```ts +value: number; +``` + +*** + +### time:event:added + +```ts +time:event:added: object; +``` + +Defined in: [client/TimeClient.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L11) + +#### end + +```ts +end: string; +``` + +#### eventId + +```ts +eventId: string; +``` + +#### eventTitle + +```ts +eventTitle: string; +``` + +#### start + +```ts +start: string; +``` + +*** + +### time:event:removed + +```ts +time:event:removed: object; +``` + +Defined in: [client/TimeClient.ts:24](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L24) + +#### end + +```ts +end: string; +``` + +#### eventId + +```ts +eventId: string; +``` + +#### eventTitle + +```ts +eventTitle: string; +``` + +#### start + +```ts +start: string; +``` + +*** + +### time:event:resize:error + +```ts +time:event:resize:error: object; +``` + +Defined in: [client/TimeClient.ts:36](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L36) + +#### attemptedEnd? + +```ts +optional attemptedEnd: string; +``` + +#### attemptedStart? + +```ts +optional attemptedStart: string; +``` + +#### conflicts? + +```ts +optional conflicts: AvailabilityConflict[]; +``` + +#### eventId + +```ts +eventId: string; +``` + +#### eventTitle + +```ts +eventTitle: string; +``` + +#### message + +```ts +message: string; +``` + +#### originalEnd + +```ts +originalEnd: string; +``` + +#### originalStart + +```ts +originalStart: string; +``` + +#### reason + +```ts +reason: "unavailable-time" | "invalid-time" | "min-duration" | "blocked"; +``` + +*** + +### time:event:resized + +```ts +time:event:resized: object; +``` + +Defined in: [client/TimeClient.ts:30](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L30) + +#### end + +```ts +end: string; +``` + +#### eventId + +```ts +eventId: string; +``` + +#### eventTitle + +```ts +eventTitle: string; +``` + +#### start + +```ts +start: string; +``` + +*** + +### time:event:updated + +```ts +time:event:updated: object; +``` + +Defined in: [client/TimeClient.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L17) + +#### end + +```ts +end: string; +``` + +#### eventId + +```ts +eventId: string; +``` + +#### eventTitle + +```ts +eventTitle: string; +``` + +#### start + +```ts +start: string; +``` + +#### updates + +```ts +updates: Record; +``` diff --git a/docs/reference/interfaces/TimeSlot.md b/docs/reference/interfaces/TimeSlot.md index 562220b9..0c8fc60a 100644 --- a/docs/reference/interfaces/TimeSlot.md +++ b/docs/reference/interfaces/TimeSlot.md @@ -5,7 +5,7 @@ title: TimeSlot # Interface: TimeSlot -Defined in: [calendar/types.ts:43](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L43) +Defined in: [calendar/types.ts:62](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L62) ## Properties @@ -15,7 +15,7 @@ Defined in: [calendar/types.ts:43](https://github.com/TanStack/time/blob/main/pa hour: number; ``` -Defined in: [calendar/types.ts:44](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L44) +Defined in: [calendar/types.ts:63](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L63) *** @@ -25,7 +25,7 @@ Defined in: [calendar/types.ts:44](https://github.com/TanStack/time/blob/main/pa label: string; ``` -Defined in: [calendar/types.ts:46](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L46) +Defined in: [calendar/types.ts:65](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L65) *** @@ -35,4 +35,4 @@ Defined in: [calendar/types.ts:46](https://github.com/TanStack/time/blob/main/pa minute: number; ``` -Defined in: [calendar/types.ts:45](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L45) +Defined in: [calendar/types.ts:64](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L64) diff --git a/docs/reference/interfaces/UnavailabilityReason.md b/docs/reference/interfaces/UnavailabilityReason.md new file mode 100644 index 00000000..44db1063 --- /dev/null +++ b/docs/reference/interfaces/UnavailabilityReason.md @@ -0,0 +1,88 @@ +--- +id: UnavailabilityReason +title: UnavailabilityReason +--- + +# Interface: UnavailabilityReason + +Defined in: [calendar/types.ts:89](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L89) + +Information about why a resource is unavailable + +## Properties + +### capacityInfo? + +```ts +optional capacityInfo: object; +``` + +Defined in: [calendar/types.ts:99](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L99) + +Current capacity usage if applicable + +#### max + +```ts +max: number; +``` + +#### remaining + +```ts +remaining: number; +``` + +#### used + +```ts +used: number; +``` + +*** + +### description + +```ts +description: string; +``` + +Defined in: [calendar/types.ts:97](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L97) + +Human-readable explanation + +*** + +### reason + +```ts +reason: "outside-hours" | "capacity" | "no-availability"; +``` + +Defined in: [calendar/types.ts:95](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L95) + +Why the resource is unavailable + +*** + +### resourceId + +```ts +resourceId: string; +``` + +Defined in: [calendar/types.ts:91](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L91) + +Resource ID + +*** + +### resourceLabel + +```ts +resourceLabel: string; +``` + +Defined in: [calendar/types.ts:93](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L93) + +Resource label/name diff --git a/docs/reference/interfaces/UnavailableRange.md b/docs/reference/interfaces/UnavailableRange.md new file mode 100644 index 00000000..6178f643 --- /dev/null +++ b/docs/reference/interfaces/UnavailableRange.md @@ -0,0 +1,56 @@ +--- +id: UnavailableRange +title: UnavailableRange +--- + +# Interface: UnavailableRange + +Defined in: [calendar/types.ts:68](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L68) + +## Properties + +### endTime + +```ts +endTime: string; +``` + +Defined in: [calendar/types.ts:76](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L76) + +End time as HH:mm string + +*** + +### height + +```ts +height: number; +``` + +Defined in: [calendar/types.ts:72](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L72) + +Height in pixels + +*** + +### startTime + +```ts +startTime: string; +``` + +Defined in: [calendar/types.ts:74](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L74) + +Start time as HH:mm string + +*** + +### top + +```ts +top: number; +``` + +Defined in: [calendar/types.ts:70](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L70) + +Top position in pixels diff --git a/docs/reference/interfaces/UnavailableTimeRange.md b/docs/reference/interfaces/UnavailableTimeRange.md new file mode 100644 index 00000000..8ae1abf4 --- /dev/null +++ b/docs/reference/interfaces/UnavailableTimeRange.md @@ -0,0 +1,32 @@ +--- +id: UnavailableTimeRange +title: UnavailableTimeRange +--- + +# Interface: UnavailableTimeRange + +Defined in: [calendar/getResizeProps.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L5) + +## Properties + +### endMinutes + +```ts +endMinutes: number; +``` + +Defined in: [calendar/getResizeProps.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L9) + +End time in minutes from midnight (0-1440) + +*** + +### startMinutes + +```ts +startMinutes: number; +``` + +Defined in: [calendar/getResizeProps.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L7) + +Start time in minutes from midnight (0-1440) diff --git a/docs/reference/interfaces/ViewMode.md b/docs/reference/interfaces/ViewMode.md index cf5d5fae..3f6c8e71 100644 --- a/docs/reference/interfaces/ViewMode.md +++ b/docs/reference/interfaces/ViewMode.md @@ -5,7 +5,7 @@ title: ViewMode # Interface: ViewMode -Defined in: [calendar/types.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L13) +Defined in: [calendar/types.ts:28](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L28) Represents the configuration for the current viewing mode of a calendar, specifying the scale and unit of time. @@ -18,7 +18,7 @@ specifying the scale and unit of time. unit: "month" | "week" | "day" | "workWeek"; ``` -Defined in: [calendar/types.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L17) +Defined in: [calendar/types.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L32) The unit of time that the calendar view should display (month, week, workWeek or day). @@ -30,6 +30,6 @@ The unit of time that the calendar view should display (month, week, workWeek or value: number; ``` -Defined in: [calendar/types.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L15) +Defined in: [calendar/types.ts:30](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L30) The number of units for the view mode. diff --git a/docs/reference/type-aliases/Day.md b/docs/reference/type-aliases/Day.md index 77228cad..55898a15 100644 --- a/docs/reference/type-aliases/Day.md +++ b/docs/reference/type-aliases/Day.md @@ -9,7 +9,7 @@ title: Day type Day = object; ``` -Defined in: [calendar/types.ts:28](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L28) +Defined in: [calendar/types.ts:47](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L47) ## Type Parameters @@ -29,7 +29,7 @@ Defined in: [calendar/types.ts:28](https://github.com/TanStack/time/blob/main/pa date: Temporal.PlainDate; ``` -Defined in: [calendar/types.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L32) +Defined in: [calendar/types.ts:51](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L51) *** @@ -39,7 +39,7 @@ Defined in: [calendar/types.ts:32](https://github.com/TanStack/time/blob/main/pa events: TEvent[]; ``` -Defined in: [calendar/types.ts:33](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L33) +Defined in: [calendar/types.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L52) *** @@ -49,7 +49,7 @@ Defined in: [calendar/types.ts:33](https://github.com/TanStack/time/blob/main/pa isInCurrentPeriod: boolean; ``` -Defined in: [calendar/types.ts:35](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L35) +Defined in: [calendar/types.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L54) *** @@ -59,4 +59,4 @@ Defined in: [calendar/types.ts:35](https://github.com/TanStack/time/blob/main/pa isToday: boolean; ``` -Defined in: [calendar/types.ts:34](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L34) +Defined in: [calendar/types.ts:53](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L53) diff --git a/docs/reference/type-aliases/GroupDaysByProps.md b/docs/reference/type-aliases/GroupDaysByProps.md index 4e5336ac..1f5551b4 100644 --- a/docs/reference/type-aliases/GroupDaysByProps.md +++ b/docs/reference/type-aliases/GroupDaysByProps.md @@ -11,7 +11,7 @@ type GroupDaysByProps = | GroupDaysByWeekProps; ``` -Defined in: [calendar/groupDaysBy.ts:29](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/groupDaysBy.ts#L29) +Defined in: [calendar/groupDaysBy.ts:30](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/groupDaysBy.ts#L30) ## Type Parameters diff --git a/docs/reference/type-aliases/ResizeEdge.md b/docs/reference/type-aliases/ResizeEdge.md new file mode 100644 index 00000000..2fa72843 --- /dev/null +++ b/docs/reference/type-aliases/ResizeEdge.md @@ -0,0 +1,12 @@ +--- +id: ResizeEdge +title: ResizeEdge +--- + +# Type Alias: ResizeEdge + +```ts +type ResizeEdge = "top" | "bottom"; +``` + +Defined in: [calendar/getResizeProps.ts:3](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L3) From 6ce6876416917309f8a830a9d4b9fd7879dc8b6f Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 2 Mar 2026 13:56:24 +0100 Subject: [PATCH 058/207] feat: timeline example --- examples/react/{basic => calendar}/index.html | 0 .../react/{basic => calendar}/package.json | 0 .../{basic => calendar}/postcss.config.js | 0 .../react/{basic => calendar}/src/index.css | 0 .../react/{basic => calendar}/src/index.tsx | 2 +- .../{basic => calendar}/tailwind.config.js | 0 .../react/{basic => calendar}/tsconfig.json | 0 .../react/{basic => calendar}/vite.config.ts | 0 examples/react/timeline/index.html | 14 + examples/react/timeline/package.json | 29 + examples/react/timeline/postcss.config.js | 6 + examples/react/timeline/src/index.css | 9 + examples/react/timeline/src/index.tsx | 694 +++++++++ examples/react/timeline/tailwind.config.js | 8 + examples/react/timeline/tsconfig.json | 19 + examples/react/timeline/vite.config.ts | 6 + .../react-time/src/useCalendar/useCalendar.ts | 493 +------ packages/time/src/calendar/calendar.ts | 518 ++++++- .../time/src/calendar/tests/calendar.test.ts | 1295 +++++++++++++++++ pnpm-lock.yaml | 48 +- 20 files changed, 2675 insertions(+), 466 deletions(-) rename examples/react/{basic => calendar}/index.html (100%) rename examples/react/{basic => calendar}/package.json (100%) rename examples/react/{basic => calendar}/postcss.config.js (100%) rename examples/react/{basic => calendar}/src/index.css (100%) rename examples/react/{basic => calendar}/src/index.tsx (99%) rename examples/react/{basic => calendar}/tailwind.config.js (100%) rename examples/react/{basic => calendar}/tsconfig.json (100%) rename examples/react/{basic => calendar}/vite.config.ts (100%) create mode 100644 examples/react/timeline/index.html create mode 100644 examples/react/timeline/package.json create mode 100644 examples/react/timeline/postcss.config.js create mode 100644 examples/react/timeline/src/index.css create mode 100644 examples/react/timeline/src/index.tsx create mode 100644 examples/react/timeline/tailwind.config.js create mode 100644 examples/react/timeline/tsconfig.json create mode 100644 examples/react/timeline/vite.config.ts create mode 100644 packages/time/src/calendar/tests/calendar.test.ts diff --git a/examples/react/basic/index.html b/examples/react/calendar/index.html similarity index 100% rename from examples/react/basic/index.html rename to examples/react/calendar/index.html diff --git a/examples/react/basic/package.json b/examples/react/calendar/package.json similarity index 100% rename from examples/react/basic/package.json rename to examples/react/calendar/package.json diff --git a/examples/react/basic/postcss.config.js b/examples/react/calendar/postcss.config.js similarity index 100% rename from examples/react/basic/postcss.config.js rename to examples/react/calendar/postcss.config.js diff --git a/examples/react/basic/src/index.css b/examples/react/calendar/src/index.css similarity index 100% rename from examples/react/basic/src/index.css rename to examples/react/calendar/src/index.css diff --git a/examples/react/basic/src/index.tsx b/examples/react/calendar/src/index.tsx similarity index 99% rename from examples/react/basic/src/index.tsx rename to examples/react/calendar/src/index.tsx index bf5417d4..9b2ecc4c 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/calendar/src/index.tsx @@ -9,7 +9,7 @@ import ReactDOM from 'react-dom/client' import { useEffect, useState } from 'react' import { TanStackDevtools } from '@tanstack/react-devtools' import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' -import type { Day, Event, Resource, ResizeError } from '@tanstack/time' +import type { Day, Event, ResizeError, Resource } from '@tanstack/time' import './index.css' diff --git a/examples/react/basic/tailwind.config.js b/examples/react/calendar/tailwind.config.js similarity index 100% rename from examples/react/basic/tailwind.config.js rename to examples/react/calendar/tailwind.config.js diff --git a/examples/react/basic/tsconfig.json b/examples/react/calendar/tsconfig.json similarity index 100% rename from examples/react/basic/tsconfig.json rename to examples/react/calendar/tsconfig.json diff --git a/examples/react/basic/vite.config.ts b/examples/react/calendar/vite.config.ts similarity index 100% rename from examples/react/basic/vite.config.ts rename to examples/react/calendar/vite.config.ts diff --git a/examples/react/timeline/index.html b/examples/react/timeline/index.html new file mode 100644 index 00000000..c316addf --- /dev/null +++ b/examples/react/timeline/index.html @@ -0,0 +1,14 @@ + + + + + + + TanStack Time - React Timeline Example + + + +
+ + + diff --git a/examples/react/timeline/package.json b/examples/react/timeline/package.json new file mode 100644 index 00000000..0d41cacd --- /dev/null +++ b/examples/react/timeline/package.json @@ -0,0 +1,29 @@ +{ + "name": "@tanstack/time-example-react-timeline", + "private": true, + "type": "module", + "scripts": { + "dev": "vite --port=3006", + "build": "vite build", + "preview": "vite preview", + "test:types": "tsc" + }, + "dependencies": { + "@tanstack/react-devtools": "^0.9.5", + "@tanstack/react-time": "^0.0.0", + "@tanstack/react-time-devtools": "^0.0.0", + "@tanstack/time": "^0.0.0", + "react": "^19.2.3", + "react-dom": "^19.2.3" + }, + "devDependencies": { + "@types/react": "^19.2.8", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.2", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.17", + "typescript": "5.9.3", + "vite": "^7.3.1" + } +} diff --git a/examples/react/timeline/postcss.config.js b/examples/react/timeline/postcss.config.js new file mode 100644 index 00000000..2e7af2b7 --- /dev/null +++ b/examples/react/timeline/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/examples/react/timeline/src/index.css b/examples/react/timeline/src/index.css new file mode 100644 index 00000000..b892ad29 --- /dev/null +++ b/examples/react/timeline/src/index.css @@ -0,0 +1,9 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + body { + @apply bg-black text-neutral-200 antialiased; + } +} diff --git a/examples/react/timeline/src/index.tsx b/examples/react/timeline/src/index.tsx new file mode 100644 index 00000000..b7a17124 --- /dev/null +++ b/examples/react/timeline/src/index.tsx @@ -0,0 +1,694 @@ +import { useCalendar } from '@tanstack/react-time' +import ReactDOM from 'react-dom/client' +import { useMemo, useRef, useState } from 'react' +import { TanStackDevtools } from '@tanstack/react-devtools' +import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' +import type { Day, Event, Resource } from '@tanstack/time' + +import './index.css' + +function formatDateToISO(date: Date): string { + const year = date.getFullYear() + const month = String(date.getMonth() + 1).padStart(2, '0') + const day = String(date.getDate()).padStart(2, '0') + return `${year}-${month}-${day}` +} + +function parseISODate(iso: string): Date { + const datePart = iso.split('T')[0] ?? '' + const parts = datePart.split('-').map(Number) + return new Date(parts[0] ?? 0, (parts[1] ?? 1) - 1, parts[2] ?? 1) +} + +const EVENT_COLORS = [ + { bg: 'bg-indigo-500/80', border: 'border-indigo-400', text: 'text-indigo-50' }, + { bg: 'bg-emerald-500/80', border: 'border-emerald-400', text: 'text-emerald-50' }, + { bg: 'bg-amber-500/80', border: 'border-amber-400', text: 'text-amber-50' }, + { bg: 'bg-rose-500/80', border: 'border-rose-400', text: 'text-rose-50' }, + { bg: 'bg-cyan-500/80', border: 'border-cyan-400', text: 'text-cyan-50' }, + { bg: 'bg-violet-500/80', border: 'border-violet-400', text: 'text-violet-50' }, + { bg: 'bg-orange-500/80', border: 'border-orange-400', text: 'text-orange-50' }, + { bg: 'bg-teal-500/80', border: 'border-teal-400', text: 'text-teal-50' }, +] + +const resourceDesign: Resource = { id: 'design', label: 'Design' } +const resourceFrontend: Resource = { id: 'frontend', label: 'Frontend' } +const resourceBackend: Resource = { id: 'backend', label: 'Backend' } +const resourceQA: Resource = { id: 'qa', label: 'QA' } +const resourceDevOps: Resource = { id: 'devops', label: 'DevOps' } + +const sampleResources: Array = [ + resourceDesign, + resourceFrontend, + resourceBackend, + resourceQA, + resourceDevOps, +] + +function getSampleEvents(): Array> { + const today = new Date() + const d = (offset: number) => { + const date = new Date(today) + date.setDate(today.getDate() + offset) + return formatDateToISO(date) + } + + return [ + { + id: '1', + title: 'UI Mockups', + start: `${d(0)}T09:00:00`, + end: `${d(2)}T17:00:00`, + resources: [resourceDesign], + }, + { + id: '2', + title: 'Component Library', + start: `${d(1)}T09:00:00`, + end: `${d(4)}T17:00:00`, + resources: [resourceFrontend], + }, + { + id: '3', + title: 'API Development', + start: `${d(0)}T09:00:00`, + end: `${d(5)}T17:00:00`, + resources: [resourceBackend], + }, + { + id: '4', + title: 'Database Schema', + start: `${d(-1)}T09:00:00`, + end: `${d(1)}T17:00:00`, + resources: [resourceBackend], + }, + { + id: '5', + title: 'Integration Tests', + start: `${d(3)}T09:00:00`, + end: `${d(6)}T17:00:00`, + resources: [resourceQA], + }, + { + id: '6', + title: 'CI/CD Pipeline', + start: `${d(2)}T09:00:00`, + end: `${d(3)}T17:00:00`, + resources: [resourceDevOps], + }, + { + id: '7', + title: 'Design Review', + start: `${d(3)}T10:00:00`, + end: `${d(3)}T16:00:00`, + resources: [resourceDesign], + }, + { + id: '8', + title: 'Auth Module', + start: `${d(2)}T09:00:00`, + end: `${d(5)}T17:00:00`, + resources: [resourceFrontend], + }, + { + id: '9', + title: 'Load Testing', + start: `${d(5)}T09:00:00`, + end: `${d(6)}T17:00:00`, + resources: [resourceQA], + }, + { + id: '10', + title: 'Deployment', + start: `${d(5)}T09:00:00`, + end: `${d(6)}T17:00:00`, + resources: [resourceDevOps], + }, + ] +} + +const sampleEvents = getSampleEvents() + +interface EventFormData { + title: string + startDate: string + endDate: string + resourceId: string +} + +const emptyFormData: EventFormData = { + title: '', + startDate: formatDateToISO(new Date()), + endDate: formatDateToISO(new Date()), + resourceId: resourceDesign.id, +} + +function EventModal({ + isOpen, + onClose, + onSave, + onDelete, + initialData, + mode, +}: { + isOpen: boolean + onClose: () => void + onSave: (data: EventFormData) => void + onDelete?: () => void + initialData: EventFormData + mode: 'add' | 'edit' +}) { + const [formData, setFormData] = useState(initialData) + + if (!isOpen) return null + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault() + onSave(formData) + onClose() + } + + return ( +
+
+

+ {mode === 'add' ? 'Add Event' : 'Edit Event'} +

+ +
+ + + setFormData({ ...formData, title: e.target.value }) + } + className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white placeholder-neutral-500 focus:outline-none focus:ring-1 focus:ring-neutral-600" + required + /> +
+
+ + +
+
+
+ + + setFormData({ ...formData, startDate: e.target.value }) + } + className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white focus:outline-none focus:ring-1 focus:ring-neutral-600" + required + /> +
+
+ + + setFormData({ ...formData, endDate: e.target.value }) + } + className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white focus:outline-none focus:ring-1 focus:ring-neutral-600" + required + /> +
+
+
+
+ {mode === 'edit' && onDelete && ( + + )} +
+
+ + +
+
+ +
+
+ ) +} + +function TodayMarker({ + days, + dayWidth, +}: { + days: Array>> + dayWidth: number +}) { + const now = new Date() + const todayStr = formatDateToISO(now) + const todayIndex = days.findIndex( + (d) => d.date.toString({ calendarName: 'never' }) === todayStr, + ) + if (todayIndex === -1) return null + + const hourFraction = (now.getHours() + now.getMinutes() / 60) / 24 + const left = todayIndex * dayWidth + hourFraction * dayWidth + + return ( +
+
+
+ ) +} + +function TimelineRow({ + events, + days, + dayWidth, + colorMap, + onEventClick, +}: { + events: Array> + days: Array>> + dayWidth: number + colorMap: Map + onEventClick: (event: Event) => void +}) { + const dayDates = useMemo( + () => days.map((d) => d.date.toString({ calendarName: 'never' })), + [days], + ) + + const firstDayDate = dayDates[0] + if (!firstDayDate) return null + const firstDay = parseISODate(firstDayDate) + const totalWidth = days.length * dayWidth + + const positionedEvents = useMemo(() => { + return events.map((event) => { + const eventStart = parseISODate(event.start) + const eventEnd = parseISODate(event.end) + + const startOffset = Math.max( + 0, + (eventStart.getTime() - firstDay.getTime()) / (1000 * 60 * 60 * 24), + ) + const endOffset = + (eventEnd.getTime() - firstDay.getTime()) / (1000 * 60 * 60 * 24) + 1 + + const left = Math.max(0, startOffset * dayWidth) + const right = Math.min(totalWidth, endOffset * dayWidth) + const width = Math.max(right - left, dayWidth * 0.3) + + return { event, left, width } + }) + }, [events, firstDay, dayWidth, totalWidth]) + + return ( +
+ {days.map((day, i) => ( +
+ ))} + {positionedEvents.map(({ event, left, width }) => { + const colorIdx = colorMap.get(event.id) ?? 0 + const color = EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] + return ( +
onEventClick(event)} + > + {event.title} +
+ ) + })} +
+ ) +} + +function TimelineView() { + const DAY_WIDTH = 140 + + const [modalState, setModalState] = useState<{ + isOpen: boolean + mode: 'add' | 'edit' + eventId?: string + initialData: EventFormData + }>({ isOpen: false, mode: 'add', initialData: emptyFormData }) + + const scrollContainerRef = useRef(null) + + const calendar = useCalendar>({ + viewMode: { value: 2, unit: 'week' }, + events: sampleEvents, + resources: sampleResources, + timeZone: 'UTC', + }) + + const colorMap = useMemo(() => { + const map = new Map() + sampleEvents.forEach((event, i) => map.set(event.id, i)) + return map + }, []) + + const eventsByResource = useMemo(() => { + const map = new Map>>() + sampleResources.forEach((r) => map.set(r.id, [])) + + const allEvents = calendar.days.flatMap((d) => d.events) + const seen = new Set() + for (const event of allEvents) { + if (seen.has(event.id)) continue + seen.add(event.id) + + const resourceIds = + event.resources?.map((r) => r.id) ?? [] + if (resourceIds.length === 0) { + map.get(resourceDesign.id)?.push(event) + } else { + for (const rid of resourceIds) { + map.get(rid)?.push(event) + } + } + } + return map + }, [calendar.days]) + + const totalWidth = calendar.days.length * DAY_WIDTH + + const formatPeriodRange = () => { + const days = calendar.days + if (days.length === 0) return '' + const first = days[0] + const last = days[days.length - 1] + const fmt = (d: typeof first.date) => + new Date(d.year, d.month - 1, d.day).toLocaleDateString(undefined, { + month: 'short', + day: 'numeric', + year: 'numeric', + }) + return `${fmt(first.date)} — ${fmt(last.date)}` + } + + const openAddModal = () => + setModalState({ isOpen: true, mode: 'add', initialData: emptyFormData }) + + const openEditModal = (event: Event) => { + setModalState({ + isOpen: true, + mode: 'edit', + eventId: event.id, + initialData: { + title: event.title, + startDate: event.start.split('T')[0] ?? '', + endDate: event.end.split('T')[0] ?? '', + resourceId: event.resources?.[0]?.id ?? resourceDesign.id, + }, + }) + } + + const handleSave = (data: EventFormData) => { + const resource = sampleResources.find((r) => r.id === data.resourceId) + const eventData = { + title: data.title, + start: `${data.startDate}T09:00:00`, + end: `${data.endDate}T17:00:00`, + resources: resource ? [resource] : [], + } + + if (modalState.mode === 'add') { + calendar.addEvent({ id: String(Date.now()), ...eventData }) + } else if (modalState.eventId) { + calendar.updateEvent(modalState.eventId, eventData) + } + } + + const handleDelete = () => { + if (modalState.eventId) calendar.removeEvent(modalState.eventId) + } + + return ( +
+
+

+ TanStack Time — Timeline +

+ +
+ + + + + +
+ {[ + { label: '1 Week', value: 1, unit: 'week' as const }, + { label: '2 Weeks', value: 2, unit: 'week' as const }, + { label: 'Month', value: 1, unit: 'month' as const }, + ].map((opt) => { + const isActive = + calendar.viewMode.value === opt.value && + calendar.viewMode.unit === opt.unit + return ( + + ) + })} +
+
+ +
+ {formatPeriodRange()} +
+
+ +
+
+ {/* Resource labels column */} +
+
+ + Resources + +
+ {sampleResources.map((resource) => ( +
+ + {resource.label} + +
+ ))} +
+ + {/* Scrollable timeline area */} +
+
+ {/* Day headers */} +
+ {calendar.days.map((day) => { + const date = new Date( + day.date.year, + day.date.month - 1, + day.date.day, + ) + const dayName = date.toLocaleDateString(undefined, { + weekday: 'short', + }) + const dayNum = day.date.day + const monthName = date.toLocaleDateString(undefined, { + month: 'short', + }) + const isWeekend = date.getDay() === 0 || date.getDay() === 6 + + return ( +
+ + {dayName} + + + {dayNum} + + + {monthName} + +
+ ) + })} +
+ + {/* Timeline rows */} +
+ + {sampleResources.map((resource) => ( + + ))} +
+
+
+
+
+ + {/* Legend */} +
+ {sampleEvents.map((event) => { + const colorIdx = colorMap.get(event.id) ?? 0 + const color = EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] + return ( +
+
+ {event.title} +
+ ) + })} +
+ + {calendar.isPending && ( +
+ Loading... +
+ )} + + setModalState((prev) => ({ ...prev, isOpen: false }))} + onSave={handleSave} + onDelete={modalState.mode === 'edit' ? handleDelete : undefined} + initialData={modalState.initialData} + mode={modalState.mode} + /> +
+ ) +} + +function App() { + return ( + <> + + + + ) +} + +ReactDOM.createRoot(document.getElementById('root')!).render() diff --git a/examples/react/timeline/tailwind.config.js b/examples/react/timeline/tailwind.config.js new file mode 100644 index 00000000..7141e452 --- /dev/null +++ b/examples/react/timeline/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], + theme: { + extend: {}, + }, + plugins: [], +} diff --git a/examples/react/timeline/tsconfig.json b/examples/react/timeline/tsconfig.json new file mode 100644 index 00000000..a97ff8c1 --- /dev/null +++ b/examples/react/timeline/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/react/timeline/vite.config.ts b/examples/react/timeline/vite.config.ts new file mode 100644 index 00000000..9ffcc675 --- /dev/null +++ b/examples/react/timeline/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 33899aac..c903899e 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -10,11 +10,9 @@ import { useStore } from '@tanstack/react-store' import { CalendarCore, calculateDeltaMinutesFromPixels, - calculateResizedEvent, getTimeClient, } from '@tanstack/time' import type { - AvailabilityConflict, CalendarApi, CalendarCoreOptions, Event, @@ -31,6 +29,7 @@ export interface ResizeState { previewStart: string | null previewEnd: string | null targetDayDate: string | null + blocked: boolean } export interface ResizeOptions { @@ -64,6 +63,7 @@ const initialResizeState: ResizeState = { previewStart: null, previewEnd: null, targetDayDate: null, + blocked: false, } export const useCalendar = < @@ -176,507 +176,81 @@ export const useCalendar = < const totalDeltaMinutes = deltaMinutes + dayOffsetMinutes - const event = calendarOptions.events?.find((ev) => ev.id === id) - const resourceIds = event?.resources?.map((r) => r.id) - - const getUnavailableMinutesForDay = (dayDate: string) => { - const rawRanges = resourceIds?.length - ? calendarCore.getUnavailableRanges(dayDate, { - containerHeight: 1440, - resourceIds, - }) - : [] - return rawRanges.map((range) => { - const startParts = range.startTime.split(':').map(Number) - const endParts = range.endTime.split(':').map(Number) - return { - startMinutes: (startParts[0] ?? 0) * 60 + (startParts[1] ?? 0), - endMinutes: (endParts[0] ?? 0) * 60 + (endParts[1] ?? 0), - } - }) - } - - const unavailableRanges = getUnavailableMinutesForDay(targetDayDate) - - const originalStartDate = start.split('T')[0] ?? '' - const originalEndDate = end.split('T')[0] ?? '' - - let shouldBlockResize = false - let blockReason: ResizeError['reason'] = 'blocked' - let blockMessage = 'Resize blocked' - const conflicts: Array = [] - - const formatMinutesToTime = (minutes: number): string => { - const hours = Math.floor(minutes / 60) - const mins = minutes % 60 - return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}` - } - - const snapToMinutes = resizeConstraints?.snapToMinutes ?? 1 - const snapMinutes = (minutes: number): number => { - if (snapToMinutes <= 1) return minutes - return Math.round(minutes / snapToMinutes) * snapToMinutes - } - - const getDetailedConflicts = ( - dayDate: string, - startMins: number, - endMins: number, - ): Array => { - if (!resourceIds?.length) return [] - - const conflicts: Array = [] - - const details = calendarCore.getUnavailabilityDetails( - dayDate, - startMins, - endMins, - { - resourceIds, - }, - ) - - const unavailableRangesForDay = getUnavailableMinutesForDay(dayDate) - - for (const range of unavailableRangesForDay) { - if (startMins < range.endMinutes && endMins > range.startMinutes) { - const overlappingDetails = details.filter((d) => { - const resource = calendarCore.options.resources?.find( - (r) => r.id === d.resourceId, - ) - if (!resource) return false - - const resourceAvailableSlots = - resource.availability?.filter((slot) => { - const slotWeekday = new Date(dayDate).getDay() || 7 - return slot.weekdays.includes(slotWeekday) - }) || [] - - if (resourceAvailableSlots.length === 0) return true - - return !resourceAvailableSlots.some((slot) => { - const slotStartParts = slot.startTime.split(':').map(Number) - const slotEndParts = slot.endTime.split(':').map(Number) - const slotStart = - (slotStartParts[0] ?? 0) * 60 + (slotStartParts[1] ?? 0) - const slotEnd = - (slotEndParts[0] ?? 0) * 60 + (slotEndParts[1] ?? 0) - - return !( - range.endMinutes <= slotStart || range.startMinutes >= slotEnd - ) - }) - }) - - if (overlappingDetails.length > 0) { - conflicts.push({ - date: dayDate, - conflictRange: { - start: formatMinutesToTime( - Math.max(startMins, range.startMinutes), - ), - end: formatMinutesToTime(Math.min(endMins, range.endMinutes)), - }, - resourceIds: overlappingDetails.map((d) => d.resourceId), - resourceDetails: overlappingDetails.map((d) => ({ - resourceId: d.resourceId, - resourceLabel: d.resourceLabel, - reason: d.reason, - description: d.description, - })), - description: overlappingDetails - .map((d) => d.description) - .join('; '), - }) - } - } - } - - const eventsOnDay = calendarCore.getEventsByDate(dayDate) - const currentEventId = id - - for (const resourceId of resourceIds) { - const resource = calendarCore.options.resources?.find( - (r) => r.id === resourceId, - ) - if (!resource || !resource.capacity) continue - - const overlappingEvents = eventsOnDay.filter((e) => { - if (e.id === currentEventId) return false - - const eventResourceIds = e.resources?.map((r) => r.id) || [] - if (!eventResourceIds.includes(resourceId)) return false - - const eventStart = new Date(e.start) - const eventEnd = new Date(e.end) - const eventStartMins = - eventStart.getHours() * 60 + eventStart.getMinutes() - const eventEndMins = - eventEnd.getHours() * 60 + eventEnd.getMinutes() - - return startMins < eventEndMins && endMins > eventStartMins - }) - - const currentUsage = overlappingEvents.length - const maxCapacity = resource.capacity - - if (currentUsage >= maxCapacity) { - conflicts.push({ - date: dayDate, - conflictRange: { - start: formatMinutesToTime(startMins), - end: formatMinutesToTime(endMins), - }, - resourceIds: [resourceId], - resourceDetails: [ - { - resourceId: resource.id, - resourceLabel: resource.label, - reason: 'capacity', - description: `${resource.label}: Capacity exceeded (${currentUsage}/${maxCapacity} slots used)`, - capacityInfo: { - max: maxCapacity, - used: currentUsage, - remaining: 0, - }, - }, - ], - description: `${resource.label}: Capacity exceeded (${currentUsage}/${maxCapacity} slots used)`, - }) - } - } - - return conflicts - } - - if (edge === 'top' && targetDayDate < originalStartDate) { - const rawStartMinutes = - new Date(start).getHours() * 60 + - new Date(start).getMinutes() + - totalDeltaMinutes - const targetStartMinutes = ((rawStartMinutes % 1440) + 1440) % 1440 - const snappedTargetStartMinutes = snapMinutes(targetStartMinutes) - const currentStartMinutes = - new Date(start).getHours() * 60 + new Date(start).getMinutes() - - if (resourceIds?.length) { - const unavailabilityDetails = calendarCore.getUnavailabilityDetails( - targetDayDate, - snappedTargetStartMinutes, - 1440, - { resourceIds }, - ) - - if (unavailabilityDetails.length > 0) { - shouldBlockResize = true - blockReason = 'unavailable-time' - const detailsText = unavailabilityDetails - .map((d) => `${d.resourceLabel} (${d.reason})`) - .join(', ') - blockMessage = `Unavailable: Event at ${formatMinutesToTime(snappedTargetStartMinutes)} conflicts with ${detailsText}` - conflicts.push({ - date: targetDayDate, - conflictRange: { - start: formatMinutesToTime(snappedTargetStartMinutes), - end: formatMinutesToTime(1440), - }, - resourceIds: unavailabilityDetails.map((d) => d.resourceId), - resourceDetails: unavailabilityDetails.map((d) => ({ - resourceId: d.resourceId, - resourceLabel: d.resourceLabel, - reason: d.reason, - description: d.description, - })), - description: unavailabilityDetails - .map((d) => d.description) - .join('; '), - }) - } - } - - // Check if we would need to pass through unavailable time on the source day - if (!shouldBlockResize && resourceIds?.length) { - const sourceUnavailabilityDetails = - calendarCore.getUnavailabilityDetails( - originalStartDate, - 0, - currentStartMinutes, - { resourceIds }, - ) - - if (sourceUnavailabilityDetails.length > 0) { - shouldBlockResize = true - blockReason = 'unavailable-time' - const detailsText = sourceUnavailabilityDetails - .map((d) => `${d.resourceLabel} (${d.reason})`) - .join(', ') - blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalStartDate} - ${detailsText}` - conflicts.push({ - date: originalStartDate, - conflictRange: { - start: formatMinutesToTime(0), - end: formatMinutesToTime(currentStartMinutes), - }, - resourceIds: sourceUnavailabilityDetails.map((d) => d.resourceId), - resourceDetails: sourceUnavailabilityDetails.map((d) => ({ - resourceId: d.resourceId, - resourceLabel: d.resourceLabel, - reason: d.reason, - description: d.description, - })), - description: sourceUnavailabilityDetails - .map((d) => d.description) - .join('; '), - }) - } - } - } else if (edge === 'bottom' && targetDayDate > originalEndDate) { - const rawEndMinutes = - new Date(end).getHours() * 60 + - new Date(end).getMinutes() + - totalDeltaMinutes - const targetEndMinutes = ((rawEndMinutes % 1440) + 1440) % 1440 - const snappedTargetEndMinutes = snapMinutes(targetEndMinutes) - const currentEndMinutes = - new Date(end).getHours() * 60 + new Date(end).getMinutes() - - // Check if any resource is unavailable at the target time on the target day - if (resourceIds?.length) { - const unavailabilityDetails = calendarCore.getUnavailabilityDetails( - targetDayDate, - 0, // Check from start of day to end time - snappedTargetEndMinutes, - { resourceIds }, - ) - - if (unavailabilityDetails.length > 0) { - shouldBlockResize = true - blockReason = 'unavailable-time' - const detailsText = unavailabilityDetails - .map((d) => `${d.resourceLabel} (${d.reason})`) - .join(', ') - blockMessage = `Unavailable: Event ending at ${formatMinutesToTime(snappedTargetEndMinutes)} conflicts with ${detailsText}` - conflicts.push({ - date: targetDayDate, - conflictRange: { - start: formatMinutesToTime(0), - end: formatMinutesToTime(snappedTargetEndMinutes), - }, - resourceIds: unavailabilityDetails.map((d) => d.resourceId), - resourceDetails: unavailabilityDetails.map((d) => ({ - resourceId: d.resourceId, - resourceLabel: d.resourceLabel, - reason: d.reason, - description: d.description, - })), - description: unavailabilityDetails - .map((d) => d.description) - .join('; '), - }) - } - } - - // Check if we would need to pass through unavailable time on the source day - if (!shouldBlockResize && resourceIds?.length) { - const sourceUnavailabilityDetails = - calendarCore.getUnavailabilityDetails( - originalEndDate, - currentEndMinutes, - 1440, - { resourceIds }, - ) - - if (sourceUnavailabilityDetails.length > 0) { - shouldBlockResize = true - blockReason = 'unavailable-time' - const detailsText = sourceUnavailabilityDetails - .map((d) => `${d.resourceLabel} (${d.reason})`) - .join(', ') - blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalEndDate} - ${detailsText}` - conflicts.push({ - date: originalEndDate, - conflictRange: { - start: formatMinutesToTime(currentEndMinutes), - end: formatMinutesToTime(1440), - }, - resourceIds: sourceUnavailabilityDetails.map((d) => d.resourceId), - resourceDetails: sourceUnavailabilityDetails.map((d) => ({ - resourceId: d.resourceId, - resourceLabel: d.resourceLabel, - reason: d.reason, - description: d.description, - })), - description: sourceUnavailabilityDetails - .map((d) => d.description) - .join('; '), - }) - } - } - } - - // Also check for conflicts when resizing within the same day - if ( - !shouldBlockResize && - targetDayDate === originalStartDate && - targetDayDate === originalEndDate - ) { - // Calculate the new time range based on the resize - const rawStartMinutes = - new Date(start).getHours() * 60 + - new Date(start).getMinutes() + - (edge === 'top' ? totalDeltaMinutes : 0) - const rawEndMinutes = - new Date(end).getHours() * 60 + - new Date(end).getMinutes() + - (edge === 'bottom' ? totalDeltaMinutes : 0) - - const snappedStartMinutes = snapMinutes( - ((rawStartMinutes % 1440) + 1440) % 1440, - ) - const snappedEndMinutes = snapMinutes( - ((rawEndMinutes % 1440) + 1440) % 1440, - ) - - // Directly check if any resource is unavailable for the new time range - // This is more reliable than using getUnavailableRanges which merges availability - if (resourceIds?.length) { - const unavailabilityDetails = calendarCore.getUnavailabilityDetails( - targetDayDate, - snappedStartMinutes, - snappedEndMinutes, - { resourceIds }, - ) - - if (unavailabilityDetails.length > 0) { - shouldBlockResize = true - blockReason = 'unavailable-time' - const detailsText = unavailabilityDetails - .map((d) => `${d.resourceLabel} (${d.reason})`) - .join(', ') - blockMessage = `Unavailable: Event at ${formatMinutesToTime(snappedStartMinutes)}-${formatMinutesToTime(snappedEndMinutes)} conflicts with ${detailsText}` - conflicts.push({ - date: targetDayDate, - conflictRange: { - start: formatMinutesToTime(snappedStartMinutes), - end: formatMinutesToTime(snappedEndMinutes), - }, - resourceIds: unavailabilityDetails.map((d) => d.resourceId), - resourceDetails: unavailabilityDetails.map((d) => ({ - resourceId: d.resourceId, - resourceLabel: d.resourceLabel, - reason: d.reason, - description: d.description, - })), - description: unavailabilityDetails - .map((d) => d.description) - .join('; '), - }) - } - } - - // Also check capacity constraints if not already blocked - if (!shouldBlockResize) { - const detailedConflicts = getDetailedConflicts( - targetDayDate, - snappedStartMinutes, - snappedEndMinutes, - ) - - // Filter to only capacity conflicts (availability already checked above) - const capacityConflicts = detailedConflicts.filter((c) => - c.resourceDetails.some((d) => d.reason === 'capacity'), - ) - - if (capacityConflicts.length > 0) { - shouldBlockResize = true - blockReason = 'unavailable-time' - const conflict = capacityConflicts[0]! - const detailsText = conflict.resourceDetails - .map((d) => `${d.resourceLabel} (${d.reason})`) - .join(', ') - blockMessage = `Unavailable: Event at ${formatMinutesToTime(snappedStartMinutes)}-${formatMinutesToTime(snappedEndMinutes)} conflicts with ${detailsText}` - conflicts.push(...capacityConflicts) - } - } - } + const validation = calendarCore.validateResize({ + eventId: id, + originalStart: start, + originalEnd: end, + edge, + totalDeltaMinutes, + targetDayDate, + originalDayDate, + constraints: resizeConstraints, + }) - // Emit error if resize is blocked (throttle to avoid emitting on every mouse move) - if (shouldBlockResize) { + if (validation.blocked && validation.error) { const event = calendarOptions.events?.find((ev) => ev.id === id) const now = Date.now() const lastError = lastEmittedErrorRef.current - // Only emit if this is a different error or it's been more than 500ms const shouldEmitError = !lastError || lastError.eventId !== id || - lastError.message !== blockMessage || + lastError.message !== validation.error.message || now - lastError.timestamp > 500 if (shouldEmitError) { const resizeError: ResizeError = { eventId: id, eventTitle: event?.title ?? 'Unknown Event', - reason: blockReason, - message: blockMessage, + reason: validation.error.reason, + message: validation.error.message, originalStart: start, originalEnd: end, - conflicts: conflicts.length > 0 ? conflicts : undefined, + conflicts: + validation.error.conflicts.length > 0 + ? validation.error.conflicts + : undefined, } - // Emit to TimeClient for devtools getTimeClient().emit('event:resize:error', { eventId: id, eventTitle: event?.title ?? 'Unknown Event', - reason: blockReason, - message: blockMessage, + reason: validation.error.reason, + message: validation.error.message, originalStart: start, originalEnd: end, - conflicts: conflicts.length > 0 ? conflicts : undefined, + conflicts: + validation.error.conflicts.length > 0 + ? validation.error.conflicts + : undefined, }) - // Call user-provided error handler resize?.onResizeError?.(resizeError) - // Track this error emission lastEmittedErrorRef.current = { eventId: id, - message: blockMessage, + message: validation.error.message, timestamp: now, } } } else { - // Clear last error when resize is no longer blocked lastEmittedErrorRef.current = null } - const effectiveDeltaMinutes = shouldBlockResize ? 0 : totalDeltaMinutes - - const result = calculateResizedEvent({ - originalStart: start, - originalEnd: end, - edge, - deltaMinutes: effectiveDeltaMinutes, - timeZone: calendarOptions.timeZone ?? 'UTC', - constraints: { - ...resizeConstraints, - unavailableRanges: shouldBlockResize ? [] : unavailableRanges, - }, - }) - updateResizeState({ eventId: id, - previewStart: result.start, - previewEnd: result.end, - targetDayDate: shouldBlockResize ? originalDayDate : targetDayDate, + previewStart: validation.result.start, + previewEnd: validation.result.end, + targetDayDate: validation.targetDayDate, + blocked: validation.blocked, }) }, [ containerHeight, - calendarOptions.timeZone, calendarOptions.events, calendarCore, resizeConstraints, + resize, getDayFromPoint, updateResizeState, ], @@ -687,7 +261,8 @@ export const useCalendar = < if ( currentState.eventId && currentState.previewStart && - currentState.previewEnd + currentState.previewEnd && + !currentState.blocked ) { calendarCore.updateEvent(currentState.eventId, { start: currentState.previewStart, diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index 585b4a8b..b6644663 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -4,11 +4,19 @@ import { splitMultiDayEvents } from './splitMultiDayEvents' import { getEventProps } from './getEventProps' import { groupDaysBy } from './groupDaysBy' import { getTimeSlots } from './getTimeSlots' +import { calculateResizedEvent } from './getResizeProps' import { DateCore } from './date-core' import type { DateCoreOptions, ParsedDateCoreOptions } from './date-core' import type { + ResizeConstraints, + ResizeEdge, + UnavailableTimeRange, +} from './getResizeProps' +import type { + AvailabilityConflict, Day, Event, + ResizeError, Resource, TimeSlot, UnavailableRange, @@ -131,11 +139,40 @@ export interface CalendarApi< CalendarActions, ConvertTemporalToString> {} -/** - * Core functionality for a calendar system, managing the state and operations of the calendar, - * such as navigating through time periods, handling events, and adjusting settings. - * @template TEvent - The type of events managed by the calendar. - */ +export interface ValidateResizeOptions { + eventId: string + originalStart: string + originalEnd: string + edge: ResizeEdge + totalDeltaMinutes: number + targetDayDate: string + originalDayDate: string + constraints?: ResizeConstraints +} + +export interface ValidateResizeResult { + blocked: boolean + error?: { + reason: ResizeError['reason'] + message: string + conflicts: Array + } + result: { + start: string + end: string + durationMinutes: number + } + targetDayDate: string +} + +const MINUTES_IN_DAY = 24 * 60 + +const formatMinutesToTime = (minutes: number): string => { + const hours = Math.floor(minutes / 60) + const mins = minutes % 60 + return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}` +} + type ParsedCalendarCoreOptions< TResource extends Resource, TEvent extends Event, @@ -533,4 +570,475 @@ export class CalendarCore< return details } + + private getUnavailableMinuteRanges( + date: string, + options?: { resourceIds?: Array }, + ): Array { + const rawRanges = this.getUnavailableRanges(date, { + containerHeight: MINUTES_IN_DAY, + resourceIds: options?.resourceIds, + }) + return rawRanges.map((range) => { + const startParts = range.startTime.split(':').map(Number) + const endParts = range.endTime.split(':').map(Number) + return { + startMinutes: (startParts[0] ?? 0) * 60 + (startParts[1] ?? 0), + endMinutes: (endParts[0] ?? 0) * 60 + (endParts[1] ?? 0), + } + }) + } + + private getResizeConflicts( + dayDate: string, + startMins: number, + endMins: number, + eventId: string, + originalStart: string, + originalEnd: string, + resourceIds: Array, + ): Array { + const conflicts: Array = [] + + const details = this.getUnavailabilityDetails(dayDate, startMins, endMins, { + resourceIds, + }) + + const unavailableRangesForDay = this.getUnavailableMinuteRanges(dayDate, { + resourceIds, + }) + + const plainDate = Temporal.PlainDate.from(dayDate) + const weekday = plainDate.dayOfWeek + + for (const range of unavailableRangesForDay) { + if (startMins < range.endMinutes && endMins > range.startMinutes) { + const overlappingDetails = details.filter((d) => { + const resource = this.options.resources?.find( + (r) => r.id === d.resourceId, + ) + if (!resource) return false + + const resourceAvailableSlots = + resource.availability?.filter((slot) => + slot.weekdays.includes(weekday), + ) || [] + + if (resourceAvailableSlots.length === 0) return true + + return !resourceAvailableSlots.some((slot) => { + const slotStartParts = slot.startTime.split(':').map(Number) + const slotEndParts = slot.endTime.split(':').map(Number) + const slotStart = + (slotStartParts[0] ?? 0) * 60 + (slotStartParts[1] ?? 0) + const slotEnd = (slotEndParts[0] ?? 0) * 60 + (slotEndParts[1] ?? 0) + + return !( + range.endMinutes <= slotStart || range.startMinutes >= slotEnd + ) + }) + }) + + if (overlappingDetails.length > 0) { + conflicts.push({ + date: dayDate, + conflictRange: { + start: formatMinutesToTime( + Math.max(startMins, range.startMinutes), + ), + end: formatMinutesToTime(Math.min(endMins, range.endMinutes)), + }, + resourceIds: overlappingDetails.map((d) => d.resourceId), + resourceDetails: overlappingDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: overlappingDetails + .map((d) => d.description) + .join('; '), + }) + } + } + } + + const eventsOnDay = this.getEventsByDate(dayDate) + + const origStartDate = new Date(originalStart) + const origEndDate = new Date(originalEnd) + const origStartMins = + origStartDate.getHours() * 60 + origStartDate.getMinutes() + const origEndMins = origEndDate.getHours() * 60 + origEndDate.getMinutes() + + for (const resourceId of resourceIds) { + const resource = this.options.resources?.find((r) => r.id === resourceId) + if (!resource || !resource.capacity) continue + + const getOverlappingEvents = ( + checkStartMins: number, + checkEndMins: number, + ) => + eventsOnDay.filter((e) => { + if (e.id === eventId) return false + + const eventResourceIds = e.resources?.map((r) => r.id) || [] + if (!eventResourceIds.includes(resourceId)) return false + + const eventStart = new Date(e.start) + const eventEnd = new Date(e.end) + const eventStartMins = + eventStart.getHours() * 60 + eventStart.getMinutes() + const eventEndMins = eventEnd.getHours() * 60 + eventEnd.getMinutes() + + return checkStartMins < eventEndMins && checkEndMins > eventStartMins + }) + + const overlappingEvents = getOverlappingEvents(startMins, endMins) + const previouslyOverlapping = getOverlappingEvents( + origStartMins, + origEndMins, + ) + + const currentUsage = overlappingEvents.length + const previousUsage = previouslyOverlapping.length + const maxCapacity = resource.capacity + + if (currentUsage > previousUsage && currentUsage >= maxCapacity) { + conflicts.push({ + date: dayDate, + conflictRange: { + start: formatMinutesToTime(startMins), + end: formatMinutesToTime(endMins), + }, + resourceIds: [resourceId], + resourceDetails: [ + { + resourceId: resource.id, + resourceLabel: resource.label, + reason: 'capacity', + description: `${resource.label}: Capacity exceeded (${currentUsage}/${maxCapacity} slots used)`, + capacityInfo: { + max: maxCapacity, + used: currentUsage, + remaining: 0, + }, + }, + ], + description: `${resource.label}: Capacity exceeded (${currentUsage}/${maxCapacity} slots used)`, + }) + } + } + + return conflicts + } + + validateResize(options: ValidateResizeOptions): ValidateResizeResult { + const { + eventId, + originalStart, + originalEnd, + edge, + totalDeltaMinutes, + targetDayDate, + originalDayDate, + constraints, + } = options + + const event = this.options.events?.find((ev) => ev.id === eventId) + const resourceIds = event?.resources?.map((r) => r.id) + + const unavailableRanges = this.getUnavailableMinuteRanges(targetDayDate, { + resourceIds, + }) + + const originalStartDate = originalStart.split('T')[0] ?? '' + const originalEndDate = originalEnd.split('T')[0] ?? '' + + let shouldBlockResize = false + let blockReason: ResizeError['reason'] = 'blocked' + let blockMessage = 'Resize blocked' + const conflicts: Array = [] + + const snapToMinutes = constraints?.snapToMinutes ?? 1 + const snapMins = (minutes: number): number => { + if (snapToMinutes <= 1) return minutes + return Math.round(minutes / snapToMinutes) * snapToMinutes + } + + if (edge === 'top' && targetDayDate < originalStartDate) { + const rawStartMinutes = + new Date(originalStart).getHours() * 60 + + new Date(originalStart).getMinutes() + + totalDeltaMinutes + const targetStartMinutes = + ((rawStartMinutes % MINUTES_IN_DAY) + MINUTES_IN_DAY) % MINUTES_IN_DAY + const snappedTargetStartMinutes = snapMins(targetStartMinutes) + const currentStartMinutes = + new Date(originalStart).getHours() * 60 + + new Date(originalStart).getMinutes() + + if (resourceIds?.length) { + const unavailabilityDetails = this.getUnavailabilityDetails( + targetDayDate, + snappedTargetStartMinutes, + MINUTES_IN_DAY, + { resourceIds }, + ) + + if (unavailabilityDetails.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const detailsText = unavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Unavailable: Event at ${formatMinutesToTime(snappedTargetStartMinutes)} conflicts with ${detailsText}` + conflicts.push({ + date: targetDayDate, + conflictRange: { + start: formatMinutesToTime(snappedTargetStartMinutes), + end: formatMinutesToTime(MINUTES_IN_DAY), + }, + resourceIds: unavailabilityDetails.map((d) => d.resourceId), + resourceDetails: unavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: unavailabilityDetails + .map((d) => d.description) + .join('; '), + }) + } + } + + if (!shouldBlockResize && resourceIds?.length) { + const sourceUnavailabilityDetails = this.getUnavailabilityDetails( + originalStartDate, + 0, + currentStartMinutes, + { resourceIds }, + ) + + if (sourceUnavailabilityDetails.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const detailsText = sourceUnavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalStartDate} - ${detailsText}` + conflicts.push({ + date: originalStartDate, + conflictRange: { + start: formatMinutesToTime(0), + end: formatMinutesToTime(currentStartMinutes), + }, + resourceIds: sourceUnavailabilityDetails.map((d) => d.resourceId), + resourceDetails: sourceUnavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: sourceUnavailabilityDetails + .map((d) => d.description) + .join('; '), + }) + } + } + } else if (edge === 'bottom' && targetDayDate > originalEndDate) { + const rawEndMinutes = + new Date(originalEnd).getHours() * 60 + + new Date(originalEnd).getMinutes() + + totalDeltaMinutes + const targetEndMinutes = + ((rawEndMinutes % MINUTES_IN_DAY) + MINUTES_IN_DAY) % MINUTES_IN_DAY + const snappedTargetEndMinutes = snapMins(targetEndMinutes) + const currentEndMinutes = + new Date(originalEnd).getHours() * 60 + + new Date(originalEnd).getMinutes() + + if (resourceIds?.length) { + const unavailabilityDetails = this.getUnavailabilityDetails( + targetDayDate, + 0, + snappedTargetEndMinutes, + { resourceIds }, + ) + + if (unavailabilityDetails.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const detailsText = unavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Unavailable: Event ending at ${formatMinutesToTime(snappedTargetEndMinutes)} conflicts with ${detailsText}` + conflicts.push({ + date: targetDayDate, + conflictRange: { + start: formatMinutesToTime(0), + end: formatMinutesToTime(snappedTargetEndMinutes), + }, + resourceIds: unavailabilityDetails.map((d) => d.resourceId), + resourceDetails: unavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: unavailabilityDetails + .map((d) => d.description) + .join('; '), + }) + } + } + + if (!shouldBlockResize && resourceIds?.length) { + const sourceUnavailabilityDetails = this.getUnavailabilityDetails( + originalEndDate, + currentEndMinutes, + MINUTES_IN_DAY, + { resourceIds }, + ) + + if (sourceUnavailabilityDetails.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const detailsText = sourceUnavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Cannot resize: Would need to pass through unavailable time on ${originalEndDate} - ${detailsText}` + conflicts.push({ + date: originalEndDate, + conflictRange: { + start: formatMinutesToTime(currentEndMinutes), + end: formatMinutesToTime(MINUTES_IN_DAY), + }, + resourceIds: sourceUnavailabilityDetails.map((d) => d.resourceId), + resourceDetails: sourceUnavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: sourceUnavailabilityDetails + .map((d) => d.description) + .join('; '), + }) + } + } + } + + if ( + !shouldBlockResize && + targetDayDate === originalStartDate && + targetDayDate === originalEndDate + ) { + const rawStartMinutes = + new Date(originalStart).getHours() * 60 + + new Date(originalStart).getMinutes() + + (edge === 'top' ? totalDeltaMinutes : 0) + const rawEndMinutes = + new Date(originalEnd).getHours() * 60 + + new Date(originalEnd).getMinutes() + + (edge === 'bottom' ? totalDeltaMinutes : 0) + + const snappedStartMinutes = snapMins( + ((rawStartMinutes % MINUTES_IN_DAY) + MINUTES_IN_DAY) % MINUTES_IN_DAY, + ) + const snappedEndMinutes = snapMins( + ((rawEndMinutes % MINUTES_IN_DAY) + MINUTES_IN_DAY) % MINUTES_IN_DAY, + ) + + if (resourceIds?.length) { + const unavailabilityDetails = this.getUnavailabilityDetails( + targetDayDate, + snappedStartMinutes, + snappedEndMinutes, + { resourceIds }, + ) + + if (unavailabilityDetails.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const detailsText = unavailabilityDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Unavailable: Event at ${formatMinutesToTime(snappedStartMinutes)}-${formatMinutesToTime(snappedEndMinutes)} conflicts with ${detailsText}` + conflicts.push({ + date: targetDayDate, + conflictRange: { + start: formatMinutesToTime(snappedStartMinutes), + end: formatMinutesToTime(snappedEndMinutes), + }, + resourceIds: unavailabilityDetails.map((d) => d.resourceId), + resourceDetails: unavailabilityDetails.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: unavailabilityDetails + .map((d) => d.description) + .join('; '), + }) + } + } + + if (!shouldBlockResize && resourceIds?.length) { + const detailedConflicts = this.getResizeConflicts( + targetDayDate, + snappedStartMinutes, + snappedEndMinutes, + eventId, + originalStart, + originalEnd, + resourceIds, + ) + + const capacityConflicts = detailedConflicts.filter((c) => + c.resourceDetails.some((d) => d.reason === 'capacity'), + ) + + if (capacityConflicts.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const conflict = capacityConflicts[0]! + const detailsText = conflict.resourceDetails + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Unavailable: Event at ${formatMinutesToTime(snappedStartMinutes)}-${formatMinutesToTime(snappedEndMinutes)} conflicts with ${detailsText}` + conflicts.push(...capacityConflicts) + } + } + } + + const effectiveDeltaMinutes = shouldBlockResize ? 0 : totalDeltaMinutes + + const result = calculateResizedEvent({ + originalStart, + originalEnd, + edge, + deltaMinutes: effectiveDeltaMinutes, + timeZone: this.options.timeZone, + constraints: { + ...constraints, + unavailableRanges: shouldBlockResize ? [] : unavailableRanges, + }, + }) + + return { + blocked: shouldBlockResize, + error: shouldBlockResize + ? { + reason: blockReason, + message: blockMessage, + conflicts, + } + : undefined, + result, + targetDayDate: shouldBlockResize ? originalDayDate : targetDayDate, + } + } } diff --git a/packages/time/src/calendar/tests/calendar.test.ts b/packages/time/src/calendar/tests/calendar.test.ts new file mode 100644 index 00000000..9299d414 --- /dev/null +++ b/packages/time/src/calendar/tests/calendar.test.ts @@ -0,0 +1,1295 @@ +import { describe, expect, test, beforeEach } from 'vitest' +import { CalendarCore } from '../calendar' +import type { Event, Resource } from '../types' + +type TestResource = Resource +type TestEvent = Event + +function createCalendar( + overrides: Partial< + ConstructorParameters>[0] + > = {}, +) { + return new CalendarCore({ + viewMode: { value: 1, unit: 'week' }, + timeZone: 'UTC', + ...overrides, + }) +} + +const weekdayResource: TestResource = { + id: 'r1', + label: 'Weekday Room', + capacity: 2, + availability: [ + { weekdays: [1, 2, 3, 4, 5], startTime: '08:00', endTime: '17:00' }, + ], +} + +const afternoonResource: TestResource = { + id: 'r2', + label: 'Afternoon Room', + capacity: 1, + availability: [ + { weekdays: [1, 2, 3, 4, 5], startTime: '12:00', endTime: '18:00' }, + ], +} + +const allDayResource: TestResource = { + id: 'r3', + label: 'All Day Room', + availability: [ + { weekdays: [1, 2, 3, 4, 5, 6, 7], startTime: '00:00', endTime: '24:00' }, + ], +} + +const noAvailabilityResource: TestResource = { + id: 'r4', + label: 'No Availability Room', +} + +const DATE_MON = '2024-03-18' +const DATE_TUE = '2024-03-19' + +describe('CalendarCore', () => { + describe('constructor', () => { + test('initializes with events and resources', () => { + const events: Array = [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ] + const cal = createCalendar({ events, resources: [weekdayResource] }) + + expect(cal.options.events).toHaveLength(1) + expect(cal.options.resources).toHaveLength(1) + }) + }) + + describe('getEventsByDate', () => { + test('returns events matching the date', () => { + const events: Array = [ + { + id: '1', + title: 'Mon Event', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + { + id: '2', + title: 'Tue Event', + start: `${DATE_TUE}T14:00:00`, + end: `${DATE_TUE}T15:00:00`, + }, + ] + const cal = createCalendar({ events }) + + const monEvents = cal.getEventsByDate(DATE_MON) + expect(monEvents).toHaveLength(1) + expect(monEvents[0]!.title).toBe('Mon Event') + }) + + test('returns empty array for date without events', () => { + const cal = createCalendar({ events: [] }) + + expect(cal.getEventsByDate(DATE_MON)).toEqual([]) + }) + + test('splits multi-day events across dates', () => { + const events: Array = [ + { + id: '1', + title: 'Multi', + start: `${DATE_MON}T14:00:00`, + end: `${DATE_TUE}T10:00:00`, + }, + ] + const cal = createCalendar({ events }) + + const monEvents = cal.getEventsByDate(DATE_MON) + const tueEvents = cal.getEventsByDate(DATE_TUE) + + expect(monEvents).toHaveLength(1) + expect(tueEvents).toHaveLength(1) + expect(monEvents[0]!._originalStart).toBe(`${DATE_MON}T14:00:00`) + expect(tueEvents[0]!._originalEnd).toBe(`${DATE_TUE}T10:00:00`) + }) + + test('returns empty when no events configured', () => { + const cal = createCalendar() + + expect(cal.getEventsByDate(DATE_MON)).toEqual([]) + }) + }) + + describe('addEvent', () => { + test('adds an event to an empty calendar', () => { + const cal = createCalendar() + const event: TestEvent = { + id: '1', + title: 'New', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + } + + cal.addEvent(event) + + expect(cal.options.events).toHaveLength(1) + expect(cal.getEventsByDate(DATE_MON)).toHaveLength(1) + }) + + test('adds an event to existing events', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Existing', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ], + }) + + cal.addEvent({ + id: '2', + title: 'New', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T12:00:00`, + }) + + expect(cal.options.events).toHaveLength(2) + }) + + test('increments store eventsVersion', () => { + const cal = createCalendar() + const versionBefore = cal.store.state.eventsVersion + + cal.addEvent({ + id: '1', + title: 'E', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }) + + expect(cal.store.state.eventsVersion).toBe(versionBefore + 1) + }) + }) + + describe('updateEvent', () => { + test('updates an existing event', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Old Title', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ], + }) + + cal.updateEvent('1', { title: 'New Title' }) + + expect(cal.options.events![0]!.title).toBe('New Title') + }) + + test('updates start/end times', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ], + }) + + cal.updateEvent('1', { + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T12:00:00`, + }) + + expect(cal.options.events![0]!.start).toBe(`${DATE_MON}T11:00:00`) + expect(cal.options.events![0]!.end).toBe(`${DATE_MON}T12:00:00`) + }) + + test('does nothing when event not found', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ], + }) + const versionBefore = cal.store.state.eventsVersion + + cal.updateEvent('nonexistent', { title: 'X' }) + + expect(cal.store.state.eventsVersion).toBe(versionBefore) + expect(cal.options.events![0]!.title).toBe('E') + }) + + test('does nothing when events is null', () => { + const cal = createCalendar() + + cal.updateEvent('1', { title: 'X' }) + + expect(cal.options.events).toBeNull() + }) + }) + + describe('removeEvent', () => { + test('removes an existing event', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T12:00:00`, + }, + ], + }) + + cal.removeEvent('1') + + expect(cal.options.events).toHaveLength(1) + expect(cal.options.events![0]!.id).toBe('2') + }) + + test('does nothing when event not found', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ], + }) + const versionBefore = cal.store.state.eventsVersion + + cal.removeEvent('nonexistent') + + expect(cal.store.state.eventsVersion).toBe(versionBefore) + expect(cal.options.events).toHaveLength(1) + }) + + test('does nothing when events is null', () => { + const cal = createCalendar() + + cal.removeEvent('1') + + expect(cal.options.events).toBeNull() + }) + }) + + describe('getUnavailableRanges', () => { + test('returns empty when no resources', () => { + const cal = createCalendar({ resources: [] }) + + expect(cal.getUnavailableRanges(DATE_MON)).toEqual([]) + }) + + test('returns full day unavailable when resource has no availability for that weekday', () => { + const weekendOnlyResource: TestResource = { + id: 'w', + label: 'Weekend Only', + availability: [ + { weekdays: [6, 7], startTime: '10:00', endTime: '15:00' }, + ], + } + const cal = createCalendar({ resources: [weekendOnlyResource] }) + + const ranges = cal.getUnavailableRanges(DATE_MON) + + expect(ranges).toHaveLength(1) + expect(ranges[0]!.startTime).toBe('00:00') + expect(ranges[0]!.endTime).toBe('24:00') + }) + + test('returns unavailable ranges before and after availability window', () => { + const cal = createCalendar({ resources: [weekdayResource] }) + + const ranges = cal.getUnavailableRanges(DATE_MON, { + containerHeight: 1440, + }) + + expect(ranges).toHaveLength(2) + expect(ranges[0]).toEqual({ + top: 0, + height: 480, + startTime: '00:00', + endTime: '08:00', + }) + expect(ranges[1]).toEqual({ + top: 1020, + height: 420, + startTime: '17:00', + endTime: '24:00', + }) + }) + + test('merges overlapping availability from multiple resources', () => { + const cal = createCalendar({ + resources: [weekdayResource, afternoonResource], + }) + + const ranges = cal.getUnavailableRanges(DATE_MON, { + containerHeight: 1440, + }) + + expect(ranges).toHaveLength(2) + expect(ranges[0]!.startTime).toBe('00:00') + expect(ranges[0]!.endTime).toBe('08:00') + expect(ranges[1]!.startTime).toBe('18:00') + expect(ranges[1]!.endTime).toBe('24:00') + }) + + test('filters by resourceIds when provided', () => { + const cal = createCalendar({ + resources: [weekdayResource, afternoonResource], + }) + + const ranges = cal.getUnavailableRanges(DATE_MON, { + containerHeight: 1440, + resourceIds: ['r2'], + }) + + expect(ranges).toHaveLength(2) + expect(ranges[0]!.endTime).toBe('12:00') + expect(ranges[1]!.startTime).toBe('18:00') + }) + + test('returns no unavailable ranges for all-day resource', () => { + const cal = createCalendar({ resources: [allDayResource] }) + + const ranges = cal.getUnavailableRanges(DATE_MON, { + containerHeight: 1440, + }) + + expect(ranges).toHaveLength(0) + }) + + test('returns full day when resource has no availability config', () => { + const cal = createCalendar({ resources: [noAvailabilityResource] }) + + const ranges = cal.getUnavailableRanges(DATE_MON) + + expect(ranges).toHaveLength(1) + expect(ranges[0]!.startTime).toBe('00:00') + expect(ranges[0]!.endTime).toBe('24:00') + }) + + test('scales pixel positions to containerHeight', () => { + const cal = createCalendar({ resources: [weekdayResource] }) + + const ranges = cal.getUnavailableRanges(DATE_MON, { + containerHeight: 720, + }) + + expect(ranges[0]!.top).toBe(0) + expect(ranges[0]!.height).toBe(240) + }) + }) + + describe('getUnavailabilityDetails', () => { + test('returns empty when no resources', () => { + const cal = createCalendar({ resources: [] }) + + expect(cal.getUnavailabilityDetails(DATE_MON, 480, 600)).toEqual([]) + }) + + test('returns no-availability for resource without availability config', () => { + const cal = createCalendar({ resources: [noAvailabilityResource] }) + + const details = cal.getUnavailabilityDetails(DATE_MON, 480, 600, { + resourceIds: ['r4'], + }) + + expect(details).toHaveLength(1) + expect(details[0]!.reason).toBe('no-availability') + }) + + test('returns outside-hours when resource not available on that weekday', () => { + const weekendResource: TestResource = { + id: 'w', + label: 'Weekend', + availability: [ + { weekdays: [6, 7], startTime: '10:00', endTime: '15:00' }, + ], + } + const cal = createCalendar({ resources: [weekendResource] }) + + const details = cal.getUnavailabilityDetails(DATE_MON, 600, 720, { + resourceIds: ['w'], + }) + + expect(details).toHaveLength(1) + expect(details[0]!.reason).toBe('outside-hours') + expect(details[0]!.description).toContain('Not available on this day') + }) + + test('returns outside-hours when time range exceeds availability window', () => { + const cal = createCalendar({ resources: [weekdayResource] }) + + const details = cal.getUnavailabilityDetails(DATE_MON, 420, 540, { + resourceIds: ['r1'], + }) + + expect(details).toHaveLength(1) + expect(details[0]!.reason).toBe('outside-hours') + expect(details[0]!.description).toContain('08:00-17:00') + }) + + test('returns empty when time range is within availability', () => { + const cal = createCalendar({ resources: [weekdayResource] }) + + const details = cal.getUnavailabilityDetails(DATE_MON, 480, 600, { + resourceIds: ['r1'], + }) + + expect(details).toHaveLength(0) + }) + + test('checks multiple resources independently', () => { + const cal = createCalendar({ + resources: [weekdayResource, afternoonResource], + }) + + const details = cal.getUnavailabilityDetails(DATE_MON, 480, 600, { + resourceIds: ['r1', 'r2'], + }) + + expect(details).toHaveLength(1) + expect(details[0]!.resourceId).toBe('r2') + expect(details[0]!.reason).toBe('outside-hours') + }) + + test('uses all resources when resourceIds not specified', () => { + const cal = createCalendar({ + resources: [weekdayResource, noAvailabilityResource], + }) + + const details = cal.getUnavailabilityDetails(DATE_MON, 480, 600) + + expect(details).toHaveLength(1) + expect(details[0]!.resourceId).toBe('r4') + }) + }) + + describe('validateResize', () => { + const baseResizeOptions = { + constraints: { snapToMinutes: 15, minDurationMinutes: 15 }, + } + + describe('same-day resize within availability', () => { + test('allows extending bottom edge within available time', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Meeting', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'bottom', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + expect(result.error).toBeUndefined() + }) + + test('allows shrinking top edge within available time', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Meeting', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T12:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T12:00:00`, + edge: 'top', + totalDeltaMinutes: 30, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + }) + }) + + describe('same-day resize blocked by availability', () => { + test('blocks extending bottom edge into unavailable time', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Meeting', + start: `${DATE_MON}T16:00:00`, + end: `${DATE_MON}T16:45:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T16:00:00`, + originalEnd: `${DATE_MON}T16:45:00`, + edge: 'bottom', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('unavailable-time') + expect(result.error?.conflicts.length).toBeGreaterThan(0) + }) + + test('blocks extending top edge into unavailable time', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Meeting', + start: `${DATE_MON}T08:15:00`, + end: `${DATE_MON}T09:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T08:15:00`, + originalEnd: `${DATE_MON}T09:00:00`, + edge: 'top', + totalDeltaMinutes: -30, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('unavailable-time') + }) + }) + + describe('capacity constraints', () => { + test('allows resize when event already coexists with other events at capacity', () => { + const resource: TestResource = { + id: 'cap1', + label: 'Cap Room', + capacity: 1, + availability: [ + { weekdays: [1, 2, 3, 4, 5], startTime: '08:00', endTime: '17:00' }, + ], + } + const cal = createCalendar({ + events: [ + { + id: 'conf', + title: 'Conference', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T16:00:00`, + resources: [resource], + }, + { + id: 'lunch', + title: 'Lunch', + start: `${DATE_MON}T12:00:00`, + end: `${DATE_MON}T13:00:00`, + resources: [resource], + }, + ], + resources: [resource], + }) + + const result = cal.validateResize({ + eventId: 'lunch', + originalStart: `${DATE_MON}T12:00:00`, + originalEnd: `${DATE_MON}T13:00:00`, + edge: 'bottom', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + }) + + test('blocks resize when it would create NEW capacity conflicts', () => { + const resource: TestResource = { + id: 'cap1', + label: 'Cap Room', + capacity: 1, + availability: [ + { weekdays: [1, 2, 3, 4, 5], startTime: '08:00', endTime: '17:00' }, + ], + } + const cal = createCalendar({ + events: [ + { + id: 'morning', + title: 'Morning', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + resources: [resource], + }, + { + id: 'afternoon', + title: 'Afternoon', + start: `${DATE_MON}T14:00:00`, + end: `${DATE_MON}T15:00:00`, + resources: [resource], + }, + { + id: 'target', + title: 'Target', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T12:00:00`, + resources: [resource], + }, + ], + resources: [resource], + }) + + const result = cal.validateResize({ + eventId: 'target', + originalStart: `${DATE_MON}T11:00:00`, + originalEnd: `${DATE_MON}T12:00:00`, + edge: 'bottom', + totalDeltaMinutes: 180, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect( + result.error?.conflicts.some((c) => + c.resourceDetails.some((d) => d.reason === 'capacity'), + ), + ).toBe(true) + }) + + test('allows resize when capacity is not exceeded', () => { + const resource: TestResource = { + id: 'cap2', + label: 'Big Room', + capacity: 3, + availability: [ + { weekdays: [1, 2, 3, 4, 5], startTime: '08:00', endTime: '17:00' }, + ], + } + const cal = createCalendar({ + events: [ + { + id: 'other', + title: 'Other', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T15:00:00`, + resources: [resource], + }, + { + id: 'target', + title: 'Target', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [resource], + }, + ], + resources: [resource], + }) + + const result = cal.validateResize({ + eventId: 'target', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'bottom', + totalDeltaMinutes: 120, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + }) + }) + + describe('event without resources', () => { + test('allows resize freely when event has no resources', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Free', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'bottom', + totalDeltaMinutes: 600, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + }) + }) + + describe('snap to minutes', () => { + test('snaps resize delta to nearest interval', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [allDayResource], + }, + ], + resources: [allDayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'bottom', + totalDeltaMinutes: 37, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + constraints: { snapToMinutes: 15, minDurationMinutes: 15 }, + }) + + expect(result.blocked).toBe(false) + const endTime = result.result.end + const endMinutes = + new Date(endTime).getHours() * 60 + new Date(endTime).getMinutes() + expect(endMinutes % 15).toBe(0) + }) + }) + + describe('zero delta', () => { + test('returns original times when delta is zero', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'bottom', + totalDeltaMinutes: 0, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + expect(result.result.start).toContain('10:00') + expect(result.result.end).toContain('11:00') + }) + }) + + describe('blocked resize returns original day date', () => { + test('targetDayDate falls back to originalDayDate when blocked', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T16:00:00`, + end: `${DATE_MON}T16:45:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T16:00:00`, + originalEnd: `${DATE_MON}T16:45:00`, + edge: 'bottom', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.targetDayDate).toBe(DATE_MON) + }) + }) + + describe('cross-day resize (top edge to earlier day)', () => { + test('blocks when target day has unavailable time at the target range', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_TUE}T09:00:00`, + end: `${DATE_TUE}T10:00:00`, + resources: [afternoonResource], + }, + ], + resources: [afternoonResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_TUE}T09:00:00`, + originalEnd: `${DATE_TUE}T10:00:00`, + edge: 'top', + totalDeltaMinutes: -1440, + targetDayDate: DATE_MON, + originalDayDate: DATE_TUE, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.targetDayDate).toBe(DATE_TUE) + }) + + test('blocks when source day has unavailable time before event start', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_TUE}T09:00:00`, + end: `${DATE_TUE}T10:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_TUE}T09:00:00`, + originalEnd: `${DATE_TUE}T10:00:00`, + edge: 'top', + totalDeltaMinutes: -1500, + targetDayDate: DATE_MON, + originalDayDate: DATE_TUE, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('unavailable-time') + }) + }) + + describe('cross-day resize (bottom edge to later day)', () => { + test('blocks when target day has unavailable time at the target range', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T15:00:00`, + end: `${DATE_MON}T16:00:00`, + resources: [afternoonResource], + }, + ], + resources: [afternoonResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T15:00:00`, + originalEnd: `${DATE_MON}T16:00:00`, + edge: 'bottom', + totalDeltaMinutes: 1440, + targetDayDate: DATE_TUE, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.targetDayDate).toBe(DATE_MON) + }) + + test('blocks when source day has unavailable time after event end', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T15:00:00`, + end: `${DATE_MON}T16:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T15:00:00`, + originalEnd: `${DATE_MON}T16:00:00`, + edge: 'bottom', + totalDeltaMinutes: 1500, + targetDayDate: DATE_TUE, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('unavailable-time') + }) + }) + + describe('result shape', () => { + test('returns valid result structure when not blocked', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'bottom', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result).toHaveProperty('blocked', false) + expect(result).toHaveProperty('result') + expect(result.result).toHaveProperty('start') + expect(result.result).toHaveProperty('end') + expect(result.result).toHaveProperty('durationMinutes') + expect(result).toHaveProperty('targetDayDate', DATE_MON) + expect(result.error).toBeUndefined() + }) + + test('returns valid error structure when blocked', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T16:00:00`, + end: `${DATE_MON}T16:45:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T16:00:00`, + originalEnd: `${DATE_MON}T16:45:00`, + edge: 'bottom', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error).toBeDefined() + expect(result.error!.reason).toBe('unavailable-time') + expect(typeof result.error!.message).toBe('string') + expect(Array.isArray(result.error!.conflicts)).toBe(true) + }) + }) + + describe('multiple resources on one event', () => { + test('blocks when any resource is unavailable for the new range', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T12:00:00`, + end: `${DATE_MON}T13:00:00`, + resources: [weekdayResource, afternoonResource], + }, + ], + resources: [weekdayResource, afternoonResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T12:00:00`, + originalEnd: `${DATE_MON}T13:00:00`, + edge: 'top', + totalDeltaMinutes: -60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect( + result.error?.conflicts.some((c) => c.resourceIds.includes('r2')), + ).toBe(true) + }) + + test('allows when all resources are available for the new range', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T13:00:00`, + end: `${DATE_MON}T14:00:00`, + resources: [weekdayResource, afternoonResource], + }, + ], + resources: [weekdayResource, afternoonResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T13:00:00`, + originalEnd: `${DATE_MON}T14:00:00`, + edge: 'bottom', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + }) + }) + + describe('no constraints provided', () => { + test('works with default snap of 1 minute', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [allDayResource], + }, + ], + resources: [allDayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'bottom', + totalDeltaMinutes: 7, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + }) + + expect(result.blocked).toBe(false) + }) + }) + }) + + describe('navigation', () => { + test('goToSpecificPeriod updates store', () => { + const cal = createCalendar() + + cal.goToSpecificPeriod('2024-06-15') + + expect(cal.store.state.currentPeriod.toString()).toContain('2024-06-15') + }) + + test('changeViewMode updates store', () => { + const cal = createCalendar() + + cal.changeViewMode({ value: 1, unit: 'day' }) + + expect(cal.store.state.viewMode).toEqual({ value: 1, unit: 'day' }) + }) + + test('goToNextPeriod advances by one week in week mode', () => { + const cal = createCalendar({ viewMode: { value: 1, unit: 'week' } }) + cal.goToSpecificPeriod('2024-03-18') + const before = cal.store.state.currentPeriod.toString() + + cal.goToNextPeriod() + + expect(cal.store.state.currentPeriod.toString()).not.toBe(before) + }) + + test('goToPreviousPeriod goes back by one week in week mode', () => { + const cal = createCalendar({ viewMode: { value: 1, unit: 'week' } }) + cal.goToSpecificPeriod('2024-03-18') + const before = cal.store.state.currentPeriod.toString() + + cal.goToPreviousPeriod() + + expect(cal.store.state.currentPeriod.toString()).not.toBe(before) + }) + + test('canGoPreviousPeriod returns true without range', () => { + const cal = createCalendar() + + expect(cal.canGoPreviousPeriod()).toBe(true) + }) + + test('canGoNextPeriod returns true without range', () => { + const cal = createCalendar() + + expect(cal.canGoNextPeriod()).toBe(true) + }) + }) + + describe('getDaysNames', () => { + test('returns 7 day names', () => { + const cal = createCalendar({ locale: 'en-US' }) + const names = cal.getDaysNames('short') + + expect(names).toHaveLength(7) + names.forEach((name) => expect(typeof name).toBe('string')) + }) + + test('returns long day names', () => { + const cal = createCalendar({ locale: 'en-US' }) + const names = cal.getDaysNames('long') + + expect(names).toHaveLength(7) + expect(names.some((n) => n.length > 3)).toBe(true) + }) + }) + + describe('getTimeSlots', () => { + test('returns time slots for the day', () => { + const cal = createCalendar() + const slots = cal.getTimeSlots() + + expect(slots.length).toBeGreaterThan(0) + expect(slots[0]).toHaveProperty('hour') + expect(slots[0]).toHaveProperty('minute') + expect(slots[0]).toHaveProperty('label') + }) + }) + + describe('getDaysWithEvents', () => { + test('returns days array with events mapped to dates', () => { + const cal = createCalendar({ + viewMode: { value: 1, unit: 'day' }, + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ], + }) + cal.goToSpecificPeriod(DATE_MON) + + const days = cal.getDaysWithEvents() + + expect(days.length).toBeGreaterThan(0) + const targetDay = days.find( + (d) => d.date.toString({ calendarName: 'never' }) === DATE_MON, + ) + expect(targetDay).toBeDefined() + expect(targetDay!.events).toHaveLength(1) + }) + + test('marks today correctly', () => { + const cal = createCalendar({ viewMode: { value: 1, unit: 'month' } }) + const days = cal.getDaysWithEvents() + + const todayCount = days.filter((d) => d.isToday).length + expect(todayCount).toBeLessThanOrEqual(1) + }) + }) + + describe('groupDaysBy', () => { + test('groups days into weeks', () => { + const cal = createCalendar({ viewMode: { value: 1, unit: 'month' } }) + const days = cal.getDaysWithEvents() + + const grouped = cal.groupDaysBy({ days, unit: 'week' }) + + expect(grouped.length).toBeGreaterThan(0) + grouped.forEach((week) => { + expect(week.length).toBeLessThanOrEqual(7) + }) + }) + }) +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a9ece014..52e5e316 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -79,7 +79,7 @@ importers: specifier: ^4.0.17 version: 4.0.18(@types/node@25.2.2)(happy-dom@20.5.3)(jiti@2.6.1)(yaml@2.8.2) - examples/react/basic: + examples/react/calendar: dependencies: '@tanstack/react-devtools': specifier: ^0.9.5 @@ -125,6 +125,52 @@ importers: specifier: ^7.3.1 version: 7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2) + examples/react/timeline: + dependencies: + '@tanstack/react-devtools': + specifier: ^0.9.5 + version: 0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) + '@tanstack/react-time': + specifier: ^0.0.0 + version: link:../../../packages/react-time + '@tanstack/react-time-devtools': + specifier: ^0.0.0 + version: link:../../../packages/react-time-devtools + '@tanstack/time': + specifier: ^0.0.0 + version: link:../../../packages/time + react: + specifier: ^19.2.3 + version: 19.2.4 + react-dom: + specifier: ^19.2.3 + version: 19.2.4(react@19.2.4) + devDependencies: + '@types/react': + specifier: ^19.2.8 + version: 19.2.13 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.13) + '@vitejs/plugin-react': + specifier: ^5.1.2 + version: 5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.24(postcss@8.5.6) + postcss: + specifier: ^8.4.49 + version: 8.5.6 + tailwindcss: + specifier: ^3.4.17 + version: 3.4.19(yaml@2.8.2) + typescript: + specifier: 5.9.3 + version: 5.9.3 + vite: + specifier: ^7.3.1 + version: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) + packages/react-time: dependencies: '@tanstack/react-store': From c664f4d790df5aad31cffd6b5152e0e7b3a49b48 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Sun, 22 Mar 2026 17:28:04 +0100 Subject: [PATCH 059/207] feat: timeline --- examples/react/calendar/src/index.tsx | 97 +- examples/react/timeline/src/index.tsx | 935 +++++++++++++----- packages/react-time/src/index.ts | 3 + .../react-time/src/useCalendar/useCalendar.ts | 205 ++-- packages/time/src/calendar/calendar.ts | 332 ++++++- packages/time/src/calendar/getEventProps.ts | 18 +- packages/time/src/calendar/getResizeProps.ts | 73 +- .../time/src/calendar/splitMultiDayEvents.ts | 14 +- .../time/src/calendar/tests/calendar.test.ts | 326 +++++- packages/time/src/calendar/types.ts | 39 +- packages/time/src/date/index.ts | 6 + packages/time/src/date/parse/parse.ts | 86 ++ 12 files changed, 1749 insertions(+), 385 deletions(-) diff --git a/examples/react/calendar/src/index.tsx b/examples/react/calendar/src/index.tsx index 9b2ecc4c..ed3bbc54 100644 --- a/examples/react/calendar/src/index.tsx +++ b/examples/react/calendar/src/index.tsx @@ -9,6 +9,7 @@ import ReactDOM from 'react-dom/client' import { useEffect, useState } from 'react' import { TanStackDevtools } from '@tanstack/react-devtools' import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' +import { toPlainDateTimeString } from '@tanstack/time' import type { Day, Event, ResizeError, Resource } from '@tanstack/time' import './index.css' @@ -35,6 +36,61 @@ function formatDateToISO(date: Date): string { return `${year}-${month}-${day}` } +function padTimePart(n: number): string { + return String(n).padStart(2, '0') +} + +// Monday of the work week containing today, or upcoming Monday on Sat–Sun. +function workWeekMonday(): Date { + const today = new Date() + const dow = today.getDay() + const monday = new Date(today) + + if (dow === 0 || dow === 6) { + monday.setDate(today.getDate() + (dow === 0 ? 1 : 2)) + } else { + monday.setDate(today.getDate() + (1 - dow)) + } + monday.setHours(0, 0, 0, 0) + return monday +} + +function weekdayAt(isoWeekday: 1 | 2 | 3 | 4 | 5): Date { + const monday = workWeekMonday() + const d = new Date(monday) + d.setDate(monday.getDate() + isoWeekday - 1) + return d +} + +function dateTimeOnWeekday( + isoWeekday: 1 | 2 | 3 | 4 | 5, + hour: number, + minute: number, +): string { + const d = weekdayAt(isoWeekday) + d.setHours(hour, minute, 0, 0) + return `${formatDateToISO(d)}T${padTimePart(hour)}:${padTimePart(minute)}:00` +} + +function eventToSegmentInfoInput( + event: Event, +): Parameters[0] { + const e = event as Event & { + _originalStart?: string | Date | number + _originalEnd?: string | Date | number + } + return { + start: toPlainDateTimeString(e.start), + end: toPlainDateTimeString(e.end), + ...(e._originalStart != null + ? { _originalStart: toPlainDateTimeString(e._originalStart) } + : {}), + ...(e._originalEnd != null + ? { _originalEnd: toPlainDateTimeString(e._originalEnd) } + : {}), + } +} + const sampleResources: Array = [ { id: '1', @@ -77,47 +133,40 @@ const sampleResources: Array = [ }, ] +/* + Every event uses both resources. Intersection of availability on Mon–Fri: + Resource1 Mon–Wed 08–17, Thu–Fri 00–24; Resource2 Mon–Fri 12–18 → 12:00–17:00. + Multi-day slots cannot cross midnight: Resource2 is off before 12:00 on each weekday, + so overnight segments would sit in unavailable time. +*/ function getSampleEvents(): Array> { - const today = new Date() - const tomorrow = new Date(today) - tomorrow.setDate(today.getDate() + 1) - - const dayAfterTomorrow = new Date(today) - dayAfterTomorrow.setDate(today.getDate() + 2) - - const threeDaysLater = new Date(today) - threeDaysLater.setDate(today.getDate() + 3) - - const fourDaysLater = new Date(today) - fourDaysLater.setDate(today.getDate() + 4) - return [ { id: '1', title: 'Team Meeting', - start: `${formatDateToISO(tomorrow)}T10:00:00`, - end: `${formatDateToISO(tomorrow)}T11:00:00`, + start: dateTimeOnWeekday(2, 12, 0), + end: dateTimeOnWeekday(2, 13, 0), resources: sampleResources, }, { id: '2', title: 'Project Review', - start: `${formatDateToISO(dayAfterTomorrow)}T14:00:00`, - end: `${formatDateToISO(dayAfterTomorrow)}T15:30:00`, + start: dateTimeOnWeekday(3, 14, 0), + end: dateTimeOnWeekday(3, 15, 30), resources: sampleResources, }, { id: '3', - title: 'Multi-day Conference', - start: `${formatDateToISO(threeDaysLater)}T09:00:00`, - end: `${formatDateToISO(fourDaysLater)}T17:00:00`, + title: 'Workshop', + start: dateTimeOnWeekday(4, 12, 0), + end: dateTimeOnWeekday(4, 16, 30), resources: sampleResources, }, { id: '4', title: 'Lunch Break', - start: `${formatDateToISO(threeDaysLater)}T12:00:00`, - end: `${formatDateToISO(threeDaysLater)}T13:00:00`, + start: dateTimeOnWeekday(5, 12, 0), + end: dateTimeOnWeekday(5, 13, 0), resources: sampleResources, }, ] @@ -421,7 +470,9 @@ function ScheduleView({ const eventProps = calendar.getEventProps(event) const { style, isSplitEvent } = eventProps - const segmentInfo = getSegmentInfo(event) + const segmentInfo = getSegmentInfo( + eventToSegmentInfoInput(event), + ) const { isFirstSegment, isLastSegment, diff --git a/examples/react/timeline/src/index.tsx b/examples/react/timeline/src/index.tsx index b7a17124..8cf772d4 100644 --- a/examples/react/timeline/src/index.tsx +++ b/examples/react/timeline/src/index.tsx @@ -1,41 +1,108 @@ -import { useCalendar } from '@tanstack/react-time' +import { + calculateTimelineResizePreview, + useCalendar, +} from '@tanstack/react-time' import ReactDOM from 'react-dom/client' -import { useMemo, useRef, useState } from 'react' +import React, { + useCallback, + useEffect, + useLayoutEffect, + useMemo, + useRef, + useState, +} from 'react' import { TanStackDevtools } from '@tanstack/react-devtools' import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' -import type { Day, Event, Resource } from '@tanstack/time' +import { + toPlainDateString, + toPlainDateTimeString, + toPlainTimeString, +} from '@tanstack/time' +import type { + Day, + Event, + ResizeError, + Resource, + TimelineResourceRow, +} from '@tanstack/time' import './index.css' -function formatDateToISO(date: Date): string { - const year = date.getFullYear() - const month = String(date.getMonth() + 1).padStart(2, '0') - const day = String(date.getDate()).padStart(2, '0') - return `${year}-${month}-${day}` -} - -function parseISODate(iso: string): Date { - const datePart = iso.split('T')[0] ?? '' - const parts = datePart.split('-').map(Number) - return new Date(parts[0] ?? 0, (parts[1] ?? 1) - 1, parts[2] ?? 1) -} - const EVENT_COLORS = [ - { bg: 'bg-indigo-500/80', border: 'border-indigo-400', text: 'text-indigo-50' }, - { bg: 'bg-emerald-500/80', border: 'border-emerald-400', text: 'text-emerald-50' }, + { + bg: 'bg-indigo-500/80', + border: 'border-indigo-400', + text: 'text-indigo-50', + }, + { + bg: 'bg-emerald-500/80', + border: 'border-emerald-400', + text: 'text-emerald-50', + }, { bg: 'bg-amber-500/80', border: 'border-amber-400', text: 'text-amber-50' }, { bg: 'bg-rose-500/80', border: 'border-rose-400', text: 'text-rose-50' }, { bg: 'bg-cyan-500/80', border: 'border-cyan-400', text: 'text-cyan-50' }, - { bg: 'bg-violet-500/80', border: 'border-violet-400', text: 'text-violet-50' }, - { bg: 'bg-orange-500/80', border: 'border-orange-400', text: 'text-orange-50' }, + { + bg: 'bg-violet-500/80', + border: 'border-violet-400', + text: 'text-violet-50', + }, + { + bg: 'bg-orange-500/80', + border: 'border-orange-400', + text: 'text-orange-50', + }, { bg: 'bg-teal-500/80', border: 'border-teal-400', text: 'text-teal-50' }, ] -const resourceDesign: Resource = { id: 'design', label: 'Design' } -const resourceFrontend: Resource = { id: 'frontend', label: 'Frontend' } -const resourceBackend: Resource = { id: 'backend', label: 'Backend' } -const resourceQA: Resource = { id: 'qa', label: 'QA' } -const resourceDevOps: Resource = { id: 'devops', label: 'DevOps' } +const RESOURCE_ZONE_COLORS = [ + '#6366f155', + '#10b98155', + '#f59e0b55', + '#f43f5e55', + '#06b6d455', +] + +const resourceDesign: Resource = { + id: 'design', + label: 'Design', + availability: [ + { weekdays: [1, 2, 3, 4], startTime: '09:00', endTime: '17:00' }, + { weekdays: [5], startTime: '09:00', endTime: '13:00' }, + ], +} +const resourceFrontend: Resource = { + id: 'frontend', + label: 'Frontend', + availability: [ + { weekdays: [1, 2, 3, 4], startTime: '08:00', endTime: '24:00' }, + { weekdays: [5], startTime: '08:00', endTime: '24:00' }, + ], +} +const resourceBackend: Resource = { + id: 'backend', + label: 'Backend', + availability: [ + { weekdays: [1, 2, 3], startTime: '10:00', endTime: '19:00' }, + { weekdays: [4, 5], startTime: '00:00', endTime: '24:00' }, + ], +} +const resourceQA: Resource = { + id: 'qa', + label: 'QA', + availability: [ + { weekdays: [1, 2, 3], startTime: '09:00', endTime: '17:00' }, + { weekdays: [4, 5], startTime: '10:00', endTime: '15:00' }, + ], +} +const resourceDevOps: Resource = { + id: 'devops', + label: 'DevOps', + availability: [ + { weekdays: [1, 2, 3, 4, 5], startTime: '07:00', endTime: '16:00' }, + { weekdays: [6, 7], startTime: '10:00', endTime: '14:00' }, + ], +} const sampleResources: Array = [ resourceDesign, @@ -45,83 +112,114 @@ const sampleResources: Array = [ resourceDevOps, ] -function getSampleEvents(): Array> { +// Monday of the visible work week: Mon–Fri use the ISO week that contains today; +// Sat–Sun use the upcoming Monday so sample data is not entirely in the past. +function workWeekMonday(): Date { const today = new Date() - const d = (offset: number) => { - const date = new Date(today) - date.setDate(today.getDate() + offset) - return formatDateToISO(date) + const day = today.getDay() + const monday = new Date(today) + + if (day === 0 || day === 6) { + monday.setDate(today.getDate() + (day === 0 ? 1 : 2)) + } else { + monday.setDate(today.getDate() + (1 - day)) } + monday.setHours(0, 0, 0, 0) + return monday +} + +// isoWeekday: 1=Mon … 5=Fri (relative to workWeekMonday()). +function weekdayAt( + isoWeekday: 1 | 2 | 3 | 4 | 5, + hour: number, + minute = 0, +): Date { + const monday = workWeekMonday() + const date = new Date(monday) + date.setDate(monday.getDate() + isoWeekday - 1) + date.setHours(hour, minute, 0, 0) + return date +} +/* + Sample times are chosen so every event stays inside availability on that weekday, + and (where it matters) inside the intersection across weekdays: + - Design: Mon–Thu 09–17, Fri 09–13 → use only 09:00–13:00 so any Mon–Fri slot is safe. + - Frontend: Mon–Fri 08–24. + - Backend: Mon–Wed 10–19, Thu–Fri 00–24 → single-day uses 10–19; Thu→Fri span uses full-day Thu/Fri. + - QA: Mon–Wed 09–17, Thu–Fri 10–15 → use 10:00–15:00 everywhere. + - DevOps: Mon–Fri 07–16. +*/ +function getSampleEvents(): Array> { return [ { id: '1', title: 'UI Mockups', - start: `${d(0)}T09:00:00`, - end: `${d(2)}T17:00:00`, + start: weekdayAt(1, 10, 0), + end: weekdayAt(1, 12, 30), resources: [resourceDesign], }, { id: '2', title: 'Component Library', - start: `${d(1)}T09:00:00`, - end: `${d(4)}T17:00:00`, + start: weekdayAt(2, 9, 0), + end: weekdayAt(2, 17, 0), resources: [resourceFrontend], }, { id: '3', title: 'API Development', - start: `${d(0)}T09:00:00`, - end: `${d(5)}T17:00:00`, + start: weekdayAt(2, 11, 0), + end: weekdayAt(2, 18, 0), resources: [resourceBackend], }, { id: '4', title: 'Database Schema', - start: `${d(-1)}T09:00:00`, - end: `${d(1)}T17:00:00`, + start: weekdayAt(1, 11, 0), + end: weekdayAt(1, 16, 0), resources: [resourceBackend], }, { id: '5', title: 'Integration Tests', - start: `${d(3)}T09:00:00`, - end: `${d(6)}T17:00:00`, + start: weekdayAt(3, 10, 0), + end: weekdayAt(3, 15, 0), resources: [resourceQA], }, { id: '6', title: 'CI/CD Pipeline', - start: `${d(2)}T09:00:00`, - end: `${d(3)}T17:00:00`, + start: weekdayAt(1, 8, 0), + end: weekdayAt(1, 14, 0), resources: [resourceDevOps], }, { id: '7', title: 'Design Review', - start: `${d(3)}T10:00:00`, - end: `${d(3)}T16:00:00`, + start: weekdayAt(3, 10, 0), + end: weekdayAt(3, 12, 30), resources: [resourceDesign], }, { id: '8', title: 'Auth Module', - start: `${d(2)}T09:00:00`, - end: `${d(5)}T17:00:00`, - resources: [resourceFrontend], + start: weekdayAt(4, 0, 0), + end: weekdayAt(5, 10, 0), + resources: [resourceBackend], }, { id: '9', title: 'Load Testing', - start: `${d(5)}T09:00:00`, - end: `${d(6)}T17:00:00`, + start: weekdayAt(4, 10, 30), + end: weekdayAt(4, 14, 30), resources: [resourceQA], }, { id: '10', title: 'Deployment', - start: `${d(5)}T09:00:00`, - end: `${d(6)}T17:00:00`, + start: weekdayAt(5, 7, 30), + end: weekdayAt(5, 13, 0), resources: [resourceDevOps], }, ] @@ -132,14 +230,18 @@ const sampleEvents = getSampleEvents() interface EventFormData { title: string startDate: string + startTime: string endDate: string + endTime: string resourceId: string } const emptyFormData: EventFormData = { title: '', - startDate: formatDateToISO(new Date()), - endDate: formatDateToISO(new Date()), + startDate: toPlainDateString(new Date()), + startTime: '09:00', + endDate: toPlainDateString(new Date()), + endTime: '10:00', resourceId: resourceDesign.id, } @@ -222,6 +324,20 @@ function EventModal({ required />
+
+ + + setFormData({ ...formData, startTime: e.target.value }) + } + className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white focus:outline-none focus:ring-1 focus:ring-neutral-600" + required + /> +
+
+ + + setFormData({ ...formData, endTime: e.target.value }) + } + className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white focus:outline-none focus:ring-1 focus:ring-neutral-600" + required + /> +
@@ -274,109 +404,268 @@ function EventModal({ ) } -function TodayMarker({ - days, - dayWidth, -}: { - days: Array>> - dayWidth: number -}) { - const now = new Date() - const todayStr = formatDateToISO(now) - const todayIndex = days.findIndex( - (d) => d.date.toString({ calendarName: 'never' }) === todayStr, - ) - if (todayIndex === -1) return null - - const hourFraction = (now.getHours() + now.getMinutes() / 60) / 24 - const left = todayIndex * dayWidth + hourFraction * dayWidth +interface HorizontalResizeHandleProps { + edge: 'left' | 'right' + onMouseDown: (e: React.MouseEvent) => void +} +function HorizontalResizeHandle({ + edge, + onMouseDown, +}: HorizontalResizeHandleProps) { return (
{ + e.stopPropagation() + }} + style={{ touchAction: 'none' }} > -
+
) } -function TimelineRow({ - events, +function ResizeErrorToast({ + error, + onDismiss, +}: { + error: ResizeError + onDismiss: () => void +}) { + useEffect(() => { + const timer = setTimeout(onDismiss, 5000) + return () => clearTimeout(timer) + }, [onDismiss]) + + return ( +
+
+
+
!
+
+
+ Cannot Resize Event +
+
{error.message}
+ {error.conflicts && error.conflicts.length > 0 && ( +
+
+ Conflicts: +
+ {error.conflicts.map((conflict, idx) => ( +
+
+ {conflict.date} +
+
+ {conflict.conflictRange.start} -{' '} + {conflict.conflictRange.end} +
+
+ {conflict.description} +
+
+ ))} +
+ )} +
+ {error.eventTitle} +
+
+ +
+
+
+ ) +} + +const EVENT_GAP_PX = 3 + +function timeStringToFraction(time: string): number { + const parts = time.split(':') + const totalHours = Number(parts[0]) + Number(parts[1]) / 60 + return Math.min(totalHours, 24) / 24 +} + +const HorizontalTimelineRow = React.memo(function HorizontalTimelineRow({ + row, days, - dayWidth, colorMap, + resourceColorIndex, onEventClick, + getResizeHandleProps, + getDayColumnProps, + getUnavailableRanges, + eventBarRefs, }: { - events: Array> + row: TimelineResourceRow> days: Array>> - dayWidth: number colorMap: Map + resourceColorIndex: number onEventClick: (event: Event) => void + getResizeHandleProps: ReturnType< + typeof useCalendar> + >['getResizeHandleProps'] + getDayColumnProps: ReturnType< + typeof useCalendar> + >['getDayColumnProps'] + getUnavailableRanges: ReturnType< + typeof useCalendar> + >['getUnavailableRanges'] + eventBarRefs: React.MutableRefObject> }) { - const dayDates = useMemo( - () => days.map((d) => d.date.toString({ calendarName: 'never' })), - [days], - ) - - const firstDayDate = dayDates[0] - if (!firstDayDate) return null - const firstDay = parseISODate(firstDayDate) - const totalWidth = days.length * dayWidth + const dayPercentage = 100 / days.length + const zoneColor = + RESOURCE_ZONE_COLORS[resourceColorIndex % RESOURCE_ZONE_COLORS.length] ?? + RESOURCE_ZONE_COLORS[0] - const positionedEvents = useMemo(() => { - return events.map((event) => { - const eventStart = parseISODate(event.start) - const eventEnd = parseISODate(event.end) - - const startOffset = Math.max( - 0, - (eventStart.getTime() - firstDay.getTime()) / (1000 * 60 * 60 * 24), - ) - const endOffset = - (eventEnd.getTime() - firstDay.getTime()) / (1000 * 60 * 60 * 24) + 1 - - const left = Math.max(0, startOffset * dayWidth) - const right = Math.min(totalWidth, endOffset * dayWidth) - const width = Math.max(right - left, dayWidth * 0.3) - - return { event, left, width } - }) - }, [events, firstDay, dayWidth, totalWidth]) + const registerEventBar = useCallback( + (eventId: string) => (el: HTMLDivElement | null) => { + if (el) { + eventBarRefs.current.set(eventId, el) + } else { + eventBarRefs.current.delete(eventId) + } + }, + [eventBarRefs], + ) return ( -
- {days.map((day, i) => ( -
- ))} - {positionedEvents.map(({ event, left, width }) => { - const colorIdx = colorMap.get(event.id) ?? 0 - const color = EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] +
+ {days.map((day, i) => { + const unavailableRanges = getUnavailableRanges(day.isoDate, { + resourceIds: [row.resource.id], + }) + return (
onEventClick(event)} + key={day.isoDate} + className={`absolute top-0 bottom-0 border-r border-neutral-800/30 ${ + day.isToday ? 'bg-neutral-800/20' : '' + }`} + style={{ + left: `${i * dayPercentage}%`, + width: `${dayPercentage}%`, + }} + {...getDayColumnProps(day.isoDate)} > - {event.title} + {Array.from({ length: 23 }, (_, h) => ( +
+ ))} + {unavailableRanges.map((range, rangeIdx) => { + const startFraction = timeStringToFraction(range.startTime) + const endFraction = timeStringToFraction(range.endTime) + return ( +
+ ) + })}
) })} + {row.events.map( + ({ event, left, width, lane, isStartClipped, isEndClipped }) => { + const colorIdx = colorMap.get(event.id) ?? 0 + const color = + EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] + const laneHeightPct = 100 / row.laneCount + const topPct = lane * laneHeightPct + + return ( +
{ + if ( + !(e.target as HTMLElement).closest('[data-resize-handle]') + ) { + onEventClick(event) + } + }} + > + {!isStartClipped && ( + + )} + {event.title} + {!isEndClipped && ( + + )} +
+ ) + }, + )}
) -} - -function TimelineView() { - const DAY_WIDTH = 140 +}) +function TimelineDemo() { const [modalState, setModalState] = useState<{ isOpen: boolean mode: 'add' | 'edit' @@ -384,13 +673,44 @@ function TimelineView() { initialData: EventFormData }>({ isOpen: false, mode: 'add', initialData: emptyFormData }) + const [resizeError, setResizeError] = useState(null) const scrollContainerRef = useRef(null) + const timelineContentRef = useRef(null) + const containerWidthRef = useRef(0) + + useEffect(() => { + const measure = () => { + const el = timelineContentRef.current ?? scrollContainerRef.current + if (el) { + containerWidthRef.current = el.getBoundingClientRect().width + } + } + measure() + const observer = new ResizeObserver(measure) + const el = timelineContentRef.current ?? scrollContainerRef.current + if (el) observer.observe(el) + return () => observer.disconnect() + }, []) const calendar = useCalendar>({ - viewMode: { value: 2, unit: 'week' }, + viewMode: { value: 1, unit: 'day' }, events: sampleEvents, resources: sampleResources, timeZone: 'UTC', + resize: { + enabled: true, + get containerWidth() { + return containerWidthRef.current + }, + orientation: 'horizontal', + constraints: { + minDurationMinutes: 15, + snapToMinutes: 15, + }, + onResizeError: (error) => { + setResizeError(error) + }, + }, }) const colorMap = useMemo(() => { @@ -399,68 +719,89 @@ function TimelineView() { return map }, []) - const eventsByResource = useMemo(() => { - const map = new Map>>() - sampleResources.forEach((r) => map.set(r.id, [])) + const timelineLayout = useMemo( + () => calendar.getTimelineLayout(), + [calendar.days], + ) + + const eventBarRefsMap = useRef>(new Map()) - const allEvents = calendar.days.flatMap((d) => d.events) - const seen = new Set() - for (const event of allEvents) { - if (seen.has(event.id)) continue - seen.add(event.id) + const firstDayIso = useMemo( + () => calendar.days[0]?.isoDate ?? '', + [calendar.days], + ) - const resourceIds = - event.resources?.map((r) => r.id) ?? [] - if (resourceIds.length === 0) { - map.get(resourceDesign.id)?.push(event) - } else { - for (const rid of resourceIds) { - map.get(rid)?.push(event) - } + const totalDays = calendar.days.length + const { resizeState } = calendar + const prevResizedIdRef = useRef(null) + + useLayoutEffect(() => { + const prevId = prevResizedIdRef.current + + if (prevId && (!resizeState.isResizing || resizeState.eventId !== prevId)) { + const prevEl = eventBarRefsMap.current.get(prevId) + if (prevEl) { + prevEl.classList.remove( + 'ring-2', + 'ring-neutral-500', + 'z-20', + 'brightness-110', + ) } + prevResizedIdRef.current = null + } + + if ( + !resizeState.isResizing || + !resizeState.eventId || + !resizeState.previewStart || + !resizeState.previewEnd || + !firstDayIso + ) { + return } - return map - }, [calendar.days]) - - const totalWidth = calendar.days.length * DAY_WIDTH - - const formatPeriodRange = () => { - const days = calendar.days - if (days.length === 0) return '' - const first = days[0] - const last = days[days.length - 1] - const fmt = (d: typeof first.date) => - new Date(d.year, d.month - 1, d.day).toLocaleDateString(undefined, { - month: 'short', - day: 'numeric', - year: 'numeric', - }) - return `${fmt(first.date)} — ${fmt(last.date)}` - } + + const el = eventBarRefsMap.current.get(resizeState.eventId) + if (!el) return + + const preview = calculateTimelineResizePreview({ + previewStart: resizeState.previewStart, + previewEnd: resizeState.previewEnd, + firstDayIso, + totalDays, + }) + + el.style.left = preview.left + el.style.width = preview.width + el.classList.add('ring-2', 'ring-neutral-500', 'z-20', 'brightness-110') + prevResizedIdRef.current = resizeState.eventId + }, [resizeState, firstDayIso, totalDays]) const openAddModal = () => setModalState({ isOpen: true, mode: 'add', initialData: emptyFormData }) - const openEditModal = (event: Event) => { + const openEditModal = useCallback((event: Event) => { setModalState({ isOpen: true, mode: 'edit', eventId: event.id, initialData: { title: event.title, - startDate: event.start.split('T')[0] ?? '', - endDate: event.end.split('T')[0] ?? '', + startDate: toPlainDateString(event.start), + startTime: toPlainTimeString(event.start), + endDate: toPlainDateString(event.end), + endTime: toPlainTimeString(event.end), resourceId: event.resources?.[0]?.id ?? resourceDesign.id, }, }) - } + }, []) const handleSave = (data: EventFormData) => { const resource = sampleResources.find((r) => r.id === data.resourceId) const eventData = { title: data.title, - start: `${data.startDate}T09:00:00`, - end: `${data.endDate}T17:00:00`, + start: `${data.startDate}T${data.startTime}:00`, + end: `${data.endDate}T${data.endTime}:00`, resources: resource ? [resource] : [], } @@ -475,6 +816,12 @@ function TimelineView() { if (modalState.eventId) calendar.removeEvent(modalState.eventId) } + const viewModeOptions = [ + { label: 'Day', value: 1, unit: 'day' as const }, + { label: 'Week', value: 1, unit: 'week' as const }, + { label: '2 Weeks', value: 2, unit: 'week' as const }, + ] + return (
@@ -520,11 +867,7 @@ function TimelineView() {
- {[ - { label: '1 Week', value: 1, unit: 'week' as const }, - { label: '2 Weeks', value: 2, unit: 'week' as const }, - { label: 'Month', value: 1, unit: 'month' as const }, - ].map((opt) => { + {viewModeOptions.map((opt) => { const isActive = calendar.viewMode.value === opt.value && calendar.viewMode.unit === opt.unit @@ -551,95 +894,140 @@ function TimelineView() {
- {formatPeriodRange()} + {calendar.formatPeriodLabel()}
- {/* Resource labels column */}
-
+
+
Resources
- {sampleResources.map((resource) => ( -
- - {resource.label} - -
- ))} + {sampleResources.map((resource, idx) => { + const zoneColor = + RESOURCE_ZONE_COLORS[idx % RESOURCE_ZONE_COLORS.length] ?? + RESOURCE_ZONE_COLORS[0] + return ( +
+
+ + {resource.label} + +
+ ) + })}
- {/* Scrollable timeline area */} -
-
- {/* Day headers */} -
- {calendar.days.map((day) => { - const date = new Date( - day.date.year, - day.date.month - 1, - day.date.day, - ) - const dayName = date.toLocaleDateString(undefined, { - weekday: 'short', - }) - const dayNum = day.date.day - const monthName = date.toLocaleDateString(undefined, { - month: 'short', - }) - const isWeekend = date.getDay() === 0 || date.getDay() === 6 - - return ( -
- - {dayName} - - +
+
+
+ {calendar.days.map((day) => { + const localDate = new Date( + day.date.year, + day.date.month - 1, + day.date.day, + ) + const dayName = localDate.toLocaleDateString(undefined, { + weekday: 'short', + }) + const dayNum = day.date.day + const monthName = localDate.toLocaleDateString(undefined, { + month: 'short', + }) + + return ( +
- {dayNum} - - - {monthName} - -
- ) - })} + + {dayName} + + + {dayNum} + + + {monthName} + +
+ ) + })} +
+
+ {calendar.days.map((day, i) => { + const dayPercentage = 100 / calendar.days.length + return ( +
+ {Array.from({ length: 24 }, (_, h) => ( +
+ + {h.toString().padStart(2, '0')} + +
+ ))} +
+ ) + })} +
- {/* Timeline rows */}
- - {sampleResources.map((resource) => ( - +
+
+ )} + {timelineLayout.rows.map((row, rowIdx) => ( + ))}
@@ -648,20 +1036,44 @@ function TimelineView() {
- {/* Legend */} -
- {sampleEvents.map((event) => { - const colorIdx = colorMap.get(event.id) ?? 0 - const color = EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] - return ( -
-
- {event.title} -
- ) - })} +
+
+ {sampleEvents.map((event) => { + const colorIdx = colorMap.get(event.id) ?? 0 + const color = + EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] + return ( +
+
+ {event.title} +
+ ) + })} +
+ +
+ {sampleResources.map((resource, idx) => { + const zoneColor = + RESOURCE_ZONE_COLORS[idx % RESOURCE_ZONE_COLORS.length] ?? + RESOURCE_ZONE_COLORS[0] + return ( +
+
+ + {resource.label} — unavailable + +
+ ) + })} +
{calendar.isPending && ( @@ -678,6 +1090,13 @@ function TimelineView() { initialData={modalState.initialData} mode={modalState.mode} /> + + {resizeError && ( + setResizeError(null)} + /> + )}
) } @@ -686,7 +1105,7 @@ function App() { return ( <> - + ) } diff --git a/packages/react-time/src/index.ts b/packages/react-time/src/index.ts index ff363e82..d719b695 100644 --- a/packages/react-time/src/index.ts +++ b/packages/react-time/src/index.ts @@ -15,6 +15,7 @@ export type { export { calculateGhostPreviewStyle, calculateSegmentResizePreview, + calculateTimelineResizePreview, formatEventTimeRange, getEventDisplayTimeRange, getSegmentInfo, @@ -30,4 +31,6 @@ export type { ResizePreviewOptions, SegmentInfo, SegmentResizePreview, + TimelineResizePreviewOptions, + TimelineResizePreviewStyle, } from '@tanstack/time' diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index c903899e..44b1aaee 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -10,6 +10,7 @@ import { useStore } from '@tanstack/react-store' import { CalendarCore, calculateDeltaMinutesFromPixels, + calculateDeltaMinutesFromPixelsHorizontal, getTimeClient, } from '@tanstack/time' import type { @@ -28,6 +29,8 @@ export interface ResizeState { edge: ResizeEdge | null previewStart: string | null previewEnd: string | null + lastValidPreviewStart: string | null + lastValidPreviewEnd: string | null targetDayDate: string | null blocked: boolean } @@ -35,6 +38,8 @@ export interface ResizeState { export interface ResizeOptions { enabled?: boolean containerHeight?: number + containerWidth?: number + orientation?: 'vertical' | 'horizontal' constraints?: ResizeConstraints onResizeStart?: (eventId: string, edge: ResizeEdge) => void onResizeEnd?: (eventId: string, newStart: string, newEnd: string) => void @@ -62,6 +67,8 @@ const initialResizeState: ResizeState = { edge: null, previewStart: null, previewEnd: null, + lastValidPreviewStart: null, + lastValidPreviewEnd: null, targetDayDate: null, blocked: false, } @@ -83,9 +90,6 @@ export const useCalendar = < getDayColumnProps: (dayDate: string) => DayColumnProps } => { const { resize, ...calendarOptions } = options - const resizeEnabled = resize?.enabled ?? true - const containerHeight = resize?.containerHeight ?? 0 - const resizeConstraints = resize?.constraints const [calendarCore] = useState( () => new CalendarCore(calendarOptions), @@ -93,6 +97,13 @@ export const useCalendar = < const state = useStore(calendarCore.store) const [isPending, startTransition] = useTransition() + const resizeOptionsRef = useRef(resize) + resizeOptionsRef.current = resize + + const calendarOptionsRef = + useRef>(calendarOptions) + calendarOptionsRef.current = calendarOptions + const resizeStateRef = useRef(initialResizeState) const resizeListenersRef = useRef void>>(new Set()) const dayColumnRefsRef = useRef>(new Map()) @@ -102,8 +113,10 @@ export const useCalendar = < end: string edge: ResizeEdge startY: number + startX: number originalDayDate: string currentDayDate: string + totalDaysInView: number } | null>(null) const lastEmittedErrorRef = useRef<{ eventId: string @@ -146,35 +159,66 @@ export const useCalendar = < return null }, []) + const getDayFromElement = useCallback( + (element: HTMLElement): string | null => { + for (const [dayDate, dayElement] of dayColumnRefsRef.current) { + if (dayElement.contains(element)) { + return dayDate + } + } + return null + }, + [], + ) + const handleMouseMove = useCallback( (e: MouseEvent) => { if (!originalEventRef.current) return - const { id, start, end, edge, startY, originalDayDate } = + const resizeOpts = resizeOptionsRef.current + const containerHeight = resizeOpts?.containerHeight ?? 0 + const containerWidth = resizeOpts?.containerWidth ?? 0 + const orientation = resizeOpts?.orientation ?? 'vertical' + const constraints = resizeOpts?.constraints + + const { id, start, end, edge, startY, startX, originalDayDate } = originalEventRef.current - const deltaY = e.clientY - startY - - const deltaMinutes = calculateDeltaMinutesFromPixels( - deltaY, - containerHeight, - ) - - const targetDayDate = getDayFromPoint(e.clientX) ?? originalDayDate - - let dayOffsetMinutes = 0 - if (targetDayDate && targetDayDate !== originalDayDate) { - const originalDate = new Date(originalDayDate + 'T00:00:00') - const targetDate = new Date(targetDayDate + 'T00:00:00') - const dayDiff = Math.round( - (targetDate.getTime() - originalDate.getTime()) / - (1000 * 60 * 60 * 24), + + let targetDayDate: string + let totalDeltaMinutes: number + + if (orientation === 'horizontal') { + if (containerWidth === 0) return + const totalMinutesInView = + originalEventRef.current.totalDaysInView * 24 * 60 + totalDeltaMinutes = calculateDeltaMinutesFromPixelsHorizontal( + e.clientX - startX, + containerWidth, + totalMinutesInView, + ) + targetDayDate = originalDayDate + } else { + const deltaMinutes = calculateDeltaMinutesFromPixels( + e.clientY - startY, + containerHeight, ) - dayOffsetMinutes = dayDiff * 24 * 60 - originalEventRef.current.currentDayDate = targetDayDate - } + targetDayDate = getDayFromPoint(e.clientX) ?? originalDayDate + + let dayOffsetMinutes = 0 + if (targetDayDate !== originalDayDate) { + const originalDate = new Date(originalDayDate + 'T00:00:00') + const targetDate = new Date(targetDayDate + 'T00:00:00') + const dayDiff = Math.round( + (targetDate.getTime() - originalDate.getTime()) / + (1000 * 60 * 60 * 24), + ) + dayOffsetMinutes = dayDiff * 24 * 60 + originalEventRef.current.currentDayDate = targetDayDate + } - const totalDeltaMinutes = deltaMinutes + dayOffsetMinutes + totalDeltaMinutes = deltaMinutes + dayOffsetMinutes + } const validation = calendarCore.validateResize({ eventId: id, @@ -184,11 +228,13 @@ export const useCalendar = < totalDeltaMinutes, targetDayDate, originalDayDate, - constraints: resizeConstraints, + constraints, }) if (validation.blocked && validation.error) { - const event = calendarOptions.events?.find((ev) => ev.id === id) + const event = calendarOptionsRef.current.events?.find( + (ev) => ev.id === id, + ) const now = Date.now() const lastError = lastEmittedErrorRef.current @@ -225,7 +271,7 @@ export const useCalendar = < : undefined, }) - resize?.onResizeError?.(resizeError) + resizeOpts?.onResizeError?.(resizeError) lastEmittedErrorRef.current = { eventId: id, @@ -237,42 +283,54 @@ export const useCalendar = < lastEmittedErrorRef.current = null } + const currentState = resizeStateRef.current + const effectivePreviewStart = validation.blocked + ? (currentState.lastValidPreviewStart ?? start) + : validation.result.start + const effectivePreviewEnd = validation.blocked + ? (currentState.lastValidPreviewEnd ?? end) + : validation.result.end + updateResizeState({ eventId: id, - previewStart: validation.result.start, - previewEnd: validation.result.end, + previewStart: effectivePreviewStart, + previewEnd: effectivePreviewEnd, + ...(!validation.blocked && { + lastValidPreviewStart: validation.result.start, + lastValidPreviewEnd: validation.result.end, + }), targetDayDate: validation.targetDayDate, blocked: validation.blocked, }) }, - [ - containerHeight, - calendarOptions.events, - calendarCore, - resizeConstraints, - resize, - getDayFromPoint, - updateResizeState, - ], + [calendarCore, getDayFromPoint, updateResizeState], ) const handleMouseUp = useCallback(() => { const currentState = resizeStateRef.current + const original = originalEventRef.current + if ( currentState.eventId && currentState.previewStart && - currentState.previewEnd && - !currentState.blocked + currentState.previewEnd ) { - calendarCore.updateEvent(currentState.eventId, { - start: currentState.previewStart, - end: currentState.previewEnd, - } as Partial>) - resize?.onResizeEnd?.( - currentState.eventId, - currentState.previewStart, - currentState.previewEnd, - ) + const hasChanged = + !original || + currentState.previewStart !== original.start || + currentState.previewEnd !== original.end + + if (hasChanged) { + calendarCore.updateEvent(currentState.eventId, { + start: currentState.previewStart, + end: currentState.previewEnd, + } as Partial>) + resizeOptionsRef.current?.onResizeEnd?.( + currentState.eventId, + currentState.previewStart, + currentState.previewEnd, + ) + } } originalEventRef.current = null @@ -281,19 +339,7 @@ export const useCalendar = < document.removeEventListener('mousemove', handleMouseMove) document.removeEventListener('mouseup', handleMouseUp) - }, [calendarCore, handleMouseMove, resize, updateResizeState]) - - const getDayFromElement = useCallback( - (element: HTMLElement): string | null => { - for (const [dayDate, dayElement] of dayColumnRefsRef.current) { - if (dayElement.contains(element)) { - return dayDate - } - } - return null - }, - [], - ) + }, [calendarCore, handleMouseMove, updateResizeState]) const getResizeHandleProps = useCallback( ( @@ -303,12 +349,14 @@ export const useCalendar = < originalEnd: string, ): ResizeHandleHandlers => ({ onMouseDown: (e: React.MouseEvent) => { - if (!resizeEnabled) return + if (!(resizeOptionsRef.current?.enabled ?? true)) return e.preventDefault() e.stopPropagation() - const dayDate = getDayFromElement(e.target as HTMLElement) + const dayDate = + getDayFromElement(e.target as HTMLElement) ?? + getDayFromPoint(e.clientX) if (!dayDate) return originalEventRef.current = { @@ -317,8 +365,10 @@ export const useCalendar = < end: originalEnd, edge, startY: e.clientY, + startX: e.clientX, originalDayDate: dayDate, currentDayDate: dayDate, + totalDaysInView: calendarCore.getDaysWithEvents().length, } updateResizeState({ @@ -327,21 +377,23 @@ export const useCalendar = < edge, previewStart: originalStart, previewEnd: originalEnd, + lastValidPreviewStart: originalStart, + lastValidPreviewEnd: originalEnd, targetDayDate: dayDate, }) - resize?.onResizeStart?.(eventId, edge) + resizeOptionsRef.current?.onResizeStart?.(eventId, edge) document.addEventListener('mousemove', handleMouseMove) document.addEventListener('mouseup', handleMouseUp) }, }), [ - resizeEnabled, + calendarCore, getDayFromElement, + getDayFromPoint, handleMouseMove, handleMouseUp, - resize, updateResizeState, ], ) @@ -450,6 +502,8 @@ export const useCalendar = < [calendarCore], ) + const containerHeight = resize?.containerHeight ?? 0 + const getUnavailableRanges = useCallback< typeof calendarCore.getUnavailableRanges >( @@ -461,6 +515,20 @@ export const useCalendar = < [calendarCore, containerHeight], ) + const getEventsByResource = useCallback< + typeof calendarCore.getEventsByResource + >(() => calendarCore.getEventsByResource(), [calendarCore]) + + const getTimelineLayout = useCallback( + () => calendarCore.getTimelineLayout(), + [calendarCore], + ) + + const formatPeriodLabel = useCallback( + (options) => calendarCore.formatPeriodLabel(options), + [calendarCore], + ) + const days = useMemo(() => { void state return calendarCore.getDaysWithEvents() @@ -491,5 +559,8 @@ export const useCalendar = < getResizeHandleProps, getDayColumnProps, getUnavailableRanges, + getEventsByResource, + getTimelineLayout, + formatPeriodLabel, } } diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index b6644663..e7d52ce0 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -5,6 +5,7 @@ import { getEventProps } from './getEventProps' import { groupDaysBy } from './groupDaysBy' import { getTimeSlots } from './getTimeSlots' import { calculateResizedEvent } from './getResizeProps' +import { toPlainDateString, toPlainDateTimeString } from '~/date/parse' import { DateCore } from './date-core' import type { DateCoreOptions, ParsedDateCoreOptions } from './date-core' import type { @@ -19,6 +20,8 @@ import type { ResizeError, Resource, TimeSlot, + TimelineLayout, + TimelineResourceRow, UnavailableRange, ViewMode, } from './types' @@ -111,6 +114,12 @@ interface CalendarActions< resourceIds?: Array }, ) => Array + /** Groups visible events by resource, merging multi-day segments back to full-span events. */ + getEventsByResource: () => Map> + /** Computes horizontal timeline layout with event positions, lane assignments, and current time marker. */ + getTimelineLayout: () => TimelineLayout + /** Returns a human-readable label for the currently visible date range. */ + formatPeriodLabel: (options?: { locale?: string }) => string } interface CalendarState< @@ -193,11 +202,21 @@ export class CalendarCore< constructor(options: CalendarCoreOptions) { super(options) Object.assign(this.options, { - events: options.events || null, + events: options.events?.map((e) => this.normalizeEvent(e)) || null, resources: options.resources || null, }) } + private normalizeEvent< + T extends { start: string | Date | number; end: string | Date | number }, + >(event: T): T { + return { + ...event, + start: toPlainDateTimeString(event.start), + end: toPlainDateTimeString(event.end), + } + } + protected getCalendarDays() { return super.getCalendarDays() } @@ -206,10 +225,10 @@ export class CalendarCore< const map = new Map>() this.options.events?.forEach((event) => { const eventStartDate = Temporal.PlainDateTime.from( - event.start, + toPlainDateTimeString(event.start), ).toZonedDateTime(this.options.timeZone) const eventEndDate = Temporal.PlainDateTime.from( - event.end, + toPlainDateTimeString(event.end), ).toZonedDateTime(this.options.timeZone) const startPlainDate = eventStartDate.toPlainDate() const endPlainDate = eventEndDate.toPlainDate() @@ -220,7 +239,9 @@ export class CalendarCore< this.options.timeZone, ) splitEvents.forEach((splitEvent) => { - const dateKey = Temporal.PlainDateTime.from(splitEvent.start) + const dateKey = Temporal.PlainDateTime.from( + toPlainDateTimeString(splitEvent.start), + ) .toPlainDate() .toString({ calendarName: 'never' }) if (!map.has(dateKey)) map.set(dateKey, []) @@ -236,12 +257,11 @@ export class CalendarCore< } getDaysWithEvents() { - console.log('getDaysWithEvents') const calendarDays = this.getCalendarDays() const eventMap = this.getEventMap() return calendarDays.map((day) => { - const dayKey = day.toString({ calendarName: 'never' }) - const dailyEvents = eventMap.get(dayKey) ?? [] + const isoDate = day.toString({ calendarName: 'never' }) + const dailyEvents = eventMap.get(isoDate) ?? [] const currentMonthRange = Array.from( { length: this.store.state.viewMode.value }, (_, i) => this.store.state.currentPeriod.add({ months: i }).month, @@ -249,6 +269,7 @@ export class CalendarCore< const isInCurrentPeriod = currentMonthRange.includes(day.month) return { date: day, + isoDate, events: dailyEvents, isToday: Temporal.PlainDate.compare(day, Temporal.Now.plainDateISO()) === 0, @@ -257,6 +278,25 @@ export class CalendarCore< }) } + formatPeriodLabel(options?: { locale?: string }): string { + const days = this.getDaysWithEvents() + if (days.length === 0) return '' + + const locale = options?.locale ?? this.options.locale + const first = days[0]! + const last = days[days.length - 1]! + + const fmt = (d: Temporal.PlainDate) => + new Date(d.year, d.month - 1, d.day).toLocaleDateString(locale, { + month: 'short', + day: 'numeric', + year: 'numeric', + }) + + if (days.length === 1) return fmt(first.date) + return `${fmt(first.date)} \u2014 ${fmt(last.date)}` + } + getEventProps(event: TEvent) { return getEventProps(this.getEventMap(), event, this.store.state, { timeZone: this.options.timeZone, @@ -297,17 +337,18 @@ export class CalendarCore< if (!this.options.events) { this.options.events = [] } - this.options.events.push(event) + const normalized = this.normalizeEvent(event) + this.options.events.push(normalized) this.store.setState((prev) => ({ ...prev, eventsVersion: prev.eventsVersion + 1, })) getTimeClient().emit('event:added', { - eventId: event.id, - eventTitle: event.title, - start: event.start, - end: event.end, + eventId: normalized.id, + eventTitle: normalized.title, + start: normalized.start, + end: normalized.end, }) } @@ -317,21 +358,33 @@ export class CalendarCore< const index = this.options.events.findIndex((e) => e.id === id) if (index === -1) return + const normalizedUpdates = { + ...updates, + ...(updates.start != null + ? { start: toPlainDateTimeString(updates.start) } + : {}), + ...(updates.end != null + ? { end: toPlainDateTimeString(updates.end) } + : {}), + } + const existingEvent = this.options.events[index] - this.options.events[index] = { ...existingEvent, ...updates } as TEvent + this.options.events[index] = { + ...existingEvent, + ...normalizedUpdates, + } as TEvent this.store.setState((prev) => ({ ...prev, eventsVersion: prev.eventsVersion + 1, })) - // Emit event to TimeClient if (existingEvent) { getTimeClient().emit('event:updated', { eventId: id, eventTitle: existingEvent.title, start: this.options.events[index].start, end: this.options.events[index].end, - updates: updates as Record, + updates: normalizedUpdates as Record, }) } } @@ -571,6 +624,158 @@ export class CalendarCore< return details } + private getMergedEventsByResource( + days: Array>, + ): Map> { + const map = new Map>() + this.options.resources?.forEach((r) => map.set(r.id, [])) + + const allSegments = days.flatMap((d) => d.events) + const merged = new Map() + for (const segment of allSegments) { + if (!merged.has(segment.id)) { + merged.set(segment.id, { + ...segment, + start: segment._originalStart ?? segment.start, + end: segment._originalEnd ?? segment.end, + } as TEvent) + } + } + + for (const event of merged.values()) { + const resourceIds = event.resources?.map((r) => r.id) ?? [] + for (const rid of resourceIds) { + map.get(rid)?.push(event) + } + } + + return map + } + + getEventsByResource(): Map> { + return this.getMergedEventsByResource(this.getDaysWithEvents()) + } + + getTimelineLayout(): TimelineLayout { + const days = this.getDaysWithEvents() + + if (days.length === 0) { + return { rows: [], currentTimePosition: null } + } + + const firstDay = days[0]!.date + const totalDays = days.length + const eventsByResource = this.getMergedEventsByResource(days) + + const rows: Array> = ( + this.options.resources ?? [] + ).map((resource) => { + const resourceEvents = eventsByResource.get(resource.id) ?? [] + + const positioned = resourceEvents + .map((event) => { + const pos = this.computeTimelineEventPosition( + event, + firstDay, + totalDays, + ) + if (pos.width <= 0) return null + return { event, ...pos, right: pos.left + pos.width } + }) + .filter((v): v is NonNullable => v !== null) + + const lanes: Array> = [] + const withLanes = positioned.map((item) => { + let assignedLane = 0 + for (assignedLane = 0; assignedLane < lanes.length; assignedLane++) { + const hasOverlap = lanes[assignedLane]!.some( + (existing) => + item.left < existing.right && item.right > existing.left, + ) + if (!hasOverlap) break + } + if (!lanes[assignedLane]) lanes[assignedLane] = [] + lanes[assignedLane]!.push({ left: item.left, right: item.right }) + return { + event: item.event, + left: item.left, + width: item.width, + lane: assignedLane, + isStartClipped: item.isStartClipped, + isEndClipped: item.isEndClipped, + } + }) + + return { + resource, + events: withLanes, + laneCount: Math.max(1, lanes.length), + } + }) + + let currentTimePosition: number | null = null + const now = Temporal.Now.zonedDateTimeISO(this.options.timeZone) + const todayStr = now.toPlainDate().toString({ calendarName: 'never' }) + const todayIndex = days.findIndex( + (d) => d.date.toString({ calendarName: 'never' }) === todayStr, + ) + if (todayIndex >= 0) { + const hourFraction = now.hour + now.minute / 60 + const totalHours = totalDays * 24 + currentTimePosition = + ((todayIndex * 24 + hourFraction) / totalHours) * 100 + } + + return { rows, currentTimePosition } + } + + private computeTimelineEventPosition( + event: TEvent, + firstDay: Temporal.PlainDate, + totalDays: number, + ): { left: number; width: number } { + const startStr = toPlainDateTimeString(event.start) + const endStr = toPlainDateTimeString(event.end) + + const startDateStr = startStr.split('T')[0]! + const endDateStr = endStr.split('T')[0]! + const startTimeStr = startStr.split('T')[1] ?? '00:00:00' + const endTimeStr = endStr.split('T')[1] ?? '00:00:00' + + const startTimeParts = startTimeStr.split(':').map(Number) + const endTimeParts = endTimeStr.split(':').map(Number) + + const firstDayIso = firstDay.toString({ calendarName: 'never' }) + const startDayOffset = Temporal.PlainDate.from(firstDayIso).until( + Temporal.PlainDate.from(startDateStr), + ).days + const endDayOffset = Temporal.PlainDate.from(firstDayIso).until( + Temporal.PlainDate.from(endDateStr), + ).days + + const startHours = + startDayOffset * 24 + + (startTimeParts[0] ?? 0) + + (startTimeParts[1] ?? 0) / 60 + const endHours = + endDayOffset * 24 + (endTimeParts[0] ?? 0) + (endTimeParts[1] ?? 0) / 60 + + const totalHours = totalDays * 24 + + const rawLeft = (startHours / totalHours) * 100 + const rawRight = (endHours / totalHours) * 100 + + const left = Math.max(0, rawLeft) + const right = Math.min(100, rawRight) + + return { + left, + width: right - left, + isStartClipped: rawLeft < 0, + isEndClipped: rawRight > 100, + } + } + private getUnavailableMinuteRanges( date: string, options?: { resourceIds?: Array }, @@ -755,6 +960,9 @@ export class CalendarCore< const originalStartDate = originalStart.split('T')[0] ?? '' const originalEndDate = originalEnd.split('T')[0] ?? '' + const effectiveEdge = + edge === 'left' ? 'top' : edge === 'right' ? 'bottom' : edge + let shouldBlockResize = false let blockReason: ResizeError['reason'] = 'blocked' let blockMessage = 'Resize blocked' @@ -766,7 +974,7 @@ export class CalendarCore< return Math.round(minutes / snapToMinutes) * snapToMinutes } - if (edge === 'top' && targetDayDate < originalStartDate) { + if (effectiveEdge === 'top' && targetDayDate < originalStartDate) { const rawStartMinutes = new Date(originalStart).getHours() * 60 + new Date(originalStart).getMinutes() + @@ -847,7 +1055,7 @@ export class CalendarCore< }) } } - } else if (edge === 'bottom' && targetDayDate > originalEndDate) { + } else if (effectiveEdge === 'bottom' && targetDayDate > originalEndDate) { const rawEndMinutes = new Date(originalEnd).getHours() * 60 + new Date(originalEnd).getMinutes() + @@ -938,11 +1146,11 @@ export class CalendarCore< const rawStartMinutes = new Date(originalStart).getHours() * 60 + new Date(originalStart).getMinutes() + - (edge === 'top' ? totalDeltaMinutes : 0) + (effectiveEdge === 'top' ? totalDeltaMinutes : 0) const rawEndMinutes = new Date(originalEnd).getHours() * 60 + new Date(originalEnd).getMinutes() + - (edge === 'bottom' ? totalDeltaMinutes : 0) + (effectiveEdge === 'bottom' ? totalDeltaMinutes : 0) const snappedStartMinutes = snapMins( ((rawStartMinutes % MINUTES_IN_DAY) + MINUTES_IN_DAY) % MINUTES_IN_DAY, @@ -1014,6 +1222,92 @@ export class CalendarCore< } } + // Comprehensive datetime-based check: catches multi-day event resizes and + // cases where the existing per-day-minute logic doesn't apply (e.g. + // horizontal timeline where targetDayDate is always the original day). + if (!shouldBlockResize && resourceIds?.length) { + const originalStartMs = new Date(originalStart).getTime() + const originalEndMs = new Date(originalEnd).getTime() + const snapMs = snapToMinutes * 60_000 + const snappedDeltaMs = + Math.round((totalDeltaMinutes * 60_000) / snapMs) * snapMs + + // Only check the *new territory* being added — shrinking is always fine. + let checkFromMs: number | null = null + let checkToMs: number | null = null + + if (effectiveEdge === 'bottom') { + const newEndMs = originalEndMs + snappedDeltaMs + if (newEndMs > originalEndMs) { + checkFromMs = originalEndMs + checkToMs = newEndMs + } + } else if (effectiveEdge === 'top') { + const newStartMs = originalStartMs + snappedDeltaMs + if (newStartMs < originalStartMs) { + checkFromMs = newStartMs + checkToMs = originalStartMs + } + } + + if (checkFromMs !== null && checkToMs !== null) { + const dayMs = 24 * 60 * 60 * 1_000 + const cursor = new Date(checkFromMs) + cursor.setHours(0, 0, 0, 0) + + while (cursor.getTime() < checkToMs && !shouldBlockResize) { + const dayStr = toPlainDateString(cursor) + const dayStartMs = cursor.getTime() + const dayEndMs = dayStartMs + dayMs + + const overlapStartMs = Math.max(checkFromMs, dayStartMs) + const overlapEndMs = Math.min(checkToMs, dayEndMs) + + if (overlapStartMs < overlapEndMs) { + const overlapStartMins = Math.floor( + (overlapStartMs - dayStartMs) / 60_000, + ) + const overlapEndMins = Math.ceil( + (overlapEndMs - dayStartMs) / 60_000, + ) + + const details = this.getUnavailabilityDetails( + dayStr, + overlapStartMins, + overlapEndMins, + { resourceIds }, + ) + + if (details.length > 0) { + shouldBlockResize = true + blockReason = 'unavailable-time' + const detailsText = details + .map((d) => `${d.resourceLabel} (${d.reason})`) + .join(', ') + blockMessage = `Unavailable: ${dayStr} ${formatMinutesToTime(overlapStartMins)}–${formatMinutesToTime(overlapEndMins)} conflicts with ${detailsText}` + conflicts.push({ + date: dayStr, + conflictRange: { + start: formatMinutesToTime(overlapStartMins), + end: formatMinutesToTime(overlapEndMins), + }, + resourceIds: details.map((d) => d.resourceId), + resourceDetails: details.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: d.description, + })), + description: details.map((d) => d.description).join('; '), + }) + } + } + + cursor.setTime(cursor.getTime() + dayMs) + } + } + } + const effectiveDeltaMinutes = shouldBlockResize ? 0 : totalDeltaMinutes const result = calculateResizedEvent({ diff --git a/packages/time/src/calendar/getEventProps.ts b/packages/time/src/calendar/getEventProps.ts index bd3b7c2a..a3efcad5 100644 --- a/packages/time/src/calendar/getEventProps.ts +++ b/packages/time/src/calendar/getEventProps.ts @@ -1,5 +1,6 @@ import { Temporal } from '@js-temporal/polyfill' -import type { CalendarStore, Event } from './types' +import type { CalendarStore, Event, EventDateTimeInput } from './types' +import { toPlainDateTimeString } from '~/date/parse' interface GetEventPropsOptions { timeZone: Temporal.TimeZoneLike @@ -9,10 +10,12 @@ const MINUTES_IN_DAY = 24 * 60 const MIN_EVENT_HEIGHT_MINUTES = 30 const toZonedDateTime = ( - dateString: string, + dateInput: EventDateTimeInput, timeZone: Temporal.TimeZoneLike, ): Temporal.ZonedDateTime => - Temporal.PlainDateTime.from(dateString).toZonedDateTime(timeZone) + Temporal.PlainDateTime.from(toPlainDateTimeString(dateInput)).toZonedDateTime( + timeZone, + ) const toMinutes = (date: Temporal.ZonedDateTime): number => date.hour * 60 + date.minute @@ -35,7 +38,10 @@ const getFullEventTimes = ( fallback: Event, ): { start: string; end: string } => { if (segments.length <= 1) { - return { start: fallback.start, end: fallback.end } + return { + start: toPlainDateTimeString(fallback.start), + end: toPlainDateTimeString(fallback.end), + } } const sorted = [...segments].sort((a, b) => @@ -46,8 +52,8 @@ const getFullEventTimes = ( ) return { - start: sorted[0]?.start ?? fallback.start, - end: sorted[sorted.length - 1]?.end ?? fallback.end, + start: toPlainDateTimeString(sorted[0]?.start ?? fallback.start), + end: toPlainDateTimeString(sorted[sorted.length - 1]?.end ?? fallback.end), } } diff --git a/packages/time/src/calendar/getResizeProps.ts b/packages/time/src/calendar/getResizeProps.ts index bb78cc47..5051ebe1 100644 --- a/packages/time/src/calendar/getResizeProps.ts +++ b/packages/time/src/calendar/getResizeProps.ts @@ -1,6 +1,6 @@ import { Temporal } from '@js-temporal/polyfill' -export type ResizeEdge = 'top' | 'bottom' +export type ResizeEdge = 'top' | 'bottom' | 'left' | 'right' export interface UnavailableTimeRange { /** Start time in minutes from midnight (0-1440) */ @@ -87,7 +87,10 @@ export function calculateResizedEvent( (range) => range.startMinutes === 0 && range.endMinutes >= MINUTES_IN_DAY, ) - if (edge === 'top') { + const effectiveEdge = + edge === 'left' ? 'top' : edge === 'right' ? 'bottom' : edge + + if (effectiveEdge === 'top') { newStartZdt = startZdt.add({ minutes: snappedDelta }) const maxStartZdt = endZdt.subtract({ minutes: minDurationMinutes }) if (Temporal.ZonedDateTime.compare(newStartZdt, maxStartZdt) > 0) { @@ -169,6 +172,14 @@ export function calculateDeltaMinutesFromPixels( return (deltaPixels / containerHeight) * minutesInDay } +export function calculateDeltaMinutesFromPixelsHorizontal( + deltaPixels: number, + containerWidth: number, + totalMinutesInView: number, +): number { + return (deltaPixels / containerWidth) * totalMinutesInView +} + export interface ResizeHandleStyle { position: 'absolute' left: number @@ -423,6 +434,64 @@ export function calculateGhostPreviewStyle( } } +export interface TimelineResizePreviewOptions { + previewStart: string + previewEnd: string + firstDayIso: string + totalDays: number +} + +export interface TimelineResizePreviewStyle { + left: string + width: string +} + +/** + * Calculates left/width percentages for timeline resize preview + */ +export function calculateTimelineResizePreview( + options: TimelineResizePreviewOptions, +): TimelineResizePreviewStyle { + const { previewStart, previewEnd, firstDayIso, totalDays } = options + + const startStr = previewStart + const endStr = previewEnd + const startDateStr = startStr.split('T')[0]! + const endDateStr = endStr.split('T')[0]! + const startTimeStr = startStr.split('T')[1] ?? '00:00:00' + const endTimeStr = endStr.split('T')[1] ?? '00:00:00' + + const startTimeParts = startTimeStr.split(':').map(Number) + const endTimeParts = endTimeStr.split(':').map(Number) + + const startDayOffset = Math.round( + (new Date(startDateStr).getTime() - new Date(firstDayIso).getTime()) / + (1000 * 60 * 60 * 24), + ) + const endDayOffset = Math.round( + (new Date(endDateStr).getTime() - new Date(firstDayIso).getTime()) / + (1000 * 60 * 60 * 24), + ) + + const startHours = + startDayOffset * 24 + + (startTimeParts[0] ?? 0) + + (startTimeParts[1] ?? 0) / 60 + const endHours = + endDayOffset * 24 + (endTimeParts[0] ?? 0) + (endTimeParts[1] ?? 0) / 60 + + const totalHours = totalDays * 24 + + const left = Math.max(0, (startHours / totalHours) * 100) + const right = Math.min(100, (endHours / totalHours) * 100) + const width = Math.max(0, right - left) + + return { + left: `${left}%`, + width: `${width}%`, + } +} + /** * Checks if an event spans multiple days */ diff --git a/packages/time/src/calendar/splitMultiDayEvents.ts b/packages/time/src/calendar/splitMultiDayEvents.ts index f0e1d167..7cd9bb51 100644 --- a/packages/time/src/calendar/splitMultiDayEvents.ts +++ b/packages/time/src/calendar/splitMultiDayEvents.ts @@ -1,6 +1,6 @@ import { Temporal } from '@js-temporal/polyfill' import type { Event, Resource } from './types' -import { endOf, startOf } from '~/date' +import { endOf, startOf, toPlainDateTimeString } from '~/date' export const splitMultiDayEvents = < TResource extends Resource = Resource, @@ -9,12 +9,12 @@ export const splitMultiDayEvents = < event: TEvent, timeZone: Temporal.TimeZoneLike, ): Array => { - const startDate = Temporal.PlainDateTime.from(event.start).toZonedDateTime( - timeZone, - ) - const endDate = Temporal.PlainDateTime.from(event.end).toZonedDateTime( - timeZone, - ) + const startDate = Temporal.PlainDateTime.from( + toPlainDateTimeString(event.start), + ).toZonedDateTime(timeZone) + const endDate = Temporal.PlainDateTime.from( + toPlainDateTimeString(event.end), + ).toZonedDateTime(timeZone) const events: Array = [] let currentDay = startDate diff --git a/packages/time/src/calendar/tests/calendar.test.ts b/packages/time/src/calendar/tests/calendar.test.ts index 9299d414..36e62bac 100644 --- a/packages/time/src/calendar/tests/calendar.test.ts +++ b/packages/time/src/calendar/tests/calendar.test.ts @@ -1,6 +1,7 @@ -import { describe, expect, test, beforeEach } from 'vitest' +import { describe, expect, test } from 'vitest' import { CalendarCore } from '../calendar' import type { Event, Resource } from '../types' +import { toPlainDateTimeString } from '~/date/parse' type TestResource = Resource type TestEvent = Event @@ -51,6 +52,55 @@ const noAvailabilityResource: TestResource = { const DATE_MON = '2024-03-18' const DATE_TUE = '2024-03-19' +describe('toPlainDateTimeString', () => { + test('passes through full ISO datetime unchanged', () => { + expect(toPlainDateTimeString('2024-03-18T09:00:00')).toBe( + '2024-03-18T09:00:00', + ) + }) + + test('adds midnight time to date-only string', () => { + expect(toPlainDateTimeString('2024-03-18')).toBe('2024-03-18T00:00:00') + }) + + test('fills in missing seconds from partial time', () => { + expect(toPlainDateTimeString('2024-03-18T09:30')).toBe( + '2024-03-18T09:30:00', + ) + }) + + test('fills in missing minutes and seconds from hour-only time', () => { + expect(toPlainDateTimeString('2024-03-18T09')).toBe('2024-03-18T09:00:00') + }) + + test('handles space separator instead of T', () => { + expect(toPlainDateTimeString('2024-03-18 14:30:00')).toBe( + '2024-03-18T14:30:00', + ) + }) + + test('strips timezone offset and returns plain datetime', () => { + expect(toPlainDateTimeString('2024-03-18T09:00:00Z')).toBe( + '2024-03-18T09:00:00', + ) + }) + + test('converts Date object to ISO datetime string using local time', () => { + const date = new Date(2024, 2, 18, 10, 30, 0) + expect(toPlainDateTimeString(date)).toBe('2024-03-18T10:30:00') + }) + + test('converts epoch number to ISO datetime string', () => { + const date = new Date(2024, 2, 18, 0, 0, 0) + const result = toPlainDateTimeString(date.getTime()) + expect(result).toBe(toPlainDateTimeString(date)) + }) + + test('throws on invalid string input', () => { + expect(() => toPlainDateTimeString('not-a-date')).toThrow() + }) +}) + describe('CalendarCore', () => { describe('constructor', () => { test('initializes with events and resources', () => { @@ -67,6 +117,53 @@ describe('CalendarCore', () => { expect(cal.options.events).toHaveLength(1) expect(cal.options.resources).toHaveLength(1) }) + + test('normalizes date-only event start/end to full datetime', () => { + const events: Array = [ + { + id: '1', + title: 'Date-only', + start: DATE_MON, + end: DATE_TUE, + }, + ] + const cal = createCalendar({ events }) + + expect(cal.options.events![0]!.start).toBe(`${DATE_MON}T00:00:00`) + expect(cal.options.events![0]!.end).toBe(`${DATE_TUE}T00:00:00`) + }) + + test('normalizes partial datetime event start/end', () => { + const events: Array = [ + { + id: '1', + title: 'Partial time', + start: `${DATE_MON}T09:30`, + end: `${DATE_MON}T17`, + }, + ] + const cal = createCalendar({ events }) + + expect(cal.options.events![0]!.start).toBe(`${DATE_MON}T09:30:00`) + expect(cal.options.events![0]!.end).toBe(`${DATE_MON}T17:00:00`) + }) + + test('normalizes Date objects in event start/end', () => { + const startDate = new Date(2024, 2, 18, 9, 0, 0) + const endDate = new Date(2024, 2, 18, 17, 0, 0) + const events: Array = [ + { + id: '1', + title: 'Date objects', + start: startDate, + end: endDate, + }, + ] + const cal = createCalendar({ events }) + + expect(cal.options.events![0]!.start).toBe(`${DATE_MON}T09:00:00`) + expect(cal.options.events![0]!.end).toBe(`${DATE_MON}T17:00:00`) + }) }) describe('getEventsByDate', () => { @@ -176,6 +273,34 @@ describe('CalendarCore', () => { expect(cal.store.state.eventsVersion).toBe(versionBefore + 1) }) + + test('normalizes date-only start/end when adding event', () => { + const cal = createCalendar() + + cal.addEvent({ + id: '1', + title: 'Date-only add', + start: DATE_MON, + end: DATE_TUE, + }) + + expect(cal.options.events![0]!.start).toBe(`${DATE_MON}T00:00:00`) + expect(cal.options.events![0]!.end).toBe(`${DATE_TUE}T00:00:00`) + }) + + test('normalizes Date objects when adding event', () => { + const cal = createCalendar() + + cal.addEvent({ + id: '1', + title: 'Date object add', + start: new Date(2024, 2, 18, 14, 0, 0), + end: new Date(2024, 2, 18, 15, 0, 0), + }) + + expect(cal.options.events![0]!.start).toBe(`${DATE_MON}T14:00:00`) + expect(cal.options.events![0]!.end).toBe(`${DATE_MON}T15:00:00`) + }) }) describe('updateEvent', () => { @@ -217,6 +342,48 @@ describe('CalendarCore', () => { expect(cal.options.events![0]!.end).toBe(`${DATE_MON}T12:00:00`) }) + test('normalizes date-only start/end when updating event', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ], + }) + + cal.updateEvent('1', { + start: DATE_TUE, + end: DATE_TUE, + }) + + expect(cal.options.events![0]!.start).toBe(`${DATE_TUE}T00:00:00`) + expect(cal.options.events![0]!.end).toBe(`${DATE_TUE}T00:00:00`) + }) + + test('normalizes Date objects when updating event', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'E', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ], + }) + + cal.updateEvent('1', { + start: new Date(2024, 2, 19, 11, 0, 0), + end: new Date(2024, 2, 19, 12, 0, 0), + }) + + expect(cal.options.events![0]!.start).toBe(`${DATE_TUE}T11:00:00`) + expect(cal.options.events![0]!.end).toBe(`${DATE_TUE}T12:00:00`) + }) + test('does nothing when event not found', () => { const cal = createCalendar({ events: [ @@ -1279,6 +1446,163 @@ describe('CalendarCore', () => { }) }) + describe('validateResize — horizontal timeline (multi-day events)', () => { + const baseResizeOptions = { + constraints: { snapToMinutes: 15, minDurationMinutes: 15 }, + } + + // In horizontal timeline mode, targetDayDate is always the original day — + // so the per-day-minute checks in the existing cases don't fire for + // multi-day events. The comprehensive datetime check must catch these. + + test('blocks extending right edge of multi-day event into unavailable hours', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Spanning Event', + start: `${DATE_MON}T13:00:00`, + end: `${DATE_TUE}T17:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + // Resize right edge: +120 min → new end = TUE 19:00 (past 17:00 limit) + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T13:00:00`, + originalEnd: `${DATE_TUE}T17:00:00`, + edge: 'right', + totalDeltaMinutes: 120, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('unavailable-time') + }) + + test('allows extending right edge of multi-day event within available hours', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Spanning Event', + start: `${DATE_MON}T13:00:00`, + end: `${DATE_TUE}T15:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + // Resize right edge: +60 min → new end = TUE 16:00 (within 08:00-17:00) + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T13:00:00`, + originalEnd: `${DATE_TUE}T15:00:00`, + edge: 'right', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + }) + + test('blocks extending left edge of multi-day event into unavailable hours', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Spanning Event', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_TUE}T12:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + // Resize left edge: -180 min → new start = MON 07:00 (before 08:00 limit) + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_TUE}T12:00:00`, + edge: 'left', + totalDeltaMinutes: -180, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('unavailable-time') + }) + + test('blocks large delta on single-day event that crosses midnight into next unavailable day', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Short Meeting', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + // Resize right edge by 10 hours → new end = MON 21:00 (past 17:00) + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T09:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'right', + totalDeltaMinutes: 600, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + }) + + test('shrinking is always allowed regardless of availability', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'Spanning Event', + start: `${DATE_MON}T13:00:00`, + end: `${DATE_TUE}T17:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + // Shrink right edge: -60 min → new end = TUE 16:00 (still within availability) + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T13:00:00`, + originalEnd: `${DATE_TUE}T17:00:00`, + edge: 'right', + totalDeltaMinutes: -60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + }) + }) + describe('groupDaysBy', () => { test('groups days into weeks', () => { const cal = createCalendar({ viewMode: { value: 1, unit: 'month' } }) diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index 44d8483e..1f6ed0b9 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -1,6 +1,8 @@ import type { Temporal } from '@js-temporal/polyfill' import type { DateInput } from '~/date' +export type EventDateTimeInput = string | Date | number + export interface Availability { /** Days of the week when available (ISO weekday: 1 = Monday, ..., 7 = Sunday) */ weekdays: Array @@ -34,8 +36,8 @@ export interface ViewMode { export interface Event { id: string - start: string - end: string + start: EventDateTimeInput + end: EventDateTimeInput title: string resources?: Array /** Original start time before splitting (only set on split segments of multi-day events) */ @@ -49,6 +51,8 @@ export type Day< TEvent extends Event = Event, > = { date: Temporal.PlainDate + /** Pre-computed ISO date string (YYYY-MM-DD) — use instead of manually formatting `date` */ + isoDate: string events: Array isToday: boolean isInCurrentPeriod: boolean @@ -145,3 +149,34 @@ export interface ResizeValidationResult { valid: boolean error?: ResizeError } + +export interface TimelineEventLayout< + TResource extends Resource = Resource, + TEvent extends Event = Event, +> { + event: TEvent + left: number + width: number + lane: number + /** True when the event starts before the first visible day (left edge is clipped) */ + isStartClipped: boolean + /** True when the event ends after the last visible day (right edge is clipped) */ + isEndClipped: boolean +} + +export interface TimelineResourceRow< + TResource extends Resource = Resource, + TEvent extends Event = Event, +> { + resource: TResource + events: Array> + laneCount: number +} + +export interface TimelineLayout< + TResource extends Resource = Resource, + TEvent extends Event = Event, +> { + rows: Array> + currentTimePosition: number | null +} diff --git a/packages/time/src/date/index.ts b/packages/time/src/date/index.ts index 039ea922..c2c04af8 100644 --- a/packages/time/src/date/index.ts +++ b/packages/time/src/date/index.ts @@ -1,4 +1,10 @@ export type * from './types' +export { + toDate, + toPlainDateString, + toPlainDateTimeString, + toPlainTimeString, +} from './parse' export * from './add' export * from './subtract' export * from './since' diff --git a/packages/time/src/date/parse/parse.ts b/packages/time/src/date/parse/parse.ts index c7cabd1c..36253211 100644 --- a/packages/time/src/date/parse/parse.ts +++ b/packages/time/src/date/parse/parse.ts @@ -136,3 +136,89 @@ export function parse(value: string | number | Date): Date | undefined { } return value } + +interface DateParts { + year: number + month: number + day: number + hour: number + minute: number + second: number +} + +const pad = (n: number): string => String(n).padStart(2, '0') + +function extractDateParts(value: string | Date | number): DateParts { + if (value instanceof Date) { + return { + year: value.getFullYear(), + month: value.getMonth() + 1, + day: value.getDate(), + hour: value.getHours(), + minute: value.getMinutes(), + second: value.getSeconds(), + } + } + + if (typeof value === 'number') { + return extractDateParts(parseEpochDateTime(value)) + } + + const match = + rfc3339DateTimeOptionalTimeRegex.exec(value) ?? dateOnlyRegex.exec(value) + + if (!match?.groups) { + throw new Error( + `"${value}" is not a valid date/time string. Expected formats: YYYY-MM-DD, YYYY-MM-DDTHH:mm, or YYYY-MM-DDTHH:mm:ss`, + ) + } + + return { + year: Number(match.groups.year), + month: Number(match.groups.month ?? '01'), + day: Number(match.groups.day ?? '01'), + hour: Number(match.groups.hour ?? '00'), + minute: Number(match.groups.minute ?? '00'), + second: Number(match.groups.second ?? '00'), + } +} + +/** + * toPlainDateTimeString + * Converts a flexible date/time input (string, Date, or epoch number) + * into a Temporal.PlainDateTime-compatible ISO string (YYYY-MM-DDTHH:mm:ss). + */ +export function toPlainDateTimeString(value: string | Date | number): string { + const { year, month, day, hour, minute, second } = extractDateParts(value) + return `${year}-${pad(month)}-${pad(day)}T${pad(hour)}:${pad(minute)}:${pad(second)}` +} + +/** + * toPlainDateString + * Converts a flexible date/time input (string, Date, or epoch number) + * into a Temporal.PlainDate-compatible ISO string (YYYY-MM-DD). + */ +export function toPlainDateString(value: string | Date | number): string { + const { year, month, day } = extractDateParts(value) + return `${year}-${pad(month)}-${pad(day)}` +} + +/** + * toPlainTimeString + * Converts a flexible date/time input (string, Date, or epoch number) + * into a time-only string (HH:mm). + */ +export function toPlainTimeString(value: string | Date | number): string { + const { hour, minute } = extractDateParts(value) + return `${pad(hour)}:${pad(minute)}` +} + +/** + * toDate + * Converts a flexible date/time input (string, Date, or epoch number) + * into a local-time Date at midnight, extracting only the date portion. + */ +export function toDate(value: string | Date | number): Date { + const { year, month, day } = extractDateParts(value) + return new Date(year, month - 1, day) +} From e836d427bc153a92f9aa7a37d727f5f7b6e1277d Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 22 Mar 2026 16:29:14 +0000 Subject: [PATCH 060/207] ci: apply automated fixes --- .../react/reference/functions/useCalendar.md | 2 +- .../reference/interfaces/ResizeOptions.md | 34 +- .../react/reference/interfaces/ResizeState.md | 44 +- .../interfaces/UseCalendarOptions.md | 4 +- docs/reference/classes/CalendarCore.md | 821 ------------------ docs/reference/classes/DateCore.md | 326 ------- docs/reference/functions/add.md | 89 -- .../calculateDeltaMinutesFromPixels.md | 33 - .../functions/calculateGhostPreviewStyle.md | 24 - .../functions/calculateResizedEvent.md | 22 - .../calculateSegmentResizePreview.md | 24 - docs/reference/functions/endOf.md | 89 -- docs/reference/functions/equals.md | 41 - docs/reference/functions/format.md | 33 - .../functions/formatEventTimeRange.md | 37 - docs/reference/functions/generateDateRange.md | 26 - .../functions/getEventDisplayTimeRange.md | 42 - docs/reference/functions/getEventProps.md | 73 -- .../functions/getResizeHandleStyle.md | 22 - docs/reference/functions/getSegmentInfo.md | 36 - docs/reference/functions/getTimeClient.md | 18 - docs/reference/functions/getTimeSlots.md | 35 - docs/reference/functions/groupDaysBy.md | 32 - docs/reference/functions/intersects.md | 33 - docs/reference/functions/isAfter.md | 36 - docs/reference/functions/isBefore.md | 36 - docs/reference/functions/isBetween.md | 33 - docs/reference/functions/isLeapYear.md | 29 - docs/reference/functions/isMultiDayEvent.md | 28 - docs/reference/functions/isSameOrAfter.md | 36 - docs/reference/functions/isSameOrBefore.md | 36 - docs/reference/functions/isWeekend.md | 29 - docs/reference/functions/range.md | 26 - docs/reference/functions/round.md | 89 -- docs/reference/functions/since.md | 37 - .../functions/splitMultiDayEvents.md | 36 - docs/reference/functions/startOf.md | 89 -- docs/reference/functions/subtract.md | 89 -- docs/reference/functions/until.md | 36 - docs/reference/index.md | 113 --- docs/reference/interfaces/AddOptions.md | 70 -- docs/reference/interfaces/Availability.md | 44 - .../interfaces/AvailabilityConflict.md | 82 -- docs/reference/interfaces/CalendarApi.md | 590 ------------- .../interfaces/CalendarCoreOptions.md | 179 ---- docs/reference/interfaces/CalendarStore.md | 48 - docs/reference/interfaces/DateCoreOptions.md | 110 --- docs/reference/interfaces/DateOptions.md | 43 - docs/reference/interfaces/DateRange.md | 28 - docs/reference/interfaces/EndOfOptions.md | 70 -- docs/reference/interfaces/EqualsOptions.md | 40 - docs/reference/interfaces/Event.md | 88 -- docs/reference/interfaces/EventTimeRange.md | 38 - .../reference/interfaces/FormatDateOptions.md | 74 -- .../interfaces/FormatEventTimeOptions.md | 32 - .../interfaces/FormattedEventTime.md | 56 -- .../interfaces/GhostPreviewOptions.md | 44 - .../reference/interfaces/IntersectsOptions.md | 50 -- docs/reference/interfaces/IsAfterOptions.md | 40 - docs/reference/interfaces/IsBeforeOptions.md | 40 - docs/reference/interfaces/IsBetweenOptions.md | 60 -- .../reference/interfaces/IsLeapYearOptions.md | 40 - .../interfaces/IsSameOrAfterOptions.md | 50 -- .../interfaces/IsSameOrBeforeOptions.md | 50 -- docs/reference/interfaces/IsWeekendOptions.md | 50 -- .../interfaces/ParsedDateCoreOptions.md | 86 -- docs/reference/interfaces/PositionStyle.md | 30 - docs/reference/interfaces/Range.md | 28 - docs/reference/interfaces/RangeOptions.md | 90 -- .../reference/interfaces/ResizeConstraints.md | 40 - docs/reference/interfaces/ResizeError.md | 102 --- .../reference/interfaces/ResizeHandleStyle.md | 88 -- .../interfaces/ResizePreviewOptions.md | 68 -- .../interfaces/ResizeValidationResult.md | 30 - docs/reference/interfaces/Resource.md | 70 -- docs/reference/interfaces/RoundOptions.md | 90 -- docs/reference/interfaces/SegmentInfo.md | 94 -- .../interfaces/SegmentResizePreview.md | 46 - docs/reference/interfaces/SinceOptions.md | 50 -- docs/reference/interfaces/StartOfOptions.md | 70 -- docs/reference/interfaces/SubtractOptions.md | 70 -- docs/reference/interfaces/TimeEventMap.md | 266 ------ docs/reference/interfaces/TimeSlot.md | 38 - .../interfaces/UnavailabilityReason.md | 88 -- docs/reference/interfaces/UnavailableRange.md | 56 -- .../interfaces/UnavailableTimeRange.md | 32 - docs/reference/interfaces/UntilOptions.md | 50 -- docs/reference/interfaces/ViewMode.md | 35 - docs/reference/type-aliases/DateInput.md | 12 - docs/reference/type-aliases/Day.md | 62 -- docs/reference/type-aliases/DurationLike.md | 12 - docs/reference/type-aliases/EndOfUnit.md | 20 - docs/reference/type-aliases/EqualsUnit.md | 20 - docs/reference/type-aliases/FormatType.md | 12 - .../type-aliases/GroupDaysByProps.md | 24 - .../type-aliases/IsSameOrAfterUnit.md | 20 - .../type-aliases/IsSameOrBeforeUnit.md | 20 - docs/reference/type-aliases/ResizeEdge.md | 12 - docs/reference/type-aliases/RoundUnit.md | 19 - docs/reference/type-aliases/StartOfUnit.md | 20 - 100 files changed, 67 insertions(+), 6537 deletions(-) delete mode 100644 docs/reference/classes/CalendarCore.md delete mode 100644 docs/reference/classes/DateCore.md delete mode 100644 docs/reference/functions/add.md delete mode 100644 docs/reference/functions/calculateDeltaMinutesFromPixels.md delete mode 100644 docs/reference/functions/calculateGhostPreviewStyle.md delete mode 100644 docs/reference/functions/calculateResizedEvent.md delete mode 100644 docs/reference/functions/calculateSegmentResizePreview.md delete mode 100644 docs/reference/functions/endOf.md delete mode 100644 docs/reference/functions/equals.md delete mode 100644 docs/reference/functions/format.md delete mode 100644 docs/reference/functions/formatEventTimeRange.md delete mode 100644 docs/reference/functions/generateDateRange.md delete mode 100644 docs/reference/functions/getEventDisplayTimeRange.md delete mode 100644 docs/reference/functions/getEventProps.md delete mode 100644 docs/reference/functions/getResizeHandleStyle.md delete mode 100644 docs/reference/functions/getSegmentInfo.md delete mode 100644 docs/reference/functions/getTimeClient.md delete mode 100644 docs/reference/functions/getTimeSlots.md delete mode 100644 docs/reference/functions/groupDaysBy.md delete mode 100644 docs/reference/functions/intersects.md delete mode 100644 docs/reference/functions/isAfter.md delete mode 100644 docs/reference/functions/isBefore.md delete mode 100644 docs/reference/functions/isBetween.md delete mode 100644 docs/reference/functions/isLeapYear.md delete mode 100644 docs/reference/functions/isMultiDayEvent.md delete mode 100644 docs/reference/functions/isSameOrAfter.md delete mode 100644 docs/reference/functions/isSameOrBefore.md delete mode 100644 docs/reference/functions/isWeekend.md delete mode 100644 docs/reference/functions/range.md delete mode 100644 docs/reference/functions/round.md delete mode 100644 docs/reference/functions/since.md delete mode 100644 docs/reference/functions/splitMultiDayEvents.md delete mode 100644 docs/reference/functions/startOf.md delete mode 100644 docs/reference/functions/subtract.md delete mode 100644 docs/reference/functions/until.md delete mode 100644 docs/reference/index.md delete mode 100644 docs/reference/interfaces/AddOptions.md delete mode 100644 docs/reference/interfaces/Availability.md delete mode 100644 docs/reference/interfaces/AvailabilityConflict.md delete mode 100644 docs/reference/interfaces/CalendarApi.md delete mode 100644 docs/reference/interfaces/CalendarCoreOptions.md delete mode 100644 docs/reference/interfaces/CalendarStore.md delete mode 100644 docs/reference/interfaces/DateCoreOptions.md delete mode 100644 docs/reference/interfaces/DateOptions.md delete mode 100644 docs/reference/interfaces/DateRange.md delete mode 100644 docs/reference/interfaces/EndOfOptions.md delete mode 100644 docs/reference/interfaces/EqualsOptions.md delete mode 100644 docs/reference/interfaces/Event.md delete mode 100644 docs/reference/interfaces/EventTimeRange.md delete mode 100644 docs/reference/interfaces/FormatDateOptions.md delete mode 100644 docs/reference/interfaces/FormatEventTimeOptions.md delete mode 100644 docs/reference/interfaces/FormattedEventTime.md delete mode 100644 docs/reference/interfaces/GhostPreviewOptions.md delete mode 100644 docs/reference/interfaces/IntersectsOptions.md delete mode 100644 docs/reference/interfaces/IsAfterOptions.md delete mode 100644 docs/reference/interfaces/IsBeforeOptions.md delete mode 100644 docs/reference/interfaces/IsBetweenOptions.md delete mode 100644 docs/reference/interfaces/IsLeapYearOptions.md delete mode 100644 docs/reference/interfaces/IsSameOrAfterOptions.md delete mode 100644 docs/reference/interfaces/IsSameOrBeforeOptions.md delete mode 100644 docs/reference/interfaces/IsWeekendOptions.md delete mode 100644 docs/reference/interfaces/ParsedDateCoreOptions.md delete mode 100644 docs/reference/interfaces/PositionStyle.md delete mode 100644 docs/reference/interfaces/Range.md delete mode 100644 docs/reference/interfaces/RangeOptions.md delete mode 100644 docs/reference/interfaces/ResizeConstraints.md delete mode 100644 docs/reference/interfaces/ResizeError.md delete mode 100644 docs/reference/interfaces/ResizeHandleStyle.md delete mode 100644 docs/reference/interfaces/ResizePreviewOptions.md delete mode 100644 docs/reference/interfaces/ResizeValidationResult.md delete mode 100644 docs/reference/interfaces/Resource.md delete mode 100644 docs/reference/interfaces/RoundOptions.md delete mode 100644 docs/reference/interfaces/SegmentInfo.md delete mode 100644 docs/reference/interfaces/SegmentResizePreview.md delete mode 100644 docs/reference/interfaces/SinceOptions.md delete mode 100644 docs/reference/interfaces/StartOfOptions.md delete mode 100644 docs/reference/interfaces/SubtractOptions.md delete mode 100644 docs/reference/interfaces/TimeEventMap.md delete mode 100644 docs/reference/interfaces/TimeSlot.md delete mode 100644 docs/reference/interfaces/UnavailabilityReason.md delete mode 100644 docs/reference/interfaces/UnavailableRange.md delete mode 100644 docs/reference/interfaces/UnavailableTimeRange.md delete mode 100644 docs/reference/interfaces/UntilOptions.md delete mode 100644 docs/reference/interfaces/ViewMode.md delete mode 100644 docs/reference/type-aliases/DateInput.md delete mode 100644 docs/reference/type-aliases/Day.md delete mode 100644 docs/reference/type-aliases/DurationLike.md delete mode 100644 docs/reference/type-aliases/EndOfUnit.md delete mode 100644 docs/reference/type-aliases/EqualsUnit.md delete mode 100644 docs/reference/type-aliases/FormatType.md delete mode 100644 docs/reference/type-aliases/GroupDaysByProps.md delete mode 100644 docs/reference/type-aliases/IsSameOrAfterUnit.md delete mode 100644 docs/reference/type-aliases/IsSameOrBeforeUnit.md delete mode 100644 docs/reference/type-aliases/ResizeEdge.md delete mode 100644 docs/reference/type-aliases/RoundUnit.md delete mode 100644 docs/reference/type-aliases/StartOfUnit.md diff --git a/docs/framework/react/reference/functions/useCalendar.md b/docs/framework/react/reference/functions/useCalendar.md index d3241b81..ed4fe312 100644 --- a/docs/framework/react/reference/functions/useCalendar.md +++ b/docs/framework/react/reference/functions/useCalendar.md @@ -9,7 +9,7 @@ title: useCalendar function useCalendar(options): CalendarApi & object; ``` -Defined in: [useCalendar.ts:69](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L69) +Defined in: [useCalendar.ts:76](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L76) ## Type Parameters diff --git a/docs/framework/react/reference/interfaces/ResizeOptions.md b/docs/framework/react/reference/interfaces/ResizeOptions.md index f00669e7..70c6b8f5 100644 --- a/docs/framework/react/reference/interfaces/ResizeOptions.md +++ b/docs/framework/react/reference/interfaces/ResizeOptions.md @@ -5,7 +5,7 @@ title: ResizeOptions # Interface: ResizeOptions -Defined in: [useCalendar.ts:36](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L36) +Defined in: [useCalendar.ts:38](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L38) ## Properties @@ -15,7 +15,7 @@ Defined in: [useCalendar.ts:36](https://github.com/TanStack/time/blob/main/packa optional constraints: ResizeConstraints; ``` -Defined in: [useCalendar.ts:39](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L39) +Defined in: [useCalendar.ts:43](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L43) *** @@ -25,7 +25,17 @@ Defined in: [useCalendar.ts:39](https://github.com/TanStack/time/blob/main/packa optional containerHeight: number; ``` -Defined in: [useCalendar.ts:38](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L38) +Defined in: [useCalendar.ts:40](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L40) + +*** + +### containerWidth? + +```ts +optional containerWidth: number; +``` + +Defined in: [useCalendar.ts:41](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L41) *** @@ -35,7 +45,7 @@ Defined in: [useCalendar.ts:38](https://github.com/TanStack/time/blob/main/packa optional enabled: boolean; ``` -Defined in: [useCalendar.ts:37](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L37) +Defined in: [useCalendar.ts:39](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L39) *** @@ -45,7 +55,7 @@ Defined in: [useCalendar.ts:37](https://github.com/TanStack/time/blob/main/packa optional onResizeEnd: (eventId, newStart, newEnd) => void; ``` -Defined in: [useCalendar.ts:41](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L41) +Defined in: [useCalendar.ts:45](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L45) #### Parameters @@ -73,7 +83,7 @@ Defined in: [useCalendar.ts:41](https://github.com/TanStack/time/blob/main/packa optional onResizeError: (error) => void; ``` -Defined in: [useCalendar.ts:42](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L42) +Defined in: [useCalendar.ts:46](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L46) #### Parameters @@ -93,7 +103,7 @@ Defined in: [useCalendar.ts:42](https://github.com/TanStack/time/blob/main/packa optional onResizeStart: (eventId, edge) => void; ``` -Defined in: [useCalendar.ts:40](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L40) +Defined in: [useCalendar.ts:44](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L44) #### Parameters @@ -108,3 +118,13 @@ Defined in: [useCalendar.ts:40](https://github.com/TanStack/time/blob/main/packa #### Returns `void` + +*** + +### orientation? + +```ts +optional orientation: "vertical" | "horizontal"; +``` + +Defined in: [useCalendar.ts:42](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L42) diff --git a/docs/framework/react/reference/interfaces/ResizeState.md b/docs/framework/react/reference/interfaces/ResizeState.md index e1d4a00a..4abb390e 100644 --- a/docs/framework/react/reference/interfaces/ResizeState.md +++ b/docs/framework/react/reference/interfaces/ResizeState.md @@ -5,17 +5,27 @@ title: ResizeState # Interface: ResizeState -Defined in: [useCalendar.ts:27](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L27) +Defined in: [useCalendar.ts:26](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L26) ## Properties +### blocked + +```ts +blocked: boolean; +``` + +Defined in: [useCalendar.ts:35](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L35) + +*** + ### edge ```ts edge: ResizeEdge | null; ``` -Defined in: [useCalendar.ts:30](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L30) +Defined in: [useCalendar.ts:29](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L29) *** @@ -25,7 +35,7 @@ Defined in: [useCalendar.ts:30](https://github.com/TanStack/time/blob/main/packa eventId: string | null; ``` -Defined in: [useCalendar.ts:29](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L29) +Defined in: [useCalendar.ts:28](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L28) *** @@ -35,7 +45,27 @@ Defined in: [useCalendar.ts:29](https://github.com/TanStack/time/blob/main/packa isResizing: boolean; ``` -Defined in: [useCalendar.ts:28](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L28) +Defined in: [useCalendar.ts:27](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L27) + +*** + +### lastValidPreviewEnd + +```ts +lastValidPreviewEnd: string | null; +``` + +Defined in: [useCalendar.ts:33](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L33) + +*** + +### lastValidPreviewStart + +```ts +lastValidPreviewStart: string | null; +``` + +Defined in: [useCalendar.ts:32](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L32) *** @@ -45,7 +75,7 @@ Defined in: [useCalendar.ts:28](https://github.com/TanStack/time/blob/main/packa previewEnd: string | null; ``` -Defined in: [useCalendar.ts:32](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L32) +Defined in: [useCalendar.ts:31](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L31) *** @@ -55,7 +85,7 @@ Defined in: [useCalendar.ts:32](https://github.com/TanStack/time/blob/main/packa previewStart: string | null; ``` -Defined in: [useCalendar.ts:31](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L31) +Defined in: [useCalendar.ts:30](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L30) *** @@ -65,4 +95,4 @@ Defined in: [useCalendar.ts:31](https://github.com/TanStack/time/blob/main/packa targetDayDate: string | null; ``` -Defined in: [useCalendar.ts:33](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L33) +Defined in: [useCalendar.ts:34](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L34) diff --git a/docs/framework/react/reference/interfaces/UseCalendarOptions.md b/docs/framework/react/reference/interfaces/UseCalendarOptions.md index e3d87648..454b16e0 100644 --- a/docs/framework/react/reference/interfaces/UseCalendarOptions.md +++ b/docs/framework/react/reference/interfaces/UseCalendarOptions.md @@ -5,7 +5,7 @@ title: UseCalendarOptions # Interface: UseCalendarOptions\ -Defined in: [useCalendar.ts:53](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L53) +Defined in: [useCalendar.ts:57](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L57) ## Extends @@ -29,4 +29,4 @@ Defined in: [useCalendar.ts:53](https://github.com/TanStack/time/blob/main/packa optional resize: ResizeOptions; ``` -Defined in: [useCalendar.ts:57](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L57) +Defined in: [useCalendar.ts:61](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L61) diff --git a/docs/reference/classes/CalendarCore.md b/docs/reference/classes/CalendarCore.md deleted file mode 100644 index 5a356179..00000000 --- a/docs/reference/classes/CalendarCore.md +++ /dev/null @@ -1,821 +0,0 @@ ---- -id: CalendarCore -title: CalendarCore ---- - -# Class: CalendarCore\ - -Defined in: [calendar/calendar.ts:147](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L147) - -## Extends - -- [`DateCore`](DateCore.md) - -## Type Parameters - -### TResource - -`TResource` *extends* [`Resource`](../interfaces/Resource.md) - -### TEvent - -`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> - -## Implements - -- `CalendarActions`\<`TResource`, `TEvent`\> - -## Constructors - -### Constructor - -```ts -new CalendarCore(options): CalendarCore; -``` - -Defined in: [calendar/calendar.ts:156](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L156) - -#### Parameters - -##### options - -[`CalendarCoreOptions`](../interfaces/CalendarCoreOptions.md)\<`TResource`, `TEvent`\> - -#### Returns - -`CalendarCore`\<`TResource`, `TEvent`\> - -#### Overrides - -[`DateCore`](DateCore.md).[`constructor`](DateCore.md#constructor) - -## Properties - -### formatters - -```ts -formatters: object; -``` - -Defined in: [calendar/date-core.ts:81](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L81) - -#### date - -```ts -date: DateTimeFormat; -``` - -#### dateTime - -```ts -dateTime: DateTimeFormat; -``` - -#### time - -```ts -time: DateTimeFormat; -``` - -#### Inherited from - -[`DateCore`](DateCore.md).[`formatters`](DateCore.md#formatters) - -*** - -### options - -```ts -options: ParsedCalendarCoreOptions; -``` - -Defined in: [calendar/calendar.ts:154](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L154) - -#### Overrides - -[`DateCore`](DateCore.md).[`options`](DateCore.md#options) - -*** - -### store - -```ts -store: Store; -``` - -Defined in: [calendar/date-core.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L79) - -#### Inherited from - -[`DateCore`](DateCore.md).[`store`](DateCore.md#store) - -## Methods - -### addEvent() - -```ts -addEvent(event): void; -``` - -Defined in: [calendar/calendar.ts:259](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L259) - -Adds a new event to the calendar. - -#### Parameters - -##### event - -`TEvent` - -#### Returns - -`void` - -#### Implementation of - -```ts -CalendarActions.addEvent -``` - -*** - -### canGoNextPeriod() - -```ts -canGoNextPeriod(): boolean; -``` - -Defined in: [calendar/date-core.ts:445](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L445) - -#### Returns - -`boolean` - -#### Implementation of - -```ts -CalendarActions.canGoNextPeriod -``` - -#### Inherited from - -[`DateCore`](DateCore.md).[`canGoNextPeriod`](DateCore.md#cangonextperiod) - -*** - -### canGoPreviousPeriod() - -```ts -canGoPreviousPeriod(): boolean; -``` - -Defined in: [calendar/date-core.ts:414](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L414) - -#### Returns - -`boolean` - -#### Implementation of - -```ts -CalendarActions.canGoPreviousPeriod -``` - -#### Inherited from - -[`DateCore`](DateCore.md).[`canGoPreviousPeriod`](DateCore.md#cangopreviousperiod) - -*** - -### changeViewMode() - -```ts -changeViewMode(newViewMode): void; -``` - -Defined in: [calendar/date-core.ts:265](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L265) - -#### Parameters - -##### newViewMode - -[`ViewMode`](../interfaces/ViewMode.md) - -#### Returns - -`void` - -#### Implementation of - -```ts -CalendarActions.changeViewMode -``` - -#### Inherited from - -[`DateCore`](DateCore.md).[`changeViewMode`](DateCore.md#changeviewmode) - -*** - -### formatDate() - -```ts -formatDate(date): string; -``` - -Defined in: [calendar/date-core.ts:131](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L131) - -#### Parameters - -##### date - -[`DateInput`](../type-aliases/DateInput.md) - -#### Returns - -`string` - -#### Inherited from - -[`DateCore`](DateCore.md).[`formatDate`](DateCore.md#formatdate) - -*** - -### formatDateTime() - -```ts -formatDateTime(date): string; -``` - -Defined in: [calendar/date-core.ts:139](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L139) - -#### Parameters - -##### date - -[`DateInput`](../type-aliases/DateInput.md) - -#### Returns - -`string` - -#### Inherited from - -[`DateCore`](DateCore.md).[`formatDateTime`](DateCore.md#formatdatetime) - -*** - -### formatTime() - -```ts -formatTime(date): string; -``` - -Defined in: [calendar/date-core.ts:135](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L135) - -#### Parameters - -##### date - -[`DateInput`](../type-aliases/DateInput.md) - -#### Returns - -`string` - -#### Inherited from - -[`DateCore`](DateCore.md).[`formatTime`](DateCore.md#formattime) - -*** - -### getCalendarDays() - -```ts -protected getCalendarDays(): PlainDate[]; -``` - -Defined in: [calendar/calendar.ts:164](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L164) - -#### Returns - -`PlainDate`[] - -#### Overrides - -[`DateCore`](DateCore.md).[`getCalendarDays`](DateCore.md#getcalendardays) - -*** - -### getDaysNames() - -```ts -getDaysNames(weekday): string[]; -``` - -Defined in: [calendar/date-core.ts:254](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L254) - -#### Parameters - -##### weekday - -`"long"` | `"short"` - -#### Returns - -`string`[] - -#### Implementation of - -```ts -CalendarActions.getDaysNames -``` - -#### Inherited from - -[`DateCore`](DateCore.md).[`getDaysNames`](DateCore.md#getdaysnames) - -*** - -### getDaysWithEvents() - -```ts -getDaysWithEvents(): object[]; -``` - -Defined in: [calendar/calendar.ts:201](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L201) - -#### Returns - -`object`[] - -*** - -### getEventProps() - -```ts -getEventProps(event): object; -``` - -Defined in: [calendar/calendar.ts:223](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L223) - -Retrieves styling properties for a specific event. - -#### Parameters - -##### event - -`TEvent` - -#### Returns - -`object` - -##### end - -```ts -end: string; -``` - -##### isSplitEvent - -```ts -isSplitEvent: boolean; -``` - -##### overlappingEvents - -```ts -overlappingEvents: TEvent[]; -``` - -##### start - -```ts -start: string; -``` - -##### style? - -```ts -optional style: object; -``` - -###### style.height - -```ts -height: string; -``` - -###### style.left - -```ts -left: string; -``` - -###### style.top - -```ts -top: string; -``` - -###### style.width - -```ts -width: string; -``` - -#### Implementation of - -```ts -CalendarActions.getEventProps -``` - -*** - -### getEventsByDate() - -```ts -getEventsByDate(date): TEvent[]; -``` - -Defined in: [calendar/calendar.ts:251](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L251) - -Retrieves events for a specific date. - -#### Parameters - -##### date - -`string` - -#### Returns - -`TEvent`[] - -#### Implementation of - -```ts -CalendarActions.getEventsByDate -``` - -*** - -### getFirstDayOfMonth() - -```ts -protected getFirstDayOfMonth(): PlainDate; -``` - -Defined in: [calendar/date-core.ts:143](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L143) - -#### Returns - -`PlainDate` - -#### Inherited from - -[`DateCore`](DateCore.md).[`getFirstDayOfMonth`](DateCore.md#getfirstdayofmonth) - -*** - -### getFirstDayOfWeek() - -```ts -protected getFirstDayOfWeek(): PlainDate; -``` - -Defined in: [calendar/date-core.ts:151](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L151) - -#### Returns - -`PlainDate` - -#### Inherited from - -[`DateCore`](DateCore.md).[`getFirstDayOfWeek`](DateCore.md#getfirstdayofweek) - -*** - -### getTimeSlots() - -```ts -getTimeSlots(options?): TimeSlot[]; -``` - -Defined in: [calendar/calendar.ts:247](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L247) - -Retrieves time slots for day view with configurable intervals. - -#### Parameters - -##### options? - -`TimeSlotOptions` - -#### Returns - -[`TimeSlot`](../interfaces/TimeSlot.md)[] - -#### Implementation of - -```ts -CalendarActions.getTimeSlots -``` - -*** - -### getUnavailabilityDetails() - -```ts -getUnavailabilityDetails( - date, - startMinutes, - endMinutes, - options?): object[]; -``` - -Defined in: [calendar/calendar.ts:437](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L437) - -Get detailed unavailability information for a specific time range on a date -Returns which resources are unavailable and why - -#### Parameters - -##### date - -`string` - -##### startMinutes - -`number` - -##### endMinutes - -`number` - -##### options? - -###### resourceIds? - -`TResource`\[`"id"`\][] - -#### Returns - -`object`[] - -*** - -### getUnavailableRanges() - -```ts -getUnavailableRanges(date, options?): UnavailableRange[]; -``` - -Defined in: [calendar/calendar.ts:325](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L325) - -Retrieves unavailable time ranges for a specific date based on resource availability. - -#### Parameters - -##### date - -`string` - -##### options? - -###### containerHeight? - -`number` - -###### resourceIds? - -`TResource`\[`"id"`\][] - -#### Returns - -[`UnavailableRange`](../interfaces/UnavailableRange.md)[] - -#### Implementation of - -```ts -CalendarActions.getUnavailableRanges -``` - -*** - -### getWeekStartsOn() - -```ts -getWeekStartsOn(): number; -``` - -Defined in: [calendar/date-core.ts:158](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L158) - -#### Returns - -`number` - -#### Inherited from - -[`DateCore`](DateCore.md).[`getWeekStartsOn`](DateCore.md#getweekstartson) - -*** - -### goToCurrentPeriod() - -```ts -goToCurrentPeriod(): void; -``` - -Defined in: [calendar/date-core.ts:375](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L375) - -#### Returns - -`void` - -#### Implementation of - -```ts -CalendarActions.goToCurrentPeriod -``` - -#### Inherited from - -[`DateCore`](DateCore.md).[`goToCurrentPeriod`](DateCore.md#gotocurrentperiod) - -*** - -### goToNextPeriod() - -```ts -goToNextPeriod(): void; -``` - -Defined in: [calendar/date-core.ts:327](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L327) - -#### Returns - -`void` - -#### Implementation of - -```ts -CalendarActions.goToNextPeriod -``` - -#### Inherited from - -[`DateCore`](DateCore.md).[`goToNextPeriod`](DateCore.md#gotonextperiod) - -*** - -### goToPreviousPeriod() - -```ts -goToPreviousPeriod(): void; -``` - -Defined in: [calendar/date-core.ts:279](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L279) - -#### Returns - -`void` - -#### Implementation of - -```ts -CalendarActions.goToPreviousPeriod -``` - -#### Inherited from - -[`DateCore`](DateCore.md).[`goToPreviousPeriod`](DateCore.md#gotopreviousperiod) - -*** - -### goToSpecificPeriod() - -```ts -goToSpecificPeriod(date): void; -``` - -Defined in: [calendar/date-core.ts:393](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L393) - -#### Parameters - -##### date - -[`DateInput`](../type-aliases/DateInput.md) - -#### Returns - -`void` - -#### Implementation of - -```ts -CalendarActions.goToSpecificPeriod -``` - -#### Inherited from - -[`DateCore`](DateCore.md).[`goToSpecificPeriod`](DateCore.md#gotospecificperiod) - -*** - -### groupDaysBy() - -```ts -groupDaysBy(__namedParameters): (Day | null)[][]; -``` - -Defined in: [calendar/calendar.ts:229](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L229) - -Groups days by a specified unit. - -#### Parameters - -##### \_\_namedParameters - -###### days - -([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[] - -###### fillMissingDays? - -`boolean` = `true` - -###### unit - -`"week"` \| `"workWeek"` - -#### Returns - -([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[][] - -#### Implementation of - -```ts -CalendarActions.groupDaysBy -``` - -*** - -### removeEvent() - -```ts -removeEvent(id): void; -``` - -Defined in: [calendar/calendar.ts:302](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L302) - -Removes an event by ID. - -#### Parameters - -##### id - -`string` - -#### Returns - -`void` - -#### Implementation of - -```ts -CalendarActions.removeEvent -``` - -*** - -### updateEvent() - -```ts -updateEvent(id, updates): void; -``` - -Defined in: [calendar/calendar.ts:277](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L277) - -Updates an existing event by ID. - -#### Parameters - -##### id - -`string` - -##### updates - -`Partial`\<`Omit`\<`TEvent`, `"id"`\>\> - -#### Returns - -`void` - -#### Implementation of - -```ts -CalendarActions.updateEvent -``` diff --git a/docs/reference/classes/DateCore.md b/docs/reference/classes/DateCore.md deleted file mode 100644 index f791e635..00000000 --- a/docs/reference/classes/DateCore.md +++ /dev/null @@ -1,326 +0,0 @@ ---- -id: DateCore -title: DateCore ---- - -# Abstract Class: DateCore - -Defined in: [calendar/date-core.ts:78](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L78) - -## Extended by - -- [`CalendarCore`](CalendarCore.md) - -## Constructors - -### Constructor - -```ts -new DateCore(options): DateCore; -``` - -Defined in: [calendar/date-core.ts:86](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L86) - -#### Parameters - -##### options - -[`DateCoreOptions`](../interfaces/DateCoreOptions.md) - -#### Returns - -`DateCore` - -## Properties - -### formatters - -```ts -formatters: object; -``` - -Defined in: [calendar/date-core.ts:81](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L81) - -#### date - -```ts -date: DateTimeFormat; -``` - -#### dateTime - -```ts -dateTime: DateTimeFormat; -``` - -#### time - -```ts -time: DateTimeFormat; -``` - -*** - -### options - -```ts -options: ParsedDateCoreOptions; -``` - -Defined in: [calendar/date-core.ts:80](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L80) - -*** - -### store - -```ts -store: Store; -``` - -Defined in: [calendar/date-core.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L79) - -## Methods - -### canGoNextPeriod() - -```ts -canGoNextPeriod(): boolean; -``` - -Defined in: [calendar/date-core.ts:445](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L445) - -#### Returns - -`boolean` - -*** - -### canGoPreviousPeriod() - -```ts -canGoPreviousPeriod(): boolean; -``` - -Defined in: [calendar/date-core.ts:414](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L414) - -#### Returns - -`boolean` - -*** - -### changeViewMode() - -```ts -changeViewMode(newViewMode): void; -``` - -Defined in: [calendar/date-core.ts:265](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L265) - -#### Parameters - -##### newViewMode - -[`ViewMode`](../interfaces/ViewMode.md) - -#### Returns - -`void` - -*** - -### formatDate() - -```ts -formatDate(date): string; -``` - -Defined in: [calendar/date-core.ts:131](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L131) - -#### Parameters - -##### date - -[`DateInput`](../type-aliases/DateInput.md) - -#### Returns - -`string` - -*** - -### formatDateTime() - -```ts -formatDateTime(date): string; -``` - -Defined in: [calendar/date-core.ts:139](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L139) - -#### Parameters - -##### date - -[`DateInput`](../type-aliases/DateInput.md) - -#### Returns - -`string` - -*** - -### formatTime() - -```ts -formatTime(date): string; -``` - -Defined in: [calendar/date-core.ts:135](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L135) - -#### Parameters - -##### date - -[`DateInput`](../type-aliases/DateInput.md) - -#### Returns - -`string` - -*** - -### getCalendarDays() - -```ts -protected getCalendarDays(): PlainDate[]; -``` - -Defined in: [calendar/date-core.ts:162](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L162) - -#### Returns - -`PlainDate`[] - -*** - -### getDaysNames() - -```ts -getDaysNames(weekday): string[]; -``` - -Defined in: [calendar/date-core.ts:254](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L254) - -#### Parameters - -##### weekday - -`"long"` | `"short"` - -#### Returns - -`string`[] - -*** - -### getFirstDayOfMonth() - -```ts -protected getFirstDayOfMonth(): PlainDate; -``` - -Defined in: [calendar/date-core.ts:143](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L143) - -#### Returns - -`PlainDate` - -*** - -### getFirstDayOfWeek() - -```ts -protected getFirstDayOfWeek(): PlainDate; -``` - -Defined in: [calendar/date-core.ts:151](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L151) - -#### Returns - -`PlainDate` - -*** - -### getWeekStartsOn() - -```ts -getWeekStartsOn(): number; -``` - -Defined in: [calendar/date-core.ts:158](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L158) - -#### Returns - -`number` - -*** - -### goToCurrentPeriod() - -```ts -goToCurrentPeriod(): void; -``` - -Defined in: [calendar/date-core.ts:375](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L375) - -#### Returns - -`void` - -*** - -### goToNextPeriod() - -```ts -goToNextPeriod(): void; -``` - -Defined in: [calendar/date-core.ts:327](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L327) - -#### Returns - -`void` - -*** - -### goToPreviousPeriod() - -```ts -goToPreviousPeriod(): void; -``` - -Defined in: [calendar/date-core.ts:279](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L279) - -#### Returns - -`void` - -*** - -### goToSpecificPeriod() - -```ts -goToSpecificPeriod(date): void; -``` - -Defined in: [calendar/date-core.ts:393](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L393) - -#### Parameters - -##### date - -[`DateInput`](../type-aliases/DateInput.md) - -#### Returns - -`void` diff --git a/docs/reference/functions/add.md b/docs/reference/functions/add.md deleted file mode 100644 index b3b99a48..00000000 --- a/docs/reference/functions/add.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: add -title: add ---- - -# Function: add() - -```ts -function add(input, options): object; -``` - -Defined in: [date/add/add.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L13) - -add -Adds a duration to a date/time instance - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`AddOptions`](../interfaces/AddOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/calculateDeltaMinutesFromPixels.md b/docs/reference/functions/calculateDeltaMinutesFromPixels.md deleted file mode 100644 index aff7522d..00000000 --- a/docs/reference/functions/calculateDeltaMinutesFromPixels.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: calculateDeltaMinutesFromPixels -title: calculateDeltaMinutesFromPixels ---- - -# Function: calculateDeltaMinutesFromPixels() - -```ts -function calculateDeltaMinutesFromPixels( - deltaPixels, - containerHeight, - minutesInDay): number; -``` - -Defined in: [calendar/getResizeProps.ts:164](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L164) - -## Parameters - -### deltaPixels - -`number` - -### containerHeight - -`number` - -### minutesInDay - -`number` = `...` - -## Returns - -`number` diff --git a/docs/reference/functions/calculateGhostPreviewStyle.md b/docs/reference/functions/calculateGhostPreviewStyle.md deleted file mode 100644 index 64389403..00000000 --- a/docs/reference/functions/calculateGhostPreviewStyle.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -id: calculateGhostPreviewStyle -title: calculateGhostPreviewStyle ---- - -# Function: calculateGhostPreviewStyle() - -```ts -function calculateGhostPreviewStyle(options): PositionStyle | null; -``` - -Defined in: [calendar/getResizeProps.ts:368](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L368) - -Calculates the ghost preview style for a day that doesn't have an existing segment - -## Parameters - -### options - -[`GhostPreviewOptions`](../interfaces/GhostPreviewOptions.md) - -## Returns - -[`PositionStyle`](../interfaces/PositionStyle.md) \| `null` diff --git a/docs/reference/functions/calculateResizedEvent.md b/docs/reference/functions/calculateResizedEvent.md deleted file mode 100644 index 174368fc..00000000 --- a/docs/reference/functions/calculateResizedEvent.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: calculateResizedEvent -title: calculateResizedEvent ---- - -# Function: calculateResizedEvent() - -```ts -function calculateResizedEvent(options): ResizedEventResult; -``` - -Defined in: [calendar/getResizeProps.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L58) - -## Parameters - -### options - -`CalculateResizedEventOptions` - -## Returns - -`ResizedEventResult` diff --git a/docs/reference/functions/calculateSegmentResizePreview.md b/docs/reference/functions/calculateSegmentResizePreview.md deleted file mode 100644 index f72c89a9..00000000 --- a/docs/reference/functions/calculateSegmentResizePreview.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -id: calculateSegmentResizePreview -title: calculateSegmentResizePreview ---- - -# Function: calculateSegmentResizePreview() - -```ts -function calculateSegmentResizePreview(options): SegmentResizePreview; -``` - -Defined in: [calendar/getResizeProps.ts:288](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L288) - -Calculates the resize preview state for a segment on a specific day - -## Parameters - -### options - -[`ResizePreviewOptions`](../interfaces/ResizePreviewOptions.md) - -## Returns - -[`SegmentResizePreview`](../interfaces/SegmentResizePreview.md) diff --git a/docs/reference/functions/endOf.md b/docs/reference/functions/endOf.md deleted file mode 100644 index 6f8e8077..00000000 --- a/docs/reference/functions/endOf.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: endOf -title: endOf ---- - -# Function: endOf() - -```ts -function endOf(input, options): object; -``` - -Defined in: [date/endOf/endOf.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L23) - -endOf -Returns the end of a given unit for a date/time instance - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`EndOfOptions`](../interfaces/EndOfOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/equals.md b/docs/reference/functions/equals.md deleted file mode 100644 index 7e9724aa..00000000 --- a/docs/reference/functions/equals.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -id: equals -title: equals ---- - -# Function: equals() - -```ts -function equals( - date1, - date2, - unit, - options?): boolean; -``` - -Defined in: [date/equals/equals.ts:22](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L22) - -equals -Returns true if two date/time instances are equal at the specified unit level - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### unit - -[`EqualsUnit`](../type-aliases/EqualsUnit.md) - -### options? - -[`EqualsOptions`](../interfaces/EqualsOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/format.md b/docs/reference/functions/format.md deleted file mode 100644 index 1c20d4a2..00000000 --- a/docs/reference/functions/format.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: format -title: format ---- - -# Function: format() - -```ts -function format(date, formatOptions?): string; -``` - -Defined in: [date/format/format.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L32) - -format -Formats a date/time instance using Intl.DateTimeFormat - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -The date to format - -### formatOptions? - -[`FormatDateOptions`](../interfaces/FormatDateOptions.md) - -Formatting options including type, locale, and Intl.DateTimeFormat options - -## Returns - -`string` diff --git a/docs/reference/functions/formatEventTimeRange.md b/docs/reference/functions/formatEventTimeRange.md deleted file mode 100644 index 89fc1f90..00000000 --- a/docs/reference/functions/formatEventTimeRange.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -id: formatEventTimeRange -title: formatEventTimeRange ---- - -# Function: formatEventTimeRange() - -```ts -function formatEventTimeRange( - start, - end, - options): FormattedEventTime; -``` - -Defined in: [calendar/getResizeProps.ts:493](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L493) - -Formats an event's time range for display -For multi-day events: includes date and time -For single-day events: includes only time (unless alwaysShowDate is true) - -## Parameters - -### start - -`string` - -### end - -`string` - -### options - -[`FormatEventTimeOptions`](../interfaces/FormatEventTimeOptions.md) = `{}` - -## Returns - -[`FormattedEventTime`](../interfaces/FormattedEventTime.md) diff --git a/docs/reference/functions/generateDateRange.md b/docs/reference/functions/generateDateRange.md deleted file mode 100644 index 8780d59c..00000000 --- a/docs/reference/functions/generateDateRange.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -id: generateDateRange -title: generateDateRange ---- - -# Function: generateDateRange() - -```ts -function generateDateRange(start, end): PlainDate[]; -``` - -Defined in: [calendar/generateDateRange.ts:3](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/generateDateRange.ts#L3) - -## Parameters - -### start - -`string` - -### end - -`string` - -## Returns - -`PlainDate`[] diff --git a/docs/reference/functions/getEventDisplayTimeRange.md b/docs/reference/functions/getEventDisplayTimeRange.md deleted file mode 100644 index ae349ea1..00000000 --- a/docs/reference/functions/getEventDisplayTimeRange.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -id: getEventDisplayTimeRange -title: getEventDisplayTimeRange ---- - -# Function: getEventDisplayTimeRange() - -```ts -function getEventDisplayTimeRange(options): EventTimeRange; -``` - -Defined in: [calendar/getResizeProps.ts:444](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L444) - -Gets the time range to display for an event, considering resize state - -## Parameters - -### options - -#### isBeingResized? - -`boolean` - -#### originalEnd - -`string` - -#### originalStart - -`string` - -#### previewEnd? - -`string` - -#### previewStart? - -`string` - -## Returns - -[`EventTimeRange`](../interfaces/EventTimeRange.md) diff --git a/docs/reference/functions/getEventProps.md b/docs/reference/functions/getEventProps.md deleted file mode 100644 index 904d9f77..00000000 --- a/docs/reference/functions/getEventProps.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: getEventProps -title: getEventProps ---- - -# Function: getEventProps() - -```ts -function getEventProps( - eventMap, - event, - state, - options): - | { - end: string; - isSplitEvent: boolean; - overlappingEvents: Event[]; - start: string; -} - | { - end: string; - isSplitEvent: boolean; - overlappingEvents: Event[]; - start: string; - style: { - height: string; - left: string; - top: string; - width: string; - }; -}; -``` - -Defined in: [calendar/getEventProps.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getEventProps.ts#L54) - -## Parameters - -### eventMap - -`Map`\<`string`, [`Event`](../interfaces/Event.md)\<[`Resource`](../interfaces/Resource.md)\>[]\> - -### event - -[`Event`](../interfaces/Event.md) - -### state - -[`CalendarStore`](../interfaces/CalendarStore.md) - -### options - -`GetEventPropsOptions` - -## Returns - - \| \{ - `end`: `string`; - `isSplitEvent`: `boolean`; - `overlappingEvents`: [`Event`](../interfaces/Event.md)\<[`Resource`](../interfaces/Resource.md)\>[]; - `start`: `string`; -\} - \| \{ - `end`: `string`; - `isSplitEvent`: `boolean`; - `overlappingEvents`: [`Event`](../interfaces/Event.md)\<[`Resource`](../interfaces/Resource.md)\>[]; - `start`: `string`; - `style`: \{ - `height`: `string`; - `left`: `string`; - `top`: `string`; - `width`: `string`; - \}; -\} diff --git a/docs/reference/functions/getResizeHandleStyle.md b/docs/reference/functions/getResizeHandleStyle.md deleted file mode 100644 index 0807e264..00000000 --- a/docs/reference/functions/getResizeHandleStyle.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -id: getResizeHandleStyle -title: getResizeHandleStyle ---- - -# Function: getResizeHandleStyle() - -```ts -function getResizeHandleStyle(edge): ResizeHandleStyle; -``` - -Defined in: [calendar/getResizeProps.ts:183](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L183) - -## Parameters - -### edge - -[`ResizeEdge`](../type-aliases/ResizeEdge.md) - -## Returns - -[`ResizeHandleStyle`](../interfaces/ResizeHandleStyle.md) diff --git a/docs/reference/functions/getSegmentInfo.md b/docs/reference/functions/getSegmentInfo.md deleted file mode 100644 index 55347ea7..00000000 --- a/docs/reference/functions/getSegmentInfo.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: getSegmentInfo -title: getSegmentInfo ---- - -# Function: getSegmentInfo() - -```ts -function getSegmentInfo(event): SegmentInfo; -``` - -Defined in: [calendar/getResizeProps.ts:219](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L219) - -## Parameters - -### event - -#### _originalEnd? - -`string` - -#### _originalStart? - -`string` - -#### end - -`string` - -#### start - -`string` - -## Returns - -[`SegmentInfo`](../interfaces/SegmentInfo.md) diff --git a/docs/reference/functions/getTimeClient.md b/docs/reference/functions/getTimeClient.md deleted file mode 100644 index f76050b5..00000000 --- a/docs/reference/functions/getTimeClient.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -id: getTimeClient -title: getTimeClient ---- - -# Function: getTimeClient() - -```ts -function getTimeClient(): TimeClient; -``` - -Defined in: [client/TimeClient.ts:86](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L86) - -Get the global TimeClient instance - -## Returns - -`TimeClient` diff --git a/docs/reference/functions/getTimeSlots.md b/docs/reference/functions/getTimeSlots.md deleted file mode 100644 index f88c1fc4..00000000 --- a/docs/reference/functions/getTimeSlots.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -id: getTimeSlots -title: getTimeSlots ---- - -# Function: getTimeSlots() - -```ts -function getTimeSlots(locale, options?): TimeSlot[]; -``` - -Defined in: [calendar/getTimeSlots.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getTimeSlots.ts#L19) - -Generates time slots for calendar day views. -Returns an array of time slots with labels formatted according to the locale. - -## Parameters - -### locale - -`string` - -The locale to use for formatting time labels (BCP 47 format) - -### options? - -`TimeSlotOptions` - -Configuration options for time slots - -## Returns - -[`TimeSlot`](../interfaces/TimeSlot.md)[] - -Array of time slots with hour, minute, and formatted label diff --git a/docs/reference/functions/groupDaysBy.md b/docs/reference/functions/groupDaysBy.md deleted file mode 100644 index 85f7a639..00000000 --- a/docs/reference/functions/groupDaysBy.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -id: groupDaysBy -title: groupDaysBy ---- - -# Function: groupDaysBy() - -```ts -function groupDaysBy(__namedParameters): (Day | null)[][]; -``` - -Defined in: [calendar/groupDaysBy.ts:37](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/groupDaysBy.ts#L37) - -## Type Parameters - -### TResource - -`TResource` *extends* [`Resource`](../interfaces/Resource.md) - -### TEvent - -`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> = [`Event`](../interfaces/Event.md)\<`TResource`\> - -## Parameters - -### \_\_namedParameters - -[`GroupDaysByProps`](../type-aliases/GroupDaysByProps.md)\<`TResource`, `TEvent`\> - -## Returns - -([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[][] diff --git a/docs/reference/functions/intersects.md b/docs/reference/functions/intersects.md deleted file mode 100644 index bdec851b..00000000 --- a/docs/reference/functions/intersects.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: intersects -title: intersects ---- - -# Function: intersects() - -```ts -function intersects(date, options): boolean; -``` - -Defined in: [date/intersects/intersects.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L16) - -intersects -Returns true if the date/time instance intersects with the range (i.e., is within or equal to the range boundaries) - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -The date to check - -### options - -[`IntersectsOptions`](../interfaces/IntersectsOptions.md) - -Options including range, timeZone and calendar - -## Returns - -`boolean` diff --git a/docs/reference/functions/isAfter.md b/docs/reference/functions/isAfter.md deleted file mode 100644 index c1c06abe..00000000 --- a/docs/reference/functions/isAfter.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: isAfter -title: isAfter ---- - -# Function: isAfter() - -```ts -function isAfter( - date1, - date2, - options?): boolean; -``` - -Defined in: [date/isAfter/isAfter.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/isAfter/isAfter.ts#L12) - -isAfter -Returns true if the first date/time instance is after the second date/time instance - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### options? - -[`IsAfterOptions`](../interfaces/IsAfterOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isBefore.md b/docs/reference/functions/isBefore.md deleted file mode 100644 index 796f97f1..00000000 --- a/docs/reference/functions/isBefore.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: isBefore -title: isBefore ---- - -# Function: isBefore() - -```ts -function isBefore( - date1, - date2, - options?): boolean; -``` - -Defined in: [date/isBefore/isBefore.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBefore/isBefore.ts#L12) - -isBefore -Returns true if the first date/time instance is before the second date/time instance - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### options? - -[`IsBeforeOptions`](../interfaces/IsBeforeOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isBetween.md b/docs/reference/functions/isBetween.md deleted file mode 100644 index 880bfb4a..00000000 --- a/docs/reference/functions/isBetween.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -id: isBetween -title: isBetween ---- - -# Function: isBetween() - -```ts -function isBetween(date, options): boolean; -``` - -Defined in: [date/isBetween/isBetween.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L18) - -isBetween -Returns true if the date/time instance is between the start and end of the range - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -The date to check - -### options - -[`IsBetweenOptions`](../interfaces/IsBetweenOptions.md) - -Options including timeZone, calendar, and inclusivity - -## Returns - -`boolean` diff --git a/docs/reference/functions/isLeapYear.md b/docs/reference/functions/isLeapYear.md deleted file mode 100644 index 0665af2b..00000000 --- a/docs/reference/functions/isLeapYear.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -id: isLeapYear -title: isLeapYear ---- - -# Function: isLeapYear() - -```ts -function isLeapYear(date, options?): boolean; -``` - -Defined in: [date/isLeapYear/isLeapYear.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/isLeapYear/isLeapYear.ts#L11) - -isLeapYear -Returns true if the year of the given date is a leap year - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -### options? - -[`IsLeapYearOptions`](../interfaces/IsLeapYearOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isMultiDayEvent.md b/docs/reference/functions/isMultiDayEvent.md deleted file mode 100644 index 1c0b4cb5..00000000 --- a/docs/reference/functions/isMultiDayEvent.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -id: isMultiDayEvent -title: isMultiDayEvent ---- - -# Function: isMultiDayEvent() - -```ts -function isMultiDayEvent(start, end): boolean; -``` - -Defined in: [calendar/getResizeProps.ts:429](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L429) - -Checks if an event spans multiple days - -## Parameters - -### start - -`string` - -### end - -`string` - -## Returns - -`boolean` diff --git a/docs/reference/functions/isSameOrAfter.md b/docs/reference/functions/isSameOrAfter.md deleted file mode 100644 index 1ff85269..00000000 --- a/docs/reference/functions/isSameOrAfter.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: isSameOrAfter -title: isSameOrAfter ---- - -# Function: isSameOrAfter() - -```ts -function isSameOrAfter( - date1, - date2, - options): boolean; -``` - -Defined in: [date/isSameOrAfter/isSameOrAfter.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L25) - -isSameOrAfter -Returns true if the first date/time instance is the same as or after the second date/time instance at the specified unit level - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`IsSameOrAfterOptions`](../interfaces/IsSameOrAfterOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isSameOrBefore.md b/docs/reference/functions/isSameOrBefore.md deleted file mode 100644 index 352fc993..00000000 --- a/docs/reference/functions/isSameOrBefore.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: isSameOrBefore -title: isSameOrBefore ---- - -# Function: isSameOrBefore() - -```ts -function isSameOrBefore( - date1, - date2, - options): boolean; -``` - -Defined in: [date/isSameOrBefore/isSameOrBefore.ts:25](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L25) - -isSameOrBefore -Returns true if the first date/time instance is the same as or before the second date/time instance at the specified unit level - -## Parameters - -### date1 - -[`DateInput`](../type-aliases/DateInput.md) - -### date2 - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`IsSameOrBeforeOptions`](../interfaces/IsSameOrBeforeOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/isWeekend.md b/docs/reference/functions/isWeekend.md deleted file mode 100644 index 152c2758..00000000 --- a/docs/reference/functions/isWeekend.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -id: isWeekend -title: isWeekend ---- - -# Function: isWeekend() - -```ts -function isWeekend(date, options?): boolean; -``` - -Defined in: [date/isWeekend/isWeekend.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L14) - -isWeekend -Returns true if the date falls on a weekend based on locale-specific week info - -## Parameters - -### date - -[`DateInput`](../type-aliases/DateInput.md) - -### options? - -[`IsWeekendOptions`](../interfaces/IsWeekendOptions.md) - -## Returns - -`boolean` diff --git a/docs/reference/functions/range.md b/docs/reference/functions/range.md deleted file mode 100644 index ed18d0a0..00000000 --- a/docs/reference/functions/range.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -id: range -title: range ---- - -# Function: range() - -```ts -function range(options): object[]; -``` - -Defined in: [date/range/range.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L18) - -range -Generates an array of dates from start to end at the specified step interval. -The range is inclusive of both start and end (if end falls exactly on a step). - -## Parameters - -### options - -[`RangeOptions`](../interfaces/RangeOptions.md) - -## Returns - -`object`[] diff --git a/docs/reference/functions/round.md b/docs/reference/functions/round.md deleted file mode 100644 index 6156d618..00000000 --- a/docs/reference/functions/round.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: round -title: round ---- - -# Function: round() - -```ts -function round(input, options): object; -``` - -Defined in: [date/round/round.ts:27](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L27) - -round -Returns the date/time instance rounded to the nearest unit - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`RoundOptions`](../interfaces/RoundOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/since.md b/docs/reference/functions/since.md deleted file mode 100644 index 3e051bea..00000000 --- a/docs/reference/functions/since.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -id: since -title: since ---- - -# Function: since() - -```ts -function since( - start, - end, - options): number; -``` - -Defined in: [date/since/since.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L15) - -since -Returns the duration from the first date/time instance since the second date/time instance -(equivalent to: how long has it been since the second date, from the first date's perspective) - -## Parameters - -### start - -[`DateInput`](../type-aliases/DateInput.md) - -### end - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`SinceOptions`](../interfaces/SinceOptions.md) - -## Returns - -`number` diff --git a/docs/reference/functions/splitMultiDayEvents.md b/docs/reference/functions/splitMultiDayEvents.md deleted file mode 100644 index 60d9dbf4..00000000 --- a/docs/reference/functions/splitMultiDayEvents.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: splitMultiDayEvents -title: splitMultiDayEvents ---- - -# Function: splitMultiDayEvents() - -```ts -function splitMultiDayEvents(event, timeZone): TEvent[]; -``` - -Defined in: [calendar/splitMultiDayEvents.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/splitMultiDayEvents.ts#L5) - -## Type Parameters - -### TResource - -`TResource` *extends* [`Resource`](../interfaces/Resource.md) = [`Resource`](../interfaces/Resource.md) - -### TEvent - -`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> = [`Event`](../interfaces/Event.md)\<`TResource`\> - -## Parameters - -### event - -`TEvent` - -### timeZone - -`TimeZoneLike` - -## Returns - -`TEvent`[] diff --git a/docs/reference/functions/startOf.md b/docs/reference/functions/startOf.md deleted file mode 100644 index d0d5e8af..00000000 --- a/docs/reference/functions/startOf.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: startOf -title: startOf ---- - -# Function: startOf() - -```ts -function startOf(input, options): object; -``` - -Defined in: [date/startOf/startOf.ts:23](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L23) - -startOf -Returns the start of a given unit for a date/time instance - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`StartOfOptions`](../interfaces/StartOfOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/subtract.md b/docs/reference/functions/subtract.md deleted file mode 100644 index 2beb5399..00000000 --- a/docs/reference/functions/subtract.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -id: subtract -title: subtract ---- - -# Function: subtract() - -```ts -function subtract(input, options): object; -``` - -Defined in: [date/subtract/subtract.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L13) - -subtract -Subtracts a duration from a date/time instance - -## Parameters - -### input - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`SubtractOptions`](../interfaces/SubtractOptions.md) - -## Returns - -`object` - -### asDate() - -```ts -asDate: () => Date; -``` - -#### Returns - -`Date` - -### asEpoch() - -```ts -asEpoch: () => number; -``` - -#### Returns - -`number` - -### asZonedDateTime() - -```ts -asZonedDateTime: () => ZonedDateTime; -``` - -#### Returns - -`ZonedDateTime` - -### calendar - -```ts -calendar: string = options.calendar; -``` - -### options - -```ts -options: ResolvedDateOperationOptions; -``` - -### returnFormat - -```ts -returnFormat: ReturnFormat; -``` - -### timeZone - -```ts -timeZone: string = options.timeZone; -``` - -### value - -```ts -value: string; -``` diff --git a/docs/reference/functions/until.md b/docs/reference/functions/until.md deleted file mode 100644 index 298e3e3e..00000000 --- a/docs/reference/functions/until.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -id: until -title: until ---- - -# Function: until() - -```ts -function until( - start, - end, - options): number; -``` - -Defined in: [date/until/until.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L14) - -until -Returns the duration from the first date/time instance until the second date/time instance - -## Parameters - -### start - -[`DateInput`](../type-aliases/DateInput.md) - -### end - -[`DateInput`](../type-aliases/DateInput.md) - -### options - -[`UntilOptions`](../interfaces/UntilOptions.md) - -## Returns - -`number` diff --git a/docs/reference/index.md b/docs/reference/index.md deleted file mode 100644 index 808f66d9..00000000 --- a/docs/reference/index.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -id: "@tanstack/time" -title: "@tanstack/time" ---- - -# @tanstack/time - -## Classes - -- [CalendarCore](classes/CalendarCore.md) -- [DateCore](classes/DateCore.md) - -## Interfaces - -- [AddOptions](interfaces/AddOptions.md) -- [Availability](interfaces/Availability.md) -- [AvailabilityConflict](interfaces/AvailabilityConflict.md) -- [CalendarApi](interfaces/CalendarApi.md) -- [CalendarCoreOptions](interfaces/CalendarCoreOptions.md) -- [CalendarStore](interfaces/CalendarStore.md) -- [DateCoreOptions](interfaces/DateCoreOptions.md) -- [DateOptions](interfaces/DateOptions.md) -- [DateRange](interfaces/DateRange.md) -- [EndOfOptions](interfaces/EndOfOptions.md) -- [EqualsOptions](interfaces/EqualsOptions.md) -- [Event](interfaces/Event.md) -- [EventTimeRange](interfaces/EventTimeRange.md) -- [FormatDateOptions](interfaces/FormatDateOptions.md) -- [FormatEventTimeOptions](interfaces/FormatEventTimeOptions.md) -- [FormattedEventTime](interfaces/FormattedEventTime.md) -- [GhostPreviewOptions](interfaces/GhostPreviewOptions.md) -- [IntersectsOptions](interfaces/IntersectsOptions.md) -- [IsAfterOptions](interfaces/IsAfterOptions.md) -- [IsBeforeOptions](interfaces/IsBeforeOptions.md) -- [IsBetweenOptions](interfaces/IsBetweenOptions.md) -- [IsLeapYearOptions](interfaces/IsLeapYearOptions.md) -- [IsSameOrAfterOptions](interfaces/IsSameOrAfterOptions.md) -- [IsSameOrBeforeOptions](interfaces/IsSameOrBeforeOptions.md) -- [IsWeekendOptions](interfaces/IsWeekendOptions.md) -- [ParsedDateCoreOptions](interfaces/ParsedDateCoreOptions.md) -- [PositionStyle](interfaces/PositionStyle.md) -- [Range](interfaces/Range.md) -- [RangeOptions](interfaces/RangeOptions.md) -- [ResizeConstraints](interfaces/ResizeConstraints.md) -- [ResizeError](interfaces/ResizeError.md) -- [ResizeHandleStyle](interfaces/ResizeHandleStyle.md) -- [ResizePreviewOptions](interfaces/ResizePreviewOptions.md) -- [ResizeValidationResult](interfaces/ResizeValidationResult.md) -- [Resource](interfaces/Resource.md) -- [RoundOptions](interfaces/RoundOptions.md) -- [SegmentInfo](interfaces/SegmentInfo.md) -- [SegmentResizePreview](interfaces/SegmentResizePreview.md) -- [SinceOptions](interfaces/SinceOptions.md) -- [StartOfOptions](interfaces/StartOfOptions.md) -- [SubtractOptions](interfaces/SubtractOptions.md) -- [TimeEventMap](interfaces/TimeEventMap.md) -- [TimeSlot](interfaces/TimeSlot.md) -- [UnavailabilityReason](interfaces/UnavailabilityReason.md) -- [UnavailableRange](interfaces/UnavailableRange.md) -- [UnavailableTimeRange](interfaces/UnavailableTimeRange.md) -- [UntilOptions](interfaces/UntilOptions.md) -- [ViewMode](interfaces/ViewMode.md) - -## Type Aliases - -- [DateInput](type-aliases/DateInput.md) -- [Day](type-aliases/Day.md) -- [DurationLike](type-aliases/DurationLike.md) -- [EndOfUnit](type-aliases/EndOfUnit.md) -- [EqualsUnit](type-aliases/EqualsUnit.md) -- [FormatType](type-aliases/FormatType.md) -- [GroupDaysByProps](type-aliases/GroupDaysByProps.md) -- [IsSameOrAfterUnit](type-aliases/IsSameOrAfterUnit.md) -- [IsSameOrBeforeUnit](type-aliases/IsSameOrBeforeUnit.md) -- [ResizeEdge](type-aliases/ResizeEdge.md) -- [RoundUnit](type-aliases/RoundUnit.md) -- [StartOfUnit](type-aliases/StartOfUnit.md) - -## Functions - -- [add](functions/add.md) -- [calculateDeltaMinutesFromPixels](functions/calculateDeltaMinutesFromPixels.md) -- [calculateGhostPreviewStyle](functions/calculateGhostPreviewStyle.md) -- [calculateResizedEvent](functions/calculateResizedEvent.md) -- [calculateSegmentResizePreview](functions/calculateSegmentResizePreview.md) -- [endOf](functions/endOf.md) -- [equals](functions/equals.md) -- [format](functions/format.md) -- [formatEventTimeRange](functions/formatEventTimeRange.md) -- [generateDateRange](functions/generateDateRange.md) -- [getEventDisplayTimeRange](functions/getEventDisplayTimeRange.md) -- [getEventProps](functions/getEventProps.md) -- [getResizeHandleStyle](functions/getResizeHandleStyle.md) -- [getSegmentInfo](functions/getSegmentInfo.md) -- [getTimeClient](functions/getTimeClient.md) -- [getTimeSlots](functions/getTimeSlots.md) -- [groupDaysBy](functions/groupDaysBy.md) -- [intersects](functions/intersects.md) -- [isAfter](functions/isAfter.md) -- [isBefore](functions/isBefore.md) -- [isBetween](functions/isBetween.md) -- [isLeapYear](functions/isLeapYear.md) -- [isMultiDayEvent](functions/isMultiDayEvent.md) -- [isSameOrAfter](functions/isSameOrAfter.md) -- [isSameOrBefore](functions/isSameOrBefore.md) -- [isWeekend](functions/isWeekend.md) -- [range](functions/range.md) -- [round](functions/round.md) -- [since](functions/since.md) -- [splitMultiDayEvents](functions/splitMultiDayEvents.md) -- [startOf](functions/startOf.md) -- [subtract](functions/subtract.md) -- [until](functions/until.md) diff --git a/docs/reference/interfaces/AddOptions.md b/docs/reference/interfaces/AddOptions.md deleted file mode 100644 index 250d3345..00000000 --- a/docs/reference/interfaces/AddOptions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: AddOptions -title: AddOptions ---- - -# Interface: AddOptions - -Defined in: [date/add/add.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L5) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### duration - -```ts -duration: DurationLike; -``` - -Defined in: [date/add/add.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/add/add.ts#L6) - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` diff --git a/docs/reference/interfaces/Availability.md b/docs/reference/interfaces/Availability.md deleted file mode 100644 index 1d9c4376..00000000 --- a/docs/reference/interfaces/Availability.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -id: Availability -title: Availability ---- - -# Interface: Availability - -Defined in: [calendar/types.ts:4](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L4) - -## Properties - -### endTime - -```ts -endTime: string; -``` - -Defined in: [calendar/types.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L10) - -End time in HH:mm format - -*** - -### startTime - -```ts -startTime: string; -``` - -Defined in: [calendar/types.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L8) - -Start time in HH:mm format - -*** - -### weekdays - -```ts -weekdays: number[]; -``` - -Defined in: [calendar/types.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L6) - -Days of the week when available (ISO weekday: 1 = Monday, ..., 7 = Sunday) diff --git a/docs/reference/interfaces/AvailabilityConflict.md b/docs/reference/interfaces/AvailabilityConflict.md deleted file mode 100644 index 0c4f5619..00000000 --- a/docs/reference/interfaces/AvailabilityConflict.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -id: AvailabilityConflict -title: AvailabilityConflict ---- - -# Interface: AvailabilityConflict - -Defined in: [calendar/types.ts:109](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L109) - -Information about a specific availability conflict - -## Properties - -### conflictRange - -```ts -conflictRange: object; -``` - -Defined in: [calendar/types.ts:113](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L113) - -Time range that conflicts with availability - -#### end - -```ts -end: string; -``` - -#### start - -```ts -start: string; -``` - -*** - -### date - -```ts -date: string; -``` - -Defined in: [calendar/types.ts:111](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L111) - -The date where the conflict occurred (YYYY-MM-DD) - -*** - -### description - -```ts -description: string; -``` - -Defined in: [calendar/types.ts:122](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L122) - -Human-readable description of the conflict - -*** - -### resourceDetails - -```ts -resourceDetails: UnavailabilityReason[]; -``` - -Defined in: [calendar/types.ts:120](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L120) - -Detailed reasons for each resource - -*** - -### resourceIds - -```ts -resourceIds: string[]; -``` - -Defined in: [calendar/types.ts:118](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L118) - -The resource(s) whose availability is being violated diff --git a/docs/reference/interfaces/CalendarApi.md b/docs/reference/interfaces/CalendarApi.md deleted file mode 100644 index f9b12cae..00000000 --- a/docs/reference/interfaces/CalendarApi.md +++ /dev/null @@ -1,590 +0,0 @@ ---- -id: CalendarApi -title: CalendarApi ---- - -# Interface: CalendarApi\ - -Defined in: [calendar/calendar.ts:126](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L126) - -## Extends - -- `CalendarActions`\<`TResource`, `TEvent`\>.`ConvertTemporalToString`\<`CalendarState`\<`TResource`, `TEvent`\>\> - -## Type Parameters - -### TResource - -`TResource` *extends* [`Resource`](Resource.md) - -### TEvent - -`TEvent` *extends* [`Event`](Event.md)\<`TResource`\> - -## Properties - -### activeDate - -```ts -activeDate: string; -``` - -Defined in: [calendar/calendar.ts:119](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L119) - -The currently active date in the calendar. - -#### Inherited from - -```ts -ConvertTemporalToString.activeDate -``` - -*** - -### addEvent() - -```ts -addEvent: (event) => void; -``` - -Defined in: [calendar/calendar.ts:93](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L93) - -Adds a new event to the calendar. - -#### Parameters - -##### event - -`TEvent` - -#### Returns - -`void` - -#### Inherited from - -```ts -CalendarActions.addEvent -``` - -*** - -### canGoNextPeriod() - -```ts -canGoNextPeriod: () => boolean; -``` - -Defined in: [calendar/calendar.ts:62](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L62) - -Checks if navigation to the next period is allowed within the range. - -#### Returns - -`boolean` - -#### Inherited from - -```ts -CalendarActions.canGoNextPeriod -``` - -*** - -### canGoPreviousPeriod() - -```ts -canGoPreviousPeriod: () => boolean; -``` - -Defined in: [calendar/calendar.ts:60](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L60) - -Checks if navigation to the previous period is allowed within the range. - -#### Returns - -`boolean` - -#### Inherited from - -```ts -CalendarActions.canGoPreviousPeriod -``` - -*** - -### changeViewMode() - -```ts -changeViewMode: (newViewMode) => void; -``` - -Defined in: [calendar/calendar.ts:64](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L64) - -Changes the current view mode of the calendar. - -#### Parameters - -##### newViewMode - -[`ViewMode`](ViewMode.md) - -#### Returns - -`void` - -#### Inherited from - -```ts -CalendarActions.changeViewMode -``` - -*** - -### currentPeriod - -```ts -currentPeriod: string; -``` - -Defined in: [calendar/calendar.ts:113](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L113) - -The currently focused date period in the calendar. - -#### Inherited from - -```ts -ConvertTemporalToString.currentPeriod -``` - -*** - -### days - -```ts -days: Day[]; -``` - -Defined in: [calendar/calendar.ts:117](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L117) - -An array of days, each potentially containing events. - -#### Inherited from - -```ts -ConvertTemporalToString.days -``` - -*** - -### getDaysNames() - -```ts -getDaysNames: (weekday?) => string[]; -``` - -Defined in: [calendar/calendar.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L79) - -Retrieves the names of the days of the week, based on the current locale. - -#### Parameters - -##### weekday? - -`"long"` | `"short"` - -#### Returns - -`string`[] - -#### Inherited from - -```ts -CalendarActions.getDaysNames -``` - -*** - -### getEventProps() - -```ts -getEventProps: (event) => object; -``` - -Defined in: [calendar/calendar.ts:66](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L66) - -Retrieves styling properties for a specific event. - -#### Parameters - -##### event - -`TEvent` - -#### Returns - -`object` - -##### end - -```ts -end: string; -``` - -##### isSplitEvent - -```ts -isSplitEvent: boolean; -``` - -##### overlappingEvents - -```ts -overlappingEvents: TEvent[]; -``` - -##### start - -```ts -start: string; -``` - -##### style? - -```ts -optional style: object; -``` - -###### style.height - -```ts -height: string; -``` - -###### style.left - -```ts -left: string; -``` - -###### style.top - -```ts -top: string; -``` - -###### style.width - -```ts -width: string; -``` - -#### Inherited from - -```ts -CalendarActions.getEventProps -``` - -*** - -### getEventsByDate() - -```ts -getEventsByDate: (date) => TEvent[]; -``` - -Defined in: [calendar/calendar.ts:91](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L91) - -Retrieves events for a specific date. - -#### Parameters - -##### date - -`string` - -#### Returns - -`TEvent`[] - -#### Inherited from - -```ts -CalendarActions.getEventsByDate -``` - -*** - -### getTimeSlots() - -```ts -getTimeSlots: (options?) => TimeSlot[]; -``` - -Defined in: [calendar/calendar.ts:87](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L87) - -Retrieves time slots for day view with configurable intervals. - -#### Parameters - -##### options? - -`TimeSlotOptions` - -#### Returns - -[`TimeSlot`](TimeSlot.md)[] - -#### Inherited from - -```ts -CalendarActions.getTimeSlots -``` - -*** - -### getUnavailableRanges() - -```ts -getUnavailableRanges: (date, options?) => UnavailableRange[]; -``` - -Defined in: [calendar/calendar.ts:99](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L99) - -Retrieves unavailable time ranges for a specific date based on resource availability. - -#### Parameters - -##### date - -`string` - -##### options? - -###### containerHeight? - -`number` - -###### resourceIds? - -`TResource`\[`"id"`\][] - -#### Returns - -[`UnavailableRange`](UnavailableRange.md)[] - -#### Inherited from - -```ts -CalendarActions.getUnavailableRanges -``` - -*** - -### goToCurrentPeriod() - -```ts -goToCurrentPeriod: () => void; -``` - -Defined in: [calendar/calendar.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L56) - -Resets the view to the current period based on today's date. - -#### Returns - -`void` - -#### Inherited from - -```ts -CalendarActions.goToCurrentPeriod -``` - -*** - -### goToNextPeriod() - -```ts -goToNextPeriod: () => void; -``` - -Defined in: [calendar/calendar.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L54) - -Navigates to the next period according to the current view mode. - -#### Returns - -`void` - -#### Inherited from - -```ts -CalendarActions.goToNextPeriod -``` - -*** - -### goToPreviousPeriod() - -```ts -goToPreviousPeriod: () => void; -``` - -Defined in: [calendar/calendar.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L52) - -Navigates to the previous period according to the current view mode. - -#### Returns - -`void` - -#### Inherited from - -```ts -CalendarActions.goToPreviousPeriod -``` - -*** - -### goToSpecificPeriod() - -```ts -goToSpecificPeriod: (date) => void; -``` - -Defined in: [calendar/calendar.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L58) - -Navigates to a specific date. - -#### Parameters - -##### date - -`string` - -#### Returns - -`void` - -#### Inherited from - -```ts -CalendarActions.goToSpecificPeriod -``` - -*** - -### groupDaysBy() - -```ts -groupDaysBy: (props) => (Day | null)[][]; -``` - -Defined in: [calendar/calendar.ts:81](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L81) - -Groups days by a specified unit. - -#### Parameters - -##### props - -###### days - -([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[] - -###### fillMissingDays? - -`boolean` - -###### unit - -`"week"` \| `"workWeek"` - -#### Returns - -([`Day`](../type-aliases/Day.md)\<`TResource`, `TEvent`\> \| `null`)[][] - -#### Inherited from - -```ts -CalendarActions.groupDaysBy -``` - -*** - -### removeEvent() - -```ts -removeEvent: (id) => void; -``` - -Defined in: [calendar/calendar.ts:97](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L97) - -Removes an event by ID. - -#### Parameters - -##### id - -`string` - -#### Returns - -`void` - -#### Inherited from - -```ts -CalendarActions.removeEvent -``` - -*** - -### updateEvent() - -```ts -updateEvent: (id, updates) => void; -``` - -Defined in: [calendar/calendar.ts:95](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L95) - -Updates an existing event by ID. - -#### Parameters - -##### id - -`string` - -##### updates - -`Partial`\<`Omit`\<`TEvent`, `"id"`\>\> - -#### Returns - -`void` - -#### Inherited from - -```ts -CalendarActions.updateEvent -``` - -*** - -### viewMode - -```ts -viewMode: ViewMode; -``` - -Defined in: [calendar/calendar.ts:115](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L115) - -The current view mode of the calendar. - -#### Inherited from - -```ts -ConvertTemporalToString.viewMode -``` diff --git a/docs/reference/interfaces/CalendarCoreOptions.md b/docs/reference/interfaces/CalendarCoreOptions.md deleted file mode 100644 index 3b65ec9b..00000000 --- a/docs/reference/interfaces/CalendarCoreOptions.md +++ /dev/null @@ -1,179 +0,0 @@ ---- -id: CalendarCoreOptions -title: CalendarCoreOptions ---- - -# Interface: CalendarCoreOptions\ - -Defined in: [calendar/calendar.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L32) - -Configuration options for initializing a CalendarCore instance, allowing customization -of events, locale, time zone, and the calendar system. - -## Extends - -- [`DateCoreOptions`](DateCoreOptions.md) - -## Type Parameters - -### TResource - -`TResource` *extends* [`Resource`](Resource.md) - -### TEvent - -`TEvent` *extends* [`Event`](Event.md)\<`TResource`\> - -Specifies the event type, extending a base Event type. - -## Properties - -### calendar? - -```ts -optional calendar: CalendarLike; -``` - -Defined in: [calendar/date-core.ts:60](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L60) - -Optional calendar system to be used. - -#### Inherited from - -[`DateCoreOptions`](DateCoreOptions.md).[`calendar`](DateCoreOptions.md#calendar) - -*** - -### dateFormatter? - -```ts -optional dateFormatter: DateTimeFormat; -``` - -Defined in: [calendar/date-core.ts:64](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L64) - -Optional date formatter. - -#### Inherited from - -[`DateCoreOptions`](DateCoreOptions.md).[`dateFormatter`](DateCoreOptions.md#dateformatter) - -*** - -### dateTimeFormatter? - -```ts -optional dateTimeFormatter: DateTimeFormat; -``` - -Defined in: [calendar/date-core.ts:68](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L68) - -Optional date time formatter. - -#### Inherited from - -[`DateCoreOptions`](DateCoreOptions.md).[`dateTimeFormatter`](DateCoreOptions.md#datetimeformatter) - -*** - -### events? - -```ts -optional events: TEvent[] | null; -``` - -Defined in: [calendar/calendar.ts:37](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L37) - -An optional array of events to be handled by the calendar. - -*** - -### locale? - -```ts -optional locale: string; -``` - -Defined in: [calendar/date-core.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L56) - -Optional locale for date formatting. Uses a BCP 47 language tag. - -#### Inherited from - -[`DateCoreOptions`](DateCoreOptions.md).[`locale`](DateCoreOptions.md#locale) - -*** - -### range? - -```ts -optional range: DateRange; -``` - -Defined in: [calendar/date-core.ts:62](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L62) - -Optional range of dates to be used. - -#### Inherited from - -[`DateCoreOptions`](DateCoreOptions.md).[`range`](DateCoreOptions.md#range) - -*** - -### resources? - -```ts -optional resources: TResource[] | null; -``` - -Defined in: [calendar/calendar.ts:39](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/calendar.ts#L39) - -Optional resources to be used in the calendar. - -*** - -### timeFormatter? - -```ts -optional timeFormatter: DateTimeFormat; -``` - -Defined in: [calendar/date-core.ts:66](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L66) - -Optional time formatter. - -#### Inherited from - -[`DateCoreOptions`](DateCoreOptions.md).[`timeFormatter`](DateCoreOptions.md#timeformatter) - -*** - -### timeZone? - -```ts -optional timeZone: TimeZoneLike; -``` - -Defined in: [calendar/date-core.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L58) - -Optional time zone specification. - -#### Inherited from - -[`DateCoreOptions`](DateCoreOptions.md).[`timeZone`](DateCoreOptions.md#timezone) - -*** - -### viewMode - -```ts -viewMode: ViewMode; -``` - -Defined in: [calendar/date-core.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L54) - -The initial view mode configuration. - -#### Inherited from - -[`DateCoreOptions`](DateCoreOptions.md).[`viewMode`](DateCoreOptions.md#viewmode) diff --git a/docs/reference/interfaces/CalendarStore.md b/docs/reference/interfaces/CalendarStore.md deleted file mode 100644 index 87a2dbaa..00000000 --- a/docs/reference/interfaces/CalendarStore.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -id: CalendarStore -title: CalendarStore ---- - -# Interface: CalendarStore - -Defined in: [calendar/types.ts:79](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L79) - -## Properties - -### activeDate - -```ts -activeDate: PlainDate; -``` - -Defined in: [calendar/types.ts:81](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L81) - -*** - -### currentPeriod - -```ts -currentPeriod: PlainDate; -``` - -Defined in: [calendar/types.ts:80](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L80) - -*** - -### eventsVersion - -```ts -eventsVersion: number; -``` - -Defined in: [calendar/types.ts:83](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L83) - -*** - -### viewMode - -```ts -viewMode: ViewMode; -``` - -Defined in: [calendar/types.ts:82](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L82) diff --git a/docs/reference/interfaces/DateCoreOptions.md b/docs/reference/interfaces/DateCoreOptions.md deleted file mode 100644 index 267fd3e3..00000000 --- a/docs/reference/interfaces/DateCoreOptions.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -id: DateCoreOptions -title: DateCoreOptions ---- - -# Interface: DateCoreOptions - -Defined in: [calendar/date-core.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L52) - -Base options interface for date-related core classes. - -## Extended by - -- [`CalendarCoreOptions`](CalendarCoreOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: CalendarLike; -``` - -Defined in: [calendar/date-core.ts:60](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L60) - -Optional calendar system to be used. - -*** - -### dateFormatter? - -```ts -optional dateFormatter: DateTimeFormat; -``` - -Defined in: [calendar/date-core.ts:64](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L64) - -Optional date formatter. - -*** - -### dateTimeFormatter? - -```ts -optional dateTimeFormatter: DateTimeFormat; -``` - -Defined in: [calendar/date-core.ts:68](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L68) - -Optional date time formatter. - -*** - -### locale? - -```ts -optional locale: string; -``` - -Defined in: [calendar/date-core.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L56) - -Optional locale for date formatting. Uses a BCP 47 language tag. - -*** - -### range? - -```ts -optional range: DateRange; -``` - -Defined in: [calendar/date-core.ts:62](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L62) - -Optional range of dates to be used. - -*** - -### timeFormatter? - -```ts -optional timeFormatter: DateTimeFormat; -``` - -Defined in: [calendar/date-core.ts:66](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L66) - -Optional time formatter. - -*** - -### timeZone? - -```ts -optional timeZone: TimeZoneLike; -``` - -Defined in: [calendar/date-core.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L58) - -Optional time zone specification. - -*** - -### viewMode - -```ts -viewMode: ViewMode; -``` - -Defined in: [calendar/date-core.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L54) - -The initial view mode configuration. diff --git a/docs/reference/interfaces/DateOptions.md b/docs/reference/interfaces/DateOptions.md deleted file mode 100644 index 90b07152..00000000 --- a/docs/reference/interfaces/DateOptions.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -id: DateOptions -title: DateOptions ---- - -# Interface: DateOptions - -Defined in: [date/types.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L10) - -## Extended by - -- [`SinceOptions`](SinceOptions.md) -- [`UntilOptions`](UntilOptions.md) -- [`EqualsOptions`](EqualsOptions.md) -- [`IsLeapYearOptions`](IsLeapYearOptions.md) -- [`IsWeekendOptions`](IsWeekendOptions.md) -- [`IsBeforeOptions`](IsBeforeOptions.md) -- [`IsAfterOptions`](IsAfterOptions.md) -- [`IsSameOrBeforeOptions`](IsSameOrBeforeOptions.md) -- [`IsSameOrAfterOptions`](IsSameOrAfterOptions.md) -- [`IsBetweenOptions`](IsBetweenOptions.md) -- [`IntersectsOptions`](IntersectsOptions.md) -- [`FormatDateOptions`](FormatDateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) diff --git a/docs/reference/interfaces/DateRange.md b/docs/reference/interfaces/DateRange.md deleted file mode 100644 index a88b8032..00000000 --- a/docs/reference/interfaces/DateRange.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -id: DateRange -title: DateRange ---- - -# Interface: DateRange - -Defined in: [calendar/types.ts:57](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L57) - -## Properties - -### end - -```ts -end: DateInput | null; -``` - -Defined in: [calendar/types.ts:59](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L59) - -*** - -### start - -```ts -start: DateInput | null; -``` - -Defined in: [calendar/types.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L58) diff --git a/docs/reference/interfaces/EndOfOptions.md b/docs/reference/interfaces/EndOfOptions.md deleted file mode 100644 index 7f3c282c..00000000 --- a/docs/reference/interfaces/EndOfOptions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: EndOfOptions -title: EndOfOptions ---- - -# Interface: EndOfOptions - -Defined in: [date/endOf/endOf.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L15) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` - -*** - -### unit - -```ts -unit: EndOfUnit; -``` - -Defined in: [date/endOf/endOf.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L16) diff --git a/docs/reference/interfaces/EqualsOptions.md b/docs/reference/interfaces/EqualsOptions.md deleted file mode 100644 index 530e281b..00000000 --- a/docs/reference/interfaces/EqualsOptions.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: EqualsOptions -title: EqualsOptions ---- - -# Interface: EqualsOptions - -Defined in: [date/equals/equals.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L16) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/Event.md b/docs/reference/interfaces/Event.md deleted file mode 100644 index 41589484..00000000 --- a/docs/reference/interfaces/Event.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -id: Event -title: Event ---- - -# Interface: Event\ - -Defined in: [calendar/types.ts:35](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L35) - -## Type Parameters - -### TResource - -`TResource` *extends* [`Resource`](Resource.md) = [`Resource`](Resource.md) - -## Properties - -### \_originalEnd? - -```ts -optional _originalEnd: string; -``` - -Defined in: [calendar/types.ts:44](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L44) - -Original end time before splitting (only set on split segments of multi-day events) - -*** - -### \_originalStart? - -```ts -optional _originalStart: string; -``` - -Defined in: [calendar/types.ts:42](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L42) - -Original start time before splitting (only set on split segments of multi-day events) - -*** - -### end - -```ts -end: string; -``` - -Defined in: [calendar/types.ts:38](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L38) - -*** - -### id - -```ts -id: string; -``` - -Defined in: [calendar/types.ts:36](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L36) - -*** - -### resources? - -```ts -optional resources: TResource[]; -``` - -Defined in: [calendar/types.ts:40](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L40) - -*** - -### start - -```ts -start: string; -``` - -Defined in: [calendar/types.ts:37](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L37) - -*** - -### title - -```ts -title: string; -``` - -Defined in: [calendar/types.ts:39](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L39) diff --git a/docs/reference/interfaces/EventTimeRange.md b/docs/reference/interfaces/EventTimeRange.md deleted file mode 100644 index 953ca2b2..00000000 --- a/docs/reference/interfaces/EventTimeRange.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -id: EventTimeRange -title: EventTimeRange ---- - -# Interface: EventTimeRange - -Defined in: [calendar/getResizeProps.ts:435](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L435) - -## Properties - -### end - -```ts -end: string; -``` - -Defined in: [calendar/getResizeProps.ts:437](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L437) - -*** - -### isMultiDay - -```ts -isMultiDay: boolean; -``` - -Defined in: [calendar/getResizeProps.ts:438](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L438) - -*** - -### start - -```ts -start: string; -``` - -Defined in: [calendar/getResizeProps.ts:436](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L436) diff --git a/docs/reference/interfaces/FormatDateOptions.md b/docs/reference/interfaces/FormatDateOptions.md deleted file mode 100644 index cb4727cd..00000000 --- a/docs/reference/interfaces/FormatDateOptions.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -id: FormatDateOptions -title: FormatDateOptions ---- - -# Interface: FormatDateOptions - -Defined in: [date/format/format.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L16) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### locale? - -```ts -optional locale: string | string[] | Locale | Locale[]; -``` - -Defined in: [date/format/format.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L18) - -*** - -### options? - -```ts -optional options: - | string - | DateFormatterOptions - | TimeFormatterOptions - | DateTimeFormatterOptions; -``` - -Defined in: [date/format/format.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L19) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### type? - -```ts -optional type: FormatType; -``` - -Defined in: [date/format/format.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L17) diff --git a/docs/reference/interfaces/FormatEventTimeOptions.md b/docs/reference/interfaces/FormatEventTimeOptions.md deleted file mode 100644 index 93c3277b..00000000 --- a/docs/reference/interfaces/FormatEventTimeOptions.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -id: FormatEventTimeOptions -title: FormatEventTimeOptions ---- - -# Interface: FormatEventTimeOptions - -Defined in: [calendar/getResizeProps.ts:470](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L470) - -## Properties - -### alwaysShowDate? - -```ts -optional alwaysShowDate: boolean; -``` - -Defined in: [calendar/getResizeProps.ts:474](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L474) - -Whether to include date for single-day events - -*** - -### locale? - -```ts -optional locale: string; -``` - -Defined in: [calendar/getResizeProps.ts:472](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L472) - -Locale for formatting (e.g., 'en-US') diff --git a/docs/reference/interfaces/FormattedEventTime.md b/docs/reference/interfaces/FormattedEventTime.md deleted file mode 100644 index 15e98376..00000000 --- a/docs/reference/interfaces/FormattedEventTime.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -id: FormattedEventTime -title: FormattedEventTime ---- - -# Interface: FormattedEventTime - -Defined in: [calendar/getResizeProps.ts:477](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L477) - -## Properties - -### endFormatted - -```ts -endFormatted: string; -``` - -Defined in: [calendar/getResizeProps.ts:481](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L481) - -Formatted end string - -*** - -### isMultiDay - -```ts -isMultiDay: boolean; -``` - -Defined in: [calendar/getResizeProps.ts:485](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L485) - -Whether this is a multi-day event - -*** - -### rangeFormatted - -```ts -rangeFormatted: string; -``` - -Defined in: [calendar/getResizeProps.ts:483](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L483) - -Full formatted range string - -*** - -### startFormatted - -```ts -startFormatted: string; -``` - -Defined in: [calendar/getResizeProps.ts:479](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L479) - -Formatted start string diff --git a/docs/reference/interfaces/GhostPreviewOptions.md b/docs/reference/interfaces/GhostPreviewOptions.md deleted file mode 100644 index 21d5b53b..00000000 --- a/docs/reference/interfaces/GhostPreviewOptions.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -id: GhostPreviewOptions -title: GhostPreviewOptions ---- - -# Interface: GhostPreviewOptions - -Defined in: [calendar/getResizeProps.ts:356](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L356) - -## Properties - -### dayDate - -```ts -dayDate: string; -``` - -Defined in: [calendar/getResizeProps.ts:358](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L358) - -The date string of the day being rendered (YYYY-MM-DD) - -*** - -### previewEnd - -```ts -previewEnd: string; -``` - -Defined in: [calendar/getResizeProps.ts:362](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L362) - -The preview end during resize - -*** - -### previewStart - -```ts -previewStart: string; -``` - -Defined in: [calendar/getResizeProps.ts:360](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L360) - -The preview start during resize diff --git a/docs/reference/interfaces/IntersectsOptions.md b/docs/reference/interfaces/IntersectsOptions.md deleted file mode 100644 index 431b4865..00000000 --- a/docs/reference/interfaces/IntersectsOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: IntersectsOptions -title: IntersectsOptions ---- - -# Interface: IntersectsOptions - -Defined in: [date/intersects/intersects.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### range - -```ts -range: Range; -``` - -Defined in: [date/intersects/intersects.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/intersects/intersects.ts#L7) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsAfterOptions.md b/docs/reference/interfaces/IsAfterOptions.md deleted file mode 100644 index fb772548..00000000 --- a/docs/reference/interfaces/IsAfterOptions.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: IsAfterOptions -title: IsAfterOptions ---- - -# Interface: IsAfterOptions - -Defined in: [date/isAfter/isAfter.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isAfter/isAfter.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsBeforeOptions.md b/docs/reference/interfaces/IsBeforeOptions.md deleted file mode 100644 index 3c06573c..00000000 --- a/docs/reference/interfaces/IsBeforeOptions.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: IsBeforeOptions -title: IsBeforeOptions ---- - -# Interface: IsBeforeOptions - -Defined in: [date/isBefore/isBefore.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBefore/isBefore.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsBetweenOptions.md b/docs/reference/interfaces/IsBetweenOptions.md deleted file mode 100644 index 48e5ca62..00000000 --- a/docs/reference/interfaces/IsBetweenOptions.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: IsBetweenOptions -title: IsBetweenOptions ---- - -# Interface: IsBetweenOptions - -Defined in: [date/isBetween/isBetween.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### inclusive? - -```ts -optional inclusive: boolean | "start" | "end"; -``` - -Defined in: [date/isBetween/isBetween.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L7) - -*** - -### range - -```ts -range: Range; -``` - -Defined in: [date/isBetween/isBetween.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/date/isBetween/isBetween.ts#L8) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsLeapYearOptions.md b/docs/reference/interfaces/IsLeapYearOptions.md deleted file mode 100644 index dcdcc9f2..00000000 --- a/docs/reference/interfaces/IsLeapYearOptions.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: IsLeapYearOptions -title: IsLeapYearOptions ---- - -# Interface: IsLeapYearOptions - -Defined in: [date/isLeapYear/isLeapYear.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/isLeapYear/isLeapYear.ts#L5) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/IsSameOrAfterOptions.md b/docs/reference/interfaces/IsSameOrAfterOptions.md deleted file mode 100644 index 92f0e03c..00000000 --- a/docs/reference/interfaces/IsSameOrAfterOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: IsSameOrAfterOptions -title: IsSameOrAfterOptions ---- - -# Interface: IsSameOrAfterOptions - -Defined in: [date/isSameOrAfter/isSameOrAfter.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L17) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### unit - -```ts -unit: IsSameOrAfterUnit; -``` - -Defined in: [date/isSameOrAfter/isSameOrAfter.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L18) diff --git a/docs/reference/interfaces/IsSameOrBeforeOptions.md b/docs/reference/interfaces/IsSameOrBeforeOptions.md deleted file mode 100644 index e818e578..00000000 --- a/docs/reference/interfaces/IsSameOrBeforeOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: IsSameOrBeforeOptions -title: IsSameOrBeforeOptions ---- - -# Interface: IsSameOrBeforeOptions - -Defined in: [date/isSameOrBefore/isSameOrBefore.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L17) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### unit - -```ts -unit: IsSameOrBeforeUnit; -``` - -Defined in: [date/isSameOrBefore/isSameOrBefore.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L18) diff --git a/docs/reference/interfaces/IsWeekendOptions.md b/docs/reference/interfaces/IsWeekendOptions.md deleted file mode 100644 index f1bc1c23..00000000 --- a/docs/reference/interfaces/IsWeekendOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: IsWeekendOptions -title: IsWeekendOptions ---- - -# Interface: IsWeekendOptions - -Defined in: [date/isWeekend/isWeekend.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### locale? - -```ts -optional locale: string; -``` - -Defined in: [date/isWeekend/isWeekend.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isWeekend/isWeekend.ts#L7) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) diff --git a/docs/reference/interfaces/ParsedDateCoreOptions.md b/docs/reference/interfaces/ParsedDateCoreOptions.md deleted file mode 100644 index 5e694cf3..00000000 --- a/docs/reference/interfaces/ParsedDateCoreOptions.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -id: ParsedDateCoreOptions -title: ParsedDateCoreOptions ---- - -# Interface: ParsedDateCoreOptions - -Defined in: [calendar/date-core.ts:71](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L71) - -## Extends - -- `Omit`\<`Required`\<[`DateCoreOptions`](DateCoreOptions.md)\>, `"range"` \| `"dateFormatter"` \| `"timeFormatter"` \| `"dateTimeFormatter"`\> - -## Properties - -### calendar - -```ts -calendar: CalendarLike; -``` - -Defined in: [calendar/date-core.ts:60](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L60) - -Optional calendar system to be used. - -#### Inherited from - -[`CalendarCoreOptions`](CalendarCoreOptions.md).[`calendar`](CalendarCoreOptions.md#calendar) - -*** - -### locale - -```ts -locale: string; -``` - -Defined in: [calendar/date-core.ts:56](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L56) - -Optional locale for date formatting. Uses a BCP 47 language tag. - -#### Inherited from - -[`CalendarCoreOptions`](CalendarCoreOptions.md).[`locale`](CalendarCoreOptions.md#locale) - -*** - -### range - -```ts -range: ParsedDateRange; -``` - -Defined in: [calendar/date-core.ts:75](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L75) - -*** - -### timeZone - -```ts -timeZone: TimeZoneLike; -``` - -Defined in: [calendar/date-core.ts:58](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L58) - -Optional time zone specification. - -#### Inherited from - -[`CalendarCoreOptions`](CalendarCoreOptions.md).[`timeZone`](CalendarCoreOptions.md#timezone) - -*** - -### viewMode - -```ts -viewMode: ViewMode; -``` - -Defined in: [calendar/date-core.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/date-core.ts#L54) - -The initial view mode configuration. - -#### Inherited from - -[`CalendarCoreOptions`](CalendarCoreOptions.md).[`viewMode`](CalendarCoreOptions.md#viewmode) diff --git a/docs/reference/interfaces/PositionStyle.md b/docs/reference/interfaces/PositionStyle.md deleted file mode 100644 index a3057e32..00000000 --- a/docs/reference/interfaces/PositionStyle.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: PositionStyle -title: PositionStyle ---- - -# Interface: PositionStyle - -Defined in: [calendar/getResizeProps.ts:255](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L255) - -Style for positioned elements (events, ghosts) - -## Properties - -### height - -```ts -height: string; -``` - -Defined in: [calendar/getResizeProps.ts:257](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L257) - -*** - -### top - -```ts -top: string; -``` - -Defined in: [calendar/getResizeProps.ts:256](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L256) diff --git a/docs/reference/interfaces/Range.md b/docs/reference/interfaces/Range.md deleted file mode 100644 index 47d83f53..00000000 --- a/docs/reference/interfaces/Range.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -id: Range -title: Range ---- - -# Interface: Range - -Defined in: [date/types.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L17) - -## Properties - -### end - -```ts -end: DateInput; -``` - -Defined in: [date/types.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L19) - -*** - -### start - -```ts -start: DateInput; -``` - -Defined in: [date/types.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L18) diff --git a/docs/reference/interfaces/RangeOptions.md b/docs/reference/interfaces/RangeOptions.md deleted file mode 100644 index 86eaaf67..00000000 --- a/docs/reference/interfaces/RangeOptions.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -id: RangeOptions -title: RangeOptions ---- - -# Interface: RangeOptions - -Defined in: [date/range/range.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L7) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### end - -```ts -end: DateInput; -``` - -Defined in: [date/range/range.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L9) - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### start - -```ts -start: DateInput; -``` - -Defined in: [date/range/range.ts:8](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L8) - -*** - -### step - -```ts -step: DurationLike; -``` - -Defined in: [date/range/range.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/date/range/range.ts#L10) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` diff --git a/docs/reference/interfaces/ResizeConstraints.md b/docs/reference/interfaces/ResizeConstraints.md deleted file mode 100644 index 7da83e72..00000000 --- a/docs/reference/interfaces/ResizeConstraints.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -id: ResizeConstraints -title: ResizeConstraints ---- - -# Interface: ResizeConstraints - -Defined in: [calendar/getResizeProps.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L12) - -## Properties - -### minDurationMinutes? - -```ts -optional minDurationMinutes: number; -``` - -Defined in: [calendar/getResizeProps.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L13) - -*** - -### snapToMinutes? - -```ts -optional snapToMinutes: number; -``` - -Defined in: [calendar/getResizeProps.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L14) - -*** - -### unavailableRanges? - -```ts -optional unavailableRanges: UnavailableTimeRange[]; -``` - -Defined in: [calendar/getResizeProps.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L16) - -Unavailable time ranges that the event cannot be resized into diff --git a/docs/reference/interfaces/ResizeError.md b/docs/reference/interfaces/ResizeError.md deleted file mode 100644 index 9a78d786..00000000 --- a/docs/reference/interfaces/ResizeError.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -id: ResizeError -title: ResizeError ---- - -# Interface: ResizeError - -Defined in: [calendar/types.ts:128](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L128) - -Error information when a resize operation is blocked - -## Properties - -### attemptedEnd? - -```ts -optional attemptedEnd: string; -``` - -Defined in: [calendar/types.ts:136](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L136) - -*** - -### attemptedStart? - -```ts -optional attemptedStart: string; -``` - -Defined in: [calendar/types.ts:135](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L135) - -*** - -### conflicts? - -```ts -optional conflicts: AvailabilityConflict[]; -``` - -Defined in: [calendar/types.ts:138](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L138) - -Specific availability conflicts that prevented the resize - -*** - -### eventId - -```ts -eventId: string; -``` - -Defined in: [calendar/types.ts:129](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L129) - -*** - -### eventTitle - -```ts -eventTitle: string; -``` - -Defined in: [calendar/types.ts:130](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L130) - -*** - -### message - -```ts -message: string; -``` - -Defined in: [calendar/types.ts:132](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L132) - -*** - -### originalEnd - -```ts -originalEnd: string; -``` - -Defined in: [calendar/types.ts:134](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L134) - -*** - -### originalStart - -```ts -originalStart: string; -``` - -Defined in: [calendar/types.ts:133](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L133) - -*** - -### reason - -```ts -reason: "unavailable-time" | "invalid-time" | "min-duration" | "blocked"; -``` - -Defined in: [calendar/types.ts:131](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L131) diff --git a/docs/reference/interfaces/ResizeHandleStyle.md b/docs/reference/interfaces/ResizeHandleStyle.md deleted file mode 100644 index 8a224faf..00000000 --- a/docs/reference/interfaces/ResizeHandleStyle.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -id: ResizeHandleStyle -title: ResizeHandleStyle ---- - -# Interface: ResizeHandleStyle - -Defined in: [calendar/getResizeProps.ts:172](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L172) - -## Properties - -### bottom? - -```ts -optional bottom: number; -``` - -Defined in: [calendar/getResizeProps.ts:180](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L180) - -*** - -### cursor - -```ts -cursor: "ns-resize"; -``` - -Defined in: [calendar/getResizeProps.ts:177](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L177) - -*** - -### height - -```ts -height: string; -``` - -Defined in: [calendar/getResizeProps.ts:176](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L176) - -*** - -### left - -```ts -left: number; -``` - -Defined in: [calendar/getResizeProps.ts:174](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L174) - -*** - -### position - -```ts -position: "absolute"; -``` - -Defined in: [calendar/getResizeProps.ts:173](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L173) - -*** - -### right - -```ts -right: number; -``` - -Defined in: [calendar/getResizeProps.ts:175](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L175) - -*** - -### top? - -```ts -optional top: number; -``` - -Defined in: [calendar/getResizeProps.ts:179](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L179) - -*** - -### zIndex - -```ts -zIndex: number; -``` - -Defined in: [calendar/getResizeProps.ts:178](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L178) diff --git a/docs/reference/interfaces/ResizePreviewOptions.md b/docs/reference/interfaces/ResizePreviewOptions.md deleted file mode 100644 index dc729825..00000000 --- a/docs/reference/interfaces/ResizePreviewOptions.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -id: ResizePreviewOptions -title: ResizePreviewOptions ---- - -# Interface: ResizePreviewOptions - -Defined in: [calendar/getResizeProps.ts:272](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L272) - -## Properties - -### dayDate - -```ts -dayDate: string; -``` - -Defined in: [calendar/getResizeProps.ts:274](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L274) - -The date string of the day being rendered (YYYY-MM-DD) - -*** - -### originalEnd - -```ts -originalEnd: string; -``` - -Defined in: [calendar/getResizeProps.ts:278](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L278) - -The original end of the event (before resize) - -*** - -### originalStart - -```ts -originalStart: string; -``` - -Defined in: [calendar/getResizeProps.ts:276](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L276) - -The original start of the event (before resize) - -*** - -### previewEnd - -```ts -previewEnd: string; -``` - -Defined in: [calendar/getResizeProps.ts:282](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L282) - -The preview end during resize - -*** - -### previewStart - -```ts -previewStart: string; -``` - -Defined in: [calendar/getResizeProps.ts:280](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L280) - -The preview start during resize diff --git a/docs/reference/interfaces/ResizeValidationResult.md b/docs/reference/interfaces/ResizeValidationResult.md deleted file mode 100644 index a5334a57..00000000 --- a/docs/reference/interfaces/ResizeValidationResult.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: ResizeValidationResult -title: ResizeValidationResult ---- - -# Interface: ResizeValidationResult - -Defined in: [calendar/types.ts:144](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L144) - -Result of checking if a resize is valid - -## Properties - -### error? - -```ts -optional error: ResizeError; -``` - -Defined in: [calendar/types.ts:146](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L146) - -*** - -### valid - -```ts -valid: boolean; -``` - -Defined in: [calendar/types.ts:145](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L145) diff --git a/docs/reference/interfaces/Resource.md b/docs/reference/interfaces/Resource.md deleted file mode 100644 index 5e7c6ef0..00000000 --- a/docs/reference/interfaces/Resource.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: Resource -title: Resource ---- - -# Interface: Resource - -Defined in: [calendar/types.ts:13](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L13) - -## Properties - -### availability? - -```ts -optional availability: Availability[]; -``` - -Defined in: [calendar/types.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L16) - -*** - -### buffer? - -```ts -optional buffer: object; -``` - -Defined in: [calendar/types.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L18) - -#### after? - -```ts -optional after: number; -``` - -#### before? - -```ts -optional before: number; -``` - -*** - -### capacity? - -```ts -optional capacity: number; -``` - -Defined in: [calendar/types.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L17) - -*** - -### id - -```ts -id: string; -``` - -Defined in: [calendar/types.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L14) - -*** - -### label - -```ts -label: string; -``` - -Defined in: [calendar/types.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L15) diff --git a/docs/reference/interfaces/RoundOptions.md b/docs/reference/interfaces/RoundOptions.md deleted file mode 100644 index 005206c6..00000000 --- a/docs/reference/interfaces/RoundOptions.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -id: RoundOptions -title: RoundOptions ---- - -# Interface: RoundOptions - -Defined in: [date/round/round.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L17) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### roundingIncrement? - -```ts -optional roundingIncrement: number; -``` - -Defined in: [date/round/round.ts:20](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L20) - -*** - -### roundingMode? - -```ts -optional roundingMode: RoundingMode; -``` - -Defined in: [date/round/round.ts:19](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L19) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` - -*** - -### unit - -```ts -unit: RoundUnit; -``` - -Defined in: [date/round/round.ts:18](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L18) diff --git a/docs/reference/interfaces/SegmentInfo.md b/docs/reference/interfaces/SegmentInfo.md deleted file mode 100644 index 5f9ba92e..00000000 --- a/docs/reference/interfaces/SegmentInfo.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -id: SegmentInfo -title: SegmentInfo ---- - -# Interface: SegmentInfo - -Defined in: [calendar/getResizeProps.ts:202](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L202) - -Information about a segment's position within a multi-day event - -## Properties - -### isFirstSegment - -```ts -isFirstSegment: boolean; -``` - -Defined in: [calendar/getResizeProps.ts:204](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L204) - -Whether this is the first segment of a multi-day event - -*** - -### isLastSegment - -```ts -isLastSegment: boolean; -``` - -Defined in: [calendar/getResizeProps.ts:206](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L206) - -Whether this is the last segment of a multi-day event - -*** - -### isSplitEvent - -```ts -isSplitEvent: boolean; -``` - -Defined in: [calendar/getResizeProps.ts:208](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L208) - -Whether this segment is part of a split multi-day event - -*** - -### originalEnd - -```ts -originalEnd: string; -``` - -Defined in: [calendar/getResizeProps.ts:212](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L212) - -The original event end (before splitting) - -*** - -### originalStart - -```ts -originalStart: string; -``` - -Defined in: [calendar/getResizeProps.ts:210](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L210) - -The original event start (before splitting) - -*** - -### segmentEnd - -```ts -segmentEnd: string; -``` - -Defined in: [calendar/getResizeProps.ts:216](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L216) - -The segment's end time - -*** - -### segmentStart - -```ts -segmentStart: string; -``` - -Defined in: [calendar/getResizeProps.ts:214](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L214) - -The segment's start time diff --git a/docs/reference/interfaces/SegmentResizePreview.md b/docs/reference/interfaces/SegmentResizePreview.md deleted file mode 100644 index 0385d37b..00000000 --- a/docs/reference/interfaces/SegmentResizePreview.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -id: SegmentResizePreview -title: SegmentResizePreview ---- - -# Interface: SegmentResizePreview - -Defined in: [calendar/getResizeProps.ts:263](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L263) - -Result of resize preview calculation for a segment - -## Properties - -### hasChanged - -```ts -hasChanged: boolean; -``` - -Defined in: [calendar/getResizeProps.ts:269](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L269) - -Whether the preview has changed from the original - -*** - -### previewStyle - -```ts -previewStyle: PositionStyle | null; -``` - -Defined in: [calendar/getResizeProps.ts:267](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L267) - -The preview style to apply, if any - -*** - -### shouldHide - -```ts -shouldHide: boolean; -``` - -Defined in: [calendar/getResizeProps.ts:265](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L265) - -Whether the segment should be hidden (shrunk away) diff --git a/docs/reference/interfaces/SinceOptions.md b/docs/reference/interfaces/SinceOptions.md deleted file mode 100644 index 1d186d23..00000000 --- a/docs/reference/interfaces/SinceOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: SinceOptions -title: SinceOptions ---- - -# Interface: SinceOptions - -Defined in: [date/since/since.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### unit - -```ts -unit: DateTimeUnit; -``` - -Defined in: [date/since/since.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/since/since.ts#L7) diff --git a/docs/reference/interfaces/StartOfOptions.md b/docs/reference/interfaces/StartOfOptions.md deleted file mode 100644 index ad444e38..00000000 --- a/docs/reference/interfaces/StartOfOptions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: StartOfOptions -title: StartOfOptions ---- - -# Interface: StartOfOptions - -Defined in: [date/startOf/startOf.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L15) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` - -*** - -### unit - -```ts -unit: StartOfUnit; -``` - -Defined in: [date/startOf/startOf.ts:16](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L16) diff --git a/docs/reference/interfaces/SubtractOptions.md b/docs/reference/interfaces/SubtractOptions.md deleted file mode 100644 index 06f82129..00000000 --- a/docs/reference/interfaces/SubtractOptions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: SubtractOptions -title: SubtractOptions ---- - -# Interface: SubtractOptions - -Defined in: [date/subtract/subtract.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L5) - -## Extends - -- `DateOperationOptions` - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -```ts -DateOperationOptions.calendar -``` - -*** - -### duration - -```ts -duration: DurationLike; -``` - -Defined in: [date/subtract/subtract.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/subtract/subtract.ts#L6) - -*** - -### returnFormat? - -```ts -optional returnFormat: ReturnFormat; -``` - -Defined in: [date/withDateOperation/withDateOperation.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/date/withDateOperation/withDateOperation.ts#L9) - -#### Inherited from - -```ts -DateOperationOptions.returnFormat -``` - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -```ts -DateOperationOptions.timeZone -``` diff --git a/docs/reference/interfaces/TimeEventMap.md b/docs/reference/interfaces/TimeEventMap.md deleted file mode 100644 index 318be9db..00000000 --- a/docs/reference/interfaces/TimeEventMap.md +++ /dev/null @@ -1,266 +0,0 @@ ---- -id: TimeEventMap -title: TimeEventMap ---- - -# Interface: TimeEventMap - -Defined in: [client/TimeClient.ts:10](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L10) - -Event map for TimeClient events - -## Properties - -### time:calendar:navigate - -```ts -time:calendar:navigate: object; -``` - -Defined in: [client/TimeClient.ts:47](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L47) - -#### direction - -```ts -direction: "previous" | "next" | "current" | "specific"; -``` - -#### targetDate - -```ts -targetDate: string; -``` - -*** - -### time:calendar:viewMode:changed - -```ts -time:calendar:viewMode:changed: object; -``` - -Defined in: [client/TimeClient.ts:51](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L51) - -#### viewMode - -```ts -viewMode: object; -``` - -##### viewMode.unit - -```ts -unit: string; -``` - -##### viewMode.value - -```ts -value: number; -``` - -*** - -### time:event:added - -```ts -time:event:added: object; -``` - -Defined in: [client/TimeClient.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L11) - -#### end - -```ts -end: string; -``` - -#### eventId - -```ts -eventId: string; -``` - -#### eventTitle - -```ts -eventTitle: string; -``` - -#### start - -```ts -start: string; -``` - -*** - -### time:event:removed - -```ts -time:event:removed: object; -``` - -Defined in: [client/TimeClient.ts:24](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L24) - -#### end - -```ts -end: string; -``` - -#### eventId - -```ts -eventId: string; -``` - -#### eventTitle - -```ts -eventTitle: string; -``` - -#### start - -```ts -start: string; -``` - -*** - -### time:event:resize:error - -```ts -time:event:resize:error: object; -``` - -Defined in: [client/TimeClient.ts:36](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L36) - -#### attemptedEnd? - -```ts -optional attemptedEnd: string; -``` - -#### attemptedStart? - -```ts -optional attemptedStart: string; -``` - -#### conflicts? - -```ts -optional conflicts: AvailabilityConflict[]; -``` - -#### eventId - -```ts -eventId: string; -``` - -#### eventTitle - -```ts -eventTitle: string; -``` - -#### message - -```ts -message: string; -``` - -#### originalEnd - -```ts -originalEnd: string; -``` - -#### originalStart - -```ts -originalStart: string; -``` - -#### reason - -```ts -reason: "unavailable-time" | "invalid-time" | "min-duration" | "blocked"; -``` - -*** - -### time:event:resized - -```ts -time:event:resized: object; -``` - -Defined in: [client/TimeClient.ts:30](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L30) - -#### end - -```ts -end: string; -``` - -#### eventId - -```ts -eventId: string; -``` - -#### eventTitle - -```ts -eventTitle: string; -``` - -#### start - -```ts -start: string; -``` - -*** - -### time:event:updated - -```ts -time:event:updated: object; -``` - -Defined in: [client/TimeClient.ts:17](https://github.com/TanStack/time/blob/main/packages/time/src/client/TimeClient.ts#L17) - -#### end - -```ts -end: string; -``` - -#### eventId - -```ts -eventId: string; -``` - -#### eventTitle - -```ts -eventTitle: string; -``` - -#### start - -```ts -start: string; -``` - -#### updates - -```ts -updates: Record; -``` diff --git a/docs/reference/interfaces/TimeSlot.md b/docs/reference/interfaces/TimeSlot.md deleted file mode 100644 index 0c8fc60a..00000000 --- a/docs/reference/interfaces/TimeSlot.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -id: TimeSlot -title: TimeSlot ---- - -# Interface: TimeSlot - -Defined in: [calendar/types.ts:62](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L62) - -## Properties - -### hour - -```ts -hour: number; -``` - -Defined in: [calendar/types.ts:63](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L63) - -*** - -### label - -```ts -label: string; -``` - -Defined in: [calendar/types.ts:65](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L65) - -*** - -### minute - -```ts -minute: number; -``` - -Defined in: [calendar/types.ts:64](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L64) diff --git a/docs/reference/interfaces/UnavailabilityReason.md b/docs/reference/interfaces/UnavailabilityReason.md deleted file mode 100644 index 44db1063..00000000 --- a/docs/reference/interfaces/UnavailabilityReason.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -id: UnavailabilityReason -title: UnavailabilityReason ---- - -# Interface: UnavailabilityReason - -Defined in: [calendar/types.ts:89](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L89) - -Information about why a resource is unavailable - -## Properties - -### capacityInfo? - -```ts -optional capacityInfo: object; -``` - -Defined in: [calendar/types.ts:99](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L99) - -Current capacity usage if applicable - -#### max - -```ts -max: number; -``` - -#### remaining - -```ts -remaining: number; -``` - -#### used - -```ts -used: number; -``` - -*** - -### description - -```ts -description: string; -``` - -Defined in: [calendar/types.ts:97](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L97) - -Human-readable explanation - -*** - -### reason - -```ts -reason: "outside-hours" | "capacity" | "no-availability"; -``` - -Defined in: [calendar/types.ts:95](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L95) - -Why the resource is unavailable - -*** - -### resourceId - -```ts -resourceId: string; -``` - -Defined in: [calendar/types.ts:91](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L91) - -Resource ID - -*** - -### resourceLabel - -```ts -resourceLabel: string; -``` - -Defined in: [calendar/types.ts:93](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L93) - -Resource label/name diff --git a/docs/reference/interfaces/UnavailableRange.md b/docs/reference/interfaces/UnavailableRange.md deleted file mode 100644 index 6178f643..00000000 --- a/docs/reference/interfaces/UnavailableRange.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -id: UnavailableRange -title: UnavailableRange ---- - -# Interface: UnavailableRange - -Defined in: [calendar/types.ts:68](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L68) - -## Properties - -### endTime - -```ts -endTime: string; -``` - -Defined in: [calendar/types.ts:76](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L76) - -End time as HH:mm string - -*** - -### height - -```ts -height: number; -``` - -Defined in: [calendar/types.ts:72](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L72) - -Height in pixels - -*** - -### startTime - -```ts -startTime: string; -``` - -Defined in: [calendar/types.ts:74](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L74) - -Start time as HH:mm string - -*** - -### top - -```ts -top: number; -``` - -Defined in: [calendar/types.ts:70](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L70) - -Top position in pixels diff --git a/docs/reference/interfaces/UnavailableTimeRange.md b/docs/reference/interfaces/UnavailableTimeRange.md deleted file mode 100644 index 8ae1abf4..00000000 --- a/docs/reference/interfaces/UnavailableTimeRange.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -id: UnavailableTimeRange -title: UnavailableTimeRange ---- - -# Interface: UnavailableTimeRange - -Defined in: [calendar/getResizeProps.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L5) - -## Properties - -### endMinutes - -```ts -endMinutes: number; -``` - -Defined in: [calendar/getResizeProps.ts:9](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L9) - -End time in minutes from midnight (0-1440) - -*** - -### startMinutes - -```ts -startMinutes: number; -``` - -Defined in: [calendar/getResizeProps.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L7) - -Start time in minutes from midnight (0-1440) diff --git a/docs/reference/interfaces/UntilOptions.md b/docs/reference/interfaces/UntilOptions.md deleted file mode 100644 index 6eb7aa61..00000000 --- a/docs/reference/interfaces/UntilOptions.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -id: UntilOptions -title: UntilOptions ---- - -# Interface: UntilOptions - -Defined in: [date/until/until.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L6) - -## Extends - -- [`DateOptions`](DateOptions.md) - -## Properties - -### calendar? - -```ts -optional calendar: string; -``` - -Defined in: [date/types.ts:11](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L11) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`calendar`](DateOptions.md#calendar) - -*** - -### timeZone? - -```ts -optional timeZone: string; -``` - -Defined in: [date/types.ts:12](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L12) - -#### Inherited from - -[`DateOptions`](DateOptions.md).[`timeZone`](DateOptions.md#timezone) - -*** - -### unit - -```ts -unit: DateTimeUnit; -``` - -Defined in: [date/until/until.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/until/until.ts#L7) diff --git a/docs/reference/interfaces/ViewMode.md b/docs/reference/interfaces/ViewMode.md deleted file mode 100644 index 3f6c8e71..00000000 --- a/docs/reference/interfaces/ViewMode.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -id: ViewMode -title: ViewMode ---- - -# Interface: ViewMode - -Defined in: [calendar/types.ts:28](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L28) - -Represents the configuration for the current viewing mode of a calendar, -specifying the scale and unit of time. - -## Properties - -### unit - -```ts -unit: "month" | "week" | "day" | "workWeek"; -``` - -Defined in: [calendar/types.ts:32](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L32) - -The unit of time that the calendar view should display (month, week, workWeek or day). - -*** - -### value - -```ts -value: number; -``` - -Defined in: [calendar/types.ts:30](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L30) - -The number of units for the view mode. diff --git a/docs/reference/type-aliases/DateInput.md b/docs/reference/type-aliases/DateInput.md deleted file mode 100644 index a62d63b6..00000000 --- a/docs/reference/type-aliases/DateInput.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: DateInput -title: DateInput ---- - -# Type Alias: DateInput - -```ts -type DateInput = string | number | Date | Temporal.ZonedDateTime | Temporal.PlainDate; -``` - -Defined in: [date/types.ts:3](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L3) diff --git a/docs/reference/type-aliases/Day.md b/docs/reference/type-aliases/Day.md deleted file mode 100644 index 55898a15..00000000 --- a/docs/reference/type-aliases/Day.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -id: Day -title: Day ---- - -# Type Alias: Day\ - -```ts -type Day = object; -``` - -Defined in: [calendar/types.ts:47](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L47) - -## Type Parameters - -### TResource - -`TResource` *extends* [`Resource`](../interfaces/Resource.md) = [`Resource`](../interfaces/Resource.md) - -### TEvent - -`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> = [`Event`](../interfaces/Event.md)\<`TResource`\> - -## Properties - -### date - -```ts -date: Temporal.PlainDate; -``` - -Defined in: [calendar/types.ts:51](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L51) - -*** - -### events - -```ts -events: TEvent[]; -``` - -Defined in: [calendar/types.ts:52](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L52) - -*** - -### isInCurrentPeriod - -```ts -isInCurrentPeriod: boolean; -``` - -Defined in: [calendar/types.ts:54](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L54) - -*** - -### isToday - -```ts -isToday: boolean; -``` - -Defined in: [calendar/types.ts:53](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/types.ts#L53) diff --git a/docs/reference/type-aliases/DurationLike.md b/docs/reference/type-aliases/DurationLike.md deleted file mode 100644 index ecdccc6f..00000000 --- a/docs/reference/type-aliases/DurationLike.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: DurationLike -title: DurationLike ---- - -# Type Alias: DurationLike - -```ts -type DurationLike = Temporal.DurationLike; -``` - -Defined in: [date/types.ts:15](https://github.com/TanStack/time/blob/main/packages/time/src/date/types.ts#L15) diff --git a/docs/reference/type-aliases/EndOfUnit.md b/docs/reference/type-aliases/EndOfUnit.md deleted file mode 100644 index 56e11564..00000000 --- a/docs/reference/type-aliases/EndOfUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: EndOfUnit -title: EndOfUnit ---- - -# Type Alias: EndOfUnit - -```ts -type EndOfUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [date/endOf/endOf.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/endOf/endOf.ts#L5) diff --git a/docs/reference/type-aliases/EqualsUnit.md b/docs/reference/type-aliases/EqualsUnit.md deleted file mode 100644 index 57c99027..00000000 --- a/docs/reference/type-aliases/EqualsUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: EqualsUnit -title: EqualsUnit ---- - -# Type Alias: EqualsUnit - -```ts -type EqualsUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [date/equals/equals.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/equals/equals.ts#L6) diff --git a/docs/reference/type-aliases/FormatType.md b/docs/reference/type-aliases/FormatType.md deleted file mode 100644 index 3d72d75f..00000000 --- a/docs/reference/type-aliases/FormatType.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: FormatType -title: FormatType ---- - -# Type Alias: FormatType - -```ts -type FormatType = "date" | "time" | "datetime"; -``` - -Defined in: [date/format/format.ts:14](https://github.com/TanStack/time/blob/main/packages/time/src/date/format/format.ts#L14) diff --git a/docs/reference/type-aliases/GroupDaysByProps.md b/docs/reference/type-aliases/GroupDaysByProps.md deleted file mode 100644 index 1f5551b4..00000000 --- a/docs/reference/type-aliases/GroupDaysByProps.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -id: GroupDaysByProps -title: GroupDaysByProps ---- - -# Type Alias: GroupDaysByProps\ - -```ts -type GroupDaysByProps = - | GroupDaysByMonthProps -| GroupDaysByWeekProps; -``` - -Defined in: [calendar/groupDaysBy.ts:30](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/groupDaysBy.ts#L30) - -## Type Parameters - -### TResource - -`TResource` *extends* [`Resource`](../interfaces/Resource.md) - -### TEvent - -`TEvent` *extends* [`Event`](../interfaces/Event.md)\<`TResource`\> = [`Event`](../interfaces/Event.md)\<`TResource`\> diff --git a/docs/reference/type-aliases/IsSameOrAfterUnit.md b/docs/reference/type-aliases/IsSameOrAfterUnit.md deleted file mode 100644 index 3c795455..00000000 --- a/docs/reference/type-aliases/IsSameOrAfterUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: IsSameOrAfterUnit -title: IsSameOrAfterUnit ---- - -# Type Alias: IsSameOrAfterUnit - -```ts -type IsSameOrAfterUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [date/isSameOrAfter/isSameOrAfter.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrAfter/isSameOrAfter.ts#L7) diff --git a/docs/reference/type-aliases/IsSameOrBeforeUnit.md b/docs/reference/type-aliases/IsSameOrBeforeUnit.md deleted file mode 100644 index 7552ceb0..00000000 --- a/docs/reference/type-aliases/IsSameOrBeforeUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: IsSameOrBeforeUnit -title: IsSameOrBeforeUnit ---- - -# Type Alias: IsSameOrBeforeUnit - -```ts -type IsSameOrBeforeUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [date/isSameOrBefore/isSameOrBefore.ts:7](https://github.com/TanStack/time/blob/main/packages/time/src/date/isSameOrBefore/isSameOrBefore.ts#L7) diff --git a/docs/reference/type-aliases/ResizeEdge.md b/docs/reference/type-aliases/ResizeEdge.md deleted file mode 100644 index 2fa72843..00000000 --- a/docs/reference/type-aliases/ResizeEdge.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -id: ResizeEdge -title: ResizeEdge ---- - -# Type Alias: ResizeEdge - -```ts -type ResizeEdge = "top" | "bottom"; -``` - -Defined in: [calendar/getResizeProps.ts:3](https://github.com/TanStack/time/blob/main/packages/time/src/calendar/getResizeProps.ts#L3) diff --git a/docs/reference/type-aliases/RoundUnit.md b/docs/reference/type-aliases/RoundUnit.md deleted file mode 100644 index c6f6620b..00000000 --- a/docs/reference/type-aliases/RoundUnit.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -id: RoundUnit -title: RoundUnit ---- - -# Type Alias: RoundUnit - -```ts -type RoundUnit = - | "day" - | "hour" - | "minute" - | "second" - | "millisecond" - | "microsecond" - | "nanosecond"; -``` - -Defined in: [date/round/round.ts:6](https://github.com/TanStack/time/blob/main/packages/time/src/date/round/round.ts#L6) diff --git a/docs/reference/type-aliases/StartOfUnit.md b/docs/reference/type-aliases/StartOfUnit.md deleted file mode 100644 index 50b40116..00000000 --- a/docs/reference/type-aliases/StartOfUnit.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -id: StartOfUnit -title: StartOfUnit ---- - -# Type Alias: StartOfUnit - -```ts -type StartOfUnit = - | "year" - | "month" - | "week" - | "day" - | "hour" - | "minute" - | "second" - | "millisecond"; -``` - -Defined in: [date/startOf/startOf.ts:5](https://github.com/TanStack/time/blob/main/packages/time/src/date/startOf/startOf.ts#L5) From 5be7365cc21d1ca015fb5bea61a35522a017f2f9 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Wed, 25 Mar 2026 12:24:39 +0100 Subject: [PATCH 061/207] feat: timeline --- examples/react/timeline/package.json | 1 + examples/react/timeline/src/index.tsx | 328 ++++++++- .../react-time/src/useCalendar/useCalendar.ts | 29 + packages/time-devtools/src/styles/tokens.ts | 305 --------- packages/time/src/calendar/calendar.ts | 495 +++++++++++++- .../time/src/calendar/tests/calendar.test.ts | 647 ++++++++++++++++++ packages/time/src/calendar/types.ts | 3 + packages/time/src/utils/dateTimeDefaults.ts | 10 - 8 files changed, 1462 insertions(+), 356 deletions(-) delete mode 100644 packages/time-devtools/src/styles/tokens.ts diff --git a/examples/react/timeline/package.json b/examples/react/timeline/package.json index 0d41cacd..bd6fc0ea 100644 --- a/examples/react/timeline/package.json +++ b/examples/react/timeline/package.json @@ -13,6 +13,7 @@ "@tanstack/react-time": "^0.0.0", "@tanstack/react-time-devtools": "^0.0.0", "@tanstack/time": "^0.0.0", + "@xyflow/react": "^12.10.1", "react": "^19.2.3", "react-dom": "^19.2.3" }, diff --git a/examples/react/timeline/src/index.tsx b/examples/react/timeline/src/index.tsx index 8cf772d4..53401e82 100644 --- a/examples/react/timeline/src/index.tsx +++ b/examples/react/timeline/src/index.tsx @@ -2,6 +2,22 @@ import { calculateTimelineResizePreview, useCalendar, } from '@tanstack/react-time' +import { TanStackDevtools } from '@tanstack/react-devtools' +import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' +import { + toPlainDateString, + toPlainDateTimeString, + toPlainTimeString, +} from '@tanstack/time' +import { + Handle, + MarkerType, + Position, + ReactFlow, + useEdgesState, + useNodesState, +} from '@xyflow/react' +import '@xyflow/react/dist/style.css' import ReactDOM from 'react-dom/client' import React, { useCallback, @@ -11,13 +27,6 @@ import React, { useRef, useState, } from 'react' -import { TanStackDevtools } from '@tanstack/react-devtools' -import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' -import { - toPlainDateString, - toPlainDateTimeString, - toPlainTimeString, -} from '@tanstack/time' import type { Day, Event, @@ -25,6 +34,7 @@ import type { Resource, TimelineResourceRow, } from '@tanstack/time' +import type { Connection, Edge, Node, NodeProps } from '@xyflow/react' import './index.css' @@ -112,8 +122,6 @@ const sampleResources: Array = [ resourceDevOps, ] -// Monday of the visible work week: Mon–Fri use the ISO week that contains today; -// Sat–Sun use the upcoming Monday so sample data is not entirely in the past. function workWeekMonday(): Date { const today = new Date() const day = today.getDay() @@ -128,7 +136,6 @@ function workWeekMonday(): Date { return monday } -// isoWeekday: 1=Mon … 5=Fri (relative to workWeekMonday()). function weekdayAt( isoWeekday: 1 | 2 | 3 | 4 | 5, hour: number, @@ -141,15 +148,6 @@ function weekdayAt( return date } -/* - Sample times are chosen so every event stays inside availability on that weekday, - and (where it matters) inside the intersection across weekdays: - - Design: Mon–Thu 09–17, Fri 09–13 → use only 09:00–13:00 so any Mon–Fri slot is safe. - - Frontend: Mon–Fri 08–24. - - Backend: Mon–Wed 10–19, Thu–Fri 00–24 → single-day uses 10–19; Thu→Fri span uses full-day Thu/Fri. - - QA: Mon–Wed 09–17, Thu–Fri 10–15 → use 10:00–15:00 everywhere. - - DevOps: Mon–Fri 07–16. -*/ function getSampleEvents(): Array> { return [ { @@ -186,6 +184,7 @@ function getSampleEvents(): Array> { start: weekdayAt(3, 10, 0), end: weekdayAt(3, 15, 0), resources: [resourceQA], + dependsOn: ['3'], }, { id: '6', @@ -200,6 +199,7 @@ function getSampleEvents(): Array> { start: weekdayAt(3, 10, 0), end: weekdayAt(3, 12, 30), resources: [resourceDesign], + dependsOn: ['1'], }, { id: '8', @@ -207,6 +207,7 @@ function getSampleEvents(): Array> { start: weekdayAt(4, 0, 0), end: weekdayAt(5, 10, 0), resources: [resourceBackend], + dependsOn: ['3'], }, { id: '9', @@ -214,6 +215,7 @@ function getSampleEvents(): Array> { start: weekdayAt(4, 10, 30), end: weekdayAt(4, 14, 30), resources: [resourceQA], + dependsOn: ['8'], }, { id: '10', @@ -221,6 +223,7 @@ function getSampleEvents(): Array> { start: weekdayAt(5, 7, 30), end: weekdayAt(5, 13, 0), resources: [resourceDevOps], + dependsOn: ['6'], }, ] } @@ -234,6 +237,7 @@ interface EventFormData { endDate: string endTime: string resourceId: string + dependsOn: Array } const emptyFormData: EventFormData = { @@ -243,6 +247,7 @@ const emptyFormData: EventFormData = { endDate: toPlainDateString(new Date()), endTime: '10:00', resourceId: resourceDesign.id, + dependsOn: [], } function EventModal({ @@ -367,6 +372,7 @@ function EventModal({ />
+
{mode === 'edit' && onDelete && ( @@ -453,13 +459,14 @@ function ResizeErrorToast({
!
- Cannot Resize Event + Cannot Resize{' '} + “{error.eventTitle}”
{error.message}
{error.conflicts && error.conflicts.length > 0 && (
- Conflicts: + Dependency conflicts:
{error.conflicts.map((conflict, idx) => (
- {conflict.date} -
-
- {conflict.conflictRange.start} -{' '} - {conflict.conflictRange.end} + {conflict.date}{' '} + + {conflict.conflictRange.start}– + {conflict.conflictRange.end} +
{conflict.description} @@ -480,9 +487,6 @@ function ResizeErrorToast({ ))}
)} -
- {error.eventTitle} -
-
+
{timelineLayout.currentTimePosition !== null && (
))} +
+ +
diff --git a/packages/react-time/src/useCalendar/useCalendar.ts b/packages/react-time/src/useCalendar/useCalendar.ts index 44b1aaee..887a7f6b 100644 --- a/packages/react-time/src/useCalendar/useCalendar.ts +++ b/packages/react-time/src/useCalendar/useCalendar.ts @@ -524,6 +524,31 @@ export const useCalendar = < [calendarCore], ) + const getEvents = useCallback( + () => calendarCore.getEvents(), + [calendarCore], + ) + + const validateMove = useCallback( + (eventId, newStart, newEnd) => + calendarCore.validateMove(eventId, newStart, newEnd), + [calendarCore], + ) + + const validateEventDependencies = useCallback( + ( + event: { id?: string; title: string; start: string; end: string }, + dependsOn: Array, + ) => calendarCore.validateEventDependencies(event, dependsOn), + [calendarCore], + ) + + const createDependency = useCallback( + (sourceId: string, targetId: string) => + calendarCore.createDependency(sourceId, targetId), + [calendarCore], + ) + const formatPeriodLabel = useCallback( (options) => calendarCore.formatPeriodLabel(options), [calendarCore], @@ -561,6 +586,10 @@ export const useCalendar = < getUnavailableRanges, getEventsByResource, getTimelineLayout, + getEvents, + validateMove, + validateEventDependencies, + createDependency, formatPeriodLabel, } } diff --git a/packages/time-devtools/src/styles/tokens.ts b/packages/time-devtools/src/styles/tokens.ts deleted file mode 100644 index 9d247cf1..00000000 --- a/packages/time-devtools/src/styles/tokens.ts +++ /dev/null @@ -1,305 +0,0 @@ -export const tokens = { - colors: { - inherit: 'inherit', - current: 'currentColor', - transparent: 'transparent', - black: '#000000', - white: '#ffffff', - neutral: { - 50: '#f9fafb', - 100: '#f2f4f7', - 200: '#eaecf0', - 300: '#d0d5dd', - 400: '#98a2b3', - 500: '#667085', - 600: '#475467', - 700: '#344054', - 800: '#1d2939', - 900: '#101828', - }, - darkGray: { - 50: '#525c7a', - 100: '#49536e', - 200: '#414962', - 300: '#394056', - 400: '#313749', - 500: '#292e3d', - 600: '#212530', - 700: '#191c24', - 800: '#111318', - 900: '#0b0d10', - }, - gray: { - 50: '#f9fafb', - 100: '#f2f4f7', - 200: '#eaecf0', - 300: '#d0d5dd', - 400: '#98a2b3', - 500: '#667085', - 600: '#475467', - 700: '#344054', - 800: '#1d2939', - 900: '#101828', - }, - blue: { - 25: '#F5FAFF', - 50: '#EFF8FF', - 100: '#D1E9FF', - 200: '#B2DDFF', - 300: '#84CAFF', - 400: '#53B1FD', - 500: '#2E90FA', - 600: '#1570EF', - 700: '#175CD3', - 800: '#1849A9', - 900: '#194185', - }, - green: { - 25: '#F6FEF9', - 50: '#ECFDF3', - 100: '#D1FADF', - 200: '#A6F4C5', - 300: '#6CE9A6', - 400: '#32D583', - 500: '#12B76A', - 600: '#039855', - 700: '#027A48', - 800: '#05603A', - 900: '#054F31', - }, - red: { - 50: '#fef2f2', - 100: '#fee2e2', - 200: '#fecaca', - 300: '#fca5a5', - 400: '#f87171', - 500: '#ef4444', - 600: '#dc2626', - 700: '#b91c1c', - 800: '#991b1b', - 900: '#7f1d1d', - 950: '#450a0a', - }, - yellow: { - 25: '#FFFCF5', - 50: '#FFFAEB', - 100: '#FEF0C7', - 200: '#FEDF89', - 300: '#FEC84B', - 400: '#FDB022', - 500: '#F79009', - 600: '#DC6803', - 700: '#B54708', - 800: '#93370D', - 900: '#7A2E0E', - }, - purple: { - 25: '#FAFAFF', - 50: '#F4F3FF', - 100: '#EBE9FE', - 200: '#D9D6FE', - 300: '#BDB4FE', - 400: '#9B8AFB', - 500: '#7A5AF8', - 600: '#6938EF', - 700: '#5925DC', - 800: '#4A1FB8', - 900: '#3E1C96', - }, - teal: { - 25: '#F6FEFC', - 50: '#F0FDF9', - 100: '#CCFBEF', - 200: '#99F6E0', - 300: '#5FE9D0', - 400: '#2ED3B7', - 500: '#15B79E', - 600: '#0E9384', - 700: '#107569', - 800: '#125D56', - 900: '#134E48', - }, - pink: { - 25: '#fdf2f8', - 50: '#fce7f3', - 100: '#fbcfe8', - 200: '#f9a8d4', - 300: '#f472b6', - 400: '#ec4899', - 500: '#db2777', - 600: '#be185d', - 700: '#9d174d', - 800: '#831843', - 900: '#500724', - }, - cyan: { - 25: '#ecfeff', - 50: '#cffafe', - 100: '#a5f3fc', - 200: '#67e8f9', - 300: '#22d3ee', - 400: '#06b6d4', - 500: '#0891b2', - 600: '#0e7490', - 700: '#155e75', - 800: '#164e63', - 900: '#083344', - }, - }, - alpha: { - 100: 'ff', - 90: 'e5', - 80: 'cc', - 70: 'b3', - 60: '99', - 50: '80', - 40: '66', - 30: '4d', - 20: '33', - 10: '1a', - 0: '00', - }, - font: { - size: { - '2xs': 'calc(var(--tsrd-font-size) * 0.625)', - xs: 'calc(var(--tsrd-font-size) * 0.75)', - sm: 'calc(var(--tsrd-font-size) * 0.875)', - md: 'var(--tsrd-font-size)', - lg: 'calc(var(--tsrd-font-size) * 1.125)', - xl: 'calc(var(--tsrd-font-size) * 1.25)', - '2xl': 'calc(var(--tsrd-font-size) * 1.5)', - '3xl': 'calc(var(--tsrd-font-size) * 1.875)', - '4xl': 'calc(var(--tsrd-font-size) * 2.25)', - '5xl': 'calc(var(--tsrd-font-size) * 3)', - '6xl': 'calc(var(--tsrd-font-size) * 3.75)', - '7xl': 'calc(var(--tsrd-font-size) * 4.5)', - '8xl': 'calc(var(--tsrd-font-size) * 6)', - '9xl': 'calc(var(--tsrd-font-size) * 8)', - }, - lineHeight: { - '3xs': 'calc(var(--tsrd-font-size) * 0.75)', - '2xs': 'calc(var(--tsrd-font-size) * 0.875)', - xs: 'calc(var(--tsrd-font-size) * 1)', - sm: 'calc(var(--tsrd-font-size) * 1.25)', - md: 'calc(var(--tsrd-font-size) * 1.5)', - lg: 'calc(var(--tsrd-font-size) * 1.75)', - xl: 'calc(var(--tsrd-font-size) * 2)', - '2xl': 'calc(var(--tsrd-font-size) * 2.25)', - '3xl': 'calc(var(--tsrd-font-size) * 2.5)', - '4xl': 'calc(var(--tsrd-font-size) * 2.75)', - '5xl': 'calc(var(--tsrd-font-size) * 3)', - '6xl': 'calc(var(--tsrd-font-size) * 3.25)', - '7xl': 'calc(var(--tsrd-font-size) * 3.5)', - '8xl': 'calc(var(--tsrd-font-size) * 3.75)', - '9xl': 'calc(var(--tsrd-font-size) * 4)', - }, - weight: { - thin: '100', - extralight: '200', - light: '300', - normal: '400', - medium: '500', - semibold: '600', - bold: '700', - extrabold: '800', - black: '900', - }, - fontFamily: { - sans: 'ui-sans-serif, Inter, system-ui, sans-serif, sans-serif', - mono: `ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace`, - }, - }, - breakpoints: { - xs: '320px', - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - border: { - radius: { - none: '0px', - xs: 'calc(var(--tsrd-font-size) * 0.125)', - sm: 'calc(var(--tsrd-font-size) * 0.25)', - md: 'calc(var(--tsrd-font-size) * 0.375)', - lg: 'calc(var(--tsrd-font-size) * 0.5)', - xl: 'calc(var(--tsrd-font-size) * 0.75)', - '2xl': 'calc(var(--tsrd-font-size) * 1)', - '3xl': 'calc(var(--tsrd-font-size) * 1.5)', - full: '9999px', - }, - }, - size: { - 0: '0px', - 0.25: 'calc(var(--tsrd-font-size) * 0.0625)', - 0.5: 'calc(var(--tsrd-font-size) * 0.125)', - 1: 'calc(var(--tsrd-font-size) * 0.25)', - 1.5: 'calc(var(--tsrd-font-size) * 0.375)', - 2: 'calc(var(--tsrd-font-size) * 0.5)', - 2.5: 'calc(var(--tsrd-font-size) * 0.625)', - 3: 'calc(var(--tsrd-font-size) * 0.75)', - 3.5: 'calc(var(--tsrd-font-size) * 0.875)', - 4: 'calc(var(--tsrd-font-size) * 1)', - 4.5: 'calc(var(--tsrd-font-size) * 1.125)', - 5: 'calc(var(--tsrd-font-size) * 1.25)', - 5.5: 'calc(var(--tsrd-font-size) * 1.375)', - 6: 'calc(var(--tsrd-font-size) * 1.5)', - 6.5: 'calc(var(--tsrd-font-size) * 1.625)', - 7: 'calc(var(--tsrd-font-size) * 1.75)', - 8: 'calc(var(--tsrd-font-size) * 2)', - 9: 'calc(var(--tsrd-font-size) * 2.25)', - 10: 'calc(var(--tsrd-font-size) * 2.5)', - 11: 'calc(var(--tsrd-font-size) * 2.75)', - 12: 'calc(var(--tsrd-font-size) * 3)', - 14: 'calc(var(--tsrd-font-size) * 3.5)', - 16: 'calc(var(--tsrd-font-size) * 4)', - 20: 'calc(var(--tsrd-font-size) * 5)', - 24: 'calc(var(--tsrd-font-size) * 6)', - 28: 'calc(var(--tsrd-font-size) * 7)', - 32: 'calc(var(--tsrd-font-size) * 8)', - 36: 'calc(var(--tsrd-font-size) * 9)', - 40: 'calc(var(--tsrd-font-size) * 10)', - 44: 'calc(var(--tsrd-font-size) * 11)', - 48: 'calc(var(--tsrd-font-size) * 12)', - 52: 'calc(var(--tsrd-font-size) * 13)', - 56: 'calc(var(--tsrd-font-size) * 14)', - 60: 'calc(var(--tsrd-font-size) * 15)', - 64: 'calc(var(--tsrd-font-size) * 16)', - 72: 'calc(var(--tsrd-font-size) * 18)', - 80: 'calc(var(--tsrd-font-size) * 20)', - 96: 'calc(var(--tsrd-font-size) * 24)', - }, - shadow: { - xs: (_: string = 'rgb(0 0 0 / 0.1)') => - `0 1px 2px 0 rgb(0 0 0 / 0.05)` as const, - sm: (color: string = 'rgb(0 0 0 / 0.1)') => - `0 1px 3px 0 ${color}, 0 1px 2px -1px ${color}` as const, - md: (color: string = 'rgb(0 0 0 / 0.1)') => - `0 4px 6px -1px ${color}, 0 2px 4px -2px ${color}` as const, - lg: (color: string = 'rgb(0 0 0 / 0.1)') => - `0 10px 15px -3px ${color}, 0 4px 6px -4px ${color}` as const, - xl: (color: string = 'rgb(0 0 0 / 0.1)') => - `0 20px 25px -5px ${color}, 0 8px 10px -6px ${color}` as const, - '2xl': (color: string = 'rgb(0 0 0 / 0.25)') => - `0 25px 50px -12px ${color}` as const, - inner: (color: string = 'rgb(0 0 0 / 0.05)') => - `inset 0 2px 4px 0 ${color}` as const, - none: () => `none` as const, - }, - zIndices: { - hide: -1, - auto: 'auto', - base: 0, - docked: 10, - dropdown: 1000, - sticky: 1100, - banner: 1200, - overlay: 1300, - modal: 1400, - popover: 1500, - skipLink: 1600, - toast: 1700, - tooltip: 1800, - }, -} as const diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index e7d52ce0..99c8f1e3 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -5,7 +5,6 @@ import { getEventProps } from './getEventProps' import { groupDaysBy } from './groupDaysBy' import { getTimeSlots } from './getTimeSlots' import { calculateResizedEvent } from './getResizeProps' -import { toPlainDateString, toPlainDateTimeString } from '~/date/parse' import { DateCore } from './date-core' import type { DateCoreOptions, ParsedDateCoreOptions } from './date-core' import type { @@ -25,6 +24,7 @@ import type { UnavailableRange, ViewMode, } from './types' +import { toPlainDateString, toPlainDateTimeString } from '~/date/parse' export type * from './types' export * from './date-core' @@ -120,6 +120,32 @@ interface CalendarActions< getTimelineLayout: () => TimelineLayout /** Returns a human-readable label for the currently visible date range. */ formatPeriodLabel: (options?: { locale?: string }) => string + /** Returns a snapshot of all events currently managed by the calendar (including those outside the visible range). */ + getEvents: () => Array + /** + * Checks whether moving `eventId` to `[newStart, newEnd]` — and cascading + * all finish-to-start dependents — would violate any resource availability. + */ + validateMove: ( + eventId: string, + newStart: string, + newEnd: string, + ) => { blocked: boolean; blockedEventTitle?: string; message?: string } + /** + * Validates if placing an event with a specific start time satisfies all dependency constraints. + */ + validateEventDependencies: ( + event: { id?: string; title: string; start: string; end: string }, + dependsOn: Array, + ) => { valid: boolean; error?: ResizeError } + /** + * Creates a dependency link from source to target event. + * If the target event starts before the source event ends, it will optionally reschedule the target. + */ + createDependency: ( + sourceId: string, + targetId: string, + ) => { blocked: boolean; error?: ResizeError } } interface CalendarState< @@ -358,6 +384,9 @@ export class CalendarCore< const index = this.options.events.findIndex((e) => e.id === id) if (index === -1) return + const existingEvent = this.options.events[index]! + const oldEndStr = toPlainDateTimeString(existingEvent.end) + const normalizedUpdates = { ...updates, ...(updates.start != null @@ -368,27 +397,411 @@ export class CalendarCore< : {}), } - const existingEvent = this.options.events[index] this.options.events[index] = { ...existingEvent, ...normalizedUpdates, } as TEvent + + // Shared visited set prevents double-shifting when both end and start change. + const visited = new Set([id]) + + const newEnd = normalizedUpdates.end as string | undefined + if (newEnd && newEnd !== oldEndStr) { + const endDeltaMs = Temporal.PlainDateTime.from(oldEndStr) + .until(Temporal.PlainDateTime.from(newEnd)) + .total('milliseconds') + + if (endDeltaMs !== 0) { + this.propagateEndDelta(id, endDeltaMs, visited) + } + } + this.store.setState((prev) => ({ ...prev, eventsVersion: prev.eventsVersion + 1, })) - if (existingEvent) { + getTimeClient().emit('event:updated', { + eventId: id, + eventTitle: existingEvent.title, + start: this.options.events[index]!.start, + end: this.options.events[index]!.end, + updates: normalizedUpdates as Record, + }) + } + + private propagateEndDelta( + sourceId: string, + _deltaMs: number, + visited: Set, + ): void { + if (!this.options.events) return + + const sourceEvent = this.options.events.find((e) => e.id === sourceId) + if (!sourceEvent) return + + const sourceEndStr = toPlainDateTimeString(sourceEvent.end) + const sourceEndMs = Temporal.PlainDateTime.from( + sourceEndStr, + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + + const dependents = this.options.events.filter( + (event) => !visited.has(event.id) && event.dependsOn?.includes(sourceId), + ) + + for (const dependent of dependents) { + visited.add(dependent.id) + + const eventIndex = this.options.events.findIndex( + (e) => e.id === dependent.id, + ) + if (eventIndex === -1) continue + + const currentEvent = this.options.events[eventIndex]! + const depStartStr = toPlainDateTimeString(currentEvent.start) + const depStartMs = Temporal.PlainDateTime.from( + depStartStr, + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + + const overflow = sourceEndMs - depStartMs + if (overflow <= 0) continue + + const depEndStr = toPlainDateTimeString(currentEvent.end) + const shiftedStart = Temporal.PlainDateTime.from(depStartStr) + .add({ milliseconds: overflow }) + .toString({ smallestUnit: 'second' }) + + const shiftedEnd = Temporal.PlainDateTime.from(depEndStr) + .add({ milliseconds: overflow }) + .toString({ smallestUnit: 'second' }) + + this.options.events[eventIndex] = { + ...currentEvent, + start: shiftedStart, + end: shiftedEnd, + } as TEvent + getTimeClient().emit('event:updated', { - eventId: id, - eventTitle: existingEvent.title, - start: this.options.events[index].start, - end: this.options.events[index].end, - updates: normalizedUpdates as Record, + eventId: currentEvent.id, + eventTitle: currentEvent.title, + start: shiftedStart, + end: shiftedEnd, + updates: { start: shiftedStart, end: shiftedEnd } as Record< + string, + unknown + >, }) + + this.propagateEndDelta(dependent.id, overflow, visited) } } + /** Simulate how deltaMs cascades forward through the dependency graph without mutating state. + * Only shifts a successor when the source's new end would exceed the successor's start (gap-aware). */ + private getAffectedByDelta( + sourceId: string, + deltaMs: number, + visited: Set, + ): Array<{ event: TEvent; newStart: string; newEnd: string }> { + if (!this.options.events || deltaMs === 0) return [] + + const affected: Array<{ event: TEvent; newStart: string; newEnd: string }> = + [] + + const projectedEndMap = new Map() + + const sourceEvent = this.options.events.find((e) => e.id === sourceId) + if (!sourceEvent) return [] + + const sourceEndStr = toPlainDateTimeString(sourceEvent.end) + const sourceEndMs = + Temporal.PlainDateTime.from(sourceEndStr).toZonedDateTime( + this.options.timeZone, + ).epochMilliseconds + deltaMs + projectedEndMap.set(sourceId, sourceEndMs) + + const queue: Array = [sourceId] + + while (queue.length > 0) { + const currentId = queue.shift()! + const currentEndMs = projectedEndMap.get(currentId)! + + const successors = this.options.events.filter( + (e) => !visited.has(e.id) && e.dependsOn?.includes(currentId), + ) + + for (const s of successors) { + const sStartStr = toPlainDateTimeString(s.start) + const sEndStr = toPlainDateTimeString(s.end) + const depStartMs = Temporal.PlainDateTime.from( + sStartStr, + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + const depEndMs = Temporal.PlainDateTime.from(sEndStr).toZonedDateTime( + this.options.timeZone, + ).epochMilliseconds + + const overflow = currentEndMs - depStartMs + if (overflow <= 0) continue + + visited.add(s.id) + const newStart = Temporal.PlainDateTime.from(sStartStr) + .add({ milliseconds: overflow }) + .toString({ smallestUnit: 'second' }) + const newEnd = Temporal.PlainDateTime.from(sEndStr) + .add({ milliseconds: overflow }) + .toString({ smallestUnit: 'second' }) + affected.push({ event: s, newStart, newEnd }) + + projectedEndMap.set(s.id, depEndMs + overflow) + queue.push(s.id) + } + } + + return affected + } + + /** Check whether the [newStart, newEnd] range for event is within its resources' availability. */ + private checkEventAvailability( + event: TEvent, + newStart: string, + newEnd: string, + ): AvailabilityConflict | null { + const resources = event.resources + if (!resources?.length) return null + + const resourceIds = resources.map((r) => r.id) + const startDt = Temporal.PlainDateTime.from(newStart) + const endDt = Temporal.PlainDateTime.from(newEnd) + + const startDate = startDt.toPlainDate() + const endDate = endDt.toPlainDate() + let cursorDate = startDate + + while (Temporal.PlainDate.compare(cursorDate, endDate) <= 0) { + const dayStr = cursorDate.toString({ calendarName: 'never' }) + const isSameAsStart = + Temporal.PlainDate.compare(cursorDate, startDate) === 0 + const isSameAsEnd = Temporal.PlainDate.compare(cursorDate, endDate) === 0 + + const overlapStartMins = isSameAsStart + ? startDt.hour * 60 + startDt.minute + : 0 + let overlapEndMins: number + if (isSameAsEnd) { + const endMins = endDt.hour * 60 + endDt.minute + overlapEndMins = + endMins === 0 && !isSameAsStart ? 0 : endMins || MINUTES_IN_DAY + } else { + overlapEndMins = MINUTES_IN_DAY + } + + if (overlapStartMins < overlapEndMins) { + const details = this.getUnavailabilityDetails( + dayStr, + overlapStartMins, + overlapEndMins, + { resourceIds }, + ) + + if (details.length > 0) { + return { + date: dayStr, + conflictRange: { + start: formatMinutesToTime(overlapStartMins), + end: formatMinutesToTime(overlapEndMins), + }, + resourceIds, + resourceDetails: details.map((d) => ({ + resourceId: d.resourceId, + resourceLabel: d.resourceLabel, + reason: d.reason, + description: `"${event.title}": ${d.description}`, + })), + description: `"${event.title}" would be pushed to unavailable time: ${details.map((d) => d.description).join('; ')}`, + } + } + } + + cursorDate = cursorDate.add({ days: 1 }) + } + + return null + } + + getEvents(): Array { + return this.options.events ? [...this.options.events] : [] + } + + /** + * Validates whether moving `eventId` to `[newStart, newEnd]` and cascading + * all finish-to-start dependents would violate any resource availability. + * + * Returns `{ blocked: false }` when the move is safe, or + * `{ blocked: true, message, blockedEventTitle }` when it would land in + * an unavailable zone (either for the event itself or for a downstream dependent). + */ + validateMove( + eventId: string, + newStart: string, + newEnd: string, + ): { blocked: boolean; blockedEventTitle?: string; message?: string } { + const event = this.options.events?.find( + (e) => e.id === eventId && !e._originalStart, + ) + if (!event) return { blocked: false } + + const conflict = this.checkEventAvailability(event, newStart, newEnd) + if (conflict) { + return { + blocked: true, + blockedEventTitle: event.title, + message: `"${event.title}" cannot be placed here — it falls inside an unavailable zone.`, + } + } + + const oldEndMs = Temporal.PlainDateTime.from( + toPlainDateTimeString(event.end), + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + const newEndMs = Temporal.PlainDateTime.from(newEnd).toZonedDateTime( + this.options.timeZone, + ).epochMilliseconds + const deltaMs = newEndMs - oldEndMs + + if (deltaMs > 0) { + const affected = this.getAffectedByDelta( + eventId, + deltaMs, + new Set([eventId]), + ) + for (const { + event: dep, + newStart: depStart, + newEnd: depEnd, + } of affected) { + const depConflict = this.checkEventAvailability(dep, depStart, depEnd) + if (depConflict) { + return { + blocked: true, + blockedEventTitle: dep.title, + message: `"${dep.title}" would be pushed to unavailable time.`, + } + } + } + } + + return { blocked: false } + } + + validateEventDependencies( + event: { id?: string; title: string; start: string; end: string }, + dependsOn: Array, + ): { valid: boolean; error?: ResizeError } { + if (!this.options.events) return { valid: true } + + const newStartMs = Temporal.PlainDateTime.from(event.start).toZonedDateTime( + this.options.timeZone, + ).epochMilliseconds + + for (const predId of dependsOn) { + const pred = this.options.events.find((e) => e.id === predId) + if (!pred) continue + + const predEndMs = Temporal.PlainDateTime.from( + toPlainDateTimeString(pred.end), + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + + if (newStartMs < predEndMs) { + return { + valid: false, + error: { + eventId: event.id ?? '', + eventTitle: event.title, + reason: 'blocked', + message: `"${event.title}" cannot start before "${pred.title}" ends`, + originalStart: event.start, + originalEnd: event.end, + }, + } + } + } + return { valid: true } + } + + createDependency( + sourceId: string, + targetId: string, + ): { blocked: boolean; error?: ResizeError } { + if (!this.options.events) return { blocked: false } + + const sourceEvent = this.options.events.find((e) => e.id === sourceId) + const targetEvent = this.options.events.find((e) => e.id === targetId) + if (!sourceEvent || !targetEvent) return { blocked: false } + + const currentDependsOn = targetEvent.dependsOn ?? [] + if (currentDependsOn.includes(sourceId)) return { blocked: false } + + const sourceEndStr = toPlainDateTimeString(sourceEvent.end) + const targetStartStr = toPlainDateTimeString(targetEvent.start) + const targetEndStr = toPlainDateTimeString(targetEvent.end) + + const sourceEndMs = Temporal.PlainDateTime.from( + sourceEndStr, + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + const targetStartMs = Temporal.PlainDateTime.from( + targetStartStr, + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + const targetEndMs = Temporal.PlainDateTime.from( + targetEndStr, + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + + const durationMs = targetEndMs - targetStartMs + const needsReschedule = targetStartMs < sourceEndMs + + let newTargetStart = targetStartStr + let newTargetEnd = targetEndStr + + if (needsReschedule) { + newTargetStart = sourceEndStr + newTargetEnd = Temporal.PlainDateTime.from(sourceEndStr) + .add({ milliseconds: durationMs }) + .toString({ smallestUnit: 'second' }) + + const validation = this.validateMove( + targetId, + newTargetStart, + newTargetEnd, + ) + + if (validation.blocked) { + return { + blocked: true, + error: { + eventId: targetId, + eventTitle: validation.blockedEventTitle ?? targetEvent.title, + reason: 'unavailable-time', + message: + validation.message ?? + `Cannot connect: the resulting schedule would fall inside an unavailable zone.`, + originalStart: targetStartStr, + originalEnd: targetEndStr, + attemptedStart: newTargetStart, + attemptedEnd: newTargetEnd, + }, + } + } + } + + this.updateEvent(targetId, { + dependsOn: [...currentDependsOn, sourceId], + ...(needsReschedule && { + start: newTargetStart, + end: newTargetEnd, + }), + } as Partial>) + + return { blocked: false } + } + removeEvent(id: Event['id']): void { if (!this.options.events) return @@ -1242,7 +1655,7 @@ export class CalendarCore< checkFromMs = originalEndMs checkToMs = newEndMs } - } else if (effectiveEdge === 'top') { + } else { const newStartMs = originalStartMs + snappedDeltaMs if (newStartMs < originalStartMs) { checkFromMs = newStartMs @@ -1308,6 +1721,70 @@ export class CalendarCore< } } + const snapMs = (constraints?.snapToMinutes ?? 1) * 60_000 + const snappedDeltaMs = + Math.round((totalDeltaMinutes * 60_000) / snapMs) * snapMs + + if (!shouldBlockResize && effectiveEdge === 'top' && this.options.events) { + const event = this.options.events.find((ev) => ev.id === eventId) + if (event?.dependsOn?.length) { + const proposedStartMs = + Temporal.PlainDateTime.from(originalStart).toZonedDateTime( + this.options.timeZone, + ).epochMilliseconds + snappedDeltaMs + + for (const predId of event.dependsOn) { + const pred = this.options.events.find((ev) => ev.id === predId) + if (!pred) continue + + const predEndMs = Temporal.PlainDateTime.from( + toPlainDateTimeString(pred.end), + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + + if (proposedStartMs < predEndMs) { + shouldBlockResize = true + blockReason = 'blocked' + blockMessage = `"${event.title}" cannot start before "${pred.title}" ends` + break + } + } + } + } + + if ( + !shouldBlockResize && + effectiveEdge === 'bottom' && + snappedDeltaMs > 0 + ) { + const affected = this.getAffectedByDelta( + eventId, + snappedDeltaMs, + new Set([eventId]), + ) + + for (const { event: affectedEvent, newStart, newEnd } of affected) { + const alreadyConflicting = this.checkEventAvailability( + affectedEvent, + toPlainDateTimeString(affectedEvent.start), + toPlainDateTimeString(affectedEvent.end), + ) + if (alreadyConflicting) continue + + const conflict = this.checkEventAvailability( + affectedEvent, + newStart, + newEnd, + ) + if (conflict) { + shouldBlockResize = true + blockReason = 'unavailable-time' + blockMessage = `Blocked: "${affectedEvent.title}" would be pushed to unavailable time` + conflicts.push(conflict) + break + } + } + } + const effectiveDeltaMinutes = shouldBlockResize ? 0 : totalDeltaMinutes const result = calculateResizedEvent({ diff --git a/packages/time/src/calendar/tests/calendar.test.ts b/packages/time/src/calendar/tests/calendar.test.ts index 36e62bac..28bf702f 100644 --- a/packages/time/src/calendar/tests/calendar.test.ts +++ b/packages/time/src/calendar/tests/calendar.test.ts @@ -1603,6 +1603,653 @@ describe('CalendarCore', () => { }) }) + describe('getEvents', () => { + test('returns a shallow copy of all events', () => { + const events: Array = [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + }, + ] + const cal = createCalendar({ events }) + const out = cal.getEvents() + + expect(out).toEqual(events) + expect(out).not.toBe(cal.options.events) + }) + + test('returns empty array when no events configured', () => { + const cal = createCalendar({ events: null }) + expect(cal.getEvents()).toEqual([]) + }) + }) + + describe('updateEvent — dependsOn cascade (propagateEndDelta)', () => { + test('shifts dependent forward when predecessor end extends past dependent start', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:30:00`, + end: `${DATE_MON}T12:30:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + cal.updateEvent('1', { end: `${DATE_MON}T12:00:00` }) + + const b = cal.options.events!.find((e) => e.id === '2')! + expect(b.start).toBe(`${DATE_MON}T12:00:00`) + expect(b.end).toBe(`${DATE_MON}T13:00:00`) + }) + + test('does not shift dependent when predecessor end still ends before dependent start', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T14:00:00`, + end: `${DATE_MON}T15:00:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + cal.updateEvent('1', { end: `${DATE_MON}T11:30:00` }) + + const b = cal.options.events!.find((e) => e.id === '2')! + expect(b.start).toBe(`${DATE_MON}T14:00:00`) + expect(b.end).toBe(`${DATE_MON}T15:00:00`) + }) + + test('propagates through a chain A → B → C', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T09:00:00`, + end: `${DATE_MON}T10:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + { + id: '3', + title: 'C', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T12:00:00`, + resources: [weekdayResource], + dependsOn: ['2'], + }, + ], + resources: [weekdayResource], + }) + + cal.updateEvent('1', { end: `${DATE_MON}T11:00:00` }) + + const b = cal.options.events!.find((e) => e.id === '2')! + const c = cal.options.events!.find((e) => e.id === '3')! + expect(b.start).toBe(`${DATE_MON}T11:00:00`) + expect(b.end).toBe(`${DATE_MON}T12:00:00`) + expect(c.start).toBe(`${DATE_MON}T12:00:00`) + expect(c.end).toBe(`${DATE_MON}T13:00:00`) + }) + + test('shifts multiple dependents of the same predecessor', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:15:00`, + end: `${DATE_MON}T12:00:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + { + id: '3', + title: 'C', + start: `${DATE_MON}T11:20:00`, + end: `${DATE_MON}T12:30:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + cal.updateEvent('1', { end: `${DATE_MON}T12:00:00` }) + + const b = cal.options.events!.find((e) => e.id === '2')! + const c = cal.options.events!.find((e) => e.id === '3')! + expect(b.start).toBe(`${DATE_MON}T12:00:00`) + expect(c.start).toBe(`${DATE_MON}T12:00:00`) + }) + + test('does not cascade when only start changes (end unchanged)', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:30:00`, + end: `${DATE_MON}T12:30:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + cal.updateEvent('1', { start: `${DATE_MON}T09:30:00` }) + + const b = cal.options.events!.find((e) => e.id === '2')! + expect(b.start).toBe(`${DATE_MON}T11:30:00`) + }) + }) + + describe('validateMove', () => { + test('returns blocked:false for unknown event id', () => { + const cal = createCalendar({ + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + expect( + cal.validateMove( + 'missing', + `${DATE_MON}T12:00:00`, + `${DATE_MON}T13:00:00`, + ), + ).toEqual({ blocked: false }) + }) + + test('allows move fully inside availability', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + expect( + cal.validateMove('1', `${DATE_MON}T13:00:00`, `${DATE_MON}T14:00:00`), + ).toEqual({ blocked: false }) + }) + + test('blocks when the moved range overlaps unavailable hours', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + ], + resources: [weekdayResource], + }) + + const r = cal.validateMove( + '1', + `${DATE_MON}T18:00:00`, + `${DATE_MON}T19:00:00`, + ) + expect(r.blocked).toBe(true) + expect(r.blockedEventTitle).toBe('A') + expect(r.message).toContain('unavailable zone') + }) + + test('allows move when event has no resources (no availability to violate)', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + }, + ], + }) + + expect( + cal.validateMove('1', `${DATE_MON}T22:00:00`, `${DATE_MON}T23:00:00`), + ).toEqual({ blocked: false }) + }) + + test('blocks when extending end pushes a dependent into unavailable time', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T16:30:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + const r = cal.validateMove( + '1', + `${DATE_MON}T10:00:00`, + `${DATE_MON}T13:00:00`, + ) + expect(r.blocked).toBe(true) + expect(r.blockedEventTitle).toBe('B') + expect(r.message).toContain('pushed to unavailable') + }) + + test('blocks transitive dependent when cascade would violate availability', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T12:00:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + { + id: '3', + title: 'C', + start: `${DATE_MON}T12:00:00`, + end: `${DATE_MON}T16:00:00`, + resources: [weekdayResource], + dependsOn: ['2'], + }, + ], + resources: [weekdayResource], + }) + + const r = cal.validateMove( + '2', + `${DATE_MON}T15:00:00`, + `${DATE_MON}T16:00:00`, + ) + expect(r.blocked).toBe(true) + expect(r.blockedEventTitle).toBe('C') + }) + + test('does not run downstream availability check when new end is not extended', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T16:30:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + expect( + cal.validateMove('1', `${DATE_MON}T10:00:00`, `${DATE_MON}T10:30:00`), + ).toEqual({ blocked: false }) + }) + + test('treats split multi-day segment rows as non-targets (no _originalStart match)', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T14:00:00`, + end: `${DATE_MON}T18:00:00`, + resources: [weekdayResource], + _originalStart: `${DATE_MON}T14:00:00`, + _originalEnd: `${DATE_TUE}T10:00:00`, + }, + ], + resources: [weekdayResource], + }) + + expect( + cal.validateMove('1', `${DATE_MON}T18:00:00`, `${DATE_MON}T19:00:00`), + ).toEqual({ blocked: false }) + }) + }) + + describe('validateResize — dependsOn (finish-to-start)', () => { + const baseResizeOptions = { + constraints: { snapToMinutes: 15, minDurationMinutes: 15 }, + } + + test('blocks moving dependent start before predecessor end (edge left → top)', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T12:00:00`, + end: `${DATE_MON}T13:00:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '2', + originalStart: `${DATE_MON}T12:00:00`, + originalEnd: `${DATE_MON}T13:00:00`, + edge: 'left', + totalDeltaMinutes: -90, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('blocked') + expect(result.error?.message).toContain('cannot start before') + }) + + test('blocks extending predecessor when dependent would enter unavailable time', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T16:30:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'right', + totalDeltaMinutes: 120, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('unavailable-time') + expect(result.error?.message).toContain('B') + }) + + test('allows extending predecessor when dependent stays inside availability', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T12:00:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'right', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + }) + + test('blocks when transitive dependent would leave availability', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T12:00:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + { + id: '3', + title: 'C', + start: `${DATE_MON}T12:00:00`, + end: `${DATE_MON}T16:00:00`, + resources: [weekdayResource], + dependsOn: ['2'], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'right', + totalDeltaMinutes: 240, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('unavailable-time') + }) + + test('skips cascade availability check when dependent is already outside hours', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T17:00:00`, + end: `${DATE_MON}T18:00:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'right', + totalDeltaMinutes: 60, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(false) + }) + + test('same cascade rule applies with edge bottom (vertical resize)', () => { + const cal = createCalendar({ + timeZone: 'UTC', + events: [ + { + id: '1', + title: 'A', + start: `${DATE_MON}T10:00:00`, + end: `${DATE_MON}T11:00:00`, + resources: [weekdayResource], + }, + { + id: '2', + title: 'B', + start: `${DATE_MON}T11:00:00`, + end: `${DATE_MON}T16:30:00`, + resources: [weekdayResource], + dependsOn: ['1'], + }, + ], + resources: [weekdayResource], + }) + + const result = cal.validateResize({ + eventId: '1', + originalStart: `${DATE_MON}T10:00:00`, + originalEnd: `${DATE_MON}T11:00:00`, + edge: 'bottom', + totalDeltaMinutes: 120, + targetDayDate: DATE_MON, + originalDayDate: DATE_MON, + ...baseResizeOptions, + }) + + expect(result.blocked).toBe(true) + expect(result.error?.reason).toBe('unavailable-time') + }) + }) + describe('groupDaysBy', () => { test('groups days into weeks', () => { const cal = createCalendar({ viewMode: { value: 1, unit: 'month' } }) diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index 1f6ed0b9..9d05a6db 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -40,6 +40,9 @@ export interface Event { end: EventDateTimeInput title: string resources?: Array + /** IDs of events this event immediately follows (finish-to-start dependency). + * When a predecessor's end time shifts, this event shifts by the same delta. */ + dependsOn?: Array /** Original start time before splitting (only set on split segments of multi-day events) */ _originalStart?: string /** Original end time before splitting (only set on split segments of multi-day events) */ diff --git a/packages/time/src/utils/dateTimeDefaults.ts b/packages/time/src/utils/dateTimeDefaults.ts index 6f562da9..9246e18f 100644 --- a/packages/time/src/utils/dateTimeDefaults.ts +++ b/packages/time/src/utils/dateTimeDefaults.ts @@ -1,15 +1,5 @@ -import type { Locale } from '../formatter/shared' - const defaults = new Intl.DateTimeFormat().resolvedOptions() export function getDateTimeDefaults() { return defaults } - -export function normalizeLocale(locale: Locale): string | Array { - return Array.isArray(locale) - ? locale.map((loc) => (typeof loc === 'string' ? loc : loc.toString())) - : typeof locale === 'string' - ? locale - : locale.toString() -} From a360030f1b781f961f6764d816c0ca7e78b90afa Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Thu, 26 Mar 2026 00:02:09 +0100 Subject: [PATCH 062/207] feat: timeline --- examples/react/timeline/package.json | 1 + examples/react/timeline/src/index.tsx | 793 +++++++++++++++---------- packages/time/src/calendar/calendar.ts | 24 +- pnpm-lock.yaml | 251 +++++++- 4 files changed, 742 insertions(+), 327 deletions(-) diff --git a/examples/react/timeline/package.json b/examples/react/timeline/package.json index bd6fc0ea..6f9effc4 100644 --- a/examples/react/timeline/package.json +++ b/examples/react/timeline/package.json @@ -9,6 +9,7 @@ "test:types": "tsc" }, "dependencies": { + "@dnd-kit/react": "^0.3.2", "@tanstack/react-devtools": "^0.9.5", "@tanstack/react-time": "^0.0.0", "@tanstack/react-time-devtools": "^0.0.0", diff --git a/examples/react/timeline/src/index.tsx b/examples/react/timeline/src/index.tsx index 53401e82..da499a29 100644 --- a/examples/react/timeline/src/index.tsx +++ b/examples/react/timeline/src/index.tsx @@ -9,6 +9,12 @@ import { toPlainDateTimeString, toPlainTimeString, } from '@tanstack/time' +import { + DragDropProvider, + DragOverlay, + useDraggable, + useDroppable, +} from '@dnd-kit/react' import { Handle, MarkerType, @@ -597,6 +603,7 @@ interface TimelineDependencyOverlayProps { previewStart: string | null previewEnd: string | null } + activeDragEvent: any onDependencyCreate: (sourceId: string, targetId: string) => void } @@ -605,6 +612,7 @@ function TimelineDependencyOverlay({ eventBarRefs, rowsContainerRef, resizeState, + activeDragEvent, onDependencyCreate, }: TimelineDependencyOverlayProps) { const [rfNodes, setRfNodes, onNodesChangeBase] = useNodesState([]) @@ -665,7 +673,7 @@ function TimelineDependencyOverlay({ useLayoutEffect(() => { updatePositions() - }, [updatePositions, resizeState]) + }, [updatePositions, resizeState, activeDragEvent]) useEffect(() => { const container = rowsContainerRef.current @@ -724,6 +732,108 @@ function timeStringToFraction(time: string): number { return Math.min(totalHours, 24) / 24 } +const DraggableTimelineEvent = React.memo(function DraggableTimelineEvent({ + event, + left, + width, + lane, + laneCount, + isStartClipped, + isEndClipped, + color, + registerEventBar, + onEventClick, + getResizeHandleProps, +}: { + event: Event + left: number + width: number + lane: number + laneCount: number + isStartClipped: boolean + isEndClipped: boolean + color: any + registerEventBar: (eventId: string) => (el: HTMLDivElement | null) => void + onEventClick: (event: Event) => void + getResizeHandleProps: ReturnType['getResizeHandleProps'] +}) { + const laneHeightPct = 100 / laneCount + const topPct = lane * laneHeightPct + + const { + ref: setDraggableRef, + handleRef: setDragHandleRef, + isDragging, + } = useDraggable({ + id: `event-${event.id}`, + data: { event, left, width, laneHeightPct, topPct, lane, color }, + }) + + return ( +
{ + registerEventBar(event.id)(el) + setDraggableRef(el) + }} + data-event-id={event.id} + data-left={left} + data-width={width} + className={`group absolute border ${color.bg} ${color.border} ${color.text} flex items-center text-xs font-medium overflow-hidden shadow-sm z-10 cursor-pointer hover:brightness-110 transition-[filter] ${ + isDragging ? 'opacity-40 shadow-xl z-50' : '' + } ${ + !isStartClipped && !isEndClipped + ? 'rounded-md' + : !isStartClipped + ? 'rounded-l-md' + : !isEndClipped + ? 'rounded-r-md' + : '' + }`} + style={{ + left: `${left}%`, + width: `${width}%`, + top: `calc(${topPct}% + ${EVENT_GAP_PX}px)`, + height: `calc(${laneHeightPct}% - ${EVENT_GAP_PX * 2}px)`, + }} + title={`${event.title} (${toPlainDateString(event.start)}T${toPlainTimeString(event.start)} \u2192 ${toPlainDateString(event.end)}T${toPlainTimeString(event.end)})`} + onClick={(e) => { + if (!(e.target as HTMLElement).closest('[data-resize-handle]')) { + onEventClick(event) + } + }} + > + {!isStartClipped && ( + + )} +
+ {event.title} +
+ {!isEndClipped && ( + + )} +
+ ) +}) + const HorizontalTimelineRow = React.memo(function HorizontalTimelineRow({ row, days, @@ -751,6 +861,11 @@ const HorizontalTimelineRow = React.memo(function HorizontalTimelineRow({ >['getUnavailableRanges'] eventBarRefs: React.MutableRefObject> }) { + const { ref: setDroppableRef } = useDroppable({ + id: `resource-${row.resource.id}`, + data: { resource: row.resource }, + }) + const dayPercentage = 100 / days.length const zoneColor = RESOURCE_ZONE_COLORS[resourceColorIndex % RESOURCE_ZONE_COLORS.length] ?? @@ -769,6 +884,7 @@ const HorizontalTimelineRow = React.memo(function HorizontalTimelineRow({ return (
@@ -820,64 +936,22 @@ const HorizontalTimelineRow = React.memo(function HorizontalTimelineRow({ const colorIdx = colorMap.get(event.id) ?? 0 const color = EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] - const laneHeightPct = 100 / row.laneCount - const topPct = lane * laneHeightPct return ( -
{ - if ( - !(e.target as HTMLElement).closest('[data-resize-handle]') - ) { - onEventClick(event) - } - }} - > - {!isStartClipped && ( - - )} - {event.title} - {!isEndClipped && ( - - )} -
+ event={event} + left={left} + width={width} + lane={lane} + laneCount={row.laneCount} + isStartClipped={isStartClipped} + isEndClipped={isEndClipped} + color={color} + registerEventBar={registerEventBar} + onEventClick={onEventClick} + getResizeHandleProps={getResizeHandleProps} + /> ) }, )} @@ -1068,6 +1142,73 @@ function TimelineDemo() { if (modalState.eventId) calendar.removeEvent(modalState.eventId) } + const [activeDragEvent, setActiveDragEvent] = useState(null) + + const handleDragStart = (e: any) => { + setActiveDragEvent(e.operation?.source?.data) + } + + const handleDragEnd = (e: any) => { + setActiveDragEvent(null) + const sourceData = e.operation?.source?.data + const targetData = e.operation?.target?.data + + if (!sourceData || !sourceData.event) return + + const draggedEvent = sourceData.event + const newResource = targetData?.resource || draggedEvent.resources?.[0] + + const deltaX = + e.operation?.transform?.x ?? + e.operation?.position?.delta?.x ?? + e.delta?.x ?? + 0 + + if (deltaX !== 0 || targetData?.resource) { + const containerW = containerWidthRef.current || 1 + const totalDays = calendar.days.length + const totalHours = totalDays * 24 + const hoursShift = (deltaX / containerW) * totalHours + + const snapShift = Math.round(hoursShift / 0.25) * 0.25 + const msShift = snapShift * 3600 * 1000 + + const newStart = new Date( + new Date(draggedEvent.start).getTime() + msShift, + ) + const newEnd = new Date(new Date(draggedEvent.end).getTime() + msShift) + + const nextStart = `${toPlainDateString(newStart)}T${toPlainTimeString(newStart)}:00` + const nextEnd = `${toPlainDateString(newEnd)}T${toPlainTimeString(newEnd)}:00` + + const validation = calendar.validateMove( + draggedEvent.id, + nextStart, + nextEnd, + newResource ? [newResource] : [], + ) + + if (validation.blocked) { + setResizeError({ + eventId: draggedEvent.id, + eventTitle: draggedEvent.title, + reason: 'unavailable-time', + message: + validation.message ?? 'This move is blocked by availability.', + originalStart: draggedEvent.start, + originalEnd: draggedEvent.end, + }) + return + } + + calendar.updateEvent(draggedEvent.id, { + start: nextStart, + end: nextEnd, + resources: newResource ? [newResource] : [], + }) + } + } + const viewModeOptions = [ { label: 'Day', value: 1, unit: 'day' as const }, { label: 'Week', value: 1, unit: 'week' as const }, @@ -1075,293 +1216,315 @@ function TimelineDemo() { ] return ( -
-
-

- TanStack Time — Timeline -

+ +
+
+

+ TanStack Time — Timeline +

+ +
+ + + + + +
+ {viewModeOptions.map((opt) => { + const isActive = + calendar.viewMode.value === opt.value && + calendar.viewMode.unit === opt.unit + return ( + + ) + })} +
+
-
- - - - +
+ {calendar.formatPeriodLabel()} +
+
-
- {viewModeOptions.map((opt) => { - const isActive = - calendar.viewMode.value === opt.value && - calendar.viewMode.unit === opt.unit +
+
+
+
+
+ + Resources + +
+ {sampleResources.map((resource, idx) => { + const zoneColor = + RESOURCE_ZONE_COLORS[idx % RESOURCE_ZONE_COLORS.length] ?? + RESOURCE_ZONE_COLORS[0] + return ( +
+
+ + {resource.label} + +
+ ) + })} +
+ +
+
+
+
+ {calendar.days.map((day) => { + const localDate = new Date( + day.date.year, + day.date.month - 1, + day.date.day, + ) + const dayName = localDate.toLocaleDateString(undefined, { + weekday: 'short', + }) + const dayNum = day.date.day + const monthName = localDate.toLocaleDateString( + undefined, + { + month: 'short', + }, + ) + + return ( +
+ + {dayName} + + + {dayNum} + + + {monthName} + +
+ ) + })} +
+
+ {calendar.days.map((day, i) => { + const dayPercentage = 100 / calendar.days.length + return ( +
+ {Array.from({ length: 24 }, (_, h) => ( +
+ + {h.toString().padStart(2, '0')} + +
+ ))} +
+ ) + })} +
+
+ +
+ {timelineLayout.currentTimePosition !== null && ( +
+
+
+ )} + {timelineLayout.rows.map((row, rowIdx) => ( + + ))} +
+ +
+
+
+
+
+
+ +
+
+ {sampleEvents.map((event) => { + const colorIdx = colorMap.get(event.id) ?? 0 + const color = + EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] return ( - +
+
+ + {event.title} + +
) })}
-
-
- {calendar.formatPeriodLabel()} -
-
- -
-
-
-
-
- - Resources - -
+
{sampleResources.map((resource, idx) => { const zoneColor = RESOURCE_ZONE_COLORS[idx % RESOURCE_ZONE_COLORS.length] ?? RESOURCE_ZONE_COLORS[0] return ( -
+
- - {resource.label} + + {resource.label} — unavailable
) })}
+
-
-
-
-
- {calendar.days.map((day) => { - const localDate = new Date( - day.date.year, - day.date.month - 1, - day.date.day, - ) - const dayName = localDate.toLocaleDateString(undefined, { - weekday: 'short', - }) - const dayNum = day.date.day - const monthName = localDate.toLocaleDateString(undefined, { - month: 'short', - }) - - return ( -
- - {dayName} - - - {dayNum} - - - {monthName} - -
- ) - })} -
-
- {calendar.days.map((day, i) => { - const dayPercentage = 100 / calendar.days.length - return ( -
- {Array.from({ length: 24 }, (_, h) => ( -
- - {h.toString().padStart(2, '0')} - -
- ))} -
- ) - })} -
-
- -
- {timelineLayout.currentTimePosition !== null && ( -
-
-
- )} - {timelineLayout.rows.map((row, rowIdx) => ( - - ))} -
- -
-
-
+ {calendar.isPending && ( +
+ Loading...
-
-
+ )} + + setModalState((prev) => ({ ...prev, isOpen: false }))} + onSave={handleSave} + onDelete={modalState.mode === 'edit' ? handleDelete : undefined} + initialData={modalState.initialData} + mode={modalState.mode} + /> -
-
- {sampleEvents.map((event) => { - const colorIdx = colorMap.get(event.id) ?? 0 - const color = - EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] - return ( -
-
- {event.title} -
- ) - })} -
+ {resizeError && ( + setResizeError(null)} + /> + )} -
- {sampleResources.map((resource, idx) => { - const zoneColor = - RESOURCE_ZONE_COLORS[idx % RESOURCE_ZONE_COLORS.length] ?? - RESOURCE_ZONE_COLORS[0] - return ( -
-
- - {resource.label} — unavailable - -
- ) - })} -
+ {activeDragEvent && ( + +
+ {activeDragEvent.event.title} +
+
+ )}
- - {calendar.isPending && ( -
- Loading... -
- )} - - setModalState((prev) => ({ ...prev, isOpen: false }))} - onSave={handleSave} - onDelete={modalState.mode === 'edit' ? handleDelete : undefined} - initialData={modalState.initialData} - mode={modalState.mode} - /> - - {resizeError && ( - setResizeError(null)} - /> - )} -
+ ) } diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index 99c8f1e3..08aa93af 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -130,6 +130,7 @@ interface CalendarActions< eventId: string, newStart: string, newEnd: string, + newResources?: Array, ) => { blocked: boolean; blockedEventTitle?: string; message?: string } /** * Validates if placing an event with a specific start time satisfies all dependency constraints. @@ -373,8 +374,8 @@ export class CalendarCore< getTimeClient().emit('event:added', { eventId: normalized.id, eventTitle: normalized.title, - start: normalized.start, - end: normalized.end, + start: normalized.start as string, + end: normalized.end as string, }) } @@ -424,8 +425,8 @@ export class CalendarCore< getTimeClient().emit('event:updated', { eventId: id, eventTitle: existingEvent.title, - start: this.options.events[index]!.start, - end: this.options.events[index]!.end, + start: this.options.events[index]!.start as string, + end: this.options.events[index]!.end as string, updates: normalizedUpdates as Record, }) } @@ -565,8 +566,9 @@ export class CalendarCore< event: TEvent, newStart: string, newEnd: string, + newResources?: Array, ): AvailabilityConflict | null { - const resources = event.resources + const resources = newResources || event.resources if (!resources?.length) return null const resourceIds = resources.map((r) => r.id) @@ -644,13 +646,19 @@ export class CalendarCore< eventId: string, newStart: string, newEnd: string, + newResources?: Array, ): { blocked: boolean; blockedEventTitle?: string; message?: string } { const event = this.options.events?.find( (e) => e.id === eventId && !e._originalStart, ) if (!event) return { blocked: false } - const conflict = this.checkEventAvailability(event, newStart, newEnd) + const conflict = this.checkEventAvailability( + event, + newStart, + newEnd, + newResources, + ) if (conflict) { return { blocked: true, @@ -819,8 +827,8 @@ export class CalendarCore< getTimeClient().emit('event:removed', { eventId: id, eventTitle: removedEvent.title, - start: removedEvent.start, - end: removedEvent.end, + start: removedEvent.start as string, + end: removedEvent.end as string, }) } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 52e5e316..fa467e9c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,7 +108,7 @@ importers: version: 19.2.3(@types/react@19.2.13) '@vitejs/plugin-react': specifier: ^5.1.2 - version: 5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2)) + version: 5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) autoprefixer: specifier: ^10.4.20 version: 10.4.24(postcss@8.5.6) @@ -123,10 +123,13 @@ importers: version: 5.9.3 vite: specifier: ^7.3.1 - version: 7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2) + version: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) examples/react/timeline: dependencies: + '@dnd-kit/react': + specifier: ^0.3.2 + version: 0.3.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-devtools': specifier: ^0.9.5 version: 0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) @@ -139,6 +142,9 @@ importers: '@tanstack/time': specifier: ^0.0.0 version: link:../../../packages/time + '@xyflow/react': + specifier: ^12.10.1 + version: 12.10.1(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: specifier: ^19.2.3 version: 19.2.4 @@ -154,7 +160,7 @@ importers: version: 19.2.3(@types/react@19.2.13) '@vitejs/plugin-react': specifier: ^5.1.2 - version: 5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) + version: 5.1.3(vite@7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2)) autoprefixer: specifier: ^10.4.20 version: 10.4.24(postcss@8.5.6) @@ -169,7 +175,7 @@ importers: version: 5.9.3 vite: specifier: ^7.3.1 - version: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) + version: 7.3.1(@types/node@25.2.2)(jiti@1.21.7)(yaml@2.8.2) packages/react-time: dependencies: @@ -528,6 +534,27 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@dnd-kit/abstract@0.3.2': + resolution: {integrity: sha512-uvPVK+SZYD6Viddn9M0K0JQdXknuVSxA/EbMlFRanve3P/XTc18oLa5zGftKSGjfQGmuzkZ34E26DSbly1zi3Q==} + + '@dnd-kit/collision@0.3.2': + resolution: {integrity: sha512-pNmNSLCI8S9fNQ7QJ3fBCDjiT0sqBhUFcKgmyYaGvGCAU+kq0AP8OWlh0JSisc9k5mFyxmRpmFQcnJpILz/RPA==} + + '@dnd-kit/dom@0.3.2': + resolution: {integrity: sha512-cIUAVgt2szQyz6JRy7I+0r+xeyOAGH21Y15hb5bIyHoDEaZBvIDH+OOlD9eoLjCbsxDLN9WloU2CBi3OE6LYDg==} + + '@dnd-kit/geometry@0.3.2': + resolution: {integrity: sha512-3UBPuIS7E3oGiHxOE8h810QA+0pnrnCtGxl4Os1z3yy5YkC/BEYGY+TxWPTQaY1/OMV7GCX7ZNMlama2QN3n3w==} + + '@dnd-kit/react@0.3.2': + resolution: {integrity: sha512-1Opg1xw6I75Z95c+rF2NJa0pdGb8rLAENtuopKtJ1J0PudWlz+P6yL137xy/6DV43uaRmNGtsdbMbR0yRYJ72g==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + + '@dnd-kit/state@0.3.2': + resolution: {integrity: sha512-dLUIkoYrIJhGXfF2wGLTfb46vUokEsO/OoE21TSfmahYrx7ysTmnwbePsznFaHlwgZhQEh6AlLvthLCeY21b1A==} + '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} @@ -1025,6 +1052,9 @@ packages: cpu: [x64] os: [win32] + '@preact/signals-core@1.14.0': + resolution: {integrity: sha512-AowtCcCU/33lFlh1zRFf/u+12rfrhtNakj7UpaGEsmMwUKpKWMVvcktOGcwBBNiB4lWrZWc01LhiyyzVklJyaQ==} + '@publint/pack@0.1.4': resolution: {integrity: sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ==} engines: {node: '>=18'} @@ -1511,6 +1541,24 @@ packages: '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -1735,6 +1783,15 @@ packages: '@vitest/utils@4.0.18': resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} + '@xyflow/react@12.10.1': + resolution: {integrity: sha512-5eSWtIK/+rkldOuFbOOz44CRgQRjtS9v5nufk77DV+XBnfCGL9HAQ8PG00o2ZYKqkEU/Ak6wrKC95Tu+2zuK3Q==} + peerDependencies: + react: '>=17' + react-dom: '>=17' + + '@xyflow/system@0.0.75': + resolution: {integrity: sha512-iXs+AGFLi8w/VlAoc/iSxk+CxfT6o64Uw/k0CKASOPqjqz6E0rb5jFZgJtXGZCpfQI6OQpu5EnumP5fGxQheaQ==} + '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} @@ -1938,6 +1995,9 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + classcat@5.0.5: + resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -2008,6 +2068,44 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} @@ -3795,6 +3893,21 @@ packages: zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zustand@4.5.7: + resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + snapshots: '@adobe/css-tools@4.4.4': {} @@ -4162,6 +4275,45 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 + '@dnd-kit/abstract@0.3.2': + dependencies: + '@dnd-kit/geometry': 0.3.2 + '@dnd-kit/state': 0.3.2 + tslib: 2.8.1 + + '@dnd-kit/collision@0.3.2': + dependencies: + '@dnd-kit/abstract': 0.3.2 + '@dnd-kit/geometry': 0.3.2 + tslib: 2.8.1 + + '@dnd-kit/dom@0.3.2': + dependencies: + '@dnd-kit/abstract': 0.3.2 + '@dnd-kit/collision': 0.3.2 + '@dnd-kit/geometry': 0.3.2 + '@dnd-kit/state': 0.3.2 + tslib: 2.8.1 + + '@dnd-kit/geometry@0.3.2': + dependencies: + '@dnd-kit/state': 0.3.2 + tslib: 2.8.1 + + '@dnd-kit/react@0.3.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@dnd-kit/abstract': 0.3.2 + '@dnd-kit/dom': 0.3.2 + '@dnd-kit/state': 0.3.2 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tslib: 2.8.1 + + '@dnd-kit/state@0.3.2': + dependencies: + '@preact/signals-core': 1.14.0 + tslib: 2.8.1 + '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -4582,6 +4734,8 @@ snapshots: '@oxc-resolver/binding-win32-x64-msvc@11.17.1': optional: true + '@preact/signals-core@1.14.0': {} + '@publint/pack@0.1.4': {} '@quansync/fs@1.0.0': @@ -4995,6 +5149,27 @@ snapshots: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 + '@types/d3-color@3.1.3': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + '@types/deep-eql@4.0.2': {} '@types/estree@1.0.8': {} @@ -5240,6 +5415,29 @@ snapshots: '@vitest/pretty-format': 4.0.18 tinyrainbow: 3.0.3 + '@xyflow/react@12.10.1(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@xyflow/system': 0.0.75 + classcat: 5.0.5 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + zustand: 4.5.7(@types/react@19.2.13)(react@19.2.4) + transitivePeerDependencies: + - '@types/react' + - immer + + '@xyflow/system@0.0.75': + dependencies: + '@types/d3-drag': 3.0.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + '@yarnpkg/lockfile@1.1.0': {} '@yarnpkg/parsers@3.0.2': @@ -5452,6 +5650,8 @@ snapshots: ci-info@3.9.0: {} + classcat@5.0.5: {} + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -5510,6 +5710,42 @@ snapshots: csstype@3.2.3: {} + d3-color@3.1.0: {} + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-ease@3.0.1: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-selection@3.0.0: {} + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + dataloader@1.4.0: {} debug@4.4.3: @@ -7388,3 +7624,10 @@ snapshots: zod@3.25.76: {} zod@4.3.6: {} + + zustand@4.5.7(@types/react@19.2.13)(react@19.2.4): + dependencies: + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + react: 19.2.4 From c755930f528108917bae09767b17f296763f1ec0 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Thu, 26 Mar 2026 13:46:14 +0100 Subject: [PATCH 063/207] feat: timeline --- examples/react/timeline/src/index.tsx | 85 ++++++++++++------- .../react-time/src/useCalendar/useCalendar.ts | 6 +- .../time-devtools/src/components/Shell.tsx | 6 +- packages/time/src/client/TimeClient.ts | 2 +- 4 files changed, 62 insertions(+), 37 deletions(-) diff --git a/examples/react/timeline/src/index.tsx b/examples/react/timeline/src/index.tsx index da499a29..c2c68eb6 100644 --- a/examples/react/timeline/src/index.tsx +++ b/examples/react/timeline/src/index.tsx @@ -5,6 +5,7 @@ import { import { TanStackDevtools } from '@tanstack/react-devtools' import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' import { + getTimeClient, toPlainDateString, toPlainDateTimeString, toPlainTimeString, @@ -38,6 +39,7 @@ import type { Event, ResizeError, Resource, + TimelineLayout, TimelineResourceRow, } from '@tanstack/time' import type { Connection, Edge, Node, NodeProps } from '@xyflow/react' @@ -190,7 +192,6 @@ function getSampleEvents(): Array> { start: weekdayAt(3, 10, 0), end: weekdayAt(3, 15, 0), resources: [resourceQA], - dependsOn: ['3'], }, { id: '6', @@ -205,15 +206,13 @@ function getSampleEvents(): Array> { start: weekdayAt(3, 10, 0), end: weekdayAt(3, 12, 30), resources: [resourceDesign], - dependsOn: ['1'], }, { id: '8', title: 'Auth Module', - start: weekdayAt(4, 0, 0), + start: weekdayAt(5, 6, 0), end: weekdayAt(5, 10, 0), resources: [resourceBackend], - dependsOn: ['3'], }, { id: '9', @@ -221,7 +220,6 @@ function getSampleEvents(): Array> { start: weekdayAt(4, 10, 30), end: weekdayAt(4, 14, 30), resources: [resourceQA], - dependsOn: ['8'], }, { id: '10', @@ -229,7 +227,6 @@ function getSampleEvents(): Array> { start: weekdayAt(5, 7, 30), end: weekdayAt(5, 13, 0), resources: [resourceDevOps], - dependsOn: ['6'], }, ] } @@ -578,8 +575,14 @@ const DEP_CANVAS_NODE_TYPES = { depCanvas: DepCanvasNode } const CANVAS_NODE_ID = '__dep_canvas__' function buildTimelineEdges(events: Array>): Array { - return events.flatMap((event) => - (event.dependsOn ?? []).map((sourceId) => ({ + const visibleEventIds = new Set(events.map((e) => e.id)) + + return events.flatMap((event) => { + const deps = (event.dependsOn ?? []).filter((sourceId) => + visibleEventIds.has(sourceId), + ) + + return deps.map((sourceId) => ({ id: `dep-${sourceId}-${event.id}`, source: CANVAS_NODE_ID, sourceHandle: `${sourceId}-source`, @@ -589,12 +592,12 @@ function buildTimelineEdges(events: Array>): Array { animated: true, markerEnd: { type: MarkerType.ArrowClosed, color: '#f59e0b' }, style: { stroke: '#f59e0b', strokeWidth: 2 }, - })), - ) + })) + }) } interface TimelineDependencyOverlayProps { - calendarEvents: Array> + timelineLayout: TimelineLayout> eventBarRefs: React.MutableRefObject> rowsContainerRef: React.RefObject resizeState: { @@ -608,12 +611,12 @@ interface TimelineDependencyOverlayProps { } function TimelineDependencyOverlay({ - calendarEvents, - eventBarRefs, + timelineLayout, rowsContainerRef, resizeState, activeDragEvent, onDependencyCreate, + eventBarRefs, }: TimelineDependencyOverlayProps) { const [rfNodes, setRfNodes, onNodesChangeBase] = useNodesState([]) const [rfEdges, setRfEdges, onEdgesChange] = useEdgesState([]) @@ -644,16 +647,24 @@ function TimelineDependencyOverlay({ const containerRect = container.getBoundingClientRect() const positions: Array = [] - for (const [eventId, el] of eventBarRefs.current) { - const rect = el.getBoundingClientRect() - positions.push({ - eventId, - x: rect.left - containerRect.left, - y: rect.top - containerRect.top, - width: rect.width, - height: rect.height, + // Use actual event-bar DOM rects so handles follow resize previews + // (resize updates styles on the event bar element, while timelineLayout + // may remain based on the committed start/end). + timelineLayout.rows.forEach((row: TimelineResourceRow) => { + row.events.forEach((e: any) => { + const el = eventBarRefs.current.get(e.event.id) + if (!el) return + + const rect = el.getBoundingClientRect() + positions.push({ + eventId: e.event.id, + x: rect.left - containerRect.left, + y: rect.top - containerRect.top, + width: rect.width, + height: rect.height, + }) }) - } + }) setRfNodes([ { @@ -668,8 +679,15 @@ function TimelineDependencyOverlay({ draggable: false, }, ]) - setRfEdges(buildTimelineEdges(calendarEvents)) - }, [calendarEvents, eventBarRefs, rowsContainerRef, setRfNodes, setRfEdges]) + const allEvents = Array.from( + new Map( + timelineLayout.rows + .flatMap((r: any) => r.events.map((e: any) => e.event)) + .map((e: any) => [e.id, e]), + ).values(), + ) + setRfEdges(buildTimelineEdges(allEvents)) + }, [timelineLayout, rowsContainerRef, eventBarRefs, setRfNodes, setRfEdges]) useLayoutEffect(() => { updatePositions() @@ -1013,11 +1031,6 @@ function TimelineDemo() { return map }, []) - const calendarEvents = useMemo( - () => calendar.getEvents(), - [calendar.days, calendar], - ) - const timelineLayout = useMemo( () => calendar.getTimelineLayout(), [calendar.days], @@ -1189,6 +1202,18 @@ function TimelineDemo() { ) if (validation.blocked) { + getTimeClient().emit('event:update:error', { + eventId: draggedEvent.id, + eventTitle: draggedEvent.title, + reason: 'unavailable-time', + message: + validation.message ?? 'This move is blocked by availability.', + originalStart: draggedEvent.start, + originalEnd: draggedEvent.end, + attemptedStart: nextStart, + attemptedEnd: nextEnd, + }) + setResizeError({ eventId: draggedEvent.id, eventTitle: draggedEvent.title, @@ -1432,7 +1457,7 @@ function TimelineDemo() { style={{ overflow: 'hidden' }} > ( - (eventId, newStart, newEnd) => - calendarCore.validateMove(eventId, newStart, newEnd), + (eventId, newStart, newEnd, newResources) => + calendarCore.validateMove(eventId, newStart, newEnd, newResources), [calendarCore], ) diff --git a/packages/time-devtools/src/components/Shell.tsx b/packages/time-devtools/src/components/Shell.tsx index f18badd3..4d275e0c 100644 --- a/packages/time-devtools/src/components/Shell.tsx +++ b/packages/time-devtools/src/components/Shell.tsx @@ -45,8 +45,8 @@ const getEventTypeLabel = ( return { text: 'Removed', color: 'red' } case 'time:event:resized': return { text: 'Resized', color: 'yellow' } - case 'time:event:resize:error': - return { text: 'Resize Error', color: 'red' } + case 'time:event:update:error': + return { text: 'Update Error', color: 'red' } case 'time:calendar:navigate': return { text: 'Navigate', color: 'purple' } case 'time:calendar:viewMode:changed': @@ -68,7 +68,7 @@ const getEventDescription = (entry: ActivityLogEntry): string => { return `${details.eventTitle || 'Event'}` case 'time:event:resized': return `Resized to ${String(details.start)} - ${String(details.end)}` - case 'time:event:resize:error': + case 'time:event:update:error': return `${details.eventTitle || 'Event'} - ${String(details.message)}` case 'time:calendar:navigate': return `${String(details.direction)} → ${String(details.targetDate)}` diff --git a/packages/time/src/client/TimeClient.ts b/packages/time/src/client/TimeClient.ts index 8fdc859d..882f426a 100644 --- a/packages/time/src/client/TimeClient.ts +++ b/packages/time/src/client/TimeClient.ts @@ -33,7 +33,7 @@ export interface TimeEventMap { start: string end: string } - 'time:event:resize:error': { + 'time:event:update:error': { eventId: string eventTitle: string reason: 'unavailable-time' | 'invalid-time' | 'min-duration' | 'blocked' From 2b98c156740d3f854972e0eddb343a43aed3fec0 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Mon, 30 Mar 2026 19:05:46 +0200 Subject: [PATCH 064/207] feat: lazy loading --- TODO.md | 5 + examples/react/timeline/src/index.tsx | 44 +- .../react-time/src/useCalendar/useCalendar.ts | 11 +- .../time-devtools/src/components/Shell.tsx | 159 ++++-- .../time-devtools/src/store/time-context.tsx | 54 +- packages/time/src/calendar/calendar.ts | 508 +++++++++++++++--- packages/time/src/calendar/date-core.ts | 3 +- packages/time/src/calendar/types.ts | 5 + packages/time/src/client/TimeClient.ts | 8 + 9 files changed, 672 insertions(+), 125 deletions(-) create mode 100644 TODO.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..530416b5 --- /dev/null +++ b/TODO.md @@ -0,0 +1,5 @@ +1. Replace `capacity` with `fractions` - eg. [2, 3, 5] = 10 and consumption based on fractions +2. Virtualization examples +3. Lazy loading events +4. Unavailability zones - friday -> monday connection should be possible with a flag on weekends +5. Recurring events diff --git a/examples/react/timeline/src/index.tsx b/examples/react/timeline/src/index.tsx index c2c68eb6..bc86cf07 100644 --- a/examples/react/timeline/src/index.tsx +++ b/examples/react/timeline/src/index.tsx @@ -231,7 +231,15 @@ function getSampleEvents(): Array> { ] } -const sampleEvents = getSampleEvents() +const MOCK_DB = getSampleEvents() + +function getEventColor(eventId: string) { + const hash = String(eventId) + .split('') + .reduce((acc, char) => acc + char.charCodeAt(0), 0) + const colorIdx = hash % EVENT_COLORS.length + return EVENT_COLORS[colorIdx] ?? EVENT_COLORS[0] +} interface EventFormData { title: string @@ -855,7 +863,6 @@ const DraggableTimelineEvent = React.memo(function DraggableTimelineEvent({ const HorizontalTimelineRow = React.memo(function HorizontalTimelineRow({ row, days, - colorMap, resourceColorIndex, onEventClick, getResizeHandleProps, @@ -865,7 +872,6 @@ const HorizontalTimelineRow = React.memo(function HorizontalTimelineRow({ }: { row: TimelineResourceRow> days: Array>> - colorMap: Map resourceColorIndex: number onEventClick: (event: Event) => void getResizeHandleProps: ReturnType< @@ -951,9 +957,7 @@ const HorizontalTimelineRow = React.memo(function HorizontalTimelineRow({ })} {row.events.map( ({ event, left, width, lane, isStartClipped, isEndClipped }) => { - const colorIdx = colorMap.get(event.id) ?? 0 - const color = - EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] + const color = getEventColor(event.id) return ( >({ viewMode: { value: 1, unit: 'day' }, - events: sampleEvents, + events: [], resources: sampleResources, timeZone: 'UTC', + fetchEvents: async ({ start, end }) => { + // Simulate network latency + await new Promise((resolve) => setTimeout(resolve, 800)) + + const startDate = new Date(start) + const endDate = new Date(end) + + return MOCK_DB.filter((e) => { + const eStart = new Date(e.start as string) + const eEnd = new Date(e.end as string) + return eStart <= endDate && eEnd >= startDate + }) + }, resize: { enabled: true, get containerWidth() { @@ -1025,12 +1042,6 @@ function TimelineDemo() { }, }) - const colorMap = useMemo(() => { - const map = new Map() - sampleEvents.forEach((event, i) => map.set(event.id, i)) - return map - }, []) - const timelineLayout = useMemo( () => calendar.getTimelineLayout(), [calendar.days], @@ -1443,7 +1454,6 @@ function TimelineDemo() { key={row.resource.id} row={row} days={calendar.days} - colorMap={colorMap} resourceColorIndex={rowIdx} onEventClick={openEditModal} getResizeHandleProps={calendar.getResizeHandleProps} @@ -1473,10 +1483,8 @@ function TimelineDemo() {
- {sampleEvents.map((event) => { - const colorIdx = colorMap.get(event.id) ?? 0 - const color = - EVENT_COLORS[colorIdx % EVENT_COLORS.length] ?? EVENT_COLORS[0] + {calendar.getEvents().map((event) => { + const color = getEventColor(event.id) return (
new CalendarCore(calendarOptions), ) const state = useStore(calendarCore.store) - const [isPending, startTransition] = useTransition() + const [isTransitionPending, startTransition] = useTransition() + // Combine React's transition pending with the async fetch pending from the store + const isPending = isTransitionPending || state.isPending + + // Trigger lazy loading when the period or view mode changes. + // This must be done in an effect to avoid triggering fetches/state updates during render. + useEffect(() => { + calendarCore.ensureRangeLoaded() + }, [calendarCore, state.currentPeriod, state.viewMode, state.activeDate]) const resizeOptionsRef = useRef(resize) resizeOptionsRef.current = resize diff --git a/packages/time-devtools/src/components/Shell.tsx b/packages/time-devtools/src/components/Shell.tsx index 4d275e0c..b9c1bc93 100644 --- a/packages/time-devtools/src/components/Shell.tsx +++ b/packages/time-devtools/src/components/Shell.tsx @@ -1,4 +1,4 @@ -import { For, Show } from 'solid-js' +import { For, Show, createSignal } from 'solid-js' import { Button, Header, @@ -37,6 +37,8 @@ const getEventTypeLabel = ( color: 'green' | 'blue' | 'red' | 'yellow' | 'purple' | 'pink' | 'gray' } => { switch (type) { + case 'time:events:set': + return { text: 'Loaded', color: 'green' } case 'time:event:added': return { text: 'Added', color: 'green' } case 'time:event:updated': @@ -60,6 +62,9 @@ const getEventDescription = (entry: ActivityLogEntry): string => { const { type, details } = entry switch (type) { + case 'time:events:set': + const evts = details.events as Array | undefined + return `Batched ${evts?.length || 0} events` case 'time:event:added': return `${details.eventTitle || 'Event'} (ID: ${String(details.eventId).slice(0, 8)}...)` case 'time:event:updated': @@ -85,12 +90,43 @@ const getEventDescription = (entry: ActivityLogEntry): string => { function DevtoolsContent() { const { state, clearLog } = useTimeStore() const styles = useStyles() + const [activeTab, setActiveTab] = createSignal<'log' | 'events'>('log') + return (
TanStack Time +
+ setActiveTab('log')} variant="primary"> + Activity + + } + > + + + setActiveTab('events')} variant="primary"> + Current Events + + } + > + + +
@@ -99,42 +135,97 @@ function DevtoolsContent() {
-
-
- Activity Log - -
+ +
+
+ Activity Log + +
- 0} - fallback={ -
- No activity yet. Start interacting with the calendar! + 0} + fallback={ +
+ No activity yet. Start interacting with the calendar! +
+ } + > +
+ + {(entry) => { + const label = getEventTypeLabel(entry.type) + return ( +
+ + {formatTime(entry.timestamp)} + + + + {getEventDescription(entry)} + +
+ ) + }} +
- } - > -
- - {(entry) => { - const label = getEventTypeLabel(entry.type) - return ( -
- - {formatTime(entry.timestamp)} - - - - {getEventDescription(entry)} - -
- ) - }} -
+ +
+
+ + +
+
+ + Loaded Events ({Object.keys(state.events).length}) +
- -
+ 0} + fallback={ +
+ No events currently loaded into the calendar scope. +
+ } + > +
+ + {(event) => ( +
+
{event.title}
+
+ {event.start} → {event.end} +
+
+ ID: {event.id} +
+
+ )} +
+
+
+
+
) } diff --git a/packages/time-devtools/src/store/time-context.tsx b/packages/time-devtools/src/store/time-context.tsx index e45a53b6..59c2a00c 100644 --- a/packages/time-devtools/src/store/time-context.tsx +++ b/packages/time-devtools/src/store/time-context.tsx @@ -1,7 +1,8 @@ -import { createContext, useContext, onMount, onCleanup } from 'solid-js' +import { createContext, onCleanup, onMount, useContext } from 'solid-js' import { createStore } from 'solid-js/store' +import { getTimeClient } from '@tanstack/time' +import type { TimeEventMap } from '@tanstack/time' import type { ParentComponent } from 'solid-js' -import { getTimeClient, type TimeEventMap } from '@tanstack/time' export interface ActivityLogEntry { id: string @@ -13,6 +14,10 @@ export interface ActivityLogEntry { interface TimeStoreState { activityLog: Array isConnected: boolean + events: Record< + string, + { id: string; title: string; start: string; end: string } + > } interface TimeContextValue { @@ -38,6 +43,7 @@ export const TimeProvider: ParentComponent = (props) => { const [state, setState] = createStore({ activityLog: [], isConnected: false, + events: {}, }) const clearLog = () => { @@ -60,11 +66,55 @@ export const TimeProvider: ParentComponent = (props) => { } setState('activityLog', (prev) => [entry, ...prev].slice(0, 100)) + + // Track the live map of events + if ( + event.type === 'time:event:added' || + event.type === 'time:event:updated' + ) { + const payload = event.payload as { + eventId: string + eventTitle: string + start: string + end: string + } + setState('events', payload.eventId, { + id: payload.eventId, + title: payload.eventTitle, + start: payload.start, + end: payload.end, + }) + } else if (event.type === 'time:event:removed') { + const payload = event.payload as { eventId: string } + setState('events', payload.eventId, undefined!) + } else if (event.type === 'time:events:set') { + const payload = event.payload as { + events: Array<{ + eventId: string + eventTitle: string + start: string + end: string + }> + } + setState('events', (prev) => { + const next = { ...prev } + for (const ev of payload.events) { + next[ev.eventId] = { + id: ev.eventId, + title: ev.eventTitle, + start: ev.start, + end: ev.end, + } + } + return next + }) + } }) onCleanup(() => { unsubscribe() setState('isConnected', false) + setState('events', {}) }) }) diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index 08aa93af..e2781822 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -48,6 +48,13 @@ export interface CalendarCoreOptions< events?: Array | null /** Optional resources to be used in the calendar. */ resources?: Array | null + /** + * Optional async callback for lazy/on-demand event loading. + * Called whenever the current viewport window is not yet fully loaded. + * The returned events are merged into the internal indices automatically. + * When omitted the calendar operates in fully-eager mode (no change in behaviour). + */ + fetchEvents?: (range: { start: string; end: string }) => Promise> } /** @@ -215,6 +222,7 @@ type ParsedCalendarCoreOptions< > = ParsedDateCoreOptions & { events: Array | null resources: Array | null + fetchEvents?: (range: { start: string; end: string }) => Promise> } export class CalendarCore< @@ -226,14 +234,135 @@ export class CalendarCore< { declare options: ParsedCalendarCoreOptions + // ─── O(1) index structures ────────────────────────────────────────────────── + /** id → normalized TEvent (master record) */ + private _eventMap = new Map() + /** id → Set of event IDs whose `dependsOn` includes this id (reverse dep graph) */ + private _dependentsMap = new Map>() + /** 'YYYY-MM-DD' → Set of event IDs that start on that date */ + private _dateIndex = new Map>() + /** Ranges already fetched by fetchEvents (sorted, non-overlapping after merge) */ + private _loadedRanges: Array<{ start: string; end: string }> = [] + // ──────────────────────────────────────────────────────────────────────────── + constructor(options: CalendarCoreOptions) { super(options) Object.assign(this.options, { events: options.events?.map((e) => this.normalizeEvent(e)) || null, resources: options.resources || null, + fetchEvents: options.fetchEvents, }) + // Build indices from initial events + this.options.events?.forEach((e) => this._indexAddEvent(e)) + } + + // ─── Index helpers ────────────────────────────────────────────────────────── + + /** Return the ISO start-date key for a normalized event. */ + private _eventDateKey(event: TEvent): string { + const startStr = event.start as string + return startStr.split('T')[0] ?? startStr + } + + /** Insert one event into all three indices. */ + private _indexAddEvent(event: TEvent): void { + this._eventMap.set(event.id, event) + // date index + const dk = this._eventDateKey(event) + if (!this._dateIndex.has(dk)) this._dateIndex.set(dk, new Set()) + this._dateIndex.get(dk)!.add(event.id) + // reverse dependency graph + for (const predId of event.dependsOn ?? []) { + if (!this._dependentsMap.has(predId)) this._dependentsMap.set(predId, new Set()) + this._dependentsMap.get(predId)!.add(event.id) + } + } + + /** Remove one event from all three indices. */ + private _indexRemoveEvent(event: TEvent): void { + this._eventMap.delete(event.id) + // date index + const dk = this._eventDateKey(event) + const bucket = this._dateIndex.get(dk) + if (bucket) { + bucket.delete(event.id) + if (bucket.size === 0) this._dateIndex.delete(dk) + } + // reverse dependency graph — remove this event as a dependent of its predecessors + for (const predId of event.dependsOn ?? []) { + this._dependentsMap.get(predId)?.delete(event.id) + } + // also remove its own forward entry (for events that depended on it) + this._dependentsMap.delete(event.id) + } + + /** + * Patch the indices when an event changes. + * Only touches the structures that actually changed. + */ + private _indexUpdateEvent(prev: TEvent, next: TEvent): void { + this._eventMap.set(next.id, next) + + // date index: only rebuild if start date changed + const prevDk = this._eventDateKey(prev) + const nextDk = this._eventDateKey(next) + if (prevDk !== nextDk) { + const old = this._dateIndex.get(prevDk) + if (old) { + old.delete(prev.id) + if (old.size === 0) this._dateIndex.delete(prevDk) + } + if (!this._dateIndex.has(nextDk)) this._dateIndex.set(nextDk, new Set()) + this._dateIndex.get(nextDk)!.add(next.id) + } + + // reverse dependency graph: rebuild only diff + const prevDeps = new Set(prev.dependsOn ?? []) + const nextDeps = new Set(next.dependsOn ?? []) + for (const predId of prevDeps) { + if (!nextDeps.has(predId)) { + this._dependentsMap.get(predId)?.delete(next.id) + } + } + for (const predId of nextDeps) { + if (!prevDeps.has(predId)) { + if (!this._dependentsMap.has(predId)) this._dependentsMap.set(predId, new Set()) + this._dependentsMap.get(predId)!.add(next.id) + } + } } + /** + * Check whether the given [start, end] viewport is already fully covered by + * previously fetched ranges. Returns true when no fetch is needed. + */ + private _isRangeLoaded(start: string, end: string): boolean { + for (const r of this._loadedRanges) { + if (r.start <= start && r.end >= end) return true + } + return false + } + + /** + * Merge a newly loaded range into `_loadedRanges` (sorted, non-overlapping). + */ + private _markRangeLoaded(start: string, end: string): void { + this._loadedRanges.push({ start, end }) + this._loadedRanges.sort((a, b) => (a.start < b.start ? -1 : 1)) + // merge overlapping/adjacent + const merged: Array<{ start: string; end: string }> = [] + for (const r of this._loadedRanges) { + const last = merged[merged.length - 1] + if (last && r.start <= last.end) { + last.end = last.end > r.end ? last.end : r.end + } else { + merged.push({ ...r }) + } + } + this._loadedRanges = merged + } + // ──────────────────────────────────────────────────────────────────────────── + private normalizeEvent< T extends { start: string | Date | number; end: string | Date | number }, >(event: T): T { @@ -248,17 +377,24 @@ export class CalendarCore< return super.getCalendarDays() } + /** + * Builds a date → [event segments] map used by getDaysWithEvents and getEventProps. + * Multi-day events are split here (segments are not stored in the indices). + * Single-day events are sourced directly from _eventMap via _dateIndex — O(k) where + * k is the number of distinct dates that have events (≪ total event count). + */ private getEventMap() { const map = new Map>() - this.options.events?.forEach((event) => { - const eventStartDate = Temporal.PlainDateTime.from( - toPlainDateTimeString(event.start), - ).toZonedDateTime(this.options.timeZone) - const eventEndDate = Temporal.PlainDateTime.from( - toPlainDateTimeString(event.end), - ).toZonedDateTime(this.options.timeZone) - const startPlainDate = eventStartDate.toPlainDate() - const endPlainDate = eventEndDate.toPlainDate() + + // Visit every event only once, via the master map + for (const event of this._eventMap.values()) { + const startStr = event.start as string + const endStr = event.end as string + + const startDt = Temporal.PlainDateTime.from(startStr) + const endDt = Temporal.PlainDateTime.from(endStr) + const startPlainDate = startDt.toPlainDate() + const endPlainDate = endDt.toPlainDate() if (Temporal.PlainDate.compare(startPlainDate, endPlainDate) !== 0) { const splitEvents = splitMultiDayEvents( @@ -272,17 +408,81 @@ export class CalendarCore< .toPlainDate() .toString({ calendarName: 'never' }) if (!map.has(dateKey)) map.set(dateKey, []) - map.get(dateKey)?.push(splitEvent) + map.get(dateKey)!.push(splitEvent) }) } else { const dateKey = startPlainDate.toString({ calendarName: 'never' }) if (!map.has(dateKey)) map.set(dateKey, []) - map.get(dateKey)?.push(event) + map.get(dateKey)!.push(event) } - }) + } return map } + /** + * Triggers the lazy-loading flow if the current viewport haven't been fetched yet. + * This is intended to be used by side-effect hooks (like useEffect in React) + * to avoid triggering fetches during the render cycle. + */ + ensureRangeLoaded(): void { + const calendarDays = this.getCalendarDays() + + // Lazy loading: if a fetchEvents callback is configured and the current + // viewport window hasn't been fetched yet, kick off the fetch asynchronously. + if (this.options.fetchEvents && calendarDays.length > 0) { + const first = calendarDays[0]! + const last = calendarDays[calendarDays.length - 1]! + const rangeStart = first.toString({ calendarName: 'never' }) + // Use the start of the NEXT day as the range end to provide a standard exclusive range [start, end) + const rangeEnd = last.add({ days: 1 }).toString({ calendarName: 'never' }) + + if (!this._isRangeLoaded(rangeStart, rangeEnd)) { + // Mark as loaded immediately to prevent concurrent duplicate fetches + this._markRangeLoaded(rangeStart, rangeEnd) + // Set isPending while fetching + this.store.setState((prev) => ({ ...prev, isPending: true })) + this.options.fetchEvents({ start: rangeStart, end: rangeEnd }) + .then((fetchedEvents) => { + if (fetchedEvents.length > 0) { + if (!this.options.events) this.options.events = [] + const newlyFetchedEvents: Array<{ eventId: string; eventTitle: string; start: string; end: string }> = [] + for (const raw of fetchedEvents) { + // Skip duplicates (event may already be known) + if (this._eventMap.has(raw.id)) continue + const normalized = this.normalizeEvent(raw) + this.options.events.push(normalized) + this._indexAddEvent(normalized) + newlyFetchedEvents.push({ + eventId: normalized.id, + eventTitle: normalized.title, + start: normalized.start as string, + end: normalized.end as string, + }) + } + if (newlyFetchedEvents.length > 0) { + getTimeClient().emit('events:set', { events: newlyFetchedEvents }) + } + } + this.store.setState((prev) => ({ + ...prev, + isPending: false, + eventsVersion: + fetchedEvents.length > 0 + ? prev.eventsVersion + 1 + : prev.eventsVersion, + })) + }) + .catch(() => { + // On error, unmark the range so the next render can retry + this._loadedRanges = this._loadedRanges.filter( + (r) => !(r.start === rangeStart && r.end === rangeEnd), + ) + this.store.setState((prev) => ({ ...prev, isPending: false })) + }) + } + } + } + getDaysWithEvents() { const calendarDays = this.getCalendarDays() const eventMap = this.getEventMap() @@ -305,6 +505,11 @@ export class CalendarCore< }) } + /** Returns the list of date ranges that have already been fetched. Useful for testing. */ + getLoadedRanges(): ReadonlyArray<{ start: string; end: string }> { + return this._loadedRanges + } + formatPeriodLabel(options?: { locale?: string }): string { const days = this.getDaysWithEvents() if (days.length === 0) return '' @@ -352,10 +557,17 @@ export class CalendarCore< return getTimeSlots(this.options.locale, options) } + /** + * Retrieves events for a specific date. + * Uses _dateIndex for O(1) date lookup, then resolves each id via _eventMap. + * Multi-day events that span onto this date are still found via getEventMap. + */ getEventsByDate(date: string): Array { const targetDate = Temporal.PlainDate.from(date).toString({ calendarName: 'never', }) + // Fast path: delegate to the same map used by getDaysWithEvents so that + // multi-day split segments are included too. const eventMap = this.getEventMap() return eventMap.get(targetDate) ?? [] } @@ -366,6 +578,8 @@ export class CalendarCore< } const normalized = this.normalizeEvent(event) this.options.events.push(normalized) + // Update indices in O(1) + this._indexAddEvent(normalized) this.store.setState((prev) => ({ ...prev, eventsVersion: prev.eventsVersion + 1, @@ -382,10 +596,14 @@ export class CalendarCore< updateEvent(id: Event['id'], updates: Partial>): void { if (!this.options.events) return - const index = this.options.events.findIndex((e) => e.id === id) + // O(1) lookup via index + const existingEvent = this._eventMap.get(id) + if (!existingEvent) return + + const index = this.options.events.indexOf(existingEvent) if (index === -1) return - const existingEvent = this.options.events[index]! + const oldStartStr = toPlainDateTimeString(existingEvent.start) const oldEndStr = toPlainDateTimeString(existingEvent.end) const normalizedUpdates = { @@ -398,14 +616,22 @@ export class CalendarCore< : {}), } - this.options.events[index] = { + const nextEvent = { ...existingEvent, ...normalizedUpdates, } as TEvent + this.options.events[index] = nextEvent + // Update all three indices atomically + this._indexUpdateEvent(existingEvent, nextEvent) // Shared visited set prevents double-shifting when both end and start change. const visited = new Set([id]) + const newStart = normalizedUpdates.start as string | undefined + if (newStart && newStart !== oldStartStr) { + this.propagateStartDeltaBackward(id, visited) + } + const newEnd = normalizedUpdates.end as string | undefined if (newEnd && newEnd !== oldEndStr) { const endDeltaMs = Temporal.PlainDateTime.from(oldEndStr) @@ -425,20 +651,84 @@ export class CalendarCore< getTimeClient().emit('event:updated', { eventId: id, eventTitle: existingEvent.title, - start: this.options.events[index]!.start as string, - end: this.options.events[index]!.end as string, + start: toPlainDateTimeString(nextEvent.start), + end: toPlainDateTimeString(nextEvent.end), updates: normalizedUpdates as Record, }) } + /** + * Walk the predecessor chain backward and push each predecessor earlier when + * the source event's new start would violate a finish-to-start constraint. + * Uses _eventMap for O(1) lookups — no array scans. + */ + private propagateStartDeltaBackward(sourceId: string, visited: Set) { + const sourceEvent = this._eventMap.get(sourceId) + if (!sourceEvent?.dependsOn?.length) return + + const sourceStartStr = toPlainDateTimeString(sourceEvent.start) + const sourceStartMs = Temporal.PlainDateTime.from( + sourceStartStr, + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + + for (const predId of sourceEvent.dependsOn) { + if (visited.has(predId)) continue + + const pred = this._eventMap.get(predId) + if (!pred) continue + const predArr = this.options.events + if (!predArr) continue + const predIndex = predArr.indexOf(pred) + if (predIndex === -1) continue + + const predEndStr = toPlainDateTimeString(pred.end) + const predEndMs = Temporal.PlainDateTime.from(predEndStr).toZonedDateTime( + this.options.timeZone, + ).epochMilliseconds + + const overlap = predEndMs - sourceStartMs + if (overlap <= 0) continue + + visited.add(predId) + + const predStartStr = toPlainDateTimeString(pred.start) + const shiftedStart = Temporal.PlainDateTime.from(predStartStr) + .subtract({ milliseconds: overlap }) + .toString({ smallestUnit: 'second' }) + const shiftedEnd = Temporal.PlainDateTime.from(predEndStr) + .subtract({ milliseconds: overlap }) + .toString({ smallestUnit: 'second' }) + + const updated = { ...pred, start: shiftedStart, end: shiftedEnd } as TEvent + predArr[predIndex] = updated + this._indexUpdateEvent(pred, updated) + + getTimeClient().emit('event:updated', { + eventId: pred.id, + eventTitle: pred.title, + start: shiftedStart, + end: shiftedEnd, + updates: { start: shiftedStart, end: shiftedEnd } as Record< + string, + unknown + >, + }) + + this.propagateStartDeltaBackward(predId, visited) + } + } + + /** + * Walk the successor (dependent) chain forward and shift each successor when + * the source event's new end would overflow into the successor's start time. + * Uses _dependentsMap for O(degree) traversal — no full array scan. + */ private propagateEndDelta( sourceId: string, _deltaMs: number, visited: Set, ): void { - if (!this.options.events) return - - const sourceEvent = this.options.events.find((e) => e.id === sourceId) + const sourceEvent = this._eventMap.get(sourceId) if (!sourceEvent) return const sourceEndStr = toPlainDateTimeString(sourceEvent.end) @@ -446,20 +736,25 @@ export class CalendarCore< sourceEndStr, ).toZonedDateTime(this.options.timeZone).epochMilliseconds - const dependents = this.options.events.filter( - (event) => !visited.has(event.id) && event.dependsOn?.includes(sourceId), - ) + // O(degree) — only the direct dependents of sourceId + const dependentIds = this._dependentsMap.get(sourceId) + if (!dependentIds || dependentIds.size === 0) return + + const eventsArr = this.options.events + if (!eventsArr) return + + for (const depId of dependentIds) { + if (visited.has(depId)) continue + + const dependent = this._eventMap.get(depId) + if (!dependent) continue - for (const dependent of dependents) { visited.add(dependent.id) - const eventIndex = this.options.events.findIndex( - (e) => e.id === dependent.id, - ) + const eventIndex = eventsArr.indexOf(dependent) if (eventIndex === -1) continue - const currentEvent = this.options.events[eventIndex]! - const depStartStr = toPlainDateTimeString(currentEvent.start) + const depStartStr = toPlainDateTimeString(dependent.start) const depStartMs = Temporal.PlainDateTime.from( depStartStr, ).toZonedDateTime(this.options.timeZone).epochMilliseconds @@ -467,7 +762,7 @@ export class CalendarCore< const overflow = sourceEndMs - depStartMs if (overflow <= 0) continue - const depEndStr = toPlainDateTimeString(currentEvent.end) + const depEndStr = toPlainDateTimeString(dependent.end) const shiftedStart = Temporal.PlainDateTime.from(depStartStr) .add({ milliseconds: overflow }) .toString({ smallestUnit: 'second' }) @@ -476,15 +771,13 @@ export class CalendarCore< .add({ milliseconds: overflow }) .toString({ smallestUnit: 'second' }) - this.options.events[eventIndex] = { - ...currentEvent, - start: shiftedStart, - end: shiftedEnd, - } as TEvent + const updated = { ...dependent, start: shiftedStart, end: shiftedEnd } as TEvent + eventsArr[eventIndex] = updated + this._indexUpdateEvent(dependent, updated) getTimeClient().emit('event:updated', { - eventId: currentEvent.id, - eventTitle: currentEvent.title, + eventId: dependent.id, + eventTitle: dependent.title, start: shiftedStart, end: shiftedEnd, updates: { start: shiftedStart, end: shiftedEnd } as Record< @@ -497,21 +790,23 @@ export class CalendarCore< } } - /** Simulate how deltaMs cascades forward through the dependency graph without mutating state. - * Only shifts a successor when the source's new end would exceed the successor's start (gap-aware). */ + /** + * Simulate how deltaMs cascades forward through the dependency graph without mutating state. + * Uses _dependentsMap for O(degree) BFS — no full array scan per step. + */ private getAffectedByDelta( sourceId: string, deltaMs: number, visited: Set, ): Array<{ event: TEvent; newStart: string; newEnd: string }> { - if (!this.options.events || deltaMs === 0) return [] + if (deltaMs === 0) return [] const affected: Array<{ event: TEvent; newStart: string; newEnd: string }> = [] const projectedEndMap = new Map() - const sourceEvent = this.options.events.find((e) => e.id === sourceId) + const sourceEvent = this._eventMap.get(sourceId) if (!sourceEvent) return [] const sourceEndStr = toPlainDateTimeString(sourceEvent.end) @@ -527,11 +822,15 @@ export class CalendarCore< const currentId = queue.shift()! const currentEndMs = projectedEndMap.get(currentId)! - const successors = this.options.events.filter( - (e) => !visited.has(e.id) && e.dependsOn?.includes(currentId), - ) + // O(degree) — only direct dependents via reverse map + const successorIds = this._dependentsMap.get(currentId) + if (!successorIds || successorIds.size === 0) continue + + for (const sId of successorIds) { + if (visited.has(sId)) continue + const s = this._eventMap.get(sId) + if (!s) continue - for (const s of successors) { const sStartStr = toPlainDateTimeString(s.start) const sEndStr = toPlainDateTimeString(s.end) const depStartMs = Temporal.PlainDateTime.from( @@ -544,7 +843,7 @@ export class CalendarCore< const overflow = currentEndMs - depStartMs if (overflow <= 0) continue - visited.add(s.id) + visited.add(sId) const newStart = Temporal.PlainDateTime.from(sStartStr) .add({ milliseconds: overflow }) .toString({ smallestUnit: 'second' }) @@ -553,8 +852,8 @@ export class CalendarCore< .toString({ smallestUnit: 'second' }) affected.push({ event: s, newStart, newEnd }) - projectedEndMap.set(s.id, depEndMs + overflow) - queue.push(s.id) + projectedEndMap.set(sId, depEndMs + overflow) + queue.push(sId) } } @@ -648,10 +947,9 @@ export class CalendarCore< newEnd: string, newResources?: Array, ): { blocked: boolean; blockedEventTitle?: string; message?: string } { - const event = this.options.events?.find( - (e) => e.id === eventId && !e._originalStart, - ) - if (!event) return { blocked: false } + // O(1) lookup — skip split segments (_originalStart set on them) + const event = this._eventMap.get(eventId) + if (!event || event._originalStart) return { blocked: false } const conflict = this.checkEventAvailability( event, @@ -675,6 +973,70 @@ export class CalendarCore< ).epochMilliseconds const deltaMs = newEndMs - oldEndMs + // If moving the event earlier would cause it to start before any predecessor ends, + // we will "pull" predecessors left to maintain finish-to-start dependencies. + // Validate that those pulled predecessors would not violate availability. + if (event.dependsOn?.length) { + const newStartMs = Temporal.PlainDateTime.from(newStart).toZonedDateTime( + this.options.timeZone, + ).epochMilliseconds + + const visited = new Set([eventId]) + const queue: Array<{ id: string; startMs: number }> = [ + { id: eventId, startMs: newStartMs }, + ] + + while (queue.length > 0) { + const current = queue.shift()! + // O(1) lookup + const currentEvent = this._eventMap.get(current.id) + if (!currentEvent?.dependsOn?.length) continue + + for (const predId of currentEvent.dependsOn) { + if (visited.has(predId)) continue + // O(1) lookup + const pred = this._eventMap.get(predId) + if (!pred) continue + + const predStartStr = toPlainDateTimeString(pred.start) + const predEndStr = toPlainDateTimeString(pred.end) + const predStartMs = Temporal.PlainDateTime.from( + predStartStr, + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + const predEndMs = Temporal.PlainDateTime.from( + predEndStr, + ).toZonedDateTime(this.options.timeZone).epochMilliseconds + + const overlap = predEndMs - current.startMs + if (overlap <= 0) continue + + visited.add(predId) + + const shiftedStart = Temporal.PlainDateTime.from(predStartStr) + .subtract({ milliseconds: overlap }) + .toString({ smallestUnit: 'second' }) + const shiftedEnd = Temporal.PlainDateTime.from(predEndStr) + .subtract({ milliseconds: overlap }) + .toString({ smallestUnit: 'second' }) + + const predConflict = this.checkEventAvailability( + pred, + shiftedStart, + shiftedEnd, + ) + if (predConflict) { + return { + blocked: true, + blockedEventTitle: pred.title, + message: `"${pred.title}" would be pulled into unavailable time.`, + } + } + + queue.push({ id: predId, startMs: predStartMs - overlap }) + } + } + } + if (deltaMs > 0) { const affected = this.getAffectedByDelta( eventId, @@ -704,14 +1066,15 @@ export class CalendarCore< event: { id?: string; title: string; start: string; end: string }, dependsOn: Array, ): { valid: boolean; error?: ResizeError } { - if (!this.options.events) return { valid: true } + if (this._eventMap.size === 0) return { valid: true } const newStartMs = Temporal.PlainDateTime.from(event.start).toZonedDateTime( this.options.timeZone, ).epochMilliseconds for (const predId of dependsOn) { - const pred = this.options.events.find((e) => e.id === predId) + // O(1) lookup + const pred = this._eventMap.get(predId) if (!pred) continue const predEndMs = Temporal.PlainDateTime.from( @@ -739,10 +1102,9 @@ export class CalendarCore< sourceId: string, targetId: string, ): { blocked: boolean; error?: ResizeError } { - if (!this.options.events) return { blocked: false } - - const sourceEvent = this.options.events.find((e) => e.id === sourceId) - const targetEvent = this.options.events.find((e) => e.id === targetId) + // O(1) lookups + const sourceEvent = this._eventMap.get(sourceId) + const targetEvent = this._eventMap.get(targetId) if (!sourceEvent || !targetEvent) return { blocked: false } const currentDependsOn = targetEvent.dependsOn ?? [] @@ -813,24 +1175,27 @@ export class CalendarCore< removeEvent(id: Event['id']): void { if (!this.options.events) return - const index = this.options.events.findIndex((e) => e.id === id) + // O(1) lookup via _eventMap + const removedEvent = this._eventMap.get(id) + if (!removedEvent) return + + const index = this.options.events.indexOf(removedEvent) if (index === -1) return - const removedEvent = this.options.events[index] this.options.events.splice(index, 1) + // Remove from all three indices + this._indexRemoveEvent(removedEvent) this.store.setState((prev) => ({ ...prev, eventsVersion: prev.eventsVersion + 1, })) - if (removedEvent) { - getTimeClient().emit('event:removed', { - eventId: id, - eventTitle: removedEvent.title, - start: removedEvent.start as string, - end: removedEvent.end as string, - }) - } + getTimeClient().emit('event:removed', { + eventId: id, + eventTitle: removedEvent.title, + start: removedEvent.start as string, + end: removedEvent.end as string, + }) } getUnavailableRanges( @@ -1154,7 +1519,12 @@ export class CalendarCore< event: TEvent, firstDay: Temporal.PlainDate, totalDays: number, - ): { left: number; width: number } { + ): { + left: number + width: number + isStartClipped: boolean + isEndClipped: boolean + } { const startStr = toPlainDateTimeString(event.start) const endStr = toPlainDateTimeString(event.end) diff --git a/packages/time/src/calendar/date-core.ts b/packages/time/src/calendar/date-core.ts index 4de82064..a4dc8092 100644 --- a/packages/time/src/calendar/date-core.ts +++ b/packages/time/src/calendar/date-core.ts @@ -120,11 +120,12 @@ export abstract class DateCore { range: this.options.range, }) - this.store = new Store({ + this.store = new Store({ currentPeriod: initialDate, activeDate: initialDate, viewMode: options.viewMode, eventsVersion: 0, + isPending: false, }) } diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index 9d05a6db..183ef87d 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -21,6 +21,8 @@ export interface Resource { before?: number after?: number } + + // fractions: Array } /** @@ -40,6 +42,7 @@ export interface Event { end: EventDateTimeInput title: string resources?: Array + fractions?: Array /** IDs of events this event immediately follows (finish-to-start dependency). * When a predecessor's end time shifts, this event shifts by the same delta. */ dependsOn?: Array @@ -88,6 +91,8 @@ export interface CalendarStore { activeDate: Temporal.PlainDate viewMode: ViewMode eventsVersion: number + /** True while an async fetchEvents call is in-flight for the current viewport. */ + isPending: boolean } /** diff --git a/packages/time/src/client/TimeClient.ts b/packages/time/src/client/TimeClient.ts index 882f426a..e44fd10e 100644 --- a/packages/time/src/client/TimeClient.ts +++ b/packages/time/src/client/TimeClient.ts @@ -14,6 +14,14 @@ export interface TimeEventMap { start: string end: string } + 'time:events:set': { + events: Array<{ + eventId: string + eventTitle: string + start: string + end: string + }> + } 'time:event:updated': { eventId: string eventTitle: string From 96d45ac2298b6f7ce32f714aa5628b9f582eed09 Mon Sep 17 00:00:00 2001 From: Bart Krakowski Date: Fri, 10 Apr 2026 23:05:18 +0200 Subject: [PATCH 065/207] feat: timeline --- examples/react/calendar/components.json | 25 + examples/react/calendar/package.json | 10 +- .../calendar/src/components/ui/badge.tsx | 52 + .../calendar/src/components/ui/button.tsx | 58 + .../react/calendar/src/components/ui/card.tsx | 103 + .../calendar/src/components/ui/dialog.tsx | 158 + .../calendar/src/components/ui/input.tsx | 20 + .../calendar/src/components/ui/label.tsx | 20 + .../calendar/src/components/ui/select.tsx | 199 ++ examples/react/calendar/src/index.css | 93 +- examples/react/calendar/src/index.tsx | 197 +- examples/react/calendar/tailwind.config.js | 48 +- examples/react/calendar/tsconfig.json | 8 +- examples/react/calendar/vite.config.ts | 6 + examples/react/timeline/components.json | 20 + examples/react/timeline/package.json | 15 +- .../timeline/src/components/ui/badge.tsx | 43 + .../timeline/src/components/ui/button.tsx | 58 + .../react/timeline/src/components/ui/card.tsx | 76 + .../timeline/src/components/ui/dialog.tsx | 120 + .../timeline/src/components/ui/input.tsx | 22 + .../timeline/src/components/ui/label.tsx | 24 + .../timeline/src/components/ui/select.tsx | 162 + .../timeline/src/components/ui/tooltip.tsx | 28 + examples/react/timeline/src/index.css | 112 +- examples/react/timeline/src/index.tsx | 383 ++- examples/react/timeline/tailwind.config.js | 46 +- examples/react/timeline/tsconfig.json | 8 +- examples/react/timeline/vite.config.ts | 6 + packages/react-time-devtools/package.json | 2 +- packages/solid-time-devtools/package.json | 2 +- packages/time-devtools/package.json | 4 +- .../time-devtools/src/components/Shell.tsx | 281 +- .../src/components/ThemedShell.tsx | 11 + packages/time-devtools/src/core.tsx | 7 +- .../time-devtools/src/styles/use-styles.ts | 98 +- packages/time/src/calendar/calendar.ts | 29 +- .../time/src/calendar/tests/calendar.test.ts | 10 +- packages/time/src/calendar/types.ts | 6 +- pnpm-lock.yaml | 2799 ++++++++++++++++- 40 files changed, 4897 insertions(+), 472 deletions(-) create mode 100644 examples/react/calendar/components.json create mode 100644 examples/react/calendar/src/components/ui/badge.tsx create mode 100644 examples/react/calendar/src/components/ui/button.tsx create mode 100644 examples/react/calendar/src/components/ui/card.tsx create mode 100644 examples/react/calendar/src/components/ui/dialog.tsx create mode 100644 examples/react/calendar/src/components/ui/input.tsx create mode 100644 examples/react/calendar/src/components/ui/label.tsx create mode 100644 examples/react/calendar/src/components/ui/select.tsx create mode 100644 examples/react/timeline/components.json create mode 100644 examples/react/timeline/src/components/ui/badge.tsx create mode 100644 examples/react/timeline/src/components/ui/button.tsx create mode 100644 examples/react/timeline/src/components/ui/card.tsx create mode 100644 examples/react/timeline/src/components/ui/dialog.tsx create mode 100644 examples/react/timeline/src/components/ui/input.tsx create mode 100644 examples/react/timeline/src/components/ui/label.tsx create mode 100644 examples/react/timeline/src/components/ui/select.tsx create mode 100644 examples/react/timeline/src/components/ui/tooltip.tsx create mode 100644 packages/time-devtools/src/components/ThemedShell.tsx diff --git a/examples/react/calendar/components.json b/examples/react/calendar/components.json new file mode 100644 index 00000000..f5ebd862 --- /dev/null +++ b/examples/react/calendar/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "base-nova", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/examples/react/calendar/package.json b/examples/react/calendar/package.json index 29645168..43097400 100644 --- a/examples/react/calendar/package.json +++ b/examples/react/calendar/package.json @@ -9,12 +9,20 @@ "test:types": "tsc" }, "dependencies": { + "@base-ui/react": "^1.3.0", + "@fontsource-variable/geist": "^5.2.8", "@tanstack/react-devtools": "^0.9.5", "@tanstack/react-time": "^0.0.0", "@tanstack/react-time-devtools": "^0.0.0", "@tanstack/time": "^0.0.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^1.8.0", "react": "^19.2.3", - "react-dom": "^19.2.3" + "react-dom": "^19.2.3", + "shadcn": "^4.2.0", + "tailwind-merge": "^3.5.0", + "tw-animate-css": "^1.4.0" }, "devDependencies": { "@types/react": "^19.2.8", diff --git a/examples/react/calendar/src/components/ui/badge.tsx b/examples/react/calendar/src/components/ui/badge.tsx new file mode 100644 index 00000000..b20959dd --- /dev/null +++ b/examples/react/calendar/src/components/ui/badge.tsx @@ -0,0 +1,52 @@ +import { mergeProps } from "@base-ui/react/merge-props" +import { useRender } from "@base-ui/react/use-render" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", + secondary: + "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80", + destructive: + "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20", + outline: + "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground", + ghost: + "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50", + link: "text-primary underline-offset-4 hover:underline", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant = "default", + render, + ...props +}: useRender.ComponentProps<"span"> & VariantProps) { + return useRender({ + defaultTagName: "span", + props: mergeProps<"span">( + { + className: cn(badgeVariants({ variant }), className), + }, + props + ), + render, + state: { + slot: "badge", + variant, + }, + }) +} + +export { Badge, badgeVariants } diff --git a/examples/react/calendar/src/components/ui/button.tsx b/examples/react/calendar/src/components/ui/button.tsx new file mode 100644 index 00000000..09df7536 --- /dev/null +++ b/examples/react/calendar/src/components/ui/button.tsx @@ -0,0 +1,58 @@ +import { Button as ButtonPrimitive } from "@base-ui/react/button" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", + outline: + "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground", + ghost: + "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50", + destructive: + "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: + "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", + xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3", + sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5", + lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", + icon: "size-8", + "icon-xs": + "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3", + "icon-sm": + "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg", + "icon-lg": "size-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +function Button({ + className, + variant = "default", + size = "default", + ...props +}: ButtonPrimitive.Props & VariantProps) { + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/examples/react/calendar/src/components/ui/card.tsx b/examples/react/calendar/src/components/ui/card.tsx new file mode 100644 index 00000000..40cac5f9 --- /dev/null +++ b/examples/react/calendar/src/components/ui/card.tsx @@ -0,0 +1,103 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Card({ + className, + size = "default", + ...props +}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) { + return ( +
img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl", + className + )} + {...props} + /> + ) +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +} diff --git a/examples/react/calendar/src/components/ui/dialog.tsx b/examples/react/calendar/src/components/ui/dialog.tsx new file mode 100644 index 00000000..3fc1dda4 --- /dev/null +++ b/examples/react/calendar/src/components/ui/dialog.tsx @@ -0,0 +1,158 @@ +import * as React from "react" +import { Dialog as DialogPrimitive } from "@base-ui/react/dialog" + +import { cn } from "@/lib/utils" +import { Button } from "@/components/ui/button" +import { XIcon } from "lucide-react" + +function Dialog({ ...props }: DialogPrimitive.Root.Props) { + return +} + +function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) { + return +} + +function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) { + return +} + +function DialogClose({ ...props }: DialogPrimitive.Close.Props) { + return +} + +function DialogOverlay({ + className, + ...props +}: DialogPrimitive.Backdrop.Props) { + return ( + + ) +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: DialogPrimitive.Popup.Props & { + showCloseButton?: boolean +}) { + return ( + + + + {children} + {showCloseButton && ( + + } + > + + Close + + )} + + + ) +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function DialogFooter({ + className, + showCloseButton = false, + children, + ...props +}: React.ComponentProps<"div"> & { + showCloseButton?: boolean +}) { + return ( +
+ {children} + {showCloseButton && ( + }> + Close + + )} +
+ ) +} + +function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) { + return ( + + ) +} + +function DialogDescription({ + className, + ...props +}: DialogPrimitive.Description.Props) { + return ( + + ) +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +} diff --git a/examples/react/calendar/src/components/ui/input.tsx b/examples/react/calendar/src/components/ui/input.tsx new file mode 100644 index 00000000..7d21babb --- /dev/null +++ b/examples/react/calendar/src/components/ui/input.tsx @@ -0,0 +1,20 @@ +import * as React from "react" +import { Input as InputPrimitive } from "@base-ui/react/input" + +import { cn } from "@/lib/utils" + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ) +} + +export { Input } diff --git a/examples/react/calendar/src/components/ui/label.tsx b/examples/react/calendar/src/components/ui/label.tsx new file mode 100644 index 00000000..74da65c3 --- /dev/null +++ b/examples/react/calendar/src/components/ui/label.tsx @@ -0,0 +1,20 @@ +"use client" + +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Label({ className, ...props }: React.ComponentProps<"label">) { + return ( +
@@ -787,82 +781,64 @@ function CalendarView() {

- + - + - + - +
- - - +
@@ -959,14 +935,15 @@ function CalendarView() {
{day.events.map((event) => ( -
openEditModal(event)} > {event.title} -
+ ))}
@@ -978,7 +955,7 @@ function CalendarView() { )} {calendar.isPending && ( -
+
Loading...
)} diff --git a/examples/react/calendar/tailwind.config.js b/examples/react/calendar/tailwind.config.js index 7141e452..0779e02a 100644 --- a/examples/react/calendar/tailwind.config.js +++ b/examples/react/calendar/tailwind.config.js @@ -1,8 +1,54 @@ /** @type {import('tailwindcss').Config} */ export default { + darkMode: ['class'], content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], theme: { - extend: {}, + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', + }, + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + fontFamily: { + sans: ['var(--font-sans)', 'system-ui', 'sans-serif'], + heading: ['var(--font-heading)', 'system-ui', 'sans-serif'], + }, + }, }, plugins: [], } diff --git a/examples/react/calendar/tsconfig.json b/examples/react/calendar/tsconfig.json index a97ff8c1..cf59d8b6 100644 --- a/examples/react/calendar/tsconfig.json +++ b/examples/react/calendar/tsconfig.json @@ -13,7 +13,11 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"], + }, }, - "include": ["src", "vite.config.ts"] + "include": ["src", "vite.config.ts"], } diff --git a/examples/react/calendar/vite.config.ts b/examples/react/calendar/vite.config.ts index 9ffcc675..711b04a3 100644 --- a/examples/react/calendar/vite.config.ts +++ b/examples/react/calendar/vite.config.ts @@ -1,6 +1,12 @@ +import path from 'path' import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, }) diff --git a/examples/react/timeline/components.json b/examples/react/timeline/components.json new file mode 100644 index 00000000..5e8cc891 --- /dev/null +++ b/examples/react/timeline/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + } +} diff --git a/examples/react/timeline/package.json b/examples/react/timeline/package.json index 6f9effc4..e73cf202 100644 --- a/examples/react/timeline/package.json +++ b/examples/react/timeline/package.json @@ -10,13 +10,26 @@ }, "dependencies": { "@dnd-kit/react": "^0.3.2", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/react-label": "^2.1.8", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-devtools": "^0.9.5", + "@tanstack/react-query": "^5.95.2", + "@tanstack/react-query-devtools": "^5.95.2", "@tanstack/react-time": "^0.0.0", "@tanstack/react-time-devtools": "^0.0.0", "@tanstack/time": "^0.0.0", "@xyflow/react": "^12.10.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^1.8.0", "react": "^19.2.3", - "react-dom": "^19.2.3" + "react-dom": "^19.2.3", + "tailwind-merge": "^3.5.0", + "tailwindcss-animate": "^1.0.7" }, "devDependencies": { "@types/react": "^19.2.8", diff --git a/examples/react/timeline/src/components/ui/badge.tsx b/examples/react/timeline/src/components/ui/badge.tsx new file mode 100644 index 00000000..7af8af0f --- /dev/null +++ b/examples/react/timeline/src/components/ui/badge.tsx @@ -0,0 +1,43 @@ +import * as React from 'react' +import { Slot } from '@radix-ui/react-slot' +import { cva, type VariantProps } from 'class-variance-authority' + +import { cn } from '@/lib/utils' + +const badgeVariants = cva( + 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none transition-[color,box-shadow] overflow-hidden', + { + variants: { + variant: { + default: + 'border-transparent bg-primary text-primary-foreground shadow-sm', + secondary: 'border-transparent bg-secondary text-secondary-foreground', + destructive: + 'border-transparent bg-destructive text-destructive-foreground shadow-sm', + outline: 'text-foreground', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<'span'> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : 'span' + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/examples/react/timeline/src/components/ui/button.tsx b/examples/react/timeline/src/components/ui/button.tsx new file mode 100644 index 00000000..d08cc970 --- /dev/null +++ b/examples/react/timeline/src/components/ui/button.tsx @@ -0,0 +1,58 @@ +import * as React from 'react' +import { Slot } from '@radix-ui/react-slot' +import { cva, type VariantProps } from 'class-variance-authority' + +import { cn } from '@/lib/utils' + +const buttonVariants = cva( + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + default: + 'bg-primary text-primary-foreground shadow hover:bg-primary/90', + destructive: + 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90', + outline: + 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground', + secondary: + 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-9 px-4 py-2', + sm: 'h-8 rounded-md px-3 text-xs', + lg: 'h-10 rounded-md px-8', + icon: 'h-9 w-9', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +) + +export interface ButtonProps + extends + React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button' + return ( + + ) + }, +) +Button.displayName = 'Button' + +export { Button, buttonVariants } diff --git a/examples/react/timeline/src/components/ui/card.tsx b/examples/react/timeline/src/components/ui/card.tsx new file mode 100644 index 00000000..cabfbfc5 --- /dev/null +++ b/examples/react/timeline/src/components/ui/card.tsx @@ -0,0 +1,76 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/examples/react/timeline/src/components/ui/dialog.tsx b/examples/react/timeline/src/components/ui/dialog.tsx new file mode 100644 index 00000000..eaff6bab --- /dev/null +++ b/examples/react/timeline/src/components/ui/dialog.tsx @@ -0,0 +1,120 @@ +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { X } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/examples/react/timeline/src/components/ui/input.tsx b/examples/react/timeline/src/components/ui/input.tsx new file mode 100644 index 00000000..69b64fb2 --- /dev/null +++ b/examples/react/timeline/src/components/ui/input.tsx @@ -0,0 +1,22 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Input = React.forwardRef>( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" + +export { Input } diff --git a/examples/react/timeline/src/components/ui/label.tsx b/examples/react/timeline/src/components/ui/label.tsx new file mode 100644 index 00000000..841669ee --- /dev/null +++ b/examples/react/timeline/src/components/ui/label.tsx @@ -0,0 +1,24 @@ +import * as React from 'react' +import * as LabelPrimitive from '@radix-ui/react-label' +import { cva, type VariantProps } from 'class-variance-authority' + +import { cn } from '@/lib/utils' + +const labelVariants = cva( + 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70' +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/examples/react/timeline/src/components/ui/select.tsx b/examples/react/timeline/src/components/ui/select.tsx new file mode 100644 index 00000000..b24841d2 --- /dev/null +++ b/examples/react/timeline/src/components/ui/select.tsx @@ -0,0 +1,162 @@ +import * as React from 'react' +import { + CaretSortIcon, + CheckIcon, + ChevronDownIcon, + ChevronUpIcon, +} from '@radix-ui/react-icons' +import * as SelectPrimitive from '@radix-ui/react-select' + +import { cn } from '@/lib/utils' + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1', + className, + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = 'popper', ...props }, ref) => ( + + + + + {children} + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} diff --git a/examples/react/timeline/src/components/ui/tooltip.tsx b/examples/react/timeline/src/components/ui/tooltip.tsx new file mode 100644 index 00000000..a9c71baa --- /dev/null +++ b/examples/react/timeline/src/components/ui/tooltip.tsx @@ -0,0 +1,28 @@ +import * as React from "react" +import * as TooltipPrimitive from "@radix-ui/react-tooltip" + +import { cn } from "@/lib/utils" + +const TooltipProvider = TooltipPrimitive.Provider + +const Tooltip = TooltipPrimitive.Root + +const TooltipTrigger = TooltipPrimitive.Trigger + +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)) +TooltipContent.displayName = TooltipPrimitive.Content.displayName + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } diff --git a/examples/react/timeline/src/index.css b/examples/react/timeline/src/index.css index b892ad29..7e49446b 100644 --- a/examples/react/timeline/src/index.css +++ b/examples/react/timeline/src/index.css @@ -3,7 +3,117 @@ @tailwind utilities; @layer base { + :root { + --background: 0 0% 0%; + --foreground: 0 0% 98%; + --card: 0 0% 3%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + --radius: 0.5rem; + } + + .dark { + --background: 0 0% 0%; + --foreground: 0 0% 98%; + --card: 0 0% 3%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + } +} + +@layer base { + * { + border-color: hsl(var(--border)); + } body { - @apply bg-black text-neutral-200 antialiased; + background-color: hsl(var(--background)); + color: hsl(var(--foreground)); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } +} + +@layer utilities { + .bg-background { + background-color: hsl(var(--background)); + } + .text-foreground { + color: hsl(var(--foreground)); + } + .bg-card { + background-color: hsl(var(--card)); + } + .text-card-foreground { + color: hsl(var(--card-foreground)); + } + .bg-popover { + background-color: hsl(var(--popover)); + } + .text-popover-foreground { + color: hsl(var(--popover-foreground)); + } + .bg-primary { + background-color: hsl(var(--primary)); + } + .text-primary-foreground { + color: hsl(var(--primary-foreground)); + } + .bg-secondary { + background-color: hsl(var(--secondary)); + } + .text-secondary-foreground { + color: hsl(var(--secondary-foreground)); + } + .text-muted-foreground { + color: hsl(var(--muted-foreground)); + } + .bg-accent { + background-color: hsl(var(--accent)); + } + .text-accent-foreground { + color: hsl(var(--accent-foreground)); + } + .bg-destructive { + background-color: hsl(var(--destructive)); + } + .text-destructive-foreground { + color: hsl(var(--destructive-foreground)); + } + .border-border { + border-color: hsl(var(--border)); + } + .bg-input { + background-color: hsl(var(--input)); + } + .ring-ring { + --tw-ring-color: hsl(var(--ring)); } } diff --git a/examples/react/timeline/src/index.tsx b/examples/react/timeline/src/index.tsx index bc86cf07..1757487b 100644 --- a/examples/react/timeline/src/index.tsx +++ b/examples/react/timeline/src/index.tsx @@ -4,6 +4,7 @@ import { } from '@tanstack/react-time' import { TanStackDevtools } from '@tanstack/react-devtools' import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { getTimeClient, toPlainDateString, @@ -34,6 +35,9 @@ import React, { useRef, useState, } from 'react' +import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools' +import { X } from 'lucide-react' + import type { Day, Event, @@ -44,6 +48,27 @@ import type { } from '@tanstack/time' import type { Connection, Edge, Node, NodeProps } from '@xyflow/react' +import { Button } from '@/components/ui/button' +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +import { Badge } from '@/components/ui/badge' +import { Card, CardContent } from '@/components/ui/card' + import './index.css' const EVENT_COLORS = [ @@ -100,6 +125,7 @@ const resourceFrontend: Resource = { const resourceBackend: Resource = { id: 'backend', label: 'Backend', + capacity: [2, 3, 5], availability: [ { weekdays: [1, 2, 3], startTime: '10:00', endTime: '19:00' }, { weekdays: [4, 5], startTime: '00:00', endTime: '24:00' }, @@ -178,6 +204,7 @@ function getSampleEvents(): Array> { start: weekdayAt(2, 11, 0), end: weekdayAt(2, 18, 0), resources: [resourceBackend], + consumption: [3], }, { id: '4', @@ -185,6 +212,7 @@ function getSampleEvents(): Array> { start: weekdayAt(1, 11, 0), end: weekdayAt(1, 16, 0), resources: [resourceBackend], + consumption: [5], }, { id: '5', @@ -278,7 +306,9 @@ function EventModal({ }) { const [formData, setFormData] = useState(initialData) - if (!isOpen) return null + useEffect(() => { + setFormData(initialData) + }, [initialData, isOpen]) const handleSubmit = (e: React.FormEvent) => { e.preventDefault() @@ -287,137 +317,128 @@ function EventModal({ } return ( -
-
-

- {mode === 'add' ? 'Add Event' : 'Edit Event'} -

+ !open && onClose()}> + + + + {mode === 'add' ? 'Add Event' : 'Edit Event'} + + + {mode === 'add' + ? 'Create a new event on the timeline.' + : 'Make changes to your event here.'} + +
-
- - + + setFormData({ ...formData, title: e.target.value }) } - className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white placeholder-neutral-500 focus:outline-none focus:ring-1 focus:ring-neutral-600" + placeholder="Event title" required />
-
- - - setFormData({ ...formData, resourceId: e.target.value }) + onValueChange={(value) => + setFormData({ ...formData, resourceId: value }) } - className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white focus:outline-none focus:ring-1 focus:ring-neutral-600" > - {sampleResources.map((r) => ( - - ))} - + + + + + {sampleResources.map((r) => ( + + {r.label} + + ))} + +
-
- - + + setFormData({ ...formData, startDate: e.target.value }) } - className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white focus:outline-none focus:ring-1 focus:ring-neutral-600" required />
-
- - + + setFormData({ ...formData, startTime: e.target.value }) } - className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white focus:outline-none focus:ring-1 focus:ring-neutral-600" required />
-
- - + + setFormData({ ...formData, endDate: e.target.value }) } - className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white focus:outline-none focus:ring-1 focus:ring-neutral-600" required />
-
- - + + setFormData({ ...formData, endTime: e.target.value }) } - className="w-full px-3 py-2 bg-black border border-neutral-800 rounded-md text-white focus:outline-none focus:ring-1 focus:ring-neutral-600" required />
-
+
{mode === 'edit' && onDelete && ( - + )}
- - + +
-
+
-
-
+ + ) } @@ -465,48 +486,54 @@ function ResizeErrorToast({ return (
-
-
-
!
-
-
- Cannot Resize{' '} - “{error.eventTitle}” -
-
{error.message}
- {error.conflicts && error.conflicts.length > 0 && ( -
-
- Dependency conflicts: -
- {error.conflicts.map((conflict, idx) => ( -
-
- {conflict.date}{' '} - - {conflict.conflictRange.start}– - {conflict.conflictRange.end} - -
-
- {conflict.description} -
-
- ))} + + +
+
!
+
+
+ Cannot Resize{' '} + “{error.eventTitle}”
- )} +
+ {error.message} +
+ {error.conflicts && error.conflicts.length > 0 && ( +
+
+ Dependency conflicts: +
+ {error.conflicts.map((conflict, idx) => ( +
+
+ {conflict.date}{' '} + + {conflict.conflictRange.start}– + {conflict.conflictRange.end} + +
+
+ {conflict.description} +
+
+ ))} +
+ )} +
+
- -
-
+ +
) } @@ -742,9 +769,13 @@ function TimelineDependencyOverlay({ nodesDraggable={false} nodesConnectable={true} elementsSelectable={false} - preventScrolling={true} + preventScrolling={false} autoPanOnConnect={false} - style={{ background: 'transparent', overflow: 'hidden' }} + style={{ + background: 'transparent', + overflow: 'hidden', + pointerEvents: 'none', + }} proOptions={{ hideAttribution: true }} autoPanOnNodeDrag={false} /> @@ -804,7 +835,7 @@ const DraggableTimelineEvent = React.memo(function DraggableTimelineEvent({ data-event-id={event.id} data-left={left} data-width={width} - className={`group absolute border ${color.bg} ${color.border} ${color.text} flex items-center text-xs font-medium overflow-hidden shadow-sm z-10 cursor-pointer hover:brightness-110 transition-[filter] ${ + className={`group absolute border ${color.bg} ${color.border} ${color.text} flex items-center text-xs font-medium overflow-hidden shadow-sm z-30 cursor-pointer hover:brightness-110 transition-[filter] pointer-events-auto ${ isDragging ? 'opacity-40 shadow-xl z-50' : '' } ${ !isStartClipped && !isEndClipped @@ -823,7 +854,11 @@ const DraggableTimelineEvent = React.memo(function DraggableTimelineEvent({ }} title={`${event.title} (${toPlainDateString(event.start)}T${toPlainTimeString(event.start)} \u2192 ${toPlainDateString(event.end)}T${toPlainTimeString(event.end)})`} onClick={(e) => { - if (!(e.target as HTMLElement).closest('[data-resize-handle]')) { + if ( + !(e.target as HTMLElement).closest('[data-drag-handle]') && + !(e.target as HTMLElement).closest('[data-resize-handle]') + ) { + e.stopPropagation() onEventClick(event) } }} @@ -841,8 +876,23 @@ const DraggableTimelineEvent = React.memo(function DraggableTimelineEvent({ )}
+ + + + + + + + + + + +
+
{event.title}
{!isEndClipped && ( @@ -1197,6 +1247,12 @@ function TimelineDemo() { const snapShift = Math.round(hoursShift / 0.25) * 0.25 const msShift = snapShift * 3600 * 1000 + const resourceChanged = + targetData?.resource && + targetData.resource.id !== draggedEvent.resources?.[0]?.id + + if (snapShift === 0 && !resourceChanged) return + const newStart = new Date( new Date(draggedEvent.start).getTime() + msShift, ) @@ -1260,41 +1316,28 @@ function TimelineDemo() {
- - - - + +
{viewModeOptions.map((opt) => { @@ -1302,22 +1345,19 @@ function TimelineDemo() { calendar.viewMode.value === opt.value && calendar.viewMode.unit === opt.unit return ( - + ) })}
@@ -1482,48 +1522,59 @@ function TimelineDemo() {
-
+
{calendar.getEvents().map((event) => { const color = getEventColor(event.id) return ( -
+
- - {event.title} - -
+ {event.title} +
) })}
-
+
{sampleResources.map((resource, idx) => { const zoneColor = RESOURCE_ZONE_COLORS[idx % RESOURCE_ZONE_COLORS.length] ?? RESOURCE_ZONE_COLORS[0] return ( -
+
- + {resource.label} — unavailable -
+
) })}
{calendar.isPending && ( -
- Loading... +
+ + Loading... +
)} @@ -1562,11 +1613,21 @@ function TimelineDemo() { } function App() { + const queryClient = new QueryClient() + return ( - <> - + + , + }, + ]} + /> - + ) } diff --git a/examples/react/timeline/tailwind.config.js b/examples/react/timeline/tailwind.config.js index 7141e452..aca8dbbc 100644 --- a/examples/react/timeline/tailwind.config.js +++ b/examples/react/timeline/tailwind.config.js @@ -1,8 +1,50 @@ /** @type {import('tailwindcss').Config} */ export default { + darkMode: ['class'], content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], theme: { - extend: {}, + extend: { + colors: { + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))', + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))', + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))', + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))', + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))', + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))', + }, + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))', + }, + }, + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', + }, + }, }, - plugins: [], + plugins: [require('tailwindcss-animate')], } diff --git a/examples/react/timeline/tsconfig.json b/examples/react/timeline/tsconfig.json index a97ff8c1..f3dc6376 100644 --- a/examples/react/timeline/tsconfig.json +++ b/examples/react/timeline/tsconfig.json @@ -1,5 +1,9 @@ { "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"], + }, "target": "ESNext", "lib": ["DOM", "DOM.Iterable", "ESNext"], "module": "ESNext", @@ -13,7 +17,7 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, }, - "include": ["src", "vite.config.ts"] + "include": ["src", "vite.config.ts"], } diff --git a/examples/react/timeline/vite.config.ts b/examples/react/timeline/vite.config.ts index 9ffcc675..0d51f19e 100644 --- a/examples/react/timeline/vite.config.ts +++ b/examples/react/timeline/vite.config.ts @@ -1,6 +1,12 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +import path from 'path' export default defineConfig({ plugins: [react()], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, }) diff --git a/packages/react-time-devtools/package.json b/packages/react-time-devtools/package.json index cc8c2425..c408289d 100644 --- a/packages/react-time-devtools/package.json +++ b/packages/react-time-devtools/package.json @@ -48,7 +48,7 @@ "src" ], "dependencies": { - "@tanstack/devtools-utils": "^0.3.0", + "@tanstack/devtools-utils": "^0.4.0", "@tanstack/time-devtools": "workspace:*" }, "devDependencies": { diff --git a/packages/solid-time-devtools/package.json b/packages/solid-time-devtools/package.json index 98e8ecfc..420424fe 100644 --- a/packages/solid-time-devtools/package.json +++ b/packages/solid-time-devtools/package.json @@ -48,7 +48,7 @@ "src" ], "dependencies": { - "@tanstack/devtools-utils": "^0.3.0", + "@tanstack/devtools-utils": "^0.4.0", "@tanstack/time-devtools": "workspace:*" }, "devDependencies": { diff --git a/packages/time-devtools/package.json b/packages/time-devtools/package.json index 0d95b4c4..5731eaf7 100644 --- a/packages/time-devtools/package.json +++ b/packages/time-devtools/package.json @@ -48,8 +48,8 @@ "src" ], "dependencies": { - "@tanstack/devtools-ui": "^0.4.4", - "@tanstack/devtools-utils": "^0.3.0", + "@tanstack/devtools-ui": "^0.5.1", + "@tanstack/devtools-utils": "^0.4.0", "@tanstack/time": "workspace:*", "goober": "^2.1.18", "solid-js": "^1.9.10" diff --git a/packages/time-devtools/src/components/Shell.tsx b/packages/time-devtools/src/components/Shell.tsx index b9c1bc93..3438d017 100644 --- a/packages/time-devtools/src/components/Shell.tsx +++ b/packages/time-devtools/src/components/Shell.tsx @@ -1,12 +1,13 @@ -import { For, Show, createSignal } from 'solid-js' +import { For, Show, createMemo, createSignal } from 'solid-js' import { Button, Header, HeaderLogo, + Input, + JsonTree, MainPanel, - Section, - SectionTitle, Tag, + X, } from '@tanstack/devtools-ui' import { useStyles } from '../styles/use-styles' import { TimeProvider, useTimeStore } from '../store/time-context' @@ -92,11 +93,47 @@ function DevtoolsContent() { const styles = useStyles() const [activeTab, setActiveTab] = createSignal<'log' | 'events'>('log') + const [selectedId, setSelectedId] = createSignal(null) + const [search, setSearch] = createSignal('') + + const filteredLog = createMemo(() => { + const s = search().toLowerCase() + return state.activityLog.filter((entry) => { + if (!s) return true + return ( + entry.type.toLowerCase().includes(s) || + getEventDescription(entry).toLowerCase().includes(s) + ) + }) + }) + + const filteredEvents = createMemo(() => { + const s = search().toLowerCase() + return (Object.values(state.events).filter(Boolean) as Array).filter( + (event) => { + if (!s) return true + return ( + event.title.toLowerCase().includes(s) || + event.id.toLowerCase().includes(s) + ) + }, + ) + }) + + const selectedEntry = createMemo(() => { + const id = selectedId() + if (!id) return null + if (activeTab() === 'log') { + return state.activityLog.find((e) => e.id === id) + } + return state.events[id] + }) + return ( - +
- TanStack Time + TanStack Time v0
setActiveTab('log')} variant="primary"> + } > - + setActiveTab('events')} variant="primary"> - Current Events + } > - +
@@ -135,29 +202,40 @@ function DevtoolsContent() {
- -
-
- Activity Log - +
+
+
+ setSearch(val)} + />
- 0} - fallback={ -
- No activity yet. Start interacting with the calendar! +
+ +
+ + {filteredLog().length} Entries + +
- } - > -
- + No activity found.
+ } + > {(entry) => { const label = getEventTypeLabel(entry.type) return ( -
+
setSelectedId(entry.id)} + > {formatTime(entry.timestamp)} @@ -169,63 +247,142 @@ function DevtoolsContent() { ) }} -
- -
-
- - -
-
- - Loaded Events ({Object.keys(state.events).length}) - + + + +
+ + {filteredEvents().length} Events + +
+ No events found.
+ } + > + {(event) => ( +
setSelectedId(event.id)} + > +
+
{event.title}
+
+ {event.start.split('T')[0]} → {event.end.split('T')[0]} +
+
+
+ )} + +
+
+ + {/* Details Panel */} +
0} + when={selectedEntry()} fallback={
- No events currently loaded into the calendar scope. + Select an item to view details
} > -
- - {(event) => ( + {(entry) => ( + <> +
-
{event.title}
+ + + + + {activeTab() === 'log' + ? (entry() as ActivityLogEntry).type + : (entry() as any).title} + +
+ +
+
+
- {event.start} → {event.end} + Raw Data
+
+ +
+
+ +
- ID: {event.id} + Metadata
-
- )} -
-
+
+ +
+
+
+ + )} - - +
+
) } diff --git a/packages/time-devtools/src/components/ThemedShell.tsx b/packages/time-devtools/src/components/ThemedShell.tsx new file mode 100644 index 00000000..cd4c31ae --- /dev/null +++ b/packages/time-devtools/src/components/ThemedShell.tsx @@ -0,0 +1,11 @@ +import { ThemeContextProvider } from '@tanstack/devtools-ui' +import type { TanStackDevtoolsPluginProps } from '@tanstack/devtools' +import Shell from './Shell' + +export default function ThemedShell(props: TanStackDevtoolsPluginProps) { + return ( + + + + ) +} diff --git a/packages/time-devtools/src/core.tsx b/packages/time-devtools/src/core.tsx index e780280c..72aa0751 100644 --- a/packages/time-devtools/src/core.tsx +++ b/packages/time-devtools/src/core.tsx @@ -1,10 +1,9 @@ -import { lazy } from 'solid-js' import { constructCoreClass } from '@tanstack/devtools-utils/solid' -const Component = lazy(() => import('./components/Shell')) +const [TimeDevtoolsCore, TimeDevtoolsCoreNoOp] = constructCoreClass( + () => import('./components/ThemedShell'), +) export interface TimeDevtoolsInit {} -const [TimeDevtoolsCore, TimeDevtoolsCoreNoOp] = constructCoreClass(Component) - export { TimeDevtoolsCore, TimeDevtoolsCoreNoOp } diff --git a/packages/time-devtools/src/styles/use-styles.ts b/packages/time-devtools/src/styles/use-styles.ts index b3c6e881..6fe6a137 100644 --- a/packages/time-devtools/src/styles/use-styles.ts +++ b/packages/time-devtools/src/styles/use-styles.ts @@ -24,7 +24,9 @@ const stylesFactory = () => { display: flex; justify-content: space-between; align-items: center; - margin-bottom: 12px; + padding: 8px 12px; + border-bottom: 1px solid #374151; + background-color: #111827; `, emptyState: css` @@ -34,29 +36,79 @@ const stylesFactory = () => { font-size: 13px; `, - activityList: css` + container: css` + display: flex; + flex-direction: row; + height: 100%; + overflow: hidden; + flex: 1; + background-color: #0b0f1a; + `, + + shellRoot: css` + height: var(--tsd-main-panel-height) !important; + overflow-y: hidden !important; + `, + + sidebar: css` display: flex; flex-direction: column; - gap: 8px; - max-height: 300px; + width: 320px; + min-width: 250px; + border-right: 1px solid #1f2937; + height: 100%; + background-color: #111827; + `, + + details: css` + flex: 1; + display: flex; + flex-direction: column; + height: 100%; + min-height: 0; overflow-y: auto; + background-color: #0b0f1a; + `, + + searchArea: css` + padding: 8px; + border-bottom: 1px solid #1f2937; + background-color: #111827; `, - activityEntry: css` + list: css` + flex: 1; + overflow-y: auto; + display: flex; + flex-direction: column; + `, + + listItem: css` display: flex; align-items: center; - gap: 10px; - padding: 8px 10px; - background-color: #1f2937; - border-radius: 6px; + gap: 8px; + padding: 8px 12px; + border-bottom: 1px solid #1f2937; + cursor: pointer; font-size: 12px; + transition: background-color 0.2s; + user-select: none; + + &:hover { + background-color: #1f2937; + } + + &.active { + background-color: #374151; + border-left: 3px solid #9dec48; + } `, timestamp: css` font-family: monospace; color: #9ca3af; - font-size: 11px; - min-width: 70px; + font-size: 10px; + white-space: nowrap; `, description: css` @@ -66,6 +118,30 @@ const stylesFactory = () => { text-overflow: ellipsis; white-space: nowrap; `, + + detailsHeader: css` + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px; + border-bottom: 1px solid #1f2937; + background-color: #111827; + `, + + detailsContent: css` + flex: 1; + overflow-y: auto; + padding: 12px; + font-size: 12px; + `, + + jsonTreeContainer: css` + background-color: #111827; + padding: 12px; + border-radius: 8px; + margin-top: 12px; + border: 1px solid #1f2937; + `, } } diff --git a/packages/time/src/calendar/calendar.ts b/packages/time/src/calendar/calendar.ts index e2781822..c93e783a 100644 --- a/packages/time/src/calendar/calendar.ts +++ b/packages/time/src/calendar/calendar.ts @@ -1669,7 +1669,8 @@ export class CalendarCore< for (const resourceId of resourceIds) { const resource = this.options.resources?.find((r) => r.id === resourceId) - if (!resource || !resource.capacity) continue + if (!resource || !resource.capacity || resource.capacity.length === 0) + continue const getOverlappingEvents = ( checkStartMins: number, @@ -1696,11 +1697,23 @@ export class CalendarCore< origEndMins, ) - const currentUsage = overlappingEvents.length - const previousUsage = previouslyOverlapping.length - const maxCapacity = resource.capacity + const getSum = (events: Array) => + events.reduce((acc, e) => { + const f = e.consumption || [1] + return acc + f.reduce((a, b) => a + b, 0) + }, 0) + + const currentUsage = getSum(overlappingEvents) + const previousUsage = getSum(previouslyOverlapping) + const resourceCapacitySum = resource.capacity.reduce( + (a, b) => a + b, + 0, + ) - if (currentUsage > previousUsage && currentUsage >= maxCapacity) { + if ( + currentUsage > previousUsage && + currentUsage >= resourceCapacitySum + ) { conflicts.push({ date: dayDate, conflictRange: { @@ -1713,15 +1726,15 @@ export class CalendarCore< resourceId: resource.id, resourceLabel: resource.label, reason: 'capacity', - description: `${resource.label}: Capacity exceeded (${currentUsage}/${maxCapacity} slots used)`, + description: `${resource.label}: Capacity exceeded (${currentUsage}/${resourceCapacitySum} units used)`, capacityInfo: { - max: maxCapacity, + max: resourceCapacitySum, used: currentUsage, remaining: 0, }, }, ], - description: `${resource.label}: Capacity exceeded (${currentUsage}/${maxCapacity} slots used)`, + description: `${resource.label}: Capacity exceeded (${currentUsage}/${resourceCapacitySum} units used)`, }) } } diff --git a/packages/time/src/calendar/tests/calendar.test.ts b/packages/time/src/calendar/tests/calendar.test.ts index 28bf702f..4a335a41 100644 --- a/packages/time/src/calendar/tests/calendar.test.ts +++ b/packages/time/src/calendar/tests/calendar.test.ts @@ -21,7 +21,7 @@ function createCalendar( const weekdayResource: TestResource = { id: 'r1', label: 'Weekday Room', - capacity: 2, + capacity: [2], availability: [ { weekdays: [1, 2, 3, 4, 5], startTime: '08:00', endTime: '17:00' }, ], @@ -30,7 +30,7 @@ const weekdayResource: TestResource = { const afternoonResource: TestResource = { id: 'r2', label: 'Afternoon Room', - capacity: 1, + capacity: [1], availability: [ { weekdays: [1, 2, 3, 4, 5], startTime: '12:00', endTime: '18:00' }, ], @@ -789,7 +789,7 @@ describe('CalendarCore', () => { const resource: TestResource = { id: 'cap1', label: 'Cap Room', - capacity: 1, + capacity: [1], availability: [ { weekdays: [1, 2, 3, 4, 5], startTime: '08:00', endTime: '17:00' }, ], @@ -832,7 +832,7 @@ describe('CalendarCore', () => { const resource: TestResource = { id: 'cap1', label: 'Cap Room', - capacity: 1, + capacity: [1], availability: [ { weekdays: [1, 2, 3, 4, 5], startTime: '08:00', endTime: '17:00' }, ], @@ -887,7 +887,7 @@ describe('CalendarCore', () => { const resource: TestResource = { id: 'cap2', label: 'Big Room', - capacity: 3, + capacity: [3], availability: [ { weekdays: [1, 2, 3, 4, 5], startTime: '08:00', endTime: '17:00' }, ], diff --git a/packages/time/src/calendar/types.ts b/packages/time/src/calendar/types.ts index 183ef87d..327047ef 100644 --- a/packages/time/src/calendar/types.ts +++ b/packages/time/src/calendar/types.ts @@ -16,13 +16,11 @@ export interface Resource { id: string label: string availability?: Array - capacity?: number + capacity?: Array buffer?: { before?: number after?: number } - - // fractions: Array } /** @@ -42,7 +40,7 @@ export interface Event { end: EventDateTimeInput title: string resources?: Array - fractions?: Array + consumption?: Array /** IDs of events this event immediately follows (finish-to-start dependency). * When a predecessor's end time shifts, this event shifts by the same delta. */ dependsOn?: Array diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fa467e9c..fa72260e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -77,13 +77,19 @@ importers: version: 5.9.3 vitest: specifier: ^4.0.17 - version: 4.0.18(@types/node@25.2.2)(happy-dom@20.5.3)(jiti@2.6.1)(yaml@2.8.2) + version: 4.0.18(@types/node@25.2.2)(happy-dom@20.5.3)(jiti@2.6.1)(msw@2.13.2(@types/node@25.2.2)(typescript@5.9.3))(yaml@2.8.2) examples/react/calendar: dependencies: + '@base-ui/react': + specifier: ^1.3.0 + version: 1.3.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fontsource-variable/geist': + specifier: ^5.2.8 + version: 5.2.8 '@tanstack/react-devtools': specifier: ^0.9.5 - version: 0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) + version: 0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.12) '@tanstack/react-time': specifier: ^0.0.0 version: link:../../../packages/react-time @@ -93,12 +99,30 @@ importers: '@tanstack/time': specifier: ^0.0.0 version: link:../../../packages/time + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-react: + specifier: ^1.8.0 + version: 1.8.0(react@19.2.4) react: specifier: ^19.2.3 version: 19.2.4 react-dom: specifier: ^19.2.3 version: 19.2.4(react@19.2.4) + shadcn: + specifier: ^4.2.0 + version: 4.2.0(@types/node@25.2.2)(typescript@5.9.3) + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 devDependencies: '@types/react': specifier: ^19.2.8 @@ -130,9 +154,33 @@ importers: '@dnd-kit/react': specifier: ^0.3.2 version: 0.3.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-icons': + specifier: ^1.3.2 + version: 1.3.2(react@19.2.4) + '@radix-ui/react-label': + specifier: ^2.1.8 + version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-select': + specifier: ^2.2.6 + version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': + specifier: ^1.2.4 + version: 1.2.4(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-tooltip': + specifier: ^1.2.8 + version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@tanstack/react-devtools': specifier: ^0.9.5 - version: 0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11) + version: 0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.12) + '@tanstack/react-query': + specifier: ^5.95.2 + version: 5.95.2(react@19.2.4) + '@tanstack/react-query-devtools': + specifier: ^5.95.2 + version: 5.95.2(@tanstack/react-query@5.95.2(react@19.2.4))(react@19.2.4) '@tanstack/react-time': specifier: ^0.0.0 version: link:../../../packages/react-time @@ -145,12 +193,27 @@ importers: '@xyflow/react': specifier: ^12.10.1 version: 12.10.1(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-react: + specifier: ^1.8.0 + version: 1.8.0(react@19.2.4) react: specifier: ^19.2.3 version: 19.2.4 react-dom: specifier: ^19.2.3 version: 19.2.4(react@19.2.4) + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.19(yaml@2.8.2)) devDependencies: '@types/react': specifier: ^19.2.8 @@ -214,8 +277,8 @@ importers: packages/react-time-devtools: dependencies: '@tanstack/devtools-utils': - specifier: ^0.3.0 - version: 0.3.0(@types/react@19.2.13)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) + specifier: ^0.4.0 + version: 0.4.0(@types/react@19.2.13)(react@19.2.4)(solid-js@1.9.11) '@tanstack/time-devtools': specifier: workspace:* version: link:../time-devtools @@ -267,8 +330,8 @@ importers: packages/solid-time-devtools: dependencies: '@tanstack/devtools-utils': - specifier: ^0.3.0 - version: 0.3.0(@types/react@19.2.13)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) + specifier: ^0.4.0 + version: 0.4.0(@types/react@19.2.13)(react@19.2.4)(solid-js@1.9.11) '@tanstack/time-devtools': specifier: workspace:* version: link:../time-devtools @@ -292,11 +355,11 @@ importers: packages/time-devtools: dependencies: '@tanstack/devtools-ui': - specifier: ^0.4.4 - version: 0.4.4(csstype@3.2.3)(solid-js@1.9.11) + specifier: ^0.5.1 + version: 0.5.1(csstype@3.2.3)(solid-js@1.9.11) '@tanstack/devtools-utils': - specifier: ^0.3.0 - version: 0.3.0(@types/react@19.2.13)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11) + specifier: ^0.4.0 + version: 0.4.0(@types/react@19.2.13)(react@19.2.4)(solid-js@1.9.11) '@tanstack/time': specifier: workspace:* version: link:../time @@ -476,6 +539,27 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@base-ui/react@1.3.0': + resolution: {integrity: sha512-FwpKqZbPz14AITp1CVgf4AjhKPe1OeeVKSBMdgD10zbFlj3QSWelmtCMLi2+/PFZZcIm3l87G7rwtCZJwHyXWA==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + + '@base-ui/utils@0.2.6': + resolution: {integrity: sha512-yQ+qeuqohwhsNpoYDqqXaLllYAkPCP4vYdDrVo8FQXaAPfHWm1pG/Vm+jmGTA5JFS0BAIjookyapuJFY8F9PIw==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + '@changesets/apply-release-plan@7.0.14': resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} @@ -555,6 +639,16 @@ packages: '@dnd-kit/state@0.3.2': resolution: {integrity: sha512-dLUIkoYrIJhGXfF2wGLTfb46vUokEsO/OoE21TSfmahYrx7ysTmnwbePsznFaHlwgZhQEh6AlLvthLCeY21b1A==} + '@dotenvx/dotenvx@1.61.0': + resolution: {integrity: sha512-utL3cpZoFzflyqUkjYbxYujI6STBTmO5LFn4bbin/NZnRWN6wQ7eErhr3/Vpa5h/jicPFC6kTa42r940mQftJQ==} + hasBin: true + + '@ecies/ciphers@0.2.6': + resolution: {integrity: sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g==} + engines: {bun: '>=1', deno: '>=2.7.10', node: '>=16'} + peerDependencies: + '@noble/ciphers': ^1.0.0 + '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} @@ -801,9 +895,33 @@ packages: resolution: {integrity: sha512-It0Sne6P3szg7JIi6CgKbvTZoMjxBZhcv91ZrqrNuaZQfB5WoqYYbzCUOq89YR+VY8juY9M1vDWmDDa2TzfXCw==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@fontsource-variable/geist@5.2.8': + resolution: {integrity: sha512-cJ6m9e+8MQ5dCYJsLylfZrgBh6KkG4bOLckB35Tr9J/EqdkEM6QllH5PxqP1dhTvFup+HtMRPuz9xOjxXJggxw==} + '@gerrit0/mini-shiki@3.22.0': resolution: {integrity: sha512-jMpciqEVUBKE1QwU64S4saNMzpsSza6diNCk4MWAeCxO2+LFi2FIFmL2S0VDLzEJCxuvCbU783xi8Hp/gkM5CQ==} + '@hono/node-server@1.19.13': + resolution: {integrity: sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -820,6 +938,28 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + '@inquirer/external-editor@1.0.3': resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} engines: {node: '>=18'} @@ -829,6 +969,19 @@ packages: '@types/node': optional: true + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} @@ -875,6 +1028,20 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@mswjs/interceptors@0.41.3': + resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} + engines: {node: '>=18'} + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -884,6 +1051,18 @@ packages: '@napi-rs/wasm-runtime@1.1.1': resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -946,6 +1125,15 @@ packages: cpu: [x64] os: [win32] + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@oxc-project/types@0.107.0': resolution: {integrity: sha512-QFDRbYfV2LVx8tyqtyiah3jQPUj1mK2+RYwxyFWyGoys6XJnwTdlzO6rdNNHOPorHAu5Uo34oWRKcvNpbJarmQ==} @@ -1062,6 +1250,337 @@ packages: '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-icons@1.3.2': + resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} + peerDependencies: + react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.8': + resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.4': + resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.6': + resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.2.4': + resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-tooltip@1.2.8': + resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rolldown/binding-android-arm64@1.0.0-beta.59': resolution: {integrity: sha512-6yLLgyswYwiCfls9+hoNFY9F8TQdwo15hpXDHzlAR0X/GojeKF+AuNcXjYNbOJ4zjl/5D6lliE8CbpB5t1OWIQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1350,6 +1869,9 @@ packages: cpu: [x64] os: [win32] + '@sec-ant/readable-stream@0.4.1': + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@shikijs/engine-oniguruma@3.22.0': resolution: {integrity: sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==} @@ -1368,6 +1890,10 @@ packages: '@sinclair/typebox@0.34.48': resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + '@solid-primitives/event-listener@2.4.3': resolution: {integrity: sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg==} peerDependencies: @@ -1434,9 +1960,16 @@ packages: peerDependencies: solid-js: '>=1.9.7' - '@tanstack/devtools-utils@0.3.0': - resolution: {integrity: sha512-JgApXVrgtgSLIPrm/QWHx0u6c9Ji0MNMDWhwujapj8eMzux5aOfi+2Ycwzj0A0qITXA12SEPYV3HC568mDtYmQ==} + '@tanstack/devtools-ui@0.5.1': + resolution: {integrity: sha512-T9JjAdqMSnxsVO6AQykD5vhxPF4iFLKtbYxee/bU3OLlk446F5C1220GdCmhDSz7y4lx+m8AvIS0bq6zzvdDUA==} + engines: {node: '>=18'} + peerDependencies: + solid-js: '>=1.9.7' + + '@tanstack/devtools-utils@0.4.0': + resolution: {integrity: sha512-KsGzYhA8L/fCNgyyMyoUy+TKtx+DjNbzWwqH6wXL48Llzo7kvV9RynYJlaO8Qkzwm+NdHXSgsljQNjQ3CKPpZA==} engines: {node: '>=18'} + hasBin: true peerDependencies: '@types/react': '>=17.0.0' preact: '>=10.0.0' @@ -1467,6 +2000,12 @@ packages: peerDependencies: eslint: ^8.0.0 || ^9.0.0 + '@tanstack/query-core@5.95.2': + resolution: {integrity: sha512-o4T8vZHZET4Bib3jZ/tCW9/7080urD4c+0/AUaYVpIqOsr7y0reBc1oX3ttNaSW5mYyvZHctiQ/UOP2PfdmFEQ==} + + '@tanstack/query-devtools@5.95.2': + resolution: {integrity: sha512-QfaoqBn9uAZ+ICkA8brd1EHj+qBF6glCFgt94U8XP5BT6ppSsDBI8IJ00BU+cAGjQzp6wcKJL2EmRYvxy0TWIg==} + '@tanstack/react-devtools@0.9.5': resolution: {integrity: sha512-/YsSSobbWfSZ0khLZ5n4cz/isa8Ac21PAVdgrX0qOEkPkS6J63JTEgFR0Ch2n2ka511dm2pIEuTvCsL7WVu1XQ==} engines: {node: '>=18'} @@ -1476,10 +2015,21 @@ packages: react: '>=16.8' react-dom: '>=16.8' - '@tanstack/react-store@0.8.0': - resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + '@tanstack/react-query-devtools@5.95.2': + resolution: {integrity: sha512-AFQFmbznVkbtfpx8VJ2DylW17wWagQel/qLstVLkYmNRo2CmJt3SNej5hvl6EnEeljJIdC3BTB+W7HZtpsH+3g==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/react-query': ^5.95.2 + react: ^18 || ^19 + + '@tanstack/react-query@5.95.2': + resolution: {integrity: sha512-/wGkvLj/st5Ud1Q76KF1uFxScV7WeqN1slQx5280ycwAyYkIPGaRZAEgHxe3bjirSd5Zpwkj6zNcR4cqYni/ZA==} + peerDependencies: + react: ^18 || ^19 + + '@tanstack/react-store@0.8.0': + resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@tanstack/solid-store@0.8.0': @@ -1517,6 +2067,9 @@ packages: '@types/react-dom': optional: true + '@ts-morph/common@0.27.0': + resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -1585,9 +2138,15 @@ packages: '@types/react@19.2.13': resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} + '@types/statuses@2.0.6': + resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/validate-npm-package-name@4.0.2': + resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} + '@types/whatwg-mimetype@3.0.2': resolution: {integrity: sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==} @@ -1803,6 +2362,10 @@ packages: resolution: {integrity: sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==} hasBin: true + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1813,9 +2376,24 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -1824,6 +2402,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -1852,6 +2434,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -1871,6 +2457,10 @@ packages: resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==} engines: {node: '>=20.19.0'} + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1929,6 +2519,10 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -1950,6 +2544,14 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -1958,6 +2560,10 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -1977,6 +2583,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} @@ -1995,6 +2605,9 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + classcat@5.0.5: resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} @@ -2002,10 +2615,22 @@ packages: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + cli-spinners@2.6.1: resolution: {integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==} engines: {node: '>=6'} + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -2018,6 +2643,9 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + code-block-writer@13.0.3: + resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -2029,6 +2657,14 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -2043,9 +2679,42 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + cosmiconfig@9.0.1: + resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2106,9 +2775,16 @@ packages: resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} engines: {node: '>=12'} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -2118,9 +2794,29 @@ packages: supports-color: optional: true + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -2128,6 +2824,10 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} @@ -2135,6 +2835,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2143,12 +2847,19 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + devalue@5.6.2: resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2187,6 +2898,10 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} + dotenv@17.4.1: + resolution: {integrity: sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==} + engines: {node: '>=12'} + dts-resolver@2.1.3: resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==} engines: {node: '>=20.19.0'} @@ -2200,9 +2915,19 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + eciesjs@0.4.18: + resolution: {integrity: sha512-wG99Zcfcys9fZux7Cft8BAX/YrOJLJSZ3jyYPfhZHqN2E+Ffx+QXBDsv3gubEgPtV6dTzJMSQUwk1H98/t/0wQ==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + electron-to-chromium@1.5.286: resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2210,6 +2935,10 @@ packages: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + encoding-sniffer@0.2.1: resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} @@ -2240,6 +2969,13 @@ packages: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -2268,6 +3004,9 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -2435,10 +3174,40 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + execa@9.6.1: + resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} + engines: {node: ^18.19.0 || >=20.5.0} + expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + express-rate-limit@8.3.2: + resolution: {integrity: sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -2455,6 +3224,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -2470,10 +3242,18 @@ packages: picomatch: optional: true + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} + figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2482,6 +3262,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -2519,15 +3303,31 @@ packages: engines: {node: '>=18.3.0'} hasBin: true + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + front-matter@4.0.2: resolution: {integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==} fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs-extra@11.3.4: + resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} + engines: {node: '>=14.14'} + fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -2544,6 +3344,9 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + fuzzysort@3.1.0: + resolution: {integrity: sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -2552,14 +3355,34 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-own-enumerable-keys@1.0.0: + resolution: {integrity: sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==} + engines: {node: '>=14.16'} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + get-tsconfig@4.13.6: resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} @@ -2602,6 +3425,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphql@16.13.2: + resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + happy-dom@20.5.3: resolution: {integrity: sha512-xqAxGnkRU0KNhheHpxb3uScqg/aehqUiVto/a9ApWMyNvnH9CAqHYq9dEPAovM6bOGbLstmTfGIln5ZIezEU0g==} engines: {node: '>=20.0.0'} @@ -2622,12 +3449,19 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hono@4.12.12: + resolution: {integrity: sha512-p1JfQMKaceuCbpJKAPKVqyqviZdS0eUxH9v82oWo1kb9xjQ5wA6iP3FNVAPDFlz5/p7d45lO+BpSk1tuSZMF4Q==} + engines: {node: '>=16.9.0'} + hookable@6.0.1: resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} @@ -2640,10 +3474,26 @@ packages: htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-id@4.1.3: resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} hasBin: true + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + human-signals@8.0.1: + resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} + engines: {node: '>=18.18.0'} + iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -2682,6 +3532,17 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -2695,6 +3556,11 @@ packages: engines: {node: '>=8'} hasBin: true + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2713,17 +3579,56 @@ packages: eslint: '*' typescript: '>=4.7.4' + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-obj@3.0.0: + resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==} + engines: {node: '>=12'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + is-regexp@3.1.0: + resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} + engines: {node: '>=12'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} @@ -2732,6 +3637,14 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-what@4.1.16: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} @@ -2744,9 +3657,17 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} + jest-diff@30.2.0: resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -2759,6 +3680,9 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jose@6.2.2: + resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2781,9 +3705,18 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -2798,9 +3731,20 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + knip@5.83.1: resolution: {integrity: sha512-av3ZG/Nui6S/BNL8Tmj12yGxYfTnwWnslouW97m40him7o8MwiMjZBY9TPvlEWUci45aVId0/HbgTwSKIDGpMw==} engines: {node: '>=18.18.0'} @@ -2848,9 +3792,18 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@1.8.0: + resolution: {integrity: sha512-WuvlsjngSk7TnTBJ1hsCy3ql9V9VOdcPkd3PKcSmM34vJD8KG6molxz7m7zbYFgICwsanQWmJ13JlYs4Zp7Arw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + lunr@2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} @@ -2880,10 +3833,21 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + merge-anything@5.1.7: resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} engines: {node: '>=12.13'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -2896,14 +3860,26 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -2933,6 +3909,20 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msw@2.13.2: + resolution: {integrity: sha512-go2H1TIERKkC48pXiwec5l6sbNqYuvqOk3/vHGo1Zd+pq/H63oFawDQerH+WQdUw/flJFHDG7F+QdWMwhntA/A==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: '>= 4.8.x' + peerDependenciesMeta: + typescript: + optional: true + + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -2949,6 +3939,15 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -2958,6 +3957,10 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-machine-id@1.1.12: resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} @@ -2972,6 +3975,10 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + npm-run-path@6.0.0: + resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} + engines: {node: '>=18'} + nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} @@ -2995,9 +4002,21 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-treeify@1.1.33: + resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} + engines: {node: '>= 10'} + obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -3005,6 +4024,14 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} + open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -3017,9 +4044,16 @@ packages: resolution: {integrity: sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==} engines: {node: '>=10'} + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} + outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + oxc-resolver@11.17.1: resolution: {integrity: sha512-pyRXK9kH81zKlirHufkFhOFBZRks8iAMLwPH8gU7lvKFiuzUH9L8MxDEllazwOb8fjXMcWjY1PMDfMJ2/yh5cw==} @@ -3061,6 +4095,14 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + parse5-htmlparser2-tree-adapter@7.1.0: resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} @@ -3070,6 +4112,13 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -3078,9 +4127,19 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -3111,6 +4170,10 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -3151,6 +4214,10 @@ packages: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -3158,6 +4225,10 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -3191,6 +4262,18 @@ packages: resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + engines: {node: '>=18'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -3207,6 +4290,10 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.15.1: + resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} + engines: {node: '>=0.6'} + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} @@ -3216,6 +4303,14 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + react-dom@19.2.4: resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: @@ -3231,14 +4326,44 @@ packages: resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} engines: {node: '>=0.10.0'} - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} - engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - read-yaml-file@1.1.0: + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} @@ -3250,6 +4375,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} + redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -3258,6 +4387,13 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -3282,6 +4418,13 @@ packages: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + rettime@0.10.1: + resolution: {integrity: sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -3327,6 +4470,14 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -3352,6 +4503,10 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + seroval-plugins@1.5.0: resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==} engines: {node: '>=10'} @@ -3362,6 +4517,17 @@ packages: resolution: {integrity: sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw==} engines: {node: '>=10'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shadcn@4.2.0: + resolution: {integrity: sha512-ZDuV340itidaUd4Gi1BxQX+Y7Ush6BHp6URZBM2RyxUUBZ6yFtOWIr4nVY+Ro+YRSpo82v7JrsmtcU5xoBCMJQ==} + hasBin: true + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -3414,6 +4580,22 @@ packages: resolution: {integrity: sha512-DHg6+Pj7ORhYyC+CaSAr8DeRxqf9GXB90yqLmUILPtY7WhZuJatMir3id2MNjuF5I/1313SbrTTItIDu//G4jg==} hasBin: true + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -3424,6 +4606,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -3435,6 +4620,9 @@ packages: solid-js@1.9.11: resolution: {integrity: sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q==} + solid-js@1.9.12: + resolution: {integrity: sha512-QzKaSJq2/iDrWR1As6MHZQ8fQkdOBf8GReYb7L5iKwMGceg7HxDcaOHk0at66tNgn9U2U7dXo8ZZpLIAmGMzgw==} + solid-refresh@0.6.3: resolution: {integrity: sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==} peerDependencies: @@ -3444,6 +4632,10 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} @@ -3457,9 +4649,20 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + string-ts@2.3.1: resolution: {integrity: sha512-xSJq+BS52SaFFAVxuStmx6n5aYZU571uYUnUrPXkPFCfdHyZMMlbP2v2Wx5sNBnAVzq/2+0+mcBLBa3Xa5ubYw==} @@ -3467,17 +4670,37 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + stringify-object@5.0.0: + resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} + engines: {node: '>=14.16'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -3507,6 +4730,21 @@ packages: resolution: {integrity: sha512-FR9kTLmX5i0oyeQ5j/+w8DuagIkQ7MWMuPpPVioW2zx9Dw77q+1ufLzF1IqNtcTXPRnIIio4PlasliVn43OnbQ==} engines: {node: '>=18'} + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + + tailwind-merge@3.5.0: + resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + tailwindcss@3.4.19: resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} engines: {node: '>=14.0.0'} @@ -3531,6 +4769,9 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -3546,6 +4787,13 @@ packages: resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} + tldts-core@7.0.28: + resolution: {integrity: sha512-7W5Efjhsc3chVdFhqtaU0KtK32J37Zcr9RKtID54nG+tIpcY79CQK/veYPODxtD/LJ4Lue66jvrQzIX2Z2/pUQ==} + + tldts@7.0.28: + resolution: {integrity: sha512-+Zg3vWhRUv8B1maGSTFdev9mjoo8Etn2Ayfs4cnjlD3CsGkxXX4QyW3j2WJ0wdjYcYmy7Lx2RDsZMhgCWafKIw==} + hasBin: true + tmp@0.2.5: resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} engines: {node: '>=14.14'} @@ -3554,6 +4802,14 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + engines: {node: '>=16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -3575,6 +4831,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-morph@26.0.0: + resolution: {integrity: sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==} + ts-pattern@5.9.0: resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} @@ -3610,10 +4869,21 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@5.5.0: + resolution: {integrity: sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==} + engines: {node: '>=20'} + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typedoc-plugin-frontmatter@1.3.0: resolution: {integrity: sha512-xYQFMAecMlsRUjmf9oM/Sq2FVz4zlgcbIeVFNLdO118CHTN06gIKJNSlyExh9+Xl8sK0YhIvoQwViUURxritWA==} peerDependencies: @@ -3657,10 +4927,22 @@ packages: resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==} engines: {node: '>=20.18.1'} + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} @@ -3674,6 +4956,9 @@ packages: synckit: optional: true + until-async@3.0.2: + resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -3683,6 +4968,26 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: @@ -3691,6 +4996,14 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + validate-npm-package-name@7.0.2: + resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} + engines: {node: ^20.17.0 || >=22.9.0} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + vite-plugin-solid@2.11.10: resolution: {integrity: sha512-Yr1dQybmtDtDAHkii6hXuc1oVH9CPcS/Zb2jN/P36qqcrkNnVPsMTzQ06jyzFPFjj3U1IYKMVt/9ZqcwGCEbjw==} peerDependencies: @@ -3796,6 +5109,10 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -3820,6 +5137,11 @@ packages: engines: {node: '>= 8'} hasBin: true + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -3829,6 +5151,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -3848,6 +5174,10 @@ packages: utf-8-validate: optional: true + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -3872,9 +5202,26 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-spinner@1.1.0: + resolution: {integrity: sha512-/BY0AUXnS7IKO354uLLA2eRcWiqDifEbd6unXCsOxkFDAkhgUL3PH9X2bFoaU0YchnDXsF+iKleeTLJGckbXfA==} + engines: {node: '>=18.19'} + + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} + + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + zimmerframe@1.1.4: resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + zod-validation-error@3.5.4: resolution: {integrity: sha512-+hEiRIiPobgyuFlEojnqjJnhFvg4r/i3cqgcm67eehZf/WBaK3g6cD02YU9mtdVxZjv8CzCA9n/Rhrs3yAAvAw==} engines: {node: '>=18.0.0'} @@ -4124,6 +5471,30 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@base-ui/react@1.3.0(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@base-ui/utils': 0.2.6(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tabbable: 6.4.0 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + + '@base-ui/utils@0.2.6(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@babel/runtime': 7.28.6 + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + reselect: 5.1.1 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@changesets/apply-release-plan@7.0.14': dependencies: '@changesets/config': 3.1.2 @@ -4314,6 +5685,23 @@ snapshots: '@preact/signals-core': 1.14.0 tslib: 2.8.1 + '@dotenvx/dotenvx@1.61.0': + dependencies: + commander: 11.1.0 + dotenv: 17.4.1 + eciesjs: 0.4.18 + execa: 5.1.1 + fdir: 6.5.0(picomatch@4.0.3) + ignore: 5.3.2 + object-treeify: 1.1.33 + picomatch: 4.0.3 + which: 4.0.0 + yocto-spinner: 1.1.0 + + '@ecies/ciphers@0.2.6(@noble/ciphers@1.3.0)': + dependencies: + '@noble/ciphers': 1.3.0 + '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -4527,6 +5915,25 @@ snapshots: '@faker-js/faker@10.3.0': {} + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/react-dom@2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@floating-ui/utils@0.2.11': {} + + '@fontsource-variable/geist@5.2.8': {} + '@gerrit0/mini-shiki@3.22.0': dependencies: '@shikijs/engine-oniguruma': 3.22.0 @@ -4535,6 +5942,10 @@ snapshots: '@shikijs/types': 3.22.0 '@shikijs/vscode-textmate': 10.0.2 + '@hono/node-server@1.19.13(hono@4.12.12)': + dependencies: + hono: 4.12.12 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -4546,6 +5957,28 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@inquirer/ansi@1.0.2': {} + + '@inquirer/confirm@5.1.21(@types/node@25.2.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@25.2.2) + '@inquirer/type': 3.0.10(@types/node@25.2.2) + optionalDependencies: + '@types/node': 25.2.2 + + '@inquirer/core@10.3.2(@types/node@25.2.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@25.2.2) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 25.2.2 + '@inquirer/external-editor@1.0.3(@types/node@25.2.2)': dependencies: chardet: 2.1.1 @@ -4553,6 +5986,12 @@ snapshots: optionalDependencies: '@types/node': 25.2.2 + '@inquirer/figures@1.0.15': {} + + '@inquirer/type@3.0.10(@types/node@25.2.2)': + optionalDependencies: + '@types/node': 25.2.2 + '@isaacs/balanced-match@4.0.1': {} '@isaacs/brace-expansion@5.0.1': @@ -4606,6 +6045,37 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 + '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.13(hono@4.12.12) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.12.12 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + '@mswjs/interceptors@0.41.3': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.8.1 @@ -4626,6 +6096,14 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/hashes@1.8.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4668,6 +6146,15 @@ snapshots: '@nx/nx-win32-x64-msvc@22.4.5': optional: true + '@open-draft/deferred-promise@2.2.0': {} + + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + '@oxc-project/types@0.107.0': {} '@oxc-project/types@0.112.0': {} @@ -4696,51 +6183,350 @@ snapshots: '@oxc-resolver/binding-linux-arm64-gnu@11.17.1': optional: true - '@oxc-resolver/binding-linux-arm64-musl@11.17.1': - optional: true + '@oxc-resolver/binding-linux-arm64-musl@11.17.1': + optional: true + + '@oxc-resolver/binding-linux-ppc64-gnu@11.17.1': + optional: true + + '@oxc-resolver/binding-linux-riscv64-gnu@11.17.1': + optional: true + + '@oxc-resolver/binding-linux-riscv64-musl@11.17.1': + optional: true + + '@oxc-resolver/binding-linux-s390x-gnu@11.17.1': + optional: true + + '@oxc-resolver/binding-linux-x64-gnu@11.17.1': + optional: true + + '@oxc-resolver/binding-linux-x64-musl@11.17.1': + optional: true + + '@oxc-resolver/binding-openharmony-arm64@11.17.1': + optional: true + + '@oxc-resolver/binding-wasm32-wasi@11.17.1': + dependencies: + '@napi-rs/wasm-runtime': 1.1.1 + optional: true + + '@oxc-resolver/binding-win32-arm64-msvc@11.17.1': + optional: true + + '@oxc-resolver/binding-win32-ia32-msvc@11.17.1': + optional: true + + '@oxc-resolver/binding-win32-x64-msvc@11.17.1': + optional: true + + '@preact/signals-core@1.14.0': {} + + '@publint/pack@0.1.4': {} + + '@quansync/fs@1.0.0': + dependencies: + quansync: 1.0.0 + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-context@1.1.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-direction@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-icons@1.3.2(react@19.2.4)': + dependencies: + react: 19.2.4 + + '@radix-ui/react-id@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/rect': 1.1.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) - '@oxc-resolver/binding-linux-ppc64-gnu@11.17.1': - optional: true + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) - '@oxc-resolver/binding-linux-riscv64-gnu@11.17.1': - optional: true + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) - '@oxc-resolver/binding-linux-riscv64-musl@11.17.1': - optional: true + '@radix-ui/react-slot@1.2.3(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@oxc-resolver/binding-linux-s390x-gnu@11.17.1': - optional: true + '@radix-ui/react-slot@1.2.4(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@oxc-resolver/binding-linux-x64-gnu@11.17.1': - optional: true + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) - '@oxc-resolver/binding-linux-x64-musl@11.17.1': - optional: true + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@oxc-resolver/binding-openharmony-arm64@11.17.1': - optional: true + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@oxc-resolver/binding-wasm32-wasi@11.17.1': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.13)(react@19.2.4)': dependencies: - '@napi-rs/wasm-runtime': 1.1.1 - optional: true + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@oxc-resolver/binding-win32-arm64-msvc@11.17.1': - optional: true + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@oxc-resolver/binding-win32-ia32-msvc@11.17.1': - optional: true + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@oxc-resolver/binding-win32-x64-msvc@11.17.1': - optional: true + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@preact/signals-core@1.14.0': {} + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@publint/pack@0.1.4': {} + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 - '@quansync/fs@1.0.0': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - quansync: 1.0.0 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/rect@1.1.1': {} '@rolldown/binding-android-arm64@1.0.0-beta.59': optional: true @@ -4905,6 +6691,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.57.1': optional: true + '@sec-ant/readable-stream@0.4.1': {} + '@shikijs/engine-oniguruma@3.22.0': dependencies: '@shikijs/types': 3.22.0 @@ -4927,39 +6715,41 @@ snapshots: '@sinclair/typebox@0.34.48': {} - '@solid-primitives/event-listener@2.4.3(solid-js@1.9.11)': + '@sindresorhus/merge-streams@4.0.0': {} + + '@solid-primitives/event-listener@2.4.3(solid-js@1.9.12)': dependencies: - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/utils': 6.3.2(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/keyboard@1.3.3(solid-js@1.9.11)': + '@solid-primitives/keyboard@1.3.3(solid-js@1.9.12)': dependencies: - '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) - '@solid-primitives/rootless': 1.5.2(solid-js@1.9.11) - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.12) + '@solid-primitives/rootless': 1.5.2(solid-js@1.9.12) + '@solid-primitives/utils': 6.3.2(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/resize-observer@2.1.3(solid-js@1.9.11)': + '@solid-primitives/resize-observer@2.1.3(solid-js@1.9.12)': dependencies: - '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) - '@solid-primitives/rootless': 1.5.2(solid-js@1.9.11) - '@solid-primitives/static-store': 0.1.2(solid-js@1.9.11) - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.12) + '@solid-primitives/rootless': 1.5.2(solid-js@1.9.12) + '@solid-primitives/static-store': 0.1.2(solid-js@1.9.12) + '@solid-primitives/utils': 6.3.2(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/rootless@1.5.2(solid-js@1.9.11)': + '@solid-primitives/rootless@1.5.2(solid-js@1.9.12)': dependencies: - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/utils': 6.3.2(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/static-store@0.1.2(solid-js@1.9.11)': + '@solid-primitives/static-store@0.1.2(solid-js@1.9.12)': dependencies: - '@solid-primitives/utils': 6.3.2(solid-js@1.9.11) - solid-js: 1.9.11 + '@solid-primitives/utils': 6.3.2(solid-js@1.9.12) + solid-js: 1.9.12 - '@solid-primitives/utils@6.3.2(solid-js@1.9.11)': + '@solid-primitives/utils@6.3.2(solid-js@1.9.12)': dependencies: - solid-js: 1.9.11 + solid-js: 1.9.12 '@standard-schema/spec@1.1.0': {} @@ -4997,35 +6787,40 @@ snapshots: '@tanstack/devtools-event-client@0.4.0': {} - '@tanstack/devtools-ui@0.4.4(csstype@3.2.3)(solid-js@1.9.11)': + '@tanstack/devtools-ui@0.4.4(csstype@3.2.3)(solid-js@1.9.12)': dependencies: clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.11 + solid-js: 1.9.12 transitivePeerDependencies: - csstype - '@tanstack/devtools-utils@0.3.0(@types/react@19.2.13)(csstype@3.2.3)(react@19.2.4)(solid-js@1.9.11)': + '@tanstack/devtools-ui@0.5.1(csstype@3.2.3)(solid-js@1.9.11)': dependencies: - '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.11) + clsx: 2.1.1 + dayjs: 1.11.20 + goober: 2.1.18(csstype@3.2.3) + solid-js: 1.9.11 + transitivePeerDependencies: + - csstype + + '@tanstack/devtools-utils@0.4.0(@types/react@19.2.13)(react@19.2.4)(solid-js@1.9.11)': optionalDependencies: '@types/react': 19.2.13 react: 19.2.4 solid-js: 1.9.11 - transitivePeerDependencies: - - csstype - '@tanstack/devtools@0.10.6(csstype@3.2.3)(solid-js@1.9.11)': + '@tanstack/devtools@0.10.6(csstype@3.2.3)(solid-js@1.9.12)': dependencies: - '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.11) - '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.11) - '@solid-primitives/resize-observer': 2.1.3(solid-js@1.9.11) + '@solid-primitives/event-listener': 2.4.3(solid-js@1.9.12) + '@solid-primitives/keyboard': 1.3.3(solid-js@1.9.12) + '@solid-primitives/resize-observer': 2.1.3(solid-js@1.9.12) '@tanstack/devtools-client': 0.0.5 '@tanstack/devtools-event-bus': 0.4.1 - '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.11) + '@tanstack/devtools-ui': 0.4.4(csstype@3.2.3)(solid-js@1.9.12) clsx: 2.1.1 goober: 2.1.18(csstype@3.2.3) - solid-js: 1.9.11 + solid-js: 1.9.12 transitivePeerDependencies: - bufferutil - csstype @@ -5047,9 +6842,13 @@ snapshots: - supports-color - typescript - '@tanstack/react-devtools@0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.11)': + '@tanstack/query-core@5.95.2': {} + + '@tanstack/query-devtools@5.95.2': {} + + '@tanstack/react-devtools@0.9.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.12)': dependencies: - '@tanstack/devtools': 0.10.6(csstype@3.2.3)(solid-js@1.9.11) + '@tanstack/devtools': 0.10.6(csstype@3.2.3)(solid-js@1.9.12) '@types/react': 19.2.13 '@types/react-dom': 19.2.3(@types/react@19.2.13) react: 19.2.4 @@ -5060,6 +6859,17 @@ snapshots: - solid-js - utf-8-validate + '@tanstack/react-query-devtools@5.95.2(@tanstack/react-query@5.95.2(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/query-devtools': 5.95.2 + '@tanstack/react-query': 5.95.2(react@19.2.4) + react: 19.2.4 + + '@tanstack/react-query@5.95.2(react@19.2.4)': + dependencies: + '@tanstack/query-core': 5.95.2 + react: 19.2.4 + '@tanstack/react-store@0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@tanstack/store': 0.8.0 @@ -5112,6 +6922,12 @@ snapshots: '@types/react': 19.2.13 '@types/react-dom': 19.2.3(@types/react@19.2.13) + '@ts-morph/common@0.27.0': + dependencies: + fast-glob: 3.3.3 + minimatch: 10.1.2 + path-browserify: 1.0.1 + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -5194,8 +7010,12 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/statuses@2.0.6': {} + '@types/unist@3.0.3': {} + '@types/validate-npm-package-name@4.0.2': {} + '@types/whatwg-mimetype@3.0.2': {} '@types/ws@8.18.1': @@ -5385,12 +7205,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2))': + '@vitest/mocker@4.0.18(msw@2.13.2(@types/node@25.2.2)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.13.2(@types/node@25.2.2)(typescript@5.9.3) vite: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) '@vitest/pretty-format@4.0.18': @@ -5449,12 +7270,23 @@ snapshots: dependencies: argparse: 2.0.1 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 acorn@8.15.0: {} + agent-base@7.1.4: {} + + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -5462,10 +7294,19 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-colors@4.1.3: {} ansi-regex@5.0.1: {} + ansi-regex@6.2.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -5489,6 +7330,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + aria-query@5.3.0: dependencies: dequal: 2.0.3 @@ -5504,6 +7349,10 @@ snapshots: '@babel/parser': 7.29.0 pathe: 2.0.3 + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + asynckit@0.4.0: {} autoprefixer@10.4.24(postcss@8.5.6): @@ -5563,6 +7412,20 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.1 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} brace-expansion@1.1.12: @@ -5591,6 +7454,12 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + bytes@3.1.2: {} + cac@6.7.14: {} call-bind-apply-helpers@1.0.2: @@ -5598,6 +7467,11 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + callsites@3.1.0: {} camelcase-css@2.0.1: {} @@ -5611,6 +7485,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.6.2: {} + chardet@2.1.1: {} cheerio-select@2.1.0: @@ -5650,14 +7526,26 @@ snapshots: ci-info@3.9.0: {} + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + classcat@5.0.5: {} cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + cli-spinners@2.6.1: {} + cli-spinners@2.9.2: {} + + cli-width@4.1.0: {} + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -5668,6 +7556,8 @@ snapshots: clsx@2.1.1: {} + code-block-writer@13.0.3: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -5678,6 +7568,10 @@ snapshots: dependencies: delayed-stream: 1.0.0 + commander@11.1.0: {} + + commander@14.0.3: {} + commander@4.1.1: {} comment-parser@1.4.5: {} @@ -5686,8 +7580,32 @@ snapshots: concat-map@0.0.1: {} + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + convert-source-map@2.0.0: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cookie@1.1.1: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cosmiconfig@9.0.1(typescript@5.9.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.9.3 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -5746,32 +7664,55 @@ snapshots: d3-selection: 3.0.0 d3-transition: 3.0.1(d3-selection@3.0.0) + data-uri-to-buffer@4.0.1: {} + dataloader@1.4.0: {} + dayjs@1.11.20: {} + debug@4.4.3: dependencies: ms: 2.1.3 + dedent@1.7.2: {} + deep-is@0.1.4: {} + deepmerge@4.3.1: {} + + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + defaults@1.0.4: dependencies: clone: 1.0.4 define-lazy-prop@2.0.0: {} + define-lazy-prop@3.0.0: {} + defu@6.1.4: {} delayed-stream@1.0.0: {} + depd@2.0.0: {} + dequal@2.0.3: {} detect-indent@6.1.0: {} + detect-node-es@1.1.0: {} + devalue@5.6.2: {} didyoumean@1.2.2: {} + diff@8.0.4: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -5808,6 +7749,8 @@ snapshots: dotenv@16.6.1: {} + dotenv@17.4.1: {} + dts-resolver@2.1.3(oxc-resolver@11.17.1): optionalDependencies: oxc-resolver: 11.17.1 @@ -5818,12 +7761,25 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + eciesjs@0.4.18: + dependencies: + '@ecies/ciphers': 0.2.6(@noble/ciphers@1.3.0) + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + + ee-first@1.1.1: {} + electron-to-chromium@1.5.286: {} + emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} empathic@2.0.0: {} + encodeurl@2.0.0: {} + encoding-sniffer@0.2.1: dependencies: iconv-lite: 0.6.3 @@ -5853,6 +7809,12 @@ snapshots: entities@7.0.1: {} + env-paths@2.2.1: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -5901,6 +7863,8 @@ snapshots: escalade@3.2.0: {} + escape-html@1.0.3: {} + escape-string-regexp@1.0.5: {} escape-string-regexp@4.0.0: {} @@ -6168,8 +8132,81 @@ snapshots: esutils@2.0.3: {} + etag@1.8.1: {} + + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + execa@9.6.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.6 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 8.0.1 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 6.0.0 + pretty-ms: 9.3.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.2 + expect-type@1.3.0: {} + express-rate-limit@8.3.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.1 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extendable-error@0.1.7: {} fast-deep-equal@3.1.3: {} @@ -6186,6 +8223,8 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-uri@3.1.0: {} + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -6198,10 +8237,19 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 + figures@6.1.0: + dependencies: + is-unicode-supported: 2.1.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -6210,6 +8258,17 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -6243,14 +8302,28 @@ snapshots: dependencies: fd-package-json: 2.0.0 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + forwarded@0.2.0: {} + fraction.js@5.3.4: {} + fresh@2.0.0: {} + front-matter@4.0.2: dependencies: js-yaml: 3.14.2 fs-constants@1.0.0: {} + fs-extra@11.3.4: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 @@ -6268,10 +8341,14 @@ snapshots: function-bind@1.1.2: {} + fuzzysort@3.1.0: {} + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} + get-east-asian-width@1.5.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -6285,10 +8362,21 @@ snapshots: hasown: 2.0.2 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + + get-own-enumerable-keys@1.0.0: {} + get-proto@1.0.1: dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@6.0.1: {} + + get-stream@9.0.1: + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 get-tsconfig@4.13.6: dependencies: @@ -6327,6 +8415,8 @@ snapshots: graceful-fs@4.2.11: {} + graphql@16.13.2: {} + happy-dom@20.5.3: dependencies: '@types/node': 25.2.2 @@ -6351,12 +8441,16 @@ snapshots: dependencies: function-bind: 1.1.2 + headers-polyfill@4.0.3: {} + hermes-estree@0.25.1: {} hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 + hono@4.12.12: {} + hookable@6.0.1: {} html-entities@2.3.3: {} @@ -6372,8 +8466,27 @@ snapshots: domutils: 3.2.2 entities: 7.0.1 + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + human-id@4.1.3: {} + human-signals@2.1.0: {} + + human-signals@8.0.1: {} + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 @@ -6401,6 +8514,12 @@ snapshots: inherits@2.0.4: {} + ip-address@10.1.0: {} + + ipaddr.js@1.9.1: {} + + is-arrayish@0.2.1: {} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -6411,6 +8530,8 @@ snapshots: is-docker@2.2.1: {} + is-docker@3.0.0: {} + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -6429,20 +8550,46 @@ snapshots: transitivePeerDependencies: - supports-color + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-interactive@1.0.0: {} + is-interactive@2.0.0: {} + + is-node-process@1.2.0: {} + is-number@7.0.0: {} + is-obj@3.0.0: {} + + is-plain-obj@4.1.0: {} + + is-promise@4.0.0: {} + is-reference@3.0.3: dependencies: '@types/estree': 1.0.8 + is-regexp@3.1.0: {} + + is-stream@2.0.1: {} + + is-stream@4.0.1: {} + is-subdir@1.2.0: dependencies: better-path-resolve: 1.0.0 is-unicode-supported@0.1.0: {} + is-unicode-supported@1.3.0: {} + + is-unicode-supported@2.1.0: {} + is-what@4.1.16: {} is-windows@1.0.2: {} @@ -6451,8 +8598,14 @@ snapshots: dependencies: is-docker: 2.2.1 + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + isexe@2.0.0: {} + isexe@3.1.5: {} + jest-diff@30.2.0: dependencies: '@jest/diff-sequences': 30.0.1 @@ -6464,6 +8617,8 @@ snapshots: jiti@2.6.1: {} + jose@6.2.2: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -6481,8 +8636,14 @@ snapshots: json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {} @@ -6493,10 +8654,20 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + kleur@3.0.3: {} + + kleur@4.1.5: {} + knip@5.83.1(@types/node@25.2.2)(typescript@5.9.3): dependencies: '@nodelib/fs.walk': 1.2.8 @@ -6548,10 +8719,19 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + log-symbols@6.0.0: + dependencies: + chalk: 5.6.2 + is-unicode-supported: 1.3.0 + lru-cache@5.1.1: dependencies: yallist: 3.1.1 + lucide-react@1.8.0(react@19.2.4): + dependencies: + react: 19.2.4 + lunr@2.3.9: {} lz-string@1.5.0: {} @@ -6580,10 +8760,16 @@ snapshots: mdurl@2.0.0: {} + media-typer@1.1.0: {} + merge-anything@5.1.7: dependencies: is-what: 4.1.16 + merge-descriptors@2.0.0: {} + + merge-stream@2.0.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -6593,12 +8779,20 @@ snapshots: mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mimic-fn@2.1.0: {} + mimic-function@5.0.1: {} + min-indent@1.0.1: {} minimatch@10.1.1: @@ -6623,6 +8817,33 @@ snapshots: ms@2.1.3: {} + msw@2.13.2(@types/node@25.2.2)(typescript@5.9.3): + dependencies: + '@inquirer/confirm': 5.1.21(@types/node@25.2.2) + '@mswjs/interceptors': 0.41.3 + '@open-draft/deferred-promise': 2.2.0 + '@types/statuses': 2.0.6 + cookie: 1.1.1 + graphql: 16.13.2 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.10.1 + statuses: 2.0.2 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.1 + type-fest: 5.5.0 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + + mute-stream@2.0.0: {} + mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -6635,10 +8856,20 @@ snapshots: natural-compare@1.4.0: {} + negotiator@1.0.0: {} + + node-domexception@1.0.0: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-machine-id@1.1.12: {} node-releases@2.0.27: {} @@ -6649,6 +8880,11 @@ snapshots: dependencies: path-key: 3.1.1 + npm-run-path@6.0.0: + dependencies: + path-key: 4.0.0 + unicorn-magic: 0.3.0 + nth-check@2.1.1: dependencies: boolbase: 1.0.0 @@ -6708,8 +8944,16 @@ snapshots: object-hash@3.0.0: {} + object-inspect@1.13.4: {} + + object-treeify@1.1.33: {} + obug@2.1.1: {} + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -6718,6 +8962,19 @@ snapshots: dependencies: mimic-fn: 2.1.0 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + open@11.0.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -6744,8 +9001,22 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + ora@8.2.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.2.0 + outdent@0.5.0: {} + outvariant@1.4.3: {} + oxc-resolver@11.17.1: optionalDependencies: '@oxc-resolver/binding-android-arm-eabi': 11.17.1 @@ -6803,6 +9074,15 @@ snapshots: dependencies: callsites: 3.1.0 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-ms@4.0.0: {} + parse5-htmlparser2-tree-adapter@7.1.0: dependencies: domhandler: 5.0.3 @@ -6816,12 +9096,22 @@ snapshots: dependencies: entities: 6.0.1 + parseurl@1.3.3: {} + + path-browserify@1.0.1: {} + path-exists@4.0.0: {} path-key@3.1.1: {} + path-key@4.0.0: {} + path-parse@1.0.7: {} + path-to-regexp@6.3.0: {} + + path-to-regexp@8.4.2: {} + path-type@4.0.0: {} pathe@2.0.3: {} @@ -6838,6 +9128,8 @@ snapshots: pirates@4.0.7: {} + pkce-challenge@5.0.1: {} + postcss-import@15.1.0(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -6868,6 +9160,11 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-value-parser@4.2.0: {} postcss@8.5.6: @@ -6876,6 +9173,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + powershell-utils@0.1.0: {} + prelude-ls@1.2.1: {} premove@4.0.0: {} @@ -6901,6 +9200,20 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + proxy-from-env@1.1.0: {} publint@0.3.17: @@ -6914,12 +9227,25 @@ snapshots: punycode@2.3.1: {} + qs@6.15.1: + dependencies: + side-channel: 1.1.0 + quansync@0.2.11: {} quansync@1.0.0: {} queue-microtask@1.2.3: {} + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + react-dom@19.2.4(react@19.2.4): dependencies: react: 19.2.4 @@ -6931,6 +9257,33 @@ snapshots: react-refresh@0.18.0: {} + react-remove-scroll-bar@2.3.8(@types/react@19.2.13)(react@19.2.4): + dependencies: + react: 19.2.4 + react-style-singleton: 2.2.3(@types/react@19.2.13)(react@19.2.4) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + + react-remove-scroll@2.7.2(@types/react@19.2.13)(react@19.2.4): + dependencies: + react: 19.2.4 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.13)(react@19.2.4) + react-style-singleton: 2.2.3(@types/react@19.2.13)(react@19.2.4) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.13)(react@19.2.4) + use-sidecar: 1.1.3(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + + react-style-singleton@2.2.3(@types/react@19.2.13)(react@19.2.4): + dependencies: + get-nonce: 1.0.1 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + react@19.2.4: {} read-cache@1.0.0: @@ -6954,6 +9307,14 @@ snapshots: dependencies: picomatch: 2.3.1 + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -6961,6 +9322,10 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + + reselect@5.1.1: {} + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -6980,6 +9345,13 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + rettime@0.10.1: {} + reusify@1.1.0: {} rolldown-plugin-dts@0.20.0(oxc-resolver@11.17.1)(rolldown@1.0.0-beta.59)(typescript@5.9.3): @@ -7077,6 +9449,18 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.57.1 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + run-applescript@7.1.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -7095,12 +9479,82 @@ snapshots: semver@7.7.4: {} + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + seroval-plugins@1.5.0(seroval@1.5.0): dependencies: seroval: 1.5.0 seroval@1.5.0: {} + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + shadcn@4.2.0(@types/node@25.2.2)(typescript@5.9.3): + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@dotenvx/dotenvx': 1.61.0 + '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76) + '@types/validate-npm-package-name': 4.0.2 + browserslist: 4.28.1 + commander: 14.0.3 + cosmiconfig: 9.0.1(typescript@5.9.3) + dedent: 1.7.2 + deepmerge: 4.3.1 + diff: 8.0.4 + execa: 9.6.1 + fast-glob: 3.3.3 + fs-extra: 11.3.4 + fuzzysort: 3.1.0 + https-proxy-agent: 7.0.6 + kleur: 4.1.5 + msw: 2.13.2(@types/node@25.2.2)(typescript@5.9.3) + node-fetch: 3.3.2 + open: 11.0.0 + ora: 8.2.0 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + prompts: 2.4.2 + recast: 0.23.11 + stringify-object: 5.0.0 + tailwind-merge: 3.5.0 + ts-morph: 26.0.0 + tsconfig-paths: 4.2.0 + validate-npm-package-name: 7.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - '@cfworker/json-schema' + - '@types/node' + - babel-plugin-macros + - supports-color + - typescript + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -7142,12 +9596,42 @@ snapshots: sherif-windows-arm64: 1.10.0 sherif-windows-x64: 1.10.0 + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} signal-exit@3.0.7: {} signal-exit@4.1.0: {} + sisteransi@1.0.5: {} + slash@3.0.0: {} smol-toml@1.6.0: {} @@ -7158,6 +9642,12 @@ snapshots: seroval: 1.5.0 seroval-plugins: 1.5.0(seroval@1.5.0) + solid-js@1.9.12: + dependencies: + csstype: 3.2.3 + seroval: 1.5.0 + seroval-plugins: 1.5.0(seroval@1.5.0) + solid-refresh@0.6.3(solid-js@1.9.11): dependencies: '@babel/generator': 7.29.1 @@ -7169,6 +9659,8 @@ snapshots: source-map-js@1.2.1: {} + source-map@0.6.1: {} + spawndamnit@3.0.1: dependencies: cross-spawn: 7.0.6 @@ -7180,8 +9672,14 @@ snapshots: stackback@0.0.2: {} + statuses@2.0.2: {} + std-env@3.10.0: {} + stdin-discarder@0.2.2: {} + + strict-event-emitter@0.5.1: {} + string-ts@2.3.1: {} string-width@4.2.3: @@ -7190,16 +9688,36 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 + stringify-object@5.0.0: + dependencies: + get-own-enumerable-keys: 1.0.0 + is-obj: 3.0.0 + is-regexp: 3.1.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + strip-bom@3.0.0: {} + strip-final-newline@2.0.0: {} + + strip-final-newline@4.0.0: {} + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 @@ -7242,6 +9760,16 @@ snapshots: magic-string: 0.30.21 zimmerframe: 1.1.4 + tabbable@6.4.0: {} + + tagged-tag@1.0.0: {} + + tailwind-merge@3.5.0: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.19(yaml@2.8.2)): + dependencies: + tailwindcss: 3.4.19(yaml@2.8.2) + tailwindcss@3.4.19(yaml@2.8.2): dependencies: '@alloc/quick-lru': 5.2.0 @@ -7290,6 +9818,8 @@ snapshots: dependencies: any-promise: 1.3.0 + tiny-invariant@1.3.3: {} + tinybench@2.9.0: {} tinyexec@1.0.2: {} @@ -7301,12 +9831,24 @@ snapshots: tinyrainbow@3.0.3: {} + tldts-core@7.0.28: {} + + tldts@7.0.28: + dependencies: + tldts-core: 7.0.28 + tmp@0.2.5: {} to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + + tough-cookie@6.0.1: + dependencies: + tldts: 7.0.28 + tr46@0.0.3: {} tree-kill@1.2.2: {} @@ -7322,6 +9864,11 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-morph@26.0.0: + dependencies: + '@ts-morph/common': 0.27.0 + code-block-writer: 13.0.3 + ts-pattern@5.9.0: {} tsconfig-paths@4.2.0: @@ -7360,10 +9907,22 @@ snapshots: tslib@2.8.1: {} + tw-animate-css@1.4.0: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 + type-fest@5.5.0: + dependencies: + tagged-tag: 1.0.0 + + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + typedoc-plugin-frontmatter@1.3.0(typedoc-plugin-markdown@4.9.0(typedoc@0.28.14(typescript@5.9.3))): dependencies: typedoc-plugin-markdown: 4.9.0(typedoc@0.28.14(typescript@5.9.3)) @@ -7406,8 +9965,14 @@ snapshots: undici@7.21.0: {} + unicorn-magic@0.3.0: {} + universalify@0.1.2: {} + universalify@2.0.1: {} + + unpipe@1.0.0: {} + unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 @@ -7436,6 +10001,8 @@ snapshots: dependencies: rolldown: 1.0.0-rc.3 + until-async@3.0.2: {} + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 @@ -7446,12 +10013,31 @@ snapshots: dependencies: punycode: 2.3.1 + use-callback-ref@1.3.3(@types/react@19.2.13)(react@19.2.4): + dependencies: + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + + use-sidecar@1.1.3(@types/react@19.2.13)(react@19.2.4): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + use-sync-external-store@1.6.0(react@19.2.4): dependencies: react: 19.2.4 util-deprecate@1.0.2: {} + validate-npm-package-name@7.0.2: {} + + vary@1.1.2: {} + vite-plugin-solid@2.11.10(@testing-library/jest-dom@6.9.1)(solid-js@1.9.11)(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)): dependencies: '@babel/core': 7.29.0 @@ -7499,10 +10085,10 @@ snapshots: optionalDependencies: vite: 7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2) - vitest@4.0.18(@types/node@25.2.2)(happy-dom@20.5.3)(jiti@2.6.1)(yaml@2.8.2): + vitest@4.0.18(@types/node@25.2.2)(happy-dom@20.5.3)(jiti@2.6.1)(msw@2.13.2(@types/node@25.2.2)(typescript@5.9.3))(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) + '@vitest/mocker': 4.0.18(msw@2.13.2(@types/node@25.2.2)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.2)(jiti@2.6.1)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 @@ -7555,6 +10141,8 @@ snapshots: dependencies: defaults: 1.0.4 + web-streams-polyfill@3.3.3: {} + webidl-conversions@3.0.1: {} whatwg-encoding@3.1.1: @@ -7574,6 +10162,10 @@ snapshots: dependencies: isexe: 2.0.0 + which@4.0.0: + dependencies: + isexe: 3.1.5 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 @@ -7581,6 +10173,12 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -7591,6 +10189,11 @@ snapshots: ws@8.19.0: {} + wsl-utils@0.3.1: + dependencies: + is-wsl: 3.1.1 + powershell-utils: 0.1.0 + y18n@5.0.8: {} yallist@3.1.1: {} @@ -7611,8 +10214,20 @@ snapshots: yocto-queue@0.1.0: {} + yocto-spinner@1.1.0: + dependencies: + yoctocolors: 2.1.2 + + yoctocolors-cjs@2.1.3: {} + + yoctocolors@2.1.2: {} + zimmerframe@1.1.4: {} + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + zod-validation-error@3.5.4(zod@3.25.76): dependencies: zod: 3.25.76 From 1d6b54198054954b6e73639b99f6e02db32c89ef Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:06:11 +0000 Subject: [PATCH 066/207] ci: apply automated fixes --- .../react/reference/functions/useCalendar.md | 2 +- .../reference/interfaces/ResizeOptions.md | 18 +++--- .../react/reference/interfaces/ResizeState.md | 20 +++---- .../interfaces/UseCalendarOptions.md | 4 +- .../calendar/src/components/ui/badge.tsx | 38 ++++++------ .../calendar/src/components/ui/button.tsx | 42 ++++++------- .../react/calendar/src/components/ui/card.tsx | 44 +++++++------- .../calendar/src/components/ui/dialog.tsx | 39 ++++++------ .../calendar/src/components/ui/input.tsx | 12 ++-- .../calendar/src/components/ui/label.tsx | 12 ++-- .../calendar/src/components/ui/select.tsx | 45 +++++++------- examples/react/calendar/tsconfig.json | 6 +- .../react/timeline/src/components/ui/card.tsx | 30 +++++----- .../timeline/src/components/ui/dialog.tsx | 34 +++++------ .../timeline/src/components/ui/input.tsx | 14 ++--- .../timeline/src/components/ui/label.tsx | 2 +- .../timeline/src/components/ui/tooltip.tsx | 10 ++-- examples/react/timeline/tsconfig.json | 6 +- packages/time/src/calendar/calendar.ts | 60 ++++++++++++------- 19 files changed, 228 insertions(+), 210 deletions(-) diff --git a/docs/framework/react/reference/functions/useCalendar.md b/docs/framework/react/reference/functions/useCalendar.md index ed4fe312..b24ffa46 100644 --- a/docs/framework/react/reference/functions/useCalendar.md +++ b/docs/framework/react/reference/functions/useCalendar.md @@ -9,7 +9,7 @@ title: useCalendar function useCalendar(options): CalendarApi & object; ``` -Defined in: [useCalendar.ts:76](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L76) +Defined in: [useCalendar.ts:77](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L77) ## Type Parameters diff --git a/docs/framework/react/reference/interfaces/ResizeOptions.md b/docs/framework/react/reference/interfaces/ResizeOptions.md index 70c6b8f5..433ffa55 100644 --- a/docs/framework/react/reference/interfaces/ResizeOptions.md +++ b/docs/framework/react/reference/interfaces/ResizeOptions.md @@ -5,7 +5,7 @@ title: ResizeOptions # Interface: ResizeOptions -Defined in: [useCalendar.ts:38](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L38) +Defined in: [useCalendar.ts:39](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L39) ## Properties @@ -15,7 +15,7 @@ Defined in: [useCalendar.ts:38](https://github.com/TanStack/time/blob/main/packa optional constraints: ResizeConstraints; ``` -Defined in: [useCalendar.ts:43](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L43) +Defined in: [useCalendar.ts:44](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L44) *** @@ -25,7 +25,7 @@ Defined in: [useCalendar.ts:43](https://github.com/TanStack/time/blob/main/packa optional containerHeight: number; ``` -Defined in: [useCalendar.ts:40](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L40) +Defined in: [useCalendar.ts:41](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L41) *** @@ -35,7 +35,7 @@ Defined in: [useCalendar.ts:40](https://github.com/TanStack/time/blob/main/packa optional containerWidth: number; ``` -Defined in: [useCalendar.ts:41](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L41) +Defined in: [useCalendar.ts:42](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L42) *** @@ -45,7 +45,7 @@ Defined in: [useCalendar.ts:41](https://github.com/TanStack/time/blob/main/packa optional enabled: boolean; ``` -Defined in: [useCalendar.ts:39](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L39) +Defined in: [useCalendar.ts:40](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L40) *** @@ -55,7 +55,7 @@ Defined in: [useCalendar.ts:39](https://github.com/TanStack/time/blob/main/packa optional onResizeEnd: (eventId, newStart, newEnd) => void; ``` -Defined in: [useCalendar.ts:45](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L45) +Defined in: [useCalendar.ts:46](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L46) #### Parameters @@ -83,7 +83,7 @@ Defined in: [useCalendar.ts:45](https://github.com/TanStack/time/blob/main/packa optional onResizeError: (error) => void; ``` -Defined in: [useCalendar.ts:46](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L46) +Defined in: [useCalendar.ts:47](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L47) #### Parameters @@ -103,7 +103,7 @@ Defined in: [useCalendar.ts:46](https://github.com/TanStack/time/blob/main/packa optional onResizeStart: (eventId, edge) => void; ``` -Defined in: [useCalendar.ts:44](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L44) +Defined in: [useCalendar.ts:45](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L45) #### Parameters @@ -127,4 +127,4 @@ Defined in: [useCalendar.ts:44](https://github.com/TanStack/time/blob/main/packa optional orientation: "vertical" | "horizontal"; ``` -Defined in: [useCalendar.ts:42](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L42) +Defined in: [useCalendar.ts:43](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L43) diff --git a/docs/framework/react/reference/interfaces/ResizeState.md b/docs/framework/react/reference/interfaces/ResizeState.md index 4abb390e..53091992 100644 --- a/docs/framework/react/reference/interfaces/ResizeState.md +++ b/docs/framework/react/reference/interfaces/ResizeState.md @@ -5,7 +5,7 @@ title: ResizeState # Interface: ResizeState -Defined in: [useCalendar.ts:26](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L26) +Defined in: [useCalendar.ts:27](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L27) ## Properties @@ -15,7 +15,7 @@ Defined in: [useCalendar.ts:26](https://github.com/TanStack/time/blob/main/packa blocked: boolean; ``` -Defined in: [useCalendar.ts:35](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L35) +Defined in: [useCalendar.ts:36](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L36) *** @@ -25,7 +25,7 @@ Defined in: [useCalendar.ts:35](https://github.com/TanStack/time/blob/main/packa edge: ResizeEdge | null; ``` -Defined in: [useCalendar.ts:29](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L29) +Defined in: [useCalendar.ts:30](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L30) *** @@ -35,7 +35,7 @@ Defined in: [useCalendar.ts:29](https://github.com/TanStack/time/blob/main/packa eventId: string | null; ``` -Defined in: [useCalendar.ts:28](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L28) +Defined in: [useCalendar.ts:29](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L29) *** @@ -45,7 +45,7 @@ Defined in: [useCalendar.ts:28](https://github.com/TanStack/time/blob/main/packa isResizing: boolean; ``` -Defined in: [useCalendar.ts:27](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L27) +Defined in: [useCalendar.ts:28](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L28) *** @@ -55,7 +55,7 @@ Defined in: [useCalendar.ts:27](https://github.com/TanStack/time/blob/main/packa lastValidPreviewEnd: string | null; ``` -Defined in: [useCalendar.ts:33](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L33) +Defined in: [useCalendar.ts:34](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L34) *** @@ -65,7 +65,7 @@ Defined in: [useCalendar.ts:33](https://github.com/TanStack/time/blob/main/packa lastValidPreviewStart: string | null; ``` -Defined in: [useCalendar.ts:32](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L32) +Defined in: [useCalendar.ts:33](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L33) *** @@ -75,7 +75,7 @@ Defined in: [useCalendar.ts:32](https://github.com/TanStack/time/blob/main/packa previewEnd: string | null; ``` -Defined in: [useCalendar.ts:31](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L31) +Defined in: [useCalendar.ts:32](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L32) *** @@ -85,7 +85,7 @@ Defined in: [useCalendar.ts:31](https://github.com/TanStack/time/blob/main/packa previewStart: string | null; ``` -Defined in: [useCalendar.ts:30](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L30) +Defined in: [useCalendar.ts:31](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L31) *** @@ -95,4 +95,4 @@ Defined in: [useCalendar.ts:30](https://github.com/TanStack/time/blob/main/packa targetDayDate: string | null; ``` -Defined in: [useCalendar.ts:34](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L34) +Defined in: [useCalendar.ts:35](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L35) diff --git a/docs/framework/react/reference/interfaces/UseCalendarOptions.md b/docs/framework/react/reference/interfaces/UseCalendarOptions.md index 454b16e0..3e4ec484 100644 --- a/docs/framework/react/reference/interfaces/UseCalendarOptions.md +++ b/docs/framework/react/reference/interfaces/UseCalendarOptions.md @@ -5,7 +5,7 @@ title: UseCalendarOptions # Interface: UseCalendarOptions\ -Defined in: [useCalendar.ts:57](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L57) +Defined in: [useCalendar.ts:58](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L58) ## Extends @@ -29,4 +29,4 @@ Defined in: [useCalendar.ts:57](https://github.com/TanStack/time/blob/main/packa optional resize: ResizeOptions; ``` -Defined in: [useCalendar.ts:61](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L61) +Defined in: [useCalendar.ts:62](https://github.com/TanStack/time/blob/main/packages/react-time/src/useCalendar/useCalendar.ts#L62) diff --git a/examples/react/calendar/src/components/ui/badge.tsx b/examples/react/calendar/src/components/ui/badge.tsx index b20959dd..83b3ed7d 100644 --- a/examples/react/calendar/src/components/ui/badge.tsx +++ b/examples/react/calendar/src/components/ui/badge.tsx @@ -1,49 +1,49 @@ -import { mergeProps } from "@base-ui/react/merge-props" -import { useRender } from "@base-ui/react/use-render" -import { cva, type VariantProps } from "class-variance-authority" +import { mergeProps } from '@base-ui/react/merge-props' +import { useRender } from '@base-ui/react/use-render' +import { cva, type VariantProps } from 'class-variance-authority' -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils' const badgeVariants = cva( - "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", + 'group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!', { variants: { variant: { - default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", + default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80', secondary: - "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80", + 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80', destructive: - "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20", + 'bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20', outline: - "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground", + 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground', ghost: - "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50", - link: "text-primary underline-offset-4 hover:underline", + 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50', + link: 'text-primary underline-offset-4 hover:underline', }, }, defaultVariants: { - variant: "default", + variant: 'default', }, - } + }, ) function Badge({ className, - variant = "default", + variant = 'default', render, ...props -}: useRender.ComponentProps<"span"> & VariantProps) { +}: useRender.ComponentProps<'span'> & VariantProps) { return useRender({ - defaultTagName: "span", - props: mergeProps<"span">( + defaultTagName: 'span', + props: mergeProps<'span'>( { className: cn(badgeVariants({ variant }), className), }, - props + props, ), render, state: { - slot: "badge", + slot: 'badge', variant, }, }) diff --git a/examples/react/calendar/src/components/ui/button.tsx b/examples/react/calendar/src/components/ui/button.tsx index 09df7536..b520e871 100644 --- a/examples/react/calendar/src/components/ui/button.tsx +++ b/examples/react/calendar/src/components/ui/button.tsx @@ -1,49 +1,49 @@ -import { Button as ButtonPrimitive } from "@base-ui/react/button" -import { cva, type VariantProps } from "class-variance-authority" +import { Button as ButtonPrimitive } from '@base-ui/react/button' +import { cva, type VariantProps } from 'class-variance-authority' -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils' const buttonVariants = cva( "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", { variants: { variant: { - default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", + default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80', outline: - "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", + 'border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50', secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground", + 'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground', ghost: - "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50", + 'hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50', destructive: - "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40", - link: "text-primary underline-offset-4 hover:underline", + 'bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40', + link: 'text-primary underline-offset-4 hover:underline', }, size: { default: - "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", + 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2', xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3", sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5", - lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2", - icon: "size-8", - "icon-xs": + lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2', + icon: 'size-8', + 'icon-xs': "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3", - "icon-sm": - "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg", - "icon-lg": "size-9", + 'icon-sm': + 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg', + 'icon-lg': 'size-9', }, }, defaultVariants: { - variant: "default", - size: "default", + variant: 'default', + size: 'default', }, - } + }, ) function Button({ className, - variant = "default", - size = "default", + variant = 'default', + size = 'default', ...props }: ButtonPrimitive.Props & VariantProps) { return ( diff --git a/examples/react/calendar/src/components/ui/card.tsx b/examples/react/calendar/src/components/ui/card.tsx index 40cac5f9..496806ea 100644 --- a/examples/react/calendar/src/components/ui/card.tsx +++ b/examples/react/calendar/src/components/ui/card.tsx @@ -1,91 +1,91 @@ -import * as React from "react" +import * as React from 'react' -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils' function Card({ className, - size = "default", + size = 'default', ...props -}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) { +}: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }) { return (
img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl", - className + 'group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl', + className, )} {...props} /> ) } -function CardHeader({ className, ...props }: React.ComponentProps<"div">) { +function CardHeader({ className, ...props }: React.ComponentProps<'div'>) { return (
) } -function CardTitle({ className, ...props }: React.ComponentProps<"div">) { +function CardTitle({ className, ...props }: React.ComponentProps<'div'>) { return (
) } -function CardDescription({ className, ...props }: React.ComponentProps<"div">) { +function CardDescription({ className, ...props }: React.ComponentProps<'div'>) { return (
) } -function CardAction({ className, ...props }: React.ComponentProps<"div">) { +function CardAction({ className, ...props }: React.ComponentProps<'div'>) { return (
) } -function CardContent({ className, ...props }: React.ComponentProps<"div">) { +function CardContent({ className, ...props }: React.ComponentProps<'div'>) { return (
) } -function CardFooter({ className, ...props }: React.ComponentProps<"div">) { +function CardFooter({ className, ...props }: React.ComponentProps<'div'>) { return (
diff --git a/examples/react/calendar/src/components/ui/dialog.tsx b/examples/react/calendar/src/components/ui/dialog.tsx index 3fc1dda4..f160efd2 100644 --- a/examples/react/calendar/src/components/ui/dialog.tsx +++ b/examples/react/calendar/src/components/ui/dialog.tsx @@ -1,9 +1,9 @@ -import * as React from "react" -import { Dialog as DialogPrimitive } from "@base-ui/react/dialog" +import * as React from 'react' +import { Dialog as DialogPrimitive } from '@base-ui/react/dialog' -import { cn } from "@/lib/utils" -import { Button } from "@/components/ui/button" -import { XIcon } from "lucide-react" +import { cn } from '@/lib/utils' +import { Button } from '@/components/ui/button' +import { XIcon } from 'lucide-react' function Dialog({ ...props }: DialogPrimitive.Root.Props) { return @@ -29,8 +29,8 @@ function DialogOverlay({ @@ -51,8 +51,8 @@ function DialogContent({ @@ -68,8 +68,7 @@ function DialogContent({ /> } > - + Close )} @@ -78,11 +77,11 @@ function DialogContent({ ) } -function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { +function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) { return (
) @@ -93,15 +92,15 @@ function DialogFooter({ showCloseButton = false, children, ...props -}: React.ComponentProps<"div"> & { +}: React.ComponentProps<'div'> & { showCloseButton?: boolean }) { return (
@@ -120,8 +119,8 @@ function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) { @@ -136,8 +135,8 @@ function DialogDescription({ diff --git a/examples/react/calendar/src/components/ui/input.tsx b/examples/react/calendar/src/components/ui/input.tsx index 7d21babb..9def7819 100644 --- a/examples/react/calendar/src/components/ui/input.tsx +++ b/examples/react/calendar/src/components/ui/input.tsx @@ -1,16 +1,16 @@ -import * as React from "react" -import { Input as InputPrimitive } from "@base-ui/react/input" +import * as React from 'react' +import { Input as InputPrimitive } from '@base-ui/react/input' -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils' -function Input({ className, type, ...props }: React.ComponentProps<"input">) { +function Input({ className, type, ...props }: React.ComponentProps<'input'>) { return ( diff --git a/examples/react/calendar/src/components/ui/label.tsx b/examples/react/calendar/src/components/ui/label.tsx index 74da65c3..9c50830b 100644 --- a/examples/react/calendar/src/components/ui/label.tsx +++ b/examples/react/calendar/src/components/ui/label.tsx @@ -1,16 +1,16 @@ -"use client" +'use client' -import * as React from "react" +import * as React from 'react' -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils' -function Label({ className, ...props }: React.ComponentProps<"label">) { +function Label({ className, ...props }: React.ComponentProps<'label'>) { return (