├── test
├── setup.ts
└── Marquee.test.tsx
├── src
├── index.ts
├── types.ts
├── marquee.css
└── Marquee.tsx
├── .prettierrc
├── tsconfig.node.json
├── examples
├── tsconfig.node.json
├── src
│ ├── main.tsx
│ ├── index.css
│ ├── App.css
│ └── App.tsx
├── vite.config.ts
├── index.html
├── package.json
├── tsconfig.json
└── pnpm-lock.yaml
├── vitest.config.ts
├── .npmignore
├── .gitignore
├── CHANGELOG.md
├── .eslintrc.cjs
├── tsconfig.json
├── vite.config.ts
├── package.json
├── README.zh-CN.md
└── README.md
/test/setup.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom';
2 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export { Marquee } from './Marquee';
2 | export type { MarqueeProps, MarqueeItem } from './types';
3 | export type { MarqueeHandle } from './Marquee';
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": true,
3 | "singleQuote": true,
4 | "trailingComma": "es5",
5 | "printWidth": 100,
6 | "tabWidth": 2,
7 | "useTabs": false,
8 | "bracketSpacing": true,
9 | "arrowParens": "avoid"
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/examples/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/examples/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 | import './index.css'
5 | import '../../src/marquee.css'
6 |
7 | ReactDOM.createRoot(document.getElementById('root')!).render(
8 |
9 |
10 | ,
11 | )
12 |
--------------------------------------------------------------------------------
/examples/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | base: '/react-marquee/',
8 | server: {
9 | port: 3000,
10 | },
11 | build: {
12 | outDir: 'dist',
13 | },
14 | })
15 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vitest/config'
2 | import react from '@vitejs/plugin-react'
3 |
4 | export default defineConfig({
5 | plugins: [react()],
6 | test: {
7 | environment: 'jsdom',
8 | setupFiles: ['./test/setup.ts'],
9 | globals: true,
10 | include: ['./test/**/*.{test,spec}.{ts,tsx}']
11 | },
12 | })
13 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Source
2 | src
3 | examples
4 | tests
5 |
6 | # Config files
7 | .eslintrc.cjs
8 | .prettierrc
9 | tsconfig.json
10 | tsconfig.node.json
11 | vite.config.ts
12 | vitest.config.ts
13 |
14 | # Development files
15 | node_modules
16 | coverage
17 | *.log
18 | .husky
19 | .vscode
20 | .idea
21 | .DS_Store
22 |
23 | # Git files
24 | .git
25 | .gitignore
26 |
27 | # CI/CD
28 | .github
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React Marquee Demo
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | # Test coverage
27 | coverage
28 | pnpm-lock.yaml
29 | package-lock.json
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [2.0.0] - 2024-12-09
4 |
5 | ### Breaking Changes
6 | - 升级到 React 18
7 | - 迁移到 TypeScript
8 | - 使用 Vite 替代 Webpack 作为构建工具
9 | - 更新了组件 API 以支持 TypeScript 类型
10 |
11 | ### Added
12 | - 添加完整的 TypeScript 类型定义
13 | - 添加 ESM 和 CommonJS 双模块格式支持
14 | - 添加 Vitest 测试支持
15 | - 添加更好的无缝滚动支持
16 | - 添加反向滚动功能优化
17 |
18 | ### Changed
19 | - 重构为函数组件
20 | - 使用 CSS transform 替代 scroll 实现更流畅的动画
21 | - 优化滚动逻辑,提供更好的性能
22 | - 改进文档和示例
23 |
24 | ### Fixed
25 | - 修复反向滚动不连续的问题
26 | - 修复滚动重置时的视觉跳动
27 |
28 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:@typescript-eslint/recommended',
7 | 'plugin:react-hooks/recommended',
8 | ],
9 | ignorePatterns: ['dist', '.eslintrc.cjs'],
10 | parser: '@typescript-eslint/parser',
11 | plugins: ['react-refresh'],
12 | rules: {
13 | 'react-refresh/only-export-components': [
14 | 'warn',
15 | { allowConstantExport: true },
16 | ],
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/examples/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-marquee-examples",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "react": "^18.2.0",
13 | "react-dom": "^18.2.0"
14 | },
15 | "devDependencies": {
16 | "@types/react": "^18.2.43",
17 | "@types/react-dom": "^18.2.17",
18 | "@vitejs/plugin-react": "^4.2.1",
19 | "typescript": "^5.2.2",
20 | "vite": "^5.0.8"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": ["src"],
24 | "references": [{ "path": "./tsconfig.node.json" }]
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 | "moduleResolution": "bundler",
9 | "allowImportingTsExtensions": true,
10 | "resolveJsonModule": true,
11 | "isolatedModules": true,
12 | "noEmit": true,
13 | "jsx": "react-jsx",
14 | "strict": true,
15 | "noUnusedLocals": false,
16 | "noUnusedParameters": false,
17 | "noFallthroughCasesInSwitch": true,
18 | "declaration": true,
19 | "declarationDir": "dist",
20 | "emitDeclarationOnly": true
21 | },
22 | "include": ["src"],
23 | "references": [{ "path": "./tsconfig.node.json" }]
24 | }
25 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 | import dts from 'vite-plugin-dts'
4 | import { resolve } from 'path'
5 |
6 | // https://vitejs.dev/config/
7 | export default defineConfig(({ command, mode }) => {
8 | const config = {
9 | plugins: [
10 | react(),
11 | dts({
12 | insertTypesEntry: true,
13 | }),
14 | ],
15 | }
16 |
17 | if (mode === 'demo') {
18 | return {
19 | ...config,
20 | root: 'examples',
21 | }
22 | }
23 |
24 | if (command === 'build') {
25 | return {
26 | ...config,
27 | build: {
28 | lib: {
29 | entry: resolve(__dirname, 'src/index.ts'),
30 | name: 'ReactMarquee',
31 | formats: ['es', 'umd'],
32 | fileName: (format) => `react-marquee.${format}.js`,
33 | },
34 | rollupOptions: {
35 | external: ['react', 'react-dom'],
36 | output: {
37 | globals: {
38 | react: 'React',
39 | 'react-dom': 'ReactDOM',
40 | },
41 | },
42 | },
43 | },
44 | }
45 | }
46 |
47 | return config
48 | })
49 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | export interface MarqueeItem {
2 | txt: string;
3 | [key: string]: any;
4 | }
5 |
6 | export interface MarqueeProps {
7 | /**
8 | * 循环显示的数据数组
9 | */
10 | loopData: MarqueeItem[];
11 |
12 | /**
13 | * 滚动方向,可选 'horizontal' 或 'vertical'
14 | * @default 'horizontal'
15 | */
16 | direction?: 'horizontal' | 'vertical';
17 |
18 | /**
19 | * 滚动速度,可选。如果不提供,将根据内容长度自动计算合适的速度。
20 | * 水平方向:内容越长,速度适当增加(每20个字符增加1的速度,上限为8)
21 | * 垂直方向:保持相对稳定的速度(仅根据内容长度做小幅调整)
22 | */
23 | speed?: number;
24 |
25 | /**
26 | * 垂直滚动时的单项高度
27 | * @default '60px'
28 | */
29 | verticalItemHeight?: string;
30 |
31 | /**
32 | * 是否反向滚动
33 | * @default false
34 | */
35 | reverse?: boolean;
36 |
37 | /**
38 | * 鼠标悬停时是否暂停
39 | * @default false
40 | */
41 | hoverPause?: boolean;
42 |
43 | /**
44 | * 是否自动播放
45 | * @default true
46 | */
47 | autoPlay?: boolean;
48 |
49 | /**
50 | * 点击事件回调
51 | */
52 | onClick?: (item: MarqueeItem, index: number) => void;
53 |
54 | /**
55 | * 自定义类名
56 | */
57 | className?: string;
58 |
59 | /**
60 | * 自定义样式
61 | */
62 | style?: React.CSSProperties;
63 | }
64 |
--------------------------------------------------------------------------------
/src/marquee.css:
--------------------------------------------------------------------------------
1 | .marquee-container {
2 | position: relative;
3 | width: 100%;
4 | height: 100%;
5 | overflow: hidden;
6 | }
7 |
8 | .marquee-container.horizontal {
9 | overflow-x: hidden;
10 | overflow-y: hidden;
11 | height: 40px;
12 | }
13 |
14 | .marquee-container.vertical {
15 | overflow-x: hidden;
16 | overflow-y: hidden;
17 | }
18 |
19 | .marquee-content {
20 | display: flex;
21 | white-space: nowrap;
22 | will-change: transform;
23 | height: 100%;
24 | }
25 |
26 | .horizontal .marquee-content {
27 | flex-direction: row;
28 | width: max-content;
29 | height: 100%;
30 | }
31 |
32 | .vertical .marquee-content {
33 | flex-direction: column;
34 | min-height: 100%;
35 | margin: 0;
36 | padding: 0;
37 | gap: 0;
38 | }
39 |
40 | .marquee-group {
41 | display: flex;
42 | flex-shrink: 0;
43 | margin: 0;
44 | padding: 0;
45 | gap: 0;
46 | }
47 |
48 | .horizontal .marquee-group {
49 | flex-direction: row;
50 | height: 100%;
51 | }
52 |
53 | .vertical .marquee-group {
54 | flex-direction: column;
55 | width: 100%;
56 | margin: 0;
57 | padding: 0;
58 | gap: 0;
59 | }
60 |
61 | .marquee-item {
62 | display: flex;
63 | align-items: center;
64 | cursor: pointer;
65 | transition: background-color 0.3s;
66 | user-select: none;
67 | box-sizing: border-box;
68 | margin: 0;
69 | padding: 0;
70 | }
71 |
72 | .horizontal .marquee-item {
73 | height: 100%;
74 | padding: 0 20px;
75 | }
76 |
77 | .vertical .marquee-item {
78 | width: 100%;
79 | height: 40px;
80 | line-height: 40px;
81 | padding: 0 10px;
82 | margin: 0;
83 | justify-content: center;
84 | border-bottom: 1px solid #eee;
85 | }
86 |
87 | .marquee-item:hover {
88 | background-color: rgba(0, 0, 0, 0.05);
89 | }
90 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-marquee-order",
3 | "version": "2.0.0",
4 | "description": "A modern React seamless scroll component with TypeScript support",
5 | "type": "module",
6 | "main": "./dist/react-marquee.umd.js",
7 | "module": "./dist/react-marquee.es.js",
8 | "types": "./dist/index.d.ts",
9 | "exports": {
10 | ".": {
11 | "import": "./dist/react-marquee.es.js",
12 | "require": "./dist/react-marquee.umd.js",
13 | "types": "./dist/index.d.ts"
14 | },
15 | "./dist/style.css": "./dist/style.css"
16 | },
17 | "files": [
18 | "dist",
19 | "README.md",
20 | "CHANGELOG.md"
21 | ],
22 | "scripts": {
23 | "build": "tsc && vite build",
24 | "examples:dev": "cd examples && pnpm dev",
25 | "examples:build": "cd examples && pnpm i && pnpm build",
26 | "test": "vitest run",
27 | "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
28 | "format": "prettier --write \"src/**/*.{ts,tsx}\"",
29 | "prepare": "husky install && pnpm build",
30 | "deploy": "npm run examples:build && gh-pages -d examples/dist"
31 | },
32 | "keywords": [
33 | "react",
34 | "scroll",
35 | "seamless",
36 | "marquee",
37 | "typescript",
38 | "animation",
39 | "component",
40 | "ui"
41 | ],
42 | "peerDependencies": {
43 | "react": ">=18.0.0",
44 | "react-dom": ">=18.0.0"
45 | },
46 | "devDependencies": {
47 | "@testing-library/jest-dom": "^6.1.0",
48 | "@testing-library/react": "^14.0.0",
49 | "@types/react": "^18.2.0",
50 | "@types/react-dom": "^18.2.0",
51 | "@typescript-eslint/eslint-plugin": "^6.0.0",
52 | "@typescript-eslint/parser": "^6.0.0",
53 | "@vitejs/plugin-react": "^4.0.0",
54 | "eslint": "^8.0.0",
55 | "eslint-plugin-react-hooks": "^4.6.0",
56 | "eslint-plugin-react-refresh": "^0.4.5",
57 | "gh-pages": "^6.2.0",
58 | "husky": "^8.0.3",
59 | "jsdom": "^22.0.0",
60 | "prettier": "^3.1.0",
61 | "typescript": "^5.0.0",
62 | "vite": "^5.0.0",
63 | "vite-plugin-dts": "^3.0.0",
64 | "vitest": "^1.0.0"
65 | },
66 | "repository": {
67 | "type": "git",
68 | "url": "git+https://github.com/zhongs/react-marquee.git"
69 | },
70 | "author": "Your Name",
71 | "license": "MIT",
72 | "publishConfig": {
73 | "access": "public"
74 | },
75 | "engines": {
76 | "node": ">=16"
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/test/Marquee.test.tsx:
--------------------------------------------------------------------------------
1 | import { describe, it, expect, beforeEach, vi } from 'vitest';
2 | import { render, screen, fireEvent } from '@testing-library/react';
3 | import { Marquee } from '../src/Marquee';
4 | import React from 'react';
5 |
6 | describe('Marquee Component', () => {
7 | const mockData = [
8 | { text: 'Item 1' },
9 | { text: 'Item 2' },
10 | { text: 'Item 3' }
11 | ];
12 |
13 | beforeEach(() => {
14 | vi.useFakeTimers();
15 | });
16 |
17 | it('renders without crashing', () => {
18 | render();
19 | expect(screen.getByText('Item 1')).toBeDefined();
20 | });
21 |
22 | it('renders all items', () => {
23 | render();
24 | mockData.forEach(item => {
25 | expect(screen.getByText(item.text)).toBeDefined();
26 | });
27 | });
28 |
29 | it('handles click events', () => {
30 | const handleClick = vi.fn();
31 | render();
32 |
33 | fireEvent.click(screen.getByText('Item 1'));
34 | expect(handleClick).toHaveBeenCalledWith(mockData[0], 0);
35 | });
36 |
37 | it('pauses on hover when hoverPause is true', () => {
38 | render();
39 | const container = screen.getByText('Item 1').parentElement;
40 |
41 | expect(container).toBeDefined();
42 | if (container) {
43 | fireEvent.mouseEnter(container);
44 | // 验证暂停状态
45 | // 这里可以添加更多具体的暂停状态检查
46 | }
47 | });
48 |
49 | it('supports both horizontal and vertical directions', () => {
50 | const { rerender } = render();
51 | expect(screen.getByText('Item 1').parentElement?.className).toContain('horizontal');
52 |
53 | rerender();
54 | expect(screen.getByText('Item 1').parentElement?.className).toContain('vertical');
55 | });
56 |
57 | it('supports reverse scrolling', () => {
58 | const { rerender } = render();
59 | const container = screen.getByText('Item 1').parentElement;
60 |
61 | expect(container).toBeDefined();
62 | if (container) {
63 | const initialTransform = container.style.transform;
64 |
65 | rerender();
66 | // 验证滚动方向改变
67 | // 这里可以添加更多具体的方向检查
68 | }
69 | });
70 | });
71 |
--------------------------------------------------------------------------------
/README.zh-CN.md:
--------------------------------------------------------------------------------
1 | # React 无缝滚动组件
2 |
3 | 一个现代化的 React 无缝滚动组件,完美支持横向和纵向滚动。基于 TypeScript 开发,具有丝滑流畅的滚动效果、灵活的配置选项和完整的类型支持。
4 |
5 | ## 🌐 演示
6 |
7 | 查看在线演示:[React 无缝滚动演示](https://zhongs.github.io/react-marquee/)
8 |
9 | ## ✨ 特性
10 |
11 | - 🔄 完美无缝滚动,无断层感
12 | - ↔️ 支持横向和纵向滚动
13 | - 🎯 自定义滚动速度
14 | - 🔁 支持正反向滚动
15 | - ⏯️ 支持鼠标悬停暂停
16 | - 🖱️ 支持点击事件处理
17 | - 🎨 灵活的样式定制
18 | - 📱 响应式设计
19 | - 🚀 TypeScript 编写,类型安全
20 | - 🔥 基于 React 18+ 构建
21 | - 📦 零依赖(仅依赖 React)
22 | - ⚡️ 基于 transform 实现,性能出众
23 |
24 | ## 📦 安装
25 |
26 | ```bash
27 | npm install react-marquee-order
28 | # 或者
29 | pnpm add react-marquee-order
30 | # 或者
31 | yarn add react-marquee-order
32 | ```
33 |
34 | ## 🚀 使用示例
35 |
36 | ```tsx
37 | import React, { useRef } from 'react';
38 | import { Marquee, MarqueeHandle } from 'react-marquee-order';
39 |
40 | const App = () => {
41 | const marqueeRef = useRef(null);
42 |
43 | const data = [
44 | { text: "无缝滚动第一项" },
45 | { text: "无缝滚动第二项" },
46 | { text: "无缝滚动第三项" }
47 | ];
48 |
49 | const handleClick = (item: any, index: number) => {
50 | console.log('点击了:', item, '索引:', index);
51 | };
52 |
53 | return (
54 |
55 |
64 |
65 | );
66 | };
67 |
68 | export default App;
69 | ```
70 |
71 | ## 📖 API 文档
72 |
73 | ### Props 属性
74 |
75 | | 属性 | 类型 | 默认值 | 描述 |
76 | |------|------|--------|------|
77 | | loopData | `Array` | `[]` | 要循环显示的数据数组 |
78 | | direction | `'horizontal' \| 'vertical'` | `'horizontal'` | 滚动方向:水平/垂直 |
79 | | speed | `number` | `2` | 滚动速度(每帧像素) |
80 | | reverse | `boolean` | `false` | 是否反向滚动 |
81 | | hoverPause | `boolean` | `true` | 鼠标悬停时是否暂停 |
82 | | onClick | `(item: any, index: number) => void` | - | 点击项目的回调函数 |
83 |
84 | ### 组件方法
85 |
86 | 通过 ref 可以调用以下方法:
87 |
88 | - `play()`: 开始滚动
89 | - `pause()`: 暂停滚动
90 | - `reset()`: 重置位置
91 |
92 | ## 🚨 v2.0.0 版本更新
93 |
94 | - 🆙 升级到 React 18
95 | - 📝 迁移到 TypeScript,提供完整类型支持
96 | - 🛠️ 构建工具升级到 Vite
97 | - ⚡️ 优化滚动算法,提供更流畅的体验
98 | - 🎯 改进 API 设计,提供更好的类型支持
99 |
100 | ## 🌐 浏览器支持
101 |
102 | 支持所有现代浏览器,搭配合适的 polyfills 可支持 IE11+。
103 |
104 | ## 🤝 参与贡献
105 |
106 | 欢迎提交 Pull Request 来改进这个组件!
107 |
108 | ## 📄 许可证
109 |
110 | MIT © [Your Name]
111 |
112 | ---
113 |
114 | [English](./README.md) | 简体中文
115 |
--------------------------------------------------------------------------------
/examples/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3 | line-height: 1.5;
4 | font-weight: 400;
5 |
6 | color-scheme: light dark;
7 | color: rgba(255, 255, 255, 0.87);
8 | background-color: #242424;
9 |
10 | font-synthesis: none;
11 | text-rendering: optimizeLegibility;
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | }
15 |
16 | body {
17 | margin: 0;
18 | display: flex;
19 | place-items: center;
20 | min-width: 320px;
21 | min-height: 100vh;
22 | }
23 |
24 | .container {
25 | max-width: 1200px;
26 | width: 100%;
27 | margin: 0 auto;
28 | padding: 2rem;
29 | box-sizing: border-box;
30 | }
31 |
32 | .demo-section {
33 | margin-bottom: 2rem;
34 | padding: 1rem;
35 | border: 1px solid #eee;
36 | border-radius: 8px;
37 | }
38 |
39 | .demo-section h2 {
40 | margin-top: 0;
41 | color: #333;
42 | }
43 |
44 | .controls {
45 | margin: 1rem 0;
46 | display: flex;
47 | flex-wrap: wrap;
48 | gap: 1rem;
49 | align-items: center;
50 | }
51 |
52 | button {
53 | padding: 0.5rem 1rem;
54 | border: none;
55 | border-radius: 4px;
56 | background: #646cff;
57 | color: white;
58 | cursor: pointer;
59 | transition: background-color 0.3s;
60 | font-size: 14px;
61 | white-space: nowrap;
62 | }
63 |
64 | button:hover {
65 | background: #747bff;
66 | }
67 |
68 | .speed-control {
69 | display: flex;
70 | align-items: center;
71 | gap: 0.5rem;
72 | flex-wrap: wrap;
73 | }
74 |
75 | .speed-control label {
76 | font-size: 14px;
77 | }
78 |
79 | .speed-control input[type="range"] {
80 | width: 100px;
81 | }
82 |
83 | .vertical-container {
84 | height: 200px;
85 | border: 1px solid #eee;
86 | margin: 1rem 0;
87 | }
88 |
89 | /* 移动端适配 */
90 | @media screen and (max-width: 768px) {
91 | .container {
92 | padding: 1rem;
93 | }
94 |
95 | .demo-section {
96 | padding: 0.75rem;
97 | }
98 |
99 | .controls {
100 | gap: 0.5rem;
101 | }
102 |
103 | button {
104 | padding: 0.4rem 0.8rem;
105 | font-size: 13px;
106 | }
107 |
108 | .speed-control {
109 | width: 100%;
110 | margin-bottom: 0.5rem;
111 | }
112 |
113 | .speed-control input[type="range"] {
114 | flex: 1;
115 | min-width: 120px;
116 | }
117 |
118 | h1 {
119 | font-size: 1.5rem;
120 | margin: 1rem 0;
121 | }
122 |
123 | h2 {
124 | font-size: 1.2rem;
125 | }
126 |
127 | p {
128 | font-size: 0.9rem;
129 | }
130 | }
131 |
132 | /* 小屏幕手机适配 */
133 | @media screen and (max-width: 480px) {
134 | .container {
135 | padding: 0.75rem;
136 | }
137 |
138 | .demo-section {
139 | padding: 0.5rem;
140 | margin-bottom: 1rem;
141 | }
142 |
143 | button {
144 | padding: 0.3rem 0.6rem;
145 | font-size: 12px;
146 | }
147 |
148 | .vertical-container {
149 | height: 150px;
150 | }
151 | }
152 |
153 | @media (prefers-color-scheme: light) {
154 | :root {
155 | color: #213547;
156 | background-color: #ffffff;
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/examples/src/App.css:
--------------------------------------------------------------------------------
1 | .demo-container {
2 | max-width: 1200px;
3 | margin: 0 auto;
4 | padding: 20px;
5 | }
6 |
7 | h1 {
8 | text-align: center;
9 | color: #333;
10 | margin-bottom: 40px;
11 | }
12 |
13 | .demo-section {
14 | margin-bottom: 40px;
15 | padding: 20px;
16 | border-radius: 8px;
17 | background: #fff;
18 | box-shadow: 0 2px 8px rgba(0,0,0,0.1);
19 | }
20 |
21 | .type-title {
22 | font-size: 18px;
23 | color: #333;
24 | margin-bottom: 20px;
25 | padding-bottom: 10px;
26 | border-bottom: 2px solid #eee;
27 | }
28 |
29 | .demo-box {
30 | display: flex;
31 | gap: 20px;
32 | margin-bottom: 20px;
33 | }
34 |
35 | .demo-box .preview {
36 | flex: 1;
37 | min-width: 0; /* 防止flex子项溢出 */
38 | }
39 |
40 | .demo-box .code {
41 | flex: 1;
42 | min-width: 0; /* 防止flex子项溢出 */
43 | }
44 |
45 | .box-landscape {
46 | width: 100%;
47 | height: 40px;
48 | position: relative;
49 | background: #f5f5f5;
50 | border-radius: 4px;
51 | margin-bottom: 15px;
52 | border: 1px solid #eee;
53 | overflow: hidden;
54 | }
55 |
56 | .box-vertical {
57 | width: 100%;
58 | height: 240px;
59 | position: relative;
60 | background: #f5f5f5;
61 | border-radius: 4px;
62 | margin-bottom: 15px;
63 | border: 1px solid #eee;
64 | overflow: hidden;
65 | }
66 |
67 | /* 垂直滚动样式 */
68 | .box-vertical .marquee-container {
69 | height: 100%;
70 | }
71 |
72 | .box-vertical .marquee-content {
73 | height: 100%;
74 | }
75 |
76 | .box-vertical .marquee-group {
77 | height: 100%;
78 | margin: 0;
79 | padding: 0;
80 | gap: 0;
81 | }
82 |
83 | .box-vertical .marquee-item {
84 | height: 40px;
85 | line-height: 40px;
86 | margin: 0;
87 | padding: 0 10px;
88 | background: #fff;
89 | display: flex;
90 | align-items: center;
91 | }
92 |
93 | .controls {
94 | display: flex;
95 | gap: 10px;
96 | justify-content: center;
97 | }
98 |
99 | .button {
100 | padding: 8px 16px;
101 | border: none;
102 | border-radius: 4px;
103 | background: #1890ff;
104 | color: white;
105 | cursor: pointer;
106 | transition: background 0.3s ease;
107 | }
108 |
109 | .button:hover {
110 | background: #40a9ff;
111 | }
112 |
113 | .button:active {
114 | background: #096dd9;
115 | }
116 |
117 | /* 代码块样式 */
118 | .code-block {
119 | margin: 0;
120 | padding: 16px;
121 | background: #f6f8fa;
122 | border-radius: 6px;
123 | font-family: Consolas, Monaco, 'Andale Mono', monospace;
124 | font-size: 14px;
125 | line-height: 1.5;
126 | overflow: auto;
127 | border: 1px solid #eee;
128 | white-space: pre;
129 | word-wrap: normal;
130 | }
131 |
132 | .code-block code {
133 | color: #476582;
134 | }
135 |
136 | /* 响应式布局 */
137 | @media (max-width: 768px) {
138 | .demo-container {
139 | padding: 10px;
140 | }
141 |
142 | .demo-section {
143 | padding: 15px;
144 | }
145 |
146 | .demo-box {
147 | flex-direction: column;
148 | }
149 |
150 | .type-title {
151 | font-size: 16px;
152 | }
153 |
154 | .box-landscape {
155 | height: 36px;
156 | }
157 |
158 | .box-vertical {
159 | height: 200px;
160 | }
161 |
162 | .button {
163 | padding: 6px 12px;
164 | font-size: 14px;
165 | }
166 |
167 | .code-block {
168 | font-size: 12px;
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Seamless Scroll
2 |
3 | English | [简体中文](./README.zh-CN.md)
4 |
5 | A modern React seamless scrolling component with perfect support for both horizontal and vertical scrolling. Built with TypeScript, featuring smooth scrolling effects, flexible configuration options, and complete type support.
6 |
7 | ## 🌐 Demo
8 |
9 | Check out the live demo: [React Seamless Scroll Demo](https://zhongs.github.io/react-marquee/)
10 |
11 | ## ✨ Features
12 |
13 | - 🔄 Perfect seamless scrolling without gaps
14 | - ↔️ Horizontal and vertical scrolling
15 | - 🎯 Customizable scroll speed
16 | - 🔁 Support for forward and reverse scrolling
17 | - ⏯️ Hover pause support
18 | - 🖱️ Click event handling
19 | - 🎨 Flexible style customization
20 | - 📱 Responsive design
21 | - 🚀 Written in TypeScript for type safety
22 | - 🔥 Built with React 18+
23 | - 📦 Zero dependencies (except React)
24 | - ⚡️ Transform-based implementation for superior performance
25 |
26 | ## 📦 Installation
27 |
28 | ```bash
29 | npm install react-marquee-order
30 | # or
31 | pnpm add react-marquee-order
32 | # or
33 | yarn add react-marquee-order
34 | ```
35 |
36 | ## 🚀 Usage
37 |
38 | ```tsx
39 | import React, { useRef } from 'react';
40 | import { Marquee, MarqueeHandle } from 'react-marquee-order';
41 |
42 | const App = () => {
43 | const marqueeRef = useRef(null);
44 |
45 | const data = [
46 | { text: "Seamless scroll item 1" },
47 | { text: "Seamless scroll item 2" },
48 | { text: "Seamless scroll item 3" }
49 | ];
50 |
51 | const handleClick = (item: any, index: number) => {
52 | console.log('Clicked:', item, 'at index:', index);
53 | };
54 |
55 | return (
56 |
57 |
66 |
67 | );
68 | };
69 |
70 | export default App;
71 | ```
72 |
73 | ## 📖 API Reference
74 |
75 | ### Props
76 |
77 | | Prop | Type | Default | Description |
78 | |------|------|---------|-------------|
79 | | loopData | `Array` | `[]` | Data array for continuous scrolling |
80 | | direction | `'horizontal' \| 'vertical'` | `'horizontal'` | Scroll direction: horizontal/vertical |
81 | | speed | `number` | `2` | Scroll speed (pixels per frame) |
82 | | reverse | `boolean` | `false` | Whether to scroll in reverse |
83 | | hoverPause | `boolean` | `true` | Whether to pause on hover |
84 | | onClick | `(item: any, index: number) => void` | - | Callback function for item clicks |
85 |
86 | ### Methods
87 |
88 | The component exposes these methods via ref:
89 |
90 | - `play()`: Start scrolling
91 | - `pause()`: Pause scrolling
92 | - `reset()`: Reset position
93 |
94 | ## 🚨 v2.0.0 Updates
95 |
96 | - 🆙 Upgraded to React 18
97 | - 📝 Migrated to TypeScript with full type support
98 | - 🛠️ Upgraded build tool to Vite
99 | - ⚡️ Optimized scrolling algorithm for smoother experience
100 | - 🎯 Improved API design with better type support
101 |
102 | ## 🌐 Browser Support
103 |
104 | Supports all modern browsers and IE11+ with appropriate polyfills.
105 |
106 | ## 🤝 Contributing
107 |
108 | Pull requests are welcome to improve this component!
109 |
110 | ## 📄 License
111 |
112 | MIT
113 |
--------------------------------------------------------------------------------
/examples/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { useRef, useState } from 'react';
2 | import { Marquee, MarqueeHandle } from '../../src/index';
3 |
4 | const DEFAULT_SPEED = 2;
5 |
6 | const App = () => {
7 | const horizontalRef = useRef(null);
8 | const verticalRef = useRef(null);
9 |
10 | const [horizontalSpeed, setHorizontalSpeed] = useState(DEFAULT_SPEED);
11 | const [verticalSpeed, setVerticalSpeed] = useState(DEFAULT_SPEED);
12 | const [horizontalReverse, setHorizontalReverse] = useState(false);
13 | const [verticalReverse, setVerticalReverse] = useState(false);
14 |
15 | const horizontalData = [
16 | { txt: "无缝滚动示例 1" },
17 | { txt: "无缝滚动示例 2" },
18 | { txt: "无缝滚动示例 3" },
19 | { txt: "无缝滚动示例 4" },
20 | { txt: "无缝滚动示例 5" }
21 | ];
22 |
23 | const verticalData = [
24 | { txt: "垂直滚动项 1" },
25 | { txt: "垂直滚动项 2" },
26 | { txt: "垂直滚动项 3" },
27 | { txt: "垂直滚动项 4" },
28 | { txt: "垂直滚动项 5" }
29 | ];
30 |
31 | const handleClick = (item: any, index: number) => {
32 | console.log('点击了:', item, '索引:', index);
33 | alert(`点击了: ${item.txt} (索引: ${index})`);
34 | };
35 |
36 | const handleHorizontalReset = () => {
37 | horizontalRef.current?.reset();
38 | setHorizontalSpeed(DEFAULT_SPEED);
39 | setHorizontalReverse(false);
40 | };
41 |
42 | const handleVerticalReset = () => {
43 | verticalRef.current?.reset();
44 | setVerticalSpeed(DEFAULT_SPEED);
45 | setVerticalReverse(false);
46 | };
47 |
48 | return (
49 |
50 |
React 无缝滚动演示
51 |
52 | {/* 水平滚动演示 */}
53 |
54 | 水平滚动
55 |
56 |
57 |
58 | setHorizontalSpeed(Number(e.target.value))}
64 | />
65 | {horizontalSpeed}
66 |
67 |
70 |
71 |
72 |
73 |
74 |
75 |
84 |
85 | 提示:鼠标悬停可暂停滚动,点击项目可触发事件
86 |
87 |
88 | {/* 垂直滚动演示 */}
89 |
90 | 垂直滚动
91 |
92 |
93 |
94 | setVerticalSpeed(Number(e.target.value))}
100 | />
101 | {verticalSpeed}
102 |
103 |
106 |
107 |
108 |
109 |
110 |
111 |
120 |
121 | 提示:鼠标悬停可暂停滚动,点击项目可触发事件
122 |
123 |
124 | );
125 | };
126 |
127 | export default App;
128 |
--------------------------------------------------------------------------------
/src/Marquee.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef, useState, useCallback, forwardRef, useImperativeHandle } from 'react';
2 | import { MarqueeProps, MarqueeItem } from './types';
3 | import './marquee.css';
4 |
5 | export interface MarqueeHandle {
6 | play: () => void;
7 | pause: () => void;
8 | reset: () => void;
9 | }
10 |
11 | // 计算建议的滚动速度
12 | const calculateSpeed = (content: MarqueeItem[], direction: 'horizontal' | 'vertical'): number => {
13 | // 计算内容总长度
14 | const totalLength = content.reduce((acc, item) => acc + (item.txt?.length || 0), 0);
15 |
16 | // 基础速度参数
17 | const baseSpeed = 2;
18 |
19 | // 根据内容长度调整速度
20 | // 水平方向:内容越长,速度适当增加
21 | // 垂直方向:保持相对稳定的速度
22 | if (direction === 'horizontal') {
23 | // 每20个字符增加1的速度,但设置上限为8
24 | const adjustedSpeed = baseSpeed + Math.min(Math.floor(totalLength / 20), 6);
25 | return adjustedSpeed;
26 | } else {
27 | // 垂直方向速度相对稳定,仅做小幅调整
28 | return baseSpeed + Math.min(Math.floor(totalLength / 50), 2);
29 | }
30 | };
31 |
32 | export const Marquee = forwardRef(({
33 | loopData,
34 | direction = 'horizontal',
35 | speed,
36 | verticalItemHeight = '60px',
37 | reverse = false,
38 | hoverPause = false,
39 | autoPlay = true,
40 | onClick,
41 | className = '',
42 | style = {},
43 | }, ref) => {
44 | const containerRef = useRef(null);
45 | const contentRef = useRef(null);
46 | const [isRunning, setIsRunning] = useState(autoPlay);
47 | const [isPaused, setIsPaused] = useState(false);
48 | const animationRef = useRef();
49 | const [offset, setOffset] = useState(0);
50 |
51 | // 如果没有提供速度,则自动计算
52 | const effectiveSpeed = speed ?? calculateSpeed(loopData, direction);
53 |
54 | useImperativeHandle(ref, () => ({
55 | play: () => {
56 | setIsRunning(true);
57 | setIsPaused(false);
58 | },
59 | pause: () => {
60 | setIsPaused(true);
61 | },
62 | reset: () => {
63 | setOffset(0);
64 | if (contentRef.current) {
65 | contentRef.current.style.transform = 'translate(0, 0)';
66 | }
67 | setIsRunning(true);
68 | setIsPaused(false);
69 | }
70 | }));
71 |
72 | const resetPosition = useCallback(() => {
73 | if (!containerRef.current || !contentRef.current) return;
74 |
75 | const content = contentRef.current;
76 | const isHorizontal = direction === 'horizontal';
77 |
78 | // 获取单个内容的尺寸
79 | const itemSize = isHorizontal ?
80 | content.scrollWidth / 3 : // 因为我们复制了两份内容,所以总宽度除以3
81 | content.scrollHeight / 3;
82 |
83 | // 设置初始位置
84 | setOffset(itemSize);
85 | }, [direction]);
86 |
87 | const animate = useCallback(() => {
88 | if (!containerRef.current || !contentRef.current || !isRunning || isPaused) return;
89 |
90 | const content = contentRef.current;
91 | const isHorizontal = direction === 'horizontal';
92 |
93 | // 获取单个内容的尺寸
94 | const itemSize = isHorizontal ?
95 | content.scrollWidth / 3 :
96 | content.scrollHeight / 3;
97 |
98 | let newOffset = offset + (reverse ? -effectiveSpeed : effectiveSpeed);
99 |
100 | // 当偏移量超出范围时重置位置
101 | if (!reverse) {
102 | if (newOffset >= itemSize * 2) {
103 | newOffset = itemSize;
104 | }
105 | } else {
106 | if (newOffset <= 0) {
107 | newOffset = itemSize;
108 | }
109 | }
110 |
111 | setOffset(newOffset);
112 |
113 | // 应用偏移量
114 | if (isHorizontal) {
115 | content.style.transform = `translateX(${-newOffset}px)`;
116 | } else {
117 | content.style.transform = `translateY(${-newOffset}px)`;
118 | }
119 |
120 | animationRef.current = requestAnimationFrame(animate);
121 | }, [isRunning, isPaused, direction, reverse, effectiveSpeed, offset]);
122 |
123 | useEffect(() => {
124 | resetPosition();
125 | }, [direction, resetPosition]);
126 |
127 | useEffect(() => {
128 | if (isRunning && !isPaused) {
129 | animationRef.current = requestAnimationFrame(animate);
130 | }
131 | return () => {
132 | if (animationRef.current) {
133 | cancelAnimationFrame(animationRef.current);
134 | }
135 | };
136 | }, [isRunning, isPaused, animate]);
137 |
138 | const handleMouseEnter = () => {
139 | if (hoverPause) {
140 | setIsPaused(true);
141 | }
142 | };
143 |
144 | const handleMouseLeave = () => {
145 | if (hoverPause) {
146 | setIsPaused(false);
147 | }
148 | };
149 |
150 | const handleClick = (item: MarqueeItem, index: number) => {
151 | if (onClick) {
152 | onClick(item, index);
153 | }
154 | };
155 |
156 | return (
157 |
164 |
179 | {/* 第一份内容 */}
180 |
181 | {loopData.map((item, index) => (
182 |
handleClick(item, index)}
190 | >
191 | {item.txt}
192 |
193 | ))}
194 |
195 | {/* 第二份内容(中间) */}
196 |
197 | {loopData.map((item, index) => (
198 |
handleClick(item, index)}
206 | >
207 | {item.txt}
208 |
209 | ))}
210 |
211 | {/* 第三份内容 */}
212 |
213 | {loopData.map((item, index) => (
214 |
handleClick(item, index)}
222 | >
223 | {item.txt}
224 |
225 | ))}
226 |
227 |
228 |
229 | );
230 | });
231 |
--------------------------------------------------------------------------------
/examples/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '9.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 |
9 | .:
10 | dependencies:
11 | react:
12 | specifier: ^18.2.0
13 | version: 18.3.1
14 | react-dom:
15 | specifier: ^18.2.0
16 | version: 18.3.1(react@18.3.1)
17 | devDependencies:
18 | '@types/react':
19 | specifier: ^18.2.43
20 | version: 18.3.14
21 | '@types/react-dom':
22 | specifier: ^18.2.17
23 | version: 18.3.2
24 | '@vitejs/plugin-react':
25 | specifier: ^4.2.1
26 | version: 4.3.4(vite@5.4.11)
27 | typescript:
28 | specifier: ^5.2.2
29 | version: 5.7.2
30 | vite:
31 | specifier: ^5.0.8
32 | version: 5.4.11
33 |
34 | packages:
35 |
36 | '@ampproject/remapping@2.3.0':
37 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
38 | engines: {node: '>=6.0.0'}
39 |
40 | '@babel/code-frame@7.26.2':
41 | resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
42 | engines: {node: '>=6.9.0'}
43 |
44 | '@babel/compat-data@7.26.3':
45 | resolution: {integrity: sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==}
46 | engines: {node: '>=6.9.0'}
47 |
48 | '@babel/core@7.26.0':
49 | resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==}
50 | engines: {node: '>=6.9.0'}
51 |
52 | '@babel/generator@7.26.3':
53 | resolution: {integrity: sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==}
54 | engines: {node: '>=6.9.0'}
55 |
56 | '@babel/helper-compilation-targets@7.25.9':
57 | resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==}
58 | engines: {node: '>=6.9.0'}
59 |
60 | '@babel/helper-module-imports@7.25.9':
61 | resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==}
62 | engines: {node: '>=6.9.0'}
63 |
64 | '@babel/helper-module-transforms@7.26.0':
65 | resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==}
66 | engines: {node: '>=6.9.0'}
67 | peerDependencies:
68 | '@babel/core': ^7.0.0
69 |
70 | '@babel/helper-plugin-utils@7.25.9':
71 | resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==}
72 | engines: {node: '>=6.9.0'}
73 |
74 | '@babel/helper-string-parser@7.25.9':
75 | resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
76 | engines: {node: '>=6.9.0'}
77 |
78 | '@babel/helper-validator-identifier@7.25.9':
79 | resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
80 | engines: {node: '>=6.9.0'}
81 |
82 | '@babel/helper-validator-option@7.25.9':
83 | resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}
84 | engines: {node: '>=6.9.0'}
85 |
86 | '@babel/helpers@7.26.0':
87 | resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==}
88 | engines: {node: '>=6.9.0'}
89 |
90 | '@babel/parser@7.26.3':
91 | resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==}
92 | engines: {node: '>=6.0.0'}
93 | hasBin: true
94 |
95 | '@babel/plugin-transform-react-jsx-self@7.25.9':
96 | resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==}
97 | engines: {node: '>=6.9.0'}
98 | peerDependencies:
99 | '@babel/core': ^7.0.0-0
100 |
101 | '@babel/plugin-transform-react-jsx-source@7.25.9':
102 | resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==}
103 | engines: {node: '>=6.9.0'}
104 | peerDependencies:
105 | '@babel/core': ^7.0.0-0
106 |
107 | '@babel/template@7.25.9':
108 | resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==}
109 | engines: {node: '>=6.9.0'}
110 |
111 | '@babel/traverse@7.26.4':
112 | resolution: {integrity: sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==}
113 | engines: {node: '>=6.9.0'}
114 |
115 | '@babel/types@7.26.3':
116 | resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==}
117 | engines: {node: '>=6.9.0'}
118 |
119 | '@esbuild/aix-ppc64@0.21.5':
120 | resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
121 | engines: {node: '>=12'}
122 | cpu: [ppc64]
123 | os: [aix]
124 |
125 | '@esbuild/android-arm64@0.21.5':
126 | resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
127 | engines: {node: '>=12'}
128 | cpu: [arm64]
129 | os: [android]
130 |
131 | '@esbuild/android-arm@0.21.5':
132 | resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
133 | engines: {node: '>=12'}
134 | cpu: [arm]
135 | os: [android]
136 |
137 | '@esbuild/android-x64@0.21.5':
138 | resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
139 | engines: {node: '>=12'}
140 | cpu: [x64]
141 | os: [android]
142 |
143 | '@esbuild/darwin-arm64@0.21.5':
144 | resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
145 | engines: {node: '>=12'}
146 | cpu: [arm64]
147 | os: [darwin]
148 |
149 | '@esbuild/darwin-x64@0.21.5':
150 | resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
151 | engines: {node: '>=12'}
152 | cpu: [x64]
153 | os: [darwin]
154 |
155 | '@esbuild/freebsd-arm64@0.21.5':
156 | resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
157 | engines: {node: '>=12'}
158 | cpu: [arm64]
159 | os: [freebsd]
160 |
161 | '@esbuild/freebsd-x64@0.21.5':
162 | resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
163 | engines: {node: '>=12'}
164 | cpu: [x64]
165 | os: [freebsd]
166 |
167 | '@esbuild/linux-arm64@0.21.5':
168 | resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
169 | engines: {node: '>=12'}
170 | cpu: [arm64]
171 | os: [linux]
172 |
173 | '@esbuild/linux-arm@0.21.5':
174 | resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
175 | engines: {node: '>=12'}
176 | cpu: [arm]
177 | os: [linux]
178 |
179 | '@esbuild/linux-ia32@0.21.5':
180 | resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
181 | engines: {node: '>=12'}
182 | cpu: [ia32]
183 | os: [linux]
184 |
185 | '@esbuild/linux-loong64@0.21.5':
186 | resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
187 | engines: {node: '>=12'}
188 | cpu: [loong64]
189 | os: [linux]
190 |
191 | '@esbuild/linux-mips64el@0.21.5':
192 | resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
193 | engines: {node: '>=12'}
194 | cpu: [mips64el]
195 | os: [linux]
196 |
197 | '@esbuild/linux-ppc64@0.21.5':
198 | resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
199 | engines: {node: '>=12'}
200 | cpu: [ppc64]
201 | os: [linux]
202 |
203 | '@esbuild/linux-riscv64@0.21.5':
204 | resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
205 | engines: {node: '>=12'}
206 | cpu: [riscv64]
207 | os: [linux]
208 |
209 | '@esbuild/linux-s390x@0.21.5':
210 | resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
211 | engines: {node: '>=12'}
212 | cpu: [s390x]
213 | os: [linux]
214 |
215 | '@esbuild/linux-x64@0.21.5':
216 | resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
217 | engines: {node: '>=12'}
218 | cpu: [x64]
219 | os: [linux]
220 |
221 | '@esbuild/netbsd-x64@0.21.5':
222 | resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
223 | engines: {node: '>=12'}
224 | cpu: [x64]
225 | os: [netbsd]
226 |
227 | '@esbuild/openbsd-x64@0.21.5':
228 | resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
229 | engines: {node: '>=12'}
230 | cpu: [x64]
231 | os: [openbsd]
232 |
233 | '@esbuild/sunos-x64@0.21.5':
234 | resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
235 | engines: {node: '>=12'}
236 | cpu: [x64]
237 | os: [sunos]
238 |
239 | '@esbuild/win32-arm64@0.21.5':
240 | resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
241 | engines: {node: '>=12'}
242 | cpu: [arm64]
243 | os: [win32]
244 |
245 | '@esbuild/win32-ia32@0.21.5':
246 | resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
247 | engines: {node: '>=12'}
248 | cpu: [ia32]
249 | os: [win32]
250 |
251 | '@esbuild/win32-x64@0.21.5':
252 | resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
253 | engines: {node: '>=12'}
254 | cpu: [x64]
255 | os: [win32]
256 |
257 | '@jridgewell/gen-mapping@0.3.5':
258 | resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
259 | engines: {node: '>=6.0.0'}
260 |
261 | '@jridgewell/resolve-uri@3.1.2':
262 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
263 | engines: {node: '>=6.0.0'}
264 |
265 | '@jridgewell/set-array@1.2.1':
266 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
267 | engines: {node: '>=6.0.0'}
268 |
269 | '@jridgewell/sourcemap-codec@1.5.0':
270 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
271 |
272 | '@jridgewell/trace-mapping@0.3.25':
273 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
274 |
275 | '@rollup/rollup-android-arm-eabi@4.28.1':
276 | resolution: {integrity: sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==}
277 | cpu: [arm]
278 | os: [android]
279 |
280 | '@rollup/rollup-android-arm64@4.28.1':
281 | resolution: {integrity: sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==}
282 | cpu: [arm64]
283 | os: [android]
284 |
285 | '@rollup/rollup-darwin-arm64@4.28.1':
286 | resolution: {integrity: sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==}
287 | cpu: [arm64]
288 | os: [darwin]
289 |
290 | '@rollup/rollup-darwin-x64@4.28.1':
291 | resolution: {integrity: sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==}
292 | cpu: [x64]
293 | os: [darwin]
294 |
295 | '@rollup/rollup-freebsd-arm64@4.28.1':
296 | resolution: {integrity: sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==}
297 | cpu: [arm64]
298 | os: [freebsd]
299 |
300 | '@rollup/rollup-freebsd-x64@4.28.1':
301 | resolution: {integrity: sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==}
302 | cpu: [x64]
303 | os: [freebsd]
304 |
305 | '@rollup/rollup-linux-arm-gnueabihf@4.28.1':
306 | resolution: {integrity: sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==}
307 | cpu: [arm]
308 | os: [linux]
309 | libc: [glibc]
310 |
311 | '@rollup/rollup-linux-arm-musleabihf@4.28.1':
312 | resolution: {integrity: sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==}
313 | cpu: [arm]
314 | os: [linux]
315 | libc: [musl]
316 |
317 | '@rollup/rollup-linux-arm64-gnu@4.28.1':
318 | resolution: {integrity: sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==}
319 | cpu: [arm64]
320 | os: [linux]
321 | libc: [glibc]
322 |
323 | '@rollup/rollup-linux-arm64-musl@4.28.1':
324 | resolution: {integrity: sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==}
325 | cpu: [arm64]
326 | os: [linux]
327 | libc: [musl]
328 |
329 | '@rollup/rollup-linux-loongarch64-gnu@4.28.1':
330 | resolution: {integrity: sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==}
331 | cpu: [loong64]
332 | os: [linux]
333 | libc: [glibc]
334 |
335 | '@rollup/rollup-linux-powerpc64le-gnu@4.28.1':
336 | resolution: {integrity: sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==}
337 | cpu: [ppc64]
338 | os: [linux]
339 | libc: [glibc]
340 |
341 | '@rollup/rollup-linux-riscv64-gnu@4.28.1':
342 | resolution: {integrity: sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==}
343 | cpu: [riscv64]
344 | os: [linux]
345 | libc: [glibc]
346 |
347 | '@rollup/rollup-linux-s390x-gnu@4.28.1':
348 | resolution: {integrity: sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==}
349 | cpu: [s390x]
350 | os: [linux]
351 | libc: [glibc]
352 |
353 | '@rollup/rollup-linux-x64-gnu@4.28.1':
354 | resolution: {integrity: sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==}
355 | cpu: [x64]
356 | os: [linux]
357 | libc: [glibc]
358 |
359 | '@rollup/rollup-linux-x64-musl@4.28.1':
360 | resolution: {integrity: sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==}
361 | cpu: [x64]
362 | os: [linux]
363 | libc: [musl]
364 |
365 | '@rollup/rollup-win32-arm64-msvc@4.28.1':
366 | resolution: {integrity: sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==}
367 | cpu: [arm64]
368 | os: [win32]
369 |
370 | '@rollup/rollup-win32-ia32-msvc@4.28.1':
371 | resolution: {integrity: sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==}
372 | cpu: [ia32]
373 | os: [win32]
374 |
375 | '@rollup/rollup-win32-x64-msvc@4.28.1':
376 | resolution: {integrity: sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==}
377 | cpu: [x64]
378 | os: [win32]
379 |
380 | '@types/babel__core@7.20.5':
381 | resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
382 |
383 | '@types/babel__generator@7.6.8':
384 | resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==}
385 |
386 | '@types/babel__template@7.4.4':
387 | resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
388 |
389 | '@types/babel__traverse@7.20.6':
390 | resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==}
391 |
392 | '@types/estree@1.0.6':
393 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
394 |
395 | '@types/prop-types@15.7.14':
396 | resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==}
397 |
398 | '@types/react-dom@18.3.2':
399 | resolution: {integrity: sha512-Fqp+rcvem9wEnGr3RY8dYNvSQ8PoLqjZ9HLgaPUOjJJD120uDyOxOjc/39M4Kddp9JQCxpGQbnhVQF0C0ncYVg==}
400 |
401 | '@types/react@18.3.14':
402 | resolution: {integrity: sha512-NzahNKvjNhVjuPBQ+2G7WlxstQ+47kXZNHlUvFakDViuIEfGY926GqhMueQFZ7woG+sPiQKlF36XfrIUVSUfFg==}
403 |
404 | '@vitejs/plugin-react@4.3.4':
405 | resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==}
406 | engines: {node: ^14.18.0 || >=16.0.0}
407 | peerDependencies:
408 | vite: ^4.2.0 || ^5.0.0 || ^6.0.0
409 |
410 | browserslist@4.24.2:
411 | resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==}
412 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
413 | hasBin: true
414 |
415 | caniuse-lite@1.0.30001687:
416 | resolution: {integrity: sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==}
417 |
418 | convert-source-map@2.0.0:
419 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
420 |
421 | csstype@3.1.3:
422 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
423 |
424 | debug@4.4.0:
425 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
426 | engines: {node: '>=6.0'}
427 | peerDependencies:
428 | supports-color: '*'
429 | peerDependenciesMeta:
430 | supports-color:
431 | optional: true
432 |
433 | electron-to-chromium@1.5.71:
434 | resolution: {integrity: sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA==}
435 |
436 | esbuild@0.21.5:
437 | resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
438 | engines: {node: '>=12'}
439 | hasBin: true
440 |
441 | escalade@3.2.0:
442 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
443 | engines: {node: '>=6'}
444 |
445 | fsevents@2.3.3:
446 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
447 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
448 | os: [darwin]
449 |
450 | gensync@1.0.0-beta.2:
451 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
452 | engines: {node: '>=6.9.0'}
453 |
454 | globals@11.12.0:
455 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
456 | engines: {node: '>=4'}
457 |
458 | js-tokens@4.0.0:
459 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
460 |
461 | jsesc@3.0.2:
462 | resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==}
463 | engines: {node: '>=6'}
464 | hasBin: true
465 |
466 | json5@2.2.3:
467 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
468 | engines: {node: '>=6'}
469 | hasBin: true
470 |
471 | loose-envify@1.4.0:
472 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
473 | hasBin: true
474 |
475 | lru-cache@5.1.1:
476 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
477 |
478 | ms@2.1.3:
479 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
480 |
481 | nanoid@3.3.8:
482 | resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
483 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
484 | hasBin: true
485 |
486 | node-releases@2.0.18:
487 | resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==}
488 |
489 | picocolors@1.1.1:
490 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
491 |
492 | postcss@8.4.49:
493 | resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
494 | engines: {node: ^10 || ^12 || >=14}
495 |
496 | react-dom@18.3.1:
497 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
498 | peerDependencies:
499 | react: ^18.3.1
500 |
501 | react-refresh@0.14.2:
502 | resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
503 | engines: {node: '>=0.10.0'}
504 |
505 | react@18.3.1:
506 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
507 | engines: {node: '>=0.10.0'}
508 |
509 | rollup@4.28.1:
510 | resolution: {integrity: sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==}
511 | engines: {node: '>=18.0.0', npm: '>=8.0.0'}
512 | hasBin: true
513 |
514 | scheduler@0.23.2:
515 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
516 |
517 | semver@6.3.1:
518 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
519 | hasBin: true
520 |
521 | source-map-js@1.2.1:
522 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
523 | engines: {node: '>=0.10.0'}
524 |
525 | typescript@5.7.2:
526 | resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==}
527 | engines: {node: '>=14.17'}
528 | hasBin: true
529 |
530 | update-browserslist-db@1.1.1:
531 | resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==}
532 | hasBin: true
533 | peerDependencies:
534 | browserslist: '>= 4.21.0'
535 |
536 | vite@5.4.11:
537 | resolution: {integrity: sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==}
538 | engines: {node: ^18.0.0 || >=20.0.0}
539 | hasBin: true
540 | peerDependencies:
541 | '@types/node': ^18.0.0 || >=20.0.0
542 | less: '*'
543 | lightningcss: ^1.21.0
544 | sass: '*'
545 | sass-embedded: '*'
546 | stylus: '*'
547 | sugarss: '*'
548 | terser: ^5.4.0
549 | peerDependenciesMeta:
550 | '@types/node':
551 | optional: true
552 | less:
553 | optional: true
554 | lightningcss:
555 | optional: true
556 | sass:
557 | optional: true
558 | sass-embedded:
559 | optional: true
560 | stylus:
561 | optional: true
562 | sugarss:
563 | optional: true
564 | terser:
565 | optional: true
566 |
567 | yallist@3.1.1:
568 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
569 |
570 | snapshots:
571 |
572 | '@ampproject/remapping@2.3.0':
573 | dependencies:
574 | '@jridgewell/gen-mapping': 0.3.5
575 | '@jridgewell/trace-mapping': 0.3.25
576 |
577 | '@babel/code-frame@7.26.2':
578 | dependencies:
579 | '@babel/helper-validator-identifier': 7.25.9
580 | js-tokens: 4.0.0
581 | picocolors: 1.1.1
582 |
583 | '@babel/compat-data@7.26.3': {}
584 |
585 | '@babel/core@7.26.0':
586 | dependencies:
587 | '@ampproject/remapping': 2.3.0
588 | '@babel/code-frame': 7.26.2
589 | '@babel/generator': 7.26.3
590 | '@babel/helper-compilation-targets': 7.25.9
591 | '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0)
592 | '@babel/helpers': 7.26.0
593 | '@babel/parser': 7.26.3
594 | '@babel/template': 7.25.9
595 | '@babel/traverse': 7.26.4
596 | '@babel/types': 7.26.3
597 | convert-source-map: 2.0.0
598 | debug: 4.4.0
599 | gensync: 1.0.0-beta.2
600 | json5: 2.2.3
601 | semver: 6.3.1
602 | transitivePeerDependencies:
603 | - supports-color
604 |
605 | '@babel/generator@7.26.3':
606 | dependencies:
607 | '@babel/parser': 7.26.3
608 | '@babel/types': 7.26.3
609 | '@jridgewell/gen-mapping': 0.3.5
610 | '@jridgewell/trace-mapping': 0.3.25
611 | jsesc: 3.0.2
612 |
613 | '@babel/helper-compilation-targets@7.25.9':
614 | dependencies:
615 | '@babel/compat-data': 7.26.3
616 | '@babel/helper-validator-option': 7.25.9
617 | browserslist: 4.24.2
618 | lru-cache: 5.1.1
619 | semver: 6.3.1
620 |
621 | '@babel/helper-module-imports@7.25.9':
622 | dependencies:
623 | '@babel/traverse': 7.26.4
624 | '@babel/types': 7.26.3
625 | transitivePeerDependencies:
626 | - supports-color
627 |
628 | '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)':
629 | dependencies:
630 | '@babel/core': 7.26.0
631 | '@babel/helper-module-imports': 7.25.9
632 | '@babel/helper-validator-identifier': 7.25.9
633 | '@babel/traverse': 7.26.4
634 | transitivePeerDependencies:
635 | - supports-color
636 |
637 | '@babel/helper-plugin-utils@7.25.9': {}
638 |
639 | '@babel/helper-string-parser@7.25.9': {}
640 |
641 | '@babel/helper-validator-identifier@7.25.9': {}
642 |
643 | '@babel/helper-validator-option@7.25.9': {}
644 |
645 | '@babel/helpers@7.26.0':
646 | dependencies:
647 | '@babel/template': 7.25.9
648 | '@babel/types': 7.26.3
649 |
650 | '@babel/parser@7.26.3':
651 | dependencies:
652 | '@babel/types': 7.26.3
653 |
654 | '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)':
655 | dependencies:
656 | '@babel/core': 7.26.0
657 | '@babel/helper-plugin-utils': 7.25.9
658 |
659 | '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)':
660 | dependencies:
661 | '@babel/core': 7.26.0
662 | '@babel/helper-plugin-utils': 7.25.9
663 |
664 | '@babel/template@7.25.9':
665 | dependencies:
666 | '@babel/code-frame': 7.26.2
667 | '@babel/parser': 7.26.3
668 | '@babel/types': 7.26.3
669 |
670 | '@babel/traverse@7.26.4':
671 | dependencies:
672 | '@babel/code-frame': 7.26.2
673 | '@babel/generator': 7.26.3
674 | '@babel/parser': 7.26.3
675 | '@babel/template': 7.25.9
676 | '@babel/types': 7.26.3
677 | debug: 4.4.0
678 | globals: 11.12.0
679 | transitivePeerDependencies:
680 | - supports-color
681 |
682 | '@babel/types@7.26.3':
683 | dependencies:
684 | '@babel/helper-string-parser': 7.25.9
685 | '@babel/helper-validator-identifier': 7.25.9
686 |
687 | '@esbuild/aix-ppc64@0.21.5':
688 | optional: true
689 |
690 | '@esbuild/android-arm64@0.21.5':
691 | optional: true
692 |
693 | '@esbuild/android-arm@0.21.5':
694 | optional: true
695 |
696 | '@esbuild/android-x64@0.21.5':
697 | optional: true
698 |
699 | '@esbuild/darwin-arm64@0.21.5':
700 | optional: true
701 |
702 | '@esbuild/darwin-x64@0.21.5':
703 | optional: true
704 |
705 | '@esbuild/freebsd-arm64@0.21.5':
706 | optional: true
707 |
708 | '@esbuild/freebsd-x64@0.21.5':
709 | optional: true
710 |
711 | '@esbuild/linux-arm64@0.21.5':
712 | optional: true
713 |
714 | '@esbuild/linux-arm@0.21.5':
715 | optional: true
716 |
717 | '@esbuild/linux-ia32@0.21.5':
718 | optional: true
719 |
720 | '@esbuild/linux-loong64@0.21.5':
721 | optional: true
722 |
723 | '@esbuild/linux-mips64el@0.21.5':
724 | optional: true
725 |
726 | '@esbuild/linux-ppc64@0.21.5':
727 | optional: true
728 |
729 | '@esbuild/linux-riscv64@0.21.5':
730 | optional: true
731 |
732 | '@esbuild/linux-s390x@0.21.5':
733 | optional: true
734 |
735 | '@esbuild/linux-x64@0.21.5':
736 | optional: true
737 |
738 | '@esbuild/netbsd-x64@0.21.5':
739 | optional: true
740 |
741 | '@esbuild/openbsd-x64@0.21.5':
742 | optional: true
743 |
744 | '@esbuild/sunos-x64@0.21.5':
745 | optional: true
746 |
747 | '@esbuild/win32-arm64@0.21.5':
748 | optional: true
749 |
750 | '@esbuild/win32-ia32@0.21.5':
751 | optional: true
752 |
753 | '@esbuild/win32-x64@0.21.5':
754 | optional: true
755 |
756 | '@jridgewell/gen-mapping@0.3.5':
757 | dependencies:
758 | '@jridgewell/set-array': 1.2.1
759 | '@jridgewell/sourcemap-codec': 1.5.0
760 | '@jridgewell/trace-mapping': 0.3.25
761 |
762 | '@jridgewell/resolve-uri@3.1.2': {}
763 |
764 | '@jridgewell/set-array@1.2.1': {}
765 |
766 | '@jridgewell/sourcemap-codec@1.5.0': {}
767 |
768 | '@jridgewell/trace-mapping@0.3.25':
769 | dependencies:
770 | '@jridgewell/resolve-uri': 3.1.2
771 | '@jridgewell/sourcemap-codec': 1.5.0
772 |
773 | '@rollup/rollup-android-arm-eabi@4.28.1':
774 | optional: true
775 |
776 | '@rollup/rollup-android-arm64@4.28.1':
777 | optional: true
778 |
779 | '@rollup/rollup-darwin-arm64@4.28.1':
780 | optional: true
781 |
782 | '@rollup/rollup-darwin-x64@4.28.1':
783 | optional: true
784 |
785 | '@rollup/rollup-freebsd-arm64@4.28.1':
786 | optional: true
787 |
788 | '@rollup/rollup-freebsd-x64@4.28.1':
789 | optional: true
790 |
791 | '@rollup/rollup-linux-arm-gnueabihf@4.28.1':
792 | optional: true
793 |
794 | '@rollup/rollup-linux-arm-musleabihf@4.28.1':
795 | optional: true
796 |
797 | '@rollup/rollup-linux-arm64-gnu@4.28.1':
798 | optional: true
799 |
800 | '@rollup/rollup-linux-arm64-musl@4.28.1':
801 | optional: true
802 |
803 | '@rollup/rollup-linux-loongarch64-gnu@4.28.1':
804 | optional: true
805 |
806 | '@rollup/rollup-linux-powerpc64le-gnu@4.28.1':
807 | optional: true
808 |
809 | '@rollup/rollup-linux-riscv64-gnu@4.28.1':
810 | optional: true
811 |
812 | '@rollup/rollup-linux-s390x-gnu@4.28.1':
813 | optional: true
814 |
815 | '@rollup/rollup-linux-x64-gnu@4.28.1':
816 | optional: true
817 |
818 | '@rollup/rollup-linux-x64-musl@4.28.1':
819 | optional: true
820 |
821 | '@rollup/rollup-win32-arm64-msvc@4.28.1':
822 | optional: true
823 |
824 | '@rollup/rollup-win32-ia32-msvc@4.28.1':
825 | optional: true
826 |
827 | '@rollup/rollup-win32-x64-msvc@4.28.1':
828 | optional: true
829 |
830 | '@types/babel__core@7.20.5':
831 | dependencies:
832 | '@babel/parser': 7.26.3
833 | '@babel/types': 7.26.3
834 | '@types/babel__generator': 7.6.8
835 | '@types/babel__template': 7.4.4
836 | '@types/babel__traverse': 7.20.6
837 |
838 | '@types/babel__generator@7.6.8':
839 | dependencies:
840 | '@babel/types': 7.26.3
841 |
842 | '@types/babel__template@7.4.4':
843 | dependencies:
844 | '@babel/parser': 7.26.3
845 | '@babel/types': 7.26.3
846 |
847 | '@types/babel__traverse@7.20.6':
848 | dependencies:
849 | '@babel/types': 7.26.3
850 |
851 | '@types/estree@1.0.6': {}
852 |
853 | '@types/prop-types@15.7.14': {}
854 |
855 | '@types/react-dom@18.3.2':
856 | dependencies:
857 | '@types/react': 18.3.14
858 |
859 | '@types/react@18.3.14':
860 | dependencies:
861 | '@types/prop-types': 15.7.14
862 | csstype: 3.1.3
863 |
864 | '@vitejs/plugin-react@4.3.4(vite@5.4.11)':
865 | dependencies:
866 | '@babel/core': 7.26.0
867 | '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0)
868 | '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0)
869 | '@types/babel__core': 7.20.5
870 | react-refresh: 0.14.2
871 | vite: 5.4.11
872 | transitivePeerDependencies:
873 | - supports-color
874 |
875 | browserslist@4.24.2:
876 | dependencies:
877 | caniuse-lite: 1.0.30001687
878 | electron-to-chromium: 1.5.71
879 | node-releases: 2.0.18
880 | update-browserslist-db: 1.1.1(browserslist@4.24.2)
881 |
882 | caniuse-lite@1.0.30001687: {}
883 |
884 | convert-source-map@2.0.0: {}
885 |
886 | csstype@3.1.3: {}
887 |
888 | debug@4.4.0:
889 | dependencies:
890 | ms: 2.1.3
891 |
892 | electron-to-chromium@1.5.71: {}
893 |
894 | esbuild@0.21.5:
895 | optionalDependencies:
896 | '@esbuild/aix-ppc64': 0.21.5
897 | '@esbuild/android-arm': 0.21.5
898 | '@esbuild/android-arm64': 0.21.5
899 | '@esbuild/android-x64': 0.21.5
900 | '@esbuild/darwin-arm64': 0.21.5
901 | '@esbuild/darwin-x64': 0.21.5
902 | '@esbuild/freebsd-arm64': 0.21.5
903 | '@esbuild/freebsd-x64': 0.21.5
904 | '@esbuild/linux-arm': 0.21.5
905 | '@esbuild/linux-arm64': 0.21.5
906 | '@esbuild/linux-ia32': 0.21.5
907 | '@esbuild/linux-loong64': 0.21.5
908 | '@esbuild/linux-mips64el': 0.21.5
909 | '@esbuild/linux-ppc64': 0.21.5
910 | '@esbuild/linux-riscv64': 0.21.5
911 | '@esbuild/linux-s390x': 0.21.5
912 | '@esbuild/linux-x64': 0.21.5
913 | '@esbuild/netbsd-x64': 0.21.5
914 | '@esbuild/openbsd-x64': 0.21.5
915 | '@esbuild/sunos-x64': 0.21.5
916 | '@esbuild/win32-arm64': 0.21.5
917 | '@esbuild/win32-ia32': 0.21.5
918 | '@esbuild/win32-x64': 0.21.5
919 |
920 | escalade@3.2.0: {}
921 |
922 | fsevents@2.3.3:
923 | optional: true
924 |
925 | gensync@1.0.0-beta.2: {}
926 |
927 | globals@11.12.0: {}
928 |
929 | js-tokens@4.0.0: {}
930 |
931 | jsesc@3.0.2: {}
932 |
933 | json5@2.2.3: {}
934 |
935 | loose-envify@1.4.0:
936 | dependencies:
937 | js-tokens: 4.0.0
938 |
939 | lru-cache@5.1.1:
940 | dependencies:
941 | yallist: 3.1.1
942 |
943 | ms@2.1.3: {}
944 |
945 | nanoid@3.3.8: {}
946 |
947 | node-releases@2.0.18: {}
948 |
949 | picocolors@1.1.1: {}
950 |
951 | postcss@8.4.49:
952 | dependencies:
953 | nanoid: 3.3.8
954 | picocolors: 1.1.1
955 | source-map-js: 1.2.1
956 |
957 | react-dom@18.3.1(react@18.3.1):
958 | dependencies:
959 | loose-envify: 1.4.0
960 | react: 18.3.1
961 | scheduler: 0.23.2
962 |
963 | react-refresh@0.14.2: {}
964 |
965 | react@18.3.1:
966 | dependencies:
967 | loose-envify: 1.4.0
968 |
969 | rollup@4.28.1:
970 | dependencies:
971 | '@types/estree': 1.0.6
972 | optionalDependencies:
973 | '@rollup/rollup-android-arm-eabi': 4.28.1
974 | '@rollup/rollup-android-arm64': 4.28.1
975 | '@rollup/rollup-darwin-arm64': 4.28.1
976 | '@rollup/rollup-darwin-x64': 4.28.1
977 | '@rollup/rollup-freebsd-arm64': 4.28.1
978 | '@rollup/rollup-freebsd-x64': 4.28.1
979 | '@rollup/rollup-linux-arm-gnueabihf': 4.28.1
980 | '@rollup/rollup-linux-arm-musleabihf': 4.28.1
981 | '@rollup/rollup-linux-arm64-gnu': 4.28.1
982 | '@rollup/rollup-linux-arm64-musl': 4.28.1
983 | '@rollup/rollup-linux-loongarch64-gnu': 4.28.1
984 | '@rollup/rollup-linux-powerpc64le-gnu': 4.28.1
985 | '@rollup/rollup-linux-riscv64-gnu': 4.28.1
986 | '@rollup/rollup-linux-s390x-gnu': 4.28.1
987 | '@rollup/rollup-linux-x64-gnu': 4.28.1
988 | '@rollup/rollup-linux-x64-musl': 4.28.1
989 | '@rollup/rollup-win32-arm64-msvc': 4.28.1
990 | '@rollup/rollup-win32-ia32-msvc': 4.28.1
991 | '@rollup/rollup-win32-x64-msvc': 4.28.1
992 | fsevents: 2.3.3
993 |
994 | scheduler@0.23.2:
995 | dependencies:
996 | loose-envify: 1.4.0
997 |
998 | semver@6.3.1: {}
999 |
1000 | source-map-js@1.2.1: {}
1001 |
1002 | typescript@5.7.2: {}
1003 |
1004 | update-browserslist-db@1.1.1(browserslist@4.24.2):
1005 | dependencies:
1006 | browserslist: 4.24.2
1007 | escalade: 3.2.0
1008 | picocolors: 1.1.1
1009 |
1010 | vite@5.4.11:
1011 | dependencies:
1012 | esbuild: 0.21.5
1013 | postcss: 8.4.49
1014 | rollup: 4.28.1
1015 | optionalDependencies:
1016 | fsevents: 2.3.3
1017 |
1018 | yallist@3.1.1: {}
1019 |
--------------------------------------------------------------------------------