├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── setup │ └── action.yml └── workflows │ └── code-check.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── biome.json ├── components.json ├── next.config.ts ├── package.json ├── pnpm-lock.yaml ├── postcss.config.cjs ├── public ├── favicon.ico └── images │ └── screenshot.png ├── src ├── app │ ├── _components │ │ └── mixed-sorting-demo.tsx │ ├── icon.png │ ├── layout.tsx │ ├── manifest.ts │ ├── page.tsx │ ├── robots.ts │ └── sitemap.ts ├── components │ ├── icons.tsx │ ├── kbd.tsx │ ├── layouts │ │ ├── mode-toggle.tsx │ │ └── site-header.tsx │ ├── providers.tsx │ ├── shell.tsx │ ├── tailwind-indicator.tsx │ └── ui │ │ ├── button.tsx │ │ ├── card.tsx │ │ ├── dropdown-menu.tsx │ │ └── sortable.tsx ├── config │ └── site.ts ├── lib │ ├── composition.ts │ ├── fonts.ts │ └── utils.ts └── styles │ └── globals.css └── tsconfig.json /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | # This template is heavily inspired by the acme-corp and shadcn-ui/ui repositories. 2 | # See: https://github.com/juliusmarminge/acme-corp/blob/main/.github/ISSUE_TEMPLATE/bug_report.yml 3 | # See: https://github.com/shadcn-ui/ui/blob/main/.github/ISSUE_TEMPLATE/feature_request.yml 4 | 5 | name: Bug report 6 | description: Create a bug report to help us improve 7 | title: "[bug]: " 8 | labels: ["🐞❔ unconfirmed bug"] 9 | body: 10 | - type: textarea 11 | attributes: 12 | label: Describe the bug 13 | description: A clear and concise description of the bug, as well as what you expected to happen when encountering it. 14 | validations: 15 | required: true 16 | - type: textarea 17 | attributes: 18 | label: How to reproduce 19 | description: A step-by-step description of how to reproduce the bug. 20 | placeholder: | 21 | 1. Go to '...' 22 | 2. Click on '....' 23 | 3. See error 24 | validations: 25 | required: true 26 | - type: input 27 | attributes: 28 | label: Link to reproduction 29 | description: A link to a CodeSandbox or StackBlitz that includes a minimal reproduction of the problem. In rare cases when not applicable, you can link to a GitHub repository that we can easily run to recreate the issue. If a report is vague and does not have a reproduction, it will be closed without warning. 30 | validations: 31 | required: true 32 | - type: textarea 33 | attributes: 34 | label: Additional information 35 | description: Add any other information related to the bug here, screenshots if applicable. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | # This template is heavily inspired by the shadcn-ui/ui repository. 2 | # See: https://github.com/shadcn-ui/ui/blob/main/.github/ISSUE_TEMPLATE/config.yml 3 | 4 | blank_issues_enabled: false 5 | contact_links: 6 | - name: General questions 7 | url: https://github.com/sadmann7/sortable/discussions?category=general 8 | about: Please ask and answer questions here 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | # This template is heavily inspired by the shadcn-ui/ui repository. 2 | # See: https://github.com/shadcn-ui/ui/blob/main/.github/ISSUE_TEMPLATE/feature_request.yml 3 | 4 | name: "Feature request" 5 | description: Create a feature request for sortable 6 | title: "[feat]: " 7 | labels: ["✨ enhancement"] 8 | body: 9 | - type: markdown 10 | attributes: 11 | value: | 12 | ### Thanks for suggesting a feature request! Make sure to see if your feature request has already been suggested by searching through the existing issues. If you find a similar request, give it a thumbs up and add any additional context you have in the comments. 13 | 14 | - type: textarea 15 | id: feature-description 16 | attributes: 17 | label: Feature description 18 | description: Tell us about your feature request. 19 | placeholder: "I think this feature would be great because..." 20 | value: "Describe your feature request..." 21 | validations: 22 | required: true 23 | 24 | - type: textarea 25 | id: context 26 | attributes: 27 | label: Additional Context 28 | description: Add any other context about the feature here. 29 | placeholder: ex. screenshots, Stack Overflow links, forum links, etc. 30 | value: "Additional details here..." 31 | validations: 32 | required: false 33 | 34 | - type: checkboxes 35 | id: terms 36 | attributes: 37 | label: Before submitting 38 | description: Please ensure the following 39 | options: 40 | - label: I've made research efforts and searched the documentation 41 | required: true 42 | - label: I've searched for existing issues and PRs 43 | required: true 44 | -------------------------------------------------------------------------------- /.github/setup/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup Workflow 2 | description: Composite action that sets up pnpm and installs dependencies 3 | runs: 4 | using: "composite" 5 | steps: 6 | - uses: actions/setup-node@v4 7 | with: 8 | node-version: 20.x 9 | 10 | - name: Setup pnpm 11 | uses: pnpm/action-setup@v4 12 | with: 13 | version: 10.8.0 14 | 15 | - run: pnpm install 16 | shell: bash 17 | -------------------------------------------------------------------------------- /.github/workflows/code-check.yml: -------------------------------------------------------------------------------- 1 | name: Code check 2 | 3 | on: 4 | pull_request: 5 | branches: ["*"] 6 | push: 7 | branches: ["main"] 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 12 | 13 | env: 14 | FORCE_COLOR: 3 15 | 16 | jobs: 17 | format: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout repo 21 | uses: actions/checkout@v4 22 | - name: Setup pnpm 23 | uses: pnpm/action-setup@v4 24 | with: 25 | version: 10.8.0 26 | - uses: ./.github/setup 27 | 28 | - name: Check formatting 29 | run: pnpm lint:fix 30 | 31 | lint: 32 | runs-on: ubuntu-latest 33 | name: Lint 34 | steps: 35 | - name: Checkout repo 36 | uses: actions/checkout@v4 37 | - name: Setup pnpm 38 | uses: pnpm/action-setup@v4 39 | with: 40 | version: 10.8.0 41 | - uses: ./.github/setup 42 | 43 | - run: pnpm lint 44 | 45 | typecheck: 46 | runs-on: ubuntu-latest 47 | name: Typecheck 48 | steps: 49 | - name: Checkout repo 50 | uses: actions/checkout@v4 51 | - name: Setup pnpm 52 | uses: pnpm/action-setup@v4 53 | with: 54 | version: 10.8.0 55 | - uses: ./.github/setup 56 | 57 | - run: pnpm typecheck 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # database 12 | /prisma/db.sqlite 13 | /prisma/db.sqlite-journal 14 | db.sqlite 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | next-env.d.ts 20 | 21 | # production 22 | /build 23 | 24 | # misc 25 | .DS_Store 26 | *.pem 27 | 28 | # debug 29 | npm-debug.log* 30 | yarn-debug.log* 31 | yarn-error.log* 32 | .pnpm-debug.log* 33 | 34 | # local env files 35 | # do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables 36 | .env 37 | .env*.local 38 | 39 | # vercel 40 | .vercel 41 | 42 | # typescript 43 | *.tsbuildinfo 44 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2024 Sadman Sakib 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Sortable](https://sortable.sadmn.com) 2 | 3 | This is a sortable built with `shadcn/ui`, `radix ui`, and `dnd-kit`. It is bootstrapped with `create-t3-app`. 4 | 5 | [![Sortable](./public/images/screenshot.png)](https://sortable.sadmn.com) 6 | 7 | ## Tech Stack 8 | 9 | - **Framework:** [Next.js](https://nextjs.org) 10 | - **Styling:** [Tailwind CSS](https://tailwindcss.com) 11 | - **UI Components:** [shadcn/ui](https://ui.shadcn.com) 12 | - **Drag and Drop:** [dnd-kit](https://dndkit.com) 13 | - **Validation:** [Zod](https://zod.dev) 14 | 15 | ## Features 16 | 17 | - [x] Headless `Sortable` ui primitives built with `shadcn/ui`, `radix ui`, and `dnd-kit`. 18 | - [x] Integration with `useFieldArray` of `react-hook-form`, and `tanstack-table`. 19 | 20 | ## Running Locally 21 | 22 | 1. Clone the repository 23 | 24 | ```bash 25 | git clone https://github.com/sadmann7/uploader 26 | ``` 27 | 28 | 2. Install dependencies using pnpm 29 | 30 | ```bash 31 | pnpm install 32 | ``` 33 | 34 | 3. Start the development server 35 | 36 | ```bash 37 | pnpm run dev 38 | ``` 39 | 40 | ## How do I deploy this? 41 | 42 | Follow the deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information. 43 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", 3 | "organizeImports": { 4 | "enabled": true 5 | }, 6 | "formatter": { 7 | "enabled": true, 8 | "indentWidth": 2, 9 | "indentStyle": "space", 10 | "ignore": [ 11 | "**/node_modules", 12 | "**/dist", 13 | "**/build", 14 | "**/public", 15 | "**/.turbo", 16 | "**/.next" 17 | ] 18 | }, 19 | "linter": { 20 | "enabled": true, 21 | "rules": { 22 | "recommended": true, 23 | "a11y": { 24 | "noSvgWithoutTitle": "off", 25 | "useButtonType": "off", 26 | "useAltText": "off", 27 | "useKeyWithClickEvents": "off", 28 | "useSemanticElements": "off", 29 | "noLabelWithoutControl": "off" 30 | }, 31 | "correctness": { 32 | "noUnusedVariables": "warn", 33 | "useExhaustiveDependencies": "warn" 34 | }, 35 | "complexity": { 36 | "noBannedTypes": "off" 37 | }, 38 | "style": { 39 | "useImportType": "warn" 40 | }, 41 | "security": { 42 | "noDangerouslySetInnerHtml": "off" 43 | }, 44 | "suspicious": { 45 | "noAssignInExpressions": "off", 46 | "noArrayIndexKey": "off" 47 | }, 48 | "nursery": { 49 | "useSortedClasses": { 50 | "level": "warn", 51 | "options": { 52 | "attributes": ["classList"], 53 | "functions": ["clsx", "cva", "tw"] 54 | } 55 | } 56 | } 57 | }, 58 | "ignore": [ 59 | "**/node_modules", 60 | "**/dist", 61 | "**/build", 62 | "**/public", 63 | "**/.turbo", 64 | "**/.next" 65 | ] 66 | }, 67 | "overrides": [ 68 | { 69 | "include": ["**/*.test.ts"] 70 | } 71 | ], 72 | "vcs": { 73 | "enabled": true, 74 | "clientKind": "git", 75 | "useIgnoreFile": true 76 | }, 77 | "files": { 78 | "ignore": [ 79 | "**/node_modules", 80 | "**/dist", 81 | "**/build", 82 | "**/public", 83 | "**/.turbo", 84 | "**/.next" 85 | ] 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "new-york", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "src/styles/globals.css", 9 | "baseColor": "zinc", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | // Already doing linting and typechecking as separate tasks in CI 5 | eslint: { ignoreDuringBuilds: true }, 6 | typescript: { ignoreBuildErrors: true }, 7 | }; 8 | 9 | export default nextConfig; 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sortable", 3 | "version": "0.1.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "clean": "rimraf --glob **/node_modules **/dist **/.next pnpm-lock.yaml **/.tsbuildinfo", 8 | "build": "next build", 9 | "dev": "next dev", 10 | "start": "next start", 11 | "lint": "biome check .", 12 | "lint:fix": "biome check . --write", 13 | "typecheck": "tsc --noEmit", 14 | "check": "pnpm lint && pnpm typecheck", 15 | "shadcn": "pnpm dlx shadcn@latest" 16 | }, 17 | "dependencies": { 18 | "@dnd-kit/core": "^6.3.1", 19 | "@dnd-kit/modifiers": "^9.0.0", 20 | "@dnd-kit/sortable": "^10.0.0", 21 | "@dnd-kit/utilities": "^3.2.2", 22 | "@radix-ui/react-dropdown-menu": "^2.1.7", 23 | "@radix-ui/react-slot": "^1.2.0", 24 | "class-variance-authority": "^0.7.1", 25 | "clsx": "^2.1.1", 26 | "lucide-react": "^0.488.0", 27 | "next": "15.3.0", 28 | "next-themes": "^0.4.6", 29 | "react": "19.1.0", 30 | "react-dom": "19.1.0", 31 | "tailwind-merge": "^3.2.0" 32 | }, 33 | "devDependencies": { 34 | "@biomejs/biome": "^1.9.4", 35 | "@tailwindcss/postcss": "^4.1.3", 36 | "@types/node": "^22.14.1", 37 | "@types/react": "^19.1.1", 38 | "@types/react-dom": "^19.1.2", 39 | "postcss": "^8.5.3", 40 | "rimraf": "^6.0.1", 41 | "tailwindcss": "^4.1.3", 42 | "tw-animate-css": "^1.2.5", 43 | "typescript": "^5.8.3" 44 | }, 45 | "ct3aMetadata": { 46 | "initVersion": "7.33.0" 47 | }, 48 | "packageManager": "pnpm@10.8.0" 49 | } 50 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@dnd-kit/core': 12 | specifier: ^6.3.1 13 | version: 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 14 | '@dnd-kit/modifiers': 15 | specifier: ^9.0.0 16 | version: 9.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) 17 | '@dnd-kit/sortable': 18 | specifier: ^10.0.0 19 | version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) 20 | '@dnd-kit/utilities': 21 | specifier: ^3.2.2 22 | version: 3.2.2(react@19.1.0) 23 | '@radix-ui/react-dropdown-menu': 24 | specifier: ^2.1.7 25 | version: 2.1.7(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 26 | '@radix-ui/react-slot': 27 | specifier: ^1.2.0 28 | version: 1.2.0(@types/react@19.1.1)(react@19.1.0) 29 | class-variance-authority: 30 | specifier: ^0.7.1 31 | version: 0.7.1 32 | clsx: 33 | specifier: ^2.1.1 34 | version: 2.1.1 35 | lucide-react: 36 | specifier: ^0.488.0 37 | version: 0.488.0(react@19.1.0) 38 | next: 39 | specifier: 15.3.0 40 | version: 15.3.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 41 | next-themes: 42 | specifier: ^0.4.6 43 | version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 44 | react: 45 | specifier: 19.1.0 46 | version: 19.1.0 47 | react-dom: 48 | specifier: 19.1.0 49 | version: 19.1.0(react@19.1.0) 50 | tailwind-merge: 51 | specifier: ^3.2.0 52 | version: 3.2.0 53 | devDependencies: 54 | '@biomejs/biome': 55 | specifier: ^1.9.4 56 | version: 1.9.4 57 | '@tailwindcss/postcss': 58 | specifier: ^4.1.3 59 | version: 4.1.3 60 | '@types/node': 61 | specifier: ^22.14.1 62 | version: 22.14.1 63 | '@types/react': 64 | specifier: ^19.1.1 65 | version: 19.1.1 66 | '@types/react-dom': 67 | specifier: ^19.1.2 68 | version: 19.1.2(@types/react@19.1.1) 69 | postcss: 70 | specifier: ^8.5.3 71 | version: 8.5.3 72 | rimraf: 73 | specifier: ^6.0.1 74 | version: 6.0.1 75 | tailwindcss: 76 | specifier: ^4.1.3 77 | version: 4.1.3 78 | tw-animate-css: 79 | specifier: ^1.2.5 80 | version: 1.2.5 81 | typescript: 82 | specifier: ^5.8.3 83 | version: 5.8.3 84 | 85 | packages: 86 | 87 | '@alloc/quick-lru@5.2.0': 88 | resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} 89 | engines: {node: '>=10'} 90 | 91 | '@biomejs/biome@1.9.4': 92 | resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} 93 | engines: {node: '>=14.21.3'} 94 | hasBin: true 95 | 96 | '@biomejs/cli-darwin-arm64@1.9.4': 97 | resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} 98 | engines: {node: '>=14.21.3'} 99 | cpu: [arm64] 100 | os: [darwin] 101 | 102 | '@biomejs/cli-darwin-x64@1.9.4': 103 | resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} 104 | engines: {node: '>=14.21.3'} 105 | cpu: [x64] 106 | os: [darwin] 107 | 108 | '@biomejs/cli-linux-arm64-musl@1.9.4': 109 | resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} 110 | engines: {node: '>=14.21.3'} 111 | cpu: [arm64] 112 | os: [linux] 113 | 114 | '@biomejs/cli-linux-arm64@1.9.4': 115 | resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} 116 | engines: {node: '>=14.21.3'} 117 | cpu: [arm64] 118 | os: [linux] 119 | 120 | '@biomejs/cli-linux-x64-musl@1.9.4': 121 | resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} 122 | engines: {node: '>=14.21.3'} 123 | cpu: [x64] 124 | os: [linux] 125 | 126 | '@biomejs/cli-linux-x64@1.9.4': 127 | resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} 128 | engines: {node: '>=14.21.3'} 129 | cpu: [x64] 130 | os: [linux] 131 | 132 | '@biomejs/cli-win32-arm64@1.9.4': 133 | resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} 134 | engines: {node: '>=14.21.3'} 135 | cpu: [arm64] 136 | os: [win32] 137 | 138 | '@biomejs/cli-win32-x64@1.9.4': 139 | resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} 140 | engines: {node: '>=14.21.3'} 141 | cpu: [x64] 142 | os: [win32] 143 | 144 | '@dnd-kit/accessibility@3.1.1': 145 | resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} 146 | peerDependencies: 147 | react: '>=16.8.0' 148 | 149 | '@dnd-kit/core@6.3.1': 150 | resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} 151 | peerDependencies: 152 | react: '>=16.8.0' 153 | react-dom: '>=16.8.0' 154 | 155 | '@dnd-kit/modifiers@9.0.0': 156 | resolution: {integrity: sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==} 157 | peerDependencies: 158 | '@dnd-kit/core': ^6.3.0 159 | react: '>=16.8.0' 160 | 161 | '@dnd-kit/sortable@10.0.0': 162 | resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} 163 | peerDependencies: 164 | '@dnd-kit/core': ^6.3.0 165 | react: '>=16.8.0' 166 | 167 | '@dnd-kit/utilities@3.2.2': 168 | resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} 169 | peerDependencies: 170 | react: '>=16.8.0' 171 | 172 | '@emnapi/runtime@1.4.1': 173 | resolution: {integrity: sha512-LMshMVP0ZhACNjQNYXiU1iZJ6QCcv0lUdPDPugqGvCGXt5xtRVBPdtA0qU12pEXZzpWAhWlZYptfdAFq10DOVQ==} 174 | 175 | '@floating-ui/core@1.6.9': 176 | resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} 177 | 178 | '@floating-ui/dom@1.6.13': 179 | resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} 180 | 181 | '@floating-ui/react-dom@2.1.2': 182 | resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} 183 | peerDependencies: 184 | react: '>=16.8.0' 185 | react-dom: '>=16.8.0' 186 | 187 | '@floating-ui/utils@0.2.9': 188 | resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} 189 | 190 | '@img/sharp-darwin-arm64@0.34.1': 191 | resolution: {integrity: sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==} 192 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 193 | cpu: [arm64] 194 | os: [darwin] 195 | 196 | '@img/sharp-darwin-x64@0.34.1': 197 | resolution: {integrity: sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==} 198 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 199 | cpu: [x64] 200 | os: [darwin] 201 | 202 | '@img/sharp-libvips-darwin-arm64@1.1.0': 203 | resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==} 204 | cpu: [arm64] 205 | os: [darwin] 206 | 207 | '@img/sharp-libvips-darwin-x64@1.1.0': 208 | resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==} 209 | cpu: [x64] 210 | os: [darwin] 211 | 212 | '@img/sharp-libvips-linux-arm64@1.1.0': 213 | resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==} 214 | cpu: [arm64] 215 | os: [linux] 216 | 217 | '@img/sharp-libvips-linux-arm@1.1.0': 218 | resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==} 219 | cpu: [arm] 220 | os: [linux] 221 | 222 | '@img/sharp-libvips-linux-ppc64@1.1.0': 223 | resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==} 224 | cpu: [ppc64] 225 | os: [linux] 226 | 227 | '@img/sharp-libvips-linux-s390x@1.1.0': 228 | resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==} 229 | cpu: [s390x] 230 | os: [linux] 231 | 232 | '@img/sharp-libvips-linux-x64@1.1.0': 233 | resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==} 234 | cpu: [x64] 235 | os: [linux] 236 | 237 | '@img/sharp-libvips-linuxmusl-arm64@1.1.0': 238 | resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==} 239 | cpu: [arm64] 240 | os: [linux] 241 | 242 | '@img/sharp-libvips-linuxmusl-x64@1.1.0': 243 | resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==} 244 | cpu: [x64] 245 | os: [linux] 246 | 247 | '@img/sharp-linux-arm64@0.34.1': 248 | resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==} 249 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 250 | cpu: [arm64] 251 | os: [linux] 252 | 253 | '@img/sharp-linux-arm@0.34.1': 254 | resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==} 255 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 256 | cpu: [arm] 257 | os: [linux] 258 | 259 | '@img/sharp-linux-s390x@0.34.1': 260 | resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==} 261 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 262 | cpu: [s390x] 263 | os: [linux] 264 | 265 | '@img/sharp-linux-x64@0.34.1': 266 | resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==} 267 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 268 | cpu: [x64] 269 | os: [linux] 270 | 271 | '@img/sharp-linuxmusl-arm64@0.34.1': 272 | resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==} 273 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 274 | cpu: [arm64] 275 | os: [linux] 276 | 277 | '@img/sharp-linuxmusl-x64@0.34.1': 278 | resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==} 279 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 280 | cpu: [x64] 281 | os: [linux] 282 | 283 | '@img/sharp-wasm32@0.34.1': 284 | resolution: {integrity: sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==} 285 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 286 | cpu: [wasm32] 287 | 288 | '@img/sharp-win32-ia32@0.34.1': 289 | resolution: {integrity: sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==} 290 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 291 | cpu: [ia32] 292 | os: [win32] 293 | 294 | '@img/sharp-win32-x64@0.34.1': 295 | resolution: {integrity: sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==} 296 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 297 | cpu: [x64] 298 | os: [win32] 299 | 300 | '@isaacs/cliui@8.0.2': 301 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 302 | engines: {node: '>=12'} 303 | 304 | '@next/env@15.3.0': 305 | resolution: {integrity: sha512-6mDmHX24nWlHOlbwUiAOmMyY7KELimmi+ed8qWcJYjqXeC+G6JzPZ3QosOAfjNwgMIzwhXBiRiCgdh8axTTdTA==} 306 | 307 | '@next/swc-darwin-arm64@15.3.0': 308 | resolution: {integrity: sha512-PDQcByT0ZfF2q7QR9d+PNj3wlNN4K6Q8JoHMwFyk252gWo4gKt7BF8Y2+KBgDjTFBETXZ/TkBEUY7NIIY7A/Kw==} 309 | engines: {node: '>= 10'} 310 | cpu: [arm64] 311 | os: [darwin] 312 | 313 | '@next/swc-darwin-x64@15.3.0': 314 | resolution: {integrity: sha512-m+eO21yg80En8HJ5c49AOQpFDq+nP51nu88ZOMCorvw3g//8g1JSUsEiPSiFpJo1KCTQ+jm9H0hwXK49H/RmXg==} 315 | engines: {node: '>= 10'} 316 | cpu: [x64] 317 | os: [darwin] 318 | 319 | '@next/swc-linux-arm64-gnu@15.3.0': 320 | resolution: {integrity: sha512-H0Kk04ZNzb6Aq/G6e0un4B3HekPnyy6D+eUBYPJv9Abx8KDYgNMWzKt4Qhj57HXV3sTTjsfc1Trc1SxuhQB+Tg==} 321 | engines: {node: '>= 10'} 322 | cpu: [arm64] 323 | os: [linux] 324 | 325 | '@next/swc-linux-arm64-musl@15.3.0': 326 | resolution: {integrity: sha512-k8GVkdMrh/+J9uIv/GpnHakzgDQhrprJ/FbGQvwWmstaeFG06nnAoZCJV+wO/bb603iKV1BXt4gHG+s2buJqZA==} 327 | engines: {node: '>= 10'} 328 | cpu: [arm64] 329 | os: [linux] 330 | 331 | '@next/swc-linux-x64-gnu@15.3.0': 332 | resolution: {integrity: sha512-ZMQ9yzDEts/vkpFLRAqfYO1wSpIJGlQNK9gZ09PgyjBJUmg8F/bb8fw2EXKgEaHbCc4gmqMpDfh+T07qUphp9A==} 333 | engines: {node: '>= 10'} 334 | cpu: [x64] 335 | os: [linux] 336 | 337 | '@next/swc-linux-x64-musl@15.3.0': 338 | resolution: {integrity: sha512-RFwq5VKYTw9TMr4T3e5HRP6T4RiAzfDJ6XsxH8j/ZeYq2aLsBqCkFzwMI0FmnSsLaUbOb46Uov0VvN3UciHX5A==} 339 | engines: {node: '>= 10'} 340 | cpu: [x64] 341 | os: [linux] 342 | 343 | '@next/swc-win32-arm64-msvc@15.3.0': 344 | resolution: {integrity: sha512-a7kUbqa/k09xPjfCl0RSVAvEjAkYBYxUzSVAzk2ptXiNEL+4bDBo9wNC43G/osLA/EOGzG4CuNRFnQyIHfkRgQ==} 345 | engines: {node: '>= 10'} 346 | cpu: [arm64] 347 | os: [win32] 348 | 349 | '@next/swc-win32-x64-msvc@15.3.0': 350 | resolution: {integrity: sha512-vHUQS4YVGJPmpjn7r5lEZuMhK5UQBNBRSB+iGDvJjaNk649pTIcRluDWNb9siunyLLiu/LDPHfvxBtNamyuLTw==} 351 | engines: {node: '>= 10'} 352 | cpu: [x64] 353 | os: [win32] 354 | 355 | '@radix-ui/primitive@1.1.2': 356 | resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} 357 | 358 | '@radix-ui/react-arrow@1.1.3': 359 | resolution: {integrity: sha512-2dvVU4jva0qkNZH6HHWuSz5FN5GeU5tymvCgutF8WaXz9WnD1NgUhy73cqzkjkN4Zkn8lfTPv5JIfrC221W+Nw==} 360 | peerDependencies: 361 | '@types/react': '*' 362 | '@types/react-dom': '*' 363 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 364 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 365 | peerDependenciesMeta: 366 | '@types/react': 367 | optional: true 368 | '@types/react-dom': 369 | optional: true 370 | 371 | '@radix-ui/react-collection@1.1.3': 372 | resolution: {integrity: sha512-mM2pxoQw5HJ49rkzwOs7Y6J4oYH22wS8BfK2/bBxROlI4xuR0c4jEenQP63LlTlDkO6Buj2Vt+QYAYcOgqtrXA==} 373 | peerDependencies: 374 | '@types/react': '*' 375 | '@types/react-dom': '*' 376 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 377 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 378 | peerDependenciesMeta: 379 | '@types/react': 380 | optional: true 381 | '@types/react-dom': 382 | optional: true 383 | 384 | '@radix-ui/react-compose-refs@1.1.2': 385 | resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} 386 | peerDependencies: 387 | '@types/react': '*' 388 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 389 | peerDependenciesMeta: 390 | '@types/react': 391 | optional: true 392 | 393 | '@radix-ui/react-context@1.1.2': 394 | resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} 395 | peerDependencies: 396 | '@types/react': '*' 397 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 398 | peerDependenciesMeta: 399 | '@types/react': 400 | optional: true 401 | 402 | '@radix-ui/react-direction@1.1.1': 403 | resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} 404 | peerDependencies: 405 | '@types/react': '*' 406 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 407 | peerDependenciesMeta: 408 | '@types/react': 409 | optional: true 410 | 411 | '@radix-ui/react-dismissable-layer@1.1.6': 412 | resolution: {integrity: sha512-7gpgMT2gyKym9Jz2ZhlRXSg2y6cNQIK8d/cqBZ0RBCaps8pFryCWXiUKI+uHGFrhMrbGUP7U6PWgiXzIxoyF3Q==} 413 | peerDependencies: 414 | '@types/react': '*' 415 | '@types/react-dom': '*' 416 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 417 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 418 | peerDependenciesMeta: 419 | '@types/react': 420 | optional: true 421 | '@types/react-dom': 422 | optional: true 423 | 424 | '@radix-ui/react-dropdown-menu@2.1.7': 425 | resolution: {integrity: sha512-7/1LiuNZuCQE3IzdicGoHdQOHkS2Q08+7p8w6TXZ6ZjgAULaCI85ZY15yPl4o4FVgoKLRT43/rsfNVN8osClQQ==} 426 | peerDependencies: 427 | '@types/react': '*' 428 | '@types/react-dom': '*' 429 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 430 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 431 | peerDependenciesMeta: 432 | '@types/react': 433 | optional: true 434 | '@types/react-dom': 435 | optional: true 436 | 437 | '@radix-ui/react-focus-guards@1.1.2': 438 | resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} 439 | peerDependencies: 440 | '@types/react': '*' 441 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 442 | peerDependenciesMeta: 443 | '@types/react': 444 | optional: true 445 | 446 | '@radix-ui/react-focus-scope@1.1.3': 447 | resolution: {integrity: sha512-4XaDlq0bPt7oJwR+0k0clCiCO/7lO7NKZTAaJBYxDNQT/vj4ig0/UvctrRscZaFREpRvUTkpKR96ov1e6jptQg==} 448 | peerDependencies: 449 | '@types/react': '*' 450 | '@types/react-dom': '*' 451 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 452 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 453 | peerDependenciesMeta: 454 | '@types/react': 455 | optional: true 456 | '@types/react-dom': 457 | optional: true 458 | 459 | '@radix-ui/react-id@1.1.1': 460 | resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} 461 | peerDependencies: 462 | '@types/react': '*' 463 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 464 | peerDependenciesMeta: 465 | '@types/react': 466 | optional: true 467 | 468 | '@radix-ui/react-menu@2.1.7': 469 | resolution: {integrity: sha512-tBODsrk68rOi1/iQzbM54toFF+gSw/y+eQgttFflqlGekuSebNqvFNHjJgjqPhiMb4Fw9A0zNFly1QT6ZFdQ+Q==} 470 | peerDependencies: 471 | '@types/react': '*' 472 | '@types/react-dom': '*' 473 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 474 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 475 | peerDependenciesMeta: 476 | '@types/react': 477 | optional: true 478 | '@types/react-dom': 479 | optional: true 480 | 481 | '@radix-ui/react-popper@1.2.3': 482 | resolution: {integrity: sha512-iNb9LYUMkne9zIahukgQmHlSBp9XWGeQQ7FvUGNk45ywzOb6kQa+Ca38OphXlWDiKvyneo9S+KSJsLfLt8812A==} 483 | peerDependencies: 484 | '@types/react': '*' 485 | '@types/react-dom': '*' 486 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 487 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 488 | peerDependenciesMeta: 489 | '@types/react': 490 | optional: true 491 | '@types/react-dom': 492 | optional: true 493 | 494 | '@radix-ui/react-portal@1.1.5': 495 | resolution: {integrity: sha512-ps/67ZqsFm+Mb6lSPJpfhRLrVL2i2fntgCmGMqqth4eaGUf+knAuuRtWVJrNjUhExgmdRqftSgzpf0DF0n6yXA==} 496 | peerDependencies: 497 | '@types/react': '*' 498 | '@types/react-dom': '*' 499 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 500 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 501 | peerDependenciesMeta: 502 | '@types/react': 503 | optional: true 504 | '@types/react-dom': 505 | optional: true 506 | 507 | '@radix-ui/react-presence@1.1.3': 508 | resolution: {integrity: sha512-IrVLIhskYhH3nLvtcBLQFZr61tBG7wx7O3kEmdzcYwRGAEBmBicGGL7ATzNgruYJ3xBTbuzEEq9OXJM3PAX3tA==} 509 | peerDependencies: 510 | '@types/react': '*' 511 | '@types/react-dom': '*' 512 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 513 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 514 | peerDependenciesMeta: 515 | '@types/react': 516 | optional: true 517 | '@types/react-dom': 518 | optional: true 519 | 520 | '@radix-ui/react-primitive@2.0.3': 521 | resolution: {integrity: sha512-Pf/t/GkndH7CQ8wE2hbkXA+WyZ83fhQQn5DDmwDiDo6AwN/fhaH8oqZ0jRjMrO2iaMhDi6P1HRx6AZwyMinY1g==} 522 | peerDependencies: 523 | '@types/react': '*' 524 | '@types/react-dom': '*' 525 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 526 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 527 | peerDependenciesMeta: 528 | '@types/react': 529 | optional: true 530 | '@types/react-dom': 531 | optional: true 532 | 533 | '@radix-ui/react-roving-focus@1.1.3': 534 | resolution: {integrity: sha512-ufbpLUjZiOg4iYgb2hQrWXEPYX6jOLBbR27bDyAff5GYMRrCzcze8lukjuXVUQvJ6HZe8+oL+hhswDcjmcgVyg==} 535 | peerDependencies: 536 | '@types/react': '*' 537 | '@types/react-dom': '*' 538 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 539 | react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 540 | peerDependenciesMeta: 541 | '@types/react': 542 | optional: true 543 | '@types/react-dom': 544 | optional: true 545 | 546 | '@radix-ui/react-slot@1.2.0': 547 | resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==} 548 | peerDependencies: 549 | '@types/react': '*' 550 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 551 | peerDependenciesMeta: 552 | '@types/react': 553 | optional: true 554 | 555 | '@radix-ui/react-use-callback-ref@1.1.1': 556 | resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} 557 | peerDependencies: 558 | '@types/react': '*' 559 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 560 | peerDependenciesMeta: 561 | '@types/react': 562 | optional: true 563 | 564 | '@radix-ui/react-use-controllable-state@1.1.1': 565 | resolution: {integrity: sha512-YnEXIy8/ga01Y1PN0VfaNH//MhA91JlEGVBDxDzROqwrAtG5Yr2QGEPz8A/rJA3C7ZAHryOYGaUv8fLSW2H/mg==} 566 | peerDependencies: 567 | '@types/react': '*' 568 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 569 | peerDependenciesMeta: 570 | '@types/react': 571 | optional: true 572 | 573 | '@radix-ui/react-use-escape-keydown@1.1.1': 574 | resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} 575 | peerDependencies: 576 | '@types/react': '*' 577 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 578 | peerDependenciesMeta: 579 | '@types/react': 580 | optional: true 581 | 582 | '@radix-ui/react-use-layout-effect@1.1.1': 583 | resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} 584 | peerDependencies: 585 | '@types/react': '*' 586 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 587 | peerDependenciesMeta: 588 | '@types/react': 589 | optional: true 590 | 591 | '@radix-ui/react-use-rect@1.1.1': 592 | resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} 593 | peerDependencies: 594 | '@types/react': '*' 595 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 596 | peerDependenciesMeta: 597 | '@types/react': 598 | optional: true 599 | 600 | '@radix-ui/react-use-size@1.1.1': 601 | resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} 602 | peerDependencies: 603 | '@types/react': '*' 604 | react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc 605 | peerDependenciesMeta: 606 | '@types/react': 607 | optional: true 608 | 609 | '@radix-ui/rect@1.1.1': 610 | resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} 611 | 612 | '@swc/counter@0.1.3': 613 | resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} 614 | 615 | '@swc/helpers@0.5.15': 616 | resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} 617 | 618 | '@tailwindcss/node@4.1.3': 619 | resolution: {integrity: sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA==} 620 | 621 | '@tailwindcss/oxide-android-arm64@4.1.3': 622 | resolution: {integrity: sha512-cxklKjtNLwFl3mDYw4XpEfBY+G8ssSg9ADL4Wm6//5woi3XGqlxFsnV5Zb6v07dxw1NvEX2uoqsxO/zWQsgR+g==} 623 | engines: {node: '>= 10'} 624 | cpu: [arm64] 625 | os: [android] 626 | 627 | '@tailwindcss/oxide-darwin-arm64@4.1.3': 628 | resolution: {integrity: sha512-mqkf2tLR5VCrjBvuRDwzKNShRu99gCAVMkVsaEOFvv6cCjlEKXRecPu9DEnxp6STk5z+Vlbh1M5zY3nQCXMXhw==} 629 | engines: {node: '>= 10'} 630 | cpu: [arm64] 631 | os: [darwin] 632 | 633 | '@tailwindcss/oxide-darwin-x64@4.1.3': 634 | resolution: {integrity: sha512-7sGraGaWzXvCLyxrc7d+CCpUN3fYnkkcso3rCzwUmo/LteAl2ZGCDlGvDD8Y/1D3ngxT8KgDj1DSwOnNewKhmg==} 635 | engines: {node: '>= 10'} 636 | cpu: [x64] 637 | os: [darwin] 638 | 639 | '@tailwindcss/oxide-freebsd-x64@4.1.3': 640 | resolution: {integrity: sha512-E2+PbcbzIReaAYZe997wb9rId246yDkCwAakllAWSGqe6VTg9hHle67hfH6ExjpV2LSK/siRzBUs5wVff3RW9w==} 641 | engines: {node: '>= 10'} 642 | cpu: [x64] 643 | os: [freebsd] 644 | 645 | '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.3': 646 | resolution: {integrity: sha512-GvfbJ8wjSSjbLFFE3UYz4Eh8i4L6GiEYqCtA8j2Zd2oXriPuom/Ah/64pg/szWycQpzRnbDiJozoxFU2oJZyfg==} 647 | engines: {node: '>= 10'} 648 | cpu: [arm] 649 | os: [linux] 650 | 651 | '@tailwindcss/oxide-linux-arm64-gnu@4.1.3': 652 | resolution: {integrity: sha512-35UkuCWQTeG9BHcBQXndDOrpsnt3Pj9NVIB4CgNiKmpG8GnCNXeMczkUpOoqcOhO6Cc/mM2W7kaQ/MTEENDDXg==} 653 | engines: {node: '>= 10'} 654 | cpu: [arm64] 655 | os: [linux] 656 | 657 | '@tailwindcss/oxide-linux-arm64-musl@4.1.3': 658 | resolution: {integrity: sha512-dm18aQiML5QCj9DQo7wMbt1Z2tl3Giht54uVR87a84X8qRtuXxUqnKQkRDK5B4bCOmcZ580lF9YcoMkbDYTXHQ==} 659 | engines: {node: '>= 10'} 660 | cpu: [arm64] 661 | os: [linux] 662 | 663 | '@tailwindcss/oxide-linux-x64-gnu@4.1.3': 664 | resolution: {integrity: sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA==} 665 | engines: {node: '>= 10'} 666 | cpu: [x64] 667 | os: [linux] 668 | 669 | '@tailwindcss/oxide-linux-x64-musl@4.1.3': 670 | resolution: {integrity: sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw==} 671 | engines: {node: '>= 10'} 672 | cpu: [x64] 673 | os: [linux] 674 | 675 | '@tailwindcss/oxide-win32-arm64-msvc@4.1.3': 676 | resolution: {integrity: sha512-PEj7XR4OGTGoboTIAdXicKuWl4EQIjKHKuR+bFy9oYN7CFZo0eu74+70O4XuERX4yjqVZGAkCdglBODlgqcCXg==} 677 | engines: {node: '>= 10'} 678 | cpu: [arm64] 679 | os: [win32] 680 | 681 | '@tailwindcss/oxide-win32-x64-msvc@4.1.3': 682 | resolution: {integrity: sha512-T8gfxECWDBENotpw3HR9SmNiHC9AOJdxs+woasRZ8Q/J4VHN0OMs7F+4yVNZ9EVN26Wv6mZbK0jv7eHYuLJLwA==} 683 | engines: {node: '>= 10'} 684 | cpu: [x64] 685 | os: [win32] 686 | 687 | '@tailwindcss/oxide@4.1.3': 688 | resolution: {integrity: sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ==} 689 | engines: {node: '>= 10'} 690 | 691 | '@tailwindcss/postcss@4.1.3': 692 | resolution: {integrity: sha512-6s5nJODm98F++QT49qn8xJKHQRamhYHfMi3X7/ltxiSQ9dyRsaFSfFkfaMsanWzf+TMYQtbk8mt5f6cCVXJwfg==} 693 | 694 | '@types/node@22.14.1': 695 | resolution: {integrity: sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==} 696 | 697 | '@types/react-dom@19.1.2': 698 | resolution: {integrity: sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==} 699 | peerDependencies: 700 | '@types/react': ^19.0.0 701 | 702 | '@types/react@19.1.1': 703 | resolution: {integrity: sha512-ePapxDL7qrgqSF67s0h9m412d9DbXyC1n59O2st+9rjuuamWsZuD2w55rqY12CbzsZ7uVXb5Nw0gEp9Z8MMutQ==} 704 | 705 | ansi-regex@5.0.1: 706 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 707 | engines: {node: '>=8'} 708 | 709 | ansi-regex@6.1.0: 710 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 711 | engines: {node: '>=12'} 712 | 713 | ansi-styles@4.3.0: 714 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 715 | engines: {node: '>=8'} 716 | 717 | ansi-styles@6.2.1: 718 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 719 | engines: {node: '>=12'} 720 | 721 | aria-hidden@1.2.4: 722 | resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} 723 | engines: {node: '>=10'} 724 | 725 | balanced-match@1.0.2: 726 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 727 | 728 | brace-expansion@2.0.1: 729 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 730 | 731 | busboy@1.6.0: 732 | resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} 733 | engines: {node: '>=10.16.0'} 734 | 735 | caniuse-lite@1.0.30001713: 736 | resolution: {integrity: sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==} 737 | 738 | class-variance-authority@0.7.1: 739 | resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} 740 | 741 | client-only@0.0.1: 742 | resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} 743 | 744 | clsx@2.1.1: 745 | resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} 746 | engines: {node: '>=6'} 747 | 748 | color-convert@2.0.1: 749 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 750 | engines: {node: '>=7.0.0'} 751 | 752 | color-name@1.1.4: 753 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 754 | 755 | color-string@1.9.1: 756 | resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} 757 | 758 | color@4.2.3: 759 | resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} 760 | engines: {node: '>=12.5.0'} 761 | 762 | cross-spawn@7.0.6: 763 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 764 | engines: {node: '>= 8'} 765 | 766 | csstype@3.1.3: 767 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 768 | 769 | detect-libc@2.0.3: 770 | resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} 771 | engines: {node: '>=8'} 772 | 773 | detect-node-es@1.1.0: 774 | resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} 775 | 776 | eastasianwidth@0.2.0: 777 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 778 | 779 | emoji-regex@8.0.0: 780 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 781 | 782 | emoji-regex@9.2.2: 783 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 784 | 785 | enhanced-resolve@5.18.1: 786 | resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} 787 | engines: {node: '>=10.13.0'} 788 | 789 | foreground-child@3.3.1: 790 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 791 | engines: {node: '>=14'} 792 | 793 | get-nonce@1.0.1: 794 | resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} 795 | engines: {node: '>=6'} 796 | 797 | glob@11.0.1: 798 | resolution: {integrity: sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==} 799 | engines: {node: 20 || >=22} 800 | hasBin: true 801 | 802 | graceful-fs@4.2.11: 803 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 804 | 805 | is-arrayish@0.3.2: 806 | resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} 807 | 808 | is-fullwidth-code-point@3.0.0: 809 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 810 | engines: {node: '>=8'} 811 | 812 | isexe@2.0.0: 813 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 814 | 815 | jackspeak@4.1.0: 816 | resolution: {integrity: sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==} 817 | engines: {node: 20 || >=22} 818 | 819 | jiti@2.4.2: 820 | resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} 821 | hasBin: true 822 | 823 | lightningcss-darwin-arm64@1.29.2: 824 | resolution: {integrity: sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==} 825 | engines: {node: '>= 12.0.0'} 826 | cpu: [arm64] 827 | os: [darwin] 828 | 829 | lightningcss-darwin-x64@1.29.2: 830 | resolution: {integrity: sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==} 831 | engines: {node: '>= 12.0.0'} 832 | cpu: [x64] 833 | os: [darwin] 834 | 835 | lightningcss-freebsd-x64@1.29.2: 836 | resolution: {integrity: sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==} 837 | engines: {node: '>= 12.0.0'} 838 | cpu: [x64] 839 | os: [freebsd] 840 | 841 | lightningcss-linux-arm-gnueabihf@1.29.2: 842 | resolution: {integrity: sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==} 843 | engines: {node: '>= 12.0.0'} 844 | cpu: [arm] 845 | os: [linux] 846 | 847 | lightningcss-linux-arm64-gnu@1.29.2: 848 | resolution: {integrity: sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==} 849 | engines: {node: '>= 12.0.0'} 850 | cpu: [arm64] 851 | os: [linux] 852 | 853 | lightningcss-linux-arm64-musl@1.29.2: 854 | resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==} 855 | engines: {node: '>= 12.0.0'} 856 | cpu: [arm64] 857 | os: [linux] 858 | 859 | lightningcss-linux-x64-gnu@1.29.2: 860 | resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==} 861 | engines: {node: '>= 12.0.0'} 862 | cpu: [x64] 863 | os: [linux] 864 | 865 | lightningcss-linux-x64-musl@1.29.2: 866 | resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==} 867 | engines: {node: '>= 12.0.0'} 868 | cpu: [x64] 869 | os: [linux] 870 | 871 | lightningcss-win32-arm64-msvc@1.29.2: 872 | resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==} 873 | engines: {node: '>= 12.0.0'} 874 | cpu: [arm64] 875 | os: [win32] 876 | 877 | lightningcss-win32-x64-msvc@1.29.2: 878 | resolution: {integrity: sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==} 879 | engines: {node: '>= 12.0.0'} 880 | cpu: [x64] 881 | os: [win32] 882 | 883 | lightningcss@1.29.2: 884 | resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==} 885 | engines: {node: '>= 12.0.0'} 886 | 887 | lru-cache@11.1.0: 888 | resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} 889 | engines: {node: 20 || >=22} 890 | 891 | lucide-react@0.488.0: 892 | resolution: {integrity: sha512-ronlL0MyKut4CEzBY/ai2ZpKPxyWO4jUqdAkm2GNK5Zn3Rj+swDz+3lvyAUXN0PNqPKIX6XM9Xadwz/skLs/pQ==} 893 | peerDependencies: 894 | react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 895 | 896 | minimatch@10.0.1: 897 | resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} 898 | engines: {node: 20 || >=22} 899 | 900 | minipass@7.1.2: 901 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 902 | engines: {node: '>=16 || 14 >=14.17'} 903 | 904 | nanoid@3.3.11: 905 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 906 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 907 | hasBin: true 908 | 909 | next-themes@0.4.6: 910 | resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} 911 | peerDependencies: 912 | react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc 913 | react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc 914 | 915 | next@15.3.0: 916 | resolution: {integrity: sha512-k0MgP6BsK8cZ73wRjMazl2y2UcXj49ZXLDEgx6BikWuby/CN+nh81qFFI16edgd7xYpe/jj2OZEIwCoqnzz0bQ==} 917 | engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} 918 | hasBin: true 919 | peerDependencies: 920 | '@opentelemetry/api': ^1.1.0 921 | '@playwright/test': ^1.41.2 922 | babel-plugin-react-compiler: '*' 923 | react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 924 | react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 925 | sass: ^1.3.0 926 | peerDependenciesMeta: 927 | '@opentelemetry/api': 928 | optional: true 929 | '@playwright/test': 930 | optional: true 931 | babel-plugin-react-compiler: 932 | optional: true 933 | sass: 934 | optional: true 935 | 936 | package-json-from-dist@1.0.1: 937 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 938 | 939 | path-key@3.1.1: 940 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 941 | engines: {node: '>=8'} 942 | 943 | path-scurry@2.0.0: 944 | resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} 945 | engines: {node: 20 || >=22} 946 | 947 | picocolors@1.1.1: 948 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 949 | 950 | postcss@8.4.31: 951 | resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} 952 | engines: {node: ^10 || ^12 || >=14} 953 | 954 | postcss@8.5.3: 955 | resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} 956 | engines: {node: ^10 || ^12 || >=14} 957 | 958 | react-dom@19.1.0: 959 | resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} 960 | peerDependencies: 961 | react: ^19.1.0 962 | 963 | react-remove-scroll-bar@2.3.8: 964 | resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} 965 | engines: {node: '>=10'} 966 | peerDependencies: 967 | '@types/react': '*' 968 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 969 | peerDependenciesMeta: 970 | '@types/react': 971 | optional: true 972 | 973 | react-remove-scroll@2.6.3: 974 | resolution: {integrity: sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==} 975 | engines: {node: '>=10'} 976 | peerDependencies: 977 | '@types/react': '*' 978 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc 979 | peerDependenciesMeta: 980 | '@types/react': 981 | optional: true 982 | 983 | react-style-singleton@2.2.3: 984 | resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} 985 | engines: {node: '>=10'} 986 | peerDependencies: 987 | '@types/react': '*' 988 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc 989 | peerDependenciesMeta: 990 | '@types/react': 991 | optional: true 992 | 993 | react@19.1.0: 994 | resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} 995 | engines: {node: '>=0.10.0'} 996 | 997 | rimraf@6.0.1: 998 | resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} 999 | engines: {node: 20 || >=22} 1000 | hasBin: true 1001 | 1002 | scheduler@0.26.0: 1003 | resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} 1004 | 1005 | semver@7.7.1: 1006 | resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} 1007 | engines: {node: '>=10'} 1008 | hasBin: true 1009 | 1010 | sharp@0.34.1: 1011 | resolution: {integrity: sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==} 1012 | engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} 1013 | 1014 | shebang-command@2.0.0: 1015 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1016 | engines: {node: '>=8'} 1017 | 1018 | shebang-regex@3.0.0: 1019 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1020 | engines: {node: '>=8'} 1021 | 1022 | signal-exit@4.1.0: 1023 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1024 | engines: {node: '>=14'} 1025 | 1026 | simple-swizzle@0.2.2: 1027 | resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} 1028 | 1029 | source-map-js@1.2.1: 1030 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1031 | engines: {node: '>=0.10.0'} 1032 | 1033 | streamsearch@1.1.0: 1034 | resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} 1035 | engines: {node: '>=10.0.0'} 1036 | 1037 | string-width@4.2.3: 1038 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1039 | engines: {node: '>=8'} 1040 | 1041 | string-width@5.1.2: 1042 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1043 | engines: {node: '>=12'} 1044 | 1045 | strip-ansi@6.0.1: 1046 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1047 | engines: {node: '>=8'} 1048 | 1049 | strip-ansi@7.1.0: 1050 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 1051 | engines: {node: '>=12'} 1052 | 1053 | styled-jsx@5.1.6: 1054 | resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} 1055 | engines: {node: '>= 12.0.0'} 1056 | peerDependencies: 1057 | '@babel/core': '*' 1058 | babel-plugin-macros: '*' 1059 | react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' 1060 | peerDependenciesMeta: 1061 | '@babel/core': 1062 | optional: true 1063 | babel-plugin-macros: 1064 | optional: true 1065 | 1066 | tailwind-merge@3.2.0: 1067 | resolution: {integrity: sha512-FQT/OVqCD+7edmmJpsgCsY820RTD5AkBryuG5IUqR5YQZSdj5xlH5nLgH7YPths7WsLPSpSBNneJdM8aS8aeFA==} 1068 | 1069 | tailwindcss@4.1.3: 1070 | resolution: {integrity: sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g==} 1071 | 1072 | tapable@2.2.1: 1073 | resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} 1074 | engines: {node: '>=6'} 1075 | 1076 | tslib@2.8.1: 1077 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1078 | 1079 | tw-animate-css@1.2.5: 1080 | resolution: {integrity: sha512-ABzjfgVo+fDbhRREGL4KQZUqqdPgvc5zVrLyeW9/6mVqvaDepXc7EvedA+pYmMnIOsUAQMwcWzNvom26J2qYvQ==} 1081 | 1082 | typescript@5.8.3: 1083 | resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} 1084 | engines: {node: '>=14.17'} 1085 | hasBin: true 1086 | 1087 | undici-types@6.21.0: 1088 | resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 1089 | 1090 | use-callback-ref@1.3.3: 1091 | resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} 1092 | engines: {node: '>=10'} 1093 | peerDependencies: 1094 | '@types/react': '*' 1095 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc 1096 | peerDependenciesMeta: 1097 | '@types/react': 1098 | optional: true 1099 | 1100 | use-sidecar@1.1.3: 1101 | resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} 1102 | engines: {node: '>=10'} 1103 | peerDependencies: 1104 | '@types/react': '*' 1105 | react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc 1106 | peerDependenciesMeta: 1107 | '@types/react': 1108 | optional: true 1109 | 1110 | which@2.0.2: 1111 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1112 | engines: {node: '>= 8'} 1113 | hasBin: true 1114 | 1115 | wrap-ansi@7.0.0: 1116 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1117 | engines: {node: '>=10'} 1118 | 1119 | wrap-ansi@8.1.0: 1120 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1121 | engines: {node: '>=12'} 1122 | 1123 | snapshots: 1124 | 1125 | '@alloc/quick-lru@5.2.0': {} 1126 | 1127 | '@biomejs/biome@1.9.4': 1128 | optionalDependencies: 1129 | '@biomejs/cli-darwin-arm64': 1.9.4 1130 | '@biomejs/cli-darwin-x64': 1.9.4 1131 | '@biomejs/cli-linux-arm64': 1.9.4 1132 | '@biomejs/cli-linux-arm64-musl': 1.9.4 1133 | '@biomejs/cli-linux-x64': 1.9.4 1134 | '@biomejs/cli-linux-x64-musl': 1.9.4 1135 | '@biomejs/cli-win32-arm64': 1.9.4 1136 | '@biomejs/cli-win32-x64': 1.9.4 1137 | 1138 | '@biomejs/cli-darwin-arm64@1.9.4': 1139 | optional: true 1140 | 1141 | '@biomejs/cli-darwin-x64@1.9.4': 1142 | optional: true 1143 | 1144 | '@biomejs/cli-linux-arm64-musl@1.9.4': 1145 | optional: true 1146 | 1147 | '@biomejs/cli-linux-arm64@1.9.4': 1148 | optional: true 1149 | 1150 | '@biomejs/cli-linux-x64-musl@1.9.4': 1151 | optional: true 1152 | 1153 | '@biomejs/cli-linux-x64@1.9.4': 1154 | optional: true 1155 | 1156 | '@biomejs/cli-win32-arm64@1.9.4': 1157 | optional: true 1158 | 1159 | '@biomejs/cli-win32-x64@1.9.4': 1160 | optional: true 1161 | 1162 | '@dnd-kit/accessibility@3.1.1(react@19.1.0)': 1163 | dependencies: 1164 | react: 19.1.0 1165 | tslib: 2.8.1 1166 | 1167 | '@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1168 | dependencies: 1169 | '@dnd-kit/accessibility': 3.1.1(react@19.1.0) 1170 | '@dnd-kit/utilities': 3.2.2(react@19.1.0) 1171 | react: 19.1.0 1172 | react-dom: 19.1.0(react@19.1.0) 1173 | tslib: 2.8.1 1174 | 1175 | '@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': 1176 | dependencies: 1177 | '@dnd-kit/core': 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1178 | '@dnd-kit/utilities': 3.2.2(react@19.1.0) 1179 | react: 19.1.0 1180 | tslib: 2.8.1 1181 | 1182 | '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': 1183 | dependencies: 1184 | '@dnd-kit/core': 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1185 | '@dnd-kit/utilities': 3.2.2(react@19.1.0) 1186 | react: 19.1.0 1187 | tslib: 2.8.1 1188 | 1189 | '@dnd-kit/utilities@3.2.2(react@19.1.0)': 1190 | dependencies: 1191 | react: 19.1.0 1192 | tslib: 2.8.1 1193 | 1194 | '@emnapi/runtime@1.4.1': 1195 | dependencies: 1196 | tslib: 2.8.1 1197 | optional: true 1198 | 1199 | '@floating-ui/core@1.6.9': 1200 | dependencies: 1201 | '@floating-ui/utils': 0.2.9 1202 | 1203 | '@floating-ui/dom@1.6.13': 1204 | dependencies: 1205 | '@floating-ui/core': 1.6.9 1206 | '@floating-ui/utils': 0.2.9 1207 | 1208 | '@floating-ui/react-dom@2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1209 | dependencies: 1210 | '@floating-ui/dom': 1.6.13 1211 | react: 19.1.0 1212 | react-dom: 19.1.0(react@19.1.0) 1213 | 1214 | '@floating-ui/utils@0.2.9': {} 1215 | 1216 | '@img/sharp-darwin-arm64@0.34.1': 1217 | optionalDependencies: 1218 | '@img/sharp-libvips-darwin-arm64': 1.1.0 1219 | optional: true 1220 | 1221 | '@img/sharp-darwin-x64@0.34.1': 1222 | optionalDependencies: 1223 | '@img/sharp-libvips-darwin-x64': 1.1.0 1224 | optional: true 1225 | 1226 | '@img/sharp-libvips-darwin-arm64@1.1.0': 1227 | optional: true 1228 | 1229 | '@img/sharp-libvips-darwin-x64@1.1.0': 1230 | optional: true 1231 | 1232 | '@img/sharp-libvips-linux-arm64@1.1.0': 1233 | optional: true 1234 | 1235 | '@img/sharp-libvips-linux-arm@1.1.0': 1236 | optional: true 1237 | 1238 | '@img/sharp-libvips-linux-ppc64@1.1.0': 1239 | optional: true 1240 | 1241 | '@img/sharp-libvips-linux-s390x@1.1.0': 1242 | optional: true 1243 | 1244 | '@img/sharp-libvips-linux-x64@1.1.0': 1245 | optional: true 1246 | 1247 | '@img/sharp-libvips-linuxmusl-arm64@1.1.0': 1248 | optional: true 1249 | 1250 | '@img/sharp-libvips-linuxmusl-x64@1.1.0': 1251 | optional: true 1252 | 1253 | '@img/sharp-linux-arm64@0.34.1': 1254 | optionalDependencies: 1255 | '@img/sharp-libvips-linux-arm64': 1.1.0 1256 | optional: true 1257 | 1258 | '@img/sharp-linux-arm@0.34.1': 1259 | optionalDependencies: 1260 | '@img/sharp-libvips-linux-arm': 1.1.0 1261 | optional: true 1262 | 1263 | '@img/sharp-linux-s390x@0.34.1': 1264 | optionalDependencies: 1265 | '@img/sharp-libvips-linux-s390x': 1.1.0 1266 | optional: true 1267 | 1268 | '@img/sharp-linux-x64@0.34.1': 1269 | optionalDependencies: 1270 | '@img/sharp-libvips-linux-x64': 1.1.0 1271 | optional: true 1272 | 1273 | '@img/sharp-linuxmusl-arm64@0.34.1': 1274 | optionalDependencies: 1275 | '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 1276 | optional: true 1277 | 1278 | '@img/sharp-linuxmusl-x64@0.34.1': 1279 | optionalDependencies: 1280 | '@img/sharp-libvips-linuxmusl-x64': 1.1.0 1281 | optional: true 1282 | 1283 | '@img/sharp-wasm32@0.34.1': 1284 | dependencies: 1285 | '@emnapi/runtime': 1.4.1 1286 | optional: true 1287 | 1288 | '@img/sharp-win32-ia32@0.34.1': 1289 | optional: true 1290 | 1291 | '@img/sharp-win32-x64@0.34.1': 1292 | optional: true 1293 | 1294 | '@isaacs/cliui@8.0.2': 1295 | dependencies: 1296 | string-width: 5.1.2 1297 | string-width-cjs: string-width@4.2.3 1298 | strip-ansi: 7.1.0 1299 | strip-ansi-cjs: strip-ansi@6.0.1 1300 | wrap-ansi: 8.1.0 1301 | wrap-ansi-cjs: wrap-ansi@7.0.0 1302 | 1303 | '@next/env@15.3.0': {} 1304 | 1305 | '@next/swc-darwin-arm64@15.3.0': 1306 | optional: true 1307 | 1308 | '@next/swc-darwin-x64@15.3.0': 1309 | optional: true 1310 | 1311 | '@next/swc-linux-arm64-gnu@15.3.0': 1312 | optional: true 1313 | 1314 | '@next/swc-linux-arm64-musl@15.3.0': 1315 | optional: true 1316 | 1317 | '@next/swc-linux-x64-gnu@15.3.0': 1318 | optional: true 1319 | 1320 | '@next/swc-linux-x64-musl@15.3.0': 1321 | optional: true 1322 | 1323 | '@next/swc-win32-arm64-msvc@15.3.0': 1324 | optional: true 1325 | 1326 | '@next/swc-win32-x64-msvc@15.3.0': 1327 | optional: true 1328 | 1329 | '@radix-ui/primitive@1.1.2': {} 1330 | 1331 | '@radix-ui/react-arrow@1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1332 | dependencies: 1333 | '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1334 | react: 19.1.0 1335 | react-dom: 19.1.0(react@19.1.0) 1336 | optionalDependencies: 1337 | '@types/react': 19.1.1 1338 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1339 | 1340 | '@radix-ui/react-collection@1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1341 | dependencies: 1342 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1343 | '@radix-ui/react-context': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1344 | '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1345 | '@radix-ui/react-slot': 1.2.0(@types/react@19.1.1)(react@19.1.0) 1346 | react: 19.1.0 1347 | react-dom: 19.1.0(react@19.1.0) 1348 | optionalDependencies: 1349 | '@types/react': 19.1.1 1350 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1351 | 1352 | '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.1)(react@19.1.0)': 1353 | dependencies: 1354 | react: 19.1.0 1355 | optionalDependencies: 1356 | '@types/react': 19.1.1 1357 | 1358 | '@radix-ui/react-context@1.1.2(@types/react@19.1.1)(react@19.1.0)': 1359 | dependencies: 1360 | react: 19.1.0 1361 | optionalDependencies: 1362 | '@types/react': 19.1.1 1363 | 1364 | '@radix-ui/react-direction@1.1.1(@types/react@19.1.1)(react@19.1.0)': 1365 | dependencies: 1366 | react: 19.1.0 1367 | optionalDependencies: 1368 | '@types/react': 19.1.1 1369 | 1370 | '@radix-ui/react-dismissable-layer@1.1.6(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1371 | dependencies: 1372 | '@radix-ui/primitive': 1.1.2 1373 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1374 | '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1375 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1376 | '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1377 | react: 19.1.0 1378 | react-dom: 19.1.0(react@19.1.0) 1379 | optionalDependencies: 1380 | '@types/react': 19.1.1 1381 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1382 | 1383 | '@radix-ui/react-dropdown-menu@2.1.7(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1384 | dependencies: 1385 | '@radix-ui/primitive': 1.1.2 1386 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1387 | '@radix-ui/react-context': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1388 | '@radix-ui/react-id': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1389 | '@radix-ui/react-menu': 2.1.7(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1390 | '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1391 | '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1392 | react: 19.1.0 1393 | react-dom: 19.1.0(react@19.1.0) 1394 | optionalDependencies: 1395 | '@types/react': 19.1.1 1396 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1397 | 1398 | '@radix-ui/react-focus-guards@1.1.2(@types/react@19.1.1)(react@19.1.0)': 1399 | dependencies: 1400 | react: 19.1.0 1401 | optionalDependencies: 1402 | '@types/react': 19.1.1 1403 | 1404 | '@radix-ui/react-focus-scope@1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1405 | dependencies: 1406 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1407 | '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1408 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1409 | react: 19.1.0 1410 | react-dom: 19.1.0(react@19.1.0) 1411 | optionalDependencies: 1412 | '@types/react': 19.1.1 1413 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1414 | 1415 | '@radix-ui/react-id@1.1.1(@types/react@19.1.1)(react@19.1.0)': 1416 | dependencies: 1417 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1418 | react: 19.1.0 1419 | optionalDependencies: 1420 | '@types/react': 19.1.1 1421 | 1422 | '@radix-ui/react-menu@2.1.7(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1423 | dependencies: 1424 | '@radix-ui/primitive': 1.1.2 1425 | '@radix-ui/react-collection': 1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1426 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1427 | '@radix-ui/react-context': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1428 | '@radix-ui/react-direction': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1429 | '@radix-ui/react-dismissable-layer': 1.1.6(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1430 | '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1431 | '@radix-ui/react-focus-scope': 1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1432 | '@radix-ui/react-id': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1433 | '@radix-ui/react-popper': 1.2.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1434 | '@radix-ui/react-portal': 1.1.5(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1435 | '@radix-ui/react-presence': 1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1436 | '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1437 | '@radix-ui/react-roving-focus': 1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1438 | '@radix-ui/react-slot': 1.2.0(@types/react@19.1.1)(react@19.1.0) 1439 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1440 | aria-hidden: 1.2.4 1441 | react: 19.1.0 1442 | react-dom: 19.1.0(react@19.1.0) 1443 | react-remove-scroll: 2.6.3(@types/react@19.1.1)(react@19.1.0) 1444 | optionalDependencies: 1445 | '@types/react': 19.1.1 1446 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1447 | 1448 | '@radix-ui/react-popper@1.2.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1449 | dependencies: 1450 | '@floating-ui/react-dom': 2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1451 | '@radix-ui/react-arrow': 1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1452 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1453 | '@radix-ui/react-context': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1454 | '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1455 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1456 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1457 | '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1458 | '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1459 | '@radix-ui/rect': 1.1.1 1460 | react: 19.1.0 1461 | react-dom: 19.1.0(react@19.1.0) 1462 | optionalDependencies: 1463 | '@types/react': 19.1.1 1464 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1465 | 1466 | '@radix-ui/react-portal@1.1.5(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1467 | dependencies: 1468 | '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1469 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1470 | react: 19.1.0 1471 | react-dom: 19.1.0(react@19.1.0) 1472 | optionalDependencies: 1473 | '@types/react': 19.1.1 1474 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1475 | 1476 | '@radix-ui/react-presence@1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1477 | dependencies: 1478 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1479 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1480 | react: 19.1.0 1481 | react-dom: 19.1.0(react@19.1.0) 1482 | optionalDependencies: 1483 | '@types/react': 19.1.1 1484 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1485 | 1486 | '@radix-ui/react-primitive@2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1487 | dependencies: 1488 | '@radix-ui/react-slot': 1.2.0(@types/react@19.1.1)(react@19.1.0) 1489 | react: 19.1.0 1490 | react-dom: 19.1.0(react@19.1.0) 1491 | optionalDependencies: 1492 | '@types/react': 19.1.1 1493 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1494 | 1495 | '@radix-ui/react-roving-focus@1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': 1496 | dependencies: 1497 | '@radix-ui/primitive': 1.1.2 1498 | '@radix-ui/react-collection': 1.1.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1499 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1500 | '@radix-ui/react-context': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1501 | '@radix-ui/react-direction': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1502 | '@radix-ui/react-id': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1503 | '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.1.2(@types/react@19.1.1))(@types/react@19.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) 1504 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1505 | '@radix-ui/react-use-controllable-state': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1506 | react: 19.1.0 1507 | react-dom: 19.1.0(react@19.1.0) 1508 | optionalDependencies: 1509 | '@types/react': 19.1.1 1510 | '@types/react-dom': 19.1.2(@types/react@19.1.1) 1511 | 1512 | '@radix-ui/react-slot@1.2.0(@types/react@19.1.1)(react@19.1.0)': 1513 | dependencies: 1514 | '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.1)(react@19.1.0) 1515 | react: 19.1.0 1516 | optionalDependencies: 1517 | '@types/react': 19.1.1 1518 | 1519 | '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.1)(react@19.1.0)': 1520 | dependencies: 1521 | react: 19.1.0 1522 | optionalDependencies: 1523 | '@types/react': 19.1.1 1524 | 1525 | '@radix-ui/react-use-controllable-state@1.1.1(@types/react@19.1.1)(react@19.1.0)': 1526 | dependencies: 1527 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1528 | react: 19.1.0 1529 | optionalDependencies: 1530 | '@types/react': 19.1.1 1531 | 1532 | '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.1)(react@19.1.0)': 1533 | dependencies: 1534 | '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1535 | react: 19.1.0 1536 | optionalDependencies: 1537 | '@types/react': 19.1.1 1538 | 1539 | '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.1)(react@19.1.0)': 1540 | dependencies: 1541 | react: 19.1.0 1542 | optionalDependencies: 1543 | '@types/react': 19.1.1 1544 | 1545 | '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.1)(react@19.1.0)': 1546 | dependencies: 1547 | '@radix-ui/rect': 1.1.1 1548 | react: 19.1.0 1549 | optionalDependencies: 1550 | '@types/react': 19.1.1 1551 | 1552 | '@radix-ui/react-use-size@1.1.1(@types/react@19.1.1)(react@19.1.0)': 1553 | dependencies: 1554 | '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.1)(react@19.1.0) 1555 | react: 19.1.0 1556 | optionalDependencies: 1557 | '@types/react': 19.1.1 1558 | 1559 | '@radix-ui/rect@1.1.1': {} 1560 | 1561 | '@swc/counter@0.1.3': {} 1562 | 1563 | '@swc/helpers@0.5.15': 1564 | dependencies: 1565 | tslib: 2.8.1 1566 | 1567 | '@tailwindcss/node@4.1.3': 1568 | dependencies: 1569 | enhanced-resolve: 5.18.1 1570 | jiti: 2.4.2 1571 | lightningcss: 1.29.2 1572 | tailwindcss: 4.1.3 1573 | 1574 | '@tailwindcss/oxide-android-arm64@4.1.3': 1575 | optional: true 1576 | 1577 | '@tailwindcss/oxide-darwin-arm64@4.1.3': 1578 | optional: true 1579 | 1580 | '@tailwindcss/oxide-darwin-x64@4.1.3': 1581 | optional: true 1582 | 1583 | '@tailwindcss/oxide-freebsd-x64@4.1.3': 1584 | optional: true 1585 | 1586 | '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.3': 1587 | optional: true 1588 | 1589 | '@tailwindcss/oxide-linux-arm64-gnu@4.1.3': 1590 | optional: true 1591 | 1592 | '@tailwindcss/oxide-linux-arm64-musl@4.1.3': 1593 | optional: true 1594 | 1595 | '@tailwindcss/oxide-linux-x64-gnu@4.1.3': 1596 | optional: true 1597 | 1598 | '@tailwindcss/oxide-linux-x64-musl@4.1.3': 1599 | optional: true 1600 | 1601 | '@tailwindcss/oxide-win32-arm64-msvc@4.1.3': 1602 | optional: true 1603 | 1604 | '@tailwindcss/oxide-win32-x64-msvc@4.1.3': 1605 | optional: true 1606 | 1607 | '@tailwindcss/oxide@4.1.3': 1608 | optionalDependencies: 1609 | '@tailwindcss/oxide-android-arm64': 4.1.3 1610 | '@tailwindcss/oxide-darwin-arm64': 4.1.3 1611 | '@tailwindcss/oxide-darwin-x64': 4.1.3 1612 | '@tailwindcss/oxide-freebsd-x64': 4.1.3 1613 | '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.3 1614 | '@tailwindcss/oxide-linux-arm64-gnu': 4.1.3 1615 | '@tailwindcss/oxide-linux-arm64-musl': 4.1.3 1616 | '@tailwindcss/oxide-linux-x64-gnu': 4.1.3 1617 | '@tailwindcss/oxide-linux-x64-musl': 4.1.3 1618 | '@tailwindcss/oxide-win32-arm64-msvc': 4.1.3 1619 | '@tailwindcss/oxide-win32-x64-msvc': 4.1.3 1620 | 1621 | '@tailwindcss/postcss@4.1.3': 1622 | dependencies: 1623 | '@alloc/quick-lru': 5.2.0 1624 | '@tailwindcss/node': 4.1.3 1625 | '@tailwindcss/oxide': 4.1.3 1626 | postcss: 8.5.3 1627 | tailwindcss: 4.1.3 1628 | 1629 | '@types/node@22.14.1': 1630 | dependencies: 1631 | undici-types: 6.21.0 1632 | 1633 | '@types/react-dom@19.1.2(@types/react@19.1.1)': 1634 | dependencies: 1635 | '@types/react': 19.1.1 1636 | 1637 | '@types/react@19.1.1': 1638 | dependencies: 1639 | csstype: 3.1.3 1640 | 1641 | ansi-regex@5.0.1: {} 1642 | 1643 | ansi-regex@6.1.0: {} 1644 | 1645 | ansi-styles@4.3.0: 1646 | dependencies: 1647 | color-convert: 2.0.1 1648 | 1649 | ansi-styles@6.2.1: {} 1650 | 1651 | aria-hidden@1.2.4: 1652 | dependencies: 1653 | tslib: 2.8.1 1654 | 1655 | balanced-match@1.0.2: {} 1656 | 1657 | brace-expansion@2.0.1: 1658 | dependencies: 1659 | balanced-match: 1.0.2 1660 | 1661 | busboy@1.6.0: 1662 | dependencies: 1663 | streamsearch: 1.1.0 1664 | 1665 | caniuse-lite@1.0.30001713: {} 1666 | 1667 | class-variance-authority@0.7.1: 1668 | dependencies: 1669 | clsx: 2.1.1 1670 | 1671 | client-only@0.0.1: {} 1672 | 1673 | clsx@2.1.1: {} 1674 | 1675 | color-convert@2.0.1: 1676 | dependencies: 1677 | color-name: 1.1.4 1678 | 1679 | color-name@1.1.4: {} 1680 | 1681 | color-string@1.9.1: 1682 | dependencies: 1683 | color-name: 1.1.4 1684 | simple-swizzle: 0.2.2 1685 | optional: true 1686 | 1687 | color@4.2.3: 1688 | dependencies: 1689 | color-convert: 2.0.1 1690 | color-string: 1.9.1 1691 | optional: true 1692 | 1693 | cross-spawn@7.0.6: 1694 | dependencies: 1695 | path-key: 3.1.1 1696 | shebang-command: 2.0.0 1697 | which: 2.0.2 1698 | 1699 | csstype@3.1.3: {} 1700 | 1701 | detect-libc@2.0.3: {} 1702 | 1703 | detect-node-es@1.1.0: {} 1704 | 1705 | eastasianwidth@0.2.0: {} 1706 | 1707 | emoji-regex@8.0.0: {} 1708 | 1709 | emoji-regex@9.2.2: {} 1710 | 1711 | enhanced-resolve@5.18.1: 1712 | dependencies: 1713 | graceful-fs: 4.2.11 1714 | tapable: 2.2.1 1715 | 1716 | foreground-child@3.3.1: 1717 | dependencies: 1718 | cross-spawn: 7.0.6 1719 | signal-exit: 4.1.0 1720 | 1721 | get-nonce@1.0.1: {} 1722 | 1723 | glob@11.0.1: 1724 | dependencies: 1725 | foreground-child: 3.3.1 1726 | jackspeak: 4.1.0 1727 | minimatch: 10.0.1 1728 | minipass: 7.1.2 1729 | package-json-from-dist: 1.0.1 1730 | path-scurry: 2.0.0 1731 | 1732 | graceful-fs@4.2.11: {} 1733 | 1734 | is-arrayish@0.3.2: 1735 | optional: true 1736 | 1737 | is-fullwidth-code-point@3.0.0: {} 1738 | 1739 | isexe@2.0.0: {} 1740 | 1741 | jackspeak@4.1.0: 1742 | dependencies: 1743 | '@isaacs/cliui': 8.0.2 1744 | 1745 | jiti@2.4.2: {} 1746 | 1747 | lightningcss-darwin-arm64@1.29.2: 1748 | optional: true 1749 | 1750 | lightningcss-darwin-x64@1.29.2: 1751 | optional: true 1752 | 1753 | lightningcss-freebsd-x64@1.29.2: 1754 | optional: true 1755 | 1756 | lightningcss-linux-arm-gnueabihf@1.29.2: 1757 | optional: true 1758 | 1759 | lightningcss-linux-arm64-gnu@1.29.2: 1760 | optional: true 1761 | 1762 | lightningcss-linux-arm64-musl@1.29.2: 1763 | optional: true 1764 | 1765 | lightningcss-linux-x64-gnu@1.29.2: 1766 | optional: true 1767 | 1768 | lightningcss-linux-x64-musl@1.29.2: 1769 | optional: true 1770 | 1771 | lightningcss-win32-arm64-msvc@1.29.2: 1772 | optional: true 1773 | 1774 | lightningcss-win32-x64-msvc@1.29.2: 1775 | optional: true 1776 | 1777 | lightningcss@1.29.2: 1778 | dependencies: 1779 | detect-libc: 2.0.3 1780 | optionalDependencies: 1781 | lightningcss-darwin-arm64: 1.29.2 1782 | lightningcss-darwin-x64: 1.29.2 1783 | lightningcss-freebsd-x64: 1.29.2 1784 | lightningcss-linux-arm-gnueabihf: 1.29.2 1785 | lightningcss-linux-arm64-gnu: 1.29.2 1786 | lightningcss-linux-arm64-musl: 1.29.2 1787 | lightningcss-linux-x64-gnu: 1.29.2 1788 | lightningcss-linux-x64-musl: 1.29.2 1789 | lightningcss-win32-arm64-msvc: 1.29.2 1790 | lightningcss-win32-x64-msvc: 1.29.2 1791 | 1792 | lru-cache@11.1.0: {} 1793 | 1794 | lucide-react@0.488.0(react@19.1.0): 1795 | dependencies: 1796 | react: 19.1.0 1797 | 1798 | minimatch@10.0.1: 1799 | dependencies: 1800 | brace-expansion: 2.0.1 1801 | 1802 | minipass@7.1.2: {} 1803 | 1804 | nanoid@3.3.11: {} 1805 | 1806 | next-themes@0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0): 1807 | dependencies: 1808 | react: 19.1.0 1809 | react-dom: 19.1.0(react@19.1.0) 1810 | 1811 | next@15.3.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): 1812 | dependencies: 1813 | '@next/env': 15.3.0 1814 | '@swc/counter': 0.1.3 1815 | '@swc/helpers': 0.5.15 1816 | busboy: 1.6.0 1817 | caniuse-lite: 1.0.30001713 1818 | postcss: 8.4.31 1819 | react: 19.1.0 1820 | react-dom: 19.1.0(react@19.1.0) 1821 | styled-jsx: 5.1.6(react@19.1.0) 1822 | optionalDependencies: 1823 | '@next/swc-darwin-arm64': 15.3.0 1824 | '@next/swc-darwin-x64': 15.3.0 1825 | '@next/swc-linux-arm64-gnu': 15.3.0 1826 | '@next/swc-linux-arm64-musl': 15.3.0 1827 | '@next/swc-linux-x64-gnu': 15.3.0 1828 | '@next/swc-linux-x64-musl': 15.3.0 1829 | '@next/swc-win32-arm64-msvc': 15.3.0 1830 | '@next/swc-win32-x64-msvc': 15.3.0 1831 | sharp: 0.34.1 1832 | transitivePeerDependencies: 1833 | - '@babel/core' 1834 | - babel-plugin-macros 1835 | 1836 | package-json-from-dist@1.0.1: {} 1837 | 1838 | path-key@3.1.1: {} 1839 | 1840 | path-scurry@2.0.0: 1841 | dependencies: 1842 | lru-cache: 11.1.0 1843 | minipass: 7.1.2 1844 | 1845 | picocolors@1.1.1: {} 1846 | 1847 | postcss@8.4.31: 1848 | dependencies: 1849 | nanoid: 3.3.11 1850 | picocolors: 1.1.1 1851 | source-map-js: 1.2.1 1852 | 1853 | postcss@8.5.3: 1854 | dependencies: 1855 | nanoid: 3.3.11 1856 | picocolors: 1.1.1 1857 | source-map-js: 1.2.1 1858 | 1859 | react-dom@19.1.0(react@19.1.0): 1860 | dependencies: 1861 | react: 19.1.0 1862 | scheduler: 0.26.0 1863 | 1864 | react-remove-scroll-bar@2.3.8(@types/react@19.1.1)(react@19.1.0): 1865 | dependencies: 1866 | react: 19.1.0 1867 | react-style-singleton: 2.2.3(@types/react@19.1.1)(react@19.1.0) 1868 | tslib: 2.8.1 1869 | optionalDependencies: 1870 | '@types/react': 19.1.1 1871 | 1872 | react-remove-scroll@2.6.3(@types/react@19.1.1)(react@19.1.0): 1873 | dependencies: 1874 | react: 19.1.0 1875 | react-remove-scroll-bar: 2.3.8(@types/react@19.1.1)(react@19.1.0) 1876 | react-style-singleton: 2.2.3(@types/react@19.1.1)(react@19.1.0) 1877 | tslib: 2.8.1 1878 | use-callback-ref: 1.3.3(@types/react@19.1.1)(react@19.1.0) 1879 | use-sidecar: 1.1.3(@types/react@19.1.1)(react@19.1.0) 1880 | optionalDependencies: 1881 | '@types/react': 19.1.1 1882 | 1883 | react-style-singleton@2.2.3(@types/react@19.1.1)(react@19.1.0): 1884 | dependencies: 1885 | get-nonce: 1.0.1 1886 | react: 19.1.0 1887 | tslib: 2.8.1 1888 | optionalDependencies: 1889 | '@types/react': 19.1.1 1890 | 1891 | react@19.1.0: {} 1892 | 1893 | rimraf@6.0.1: 1894 | dependencies: 1895 | glob: 11.0.1 1896 | package-json-from-dist: 1.0.1 1897 | 1898 | scheduler@0.26.0: {} 1899 | 1900 | semver@7.7.1: 1901 | optional: true 1902 | 1903 | sharp@0.34.1: 1904 | dependencies: 1905 | color: 4.2.3 1906 | detect-libc: 2.0.3 1907 | semver: 7.7.1 1908 | optionalDependencies: 1909 | '@img/sharp-darwin-arm64': 0.34.1 1910 | '@img/sharp-darwin-x64': 0.34.1 1911 | '@img/sharp-libvips-darwin-arm64': 1.1.0 1912 | '@img/sharp-libvips-darwin-x64': 1.1.0 1913 | '@img/sharp-libvips-linux-arm': 1.1.0 1914 | '@img/sharp-libvips-linux-arm64': 1.1.0 1915 | '@img/sharp-libvips-linux-ppc64': 1.1.0 1916 | '@img/sharp-libvips-linux-s390x': 1.1.0 1917 | '@img/sharp-libvips-linux-x64': 1.1.0 1918 | '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 1919 | '@img/sharp-libvips-linuxmusl-x64': 1.1.0 1920 | '@img/sharp-linux-arm': 0.34.1 1921 | '@img/sharp-linux-arm64': 0.34.1 1922 | '@img/sharp-linux-s390x': 0.34.1 1923 | '@img/sharp-linux-x64': 0.34.1 1924 | '@img/sharp-linuxmusl-arm64': 0.34.1 1925 | '@img/sharp-linuxmusl-x64': 0.34.1 1926 | '@img/sharp-wasm32': 0.34.1 1927 | '@img/sharp-win32-ia32': 0.34.1 1928 | '@img/sharp-win32-x64': 0.34.1 1929 | optional: true 1930 | 1931 | shebang-command@2.0.0: 1932 | dependencies: 1933 | shebang-regex: 3.0.0 1934 | 1935 | shebang-regex@3.0.0: {} 1936 | 1937 | signal-exit@4.1.0: {} 1938 | 1939 | simple-swizzle@0.2.2: 1940 | dependencies: 1941 | is-arrayish: 0.3.2 1942 | optional: true 1943 | 1944 | source-map-js@1.2.1: {} 1945 | 1946 | streamsearch@1.1.0: {} 1947 | 1948 | string-width@4.2.3: 1949 | dependencies: 1950 | emoji-regex: 8.0.0 1951 | is-fullwidth-code-point: 3.0.0 1952 | strip-ansi: 6.0.1 1953 | 1954 | string-width@5.1.2: 1955 | dependencies: 1956 | eastasianwidth: 0.2.0 1957 | emoji-regex: 9.2.2 1958 | strip-ansi: 7.1.0 1959 | 1960 | strip-ansi@6.0.1: 1961 | dependencies: 1962 | ansi-regex: 5.0.1 1963 | 1964 | strip-ansi@7.1.0: 1965 | dependencies: 1966 | ansi-regex: 6.1.0 1967 | 1968 | styled-jsx@5.1.6(react@19.1.0): 1969 | dependencies: 1970 | client-only: 0.0.1 1971 | react: 19.1.0 1972 | 1973 | tailwind-merge@3.2.0: {} 1974 | 1975 | tailwindcss@4.1.3: {} 1976 | 1977 | tapable@2.2.1: {} 1978 | 1979 | tslib@2.8.1: {} 1980 | 1981 | tw-animate-css@1.2.5: {} 1982 | 1983 | typescript@5.8.3: {} 1984 | 1985 | undici-types@6.21.0: {} 1986 | 1987 | use-callback-ref@1.3.3(@types/react@19.1.1)(react@19.1.0): 1988 | dependencies: 1989 | react: 19.1.0 1990 | tslib: 2.8.1 1991 | optionalDependencies: 1992 | '@types/react': 19.1.1 1993 | 1994 | use-sidecar@1.1.3(@types/react@19.1.1)(react@19.1.0): 1995 | dependencies: 1996 | detect-node-es: 1.1.0 1997 | react: 19.1.0 1998 | tslib: 2.8.1 1999 | optionalDependencies: 2000 | '@types/react': 19.1.1 2001 | 2002 | which@2.0.2: 2003 | dependencies: 2004 | isexe: 2.0.0 2005 | 2006 | wrap-ansi@7.0.0: 2007 | dependencies: 2008 | ansi-styles: 4.3.0 2009 | string-width: 4.2.3 2010 | strip-ansi: 6.0.1 2011 | 2012 | wrap-ansi@8.1.0: 2013 | dependencies: 2014 | ansi-styles: 6.2.1 2015 | string-width: 5.1.2 2016 | strip-ansi: 7.1.0 2017 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: { 3 | "@tailwindcss/postcss": {}, 4 | }, 5 | }; 6 | 7 | module.exports = config; 8 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- 1 |  h6  (�00 h&�(  ���L���A���$������������5����������A����������������������b�������������������� 2 | �����������������������}���0����������b�����������������l����������_�������2����������_���X���\�������������������������R������m�����������������������L�������������������G���N������������������������������Q�������������A���O���������������������������������������|������( @ ������B���h���n���R������f�����������;��� ���������������������������������%��������������J����������������������������������������������O��������������J�������������������������f���_����������������������>��������������J������������������)��� ��������������������������������J������������������"������������������_��������������J���{����������=�������������������������J���{���5�����������������������������J��������������������������J�����������������������������J���i�������������������������J���%���������������3��������������J���4���9������U�����������������������������J���S�����������5���*���������������������������������J���������������������1���8������������������������J��� ������������������,�����������������J��� 3 | ������������������(��������������J��� �������������������$������<���<�������������������������!�������������������������V���a���a���a���a���a���a���a���a���a���a���a���a���a���a���a���a���a���a���+���������������������������������������������������������������������������������������������������������-�������������������������������������������������������������������������������������������������������������(�������������������������[���h���h���h���h���h���h���h���h���h���h���h���h���h���h���h���h���h���h���h���h���M��������������� 4 | (0` ������ ������"���%���$������������ ���J���J���J���;������ ���g��������������������������������B��� ���+������������������������b�����������������������������������������������������.������������������������������������������������������������������������������������;������.��������������������������������������������������������������������������������������������O������.���������������������������������������������������O���$������!���2������������������������������#���.����������������������:�����������������������j������!����������������������������.��������������������������������������������N�������������������������G���.����������������������)�������������������x������)�������������������������.����������������������y��������������� ����������������������&���.���������������������� 5 | ���{�������������!�������������������J���.���������������������� 6 | ���y���A����������������������_���.�����������������������������������������e���.�����������������������������������������]���.����������������������%�������������������G���.��������������������������������������������!���.����������������������5�������������������������.��������������������������������������������5���.����������������������������&������ ���,��������������������������.�������������������������C�����������8������ ���������������������������������.����������������������L�������������������"������y�����������������������8������.������������������������������������������������������������������������*���.����������������������$��������������������������.������u���������.�������������������������&�����������������������������������.���������������������������������������������������.����������������������*��������������������������&���.�������������������������-��������������������������������d���d���d���O��� 7 | ���%�����������������������������1��������������������������������4����������������������������� ������!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���!���������.�����������������������������U����������������������������������������������������������������������������������������������������������������������0���8�����������������������������a���������������������������������������������������������������������������������������������������������������������������������<�������������������������� ���a����������������������������������������������������������������������������������������������������������������������������������9�������������������������� ���X�������������������������������������������������������������������������������������������������������������������������������������<������������������1��� ���!���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#���#��� ��� ��������������������� -------------------------------------------------------------------------------- /public/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sadmann7/sortable/552eaa44810fd26c20fdb7f7c8e2d13ba08d6832/public/images/screenshot.png -------------------------------------------------------------------------------- /src/app/_components/mixed-sorting-demo.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { 4 | Card, 5 | CardDescription, 6 | CardHeader, 7 | CardTitle, 8 | } from "@/components/ui/card"; 9 | import { 10 | Sortable, 11 | SortableContent, 12 | SortableItem, 13 | SortableOverlay, 14 | } from "@/components/ui/sortable"; 15 | import type { UniqueIdentifier } from "@dnd-kit/core"; 16 | import * as React from "react"; 17 | 18 | interface Trick { 19 | id: string; 20 | title: string; 21 | description: string; 22 | } 23 | 24 | const data: Trick[] = [ 25 | { 26 | id: "1", 27 | title: "The 900", 28 | description: "The 900 is a trick where you spin 900 degrees in the air.", 29 | }, 30 | { 31 | id: "2", 32 | title: "Indy Backflip", 33 | description: "The Indy Backflip is a trick where you backflip in the air.", 34 | }, 35 | { 36 | id: "3", 37 | title: "Pizza Guy", 38 | description: "The Pizza Guy is a trick where you flip the pizza guy.", 39 | }, 40 | { 41 | id: "4", 42 | title: "Rocket Air", 43 | description: "The Rocket Air is a trick where you rocket air.", 44 | }, 45 | { 46 | id: "5", 47 | title: "Kickflip Backflip", 48 | description: 49 | "The Kickflip Backflip is a trick where you kickflip backflip.", 50 | }, 51 | { 52 | id: "6", 53 | title: "FS 540", 54 | description: "The FS 540 is a trick where you fs 540.", 55 | }, 56 | { 57 | id: "7", 58 | title: "Double Cork 1080", 59 | description: 60 | "A complex aerial maneuver combining three rotations with two off-axis flips.", 61 | }, 62 | { 63 | id: "8", 64 | title: "Triple Cork 1440", 65 | description: 66 | "An advanced aerial trick with four full rotations and three off-axis flips.", 67 | }, 68 | { 69 | id: "9", 70 | title: "Rodeo 540", 71 | description: 72 | "A backflip combined with a 540-degree rotation, creating a stylish off-axis spin.", 73 | }, 74 | { 75 | id: "10", 76 | title: "Switch Double Backflip", 77 | description: 78 | "Two backflips performed while riding in the opposite stance from normal.", 79 | }, 80 | { 81 | id: "11", 82 | title: "Misty 720", 83 | description: 84 | "An off-axis rotation combining a front flip with two full spins.", 85 | }, 86 | { 87 | id: "12", 88 | title: "Cork 720 Japan", 89 | description: 90 | "A cork rotation with two spins while grabbing the board in japan position.", 91 | }, 92 | { 93 | id: "13", 94 | title: "Cab 1080 Double Cork", 95 | description: 96 | "A switch frontside 1080 with two cork rotations, performed with exceptional style.", 97 | }, 98 | { 99 | id: "14", 100 | title: "Frontside Triple Underflip", 101 | description: 102 | "Three underflipped rotations performed while spinning frontside.", 103 | }, 104 | { 105 | id: "15", 106 | title: "Double Wildcat", 107 | description: 108 | "Two consecutive backflips performed without vertical rotation, staying flat.", 109 | }, 110 | { 111 | id: "16", 112 | title: "Quad Cork 1800", 113 | description: 114 | "A groundbreaking trick combining five rotations with four off-axis flips.", 115 | }, 116 | ]; 117 | 118 | export function MixedSortingDemo() { 119 | const [tricks, setTricks] = React.useState(data); 120 | 121 | const onValueChange = React.useCallback((newTricks: Trick[]) => { 122 | setTricks(newTricks); 123 | }, []); 124 | 125 | const getItemValue = React.useCallback((item: Trick) => item.id, []); 126 | 127 | const renderOverlay = React.useCallback( 128 | ({ value }: { value: UniqueIdentifier }) => { 129 | const trick = tricks.find((trick) => trick.id === value); 130 | if (!trick) return null; 131 | 132 | return ; 133 | }, 134 | [tricks], 135 | ); 136 | 137 | return ( 138 | 144 | 145 | {tricks.map((trick) => ( 146 | 147 | ))} 148 | 149 | {renderOverlay} 150 | 151 | ); 152 | } 153 | 154 | interface TrickCardProps 155 | extends Omit, "value"> { 156 | trick: Trick; 157 | } 158 | 159 | function TrickCard({ trick, ...props }: TrickCardProps) { 160 | return ( 161 | 162 | 163 | 164 | {trick.title} 165 | 166 | {trick.description} 167 | 168 | 169 | 170 | 171 | ); 172 | } 173 | -------------------------------------------------------------------------------- /src/app/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sadmann7/sortable/552eaa44810fd26c20fdb7f7c8e2d13ba08d6832/src/app/icon.png -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import { SiteHeader } from "@/components/layouts/site-header"; 2 | import { ThemeProvider } from "@/components/providers"; 3 | import { TailwindIndicator } from "@/components/tailwind-indicator"; 4 | import { siteConfig } from "@/config/site"; 5 | import { cn } from "@/lib/utils"; 6 | 7 | import "@/styles/globals.css"; 8 | 9 | import type { Metadata, Viewport } from "next"; 10 | 11 | import { fontMono, fontSans } from "@/lib/fonts"; 12 | 13 | export const metadata: Metadata = { 14 | metadataBase: new URL(siteConfig.url), 15 | title: { 16 | default: siteConfig.name, 17 | template: `%s - ${siteConfig.name}`, 18 | }, 19 | description: siteConfig.description, 20 | keywords: [ 21 | "nextjs", 22 | "react", 23 | "react server components", 24 | "sortable", 25 | "dnd", 26 | "react hook form useFieldArray", 27 | "tanstack table row dnd", 28 | ], 29 | authors: [ 30 | { 31 | name: "sadmann7", 32 | url: "https://www.sadmn.com", 33 | }, 34 | ], 35 | creator: "sadmann7", 36 | openGraph: { 37 | type: "website", 38 | locale: "en_US", 39 | url: siteConfig.url, 40 | title: siteConfig.name, 41 | description: siteConfig.description, 42 | siteName: siteConfig.name, 43 | }, 44 | twitter: { 45 | card: "summary_large_image", 46 | title: siteConfig.name, 47 | description: siteConfig.description, 48 | images: [`${siteConfig.url}/og.jpg`], 49 | creator: "@sadmann17", 50 | }, 51 | icons: { 52 | icon: "/icon.png", 53 | }, 54 | }; 55 | 56 | export const viewport: Viewport = { 57 | colorScheme: "dark light", 58 | themeColor: [ 59 | { media: "(prefers-color-scheme: light)", color: "white" }, 60 | { media: "(prefers-color-scheme: dark)", color: "black" }, 61 | ], 62 | }; 63 | 64 | export default function RootLayout({ children }: React.PropsWithChildren) { 65 | return ( 66 | 67 | 68 | 75 | 81 |
82 | 83 |
{children}
84 |
85 | 86 |
87 | 88 | 89 | ); 90 | } 91 | -------------------------------------------------------------------------------- /src/app/manifest.ts: -------------------------------------------------------------------------------- 1 | import { siteConfig } from "@/config/site"; 2 | import type { MetadataRoute } from "next"; 3 | 4 | export default function manifest(): MetadataRoute.Manifest { 5 | return { 6 | name: siteConfig.name, 7 | short_name: siteConfig.name, 8 | description: siteConfig.description, 9 | start_url: "/", 10 | display: "standalone", 11 | background_color: "#fff", 12 | theme_color: "#fff", 13 | icons: [ 14 | { 15 | src: "/icon.png", 16 | sizes: "32x32", 17 | type: "image/png", 18 | }, 19 | ], 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { Shell } from "@/components/shell"; 2 | 3 | import { MixedSortingDemo } from "./_components/mixed-sorting-demo"; 4 | 5 | export default function IndexPage() { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/app/robots.ts: -------------------------------------------------------------------------------- 1 | import type { MetadataRoute } from "next"; 2 | 3 | import { siteConfig } from "@/config/site"; 4 | 5 | export default function robots(): MetadataRoute.Robots { 6 | return { 7 | rules: { 8 | userAgent: "*", 9 | allow: "/", 10 | }, 11 | sitemap: `${siteConfig.url}/sitemap.xml`, 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/app/sitemap.ts: -------------------------------------------------------------------------------- 1 | import type { MetadataRoute } from "next"; 2 | 3 | import { siteConfig } from "@/config/site"; 4 | 5 | export default function sitemap(): MetadataRoute.Sitemap { 6 | const routes: MetadataRoute.Sitemap = [""].map((route) => ({ 7 | url: `${siteConfig.url}${route}`, 8 | lastModified: new Date().toISOString(), 9 | })); 10 | 11 | const externalRoutes: MetadataRoute.Sitemap = [ 12 | { 13 | url: siteConfig.links.docs, 14 | lastModified: new Date().toISOString(), 15 | }, 16 | ]; 17 | 18 | return [...routes, ...externalRoutes]; 19 | } 20 | -------------------------------------------------------------------------------- /src/components/icons.tsx: -------------------------------------------------------------------------------- 1 | export type IconProps = React.HTMLAttributes; 2 | 3 | export const Icons = { 4 | gitHub: (props: IconProps) => ( 5 | 6 | 10 | 11 | ), 12 | }; 13 | -------------------------------------------------------------------------------- /src/components/kbd.tsx: -------------------------------------------------------------------------------- 1 | import { type VariantProps, cva } from "class-variance-authority"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | const kbdVariants = cva( 6 | "select-none rounded border px-1.5 py-px font-mono font-normal text-[0.7rem] shadow-xs disabled:opacity-50", 7 | { 8 | variants: { 9 | variant: { 10 | default: "bg-accent text-accent-foreground", 11 | outline: "bg-background text-foreground", 12 | }, 13 | }, 14 | defaultVariants: { 15 | variant: "default", 16 | }, 17 | }, 18 | ); 19 | 20 | export interface KbdProps 21 | extends React.ComponentPropsWithoutRef<"kbd">, 22 | VariantProps {} 23 | 24 | function Kbd({ title, children, className, variant, ...props }: KbdProps) { 25 | return ( 26 | 27 | {title ? ( 28 | 29 | {children} 30 | 31 | ) : ( 32 | children 33 | )} 34 | 35 | ); 36 | } 37 | 38 | export { Kbd }; 39 | -------------------------------------------------------------------------------- /src/components/layouts/mode-toggle.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Laptop, Moon, Sun } from "lucide-react"; 4 | import { useTheme } from "next-themes"; 5 | 6 | import { Button } from "@/components/ui/button"; 7 | import { 8 | DropdownMenu, 9 | DropdownMenuContent, 10 | DropdownMenuItem, 11 | DropdownMenuTrigger, 12 | } from "@/components/ui/dropdown-menu"; 13 | 14 | export function ModeToggle() { 15 | const { setTheme } = useTheme(); 16 | 17 | return ( 18 | 19 | 20 | 25 | 26 | 27 | setTheme("light")}> 28 | 29 | Light 30 | 31 | setTheme("dark")}> 32 | 33 | Dark 34 | 35 | setTheme("system")}> 36 | 37 | System 38 | 39 | 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/components/layouts/site-header.tsx: -------------------------------------------------------------------------------- 1 | import { File } from "lucide-react"; 2 | import Link from "next/link"; 3 | 4 | import { Icons } from "@/components/icons"; 5 | import { ModeToggle } from "@/components/layouts/mode-toggle"; 6 | import { Button } from "@/components/ui/button"; 7 | import { siteConfig } from "@/config/site"; 8 | 9 | export function SiteHeader() { 10 | return ( 11 |
12 |
13 | 14 | 15 | 16 | {siteConfig.name} 17 | 18 | 19 | 29 | 42 |
43 |
44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src/components/providers.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { 4 | ThemeProvider as NextThemesProvider, 5 | type ThemeProviderProps, 6 | } from "next-themes"; 7 | 8 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 9 | return {children}; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/shell.tsx: -------------------------------------------------------------------------------- 1 | import { type VariantProps, cva } from "class-variance-authority"; 2 | import type * as React from "react"; 3 | 4 | import { cn } from "@/lib/utils"; 5 | 6 | const shellVariants = cva("grid items-center gap-8 pt-6 pb-8 md:py-8", { 7 | variants: { 8 | variant: { 9 | default: "container", 10 | sidebar: "", 11 | centered: "container flex h-dvh max-w-2xl flex-col justify-center py-16", 12 | markdown: "container max-w-3xl py-8 md:py-10 lg:py-10", 13 | }, 14 | }, 15 | defaultVariants: { 16 | variant: "default", 17 | }, 18 | }); 19 | 20 | interface ShellProps 21 | extends React.HTMLAttributes, 22 | VariantProps { 23 | as?: React.ElementType; 24 | } 25 | 26 | function Shell({ 27 | className, 28 | as: Comp = "section", 29 | variant, 30 | ...props 31 | }: ShellProps) { 32 | return ( 33 | 34 | ); 35 | } 36 | 37 | export { Shell, shellVariants }; 38 | -------------------------------------------------------------------------------- /src/components/tailwind-indicator.tsx: -------------------------------------------------------------------------------- 1 | export function TailwindIndicator() { 2 | if (process.env.NODE_ENV === "production") return null; 3 | 4 | return ( 5 |
6 |
xs
7 |
8 | sm 9 |
10 |
md
11 |
lg
12 |
xl
13 |
2xl
14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import { Slot } from "@radix-ui/react-slot"; 2 | import { type VariantProps, cva } from "class-variance-authority"; 3 | import type * as React from "react"; 4 | 5 | import { cn } from "@/lib/utils"; 6 | 7 | const buttonVariants = cva( 8 | "inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", 14 | destructive: 15 | "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40", 16 | outline: 17 | "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", 18 | secondary: 19 | "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", 20 | ghost: 21 | "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", 22 | link: "text-primary underline-offset-4 hover:underline", 23 | }, 24 | size: { 25 | default: "h-9 px-4 py-2 has-[>svg]:px-3", 26 | sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5", 27 | lg: "h-10 rounded-md px-6 has-[>svg]:px-4", 28 | icon: "size-9", 29 | }, 30 | }, 31 | defaultVariants: { 32 | variant: "default", 33 | size: "default", 34 | }, 35 | }, 36 | ); 37 | 38 | function Button({ 39 | className, 40 | variant, 41 | size, 42 | asChild = false, 43 | ...props 44 | }: React.ComponentProps<"button"> & 45 | VariantProps & { 46 | asChild?: boolean; 47 | }) { 48 | const Comp = asChild ? Slot : "button"; 49 | 50 | return ( 51 | 56 | ); 57 | } 58 | 59 | export { Button, buttonVariants }; 60 | -------------------------------------------------------------------------------- /src/components/ui/card.tsx: -------------------------------------------------------------------------------- 1 | import type * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | function Card({ className, ...props }: React.ComponentProps<"div">) { 6 | return ( 7 |
15 | ); 16 | } 17 | 18 | function CardHeader({ className, ...props }: React.ComponentProps<"div">) { 19 | return ( 20 |
28 | ); 29 | } 30 | 31 | function CardTitle({ className, ...props }: React.ComponentProps<"div">) { 32 | return ( 33 |
38 | ); 39 | } 40 | 41 | function CardDescription({ className, ...props }: React.ComponentProps<"div">) { 42 | return ( 43 |
48 | ); 49 | } 50 | 51 | function CardAction({ className, ...props }: React.ComponentProps<"div">) { 52 | return ( 53 |
61 | ); 62 | } 63 | 64 | function CardContent({ className, ...props }: React.ComponentProps<"div">) { 65 | return ( 66 |
71 | ); 72 | } 73 | 74 | function CardFooter({ className, ...props }: React.ComponentProps<"div">) { 75 | return ( 76 |
81 | ); 82 | } 83 | 84 | export { 85 | Card, 86 | CardHeader, 87 | CardFooter, 88 | CardTitle, 89 | CardAction, 90 | CardDescription, 91 | CardContent, 92 | }; 93 | -------------------------------------------------------------------------------- /src/components/ui/dropdown-menu.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; 4 | import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; 5 | import type * as React from "react"; 6 | 7 | import { cn } from "@/lib/utils"; 8 | 9 | function DropdownMenu({ 10 | ...props 11 | }: React.ComponentProps) { 12 | return ; 13 | } 14 | 15 | function DropdownMenuPortal({ 16 | ...props 17 | }: React.ComponentProps) { 18 | return ( 19 | 20 | ); 21 | } 22 | 23 | function DropdownMenuTrigger({ 24 | ...props 25 | }: React.ComponentProps) { 26 | return ( 27 | 31 | ); 32 | } 33 | 34 | function DropdownMenuContent({ 35 | className, 36 | sideOffset = 4, 37 | ...props 38 | }: React.ComponentProps) { 39 | return ( 40 | 41 | 50 | 51 | ); 52 | } 53 | 54 | function DropdownMenuGroup({ 55 | ...props 56 | }: React.ComponentProps) { 57 | return ( 58 | 59 | ); 60 | } 61 | 62 | function DropdownMenuItem({ 63 | className, 64 | inset, 65 | variant = "default", 66 | ...props 67 | }: React.ComponentProps & { 68 | inset?: boolean; 69 | variant?: "default" | "destructive"; 70 | }) { 71 | return ( 72 | 82 | ); 83 | } 84 | 85 | function DropdownMenuCheckboxItem({ 86 | className, 87 | children, 88 | checked, 89 | ...props 90 | }: React.ComponentProps) { 91 | return ( 92 | 101 | 102 | 103 | 104 | 105 | 106 | {children} 107 | 108 | ); 109 | } 110 | 111 | function DropdownMenuRadioGroup({ 112 | ...props 113 | }: React.ComponentProps) { 114 | return ( 115 | 119 | ); 120 | } 121 | 122 | function DropdownMenuRadioItem({ 123 | className, 124 | children, 125 | ...props 126 | }: React.ComponentProps) { 127 | return ( 128 | 136 | 137 | 138 | 139 | 140 | 141 | {children} 142 | 143 | ); 144 | } 145 | 146 | function DropdownMenuLabel({ 147 | className, 148 | inset, 149 | ...props 150 | }: React.ComponentProps & { 151 | inset?: boolean; 152 | }) { 153 | return ( 154 | 163 | ); 164 | } 165 | 166 | function DropdownMenuSeparator({ 167 | className, 168 | ...props 169 | }: React.ComponentProps) { 170 | return ( 171 | 176 | ); 177 | } 178 | 179 | function DropdownMenuShortcut({ 180 | className, 181 | ...props 182 | }: React.ComponentProps<"span">) { 183 | return ( 184 | 192 | ); 193 | } 194 | 195 | function DropdownMenuSub({ 196 | ...props 197 | }: React.ComponentProps) { 198 | return ; 199 | } 200 | 201 | function DropdownMenuSubTrigger({ 202 | className, 203 | inset, 204 | children, 205 | ...props 206 | }: React.ComponentProps & { 207 | inset?: boolean; 208 | }) { 209 | return ( 210 | 219 | {children} 220 | 221 | 222 | ); 223 | } 224 | 225 | function DropdownMenuSubContent({ 226 | className, 227 | ...props 228 | }: React.ComponentProps) { 229 | return ( 230 | 238 | ); 239 | } 240 | 241 | export { 242 | DropdownMenu, 243 | DropdownMenuPortal, 244 | DropdownMenuTrigger, 245 | DropdownMenuContent, 246 | DropdownMenuGroup, 247 | DropdownMenuLabel, 248 | DropdownMenuItem, 249 | DropdownMenuCheckboxItem, 250 | DropdownMenuRadioGroup, 251 | DropdownMenuRadioItem, 252 | DropdownMenuSeparator, 253 | DropdownMenuShortcut, 254 | DropdownMenuSub, 255 | DropdownMenuSubTrigger, 256 | DropdownMenuSubContent, 257 | }; 258 | -------------------------------------------------------------------------------- /src/components/ui/sortable.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { 4 | type Announcements, 5 | DndContext, 6 | type DndContextProps, 7 | type DragEndEvent, 8 | DragOverlay, 9 | type DraggableSyntheticListeners, 10 | type DropAnimation, 11 | KeyboardSensor, 12 | MouseSensor, 13 | type ScreenReaderInstructions, 14 | TouchSensor, 15 | type UniqueIdentifier, 16 | closestCenter, 17 | closestCorners, 18 | defaultDropAnimationSideEffects, 19 | useSensor, 20 | useSensors, 21 | } from "@dnd-kit/core"; 22 | import { 23 | restrictToHorizontalAxis, 24 | restrictToParentElement, 25 | restrictToVerticalAxis, 26 | } from "@dnd-kit/modifiers"; 27 | import { 28 | SortableContext, 29 | type SortableContextProps, 30 | arrayMove, 31 | horizontalListSortingStrategy, 32 | sortableKeyboardCoordinates, 33 | useSortable, 34 | verticalListSortingStrategy, 35 | } from "@dnd-kit/sortable"; 36 | import { CSS } from "@dnd-kit/utilities"; 37 | import { Slot } from "@radix-ui/react-slot"; 38 | import * as React from "react"; 39 | import * as ReactDOM from "react-dom"; 40 | 41 | import { composeEventHandlers, useComposedRefs } from "@/lib/composition"; 42 | import { cn } from "@/lib/utils"; 43 | 44 | const orientationConfig = { 45 | vertical: { 46 | modifiers: [restrictToVerticalAxis, restrictToParentElement], 47 | strategy: verticalListSortingStrategy, 48 | collisionDetection: closestCenter, 49 | }, 50 | horizontal: { 51 | modifiers: [restrictToHorizontalAxis, restrictToParentElement], 52 | strategy: horizontalListSortingStrategy, 53 | collisionDetection: closestCenter, 54 | }, 55 | mixed: { 56 | modifiers: [restrictToParentElement], 57 | strategy: undefined, 58 | collisionDetection: closestCorners, 59 | }, 60 | }; 61 | 62 | const ROOT_NAME = "Sortable"; 63 | const CONTENT_NAME = "SortableContent"; 64 | const ITEM_NAME = "SortableItem"; 65 | const ITEM_HANDLE_NAME = "SortableItemHandle"; 66 | const OVERLAY_NAME = "SortableOverlay"; 67 | 68 | const SORTABLE_ERRORS = { 69 | [ROOT_NAME]: `\`${ROOT_NAME}\` components must be within \`${ROOT_NAME}\``, 70 | [CONTENT_NAME]: `\`${CONTENT_NAME}\` must be within \`${ROOT_NAME}\``, 71 | [ITEM_NAME]: `\`${ITEM_NAME}\` must be within \`${CONTENT_NAME}\``, 72 | [ITEM_HANDLE_NAME]: `\`${ITEM_HANDLE_NAME}\` must be within \`${ITEM_NAME}\``, 73 | [OVERLAY_NAME]: `\`${OVERLAY_NAME}\` must be within \`${ROOT_NAME}\``, 74 | } as const; 75 | 76 | interface SortableRootContextValue { 77 | id: string; 78 | items: UniqueIdentifier[]; 79 | modifiers: DndContextProps["modifiers"]; 80 | strategy: SortableContextProps["strategy"]; 81 | activeId: UniqueIdentifier | null; 82 | setActiveId: (id: UniqueIdentifier | null) => void; 83 | getItemValue: (item: T) => UniqueIdentifier; 84 | flatCursor: boolean; 85 | } 86 | 87 | const SortableRootContext = 88 | React.createContext | null>(null); 89 | SortableRootContext.displayName = ROOT_NAME; 90 | 91 | function useSortableContext(name: keyof typeof SORTABLE_ERRORS) { 92 | const context = React.useContext(SortableRootContext); 93 | if (!context) { 94 | throw new Error(SORTABLE_ERRORS[name]); 95 | } 96 | return context; 97 | } 98 | 99 | interface GetItemValue { 100 | /** 101 | * Callback that returns a unique identifier for each sortable item. Required for array of objects. 102 | * @example getItemValue={(item) => item.id} 103 | */ 104 | getItemValue: (item: T) => UniqueIdentifier; 105 | } 106 | 107 | type SortableProps = DndContextProps & { 108 | value: T[]; 109 | onValueChange?: (items: T[]) => void; 110 | onMove?: ( 111 | event: DragEndEvent & { activeIndex: number; overIndex: number }, 112 | ) => void; 113 | strategy?: SortableContextProps["strategy"]; 114 | orientation?: "vertical" | "horizontal" | "mixed"; 115 | flatCursor?: boolean; 116 | } & (T extends object ? GetItemValue : Partial>); 117 | 118 | function Sortable(props: SortableProps) { 119 | const { 120 | value, 121 | onValueChange, 122 | collisionDetection, 123 | modifiers, 124 | strategy, 125 | onMove, 126 | orientation = "vertical", 127 | flatCursor = false, 128 | getItemValue: getItemValueProp, 129 | accessibility, 130 | ...sortableProps 131 | } = props; 132 | const id = React.useId(); 133 | const [activeId, setActiveId] = React.useState(null); 134 | 135 | const sensors = useSensors( 136 | useSensor(MouseSensor), 137 | useSensor(TouchSensor), 138 | useSensor(KeyboardSensor, { 139 | coordinateGetter: sortableKeyboardCoordinates, 140 | }), 141 | ); 142 | const config = React.useMemo( 143 | () => orientationConfig[orientation], 144 | [orientation], 145 | ); 146 | 147 | const getItemValue = React.useCallback( 148 | (item: T): UniqueIdentifier => { 149 | if (typeof item === "object" && !getItemValueProp) { 150 | throw new Error( 151 | "getItemValue is required when using array of objects.", 152 | ); 153 | } 154 | return getItemValueProp 155 | ? getItemValueProp(item) 156 | : (item as UniqueIdentifier); 157 | }, 158 | [getItemValueProp], 159 | ); 160 | 161 | const items = React.useMemo(() => { 162 | return value.map((item) => getItemValue(item)); 163 | }, [value, getItemValue]); 164 | 165 | const onDragEnd = React.useCallback( 166 | (event: DragEndEvent) => { 167 | const { active, over } = event; 168 | if (over && active.id !== over?.id) { 169 | const activeIndex = value.findIndex( 170 | (item) => getItemValue(item) === active.id, 171 | ); 172 | const overIndex = value.findIndex( 173 | (item) => getItemValue(item) === over.id, 174 | ); 175 | 176 | if (onMove) { 177 | onMove({ ...event, activeIndex, overIndex }); 178 | } else { 179 | onValueChange?.(arrayMove(value, activeIndex, overIndex)); 180 | } 181 | } 182 | setActiveId(null); 183 | }, 184 | [value, onValueChange, onMove, getItemValue], 185 | ); 186 | 187 | const announcements: Announcements = React.useMemo( 188 | () => ({ 189 | onDragStart({ active }) { 190 | const activeValue = active.id.toString(); 191 | return `Grabbed sortable item "${activeValue}". Current position is ${active.data.current?.sortable.index + 1} of ${value.length}. Use arrow keys to move, space to drop.`; 192 | }, 193 | onDragOver({ active, over }) { 194 | if (over) { 195 | const overIndex = over.data.current?.sortable.index ?? 0; 196 | const activeIndex = active.data.current?.sortable.index ?? 0; 197 | const moveDirection = overIndex > activeIndex ? "down" : "up"; 198 | const activeValue = active.id.toString(); 199 | return `Sortable item "${activeValue}" moved ${moveDirection} to position ${overIndex + 1} of ${value.length}.`; 200 | } 201 | return "Sortable item is no longer over a droppable area. Press escape to cancel."; 202 | }, 203 | onDragEnd({ active, over }) { 204 | const activeValue = active.id.toString(); 205 | if (over) { 206 | const overIndex = over.data.current?.sortable.index ?? 0; 207 | return `Sortable item "${activeValue}" dropped at position ${overIndex + 1} of ${value.length}.`; 208 | } 209 | return `Sortable item "${activeValue}" dropped. No changes were made.`; 210 | }, 211 | onDragCancel({ active }) { 212 | const activeIndex = active.data.current?.sortable.index ?? 0; 213 | const activeValue = active.id.toString(); 214 | return `Sorting cancelled. Sortable item "${activeValue}" returned to position ${activeIndex + 1} of ${value.length}.`; 215 | }, 216 | onDragMove({ active, over }) { 217 | if (over) { 218 | const overIndex = over.data.current?.sortable.index ?? 0; 219 | const activeIndex = active.data.current?.sortable.index ?? 0; 220 | const moveDirection = overIndex > activeIndex ? "down" : "up"; 221 | const activeValue = active.id.toString(); 222 | return `Sortable item "${activeValue}" is moving ${moveDirection} to position ${overIndex + 1} of ${value.length}.`; 223 | } 224 | return "Sortable item is no longer over a droppable area. Press escape to cancel."; 225 | }, 226 | }), 227 | [value], 228 | ); 229 | 230 | const screenReaderInstructions: ScreenReaderInstructions = React.useMemo( 231 | () => ({ 232 | draggable: ` 233 | To pick up a sortable item, press space or enter. 234 | While dragging, use the ${orientation === "vertical" ? "up and down" : orientation === "horizontal" ? "left and right" : "arrow"} keys to move the item. 235 | Press space or enter again to drop the item in its new position, or press escape to cancel. 236 | `, 237 | }), 238 | [orientation], 239 | ); 240 | 241 | const contextValue = React.useMemo( 242 | () => ({ 243 | id, 244 | items, 245 | modifiers: modifiers ?? config.modifiers, 246 | strategy: strategy ?? config.strategy, 247 | activeId, 248 | setActiveId, 249 | getItemValue, 250 | flatCursor, 251 | }), 252 | [ 253 | id, 254 | items, 255 | modifiers, 256 | strategy, 257 | config.modifiers, 258 | config.strategy, 259 | activeId, 260 | getItemValue, 261 | flatCursor, 262 | ], 263 | ); 264 | 265 | return ( 266 | } 268 | > 269 | setActiveId(active.id), 278 | )} 279 | onDragEnd={composeEventHandlers(sortableProps.onDragEnd, onDragEnd)} 280 | onDragCancel={composeEventHandlers(sortableProps.onDragCancel, () => 281 | setActiveId(null), 282 | )} 283 | accessibility={{ 284 | announcements, 285 | screenReaderInstructions, 286 | ...accessibility, 287 | }} 288 | /> 289 | 290 | ); 291 | } 292 | 293 | const SortableContentContext = React.createContext(false); 294 | SortableContentContext.displayName = CONTENT_NAME; 295 | 296 | interface SortableContentProps extends React.ComponentPropsWithoutRef<"div"> { 297 | strategy?: SortableContextProps["strategy"]; 298 | children: React.ReactNode; 299 | asChild?: boolean; 300 | withoutSlot?: boolean; 301 | } 302 | 303 | const SortableContent = React.forwardRef( 304 | (props, forwardedRef) => { 305 | const { 306 | strategy: strategyProp, 307 | asChild, 308 | withoutSlot, 309 | children, 310 | ...contentProps 311 | } = props; 312 | const context = useSortableContext(CONTENT_NAME); 313 | 314 | const ContentPrimitive = asChild ? Slot : "div"; 315 | 316 | return ( 317 | 318 | 322 | {withoutSlot ? ( 323 | children 324 | ) : ( 325 | 326 | {children} 327 | 328 | )} 329 | 330 | 331 | ); 332 | }, 333 | ); 334 | SortableContent.displayName = CONTENT_NAME; 335 | 336 | interface SortableItemContextValue { 337 | id: string; 338 | attributes: React.HTMLAttributes; 339 | listeners: DraggableSyntheticListeners | undefined; 340 | setActivatorNodeRef: (node: HTMLElement | null) => void; 341 | isDragging?: boolean; 342 | disabled?: boolean; 343 | } 344 | 345 | const SortableItemContext = 346 | React.createContext(null); 347 | SortableItemContext.displayName = ITEM_NAME; 348 | 349 | interface SortableItemProps extends React.ComponentPropsWithoutRef<"div"> { 350 | value: UniqueIdentifier; 351 | asHandle?: boolean; 352 | asChild?: boolean; 353 | disabled?: boolean; 354 | } 355 | 356 | const SortableItem = React.forwardRef( 357 | (props, forwardedRef) => { 358 | const { 359 | value, 360 | style, 361 | asHandle, 362 | asChild, 363 | disabled, 364 | className, 365 | ...itemProps 366 | } = props; 367 | const inSortableContent = React.useContext(SortableContentContext); 368 | const inSortableOverlay = React.useContext(SortableOverlayContext); 369 | 370 | if (!inSortableContent && !inSortableOverlay) { 371 | throw new Error(SORTABLE_ERRORS[ITEM_NAME]); 372 | } 373 | 374 | if (value === "") { 375 | throw new Error(`\`${ITEM_NAME}\` value cannot be an empty string`); 376 | } 377 | 378 | const context = useSortableContext(ITEM_NAME); 379 | const id = React.useId(); 380 | const { 381 | attributes, 382 | listeners, 383 | setNodeRef, 384 | setActivatorNodeRef, 385 | transform, 386 | transition, 387 | isDragging, 388 | } = useSortable({ id: value, disabled }); 389 | 390 | const composedRef = useComposedRefs(forwardedRef, (node) => { 391 | if (disabled) return; 392 | setNodeRef(node); 393 | if (asHandle) setActivatorNodeRef(node); 394 | }); 395 | 396 | const composedStyle = React.useMemo(() => { 397 | return { 398 | transform: CSS.Translate.toString(transform), 399 | transition, 400 | ...style, 401 | }; 402 | }, [transform, transition, style]); 403 | 404 | const itemContext = React.useMemo( 405 | () => ({ 406 | id, 407 | attributes, 408 | listeners, 409 | setActivatorNodeRef, 410 | isDragging, 411 | disabled, 412 | }), 413 | [id, attributes, listeners, setActivatorNodeRef, isDragging, disabled], 414 | ); 415 | 416 | const ItemPrimitive = asChild ? Slot : "div"; 417 | 418 | return ( 419 | 420 | 442 | 443 | ); 444 | }, 445 | ); 446 | SortableItem.displayName = ITEM_NAME; 447 | 448 | interface SortableItemHandleProps 449 | extends React.ComponentPropsWithoutRef<"button"> { 450 | asChild?: boolean; 451 | } 452 | 453 | const SortableItemHandle = React.forwardRef< 454 | HTMLButtonElement, 455 | SortableItemHandleProps 456 | >((props, forwardedRef) => { 457 | const { asChild, disabled, className, ...itemHandleProps } = props; 458 | const itemContext = React.useContext(SortableItemContext); 459 | if (!itemContext) { 460 | throw new Error(SORTABLE_ERRORS[ITEM_HANDLE_NAME]); 461 | } 462 | const context = useSortableContext(ITEM_HANDLE_NAME); 463 | 464 | const isDisabled = disabled ?? itemContext.disabled; 465 | 466 | const composedRef = useComposedRefs(forwardedRef, (node) => { 467 | if (!isDisabled) return; 468 | itemContext.setActivatorNodeRef(node); 469 | }); 470 | 471 | const HandlePrimitive = asChild ? Slot : "button"; 472 | 473 | return ( 474 | 491 | ); 492 | }); 493 | SortableItemHandle.displayName = ITEM_HANDLE_NAME; 494 | 495 | const SortableOverlayContext = React.createContext(false); 496 | SortableOverlayContext.displayName = OVERLAY_NAME; 497 | 498 | const dropAnimation: DropAnimation = { 499 | sideEffects: defaultDropAnimationSideEffects({ 500 | styles: { 501 | active: { 502 | opacity: "0.4", 503 | }, 504 | }, 505 | }), 506 | }; 507 | 508 | interface SortableOverlayProps 509 | extends Omit, "children"> { 510 | container?: Element | DocumentFragment | null; 511 | children?: 512 | | ((params: { value: UniqueIdentifier }) => React.ReactNode) 513 | | React.ReactNode; 514 | } 515 | 516 | function SortableOverlay(props: SortableOverlayProps) { 517 | const { container: containerProp, children, ...overlayProps } = props; 518 | const context = useSortableContext(OVERLAY_NAME); 519 | 520 | const [mounted, setMounted] = React.useState(false); 521 | React.useLayoutEffect(() => setMounted(true), []); 522 | 523 | const container = 524 | containerProp ?? (mounted ? globalThis.document?.body : null); 525 | 526 | if (!container) return null; 527 | 528 | return ReactDOM.createPortal( 529 | 535 | 536 | {context.activeId 537 | ? typeof children === "function" 538 | ? children({ value: context.activeId }) 539 | : children 540 | : null} 541 | 542 | , 543 | container, 544 | ); 545 | } 546 | 547 | const Root = Sortable; 548 | const Content = SortableContent; 549 | const Item = SortableItem; 550 | const ItemHandle = SortableItemHandle; 551 | const Overlay = SortableOverlay; 552 | 553 | export { 554 | Root, 555 | Content, 556 | Item, 557 | ItemHandle, 558 | Overlay, 559 | // 560 | Sortable, 561 | SortableContent, 562 | SortableItem, 563 | SortableItemHandle, 564 | SortableOverlay, 565 | }; 566 | -------------------------------------------------------------------------------- /src/config/site.ts: -------------------------------------------------------------------------------- 1 | export type SiteConfig = typeof siteConfig; 2 | 3 | export const siteConfig = { 4 | name: "Sortable", 5 | description: "Sortable built with shadcn/ui, radix ui, and dnd-kit", 6 | url: 7 | process.env.NODE_ENV === "development" 8 | ? "http://localhost:3000" 9 | : "https://sortable.sadmn.com", 10 | links: { 11 | github: "https://github.com/sadmann7/sortable", 12 | docs: "https://github.com/sadmann7/sortable/blob/main/README.md", 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /src/lib/composition.ts: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | /** 4 | * A utility to compose multiple event handlers into a single event handler. 5 | * Run originalEventHandler first, then ourEventHandler unless prevented. 6 | */ 7 | function composeEventHandlers( 8 | originalEventHandler?: (event: E) => void, 9 | ourEventHandler?: (event: E) => void, 10 | { checkForDefaultPrevented = true } = {}, 11 | ) { 12 | return function handleEvent(event: E) { 13 | originalEventHandler?.(event); 14 | 15 | if ( 16 | checkForDefaultPrevented === false || 17 | !(event as unknown as Event).defaultPrevented 18 | ) { 19 | return ourEventHandler?.(event); 20 | } 21 | }; 22 | } 23 | 24 | /** 25 | * @see https://github.com/radix-ui/primitives/blob/main/packages/react/compose-refs/src/compose-refs.tsx 26 | */ 27 | 28 | type PossibleRef = React.Ref | undefined; 29 | 30 | /** 31 | * Set a given ref to a given value. 32 | * This utility takes care of different types of refs: callback refs and RefObject(s). 33 | */ 34 | function setRef(ref: PossibleRef, value: T) { 35 | if (typeof ref === "function") { 36 | return ref(value); 37 | } 38 | 39 | if (ref !== null && ref !== undefined) { 40 | ref.current = value; 41 | } 42 | } 43 | 44 | /** 45 | * A utility to compose multiple refs together. 46 | * Accepts callback refs and RefObject(s). 47 | */ 48 | function composeRefs(...refs: PossibleRef[]): React.RefCallback { 49 | return (node) => { 50 | let hasCleanup = false; 51 | const cleanups = refs.map((ref) => { 52 | const cleanup = setRef(ref, node); 53 | if (!hasCleanup && typeof cleanup === "function") { 54 | hasCleanup = true; 55 | } 56 | return cleanup; 57 | }); 58 | 59 | // React <19 will log an error to the console if a callback ref returns a 60 | // value. We don't use ref cleanups internally so this will only happen if a 61 | // user's ref callback returns a value, which we only expect if they are 62 | // using the cleanup functionality added in React 19. 63 | if (hasCleanup) { 64 | return () => { 65 | for (let i = 0; i < cleanups.length; i++) { 66 | const cleanup = cleanups[i]; 67 | if (typeof cleanup === "function") { 68 | cleanup(); 69 | } else { 70 | setRef(refs[i], null); 71 | } 72 | } 73 | }; 74 | } 75 | }; 76 | } 77 | 78 | /** 79 | * A custom hook that composes multiple refs. 80 | * Accepts callback refs and RefObject(s). 81 | */ 82 | function useComposedRefs(...refs: PossibleRef[]): React.RefCallback { 83 | // eslint-disable-next-line react-hooks/exhaustive-deps 84 | return React.useCallback(composeRefs(...refs), refs); 85 | } 86 | 87 | export { composeEventHandlers, composeRefs, useComposedRefs }; 88 | -------------------------------------------------------------------------------- /src/lib/fonts.ts: -------------------------------------------------------------------------------- 1 | import { Geist, Geist_Mono } from "next/font/google"; 2 | 3 | export const fontSans = Geist({ 4 | subsets: ["latin"], 5 | variable: "--font-sans", 6 | }); 7 | 8 | export const fontMono = Geist_Mono({ 9 | subsets: ["latin"], 10 | variable: "--font-mono", 11 | }); 12 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | @import "tw-animate-css"; 4 | 5 | @custom-variant dark (&:is(.dark *)); 6 | 7 | :root { 8 | --background: oklch(1 0 0); 9 | --foreground: oklch(0.145 0 0); 10 | --card: oklch(1 0 0); 11 | --card-foreground: oklch(0.145 0 0); 12 | --popover: oklch(1 0 0); 13 | --popover-foreground: oklch(0.145 0 0); 14 | --primary: oklch(0.205 0 0); 15 | --primary-foreground: oklch(0.985 0 0); 16 | --secondary: oklch(0.97 0 0); 17 | --secondary-foreground: oklch(0.205 0 0); 18 | --muted: oklch(0.97 0 0); 19 | --muted-foreground: oklch(0.556 0 0); 20 | --accent: oklch(0.97 0 0); 21 | --accent-foreground: oklch(0.205 0 0); 22 | --destructive: oklch(0.577 0.245 27.325); 23 | --destructive-foreground: oklch(0.577 0.245 27.325); 24 | --border: oklch(0.922 0 0); 25 | --input: oklch(0.922 0 0); 26 | --ring: oklch(0.708 0 0); 27 | --chart-1: oklch(0.646 0.222 41.116); 28 | --chart-2: oklch(0.6 0.118 184.704); 29 | --chart-3: oklch(0.398 0.07 227.392); 30 | --chart-4: oklch(0.828 0.189 84.429); 31 | --chart-5: oklch(0.769 0.188 70.08); 32 | --radius: 0.5rem; 33 | --sidebar: oklch(0.985 0 0); 34 | --sidebar-foreground: oklch(0.145 0 0); 35 | --sidebar-primary: oklch(0.205 0 0); 36 | --sidebar-primary-foreground: oklch(0.985 0 0); 37 | --sidebar-accent: oklch(0.97 0 0); 38 | --sidebar-accent-foreground: oklch(0.205 0 0); 39 | --sidebar-border: oklch(0.922 0 0); 40 | --sidebar-ring: oklch(0.708 0 0); 41 | } 42 | 43 | .dark { 44 | --background: oklch(0.145 0 0); 45 | --foreground: oklch(0.985 0 0); 46 | --card: oklch(0.145 0 0); 47 | --card-foreground: oklch(0.985 0 0); 48 | --popover: oklch(0.145 0 0); 49 | --popover-foreground: oklch(0.985 0 0); 50 | --primary: oklch(0.985 0 0); 51 | --primary-foreground: oklch(0.205 0 0); 52 | --secondary: oklch(0.269 0 0); 53 | --secondary-foreground: oklch(0.985 0 0); 54 | --muted: oklch(0.269 0 0); 55 | --muted-foreground: oklch(0.708 0 0); 56 | --accent: oklch(0.269 0 0); 57 | --accent-foreground: oklch(0.985 0 0); 58 | --destructive: oklch(0.396 0.141 25.723); 59 | --destructive-foreground: oklch(0.637 0.237 25.331); 60 | --border: oklch(0.269 0 0); 61 | --input: oklch(0.269 0 0); 62 | --ring: oklch(0.556 0 0); 63 | --chart-1: oklch(0.488 0.243 264.376); 64 | --chart-2: oklch(0.696 0.17 162.48); 65 | --chart-3: oklch(0.769 0.188 70.08); 66 | --chart-4: oklch(0.627 0.265 303.9); 67 | --chart-5: oklch(0.645 0.246 16.439); 68 | --sidebar: oklch(0.205 0 0); 69 | --sidebar-foreground: oklch(0.985 0 0); 70 | --sidebar-primary: oklch(0.488 0.243 264.376); 71 | --sidebar-primary-foreground: oklch(0.985 0 0); 72 | --sidebar-accent: oklch(0.269 0 0); 73 | --sidebar-accent-foreground: oklch(0.985 0 0); 74 | --sidebar-border: oklch(0.269 0 0); 75 | --sidebar-ring: oklch(0.439 0 0); 76 | } 77 | 78 | @theme inline { 79 | --font-sans: var(--font-sans); 80 | --font-mono: var(--font-mono); 81 | --color-background: var(--background); 82 | --color-foreground: var(--foreground); 83 | --color-card: var(--card); 84 | --color-card-foreground: var(--card-foreground); 85 | --color-popover: var(--popover); 86 | --color-popover-foreground: var(--popover-foreground); 87 | --color-primary: var(--primary); 88 | --color-primary-foreground: var(--primary-foreground); 89 | --color-secondary: var(--secondary); 90 | --color-secondary-foreground: var(--secondary-foreground); 91 | --color-muted: var(--muted); 92 | --color-muted-foreground: var(--muted-foreground); 93 | --color-accent: var(--accent); 94 | --color-accent-foreground: var(--accent-foreground); 95 | --color-destructive: var(--destructive); 96 | --color-destructive-foreground: var(--destructive-foreground); 97 | --color-border: var(--border); 98 | --color-input: var(--input); 99 | --color-ring: var(--ring); 100 | --color-chart-1: var(--chart-1); 101 | --color-chart-2: var(--chart-2); 102 | --color-chart-3: var(--chart-3); 103 | --color-chart-4: var(--chart-4); 104 | --color-chart-5: var(--chart-5); 105 | --radius-sm: calc(var(--radius) - 4px); 106 | --radius-md: calc(var(--radius) - 2px); 107 | --radius-lg: var(--radius); 108 | --radius-xl: calc(var(--radius) + 4px); 109 | --color-sidebar: var(--sidebar); 110 | --color-sidebar-foreground: var(--sidebar-foreground); 111 | --color-sidebar-primary: var(--sidebar-primary); 112 | --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); 113 | --color-sidebar-accent: var(--sidebar-accent); 114 | --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); 115 | --color-sidebar-border: var(--sidebar-border); 116 | --color-sidebar-ring: var(--sidebar-ring); 117 | --animate-accordion-down: accordion-down 0.2s ease-out; 118 | --animate-accordion-up: accordion-up 0.2s ease-out; 119 | 120 | @keyframes accordion-down { 121 | from { 122 | height: 0; 123 | } 124 | to { 125 | height: var(--radix-accordion-content-height); 126 | } 127 | } 128 | 129 | @keyframes accordion-up { 130 | from { 131 | height: var(--radix-accordion-content-height); 132 | } 133 | to { 134 | height: 0; 135 | } 136 | } 137 | } 138 | 139 | @layer base { 140 | * { 141 | @apply border-border outline-ring/50; 142 | } 143 | body { 144 | @apply bg-background text-foreground; 145 | } 146 | } 147 | 148 | @utility container { 149 | margin-inline: auto; 150 | padding-inline: 2rem; 151 | 152 | @media (width >= --theme(--breakpoint-sm)) { 153 | max-width: none; 154 | } 155 | 156 | @media (width >= 1400px) { 157 | max-width: 1400px; 158 | } 159 | 160 | @media (max-width: 640px) { 161 | @apply px-4; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Base Options: */ 4 | "esModuleInterop": true, 5 | "skipLibCheck": true, 6 | "target": "es2022", 7 | "allowJs": true, 8 | "resolveJsonModule": true, 9 | "moduleDetection": "force", 10 | "isolatedModules": true, 11 | 12 | /* Strictness */ 13 | "strict": true, 14 | "noUncheckedIndexedAccess": true, 15 | "checkJs": true, 16 | 17 | /* Bundled projects */ 18 | "lib": ["dom", "dom.iterable", "ES2022"], 19 | "noEmit": true, 20 | "module": "ESNext", 21 | "moduleResolution": "Bundler", 22 | "jsx": "preserve", 23 | "plugins": [{ "name": "next" }], 24 | "incremental": true, 25 | 26 | /* Path Aliases */ 27 | "baseUrl": ".", 28 | "paths": { 29 | "@/*": ["./src/*"] 30 | } 31 | }, 32 | "include": [ 33 | "next-env.d.ts", 34 | "**/*.ts", 35 | "**/*.tsx", 36 | "**/*.cjs", 37 | "**/*.js", 38 | ".next/types/**/*.ts" 39 | ], 40 | "exclude": ["node_modules"] 41 | } 42 | --------------------------------------------------------------------------------