reborn-ui 0.1.78 → 0.1.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/index.js +2 -2
  2. package/dist/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/registry/components/icon-cloud.json +17 -0
  5. package/registry/components/liquid-glass.json +21 -0
  6. package/registry/components/pattern-background.json +19 -0
  7. package/registry/components/reborn-back-top.json +2 -2
  8. package/registry/components/reborn-badge.json +7 -13
  9. package/registry/components/reborn-button.json +5 -5
  10. package/registry/components/reborn-cascader.json +3 -3
  11. package/registry/components/reborn-dropdown-select.json +3 -3
  12. package/registry/components/reborn-fab.json +28 -0
  13. package/registry/components/reborn-form.json +2 -2
  14. package/registry/components/reborn-image.json +2 -2
  15. package/registry/components/reborn-input-number.json +5 -5
  16. package/registry/components/reborn-input.json +5 -5
  17. package/registry/components/reborn-loading.json +14 -4
  18. package/registry/components/reborn-page.json +2 -2
  19. package/registry/components/reborn-pagination.json +32 -0
  20. package/registry/components/reborn-popup.json +3 -3
  21. package/registry/components/reborn-radio.json +9 -4
  22. package/registry/components/reborn-search-box.json +28 -0
  23. package/registry/components/reborn-select-trigger.json +2 -2
  24. package/registry/components/reborn-select.json +4 -4
  25. package/registry/components/reborn-sku.json +17 -0
  26. package/registry/components/reborn-switch.json +2 -2
  27. package/registry/components/reborn-tabbar.json +3 -3
  28. package/registry/components/reborn-tabs.json +4 -4
  29. package/registry/components/reborn-text.json +2 -2
  30. package/registry/components/reborn-toast.json +2 -2
  31. package/registry/components/reborn-transition.json +4 -4
  32. package/registry/registry.json +210 -53
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/add.ts","../src/utils/fs.ts","../src/utils/pm.ts","../src/utils/dependencies.ts","../src/utils/registry.ts","../src/utils/ui.ts","../src/commands/build.ts","../src/utils/imports.ts","../src/utils/transformers.ts","../src/commands/init.ts","../src/utils/templates.ts","../src/generated/templates.ts","../package.json"],"sourcesContent":["import { Command } from \"commander\";\r\nimport { addCommand } from \"./commands/add.js\";\r\nimport { buildCommand } from \"./commands/build.js\";\r\nimport { initCommand } from \"./commands/init.js\";\r\nimport packageJson from \"../package.json\" assert { type: \"json\" };\r\n\r\nconst program = new Command()\r\n .name(\"reborn-ui\")\r\n .description(\"Reborn UI - 组件安装与 registry 辅助 CLI\")\r\n .version(packageJson.version);\r\n\r\nprogram.addCommand(initCommand());\r\nprogram.addCommand(addCommand());\r\nprogram.addCommand(buildCommand());\r\n\r\nawait program.parseAsync(process.argv);\r\n\r\n\r\n","import path from \"node:path\";\r\nimport { Command } from \"commander\";\r\nimport prompts from \"prompts\";\r\nimport type { PackageManager, RegistryComponent } from \"../types.js\";\r\nimport { ensureDir, pathExists, writeTextFile } from \"../utils/fs.js\";\r\nimport {\r\n detectPackageManager,\r\n readPackageJson,\r\n getMissingDeps,\r\n installDeps,\r\n} from \"../utils/pm.js\";\r\nimport { getDependencies } from \"../utils/dependencies.js\";\r\nimport { defaultConfig, loadConfigCompat, loadRegistry } from \"../utils/registry.js\";\r\nimport cliProgress from \"cli-progress\";\r\nimport chalk from \"chalk\";\r\nimport { successLog } from \"../utils/ui.js\";\r\n\r\nfunction rewriteImports(params: {\r\n content: string;\r\n aliasSymbol: string;\r\n}) {\r\n const { content, aliasSymbol } = params;\r\n if (!aliasSymbol || aliasSymbol === \"@\") return content;\r\n\r\n // 仅替换项目根目录映射符号:把 \"@/xxx\" -> \"<aliasSymbol>/xxx\"\r\n // 注意:不要影响 scoped package(@scope/name),这里只替换 \"@/\" 前缀。\r\n return content.replaceAll(\"@/\", `${aliasSymbol}/`);\r\n}\r\n\r\nasync function writeComponentFiles(params: {\r\n cwd: string;\r\n componentsDir: string;\r\n aliasSymbol: string;\r\n component: RegistryComponent;\r\n overwrite?: boolean;\r\n onProgress?: () => void;\r\n platform: \"web\" | \"uniapp\";\r\n}) {\r\n const { cwd, componentsDir, aliasSymbol, component, overwrite, onProgress, platform } = params;\r\n const baseDir = path.join(cwd, componentsDir, component.name);\r\n await ensureDir(baseDir);\r\n\r\n for (const f of component.files) {\r\n // 过滤逻辑:\r\n // 1. 如果 f.target 存在且不等于 platform,跳过\r\n // 2. 如果 f.target 不存在,视为通用文件,不跳过\r\n if (f.target && f.target !== platform) {\r\n continue;\r\n }\r\n\r\n const target = path.join(baseDir, ...f.path.split(\"/\"));\r\n if (!overwrite && (await pathExists(target))) {\r\n onProgress?.();\r\n continue;\r\n }\r\n const nextContent = rewriteImports({ content: f.content, aliasSymbol });\r\n await writeTextFile(target, nextContent);\r\n onProgress?.();\r\n // 增加一个极小的延迟,让进度条看起来在“跑”\r\n await new Promise(r => setTimeout(r, 10));\r\n }\r\n\r\n return baseDir;\r\n}\r\n\r\nexport function addCommand() {\r\n const cmd = new Command(\"add\")\r\n .description(\"向项目中添加组件与相关依赖\")\r\n .argument(\"[components...]\", \"组件名(可多个)\")\r\n .option(\"--cwd <path>\", \"目标项目目录\", process.cwd())\r\n .option(\"--pm <pm>\", \"包管理器:pnpm|npm|yarn|bun\")\r\n .option(\"--yes\", \"跳过交互\", false)\r\n .option(\"--overwrite\", \"覆盖已存在文件\", false)\r\n .option(\"--config <path>\", \"配置文件路径(相对 cwd)\", \"components.json\")\r\n .option(\"--registry <pkgOrPath>\", \"覆盖配置里的 registry\")\r\n .option(\"--components-dir <path>\", \"覆盖配置里的 componentsDir\")\r\n .option(\"--lib-dir <path>\", \"覆盖配置里的 libDir\")\r\n .option(\"--alias-symbol <symbol>\", \"覆盖配置里的 aliasSymbol(默认 @)\")\r\n .action(async (components: string[], opts) => {\r\n const cwd = path.resolve(opts.cwd);\r\n const pm: PackageManager =\r\n opts.pm ?? (await detectPackageManager(cwd));\r\n\r\n const cfg = (await loadConfigCompat(cwd, opts.config)) ?? defaultConfig();\r\n if (opts.registry) cfg.registry = opts.registry;\r\n if (opts.componentsDir) cfg.componentsDir = opts.componentsDir;\r\n if (opts.libDir) cfg.libDir = opts.libDir;\r\n if (opts.aliasSymbol) cfg.aliasSymbol = opts.aliasSymbol;\r\n\r\n const registry = await loadRegistry({ cwd, registry: cfg.registry });\r\n\r\n let targets = components ?? [];\r\n if (!targets.length) {\r\n if (opts.yes) {\r\n throw new Error(\"未指定组件名;请传入组件参数或去掉 --yes 以交互选择。\");\r\n }\r\n const choices = registry.components?.map((c) => ({\r\n title: c.name,\r\n value: c.name,\r\n }));\r\n const res = await prompts(\r\n [\r\n {\r\n type: \"multiselect\",\r\n name: \"selected\",\r\n message: \"选择要添加的组件\",\r\n choices,\r\n min: 1,\r\n },\r\n ],\r\n {\r\n onCancel: () => {\r\n throw new Error(\"已取消\");\r\n },\r\n },\r\n );\r\n targets = res.selected ?? [];\r\n }\r\n\r\n // 询问平台 (Web / UniApp)\r\n const { platform } = await prompts({\r\n type: \"select\",\r\n name: \"platform\",\r\n message: \"选择目标平台\",\r\n choices: [\r\n { title: \"Web (默认)\", value: \"web\" },\r\n { title: \"UniApp\", value: \"uniapp\" },\r\n ],\r\n initial: 0,\r\n });\r\n\r\n if (!platform) {\r\n throw new Error(\"已取消\");\r\n }\r\n\r\n const allComponentsToInstall = new Set<string>(targets);\r\n const allNpmDependencies = new Set<string>();\r\n\r\n for (const target of targets) {\r\n const deps = getDependencies(target, platform as \"web\" | \"uniapp\");\r\n if (deps.components) {\r\n for (const c of deps.components) allComponentsToInstall.add(c);\r\n }\r\n if (deps.npmDependencies) {\r\n for (const d of deps.npmDependencies) allNpmDependencies.add(d);\r\n }\r\n }\r\n\r\n const additionalComponents = Array.from(allComponentsToInstall).filter(c => !targets.includes(c));\r\n const npmDependenciesArray = Array.from(allNpmDependencies);\r\n\r\n // Prompt for NPM dependencies\r\n if (npmDependenciesArray.length > 0) {\r\n const pkg = await readPackageJson(cwd);\r\n const missingDeps = getMissingDeps(pkg, npmDependenciesArray);\r\n if (missingDeps.length > 0) {\r\n console.log(chalk.blue(`\\n检测到当前组件需要以下未安装的 npm 依赖:${missingDeps.join(\", \")}`));\r\n const { installNpm } = await prompts({\r\n type: \"confirm\",\r\n name: \"installNpm\",\r\n message: `是否需要为这些组件安装以上 npm 依赖?`,\r\n initial: true,\r\n });\r\n\r\n if (installNpm) {\r\n console.log(chalk.cyan(\"正在安装 npm 依赖...\"));\r\n await installDeps({ cwd, pm, deps: missingDeps });\r\n successLog(`npm 依赖安装完成`);\r\n }\r\n }\r\n }\r\n\r\n let finalTargets = [...targets];\r\n if (additionalComponents.length > 0) {\r\n const missingComponents = [];\r\n for (const c of additionalComponents) {\r\n const baseDir = path.join(cwd, cfg.componentsDir, c);\r\n if (!(await pathExists(baseDir))) {\r\n missingComponents.push(c);\r\n }\r\n }\r\n\r\n if (missingComponents.length > 0) {\r\n console.log(chalk.blue(`\\n检测到需要前置或关联组件:${missingComponents.join(\", \")}`));\r\n const { installComponents } = await prompts({\r\n type: \"confirm\",\r\n name: \"installComponents\",\r\n message: `是否自动安装缺失的前置组件?`,\r\n initial: true,\r\n });\r\n if (installComponents) {\r\n finalTargets = [...finalTargets, ...missingComponents];\r\n }\r\n }\r\n }\r\n\r\n if (!opts.overwrite) {\r\n const existingComponents = [];\r\n for (const name of finalTargets) {\r\n const baseDir = path.join(cwd, cfg.componentsDir, name);\r\n if (await pathExists(baseDir)) {\r\n existingComponents.push(name);\r\n }\r\n }\r\n\r\n if (existingComponents.length > 0) {\r\n console.log(chalk.yellow(`\\n遇到已存在的组件:${existingComponents.join(\", \")}`));\r\n const { overwrite } = await prompts({\r\n type: \"confirm\",\r\n name: \"overwrite\",\r\n message: `是否覆盖并继续安装?`,\r\n initial: false,\r\n });\r\n\r\n if (!overwrite) {\r\n console.log(chalk.red(\"已终止安装\"));\r\n return;\r\n }\r\n opts.overwrite = true;\r\n }\r\n }\r\n\r\n const totalFiles = finalTargets.reduce((acc, name) => {\r\n const c = registry.components.find((x) => x.name === name);\r\n return acc + (c?.files.length ?? 0);\r\n }, 0);\r\n\r\n const bar = new cliProgress.SingleBar({\r\n format: '正在写入文件 |' + chalk.cyan('{bar}') + '| {percentage}% || {value}/{total} 文件',\r\n barCompleteChar: '\\u2588',\r\n barIncompleteChar: '\\u2591',\r\n hideCursor: true\r\n });\r\n\r\n bar.start(totalFiles, 0);\r\n\r\n for (const name of finalTargets) {\r\n const c = registry.components.find((x) => x.name === name);\r\n if (!c) {\r\n bar.stop();\r\n throw new Error(`registry 中不存在该组件:${name}`);\r\n }\r\n\r\n await writeComponentFiles({\r\n cwd,\r\n componentsDir: cfg.componentsDir,\r\n aliasSymbol: cfg.aliasSymbol ?? \"@\",\r\n component: c,\r\n overwrite: opts.overwrite,\r\n onProgress: () => bar.increment(),\r\n platform,\r\n });\r\n }\r\n bar.stop();\r\n\r\n console.log(\"\");\r\n for (const name of finalTargets) {\r\n successLog(`组件 ${chalk.bold(name)} 已成功添加到项目`);\r\n }\r\n\r\n // eslint-disable-next-line no-console\r\n console.log(`\\n${chalk.bold.green('DONE')} 已完成 ${finalTargets.length} 个组件的添加(pm=${pm})`);\r\n });\r\n\r\n return cmd;\r\n}\r\n\r\n\r\n","import { createHash } from \"node:crypto\";\r\nimport fs from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\n\r\nexport async function pathExists(p: string) {\r\n try {\r\n await fs.access(p);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport async function ensureDir(dirPath: string) {\r\n await fs.mkdir(dirPath, { recursive: true });\r\n}\r\n\r\nexport async function readJsonFile<T>(filePath: string): Promise<T> {\r\n const raw = await fs.readFile(filePath, \"utf8\");\r\n return JSON.parse(raw) as T;\r\n}\r\n\r\nexport async function writeJsonFile(filePath: string, data: unknown) {\r\n await ensureDir(path.dirname(filePath));\r\n await fs.writeFile(filePath, JSON.stringify(data, null, 2) + \"\\n\", \"utf8\");\r\n}\r\n\r\nexport async function writeTextFile(filePath: string, content: string) {\r\n await ensureDir(path.dirname(filePath));\r\n await fs.writeFile(filePath, content, \"utf8\");\r\n}\r\n\r\nexport async function listFilesRecursive(\r\n dirPath: string,\r\n opts?: { ignoreDirNames?: Set<string> },\r\n) {\r\n const ignoreDirNames =\r\n opts?.ignoreDirNames ??\r\n new Set([\"node_modules\", \".git\", \".nuxt\", \"dist\", \".output\"]);\r\n\r\n const out: string[] = [];\r\n\r\n async function walk(current: string) {\r\n const entries = await fs.readdir(current, { withFileTypes: true });\r\n for (const entry of entries) {\r\n const p = path.join(current, entry.name);\r\n if (entry.isDirectory()) {\r\n if (ignoreDirNames.has(entry.name)) continue;\r\n await walk(p);\r\n } else if (entry.isFile()) {\r\n out.push(p);\r\n }\r\n }\r\n }\r\n\r\n await walk(dirPath);\r\n return out;\r\n}\r\n\r\nexport async function copyDirRecursive(params: {\r\n fromDir: string;\r\n toDir: string;\r\n overwrite?: boolean;\r\n ignoreFileNames?: Set<string>;\r\n}) {\r\n const { fromDir, toDir, overwrite } = params;\r\n const ignoreFileNames = params.ignoreFileNames ?? new Set([\".DS_Store\"]);\r\n\r\n const entries = await fs.readdir(fromDir, { withFileTypes: true });\r\n await ensureDir(toDir);\r\n\r\n for (const entry of entries) {\r\n if (ignoreFileNames.has(entry.name)) continue;\r\n const from = path.join(fromDir, entry.name);\r\n const to = path.join(toDir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n await copyDirRecursive({ fromDir: from, toDir: to, overwrite, ignoreFileNames });\r\n continue;\r\n }\r\n\r\n if (!entry.isFile()) continue;\r\n\r\n if (!overwrite) {\r\n try {\r\n await fs.access(to);\r\n continue; // 已存在则跳过\r\n } catch {\r\n // not exists\r\n }\r\n }\r\n\r\n await ensureDir(path.dirname(to));\r\n await fs.copyFile(from, to);\r\n }\r\n}\r\n\r\nexport function sha1(text: string) {\r\n return createHash(\"sha1\").update(text).digest(\"hex\");\r\n}\r\n\r\n\r\n","import fs from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { execa } from \"execa\";\r\nimport type { PackageManager } from \"../types.js\";\r\nimport { pathExists, readJsonFile, writeJsonFile } from \"./fs.js\";\r\n\r\nexport async function detectPackageManager(cwd: string): Promise<PackageManager> {\r\n if (await pathExists(path.join(cwd, \"pnpm-lock.yaml\"))) return \"pnpm\";\r\n if (await pathExists(path.join(cwd, \"yarn.lock\"))) return \"yarn\";\r\n if (await pathExists(path.join(cwd, \"package-lock.json\"))) return \"npm\";\r\n if (await pathExists(path.join(cwd, \"bun.lockb\"))) return \"bun\";\r\n return \"pnpm\";\r\n}\r\n\r\nexport async function readPackageJson(\r\n cwd: string,\r\n): Promise<Record<string, any> & { dependencies?: Record<string, string>; devDependencies?: Record<string, string> }> {\r\n return await readJsonFile(path.join(cwd, \"package.json\"));\r\n}\r\n\r\nexport async function writePackageJson(cwd: string, pkg: unknown) {\r\n await writeJsonFile(path.join(cwd, \"package.json\"), pkg);\r\n}\r\n\r\nexport function getMissingDeps(\r\n pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> },\r\n deps: string[],\r\n) {\r\n const existing = new Set([\r\n ...Object.keys(pkg.dependencies ?? {}),\r\n ...Object.keys(pkg.devDependencies ?? {}),\r\n ]);\r\n return deps.filter((d) => !existing.has(d));\r\n}\r\n\r\nexport async function installDeps(params: {\r\n cwd: string;\r\n pm: PackageManager;\r\n deps: string[];\r\n dev?: boolean;\r\n}) {\r\n const { cwd, pm, deps, dev } = params;\r\n if (!deps.length) return;\r\n\r\n const args: string[] = [];\r\n if (pm === \"pnpm\") args.push(\"add\");\r\n else if (pm === \"npm\") args.push(\"install\");\r\n else if (pm === \"yarn\") args.push(\"add\");\r\n else if (pm === \"bun\") args.push(\"add\");\r\n\r\n if (dev) {\r\n if (pm === \"npm\") args.push(\"--save-dev\");\r\n else args.push(\"-D\");\r\n }\r\n\r\n args.push(...deps);\r\n\r\n await execa(pm, args, { cwd, stdio: \"inherit\" });\r\n}\r\n\r\nexport async function ensureJsonFile(cwd: string, relPath: string, defaultJson: unknown) {\r\n const p = path.join(cwd, relPath);\r\n if (await pathExists(p)) return;\r\n await fs.mkdir(path.dirname(p), { recursive: true });\r\n await fs.writeFile(p, JSON.stringify(defaultJson, null, 2) + \"\\n\", \"utf8\");\r\n}\r\n\r\n\r\n","export interface DependencyInfo {\r\n components?: string[];\r\n npmDependencies?: string[];\r\n}\r\n\r\nexport const DEPENDENCY_MAP: Record<string, DependencyInfo> = {\r\n // UniApp 版本的 Reborn Select 需要特定的前置组件和 lodash-es\r\n \"reborn-select/uniapp\": {\r\n components: [\"reborn-button\", \"reborn-picker-view\", \"reborn-popup\", \"reborn-select-trigger\"],\r\n npmDependencies: [\"lodash-es\", \"@types/lodash-es\"],\r\n },\r\n \"reborn-select-date/uniapp\": {\r\n components: [\"reborn-button\", \"reborn-picker-view\", \"reborn-popup\", \"reborn-select-trigger\"],\r\n npmDependencies: [\"lodash-es\", \"@types/lodash-es\"],\r\n },\r\n // 在此处添加其他已知的依赖映射\r\n};\r\n\r\n/**\r\n * 递归解析组件和 npm 依赖\r\n * @param componentName 例如 \"reborn-select/web\" 或 \"reborn-select/uniapp\"\r\n * @param platform 例如 \"web\" | \"uniapp\"\r\n */\r\nexport function getDependencies(componentName: string, platform?: \"web\" | \"uniapp\"): DependencyInfo {\r\n const result: DependencyInfo = { components: [], npmDependencies: [] };\r\n const visited = new Set<string>();\r\n\r\n function resolve(name: string) {\r\n const keyWithPlatform = platform ? `${name}/${platform}` : name;\r\n\r\n // 首先检查是否存在特定平台的映射\r\n const deps = DEPENDENCY_MAP[keyWithPlatform] || DEPENDENCY_MAP[name];\r\n if (!deps) return;\r\n\r\n if (deps.components) {\r\n for (const comp of deps.components) {\r\n if (!visited.has(comp)) {\r\n visited.add(comp);\r\n result.components!.push(comp);\r\n resolve(comp); // 递归解析依赖\r\n }\r\n }\r\n }\r\n\r\n if (deps.npmDependencies) {\r\n for (const npmDep of deps.npmDependencies) {\r\n if (!result.npmDependencies!.includes(npmDep)) {\r\n result.npmDependencies!.push(npmDep);\r\n }\r\n }\r\n }\r\n }\r\n\r\n resolve(componentName);\r\n\r\n return result;\r\n}\r\n","import path from \"node:path\";\r\nimport fs from \"node:fs\";\r\nimport { createRequire } from \"node:module\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport type { CliConfig, RegistryFile } from \"../types.js\";\r\nimport { pathExists, readJsonFile } from \"./fs.js\";\r\n\r\nexport const DEFAULT_CONFIG_PATH = \"components.json\";\r\n\r\nfunction findNearestPackageRoot(from: string) {\r\n // from: import.meta.url\r\n let dir = path.dirname(fileURLToPath(from));\r\n while (true) {\r\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\r\n const parent = path.dirname(dir);\r\n if (parent === dir) return dir;\r\n dir = parent;\r\n }\r\n}\r\n\r\nexport function defaultConfig(): CliConfig {\r\n return {\r\n schemaVersion: 1,\r\n componentsDir: \"components\",\r\n libDir: \"lib\",\r\n composablesDir: \"composables\",\r\n // 默认使用 CLI 包内置的 registry(随 reborn-ui 一起发布)\r\n registry: \"builtin\",\r\n // 项目根目录映射别名符号(默认 @)\r\n aliasSymbol: \"@\",\r\n };\r\n}\r\n\r\nexport async function loadConfig(cwd: string, configPath = DEFAULT_CONFIG_PATH) {\r\n const abs = path.isAbsolute(configPath)\r\n ? configPath\r\n : path.join(cwd, configPath);\r\n if (!(await pathExists(abs))) return null;\r\n return await readJsonFile<CliConfig>(abs);\r\n}\r\n\r\nexport function resolveRegistryJsonPath(params: { cwd: string; registry: string }) {\r\n const { cwd, registry } = params;\r\n\r\n // 0) 内置 registry\r\n if (!registry || registry === \"builtin\") {\r\n // 注意:CLI 经过打包后可能变成单文件(例如 dist/index.js),\r\n // import.meta.url 的相对基准会变化,不能用固定的 ../../registry/...\r\n // 这里通过向上查找最近的 package.json 来定位包根目录。\r\n const pkgRoot = findNearestPackageRoot(import.meta.url);\r\n return path.join(pkgRoot, \"registry\", \"registry.json\");\r\n }\r\n\r\n // 1) 如果是文件路径(包含分隔符或 .json),优先当成路径处理\r\n const looksLikePath =\r\n registry.includes(\"/\") ||\r\n registry.includes(\"\\\\\") ||\r\n registry.endsWith(\".json\");\r\n\r\n if (looksLikePath) {\r\n const abs = path.isAbsolute(registry) ? registry : path.join(cwd, registry);\r\n return abs;\r\n }\r\n\r\n // 2) 当成包名处理:默认读取 <pkg>/registry/registry.json\r\n const require = createRequire(import.meta.url);\r\n // 不显式绑定 cwd,避免 npx 场景下找不到 registry 包\r\n return require.resolve(`${registry}/registry/registry.json`);\r\n}\r\n\r\nexport async function loadRegistry(params: { cwd: string; registry: string }) {\r\n const jsonPath = resolveRegistryJsonPath(params);\r\n return await readJsonFile<RegistryFile>(jsonPath);\r\n}\r\n\r\n// 兼容旧配置文件名:shadcn-docs.json\r\nexport async function loadConfigCompat(cwd: string, configPath?: string) {\r\n if (configPath) return await loadConfig(cwd, configPath);\r\n const primary = await loadConfig(cwd, DEFAULT_CONFIG_PATH);\r\n if (primary) return primary;\r\n return await loadConfig(cwd, \"shadcn-docs.json\");\r\n}\r\n\r\n\r\n","import chalk from 'chalk';\r\nimport figlet from 'figlet';\r\n\r\n/**\r\n * 模拟打字机效果\r\n * @param text 要显示的文本\r\n * @param delay 每字符延迟时间 (ms)\r\n * @param newline 是否在结束时换行\r\n */\r\nexport async function typewriter(text: string, delay: number = 15, newline: boolean = true) {\r\n for (const char of text) {\r\n process.stdout.write(char);\r\n if (delay > 0) {\r\n await new Promise((resolve) => setTimeout(resolve, delay));\r\n }\r\n }\r\n if (newline) {\r\n process.stdout.write('\\n');\r\n }\r\n}\r\n\r\n/**\r\n * 显示 ASCII Logo\r\n */\r\nexport async function showLogo(text: string = 'Reborn UI') {\r\n return new Promise<void>((resolve) => {\r\n figlet.text(text, {\r\n font: 'Slant',\r\n horizontalLayout: 'default',\r\n verticalLayout: 'default',\r\n width: 80,\r\n whitespaceBreak: true\r\n }, async (err, data) => {\r\n if (err) {\r\n console.log(gradientText(text));\r\n resolve();\r\n return;\r\n }\r\n if (data) {\r\n const lines = data.split('\\n');\r\n for (const line of lines) {\r\n console.log(gradientText(line));\r\n await new Promise(r => setTimeout(r, 20)); // 每行显示间隔,增加动感\r\n }\r\n }\r\n resolve();\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * 带有样式的成功提示\r\n */\r\nexport function successLog(message: string) {\r\n console.log(`${chalk.green('✔')} ${message}`);\r\n}\r\n\r\n/**\r\n * 带有样式的警告提示\r\n */\r\nexport function warnLog(message: string) {\r\n console.log(`${chalk.yellow('⚠')} ${message}`);\r\n}\r\n\r\n/**\r\n * 带有样式的错误提示\r\n */\r\nexport function errorLog(message: string) {\r\n console.log(`${chalk.red('✘')} ${message}`);\r\n}\r\n\r\n/**\r\n * 渐变色文本 (简单模拟,不依赖第三方复杂渐变库)\r\n */\r\nexport function gradientText(text: string) {\r\n const colors = [\r\n chalk.hex('#FF0080'),\r\n chalk.hex('#FF8C00'),\r\n chalk.hex('#40E0D0'),\r\n chalk.hex('#0080FF'),\r\n chalk.hex('#7B68EE'),\r\n ];\r\n\r\n let result = '';\r\n for (let i = 0; i < text.length; i++) {\r\n const color = colors[i % colors.length];\r\n result += color!(text[i]);\r\n }\r\n return result;\r\n}\r\n","import path from \"node:path\";\r\nimport fs from \"node:fs/promises\";\r\nimport fssync from \"node:fs\";\r\nimport { Command } from \"commander\";\r\nimport type { RegistryComponent, RegistryFile } from \"../types.js\";\r\nimport { listFilesRecursive, sha1, writeJsonFile } from \"../utils/fs.js\";\r\nimport { extractNpmDependenciesFromText } from \"../utils/imports.js\";\r\n\r\nfunction isAllowedFile(filePath: string) {\r\n const ext = path.extname(filePath).toLowerCase();\r\n return [\r\n \".vue\",\r\n \".ts\",\r\n \".js\",\r\n \".json\",\r\n \".css\",\r\n \".md\",\r\n \".svg\",\r\n ].includes(ext);\r\n}\r\n\r\nimport { transformToUniapp } from \"../utils/transformers.js\";\r\n\r\nfunction findWorkspaceRoot(startDir: string) {\r\n let current = path.resolve(startDir);\r\n for (; ;) {\r\n const marker = path.join(current, \"pnpm-workspace.yaml\");\r\n if (fssync.existsSync(marker)) return current;\r\n const parent = path.dirname(current);\r\n if (parent === current) return startDir;\r\n current = parent;\r\n }\r\n}\r\n\r\nexport function buildCommand() {\r\n const cmd = new Command(\"build\")\r\n .description(\"(内部)扫描组件源码并生成 registry JSON\")\r\n .option(\"--root <path>\", \"仓库根目录(默认自动向上查找 pnpm-workspace.yaml)\")\r\n .option(\r\n \"--source <path>\",\r\n \"组件源码目录(相对 root)\",\r\n \"app/components/reborn/ui\",\r\n )\r\n .option(\r\n \"--uniapp-source <path>\",\r\n \"UniApp 组件源码目录(相对 root),如果不提供则通过转换生成\",\r\n \"\",\r\n )\r\n .option(\r\n \"--out <path>\",\r\n \"输出 registry.json 路径(相对 root)\",\r\n \"packages/cli/registry/registry.json\",\r\n )\r\n .option(\r\n \"--also-out <path>\",\r\n \"额外再输出一份 registry.json(可重复传参)\",\r\n (val, acc: string[]) => {\r\n acc.push(val);\r\n return acc;\r\n },\r\n [],\r\n )\r\n .action(async (opts) => {\r\n const rootDir = opts.root\r\n ? path.resolve(opts.root)\r\n : findWorkspaceRoot(process.cwd());\r\n const sourceDir = path.join(rootDir, opts.source);\r\n const uniappSourceDir = opts.uniappSource\r\n ? path.join(rootDir, opts.uniappSource)\r\n : \"\";\r\n const outPath = path.join(rootDir, opts.out);\r\n const alsoOutPaths: string[] = (opts.alsoOut ?? [])?.map((p: string) =>\r\n path.join(rootDir, p),\r\n );\r\n\r\n const dirents = await fs.readdir(sourceDir, { withFileTypes: true });\r\n let componentDirs = dirents\r\n .filter((d) => d.isDirectory())\r\n ?.map((d) => d.name);\r\n\r\n if (uniappSourceDir && fssync.existsSync(uniappSourceDir)) {\r\n const uniappDirents = await fs.readdir(uniappSourceDir, { withFileTypes: true });\r\n const uniappDirs = uniappDirents\r\n .filter((d) => d.isDirectory())\r\n ?.map((d) => d.name);\r\n for (const dir of uniappDirs) {\r\n if (!componentDirs.includes(dir)) {\r\n componentDirs.push(dir);\r\n }\r\n }\r\n }\r\n\r\n componentDirs = componentDirs.sort((a, b) => a.localeCompare(b));\r\n\r\n const components: RegistryComponent[] = [];\r\n\r\n for (const componentName of componentDirs) {\r\n const name = componentName;\r\n const absComponentDir = path.join(sourceDir, componentName);\r\n let absFiles: string[] = [];\r\n\r\n if (fssync.existsSync(absComponentDir)) {\r\n absFiles = (await listFilesRecursive(absComponentDir)).filter(isAllowedFile);\r\n }\r\n const files: RegistryComponent[\"files\"] = [];\r\n const depSet = new Set<string>();\r\n\r\n for (const absFile of absFiles) {\r\n const rel = path\r\n .relative(absComponentDir, absFile)\r\n .split(path.sep)\r\n .join(\"/\");\r\n const content = await fs.readFile(absFile, \"utf8\");\r\n\r\n const ext = path.extname(absFile).toLowerCase();\r\n\r\n // 1. Web 版本(原样)\r\n if (ext === \".vue\") {\r\n files.push({ path: rel, content, target: \"web\" });\r\n } else {\r\n // Check for collision with UniApp source\r\n let target: \"web\" | \"uniapp\" | undefined;\r\n if (uniappSourceDir) {\r\n const parts = rel.split(\"/\");\r\n const uniappFile = path.join(uniappSourceDir, name, ...parts);\r\n if (fssync.existsSync(uniappFile)) {\r\n target = \"web\";\r\n }\r\n }\r\n if (target) {\r\n files.push({ path: rel, content, target });\r\n } else {\r\n files.push({ path: rel, content });\r\n }\r\n }\r\n\r\n // 只从代码文件里抽依赖\r\n if (ext === \".ts\" || ext === \".js\" || ext === \".vue\") {\r\n for (const dep of extractNpmDependenciesFromText(content)) {\r\n depSet.add(dep);\r\n }\r\n }\r\n }\r\n\r\n // 2. UniApp 版本\r\n // 如果提供了 uniappSourceDir,从那里读取;否则通过转换生成\r\n if (uniappSourceDir) {\r\n const uniappComponentDir = path.join(uniappSourceDir, name);\r\n if (fssync.existsSync(uniappComponentDir)) {\r\n const uniappFiles = (await listFilesRecursive(uniappComponentDir)).filter(\r\n isAllowedFile,\r\n );\r\n\r\n for (const absFile of uniappFiles) {\r\n const rel = path\r\n .relative(uniappComponentDir, absFile)\r\n .split(path.sep)\r\n .join(\"/\");\r\n const content = await fs.readFile(absFile, \"utf8\");\r\n const ext = path.extname(absFile).toLowerCase();\r\n\r\n files.push({ path: rel, content, target: \"uniapp\" });\r\n\r\n // 抽取依赖\r\n if (ext === \".ts\" || ext === \".js\" || ext === \".vue\") {\r\n for (const dep of extractNpmDependenciesFromText(content)) {\r\n depSet.add(dep);\r\n }\r\n }\r\n }\r\n }\r\n } else {\r\n // 通过转换生成 UniApp 版本\r\n for (const absFile of absFiles) {\r\n const ext = path.extname(absFile).toLowerCase();\r\n if (ext === \".vue\") {\r\n const rel = path\r\n .relative(absComponentDir, absFile)\r\n .split(path.sep)\r\n .join(\"/\");\r\n const content = await fs.readFile(absFile, \"utf8\");\r\n files.push({\r\n path: rel,\r\n content: transformToUniapp(content),\r\n target: \"uniapp\",\r\n });\r\n }\r\n }\r\n }\r\n\r\n components.push({\r\n name,\r\n dependencies: [...depSet].sort(),\r\n files,\r\n });\r\n }\r\n\r\n const registry: RegistryFile = {\r\n schemaVersion: 1,\r\n generatedAt: new Date().toISOString(),\r\n source: {\r\n rootDir: rootDir.split(path.sep).join(\"/\"),\r\n componentsDir: opts.source,\r\n },\r\n components,\r\n };\r\n\r\n async function writeOut(targetRegistryPath: string) {\r\n const outComponentsDir = path.join(\r\n path.dirname(targetRegistryPath),\r\n \"components\",\r\n );\r\n await writeJsonFile(targetRegistryPath, registry);\r\n\r\n // 额外输出每个组件的 json,方便调试/按需读取\r\n await fs.mkdir(outComponentsDir, { recursive: true });\r\n for (const c of components) {\r\n await writeJsonFile(\r\n path.join(outComponentsDir, `${c.name}.json`),\r\n {\r\n ...c,\r\n fileCount: c.files.length,\r\n contentHash: sha1(JSON.stringify(c.files?.map((f) => f.content))),\r\n },\r\n );\r\n }\r\n }\r\n\r\n await writeOut(outPath);\r\n for (const p of alsoOutPaths) await writeOut(p);\r\n\r\n // eslint-disable-next-line no-console\r\n console.log(\r\n `registry 已生成:${path.relative(process.cwd(), outPath)}(${components.length} 个组件)`,\r\n );\r\n });\r\n\r\n return cmd;\r\n}\r\n\r\n\r\n","const IMPORT_RE =\r\n /\\bfrom\\s+[\"']([^\"']+)[\"']|\\bimport\\(\\s*[\"']([^\"']+)[\"']\\s*\\)|\\brequire\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/g;\r\n\r\nfunction normalizePackageName(specifier: string) {\r\n // ignore relative/alias/virtual\r\n if (\r\n specifier.startsWith(\".\") ||\r\n specifier.startsWith(\"/\") ||\r\n specifier.startsWith(\"@/\") ||\r\n specifier.startsWith(\"~/\") ||\r\n specifier.startsWith(\"#\") ||\r\n specifier.startsWith(\"virtual:\")\r\n ) {\r\n return null;\r\n }\r\n\r\n // scoped package: @scope/name[/...]\r\n if (specifier.startsWith(\"@\")) {\r\n const parts = specifier.split(\"/\");\r\n if (parts.length >= 2) return `${parts[0]}/${parts[1]}`;\r\n return specifier;\r\n }\r\n\r\n // normal package: name[/...]\r\n return specifier.split(\"/\")[0] ?? null;\r\n}\r\n\r\nexport function extractNpmDependenciesFromText(text: string) {\r\n const out = new Set<string>();\r\n\r\n for (const match of text.matchAll(IMPORT_RE)) {\r\n const spec = match[1] ?? match[2] ?? match[3];\r\n if (!spec) continue;\r\n const pkg = normalizePackageName(spec);\r\n if (!pkg) continue;\r\n out.add(pkg);\r\n }\r\n\r\n // 常见“框架自带/不应自动安装”的虚拟模块\r\n out.delete(\"nuxt\");\r\n out.delete(\"vue\");\r\n\r\n return [...out].sort();\r\n}\r\n\r\n\r\n","\r\nexport function transformToUniapp(code: string): string {\r\n // 1. 标签替换\r\n // div -> view\r\n // span, font -> text(注意:span可能嵌套,正则要注意)\r\n // ul, li -> view\r\n // img -> image\r\n // a -> navigator\r\n // select -> picker\r\n // iframe -> web-view\r\n\r\n let newCode = code;\r\n\r\n // 简单正则替换标签名\r\n const tagMap: Record<string, string> = {\r\n div: \"view\",\r\n span: \"text\",\r\n font: \"text\",\r\n ul: \"view\",\r\n li: \"view\",\r\n img: \"image\",\r\n a: \"navigator\",\r\n select: \"picker\",\r\n iframe: \"web-view\",\r\n };\r\n\r\n for (const [k, v] of Object.entries(tagMap)) {\r\n // 匹配 <tag ...> 和 </tag>\r\n // 1. <tag\r\n newCode = newCode.replace(new RegExp(`<${k}(\\\\s+|>)`, \"g\"), `<${v}$1`);\r\n // 2. </tag>\r\n newCode = newCode.replace(new RegExp(`<\\\\/${k}>`, \"g\"), `</${v}>`);\r\n }\r\n\r\n // 2. 特殊处理\r\n // input[type=\"search\"] -> type=\"text\" confirm-type=\"search\"\r\n newCode = newCode.replace(/type=[\"']search[\"']/g, 'confirm-type=\"search\"');\r\n\r\n return newCode;\r\n}\r\n","import path from \"node:path\";\r\nimport fs from \"node:fs/promises\";\r\nimport fssync from \"node:fs\";\r\nimport { Command } from \"commander\";\r\nimport prompts from \"prompts\";\r\nimport type { CliConfig, PackageManager } from \"../types.js\";\r\nimport { copyDirRecursive, ensureDir, listFilesRecursive, pathExists, writeJsonFile, writeTextFile } from \"../utils/fs.js\";\r\nimport { detectPackageManager } from \"../utils/pm.js\";\r\nimport { DEFAULT_CONFIG_PATH, defaultConfig, loadConfigCompat } from \"../utils/registry.js\";\r\nimport { findNearestPackageRoot } from \"../utils/templates.js\";\r\nimport { TEMPLATES } from \"../generated/templates.js\";\r\nimport { gradientText, showLogo, typewriter } from \"../utils/ui.js\";\r\n\r\nfunction looksLikeNuxtProject(cwd: string) {\r\n return Promise.all([\r\n pathExists(path.join(cwd, \"nuxt.config.ts\")),\r\n pathExists(path.join(cwd, \"nuxt.config.js\")),\r\n pathExists(path.join(cwd, \"nuxt.config.mjs\")),\r\n ]).then((arr) => arr.some(Boolean));\r\n}\r\n\r\nfunction findWorkspaceRoot(startDir: string) {\r\n let current = path.resolve(startDir);\r\n for (; ;) {\r\n const marker = path.join(current, \"pnpm-workspace.yaml\");\r\n if (fssync.existsSync(marker)) return current;\r\n const parent = path.dirname(current);\r\n if (parent === current) return startDir;\r\n current = parent;\r\n }\r\n}\r\n\r\n\r\n// function makeDefaultTailwindConfig removed in favor of template file\r\n\r\n\r\n\r\n\r\nfunction cnUtilsTs(params: { importPath?: string }) {\r\n // importPath 预留:如果用户想从别处导入 clsx/twMerge\r\n void params;\r\n return `import { type ClassValue, clsx } from \"clsx\";\\nimport { twMerge } from \"tailwind-merge\";\\n\\nexport function cn(...inputs: ClassValue[]) {\\n return twMerge(clsx(inputs));\\n}\\n`;\r\n}\r\n\r\nasync function rewriteAliasInDir(params: {\r\n cwd: string;\r\n targetDir: string;\r\n aliasSymbol: string;\r\n}) {\r\n const { cwd, targetDir, aliasSymbol } = params;\r\n if (!aliasSymbol || aliasSymbol === \"@\") return;\r\n const absDir = path.join(cwd, targetDir);\r\n if (!(await pathExists(absDir))) return;\r\n\r\n const files = await listFilesRecursive(absDir);\r\n for (const f of files) {\r\n const ext = path.extname(f).toLowerCase();\r\n // 只处理常见文本文件,避免误改二进制\r\n if (![\".ts\", \".tsx\", \".js\", \".jsx\", \".vue\", \".mjs\", \".cjs\"].includes(ext)) continue;\r\n const raw = await fs.readFile(f, \"utf8\");\r\n const next = raw.replaceAll(\"@/\", `${aliasSymbol}/`);\r\n if (next !== raw) await fs.writeFile(f, next, \"utf8\");\r\n }\r\n}\r\n\r\nasync function copyTemplates(params: {\r\n cwd: string;\r\n workspaceRoot: string;\r\n platform: \"web\" | \"uniapp\";\r\n cfg: CliConfig;\r\n overwrite?: boolean;\r\n}) {\r\n const { cwd, workspaceRoot, platform, cfg, overwrite } = params;\r\n\r\n // 1. 尝试从仓库源码目录拷贝(本地开发场景)\r\n const repoPaths = {\r\n web: {\r\n lib: path.join(workspaceRoot, \"app/lib\"),\r\n composables: path.join(workspaceRoot, \"app/composables\"),\r\n },\r\n uniapp: {\r\n lib: path.join(workspaceRoot, \"packages/uniapp-project/src/lib\"),\r\n composables: path.join(workspaceRoot, \"packages/uniapp-project/src/composables\"),\r\n },\r\n };\r\n\r\n const currentRepoPaths = repoPaths[platform];\r\n let copiedFromRepo = false;\r\n\r\n if (await pathExists(currentRepoPaths.lib)) {\r\n await copyDirRecursive({\r\n fromDir: currentRepoPaths.lib,\r\n toDir: path.join(cwd, cfg.libDir),\r\n overwrite,\r\n });\r\n copiedFromRepo = true;\r\n }\r\n\r\n if (await pathExists(currentRepoPaths.composables)) {\r\n await copyDirRecursive({\r\n fromDir: currentRepoPaths.composables,\r\n toDir: path.join(cwd, cfg.composablesDir),\r\n overwrite,\r\n ignoreFileNames: platform === \"web\" ? new Set([\"useComponentCode.ts\", \"useCopyToClipboard.ts\",\"getComponentCode.ts\",\"getUniappCode.ts\"]) : undefined,\r\n });\r\n copiedFromRepo = true;\r\n }\r\n\r\n // 2. 如果不是在仓库内运行(例如 npx),则使用生成的字符串模板\r\n if (!copiedFromRepo) {\r\n const platformTemplates = TEMPLATES[platform];\r\n for (const [relPath, content] of Object.entries(platformTemplates)) {\r\n let targetPath = \"\";\r\n if (relPath.startsWith(\"lib/\")) {\r\n targetPath = path.join(cwd, cfg.libDir, relPath.replace(\"lib/\", \"\"));\r\n } else if (relPath.startsWith(\"composables/\")) {\r\n targetPath = path.join(cwd, cfg.composablesDir, relPath.replace(\"composables/\", \"\"));\r\n }\r\n\r\n if (targetPath) {\r\n if (!overwrite && (await pathExists(targetPath))) continue;\r\n await writeTextFile(targetPath, content);\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport function initCommand() {\r\n const cmd = new Command(\"init\")\r\n .description(\"初始化新项目\")\r\n .option(\"--cwd <path>\", \"目标项目目录\", process.cwd())\r\n .option(\"--pm <pm>\", \"包管理器:pnpm|npm|yarn|bun\")\r\n .option(\"--yes\", \"跳过交互,使用默认值\", false)\r\n .option(\"--overwrite\", \"覆盖已存在的模板文件(lib/composables)\", false)\r\n .option(\r\n \"--config <path>\",\r\n \"配置文件路径(相对 cwd)\",\r\n DEFAULT_CONFIG_PATH,\r\n )\r\n .option(\r\n \"--components-dir <path>\",\r\n \"组件写入目录\",\r\n defaultConfig().componentsDir,\r\n )\r\n .option(\r\n \"--lib-dir <path>\",\r\n \"lib 目录(cn/utils)\",\r\n defaultConfig().libDir,\r\n )\r\n .option(\r\n \"--composables-dir <path>\",\r\n \"composables 目录\",\r\n defaultConfig().composablesDir,\r\n )\r\n .option(\r\n \"--alias-symbol <symbol>\",\r\n \"项目根目录映射别名符号(默认 @)\",\r\n defaultConfig().aliasSymbol,\r\n )\r\n .option(\"--platform <platform>\", \"目标平台:web|uniapp\", \"web\")\r\n .option(\"--registry <pkgOrPath>\", \"registry 来源(默认 builtin)\", defaultConfig().registry)\r\n .action(async (opts) => {\r\n const cwd = path.resolve(opts.cwd);\r\n\r\n // eslint-disable-next-line no-console\r\n console.log(\r\n \"提示:项目中有部分依赖需要使用@/ 路径进行配置,请您安装到项目中配置好的路径下,请慎重选择文件位置\",\r\n );\r\n\r\n const pkgPath = path.join(cwd, \"package.json\");\r\n if (!(await pathExists(pkgPath))) {\r\n throw new Error(`未找到 package.json:${pkgPath}`);\r\n }\r\n\r\n const pm: PackageManager =\r\n opts.pm ?? (await detectPackageManager(cwd));\r\n\r\n const cfg: CliConfig = {\r\n schemaVersion: 1,\r\n componentsDir: opts.componentsDir,\r\n libDir: opts.libDir,\r\n composablesDir: opts.composablesDir,\r\n aliasSymbol: opts.aliasSymbol,\r\n registry: opts.registry,\r\n platform: opts.platform,\r\n };\r\n\r\n // 如果已存在 components.json,默认沿用(除非用户显式传参覆盖)\r\n const existing = await loadConfigCompat(cwd);\r\n if (existing) {\r\n cfg.componentsDir = opts.componentsDir ?? existing.componentsDir ?? cfg.componentsDir;\r\n cfg.libDir = opts.libDir ?? existing.libDir ?? cfg.libDir;\r\n cfg.composablesDir = opts.composablesDir ?? existing.composablesDir ?? cfg.composablesDir;\r\n cfg.aliasSymbol = opts.aliasSymbol ?? existing.aliasSymbol ?? cfg.aliasSymbol;\r\n cfg.registry = opts.registry ?? existing.registry ?? cfg.registry;\r\n cfg.platform = opts.platform ?? existing.platform ?? cfg.platform;\r\n }\r\n\r\n if (!opts.yes) {\r\n const nuxt = await looksLikeNuxtProject(cwd);\r\n const res = await prompts(\r\n [\r\n {\r\n type: \"select\",\r\n name: \"platform\",\r\n message: \"选择目标平台\",\r\n choices: [\r\n { title: \"Web (默认)\", value: \"web\" },\r\n { title: \"UniApp\", value: \"uniapp\" },\r\n ],\r\n initial: cfg.platform === \"uniapp\" ? 1 : 0,\r\n },\r\n {\r\n type: \"text\",\r\n name: \"componentsDir\",\r\n message: \"组件目录(componentsDir)\",\r\n initial: cfg.componentsDir,\r\n },\r\n {\r\n type: \"text\",\r\n name: \"libDir\",\r\n message: \"lib 目录(libDir,用于 cn/utils)\",\r\n initial: cfg.libDir,\r\n },\r\n {\r\n type: \"text\",\r\n name: \"composablesDir\",\r\n message: \"composables 目录(composablesDir)\",\r\n initial: cfg.composablesDir,\r\n },\r\n {\r\n type: \"text\",\r\n name: \"aliasSymbol\",\r\n message: \"基于项目根目录的“映射”的符号是?(aliasSymbol)\",\r\n initial: cfg.aliasSymbol ?? \"@\",\r\n },\r\n ],\r\n {\r\n onCancel: () => {\r\n throw new Error(\"已取消\");\r\n },\r\n },\r\n );\r\n\r\n cfg.platform = res.platform ?? cfg.platform;\r\n cfg.componentsDir = res.componentsDir ?? cfg.componentsDir;\r\n cfg.libDir = res.libDir ?? cfg.libDir;\r\n cfg.composablesDir = res.composablesDir ?? cfg.composablesDir;\r\n cfg.aliasSymbol = res.aliasSymbol ?? cfg.aliasSymbol;\r\n\r\n // 写配置\r\n const cfgPath = path.join(cwd, opts.config);\r\n await writeJsonFile(cfgPath, cfg);\r\n\r\n // 复制模板:lib/ + composables/\r\n const workspaceRoot = findWorkspaceRoot(findNearestPackageRoot(import.meta.url));\r\n await copyTemplates({\r\n cwd,\r\n workspaceRoot,\r\n platform: cfg.platform as \"web\" | \"uniapp\",\r\n cfg,\r\n overwrite: opts.overwrite,\r\n });\r\n\r\n // 仅替换 \"@/...\" 的别名符号,不改其它路径内容\r\n await rewriteAliasInDir({ cwd, targetDir: cfg.libDir, aliasSymbol: cfg.aliasSymbol ?? \"@\" });\r\n await rewriteAliasInDir({\r\n cwd,\r\n targetDir: cfg.composablesDir,\r\n aliasSymbol: cfg.aliasSymbol ?? \"@\",\r\n });\r\n\r\n // 兜底:如果用户模板里没有 utils.ts,则生成 cn\r\n const libUtilsPath = path.join(cwd, cfg.libDir, \"utils.ts\");\r\n if (!(await pathExists(libUtilsPath))) await writeTextFile(libUtilsPath, cnUtilsTs({}));\r\n\r\n console.log(`已写入配置:${path.relative(process.cwd(), cfgPath)};并生成 cn/utils(pm=${pm})`);\r\n console.log(\"请按照 https://tw.icebreaker.top/docs/quick-start/v4/uni-app-vite 指引进行项目配置初始化\");\r\n\r\n console.log(\"\");\r\n await showLogo();\r\n await typewriter(gradientText(\"感谢使用 Reborn UI ! ✨\"), 20);\r\n return;\r\n }\r\n\r\n // --yes:直接写默认配置\r\n const cfgPath = path.join(cwd, opts.config);\r\n await ensureDir(path.dirname(cfgPath));\r\n await fs.writeFile(cfgPath, JSON.stringify(cfg, null, 2) + \"\\n\", \"utf8\");\r\n\r\n // 复制模板逻辑\r\n const workspaceRoot = findWorkspaceRoot(findNearestPackageRoot(import.meta.url));\r\n await copyTemplates({\r\n cwd,\r\n workspaceRoot,\r\n platform: cfg.platform as \"web\" | \"uniapp\",\r\n cfg,\r\n overwrite: opts.overwrite,\r\n });\r\n\r\n // 仅替换 \"@/...\" 的别名符号,不改其它路径内容\r\n await rewriteAliasInDir({ cwd, targetDir: cfg.libDir, aliasSymbol: cfg.aliasSymbol ?? \"@\" });\r\n await rewriteAliasInDir({\r\n cwd,\r\n targetDir: cfg.composablesDir,\r\n aliasSymbol: cfg.aliasSymbol ?? \"@\",\r\n });\r\n\r\n // 兜底:如果用户模板里没有 utils.ts,则生成 cn\r\n const libUtilsPath = path.join(cwd, cfg.libDir, \"utils.ts\");\r\n if (!(await pathExists(libUtilsPath))) await writeTextFile(libUtilsPath, cnUtilsTs({}));\r\n\r\n // eslint-disable-next-line no-console\r\n console.log(`已初始化:${path.relative(process.cwd(), cfgPath)};并生成 cn/utils(pm=${pm})`);\r\n console.log(\"请按照 https://tw.icebreaker.top/docs/quick-start/v4/uni-app-vite 指引进行项目配置初始化\");\r\n\r\n console.log(\"\");\r\n await showLogo();\r\n await typewriter(gradientText(\"感谢使用 Reborn UI ! ✨\"), 2);\r\n });\r\n\r\n return cmd;\r\n}\r\n\r\n\r\n","import path from \"node:path\";\r\nimport fs from \"node:fs\";\r\nimport { fileURLToPath } from \"node:url\";\r\n\r\nexport function findNearestPackageRoot(from: string) {\r\n // from: import.meta.url\r\n let dir = path.dirname(fileURLToPath(from));\r\n while (true) {\r\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\r\n const parent = path.dirname(dir);\r\n if (parent === dir) return dir;\r\n dir = parent;\r\n }\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n","// 此文件由 sync-templates.ts 自动生成,请勿手动修改\nexport const TEMPLATES = {\n \"web\": {\n \"lib/tv.ts\": \"import { createTV } from \\\"tailwind-variants\\\";\\r\\nimport { twMergeConfig } from \\\"./utils\\\";\\r\\n\\r\\nexport const tv = createTV({\\r\\n twMergeConfig,\\r\\n});\\r\\nexport type { VariantProps } from \\\"tailwind-variants\\\";\\r\\n\",\n \"lib/utils.ts\": \"import type { ClassValue } from \\\"clsx\\\";\\r\\nimport { clsx } from \\\"clsx\\\";\\r\\nimport { extendTailwindMerge } from \\\"tailwind-merge\\\";\\r\\n\\r\\nexport const twMergeConfig = {\\r\\n extend: {\\r\\n classGroups: {\\r\\n \\\"font-size\\\": [{ text: [(value: string) => !isNaN(Number(value))] }],\\r\\n },\\r\\n },\\r\\n};\\r\\n\\r\\nconst customTwMerge = extendTailwindMerge(twMergeConfig);\\r\\n\\r\\nexport function cn(...inputs: ClassValue[]) {\\r\\n return customTwMerge(clsx(inputs));\\r\\n}\\r\\n\\r\\nexport type ObjectValues<T> = T[keyof T];\\r\\n\",\n \"composables/useFieldGroup.ts\": \"\\r\\nimport { ref } from 'vue'\\r\\n\\r\\nexport function useFieldGroup(props: any) {\\r\\n return {\\r\\n disabled: ref(undefined),\\r\\n isError: ref(undefined),\\r\\n orientation: ref(undefined),\\r\\n size: ref(undefined)\\r\\n }\\r\\n}\\r\\n\",\n \"composables/useMouseState.ts\": \"import { readonly, ref } from \\\"vue\\\";\\r\\n\\r\\nexport function useMouseState() {\\r\\n const isMouseEntered = ref(false);\\r\\n\\r\\n function setMouseEntered(value: boolean) {\\r\\n isMouseEntered.value = value;\\r\\n }\\r\\n\\r\\n return {\\r\\n isMouseEntered: readonly(isMouseEntered),\\r\\n setMouseEntered,\\r\\n };\\r\\n}\\r\\n\",\n \"composables/useNavigation.ts\": \"import type { ContentNavigationItem } from \\\"@nuxt/content\\\";\\r\\n\\r\\nexport function useNavigation(navigation?: Ref<ContentNavigationItem[]>) {\\r\\n const route = useRoute();\\r\\n\\r\\n const children = computed(() => {\\r\\n const nav = toValue(navigation);\\r\\n\\r\\n // Get the current path segments\\r\\n const pathSegments = route.path.split(\\\"/\\\").filter(Boolean);\\r\\n\\r\\n // Need at least one section (e.g., ['components', 'button'])\\r\\n if (pathSegments.length < 1) {\\r\\n return [];\\r\\n }\\r\\n\\r\\n // Build the top parent path (e.g., '/components')\\r\\n const topParentPath = `/${pathSegments[0]}`;\\r\\n\\r\\n // Find the matching top-level navigation item\\r\\n const topParent = nav?.find((item) => item.path === topParentPath);\\r\\n\\r\\n return topParent?.children || [];\\r\\n });\\r\\n\\r\\n const isFlatList = computed(() => {\\r\\n return children.value.every((child) => !child.children || child.children.length === 0);\\r\\n });\\r\\n\\r\\n const nav = computed(() => {\\r\\n if (isFlatList.value) {\\r\\n return [\\r\\n {\\r\\n title: \\\"Overview\\\",\\r\\n path: children.value.at(0)?.path || \\\"\\\",\\r\\n children: children.value,\\r\\n },\\r\\n ];\\r\\n }\\r\\n\\r\\n return children.value;\\r\\n });\\r\\n\\r\\n return {\\r\\n nav,\\r\\n };\\r\\n}\\r\\n\"\n },\n \"uniapp\": {\n \"lib/AbortablePromise.ts\": \"export class AbortablePromise<T> {\\r\\n promise: Promise<T>\\r\\n private _reject: ((res?: any) => void) | null = null\\r\\n\\r\\n constructor(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) {\\r\\n this.promise = new Promise<T>((resolve, reject) => {\\r\\n executor(resolve, reject)\\r\\n this._reject = reject // 保存reject方法的引用,以便在abort时调用\\r\\n })\\r\\n }\\r\\n // 提供abort方法来中止Promise\\r\\n abort(error?: any) {\\r\\n if (this._reject) {\\r\\n this._reject(error) // 调用reject方法来中止Promise\\r\\n }\\r\\n }\\r\\n\\r\\n then<TResult1 = T, TResult2 = never>(\\r\\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,\\r\\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null\\r\\n ): Promise<TResult1 | TResult2> {\\r\\n return this.promise.then(onfulfilled, onrejected)\\r\\n }\\r\\n\\r\\n catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult> {\\r\\n return this.promise.catch(onrejected)\\r\\n }\\r\\n}\\r\\n\",\n \"lib/animation.ts\": \"import type FrameCallback from 'android.view.Choreographer.FrameCallback' // 帧回调接口\\r\\nimport type Long from 'kotlin.Long' // Kotlin Long 类型\\r\\n// #ifdef APP-ANDROID\\r\\nimport Choreographer from 'android.view.Choreographer' // Android 帧同步器,提供垂直同步信号\\r\\n// #endif\\r\\n\\r\\n/**\\r\\n * 缓动函数类型定义\\r\\n */\\r\\nexport type EasingFunction = (progress: number) => number\\r\\n\\r\\n/**\\r\\n * 动画属性配置\\r\\n */\\r\\nexport interface AnimationAttribute {\\r\\n /** 起始值 */\\r\\n fromValue: string\\r\\n /** 结束值 */\\r\\n toValue: string\\r\\n /** 单位 (px, %, deg等) */\\r\\n unit: string\\r\\n /** 当前值 */\\r\\n currentValue: string\\r\\n /** 当前进度 (0-1) */\\r\\n progress: number\\r\\n /** 属性名称 */\\r\\n propertyName: string\\r\\n}\\r\\n\\r\\n/**\\r\\n * 动画配置选项\\r\\n */\\r\\nexport interface AnimationOptions {\\r\\n /** 动画持续时间(毫秒) */\\r\\n duration?: number\\r\\n /** 循环次数 (-1为无限循环) */\\r\\n loop?: number\\r\\n /** 是否往返播放 */\\r\\n alternate?: boolean\\r\\n /** 是否按属性顺序依次执行动画 */\\r\\n sequential?: boolean\\r\\n /** 缓动函数名称 */\\r\\n timingFunction?: string\\r\\n /** 自定义贝塞尔曲线参数 */\\r\\n bezier?: number[]\\r\\n /** 动画完成回调 */\\r\\n complete?: () => void\\r\\n /** 动画开始回调 */\\r\\n start?: () => void\\r\\n /** 每帧回调 */\\r\\n frame?: (progress: number) => void\\r\\n}\\r\\n\\r\\n// 贝塞尔曲线计算常量\\r\\nconst BEZIER_SPLINE_SIZE = 11 // 样本点数量,用于预计算优化\\r\\nconst BEZIER_SAMPLE_STEP = 1.0 / (BEZIER_SPLINE_SIZE - 1.0) // 样本步长\\r\\n\\r\\n/**\\r\\n * 贝塞尔曲线系数A\\r\\n * 三次贝塞尔曲线的三次项系数\\r\\n */\\r\\nfunction getBezierCoefficientA(x1: number, x2: number): number {\\r\\n return 1.0 - 3.0 * x2 + 3.0 * x1 // B(t) = (1-t)³P₀ + 3(1-t)²tP₁ + 3(1-t)t²P₂ + t³P₃ 中的 t³ 系数\\r\\n}\\r\\n\\r\\n/**\\r\\n * 贝塞尔曲线系数B\\r\\n * 三次贝塞尔曲线的二次项系数\\r\\n */\\r\\nfunction getBezierCoefficientB(x1: number, x2: number): number {\\r\\n return 3.0 * x2 - 6.0 * x1 // 二次项系数\\r\\n}\\r\\n\\r\\n/**\\r\\n * 贝塞尔曲线系数C\\r\\n * 三次贝塞尔曲线的一次项系数\\r\\n */\\r\\nfunction getBezierCoefficientC(x1: number): number {\\r\\n return 3.0 * x1 // 一次项系数\\r\\n}\\r\\n\\r\\n/**\\r\\n * 计算贝塞尔曲线值\\r\\n * 使用霍纳法则提高计算效率\\r\\n * @param t 时间参数 (0-1)\\r\\n * @param x1 控制点1的x坐标\\r\\n * @param x2 控制点2的x坐标\\r\\n */\\r\\nfunction calculateBezierValue(t: number, x1: number, x2: number): number {\\r\\n const a = getBezierCoefficientA(x1, x2) // 获取三次项系数\\r\\n const b = getBezierCoefficientB(x1, x2) // 获取二次项系数\\r\\n const c = getBezierCoefficientC(x1) // 获取一次项系数\\r\\n return ((a * t + b) * t + c) * t // 霍纳法则:((at + b)t + c)t,减少乘法运算\\r\\n}\\r\\n\\r\\n/**\\r\\n * 计算贝塞尔曲线斜率\\r\\n * 对贝塞尔曲线求导得到斜率函数\\r\\n * @param t 时间参数 (0-1)\\r\\n * @param x1 控制点1的x坐标\\r\\n * @param x2 控制点2的x坐标\\r\\n */\\r\\nfunction getBezierSlope(t: number, x1: number, x2: number): number {\\r\\n const a = getBezierCoefficientA(x1, x2) // 三次项系数\\r\\n const b = getBezierCoefficientB(x1, x2) // 二次项系数\\r\\n const c = getBezierCoefficientC(x1) // 一次项系数\\r\\n return 3.0 * a * t * t + 2.0 * b * t + c // 导数:3at² + 2bt + c\\r\\n}\\r\\n\\r\\n/**\\r\\n * 二分法求解贝塞尔曲线参数\\r\\n * 用于根据x值反推t参数,适用于斜率较小的情况\\r\\n * @param targetX 目标x值\\r\\n * @param startT 起始t值\\r\\n * @param endT 结束t值\\r\\n * @param x1 控制点1的x坐标\\r\\n * @param x2 控制点2的x坐标\\r\\n */\\r\\nfunction binarySearchBezierT(\\r\\n targetX: number,\\r\\n startT: number,\\r\\n endT: number,\\r\\n x1: number,\\r\\n x2: number,\\r\\n): number {\\r\\n let currentX: number // 当前计算的x值\\r\\n let currentT: number // 当前的t参数\\r\\n let iterations = 0 // 迭代次数计数器\\r\\n const maxIterations = 10 // 最大迭代次数,避免无限循环\\r\\n const precision = 0.0000001 // 精度要求\\r\\n\\r\\n do {\\r\\n currentT = startT + (endT - startT) / 2.0 // 取中点\\r\\n currentX = calculateBezierValue(currentT, x1, x2) - targetX // 计算误差\\r\\n if (currentX > 0.0) {\\r\\n // 如果当前x值大于目标值\\r\\n endT = currentT // 缩小右边界\\r\\n }\\r\\n else {\\r\\n // 如果当前x值小于目标值\\r\\n startT = currentT // 缩小左边界\\r\\n }\\r\\n iterations++ // 增加迭代计数\\r\\n } while (Math.abs(currentX) > precision && iterations < maxIterations) // 直到精度满足或达到最大迭代次数\\r\\n\\r\\n return currentT // 返回找到的t参数\\r\\n}\\r\\n\\r\\n/**\\r\\n * 牛顿-拉夫逊法求解贝塞尔曲线参数\\r\\n * 适用于斜率较大的情况,收敛速度快\\r\\n * @param targetX 目标x值\\r\\n * @param initialGuess 初始猜测值\\r\\n * @param x1 控制点1的x坐标\\r\\n * @param x2 控制点2的x坐标\\r\\n */\\r\\nfunction newtonRaphsonBezierT(\\r\\n targetX: number,\\r\\n initialGuess: number,\\r\\n x1: number,\\r\\n x2: number,\\r\\n): number {\\r\\n let t = initialGuess // 当前t值,从初始猜测开始\\r\\n const maxIterations = 4 // 最大迭代次数,牛顿法收敛快\\r\\n\\r\\n for (let i = 0; i < maxIterations; i++) {\\r\\n const slope = getBezierSlope(t, x1, x2) // 计算当前点的斜率\\r\\n if (slope == 0.0) {\\r\\n // 如果斜率为0,避免除零错误\\r\\n return t\\r\\n }\\r\\n const currentX = calculateBezierValue(t, x1, x2) - targetX // 计算当前误差\\r\\n t = t - currentX / slope // 牛顿法迭代公式:t_new = t - f(t)/f'(t)\\r\\n }\\r\\n return t // 返回收敛后的t值\\r\\n}\\r\\n\\r\\n/**\\r\\n * 创建贝塞尔缓动函数\\r\\n * 根据四个控制点坐标生成缓动函数,类似CSS的cubic-bezier\\r\\n * @param x1 控制点1的x坐标 (0-1)\\r\\n * @param y1 控制点1的y坐标 (0-1)\\r\\n * @param x2 控制点2的x坐标 (0-1)\\r\\n * @param y2 控制点2的y坐标 (0-1)\\r\\n */\\r\\nfunction createBezierEasing(x1: number, y1: number, x2: number, y2: number): EasingFunction | null {\\r\\n // 验证控制点坐标范围,x坐标必须在0-1之间\\r\\n if (!(x1 >= 0 && x1 <= 1 && x2 >= 0 && x2 <= 1)) {\\r\\n return null // 参数无效时返回null\\r\\n }\\r\\n\\r\\n const sampleValues: number[] = [] // 预计算的样本值数组\\r\\n\\r\\n // 预计算样本值以提高性能,仅对非线性曲线进行预计算\\r\\n if (x1 != y1 || x2 != y2) {\\r\\n // 如果不是线性函数\\r\\n for (let i = 0; i < BEZIER_SPLINE_SIZE; i++) {\\r\\n // 计算等间距的样本点,用于快速查找\\r\\n sampleValues.push(calculateBezierValue(i * BEZIER_SAMPLE_STEP, x1, x2))\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 根据x值获取对应的t参数\\r\\n * 使用预计算样本进行快速查找和插值\\r\\n * @param x 输入的x值 (0-1)\\r\\n */\\r\\n function getTParameterForX(x: number): number {\\r\\n let intervalStart = 0.0 // 区间起始位置\\r\\n let currentSample = 1 // 当前样本索引\\r\\n const lastSample = BEZIER_SPLINE_SIZE - 1 // 最后一个样本索引\\r\\n\\r\\n // 找到x值所在的区间,线性搜索预计算的样本\\r\\n for (; currentSample != lastSample && sampleValues[currentSample] <= x; currentSample++) {\\r\\n intervalStart += BEZIER_SAMPLE_STEP // 移动区间起始位置\\r\\n }\\r\\n currentSample-- // 回退到正确的区间\\r\\n\\r\\n // 线性插值获得初始猜测值,提高后续求解精度\\r\\n const dist\\r\\n = (x - sampleValues[currentSample])\\r\\n / (sampleValues[currentSample + 1] - sampleValues[currentSample]) // 计算在区间内的相对位置\\r\\n const initialGuess = intervalStart + dist * BEZIER_SAMPLE_STEP // 计算初始猜测的t值\\r\\n const initialSlope = getBezierSlope(initialGuess, x1, x2) // 计算初始点的斜率\\r\\n\\r\\n // 根据斜率选择合适的求解方法\\r\\n if (initialSlope >= 0.001) {\\r\\n // 斜率足够大时使用牛顿法\\r\\n return newtonRaphsonBezierT(x, initialGuess, x1, x2)\\r\\n }\\r\\n else if (initialSlope == 0.0) {\\r\\n // 斜率为0时直接返回\\r\\n return initialGuess\\r\\n }\\r\\n // 斜率太小时使用二分法,更稳定\\r\\n return binarySearchBezierT(x, intervalStart, intervalStart + BEZIER_SAMPLE_STEP, x1, x2)\\r\\n }\\r\\n\\r\\n // 返回缓动函数,这是最终的缓动函数接口\\r\\n return function (progress: number): number {\\r\\n // 线性情况直接返回,优化性能\\r\\n if (x1 == y1 && x2 == y2) {\\r\\n return progress\\r\\n }\\r\\n // 边界情况处理,避免计算误差\\r\\n if (progress == 0.0 || progress == 1.0) {\\r\\n return progress\\r\\n }\\r\\n // 计算贝塞尔曲线值:先根据progress(x)找到对应的t,再计算y值\\r\\n return calculateBezierValue(getTParameterForX(progress), y1, y2)\\r\\n }\\r\\n}\\r\\n\\r\\n/**\\r\\n * 颜色工具函数:标准化颜色值格式\\r\\n * 处理不同格式的颜色输入,确保返回有效的颜色值\\r\\n */\\r\\nfunction getDefaultColor(colorValue: string): string {\\r\\n // 简化的颜色处理,实际项目中可能需要更完整的颜色转换\\r\\n if (colorValue.startsWith('#')) {\\r\\n // 十六进制颜色格式\\r\\n return colorValue\\r\\n }\\r\\n if (colorValue.startsWith('rgb')) {\\r\\n // RGB或RGBA颜色格式\\r\\n return colorValue\\r\\n }\\r\\n // 默认返回黑色,作为兜底处理\\r\\n return '#000000'\\r\\n}\\r\\n\\r\\n/**\\r\\n * 十六进制颜色转RGB对象\\r\\n * 将#RRGGBB格式的颜色转换为{r,g,b,a}对象,用于颜色动画插值\\r\\n * @param hex 十六进制颜色值,如\\\"#FF0000\\\"\\r\\n * @returns 包含r,g,b,a属性的颜色对象\\r\\n */\\r\\nfunction hexToRgb(hex: string): any {\\r\\n // 使用正则表达式解析十六进制颜色,支持带#和不带#的格式\\r\\n const result = /^#?([a-f\\\\d]{2})([a-f\\\\d]{2})([a-f\\\\d]{2})$/i.exec(hex)\\r\\n if (result != null) {\\r\\n // 解析成功\\r\\n return {\\r\\n r: Number.parseInt(result[1] ?? '0', 16), // 红色分量,16进制转10进制\\r\\n g: Number.parseInt(result[2] ?? '0', 16), // 绿色分量\\r\\n b: Number.parseInt(result[3] ?? '0', 16), // 蓝色分量\\r\\n a: 1.0, // 透明度,默认不透明\\r\\n }\\r\\n }\\r\\n // 解析失败时返回黑色\\r\\n return {\\r\\n r: 0,\\r\\n g: 0,\\r\\n b: 0,\\r\\n a: 1.0,\\r\\n }\\r\\n}\\r\\n\\r\\n/**\\r\\n * 高性能动画引擎类\\r\\n * 支持多平台的流畅动画效果,提供丰富的缓动函数和动画控制\\r\\n */\\r\\nexport class AnimationEngine {\\r\\n /** 预定义缓动函数映射,存储常用的贝塞尔曲线参数 */\\r\\n private readonly easingPresets = new Map<string, number[]>([\\r\\n ['linear', [0.0, 0.0, 1.0, 1.0]], // 线性缓动\\r\\n ['ease', [0.25, 0.1, 0.25, 1.0]], // 默认缓动\\r\\n ['easeIn', [0.42, 0.0, 1.0, 1.0]], // 加速进入\\r\\n ['easeOut', [0.0, 0.0, 0.58, 1.0]], // 减速退出\\r\\n ['easeInOut', [0.42, 0.0, 0.58, 1.0]], // 先加速后减速\\r\\n ['easeInQuad', [0.55, 0.085, 0.68, 0.53]], // 二次方加速\\r\\n ['easeOutQuad', [0.25, 0.46, 0.45, 0.94]], // 二次方减速\\r\\n ['easeInOutQuad', [0.455, 0.03, 0.515, 0.955]], // 二次方先加速后减速\\r\\n ['easeInCubic', [0.55, 0.055, 0.675, 0.19]], // 三次方加速\\r\\n ['easeOutCubic', [0.215, 0.61, 0.355, 1.0]], // 三次方减速\\r\\n ['easeInOutCubic', [0.645, 0.045, 0.355, 1.0]], // 三次方先加速后减速\\r\\n ['easeInQuart', [0.895, 0.03, 0.685, 0.22]], // 四次方加速\\r\\n ['easeOutQuart', [0.165, 0.84, 0.44, 1.0]], // 四次方减速\\r\\n ['easeInOutQuart', [0.77, 0.0, 0.175, 1.0]], // 四次方先加速后减速\\r\\n ['easeInQuint', [0.755, 0.05, 0.855, 0.06]], // 五次方加速\\r\\n ['easeOutQuint', [0.23, 1.0, 0.32, 1.0]], // 五次方减速\\r\\n ['easeInOutQuint', [0.86, 0.0, 0.07, 1.0]], // 五次方先加速后减速\\r\\n ['easeInSine', [0.47, 0.0, 0.745, 0.715]], // 正弦加速\\r\\n ['easeOutSine', [0.39, 0.575, 0.565, 1.0]], // 正弦减速\\r\\n ['easeInOutSine', [0.445, 0.05, 0.55, 0.95]], // 正弦先加速后减速\\r\\n ['easeInExpo', [0.95, 0.05, 0.795, 0.035]], // 指数加速\\r\\n ['easeOutExpo', [0.19, 1.0, 0.22, 1.0]], // 指数减速\\r\\n ['easeInOutExpo', [1.0, 0.0, 0.0, 1.0]], // 指数先加速后减速\\r\\n ['easeInCirc', [0.6, 0.04, 0.98, 0.335]], // 圆形加速\\r\\n ['easeOutCirc', [0.075, 0.82, 0.165, 1.0]], // 圆形减速\\r\\n ['easeInOutBack', [0.68, -0.55, 0.265, 1.55]], // 回弹效果\\r\\n ])\\r\\n\\r\\n /** 目标DOM元素,动画作用的对象 */\\r\\n private targetElement: any | null = null\\r\\n\\r\\n /** 动画持续时间(毫秒),默认500ms */\\r\\n private animationDuration: number = 500\\r\\n\\r\\n /** 动画是否正在运行,用于控制动画循环 */\\r\\n private isRunning: boolean = false\\r\\n\\r\\n /** 动画是否暂停,暂停时保留当前进度 */\\r\\n private isPaused: boolean = false\\r\\n\\r\\n /** 当前动画进度 (0-1),用于恢复暂停的动画 */\\r\\n private currentProgress: number = 0\\r\\n\\r\\n /** 是否反向播放,影响动画方向 */\\r\\n private isReversed: boolean = false\\r\\n\\r\\n /** 是否往返播放模式,控制动画是否来回播放 */\\r\\n private isAlternate: boolean = false\\r\\n /** 往返播放时是否处于反向状态 */\\r\\n private isAlternateReversed: boolean = false\\r\\n\\r\\n /** 循环播放次数 (-1为无限循环) */\\r\\n private loopCount: number = 1\\r\\n /** 当前已完成的循环次数 */\\r\\n private currentLoop: number = 0\\r\\n\\r\\n /** 动画是否正在停止,用于提前终止动画 */\\r\\n private isStopping: boolean = true\\r\\n\\r\\n /** 当前执行的属性索引(顺序执行模式),用于控制属性依次动画 */\\r\\n private currentAttributeIndex: number = 0\\r\\n\\r\\n /** 回调函数,提供动画生命周期钩子 */\\r\\n private onComplete: () => void = () => { } // 动画完成回调\\r\\n private onStart: () => void = () => { } // 动画开始回调\\r\\n private onFrame: (progress: number) => void = () => { } // 每帧回调\\r\\n\\r\\n /** 动画属性列表,存储所有要动画的CSS属性 */\\r\\n private animationAttributes: AnimationAttribute[] = []\\r\\n\\r\\n /** 动画开始时间戳,用于计算动画进度 */\\r\\n private startTimestamp: number = 0\\r\\n\\r\\n /** 当前使用的缓动函数,将线性进度转换为缓动进度 */\\r\\n private currentEasingFunction: EasingFunction | null = null\\r\\n\\r\\n /** 是否按属性顺序依次执行动画,而非并行执行 */\\r\\n private isSequentialMode: boolean = false\\r\\n\\r\\n // 平台相关的动画控制器\\r\\n // Android平台使用Choreographer提供高性能动画\\r\\n // #ifdef APP-ANDROID\\r\\n private choreographer: Choreographer | null = null // Android系统帧同步器\\r\\n private frameCallback: FrameCallback | null = null // 帧回调处理器\\r\\n // #endif\\r\\n\\r\\n // iOS/小程序平台使用定时器\\r\\n // #ifdef APP-IOS\\r\\n private displayLinkTimer: number = 0 // iOS定时器ID\\r\\n // #endif\\r\\n\\r\\n // Web平台使用requestAnimationFrame\\r\\n private animationFrameId: number | null = null // 动画帧ID\\r\\n\\r\\n /**\\r\\n * 创建动画引擎实例\\r\\n * 初始化动画引擎,设置目标元素和动画配置\\r\\n * @param element 目标DOM元素,null时仅做计算不应用样式\\r\\n * @param options 动画配置选项,包含持续时间、缓动函数等\\r\\n */\\r\\n constructor(element: any | null, options: AnimationOptions) {\\r\\n this.targetElement = element // 保存目标元素引用\\r\\n\\r\\n // 设置动画参数,使用选项值或默认值\\r\\n this.animationDuration\\r\\n = options.duration != null ? options.duration : this.animationDuration // 设置动画持续时间\\r\\n this.loopCount = options.loop != null ? options.loop : this.loopCount // 设置循环次数\\r\\n this.isAlternate = options.alternate != null ? options.alternate : this.isAlternate // 设置往返播放\\r\\n this.isSequentialMode\\r\\n = options.sequential != null ? options.sequential : this.isSequentialMode // 设置顺序执行模式\\r\\n\\r\\n // 设置缓动函数,优先使用预定义函数\\r\\n if (options.timingFunction != null) {\\r\\n const easingParams = this.easingPresets.get(options.timingFunction) // 查找预定义缓动参数\\r\\n if (easingParams != null) {\\r\\n // 根据贝塞尔参数创建缓动函数\\r\\n this.currentEasingFunction = createBezierEasing(\\r\\n easingParams[0], // x1坐标\\r\\n easingParams[1], // y1坐标\\r\\n easingParams[2], // x2坐标\\r\\n easingParams[3], // y2坐标\\r\\n )\\r\\n }\\r\\n }\\r\\n\\r\\n // 自定义贝塞尔曲线,会覆盖预定义函数\\r\\n if (options.bezier != null && options.bezier.length == 4) {\\r\\n this.currentEasingFunction = createBezierEasing(\\r\\n options.bezier[0], // 自定义x1坐标\\r\\n options.bezier[1], // 自定义y1坐标\\r\\n options.bezier[2], // 自定义x2坐标\\r\\n options.bezier[3], // 自定义y2坐标\\r\\n )\\r\\n }\\r\\n\\r\\n // 设置回调函数,提供动画生命周期钩子\\r\\n if (options.complete != null) {\\r\\n this.onComplete = options.complete // 动画完成回调\\r\\n }\\r\\n if (options.start != null) {\\r\\n this.onStart = options.start // 动画开始回调\\r\\n }\\r\\n if (options.frame != null) {\\r\\n this.onFrame = options.frame // 每帧更新回调\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 从样式值中提取单位\\r\\n * 解析CSS值中的单位部分,用于动画计算\\r\\n * @param value 样式值,如 \\\"100px\\\", \\\"50%\\\"\\r\\n * @param propertyName CSS属性名称,用于判断是否需要默认单位\\r\\n * @returns 单位字符串\\r\\n */\\r\\n private extractUnit(value?: string, propertyName?: string): string {\\r\\n if (value == null) { return 'px' } // 默认单位为px\\r\\n const unit = value.replace(/[\\\\d|\\\\-+.]/g, '') // 移除数字、负号、正号、小数点,保留单位\\r\\n\\r\\n // opacity、z-index等属性无需单位\\r\\n if (propertyName == 'opacity' || propertyName == 'z-index') {\\r\\n return '' // 返回空字符串表示无单位\\r\\n }\\r\\n\\r\\n return unit == '' ? 'px' : unit // 如果没有单位则默认为px\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加自定义缓动函数\\r\\n * 向引擎注册新的缓动函数,可在后续动画中使用\\r\\n * @param name 缓动函数名称\\r\\n * @param bezierParams 贝塞尔曲线参数 [x1, y1, x2, y2]\\r\\n */\\r\\n addCustomEasing(name: string, bezierParams: number[]): AnimationEngine {\\r\\n if (bezierParams.length == 4) {\\r\\n // 验证参数数量\\r\\n this.easingPresets.set(name, bezierParams) // 添加到预设映射中\\r\\n }\\r\\n return this // 返回自身支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置动画反向播放\\r\\n * 控制动画从结束值向起始值播放\\r\\n * @param reverse 是否反向播放,null表示切换当前状态\\r\\n */\\r\\n setReverse(reverse: boolean | null = null): AnimationEngine {\\r\\n if (reverse != null) {\\r\\n this.isReversed = reverse // 设置指定状态\\r\\n }\\r\\n else {\\r\\n this.isReversed = !this.isReversed // 切换当前状态\\r\\n }\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置循环播放次数\\r\\n * 控制动画重复执行的次数\\r\\n * @param count 循环次数,-1表示无限循环\\r\\n */\\r\\n setLoopCount(count: number): AnimationEngine {\\r\\n this.loopCount = count // 设置循环次数\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置动画持续时间\\r\\n * 控制动画从开始到结束的总时长\\r\\n * @param duration 持续时间(毫秒)\\r\\n */\\r\\n setDuration(duration: number): AnimationEngine {\\r\\n this.animationDuration = duration // 设置动画持续时间\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置往返播放模式\\r\\n * 控制动画是否在每次循环时反向播放\\r\\n * @param alternate 是否往返播放\\r\\n */\\r\\n setAlternate(alternate: boolean): AnimationEngine {\\r\\n this.isAlternate = alternate // 设置往返播放标志\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置顺序执行模式\\r\\n * 控制多个属性是同时动画还是依次动画\\r\\n * @param sequential 是否按属性顺序依次执行\\r\\n */\\r\\n setSequential(sequential: boolean): AnimationEngine {\\r\\n this.isSequentialMode = sequential // 设置执行模式\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加动画属性\\r\\n * 向动画引擎添加一个CSS属性的动画配置\\r\\n * @param propertyName CSS属性名称\\r\\n * @param fromValue 起始值(支持数字+单位,如\\\"100px\\\"、\\\"50%\\\")\\r\\n * @param toValue 结束值(单位必须与起始值一致)\\r\\n * @param unique 是否唯一,true时同名属性会被替换\\r\\n */\\r\\n addAttribute(\\r\\n propertyName: string,\\r\\n fromValue: string,\\r\\n toValue: string,\\r\\n unique: boolean = true,\\r\\n ): AnimationEngine {\\r\\n const isColor = this.isColorProperty(propertyName) // 检测是否为颜色属性\\r\\n const unit = isColor ? '' : this.extractUnit(fromValue, propertyName) // 提取单位\\r\\n\\r\\n // 根据属性类型处理值\\r\\n const processedFromValue = isColor\\r\\n ? getDefaultColor(fromValue) // 颜色属性标准化\\r\\n : Number.parseFloat(fromValue).toString() // 数值属性提取数字\\r\\n const processedToValue = isColor\\r\\n ? getDefaultColor(toValue) // 颜色属性标准化\\r\\n : Number.parseFloat(toValue).toString() // 数值属性提取数字\\r\\n\\r\\n // 查找是否已存在同名属性,用于决定是替换还是新增\\r\\n let existingIndex = this.animationAttributes.findIndex(\\r\\n (attr: AnimationAttribute): boolean => attr.propertyName == propertyName,\\r\\n )\\r\\n\\r\\n if (!unique) {\\r\\n existingIndex = -1 // 强制添加新属性,不替换\\r\\n }\\r\\n\\r\\n // 创建新的动画属性对象\\r\\n const newAttribute: AnimationAttribute = {\\r\\n fromValue: processedFromValue, // 处理后的起始值\\r\\n toValue: processedToValue, // 处理后的结束值\\r\\n unit, // 单位\\r\\n progress: 0, // 初始进度为0\\r\\n currentValue: processedFromValue, // 当前值初始化为起始值\\r\\n propertyName, // 属性名称\\r\\n }\\r\\n\\r\\n if (existingIndex == -1) {\\r\\n this.animationAttributes.push(newAttribute) // 添加新属性\\r\\n }\\r\\n else {\\r\\n this.animationAttributes[existingIndex] = newAttribute // 替换现有属性\\r\\n }\\r\\n\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加变换属性\\r\\n */\\r\\n transform(property: string, fromValue: string, toValue: string): AnimationEngine {\\r\\n return this.addAttribute(property, fromValue, toValue)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加位移动画\\r\\n */\\r\\n translate(fromX: string, fromY: string, toX: string, toY: string): AnimationEngine {\\r\\n this.addAttribute('translateX', fromX, toX)\\r\\n this.addAttribute('translateY', fromY, toY)\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加X轴位移动画\\r\\n * @param fromX 起始X位置,可以使用\\\"current\\\"表示当前位置\\r\\n * @param toX 结束X位置\\r\\n * @returns\\r\\n */\\r\\n translateX(fromX: string, toX: string): AnimationEngine {\\r\\n return this.addAttribute('translateX', fromX, toX)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加Y轴位移动画\\r\\n * @param fromY 起始Y位置,可以使用\\\"current\\\"表示当前位置\\r\\n * @param toY 结束Y位置\\r\\n * @returns\\r\\n */\\r\\n translateY(fromY: string, toY: string): AnimationEngine {\\r\\n return this.addAttribute('translateY', fromY, toY)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加缩放动画\\r\\n */\\r\\n scale(fromScale: string, toScale: string): AnimationEngine {\\r\\n return this.addAttribute('scale', fromScale, toScale)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加旋转动画\\r\\n */\\r\\n rotate(fromDegree: string, toDegree: string): AnimationEngine {\\r\\n return this.addAttribute('rotate', fromDegree, toDegree)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加透明度动画\\r\\n */\\r\\n opacity(fromOpacity: string, toOpacity: string): AnimationEngine {\\r\\n return this.addAttribute('opacity', fromOpacity, toOpacity)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 线性插值计算\\r\\n * 根据进度在两个数值之间进行插值,用于计算动画中间值\\r\\n * @param startValue 起始值\\r\\n * @param endValue 结束值\\r\\n * @param progress 进度 (0-1)\\r\\n */\\r\\n private interpolateValue(startValue: number, endValue: number, progress: number): number {\\r\\n return startValue + (endValue - startValue) * progress // 线性插值公式:start + (end - start) * progress\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否为颜色相关属性\\r\\n * 检测CSS属性名是否与颜色相关,用于特殊的颜色动画处理\\r\\n * @param propertyName 属性名称\\r\\n */\\r\\n private isColorProperty(propertyName: string): boolean {\\r\\n return (\\r\\n propertyName.includes('background') // 背景颜色相关\\r\\n || propertyName.includes('color') // 文字颜色相关\\r\\n || propertyName.includes('border-color') // 边框颜色相关\\r\\n || propertyName.includes('shadow') // 阴影颜色相关\\r\\n )\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否为Transform相关属性\\r\\n * 检测属性名是否为transform相关的CSS属性\\r\\n * @param propertyName CSS属性名称\\r\\n * @returns 是否为transform属性\\r\\n */\\r\\n private isTransformProperty(propertyName: string): boolean {\\r\\n return (\\r\\n propertyName == 'scaleX' // X轴缩放\\r\\n || propertyName == 'scaleY' // Y轴缩放\\r\\n || propertyName == 'scale' // 等比缩放\\r\\n || propertyName == 'rotateX' // X轴旋转\\r\\n || propertyName == 'rotateY' // Y轴旋转\\r\\n || propertyName == 'rotate' // Z轴旋转\\r\\n || propertyName == 'translateX' // X轴位移\\r\\n || propertyName == 'translateY' // Y轴位移\\r\\n || propertyName == 'translate' // 双轴位移\\r\\n )\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置元素样式属性\\r\\n * 根据属性类型应用相应的样式值,支持transform、颜色、普通数值属性\\r\\n * @param propertyName 属性名称\\r\\n * @param currentValue 当前值\\r\\n * @param unit 单位\\r\\n * @param progress 动画进度\\r\\n * @param attribute 动画属性对象\\r\\n */\\r\\n private setElementProperty(\\r\\n propertyName: string,\\r\\n currentValue: number,\\r\\n unit: string,\\r\\n progress: number,\\r\\n attribute: AnimationAttribute,\\r\\n ): void {\\r\\n if (this.targetElement == null) { return } // 没有目标元素时直接返回\\r\\n\\r\\n const element = this.targetElement // 获取目标元素引用\\r\\n const valueStr = currentValue.toFixed(2) // 数值保留两位小数\\r\\n\\r\\n // #ifdef MP\\r\\n if (element.style == null) {\\r\\n return\\r\\n }\\r\\n // #endif\\r\\n\\r\\n // Transform 相关属性处理,使用CSS transform属性\\r\\n switch (propertyName) {\\r\\n case 'scaleX': // X轴缩放\\r\\n element.style!.setProperty('transform', `scaleX(${currentValue})`)\\r\\n break\\r\\n case 'scaleY': // Y轴缩放\\r\\n element.style!.setProperty('transform', `scaleY(${currentValue})`)\\r\\n break\\r\\n case 'scale': // 等比缩放\\r\\n element.style!.setProperty('transform', `scale(${currentValue})`)\\r\\n break\\r\\n case 'rotateX': // X轴旋转\\r\\n element.style!.setProperty('transform', `rotateX(${valueStr + unit})`)\\r\\n break\\r\\n case 'rotateY': // Y轴旋转\\r\\n element.style!.setProperty('transform', `rotateY(${valueStr + unit})`)\\r\\n break\\r\\n case 'rotate': // Z轴旋转\\r\\n element.style!.setProperty('transform', `rotate(${valueStr + unit})`)\\r\\n break\\r\\n case 'translateX': // X轴位移\\r\\n element.style!.setProperty('transform', `translateX(${valueStr + unit})`)\\r\\n break\\r\\n case 'translateY': // Y轴位移\\r\\n element.style!.setProperty('transform', `translateY(${valueStr + unit})`)\\r\\n break\\r\\n case 'translate': // 双轴位移\\r\\n element.style!.setProperty(\\r\\n 'transform',\\r\\n `translate(${valueStr + unit},${valueStr + unit})`,\\r\\n )\\r\\n break\\r\\n default:\\r\\n // 颜色属性处理,需要进行RGBA插值\\r\\n if (this.isColorProperty(propertyName)) {\\r\\n const startColor = hexToRgb(attribute.fromValue) // 解析起始颜色\\r\\n const endColor = hexToRgb(attribute.toValue) // 解析结束颜色\\r\\n\\r\\n // 提取起始颜色的RGBA分量,兼容不同的JSON对象访问方式\\r\\n const startR\\r\\n = startColor.getNumber != null\\r\\n ? startColor.getNumber('r')\\r\\n : (startColor.r as number)\\r\\n const startG\\r\\n = startColor.getNumber != null\\r\\n ? startColor.getNumber('g')\\r\\n : (startColor.g as number)\\r\\n const startB\\r\\n = startColor.getNumber != null\\r\\n ? startColor.getNumber('b')\\r\\n : (startColor.b as number)\\r\\n const startA\\r\\n = startColor.getNumber != null\\r\\n ? startColor.getNumber('a')\\r\\n : (startColor.a as number)\\r\\n\\r\\n // 提取结束颜色的RGBA分量\\r\\n const endR\\r\\n = endColor.getNumber != null\\r\\n ? endColor.getNumber('r')\\r\\n : (endColor.r as number)\\r\\n const endG\\r\\n = endColor.getNumber != null\\r\\n ? endColor.getNumber('g')\\r\\n : (endColor.g as number)\\r\\n const endB\\r\\n = endColor.getNumber != null\\r\\n ? endColor.getNumber('b')\\r\\n : (endColor.b as number)\\r\\n const endA\\r\\n = endColor.getNumber != null\\r\\n ? endColor.getNumber('a')\\r\\n : (endColor.a as number)\\r\\n\\r\\n // 对每个颜色分量进行插值计算\\r\\n const r = this.interpolateValue(\\r\\n startR != null ? startR : 0,\\r\\n endR != null ? endR : 0,\\r\\n progress,\\r\\n )\\r\\n const g = this.interpolateValue(\\r\\n startG != null ? startG : 0,\\r\\n endG != null ? endG : 0,\\r\\n progress,\\r\\n )\\r\\n const b = this.interpolateValue(\\r\\n startB != null ? startB : 0,\\r\\n endB != null ? endB : 0,\\r\\n progress,\\r\\n )\\r\\n const a = this.interpolateValue(\\r\\n startA != null ? startA : 1,\\r\\n endA != null ? endA : 1,\\r\\n progress,\\r\\n )\\r\\n\\r\\n // 设置RGBA颜色值\\r\\n element.style!.setProperty(\\r\\n propertyName,\\r\\n `rgba(${r.toFixed(0)},${g.toFixed(0)},${b.toFixed(0)},${a.toFixed(1)})`,\\r\\n )\\r\\n }\\r\\n else {\\r\\n // 普通数值属性处理,直接设置数值和单位\\r\\n element.style!.setProperty(propertyName, valueStr + unit)\\r\\n }\\r\\n break\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * Web平台动画运行方法 (H5/iOS/Harmony)\\r\\n * 使用requestAnimationFrame实现流畅的动画循环\\r\\n */\\r\\n private runWebAnimation(): void {\\r\\n // #ifdef H5 || APP-IOS || APP-HARMONY\\r\\n const self = this // 保存this引用,避免在内部函数中this指向改变\\r\\n self.startTimestamp = 0 // 重置开始时间戳\\r\\n\\r\\n // 取消之前的动画帧,避免重复执行\\r\\n if (self.animationFrameId != null) {\\r\\n cancelAnimationFrame(self.animationFrameId)\\r\\n }\\r\\n\\r\\n function animationLoop(): void {\\r\\n // 初始化开始时间,首次执行时记录时间戳\\r\\n if (self.startTimestamp <= 0) {\\r\\n self.startTimestamp = Date.now()\\r\\n }\\r\\n\\r\\n // 计算当前进度:(已用时间 / 总时间) + 暂停前的进度\\r\\n const elapsed = Date.now() - self.startTimestamp // 已经过的时间\\r\\n const progress = Math.min(elapsed / self.animationDuration + self.currentProgress, 1.0) // 限制进度不超过1\\r\\n\\r\\n // 执行动画更新,应用当前进度到所有属性\\r\\n self.updateAnimationFrame(progress)\\r\\n\\r\\n // 检查暂停状态\\r\\n if (self.isPaused) {\\r\\n self.isRunning = false // 停止运行标志\\r\\n self.currentProgress = progress // 保存当前进度,用于恢复\\r\\n console.log('动画已暂停')\\r\\n return // 退出动画循环\\r\\n }\\r\\n\\r\\n // 检查动画完成或停止\\r\\n if (progress >= 1.0 || self.isStopping) {\\r\\n self.handleAnimationComplete() // 处理动画完成逻辑\\r\\n return // 退出动画循环\\r\\n }\\r\\n\\r\\n // 继续下一帧,动画未完成且仍在运行\\r\\n if (progress < 1.0 && self.isRunning) {\\r\\n self.onFrame(progress) // 触发每帧回调\\r\\n self.animationFrameId = requestAnimationFrame(animationLoop) // 请求下一帧\\r\\n }\\r\\n }\\r\\n\\r\\n // 开始动画,触发开始回调并启动动画循环\\r\\n self.onStart()\\r\\n animationLoop()\\r\\n // #endif\\r\\n }\\r\\n\\r\\n /**\\r\\n * 更新动画帧\\r\\n * 根据执行模式更新所有或当前属性的动画值\\r\\n * @param progress 当前进度 (0-1)\\r\\n */\\r\\n private updateAnimationFrame(progress: number): void {\\r\\n if (this.targetElement == null) { return } // 没有目标元素时直接返回\\r\\n\\r\\n if (!this.isSequentialMode) {\\r\\n // 并行执行所有属性动画,所有属性同时进行动画\\r\\n for (let i = 0; i < this.animationAttributes.length; i++) {\\r\\n this.updateSingleAttribute(this.animationAttributes[i], progress)\\r\\n }\\r\\n }\\r\\n else {\\r\\n // 顺序执行属性动画,一个接一个地执行属性动画\\r\\n if (this.currentAttributeIndex < this.animationAttributes.length) {\\r\\n this.updateSingleAttribute(\\r\\n this.animationAttributes[this.currentAttributeIndex],\\r\\n progress,\\r\\n )\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 更新单个属性的动画\\r\\n * 计算属性的当前值并应用到元素上\\r\\n * @param attribute 动画属性\\r\\n * @param progress 进度\\r\\n */\\r\\n private updateSingleAttribute(attribute: AnimationAttribute, progress: number): void {\\r\\n attribute.progress = progress // 更新属性的进度记录\\r\\n\\r\\n if (!this.isColorProperty(attribute.propertyName)) {\\r\\n // 数值属性处理\\r\\n const fromValue = Number.parseFloat(attribute.fromValue) // 起始数值\\r\\n const toValue = Number.parseFloat(attribute.toValue) // 结束数值\\r\\n\\r\\n // 应用缓动函数,将线性进度转换为缓动进度\\r\\n let easedProgress = progress\\r\\n if (this.currentEasingFunction != null) {\\r\\n easedProgress = this.currentEasingFunction(progress)\\r\\n }\\r\\n\\r\\n // 计算当前值,使用缓动进度进行插值\\r\\n let currentValue = this.interpolateValue(fromValue, toValue, easedProgress)\\r\\n\\r\\n // 处理反向和往返播放,交换起始和结束值\\r\\n if (this.isReversed || this.isAlternateReversed) {\\r\\n currentValue = this.interpolateValue(toValue, fromValue, easedProgress)\\r\\n }\\r\\n\\r\\n // 应用计算出的值到元素属性\\r\\n this.setElementProperty(\\r\\n attribute.propertyName,\\r\\n currentValue,\\r\\n attribute.unit,\\r\\n progress,\\r\\n attribute,\\r\\n )\\r\\n }\\r\\n else {\\r\\n // 颜色属性处理,progress参数会在setElementProperty中用于颜色插值\\r\\n this.setElementProperty(attribute.propertyName, 0, attribute.unit, progress, attribute)\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 处理动画完成\\r\\n */\\r\\n private handleAnimationComplete(): void {\\r\\n // 顺序模式下检查是否还有未执行的属性\\r\\n if (\\r\\n this.isSequentialMode\\r\\n && this.currentAttributeIndex < this.animationAttributes.length - 1\\r\\n ) {\\r\\n this.currentAttributeIndex++\\r\\n this.currentProgress = 0\\r\\n this.restartAnimation()\\r\\n return\\r\\n }\\r\\n\\r\\n // 重置状态\\r\\n // #ifdef H5 || APP-IOS || APP-HARMONY\\r\\n if (this.animationFrameId != null) {\\r\\n cancelAnimationFrame(this.animationFrameId)\\r\\n }\\r\\n // #endif\\r\\n\\r\\n this.currentAttributeIndex = 0\\r\\n this.currentProgress = 0\\r\\n\\r\\n // 处理往返播放\\r\\n if (this.isAlternate) {\\r\\n this.isAlternateReversed = !this.isAlternateReversed\\r\\n }\\r\\n\\r\\n // 处理循环播放\\r\\n if (this.loopCount == -1) {\\r\\n // 无限循环\\r\\n this.restartAnimation()\\r\\n return\\r\\n }\\r\\n else {\\r\\n this.currentLoop++\\r\\n if (this.currentLoop < this.loopCount) {\\r\\n this.restartAnimation()\\r\\n return\\r\\n }\\r\\n }\\r\\n\\r\\n // 动画完成\\r\\n this.isRunning = false\\r\\n this.onComplete()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 根据平台重新启动动画\\r\\n */\\r\\n private restartAnimation(): void {\\r\\n // 重置开始时间戳,确保循环动画正确计时\\r\\n this.startTimestamp = 0\\r\\n\\r\\n // 根据平台选择合适的动画引擎\\r\\n // #ifdef H5 || APP-IOS || APP-HARMONY\\r\\n this.runWebAnimation()\\r\\n // #endif\\r\\n // #ifdef APP-ANDROID\\r\\n this.runAndroidAnimation()\\r\\n // #endif\\r\\n // #ifdef MP\\r\\n this.runMPAnimation()\\r\\n // #endif\\r\\n }\\r\\n\\r\\n /**\\r\\n * Android平台动画运行方法\\r\\n */\\r\\n private runAndroidAnimation(): void {\\r\\n // #ifdef APP-ANDROID\\r\\n const self = this\\r\\n self.startTimestamp = 0\\r\\n\\r\\n // 初始化Choreographer\\r\\n if (self.choreographer == null) {\\r\\n self.choreographer = Choreographer.getInstance()\\r\\n }\\r\\n else {\\r\\n // 清除之前的回调\\r\\n if (self.frameCallback != null) {\\r\\n self.choreographer.removeFrameCallback(self.frameCallback)\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * Android原生帧回调类\\r\\n */\\r\\n class frameCallback extends Choreographer.FrameCallback {\\r\\n // @ts-ignore\\r\\n override doFrame(frameTimeNanos: Long) {\\r\\n // 检查动画是否应该停止\\r\\n if (!self.isRunning || self.isStopping) {\\r\\n return\\r\\n }\\r\\n\\r\\n // 初始化开始时间\\r\\n if (self.startTimestamp <= 0) {\\r\\n self.startTimestamp = Date.now()\\r\\n }\\r\\n\\r\\n // 计算当前进度\\r\\n const elapsed = Date.now() - self.startTimestamp\\r\\n const progress = Math.min(\\r\\n elapsed / self.animationDuration + self.currentProgress,\\r\\n 1.0,\\r\\n )\\r\\n\\r\\n // 执行动画更新\\r\\n self.updateAnimationFrame(progress)\\r\\n\\r\\n // 检查暂停状态\\r\\n if (self.isPaused) {\\r\\n self.isRunning = false\\r\\n self.currentProgress = progress\\r\\n return\\r\\n }\\r\\n\\r\\n // 检查动画完成或停止\\r\\n if (progress >= 1.0 || self.isStopping) {\\r\\n self.handleAnimationComplete()\\r\\n return\\r\\n }\\r\\n\\r\\n // 继续下一帧\\r\\n if (progress < 1.0 && self.isRunning && !self.isStopping) {\\r\\n self.onFrame(progress)\\r\\n if (self.choreographer != null) {\\r\\n self.choreographer.postFrameCallback(this)\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // 启动动画\\r\\n self.onStart()\\r\\n self.frameCallback = new frameCallback()\\r\\n self.choreographer!.postFrameCallback(self.frameCallback)\\r\\n // #endif\\r\\n }\\r\\n\\r\\n /**\\r\\n * 小程序平台动画运行方法\\r\\n */\\r\\n private runMPAnimation(): void {\\r\\n // #ifdef MP\\r\\n const self = this\\r\\n self.startTimestamp = 0\\r\\n\\r\\n // 清除之前的定时器\\r\\n if (self.displayLinkTimer != 0) {\\r\\n clearTimeout(self.displayLinkTimer)\\r\\n }\\r\\n\\r\\n function animationLoop(): void {\\r\\n // 初始化开始时间\\r\\n if (self.startTimestamp <= 0) {\\r\\n self.startTimestamp = Date.now()\\r\\n }\\r\\n\\r\\n // 计算当前进度\\r\\n const elapsed = Date.now() - self.startTimestamp\\r\\n const progress = Math.min(elapsed / self.animationDuration + self.currentProgress, 1.0)\\r\\n\\r\\n // 执行动画更新\\r\\n self.updateAnimationFrame(progress)\\r\\n\\r\\n // 检查暂停状态\\r\\n if (self.isPaused) {\\r\\n self.isRunning = false\\r\\n self.currentProgress = progress\\r\\n return\\r\\n }\\r\\n\\r\\n // 检查动画完成或停止\\r\\n if (progress >= 1.0 || self.isStopping) {\\r\\n self.handleAnimationComplete()\\r\\n return\\r\\n }\\r\\n\\r\\n // 继续下一帧\\r\\n if (progress < 1.0 && self.isRunning) {\\r\\n self.onFrame(progress)\\r\\n self.displayLinkTimer = setTimeout(animationLoop, 16) as any // 约60fps\\r\\n }\\r\\n }\\r\\n\\r\\n // 开始动画\\r\\n self.onStart()\\r\\n animationLoop()\\r\\n // #endif\\r\\n }\\r\\n\\r\\n /**\\r\\n * 开始播放动画\\r\\n */\\r\\n play(): AnimationEngine {\\r\\n if (this.isRunning) { return this }\\r\\n\\r\\n // 初始化动画状态\\r\\n this.isRunning = true\\r\\n this.isStopping = false\\r\\n this.isPaused = false\\r\\n this.currentLoop = 0\\r\\n this.currentAttributeIndex = 0\\r\\n\\r\\n // 根据平台选择合适的动画引擎\\r\\n // #ifdef H5 || APP-IOS || APP-HARMONY\\r\\n this.runWebAnimation()\\r\\n // #endif\\r\\n // #ifdef APP-ANDROID\\r\\n this.runAndroidAnimation()\\r\\n // #endif\\r\\n // #ifdef MP\\r\\n this.runMPAnimation()\\r\\n // #endif\\r\\n\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 异步播放动画,支持await\\r\\n * @returns Promise,动画完成时resolve\\r\\n */\\r\\n playAsync(): Promise<void> {\\r\\n return new Promise<void>((resolve) => {\\r\\n const originalComplete = this.onComplete\\r\\n this.onComplete = () => {\\r\\n originalComplete()\\r\\n resolve()\\r\\n }\\r\\n this.play()\\r\\n })\\r\\n }\\r\\n\\r\\n /**\\r\\n * 停止动画\\r\\n * 会立即停止动画并跳转到结束状态\\r\\n */\\r\\n stop(): AnimationEngine {\\r\\n this.isStopping = true\\r\\n this.currentProgress = 0\\r\\n this.currentAttributeIndex = this.animationAttributes.length\\r\\n\\r\\n // 清理平台相关的动画控制器\\r\\n // #ifdef WEB || APP-IOS || APP-HARMONY\\r\\n if (this.animationFrameId != null) {\\r\\n cancelAnimationFrame(this.animationFrameId)\\r\\n this.animationFrameId = null\\r\\n }\\r\\n // #endif\\r\\n\\r\\n // #ifdef APP-ANDROID\\r\\n if (this.choreographer != null && this.frameCallback != null) {\\r\\n this.choreographer.removeFrameCallback(this.frameCallback)\\r\\n }\\r\\n // #endif\\r\\n\\r\\n // #ifdef MP\\r\\n if (this.displayLinkTimer != 0) {\\r\\n clearTimeout(this.displayLinkTimer)\\r\\n this.displayLinkTimer = 0\\r\\n }\\r\\n // #endif\\r\\n\\r\\n this.isRunning = false\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 暂停动画\\r\\n * 保留当前状态,可以通过play()恢复\\r\\n */\\r\\n pause(): AnimationEngine {\\r\\n this.isPaused = true\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 恢复暂停的动画\\r\\n */\\r\\n resume(): AnimationEngine {\\r\\n if (this.isPaused) {\\r\\n this.isPaused = false\\r\\n this.play()\\r\\n }\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 清空应用到元素上的动画样式\\r\\n * 只清空实际被动画引擎设置过的CSS属性\\r\\n */\\r\\n private clearElementStyles(): void {\\r\\n if (this.targetElement == null) { return }\\r\\n\\r\\n const element = this.targetElement\\r\\n\\r\\n // 清空所有动画属性列表中记录的属性\\r\\n for (const attr of this.animationAttributes) {\\r\\n const propertyName = attr.propertyName\\r\\n\\r\\n // Transform 相关属性需要清空transform\\r\\n if (this.isTransformProperty(propertyName)) {\\r\\n element.style!.setProperty('transform', '')\\r\\n }\\r\\n else {\\r\\n // 其他属性直接清空\\r\\n element.style!.setProperty(propertyName, '')\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 重置动画到初始状态,清空所有内容\\r\\n */\\r\\n reset(): AnimationEngine {\\r\\n // 停止当前动画\\r\\n this.stop()\\r\\n\\r\\n // 清空应用到元素上的所有样式\\r\\n this.clearElementStyles()\\r\\n\\r\\n // 重置所有动画状态\\r\\n this.currentProgress = 0\\r\\n this.currentLoop = 0\\r\\n this.currentAttributeIndex = 0\\r\\n this.isAlternateReversed = false\\r\\n this.isReversed = false\\r\\n this.isPaused = false\\r\\n this.isStopping = true\\r\\n this.startTimestamp = 0\\r\\n\\r\\n // 清空动画属性列表\\r\\n this.animationAttributes = []\\r\\n\\r\\n // 重置缓动函数\\r\\n this.currentEasingFunction = null\\r\\n\\r\\n // 重置回调函数\\r\\n this.onComplete = () => { }\\r\\n this.onStart = () => { }\\r\\n this.onFrame = () => { }\\r\\n\\r\\n // 清理平台相关的动画控制器\\r\\n // #ifdef WEB || APP-IOS || APP-HARMONY\\r\\n if (this.animationFrameId != null) {\\r\\n cancelAnimationFrame(this.animationFrameId)\\r\\n this.animationFrameId = null\\r\\n }\\r\\n // #endif\\r\\n\\r\\n // #ifdef APP-ANDROID\\r\\n if (this.choreographer != null && this.frameCallback != null) {\\r\\n this.choreographer.removeFrameCallback(this.frameCallback)\\r\\n this.frameCallback = null\\r\\n }\\r\\n this.choreographer = null\\r\\n // #endif\\r\\n\\r\\n // #ifdef MP\\r\\n if (this.displayLinkTimer != 0) {\\r\\n clearTimeout(this.displayLinkTimer)\\r\\n this.displayLinkTimer = 0\\r\\n }\\r\\n // #endif\\r\\n\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取当前动画进度\\r\\n */\\r\\n getProgress(): number {\\r\\n return this.currentProgress\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取动画是否正在运行\\r\\n */\\r\\n isAnimating(): boolean {\\r\\n return this.isRunning\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取当前循环次数\\r\\n */\\r\\n getCurrentLoop(): number {\\r\\n return this.currentLoop\\r\\n }\\r\\n\\r\\n /**\\r\\n * 清除所有动画属性\\r\\n */\\r\\n clearAttributes(): AnimationEngine {\\r\\n this.animationAttributes = []\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取动画属性数量\\r\\n */\\r\\n getAttributeCount(): number {\\r\\n return this.animationAttributes.length\\r\\n }\\r\\n\\r\\n /**\\r\\n * 淡入动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n fadeIn(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 淡出动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n fadeOut(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑入动画(从左)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideInLeft(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).translateX('-100%', '0%').opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑入动画(从右)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideInRight(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).translateX('100%', '0%').opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑入动画(从上)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideInUp(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateY', '-100%', '0%')\\r\\n .opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑入动画(从下)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideInDown(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateY', '100%', '0%')\\r\\n .opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 缩放动画(放大)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n zoomIn(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).scale('0', '1').opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 缩放动画(缩小)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n zoomOut(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).scale('1', '0').opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 旋转动画\\r\\n * @param duration 持续时间\\r\\n * @param degrees 旋转角度\\r\\n */\\r\\n rotateIn(duration: number = 500, degrees: number = 360): AnimationEngine {\\r\\n return this.setDuration(duration).rotate('0deg', `${degrees}deg`).opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 旋转退出动画\\r\\n * @param duration 持续时间\\r\\n * @param degrees 旋转角度\\r\\n */\\r\\n rotateOut(duration: number = 500, degrees: number = 360): AnimationEngine {\\r\\n return this.setDuration(duration).rotate('0deg', `${degrees}deg`).opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 弹跳动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n bounce(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addCustomEasing('bounce', [0.68, -0.55, 0.265, 1.55])\\r\\n .scale('1', '1.1')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(2)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 摇摆动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n shake(duration: number = 500): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateX', '0px', '10px')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(6)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 链式动画:支持多个动画依次执行\\r\\n * @param animations 动画配置函数数组\\r\\n */\\r\\n sequence(animations: ((engine: AnimationEngine) => AnimationEngine)[]): AnimationEngine {\\r\\n const self = this\\r\\n\\r\\n if (animations.length == 0) {\\r\\n return this\\r\\n }\\r\\n\\r\\n // 执行第一个动画\\r\\n const firstEngine = animations[0](new AnimationEngine(this.targetElement, {}))\\r\\n\\r\\n // 如果只有一个动画,直接返回\\r\\n if (animations.length == 1) {\\r\\n return firstEngine\\r\\n }\\r\\n\\r\\n // 递归设置后续动画\\r\\n function setNextAnimation(\\r\\n currentEngine: AnimationEngine,\\r\\n remainingAnimations: ((engine: AnimationEngine) => AnimationEngine)[],\\r\\n ): void {\\r\\n if (remainingAnimations.length == 0) {\\r\\n return\\r\\n }\\r\\n\\r\\n const originalComplete = currentEngine.onComplete\\r\\n currentEngine.onComplete = () => {\\r\\n originalComplete()\\r\\n\\r\\n // 执行下一个动画\\r\\n const nextEngine = remainingAnimations[0](\\r\\n new AnimationEngine(self.targetElement, {}),\\r\\n )\\r\\n\\r\\n // 如果还有更多动画,继续设置链式\\r\\n if (remainingAnimations.length > 1) {\\r\\n setNextAnimation(nextEngine, remainingAnimations.slice(1))\\r\\n }\\r\\n\\r\\n nextEngine.play()\\r\\n }\\r\\n }\\r\\n\\r\\n // 设置动画链\\r\\n setNextAnimation(firstEngine, animations.slice(1))\\r\\n\\r\\n return firstEngine\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑出动画(向左)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideOutLeft(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).translateX('0%', '-100%').opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑出动画(向右)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideOutRight(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).translateX('0%', '100%').opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑出动画(向上)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideOutUp(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateY', '0%', '-100%')\\r\\n .opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑出动画(向下)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideOutDown(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateY', '0%', '100%')\\r\\n .opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 翻转动画(水平)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n flipX(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('rotateX', '0deg', '180deg')\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 翻转动画(垂直)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n flipY(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('rotateY', '0deg', '180deg')\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 弹性进入动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n elasticIn(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('0', '1')\\r\\n .opacity('0', '1')\\r\\n .addCustomEasing('elastic', [0.175, 0.885, 0.32, 1.275])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 弹性退出动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n elasticOut(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('1', '0')\\r\\n .opacity('1', '0')\\r\\n .addCustomEasing('elastic', [0.68, -0.55, 0.265, 1.55])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 回弹动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n rubberBand(duration: number = 1000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('scaleX', '1', '1.25')\\r\\n .addAttribute('scaleY', '1', '0.75')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(2)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 摆动动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n swing(duration: number = 1000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('rotate', '0deg', '15deg')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(4)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 抖动动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n wobble(duration: number = 1000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateX', '0px', '25px')\\r\\n .addAttribute('rotate', '0deg', '5deg')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(4)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滚动进入动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n rollIn(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .translateX('-100%', '0%')\\r\\n .rotate('-120deg', '0deg')\\r\\n .opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滚动退出动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n rollOut(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .translateX('0%', '100%')\\r\\n .rotate('0deg', '120deg')\\r\\n .opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 灯光效果动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n lightSpeed(duration: number = 500): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .translateX('-100%', '0%')\\r\\n .addAttribute('skewX', '-30deg', '0deg')\\r\\n .opacity('0', '1')\\r\\n .addCustomEasing('ease-out', [0.25, 0.46, 0.45, 0.94])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 浮动动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n float(duration: number = 3000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .translateY('0px', '-10px')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(-1)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 呼吸动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n breathe(duration: number = 2000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('1', '1.1')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(-1)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 发光动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n glow(duration: number = 1500): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute(\\r\\n 'boxShadow',\\r\\n '0 0 5px rgba(255,255,255,0.5)',\\r\\n '0 0 20px rgba(255,255,255,1)',\\r\\n )\\r\\n .setAlternate(true)\\r\\n .setLoopCount(-1)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 进度条动画\\r\\n * @param duration 持续时间\\r\\n * @param progress 进度百分比 (0-100)\\r\\n */\\r\\n progressBar(duration: number = 1000, progress: number = 100): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('width', '0%', `${progress}%`)\\r\\n .addCustomEasing('ease-out', [0.25, 0.46, 0.45, 0.94])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 模态框进入动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n modalIn(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('0.7', '1')\\r\\n .opacity('0', '1')\\r\\n .addCustomEasing('ease-out', [0.25, 0.46, 0.45, 0.94])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 模态框退出动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n modalOut(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('1', '0.7')\\r\\n .opacity('1', '0')\\r\\n .addCustomEasing('ease-in', [0.42, 0.0, 1.0, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 卡片翻转动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n cardFlip(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('rotateY', '0deg', '180deg')\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 波纹扩散动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n ripple(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('0', '4')\\r\\n .opacity('0.7', '0')\\r\\n .addCustomEasing('ease-out', [0.25, 0.46, 0.45, 0.94])\\r\\n }\\r\\n}\\r\\n\\r\\n/**\\r\\n * 创建动画实例\\r\\n * @param element 目标元素\\r\\n * @param options 动画选项\\r\\n */\\r\\nexport function createAnimation(\\r\\n element: any | null,\\r\\n options: AnimationOptions = {},\\r\\n): AnimationEngine {\\r\\n return new AnimationEngine(element, options)\\r\\n}\\r\\n\",\n \"lib/base64.ts\": \"const _b64chars: string[] = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/']\\r\\nconst _mkUriSafe = (src: string): string => src.replace(/[+/]/g, (m0: string) => (m0 === '+' ? '-' : '_')).replace(/=+\\\\$/m, '')\\r\\nconst fromUint8Array = (src: Uint8Array, rfc4648 = false): string => {\\r\\n let b64 = ''\\r\\n for (let i = 0, l = src.length; i < l; i += 3) {\\r\\n const [a0, a1, a2] = [src[i], src[i + 1], src[i + 2]]\\r\\n const ord = (a0 << 16) | (a1 << 8) | a2\\r\\n b64 += _b64chars[ord >>> 18]\\r\\n b64 += _b64chars[(ord >>> 12) & 63]\\r\\n b64 += typeof a1 !== 'undefined' ? _b64chars[(ord >>> 6) & 63] : '='\\r\\n b64 += typeof a2 !== 'undefined' ? _b64chars[ord & 63] : '='\\r\\n }\\r\\n return rfc4648 ? _mkUriSafe(b64) : b64\\r\\n}\\r\\nconst _btoa: (s: string) => string =\\r\\n typeof btoa === 'function'\\r\\n ? (s: string) => btoa(s)\\r\\n : (s: string) => {\\r\\n if (s.charCodeAt(0) > 255) {\\r\\n throw new RangeError('The string contains invalid characters.')\\r\\n }\\r\\n return fromUint8Array(Uint8Array.from(s, (c: string) => c.charCodeAt(0)))\\r\\n }\\r\\nconst utob = (src: string): string => unescape(encodeURIComponent(src))\\r\\n\\r\\nexport default function encode(src: string, rfc4648 = false): string {\\r\\n const b64 = _btoa(utob(src))\\r\\n return rfc4648 ? _mkUriSafe(b64) : b64\\r\\n}\\r\\n\",\n \"lib/color-utils.ts\": \"export interface HsvaColor {\\r\\n h: number\\r\\n s: number\\r\\n v: number\\r\\n a: number\\r\\n}\\r\\n\\r\\nexport interface RgbaColor {\\r\\n r: number\\r\\n g: number\\r\\n b: number\\r\\n a: number\\r\\n}\\r\\n\\r\\nexport type ColorFormat = 'hex' | 'rgb' | 'rgba'\\r\\n\\r\\nexport function hexToHsva(hex: string): HsvaColor {\\r\\n const rgba = hexToRgba(hex)\\r\\n return rgbaToHsva(rgba)\\r\\n}\\r\\n\\r\\nexport function hsvaToHex(hsva: HsvaColor): string {\\r\\n const rgba = hsvaToRgba(hsva)\\r\\n return rgbaToHex(rgba)\\r\\n}\\r\\n\\r\\nexport function hexToRgba(hex: string): RgbaColor {\\r\\n hex = hex.replace(/^#/, '')\\r\\n if (hex.length === 3) {\\r\\n hex = hex.split('').map(char => char + char).join('')\\r\\n }\\r\\n\\r\\n if (hex.length !== 6 && hex.length !== 8) {\\r\\n return { r: 0, g: 0, b: 0, a: 1 }\\r\\n }\\r\\n\\r\\n const r = parseInt(hex.slice(0, 2), 16)\\r\\n const g = parseInt(hex.slice(2, 4), 16)\\r\\n const b = parseInt(hex.slice(4, 6), 16)\\r\\n const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1\\r\\n\\r\\n return { r, g, b, a }\\r\\n}\\r\\n\\r\\nexport function rgbaToHex(rgba: RgbaColor): string {\\r\\n const r = Math.round(rgba.r).toString(16).padStart(2, '0')\\r\\n const g = Math.round(rgba.g).toString(16).padStart(2, '0')\\r\\n const b = Math.round(rgba.b).toString(16).padStart(2, '0')\\r\\n const a = rgba.a < 1 ? Math.round(rgba.a * 255).toString(16).padStart(2, '0') : ''\\r\\n return `#${r}${g}${b}${a}`.toLowerCase()\\r\\n}\\r\\n\\r\\nexport function rgbaToHsva(rgba: RgbaColor): HsvaColor {\\r\\n const r = rgba.r / 255\\r\\n const g = rgba.g / 255\\r\\n const b = rgba.b / 255\\r\\n const max = Math.max(r, g, b)\\r\\n const min = Math.min(r, g, b)\\r\\n const delta = max - min\\r\\n let h = 0\\r\\n if (delta !== 0) {\\r\\n if (max === r) h = ((g - b) / delta) % 6\\r\\n else if (max === g) h = (b - r) / delta + 2\\r\\n else h = (r - g) / delta + 4\\r\\n h = Math.round(h * 60)\\r\\n if (h < 0) h += 360\\r\\n }\\r\\n const s = max === 0 ? 0 : delta / max\\r\\n const v = max\\r\\n return { h, s: s * 100, v: v * 100, a: rgba.a }\\r\\n}\\r\\n\\r\\nexport function hsvaToRgba(hsva: HsvaColor): RgbaColor {\\r\\n const h = hsva.h / 60\\r\\n const s = hsva.s / 100\\r\\n const v = hsva.v / 100\\r\\n const i = Math.floor(h)\\r\\n const f = h - i\\r\\n const p = v * (1 - s)\\r\\n const q = v * (1 - f * s)\\r\\n const t = v * (1 - (1 - f) * s)\\r\\n const mod = i % 6\\r\\n let r = 0, g = 0, b = 0\\r\\n if (mod === 0) { r = v; g = t; b = p }\\r\\n else if (mod === 1) { r = q; g = v; b = p }\\r\\n else if (mod === 2) { r = p; g = v; b = t }\\r\\n else if (mod === 3) { r = p; g = q; b = v }\\r\\n else if (mod === 4) { r = t; g = p; b = v }\\r\\n else if (mod === 5) { r = v; g = p; b = q }\\r\\n return {\\r\\n r: Math.round(r * 255),\\r\\n g: Math.round(g * 255),\\r\\n b: Math.round(b * 255),\\r\\n a: hsva.a\\r\\n }\\r\\n}\\r\\n\\r\\nexport function detectColorFormat(value: string | undefined | null): ColorFormat {\\r\\n if (!value) return 'hex'\\r\\n\\r\\n const normalized = value.trim().toLowerCase()\\r\\n if (normalized.startsWith('rgba(')) return 'rgba'\\r\\n if (normalized.startsWith('rgb(')) return 'rgb'\\r\\n return 'hex'\\r\\n}\\r\\n\\r\\nexport function parseColorString(value: string | undefined | null): RgbaColor | null {\\r\\n if (!value) return null\\r\\n\\r\\n const normalized = value.trim()\\r\\n\\r\\n if (normalized.startsWith('#')) {\\r\\n return hexToRgba(normalized)\\r\\n }\\r\\n\\r\\n const match = normalized.match(/rgba?\\\\((\\\\d+),\\\\s*(\\\\d+),\\\\s*(\\\\d+)(?:,\\\\s*([\\\\d.]+))?\\\\)/i)\\r\\n if (!match) return null\\r\\n\\r\\n return {\\r\\n r: Number.parseInt(match[1] || '0'),\\r\\n g: Number.parseInt(match[2] || '0'),\\r\\n b: Number.parseInt(match[3] || '0'),\\r\\n a: match[4] ? Number.parseFloat(match[4]) : 1,\\r\\n }\\r\\n}\\r\\n\\r\\nexport function colorStringToHsva(value: string | undefined | null): HsvaColor {\\r\\n const rgba = parseColorString(value)\\r\\n if (!rgba) {\\r\\n return hexToHsva('#000000')\\r\\n }\\r\\n\\r\\n return rgbaToHsva(rgba)\\r\\n}\\r\\n\\r\\nexport function hsvaToColorString(hsva: HsvaColor, format: ColorFormat): string {\\r\\n if (format === 'hex') {\\r\\n return hsvaToHex(hsva)\\r\\n }\\r\\n\\r\\n const rgba = hsvaToRgba(hsva)\\r\\n if (format === 'rgb') {\\r\\n return `rgb(${rgba.r}, ${rgba.g}, ${rgba.b})`\\r\\n }\\r\\n\\r\\n return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a.toFixed(2)})`\\r\\n}\\r\\n\",\n \"lib/dayUts.ts\": \"export class DayUts {\\r\\n private _date: Date\\r\\n\\r\\n constructor(date?: Date | string | number | null) {\\r\\n if (date == null || date == '') {\\r\\n this._date = new Date()\\r\\n }\\r\\n else if (typeof date == 'string') {\\r\\n // 修复 iOS/Safari 的 'YYYY-MM-DD HH:mm:ss' 格式兼容性问题\\r\\n // iOS 只支持 'YYYY/MM/DD' 等使用斜杠的格式,所以如果包含 '-' 则替换为 '/' (仅日期部分的 '-')\\r\\n const safeDateStr = date.includes('-') && date.includes(':')\\r\\n ? date.replace(/-/g, '/')\\r\\n : date\\r\\n this._date = new Date(safeDateStr)\\r\\n }\\r\\n else if (typeof date == 'number') {\\r\\n this._date = new Date(date)\\r\\n }\\r\\n else if (date instanceof Date) {\\r\\n this._date = new Date(date.getTime())\\r\\n }\\r\\n else {\\r\\n this._date = new Date()\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 格式化日期\\r\\n * @param template 格式模板,支持 YYYY-MM-DD HH:mm:ss 等\\r\\n */\\r\\n format(template: string): string {\\r\\n // 使用传入的模板\\r\\n const actualTemplate: string = template\\r\\n\\r\\n const year = this._date.getFullYear()\\r\\n const month = this._date.getMonth() + 1\\r\\n const date = this._date.getDate()\\r\\n const hours = this._date.getHours()\\r\\n const minutes = this._date.getMinutes()\\r\\n const seconds = this._date.getSeconds()\\r\\n const milliseconds = this._date.getMilliseconds()\\r\\n\\r\\n // 使用数组来依次替换,避免UTS的replace方法兼容性问题\\r\\n let result: string = actualTemplate\\r\\n\\r\\n // 按照长度从长到短替换,避免冲突\\r\\n // 替换年份 (YYYY 必须在 YY 之前)\\r\\n result = result.replace('YYYY', year.toString())\\r\\n result = result.replace('YY', year.toString().slice(-2))\\r\\n\\r\\n // 替换月份 (MM 必须在 M 之前)\\r\\n result = result.replace('MM', month.toString().padStart(2, '0'))\\r\\n result = result.replace('M', month.toString())\\r\\n\\r\\n // 替换日期 (DD 必须在 D 之前)\\r\\n result = result.replace('DD', date.toString().padStart(2, '0'))\\r\\n result = result.replace('D', date.toString())\\r\\n\\r\\n // 替换小时 (HH 必须在 H 之前)\\r\\n result = result.replace('HH', hours.toString().padStart(2, '0'))\\r\\n result = result.replace('H', hours.toString())\\r\\n\\r\\n // 替换分钟 (mm 必须在 m 之前)\\r\\n result = result.replace('mm', minutes.toString().padStart(2, '0'))\\r\\n result = result.replace('m', minutes.toString())\\r\\n\\r\\n // 替换秒数 (ss 必须在 s 之前)\\r\\n result = result.replace('ss', seconds.toString().padStart(2, '0'))\\r\\n result = result.replace('s', seconds.toString())\\r\\n\\r\\n // 替换毫秒\\r\\n result = result.replace('SSS', milliseconds.toString().padStart(3, '0'))\\r\\n\\r\\n return result\\r\\n }\\r\\n\\r\\n /**\\r\\n * 本月多少天\\r\\n */\\r\\n getDays(): number {\\r\\n return new Date(this._date.getFullYear(), this._date.getMonth() + 1, 0).getDate()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 是否为闰年\\r\\n */\\r\\n isLeapYear(): boolean {\\r\\n return this._date.getFullYear() % 4 == 0 && this._date.getFullYear() % 100 != 0\\r\\n }\\r\\n\\r\\n /**\\r\\n * 星期几\\r\\n */\\r\\n getDay(): number {\\r\\n return this._date.getDay()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取某个单位的开始时间\\r\\n */\\r\\n startOf(unit: 'month' | 'day' | 'year' | 'week'): DayUts {\\r\\n const newDate = new Date(this._date.getTime())\\r\\n\\r\\n switch (unit) {\\r\\n case 'year':\\r\\n newDate.setMonth(0)\\r\\n newDate.setDate(1)\\r\\n newDate.setHours(0)\\r\\n newDate.setMinutes(0)\\r\\n newDate.setSeconds(0)\\r\\n newDate.setMilliseconds(0)\\r\\n break\\r\\n case 'month':\\r\\n newDate.setDate(1)\\r\\n newDate.setHours(0)\\r\\n newDate.setMinutes(0)\\r\\n newDate.setSeconds(0)\\r\\n newDate.setMilliseconds(0)\\r\\n break\\r\\n case 'week':\\r\\n newDate.setDate(newDate.getDate() - newDate.getDay())\\r\\n newDate.setHours(0)\\r\\n newDate.setMinutes(0)\\r\\n newDate.setSeconds(0)\\r\\n newDate.setMilliseconds(0)\\r\\n break\\r\\n case 'day':\\r\\n newDate.setHours(0)\\r\\n newDate.setMinutes(0)\\r\\n newDate.setSeconds(0)\\r\\n newDate.setMilliseconds(0)\\r\\n break\\r\\n }\\r\\n\\r\\n return new DayUts(newDate)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取某个单位的结束时间\\r\\n */\\r\\n endOf(unit: 'month' | 'day' | 'year' | 'week'): DayUts {\\r\\n const newDate = new Date(this._date.getTime())\\r\\n\\r\\n switch (unit) {\\r\\n case 'year':\\r\\n newDate.setMonth(11)\\r\\n newDate.setDate(31)\\r\\n newDate.setHours(23)\\r\\n newDate.setMinutes(59)\\r\\n newDate.setSeconds(59)\\r\\n newDate.setMilliseconds(999)\\r\\n break\\r\\n case 'month':\\r\\n newDate.setMonth(newDate.getMonth() + 1)\\r\\n newDate.setDate(0)\\r\\n newDate.setHours(23)\\r\\n newDate.setMinutes(59)\\r\\n newDate.setSeconds(59)\\r\\n newDate.setMilliseconds(999)\\r\\n break\\r\\n case 'week':\\r\\n const day = newDate.getDay()\\r\\n const diff = 6 - day\\r\\n newDate.setDate(newDate.getDate() + diff)\\r\\n newDate.setHours(23)\\r\\n newDate.setMinutes(59)\\r\\n newDate.setSeconds(59)\\r\\n newDate.setMilliseconds(999)\\r\\n break\\r\\n case 'day':\\r\\n newDate.setHours(23)\\r\\n newDate.setMinutes(59)\\r\\n newDate.setSeconds(59)\\r\\n newDate.setMilliseconds(999)\\r\\n break\\r\\n }\\r\\n\\r\\n return new DayUts(newDate)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否早于另一个日期\\r\\n */\\r\\n isBefore(date: DayUts | Date | string | number): boolean {\\r\\n const compareDate = this._parseDate(date)\\r\\n return this._date.getTime() < compareDate.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否晚于另一个日期\\r\\n */\\r\\n isAfter(date: DayUts | Date | string | number): boolean {\\r\\n const compareDate = this._parseDate(date)\\r\\n return this._date.getTime() > compareDate.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否与另一个日期相同\\r\\n */\\r\\n isSame(date: DayUts | Date | string | number): boolean {\\r\\n const compareDate = this._parseDate(date)\\r\\n return this._date.getTime() == compareDate.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 计算与另一个日期的差值(毫秒)\\r\\n */\\r\\n diff(date: DayUts | Date | string | number): number {\\r\\n const compareDate = this._parseDate(date)\\r\\n return this._date.getTime() - compareDate.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 计算与另一个日期的差值(指定单位)\\r\\n */\\r\\n diffUnit(\\r\\n date: DayUts | Date | string | number,\\r\\n unit: 'day' | 'hour' | 'minute' | 'second' | 'millisecond',\\r\\n ): number {\\r\\n const compareDate = this._parseDate(date)\\r\\n const diffMs = this._date.getTime() - compareDate.getTime()\\r\\n\\r\\n switch (unit) {\\r\\n case 'day':\\r\\n return Math.floor(diffMs / (1000 * 60 * 60 * 24))\\r\\n case 'hour':\\r\\n return Math.floor(diffMs / (1000 * 60 * 60))\\r\\n case 'minute':\\r\\n return Math.floor(diffMs / (1000 * 60))\\r\\n case 'second':\\r\\n return Math.floor(diffMs / 1000)\\r\\n case 'millisecond':\\r\\n default:\\r\\n return diffMs\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加时间\\r\\n */\\r\\n add(value: number, unit: 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second'): DayUts {\\r\\n const newDate = new Date(this._date.getTime())\\r\\n\\r\\n switch (unit) {\\r\\n case 'year':\\r\\n newDate.setFullYear(newDate.getFullYear() + value)\\r\\n break\\r\\n case 'month':\\r\\n newDate.setMonth(newDate.getMonth() + value)\\r\\n break\\r\\n case 'day':\\r\\n newDate.setDate(newDate.getDate() + value)\\r\\n break\\r\\n case 'hour':\\r\\n newDate.setHours(newDate.getHours() + value)\\r\\n break\\r\\n case 'minute':\\r\\n newDate.setMinutes(newDate.getMinutes() + value)\\r\\n break\\r\\n case 'second':\\r\\n newDate.setSeconds(newDate.getSeconds() + value)\\r\\n break\\r\\n }\\r\\n\\r\\n return new DayUts(newDate)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 减少时间\\r\\n */\\r\\n subtract(value: number, unit: 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second'): DayUts {\\r\\n return this.add(-value, unit)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取时间戳\\r\\n */\\r\\n valueOf(): number {\\r\\n return this._date.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取原生Date对象\\r\\n */\\r\\n toDate(): Date {\\r\\n return new Date(this._date.getTime())\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取日期数组\\r\\n */\\r\\n toArray(): number[] {\\r\\n return [\\r\\n this._date.getFullYear(),\\r\\n this._date.getMonth() + 1,\\r\\n this._date.getDate(),\\r\\n this._date.getHours(),\\r\\n this._date.getMinutes(),\\r\\n this._date.getSeconds(),\\r\\n ]\\r\\n }\\r\\n\\r\\n /**\\r\\n * 私有方法:解析不同类型的日期参数\\r\\n */\\r\\n private _parseDate(date: DayUts | Date | string | number): Date {\\r\\n if (date instanceof DayUts) {\\r\\n return date.toDate()\\r\\n }\\r\\n else if (date instanceof Date) {\\r\\n return date\\r\\n }\\r\\n else if (typeof date == 'string') {\\r\\n const safeDateStr = date.includes('-') && date.includes(':')\\r\\n ? date.replace(/-/g, '/')\\r\\n : date\\r\\n return new Date(safeDateStr)\\r\\n }\\r\\n else if (typeof date == 'number') {\\r\\n return new Date(date)\\r\\n }\\r\\n else {\\r\\n // 如果都不匹配,返回当前时间\\r\\n return new Date()\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n/**\\r\\n * 创建 DayUts 实例\\r\\n */\\r\\nexport function dayUts(date: Date | string | number | null = new Date()): DayUts {\\r\\n return new DayUts(date)\\r\\n}\\r\\n\",\n \"lib/device.ts\": \"/**\\r\\n * 系统信息接口,包含项目中实际使用的字段\\r\\n */\\r\\nexport interface SystemInfo {\\r\\n /** 窗口宽度 */\\r\\n windowWidth: number\\r\\n /** 窗口高度 */\\r\\n windowHeight: number\\r\\n /** 窗口顶部位置 */\\r\\n windowTop: number\\r\\n /** 设备像素比 */\\r\\n pixelRatio: number\\r\\n /** 平台信息 */\\r\\n platform: string\\r\\n /** 主题模式 */\\r\\n theme?: string\\r\\n /** 状态栏高度 */\\r\\n statusBarHeight?: number\\r\\n /** 安全区域信息 */\\r\\n safeArea?: UniApp.SafeArea\\r\\n /** 屏幕高度 */\\r\\n screenHeight: number\\r\\n /** 安全区域插入信息 */\\r\\n safeAreaInsets?: UniApp.SafeAreaInsets\\r\\n // 未尽字段\\r\\n [key: string]: any\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为小程序环境\\r\\n * @returns 是否为小程序环境\\r\\n */\\r\\nexport function isMp(): boolean {\\r\\n // #ifdef MP\\r\\n return true\\r\\n // #endif\\r\\n\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为App环境\\r\\n * @returns 是否为App环境\\r\\n */\\r\\nexport function isApp(): boolean {\\r\\n // #ifdef APP\\r\\n return true\\r\\n // #endif\\r\\n\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为App-IOS环境\\r\\n * @returns 是否为App-IOS环境\\r\\n */\\r\\nexport function isAppIOS(): boolean {\\r\\n // #ifdef APP-IOS\\r\\n return true\\r\\n // #endif\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为App-Android环境\\r\\n * @returns 是否为App-Android环境\\r\\n */\\r\\nexport function isAppAndroid(): boolean {\\r\\n // #ifdef APP-ANDROID\\r\\n return true\\r\\n // #endif\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为H5环境\\r\\n * @returns 是否为H5环境\\r\\n */\\r\\nexport function isH5(): boolean {\\r\\n // #ifdef H5\\r\\n return true\\r\\n // #endif\\r\\n\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为鸿蒙环境\\r\\n * @returns 是否为鸿蒙环境\\r\\n */\\r\\nexport function isHarmony(): boolean {\\r\\n // #ifdef APP-HARMONY\\r\\n return true\\r\\n // #endif\\r\\n\\r\\n return false\\r\\n}\\r\\n\\r\\nexport function initTheme() {\\r\\n let value: string | null\\r\\n\\r\\n // #ifdef APP\\r\\n const appInfo = uni.getAppBaseInfo()\\r\\n // @ts-ignore\\r\\n const appTheme = appInfo.appTheme as string\\r\\n const osTheme = uni.getSystemInfoSync().osTheme!\\r\\n\\r\\n // 如果 appTheme 为 auto,则跟随系统主题,否则使用 appTheme\\r\\n value = appTheme == 'auto' ? osTheme : appTheme\\r\\n // #endif\\r\\n\\r\\n // #ifdef H5 || MP\\r\\n const hostTheme = uni.getAppBaseInfo().hostTheme\\r\\n if (hostTheme) {\\r\\n // 如果有 hostTheme,则使用 hostTheme\\r\\n value = hostTheme\\r\\n }\\r\\n else {\\r\\n // 默认使用 light 主题\\r\\n value = 'light'\\r\\n }\\r\\n // #endif\\r\\n return value\\r\\n}\\r\\n\\r\\n/**\\r\\n * 获取安全区域高度\\r\\n * @param type 类型\\r\\n * @returns 安全区域高度\\r\\n */\\r\\nexport function getSafeAreaHeight(type: 'top' | 'bottom') {\\r\\n const { safeAreaInsets } = uni.getWindowInfo()\\r\\n\\r\\n let h: number\\r\\n\\r\\n if (type == 'top') {\\r\\n h = safeAreaInsets.top\\r\\n }\\r\\n else {\\r\\n h = safeAreaInsets.bottom\\r\\n\\r\\n // #ifdef APP-ANDROID\\r\\n if (h == 0) {\\r\\n h = 16\\r\\n }\\r\\n // #endif\\r\\n }\\r\\n\\r\\n return h\\r\\n}\\r\\n\\r\\n/**\\r\\n * 兼容微信小程序端获取系统信息的方法\\r\\n * 在微信小程序端使用新的API替代getSystemInfoSync,在其他端仍然使用getSystemInfoSync\\r\\n * @returns 系统信息对象\\r\\n */\\r\\nexport function getSystemInfo(): SystemInfo {\\r\\n let systemInfo: SystemInfo\\r\\n // #ifdef MP-WEIXIN\\r\\n try {\\r\\n // const systemSetting = uni.getSystemInfoSync() // 暂时不需要\\r\\n const deviceInfo = uni.getDeviceInfo()\\r\\n const windowInfo = uni.getWindowInfo()\\r\\n const appBaseInfo = uni.getAppBaseInfo()\\r\\n systemInfo = {\\r\\n ...deviceInfo,\\r\\n ...windowInfo,\\r\\n ...appBaseInfo\\r\\n }\\r\\n } catch (error) {\\r\\n console.warn('获取系统信息失败,降级使用uni.getSystemInfoSync:', error)\\r\\n // 降级处理,使用原来的方法\\r\\n systemInfo = uni.getSystemInfoSync()\\r\\n }\\r\\n // #endif\\r\\n // #ifndef MP-WEIXIN\\r\\n systemInfo = uni.getSystemInfoSync()\\r\\n // #endif\\r\\n return systemInfo\\r\\n}\",\n \"lib/file.ts\": \"export function uuid(): string {\\r\\n\\tlet uuid = \\\"\\\";\\r\\n\\tlet i: number;\\r\\n\\tlet random: number;\\r\\n\\r\\n\\tfor (i = 0; i < 36; i++) {\\r\\n\\t\\tif (i == 8 || i == 13 || i == 18 || i == 23) {\\r\\n\\t\\t\\tuuid += \\\"-\\\";\\r\\n\\t\\t} else if (i == 14) {\\r\\n\\t\\t\\tuuid += \\\"4\\\";\\r\\n\\t\\t} else if (i == 19) {\\r\\n\\t\\t\\trandom = (Math.random() * 16) | 0;\\r\\n\\t\\t\\tuuid += ((random & 0x3) | 0x8).toString(16);\\r\\n\\t\\t} else {\\r\\n\\t\\t\\trandom = (Math.random() * 16) | 0;\\r\\n\\t\\t\\tuuid += random.toString(16);\\r\\n\\t\\t}\\r\\n\\t}\\r\\n\\treturn uuid;\\r\\n}\\r\\n\\r\\n\\r\\nexport function base64ToBlob(data: string, type: string = \\\"image/jpeg\\\"): Blob {\\r\\n\\t// #ifdef H5\\r\\n\\tlet bytes = window.atob(data.split(\\\",\\\")[1]);\\r\\n\\tlet ab = new ArrayBuffer(bytes.length);\\r\\n\\tlet ia = new Uint8Array(ab);\\r\\n\\tfor (let i = 0; i < bytes.length; i++) {\\r\\n\\t\\tia[i] = bytes.charCodeAt(i);\\r\\n\\t}\\r\\n\\treturn new Blob([ab], { type });\\r\\n\\t// #endif\\r\\n}\\r\\n\\r\\n/**\\r\\n * 将canvas转换为png图片\\r\\n * @param options 转换参数\\r\\n * @returns 图片路径\\r\\n */\\r\\nexport function canvasToPng(canvasRef: any): Promise<string> {\\r\\n\\treturn new Promise((resolve) => {\\r\\n\\t\\t// #ifdef APP\\r\\n\\t\\tcanvasRef.parentElement!.takeSnapshot({\\r\\n\\t\\t\\tsuccess(res: any) {\\r\\n\\t\\t\\t\\tresolve(res.tempFilePath);\\r\\n\\t\\t\\t},\\r\\n\\t\\t\\tfail(err: any) {\\r\\n\\t\\t\\t\\tconsole.error(err);\\r\\n\\t\\t\\t\\tresolve(\\\"\\\");\\r\\n\\t\\t\\t}\\r\\n\\t\\t});\\r\\n\\t\\t// #endif\\r\\n\\r\\n\\t\\t// #ifdef H5\\r\\n\\t\\tconst url = URL.createObjectURL(\\r\\n\\t\\t\\tbase64ToBlob(\\r\\n\\t\\t\\t\\t(canvasRef as unknown as HTMLCanvasElement)?.toDataURL(\\\"image/png\\\", 1) ?? \\\"\\\"\\r\\n\\t\\t\\t)\\r\\n\\t\\t);\\r\\n\\r\\n\\t\\tresolve(url);\\r\\n\\t\\t// #endif\\r\\n\\r\\n\\t\\t// #ifdef MP\\r\\n\\t\\tuni.createCanvasContextAsync({\\r\\n\\t\\t\\tid: canvasRef.id,\\r\\n\\t\\t\\tcomponent: canvasRef.$vm,\\r\\n\\t\\t\\tsuccess(context: any) {\\r\\n\\t\\t\\t\\t// 获取2D绘图上下文\\r\\n\\t\\t\\t\\tconst ctx = context.getContext(\\\"2d\\\")!;\\r\\n\\r\\n\\t\\t\\t\\t// 获取canvas对象\\r\\n\\t\\t\\t\\tconst canvas = ctx.canvas;\\r\\n\\r\\n\\t\\t\\t\\t// 将canvas转换为base64格式的PNG图片数据\\r\\n\\t\\t\\t\\tconst data = canvas.toDataURL(\\\"image/png\\\", 1);\\r\\n\\r\\n\\t\\t\\t\\t// 获取文件系统管理器\\r\\n\\t\\t\\t\\tconst fileMg = uni.getFileSystemManager();\\r\\n\\r\\n\\t\\t\\t\\t// 生成临时文件路径\\r\\n\\t\\t\\t\\t// @ts-ignore\\r\\n\\t\\t\\t\\tconst filepath = `${wx.env.USER_DATA_PATH}/${uuid()}.png`;\\r\\n\\r\\n\\t\\t\\t\\t// 将base64数据写入文件\\r\\n\\t\\t\\t\\tfileMg.writeFile({\\r\\n\\t\\t\\t\\t\\tfilePath: filepath,\\r\\n\\t\\t\\t\\t\\tdata: data.split(\\\",\\\")[1],\\r\\n\\t\\t\\t\\t\\tencoding: \\\"base64\\\",\\r\\n\\t\\t\\t\\t\\tsuccess() {\\r\\n\\t\\t\\t\\t\\t\\tresolve(filepath);\\r\\n\\t\\t\\t\\t\\t},\\r\\n\\t\\t\\t\\t\\tfail(err) {\\r\\n\\t\\t\\t\\t\\t\\tconsole.error(err);\\r\\n\\t\\t\\t\\t\\t\\tresolve(\\\"\\\");\\r\\n\\t\\t\\t\\t\\t}\\r\\n\\t\\t\\t\\t});\\r\\n\\t\\t\\t},\\r\\n\\t\\t\\tfail(err: any) {\\r\\n\\t\\t\\t\\tconsole.error(err);\\r\\n\\t\\t\\t\\tresolve(\\\"\\\");\\r\\n\\t\\t\\t}\\r\\n\\t\\t});\\r\\n\\t\\t// #endif\\r\\n\\t});\\r\\n}\\r\\n\",\n \"lib/tv.ts\": \"import type { TV } from 'tailwind-variants'\\r\\n\\r\\n// #ifdef MP-WEIXIN\\r\\n// @ts-ignore\\r\\nimport { create } from '@weapp-tailwindcss/variants-v3'\\r\\n// #endif\\r\\n\\r\\n// #ifndef MP-WEIXIN\\r\\nimport { tv as originTv } from 'tailwind-variants'\\r\\n// #endif\\r\\n\\r\\nconst textSizeKeys = ['20', '22', '24', '26', '28', '30', '32', '36', '40', '48', '52']\\r\\n\\r\\nconst twMergeConfig = {\\r\\n extend: {\\r\\n classGroups: {\\r\\n 'font-size': [{ text: textSizeKeys }],\\r\\n },\\r\\n },\\r\\n}\\r\\n\\r\\n// #ifdef MP-WEIXIN\\r\\n\\r\\n// @ts-ignore\\r\\nconst isH5 = process.env.UNI_PLATFORM === 'h5'\\r\\n\\r\\nconst { tv: createTV } = create({\\r\\n // @ts-ignore\\r\\n escape: !isH5,\\r\\n // @ts-ignore\\r\\n unescape: !isH5,\\r\\n})\\r\\n\\r\\n// @ts-ignore\\r\\nexport const tv: TV = (options, config) =>\\r\\n // @ts-ignore\\r\\n createTV(options, {\\r\\n ...config,\\r\\n twMerge: config?.twMerge ?? true,\\r\\n twMergeConfig: {\\r\\n ...config?.twMergeConfig,\\r\\n ...twMergeConfig,\\r\\n },\\r\\n })\\r\\n\\r\\n// #endif\\r\\n\\r\\n// #ifndef MP-WEIXIN\\r\\n// @ts-ignore\\r\\nexport const tv: TV = (options, config) =>\\r\\n originTv(options, {\\r\\n ...config,\\r\\n twMerge: config?.twMerge ?? true,\\r\\n twMergeConfig: {\\r\\n ...config?.twMergeConfig,\\r\\n ...twMergeConfig,\\r\\n },\\r\\n })\\r\\n\\r\\n// #endif\\r\\n\",\n \"lib/util.ts\": \"import { AbortablePromise } from './AbortablePromise'\\r\\n\\r\\ntype NotUndefined<T> = T extends undefined ? never : T\\r\\n\\r\\nexport function isObj(value: any): value is object {\\r\\n return Object.prototype.toString.call(value) === '[object Object]' || typeof value === 'object'\\r\\n}\\r\\n\\r\\nexport function getType(target: unknown): string {\\r\\n const typeStr = Object.prototype.toString.call(target)\\r\\n const match = typeStr.match(/\\\\[object (\\\\w+)\\\\]/)\\r\\n return match && match.length ? match[1].toLowerCase() : ''\\r\\n}\\r\\n\\r\\nexport const isDef = <T>(value: T): value is NonNullable<T> => value !== undefined && value !== null\\r\\n\\r\\nexport function addUnit(num: number | string) {\\r\\n return Number.isNaN(Number(num)) ? `${num}` : `${num}rpx`\\r\\n}\\r\\n\\r\\nexport function rgbToHex(r: number, g: number, b: number): string {\\r\\n const hex = ((r << 16) | (g << 8) | b).toString(16)\\r\\n return '#' + '0'.repeat(Math.max(0, 6 - hex.length)) + hex\\r\\n}\\r\\n\\r\\nexport function hexToRgb(hex: string): number[] {\\r\\n const rgb: number[] = []\\r\\n for (let i = 1; i < 7; i += 2) {\\r\\n rgb.push(parseInt('0x' + hex.slice(i, i + 2), 16))\\r\\n }\\r\\n return rgb\\r\\n}\\r\\n\\r\\nexport const gradient = (startColor: string, endColor: string, step: number = 2): string[] => {\\r\\n const sColor: number[] = hexToRgb(startColor)\\r\\n const eColor: number[] = hexToRgb(endColor)\\r\\n const rStep: number = (eColor[0] - sColor[0]) / step\\r\\n const gStep: number = (eColor[1] - sColor[1]) / step\\r\\n const bStep: number = (eColor[2] - sColor[2]) / step\\r\\n const gradientColorArr: string[] = []\\r\\n for (let i = 0; i < step; i++) {\\r\\n gradientColorArr.push(\\r\\n rgbToHex(parseInt(String(rStep * i + sColor[0])), parseInt(String(gStep * i + sColor[1])), parseInt(String(bStep * i + sColor[2])))\\r\\n )\\r\\n }\\r\\n return gradientColorArr\\r\\n}\\r\\n\\r\\nexport const context = {\\r\\n id: 1000\\r\\n}\\r\\n\\r\\nexport function kebabCase(word: string): string {\\r\\n return word.replace(/[A-Z]/g, function (match) {\\r\\n return '-' + match\\r\\n }).toLowerCase()\\r\\n}\\r\\n\\r\\nexport function camelCase(word: string): string {\\r\\n return word.replace(/-(\\\\w)/g, (_, c) => c.toUpperCase())\\r\\n}\\r\\n\\r\\nexport function isArray(value: any): value is Array<any> {\\r\\n if (typeof Array.isArray === 'function') {\\r\\n return Array.isArray(value)\\r\\n }\\r\\n return Object.prototype.toString.call(value) === '[object Array]'\\r\\n}\\r\\n\\r\\nexport function isFunction<T extends Function>(value: any): value is T {\\r\\n return getType(value) === 'function' || getType(value) === 'asyncfunction'\\r\\n}\\r\\n\\r\\nexport function isString(value: unknown): value is string {\\r\\n return getType(value) === 'string'\\r\\n}\\r\\n\\r\\nexport function isNumber(value: any): value is number {\\r\\n return getType(value) === 'number'\\r\\n}\\r\\n\\r\\nexport function isPromise(value: unknown): value is Promise<any> {\\r\\n if (isObj(value) && isDef(value)) {\\r\\n return isFunction((value as Promise<any>).then) && isFunction((value as Promise<any>).catch)\\r\\n }\\r\\n return false\\r\\n}\\r\\n\\r\\nexport function isBoolean(value: any): value is boolean {\\r\\n return typeof value === 'boolean'\\r\\n}\\r\\n\\r\\nexport function isUndefined(value: any): value is undefined {\\r\\n return typeof value === 'undefined'\\r\\n}\\r\\n\\r\\nexport function isNotUndefined<T>(value: T): value is NotUndefined<T> {\\r\\n return !isUndefined(value)\\r\\n}\\r\\n\\r\\nexport function objToStyle(styles: Record<string, any> | Record<string, any>[]): string {\\r\\n if (isArray(styles)) {\\r\\n const result = styles\\r\\n .filter((item) => item != null && item !== '')\\r\\n .map((item) => objToStyle(item))\\r\\n .join(';')\\r\\n return result ? (result.endsWith(';') ? result : result + ';') : ''\\r\\n }\\r\\n if (isString(styles)) {\\r\\n return styles ? (styles.endsWith(';') ? styles : styles + ';') : ''\\r\\n }\\r\\n if (isObj(styles)) {\\r\\n const result = Object.keys(styles)\\r\\n .filter((key) => styles[key] != null && styles[key] !== '')\\r\\n .map((key) => [kebabCase(key), styles[key]].join(':'))\\r\\n .join(';')\\r\\n return result ? (result.endsWith(';') ? result : result + ';') : ''\\r\\n }\\r\\n return ''\\r\\n}\\r\\n\\r\\nexport const pause = (ms: number = 1000 / 30) => {\\r\\n return new AbortablePromise((resolve) => {\\r\\n const timer = setTimeout(() => {\\r\\n clearTimeout(timer)\\r\\n resolve(true)\\r\\n }, ms)\\r\\n })\\r\\n}\\r\\n\\r\\nexport const isDate = (val: unknown): val is Date => Object.prototype.toString.call(val) === '[object Date]' && !Number.isNaN((val as Date).getTime())\\r\\n\\r\\nexport function deepClone<T>(obj: T, cache: Map<any, any> = new Map()): T {\\r\\n if (obj === null || typeof obj !== 'object') return obj\\r\\n if (isDate(obj)) return new Date((obj as any).getTime()) as any\\r\\n if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags) as any\\r\\n if (obj instanceof Error) {\\r\\n const errorCopy = new Error(obj.message) as any\\r\\n errorCopy.stack = obj.stack\\r\\n return errorCopy\\r\\n }\\r\\n if (cache.has(obj)) return cache.get(obj)\\r\\n const copy: any = Array.isArray(obj) ? [] : {}\\r\\n cache.set(obj, copy)\\r\\n for (const key in obj) {\\r\\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\\r\\n copy[key] = deepClone((obj as any)[key], cache)\\r\\n }\\r\\n }\\r\\n return copy as T\\r\\n}\\r\\n\\r\\nexport function deepMerge<T extends Record<string, any>>(target: T, source: Record<string, any>): T {\\r\\n target = deepClone(target)\\r\\n if (typeof target !== 'object' || typeof source !== 'object') {\\r\\n throw new Error('Both target and source must be objects.')\\r\\n }\\r\\n for (const prop in source) {\\r\\n if (!Object.prototype.hasOwnProperty.call(source, prop)) continue\\r\\n (target as Record<string, any>)[prop] = source[prop]\\r\\n }\\r\\n return target\\r\\n}\\r\\n\\r\\nexport function deepAssign(target: Record<string, any>, source: Record<string, any>): Record<string, any> {\\r\\n Object.keys(source).forEach((key) => {\\r\\n const targetValue = target[key]\\r\\n const newObjValue = source[key]\\r\\n if (isObj(targetValue) && isObj(newObjValue)) {\\r\\n deepAssign(targetValue, newObjValue)\\r\\n } else {\\r\\n target[key] = newObjValue\\r\\n }\\r\\n })\\r\\n return target\\r\\n}\\r\\n\\r\\nexport const getPropByPath = (obj: any, path: string): any => {\\r\\n const keys: string[] = path.split('.')\\r\\n try {\\r\\n return keys.reduce((acc: any, key: string) => (acc !== undefined && acc !== null ? acc[key] : undefined), obj)\\r\\n } catch (error) {\\r\\n return undefined\\r\\n }\\r\\n}\\r\\n\\r\\nexport function omitBy<O extends Record<string, any>>(obj: O, predicate: (value: any, key: keyof O) => boolean): Partial<O> {\\r\\n const newObj = deepClone(obj)\\r\\n Object.keys(newObj).forEach((key) => predicate(newObj[key], key) && delete newObj[key])\\r\\n return newObj\\r\\n}\\r\\n\\r\\nexport const isH5 = (() => {\\r\\n let isH5 = false\\r\\n // #ifdef H5\\r\\n isH5 = true\\r\\n // #endif\\r\\n return isH5\\r\\n})()\\r\\n\",\n \"lib/utils.ts\": \"\\r\\nimport { type ClassValue, clsx } from 'clsx'\\r\\n\\r\\n// #ifndef MP-WEIXIN\\r\\nimport { extendTailwindMerge } from 'tailwind-merge'\\r\\n// @ts-ignore\\r\\nconst twMerge = extendTailwindMerge({\\r\\n extend: {\\r\\n classGroups: {\\r\\n 'font-size': [{ text: ['20', '22', '24', '26', '28', '30', '32', '36', '40', '48', '52'] }],\\r\\n },\\r\\n },\\r\\n})\\r\\n\\r\\n// #endif\\r\\n\\r\\n// #ifdef MP-WEIXIN\\r\\nimport { create } from '@weapp-tailwindcss/merge-v3'\\r\\n\\r\\n// @ts-ignore\\r\\nconst isH5 = process.env.UNI_PLATFORM === 'h5'\\r\\n// @ts-ignore\\r\\nconst { twMerge } = create({\\r\\n escape: !isH5,\\r\\n unescape: !isH5,\\r\\n // @ts-ignore\\r\\n extend: {\\r\\n classGroups: {\\r\\n 'font-size': [{ text: ['20', '22', '24', '26', '28', '30', '32', '36', '40', '48', '52'] }],\\r\\n },\\r\\n },\\r\\n})\\r\\n// #endif\\r\\n\\r\\nexport function cn(...inputs: ClassValue[]) {\\r\\n return twMerge(clsx(inputs))\\r\\n}\",\n \"composables/useChildren.ts\": \"import {\\r\\n provide,\\r\\n inject,\\r\\n reactive,\\r\\n getCurrentInstance,\\r\\n onUnmounted,\\r\\n computed,\\r\\n ref,\\r\\n type VNode,\\r\\n type InjectionKey,\\r\\n type VNodeNormalizedChildren,\\r\\n type ComponentPublicInstance,\\r\\n type ComponentInternalInstance\\r\\n} from 'vue'\\r\\n\\r\\n// 小程序端不支持从vue导出的isVNode方法,参考uni-mp-vue的实现\\r\\nfunction isVNode(value: any): value is VNode {\\r\\n return value ? value.__v_isVNode === true : false\\r\\n}\\r\\n\\r\\nexport function flattenVNodes(children: VNode) {\\r\\n const result: VNode[] = []\\r\\n\\r\\n const traverse = (children: VNode | VNodeNormalizedChildren) => {\\r\\n const vNode = Array.isArray(children) ? children : [children]\\r\\n vNode.forEach((child) => {\\r\\n if (Array.isArray(child)) {\\r\\n traverse(child)\\r\\n } else if (isVNode(child) && child.component?.subTree) {\\r\\n result.push(child)\\r\\n traverse(child.component.subTree)\\r\\n } else if (isVNode(child) && Array.isArray(child.children)) {\\r\\n traverse(child.children)\\r\\n } else if (isVNode(child)) {\\r\\n result.push(child)\\r\\n }\\r\\n })\\r\\n }\\r\\n\\r\\n traverse(children)\\r\\n\\r\\n return result\\r\\n}\\r\\n\\r\\nconst findVNodeIndex = (vnodes: VNode[], vnode: VNode) => {\\r\\n const index = vnodes.indexOf(vnode)\\r\\n if (index === -1) {\\r\\n return vnodes.findIndex(\\r\\n (item) => vnode.key !== undefined && vnode.key !== null && item.type === vnode.type && item.key === vnode.key\\r\\n )\\r\\n }\\r\\n return index\\r\\n}\\r\\n\\r\\n// sort children instances by vnodes order\\r\\nexport function sortChildren(\\r\\n parent: ComponentInternalInstance,\\r\\n publicChildren: ComponentPublicInstance[],\\r\\n internalChildren: ComponentInternalInstance[]\\r\\n) {\\r\\n const vnodes = parent && parent.subTree && parent.subTree.children ? flattenVNodes(parent.subTree) : []\\r\\n internalChildren.sort((a, b) => findVNodeIndex(vnodes, a.vnode) - findVNodeIndex(vnodes, b.vnode))\\r\\n\\r\\n const orderedPublicChildren = internalChildren.map((item) => item.proxy!)\\r\\n\\r\\n publicChildren.sort((a, b) => {\\r\\n const getIndex = (comp: ComponentPublicInstance) => {\\r\\n const uid = comp.$.uid\\r\\n return orderedPublicChildren.findIndex((i) => i.$.uid === uid)\\r\\n }\\r\\n return getIndex(a) - getIndex(b)\\r\\n })\\r\\n}\\r\\n\\r\\nexport function useChildren<\\r\\n // eslint-disable-next-line\\r\\n Child extends ComponentPublicInstance = ComponentPublicInstance<{}, any>,\\r\\n ProvideValue = never\\r\\n>(key: InjectionKey<ProvideValue>) {\\r\\n const publicChildren: Child[] = reactive([])\\r\\n const internalChildren: ComponentInternalInstance[] = reactive([])\\r\\n const parent = getCurrentInstance()!\\r\\n\\r\\n const linkChildren = (value?: ProvideValue) => {\\r\\n const link = (child: ComponentInternalInstance) => {\\r\\n if (child.proxy) {\\r\\n internalChildren.push(child)\\r\\n publicChildren.push(child.proxy as Child)\\r\\n sortChildren(parent, publicChildren, internalChildren)\\r\\n }\\r\\n }\\r\\n\\r\\n const unlink = (child: ComponentInternalInstance) => {\\r\\n const index = internalChildren.indexOf(child)\\r\\n publicChildren.splice(index, 1)\\r\\n internalChildren.splice(index, 1)\\r\\n }\\r\\n\\r\\n provide(\\r\\n key,\\r\\n Object.assign(\\r\\n {\\r\\n link,\\r\\n unlink,\\r\\n children: publicChildren,\\r\\n internalChildren\\r\\n },\\r\\n value\\r\\n )\\r\\n )\\r\\n }\\r\\n\\r\\n return {\\r\\n children: publicChildren,\\r\\n linkChildren\\r\\n }\\r\\n}\\r\\n\\r\\nexport function useParent<T>(key: InjectionKey<T>) {\\r\\n const parent = inject(key, null) as (T & { link: Function; unlink: Function }) | null\\r\\n\\r\\n if (parent) {\\r\\n const instance = getCurrentInstance()!\\r\\n const index = computed(() => {\\r\\n const internalChildren = (parent as any).internalChildren as ComponentInternalInstance[]\\r\\n return internalChildren ? internalChildren.indexOf(instance) : -1\\r\\n })\\r\\n\\r\\n ; (parent as any).link(instance)\\r\\n\\r\\n onUnmounted(() => {\\r\\n ; (parent as any).unlink(instance)\\r\\n })\\r\\n\\r\\n return {\\r\\n parent,\\r\\n index\\r\\n }\\r\\n }\\r\\n\\r\\n return {\\r\\n parent: null,\\r\\n index: ref(-1)\\r\\n }\\r\\n}\\r\\n\",\n \"composables/useDarkMode.ts\": \"export function useDarkMode() {\\r\\n const isDark = ref(false)\\r\\n\\r\\n const toggleDarkMode = () => {\\r\\n isDark.value = !isDark.value\\r\\n updateTheme()\\r\\n }\\r\\n\\r\\n const updateTheme = () => {\\r\\n const value = isDark.value\\r\\n uni.setStorageSync('darkMode', value)\\r\\n\\r\\n // #ifdef H5\\r\\n if (value) {\\r\\n document.documentElement.classList.add('dark')\\r\\n }\\r\\n else {\\r\\n document.documentElement.classList.remove('dark')\\r\\n }\\r\\n // #endif\\r\\n }\\r\\n\\r\\n const initTheme = () => {\\r\\n const saved = uni.getStorageSync('darkMode')\\r\\n if (saved !== '') {\\r\\n isDark.value = !!saved\\r\\n }\\r\\n else {\\r\\n isDark.value = false\\r\\n }\\r\\n updateTheme()\\r\\n }\\r\\n\\r\\n initTheme()\\r\\n\\r\\n return {\\r\\n isDark,\\r\\n toggleDarkMode,\\r\\n }\\r\\n}\\r\\n\",\n \"composables/useFieldGroup.ts\": \"import { computed, getCurrentInstance, inject, onMounted, onUnmounted, ref, watch } from 'vue'\\r\\n\\r\\nexport interface FormValidateError {\\r\\n field: string\\r\\n message: string\\r\\n}\\r\\n\\r\\nexport interface UseFieldGroupProps {\\r\\n modelValue?: any\\r\\n}\\r\\n\\r\\nexport function useFieldGroup() {\\r\\n const errors = ref<Record<string, string>>({})\\r\\n const fields = ref(new Set<string>([]))\\r\\n const fieldInstances = ref<any[]>([])\\r\\n\\r\\n const addField = (field: any) => {\\r\\n fieldInstances.value.push(field)\\r\\n if (field.prop) {\\r\\n fields.value.add(field.prop)\\r\\n }\\r\\n }\\r\\n\\r\\n const removeField = (field: any) => {\\r\\n const index = fieldInstances.value.indexOf(field)\\r\\n if (index > -1) {\\r\\n fieldInstances.value.splice(index, 1)\\r\\n }\\r\\n if (field.prop) {\\r\\n fields.value.delete(field.prop)\\r\\n }\\r\\n }\\r\\n\\r\\n const errorLock = ref(false)\\r\\n\\r\\n function setError(prop: string, error: string) {\\r\\n if (errorLock.value) { return }\\r\\n if (prop !== '') {\\r\\n errors.value = { ...errors.value, [prop]: error }\\r\\n }\\r\\n }\\r\\n\\r\\n function removeError(prop: string) {\\r\\n if (prop !== '' && errors.value[prop] !== undefined) {\\r\\n const newErrors = { ...errors.value }\\r\\n delete newErrors[prop]\\r\\n errors.value = newErrors\\r\\n }\\r\\n }\\r\\n\\r\\n function getError(prop: string): string {\\r\\n if (prop !== '') { return errors.value[prop] ?? '' }\\r\\n return ''\\r\\n }\\r\\n\\r\\n async function getErrors(): Promise<FormValidateError[]> {\\r\\n return Object.entries(errors.value).map(([field, message]) => ({ field, message }))\\r\\n }\\r\\n\\r\\n function clearValidate(fieldsToClear?: string | string[]) {\\r\\n if (fieldsToClear) {\\r\\n const propsArray = Array.isArray(fieldsToClear) ? fieldsToClear : [fieldsToClear]\\r\\n propsArray.forEach(prop => removeError(prop))\\r\\n }\\r\\n else {\\r\\n errors.value = {}\\r\\n }\\r\\n }\\r\\n\\r\\n return {\\r\\n errors,\\r\\n fields,\\r\\n fieldInstances,\\r\\n addField,\\r\\n removeField,\\r\\n setError,\\r\\n removeError,\\r\\n getError,\\r\\n getErrors,\\r\\n clearValidate,\\r\\n }\\r\\n}\\r\\n\\r\\nexport interface UseFieldGroupItemProps {\\r\\n prop?: string\\r\\n label?: string\\r\\n labelPosition?: string\\r\\n labelWidth?: string | number\\r\\n trigger?: 'blur' | 'change' | 'none' | Array<'blur' | 'change'>\\r\\n ui?: any\\r\\n}\\r\\n\\r\\nexport function useFieldGroupItem(props: UseFieldGroupItemProps) {\\r\\n const form = inject<any>('rebornForm', undefined)\\r\\n const instance = getCurrentInstance()\\r\\n\\r\\n const error = computed(() => {\\r\\n if (!form || !props.prop) { return '' }\\r\\n return form.getError ? form.getError(props.prop) : ''\\r\\n })\\r\\n\\r\\n const labelPosition = computed(() => {\\r\\n return props.labelPosition || form?.props?.labelPosition || 'left'\\r\\n })\\r\\n\\r\\n const labelWidth = computed(() => {\\r\\n if (labelPosition.value === 'top') { return 'auto' }\\r\\n return props.labelWidth || form?.props?.labelWidth || 'auto'\\r\\n })\\r\\n\\r\\n const size = computed(() => {\\r\\n const s = form?.props?.size\\r\\n if (s && ['sm', 'md', 'lg'].includes(s)) {\\r\\n return s as 'sm' | 'md' | 'lg'\\r\\n }\\r\\n return 'sm'\\r\\n })\\r\\n\\r\\n const getBoundingClientRect = (callback: (res: any) => void) => {\\r\\n uni.createSelectorQuery()\\r\\n .in(instance?.proxy)\\r\\n .select('.re-form-item')\\r\\n .boundingClientRect(callback)\\r\\n .exec()\\r\\n }\\r\\n\\r\\n const validate = (trigger: 'blur' | 'change') => {\\r\\n if (!form || !props.prop) { return }\\r\\n\\r\\n let currentTrigger = props.trigger\\r\\n if (currentTrigger === undefined) {\\r\\n currentTrigger = form.props?.trigger\\r\\n }\\r\\n\\r\\n if (!currentTrigger || currentTrigger === 'none') { return }\\r\\n\\r\\n let shouldValidate = false\\r\\n if (Array.isArray(currentTrigger)) {\\r\\n shouldValidate = currentTrigger.includes(trigger)\\r\\n }\\r\\n else {\\r\\n shouldValidate = currentTrigger === trigger\\r\\n }\\r\\n\\r\\n if (shouldValidate && form.validateField) {\\r\\n form.validateField(props.prop)\\r\\n }\\r\\n }\\r\\n\\r\\n watch(() => props.prop, (newProp, oldProp) => {\\r\\n if (form) {\\r\\n if (oldProp) {\\r\\n form.removeField({ uid: instance?.uid, prop: oldProp })\\r\\n }\\r\\n if (newProp) {\\r\\n form.addField({ uid: instance?.uid, prop: newProp, getBoundingClientRect })\\r\\n }\\r\\n }\\r\\n })\\r\\n\\r\\n onMounted(() => {\\r\\n if (form && props.prop) {\\r\\n form.addField({ uid: instance?.uid, prop: props.prop, getBoundingClientRect })\\r\\n }\\r\\n })\\r\\n\\r\\n onUnmounted(() => {\\r\\n if (form && props.prop) {\\r\\n form.removeField({ uid: instance?.uid, prop: props.prop })\\r\\n }\\r\\n })\\r\\n\\r\\n return {\\r\\n form,\\r\\n error,\\r\\n labelPosition,\\r\\n labelWidth,\\r\\n size,\\r\\n getBoundingClientRect,\\r\\n validate,\\r\\n }\\r\\n}\\r\\n\\r\\nexport function useFormInject(props: any) {\\r\\n const form = inject<any>('rebornForm', null)\\r\\n const formItem = inject<any>('rebornFormItem', null)\\r\\n\\r\\n const size = computed(() => {\\r\\n return form?.props?.size || props.size\\r\\n })\\r\\n\\r\\n const disabled = computed(() => {\\r\\n return form?.props?.disabled || props.disabled\\r\\n })\\r\\n\\r\\n const orientation = computed(() => {\\r\\n return form?.props?.orientation || props.orientation\\r\\n })\\r\\n\\r\\n const isError = computed(() => {\\r\\n return formItem?.isError?.value || false\\r\\n })\\r\\n\\r\\n const validate = (trigger: 'blur' | 'change') => {\\r\\n if (formItem?.validate) {\\r\\n formItem.validate(trigger)\\r\\n }\\r\\n }\\r\\n\\r\\n return {\\r\\n form,\\r\\n size,\\r\\n disabled,\\r\\n orientation,\\r\\n isError,\\r\\n validate,\\r\\n }\\r\\n}\\r\\n\",\n \"composables/useLockScroll.ts\": \"import { onBeforeUnmount, onDeactivated, ref, watch } from 'vue'\\r\\n\\r\\nexport function useLockScroll(shouldLock: () => boolean) {\\r\\n const scrollLockCount = ref(0)\\r\\n\\r\\n const lock = () => {\\r\\n if (scrollLockCount.value === 0) {\\r\\n document.getElementsByTagName('body')[0].style.overflow = 'hidden'\\r\\n }\\r\\n scrollLockCount.value++\\r\\n }\\r\\n\\r\\n const unlock = () => {\\r\\n if (scrollLockCount.value > 0) {\\r\\n scrollLockCount.value--\\r\\n if (scrollLockCount.value === 0) {\\r\\n document.getElementsByTagName('body')[0].style.overflow = ''\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n const destroy = () => {\\r\\n shouldLock() && unlock()\\r\\n }\\r\\n\\r\\n watch(shouldLock, (value) => {\\r\\n value ? lock() : unlock()\\r\\n })\\r\\n\\r\\n onDeactivated(destroy)\\r\\n onBeforeUnmount(destroy)\\r\\n\\r\\n return {\\r\\n lock,\\r\\n unlock\\r\\n }\\r\\n}\\r\\n\"\n }\n} as const;\n\nexport type Platform = keyof typeof TEMPLATES;\n","{\r\n \"name\": \"reborn-ui\",\r\n \"version\": \"0.1.78\",\r\n \"description\": \"A CLI for Reborn UI\",\r\n \"author\": \"1997liuyh-boop\",\r\n \"license\": \"MIT\",\r\n \"repository\": {\r\n \"type\": \"git\",\r\n \"url\": \"https://github.com/1997liuyh-boop/Reborn-UI.git\"\r\n },\r\n \"type\": \"module\",\r\n \"bin\": {\r\n \"reborn-ui\": \"dist/index.js\"\r\n },\r\n \"files\": [\r\n \"dist\",\r\n \"registry\",\r\n \"README.md\"\r\n ],\r\n \"publishConfig\": {\r\n \"access\": \"public\"\r\n },\r\n \"scripts\": {\r\n \"cli\": \"tsx src/index.ts\",\r\n \"build\": \"tsup\",\r\n \"dev\": \"tsx src/index.ts\",\r\n \"clean\": \"rimraf dist\",\r\n \"prepare\": \"tsup\",\r\n \"templates:sync\": \"tsx src/scripts/sync-templates.ts\",\r\n \"registry:build\": \"tsx src/index.ts build --root ../.. --uniapp-source packages/uniapp-project/src/components\",\r\n \"prepack\": \"npm run templates:sync && npm run build && npm run registry:build\",\r\n \"prepublishOnly\": \"npm run templates:sync && npm run build && npm run registry:build\"\r\n },\r\n \"dependencies\": {\r\n \"chalk\": \"^5.6.2\",\r\n \"cli-progress\": \"^3.12.0\",\r\n \"commander\": \"^14.0.0\",\r\n \"execa\": \"^9.6.0\",\r\n \"figlet\": \"^1.9.4\",\r\n \"ora\": \"^9.0.0\",\r\n \"prompts\": \"^2.4.2\"\r\n },\r\n \"devDependencies\": {\r\n \"@types/cli-progress\": \"^3.11.6\",\r\n \"@types/figlet\": \"^1.7.0\",\r\n \"@types/node\": \"^22.10.7\",\r\n \"@types/prompts\": \"^2.4.9\",\r\n \"rimraf\": \"^6.0.1\",\r\n \"tsup\": \"^8.5.0\",\r\n \"tsx\": \"^4.20.0\",\r\n \"typescript\": \"^5.8.3\"\r\n }\r\n}\r\n"],"mappings":"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","names":["Command","path","fs","path","path","path","fs","path","fs","require","chalk","path","chalk","path","fs","Command","path","Command","fs","path","fs","fssync","Command","prompts","path","fs","fileURLToPath","findNearestPackageRoot","path","findWorkspaceRoot","fssync","fs","Command","prompts","cfgPath","workspaceRoot","findNearestPackageRoot","libUtilsPath","Command"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/add.ts","../src/utils/fs.ts","../src/utils/pm.ts","../src/utils/dependencies.ts","../src/utils/registry.ts","../src/utils/ui.ts","../src/commands/build.ts","../src/utils/imports.ts","../src/utils/transformers.ts","../src/commands/init.ts","../src/utils/templates.ts","../src/generated/templates.ts","../package.json"],"sourcesContent":["import { Command } from \"commander\";\r\nimport { addCommand } from \"./commands/add.js\";\r\nimport { buildCommand } from \"./commands/build.js\";\r\nimport { initCommand } from \"./commands/init.js\";\r\nimport packageJson from \"../package.json\" assert { type: \"json\" };\r\n\r\nconst program = new Command()\r\n .name(\"reborn-ui\")\r\n .description(\"Reborn UI - 组件安装与 registry 辅助 CLI\")\r\n .version(packageJson.version);\r\n\r\nprogram.addCommand(initCommand());\r\nprogram.addCommand(addCommand());\r\nprogram.addCommand(buildCommand());\r\n\r\nawait program.parseAsync(process.argv);\r\n\r\n\r\n","import path from \"node:path\";\r\nimport { Command } from \"commander\";\r\nimport prompts from \"prompts\";\r\nimport type { PackageManager, RegistryComponent } from \"../types.js\";\r\nimport { ensureDir, pathExists, writeTextFile } from \"../utils/fs.js\";\r\nimport {\r\n detectPackageManager,\r\n readPackageJson,\r\n getMissingDeps,\r\n installDeps,\r\n} from \"../utils/pm.js\";\r\nimport { getDependencies } from \"../utils/dependencies.js\";\r\nimport { defaultConfig, loadConfigCompat, loadRegistry } from \"../utils/registry.js\";\r\nimport cliProgress from \"cli-progress\";\r\nimport chalk from \"chalk\";\r\nimport { successLog } from \"../utils/ui.js\";\r\n\r\nfunction rewriteImports(params: {\r\n content: string;\r\n aliasSymbol: string;\r\n}) {\r\n const { content, aliasSymbol } = params;\r\n if (!aliasSymbol || aliasSymbol === \"@\") return content;\r\n\r\n // 仅替换项目根目录映射符号:把 \"@/xxx\" -> \"<aliasSymbol>/xxx\"\r\n // 注意:不要影响 scoped package(@scope/name),这里只替换 \"@/\" 前缀。\r\n return content.replaceAll(\"@/\", `${aliasSymbol}/`);\r\n}\r\n\r\nasync function writeComponentFiles(params: {\r\n cwd: string;\r\n componentsDir: string;\r\n aliasSymbol: string;\r\n component: RegistryComponent;\r\n overwrite?: boolean;\r\n onProgress?: () => void;\r\n platform: \"web\" | \"uniapp\";\r\n}) {\r\n const { cwd, componentsDir, aliasSymbol, component, overwrite, onProgress, platform } = params;\r\n const baseDir = path.join(cwd, componentsDir, component.name);\r\n await ensureDir(baseDir);\r\n\r\n for (const f of component.files) {\r\n // 过滤逻辑:\r\n // 1. 如果 f.target 存在且不等于 platform,跳过\r\n // 2. 如果 f.target 不存在,视为通用文件,不跳过\r\n if (f.target && f.target !== platform) {\r\n continue;\r\n }\r\n\r\n const target = path.join(baseDir, ...f.path.split(\"/\"));\r\n if (!overwrite && (await pathExists(target))) {\r\n onProgress?.();\r\n continue;\r\n }\r\n const nextContent = rewriteImports({ content: f.content, aliasSymbol });\r\n await writeTextFile(target, nextContent);\r\n onProgress?.();\r\n // 增加一个极小的延迟,让进度条看起来在“跑”\r\n await new Promise(r => setTimeout(r, 10));\r\n }\r\n\r\n return baseDir;\r\n}\r\n\r\nexport function addCommand() {\r\n const cmd = new Command(\"add\")\r\n .description(\"向项目中添加组件与相关依赖\")\r\n .argument(\"[components...]\", \"组件名(可多个)\")\r\n .option(\"--cwd <path>\", \"目标项目目录\", process.cwd())\r\n .option(\"--pm <pm>\", \"包管理器:pnpm|npm|yarn|bun\")\r\n .option(\"--yes\", \"跳过交互\", false)\r\n .option(\"--overwrite\", \"覆盖已存在文件\", false)\r\n .option(\"--config <path>\", \"配置文件路径(相对 cwd)\", \"components.json\")\r\n .option(\"--registry <pkgOrPath>\", \"覆盖配置里的 registry\")\r\n .option(\"--components-dir <path>\", \"覆盖配置里的 componentsDir\")\r\n .option(\"--lib-dir <path>\", \"覆盖配置里的 libDir\")\r\n .option(\"--alias-symbol <symbol>\", \"覆盖配置里的 aliasSymbol(默认 @)\")\r\n .action(async (components: string[], opts) => {\r\n const cwd = path.resolve(opts.cwd);\r\n const pm: PackageManager =\r\n opts.pm ?? (await detectPackageManager(cwd));\r\n\r\n const cfg = (await loadConfigCompat(cwd, opts.config)) ?? defaultConfig();\r\n if (opts.registry) cfg.registry = opts.registry;\r\n if (opts.componentsDir) cfg.componentsDir = opts.componentsDir;\r\n if (opts.libDir) cfg.libDir = opts.libDir;\r\n if (opts.aliasSymbol) cfg.aliasSymbol = opts.aliasSymbol;\r\n\r\n const registry = await loadRegistry({ cwd, registry: cfg.registry });\r\n\r\n let targets = components ?? [];\r\n if (!targets.length) {\r\n if (opts.yes) {\r\n throw new Error(\"未指定组件名;请传入组件参数或去掉 --yes 以交互选择。\");\r\n }\r\n const choices = registry.components?.map((c) => ({\r\n title: c.name,\r\n value: c.name,\r\n }));\r\n const res = await prompts(\r\n [\r\n {\r\n type: \"multiselect\",\r\n name: \"selected\",\r\n message: \"选择要添加的组件\",\r\n choices,\r\n min: 1,\r\n },\r\n ],\r\n {\r\n onCancel: () => {\r\n throw new Error(\"已取消\");\r\n },\r\n },\r\n );\r\n targets = res.selected ?? [];\r\n }\r\n\r\n // 询问平台 (Web / UniApp)\r\n const { platform } = await prompts({\r\n type: \"select\",\r\n name: \"platform\",\r\n message: \"选择目标平台\",\r\n choices: [\r\n { title: \"Web (默认)\", value: \"web\" },\r\n { title: \"UniApp\", value: \"uniapp\" },\r\n ],\r\n initial: 0,\r\n });\r\n\r\n if (!platform) {\r\n throw new Error(\"已取消\");\r\n }\r\n\r\n const allComponentsToInstall = new Set<string>(targets);\r\n const allNpmDependencies = new Set<string>();\r\n\r\n for (const target of targets) {\r\n const deps = getDependencies(target, platform as \"web\" | \"uniapp\");\r\n if (deps.components) {\r\n for (const c of deps.components) allComponentsToInstall.add(c);\r\n }\r\n if (deps.npmDependencies) {\r\n for (const d of deps.npmDependencies) allNpmDependencies.add(d);\r\n }\r\n }\r\n\r\n const additionalComponents = Array.from(allComponentsToInstall).filter(c => !targets.includes(c));\r\n const npmDependenciesArray = Array.from(allNpmDependencies);\r\n\r\n // Prompt for NPM dependencies\r\n if (npmDependenciesArray.length > 0) {\r\n const pkg = await readPackageJson(cwd);\r\n const missingDeps = getMissingDeps(pkg, npmDependenciesArray);\r\n if (missingDeps.length > 0) {\r\n console.log(chalk.blue(`\\n检测到当前组件需要以下未安装的 npm 依赖:${missingDeps.join(\", \")}`));\r\n const { installNpm } = await prompts({\r\n type: \"confirm\",\r\n name: \"installNpm\",\r\n message: `是否需要为这些组件安装以上 npm 依赖?`,\r\n initial: true,\r\n });\r\n\r\n if (installNpm) {\r\n console.log(chalk.cyan(\"正在安装 npm 依赖...\"));\r\n await installDeps({ cwd, pm, deps: missingDeps });\r\n successLog(`npm 依赖安装完成`);\r\n }\r\n }\r\n }\r\n\r\n let finalTargets = [...targets];\r\n if (additionalComponents.length > 0) {\r\n const missingComponents = [];\r\n for (const c of additionalComponents) {\r\n const baseDir = path.join(cwd, cfg.componentsDir, c);\r\n if (!(await pathExists(baseDir))) {\r\n missingComponents.push(c);\r\n }\r\n }\r\n\r\n if (missingComponents.length > 0) {\r\n console.log(chalk.blue(`\\n检测到需要前置或关联组件:${missingComponents.join(\", \")}`));\r\n const { installComponents } = await prompts({\r\n type: \"confirm\",\r\n name: \"installComponents\",\r\n message: `是否自动安装缺失的前置组件?`,\r\n initial: true,\r\n });\r\n if (installComponents) {\r\n finalTargets = [...finalTargets, ...missingComponents];\r\n }\r\n }\r\n }\r\n\r\n if (!opts.overwrite) {\r\n const existingComponents = [];\r\n for (const name of finalTargets) {\r\n const baseDir = path.join(cwd, cfg.componentsDir, name);\r\n if (await pathExists(baseDir)) {\r\n existingComponents.push(name);\r\n }\r\n }\r\n\r\n if (existingComponents.length > 0) {\r\n console.log(chalk.yellow(`\\n遇到已存在的组件:${existingComponents.join(\", \")}`));\r\n const { overwrite } = await prompts({\r\n type: \"confirm\",\r\n name: \"overwrite\",\r\n message: `是否覆盖并继续安装?`,\r\n initial: false,\r\n });\r\n\r\n if (!overwrite) {\r\n console.log(chalk.red(\"已终止安装\"));\r\n return;\r\n }\r\n opts.overwrite = true;\r\n }\r\n }\r\n\r\n const totalFiles = finalTargets.reduce((acc, name) => {\r\n const c = registry.components.find((x) => x.name === name);\r\n return acc + (c?.files.length ?? 0);\r\n }, 0);\r\n\r\n const bar = new cliProgress.SingleBar({\r\n format: '正在写入文件 |' + chalk.cyan('{bar}') + '| {percentage}% || {value}/{total} 文件',\r\n barCompleteChar: '\\u2588',\r\n barIncompleteChar: '\\u2591',\r\n hideCursor: true\r\n });\r\n\r\n bar.start(totalFiles, 0);\r\n\r\n for (const name of finalTargets) {\r\n const c = registry.components.find((x) => x.name === name);\r\n if (!c) {\r\n bar.stop();\r\n throw new Error(`registry 中不存在该组件:${name}`);\r\n }\r\n\r\n await writeComponentFiles({\r\n cwd,\r\n componentsDir: cfg.componentsDir,\r\n aliasSymbol: cfg.aliasSymbol ?? \"@\",\r\n component: c,\r\n overwrite: opts.overwrite,\r\n onProgress: () => bar.increment(),\r\n platform,\r\n });\r\n }\r\n bar.stop();\r\n\r\n console.log(\"\");\r\n for (const name of finalTargets) {\r\n successLog(`组件 ${chalk.bold(name)} 已成功添加到项目`);\r\n }\r\n\r\n // eslint-disable-next-line no-console\r\n console.log(`\\n${chalk.bold.green('DONE')} 已完成 ${finalTargets.length} 个组件的添加(pm=${pm})`);\r\n });\r\n\r\n return cmd;\r\n}\r\n\r\n\r\n","import { createHash } from \"node:crypto\";\r\nimport fs from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\n\r\nexport async function pathExists(p: string) {\r\n try {\r\n await fs.access(p);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport async function ensureDir(dirPath: string) {\r\n await fs.mkdir(dirPath, { recursive: true });\r\n}\r\n\r\nexport async function readJsonFile<T>(filePath: string): Promise<T> {\r\n const raw = await fs.readFile(filePath, \"utf8\");\r\n return JSON.parse(raw) as T;\r\n}\r\n\r\nexport async function writeJsonFile(filePath: string, data: unknown) {\r\n await ensureDir(path.dirname(filePath));\r\n await fs.writeFile(filePath, JSON.stringify(data, null, 2) + \"\\n\", \"utf8\");\r\n}\r\n\r\nexport async function writeTextFile(filePath: string, content: string) {\r\n await ensureDir(path.dirname(filePath));\r\n await fs.writeFile(filePath, content, \"utf8\");\r\n}\r\n\r\nexport async function listFilesRecursive(\r\n dirPath: string,\r\n opts?: { ignoreDirNames?: Set<string> },\r\n) {\r\n const ignoreDirNames =\r\n opts?.ignoreDirNames ??\r\n new Set([\"node_modules\", \".git\", \".nuxt\", \"dist\", \".output\"]);\r\n\r\n const out: string[] = [];\r\n\r\n async function walk(current: string) {\r\n const entries = await fs.readdir(current, { withFileTypes: true });\r\n for (const entry of entries) {\r\n const p = path.join(current, entry.name);\r\n if (entry.isDirectory()) {\r\n if (ignoreDirNames.has(entry.name)) continue;\r\n await walk(p);\r\n } else if (entry.isFile()) {\r\n out.push(p);\r\n }\r\n }\r\n }\r\n\r\n await walk(dirPath);\r\n return out;\r\n}\r\n\r\nexport async function copyDirRecursive(params: {\r\n fromDir: string;\r\n toDir: string;\r\n overwrite?: boolean;\r\n ignoreFileNames?: Set<string>;\r\n}) {\r\n const { fromDir, toDir, overwrite } = params;\r\n const ignoreFileNames = params.ignoreFileNames ?? new Set([\".DS_Store\"]);\r\n\r\n const entries = await fs.readdir(fromDir, { withFileTypes: true });\r\n await ensureDir(toDir);\r\n\r\n for (const entry of entries) {\r\n if (ignoreFileNames.has(entry.name)) continue;\r\n const from = path.join(fromDir, entry.name);\r\n const to = path.join(toDir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n await copyDirRecursive({ fromDir: from, toDir: to, overwrite, ignoreFileNames });\r\n continue;\r\n }\r\n\r\n if (!entry.isFile()) continue;\r\n\r\n if (!overwrite) {\r\n try {\r\n await fs.access(to);\r\n continue; // 已存在则跳过\r\n } catch {\r\n // not exists\r\n }\r\n }\r\n\r\n await ensureDir(path.dirname(to));\r\n await fs.copyFile(from, to);\r\n }\r\n}\r\n\r\nexport function sha1(text: string) {\r\n return createHash(\"sha1\").update(text).digest(\"hex\");\r\n}\r\n\r\n\r\n","import fs from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { execa } from \"execa\";\r\nimport type { PackageManager } from \"../types.js\";\r\nimport { pathExists, readJsonFile, writeJsonFile } from \"./fs.js\";\r\n\r\nexport async function detectPackageManager(cwd: string): Promise<PackageManager> {\r\n if (await pathExists(path.join(cwd, \"pnpm-lock.yaml\"))) return \"pnpm\";\r\n if (await pathExists(path.join(cwd, \"yarn.lock\"))) return \"yarn\";\r\n if (await pathExists(path.join(cwd, \"package-lock.json\"))) return \"npm\";\r\n if (await pathExists(path.join(cwd, \"bun.lockb\"))) return \"bun\";\r\n return \"pnpm\";\r\n}\r\n\r\nexport async function readPackageJson(\r\n cwd: string,\r\n): Promise<Record<string, any> & { dependencies?: Record<string, string>; devDependencies?: Record<string, string> }> {\r\n return await readJsonFile(path.join(cwd, \"package.json\"));\r\n}\r\n\r\nexport async function writePackageJson(cwd: string, pkg: unknown) {\r\n await writeJsonFile(path.join(cwd, \"package.json\"), pkg);\r\n}\r\n\r\nexport function getMissingDeps(\r\n pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> },\r\n deps: string[],\r\n) {\r\n const existing = new Set([\r\n ...Object.keys(pkg.dependencies ?? {}),\r\n ...Object.keys(pkg.devDependencies ?? {}),\r\n ]);\r\n return deps.filter((d) => !existing.has(d));\r\n}\r\n\r\nexport async function installDeps(params: {\r\n cwd: string;\r\n pm: PackageManager;\r\n deps: string[];\r\n dev?: boolean;\r\n}) {\r\n const { cwd, pm, deps, dev } = params;\r\n if (!deps.length) return;\r\n\r\n const args: string[] = [];\r\n if (pm === \"pnpm\") args.push(\"add\");\r\n else if (pm === \"npm\") args.push(\"install\");\r\n else if (pm === \"yarn\") args.push(\"add\");\r\n else if (pm === \"bun\") args.push(\"add\");\r\n\r\n if (dev) {\r\n if (pm === \"npm\") args.push(\"--save-dev\");\r\n else args.push(\"-D\");\r\n }\r\n\r\n args.push(...deps);\r\n\r\n await execa(pm, args, { cwd, stdio: \"inherit\" });\r\n}\r\n\r\nexport async function ensureJsonFile(cwd: string, relPath: string, defaultJson: unknown) {\r\n const p = path.join(cwd, relPath);\r\n if (await pathExists(p)) return;\r\n await fs.mkdir(path.dirname(p), { recursive: true });\r\n await fs.writeFile(p, JSON.stringify(defaultJson, null, 2) + \"\\n\", \"utf8\");\r\n}\r\n\r\n\r\n","export interface DependencyInfo {\r\n components?: string[];\r\n npmDependencies?: string[];\r\n}\r\n\r\nexport const DEPENDENCY_MAP: Record<string, DependencyInfo> = {\r\n // UniApp 版本的 Reborn Select 需要特定的前置组件和 lodash-es\r\n \"reborn-select/uniapp\": {\r\n components: [\"reborn-button\", \"reborn-picker-view\", \"reborn-popup\", \"reborn-select-trigger\"],\r\n npmDependencies: [\"lodash-es\", \"@types/lodash-es\"],\r\n },\r\n \"reborn-select-date/uniapp\": {\r\n components: [\"reborn-button\", \"reborn-picker-view\", \"reborn-popup\", \"reborn-select-trigger\"],\r\n npmDependencies: [\"lodash-es\", \"@types/lodash-es\"],\r\n },\r\n // 在此处添加其他已知的依赖映射\r\n};\r\n\r\n/**\r\n * 递归解析组件和 npm 依赖\r\n * @param componentName 例如 \"reborn-select/web\" 或 \"reborn-select/uniapp\"\r\n * @param platform 例如 \"web\" | \"uniapp\"\r\n */\r\nexport function getDependencies(componentName: string, platform?: \"web\" | \"uniapp\"): DependencyInfo {\r\n const result: DependencyInfo = { components: [], npmDependencies: [] };\r\n const visited = new Set<string>();\r\n\r\n function resolve(name: string) {\r\n const keyWithPlatform = platform ? `${name}/${platform}` : name;\r\n\r\n // 首先检查是否存在特定平台的映射\r\n const deps = DEPENDENCY_MAP[keyWithPlatform] || DEPENDENCY_MAP[name];\r\n if (!deps) return;\r\n\r\n if (deps.components) {\r\n for (const comp of deps.components) {\r\n if (!visited.has(comp)) {\r\n visited.add(comp);\r\n result.components!.push(comp);\r\n resolve(comp); // 递归解析依赖\r\n }\r\n }\r\n }\r\n\r\n if (deps.npmDependencies) {\r\n for (const npmDep of deps.npmDependencies) {\r\n if (!result.npmDependencies!.includes(npmDep)) {\r\n result.npmDependencies!.push(npmDep);\r\n }\r\n }\r\n }\r\n }\r\n\r\n resolve(componentName);\r\n\r\n return result;\r\n}\r\n","import path from \"node:path\";\r\nimport fs from \"node:fs\";\r\nimport { createRequire } from \"node:module\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport type { CliConfig, RegistryFile } from \"../types.js\";\r\nimport { pathExists, readJsonFile } from \"./fs.js\";\r\n\r\nexport const DEFAULT_CONFIG_PATH = \"components.json\";\r\n\r\nfunction findNearestPackageRoot(from: string) {\r\n // from: import.meta.url\r\n let dir = path.dirname(fileURLToPath(from));\r\n while (true) {\r\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\r\n const parent = path.dirname(dir);\r\n if (parent === dir) return dir;\r\n dir = parent;\r\n }\r\n}\r\n\r\nexport function defaultConfig(): CliConfig {\r\n return {\r\n schemaVersion: 1,\r\n componentsDir: \"components\",\r\n libDir: \"lib\",\r\n composablesDir: \"composables\",\r\n // 默认使用 CLI 包内置的 registry(随 reborn-ui 一起发布)\r\n registry: \"builtin\",\r\n // 项目根目录映射别名符号(默认 @)\r\n aliasSymbol: \"@\",\r\n };\r\n}\r\n\r\nexport async function loadConfig(cwd: string, configPath = DEFAULT_CONFIG_PATH) {\r\n const abs = path.isAbsolute(configPath)\r\n ? configPath\r\n : path.join(cwd, configPath);\r\n if (!(await pathExists(abs))) return null;\r\n return await readJsonFile<CliConfig>(abs);\r\n}\r\n\r\nexport function resolveRegistryJsonPath(params: { cwd: string; registry: string }) {\r\n const { cwd, registry } = params;\r\n\r\n // 0) 内置 registry\r\n if (!registry || registry === \"builtin\") {\r\n // 注意:CLI 经过打包后可能变成单文件(例如 dist/index.js),\r\n // import.meta.url 的相对基准会变化,不能用固定的 ../../registry/...\r\n // 这里通过向上查找最近的 package.json 来定位包根目录。\r\n const pkgRoot = findNearestPackageRoot(import.meta.url);\r\n return path.join(pkgRoot, \"registry\", \"registry.json\");\r\n }\r\n\r\n // 1) 如果是文件路径(包含分隔符或 .json),优先当成路径处理\r\n const looksLikePath =\r\n registry.includes(\"/\") ||\r\n registry.includes(\"\\\\\") ||\r\n registry.endsWith(\".json\");\r\n\r\n if (looksLikePath) {\r\n const abs = path.isAbsolute(registry) ? registry : path.join(cwd, registry);\r\n return abs;\r\n }\r\n\r\n // 2) 当成包名处理:默认读取 <pkg>/registry/registry.json\r\n const require = createRequire(import.meta.url);\r\n // 不显式绑定 cwd,避免 npx 场景下找不到 registry 包\r\n return require.resolve(`${registry}/registry/registry.json`);\r\n}\r\n\r\nexport async function loadRegistry(params: { cwd: string; registry: string }) {\r\n const jsonPath = resolveRegistryJsonPath(params);\r\n return await readJsonFile<RegistryFile>(jsonPath);\r\n}\r\n\r\n// 兼容旧配置文件名:shadcn-docs.json\r\nexport async function loadConfigCompat(cwd: string, configPath?: string) {\r\n if (configPath) return await loadConfig(cwd, configPath);\r\n const primary = await loadConfig(cwd, DEFAULT_CONFIG_PATH);\r\n if (primary) return primary;\r\n return await loadConfig(cwd, \"shadcn-docs.json\");\r\n}\r\n\r\n\r\n","import chalk from 'chalk';\r\nimport figlet from 'figlet';\r\n\r\n/**\r\n * 模拟打字机效果\r\n * @param text 要显示的文本\r\n * @param delay 每字符延迟时间 (ms)\r\n * @param newline 是否在结束时换行\r\n */\r\nexport async function typewriter(text: string, delay: number = 15, newline: boolean = true) {\r\n for (const char of text) {\r\n process.stdout.write(char);\r\n if (delay > 0) {\r\n await new Promise((resolve) => setTimeout(resolve, delay));\r\n }\r\n }\r\n if (newline) {\r\n process.stdout.write('\\n');\r\n }\r\n}\r\n\r\n/**\r\n * 显示 ASCII Logo\r\n */\r\nexport async function showLogo(text: string = 'Reborn UI') {\r\n return new Promise<void>((resolve) => {\r\n figlet.text(text, {\r\n font: 'Slant',\r\n horizontalLayout: 'default',\r\n verticalLayout: 'default',\r\n width: 80,\r\n whitespaceBreak: true\r\n }, async (err, data) => {\r\n if (err) {\r\n console.log(gradientText(text));\r\n resolve();\r\n return;\r\n }\r\n if (data) {\r\n const lines = data.split('\\n');\r\n for (const line of lines) {\r\n console.log(gradientText(line));\r\n await new Promise(r => setTimeout(r, 20)); // 每行显示间隔,增加动感\r\n }\r\n }\r\n resolve();\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * 带有样式的成功提示\r\n */\r\nexport function successLog(message: string) {\r\n console.log(`${chalk.green('✔')} ${message}`);\r\n}\r\n\r\n/**\r\n * 带有样式的警告提示\r\n */\r\nexport function warnLog(message: string) {\r\n console.log(`${chalk.yellow('⚠')} ${message}`);\r\n}\r\n\r\n/**\r\n * 带有样式的错误提示\r\n */\r\nexport function errorLog(message: string) {\r\n console.log(`${chalk.red('✘')} ${message}`);\r\n}\r\n\r\n/**\r\n * 渐变色文本 (简单模拟,不依赖第三方复杂渐变库)\r\n */\r\nexport function gradientText(text: string) {\r\n const colors = [\r\n chalk.hex('#FF0080'),\r\n chalk.hex('#FF8C00'),\r\n chalk.hex('#40E0D0'),\r\n chalk.hex('#0080FF'),\r\n chalk.hex('#7B68EE'),\r\n ];\r\n\r\n let result = '';\r\n for (let i = 0; i < text.length; i++) {\r\n const color = colors[i % colors.length];\r\n result += color!(text[i]);\r\n }\r\n return result;\r\n}\r\n","import path from \"node:path\";\r\nimport fs from \"node:fs/promises\";\r\nimport fssync from \"node:fs\";\r\nimport { Command } from \"commander\";\r\nimport type { RegistryComponent, RegistryFile } from \"../types.js\";\r\nimport { listFilesRecursive, sha1, writeJsonFile } from \"../utils/fs.js\";\r\nimport { extractNpmDependenciesFromText } from \"../utils/imports.js\";\r\n\r\nfunction isAllowedFile(filePath: string) {\r\n const ext = path.extname(filePath).toLowerCase();\r\n return [\r\n \".vue\",\r\n \".ts\",\r\n \".js\",\r\n \".json\",\r\n \".css\",\r\n \".md\",\r\n \".svg\",\r\n ].includes(ext);\r\n}\r\n\r\nimport { transformToUniapp } from \"../utils/transformers.js\";\r\n\r\nfunction findWorkspaceRoot(startDir: string) {\r\n let current = path.resolve(startDir);\r\n for (; ;) {\r\n const marker = path.join(current, \"pnpm-workspace.yaml\");\r\n if (fssync.existsSync(marker)) return current;\r\n const parent = path.dirname(current);\r\n if (parent === current) return startDir;\r\n current = parent;\r\n }\r\n}\r\n\r\nexport function buildCommand() {\r\n const cmd = new Command(\"build\")\r\n .description(\"(内部)扫描组件源码并生成 registry JSON\")\r\n .option(\"--root <path>\", \"仓库根目录(默认自动向上查找 pnpm-workspace.yaml)\")\r\n .option(\r\n \"--source <path>\",\r\n \"组件源码目录(相对 root)\",\r\n \"app/components/reborn/ui\",\r\n )\r\n .option(\r\n \"--uniapp-source <path>\",\r\n \"UniApp 组件源码目录(相对 root),如果不提供则通过转换生成\",\r\n \"\",\r\n )\r\n .option(\r\n \"--out <path>\",\r\n \"输出 registry.json 路径(相对 root)\",\r\n \"packages/cli/registry/registry.json\",\r\n )\r\n .option(\r\n \"--also-out <path>\",\r\n \"额外再输出一份 registry.json(可重复传参)\",\r\n (val, acc: string[]) => {\r\n acc.push(val);\r\n return acc;\r\n },\r\n [],\r\n )\r\n .action(async (opts) => {\r\n const rootDir = opts.root\r\n ? path.resolve(opts.root)\r\n : findWorkspaceRoot(process.cwd());\r\n const sourceDir = path.join(rootDir, opts.source);\r\n const uniappSourceDir = opts.uniappSource\r\n ? path.join(rootDir, opts.uniappSource)\r\n : \"\";\r\n const outPath = path.join(rootDir, opts.out);\r\n const alsoOutPaths: string[] = (opts.alsoOut ?? [])?.map((p: string) =>\r\n path.join(rootDir, p),\r\n );\r\n\r\n const dirents = await fs.readdir(sourceDir, { withFileTypes: true });\r\n let componentDirs = dirents\r\n .filter((d) => d.isDirectory())\r\n ?.map((d) => d.name);\r\n\r\n if (uniappSourceDir && fssync.existsSync(uniappSourceDir)) {\r\n const uniappDirents = await fs.readdir(uniappSourceDir, { withFileTypes: true });\r\n const uniappDirs = uniappDirents\r\n .filter((d) => d.isDirectory())\r\n ?.map((d) => d.name);\r\n for (const dir of uniappDirs) {\r\n if (!componentDirs.includes(dir)) {\r\n componentDirs.push(dir);\r\n }\r\n }\r\n }\r\n\r\n componentDirs = componentDirs.sort((a, b) => a.localeCompare(b));\r\n\r\n const components: RegistryComponent[] = [];\r\n\r\n for (const componentName of componentDirs) {\r\n const name = componentName;\r\n const absComponentDir = path.join(sourceDir, componentName);\r\n let absFiles: string[] = [];\r\n\r\n if (fssync.existsSync(absComponentDir)) {\r\n absFiles = (await listFilesRecursive(absComponentDir)).filter(isAllowedFile);\r\n }\r\n const files: RegistryComponent[\"files\"] = [];\r\n const depSet = new Set<string>();\r\n\r\n for (const absFile of absFiles) {\r\n const rel = path\r\n .relative(absComponentDir, absFile)\r\n .split(path.sep)\r\n .join(\"/\");\r\n const content = await fs.readFile(absFile, \"utf8\");\r\n\r\n const ext = path.extname(absFile).toLowerCase();\r\n\r\n // 1. Web 版本(原样)\r\n if (ext === \".vue\") {\r\n files.push({ path: rel, content, target: \"web\" });\r\n } else {\r\n // Check for collision with UniApp source\r\n let target: \"web\" | \"uniapp\" | undefined;\r\n if (uniappSourceDir) {\r\n const parts = rel.split(\"/\");\r\n const uniappFile = path.join(uniappSourceDir, name, ...parts);\r\n if (fssync.existsSync(uniappFile)) {\r\n target = \"web\";\r\n }\r\n }\r\n if (target) {\r\n files.push({ path: rel, content, target });\r\n } else {\r\n files.push({ path: rel, content });\r\n }\r\n }\r\n\r\n // 只从代码文件里抽依赖\r\n if (ext === \".ts\" || ext === \".js\" || ext === \".vue\") {\r\n for (const dep of extractNpmDependenciesFromText(content)) {\r\n depSet.add(dep);\r\n }\r\n }\r\n }\r\n\r\n // 2. UniApp 版本\r\n // 如果提供了 uniappSourceDir,从那里读取;否则通过转换生成\r\n if (uniappSourceDir) {\r\n const uniappComponentDir = path.join(uniappSourceDir, name);\r\n if (fssync.existsSync(uniappComponentDir)) {\r\n const uniappFiles = (await listFilesRecursive(uniappComponentDir)).filter(\r\n isAllowedFile,\r\n );\r\n\r\n for (const absFile of uniappFiles) {\r\n const rel = path\r\n .relative(uniappComponentDir, absFile)\r\n .split(path.sep)\r\n .join(\"/\");\r\n const content = await fs.readFile(absFile, \"utf8\");\r\n const ext = path.extname(absFile).toLowerCase();\r\n\r\n files.push({ path: rel, content, target: \"uniapp\" });\r\n\r\n // 抽取依赖\r\n if (ext === \".ts\" || ext === \".js\" || ext === \".vue\") {\r\n for (const dep of extractNpmDependenciesFromText(content)) {\r\n depSet.add(dep);\r\n }\r\n }\r\n }\r\n }\r\n } else {\r\n // 通过转换生成 UniApp 版本\r\n for (const absFile of absFiles) {\r\n const ext = path.extname(absFile).toLowerCase();\r\n if (ext === \".vue\") {\r\n const rel = path\r\n .relative(absComponentDir, absFile)\r\n .split(path.sep)\r\n .join(\"/\");\r\n const content = await fs.readFile(absFile, \"utf8\");\r\n files.push({\r\n path: rel,\r\n content: transformToUniapp(content),\r\n target: \"uniapp\",\r\n });\r\n }\r\n }\r\n }\r\n\r\n components.push({\r\n name,\r\n dependencies: [...depSet].sort(),\r\n files,\r\n });\r\n }\r\n\r\n const registry: RegistryFile = {\r\n schemaVersion: 1,\r\n generatedAt: new Date().toISOString(),\r\n source: {\r\n rootDir: rootDir.split(path.sep).join(\"/\"),\r\n componentsDir: opts.source,\r\n },\r\n components,\r\n };\r\n\r\n async function writeOut(targetRegistryPath: string) {\r\n const outComponentsDir = path.join(\r\n path.dirname(targetRegistryPath),\r\n \"components\",\r\n );\r\n await writeJsonFile(targetRegistryPath, registry);\r\n\r\n // 额外输出每个组件的 json,方便调试/按需读取\r\n await fs.mkdir(outComponentsDir, { recursive: true });\r\n for (const c of components) {\r\n await writeJsonFile(\r\n path.join(outComponentsDir, `${c.name}.json`),\r\n {\r\n ...c,\r\n fileCount: c.files.length,\r\n contentHash: sha1(JSON.stringify(c.files?.map((f) => f.content))),\r\n },\r\n );\r\n }\r\n }\r\n\r\n await writeOut(outPath);\r\n for (const p of alsoOutPaths) await writeOut(p);\r\n\r\n // eslint-disable-next-line no-console\r\n console.log(\r\n `registry 已生成:${path.relative(process.cwd(), outPath)}(${components.length} 个组件)`,\r\n );\r\n });\r\n\r\n return cmd;\r\n}\r\n\r\n\r\n","const IMPORT_RE =\r\n /\\bfrom\\s+[\"']([^\"']+)[\"']|\\bimport\\(\\s*[\"']([^\"']+)[\"']\\s*\\)|\\brequire\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/g;\r\n\r\nfunction normalizePackageName(specifier: string) {\r\n // ignore relative/alias/virtual\r\n if (\r\n specifier.startsWith(\".\") ||\r\n specifier.startsWith(\"/\") ||\r\n specifier.startsWith(\"@/\") ||\r\n specifier.startsWith(\"~/\") ||\r\n specifier.startsWith(\"#\") ||\r\n specifier.startsWith(\"virtual:\")\r\n ) {\r\n return null;\r\n }\r\n\r\n // scoped package: @scope/name[/...]\r\n if (specifier.startsWith(\"@\")) {\r\n const parts = specifier.split(\"/\");\r\n if (parts.length >= 2) return `${parts[0]}/${parts[1]}`;\r\n return specifier;\r\n }\r\n\r\n // normal package: name[/...]\r\n return specifier.split(\"/\")[0] ?? null;\r\n}\r\n\r\nexport function extractNpmDependenciesFromText(text: string) {\r\n const out = new Set<string>();\r\n\r\n for (const match of text.matchAll(IMPORT_RE)) {\r\n const spec = match[1] ?? match[2] ?? match[3];\r\n if (!spec) continue;\r\n const pkg = normalizePackageName(spec);\r\n if (!pkg) continue;\r\n out.add(pkg);\r\n }\r\n\r\n // 常见“框架自带/不应自动安装”的虚拟模块\r\n out.delete(\"nuxt\");\r\n out.delete(\"vue\");\r\n\r\n return [...out].sort();\r\n}\r\n\r\n\r\n","\r\nexport function transformToUniapp(code: string): string {\r\n // 1. 标签替换\r\n // div -> view\r\n // span, font -> text(注意:span可能嵌套,正则要注意)\r\n // ul, li -> view\r\n // img -> image\r\n // a -> navigator\r\n // select -> picker\r\n // iframe -> web-view\r\n\r\n let newCode = code;\r\n\r\n // 简单正则替换标签名\r\n const tagMap: Record<string, string> = {\r\n div: \"view\",\r\n span: \"text\",\r\n font: \"text\",\r\n ul: \"view\",\r\n li: \"view\",\r\n img: \"image\",\r\n a: \"navigator\",\r\n select: \"picker\",\r\n iframe: \"web-view\",\r\n };\r\n\r\n for (const [k, v] of Object.entries(tagMap)) {\r\n // 匹配 <tag ...> 和 </tag>\r\n // 1. <tag\r\n newCode = newCode.replace(new RegExp(`<${k}(\\\\s+|>)`, \"g\"), `<${v}$1`);\r\n // 2. </tag>\r\n newCode = newCode.replace(new RegExp(`<\\\\/${k}>`, \"g\"), `</${v}>`);\r\n }\r\n\r\n // 2. 特殊处理\r\n // input[type=\"search\"] -> type=\"text\" confirm-type=\"search\"\r\n newCode = newCode.replace(/type=[\"']search[\"']/g, 'confirm-type=\"search\"');\r\n\r\n return newCode;\r\n}\r\n","import path from \"node:path\";\r\nimport fs from \"node:fs/promises\";\r\nimport fssync from \"node:fs\";\r\nimport { Command } from \"commander\";\r\nimport prompts from \"prompts\";\r\nimport type { CliConfig, PackageManager } from \"../types.js\";\r\nimport { copyDirRecursive, ensureDir, listFilesRecursive, pathExists, writeJsonFile, writeTextFile } from \"../utils/fs.js\";\r\nimport { detectPackageManager } from \"../utils/pm.js\";\r\nimport { DEFAULT_CONFIG_PATH, defaultConfig, loadConfigCompat } from \"../utils/registry.js\";\r\nimport { findNearestPackageRoot } from \"../utils/templates.js\";\r\nimport { TEMPLATES } from \"../generated/templates.js\";\r\nimport { gradientText, showLogo, typewriter } from \"../utils/ui.js\";\r\n\r\nfunction looksLikeNuxtProject(cwd: string) {\r\n return Promise.all([\r\n pathExists(path.join(cwd, \"nuxt.config.ts\")),\r\n pathExists(path.join(cwd, \"nuxt.config.js\")),\r\n pathExists(path.join(cwd, \"nuxt.config.mjs\")),\r\n ]).then((arr) => arr.some(Boolean));\r\n}\r\n\r\nfunction findWorkspaceRoot(startDir: string) {\r\n let current = path.resolve(startDir);\r\n for (; ;) {\r\n const marker = path.join(current, \"pnpm-workspace.yaml\");\r\n if (fssync.existsSync(marker)) return current;\r\n const parent = path.dirname(current);\r\n if (parent === current) return startDir;\r\n current = parent;\r\n }\r\n}\r\n\r\n\r\n// function makeDefaultTailwindConfig removed in favor of template file\r\n\r\n\r\n\r\n\r\nfunction cnUtilsTs(params: { importPath?: string }) {\r\n // importPath 预留:如果用户想从别处导入 clsx/twMerge\r\n void params;\r\n return `import { type ClassValue, clsx } from \"clsx\";\\nimport { twMerge } from \"tailwind-merge\";\\n\\nexport function cn(...inputs: ClassValue[]) {\\n return twMerge(clsx(inputs));\\n}\\n`;\r\n}\r\n\r\nasync function rewriteAliasInDir(params: {\r\n cwd: string;\r\n targetDir: string;\r\n aliasSymbol: string;\r\n}) {\r\n const { cwd, targetDir, aliasSymbol } = params;\r\n if (!aliasSymbol || aliasSymbol === \"@\") return;\r\n const absDir = path.join(cwd, targetDir);\r\n if (!(await pathExists(absDir))) return;\r\n\r\n const files = await listFilesRecursive(absDir);\r\n for (const f of files) {\r\n const ext = path.extname(f).toLowerCase();\r\n // 只处理常见文本文件,避免误改二进制\r\n if (![\".ts\", \".tsx\", \".js\", \".jsx\", \".vue\", \".mjs\", \".cjs\"].includes(ext)) continue;\r\n const raw = await fs.readFile(f, \"utf8\");\r\n const next = raw.replaceAll(\"@/\", `${aliasSymbol}/`);\r\n if (next !== raw) await fs.writeFile(f, next, \"utf8\");\r\n }\r\n}\r\n\r\nasync function copyTemplates(params: {\r\n cwd: string;\r\n workspaceRoot: string;\r\n platform: \"web\" | \"uniapp\";\r\n cfg: CliConfig;\r\n overwrite?: boolean;\r\n}) {\r\n const { cwd, workspaceRoot, platform, cfg, overwrite } = params;\r\n\r\n // 1. 尝试从仓库源码目录拷贝(本地开发场景)\r\n const repoPaths = {\r\n web: {\r\n lib: path.join(workspaceRoot, \"app/lib\"),\r\n composables: path.join(workspaceRoot, \"app/composables\"),\r\n },\r\n uniapp: {\r\n lib: path.join(workspaceRoot, \"packages/uniapp-project/src/lib\"),\r\n composables: path.join(workspaceRoot, \"packages/uniapp-project/src/composables\"),\r\n },\r\n };\r\n\r\n const currentRepoPaths = repoPaths[platform];\r\n let copiedFromRepo = false;\r\n\r\n if (await pathExists(currentRepoPaths.lib)) {\r\n await copyDirRecursive({\r\n fromDir: currentRepoPaths.lib,\r\n toDir: path.join(cwd, cfg.libDir),\r\n overwrite,\r\n });\r\n copiedFromRepo = true;\r\n }\r\n\r\n if (await pathExists(currentRepoPaths.composables)) {\r\n await copyDirRecursive({\r\n fromDir: currentRepoPaths.composables,\r\n toDir: path.join(cwd, cfg.composablesDir),\r\n overwrite,\r\n ignoreFileNames: platform === \"web\" ? new Set([\"useComponentCode.ts\", \"useCopyToClipboard.ts\",\"getComponentCode.ts\",\"getUniappCode.ts\"]) : undefined,\r\n });\r\n copiedFromRepo = true;\r\n }\r\n\r\n // 2. 如果不是在仓库内运行(例如 npx),则使用生成的字符串模板\r\n if (!copiedFromRepo) {\r\n const platformTemplates = TEMPLATES[platform];\r\n for (const [relPath, content] of Object.entries(platformTemplates)) {\r\n let targetPath = \"\";\r\n if (relPath.startsWith(\"lib/\")) {\r\n targetPath = path.join(cwd, cfg.libDir, relPath.replace(\"lib/\", \"\"));\r\n } else if (relPath.startsWith(\"composables/\")) {\r\n targetPath = path.join(cwd, cfg.composablesDir, relPath.replace(\"composables/\", \"\"));\r\n }\r\n\r\n if (targetPath) {\r\n if (!overwrite && (await pathExists(targetPath))) continue;\r\n await writeTextFile(targetPath, content);\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport function initCommand() {\r\n const cmd = new Command(\"init\")\r\n .description(\"初始化新项目\")\r\n .option(\"--cwd <path>\", \"目标项目目录\", process.cwd())\r\n .option(\"--pm <pm>\", \"包管理器:pnpm|npm|yarn|bun\")\r\n .option(\"--yes\", \"跳过交互,使用默认值\", false)\r\n .option(\"--overwrite\", \"覆盖已存在的模板文件(lib/composables)\", false)\r\n .option(\r\n \"--config <path>\",\r\n \"配置文件路径(相对 cwd)\",\r\n DEFAULT_CONFIG_PATH,\r\n )\r\n .option(\r\n \"--components-dir <path>\",\r\n \"组件写入目录\",\r\n defaultConfig().componentsDir,\r\n )\r\n .option(\r\n \"--lib-dir <path>\",\r\n \"lib 目录(cn/utils)\",\r\n defaultConfig().libDir,\r\n )\r\n .option(\r\n \"--composables-dir <path>\",\r\n \"composables 目录\",\r\n defaultConfig().composablesDir,\r\n )\r\n .option(\r\n \"--alias-symbol <symbol>\",\r\n \"项目根目录映射别名符号(默认 @)\",\r\n defaultConfig().aliasSymbol,\r\n )\r\n .option(\"--platform <platform>\", \"目标平台:web|uniapp\", \"web\")\r\n .option(\"--registry <pkgOrPath>\", \"registry 来源(默认 builtin)\", defaultConfig().registry)\r\n .action(async (opts) => {\r\n const cwd = path.resolve(opts.cwd);\r\n\r\n // eslint-disable-next-line no-console\r\n console.log(\r\n \"提示:项目中有部分依赖需要使用@/ 路径进行配置,请您安装到项目中配置好的路径下,请慎重选择文件位置\",\r\n );\r\n\r\n const pkgPath = path.join(cwd, \"package.json\");\r\n if (!(await pathExists(pkgPath))) {\r\n throw new Error(`未找到 package.json:${pkgPath}`);\r\n }\r\n\r\n const pm: PackageManager =\r\n opts.pm ?? (await detectPackageManager(cwd));\r\n\r\n const cfg: CliConfig = {\r\n schemaVersion: 1,\r\n componentsDir: opts.componentsDir,\r\n libDir: opts.libDir,\r\n composablesDir: opts.composablesDir,\r\n aliasSymbol: opts.aliasSymbol,\r\n registry: opts.registry,\r\n platform: opts.platform,\r\n };\r\n\r\n // 如果已存在 components.json,默认沿用(除非用户显式传参覆盖)\r\n const existing = await loadConfigCompat(cwd);\r\n if (existing) {\r\n cfg.componentsDir = opts.componentsDir ?? existing.componentsDir ?? cfg.componentsDir;\r\n cfg.libDir = opts.libDir ?? existing.libDir ?? cfg.libDir;\r\n cfg.composablesDir = opts.composablesDir ?? existing.composablesDir ?? cfg.composablesDir;\r\n cfg.aliasSymbol = opts.aliasSymbol ?? existing.aliasSymbol ?? cfg.aliasSymbol;\r\n cfg.registry = opts.registry ?? existing.registry ?? cfg.registry;\r\n cfg.platform = opts.platform ?? existing.platform ?? cfg.platform;\r\n }\r\n\r\n if (!opts.yes) {\r\n const nuxt = await looksLikeNuxtProject(cwd);\r\n const res = await prompts(\r\n [\r\n {\r\n type: \"select\",\r\n name: \"platform\",\r\n message: \"选择目标平台\",\r\n choices: [\r\n { title: \"Web (默认)\", value: \"web\" },\r\n { title: \"UniApp\", value: \"uniapp\" },\r\n ],\r\n initial: cfg.platform === \"uniapp\" ? 1 : 0,\r\n },\r\n {\r\n type: \"text\",\r\n name: \"componentsDir\",\r\n message: \"组件目录(componentsDir)\",\r\n initial: cfg.componentsDir,\r\n },\r\n {\r\n type: \"text\",\r\n name: \"libDir\",\r\n message: \"lib 目录(libDir,用于 cn/utils)\",\r\n initial: cfg.libDir,\r\n },\r\n {\r\n type: \"text\",\r\n name: \"composablesDir\",\r\n message: \"composables 目录(composablesDir)\",\r\n initial: cfg.composablesDir,\r\n },\r\n {\r\n type: \"text\",\r\n name: \"aliasSymbol\",\r\n message: \"基于项目根目录的“映射”的符号是?(aliasSymbol)\",\r\n initial: cfg.aliasSymbol ?? \"@\",\r\n },\r\n ],\r\n {\r\n onCancel: () => {\r\n throw new Error(\"已取消\");\r\n },\r\n },\r\n );\r\n\r\n cfg.platform = res.platform ?? cfg.platform;\r\n cfg.componentsDir = res.componentsDir ?? cfg.componentsDir;\r\n cfg.libDir = res.libDir ?? cfg.libDir;\r\n cfg.composablesDir = res.composablesDir ?? cfg.composablesDir;\r\n cfg.aliasSymbol = res.aliasSymbol ?? cfg.aliasSymbol;\r\n\r\n // 写配置\r\n const cfgPath = path.join(cwd, opts.config);\r\n await writeJsonFile(cfgPath, cfg);\r\n\r\n // 复制模板:lib/ + composables/\r\n const workspaceRoot = findWorkspaceRoot(findNearestPackageRoot(import.meta.url));\r\n await copyTemplates({\r\n cwd,\r\n workspaceRoot,\r\n platform: cfg.platform as \"web\" | \"uniapp\",\r\n cfg,\r\n overwrite: opts.overwrite,\r\n });\r\n\r\n // 仅替换 \"@/...\" 的别名符号,不改其它路径内容\r\n await rewriteAliasInDir({ cwd, targetDir: cfg.libDir, aliasSymbol: cfg.aliasSymbol ?? \"@\" });\r\n await rewriteAliasInDir({\r\n cwd,\r\n targetDir: cfg.composablesDir,\r\n aliasSymbol: cfg.aliasSymbol ?? \"@\",\r\n });\r\n\r\n // 兜底:如果用户模板里没有 utils.ts,则生成 cn\r\n const libUtilsPath = path.join(cwd, cfg.libDir, \"utils.ts\");\r\n if (!(await pathExists(libUtilsPath))) await writeTextFile(libUtilsPath, cnUtilsTs({}));\r\n\r\n console.log(`已写入配置:${path.relative(process.cwd(), cfgPath)};并生成 cn/utils(pm=${pm})`);\r\n console.log(\"请按照 https://tw.icebreaker.top/docs/quick-start/v4/uni-app-vite 指引进行项目配置初始化\");\r\n\r\n console.log(\"\");\r\n await showLogo();\r\n await typewriter(gradientText(\"感谢使用 Reborn UI ! ✨\"), 20);\r\n return;\r\n }\r\n\r\n // --yes:直接写默认配置\r\n const cfgPath = path.join(cwd, opts.config);\r\n await ensureDir(path.dirname(cfgPath));\r\n await fs.writeFile(cfgPath, JSON.stringify(cfg, null, 2) + \"\\n\", \"utf8\");\r\n\r\n // 复制模板逻辑\r\n const workspaceRoot = findWorkspaceRoot(findNearestPackageRoot(import.meta.url));\r\n await copyTemplates({\r\n cwd,\r\n workspaceRoot,\r\n platform: cfg.platform as \"web\" | \"uniapp\",\r\n cfg,\r\n overwrite: opts.overwrite,\r\n });\r\n\r\n // 仅替换 \"@/...\" 的别名符号,不改其它路径内容\r\n await rewriteAliasInDir({ cwd, targetDir: cfg.libDir, aliasSymbol: cfg.aliasSymbol ?? \"@\" });\r\n await rewriteAliasInDir({\r\n cwd,\r\n targetDir: cfg.composablesDir,\r\n aliasSymbol: cfg.aliasSymbol ?? \"@\",\r\n });\r\n\r\n // 兜底:如果用户模板里没有 utils.ts,则生成 cn\r\n const libUtilsPath = path.join(cwd, cfg.libDir, \"utils.ts\");\r\n if (!(await pathExists(libUtilsPath))) await writeTextFile(libUtilsPath, cnUtilsTs({}));\r\n\r\n // eslint-disable-next-line no-console\r\n console.log(`已初始化:${path.relative(process.cwd(), cfgPath)};并生成 cn/utils(pm=${pm})`);\r\n console.log(\"请按照 https://tw.icebreaker.top/docs/quick-start/v4/uni-app-vite 指引进行项目配置初始化\");\r\n\r\n console.log(\"\");\r\n await showLogo();\r\n await typewriter(gradientText(\"感谢使用 Reborn UI ! ✨\"), 2);\r\n });\r\n\r\n return cmd;\r\n}\r\n\r\n\r\n","import path from \"node:path\";\r\nimport fs from \"node:fs\";\r\nimport { fileURLToPath } from \"node:url\";\r\n\r\nexport function findNearestPackageRoot(from: string) {\r\n // from: import.meta.url\r\n let dir = path.dirname(fileURLToPath(from));\r\n while (true) {\r\n if (fs.existsSync(path.join(dir, \"package.json\"))) return dir;\r\n const parent = path.dirname(dir);\r\n if (parent === dir) return dir;\r\n dir = parent;\r\n }\r\n}\r\n\r\n\r\n\r\n\r\n\r\n\r\n","// 此文件由 sync-templates.ts 自动生成,请勿手动修改\nexport const TEMPLATES = {\n \"web\": {\n \"lib/tv.ts\": \"import { createTV } from \\\"tailwind-variants\\\";\\r\\nimport { twMergeConfig } from \\\"./utils\\\";\\r\\n\\r\\nexport const tv = createTV({\\r\\n twMergeConfig,\\r\\n});\\r\\nexport type { VariantProps } from \\\"tailwind-variants\\\";\\r\\n\",\n \"lib/utils.ts\": \"import type { ClassValue } from \\\"clsx\\\";\\r\\nimport { clsx } from \\\"clsx\\\";\\r\\nimport { extendTailwindMerge } from \\\"tailwind-merge\\\";\\r\\n\\r\\nexport const twMergeConfig = {\\r\\n extend: {\\r\\n classGroups: {\\r\\n \\\"font-size\\\": [\\r\\n {\\r\\n text: [\\r\\n (value: string) => !isNaN(Number(value)),\\r\\n (value: string) => value.startsWith(\\\"caption-\\\"),\\r\\n (value: string) => value.startsWith(\\\"body-\\\"),\\r\\n (value: string) => value.startsWith(\\\"title-\\\"),\\r\\n ],\\r\\n },\\r\\n ],\\r\\n },\\r\\n },\\r\\n};\\r\\n\\r\\nconst customTwMerge = extendTailwindMerge(twMergeConfig);\\r\\n\\r\\nexport function cn(...inputs: ClassValue[]) {\\r\\n return customTwMerge(clsx(inputs));\\r\\n}\\r\\n\\r\\nexport type ObjectValues<T> = T[keyof T];\\r\\n\",\n \"composables/useFieldGroup.ts\": \"\\r\\nimport { ref } from 'vue'\\r\\n\\r\\nexport function useFieldGroup(props: any) {\\r\\n return {\\r\\n disabled: ref(undefined),\\r\\n isError: ref(undefined),\\r\\n orientation: ref(undefined),\\r\\n size: ref(undefined)\\r\\n }\\r\\n}\\r\\n\",\n \"composables/useMouseState.ts\": \"import { readonly, ref } from \\\"vue\\\";\\r\\n\\r\\nexport function useMouseState() {\\r\\n const isMouseEntered = ref(false);\\r\\n\\r\\n function setMouseEntered(value: boolean) {\\r\\n isMouseEntered.value = value;\\r\\n }\\r\\n\\r\\n return {\\r\\n isMouseEntered: readonly(isMouseEntered),\\r\\n setMouseEntered,\\r\\n };\\r\\n}\\r\\n\",\n \"composables/useNavigation.ts\": \"import type { ContentNavigationItem } from \\\"@nuxt/content\\\";\\r\\n\\r\\nexport function useNavigation(navigation?: Ref<ContentNavigationItem[]>) {\\r\\n const route = useRoute();\\r\\n\\r\\n const children = computed(() => {\\r\\n const nav = toValue(navigation);\\r\\n\\r\\n // Get the current path segments\\r\\n const pathSegments = route.path.split(\\\"/\\\").filter(Boolean);\\r\\n\\r\\n // Need at least one section (e.g., ['components', 'button'])\\r\\n if (pathSegments.length < 1) {\\r\\n return [];\\r\\n }\\r\\n\\r\\n // Build the top parent path (e.g., '/components')\\r\\n const topParentPath = `/${pathSegments[0]}`;\\r\\n\\r\\n // Find the matching top-level navigation item\\r\\n const topParent = nav?.find((item) => item.path === topParentPath);\\r\\n\\r\\n return topParent?.children || [];\\r\\n });\\r\\n\\r\\n const isFlatList = computed(() => {\\r\\n return children.value.every((child) => !child.children || child.children.length === 0);\\r\\n });\\r\\n\\r\\n const nav = computed(() => {\\r\\n if (isFlatList.value) {\\r\\n return [\\r\\n {\\r\\n title: \\\"Overview\\\",\\r\\n path: children.value.at(0)?.path || \\\"\\\",\\r\\n children: children.value,\\r\\n },\\r\\n ];\\r\\n }\\r\\n\\r\\n return children.value;\\r\\n });\\r\\n\\r\\n return {\\r\\n nav,\\r\\n };\\r\\n}\\r\\n\"\n },\n \"uniapp\": {\n \"lib/AbortablePromise.ts\": \"export class AbortablePromise<T> {\\r\\n promise: Promise<T>\\r\\n private _reject: ((res?: any) => void) | null = null\\r\\n\\r\\n constructor(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) {\\r\\n this.promise = new Promise<T>((resolve, reject) => {\\r\\n executor(resolve, reject)\\r\\n this._reject = reject // 保存reject方法的引用,以便在abort时调用\\r\\n })\\r\\n }\\r\\n // 提供abort方法来中止Promise\\r\\n abort(error?: any) {\\r\\n if (this._reject) {\\r\\n this._reject(error) // 调用reject方法来中止Promise\\r\\n }\\r\\n }\\r\\n\\r\\n then<TResult1 = T, TResult2 = never>(\\r\\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,\\r\\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null\\r\\n ): Promise<TResult1 | TResult2> {\\r\\n return this.promise.then(onfulfilled, onrejected)\\r\\n }\\r\\n\\r\\n catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult> {\\r\\n return this.promise.catch(onrejected)\\r\\n }\\r\\n}\\r\\n\",\n \"lib/animation.ts\": \"import type FrameCallback from 'android.view.Choreographer.FrameCallback' // 帧回调接口\\r\\nimport type Long from 'kotlin.Long' // Kotlin Long 类型\\r\\n// #ifdef APP-ANDROID\\r\\nimport Choreographer from 'android.view.Choreographer' // Android 帧同步器,提供垂直同步信号\\r\\n// #endif\\r\\n\\r\\n/**\\r\\n * 缓动函数类型定义\\r\\n */\\r\\nexport type EasingFunction = (progress: number) => number\\r\\n\\r\\n/**\\r\\n * 动画属性配置\\r\\n */\\r\\nexport interface AnimationAttribute {\\r\\n /** 起始值 */\\r\\n fromValue: string\\r\\n /** 结束值 */\\r\\n toValue: string\\r\\n /** 单位 (px, %, deg等) */\\r\\n unit: string\\r\\n /** 当前值 */\\r\\n currentValue: string\\r\\n /** 当前进度 (0-1) */\\r\\n progress: number\\r\\n /** 属性名称 */\\r\\n propertyName: string\\r\\n}\\r\\n\\r\\n/**\\r\\n * 动画配置选项\\r\\n */\\r\\nexport interface AnimationOptions {\\r\\n /** 动画持续时间(毫秒) */\\r\\n duration?: number\\r\\n /** 循环次数 (-1为无限循环) */\\r\\n loop?: number\\r\\n /** 是否往返播放 */\\r\\n alternate?: boolean\\r\\n /** 是否按属性顺序依次执行动画 */\\r\\n sequential?: boolean\\r\\n /** 缓动函数名称 */\\r\\n timingFunction?: string\\r\\n /** 自定义贝塞尔曲线参数 */\\r\\n bezier?: number[]\\r\\n /** 动画完成回调 */\\r\\n complete?: () => void\\r\\n /** 动画开始回调 */\\r\\n start?: () => void\\r\\n /** 每帧回调 */\\r\\n frame?: (progress: number) => void\\r\\n}\\r\\n\\r\\n// 贝塞尔曲线计算常量\\r\\nconst BEZIER_SPLINE_SIZE = 11 // 样本点数量,用于预计算优化\\r\\nconst BEZIER_SAMPLE_STEP = 1.0 / (BEZIER_SPLINE_SIZE - 1.0) // 样本步长\\r\\n\\r\\n/**\\r\\n * 贝塞尔曲线系数A\\r\\n * 三次贝塞尔曲线的三次项系数\\r\\n */\\r\\nfunction getBezierCoefficientA(x1: number, x2: number): number {\\r\\n return 1.0 - 3.0 * x2 + 3.0 * x1 // B(t) = (1-t)³P₀ + 3(1-t)²tP₁ + 3(1-t)t²P₂ + t³P₃ 中的 t³ 系数\\r\\n}\\r\\n\\r\\n/**\\r\\n * 贝塞尔曲线系数B\\r\\n * 三次贝塞尔曲线的二次项系数\\r\\n */\\r\\nfunction getBezierCoefficientB(x1: number, x2: number): number {\\r\\n return 3.0 * x2 - 6.0 * x1 // 二次项系数\\r\\n}\\r\\n\\r\\n/**\\r\\n * 贝塞尔曲线系数C\\r\\n * 三次贝塞尔曲线的一次项系数\\r\\n */\\r\\nfunction getBezierCoefficientC(x1: number): number {\\r\\n return 3.0 * x1 // 一次项系数\\r\\n}\\r\\n\\r\\n/**\\r\\n * 计算贝塞尔曲线值\\r\\n * 使用霍纳法则提高计算效率\\r\\n * @param t 时间参数 (0-1)\\r\\n * @param x1 控制点1的x坐标\\r\\n * @param x2 控制点2的x坐标\\r\\n */\\r\\nfunction calculateBezierValue(t: number, x1: number, x2: number): number {\\r\\n const a = getBezierCoefficientA(x1, x2) // 获取三次项系数\\r\\n const b = getBezierCoefficientB(x1, x2) // 获取二次项系数\\r\\n const c = getBezierCoefficientC(x1) // 获取一次项系数\\r\\n return ((a * t + b) * t + c) * t // 霍纳法则:((at + b)t + c)t,减少乘法运算\\r\\n}\\r\\n\\r\\n/**\\r\\n * 计算贝塞尔曲线斜率\\r\\n * 对贝塞尔曲线求导得到斜率函数\\r\\n * @param t 时间参数 (0-1)\\r\\n * @param x1 控制点1的x坐标\\r\\n * @param x2 控制点2的x坐标\\r\\n */\\r\\nfunction getBezierSlope(t: number, x1: number, x2: number): number {\\r\\n const a = getBezierCoefficientA(x1, x2) // 三次项系数\\r\\n const b = getBezierCoefficientB(x1, x2) // 二次项系数\\r\\n const c = getBezierCoefficientC(x1) // 一次项系数\\r\\n return 3.0 * a * t * t + 2.0 * b * t + c // 导数:3at² + 2bt + c\\r\\n}\\r\\n\\r\\n/**\\r\\n * 二分法求解贝塞尔曲线参数\\r\\n * 用于根据x值反推t参数,适用于斜率较小的情况\\r\\n * @param targetX 目标x值\\r\\n * @param startT 起始t值\\r\\n * @param endT 结束t值\\r\\n * @param x1 控制点1的x坐标\\r\\n * @param x2 控制点2的x坐标\\r\\n */\\r\\nfunction binarySearchBezierT(\\r\\n targetX: number,\\r\\n startT: number,\\r\\n endT: number,\\r\\n x1: number,\\r\\n x2: number,\\r\\n): number {\\r\\n let currentX: number // 当前计算的x值\\r\\n let currentT: number // 当前的t参数\\r\\n let iterations = 0 // 迭代次数计数器\\r\\n const maxIterations = 10 // 最大迭代次数,避免无限循环\\r\\n const precision = 0.0000001 // 精度要求\\r\\n\\r\\n do {\\r\\n currentT = startT + (endT - startT) / 2.0 // 取中点\\r\\n currentX = calculateBezierValue(currentT, x1, x2) - targetX // 计算误差\\r\\n if (currentX > 0.0) {\\r\\n // 如果当前x值大于目标值\\r\\n endT = currentT // 缩小右边界\\r\\n }\\r\\n else {\\r\\n // 如果当前x值小于目标值\\r\\n startT = currentT // 缩小左边界\\r\\n }\\r\\n iterations++ // 增加迭代计数\\r\\n } while (Math.abs(currentX) > precision && iterations < maxIterations) // 直到精度满足或达到最大迭代次数\\r\\n\\r\\n return currentT // 返回找到的t参数\\r\\n}\\r\\n\\r\\n/**\\r\\n * 牛顿-拉夫逊法求解贝塞尔曲线参数\\r\\n * 适用于斜率较大的情况,收敛速度快\\r\\n * @param targetX 目标x值\\r\\n * @param initialGuess 初始猜测值\\r\\n * @param x1 控制点1的x坐标\\r\\n * @param x2 控制点2的x坐标\\r\\n */\\r\\nfunction newtonRaphsonBezierT(\\r\\n targetX: number,\\r\\n initialGuess: number,\\r\\n x1: number,\\r\\n x2: number,\\r\\n): number {\\r\\n let t = initialGuess // 当前t值,从初始猜测开始\\r\\n const maxIterations = 4 // 最大迭代次数,牛顿法收敛快\\r\\n\\r\\n for (let i = 0; i < maxIterations; i++) {\\r\\n const slope = getBezierSlope(t, x1, x2) // 计算当前点的斜率\\r\\n if (slope == 0.0) {\\r\\n // 如果斜率为0,避免除零错误\\r\\n return t\\r\\n }\\r\\n const currentX = calculateBezierValue(t, x1, x2) - targetX // 计算当前误差\\r\\n t = t - currentX / slope // 牛顿法迭代公式:t_new = t - f(t)/f'(t)\\r\\n }\\r\\n return t // 返回收敛后的t值\\r\\n}\\r\\n\\r\\n/**\\r\\n * 创建贝塞尔缓动函数\\r\\n * 根据四个控制点坐标生成缓动函数,类似CSS的cubic-bezier\\r\\n * @param x1 控制点1的x坐标 (0-1)\\r\\n * @param y1 控制点1的y坐标 (0-1)\\r\\n * @param x2 控制点2的x坐标 (0-1)\\r\\n * @param y2 控制点2的y坐标 (0-1)\\r\\n */\\r\\nfunction createBezierEasing(x1: number, y1: number, x2: number, y2: number): EasingFunction | null {\\r\\n // 验证控制点坐标范围,x坐标必须在0-1之间\\r\\n if (!(x1 >= 0 && x1 <= 1 && x2 >= 0 && x2 <= 1)) {\\r\\n return null // 参数无效时返回null\\r\\n }\\r\\n\\r\\n const sampleValues: number[] = [] // 预计算的样本值数组\\r\\n\\r\\n // 预计算样本值以提高性能,仅对非线性曲线进行预计算\\r\\n if (x1 != y1 || x2 != y2) {\\r\\n // 如果不是线性函数\\r\\n for (let i = 0; i < BEZIER_SPLINE_SIZE; i++) {\\r\\n // 计算等间距的样本点,用于快速查找\\r\\n sampleValues.push(calculateBezierValue(i * BEZIER_SAMPLE_STEP, x1, x2))\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 根据x值获取对应的t参数\\r\\n * 使用预计算样本进行快速查找和插值\\r\\n * @param x 输入的x值 (0-1)\\r\\n */\\r\\n function getTParameterForX(x: number): number {\\r\\n let intervalStart = 0.0 // 区间起始位置\\r\\n let currentSample = 1 // 当前样本索引\\r\\n const lastSample = BEZIER_SPLINE_SIZE - 1 // 最后一个样本索引\\r\\n\\r\\n // 找到x值所在的区间,线性搜索预计算的样本\\r\\n for (; currentSample != lastSample && sampleValues[currentSample] <= x; currentSample++) {\\r\\n intervalStart += BEZIER_SAMPLE_STEP // 移动区间起始位置\\r\\n }\\r\\n currentSample-- // 回退到正确的区间\\r\\n\\r\\n // 线性插值获得初始猜测值,提高后续求解精度\\r\\n const dist\\r\\n = (x - sampleValues[currentSample])\\r\\n / (sampleValues[currentSample + 1] - sampleValues[currentSample]) // 计算在区间内的相对位置\\r\\n const initialGuess = intervalStart + dist * BEZIER_SAMPLE_STEP // 计算初始猜测的t值\\r\\n const initialSlope = getBezierSlope(initialGuess, x1, x2) // 计算初始点的斜率\\r\\n\\r\\n // 根据斜率选择合适的求解方法\\r\\n if (initialSlope >= 0.001) {\\r\\n // 斜率足够大时使用牛顿法\\r\\n return newtonRaphsonBezierT(x, initialGuess, x1, x2)\\r\\n }\\r\\n else if (initialSlope == 0.0) {\\r\\n // 斜率为0时直接返回\\r\\n return initialGuess\\r\\n }\\r\\n // 斜率太小时使用二分法,更稳定\\r\\n return binarySearchBezierT(x, intervalStart, intervalStart + BEZIER_SAMPLE_STEP, x1, x2)\\r\\n }\\r\\n\\r\\n // 返回缓动函数,这是最终的缓动函数接口\\r\\n return function (progress: number): number {\\r\\n // 线性情况直接返回,优化性能\\r\\n if (x1 == y1 && x2 == y2) {\\r\\n return progress\\r\\n }\\r\\n // 边界情况处理,避免计算误差\\r\\n if (progress == 0.0 || progress == 1.0) {\\r\\n return progress\\r\\n }\\r\\n // 计算贝塞尔曲线值:先根据progress(x)找到对应的t,再计算y值\\r\\n return calculateBezierValue(getTParameterForX(progress), y1, y2)\\r\\n }\\r\\n}\\r\\n\\r\\n/**\\r\\n * 颜色工具函数:标准化颜色值格式\\r\\n * 处理不同格式的颜色输入,确保返回有效的颜色值\\r\\n */\\r\\nfunction getDefaultColor(colorValue: string): string {\\r\\n // 简化的颜色处理,实际项目中可能需要更完整的颜色转换\\r\\n if (colorValue.startsWith('#')) {\\r\\n // 十六进制颜色格式\\r\\n return colorValue\\r\\n }\\r\\n if (colorValue.startsWith('rgb')) {\\r\\n // RGB或RGBA颜色格式\\r\\n return colorValue\\r\\n }\\r\\n // 默认返回黑色,作为兜底处理\\r\\n return '#000000'\\r\\n}\\r\\n\\r\\n/**\\r\\n * 十六进制颜色转RGB对象\\r\\n * 将#RRGGBB格式的颜色转换为{r,g,b,a}对象,用于颜色动画插值\\r\\n * @param hex 十六进制颜色值,如\\\"#FF0000\\\"\\r\\n * @returns 包含r,g,b,a属性的颜色对象\\r\\n */\\r\\nfunction hexToRgb(hex: string): any {\\r\\n // 使用正则表达式解析十六进制颜色,支持带#和不带#的格式\\r\\n const result = /^#?([a-f\\\\d]{2})([a-f\\\\d]{2})([a-f\\\\d]{2})$/i.exec(hex)\\r\\n if (result != null) {\\r\\n // 解析成功\\r\\n return {\\r\\n r: Number.parseInt(result[1] ?? '0', 16), // 红色分量,16进制转10进制\\r\\n g: Number.parseInt(result[2] ?? '0', 16), // 绿色分量\\r\\n b: Number.parseInt(result[3] ?? '0', 16), // 蓝色分量\\r\\n a: 1.0, // 透明度,默认不透明\\r\\n }\\r\\n }\\r\\n // 解析失败时返回黑色\\r\\n return {\\r\\n r: 0,\\r\\n g: 0,\\r\\n b: 0,\\r\\n a: 1.0,\\r\\n }\\r\\n}\\r\\n\\r\\n/**\\r\\n * 高性能动画引擎类\\r\\n * 支持多平台的流畅动画效果,提供丰富的缓动函数和动画控制\\r\\n */\\r\\nexport class AnimationEngine {\\r\\n /** 预定义缓动函数映射,存储常用的贝塞尔曲线参数 */\\r\\n private readonly easingPresets = new Map<string, number[]>([\\r\\n ['linear', [0.0, 0.0, 1.0, 1.0]], // 线性缓动\\r\\n ['ease', [0.25, 0.1, 0.25, 1.0]], // 默认缓动\\r\\n ['easeIn', [0.42, 0.0, 1.0, 1.0]], // 加速进入\\r\\n ['easeOut', [0.0, 0.0, 0.58, 1.0]], // 减速退出\\r\\n ['easeInOut', [0.42, 0.0, 0.58, 1.0]], // 先加速后减速\\r\\n ['easeInQuad', [0.55, 0.085, 0.68, 0.53]], // 二次方加速\\r\\n ['easeOutQuad', [0.25, 0.46, 0.45, 0.94]], // 二次方减速\\r\\n ['easeInOutQuad', [0.455, 0.03, 0.515, 0.955]], // 二次方先加速后减速\\r\\n ['easeInCubic', [0.55, 0.055, 0.675, 0.19]], // 三次方加速\\r\\n ['easeOutCubic', [0.215, 0.61, 0.355, 1.0]], // 三次方减速\\r\\n ['easeInOutCubic', [0.645, 0.045, 0.355, 1.0]], // 三次方先加速后减速\\r\\n ['easeInQuart', [0.895, 0.03, 0.685, 0.22]], // 四次方加速\\r\\n ['easeOutQuart', [0.165, 0.84, 0.44, 1.0]], // 四次方减速\\r\\n ['easeInOutQuart', [0.77, 0.0, 0.175, 1.0]], // 四次方先加速后减速\\r\\n ['easeInQuint', [0.755, 0.05, 0.855, 0.06]], // 五次方加速\\r\\n ['easeOutQuint', [0.23, 1.0, 0.32, 1.0]], // 五次方减速\\r\\n ['easeInOutQuint', [0.86, 0.0, 0.07, 1.0]], // 五次方先加速后减速\\r\\n ['easeInSine', [0.47, 0.0, 0.745, 0.715]], // 正弦加速\\r\\n ['easeOutSine', [0.39, 0.575, 0.565, 1.0]], // 正弦减速\\r\\n ['easeInOutSine', [0.445, 0.05, 0.55, 0.95]], // 正弦先加速后减速\\r\\n ['easeInExpo', [0.95, 0.05, 0.795, 0.035]], // 指数加速\\r\\n ['easeOutExpo', [0.19, 1.0, 0.22, 1.0]], // 指数减速\\r\\n ['easeInOutExpo', [1.0, 0.0, 0.0, 1.0]], // 指数先加速后减速\\r\\n ['easeInCirc', [0.6, 0.04, 0.98, 0.335]], // 圆形加速\\r\\n ['easeOutCirc', [0.075, 0.82, 0.165, 1.0]], // 圆形减速\\r\\n ['easeInOutBack', [0.68, -0.55, 0.265, 1.55]], // 回弹效果\\r\\n ])\\r\\n\\r\\n /** 目标DOM元素,动画作用的对象 */\\r\\n private targetElement: any | null = null\\r\\n\\r\\n /** 动画持续时间(毫秒),默认500ms */\\r\\n private animationDuration: number = 500\\r\\n\\r\\n /** 动画是否正在运行,用于控制动画循环 */\\r\\n private isRunning: boolean = false\\r\\n\\r\\n /** 动画是否暂停,暂停时保留当前进度 */\\r\\n private isPaused: boolean = false\\r\\n\\r\\n /** 当前动画进度 (0-1),用于恢复暂停的动画 */\\r\\n private currentProgress: number = 0\\r\\n\\r\\n /** 是否反向播放,影响动画方向 */\\r\\n private isReversed: boolean = false\\r\\n\\r\\n /** 是否往返播放模式,控制动画是否来回播放 */\\r\\n private isAlternate: boolean = false\\r\\n /** 往返播放时是否处于反向状态 */\\r\\n private isAlternateReversed: boolean = false\\r\\n\\r\\n /** 循环播放次数 (-1为无限循环) */\\r\\n private loopCount: number = 1\\r\\n /** 当前已完成的循环次数 */\\r\\n private currentLoop: number = 0\\r\\n\\r\\n /** 动画是否正在停止,用于提前终止动画 */\\r\\n private isStopping: boolean = true\\r\\n\\r\\n /** 当前执行的属性索引(顺序执行模式),用于控制属性依次动画 */\\r\\n private currentAttributeIndex: number = 0\\r\\n\\r\\n /** 回调函数,提供动画生命周期钩子 */\\r\\n private onComplete: () => void = () => { } // 动画完成回调\\r\\n private onStart: () => void = () => { } // 动画开始回调\\r\\n private onFrame: (progress: number) => void = () => { } // 每帧回调\\r\\n\\r\\n /** 动画属性列表,存储所有要动画的CSS属性 */\\r\\n private animationAttributes: AnimationAttribute[] = []\\r\\n\\r\\n /** 动画开始时间戳,用于计算动画进度 */\\r\\n private startTimestamp: number = 0\\r\\n\\r\\n /** 当前使用的缓动函数,将线性进度转换为缓动进度 */\\r\\n private currentEasingFunction: EasingFunction | null = null\\r\\n\\r\\n /** 是否按属性顺序依次执行动画,而非并行执行 */\\r\\n private isSequentialMode: boolean = false\\r\\n\\r\\n // 平台相关的动画控制器\\r\\n // Android平台使用Choreographer提供高性能动画\\r\\n // #ifdef APP-ANDROID\\r\\n private choreographer: Choreographer | null = null // Android系统帧同步器\\r\\n private frameCallback: FrameCallback | null = null // 帧回调处理器\\r\\n // #endif\\r\\n\\r\\n // iOS/小程序平台使用定时器\\r\\n // #ifdef APP-IOS\\r\\n private displayLinkTimer: number = 0 // iOS定时器ID\\r\\n // #endif\\r\\n\\r\\n // Web平台使用requestAnimationFrame\\r\\n private animationFrameId: number | null = null // 动画帧ID\\r\\n\\r\\n /**\\r\\n * 创建动画引擎实例\\r\\n * 初始化动画引擎,设置目标元素和动画配置\\r\\n * @param element 目标DOM元素,null时仅做计算不应用样式\\r\\n * @param options 动画配置选项,包含持续时间、缓动函数等\\r\\n */\\r\\n constructor(element: any | null, options: AnimationOptions) {\\r\\n this.targetElement = element // 保存目标元素引用\\r\\n\\r\\n // 设置动画参数,使用选项值或默认值\\r\\n this.animationDuration\\r\\n = options.duration != null ? options.duration : this.animationDuration // 设置动画持续时间\\r\\n this.loopCount = options.loop != null ? options.loop : this.loopCount // 设置循环次数\\r\\n this.isAlternate = options.alternate != null ? options.alternate : this.isAlternate // 设置往返播放\\r\\n this.isSequentialMode\\r\\n = options.sequential != null ? options.sequential : this.isSequentialMode // 设置顺序执行模式\\r\\n\\r\\n // 设置缓动函数,优先使用预定义函数\\r\\n if (options.timingFunction != null) {\\r\\n const easingParams = this.easingPresets.get(options.timingFunction) // 查找预定义缓动参数\\r\\n if (easingParams != null) {\\r\\n // 根据贝塞尔参数创建缓动函数\\r\\n this.currentEasingFunction = createBezierEasing(\\r\\n easingParams[0], // x1坐标\\r\\n easingParams[1], // y1坐标\\r\\n easingParams[2], // x2坐标\\r\\n easingParams[3], // y2坐标\\r\\n )\\r\\n }\\r\\n }\\r\\n\\r\\n // 自定义贝塞尔曲线,会覆盖预定义函数\\r\\n if (options.bezier != null && options.bezier.length == 4) {\\r\\n this.currentEasingFunction = createBezierEasing(\\r\\n options.bezier[0], // 自定义x1坐标\\r\\n options.bezier[1], // 自定义y1坐标\\r\\n options.bezier[2], // 自定义x2坐标\\r\\n options.bezier[3], // 自定义y2坐标\\r\\n )\\r\\n }\\r\\n\\r\\n // 设置回调函数,提供动画生命周期钩子\\r\\n if (options.complete != null) {\\r\\n this.onComplete = options.complete // 动画完成回调\\r\\n }\\r\\n if (options.start != null) {\\r\\n this.onStart = options.start // 动画开始回调\\r\\n }\\r\\n if (options.frame != null) {\\r\\n this.onFrame = options.frame // 每帧更新回调\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 从样式值中提取单位\\r\\n * 解析CSS值中的单位部分,用于动画计算\\r\\n * @param value 样式值,如 \\\"100px\\\", \\\"50%\\\"\\r\\n * @param propertyName CSS属性名称,用于判断是否需要默认单位\\r\\n * @returns 单位字符串\\r\\n */\\r\\n private extractUnit(value?: string, propertyName?: string): string {\\r\\n if (value == null) { return 'px' } // 默认单位为px\\r\\n const unit = value.replace(/[\\\\d|\\\\-+.]/g, '') // 移除数字、负号、正号、小数点,保留单位\\r\\n\\r\\n // opacity、z-index等属性无需单位\\r\\n if (propertyName == 'opacity' || propertyName == 'z-index') {\\r\\n return '' // 返回空字符串表示无单位\\r\\n }\\r\\n\\r\\n return unit == '' ? 'px' : unit // 如果没有单位则默认为px\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加自定义缓动函数\\r\\n * 向引擎注册新的缓动函数,可在后续动画中使用\\r\\n * @param name 缓动函数名称\\r\\n * @param bezierParams 贝塞尔曲线参数 [x1, y1, x2, y2]\\r\\n */\\r\\n addCustomEasing(name: string, bezierParams: number[]): AnimationEngine {\\r\\n if (bezierParams.length == 4) {\\r\\n // 验证参数数量\\r\\n this.easingPresets.set(name, bezierParams) // 添加到预设映射中\\r\\n }\\r\\n return this // 返回自身支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置动画反向播放\\r\\n * 控制动画从结束值向起始值播放\\r\\n * @param reverse 是否反向播放,null表示切换当前状态\\r\\n */\\r\\n setReverse(reverse: boolean | null = null): AnimationEngine {\\r\\n if (reverse != null) {\\r\\n this.isReversed = reverse // 设置指定状态\\r\\n }\\r\\n else {\\r\\n this.isReversed = !this.isReversed // 切换当前状态\\r\\n }\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置循环播放次数\\r\\n * 控制动画重复执行的次数\\r\\n * @param count 循环次数,-1表示无限循环\\r\\n */\\r\\n setLoopCount(count: number): AnimationEngine {\\r\\n this.loopCount = count // 设置循环次数\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置动画持续时间\\r\\n * 控制动画从开始到结束的总时长\\r\\n * @param duration 持续时间(毫秒)\\r\\n */\\r\\n setDuration(duration: number): AnimationEngine {\\r\\n this.animationDuration = duration // 设置动画持续时间\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置往返播放模式\\r\\n * 控制动画是否在每次循环时反向播放\\r\\n * @param alternate 是否往返播放\\r\\n */\\r\\n setAlternate(alternate: boolean): AnimationEngine {\\r\\n this.isAlternate = alternate // 设置往返播放标志\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置顺序执行模式\\r\\n * 控制多个属性是同时动画还是依次动画\\r\\n * @param sequential 是否按属性顺序依次执行\\r\\n */\\r\\n setSequential(sequential: boolean): AnimationEngine {\\r\\n this.isSequentialMode = sequential // 设置执行模式\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加动画属性\\r\\n * 向动画引擎添加一个CSS属性的动画配置\\r\\n * @param propertyName CSS属性名称\\r\\n * @param fromValue 起始值(支持数字+单位,如\\\"100px\\\"、\\\"50%\\\")\\r\\n * @param toValue 结束值(单位必须与起始值一致)\\r\\n * @param unique 是否唯一,true时同名属性会被替换\\r\\n */\\r\\n addAttribute(\\r\\n propertyName: string,\\r\\n fromValue: string,\\r\\n toValue: string,\\r\\n unique: boolean = true,\\r\\n ): AnimationEngine {\\r\\n const isColor = this.isColorProperty(propertyName) // 检测是否为颜色属性\\r\\n const unit = isColor ? '' : this.extractUnit(fromValue, propertyName) // 提取单位\\r\\n\\r\\n // 根据属性类型处理值\\r\\n const processedFromValue = isColor\\r\\n ? getDefaultColor(fromValue) // 颜色属性标准化\\r\\n : Number.parseFloat(fromValue).toString() // 数值属性提取数字\\r\\n const processedToValue = isColor\\r\\n ? getDefaultColor(toValue) // 颜色属性标准化\\r\\n : Number.parseFloat(toValue).toString() // 数值属性提取数字\\r\\n\\r\\n // 查找是否已存在同名属性,用于决定是替换还是新增\\r\\n let existingIndex = this.animationAttributes.findIndex(\\r\\n (attr: AnimationAttribute): boolean => attr.propertyName == propertyName,\\r\\n )\\r\\n\\r\\n if (!unique) {\\r\\n existingIndex = -1 // 强制添加新属性,不替换\\r\\n }\\r\\n\\r\\n // 创建新的动画属性对象\\r\\n const newAttribute: AnimationAttribute = {\\r\\n fromValue: processedFromValue, // 处理后的起始值\\r\\n toValue: processedToValue, // 处理后的结束值\\r\\n unit, // 单位\\r\\n progress: 0, // 初始进度为0\\r\\n currentValue: processedFromValue, // 当前值初始化为起始值\\r\\n propertyName, // 属性名称\\r\\n }\\r\\n\\r\\n if (existingIndex == -1) {\\r\\n this.animationAttributes.push(newAttribute) // 添加新属性\\r\\n }\\r\\n else {\\r\\n this.animationAttributes[existingIndex] = newAttribute // 替换现有属性\\r\\n }\\r\\n\\r\\n return this // 支持链式调用\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加变换属性\\r\\n */\\r\\n transform(property: string, fromValue: string, toValue: string): AnimationEngine {\\r\\n return this.addAttribute(property, fromValue, toValue)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加位移动画\\r\\n */\\r\\n translate(fromX: string, fromY: string, toX: string, toY: string): AnimationEngine {\\r\\n this.addAttribute('translateX', fromX, toX)\\r\\n this.addAttribute('translateY', fromY, toY)\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加X轴位移动画\\r\\n * @param fromX 起始X位置,可以使用\\\"current\\\"表示当前位置\\r\\n * @param toX 结束X位置\\r\\n * @returns\\r\\n */\\r\\n translateX(fromX: string, toX: string): AnimationEngine {\\r\\n return this.addAttribute('translateX', fromX, toX)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加Y轴位移动画\\r\\n * @param fromY 起始Y位置,可以使用\\\"current\\\"表示当前位置\\r\\n * @param toY 结束Y位置\\r\\n * @returns\\r\\n */\\r\\n translateY(fromY: string, toY: string): AnimationEngine {\\r\\n return this.addAttribute('translateY', fromY, toY)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加缩放动画\\r\\n */\\r\\n scale(fromScale: string, toScale: string): AnimationEngine {\\r\\n return this.addAttribute('scale', fromScale, toScale)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加旋转动画\\r\\n */\\r\\n rotate(fromDegree: string, toDegree: string): AnimationEngine {\\r\\n return this.addAttribute('rotate', fromDegree, toDegree)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 快捷方法:添加透明度动画\\r\\n */\\r\\n opacity(fromOpacity: string, toOpacity: string): AnimationEngine {\\r\\n return this.addAttribute('opacity', fromOpacity, toOpacity)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 线性插值计算\\r\\n * 根据进度在两个数值之间进行插值,用于计算动画中间值\\r\\n * @param startValue 起始值\\r\\n * @param endValue 结束值\\r\\n * @param progress 进度 (0-1)\\r\\n */\\r\\n private interpolateValue(startValue: number, endValue: number, progress: number): number {\\r\\n return startValue + (endValue - startValue) * progress // 线性插值公式:start + (end - start) * progress\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否为颜色相关属性\\r\\n * 检测CSS属性名是否与颜色相关,用于特殊的颜色动画处理\\r\\n * @param propertyName 属性名称\\r\\n */\\r\\n private isColorProperty(propertyName: string): boolean {\\r\\n return (\\r\\n propertyName.includes('background') // 背景颜色相关\\r\\n || propertyName.includes('color') // 文字颜色相关\\r\\n || propertyName.includes('border-color') // 边框颜色相关\\r\\n || propertyName.includes('shadow') // 阴影颜色相关\\r\\n )\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否为Transform相关属性\\r\\n * 检测属性名是否为transform相关的CSS属性\\r\\n * @param propertyName CSS属性名称\\r\\n * @returns 是否为transform属性\\r\\n */\\r\\n private isTransformProperty(propertyName: string): boolean {\\r\\n return (\\r\\n propertyName == 'scaleX' // X轴缩放\\r\\n || propertyName == 'scaleY' // Y轴缩放\\r\\n || propertyName == 'scale' // 等比缩放\\r\\n || propertyName == 'rotateX' // X轴旋转\\r\\n || propertyName == 'rotateY' // Y轴旋转\\r\\n || propertyName == 'rotate' // Z轴旋转\\r\\n || propertyName == 'translateX' // X轴位移\\r\\n || propertyName == 'translateY' // Y轴位移\\r\\n || propertyName == 'translate' // 双轴位移\\r\\n )\\r\\n }\\r\\n\\r\\n /**\\r\\n * 设置元素样式属性\\r\\n * 根据属性类型应用相应的样式值,支持transform、颜色、普通数值属性\\r\\n * @param propertyName 属性名称\\r\\n * @param currentValue 当前值\\r\\n * @param unit 单位\\r\\n * @param progress 动画进度\\r\\n * @param attribute 动画属性对象\\r\\n */\\r\\n private setElementProperty(\\r\\n propertyName: string,\\r\\n currentValue: number,\\r\\n unit: string,\\r\\n progress: number,\\r\\n attribute: AnimationAttribute,\\r\\n ): void {\\r\\n if (this.targetElement == null) { return } // 没有目标元素时直接返回\\r\\n\\r\\n const element = this.targetElement // 获取目标元素引用\\r\\n const valueStr = currentValue.toFixed(2) // 数值保留两位小数\\r\\n\\r\\n // #ifdef MP\\r\\n if (element.style == null) {\\r\\n return\\r\\n }\\r\\n // #endif\\r\\n\\r\\n // Transform 相关属性处理,使用CSS transform属性\\r\\n switch (propertyName) {\\r\\n case 'scaleX': // X轴缩放\\r\\n element.style!.setProperty('transform', `scaleX(${currentValue})`)\\r\\n break\\r\\n case 'scaleY': // Y轴缩放\\r\\n element.style!.setProperty('transform', `scaleY(${currentValue})`)\\r\\n break\\r\\n case 'scale': // 等比缩放\\r\\n element.style!.setProperty('transform', `scale(${currentValue})`)\\r\\n break\\r\\n case 'rotateX': // X轴旋转\\r\\n element.style!.setProperty('transform', `rotateX(${valueStr + unit})`)\\r\\n break\\r\\n case 'rotateY': // Y轴旋转\\r\\n element.style!.setProperty('transform', `rotateY(${valueStr + unit})`)\\r\\n break\\r\\n case 'rotate': // Z轴旋转\\r\\n element.style!.setProperty('transform', `rotate(${valueStr + unit})`)\\r\\n break\\r\\n case 'translateX': // X轴位移\\r\\n element.style!.setProperty('transform', `translateX(${valueStr + unit})`)\\r\\n break\\r\\n case 'translateY': // Y轴位移\\r\\n element.style!.setProperty('transform', `translateY(${valueStr + unit})`)\\r\\n break\\r\\n case 'translate': // 双轴位移\\r\\n element.style!.setProperty(\\r\\n 'transform',\\r\\n `translate(${valueStr + unit},${valueStr + unit})`,\\r\\n )\\r\\n break\\r\\n default:\\r\\n // 颜色属性处理,需要进行RGBA插值\\r\\n if (this.isColorProperty(propertyName)) {\\r\\n const startColor = hexToRgb(attribute.fromValue) // 解析起始颜色\\r\\n const endColor = hexToRgb(attribute.toValue) // 解析结束颜色\\r\\n\\r\\n // 提取起始颜色的RGBA分量,兼容不同的JSON对象访问方式\\r\\n const startR\\r\\n = startColor.getNumber != null\\r\\n ? startColor.getNumber('r')\\r\\n : (startColor.r as number)\\r\\n const startG\\r\\n = startColor.getNumber != null\\r\\n ? startColor.getNumber('g')\\r\\n : (startColor.g as number)\\r\\n const startB\\r\\n = startColor.getNumber != null\\r\\n ? startColor.getNumber('b')\\r\\n : (startColor.b as number)\\r\\n const startA\\r\\n = startColor.getNumber != null\\r\\n ? startColor.getNumber('a')\\r\\n : (startColor.a as number)\\r\\n\\r\\n // 提取结束颜色的RGBA分量\\r\\n const endR\\r\\n = endColor.getNumber != null\\r\\n ? endColor.getNumber('r')\\r\\n : (endColor.r as number)\\r\\n const endG\\r\\n = endColor.getNumber != null\\r\\n ? endColor.getNumber('g')\\r\\n : (endColor.g as number)\\r\\n const endB\\r\\n = endColor.getNumber != null\\r\\n ? endColor.getNumber('b')\\r\\n : (endColor.b as number)\\r\\n const endA\\r\\n = endColor.getNumber != null\\r\\n ? endColor.getNumber('a')\\r\\n : (endColor.a as number)\\r\\n\\r\\n // 对每个颜色分量进行插值计算\\r\\n const r = this.interpolateValue(\\r\\n startR != null ? startR : 0,\\r\\n endR != null ? endR : 0,\\r\\n progress,\\r\\n )\\r\\n const g = this.interpolateValue(\\r\\n startG != null ? startG : 0,\\r\\n endG != null ? endG : 0,\\r\\n progress,\\r\\n )\\r\\n const b = this.interpolateValue(\\r\\n startB != null ? startB : 0,\\r\\n endB != null ? endB : 0,\\r\\n progress,\\r\\n )\\r\\n const a = this.interpolateValue(\\r\\n startA != null ? startA : 1,\\r\\n endA != null ? endA : 1,\\r\\n progress,\\r\\n )\\r\\n\\r\\n // 设置RGBA颜色值\\r\\n element.style!.setProperty(\\r\\n propertyName,\\r\\n `rgba(${r.toFixed(0)},${g.toFixed(0)},${b.toFixed(0)},${a.toFixed(1)})`,\\r\\n )\\r\\n }\\r\\n else {\\r\\n // 普通数值属性处理,直接设置数值和单位\\r\\n element.style!.setProperty(propertyName, valueStr + unit)\\r\\n }\\r\\n break\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * Web平台动画运行方法 (H5/iOS/Harmony)\\r\\n * 使用requestAnimationFrame实现流畅的动画循环\\r\\n */\\r\\n private runWebAnimation(): void {\\r\\n // #ifdef H5 || APP-IOS || APP-HARMONY\\r\\n const self = this // 保存this引用,避免在内部函数中this指向改变\\r\\n self.startTimestamp = 0 // 重置开始时间戳\\r\\n\\r\\n // 取消之前的动画帧,避免重复执行\\r\\n if (self.animationFrameId != null) {\\r\\n cancelAnimationFrame(self.animationFrameId)\\r\\n }\\r\\n\\r\\n function animationLoop(): void {\\r\\n // 初始化开始时间,首次执行时记录时间戳\\r\\n if (self.startTimestamp <= 0) {\\r\\n self.startTimestamp = Date.now()\\r\\n }\\r\\n\\r\\n // 计算当前进度:(已用时间 / 总时间) + 暂停前的进度\\r\\n const elapsed = Date.now() - self.startTimestamp // 已经过的时间\\r\\n const progress = Math.min(elapsed / self.animationDuration + self.currentProgress, 1.0) // 限制进度不超过1\\r\\n\\r\\n // 执行动画更新,应用当前进度到所有属性\\r\\n self.updateAnimationFrame(progress)\\r\\n\\r\\n // 检查暂停状态\\r\\n if (self.isPaused) {\\r\\n self.isRunning = false // 停止运行标志\\r\\n self.currentProgress = progress // 保存当前进度,用于恢复\\r\\n console.log('动画已暂停')\\r\\n return // 退出动画循环\\r\\n }\\r\\n\\r\\n // 检查动画完成或停止\\r\\n if (progress >= 1.0 || self.isStopping) {\\r\\n self.handleAnimationComplete() // 处理动画完成逻辑\\r\\n return // 退出动画循环\\r\\n }\\r\\n\\r\\n // 继续下一帧,动画未完成且仍在运行\\r\\n if (progress < 1.0 && self.isRunning) {\\r\\n self.onFrame(progress) // 触发每帧回调\\r\\n self.animationFrameId = requestAnimationFrame(animationLoop) // 请求下一帧\\r\\n }\\r\\n }\\r\\n\\r\\n // 开始动画,触发开始回调并启动动画循环\\r\\n self.onStart()\\r\\n animationLoop()\\r\\n // #endif\\r\\n }\\r\\n\\r\\n /**\\r\\n * 更新动画帧\\r\\n * 根据执行模式更新所有或当前属性的动画值\\r\\n * @param progress 当前进度 (0-1)\\r\\n */\\r\\n private updateAnimationFrame(progress: number): void {\\r\\n if (this.targetElement == null) { return } // 没有目标元素时直接返回\\r\\n\\r\\n if (!this.isSequentialMode) {\\r\\n // 并行执行所有属性动画,所有属性同时进行动画\\r\\n for (let i = 0; i < this.animationAttributes.length; i++) {\\r\\n this.updateSingleAttribute(this.animationAttributes[i], progress)\\r\\n }\\r\\n }\\r\\n else {\\r\\n // 顺序执行属性动画,一个接一个地执行属性动画\\r\\n if (this.currentAttributeIndex < this.animationAttributes.length) {\\r\\n this.updateSingleAttribute(\\r\\n this.animationAttributes[this.currentAttributeIndex],\\r\\n progress,\\r\\n )\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 更新单个属性的动画\\r\\n * 计算属性的当前值并应用到元素上\\r\\n * @param attribute 动画属性\\r\\n * @param progress 进度\\r\\n */\\r\\n private updateSingleAttribute(attribute: AnimationAttribute, progress: number): void {\\r\\n attribute.progress = progress // 更新属性的进度记录\\r\\n\\r\\n if (!this.isColorProperty(attribute.propertyName)) {\\r\\n // 数值属性处理\\r\\n const fromValue = Number.parseFloat(attribute.fromValue) // 起始数值\\r\\n const toValue = Number.parseFloat(attribute.toValue) // 结束数值\\r\\n\\r\\n // 应用缓动函数,将线性进度转换为缓动进度\\r\\n let easedProgress = progress\\r\\n if (this.currentEasingFunction != null) {\\r\\n easedProgress = this.currentEasingFunction(progress)\\r\\n }\\r\\n\\r\\n // 计算当前值,使用缓动进度进行插值\\r\\n let currentValue = this.interpolateValue(fromValue, toValue, easedProgress)\\r\\n\\r\\n // 处理反向和往返播放,交换起始和结束值\\r\\n if (this.isReversed || this.isAlternateReversed) {\\r\\n currentValue = this.interpolateValue(toValue, fromValue, easedProgress)\\r\\n }\\r\\n\\r\\n // 应用计算出的值到元素属性\\r\\n this.setElementProperty(\\r\\n attribute.propertyName,\\r\\n currentValue,\\r\\n attribute.unit,\\r\\n progress,\\r\\n attribute,\\r\\n )\\r\\n }\\r\\n else {\\r\\n // 颜色属性处理,progress参数会在setElementProperty中用于颜色插值\\r\\n this.setElementProperty(attribute.propertyName, 0, attribute.unit, progress, attribute)\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 处理动画完成\\r\\n */\\r\\n private handleAnimationComplete(): void {\\r\\n // 顺序模式下检查是否还有未执行的属性\\r\\n if (\\r\\n this.isSequentialMode\\r\\n && this.currentAttributeIndex < this.animationAttributes.length - 1\\r\\n ) {\\r\\n this.currentAttributeIndex++\\r\\n this.currentProgress = 0\\r\\n this.restartAnimation()\\r\\n return\\r\\n }\\r\\n\\r\\n // 重置状态\\r\\n // #ifdef H5 || APP-IOS || APP-HARMONY\\r\\n if (this.animationFrameId != null) {\\r\\n cancelAnimationFrame(this.animationFrameId)\\r\\n }\\r\\n // #endif\\r\\n\\r\\n this.currentAttributeIndex = 0\\r\\n this.currentProgress = 0\\r\\n\\r\\n // 处理往返播放\\r\\n if (this.isAlternate) {\\r\\n this.isAlternateReversed = !this.isAlternateReversed\\r\\n }\\r\\n\\r\\n // 处理循环播放\\r\\n if (this.loopCount == -1) {\\r\\n // 无限循环\\r\\n this.restartAnimation()\\r\\n return\\r\\n }\\r\\n else {\\r\\n this.currentLoop++\\r\\n if (this.currentLoop < this.loopCount) {\\r\\n this.restartAnimation()\\r\\n return\\r\\n }\\r\\n }\\r\\n\\r\\n // 动画完成\\r\\n this.isRunning = false\\r\\n this.onComplete()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 根据平台重新启动动画\\r\\n */\\r\\n private restartAnimation(): void {\\r\\n // 重置开始时间戳,确保循环动画正确计时\\r\\n this.startTimestamp = 0\\r\\n\\r\\n // 根据平台选择合适的动画引擎\\r\\n // #ifdef H5 || APP-IOS || APP-HARMONY\\r\\n this.runWebAnimation()\\r\\n // #endif\\r\\n // #ifdef APP-ANDROID\\r\\n this.runAndroidAnimation()\\r\\n // #endif\\r\\n // #ifdef MP\\r\\n this.runMPAnimation()\\r\\n // #endif\\r\\n }\\r\\n\\r\\n /**\\r\\n * Android平台动画运行方法\\r\\n */\\r\\n private runAndroidAnimation(): void {\\r\\n // #ifdef APP-ANDROID\\r\\n const self = this\\r\\n self.startTimestamp = 0\\r\\n\\r\\n // 初始化Choreographer\\r\\n if (self.choreographer == null) {\\r\\n self.choreographer = Choreographer.getInstance()\\r\\n }\\r\\n else {\\r\\n // 清除之前的回调\\r\\n if (self.frameCallback != null) {\\r\\n self.choreographer.removeFrameCallback(self.frameCallback)\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * Android原生帧回调类\\r\\n */\\r\\n class frameCallback extends Choreographer.FrameCallback {\\r\\n // @ts-ignore\\r\\n override doFrame(frameTimeNanos: Long) {\\r\\n // 检查动画是否应该停止\\r\\n if (!self.isRunning || self.isStopping) {\\r\\n return\\r\\n }\\r\\n\\r\\n // 初始化开始时间\\r\\n if (self.startTimestamp <= 0) {\\r\\n self.startTimestamp = Date.now()\\r\\n }\\r\\n\\r\\n // 计算当前进度\\r\\n const elapsed = Date.now() - self.startTimestamp\\r\\n const progress = Math.min(\\r\\n elapsed / self.animationDuration + self.currentProgress,\\r\\n 1.0,\\r\\n )\\r\\n\\r\\n // 执行动画更新\\r\\n self.updateAnimationFrame(progress)\\r\\n\\r\\n // 检查暂停状态\\r\\n if (self.isPaused) {\\r\\n self.isRunning = false\\r\\n self.currentProgress = progress\\r\\n return\\r\\n }\\r\\n\\r\\n // 检查动画完成或停止\\r\\n if (progress >= 1.0 || self.isStopping) {\\r\\n self.handleAnimationComplete()\\r\\n return\\r\\n }\\r\\n\\r\\n // 继续下一帧\\r\\n if (progress < 1.0 && self.isRunning && !self.isStopping) {\\r\\n self.onFrame(progress)\\r\\n if (self.choreographer != null) {\\r\\n self.choreographer.postFrameCallback(this)\\r\\n }\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n // 启动动画\\r\\n self.onStart()\\r\\n self.frameCallback = new frameCallback()\\r\\n self.choreographer!.postFrameCallback(self.frameCallback)\\r\\n // #endif\\r\\n }\\r\\n\\r\\n /**\\r\\n * 小程序平台动画运行方法\\r\\n */\\r\\n private runMPAnimation(): void {\\r\\n // #ifdef MP\\r\\n const self = this\\r\\n self.startTimestamp = 0\\r\\n\\r\\n // 清除之前的定时器\\r\\n if (self.displayLinkTimer != 0) {\\r\\n clearTimeout(self.displayLinkTimer)\\r\\n }\\r\\n\\r\\n function animationLoop(): void {\\r\\n // 初始化开始时间\\r\\n if (self.startTimestamp <= 0) {\\r\\n self.startTimestamp = Date.now()\\r\\n }\\r\\n\\r\\n // 计算当前进度\\r\\n const elapsed = Date.now() - self.startTimestamp\\r\\n const progress = Math.min(elapsed / self.animationDuration + self.currentProgress, 1.0)\\r\\n\\r\\n // 执行动画更新\\r\\n self.updateAnimationFrame(progress)\\r\\n\\r\\n // 检查暂停状态\\r\\n if (self.isPaused) {\\r\\n self.isRunning = false\\r\\n self.currentProgress = progress\\r\\n return\\r\\n }\\r\\n\\r\\n // 检查动画完成或停止\\r\\n if (progress >= 1.0 || self.isStopping) {\\r\\n self.handleAnimationComplete()\\r\\n return\\r\\n }\\r\\n\\r\\n // 继续下一帧\\r\\n if (progress < 1.0 && self.isRunning) {\\r\\n self.onFrame(progress)\\r\\n self.displayLinkTimer = setTimeout(animationLoop, 16) as any // 约60fps\\r\\n }\\r\\n }\\r\\n\\r\\n // 开始动画\\r\\n self.onStart()\\r\\n animationLoop()\\r\\n // #endif\\r\\n }\\r\\n\\r\\n /**\\r\\n * 开始播放动画\\r\\n */\\r\\n play(): AnimationEngine {\\r\\n if (this.isRunning) { return this }\\r\\n\\r\\n // 初始化动画状态\\r\\n this.isRunning = true\\r\\n this.isStopping = false\\r\\n this.isPaused = false\\r\\n this.currentLoop = 0\\r\\n this.currentAttributeIndex = 0\\r\\n\\r\\n // 根据平台选择合适的动画引擎\\r\\n // #ifdef H5 || APP-IOS || APP-HARMONY\\r\\n this.runWebAnimation()\\r\\n // #endif\\r\\n // #ifdef APP-ANDROID\\r\\n this.runAndroidAnimation()\\r\\n // #endif\\r\\n // #ifdef MP\\r\\n this.runMPAnimation()\\r\\n // #endif\\r\\n\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 异步播放动画,支持await\\r\\n * @returns Promise,动画完成时resolve\\r\\n */\\r\\n playAsync(): Promise<void> {\\r\\n return new Promise<void>((resolve) => {\\r\\n const originalComplete = this.onComplete\\r\\n this.onComplete = () => {\\r\\n originalComplete()\\r\\n resolve()\\r\\n }\\r\\n this.play()\\r\\n })\\r\\n }\\r\\n\\r\\n /**\\r\\n * 停止动画\\r\\n * 会立即停止动画并跳转到结束状态\\r\\n */\\r\\n stop(): AnimationEngine {\\r\\n this.isStopping = true\\r\\n this.currentProgress = 0\\r\\n this.currentAttributeIndex = this.animationAttributes.length\\r\\n\\r\\n // 清理平台相关的动画控制器\\r\\n // #ifdef WEB || APP-IOS || APP-HARMONY\\r\\n if (this.animationFrameId != null) {\\r\\n cancelAnimationFrame(this.animationFrameId)\\r\\n this.animationFrameId = null\\r\\n }\\r\\n // #endif\\r\\n\\r\\n // #ifdef APP-ANDROID\\r\\n if (this.choreographer != null && this.frameCallback != null) {\\r\\n this.choreographer.removeFrameCallback(this.frameCallback)\\r\\n }\\r\\n // #endif\\r\\n\\r\\n // #ifdef MP\\r\\n if (this.displayLinkTimer != 0) {\\r\\n clearTimeout(this.displayLinkTimer)\\r\\n this.displayLinkTimer = 0\\r\\n }\\r\\n // #endif\\r\\n\\r\\n this.isRunning = false\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 暂停动画\\r\\n * 保留当前状态,可以通过play()恢复\\r\\n */\\r\\n pause(): AnimationEngine {\\r\\n this.isPaused = true\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 恢复暂停的动画\\r\\n */\\r\\n resume(): AnimationEngine {\\r\\n if (this.isPaused) {\\r\\n this.isPaused = false\\r\\n this.play()\\r\\n }\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 清空应用到元素上的动画样式\\r\\n * 只清空实际被动画引擎设置过的CSS属性\\r\\n */\\r\\n private clearElementStyles(): void {\\r\\n if (this.targetElement == null) { return }\\r\\n\\r\\n const element = this.targetElement\\r\\n\\r\\n // 清空所有动画属性列表中记录的属性\\r\\n for (const attr of this.animationAttributes) {\\r\\n const propertyName = attr.propertyName\\r\\n\\r\\n // Transform 相关属性需要清空transform\\r\\n if (this.isTransformProperty(propertyName)) {\\r\\n element.style!.setProperty('transform', '')\\r\\n }\\r\\n else {\\r\\n // 其他属性直接清空\\r\\n element.style!.setProperty(propertyName, '')\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 重置动画到初始状态,清空所有内容\\r\\n */\\r\\n reset(): AnimationEngine {\\r\\n // 停止当前动画\\r\\n this.stop()\\r\\n\\r\\n // 清空应用到元素上的所有样式\\r\\n this.clearElementStyles()\\r\\n\\r\\n // 重置所有动画状态\\r\\n this.currentProgress = 0\\r\\n this.currentLoop = 0\\r\\n this.currentAttributeIndex = 0\\r\\n this.isAlternateReversed = false\\r\\n this.isReversed = false\\r\\n this.isPaused = false\\r\\n this.isStopping = true\\r\\n this.startTimestamp = 0\\r\\n\\r\\n // 清空动画属性列表\\r\\n this.animationAttributes = []\\r\\n\\r\\n // 重置缓动函数\\r\\n this.currentEasingFunction = null\\r\\n\\r\\n // 重置回调函数\\r\\n this.onComplete = () => { }\\r\\n this.onStart = () => { }\\r\\n this.onFrame = () => { }\\r\\n\\r\\n // 清理平台相关的动画控制器\\r\\n // #ifdef WEB || APP-IOS || APP-HARMONY\\r\\n if (this.animationFrameId != null) {\\r\\n cancelAnimationFrame(this.animationFrameId)\\r\\n this.animationFrameId = null\\r\\n }\\r\\n // #endif\\r\\n\\r\\n // #ifdef APP-ANDROID\\r\\n if (this.choreographer != null && this.frameCallback != null) {\\r\\n this.choreographer.removeFrameCallback(this.frameCallback)\\r\\n this.frameCallback = null\\r\\n }\\r\\n this.choreographer = null\\r\\n // #endif\\r\\n\\r\\n // #ifdef MP\\r\\n if (this.displayLinkTimer != 0) {\\r\\n clearTimeout(this.displayLinkTimer)\\r\\n this.displayLinkTimer = 0\\r\\n }\\r\\n // #endif\\r\\n\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取当前动画进度\\r\\n */\\r\\n getProgress(): number {\\r\\n return this.currentProgress\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取动画是否正在运行\\r\\n */\\r\\n isAnimating(): boolean {\\r\\n return this.isRunning\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取当前循环次数\\r\\n */\\r\\n getCurrentLoop(): number {\\r\\n return this.currentLoop\\r\\n }\\r\\n\\r\\n /**\\r\\n * 清除所有动画属性\\r\\n */\\r\\n clearAttributes(): AnimationEngine {\\r\\n this.animationAttributes = []\\r\\n return this\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取动画属性数量\\r\\n */\\r\\n getAttributeCount(): number {\\r\\n return this.animationAttributes.length\\r\\n }\\r\\n\\r\\n /**\\r\\n * 淡入动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n fadeIn(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 淡出动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n fadeOut(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑入动画(从左)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideInLeft(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).translateX('-100%', '0%').opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑入动画(从右)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideInRight(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).translateX('100%', '0%').opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑入动画(从上)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideInUp(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateY', '-100%', '0%')\\r\\n .opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑入动画(从下)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideInDown(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateY', '100%', '0%')\\r\\n .opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 缩放动画(放大)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n zoomIn(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).scale('0', '1').opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 缩放动画(缩小)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n zoomOut(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).scale('1', '0').opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 旋转动画\\r\\n * @param duration 持续时间\\r\\n * @param degrees 旋转角度\\r\\n */\\r\\n rotateIn(duration: number = 500, degrees: number = 360): AnimationEngine {\\r\\n return this.setDuration(duration).rotate('0deg', `${degrees}deg`).opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 旋转退出动画\\r\\n * @param duration 持续时间\\r\\n * @param degrees 旋转角度\\r\\n */\\r\\n rotateOut(duration: number = 500, degrees: number = 360): AnimationEngine {\\r\\n return this.setDuration(duration).rotate('0deg', `${degrees}deg`).opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 弹跳动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n bounce(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addCustomEasing('bounce', [0.68, -0.55, 0.265, 1.55])\\r\\n .scale('1', '1.1')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(2)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 摇摆动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n shake(duration: number = 500): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateX', '0px', '10px')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(6)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 链式动画:支持多个动画依次执行\\r\\n * @param animations 动画配置函数数组\\r\\n */\\r\\n sequence(animations: ((engine: AnimationEngine) => AnimationEngine)[]): AnimationEngine {\\r\\n const self = this\\r\\n\\r\\n if (animations.length == 0) {\\r\\n return this\\r\\n }\\r\\n\\r\\n // 执行第一个动画\\r\\n const firstEngine = animations[0](new AnimationEngine(this.targetElement, {}))\\r\\n\\r\\n // 如果只有一个动画,直接返回\\r\\n if (animations.length == 1) {\\r\\n return firstEngine\\r\\n }\\r\\n\\r\\n // 递归设置后续动画\\r\\n function setNextAnimation(\\r\\n currentEngine: AnimationEngine,\\r\\n remainingAnimations: ((engine: AnimationEngine) => AnimationEngine)[],\\r\\n ): void {\\r\\n if (remainingAnimations.length == 0) {\\r\\n return\\r\\n }\\r\\n\\r\\n const originalComplete = currentEngine.onComplete\\r\\n currentEngine.onComplete = () => {\\r\\n originalComplete()\\r\\n\\r\\n // 执行下一个动画\\r\\n const nextEngine = remainingAnimations[0](\\r\\n new AnimationEngine(self.targetElement, {}),\\r\\n )\\r\\n\\r\\n // 如果还有更多动画,继续设置链式\\r\\n if (remainingAnimations.length > 1) {\\r\\n setNextAnimation(nextEngine, remainingAnimations.slice(1))\\r\\n }\\r\\n\\r\\n nextEngine.play()\\r\\n }\\r\\n }\\r\\n\\r\\n // 设置动画链\\r\\n setNextAnimation(firstEngine, animations.slice(1))\\r\\n\\r\\n return firstEngine\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑出动画(向左)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideOutLeft(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).translateX('0%', '-100%').opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑出动画(向右)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideOutRight(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration).translateX('0%', '100%').opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑出动画(向上)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideOutUp(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateY', '0%', '-100%')\\r\\n .opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滑出动画(向下)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n slideOutDown(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateY', '0%', '100%')\\r\\n .opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 翻转动画(水平)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n flipX(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('rotateX', '0deg', '180deg')\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 翻转动画(垂直)\\r\\n * @param duration 持续时间\\r\\n */\\r\\n flipY(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('rotateY', '0deg', '180deg')\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 弹性进入动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n elasticIn(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('0', '1')\\r\\n .opacity('0', '1')\\r\\n .addCustomEasing('elastic', [0.175, 0.885, 0.32, 1.275])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 弹性退出动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n elasticOut(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('1', '0')\\r\\n .opacity('1', '0')\\r\\n .addCustomEasing('elastic', [0.68, -0.55, 0.265, 1.55])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 回弹动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n rubberBand(duration: number = 1000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('scaleX', '1', '1.25')\\r\\n .addAttribute('scaleY', '1', '0.75')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(2)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 摆动动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n swing(duration: number = 1000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('rotate', '0deg', '15deg')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(4)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 抖动动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n wobble(duration: number = 1000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('translateX', '0px', '25px')\\r\\n .addAttribute('rotate', '0deg', '5deg')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(4)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滚动进入动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n rollIn(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .translateX('-100%', '0%')\\r\\n .rotate('-120deg', '0deg')\\r\\n .opacity('0', '1')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 滚动退出动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n rollOut(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .translateX('0%', '100%')\\r\\n .rotate('0deg', '120deg')\\r\\n .opacity('1', '0')\\r\\n }\\r\\n\\r\\n /**\\r\\n * 灯光效果动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n lightSpeed(duration: number = 500): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .translateX('-100%', '0%')\\r\\n .addAttribute('skewX', '-30deg', '0deg')\\r\\n .opacity('0', '1')\\r\\n .addCustomEasing('ease-out', [0.25, 0.46, 0.45, 0.94])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 浮动动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n float(duration: number = 3000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .translateY('0px', '-10px')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(-1)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 呼吸动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n breathe(duration: number = 2000): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('1', '1.1')\\r\\n .setAlternate(true)\\r\\n .setLoopCount(-1)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 发光动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n glow(duration: number = 1500): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute(\\r\\n 'boxShadow',\\r\\n '0 0 5px rgba(255,255,255,0.5)',\\r\\n '0 0 20px rgba(255,255,255,1)',\\r\\n )\\r\\n .setAlternate(true)\\r\\n .setLoopCount(-1)\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 进度条动画\\r\\n * @param duration 持续时间\\r\\n * @param progress 进度百分比 (0-100)\\r\\n */\\r\\n progressBar(duration: number = 1000, progress: number = 100): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('width', '0%', `${progress}%`)\\r\\n .addCustomEasing('ease-out', [0.25, 0.46, 0.45, 0.94])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 模态框进入动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n modalIn(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('0.7', '1')\\r\\n .opacity('0', '1')\\r\\n .addCustomEasing('ease-out', [0.25, 0.46, 0.45, 0.94])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 模态框退出动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n modalOut(duration: number = 300): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('1', '0.7')\\r\\n .opacity('1', '0')\\r\\n .addCustomEasing('ease-in', [0.42, 0.0, 1.0, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 卡片翻转动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n cardFlip(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .addAttribute('rotateY', '0deg', '180deg')\\r\\n .addCustomEasing('ease-in-out', [0.25, 0.1, 0.25, 1.0])\\r\\n }\\r\\n\\r\\n /**\\r\\n * 波纹扩散动画\\r\\n * @param duration 持续时间\\r\\n */\\r\\n ripple(duration: number = 600): AnimationEngine {\\r\\n return this.setDuration(duration)\\r\\n .scale('0', '4')\\r\\n .opacity('0.7', '0')\\r\\n .addCustomEasing('ease-out', [0.25, 0.46, 0.45, 0.94])\\r\\n }\\r\\n}\\r\\n\\r\\n/**\\r\\n * 创建动画实例\\r\\n * @param element 目标元素\\r\\n * @param options 动画选项\\r\\n */\\r\\nexport function createAnimation(\\r\\n element: any | null,\\r\\n options: AnimationOptions = {},\\r\\n): AnimationEngine {\\r\\n return new AnimationEngine(element, options)\\r\\n}\\r\\n\",\n \"lib/base64.ts\": \"const _b64chars: string[] = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/']\\r\\nconst _mkUriSafe = (src: string): string => src.replace(/[+/]/g, (m0: string) => (m0 === '+' ? '-' : '_')).replace(/=+\\\\$/m, '')\\r\\nconst fromUint8Array = (src: Uint8Array, rfc4648 = false): string => {\\r\\n let b64 = ''\\r\\n for (let i = 0, l = src.length; i < l; i += 3) {\\r\\n const [a0, a1, a2] = [src[i], src[i + 1], src[i + 2]]\\r\\n const ord = (a0 << 16) | (a1 << 8) | a2\\r\\n b64 += _b64chars[ord >>> 18]\\r\\n b64 += _b64chars[(ord >>> 12) & 63]\\r\\n b64 += typeof a1 !== 'undefined' ? _b64chars[(ord >>> 6) & 63] : '='\\r\\n b64 += typeof a2 !== 'undefined' ? _b64chars[ord & 63] : '='\\r\\n }\\r\\n return rfc4648 ? _mkUriSafe(b64) : b64\\r\\n}\\r\\nconst _btoa: (s: string) => string =\\r\\n typeof btoa === 'function'\\r\\n ? (s: string) => btoa(s)\\r\\n : (s: string) => {\\r\\n if (s.charCodeAt(0) > 255) {\\r\\n throw new RangeError('The string contains invalid characters.')\\r\\n }\\r\\n return fromUint8Array(Uint8Array.from(s, (c: string) => c.charCodeAt(0)))\\r\\n }\\r\\nconst utob = (src: string): string => unescape(encodeURIComponent(src))\\r\\n\\r\\nexport default function encode(src: string, rfc4648 = false): string {\\r\\n const b64 = _btoa(utob(src))\\r\\n return rfc4648 ? _mkUriSafe(b64) : b64\\r\\n}\\r\\n\",\n \"lib/color-utils.ts\": \"export interface HsvaColor {\\r\\n h: number\\r\\n s: number\\r\\n v: number\\r\\n a: number\\r\\n}\\r\\n\\r\\nexport interface RgbaColor {\\r\\n r: number\\r\\n g: number\\r\\n b: number\\r\\n a: number\\r\\n}\\r\\n\\r\\nexport type ColorFormat = 'hex' | 'rgb' | 'rgba'\\r\\n\\r\\nexport function hexToHsva(hex: string): HsvaColor {\\r\\n const rgba = hexToRgba(hex)\\r\\n return rgbaToHsva(rgba)\\r\\n}\\r\\n\\r\\nexport function hsvaToHex(hsva: HsvaColor): string {\\r\\n const rgba = hsvaToRgba(hsva)\\r\\n return rgbaToHex(rgba)\\r\\n}\\r\\n\\r\\nexport function hexToRgba(hex: string): RgbaColor {\\r\\n hex = hex.replace(/^#/, '')\\r\\n if (hex.length === 3) {\\r\\n hex = hex.split('').map(char => char + char).join('')\\r\\n }\\r\\n\\r\\n if (hex.length !== 6 && hex.length !== 8) {\\r\\n return { r: 0, g: 0, b: 0, a: 1 }\\r\\n }\\r\\n\\r\\n const r = parseInt(hex.slice(0, 2), 16)\\r\\n const g = parseInt(hex.slice(2, 4), 16)\\r\\n const b = parseInt(hex.slice(4, 6), 16)\\r\\n const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1\\r\\n\\r\\n return { r, g, b, a }\\r\\n}\\r\\n\\r\\nexport function rgbaToHex(rgba: RgbaColor): string {\\r\\n const r = Math.round(rgba.r).toString(16).padStart(2, '0')\\r\\n const g = Math.round(rgba.g).toString(16).padStart(2, '0')\\r\\n const b = Math.round(rgba.b).toString(16).padStart(2, '0')\\r\\n const a = rgba.a < 1 ? Math.round(rgba.a * 255).toString(16).padStart(2, '0') : ''\\r\\n return `#${r}${g}${b}${a}`.toLowerCase()\\r\\n}\\r\\n\\r\\nexport function rgbaToHsva(rgba: RgbaColor): HsvaColor {\\r\\n const r = rgba.r / 255\\r\\n const g = rgba.g / 255\\r\\n const b = rgba.b / 255\\r\\n const max = Math.max(r, g, b)\\r\\n const min = Math.min(r, g, b)\\r\\n const delta = max - min\\r\\n let h = 0\\r\\n if (delta !== 0) {\\r\\n if (max === r) h = ((g - b) / delta) % 6\\r\\n else if (max === g) h = (b - r) / delta + 2\\r\\n else h = (r - g) / delta + 4\\r\\n h = Math.round(h * 60)\\r\\n if (h < 0) h += 360\\r\\n }\\r\\n const s = max === 0 ? 0 : delta / max\\r\\n const v = max\\r\\n return { h, s: s * 100, v: v * 100, a: rgba.a }\\r\\n}\\r\\n\\r\\nexport function hsvaToRgba(hsva: HsvaColor): RgbaColor {\\r\\n const h = hsva.h / 60\\r\\n const s = hsva.s / 100\\r\\n const v = hsva.v / 100\\r\\n const i = Math.floor(h)\\r\\n const f = h - i\\r\\n const p = v * (1 - s)\\r\\n const q = v * (1 - f * s)\\r\\n const t = v * (1 - (1 - f) * s)\\r\\n const mod = i % 6\\r\\n let r = 0, g = 0, b = 0\\r\\n if (mod === 0) { r = v; g = t; b = p }\\r\\n else if (mod === 1) { r = q; g = v; b = p }\\r\\n else if (mod === 2) { r = p; g = v; b = t }\\r\\n else if (mod === 3) { r = p; g = q; b = v }\\r\\n else if (mod === 4) { r = t; g = p; b = v }\\r\\n else if (mod === 5) { r = v; g = p; b = q }\\r\\n return {\\r\\n r: Math.round(r * 255),\\r\\n g: Math.round(g * 255),\\r\\n b: Math.round(b * 255),\\r\\n a: hsva.a\\r\\n }\\r\\n}\\r\\n\\r\\nexport function detectColorFormat(value: string | undefined | null): ColorFormat {\\r\\n if (!value) return 'hex'\\r\\n\\r\\n const normalized = value.trim().toLowerCase()\\r\\n if (normalized.startsWith('rgba(')) return 'rgba'\\r\\n if (normalized.startsWith('rgb(')) return 'rgb'\\r\\n return 'hex'\\r\\n}\\r\\n\\r\\nexport function parseColorString(value: string | undefined | null): RgbaColor | null {\\r\\n if (!value) return null\\r\\n\\r\\n const normalized = value.trim()\\r\\n\\r\\n if (normalized.startsWith('#')) {\\r\\n return hexToRgba(normalized)\\r\\n }\\r\\n\\r\\n const match = normalized.match(/rgba?\\\\((\\\\d+),\\\\s*(\\\\d+),\\\\s*(\\\\d+)(?:,\\\\s*([\\\\d.]+))?\\\\)/i)\\r\\n if (!match) return null\\r\\n\\r\\n return {\\r\\n r: Number.parseInt(match[1] || '0'),\\r\\n g: Number.parseInt(match[2] || '0'),\\r\\n b: Number.parseInt(match[3] || '0'),\\r\\n a: match[4] ? Number.parseFloat(match[4]) : 1,\\r\\n }\\r\\n}\\r\\n\\r\\nexport function colorStringToHsva(value: string | undefined | null): HsvaColor {\\r\\n const rgba = parseColorString(value)\\r\\n if (!rgba) {\\r\\n return hexToHsva('#000000')\\r\\n }\\r\\n\\r\\n return rgbaToHsva(rgba)\\r\\n}\\r\\n\\r\\nexport function hsvaToColorString(hsva: HsvaColor, format: ColorFormat): string {\\r\\n if (format === 'hex') {\\r\\n return hsvaToHex(hsva)\\r\\n }\\r\\n\\r\\n const rgba = hsvaToRgba(hsva)\\r\\n if (format === 'rgb') {\\r\\n return `rgb(${rgba.r}, ${rgba.g}, ${rgba.b})`\\r\\n }\\r\\n\\r\\n return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a.toFixed(2)})`\\r\\n}\\r\\n\",\n \"lib/dayUts.ts\": \"export class DayUts {\\r\\n private _date: Date\\r\\n\\r\\n constructor(date?: Date | string | number | null) {\\r\\n if (date == null || date == '') {\\r\\n this._date = new Date()\\r\\n }\\r\\n else if (typeof date == 'string') {\\r\\n // 修复 iOS/Safari 的 'YYYY-MM-DD HH:mm:ss' 格式兼容性问题\\r\\n // iOS 只支持 'YYYY/MM/DD' 等使用斜杠的格式,所以如果包含 '-' 则替换为 '/' (仅日期部分的 '-')\\r\\n const safeDateStr = date.includes('-') && date.includes(':')\\r\\n ? date.replace(/-/g, '/')\\r\\n : date\\r\\n this._date = new Date(safeDateStr)\\r\\n }\\r\\n else if (typeof date == 'number') {\\r\\n this._date = new Date(date)\\r\\n }\\r\\n else if (date instanceof Date) {\\r\\n this._date = new Date(date.getTime())\\r\\n }\\r\\n else {\\r\\n this._date = new Date()\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 格式化日期\\r\\n * @param template 格式模板,支持 YYYY-MM-DD HH:mm:ss 等\\r\\n */\\r\\n format(template: string): string {\\r\\n // 使用传入的模板\\r\\n const actualTemplate: string = template\\r\\n\\r\\n const year = this._date.getFullYear()\\r\\n const month = this._date.getMonth() + 1\\r\\n const date = this._date.getDate()\\r\\n const hours = this._date.getHours()\\r\\n const minutes = this._date.getMinutes()\\r\\n const seconds = this._date.getSeconds()\\r\\n const milliseconds = this._date.getMilliseconds()\\r\\n\\r\\n // 使用数组来依次替换,避免UTS的replace方法兼容性问题\\r\\n let result: string = actualTemplate\\r\\n\\r\\n // 按照长度从长到短替换,避免冲突\\r\\n // 替换年份 (YYYY 必须在 YY 之前)\\r\\n result = result.replace('YYYY', year.toString())\\r\\n result = result.replace('YY', year.toString().slice(-2))\\r\\n\\r\\n // 替换月份 (MM 必须在 M 之前)\\r\\n result = result.replace('MM', month.toString().padStart(2, '0'))\\r\\n result = result.replace('M', month.toString())\\r\\n\\r\\n // 替换日期 (DD 必须在 D 之前)\\r\\n result = result.replace('DD', date.toString().padStart(2, '0'))\\r\\n result = result.replace('D', date.toString())\\r\\n\\r\\n // 替换小时 (HH 必须在 H 之前)\\r\\n result = result.replace('HH', hours.toString().padStart(2, '0'))\\r\\n result = result.replace('H', hours.toString())\\r\\n\\r\\n // 替换分钟 (mm 必须在 m 之前)\\r\\n result = result.replace('mm', minutes.toString().padStart(2, '0'))\\r\\n result = result.replace('m', minutes.toString())\\r\\n\\r\\n // 替换秒数 (ss 必须在 s 之前)\\r\\n result = result.replace('ss', seconds.toString().padStart(2, '0'))\\r\\n result = result.replace('s', seconds.toString())\\r\\n\\r\\n // 替换毫秒\\r\\n result = result.replace('SSS', milliseconds.toString().padStart(3, '0'))\\r\\n\\r\\n return result\\r\\n }\\r\\n\\r\\n /**\\r\\n * 本月多少天\\r\\n */\\r\\n getDays(): number {\\r\\n return new Date(this._date.getFullYear(), this._date.getMonth() + 1, 0).getDate()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 是否为闰年\\r\\n */\\r\\n isLeapYear(): boolean {\\r\\n return this._date.getFullYear() % 4 == 0 && this._date.getFullYear() % 100 != 0\\r\\n }\\r\\n\\r\\n /**\\r\\n * 星期几\\r\\n */\\r\\n getDay(): number {\\r\\n return this._date.getDay()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取某个单位的开始时间\\r\\n */\\r\\n startOf(unit: 'month' | 'day' | 'year' | 'week'): DayUts {\\r\\n const newDate = new Date(this._date.getTime())\\r\\n\\r\\n switch (unit) {\\r\\n case 'year':\\r\\n newDate.setMonth(0)\\r\\n newDate.setDate(1)\\r\\n newDate.setHours(0)\\r\\n newDate.setMinutes(0)\\r\\n newDate.setSeconds(0)\\r\\n newDate.setMilliseconds(0)\\r\\n break\\r\\n case 'month':\\r\\n newDate.setDate(1)\\r\\n newDate.setHours(0)\\r\\n newDate.setMinutes(0)\\r\\n newDate.setSeconds(0)\\r\\n newDate.setMilliseconds(0)\\r\\n break\\r\\n case 'week':\\r\\n newDate.setDate(newDate.getDate() - newDate.getDay())\\r\\n newDate.setHours(0)\\r\\n newDate.setMinutes(0)\\r\\n newDate.setSeconds(0)\\r\\n newDate.setMilliseconds(0)\\r\\n break\\r\\n case 'day':\\r\\n newDate.setHours(0)\\r\\n newDate.setMinutes(0)\\r\\n newDate.setSeconds(0)\\r\\n newDate.setMilliseconds(0)\\r\\n break\\r\\n }\\r\\n\\r\\n return new DayUts(newDate)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取某个单位的结束时间\\r\\n */\\r\\n endOf(unit: 'month' | 'day' | 'year' | 'week'): DayUts {\\r\\n const newDate = new Date(this._date.getTime())\\r\\n\\r\\n switch (unit) {\\r\\n case 'year':\\r\\n newDate.setMonth(11)\\r\\n newDate.setDate(31)\\r\\n newDate.setHours(23)\\r\\n newDate.setMinutes(59)\\r\\n newDate.setSeconds(59)\\r\\n newDate.setMilliseconds(999)\\r\\n break\\r\\n case 'month':\\r\\n newDate.setMonth(newDate.getMonth() + 1)\\r\\n newDate.setDate(0)\\r\\n newDate.setHours(23)\\r\\n newDate.setMinutes(59)\\r\\n newDate.setSeconds(59)\\r\\n newDate.setMilliseconds(999)\\r\\n break\\r\\n case 'week':\\r\\n const day = newDate.getDay()\\r\\n const diff = 6 - day\\r\\n newDate.setDate(newDate.getDate() + diff)\\r\\n newDate.setHours(23)\\r\\n newDate.setMinutes(59)\\r\\n newDate.setSeconds(59)\\r\\n newDate.setMilliseconds(999)\\r\\n break\\r\\n case 'day':\\r\\n newDate.setHours(23)\\r\\n newDate.setMinutes(59)\\r\\n newDate.setSeconds(59)\\r\\n newDate.setMilliseconds(999)\\r\\n break\\r\\n }\\r\\n\\r\\n return new DayUts(newDate)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否早于另一个日期\\r\\n */\\r\\n isBefore(date: DayUts | Date | string | number): boolean {\\r\\n const compareDate = this._parseDate(date)\\r\\n return this._date.getTime() < compareDate.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否晚于另一个日期\\r\\n */\\r\\n isAfter(date: DayUts | Date | string | number): boolean {\\r\\n const compareDate = this._parseDate(date)\\r\\n return this._date.getTime() > compareDate.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 判断是否与另一个日期相同\\r\\n */\\r\\n isSame(date: DayUts | Date | string | number): boolean {\\r\\n const compareDate = this._parseDate(date)\\r\\n return this._date.getTime() == compareDate.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 计算与另一个日期的差值(毫秒)\\r\\n */\\r\\n diff(date: DayUts | Date | string | number): number {\\r\\n const compareDate = this._parseDate(date)\\r\\n return this._date.getTime() - compareDate.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 计算与另一个日期的差值(指定单位)\\r\\n */\\r\\n diffUnit(\\r\\n date: DayUts | Date | string | number,\\r\\n unit: 'day' | 'hour' | 'minute' | 'second' | 'millisecond',\\r\\n ): number {\\r\\n const compareDate = this._parseDate(date)\\r\\n const diffMs = this._date.getTime() - compareDate.getTime()\\r\\n\\r\\n switch (unit) {\\r\\n case 'day':\\r\\n return Math.floor(diffMs / (1000 * 60 * 60 * 24))\\r\\n case 'hour':\\r\\n return Math.floor(diffMs / (1000 * 60 * 60))\\r\\n case 'minute':\\r\\n return Math.floor(diffMs / (1000 * 60))\\r\\n case 'second':\\r\\n return Math.floor(diffMs / 1000)\\r\\n case 'millisecond':\\r\\n default:\\r\\n return diffMs\\r\\n }\\r\\n }\\r\\n\\r\\n /**\\r\\n * 添加时间\\r\\n */\\r\\n add(value: number, unit: 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second'): DayUts {\\r\\n const newDate = new Date(this._date.getTime())\\r\\n\\r\\n switch (unit) {\\r\\n case 'year':\\r\\n newDate.setFullYear(newDate.getFullYear() + value)\\r\\n break\\r\\n case 'month':\\r\\n newDate.setMonth(newDate.getMonth() + value)\\r\\n break\\r\\n case 'day':\\r\\n newDate.setDate(newDate.getDate() + value)\\r\\n break\\r\\n case 'hour':\\r\\n newDate.setHours(newDate.getHours() + value)\\r\\n break\\r\\n case 'minute':\\r\\n newDate.setMinutes(newDate.getMinutes() + value)\\r\\n break\\r\\n case 'second':\\r\\n newDate.setSeconds(newDate.getSeconds() + value)\\r\\n break\\r\\n }\\r\\n\\r\\n return new DayUts(newDate)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 减少时间\\r\\n */\\r\\n subtract(value: number, unit: 'day' | 'month' | 'year' | 'hour' | 'minute' | 'second'): DayUts {\\r\\n return this.add(-value, unit)\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取时间戳\\r\\n */\\r\\n valueOf(): number {\\r\\n return this._date.getTime()\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取原生Date对象\\r\\n */\\r\\n toDate(): Date {\\r\\n return new Date(this._date.getTime())\\r\\n }\\r\\n\\r\\n /**\\r\\n * 获取日期数组\\r\\n */\\r\\n toArray(): number[] {\\r\\n return [\\r\\n this._date.getFullYear(),\\r\\n this._date.getMonth() + 1,\\r\\n this._date.getDate(),\\r\\n this._date.getHours(),\\r\\n this._date.getMinutes(),\\r\\n this._date.getSeconds(),\\r\\n ]\\r\\n }\\r\\n\\r\\n /**\\r\\n * 私有方法:解析不同类型的日期参数\\r\\n */\\r\\n private _parseDate(date: DayUts | Date | string | number): Date {\\r\\n if (date instanceof DayUts) {\\r\\n return date.toDate()\\r\\n }\\r\\n else if (date instanceof Date) {\\r\\n return date\\r\\n }\\r\\n else if (typeof date == 'string') {\\r\\n const safeDateStr = date.includes('-') && date.includes(':')\\r\\n ? date.replace(/-/g, '/')\\r\\n : date\\r\\n return new Date(safeDateStr)\\r\\n }\\r\\n else if (typeof date == 'number') {\\r\\n return new Date(date)\\r\\n }\\r\\n else {\\r\\n // 如果都不匹配,返回当前时间\\r\\n return new Date()\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n/**\\r\\n * 创建 DayUts 实例\\r\\n */\\r\\nexport function dayUts(date: Date | string | number | null = new Date()): DayUts {\\r\\n return new DayUts(date)\\r\\n}\\r\\n\",\n \"lib/device.ts\": \"/**\\r\\n * 系统信息接口,包含项目中实际使用的字段\\r\\n */\\r\\nexport interface SystemInfo {\\r\\n /** 窗口宽度 */\\r\\n windowWidth: number\\r\\n /** 窗口高度 */\\r\\n windowHeight: number\\r\\n /** 窗口顶部位置 */\\r\\n windowTop: number\\r\\n /** 设备像素比 */\\r\\n pixelRatio: number\\r\\n /** 平台信息 */\\r\\n platform: string\\r\\n /** 主题模式 */\\r\\n theme?: string\\r\\n /** 状态栏高度 */\\r\\n statusBarHeight?: number\\r\\n /** 安全区域信息 */\\r\\n safeArea?: UniApp.SafeArea\\r\\n /** 屏幕高度 */\\r\\n screenHeight: number\\r\\n /** 安全区域插入信息 */\\r\\n safeAreaInsets?: UniApp.SafeAreaInsets\\r\\n // 未尽字段\\r\\n [key: string]: any\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为小程序环境\\r\\n * @returns 是否为小程序环境\\r\\n */\\r\\nexport function isMp(): boolean {\\r\\n // #ifdef MP\\r\\n return true\\r\\n // #endif\\r\\n\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为App环境\\r\\n * @returns 是否为App环境\\r\\n */\\r\\nexport function isApp(): boolean {\\r\\n // #ifdef APP\\r\\n return true\\r\\n // #endif\\r\\n\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为App-IOS环境\\r\\n * @returns 是否为App-IOS环境\\r\\n */\\r\\nexport function isAppIOS(): boolean {\\r\\n // #ifdef APP-IOS\\r\\n return true\\r\\n // #endif\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为App-Android环境\\r\\n * @returns 是否为App-Android环境\\r\\n */\\r\\nexport function isAppAndroid(): boolean {\\r\\n // #ifdef APP-ANDROID\\r\\n return true\\r\\n // #endif\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为H5环境\\r\\n * @returns 是否为H5环境\\r\\n */\\r\\nexport function isH5(): boolean {\\r\\n // #ifdef H5\\r\\n return true\\r\\n // #endif\\r\\n\\r\\n return false\\r\\n}\\r\\n\\r\\n/**\\r\\n * 检查是否为鸿蒙环境\\r\\n * @returns 是否为鸿蒙环境\\r\\n */\\r\\nexport function isHarmony(): boolean {\\r\\n // #ifdef APP-HARMONY\\r\\n return true\\r\\n // #endif\\r\\n\\r\\n return false\\r\\n}\\r\\n\\r\\nexport function initTheme() {\\r\\n let value: string | null\\r\\n\\r\\n // #ifdef APP\\r\\n const appInfo = uni.getAppBaseInfo()\\r\\n // @ts-ignore\\r\\n const appTheme = appInfo.appTheme as string\\r\\n const osTheme = uni.getSystemInfoSync().osTheme!\\r\\n\\r\\n // 如果 appTheme 为 auto,则跟随系统主题,否则使用 appTheme\\r\\n value = appTheme == 'auto' ? osTheme : appTheme\\r\\n // #endif\\r\\n\\r\\n // #ifdef H5 || MP\\r\\n const hostTheme = uni.getAppBaseInfo().hostTheme\\r\\n if (hostTheme) {\\r\\n // 如果有 hostTheme,则使用 hostTheme\\r\\n value = hostTheme\\r\\n }\\r\\n else {\\r\\n // 默认使用 light 主题\\r\\n value = 'light'\\r\\n }\\r\\n // #endif\\r\\n return value\\r\\n}\\r\\n\\r\\n/**\\r\\n * 获取安全区域高度\\r\\n * @param type 类型\\r\\n * @returns 安全区域高度\\r\\n */\\r\\nexport function getSafeAreaHeight(type: 'top' | 'bottom') {\\r\\n const { safeAreaInsets } = uni.getWindowInfo()\\r\\n\\r\\n let h: number\\r\\n\\r\\n if (type == 'top') {\\r\\n h = safeAreaInsets.top\\r\\n }\\r\\n else {\\r\\n h = safeAreaInsets.bottom\\r\\n\\r\\n // #ifdef APP-ANDROID\\r\\n if (h == 0) {\\r\\n h = 16\\r\\n }\\r\\n // #endif\\r\\n }\\r\\n\\r\\n return h\\r\\n}\\r\\n\\r\\n/**\\r\\n * 兼容微信小程序端获取系统信息的方法\\r\\n * 在微信小程序端使用新的API替代getSystemInfoSync,在其他端仍然使用getSystemInfoSync\\r\\n * @returns 系统信息对象\\r\\n */\\r\\nexport function getSystemInfo(): SystemInfo {\\r\\n let systemInfo: SystemInfo\\r\\n // #ifdef MP-WEIXIN\\r\\n try {\\r\\n // const systemSetting = uni.getSystemInfoSync() // 暂时不需要\\r\\n const deviceInfo = uni.getDeviceInfo()\\r\\n const windowInfo = uni.getWindowInfo()\\r\\n const appBaseInfo = uni.getAppBaseInfo()\\r\\n systemInfo = {\\r\\n ...deviceInfo,\\r\\n ...windowInfo,\\r\\n ...appBaseInfo\\r\\n }\\r\\n } catch (error) {\\r\\n console.warn('获取系统信息失败,降级使用uni.getSystemInfoSync:', error)\\r\\n // 降级处理,使用原来的方法\\r\\n systemInfo = uni.getSystemInfoSync()\\r\\n }\\r\\n // #endif\\r\\n // #ifndef MP-WEIXIN\\r\\n systemInfo = uni.getSystemInfoSync()\\r\\n // #endif\\r\\n return systemInfo\\r\\n}\",\n \"lib/file.ts\": \"export function uuid(): string {\\r\\n\\tlet uuid = \\\"\\\";\\r\\n\\tlet i: number;\\r\\n\\tlet random: number;\\r\\n\\r\\n\\tfor (i = 0; i < 36; i++) {\\r\\n\\t\\tif (i == 8 || i == 13 || i == 18 || i == 23) {\\r\\n\\t\\t\\tuuid += \\\"-\\\";\\r\\n\\t\\t} else if (i == 14) {\\r\\n\\t\\t\\tuuid += \\\"4\\\";\\r\\n\\t\\t} else if (i == 19) {\\r\\n\\t\\t\\trandom = (Math.random() * 16) | 0;\\r\\n\\t\\t\\tuuid += ((random & 0x3) | 0x8).toString(16);\\r\\n\\t\\t} else {\\r\\n\\t\\t\\trandom = (Math.random() * 16) | 0;\\r\\n\\t\\t\\tuuid += random.toString(16);\\r\\n\\t\\t}\\r\\n\\t}\\r\\n\\treturn uuid;\\r\\n}\\r\\n\\r\\n\\r\\nexport function base64ToBlob(data: string, type: string = \\\"image/jpeg\\\"): Blob {\\r\\n\\t// #ifdef H5\\r\\n\\tlet bytes = window.atob(data.split(\\\",\\\")[1]);\\r\\n\\tlet ab = new ArrayBuffer(bytes.length);\\r\\n\\tlet ia = new Uint8Array(ab);\\r\\n\\tfor (let i = 0; i < bytes.length; i++) {\\r\\n\\t\\tia[i] = bytes.charCodeAt(i);\\r\\n\\t}\\r\\n\\treturn new Blob([ab], { type });\\r\\n\\t// #endif\\r\\n}\\r\\n\\r\\n/**\\r\\n * 将canvas转换为png图片\\r\\n * @param options 转换参数\\r\\n * @returns 图片路径\\r\\n */\\r\\nexport function canvasToPng(canvasRef: any): Promise<string> {\\r\\n\\treturn new Promise((resolve) => {\\r\\n\\t\\t// #ifdef APP\\r\\n\\t\\tcanvasRef.parentElement!.takeSnapshot({\\r\\n\\t\\t\\tsuccess(res: any) {\\r\\n\\t\\t\\t\\tresolve(res.tempFilePath);\\r\\n\\t\\t\\t},\\r\\n\\t\\t\\tfail(err: any) {\\r\\n\\t\\t\\t\\tconsole.error(err);\\r\\n\\t\\t\\t\\tresolve(\\\"\\\");\\r\\n\\t\\t\\t}\\r\\n\\t\\t});\\r\\n\\t\\t// #endif\\r\\n\\r\\n\\t\\t// #ifdef H5\\r\\n\\t\\tconst url = URL.createObjectURL(\\r\\n\\t\\t\\tbase64ToBlob(\\r\\n\\t\\t\\t\\t(canvasRef as unknown as HTMLCanvasElement)?.toDataURL(\\\"image/png\\\", 1) ?? \\\"\\\"\\r\\n\\t\\t\\t)\\r\\n\\t\\t);\\r\\n\\r\\n\\t\\tresolve(url);\\r\\n\\t\\t// #endif\\r\\n\\r\\n\\t\\t// #ifdef MP\\r\\n\\t\\tuni.createCanvasContextAsync({\\r\\n\\t\\t\\tid: canvasRef.id,\\r\\n\\t\\t\\tcomponent: canvasRef.$vm,\\r\\n\\t\\t\\tsuccess(context: any) {\\r\\n\\t\\t\\t\\t// 获取2D绘图上下文\\r\\n\\t\\t\\t\\tconst ctx = context.getContext(\\\"2d\\\")!;\\r\\n\\r\\n\\t\\t\\t\\t// 获取canvas对象\\r\\n\\t\\t\\t\\tconst canvas = ctx.canvas;\\r\\n\\r\\n\\t\\t\\t\\t// 将canvas转换为base64格式的PNG图片数据\\r\\n\\t\\t\\t\\tconst data = canvas.toDataURL(\\\"image/png\\\", 1);\\r\\n\\r\\n\\t\\t\\t\\t// 获取文件系统管理器\\r\\n\\t\\t\\t\\tconst fileMg = uni.getFileSystemManager();\\r\\n\\r\\n\\t\\t\\t\\t// 生成临时文件路径\\r\\n\\t\\t\\t\\t// @ts-ignore\\r\\n\\t\\t\\t\\tconst filepath = `${wx.env.USER_DATA_PATH}/${uuid()}.png`;\\r\\n\\r\\n\\t\\t\\t\\t// 将base64数据写入文件\\r\\n\\t\\t\\t\\tfileMg.writeFile({\\r\\n\\t\\t\\t\\t\\tfilePath: filepath,\\r\\n\\t\\t\\t\\t\\tdata: data.split(\\\",\\\")[1],\\r\\n\\t\\t\\t\\t\\tencoding: \\\"base64\\\",\\r\\n\\t\\t\\t\\t\\tsuccess() {\\r\\n\\t\\t\\t\\t\\t\\tresolve(filepath);\\r\\n\\t\\t\\t\\t\\t},\\r\\n\\t\\t\\t\\t\\tfail(err) {\\r\\n\\t\\t\\t\\t\\t\\tconsole.error(err);\\r\\n\\t\\t\\t\\t\\t\\tresolve(\\\"\\\");\\r\\n\\t\\t\\t\\t\\t}\\r\\n\\t\\t\\t\\t});\\r\\n\\t\\t\\t},\\r\\n\\t\\t\\tfail(err: any) {\\r\\n\\t\\t\\t\\tconsole.error(err);\\r\\n\\t\\t\\t\\tresolve(\\\"\\\");\\r\\n\\t\\t\\t}\\r\\n\\t\\t});\\r\\n\\t\\t// #endif\\r\\n\\t});\\r\\n}\\r\\n\",\n \"lib/tv.ts\": \"import type { TV } from 'tailwind-variants'\\r\\n\\r\\n// #ifdef MP-WEIXIN\\r\\n// @ts-ignore\\r\\nimport { create } from '@weapp-tailwindcss/variants-v3'\\r\\n// #endif\\r\\n\\r\\n// #ifndef MP-WEIXIN\\r\\nimport { tv as originTv } from 'tailwind-variants'\\r\\n// #endif\\r\\n\\r\\nconst textSizeKeys = ['20', '22', '24', '26', '28', '30', '32', '36', '40', '48', '52']\\r\\n\\r\\nconst twMergeConfig = {\\r\\n extend: {\\r\\n classGroups: {\\r\\n 'font-size': [{ text: textSizeKeys }],\\r\\n },\\r\\n },\\r\\n}\\r\\n\\r\\n// #ifdef MP-WEIXIN\\r\\n\\r\\n// @ts-ignore\\r\\nconst isH5 = process.env.UNI_PLATFORM === 'h5'\\r\\n\\r\\nconst { tv: createTV } = create({\\r\\n // @ts-ignore\\r\\n escape: !isH5,\\r\\n // @ts-ignore\\r\\n unescape: !isH5,\\r\\n})\\r\\n\\r\\n// @ts-ignore\\r\\nexport const tv: TV = (options, config) =>\\r\\n // @ts-ignore\\r\\n createTV(options, {\\r\\n ...config,\\r\\n twMerge: config?.twMerge ?? true,\\r\\n twMergeConfig: {\\r\\n ...config?.twMergeConfig,\\r\\n ...twMergeConfig,\\r\\n },\\r\\n })\\r\\n\\r\\n// #endif\\r\\n\\r\\n// #ifndef MP-WEIXIN\\r\\n// @ts-ignore\\r\\nexport const tv: TV = (options, config) =>\\r\\n originTv(options, {\\r\\n ...config,\\r\\n twMerge: config?.twMerge ?? true,\\r\\n twMergeConfig: {\\r\\n ...config?.twMergeConfig,\\r\\n ...twMergeConfig,\\r\\n },\\r\\n })\\r\\n\\r\\n// #endif\\r\\n\",\n \"lib/util.ts\": \"import { AbortablePromise } from './AbortablePromise'\\r\\n\\r\\ntype NotUndefined<T> = T extends undefined ? never : T\\r\\n\\r\\nexport function isObj(value: any): value is object {\\r\\n return Object.prototype.toString.call(value) === '[object Object]' || typeof value === 'object'\\r\\n}\\r\\n\\r\\nexport function getType(target: unknown): string {\\r\\n const typeStr = Object.prototype.toString.call(target)\\r\\n const match = typeStr.match(/\\\\[object (\\\\w+)\\\\]/)\\r\\n return match && match.length ? match[1].toLowerCase() : ''\\r\\n}\\r\\n\\r\\nexport const isDef = <T>(value: T): value is NonNullable<T> => value !== undefined && value !== null\\r\\n\\r\\nexport function addUnit(num: number | string) {\\r\\n return Number.isNaN(Number(num)) ? `${num}` : `${num}rpx`\\r\\n}\\r\\n\\r\\nexport function rgbToHex(r: number, g: number, b: number): string {\\r\\n const hex = ((r << 16) | (g << 8) | b).toString(16)\\r\\n return '#' + '0'.repeat(Math.max(0, 6 - hex.length)) + hex\\r\\n}\\r\\n\\r\\nexport function hexToRgb(hex: string): number[] {\\r\\n const rgb: number[] = []\\r\\n for (let i = 1; i < 7; i += 2) {\\r\\n rgb.push(parseInt('0x' + hex.slice(i, i + 2), 16))\\r\\n }\\r\\n return rgb\\r\\n}\\r\\n\\r\\nexport const gradient = (startColor: string, endColor: string, step: number = 2): string[] => {\\r\\n const sColor: number[] = hexToRgb(startColor)\\r\\n const eColor: number[] = hexToRgb(endColor)\\r\\n const rStep: number = (eColor[0] - sColor[0]) / step\\r\\n const gStep: number = (eColor[1] - sColor[1]) / step\\r\\n const bStep: number = (eColor[2] - sColor[2]) / step\\r\\n const gradientColorArr: string[] = []\\r\\n for (let i = 0; i < step; i++) {\\r\\n gradientColorArr.push(\\r\\n rgbToHex(parseInt(String(rStep * i + sColor[0])), parseInt(String(gStep * i + sColor[1])), parseInt(String(bStep * i + sColor[2])))\\r\\n )\\r\\n }\\r\\n return gradientColorArr\\r\\n}\\r\\n\\r\\nexport const context = {\\r\\n id: 1000\\r\\n}\\r\\n\\r\\nexport function kebabCase(word: string): string {\\r\\n return word.replace(/[A-Z]/g, function (match) {\\r\\n return '-' + match\\r\\n }).toLowerCase()\\r\\n}\\r\\n\\r\\nexport function camelCase(word: string): string {\\r\\n return word.replace(/-(\\\\w)/g, (_, c) => c.toUpperCase())\\r\\n}\\r\\n\\r\\nexport function isArray(value: any): value is Array<any> {\\r\\n if (typeof Array.isArray === 'function') {\\r\\n return Array.isArray(value)\\r\\n }\\r\\n return Object.prototype.toString.call(value) === '[object Array]'\\r\\n}\\r\\n\\r\\nexport function isFunction<T extends Function>(value: any): value is T {\\r\\n return getType(value) === 'function' || getType(value) === 'asyncfunction'\\r\\n}\\r\\n\\r\\nexport function isString(value: unknown): value is string {\\r\\n return getType(value) === 'string'\\r\\n}\\r\\n\\r\\nexport function isNumber(value: any): value is number {\\r\\n return getType(value) === 'number'\\r\\n}\\r\\n\\r\\nexport function isPromise(value: unknown): value is Promise<any> {\\r\\n if (isObj(value) && isDef(value)) {\\r\\n return isFunction((value as Promise<any>).then) && isFunction((value as Promise<any>).catch)\\r\\n }\\r\\n return false\\r\\n}\\r\\n\\r\\nexport function isBoolean(value: any): value is boolean {\\r\\n return typeof value === 'boolean'\\r\\n}\\r\\n\\r\\nexport function isUndefined(value: any): value is undefined {\\r\\n return typeof value === 'undefined'\\r\\n}\\r\\n\\r\\nexport function isNotUndefined<T>(value: T): value is NotUndefined<T> {\\r\\n return !isUndefined(value)\\r\\n}\\r\\n\\r\\nexport function objToStyle(styles: Record<string, any> | Record<string, any>[]): string {\\r\\n if (isArray(styles)) {\\r\\n const result = styles\\r\\n .filter((item) => item != null && item !== '')\\r\\n .map((item) => objToStyle(item))\\r\\n .join(';')\\r\\n return result ? (result.endsWith(';') ? result : result + ';') : ''\\r\\n }\\r\\n if (isString(styles)) {\\r\\n return styles ? (styles.endsWith(';') ? styles : styles + ';') : ''\\r\\n }\\r\\n if (isObj(styles)) {\\r\\n const result = Object.keys(styles)\\r\\n .filter((key) => styles[key] != null && styles[key] !== '')\\r\\n .map((key) => [kebabCase(key), styles[key]].join(':'))\\r\\n .join(';')\\r\\n return result ? (result.endsWith(';') ? result : result + ';') : ''\\r\\n }\\r\\n return ''\\r\\n}\\r\\n\\r\\nexport const pause = (ms: number = 1000 / 30) => {\\r\\n return new AbortablePromise((resolve) => {\\r\\n const timer = setTimeout(() => {\\r\\n clearTimeout(timer)\\r\\n resolve(true)\\r\\n }, ms)\\r\\n })\\r\\n}\\r\\n\\r\\nexport const isDate = (val: unknown): val is Date => Object.prototype.toString.call(val) === '[object Date]' && !Number.isNaN((val as Date).getTime())\\r\\n\\r\\nexport function deepClone<T>(obj: T, cache: Map<any, any> = new Map()): T {\\r\\n if (obj === null || typeof obj !== 'object') return obj\\r\\n if (isDate(obj)) return new Date((obj as any).getTime()) as any\\r\\n if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags) as any\\r\\n if (obj instanceof Error) {\\r\\n const errorCopy = new Error(obj.message) as any\\r\\n errorCopy.stack = obj.stack\\r\\n return errorCopy\\r\\n }\\r\\n if (cache.has(obj)) return cache.get(obj)\\r\\n const copy: any = Array.isArray(obj) ? [] : {}\\r\\n cache.set(obj, copy)\\r\\n for (const key in obj) {\\r\\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\\r\\n copy[key] = deepClone((obj as any)[key], cache)\\r\\n }\\r\\n }\\r\\n return copy as T\\r\\n}\\r\\n\\r\\nexport function deepMerge<T extends Record<string, any>>(target: T, source: Record<string, any>): T {\\r\\n target = deepClone(target)\\r\\n if (typeof target !== 'object' || typeof source !== 'object') {\\r\\n throw new Error('Both target and source must be objects.')\\r\\n }\\r\\n for (const prop in source) {\\r\\n if (!Object.prototype.hasOwnProperty.call(source, prop)) continue\\r\\n (target as Record<string, any>)[prop] = source[prop]\\r\\n }\\r\\n return target\\r\\n}\\r\\n\\r\\nexport function deepAssign(target: Record<string, any>, source: Record<string, any>): Record<string, any> {\\r\\n Object.keys(source).forEach((key) => {\\r\\n const targetValue = target[key]\\r\\n const newObjValue = source[key]\\r\\n if (isObj(targetValue) && isObj(newObjValue)) {\\r\\n deepAssign(targetValue, newObjValue)\\r\\n } else {\\r\\n target[key] = newObjValue\\r\\n }\\r\\n })\\r\\n return target\\r\\n}\\r\\n\\r\\nexport const getPropByPath = (obj: any, path: string): any => {\\r\\n const keys: string[] = path.split('.')\\r\\n try {\\r\\n return keys.reduce((acc: any, key: string) => (acc !== undefined && acc !== null ? acc[key] : undefined), obj)\\r\\n } catch (error) {\\r\\n return undefined\\r\\n }\\r\\n}\\r\\n\\r\\nexport function omitBy<O extends Record<string, any>>(obj: O, predicate: (value: any, key: keyof O) => boolean): Partial<O> {\\r\\n const newObj = deepClone(obj)\\r\\n Object.keys(newObj).forEach((key) => predicate(newObj[key], key) && delete newObj[key])\\r\\n return newObj\\r\\n}\\r\\n\\r\\nexport const isH5 = (() => {\\r\\n let isH5 = false\\r\\n // #ifdef H5\\r\\n isH5 = true\\r\\n // #endif\\r\\n return isH5\\r\\n})()\\r\\n\",\n \"lib/utils.ts\": \"\\r\\nimport { type ClassValue, clsx } from 'clsx'\\r\\n\\r\\n// #ifndef MP-WEIXIN\\r\\nimport { extendTailwindMerge } from 'tailwind-merge'\\r\\n// @ts-ignore\\r\\nconst twMerge = extendTailwindMerge({\\r\\n extend: {\\r\\n classGroups: {\\r\\n 'font-size': [{ text: ['20', '22', '24', '26', '28', '30', '32', '36', '40', '48', '52'] }],\\r\\n },\\r\\n },\\r\\n})\\r\\n\\r\\n// #endif\\r\\n\\r\\n// #ifdef MP-WEIXIN\\r\\nimport { create } from '@weapp-tailwindcss/merge-v3'\\r\\n\\r\\n// @ts-ignore\\r\\nconst isH5 = process.env.UNI_PLATFORM === 'h5'\\r\\n// @ts-ignore\\r\\nconst { twMerge } = create({\\r\\n escape: !isH5,\\r\\n unescape: !isH5,\\r\\n // @ts-ignore\\r\\n extend: {\\r\\n classGroups: {\\r\\n 'font-size': [{ text: ['20', '22', '24', '26', '28', '30', '32', '36', '40', '48', '52'] }],\\r\\n },\\r\\n },\\r\\n})\\r\\n// #endif\\r\\n\\r\\nexport function cn(...inputs: ClassValue[]) {\\r\\n return twMerge(clsx(inputs))\\r\\n}\",\n \"composables/useChildren.ts\": \"import {\\r\\n provide,\\r\\n inject,\\r\\n reactive,\\r\\n getCurrentInstance,\\r\\n onUnmounted,\\r\\n computed,\\r\\n ref,\\r\\n type VNode,\\r\\n type InjectionKey,\\r\\n type VNodeNormalizedChildren,\\r\\n type ComponentPublicInstance,\\r\\n type ComponentInternalInstance\\r\\n} from 'vue'\\r\\n\\r\\n// 小程序端不支持从vue导出的isVNode方法,参考uni-mp-vue的实现\\r\\nfunction isVNode(value: any): value is VNode {\\r\\n return value ? value.__v_isVNode === true : false\\r\\n}\\r\\n\\r\\nexport function flattenVNodes(children: VNode) {\\r\\n const result: VNode[] = []\\r\\n\\r\\n const traverse = (children: VNode | VNodeNormalizedChildren) => {\\r\\n const vNode = Array.isArray(children) ? children : [children]\\r\\n vNode.forEach((child) => {\\r\\n if (Array.isArray(child)) {\\r\\n traverse(child)\\r\\n } else if (isVNode(child) && child.component?.subTree) {\\r\\n result.push(child)\\r\\n traverse(child.component.subTree)\\r\\n } else if (isVNode(child) && Array.isArray(child.children)) {\\r\\n traverse(child.children)\\r\\n } else if (isVNode(child)) {\\r\\n result.push(child)\\r\\n }\\r\\n })\\r\\n }\\r\\n\\r\\n traverse(children)\\r\\n\\r\\n return result\\r\\n}\\r\\n\\r\\nconst findVNodeIndex = (vnodes: VNode[], vnode: VNode) => {\\r\\n const index = vnodes.indexOf(vnode)\\r\\n if (index === -1) {\\r\\n return vnodes.findIndex(\\r\\n (item) => vnode.key !== undefined && vnode.key !== null && item.type === vnode.type && item.key === vnode.key\\r\\n )\\r\\n }\\r\\n return index\\r\\n}\\r\\n\\r\\n// sort children instances by vnodes order\\r\\nexport function sortChildren(\\r\\n parent: ComponentInternalInstance,\\r\\n publicChildren: ComponentPublicInstance[],\\r\\n internalChildren: ComponentInternalInstance[]\\r\\n) {\\r\\n const vnodes = parent && parent.subTree && parent.subTree.children ? flattenVNodes(parent.subTree) : []\\r\\n internalChildren.sort((a, b) => findVNodeIndex(vnodes, a.vnode) - findVNodeIndex(vnodes, b.vnode))\\r\\n\\r\\n const orderedPublicChildren = internalChildren.map((item) => item.proxy!)\\r\\n\\r\\n publicChildren.sort((a, b) => {\\r\\n const getIndex = (comp: ComponentPublicInstance) => {\\r\\n const uid = comp.$.uid\\r\\n return orderedPublicChildren.findIndex((i) => i.$.uid === uid)\\r\\n }\\r\\n return getIndex(a) - getIndex(b)\\r\\n })\\r\\n}\\r\\n\\r\\nexport function useChildren<\\r\\n // eslint-disable-next-line\\r\\n Child extends ComponentPublicInstance = ComponentPublicInstance<{}, any>,\\r\\n ProvideValue = never\\r\\n>(key: InjectionKey<ProvideValue>) {\\r\\n const publicChildren: Child[] = reactive([])\\r\\n const internalChildren: ComponentInternalInstance[] = reactive([])\\r\\n const parent = getCurrentInstance()!\\r\\n\\r\\n const linkChildren = (value?: ProvideValue) => {\\r\\n const link = (child: ComponentInternalInstance) => {\\r\\n if (child.proxy) {\\r\\n internalChildren.push(child)\\r\\n publicChildren.push(child.proxy as Child)\\r\\n sortChildren(parent, publicChildren, internalChildren)\\r\\n }\\r\\n }\\r\\n\\r\\n const unlink = (child: ComponentInternalInstance) => {\\r\\n const index = internalChildren.indexOf(child)\\r\\n publicChildren.splice(index, 1)\\r\\n internalChildren.splice(index, 1)\\r\\n }\\r\\n\\r\\n provide(\\r\\n key,\\r\\n Object.assign(\\r\\n {\\r\\n link,\\r\\n unlink,\\r\\n children: publicChildren,\\r\\n internalChildren\\r\\n },\\r\\n value\\r\\n )\\r\\n )\\r\\n }\\r\\n\\r\\n return {\\r\\n children: publicChildren,\\r\\n linkChildren\\r\\n }\\r\\n}\\r\\n\\r\\nexport function useParent<T>(key: InjectionKey<T>) {\\r\\n const parent = inject(key, null) as (T & { link: Function; unlink: Function }) | null\\r\\n\\r\\n if (parent) {\\r\\n const instance = getCurrentInstance()!\\r\\n const index = computed(() => {\\r\\n const internalChildren = (parent as any).internalChildren as ComponentInternalInstance[]\\r\\n return internalChildren ? internalChildren.indexOf(instance) : -1\\r\\n })\\r\\n\\r\\n ; (parent as any).link(instance)\\r\\n\\r\\n onUnmounted(() => {\\r\\n ; (parent as any).unlink(instance)\\r\\n })\\r\\n\\r\\n return {\\r\\n parent,\\r\\n index\\r\\n }\\r\\n }\\r\\n\\r\\n return {\\r\\n parent: null,\\r\\n index: ref(-1)\\r\\n }\\r\\n}\\r\\n\",\n \"composables/useDarkMode.ts\": \"export function useDarkMode() {\\r\\n const isDark = ref(false)\\r\\n\\r\\n const toggleDarkMode = () => {\\r\\n isDark.value = !isDark.value\\r\\n updateTheme()\\r\\n }\\r\\n\\r\\n const updateTheme = () => {\\r\\n const value = isDark.value\\r\\n uni.setStorageSync('darkMode', value)\\r\\n\\r\\n // #ifdef H5\\r\\n if (value) {\\r\\n document.documentElement.classList.add('dark')\\r\\n }\\r\\n else {\\r\\n document.documentElement.classList.remove('dark')\\r\\n }\\r\\n // #endif\\r\\n }\\r\\n\\r\\n const initTheme = () => {\\r\\n const saved = uni.getStorageSync('darkMode')\\r\\n if (saved !== '') {\\r\\n isDark.value = !!saved\\r\\n }\\r\\n else {\\r\\n isDark.value = false\\r\\n }\\r\\n updateTheme()\\r\\n }\\r\\n\\r\\n initTheme()\\r\\n\\r\\n return {\\r\\n isDark,\\r\\n toggleDarkMode,\\r\\n }\\r\\n}\\r\\n\",\n \"composables/useFieldGroup.ts\": \"import { computed, getCurrentInstance, inject, onMounted, onUnmounted, ref, watch } from 'vue'\\r\\n\\r\\nexport interface FormValidateError {\\r\\n field: string\\r\\n message: string\\r\\n}\\r\\n\\r\\nexport interface UseFieldGroupProps {\\r\\n modelValue?: any\\r\\n}\\r\\n\\r\\nexport function useFieldGroup() {\\r\\n const errors = ref<Record<string, string>>({})\\r\\n const fields = ref(new Set<string>([]))\\r\\n const fieldInstances = ref<any[]>([])\\r\\n\\r\\n const addField = (field: any) => {\\r\\n fieldInstances.value.push(field)\\r\\n if (field.prop) {\\r\\n fields.value.add(field.prop)\\r\\n }\\r\\n }\\r\\n\\r\\n const removeField = (field: any) => {\\r\\n const index = fieldInstances.value.indexOf(field)\\r\\n if (index > -1) {\\r\\n fieldInstances.value.splice(index, 1)\\r\\n }\\r\\n if (field.prop) {\\r\\n fields.value.delete(field.prop)\\r\\n }\\r\\n }\\r\\n\\r\\n const errorLock = ref(false)\\r\\n\\r\\n function setError(prop: string, error: string) {\\r\\n if (errorLock.value) { return }\\r\\n if (prop !== '') {\\r\\n errors.value = { ...errors.value, [prop]: error }\\r\\n }\\r\\n }\\r\\n\\r\\n function removeError(prop: string) {\\r\\n if (prop !== '' && errors.value[prop] !== undefined) {\\r\\n const newErrors = { ...errors.value }\\r\\n delete newErrors[prop]\\r\\n errors.value = newErrors\\r\\n }\\r\\n }\\r\\n\\r\\n function getError(prop: string): string {\\r\\n if (prop !== '') { return errors.value[prop] ?? '' }\\r\\n return ''\\r\\n }\\r\\n\\r\\n async function getErrors(): Promise<FormValidateError[]> {\\r\\n return Object.entries(errors.value).map(([field, message]) => ({ field, message }))\\r\\n }\\r\\n\\r\\n function clearValidate(fieldsToClear?: string | string[]) {\\r\\n if (fieldsToClear) {\\r\\n const propsArray = Array.isArray(fieldsToClear) ? fieldsToClear : [fieldsToClear]\\r\\n propsArray.forEach(prop => removeError(prop))\\r\\n }\\r\\n else {\\r\\n errors.value = {}\\r\\n }\\r\\n }\\r\\n\\r\\n return {\\r\\n errors,\\r\\n fields,\\r\\n fieldInstances,\\r\\n addField,\\r\\n removeField,\\r\\n setError,\\r\\n removeError,\\r\\n getError,\\r\\n getErrors,\\r\\n clearValidate,\\r\\n }\\r\\n}\\r\\n\\r\\nexport interface UseFieldGroupItemProps {\\r\\n prop?: string\\r\\n label?: string\\r\\n labelPosition?: string\\r\\n labelWidth?: string | number\\r\\n trigger?: 'blur' | 'change' | 'none' | Array<'blur' | 'change'>\\r\\n ui?: any\\r\\n}\\r\\n\\r\\nexport function useFieldGroupItem(props: UseFieldGroupItemProps) {\\r\\n const form = inject<any>('rebornForm', undefined)\\r\\n const instance = getCurrentInstance()\\r\\n\\r\\n const error = computed(() => {\\r\\n if (!form || !props.prop) { return '' }\\r\\n return form.getError ? form.getError(props.prop) : ''\\r\\n })\\r\\n\\r\\n const labelPosition = computed(() => {\\r\\n return props.labelPosition || form?.props?.labelPosition || 'left'\\r\\n })\\r\\n\\r\\n const labelWidth = computed(() => {\\r\\n if (labelPosition.value === 'top') { return 'auto' }\\r\\n return props.labelWidth || form?.props?.labelWidth || 'auto'\\r\\n })\\r\\n\\r\\n const size = computed(() => {\\r\\n const s = form?.props?.size\\r\\n if (s && ['sm', 'md', 'lg'].includes(s)) {\\r\\n return s as 'sm' | 'md' | 'lg'\\r\\n }\\r\\n return 'sm'\\r\\n })\\r\\n\\r\\n const getBoundingClientRect = (callback: (res: any) => void) => {\\r\\n uni.createSelectorQuery()\\r\\n .in(instance?.proxy)\\r\\n .select('.re-form-item')\\r\\n .boundingClientRect(callback)\\r\\n .exec()\\r\\n }\\r\\n\\r\\n const validate = (trigger: 'blur' | 'change') => {\\r\\n if (!form || !props.prop) { return }\\r\\n\\r\\n let currentTrigger = props.trigger\\r\\n if (currentTrigger === undefined) {\\r\\n currentTrigger = form.props?.trigger\\r\\n }\\r\\n\\r\\n if (!currentTrigger || currentTrigger === 'none') { return }\\r\\n\\r\\n let shouldValidate = false\\r\\n if (Array.isArray(currentTrigger)) {\\r\\n shouldValidate = currentTrigger.includes(trigger)\\r\\n }\\r\\n else {\\r\\n shouldValidate = currentTrigger === trigger\\r\\n }\\r\\n\\r\\n if (shouldValidate && form.validateField) {\\r\\n form.validateField(props.prop)\\r\\n }\\r\\n }\\r\\n\\r\\n watch(() => props.prop, (newProp, oldProp) => {\\r\\n if (form) {\\r\\n if (oldProp) {\\r\\n form.removeField({ uid: instance?.uid, prop: oldProp })\\r\\n }\\r\\n if (newProp) {\\r\\n form.addField({ uid: instance?.uid, prop: newProp, getBoundingClientRect })\\r\\n }\\r\\n }\\r\\n })\\r\\n\\r\\n onMounted(() => {\\r\\n if (form && props.prop) {\\r\\n form.addField({ uid: instance?.uid, prop: props.prop, getBoundingClientRect })\\r\\n }\\r\\n })\\r\\n\\r\\n onUnmounted(() => {\\r\\n if (form && props.prop) {\\r\\n form.removeField({ uid: instance?.uid, prop: props.prop })\\r\\n }\\r\\n })\\r\\n\\r\\n return {\\r\\n form,\\r\\n error,\\r\\n labelPosition,\\r\\n labelWidth,\\r\\n size,\\r\\n getBoundingClientRect,\\r\\n validate,\\r\\n }\\r\\n}\\r\\n\\r\\nexport function useFormInject(props: any) {\\r\\n const form = inject<any>('rebornForm', null)\\r\\n const formItem = inject<any>('rebornFormItem', null)\\r\\n\\r\\n const size = computed(() => {\\r\\n return form?.props?.size || props.size\\r\\n })\\r\\n\\r\\n const disabled = computed(() => {\\r\\n return form?.props?.disabled || props.disabled\\r\\n })\\r\\n\\r\\n const orientation = computed(() => {\\r\\n return form?.props?.orientation || props.orientation\\r\\n })\\r\\n\\r\\n const isError = computed(() => {\\r\\n return formItem?.isError?.value || false\\r\\n })\\r\\n\\r\\n const validate = (trigger: 'blur' | 'change') => {\\r\\n if (formItem?.validate) {\\r\\n formItem.validate(trigger)\\r\\n }\\r\\n }\\r\\n\\r\\n return {\\r\\n form,\\r\\n size,\\r\\n disabled,\\r\\n orientation,\\r\\n isError,\\r\\n validate,\\r\\n }\\r\\n}\\r\\n\",\n \"composables/useLockScroll.ts\": \"import { onBeforeUnmount, onDeactivated, ref, watch } from 'vue'\\r\\n\\r\\nexport function useLockScroll(shouldLock: () => boolean) {\\r\\n const scrollLockCount = ref(0)\\r\\n\\r\\n const lock = () => {\\r\\n if (scrollLockCount.value === 0) {\\r\\n document.getElementsByTagName('body')[0].style.overflow = 'hidden'\\r\\n }\\r\\n scrollLockCount.value++\\r\\n }\\r\\n\\r\\n const unlock = () => {\\r\\n if (scrollLockCount.value > 0) {\\r\\n scrollLockCount.value--\\r\\n if (scrollLockCount.value === 0) {\\r\\n document.getElementsByTagName('body')[0].style.overflow = ''\\r\\n }\\r\\n }\\r\\n }\\r\\n\\r\\n const destroy = () => {\\r\\n shouldLock() && unlock()\\r\\n }\\r\\n\\r\\n watch(shouldLock, (value) => {\\r\\n value ? lock() : unlock()\\r\\n })\\r\\n\\r\\n onDeactivated(destroy)\\r\\n onBeforeUnmount(destroy)\\r\\n\\r\\n return {\\r\\n lock,\\r\\n unlock\\r\\n }\\r\\n}\\r\\n\"\n }\n} as const;\n\nexport type Platform = keyof typeof TEMPLATES;\n","{\r\n \"name\": \"reborn-ui\",\r\n \"version\": \"0.1.80\",\r\n \"description\": \"A CLI for Reborn UI\",\r\n \"author\": \"1997liuyh-boop\",\r\n \"license\": \"MIT\",\r\n \"repository\": {\r\n \"type\": \"git\",\r\n \"url\": \"https://github.com/1997liuyh-boop/Reborn-UI.git\"\r\n },\r\n \"type\": \"module\",\r\n \"bin\": {\r\n \"reborn-ui\": \"dist/index.js\"\r\n },\r\n \"files\": [\r\n \"dist\",\r\n \"registry\",\r\n \"README.md\"\r\n ],\r\n \"publishConfig\": {\r\n \"access\": \"public\"\r\n },\r\n \"scripts\": {\r\n \"cli\": \"tsx src/index.ts\",\r\n \"build\": \"tsup\",\r\n \"dev\": \"tsx src/index.ts\",\r\n \"clean\": \"rimraf dist\",\r\n \"prepare\": \"tsup\",\r\n \"templates:sync\": \"tsx src/scripts/sync-templates.ts\",\r\n \"registry:build\": \"tsx src/index.ts build --root ../.. --uniapp-source packages/uniapp-project/src/components\",\r\n \"prepack\": \"npm run templates:sync && npm run build && npm run registry:build\",\r\n \"prepublishOnly\": \"npm run templates:sync && npm run build && npm run registry:build\"\r\n },\r\n \"dependencies\": {\r\n \"chalk\": \"^5.6.2\",\r\n \"cli-progress\": \"^3.12.0\",\r\n \"commander\": \"^14.0.0\",\r\n \"execa\": \"^9.6.0\",\r\n \"figlet\": \"^1.9.4\",\r\n \"ora\": \"^9.0.0\",\r\n \"prompts\": \"^2.4.2\"\r\n },\r\n \"devDependencies\": {\r\n \"@types/cli-progress\": \"^3.11.6\",\r\n \"@types/figlet\": \"^1.7.0\",\r\n \"@types/node\": \"^22.10.7\",\r\n \"@types/prompts\": \"^2.4.9\",\r\n \"rimraf\": \"^6.0.1\",\r\n \"tsup\": \"^8.5.0\",\r\n \"tsx\": \"^4.20.0\",\r\n \"typescript\": \"^5.8.3\"\r\n }\r\n}\r\n"],"mappings":"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","names":["Command","path","fs","path","path","path","fs","path","fs","require","chalk","path","chalk","path","fs","Command","path","Command","fs","path","fs","fssync","Command","prompts","path","fs","fileURLToPath","findNearestPackageRoot","path","findWorkspaceRoot","fssync","fs","Command","prompts","cfgPath","workspaceRoot","findNearestPackageRoot","libUtilsPath","Command"]}