reborn-ui 0.1.76 → 0.1.78
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.
- package/dist/index.js +182 -240
- package/dist/index.js.map +1 -1
- package/package.json +53 -53
- package/registry/components/reborn-affix.json +8 -3
- package/registry/components/reborn-back-top.json +9 -4
- package/registry/components/reborn-badge.json +11 -5
- package/registry/components/reborn-button.json +5 -5
- package/registry/components/reborn-card.json +18 -0
- package/registry/components/reborn-cascader.json +18 -0
- package/registry/components/reborn-checkbox.json +4 -4
- package/registry/components/reborn-chip.json +11 -5
- package/registry/components/reborn-collapse.json +11 -5
- package/registry/components/reborn-color-picker.json +50 -0
- package/registry/components/reborn-draggable.json +32 -0
- package/registry/components/reborn-drawer.json +17 -0
- package/registry/components/reborn-dropdown-select.json +18 -0
- package/registry/components/reborn-footer.json +40 -0
- package/registry/components/reborn-form.json +11 -6
- package/registry/components/reborn-image.json +10 -5
- package/registry/components/reborn-input-number.json +12 -6
- package/registry/components/reborn-input-otp.json +40 -0
- package/registry/components/reborn-input.json +4 -4
- package/registry/components/reborn-loading.json +23 -0
- package/registry/components/reborn-loadmore.json +23 -0
- package/registry/components/reborn-overlay.json +38 -0
- package/registry/components/reborn-page.json +18 -0
- package/registry/components/reborn-picker-view.json +26 -0
- package/registry/components/reborn-popover.json +58 -0
- package/registry/components/reborn-popup.json +23 -0
- package/registry/components/reborn-qrcode.json +45 -0
- package/registry/components/reborn-radio.json +45 -0
- package/registry/components/reborn-rate.json +40 -0
- package/registry/components/reborn-root-portal.json +26 -0
- package/registry/components/reborn-select-date.json +40 -0
- package/registry/components/reborn-select-trigger.json +25 -0
- package/registry/components/reborn-select.json +41 -0
- package/registry/components/reborn-slider.json +40 -0
- package/registry/components/reborn-sticky.json +12 -6
- package/registry/components/reborn-switch.json +13 -7
- package/registry/components/reborn-tabbar.json +38 -0
- package/registry/components/reborn-tabs copy.json +46 -0
- package/registry/components/reborn-tabs-test.json +46 -0
- package/registry/components/reborn-tabs.json +12 -6
- package/registry/components/reborn-text.json +34 -0
- package/registry/components/reborn-textarea.json +5 -5
- package/registry/components/reborn-toast.json +38 -0
- package/registry/components/reborn-transition.json +38 -0
- package/registry/components/reborn-waterfall.json +18 -0
- package/registry/components/scroll-island.json +2 -2
- package/registry/registry.json +1101 -97
package/dist/index.js
CHANGED
|
@@ -93,6 +93,72 @@ async function detectPackageManager(cwd) {
|
|
|
93
93
|
if (await pathExists(path2.join(cwd, "bun.lockb"))) return "bun";
|
|
94
94
|
return "pnpm";
|
|
95
95
|
}
|
|
96
|
+
async function readPackageJson(cwd) {
|
|
97
|
+
return await readJsonFile(path2.join(cwd, "package.json"));
|
|
98
|
+
}
|
|
99
|
+
function getMissingDeps(pkg, deps) {
|
|
100
|
+
const existing = /* @__PURE__ */ new Set([
|
|
101
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
102
|
+
...Object.keys(pkg.devDependencies ?? {})
|
|
103
|
+
]);
|
|
104
|
+
return deps.filter((d) => !existing.has(d));
|
|
105
|
+
}
|
|
106
|
+
async function installDeps(params) {
|
|
107
|
+
const { cwd, pm, deps, dev } = params;
|
|
108
|
+
if (!deps.length) return;
|
|
109
|
+
const args = [];
|
|
110
|
+
if (pm === "pnpm") args.push("add");
|
|
111
|
+
else if (pm === "npm") args.push("install");
|
|
112
|
+
else if (pm === "yarn") args.push("add");
|
|
113
|
+
else if (pm === "bun") args.push("add");
|
|
114
|
+
if (dev) {
|
|
115
|
+
if (pm === "npm") args.push("--save-dev");
|
|
116
|
+
else args.push("-D");
|
|
117
|
+
}
|
|
118
|
+
args.push(...deps);
|
|
119
|
+
await execa(pm, args, { cwd, stdio: "inherit" });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/utils/dependencies.ts
|
|
123
|
+
var DEPENDENCY_MAP = {
|
|
124
|
+
// UniApp 版本的 Reborn Select 需要特定的前置组件和 lodash-es
|
|
125
|
+
"reborn-select/uniapp": {
|
|
126
|
+
components: ["reborn-button", "reborn-picker-view", "reborn-popup", "reborn-select-trigger"],
|
|
127
|
+
npmDependencies: ["lodash-es", "@types/lodash-es"]
|
|
128
|
+
},
|
|
129
|
+
"reborn-select-date/uniapp": {
|
|
130
|
+
components: ["reborn-button", "reborn-picker-view", "reborn-popup", "reborn-select-trigger"],
|
|
131
|
+
npmDependencies: ["lodash-es", "@types/lodash-es"]
|
|
132
|
+
}
|
|
133
|
+
// 在此处添加其他已知的依赖映射
|
|
134
|
+
};
|
|
135
|
+
function getDependencies(componentName, platform) {
|
|
136
|
+
const result = { components: [], npmDependencies: [] };
|
|
137
|
+
const visited = /* @__PURE__ */ new Set();
|
|
138
|
+
function resolve(name) {
|
|
139
|
+
const keyWithPlatform = platform ? `${name}/${platform}` : name;
|
|
140
|
+
const deps = DEPENDENCY_MAP[keyWithPlatform] || DEPENDENCY_MAP[name];
|
|
141
|
+
if (!deps) return;
|
|
142
|
+
if (deps.components) {
|
|
143
|
+
for (const comp of deps.components) {
|
|
144
|
+
if (!visited.has(comp)) {
|
|
145
|
+
visited.add(comp);
|
|
146
|
+
result.components.push(comp);
|
|
147
|
+
resolve(comp);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (deps.npmDependencies) {
|
|
152
|
+
for (const npmDep of deps.npmDependencies) {
|
|
153
|
+
if (!result.npmDependencies.includes(npmDep)) {
|
|
154
|
+
result.npmDependencies.push(npmDep);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
resolve(componentName);
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
96
162
|
|
|
97
163
|
// src/utils/registry.ts
|
|
98
164
|
import path3 from "path";
|
|
@@ -289,7 +355,86 @@ function addCommand() {
|
|
|
289
355
|
if (!platform) {
|
|
290
356
|
throw new Error("\u5DF2\u53D6\u6D88");
|
|
291
357
|
}
|
|
292
|
-
const
|
|
358
|
+
const allComponentsToInstall = new Set(targets);
|
|
359
|
+
const allNpmDependencies = /* @__PURE__ */ new Set();
|
|
360
|
+
for (const target of targets) {
|
|
361
|
+
const deps = getDependencies(target, platform);
|
|
362
|
+
if (deps.components) {
|
|
363
|
+
for (const c of deps.components) allComponentsToInstall.add(c);
|
|
364
|
+
}
|
|
365
|
+
if (deps.npmDependencies) {
|
|
366
|
+
for (const d of deps.npmDependencies) allNpmDependencies.add(d);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const additionalComponents = Array.from(allComponentsToInstall).filter((c) => !targets.includes(c));
|
|
370
|
+
const npmDependenciesArray = Array.from(allNpmDependencies);
|
|
371
|
+
if (npmDependenciesArray.length > 0) {
|
|
372
|
+
const pkg = await readPackageJson(cwd);
|
|
373
|
+
const missingDeps = getMissingDeps(pkg, npmDependenciesArray);
|
|
374
|
+
if (missingDeps.length > 0) {
|
|
375
|
+
console.log(chalk2.blue(`
|
|
376
|
+
\u68C0\u6D4B\u5230\u5F53\u524D\u7EC4\u4EF6\u9700\u8981\u4EE5\u4E0B\u672A\u5B89\u88C5\u7684 npm \u4F9D\u8D56\uFF1A${missingDeps.join(", ")}`));
|
|
377
|
+
const { installNpm } = await prompts({
|
|
378
|
+
type: "confirm",
|
|
379
|
+
name: "installNpm",
|
|
380
|
+
message: `\u662F\u5426\u9700\u8981\u4E3A\u8FD9\u4E9B\u7EC4\u4EF6\u5B89\u88C5\u4EE5\u4E0A npm \u4F9D\u8D56?`,
|
|
381
|
+
initial: true
|
|
382
|
+
});
|
|
383
|
+
if (installNpm) {
|
|
384
|
+
console.log(chalk2.cyan("\u6B63\u5728\u5B89\u88C5 npm \u4F9D\u8D56..."));
|
|
385
|
+
await installDeps({ cwd, pm, deps: missingDeps });
|
|
386
|
+
successLog(`npm \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
let finalTargets = [...targets];
|
|
391
|
+
if (additionalComponents.length > 0) {
|
|
392
|
+
const missingComponents = [];
|
|
393
|
+
for (const c of additionalComponents) {
|
|
394
|
+
const baseDir = path4.join(cwd, cfg.componentsDir, c);
|
|
395
|
+
if (!await pathExists(baseDir)) {
|
|
396
|
+
missingComponents.push(c);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (missingComponents.length > 0) {
|
|
400
|
+
console.log(chalk2.blue(`
|
|
401
|
+
\u68C0\u6D4B\u5230\u9700\u8981\u524D\u7F6E\u6216\u5173\u8054\u7EC4\u4EF6\uFF1A${missingComponents.join(", ")}`));
|
|
402
|
+
const { installComponents } = await prompts({
|
|
403
|
+
type: "confirm",
|
|
404
|
+
name: "installComponents",
|
|
405
|
+
message: `\u662F\u5426\u81EA\u52A8\u5B89\u88C5\u7F3A\u5931\u7684\u524D\u7F6E\u7EC4\u4EF6?`,
|
|
406
|
+
initial: true
|
|
407
|
+
});
|
|
408
|
+
if (installComponents) {
|
|
409
|
+
finalTargets = [...finalTargets, ...missingComponents];
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (!opts.overwrite) {
|
|
414
|
+
const existingComponents = [];
|
|
415
|
+
for (const name of finalTargets) {
|
|
416
|
+
const baseDir = path4.join(cwd, cfg.componentsDir, name);
|
|
417
|
+
if (await pathExists(baseDir)) {
|
|
418
|
+
existingComponents.push(name);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (existingComponents.length > 0) {
|
|
422
|
+
console.log(chalk2.yellow(`
|
|
423
|
+
\u9047\u5230\u5DF2\u5B58\u5728\u7684\u7EC4\u4EF6\uFF1A${existingComponents.join(", ")}`));
|
|
424
|
+
const { overwrite } = await prompts({
|
|
425
|
+
type: "confirm",
|
|
426
|
+
name: "overwrite",
|
|
427
|
+
message: `\u662F\u5426\u8986\u76D6\u5E76\u7EE7\u7EED\u5B89\u88C5\uFF1F`,
|
|
428
|
+
initial: false
|
|
429
|
+
});
|
|
430
|
+
if (!overwrite) {
|
|
431
|
+
console.log(chalk2.red("\u5DF2\u7EC8\u6B62\u5B89\u88C5"));
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
opts.overwrite = true;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
const totalFiles = finalTargets.reduce((acc, name) => {
|
|
293
438
|
const c = registry.components.find((x) => x.name === name);
|
|
294
439
|
return acc + (c?.files.length ?? 0);
|
|
295
440
|
}, 0);
|
|
@@ -300,7 +445,7 @@ function addCommand() {
|
|
|
300
445
|
hideCursor: true
|
|
301
446
|
});
|
|
302
447
|
bar.start(totalFiles, 0);
|
|
303
|
-
for (const name of
|
|
448
|
+
for (const name of finalTargets) {
|
|
304
449
|
const c = registry.components.find((x) => x.name === name);
|
|
305
450
|
if (!c) {
|
|
306
451
|
bar.stop();
|
|
@@ -318,11 +463,11 @@ function addCommand() {
|
|
|
318
463
|
}
|
|
319
464
|
bar.stop();
|
|
320
465
|
console.log("");
|
|
321
|
-
for (const name of
|
|
466
|
+
for (const name of finalTargets) {
|
|
322
467
|
successLog(`\u7EC4\u4EF6 ${chalk2.bold(name)} \u5DF2\u6210\u529F\u6DFB\u52A0\u5230\u9879\u76EE`);
|
|
323
468
|
}
|
|
324
469
|
console.log(`
|
|
325
|
-
${chalk2.bold.green("DONE")} \u5DF2\u5B8C\u6210 ${
|
|
470
|
+
${chalk2.bold.green("DONE")} \u5DF2\u5B8C\u6210 ${finalTargets.length} \u4E2A\u7EC4\u4EF6\u7684\u6DFB\u52A0\uFF08pm=${pm}\uFF09`);
|
|
326
471
|
});
|
|
327
472
|
return cmd;
|
|
328
473
|
}
|
|
@@ -435,13 +580,25 @@ function buildCommand() {
|
|
|
435
580
|
(p) => path5.join(rootDir, p)
|
|
436
581
|
);
|
|
437
582
|
const dirents = await fs4.readdir(sourceDir, { withFileTypes: true });
|
|
438
|
-
|
|
583
|
+
let componentDirs = dirents.filter((d) => d.isDirectory())?.map((d) => d.name);
|
|
584
|
+
if (uniappSourceDir && fssync.existsSync(uniappSourceDir)) {
|
|
585
|
+
const uniappDirents = await fs4.readdir(uniappSourceDir, { withFileTypes: true });
|
|
586
|
+
const uniappDirs = uniappDirents.filter((d) => d.isDirectory())?.map((d) => d.name);
|
|
587
|
+
for (const dir of uniappDirs) {
|
|
588
|
+
if (!componentDirs.includes(dir)) {
|
|
589
|
+
componentDirs.push(dir);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
componentDirs = componentDirs.sort((a, b) => a.localeCompare(b));
|
|
439
594
|
const components = [];
|
|
440
|
-
for (const
|
|
441
|
-
const name =
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
)
|
|
595
|
+
for (const componentName of componentDirs) {
|
|
596
|
+
const name = componentName;
|
|
597
|
+
const absComponentDir = path5.join(sourceDir, componentName);
|
|
598
|
+
let absFiles = [];
|
|
599
|
+
if (fssync.existsSync(absComponentDir)) {
|
|
600
|
+
absFiles = (await listFilesRecursive(absComponentDir)).filter(isAllowedFile);
|
|
601
|
+
}
|
|
445
602
|
const files = [];
|
|
446
603
|
const depSet = /* @__PURE__ */ new Set();
|
|
447
604
|
for (const absFile of absFiles) {
|
|
@@ -623,235 +780,20 @@ export function useNavigation(navigation?: Ref<ContentNavigationItem[]>) {\r
|
|
|
623
780
|
`
|
|
624
781
|
},
|
|
625
782
|
"uniapp": {
|
|
626
|
-
"lib/
|
|
627
|
-
import type { TV } from "tailwind-variants";\r
|
|
628
|
-
|
|
629
|
-
\r
|
|
630
|
-
// @ts-ignore\r
|
|
631
|
-
|
|
632
|
-
\r
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
escape: !isH5,\r
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
})\r
|
|
639
|
-
\r
|
|
640
|
-
const textSizeKeys = ['20', '22', '24', '26', '28', '30', '32', '36', '40', '48', '52']\r
|
|
641
|
-
\r
|
|
642
|
-
const twMergeConfig = {\r
|
|
643
|
-
extend: {\r
|
|
644
|
-
classGroups: {\r
|
|
645
|
-
'font-size': [{ text: textSizeKeys }],\r
|
|
646
|
-
},\r
|
|
647
|
-
},\r
|
|
648
|
-
} as const\r
|
|
649
|
-
\r
|
|
650
|
-
export const tv: TV = (options, config) =>\r
|
|
651
|
-
createTV(options, {\r
|
|
652
|
-
...config,\r
|
|
653
|
-
twMerge: config?.twMerge ?? true,\r
|
|
654
|
-
twMergeConfig: {\r
|
|
655
|
-
...config?.twMergeConfig,\r
|
|
656
|
-
...twMergeConfig,\r
|
|
657
|
-
},\r
|
|
658
|
-
});\r
|
|
659
|
-
`,
|
|
660
|
-
"lib/utils.ts": "import { type ClassValue, clsx } from 'clsx'\r\nimport { create } from '@weapp-tailwindcss/merge-v3'\r\n\r\n// @ts-ignore\r\nconst isH5 = process.env.UNI_PLATFORM === 'h5'\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\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs))\r\n}\r\n",
|
|
661
|
-
"composables/useDarkMode.ts": "export const 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 } else {\r\n document.documentElement.classList.remove('dark')\r\n }\r\n // #endif\r\n\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 } 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",
|
|
662
|
-
"composables/useFieldGroup.ts": `import { ref, provide, inject, computed, watch, onMounted, onUnmounted, getCurrentInstance } from 'vue';\r
|
|
663
|
-
import * as z from 'zod';\r
|
|
664
|
-
\r
|
|
665
|
-
export type FormValidateError = {\r
|
|
666
|
-
field: string;\r
|
|
667
|
-
message: string;\r
|
|
668
|
-
};\r
|
|
669
|
-
\r
|
|
670
|
-
export interface UseFieldGroupProps {\r
|
|
671
|
-
modelValue?: any;\r
|
|
672
|
-
}\r
|
|
673
|
-
\r
|
|
674
|
-
export function useFieldGroup() {\r
|
|
675
|
-
\r
|
|
676
|
-
// Data & Context\r
|
|
677
|
-
const errors = ref(new Map<string, string>());\r
|
|
678
|
-
const fields = ref(new Set<string>([]));\r
|
|
679
|
-
const fieldInstances = ref<any[]>([]);\r
|
|
680
|
-
\r
|
|
681
|
-
// --- Field Management ---\r
|
|
682
|
-
const addField = (field: any) => {\r
|
|
683
|
-
fieldInstances.value.push(field);\r
|
|
684
|
-
if (field.prop) {\r
|
|
685
|
-
fields.value.add(field.prop);\r
|
|
686
|
-
}\r
|
|
687
|
-
};\r
|
|
688
|
-
\r
|
|
689
|
-
const removeField = (field: any) => {\r
|
|
690
|
-
const index = fieldInstances.value.indexOf(field);\r
|
|
691
|
-
if (index > -1) {\r
|
|
692
|
-
fieldInstances.value.splice(index, 1);\r
|
|
693
|
-
}\r
|
|
694
|
-
if (field.prop) {\r
|
|
695
|
-
fields.value.delete(field.prop);\r
|
|
696
|
-
}\r
|
|
697
|
-
};\r
|
|
698
|
-
\r
|
|
699
|
-
// --- Error Management ---\r
|
|
700
|
-
const errorLock = ref(false);\r
|
|
701
|
-
\r
|
|
702
|
-
function setError(prop: string, error: string) {\r
|
|
703
|
-
if (errorLock.value) return;\r
|
|
704
|
-
if (prop !== "") errors.value.set(prop, error);\r
|
|
705
|
-
}\r
|
|
706
|
-
\r
|
|
707
|
-
function removeError(prop: string) {\r
|
|
708
|
-
if (prop !== "") errors.value.delete(prop);\r
|
|
709
|
-
}\r
|
|
710
|
-
\r
|
|
711
|
-
function getError(prop: string): string {\r
|
|
712
|
-
if (prop !== "") return errors.value.get(prop) ?? "";\r
|
|
713
|
-
return "";\r
|
|
714
|
-
}\r
|
|
715
|
-
\r
|
|
716
|
-
async function getErrors(): Promise<FormValidateError[]> {\r
|
|
717
|
-
const errs = [] as FormValidateError[];\r
|
|
718
|
-
errors.value.forEach((msg, field) => {\r
|
|
719
|
-
errs.push({ field, message: msg });\r
|
|
720
|
-
});\r
|
|
721
|
-
return errs;\r
|
|
722
|
-
}\r
|
|
723
|
-
\r
|
|
724
|
-
function clearValidate(fieldsToClear?: string | string[]) {\r
|
|
725
|
-
if (fieldsToClear) {\r
|
|
726
|
-
const propsArray = Array.isArray(fieldsToClear) ? fieldsToClear : [fieldsToClear];\r
|
|
727
|
-
propsArray.forEach(prop => removeError(prop));\r
|
|
728
|
-
} else {\r
|
|
729
|
-
errors.value.clear();\r
|
|
730
|
-
}\r
|
|
731
|
-
}\r
|
|
732
|
-
\r
|
|
733
|
-
return {\r
|
|
734
|
-
errors,\r
|
|
735
|
-
fields,\r
|
|
736
|
-
fieldInstances,\r
|
|
737
|
-
addField,\r
|
|
738
|
-
removeField,\r
|
|
739
|
-
setError,\r
|
|
740
|
-
removeError,\r
|
|
741
|
-
getError, // Used by children\r
|
|
742
|
-
getErrors, // Used by validate\r
|
|
743
|
-
clearValidate\r
|
|
744
|
-
};\r
|
|
745
|
-
}\r
|
|
746
|
-
\r
|
|
747
|
-
\r
|
|
748
|
-
export interface UseFieldGroupItemProps {\r
|
|
749
|
-
prop?: string;\r
|
|
750
|
-
label?: string;\r
|
|
751
|
-
labelPosition?: string;\r
|
|
752
|
-
labelWidth?: string | number;\r
|
|
753
|
-
ui?: any;\r
|
|
754
|
-
}\r
|
|
755
|
-
\r
|
|
756
|
-
export function useFieldGroupItem(props: UseFieldGroupItemProps) {\r
|
|
757
|
-
const form = inject<any>('rebornForm', undefined);\r
|
|
758
|
-
const instance = getCurrentInstance();\r
|
|
759
|
-
\r
|
|
760
|
-
\r
|
|
761
|
-
const error = computed(() => {\r
|
|
762
|
-
if (!form || !props.prop) return '';\r
|
|
763
|
-
return form.getError ? form.getError(props.prop) : '';\r
|
|
764
|
-
});\r
|
|
765
|
-
\r
|
|
766
|
-
const labelPosition = computed(() => {\r
|
|
767
|
-
return props.labelPosition || form?.props?.labelPosition || 'left';\r
|
|
768
|
-
});\r
|
|
769
|
-
\r
|
|
770
|
-
const labelWidth = computed(() => {\r
|
|
771
|
-
if (labelPosition.value === 'top') return 'auto';\r
|
|
772
|
-
return props.labelWidth || form?.props?.labelWidth || 'auto';\r
|
|
773
|
-
});\r
|
|
774
|
-
\r
|
|
775
|
-
const size = computed(() => {\r
|
|
776
|
-
const s = form?.props?.size;\r
|
|
777
|
-
if (s && ['sm', 'md', 'lg'].includes(s)) {\r
|
|
778
|
-
return s as "sm" | "md" | "lg";\r
|
|
779
|
-
}\r
|
|
780
|
-
return 'sm';\r
|
|
781
|
-
});\r
|
|
782
|
-
\r
|
|
783
|
-
const getBoundingClientRect = (callback: (res: any) => void) => {\r
|
|
784
|
-
uni.createSelectorQuery()\r
|
|
785
|
-
.in(instance?.proxy)\r
|
|
786
|
-
.select('.re-form-item')\r
|
|
787
|
-
.boundingClientRect(callback)\r
|
|
788
|
-
.exec();\r
|
|
789
|
-
};\r
|
|
790
|
-
\r
|
|
791
|
-
// Watch for prop changes to update registration\r
|
|
792
|
-
watch(() => props.prop, (newProp, oldProp) => {\r
|
|
793
|
-
if (form) {\r
|
|
794
|
-
if (oldProp) {\r
|
|
795
|
-
form.removeField({ uid: instance?.uid, prop: oldProp });\r
|
|
796
|
-
}\r
|
|
797
|
-
if (newProp) {\r
|
|
798
|
-
form.addField({ uid: instance?.uid, prop: newProp, getBoundingClientRect });\r
|
|
799
|
-
}\r
|
|
800
|
-
}\r
|
|
801
|
-
});\r
|
|
802
|
-
\r
|
|
803
|
-
onMounted(() => {\r
|
|
804
|
-
if (form && props.prop) {\r
|
|
805
|
-
form.addField({ uid: instance?.uid, prop: props.prop, getBoundingClientRect });\r
|
|
806
|
-
}\r
|
|
807
|
-
});\r
|
|
808
|
-
\r
|
|
809
|
-
onUnmounted(() => {\r
|
|
810
|
-
if (form && props.prop) {\r
|
|
811
|
-
form.removeField({ uid: instance?.uid, prop: props.prop });\r
|
|
812
|
-
}\r
|
|
813
|
-
});\r
|
|
814
|
-
\r
|
|
815
|
-
return {\r
|
|
816
|
-
form,\r
|
|
817
|
-
error,\r
|
|
818
|
-
labelPosition,\r
|
|
819
|
-
labelWidth,\r
|
|
820
|
-
size,\r
|
|
821
|
-
getBoundingClientRect\r
|
|
822
|
-
};\r
|
|
823
|
-
}\r
|
|
824
|
-
\r
|
|
825
|
-
// Consumer for inner components (Input, Select, etc.)\r
|
|
826
|
-
export function useFormInject(props: any) {\r
|
|
827
|
-
const form = inject<any>('rebornForm', null);\r
|
|
828
|
-
const formItem = inject<any>('rebornFormItem', null);\r
|
|
829
|
-
\r
|
|
830
|
-
const size = computed(() => {\r
|
|
831
|
-
return form?.props?.size || props.size;\r
|
|
832
|
-
});\r
|
|
833
|
-
\r
|
|
834
|
-
const disabled = computed(() => {\r
|
|
835
|
-
return form?.props?.disabled || props.disabled;\r
|
|
836
|
-
});\r
|
|
837
|
-
\r
|
|
838
|
-
const orientation = computed(() => {\r
|
|
839
|
-
return form?.props?.orientation || props.orientation;\r
|
|
840
|
-
});\r
|
|
841
|
-
\r
|
|
842
|
-
const isError = computed(() => {\r
|
|
843
|
-
return formItem?.isError?.value || false;\r
|
|
844
|
-
});\r
|
|
845
|
-
\r
|
|
846
|
-
return {\r
|
|
847
|
-
form,\r
|
|
848
|
-
size,\r
|
|
849
|
-
disabled,\r
|
|
850
|
-
orientation,\r
|
|
851
|
-
isError\r
|
|
852
|
-
};\r
|
|
853
|
-
}\r
|
|
854
|
-
`
|
|
783
|
+
"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 // \u4FDD\u5B58reject\u65B9\u6CD5\u7684\u5F15\u7528\uFF0C\u4EE5\u4FBF\u5728abort\u65F6\u8C03\u7528\r\n })\r\n }\r\n // \u63D0\u4F9Babort\u65B9\u6CD5\u6765\u4E2D\u6B62Promise\r\n abort(error?: any) {\r\n if (this._reject) {\r\n this._reject(error) // \u8C03\u7528reject\u65B9\u6CD5\u6765\u4E2D\u6B62Promise\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",
|
|
784
|
+
"lib/animation.ts": "import type FrameCallback from 'android.view.Choreographer.FrameCallback' // \u5E27\u56DE\u8C03\u63A5\u53E3\r\nimport type Long from 'kotlin.Long' // Kotlin Long \u7C7B\u578B\r\n// #ifdef APP-ANDROID\r\nimport Choreographer from 'android.view.Choreographer' // Android \u5E27\u540C\u6B65\u5668\uFF0C\u63D0\u4F9B\u5782\u76F4\u540C\u6B65\u4FE1\u53F7\r\n// #endif\r\n\r\n/**\r\n * \u7F13\u52A8\u51FD\u6570\u7C7B\u578B\u5B9A\u4E49\r\n */\r\nexport type EasingFunction = (progress: number) => number\r\n\r\n/**\r\n * \u52A8\u753B\u5C5E\u6027\u914D\u7F6E\r\n */\r\nexport interface AnimationAttribute {\r\n /** \u8D77\u59CB\u503C */\r\n fromValue: string\r\n /** \u7ED3\u675F\u503C */\r\n toValue: string\r\n /** \u5355\u4F4D (px, %, deg\u7B49) */\r\n unit: string\r\n /** \u5F53\u524D\u503C */\r\n currentValue: string\r\n /** \u5F53\u524D\u8FDB\u5EA6 (0-1) */\r\n progress: number\r\n /** \u5C5E\u6027\u540D\u79F0 */\r\n propertyName: string\r\n}\r\n\r\n/**\r\n * \u52A8\u753B\u914D\u7F6E\u9009\u9879\r\n */\r\nexport interface AnimationOptions {\r\n /** \u52A8\u753B\u6301\u7EED\u65F6\u95F4(\u6BEB\u79D2) */\r\n duration?: number\r\n /** \u5FAA\u73AF\u6B21\u6570 (-1\u4E3A\u65E0\u9650\u5FAA\u73AF) */\r\n loop?: number\r\n /** \u662F\u5426\u5F80\u8FD4\u64AD\u653E */\r\n alternate?: boolean\r\n /** \u662F\u5426\u6309\u5C5E\u6027\u987A\u5E8F\u4F9D\u6B21\u6267\u884C\u52A8\u753B */\r\n sequential?: boolean\r\n /** \u7F13\u52A8\u51FD\u6570\u540D\u79F0 */\r\n timingFunction?: string\r\n /** \u81EA\u5B9A\u4E49\u8D1D\u585E\u5C14\u66F2\u7EBF\u53C2\u6570 */\r\n bezier?: number[]\r\n /** \u52A8\u753B\u5B8C\u6210\u56DE\u8C03 */\r\n complete?: () => void\r\n /** \u52A8\u753B\u5F00\u59CB\u56DE\u8C03 */\r\n start?: () => void\r\n /** \u6BCF\u5E27\u56DE\u8C03 */\r\n frame?: (progress: number) => void\r\n}\r\n\r\n// \u8D1D\u585E\u5C14\u66F2\u7EBF\u8BA1\u7B97\u5E38\u91CF\r\nconst BEZIER_SPLINE_SIZE = 11 // \u6837\u672C\u70B9\u6570\u91CF\uFF0C\u7528\u4E8E\u9884\u8BA1\u7B97\u4F18\u5316\r\nconst BEZIER_SAMPLE_STEP = 1.0 / (BEZIER_SPLINE_SIZE - 1.0) // \u6837\u672C\u6B65\u957F\r\n\r\n/**\r\n * \u8D1D\u585E\u5C14\u66F2\u7EBF\u7CFB\u6570A\r\n * \u4E09\u6B21\u8D1D\u585E\u5C14\u66F2\u7EBF\u7684\u4E09\u6B21\u9879\u7CFB\u6570\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)\xB3P\u2080 + 3(1-t)\xB2tP\u2081 + 3(1-t)t\xB2P\u2082 + t\xB3P\u2083 \u4E2D\u7684 t\xB3 \u7CFB\u6570\r\n}\r\n\r\n/**\r\n * \u8D1D\u585E\u5C14\u66F2\u7EBF\u7CFB\u6570B\r\n * \u4E09\u6B21\u8D1D\u585E\u5C14\u66F2\u7EBF\u7684\u4E8C\u6B21\u9879\u7CFB\u6570\r\n */\r\nfunction getBezierCoefficientB(x1: number, x2: number): number {\r\n return 3.0 * x2 - 6.0 * x1 // \u4E8C\u6B21\u9879\u7CFB\u6570\r\n}\r\n\r\n/**\r\n * \u8D1D\u585E\u5C14\u66F2\u7EBF\u7CFB\u6570C\r\n * \u4E09\u6B21\u8D1D\u585E\u5C14\u66F2\u7EBF\u7684\u4E00\u6B21\u9879\u7CFB\u6570\r\n */\r\nfunction getBezierCoefficientC(x1: number): number {\r\n return 3.0 * x1 // \u4E00\u6B21\u9879\u7CFB\u6570\r\n}\r\n\r\n/**\r\n * \u8BA1\u7B97\u8D1D\u585E\u5C14\u66F2\u7EBF\u503C\r\n * \u4F7F\u7528\u970D\u7EB3\u6CD5\u5219\u63D0\u9AD8\u8BA1\u7B97\u6548\u7387\r\n * @param t \u65F6\u95F4\u53C2\u6570 (0-1)\r\n * @param x1 \u63A7\u5236\u70B91\u7684x\u5750\u6807\r\n * @param x2 \u63A7\u5236\u70B92\u7684x\u5750\u6807\r\n */\r\nfunction calculateBezierValue(t: number, x1: number, x2: number): number {\r\n const a = getBezierCoefficientA(x1, x2) // \u83B7\u53D6\u4E09\u6B21\u9879\u7CFB\u6570\r\n const b = getBezierCoefficientB(x1, x2) // \u83B7\u53D6\u4E8C\u6B21\u9879\u7CFB\u6570\r\n const c = getBezierCoefficientC(x1) // \u83B7\u53D6\u4E00\u6B21\u9879\u7CFB\u6570\r\n return ((a * t + b) * t + c) * t // \u970D\u7EB3\u6CD5\u5219\uFF1A((at + b)t + c)t\uFF0C\u51CF\u5C11\u4E58\u6CD5\u8FD0\u7B97\r\n}\r\n\r\n/**\r\n * \u8BA1\u7B97\u8D1D\u585E\u5C14\u66F2\u7EBF\u659C\u7387\r\n * \u5BF9\u8D1D\u585E\u5C14\u66F2\u7EBF\u6C42\u5BFC\u5F97\u5230\u659C\u7387\u51FD\u6570\r\n * @param t \u65F6\u95F4\u53C2\u6570 (0-1)\r\n * @param x1 \u63A7\u5236\u70B91\u7684x\u5750\u6807\r\n * @param x2 \u63A7\u5236\u70B92\u7684x\u5750\u6807\r\n */\r\nfunction getBezierSlope(t: number, x1: number, x2: number): number {\r\n const a = getBezierCoefficientA(x1, x2) // \u4E09\u6B21\u9879\u7CFB\u6570\r\n const b = getBezierCoefficientB(x1, x2) // \u4E8C\u6B21\u9879\u7CFB\u6570\r\n const c = getBezierCoefficientC(x1) // \u4E00\u6B21\u9879\u7CFB\u6570\r\n return 3.0 * a * t * t + 2.0 * b * t + c // \u5BFC\u6570\uFF1A3at\xB2 + 2bt + c\r\n}\r\n\r\n/**\r\n * \u4E8C\u5206\u6CD5\u6C42\u89E3\u8D1D\u585E\u5C14\u66F2\u7EBF\u53C2\u6570\r\n * \u7528\u4E8E\u6839\u636Ex\u503C\u53CD\u63A8t\u53C2\u6570\uFF0C\u9002\u7528\u4E8E\u659C\u7387\u8F83\u5C0F\u7684\u60C5\u51B5\r\n * @param targetX \u76EE\u6807x\u503C\r\n * @param startT \u8D77\u59CBt\u503C\r\n * @param endT \u7ED3\u675Ft\u503C\r\n * @param x1 \u63A7\u5236\u70B91\u7684x\u5750\u6807\r\n * @param x2 \u63A7\u5236\u70B92\u7684x\u5750\u6807\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 // \u5F53\u524D\u8BA1\u7B97\u7684x\u503C\r\n let currentT: number // \u5F53\u524D\u7684t\u53C2\u6570\r\n let iterations = 0 // \u8FED\u4EE3\u6B21\u6570\u8BA1\u6570\u5668\r\n const maxIterations = 10 // \u6700\u5927\u8FED\u4EE3\u6B21\u6570\uFF0C\u907F\u514D\u65E0\u9650\u5FAA\u73AF\r\n const precision = 0.0000001 // \u7CBE\u5EA6\u8981\u6C42\r\n\r\n do {\r\n currentT = startT + (endT - startT) / 2.0 // \u53D6\u4E2D\u70B9\r\n currentX = calculateBezierValue(currentT, x1, x2) - targetX // \u8BA1\u7B97\u8BEF\u5DEE\r\n if (currentX > 0.0) {\r\n // \u5982\u679C\u5F53\u524Dx\u503C\u5927\u4E8E\u76EE\u6807\u503C\r\n endT = currentT // \u7F29\u5C0F\u53F3\u8FB9\u754C\r\n }\r\n else {\r\n // \u5982\u679C\u5F53\u524Dx\u503C\u5C0F\u4E8E\u76EE\u6807\u503C\r\n startT = currentT // \u7F29\u5C0F\u5DE6\u8FB9\u754C\r\n }\r\n iterations++ // \u589E\u52A0\u8FED\u4EE3\u8BA1\u6570\r\n } while (Math.abs(currentX) > precision && iterations < maxIterations) // \u76F4\u5230\u7CBE\u5EA6\u6EE1\u8DB3\u6216\u8FBE\u5230\u6700\u5927\u8FED\u4EE3\u6B21\u6570\r\n\r\n return currentT // \u8FD4\u56DE\u627E\u5230\u7684t\u53C2\u6570\r\n}\r\n\r\n/**\r\n * \u725B\u987F-\u62C9\u592B\u900A\u6CD5\u6C42\u89E3\u8D1D\u585E\u5C14\u66F2\u7EBF\u53C2\u6570\r\n * \u9002\u7528\u4E8E\u659C\u7387\u8F83\u5927\u7684\u60C5\u51B5\uFF0C\u6536\u655B\u901F\u5EA6\u5FEB\r\n * @param targetX \u76EE\u6807x\u503C\r\n * @param initialGuess \u521D\u59CB\u731C\u6D4B\u503C\r\n * @param x1 \u63A7\u5236\u70B91\u7684x\u5750\u6807\r\n * @param x2 \u63A7\u5236\u70B92\u7684x\u5750\u6807\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 // \u5F53\u524Dt\u503C\uFF0C\u4ECE\u521D\u59CB\u731C\u6D4B\u5F00\u59CB\r\n const maxIterations = 4 // \u6700\u5927\u8FED\u4EE3\u6B21\u6570\uFF0C\u725B\u987F\u6CD5\u6536\u655B\u5FEB\r\n\r\n for (let i = 0; i < maxIterations; i++) {\r\n const slope = getBezierSlope(t, x1, x2) // \u8BA1\u7B97\u5F53\u524D\u70B9\u7684\u659C\u7387\r\n if (slope == 0.0) {\r\n // \u5982\u679C\u659C\u7387\u4E3A0\uFF0C\u907F\u514D\u9664\u96F6\u9519\u8BEF\r\n return t\r\n }\r\n const currentX = calculateBezierValue(t, x1, x2) - targetX // \u8BA1\u7B97\u5F53\u524D\u8BEF\u5DEE\r\n t = t - currentX / slope // \u725B\u987F\u6CD5\u8FED\u4EE3\u516C\u5F0F\uFF1At_new = t - f(t)/f'(t)\r\n }\r\n return t // \u8FD4\u56DE\u6536\u655B\u540E\u7684t\u503C\r\n}\r\n\r\n/**\r\n * \u521B\u5EFA\u8D1D\u585E\u5C14\u7F13\u52A8\u51FD\u6570\r\n * \u6839\u636E\u56DB\u4E2A\u63A7\u5236\u70B9\u5750\u6807\u751F\u6210\u7F13\u52A8\u51FD\u6570\uFF0C\u7C7B\u4F3CCSS\u7684cubic-bezier\r\n * @param x1 \u63A7\u5236\u70B91\u7684x\u5750\u6807 (0-1)\r\n * @param y1 \u63A7\u5236\u70B91\u7684y\u5750\u6807 (0-1)\r\n * @param x2 \u63A7\u5236\u70B92\u7684x\u5750\u6807 (0-1)\r\n * @param y2 \u63A7\u5236\u70B92\u7684y\u5750\u6807 (0-1)\r\n */\r\nfunction createBezierEasing(x1: number, y1: number, x2: number, y2: number): EasingFunction | null {\r\n // \u9A8C\u8BC1\u63A7\u5236\u70B9\u5750\u6807\u8303\u56F4\uFF0Cx\u5750\u6807\u5FC5\u987B\u57280-1\u4E4B\u95F4\r\n if (!(x1 >= 0 && x1 <= 1 && x2 >= 0 && x2 <= 1)) {\r\n return null // \u53C2\u6570\u65E0\u6548\u65F6\u8FD4\u56DEnull\r\n }\r\n\r\n const sampleValues: number[] = [] // \u9884\u8BA1\u7B97\u7684\u6837\u672C\u503C\u6570\u7EC4\r\n\r\n // \u9884\u8BA1\u7B97\u6837\u672C\u503C\u4EE5\u63D0\u9AD8\u6027\u80FD\uFF0C\u4EC5\u5BF9\u975E\u7EBF\u6027\u66F2\u7EBF\u8FDB\u884C\u9884\u8BA1\u7B97\r\n if (x1 != y1 || x2 != y2) {\r\n // \u5982\u679C\u4E0D\u662F\u7EBF\u6027\u51FD\u6570\r\n for (let i = 0; i < BEZIER_SPLINE_SIZE; i++) {\r\n // \u8BA1\u7B97\u7B49\u95F4\u8DDD\u7684\u6837\u672C\u70B9\uFF0C\u7528\u4E8E\u5FEB\u901F\u67E5\u627E\r\n sampleValues.push(calculateBezierValue(i * BEZIER_SAMPLE_STEP, x1, x2))\r\n }\r\n }\r\n\r\n /**\r\n * \u6839\u636Ex\u503C\u83B7\u53D6\u5BF9\u5E94\u7684t\u53C2\u6570\r\n * \u4F7F\u7528\u9884\u8BA1\u7B97\u6837\u672C\u8FDB\u884C\u5FEB\u901F\u67E5\u627E\u548C\u63D2\u503C\r\n * @param x \u8F93\u5165\u7684x\u503C (0-1)\r\n */\r\n function getTParameterForX(x: number): number {\r\n let intervalStart = 0.0 // \u533A\u95F4\u8D77\u59CB\u4F4D\u7F6E\r\n let currentSample = 1 // \u5F53\u524D\u6837\u672C\u7D22\u5F15\r\n const lastSample = BEZIER_SPLINE_SIZE - 1 // \u6700\u540E\u4E00\u4E2A\u6837\u672C\u7D22\u5F15\r\n\r\n // \u627E\u5230x\u503C\u6240\u5728\u7684\u533A\u95F4\uFF0C\u7EBF\u6027\u641C\u7D22\u9884\u8BA1\u7B97\u7684\u6837\u672C\r\n for (; currentSample != lastSample && sampleValues[currentSample] <= x; currentSample++) {\r\n intervalStart += BEZIER_SAMPLE_STEP // \u79FB\u52A8\u533A\u95F4\u8D77\u59CB\u4F4D\u7F6E\r\n }\r\n currentSample-- // \u56DE\u9000\u5230\u6B63\u786E\u7684\u533A\u95F4\r\n\r\n // \u7EBF\u6027\u63D2\u503C\u83B7\u5F97\u521D\u59CB\u731C\u6D4B\u503C\uFF0C\u63D0\u9AD8\u540E\u7EED\u6C42\u89E3\u7CBE\u5EA6\r\n const dist\r\n = (x - sampleValues[currentSample])\r\n / (sampleValues[currentSample + 1] - sampleValues[currentSample]) // \u8BA1\u7B97\u5728\u533A\u95F4\u5185\u7684\u76F8\u5BF9\u4F4D\u7F6E\r\n const initialGuess = intervalStart + dist * BEZIER_SAMPLE_STEP // \u8BA1\u7B97\u521D\u59CB\u731C\u6D4B\u7684t\u503C\r\n const initialSlope = getBezierSlope(initialGuess, x1, x2) // \u8BA1\u7B97\u521D\u59CB\u70B9\u7684\u659C\u7387\r\n\r\n // \u6839\u636E\u659C\u7387\u9009\u62E9\u5408\u9002\u7684\u6C42\u89E3\u65B9\u6CD5\r\n if (initialSlope >= 0.001) {\r\n // \u659C\u7387\u8DB3\u591F\u5927\u65F6\u4F7F\u7528\u725B\u987F\u6CD5\r\n return newtonRaphsonBezierT(x, initialGuess, x1, x2)\r\n }\r\n else if (initialSlope == 0.0) {\r\n // \u659C\u7387\u4E3A0\u65F6\u76F4\u63A5\u8FD4\u56DE\r\n return initialGuess\r\n }\r\n // \u659C\u7387\u592A\u5C0F\u65F6\u4F7F\u7528\u4E8C\u5206\u6CD5\uFF0C\u66F4\u7A33\u5B9A\r\n return binarySearchBezierT(x, intervalStart, intervalStart + BEZIER_SAMPLE_STEP, x1, x2)\r\n }\r\n\r\n // \u8FD4\u56DE\u7F13\u52A8\u51FD\u6570\uFF0C\u8FD9\u662F\u6700\u7EC8\u7684\u7F13\u52A8\u51FD\u6570\u63A5\u53E3\r\n return function (progress: number): number {\r\n // \u7EBF\u6027\u60C5\u51B5\u76F4\u63A5\u8FD4\u56DE\uFF0C\u4F18\u5316\u6027\u80FD\r\n if (x1 == y1 && x2 == y2) {\r\n return progress\r\n }\r\n // \u8FB9\u754C\u60C5\u51B5\u5904\u7406\uFF0C\u907F\u514D\u8BA1\u7B97\u8BEF\u5DEE\r\n if (progress == 0.0 || progress == 1.0) {\r\n return progress\r\n }\r\n // \u8BA1\u7B97\u8D1D\u585E\u5C14\u66F2\u7EBF\u503C\uFF1A\u5148\u6839\u636Eprogress(x)\u627E\u5230\u5BF9\u5E94\u7684t\uFF0C\u518D\u8BA1\u7B97y\u503C\r\n return calculateBezierValue(getTParameterForX(progress), y1, y2)\r\n }\r\n}\r\n\r\n/**\r\n * \u989C\u8272\u5DE5\u5177\u51FD\u6570\uFF1A\u6807\u51C6\u5316\u989C\u8272\u503C\u683C\u5F0F\r\n * \u5904\u7406\u4E0D\u540C\u683C\u5F0F\u7684\u989C\u8272\u8F93\u5165\uFF0C\u786E\u4FDD\u8FD4\u56DE\u6709\u6548\u7684\u989C\u8272\u503C\r\n */\r\nfunction getDefaultColor(colorValue: string): string {\r\n // \u7B80\u5316\u7684\u989C\u8272\u5904\u7406\uFF0C\u5B9E\u9645\u9879\u76EE\u4E2D\u53EF\u80FD\u9700\u8981\u66F4\u5B8C\u6574\u7684\u989C\u8272\u8F6C\u6362\r\n if (colorValue.startsWith('#')) {\r\n // \u5341\u516D\u8FDB\u5236\u989C\u8272\u683C\u5F0F\r\n return colorValue\r\n }\r\n if (colorValue.startsWith('rgb')) {\r\n // RGB\u6216RGBA\u989C\u8272\u683C\u5F0F\r\n return colorValue\r\n }\r\n // \u9ED8\u8BA4\u8FD4\u56DE\u9ED1\u8272\uFF0C\u4F5C\u4E3A\u515C\u5E95\u5904\u7406\r\n return '#000000'\r\n}\r\n\r\n/**\r\n * \u5341\u516D\u8FDB\u5236\u989C\u8272\u8F6CRGB\u5BF9\u8C61\r\n * \u5C06#RRGGBB\u683C\u5F0F\u7684\u989C\u8272\u8F6C\u6362\u4E3A{r,g,b,a}\u5BF9\u8C61\uFF0C\u7528\u4E8E\u989C\u8272\u52A8\u753B\u63D2\u503C\r\n * @param hex \u5341\u516D\u8FDB\u5236\u989C\u8272\u503C\uFF0C\u5982\"#FF0000\"\r\n * @returns \u5305\u542Br,g,b,a\u5C5E\u6027\u7684\u989C\u8272\u5BF9\u8C61\r\n */\r\nfunction hexToRgb(hex: string): any {\r\n // \u4F7F\u7528\u6B63\u5219\u8868\u8FBE\u5F0F\u89E3\u6790\u5341\u516D\u8FDB\u5236\u989C\u8272\uFF0C\u652F\u6301\u5E26#\u548C\u4E0D\u5E26#\u7684\u683C\u5F0F\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 // \u89E3\u6790\u6210\u529F\r\n return {\r\n r: Number.parseInt(result[1] ?? '0', 16), // \u7EA2\u8272\u5206\u91CF\uFF0C16\u8FDB\u5236\u8F6C10\u8FDB\u5236\r\n g: Number.parseInt(result[2] ?? '0', 16), // \u7EFF\u8272\u5206\u91CF\r\n b: Number.parseInt(result[3] ?? '0', 16), // \u84DD\u8272\u5206\u91CF\r\n a: 1.0, // \u900F\u660E\u5EA6\uFF0C\u9ED8\u8BA4\u4E0D\u900F\u660E\r\n }\r\n }\r\n // \u89E3\u6790\u5931\u8D25\u65F6\u8FD4\u56DE\u9ED1\u8272\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 * \u9AD8\u6027\u80FD\u52A8\u753B\u5F15\u64CE\u7C7B\r\n * \u652F\u6301\u591A\u5E73\u53F0\u7684\u6D41\u7545\u52A8\u753B\u6548\u679C\uFF0C\u63D0\u4F9B\u4E30\u5BCC\u7684\u7F13\u52A8\u51FD\u6570\u548C\u52A8\u753B\u63A7\u5236\r\n */\r\nexport class AnimationEngine {\r\n /** \u9884\u5B9A\u4E49\u7F13\u52A8\u51FD\u6570\u6620\u5C04\uFF0C\u5B58\u50A8\u5E38\u7528\u7684\u8D1D\u585E\u5C14\u66F2\u7EBF\u53C2\u6570 */\r\n private readonly easingPresets = new Map<string, number[]>([\r\n ['linear', [0.0, 0.0, 1.0, 1.0]], // \u7EBF\u6027\u7F13\u52A8\r\n ['ease', [0.25, 0.1, 0.25, 1.0]], // \u9ED8\u8BA4\u7F13\u52A8\r\n ['easeIn', [0.42, 0.0, 1.0, 1.0]], // \u52A0\u901F\u8FDB\u5165\r\n ['easeOut', [0.0, 0.0, 0.58, 1.0]], // \u51CF\u901F\u9000\u51FA\r\n ['easeInOut', [0.42, 0.0, 0.58, 1.0]], // \u5148\u52A0\u901F\u540E\u51CF\u901F\r\n ['easeInQuad', [0.55, 0.085, 0.68, 0.53]], // \u4E8C\u6B21\u65B9\u52A0\u901F\r\n ['easeOutQuad', [0.25, 0.46, 0.45, 0.94]], // \u4E8C\u6B21\u65B9\u51CF\u901F\r\n ['easeInOutQuad', [0.455, 0.03, 0.515, 0.955]], // \u4E8C\u6B21\u65B9\u5148\u52A0\u901F\u540E\u51CF\u901F\r\n ['easeInCubic', [0.55, 0.055, 0.675, 0.19]], // \u4E09\u6B21\u65B9\u52A0\u901F\r\n ['easeOutCubic', [0.215, 0.61, 0.355, 1.0]], // \u4E09\u6B21\u65B9\u51CF\u901F\r\n ['easeInOutCubic', [0.645, 0.045, 0.355, 1.0]], // \u4E09\u6B21\u65B9\u5148\u52A0\u901F\u540E\u51CF\u901F\r\n ['easeInQuart', [0.895, 0.03, 0.685, 0.22]], // \u56DB\u6B21\u65B9\u52A0\u901F\r\n ['easeOutQuart', [0.165, 0.84, 0.44, 1.0]], // \u56DB\u6B21\u65B9\u51CF\u901F\r\n ['easeInOutQuart', [0.77, 0.0, 0.175, 1.0]], // \u56DB\u6B21\u65B9\u5148\u52A0\u901F\u540E\u51CF\u901F\r\n ['easeInQuint', [0.755, 0.05, 0.855, 0.06]], // \u4E94\u6B21\u65B9\u52A0\u901F\r\n ['easeOutQuint', [0.23, 1.0, 0.32, 1.0]], // \u4E94\u6B21\u65B9\u51CF\u901F\r\n ['easeInOutQuint', [0.86, 0.0, 0.07, 1.0]], // \u4E94\u6B21\u65B9\u5148\u52A0\u901F\u540E\u51CF\u901F\r\n ['easeInSine', [0.47, 0.0, 0.745, 0.715]], // \u6B63\u5F26\u52A0\u901F\r\n ['easeOutSine', [0.39, 0.575, 0.565, 1.0]], // \u6B63\u5F26\u51CF\u901F\r\n ['easeInOutSine', [0.445, 0.05, 0.55, 0.95]], // \u6B63\u5F26\u5148\u52A0\u901F\u540E\u51CF\u901F\r\n ['easeInExpo', [0.95, 0.05, 0.795, 0.035]], // \u6307\u6570\u52A0\u901F\r\n ['easeOutExpo', [0.19, 1.0, 0.22, 1.0]], // \u6307\u6570\u51CF\u901F\r\n ['easeInOutExpo', [1.0, 0.0, 0.0, 1.0]], // \u6307\u6570\u5148\u52A0\u901F\u540E\u51CF\u901F\r\n ['easeInCirc', [0.6, 0.04, 0.98, 0.335]], // \u5706\u5F62\u52A0\u901F\r\n ['easeOutCirc', [0.075, 0.82, 0.165, 1.0]], // \u5706\u5F62\u51CF\u901F\r\n ['easeInOutBack', [0.68, -0.55, 0.265, 1.55]], // \u56DE\u5F39\u6548\u679C\r\n ])\r\n\r\n /** \u76EE\u6807DOM\u5143\u7D20\uFF0C\u52A8\u753B\u4F5C\u7528\u7684\u5BF9\u8C61 */\r\n private targetElement: any | null = null\r\n\r\n /** \u52A8\u753B\u6301\u7EED\u65F6\u95F4(\u6BEB\u79D2)\uFF0C\u9ED8\u8BA4500ms */\r\n private animationDuration: number = 500\r\n\r\n /** \u52A8\u753B\u662F\u5426\u6B63\u5728\u8FD0\u884C\uFF0C\u7528\u4E8E\u63A7\u5236\u52A8\u753B\u5FAA\u73AF */\r\n private isRunning: boolean = false\r\n\r\n /** \u52A8\u753B\u662F\u5426\u6682\u505C\uFF0C\u6682\u505C\u65F6\u4FDD\u7559\u5F53\u524D\u8FDB\u5EA6 */\r\n private isPaused: boolean = false\r\n\r\n /** \u5F53\u524D\u52A8\u753B\u8FDB\u5EA6 (0-1)\uFF0C\u7528\u4E8E\u6062\u590D\u6682\u505C\u7684\u52A8\u753B */\r\n private currentProgress: number = 0\r\n\r\n /** \u662F\u5426\u53CD\u5411\u64AD\u653E\uFF0C\u5F71\u54CD\u52A8\u753B\u65B9\u5411 */\r\n private isReversed: boolean = false\r\n\r\n /** \u662F\u5426\u5F80\u8FD4\u64AD\u653E\u6A21\u5F0F\uFF0C\u63A7\u5236\u52A8\u753B\u662F\u5426\u6765\u56DE\u64AD\u653E */\r\n private isAlternate: boolean = false\r\n /** \u5F80\u8FD4\u64AD\u653E\u65F6\u662F\u5426\u5904\u4E8E\u53CD\u5411\u72B6\u6001 */\r\n private isAlternateReversed: boolean = false\r\n\r\n /** \u5FAA\u73AF\u64AD\u653E\u6B21\u6570 (-1\u4E3A\u65E0\u9650\u5FAA\u73AF) */\r\n private loopCount: number = 1\r\n /** \u5F53\u524D\u5DF2\u5B8C\u6210\u7684\u5FAA\u73AF\u6B21\u6570 */\r\n private currentLoop: number = 0\r\n\r\n /** \u52A8\u753B\u662F\u5426\u6B63\u5728\u505C\u6B62\uFF0C\u7528\u4E8E\u63D0\u524D\u7EC8\u6B62\u52A8\u753B */\r\n private isStopping: boolean = true\r\n\r\n /** \u5F53\u524D\u6267\u884C\u7684\u5C5E\u6027\u7D22\u5F15(\u987A\u5E8F\u6267\u884C\u6A21\u5F0F)\uFF0C\u7528\u4E8E\u63A7\u5236\u5C5E\u6027\u4F9D\u6B21\u52A8\u753B */\r\n private currentAttributeIndex: number = 0\r\n\r\n /** \u56DE\u8C03\u51FD\u6570\uFF0C\u63D0\u4F9B\u52A8\u753B\u751F\u547D\u5468\u671F\u94A9\u5B50 */\r\n private onComplete: () => void = () => { } // \u52A8\u753B\u5B8C\u6210\u56DE\u8C03\r\n private onStart: () => void = () => { } // \u52A8\u753B\u5F00\u59CB\u56DE\u8C03\r\n private onFrame: (progress: number) => void = () => { } // \u6BCF\u5E27\u56DE\u8C03\r\n\r\n /** \u52A8\u753B\u5C5E\u6027\u5217\u8868\uFF0C\u5B58\u50A8\u6240\u6709\u8981\u52A8\u753B\u7684CSS\u5C5E\u6027 */\r\n private animationAttributes: AnimationAttribute[] = []\r\n\r\n /** \u52A8\u753B\u5F00\u59CB\u65F6\u95F4\u6233\uFF0C\u7528\u4E8E\u8BA1\u7B97\u52A8\u753B\u8FDB\u5EA6 */\r\n private startTimestamp: number = 0\r\n\r\n /** \u5F53\u524D\u4F7F\u7528\u7684\u7F13\u52A8\u51FD\u6570\uFF0C\u5C06\u7EBF\u6027\u8FDB\u5EA6\u8F6C\u6362\u4E3A\u7F13\u52A8\u8FDB\u5EA6 */\r\n private currentEasingFunction: EasingFunction | null = null\r\n\r\n /** \u662F\u5426\u6309\u5C5E\u6027\u987A\u5E8F\u4F9D\u6B21\u6267\u884C\u52A8\u753B\uFF0C\u800C\u975E\u5E76\u884C\u6267\u884C */\r\n private isSequentialMode: boolean = false\r\n\r\n // \u5E73\u53F0\u76F8\u5173\u7684\u52A8\u753B\u63A7\u5236\u5668\r\n // Android\u5E73\u53F0\u4F7F\u7528Choreographer\u63D0\u4F9B\u9AD8\u6027\u80FD\u52A8\u753B\r\n // #ifdef APP-ANDROID\r\n private choreographer: Choreographer | null = null // Android\u7CFB\u7EDF\u5E27\u540C\u6B65\u5668\r\n private frameCallback: FrameCallback | null = null // \u5E27\u56DE\u8C03\u5904\u7406\u5668\r\n // #endif\r\n\r\n // iOS/\u5C0F\u7A0B\u5E8F\u5E73\u53F0\u4F7F\u7528\u5B9A\u65F6\u5668\r\n // #ifdef APP-IOS\r\n private displayLinkTimer: number = 0 // iOS\u5B9A\u65F6\u5668ID\r\n // #endif\r\n\r\n // Web\u5E73\u53F0\u4F7F\u7528requestAnimationFrame\r\n private animationFrameId: number | null = null // \u52A8\u753B\u5E27ID\r\n\r\n /**\r\n * \u521B\u5EFA\u52A8\u753B\u5F15\u64CE\u5B9E\u4F8B\r\n * \u521D\u59CB\u5316\u52A8\u753B\u5F15\u64CE\uFF0C\u8BBE\u7F6E\u76EE\u6807\u5143\u7D20\u548C\u52A8\u753B\u914D\u7F6E\r\n * @param element \u76EE\u6807DOM\u5143\u7D20\uFF0Cnull\u65F6\u4EC5\u505A\u8BA1\u7B97\u4E0D\u5E94\u7528\u6837\u5F0F\r\n * @param options \u52A8\u753B\u914D\u7F6E\u9009\u9879\uFF0C\u5305\u542B\u6301\u7EED\u65F6\u95F4\u3001\u7F13\u52A8\u51FD\u6570\u7B49\r\n */\r\n constructor(element: any | null, options: AnimationOptions) {\r\n this.targetElement = element // \u4FDD\u5B58\u76EE\u6807\u5143\u7D20\u5F15\u7528\r\n\r\n // \u8BBE\u7F6E\u52A8\u753B\u53C2\u6570\uFF0C\u4F7F\u7528\u9009\u9879\u503C\u6216\u9ED8\u8BA4\u503C\r\n this.animationDuration\r\n = options.duration != null ? options.duration : this.animationDuration // \u8BBE\u7F6E\u52A8\u753B\u6301\u7EED\u65F6\u95F4\r\n this.loopCount = options.loop != null ? options.loop : this.loopCount // \u8BBE\u7F6E\u5FAA\u73AF\u6B21\u6570\r\n this.isAlternate = options.alternate != null ? options.alternate : this.isAlternate // \u8BBE\u7F6E\u5F80\u8FD4\u64AD\u653E\r\n this.isSequentialMode\r\n = options.sequential != null ? options.sequential : this.isSequentialMode // \u8BBE\u7F6E\u987A\u5E8F\u6267\u884C\u6A21\u5F0F\r\n\r\n // \u8BBE\u7F6E\u7F13\u52A8\u51FD\u6570\uFF0C\u4F18\u5148\u4F7F\u7528\u9884\u5B9A\u4E49\u51FD\u6570\r\n if (options.timingFunction != null) {\r\n const easingParams = this.easingPresets.get(options.timingFunction) // \u67E5\u627E\u9884\u5B9A\u4E49\u7F13\u52A8\u53C2\u6570\r\n if (easingParams != null) {\r\n // \u6839\u636E\u8D1D\u585E\u5C14\u53C2\u6570\u521B\u5EFA\u7F13\u52A8\u51FD\u6570\r\n this.currentEasingFunction = createBezierEasing(\r\n easingParams[0], // x1\u5750\u6807\r\n easingParams[1], // y1\u5750\u6807\r\n easingParams[2], // x2\u5750\u6807\r\n easingParams[3], // y2\u5750\u6807\r\n )\r\n }\r\n }\r\n\r\n // \u81EA\u5B9A\u4E49\u8D1D\u585E\u5C14\u66F2\u7EBF\uFF0C\u4F1A\u8986\u76D6\u9884\u5B9A\u4E49\u51FD\u6570\r\n if (options.bezier != null && options.bezier.length == 4) {\r\n this.currentEasingFunction = createBezierEasing(\r\n options.bezier[0], // \u81EA\u5B9A\u4E49x1\u5750\u6807\r\n options.bezier[1], // \u81EA\u5B9A\u4E49y1\u5750\u6807\r\n options.bezier[2], // \u81EA\u5B9A\u4E49x2\u5750\u6807\r\n options.bezier[3], // \u81EA\u5B9A\u4E49y2\u5750\u6807\r\n )\r\n }\r\n\r\n // \u8BBE\u7F6E\u56DE\u8C03\u51FD\u6570\uFF0C\u63D0\u4F9B\u52A8\u753B\u751F\u547D\u5468\u671F\u94A9\u5B50\r\n if (options.complete != null) {\r\n this.onComplete = options.complete // \u52A8\u753B\u5B8C\u6210\u56DE\u8C03\r\n }\r\n if (options.start != null) {\r\n this.onStart = options.start // \u52A8\u753B\u5F00\u59CB\u56DE\u8C03\r\n }\r\n if (options.frame != null) {\r\n this.onFrame = options.frame // \u6BCF\u5E27\u66F4\u65B0\u56DE\u8C03\r\n }\r\n }\r\n\r\n /**\r\n * \u4ECE\u6837\u5F0F\u503C\u4E2D\u63D0\u53D6\u5355\u4F4D\r\n * \u89E3\u6790CSS\u503C\u4E2D\u7684\u5355\u4F4D\u90E8\u5206\uFF0C\u7528\u4E8E\u52A8\u753B\u8BA1\u7B97\r\n * @param value \u6837\u5F0F\u503C\uFF0C\u5982 \"100px\", \"50%\"\r\n * @param propertyName CSS\u5C5E\u6027\u540D\u79F0\uFF0C\u7528\u4E8E\u5224\u65AD\u662F\u5426\u9700\u8981\u9ED8\u8BA4\u5355\u4F4D\r\n * @returns \u5355\u4F4D\u5B57\u7B26\u4E32\r\n */\r\n private extractUnit(value?: string, propertyName?: string): string {\r\n if (value == null) { return 'px' } // \u9ED8\u8BA4\u5355\u4F4D\u4E3Apx\r\n const unit = value.replace(/[\\d|\\-+.]/g, '') // \u79FB\u9664\u6570\u5B57\u3001\u8D1F\u53F7\u3001\u6B63\u53F7\u3001\u5C0F\u6570\u70B9\uFF0C\u4FDD\u7559\u5355\u4F4D\r\n\r\n // opacity\u3001z-index\u7B49\u5C5E\u6027\u65E0\u9700\u5355\u4F4D\r\n if (propertyName == 'opacity' || propertyName == 'z-index') {\r\n return '' // \u8FD4\u56DE\u7A7A\u5B57\u7B26\u4E32\u8868\u793A\u65E0\u5355\u4F4D\r\n }\r\n\r\n return unit == '' ? 'px' : unit // \u5982\u679C\u6CA1\u6709\u5355\u4F4D\u5219\u9ED8\u8BA4\u4E3Apx\r\n }\r\n\r\n /**\r\n * \u6DFB\u52A0\u81EA\u5B9A\u4E49\u7F13\u52A8\u51FD\u6570\r\n * \u5411\u5F15\u64CE\u6CE8\u518C\u65B0\u7684\u7F13\u52A8\u51FD\u6570\uFF0C\u53EF\u5728\u540E\u7EED\u52A8\u753B\u4E2D\u4F7F\u7528\r\n * @param name \u7F13\u52A8\u51FD\u6570\u540D\u79F0\r\n * @param bezierParams \u8D1D\u585E\u5C14\u66F2\u7EBF\u53C2\u6570 [x1, y1, x2, y2]\r\n */\r\n addCustomEasing(name: string, bezierParams: number[]): AnimationEngine {\r\n if (bezierParams.length == 4) {\r\n // \u9A8C\u8BC1\u53C2\u6570\u6570\u91CF\r\n this.easingPresets.set(name, bezierParams) // \u6DFB\u52A0\u5230\u9884\u8BBE\u6620\u5C04\u4E2D\r\n }\r\n return this // \u8FD4\u56DE\u81EA\u8EAB\u652F\u6301\u94FE\u5F0F\u8C03\u7528\r\n }\r\n\r\n /**\r\n * \u8BBE\u7F6E\u52A8\u753B\u53CD\u5411\u64AD\u653E\r\n * \u63A7\u5236\u52A8\u753B\u4ECE\u7ED3\u675F\u503C\u5411\u8D77\u59CB\u503C\u64AD\u653E\r\n * @param reverse \u662F\u5426\u53CD\u5411\u64AD\u653E\uFF0Cnull\u8868\u793A\u5207\u6362\u5F53\u524D\u72B6\u6001\r\n */\r\n setReverse(reverse: boolean | null = null): AnimationEngine {\r\n if (reverse != null) {\r\n this.isReversed = reverse // \u8BBE\u7F6E\u6307\u5B9A\u72B6\u6001\r\n }\r\n else {\r\n this.isReversed = !this.isReversed // \u5207\u6362\u5F53\u524D\u72B6\u6001\r\n }\r\n return this // \u652F\u6301\u94FE\u5F0F\u8C03\u7528\r\n }\r\n\r\n /**\r\n * \u8BBE\u7F6E\u5FAA\u73AF\u64AD\u653E\u6B21\u6570\r\n * \u63A7\u5236\u52A8\u753B\u91CD\u590D\u6267\u884C\u7684\u6B21\u6570\r\n * @param count \u5FAA\u73AF\u6B21\u6570\uFF0C-1\u8868\u793A\u65E0\u9650\u5FAA\u73AF\r\n */\r\n setLoopCount(count: number): AnimationEngine {\r\n this.loopCount = count // \u8BBE\u7F6E\u5FAA\u73AF\u6B21\u6570\r\n return this // \u652F\u6301\u94FE\u5F0F\u8C03\u7528\r\n }\r\n\r\n /**\r\n * \u8BBE\u7F6E\u52A8\u753B\u6301\u7EED\u65F6\u95F4\r\n * \u63A7\u5236\u52A8\u753B\u4ECE\u5F00\u59CB\u5230\u7ED3\u675F\u7684\u603B\u65F6\u957F\r\n * @param duration \u6301\u7EED\u65F6\u95F4(\u6BEB\u79D2)\r\n */\r\n setDuration(duration: number): AnimationEngine {\r\n this.animationDuration = duration // \u8BBE\u7F6E\u52A8\u753B\u6301\u7EED\u65F6\u95F4\r\n return this // \u652F\u6301\u94FE\u5F0F\u8C03\u7528\r\n }\r\n\r\n /**\r\n * \u8BBE\u7F6E\u5F80\u8FD4\u64AD\u653E\u6A21\u5F0F\r\n * \u63A7\u5236\u52A8\u753B\u662F\u5426\u5728\u6BCF\u6B21\u5FAA\u73AF\u65F6\u53CD\u5411\u64AD\u653E\r\n * @param alternate \u662F\u5426\u5F80\u8FD4\u64AD\u653E\r\n */\r\n setAlternate(alternate: boolean): AnimationEngine {\r\n this.isAlternate = alternate // \u8BBE\u7F6E\u5F80\u8FD4\u64AD\u653E\u6807\u5FD7\r\n return this // \u652F\u6301\u94FE\u5F0F\u8C03\u7528\r\n }\r\n\r\n /**\r\n * \u8BBE\u7F6E\u987A\u5E8F\u6267\u884C\u6A21\u5F0F\r\n * \u63A7\u5236\u591A\u4E2A\u5C5E\u6027\u662F\u540C\u65F6\u52A8\u753B\u8FD8\u662F\u4F9D\u6B21\u52A8\u753B\r\n * @param sequential \u662F\u5426\u6309\u5C5E\u6027\u987A\u5E8F\u4F9D\u6B21\u6267\u884C\r\n */\r\n setSequential(sequential: boolean): AnimationEngine {\r\n this.isSequentialMode = sequential // \u8BBE\u7F6E\u6267\u884C\u6A21\u5F0F\r\n return this // \u652F\u6301\u94FE\u5F0F\u8C03\u7528\r\n }\r\n\r\n /**\r\n * \u6DFB\u52A0\u52A8\u753B\u5C5E\u6027\r\n * \u5411\u52A8\u753B\u5F15\u64CE\u6DFB\u52A0\u4E00\u4E2ACSS\u5C5E\u6027\u7684\u52A8\u753B\u914D\u7F6E\r\n * @param propertyName CSS\u5C5E\u6027\u540D\u79F0\r\n * @param fromValue \u8D77\u59CB\u503C(\u652F\u6301\u6570\u5B57+\u5355\u4F4D\uFF0C\u5982\"100px\"\u3001\"50%\")\r\n * @param toValue \u7ED3\u675F\u503C(\u5355\u4F4D\u5FC5\u987B\u4E0E\u8D77\u59CB\u503C\u4E00\u81F4)\r\n * @param unique \u662F\u5426\u552F\u4E00\uFF0Ctrue\u65F6\u540C\u540D\u5C5E\u6027\u4F1A\u88AB\u66FF\u6362\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) // \u68C0\u6D4B\u662F\u5426\u4E3A\u989C\u8272\u5C5E\u6027\r\n const unit = isColor ? '' : this.extractUnit(fromValue, propertyName) // \u63D0\u53D6\u5355\u4F4D\r\n\r\n // \u6839\u636E\u5C5E\u6027\u7C7B\u578B\u5904\u7406\u503C\r\n const processedFromValue = isColor\r\n ? getDefaultColor(fromValue) // \u989C\u8272\u5C5E\u6027\u6807\u51C6\u5316\r\n : Number.parseFloat(fromValue).toString() // \u6570\u503C\u5C5E\u6027\u63D0\u53D6\u6570\u5B57\r\n const processedToValue = isColor\r\n ? getDefaultColor(toValue) // \u989C\u8272\u5C5E\u6027\u6807\u51C6\u5316\r\n : Number.parseFloat(toValue).toString() // \u6570\u503C\u5C5E\u6027\u63D0\u53D6\u6570\u5B57\r\n\r\n // \u67E5\u627E\u662F\u5426\u5DF2\u5B58\u5728\u540C\u540D\u5C5E\u6027\uFF0C\u7528\u4E8E\u51B3\u5B9A\u662F\u66FF\u6362\u8FD8\u662F\u65B0\u589E\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 // \u5F3A\u5236\u6DFB\u52A0\u65B0\u5C5E\u6027\uFF0C\u4E0D\u66FF\u6362\r\n }\r\n\r\n // \u521B\u5EFA\u65B0\u7684\u52A8\u753B\u5C5E\u6027\u5BF9\u8C61\r\n const newAttribute: AnimationAttribute = {\r\n fromValue: processedFromValue, // \u5904\u7406\u540E\u7684\u8D77\u59CB\u503C\r\n toValue: processedToValue, // \u5904\u7406\u540E\u7684\u7ED3\u675F\u503C\r\n unit, // \u5355\u4F4D\r\n progress: 0, // \u521D\u59CB\u8FDB\u5EA6\u4E3A0\r\n currentValue: processedFromValue, // \u5F53\u524D\u503C\u521D\u59CB\u5316\u4E3A\u8D77\u59CB\u503C\r\n propertyName, // \u5C5E\u6027\u540D\u79F0\r\n }\r\n\r\n if (existingIndex == -1) {\r\n this.animationAttributes.push(newAttribute) // \u6DFB\u52A0\u65B0\u5C5E\u6027\r\n }\r\n else {\r\n this.animationAttributes[existingIndex] = newAttribute // \u66FF\u6362\u73B0\u6709\u5C5E\u6027\r\n }\r\n\r\n return this // \u652F\u6301\u94FE\u5F0F\u8C03\u7528\r\n }\r\n\r\n /**\r\n * \u5FEB\u6377\u65B9\u6CD5\uFF1A\u6DFB\u52A0\u53D8\u6362\u5C5E\u6027\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 * \u5FEB\u6377\u65B9\u6CD5\uFF1A\u6DFB\u52A0\u4F4D\u79FB\u52A8\u753B\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 * \u6DFB\u52A0X\u8F74\u4F4D\u79FB\u52A8\u753B\r\n * @param fromX \u8D77\u59CBX\u4F4D\u7F6E\uFF0C\u53EF\u4EE5\u4F7F\u7528\"current\"\u8868\u793A\u5F53\u524D\u4F4D\u7F6E\r\n * @param toX \u7ED3\u675FX\u4F4D\u7F6E\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 * \u6DFB\u52A0Y\u8F74\u4F4D\u79FB\u52A8\u753B\r\n * @param fromY \u8D77\u59CBY\u4F4D\u7F6E\uFF0C\u53EF\u4EE5\u4F7F\u7528\"current\"\u8868\u793A\u5F53\u524D\u4F4D\u7F6E\r\n * @param toY \u7ED3\u675FY\u4F4D\u7F6E\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 * \u5FEB\u6377\u65B9\u6CD5\uFF1A\u6DFB\u52A0\u7F29\u653E\u52A8\u753B\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 * \u5FEB\u6377\u65B9\u6CD5\uFF1A\u6DFB\u52A0\u65CB\u8F6C\u52A8\u753B\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 * \u5FEB\u6377\u65B9\u6CD5\uFF1A\u6DFB\u52A0\u900F\u660E\u5EA6\u52A8\u753B\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 * \u7EBF\u6027\u63D2\u503C\u8BA1\u7B97\r\n * \u6839\u636E\u8FDB\u5EA6\u5728\u4E24\u4E2A\u6570\u503C\u4E4B\u95F4\u8FDB\u884C\u63D2\u503C\uFF0C\u7528\u4E8E\u8BA1\u7B97\u52A8\u753B\u4E2D\u95F4\u503C\r\n * @param startValue \u8D77\u59CB\u503C\r\n * @param endValue \u7ED3\u675F\u503C\r\n * @param progress \u8FDB\u5EA6 (0-1)\r\n */\r\n private interpolateValue(startValue: number, endValue: number, progress: number): number {\r\n return startValue + (endValue - startValue) * progress // \u7EBF\u6027\u63D2\u503C\u516C\u5F0F\uFF1Astart + (end - start) * progress\r\n }\r\n\r\n /**\r\n * \u5224\u65AD\u662F\u5426\u4E3A\u989C\u8272\u76F8\u5173\u5C5E\u6027\r\n * \u68C0\u6D4BCSS\u5C5E\u6027\u540D\u662F\u5426\u4E0E\u989C\u8272\u76F8\u5173\uFF0C\u7528\u4E8E\u7279\u6B8A\u7684\u989C\u8272\u52A8\u753B\u5904\u7406\r\n * @param propertyName \u5C5E\u6027\u540D\u79F0\r\n */\r\n private isColorProperty(propertyName: string): boolean {\r\n return (\r\n propertyName.includes('background') // \u80CC\u666F\u989C\u8272\u76F8\u5173\r\n || propertyName.includes('color') // \u6587\u5B57\u989C\u8272\u76F8\u5173\r\n || propertyName.includes('border-color') // \u8FB9\u6846\u989C\u8272\u76F8\u5173\r\n || propertyName.includes('shadow') // \u9634\u5F71\u989C\u8272\u76F8\u5173\r\n )\r\n }\r\n\r\n /**\r\n * \u5224\u65AD\u662F\u5426\u4E3ATransform\u76F8\u5173\u5C5E\u6027\r\n * \u68C0\u6D4B\u5C5E\u6027\u540D\u662F\u5426\u4E3Atransform\u76F8\u5173\u7684CSS\u5C5E\u6027\r\n * @param propertyName CSS\u5C5E\u6027\u540D\u79F0\r\n * @returns \u662F\u5426\u4E3Atransform\u5C5E\u6027\r\n */\r\n private isTransformProperty(propertyName: string): boolean {\r\n return (\r\n propertyName == 'scaleX' // X\u8F74\u7F29\u653E\r\n || propertyName == 'scaleY' // Y\u8F74\u7F29\u653E\r\n || propertyName == 'scale' // \u7B49\u6BD4\u7F29\u653E\r\n || propertyName == 'rotateX' // X\u8F74\u65CB\u8F6C\r\n || propertyName == 'rotateY' // Y\u8F74\u65CB\u8F6C\r\n || propertyName == 'rotate' // Z\u8F74\u65CB\u8F6C\r\n || propertyName == 'translateX' // X\u8F74\u4F4D\u79FB\r\n || propertyName == 'translateY' // Y\u8F74\u4F4D\u79FB\r\n || propertyName == 'translate' // \u53CC\u8F74\u4F4D\u79FB\r\n )\r\n }\r\n\r\n /**\r\n * \u8BBE\u7F6E\u5143\u7D20\u6837\u5F0F\u5C5E\u6027\r\n * \u6839\u636E\u5C5E\u6027\u7C7B\u578B\u5E94\u7528\u76F8\u5E94\u7684\u6837\u5F0F\u503C\uFF0C\u652F\u6301transform\u3001\u989C\u8272\u3001\u666E\u901A\u6570\u503C\u5C5E\u6027\r\n * @param propertyName \u5C5E\u6027\u540D\u79F0\r\n * @param currentValue \u5F53\u524D\u503C\r\n * @param unit \u5355\u4F4D\r\n * @param progress \u52A8\u753B\u8FDB\u5EA6\r\n * @param attribute \u52A8\u753B\u5C5E\u6027\u5BF9\u8C61\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 } // \u6CA1\u6709\u76EE\u6807\u5143\u7D20\u65F6\u76F4\u63A5\u8FD4\u56DE\r\n\r\n const element = this.targetElement // \u83B7\u53D6\u76EE\u6807\u5143\u7D20\u5F15\u7528\r\n const valueStr = currentValue.toFixed(2) // \u6570\u503C\u4FDD\u7559\u4E24\u4F4D\u5C0F\u6570\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 \u76F8\u5173\u5C5E\u6027\u5904\u7406\uFF0C\u4F7F\u7528CSS transform\u5C5E\u6027\r\n switch (propertyName) {\r\n case 'scaleX': // X\u8F74\u7F29\u653E\r\n element.style!.setProperty('transform', `scaleX(${currentValue})`)\r\n break\r\n case 'scaleY': // Y\u8F74\u7F29\u653E\r\n element.style!.setProperty('transform', `scaleY(${currentValue})`)\r\n break\r\n case 'scale': // \u7B49\u6BD4\u7F29\u653E\r\n element.style!.setProperty('transform', `scale(${currentValue})`)\r\n break\r\n case 'rotateX': // X\u8F74\u65CB\u8F6C\r\n element.style!.setProperty('transform', `rotateX(${valueStr + unit})`)\r\n break\r\n case 'rotateY': // Y\u8F74\u65CB\u8F6C\r\n element.style!.setProperty('transform', `rotateY(${valueStr + unit})`)\r\n break\r\n case 'rotate': // Z\u8F74\u65CB\u8F6C\r\n element.style!.setProperty('transform', `rotate(${valueStr + unit})`)\r\n break\r\n case 'translateX': // X\u8F74\u4F4D\u79FB\r\n element.style!.setProperty('transform', `translateX(${valueStr + unit})`)\r\n break\r\n case 'translateY': // Y\u8F74\u4F4D\u79FB\r\n element.style!.setProperty('transform', `translateY(${valueStr + unit})`)\r\n break\r\n case 'translate': // \u53CC\u8F74\u4F4D\u79FB\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 // \u989C\u8272\u5C5E\u6027\u5904\u7406\uFF0C\u9700\u8981\u8FDB\u884CRGBA\u63D2\u503C\r\n if (this.isColorProperty(propertyName)) {\r\n const startColor = hexToRgb(attribute.fromValue) // \u89E3\u6790\u8D77\u59CB\u989C\u8272\r\n const endColor = hexToRgb(attribute.toValue) // \u89E3\u6790\u7ED3\u675F\u989C\u8272\r\n\r\n // \u63D0\u53D6\u8D77\u59CB\u989C\u8272\u7684RGBA\u5206\u91CF\uFF0C\u517C\u5BB9\u4E0D\u540C\u7684JSON\u5BF9\u8C61\u8BBF\u95EE\u65B9\u5F0F\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 // \u63D0\u53D6\u7ED3\u675F\u989C\u8272\u7684RGBA\u5206\u91CF\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 // \u5BF9\u6BCF\u4E2A\u989C\u8272\u5206\u91CF\u8FDB\u884C\u63D2\u503C\u8BA1\u7B97\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 // \u8BBE\u7F6ERGBA\u989C\u8272\u503C\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 // \u666E\u901A\u6570\u503C\u5C5E\u6027\u5904\u7406\uFF0C\u76F4\u63A5\u8BBE\u7F6E\u6570\u503C\u548C\u5355\u4F4D\r\n element.style!.setProperty(propertyName, valueStr + unit)\r\n }\r\n break\r\n }\r\n }\r\n\r\n /**\r\n * Web\u5E73\u53F0\u52A8\u753B\u8FD0\u884C\u65B9\u6CD5 (H5/iOS/Harmony)\r\n * \u4F7F\u7528requestAnimationFrame\u5B9E\u73B0\u6D41\u7545\u7684\u52A8\u753B\u5FAA\u73AF\r\n */\r\n private runWebAnimation(): void {\r\n // #ifdef H5 || APP-IOS || APP-HARMONY\r\n const self = this // \u4FDD\u5B58this\u5F15\u7528\uFF0C\u907F\u514D\u5728\u5185\u90E8\u51FD\u6570\u4E2Dthis\u6307\u5411\u6539\u53D8\r\n self.startTimestamp = 0 // \u91CD\u7F6E\u5F00\u59CB\u65F6\u95F4\u6233\r\n\r\n // \u53D6\u6D88\u4E4B\u524D\u7684\u52A8\u753B\u5E27\uFF0C\u907F\u514D\u91CD\u590D\u6267\u884C\r\n if (self.animationFrameId != null) {\r\n cancelAnimationFrame(self.animationFrameId)\r\n }\r\n\r\n function animationLoop(): void {\r\n // \u521D\u59CB\u5316\u5F00\u59CB\u65F6\u95F4\uFF0C\u9996\u6B21\u6267\u884C\u65F6\u8BB0\u5F55\u65F6\u95F4\u6233\r\n if (self.startTimestamp <= 0) {\r\n self.startTimestamp = Date.now()\r\n }\r\n\r\n // \u8BA1\u7B97\u5F53\u524D\u8FDB\u5EA6\uFF1A(\u5DF2\u7528\u65F6\u95F4 / \u603B\u65F6\u95F4) + \u6682\u505C\u524D\u7684\u8FDB\u5EA6\r\n const elapsed = Date.now() - self.startTimestamp // \u5DF2\u7ECF\u8FC7\u7684\u65F6\u95F4\r\n const progress = Math.min(elapsed / self.animationDuration + self.currentProgress, 1.0) // \u9650\u5236\u8FDB\u5EA6\u4E0D\u8D85\u8FC71\r\n\r\n // \u6267\u884C\u52A8\u753B\u66F4\u65B0\uFF0C\u5E94\u7528\u5F53\u524D\u8FDB\u5EA6\u5230\u6240\u6709\u5C5E\u6027\r\n self.updateAnimationFrame(progress)\r\n\r\n // \u68C0\u67E5\u6682\u505C\u72B6\u6001\r\n if (self.isPaused) {\r\n self.isRunning = false // \u505C\u6B62\u8FD0\u884C\u6807\u5FD7\r\n self.currentProgress = progress // \u4FDD\u5B58\u5F53\u524D\u8FDB\u5EA6\uFF0C\u7528\u4E8E\u6062\u590D\r\n console.log('\u52A8\u753B\u5DF2\u6682\u505C')\r\n return // \u9000\u51FA\u52A8\u753B\u5FAA\u73AF\r\n }\r\n\r\n // \u68C0\u67E5\u52A8\u753B\u5B8C\u6210\u6216\u505C\u6B62\r\n if (progress >= 1.0 || self.isStopping) {\r\n self.handleAnimationComplete() // \u5904\u7406\u52A8\u753B\u5B8C\u6210\u903B\u8F91\r\n return // \u9000\u51FA\u52A8\u753B\u5FAA\u73AF\r\n }\r\n\r\n // \u7EE7\u7EED\u4E0B\u4E00\u5E27\uFF0C\u52A8\u753B\u672A\u5B8C\u6210\u4E14\u4ECD\u5728\u8FD0\u884C\r\n if (progress < 1.0 && self.isRunning) {\r\n self.onFrame(progress) // \u89E6\u53D1\u6BCF\u5E27\u56DE\u8C03\r\n self.animationFrameId = requestAnimationFrame(animationLoop) // \u8BF7\u6C42\u4E0B\u4E00\u5E27\r\n }\r\n }\r\n\r\n // \u5F00\u59CB\u52A8\u753B\uFF0C\u89E6\u53D1\u5F00\u59CB\u56DE\u8C03\u5E76\u542F\u52A8\u52A8\u753B\u5FAA\u73AF\r\n self.onStart()\r\n animationLoop()\r\n // #endif\r\n }\r\n\r\n /**\r\n * \u66F4\u65B0\u52A8\u753B\u5E27\r\n * \u6839\u636E\u6267\u884C\u6A21\u5F0F\u66F4\u65B0\u6240\u6709\u6216\u5F53\u524D\u5C5E\u6027\u7684\u52A8\u753B\u503C\r\n * @param progress \u5F53\u524D\u8FDB\u5EA6 (0-1)\r\n */\r\n private updateAnimationFrame(progress: number): void {\r\n if (this.targetElement == null) { return } // \u6CA1\u6709\u76EE\u6807\u5143\u7D20\u65F6\u76F4\u63A5\u8FD4\u56DE\r\n\r\n if (!this.isSequentialMode) {\r\n // \u5E76\u884C\u6267\u884C\u6240\u6709\u5C5E\u6027\u52A8\u753B\uFF0C\u6240\u6709\u5C5E\u6027\u540C\u65F6\u8FDB\u884C\u52A8\u753B\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 // \u987A\u5E8F\u6267\u884C\u5C5E\u6027\u52A8\u753B\uFF0C\u4E00\u4E2A\u63A5\u4E00\u4E2A\u5730\u6267\u884C\u5C5E\u6027\u52A8\u753B\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 * \u66F4\u65B0\u5355\u4E2A\u5C5E\u6027\u7684\u52A8\u753B\r\n * \u8BA1\u7B97\u5C5E\u6027\u7684\u5F53\u524D\u503C\u5E76\u5E94\u7528\u5230\u5143\u7D20\u4E0A\r\n * @param attribute \u52A8\u753B\u5C5E\u6027\r\n * @param progress \u8FDB\u5EA6\r\n */\r\n private updateSingleAttribute(attribute: AnimationAttribute, progress: number): void {\r\n attribute.progress = progress // \u66F4\u65B0\u5C5E\u6027\u7684\u8FDB\u5EA6\u8BB0\u5F55\r\n\r\n if (!this.isColorProperty(attribute.propertyName)) {\r\n // \u6570\u503C\u5C5E\u6027\u5904\u7406\r\n const fromValue = Number.parseFloat(attribute.fromValue) // \u8D77\u59CB\u6570\u503C\r\n const toValue = Number.parseFloat(attribute.toValue) // \u7ED3\u675F\u6570\u503C\r\n\r\n // \u5E94\u7528\u7F13\u52A8\u51FD\u6570\uFF0C\u5C06\u7EBF\u6027\u8FDB\u5EA6\u8F6C\u6362\u4E3A\u7F13\u52A8\u8FDB\u5EA6\r\n let easedProgress = progress\r\n if (this.currentEasingFunction != null) {\r\n easedProgress = this.currentEasingFunction(progress)\r\n }\r\n\r\n // \u8BA1\u7B97\u5F53\u524D\u503C\uFF0C\u4F7F\u7528\u7F13\u52A8\u8FDB\u5EA6\u8FDB\u884C\u63D2\u503C\r\n let currentValue = this.interpolateValue(fromValue, toValue, easedProgress)\r\n\r\n // \u5904\u7406\u53CD\u5411\u548C\u5F80\u8FD4\u64AD\u653E\uFF0C\u4EA4\u6362\u8D77\u59CB\u548C\u7ED3\u675F\u503C\r\n if (this.isReversed || this.isAlternateReversed) {\r\n currentValue = this.interpolateValue(toValue, fromValue, easedProgress)\r\n }\r\n\r\n // \u5E94\u7528\u8BA1\u7B97\u51FA\u7684\u503C\u5230\u5143\u7D20\u5C5E\u6027\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 // \u989C\u8272\u5C5E\u6027\u5904\u7406\uFF0Cprogress\u53C2\u6570\u4F1A\u5728setElementProperty\u4E2D\u7528\u4E8E\u989C\u8272\u63D2\u503C\r\n this.setElementProperty(attribute.propertyName, 0, attribute.unit, progress, attribute)\r\n }\r\n }\r\n\r\n /**\r\n * \u5904\u7406\u52A8\u753B\u5B8C\u6210\r\n */\r\n private handleAnimationComplete(): void {\r\n // \u987A\u5E8F\u6A21\u5F0F\u4E0B\u68C0\u67E5\u662F\u5426\u8FD8\u6709\u672A\u6267\u884C\u7684\u5C5E\u6027\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 // \u91CD\u7F6E\u72B6\u6001\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 // \u5904\u7406\u5F80\u8FD4\u64AD\u653E\r\n if (this.isAlternate) {\r\n this.isAlternateReversed = !this.isAlternateReversed\r\n }\r\n\r\n // \u5904\u7406\u5FAA\u73AF\u64AD\u653E\r\n if (this.loopCount == -1) {\r\n // \u65E0\u9650\u5FAA\u73AF\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 // \u52A8\u753B\u5B8C\u6210\r\n this.isRunning = false\r\n this.onComplete()\r\n }\r\n\r\n /**\r\n * \u6839\u636E\u5E73\u53F0\u91CD\u65B0\u542F\u52A8\u52A8\u753B\r\n */\r\n private restartAnimation(): void {\r\n // \u91CD\u7F6E\u5F00\u59CB\u65F6\u95F4\u6233\uFF0C\u786E\u4FDD\u5FAA\u73AF\u52A8\u753B\u6B63\u786E\u8BA1\u65F6\r\n this.startTimestamp = 0\r\n\r\n // \u6839\u636E\u5E73\u53F0\u9009\u62E9\u5408\u9002\u7684\u52A8\u753B\u5F15\u64CE\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\u5E73\u53F0\u52A8\u753B\u8FD0\u884C\u65B9\u6CD5\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 // \u521D\u59CB\u5316Choreographer\r\n if (self.choreographer == null) {\r\n self.choreographer = Choreographer.getInstance()\r\n }\r\n else {\r\n // \u6E05\u9664\u4E4B\u524D\u7684\u56DE\u8C03\r\n if (self.frameCallback != null) {\r\n self.choreographer.removeFrameCallback(self.frameCallback)\r\n }\r\n }\r\n\r\n /**\r\n * Android\u539F\u751F\u5E27\u56DE\u8C03\u7C7B\r\n */\r\n class frameCallback extends Choreographer.FrameCallback {\r\n // @ts-ignore\r\n override doFrame(frameTimeNanos: Long) {\r\n // \u68C0\u67E5\u52A8\u753B\u662F\u5426\u5E94\u8BE5\u505C\u6B62\r\n if (!self.isRunning || self.isStopping) {\r\n return\r\n }\r\n\r\n // \u521D\u59CB\u5316\u5F00\u59CB\u65F6\u95F4\r\n if (self.startTimestamp <= 0) {\r\n self.startTimestamp = Date.now()\r\n }\r\n\r\n // \u8BA1\u7B97\u5F53\u524D\u8FDB\u5EA6\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 // \u6267\u884C\u52A8\u753B\u66F4\u65B0\r\n self.updateAnimationFrame(progress)\r\n\r\n // \u68C0\u67E5\u6682\u505C\u72B6\u6001\r\n if (self.isPaused) {\r\n self.isRunning = false\r\n self.currentProgress = progress\r\n return\r\n }\r\n\r\n // \u68C0\u67E5\u52A8\u753B\u5B8C\u6210\u6216\u505C\u6B62\r\n if (progress >= 1.0 || self.isStopping) {\r\n self.handleAnimationComplete()\r\n return\r\n }\r\n\r\n // \u7EE7\u7EED\u4E0B\u4E00\u5E27\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 // \u542F\u52A8\u52A8\u753B\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 * \u5C0F\u7A0B\u5E8F\u5E73\u53F0\u52A8\u753B\u8FD0\u884C\u65B9\u6CD5\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 // \u6E05\u9664\u4E4B\u524D\u7684\u5B9A\u65F6\u5668\r\n if (self.displayLinkTimer != 0) {\r\n clearTimeout(self.displayLinkTimer)\r\n }\r\n\r\n function animationLoop(): void {\r\n // \u521D\u59CB\u5316\u5F00\u59CB\u65F6\u95F4\r\n if (self.startTimestamp <= 0) {\r\n self.startTimestamp = Date.now()\r\n }\r\n\r\n // \u8BA1\u7B97\u5F53\u524D\u8FDB\u5EA6\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 // \u6267\u884C\u52A8\u753B\u66F4\u65B0\r\n self.updateAnimationFrame(progress)\r\n\r\n // \u68C0\u67E5\u6682\u505C\u72B6\u6001\r\n if (self.isPaused) {\r\n self.isRunning = false\r\n self.currentProgress = progress\r\n return\r\n }\r\n\r\n // \u68C0\u67E5\u52A8\u753B\u5B8C\u6210\u6216\u505C\u6B62\r\n if (progress >= 1.0 || self.isStopping) {\r\n self.handleAnimationComplete()\r\n return\r\n }\r\n\r\n // \u7EE7\u7EED\u4E0B\u4E00\u5E27\r\n if (progress < 1.0 && self.isRunning) {\r\n self.onFrame(progress)\r\n self.displayLinkTimer = setTimeout(animationLoop, 16) as any // \u7EA660fps\r\n }\r\n }\r\n\r\n // \u5F00\u59CB\u52A8\u753B\r\n self.onStart()\r\n animationLoop()\r\n // #endif\r\n }\r\n\r\n /**\r\n * \u5F00\u59CB\u64AD\u653E\u52A8\u753B\r\n */\r\n play(): AnimationEngine {\r\n if (this.isRunning) { return this }\r\n\r\n // \u521D\u59CB\u5316\u52A8\u753B\u72B6\u6001\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 // \u6839\u636E\u5E73\u53F0\u9009\u62E9\u5408\u9002\u7684\u52A8\u753B\u5F15\u64CE\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 * \u5F02\u6B65\u64AD\u653E\u52A8\u753B\uFF0C\u652F\u6301await\r\n * @returns Promise\uFF0C\u52A8\u753B\u5B8C\u6210\u65F6resolve\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 * \u505C\u6B62\u52A8\u753B\r\n * \u4F1A\u7ACB\u5373\u505C\u6B62\u52A8\u753B\u5E76\u8DF3\u8F6C\u5230\u7ED3\u675F\u72B6\u6001\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 // \u6E05\u7406\u5E73\u53F0\u76F8\u5173\u7684\u52A8\u753B\u63A7\u5236\u5668\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 * \u6682\u505C\u52A8\u753B\r\n * \u4FDD\u7559\u5F53\u524D\u72B6\u6001\uFF0C\u53EF\u4EE5\u901A\u8FC7play()\u6062\u590D\r\n */\r\n pause(): AnimationEngine {\r\n this.isPaused = true\r\n return this\r\n }\r\n\r\n /**\r\n * \u6062\u590D\u6682\u505C\u7684\u52A8\u753B\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 * \u6E05\u7A7A\u5E94\u7528\u5230\u5143\u7D20\u4E0A\u7684\u52A8\u753B\u6837\u5F0F\r\n * \u53EA\u6E05\u7A7A\u5B9E\u9645\u88AB\u52A8\u753B\u5F15\u64CE\u8BBE\u7F6E\u8FC7\u7684CSS\u5C5E\u6027\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 // \u6E05\u7A7A\u6240\u6709\u52A8\u753B\u5C5E\u6027\u5217\u8868\u4E2D\u8BB0\u5F55\u7684\u5C5E\u6027\r\n for (const attr of this.animationAttributes) {\r\n const propertyName = attr.propertyName\r\n\r\n // Transform \u76F8\u5173\u5C5E\u6027\u9700\u8981\u6E05\u7A7Atransform\r\n if (this.isTransformProperty(propertyName)) {\r\n element.style!.setProperty('transform', '')\r\n }\r\n else {\r\n // \u5176\u4ED6\u5C5E\u6027\u76F4\u63A5\u6E05\u7A7A\r\n element.style!.setProperty(propertyName, '')\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * \u91CD\u7F6E\u52A8\u753B\u5230\u521D\u59CB\u72B6\u6001\uFF0C\u6E05\u7A7A\u6240\u6709\u5185\u5BB9\r\n */\r\n reset(): AnimationEngine {\r\n // \u505C\u6B62\u5F53\u524D\u52A8\u753B\r\n this.stop()\r\n\r\n // \u6E05\u7A7A\u5E94\u7528\u5230\u5143\u7D20\u4E0A\u7684\u6240\u6709\u6837\u5F0F\r\n this.clearElementStyles()\r\n\r\n // \u91CD\u7F6E\u6240\u6709\u52A8\u753B\u72B6\u6001\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 // \u6E05\u7A7A\u52A8\u753B\u5C5E\u6027\u5217\u8868\r\n this.animationAttributes = []\r\n\r\n // \u91CD\u7F6E\u7F13\u52A8\u51FD\u6570\r\n this.currentEasingFunction = null\r\n\r\n // \u91CD\u7F6E\u56DE\u8C03\u51FD\u6570\r\n this.onComplete = () => { }\r\n this.onStart = () => { }\r\n this.onFrame = () => { }\r\n\r\n // \u6E05\u7406\u5E73\u53F0\u76F8\u5173\u7684\u52A8\u753B\u63A7\u5236\u5668\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 * \u83B7\u53D6\u5F53\u524D\u52A8\u753B\u8FDB\u5EA6\r\n */\r\n getProgress(): number {\r\n return this.currentProgress\r\n }\r\n\r\n /**\r\n * \u83B7\u53D6\u52A8\u753B\u662F\u5426\u6B63\u5728\u8FD0\u884C\r\n */\r\n isAnimating(): boolean {\r\n return this.isRunning\r\n }\r\n\r\n /**\r\n * \u83B7\u53D6\u5F53\u524D\u5FAA\u73AF\u6B21\u6570\r\n */\r\n getCurrentLoop(): number {\r\n return this.currentLoop\r\n }\r\n\r\n /**\r\n * \u6E05\u9664\u6240\u6709\u52A8\u753B\u5C5E\u6027\r\n */\r\n clearAttributes(): AnimationEngine {\r\n this.animationAttributes = []\r\n return this\r\n }\r\n\r\n /**\r\n * \u83B7\u53D6\u52A8\u753B\u5C5E\u6027\u6570\u91CF\r\n */\r\n getAttributeCount(): number {\r\n return this.animationAttributes.length\r\n }\r\n\r\n /**\r\n * \u6DE1\u5165\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6DE1\u51FA\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6ED1\u5165\u52A8\u753B(\u4ECE\u5DE6)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6ED1\u5165\u52A8\u753B(\u4ECE\u53F3)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6ED1\u5165\u52A8\u753B(\u4ECE\u4E0A)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6ED1\u5165\u52A8\u753B(\u4ECE\u4E0B)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u7F29\u653E\u52A8\u753B(\u653E\u5927)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u7F29\u653E\u52A8\u753B(\u7F29\u5C0F)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u65CB\u8F6C\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\r\n * @param degrees \u65CB\u8F6C\u89D2\u5EA6\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 * \u65CB\u8F6C\u9000\u51FA\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\r\n * @param degrees \u65CB\u8F6C\u89D2\u5EA6\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 * \u5F39\u8DF3\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6447\u6446\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u94FE\u5F0F\u52A8\u753B\uFF1A\u652F\u6301\u591A\u4E2A\u52A8\u753B\u4F9D\u6B21\u6267\u884C\r\n * @param animations \u52A8\u753B\u914D\u7F6E\u51FD\u6570\u6570\u7EC4\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 // \u6267\u884C\u7B2C\u4E00\u4E2A\u52A8\u753B\r\n const firstEngine = animations[0](new AnimationEngine(this.targetElement, {}))\r\n\r\n // \u5982\u679C\u53EA\u6709\u4E00\u4E2A\u52A8\u753B\uFF0C\u76F4\u63A5\u8FD4\u56DE\r\n if (animations.length == 1) {\r\n return firstEngine\r\n }\r\n\r\n // \u9012\u5F52\u8BBE\u7F6E\u540E\u7EED\u52A8\u753B\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 // \u6267\u884C\u4E0B\u4E00\u4E2A\u52A8\u753B\r\n const nextEngine = remainingAnimations[0](\r\n new AnimationEngine(self.targetElement, {}),\r\n )\r\n\r\n // \u5982\u679C\u8FD8\u6709\u66F4\u591A\u52A8\u753B\uFF0C\u7EE7\u7EED\u8BBE\u7F6E\u94FE\u5F0F\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 // \u8BBE\u7F6E\u52A8\u753B\u94FE\r\n setNextAnimation(firstEngine, animations.slice(1))\r\n\r\n return firstEngine\r\n }\r\n\r\n /**\r\n * \u6ED1\u51FA\u52A8\u753B(\u5411\u5DE6)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6ED1\u51FA\u52A8\u753B(\u5411\u53F3)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6ED1\u51FA\u52A8\u753B(\u5411\u4E0A)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6ED1\u51FA\u52A8\u753B(\u5411\u4E0B)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u7FFB\u8F6C\u52A8\u753B(\u6C34\u5E73)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u7FFB\u8F6C\u52A8\u753B(\u5782\u76F4)\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u5F39\u6027\u8FDB\u5165\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u5F39\u6027\u9000\u51FA\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u56DE\u5F39\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6446\u52A8\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6296\u52A8\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6EDA\u52A8\u8FDB\u5165\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6EDA\u52A8\u9000\u51FA\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u706F\u5149\u6548\u679C\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6D6E\u52A8\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u547C\u5438\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u53D1\u5149\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u8FDB\u5EA6\u6761\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\r\n * @param progress \u8FDB\u5EA6\u767E\u5206\u6BD4 (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 * \u6A21\u6001\u6846\u8FDB\u5165\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6A21\u6001\u6846\u9000\u51FA\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u5361\u7247\u7FFB\u8F6C\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u6CE2\u7EB9\u6269\u6563\u52A8\u753B\r\n * @param duration \u6301\u7EED\u65F6\u95F4\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 * \u521B\u5EFA\u52A8\u753B\u5B9E\u4F8B\r\n * @param element \u76EE\u6807\u5143\u7D20\r\n * @param options \u52A8\u753B\u9009\u9879\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",
|
|
785
|
+
"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",
|
|
786
|
+
"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",
|
|
787
|
+
"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 // \u4FEE\u590D iOS/Safari \u7684 'YYYY-MM-DD HH:mm:ss' \u683C\u5F0F\u517C\u5BB9\u6027\u95EE\u9898\r\n // iOS \u53EA\u652F\u6301 'YYYY/MM/DD' \u7B49\u4F7F\u7528\u659C\u6760\u7684\u683C\u5F0F\uFF0C\u6240\u4EE5\u5982\u679C\u5305\u542B '-' \u5219\u66FF\u6362\u4E3A '/' (\u4EC5\u65E5\u671F\u90E8\u5206\u7684 '-')\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 * \u683C\u5F0F\u5316\u65E5\u671F\r\n * @param template \u683C\u5F0F\u6A21\u677F\uFF0C\u652F\u6301 YYYY-MM-DD HH:mm:ss \u7B49\r\n */\r\n format(template: string): string {\r\n // \u4F7F\u7528\u4F20\u5165\u7684\u6A21\u677F\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 // \u4F7F\u7528\u6570\u7EC4\u6765\u4F9D\u6B21\u66FF\u6362\uFF0C\u907F\u514DUTS\u7684replace\u65B9\u6CD5\u517C\u5BB9\u6027\u95EE\u9898\r\n let result: string = actualTemplate\r\n\r\n // \u6309\u7167\u957F\u5EA6\u4ECE\u957F\u5230\u77ED\u66FF\u6362\uFF0C\u907F\u514D\u51B2\u7A81\r\n // \u66FF\u6362\u5E74\u4EFD (YYYY \u5FC5\u987B\u5728 YY \u4E4B\u524D)\r\n result = result.replace('YYYY', year.toString())\r\n result = result.replace('YY', year.toString().slice(-2))\r\n\r\n // \u66FF\u6362\u6708\u4EFD (MM \u5FC5\u987B\u5728 M \u4E4B\u524D)\r\n result = result.replace('MM', month.toString().padStart(2, '0'))\r\n result = result.replace('M', month.toString())\r\n\r\n // \u66FF\u6362\u65E5\u671F (DD \u5FC5\u987B\u5728 D \u4E4B\u524D)\r\n result = result.replace('DD', date.toString().padStart(2, '0'))\r\n result = result.replace('D', date.toString())\r\n\r\n // \u66FF\u6362\u5C0F\u65F6 (HH \u5FC5\u987B\u5728 H \u4E4B\u524D)\r\n result = result.replace('HH', hours.toString().padStart(2, '0'))\r\n result = result.replace('H', hours.toString())\r\n\r\n // \u66FF\u6362\u5206\u949F (mm \u5FC5\u987B\u5728 m \u4E4B\u524D)\r\n result = result.replace('mm', minutes.toString().padStart(2, '0'))\r\n result = result.replace('m', minutes.toString())\r\n\r\n // \u66FF\u6362\u79D2\u6570 (ss \u5FC5\u987B\u5728 s \u4E4B\u524D)\r\n result = result.replace('ss', seconds.toString().padStart(2, '0'))\r\n result = result.replace('s', seconds.toString())\r\n\r\n // \u66FF\u6362\u6BEB\u79D2\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 * \u672C\u6708\u591A\u5C11\u5929\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 * \u662F\u5426\u4E3A\u95F0\u5E74\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 * \u661F\u671F\u51E0\r\n */\r\n getDay(): number {\r\n return this._date.getDay()\r\n }\r\n\r\n /**\r\n * \u83B7\u53D6\u67D0\u4E2A\u5355\u4F4D\u7684\u5F00\u59CB\u65F6\u95F4\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 * \u83B7\u53D6\u67D0\u4E2A\u5355\u4F4D\u7684\u7ED3\u675F\u65F6\u95F4\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 * \u5224\u65AD\u662F\u5426\u65E9\u4E8E\u53E6\u4E00\u4E2A\u65E5\u671F\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 * \u5224\u65AD\u662F\u5426\u665A\u4E8E\u53E6\u4E00\u4E2A\u65E5\u671F\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 * \u5224\u65AD\u662F\u5426\u4E0E\u53E6\u4E00\u4E2A\u65E5\u671F\u76F8\u540C\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 * \u8BA1\u7B97\u4E0E\u53E6\u4E00\u4E2A\u65E5\u671F\u7684\u5DEE\u503C\uFF08\u6BEB\u79D2\uFF09\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 * \u8BA1\u7B97\u4E0E\u53E6\u4E00\u4E2A\u65E5\u671F\u7684\u5DEE\u503C\uFF08\u6307\u5B9A\u5355\u4F4D\uFF09\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 * \u6DFB\u52A0\u65F6\u95F4\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 * \u51CF\u5C11\u65F6\u95F4\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 * \u83B7\u53D6\u65F6\u95F4\u6233\r\n */\r\n valueOf(): number {\r\n return this._date.getTime()\r\n }\r\n\r\n /**\r\n * \u83B7\u53D6\u539F\u751FDate\u5BF9\u8C61\r\n */\r\n toDate(): Date {\r\n return new Date(this._date.getTime())\r\n }\r\n\r\n /**\r\n * \u83B7\u53D6\u65E5\u671F\u6570\u7EC4\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 * \u79C1\u6709\u65B9\u6CD5\uFF1A\u89E3\u6790\u4E0D\u540C\u7C7B\u578B\u7684\u65E5\u671F\u53C2\u6570\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 // \u5982\u679C\u90FD\u4E0D\u5339\u914D\uFF0C\u8FD4\u56DE\u5F53\u524D\u65F6\u95F4\r\n return new Date()\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * \u521B\u5EFA DayUts \u5B9E\u4F8B\r\n */\r\nexport function dayUts(date: Date | string | number | null = new Date()): DayUts {\r\n return new DayUts(date)\r\n}\r\n",
|
|
788
|
+
"lib/device.ts": "/**\r\n * \u7CFB\u7EDF\u4FE1\u606F\u63A5\u53E3\uFF0C\u5305\u542B\u9879\u76EE\u4E2D\u5B9E\u9645\u4F7F\u7528\u7684\u5B57\u6BB5\r\n */\r\nexport interface SystemInfo {\r\n /** \u7A97\u53E3\u5BBD\u5EA6 */\r\n windowWidth: number\r\n /** \u7A97\u53E3\u9AD8\u5EA6 */\r\n windowHeight: number\r\n /** \u7A97\u53E3\u9876\u90E8\u4F4D\u7F6E */\r\n windowTop: number\r\n /** \u8BBE\u5907\u50CF\u7D20\u6BD4 */\r\n pixelRatio: number\r\n /** \u5E73\u53F0\u4FE1\u606F */\r\n platform: string\r\n /** \u4E3B\u9898\u6A21\u5F0F */\r\n theme?: string\r\n /** \u72B6\u6001\u680F\u9AD8\u5EA6 */\r\n statusBarHeight?: number\r\n /** \u5B89\u5168\u533A\u57DF\u4FE1\u606F */\r\n safeArea?: UniApp.SafeArea\r\n /** \u5C4F\u5E55\u9AD8\u5EA6 */\r\n screenHeight: number\r\n /** \u5B89\u5168\u533A\u57DF\u63D2\u5165\u4FE1\u606F */\r\n safeAreaInsets?: UniApp.SafeAreaInsets\r\n // \u672A\u5C3D\u5B57\u6BB5\r\n [key: string]: any\r\n}\r\n\r\n/**\r\n * \u68C0\u67E5\u662F\u5426\u4E3A\u5C0F\u7A0B\u5E8F\u73AF\u5883\r\n * @returns \u662F\u5426\u4E3A\u5C0F\u7A0B\u5E8F\u73AF\u5883\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 * \u68C0\u67E5\u662F\u5426\u4E3AApp\u73AF\u5883\r\n * @returns \u662F\u5426\u4E3AApp\u73AF\u5883\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 * \u68C0\u67E5\u662F\u5426\u4E3AApp-IOS\u73AF\u5883\r\n * @returns \u662F\u5426\u4E3AApp-IOS\u73AF\u5883\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 * \u68C0\u67E5\u662F\u5426\u4E3AApp-Android\u73AF\u5883\r\n * @returns \u662F\u5426\u4E3AApp-Android\u73AF\u5883\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 * \u68C0\u67E5\u662F\u5426\u4E3AH5\u73AF\u5883\r\n * @returns \u662F\u5426\u4E3AH5\u73AF\u5883\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 * \u68C0\u67E5\u662F\u5426\u4E3A\u9E3F\u8499\u73AF\u5883\r\n * @returns \u662F\u5426\u4E3A\u9E3F\u8499\u73AF\u5883\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 // \u5982\u679C appTheme \u4E3A auto\uFF0C\u5219\u8DDF\u968F\u7CFB\u7EDF\u4E3B\u9898\uFF0C\u5426\u5219\u4F7F\u7528 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 // \u5982\u679C\u6709 hostTheme\uFF0C\u5219\u4F7F\u7528 hostTheme\r\n value = hostTheme\r\n }\r\n else {\r\n // \u9ED8\u8BA4\u4F7F\u7528 light \u4E3B\u9898\r\n value = 'light'\r\n }\r\n // #endif\r\n return value\r\n}\r\n\r\n/**\r\n * \u83B7\u53D6\u5B89\u5168\u533A\u57DF\u9AD8\u5EA6\r\n * @param type \u7C7B\u578B\r\n * @returns \u5B89\u5168\u533A\u57DF\u9AD8\u5EA6\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 * \u517C\u5BB9\u5FAE\u4FE1\u5C0F\u7A0B\u5E8F\u7AEF\u83B7\u53D6\u7CFB\u7EDF\u4FE1\u606F\u7684\u65B9\u6CD5\r\n * \u5728\u5FAE\u4FE1\u5C0F\u7A0B\u5E8F\u7AEF\u4F7F\u7528\u65B0\u7684API\u66FF\u4EE3getSystemInfoSync\uFF0C\u5728\u5176\u4ED6\u7AEF\u4ECD\u7136\u4F7F\u7528getSystemInfoSync\r\n * @returns \u7CFB\u7EDF\u4FE1\u606F\u5BF9\u8C61\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() // \u6682\u65F6\u4E0D\u9700\u8981\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('\u83B7\u53D6\u7CFB\u7EDF\u4FE1\u606F\u5931\u8D25\uFF0C\u964D\u7EA7\u4F7F\u7528uni.getSystemInfoSync:', error)\r\n // \u964D\u7EA7\u5904\u7406\uFF0C\u4F7F\u7528\u539F\u6765\u7684\u65B9\u6CD5\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}",
|
|
789
|
+
"lib/file.ts": 'export function uuid(): string {\r\n let uuid = "";\r\n let i: number;\r\n let random: number;\r\n\r\n for (i = 0; i < 36; i++) {\r\n if (i == 8 || i == 13 || i == 18 || i == 23) {\r\n uuid += "-";\r\n } else if (i == 14) {\r\n uuid += "4";\r\n } else if (i == 19) {\r\n random = (Math.random() * 16) | 0;\r\n uuid += ((random & 0x3) | 0x8).toString(16);\r\n } else {\r\n random = (Math.random() * 16) | 0;\r\n uuid += random.toString(16);\r\n }\r\n }\r\n return uuid;\r\n}\r\n\r\n\r\nexport function base64ToBlob(data: string, type: string = "image/jpeg"): Blob {\r\n // #ifdef H5\r\n let bytes = window.atob(data.split(",")[1]);\r\n let ab = new ArrayBuffer(bytes.length);\r\n let ia = new Uint8Array(ab);\r\n for (let i = 0; i < bytes.length; i++) {\r\n ia[i] = bytes.charCodeAt(i);\r\n }\r\n return new Blob([ab], { type });\r\n // #endif\r\n}\r\n\r\n/**\r\n * \u5C06canvas\u8F6C\u6362\u4E3Apng\u56FE\u7247\r\n * @param options \u8F6C\u6362\u53C2\u6570\r\n * @returns \u56FE\u7247\u8DEF\u5F84\r\n */\r\nexport function canvasToPng(canvasRef: any): Promise<string> {\r\n return new Promise((resolve) => {\r\n // #ifdef APP\r\n canvasRef.parentElement!.takeSnapshot({\r\n success(res: any) {\r\n resolve(res.tempFilePath);\r\n },\r\n fail(err: any) {\r\n console.error(err);\r\n resolve("");\r\n }\r\n });\r\n // #endif\r\n\r\n // #ifdef H5\r\n const url = URL.createObjectURL(\r\n base64ToBlob(\r\n (canvasRef as unknown as HTMLCanvasElement)?.toDataURL("image/png", 1) ?? ""\r\n )\r\n );\r\n\r\n resolve(url);\r\n // #endif\r\n\r\n // #ifdef MP\r\n uni.createCanvasContextAsync({\r\n id: canvasRef.id,\r\n component: canvasRef.$vm,\r\n success(context: any) {\r\n // \u83B7\u53D62D\u7ED8\u56FE\u4E0A\u4E0B\u6587\r\n const ctx = context.getContext("2d")!;\r\n\r\n // \u83B7\u53D6canvas\u5BF9\u8C61\r\n const canvas = ctx.canvas;\r\n\r\n // \u5C06canvas\u8F6C\u6362\u4E3Abase64\u683C\u5F0F\u7684PNG\u56FE\u7247\u6570\u636E\r\n const data = canvas.toDataURL("image/png", 1);\r\n\r\n // \u83B7\u53D6\u6587\u4EF6\u7CFB\u7EDF\u7BA1\u7406\u5668\r\n const fileMg = uni.getFileSystemManager();\r\n\r\n // \u751F\u6210\u4E34\u65F6\u6587\u4EF6\u8DEF\u5F84\r\n // @ts-ignore\r\n const filepath = `${wx.env.USER_DATA_PATH}/${uuid()}.png`;\r\n\r\n // \u5C06base64\u6570\u636E\u5199\u5165\u6587\u4EF6\r\n fileMg.writeFile({\r\n filePath: filepath,\r\n data: data.split(",")[1],\r\n encoding: "base64",\r\n success() {\r\n resolve(filepath);\r\n },\r\n fail(err) {\r\n console.error(err);\r\n resolve("");\r\n }\r\n });\r\n },\r\n fail(err: any) {\r\n console.error(err);\r\n resolve("");\r\n }\r\n });\r\n // #endif\r\n });\r\n}\r\n',
|
|
790
|
+
"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",
|
|
791
|
+
"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",
|
|
792
|
+
"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}",
|
|
793
|
+
"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// \u5C0F\u7A0B\u5E8F\u7AEF\u4E0D\u652F\u6301\u4ECEvue\u5BFC\u51FA\u7684isVNode\u65B9\u6CD5\uFF0C\u53C2\u8003uni-mp-vue\u7684\u5B9E\u73B0\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",
|
|
794
|
+
"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",
|
|
795
|
+
"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",
|
|
796
|
+
"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"
|
|
855
797
|
}
|
|
856
798
|
};
|
|
857
799
|
|
|
@@ -1099,7 +1041,7 @@ function initCommand() {
|
|
|
1099
1041
|
// package.json
|
|
1100
1042
|
var package_default = {
|
|
1101
1043
|
name: "reborn-ui",
|
|
1102
|
-
version: "0.1.
|
|
1044
|
+
version: "0.1.78",
|
|
1103
1045
|
description: "A CLI for Reborn UI",
|
|
1104
1046
|
author: "1997liuyh-boop",
|
|
1105
1047
|
license: "MIT",
|