@fast-china/utils 2.1.4 → 2.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +14 -4
  3. package/README.zh.md +14 -4
  4. package/dist/array/index.d.mts +8 -0
  5. package/dist/array/index.mjs +15 -1
  6. package/dist/array/index.mjs.map +1 -1
  7. package/dist/async/index.mjs.map +1 -1
  8. package/dist/color/index.mjs.map +1 -1
  9. package/dist/date/index.mjs.map +1 -1
  10. package/dist/function/index.d.mts +13 -0
  11. package/dist/function/index.mjs +38 -0
  12. package/dist/function/index.mjs.map +1 -0
  13. package/dist/index.d.mts +10 -3
  14. package/dist/index.global.min.js +2 -2
  15. package/dist/index.global.min.js.map +1 -1
  16. package/dist/index.mjs +10 -3
  17. package/dist/internal/runtime.mjs.map +1 -1
  18. package/dist/internal/text.mjs.map +1 -1
  19. package/dist/logger/index.mjs +4 -6
  20. package/dist/logger/index.mjs.map +1 -1
  21. package/dist/number/index.mjs.map +1 -1
  22. package/dist/object/index.d.mts +41 -2
  23. package/dist/object/index.mjs +258 -14
  24. package/dist/object/index.mjs.map +1 -1
  25. package/dist/storage/index.mjs.map +1 -1
  26. package/dist/string/index.mjs.map +1 -1
  27. package/dist/vue/breakpoints.d.mts +21 -0
  28. package/dist/vue/breakpoints.mjs +46 -0
  29. package/dist/vue/breakpoints.mjs.map +1 -0
  30. package/dist/vue/element-size.d.mts +25 -0
  31. package/dist/vue/element-size.mjs +33 -0
  32. package/dist/vue/element-size.mjs.map +1 -0
  33. package/dist/vue/emits.mjs.map +1 -1
  34. package/dist/vue/event-listener.d.mts +16 -0
  35. package/dist/vue/event-listener.mjs +30 -0
  36. package/dist/vue/event-listener.mjs.map +1 -0
  37. package/dist/vue/index.d.mts +7 -1
  38. package/dist/vue/install.mjs.map +1 -1
  39. package/dist/vue/now.d.mts +13 -0
  40. package/dist/vue/now.mjs +29 -0
  41. package/dist/vue/now.mjs.map +1 -0
  42. package/dist/vue/render.mjs.map +1 -1
  43. package/dist/vue/resize-observer.d.mts +15 -0
  44. package/dist/vue/resize-observer.mjs +31 -0
  45. package/dist/vue/resize-observer.mjs.map +1 -0
  46. package/dist/vue/window-size.d.mts +16 -0
  47. package/dist/vue/window-size.mjs +32 -0
  48. package/dist/vue/window-size.mjs.map +1 -0
  49. package/docs/API.md +4 -3
  50. package/docs/API.zh-CN.md +4 -3
  51. package/docs/RUNTIME_CONTRACT.md +4 -2
  52. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"install.mjs","names":[],"sources":["../../src/vue/install.ts"],"sourcesContent":["import type { App } from \"vue\";\n\n/** Vue 组件对象、函数组件或指令对象可接受的最小结构类型。 */\nexport type VueInstallValue = object | ((...arguments_: never[]) => unknown);\n\n/** 为 Vue 组件或指令附加供 Vue 3 `app.use()` 调用的安装能力。 */\nexport type Installable<Value> = Value & {\n\t/**\n\t * 把当前组件或指令安装到 Vue 3 App。\n\t * @param app - Vue 3 App 实例。\n\t */\n\tinstall: (app: App) => void;\n};\n\n/** TSX 组件安装类型;与 {@link Installable} 保持同一运行时契约。 */\nexport type TSXWithInstall<Value> = Installable<Value>;\n\n/** 组件、指令注册所需的 Vue 3 App 能力。 */\ninterface VueAppRegistrationTarget {\n\t/**\n\t * 读取或注册全局组件。\n\t *\n\t * @param name - 全局组件名。\n\t * @param component - 注册时传入的组件;省略时读取现有组件。\n\t * @returns Vue App 返回的现有组件、注册结果或 App 自身。\n\t */\n\tcomponent: (name: string, component?: unknown) => unknown;\n\t/**\n\t * 读取或注册全局指令。\n\t *\n\t * @param name - 不带 `v-` 的全局指令名。\n\t * @param directive - 注册时传入的指令;省略时读取现有指令。\n\t * @returns Vue App 返回的现有指令、注册结果或 App 自身。\n\t */\n\tdirective: (name: string, directive?: unknown) => unknown;\n}\n\n/**\n * 校验 Vue 3 插件安装目标。\n *\n * @param value - Vue 3 App 实例。\n * @returns 只包含组件和指令注册能力的 App。\n * @throws `TypeError` 当目标不是对象或缺少 `component`、`directive` 方法。\n */\nconst assertApp = (value: unknown): VueAppRegistrationTarget => {\n\tif (typeof value !== \"object\" || value === null) {\n\t\tthrow new TypeError(\"安装 Vue 插件需要 Vue 3 App 实例。\");\n\t}\n\tconst app = value as unknown as Partial<VueAppRegistrationTarget>;\n\tif (typeof app.component !== \"function\" || typeof app.directive !== \"function\") {\n\t\tthrow new TypeError(\"安装 Vue 插件需要 `component()` 和 `directive()` 注册方法。\");\n\t}\n\treturn app as VueAppRegistrationTarget;\n};\n\n/**\n * 提取组件的全局注册名称。\n *\n * @param component - 待注册组件。\n * @returns 经过校验的显式名称。\n * @throws `TypeError` 当组件没有非空字符串名称,或名称包含空白。\n */\nconst getComponentName = (component: VueInstallValue): string => {\n\tconst name = (component as { name?: unknown }).name;\n\tif (typeof name !== \"string\" || name.length === 0 || /\\s/u.test(name)) {\n\t\tthrow new TypeError(\"可安装的 Vue 组件必须公开不含空白的非空名称。\");\n\t}\n\treturn name;\n};\n\n/** 预检完成、可以无失败注册的组件动作。 */\ninterface ComponentRegistration {\n\t/** 已校验的组件引用。 */\n\tcomponent: VueInstallValue;\n\t/** 已校验的组件名称。 */\n\tname: string;\n\t/** 目标中是否已经注册了完全相同的组件引用。 */\n\tregistered: boolean;\n}\n\n/**\n * 预检单个组件注册。\n *\n * @remarks 先读取同名组件并完成冲突判断,再返回延迟执行动作;调用方可以在所有组件预检通过后统一提交。\n * @param app - 已校验的 Vue 3 App 注册目标。\n * @param component - 待注册组件。\n * @returns 已校验的组件引用、名称和目标中是否已经存在同一引用。\n * @throws `Error` 当同名位置已由其他组件占用。\n */\nconst prepareComponentRegistration = (app: VueAppRegistrationTarget, component: VueInstallValue): ComponentRegistration => {\n\tconst name = getComponentName(component);\n\tconst existing = app.component(name);\n\tif (existing !== undefined && existing !== component) {\n\t\tthrow new Error(`Vue 组件名称“${name}”已被其他组件注册。`);\n\t}\n\treturn { component, name, registered: existing === component };\n};\n\n/**\n * 为主组件附加 Vue 3 `app.use()` 安装能力。\n *\n * @remarks 函数会直接为 `main` 定义附属组件属性和 `install`。所有组件名称、附属属性\n * 冲突会在修改 `main` 前完成校验;安装到 App 时也会先预检全部全局名称,再统一注册。\n * @param main - 具有非空 `name` 的组件。\n * @param extras - 同时注册并以可枚举属性挂到主组件的附属组件映射。\n * @returns 原始 `main` 引用,并附加类型化的 `install` 与 `extras` 属性。\n * @throws `TypeError` 当组件缺少合法名称、已有 `install`、附属键或名称发生冲突。\n * @throws `Error` 当 App 中同名位置已经注册其他组件。\n */\n// eslint-disable-next-line @typescript-eslint/no-generated-empty-object-type -- 空 Record 是无附属组件时精确且已发布的默认返回契约。\nexport function withInstall<Main extends VueInstallValue, Extras extends Record<string, VueInstallValue> = Record<never, never>>(\n\tmain: Main,\n\textras?: Extras\n): Installable<Main> & Extras {\n\tconst componentNames = new Set([getComponentName(main)]);\n\tif (\"install\" in Object(main)) throw new TypeError(\"Vue 组件已定义 `install` 属性。\");\n\tconst extraEntries = Object.entries(extras ?? {});\n\tif (extras !== undefined && Object.getOwnPropertySymbols(extras).some((key) => Object.prototype.propertyIsEnumerable.call(extras, key))) {\n\t\tthrow new TypeError(\"Vue 组件附属项必须使用字符串属性名。\");\n\t}\n\tfor (const [key, component] of extraEntries) {\n\t\tconst componentName = getComponentName(component);\n\t\tif (componentNames.has(componentName)) throw new TypeError(`Vue 组件名称“${componentName}”被重复注册。`);\n\t\tcomponentNames.add(componentName);\n\t\tif (key === \"install\" || key in Object(main)) {\n\t\t\tthrow new TypeError(`Vue 组件附属项“${key}”会覆盖主组件上的属性。`);\n\t\t}\n\t}\n\tconst installable = main as Installable<Main> & Extras;\n\tfor (const [key, component] of extraEntries) {\n\t\tObject.defineProperty(installable, key, { configurable: true, enumerable: true, value: component, writable: true });\n\t}\n\tinstallable.install = (value: App): void => {\n\t\tconst app = assertApp(value);\n\t\t// 先完成全部冲突检查,再统一注册,避免安装到一半留下部分全局组件。\n\t\tconst registrations = [main, ...extraEntries.map(([, component]) => component)].map((component) =>\n\t\t\tprepareComponentRegistration(app, component)\n\t\t);\n\t\tfor (const registration of registrations) {\n\t\t\tif (!registration.registered) app.component(registration.name, registration.component);\n\t\t}\n\t};\n\treturn installable;\n}\n\n/**\n * 为不需要单独注册的附属组件附加空安装函数。\n *\n * @remarks 适用于只能作为主组件附属属性使用、但仍需满足 Vue Plugin 类型的组件。\n * 函数直接修改并返回传入组件,不会向 Vue 3 App 注册内容。\n * @param component - 尚未定义或继承 `install` 属性的组件。\n * @returns 原组件引用及无副作用的 `install` 方法。\n * @throws `TypeError` 当组件自身或原型链已经存在 `install`。\n */\nexport function withNoopInstall<Value extends VueInstallValue>(component: Value): TSXWithInstall<Value> {\n\tif (\"install\" in Object(component)) throw new TypeError(\"Vue 组件已定义 `install` 属性。\");\n\tconst installable = component as TSXWithInstall<Value>;\n\tinstallable.install = (): void => undefined;\n\treturn installable;\n}\n\n/**\n * 为 Vue 3 指令附加插件安装能力。\n *\n * @remarks 函数直接修改并返回指令。安装时重复注册同一引用保持幂等,不会覆盖同名的\n * 其他指令。名称只传给 `directive()`,不得包含 `v-` 前缀。\n * @param directive - 尚未定义或继承 `install` 属性的 Vue 指令对象。\n * @param name - 非空、无空白且不以 `v-` 开头的全局指令名。\n * @returns 原指令引用及 Vue Plugin `install` 方法。\n * @throws `TypeError` 当名称非法、指令已有 `install`,或安装目标无效。\n * @throws `Error` 当 App 中同名位置已经注册其他指令。\n */\nexport function withInstallDirective<Value extends VueInstallValue>(directive: Value, name: string): Installable<Value> {\n\tif (name.length === 0 || /\\s/u.test(name) || name.startsWith(\"v-\")) {\n\t\tthrow new TypeError(\"可安装的 Vue 指令名称不能包含空白或 `v-` 前缀。\");\n\t}\n\tif (\"install\" in Object(directive)) throw new TypeError(\"Vue 指令已定义 `install` 属性。\");\n\tconst installable = directive as Installable<Value>;\n\tinstallable.install = (value: App): void => {\n\t\tconst app = assertApp(value);\n\t\tconst existing = app.directive(name);\n\t\tif (existing !== undefined && existing !== directive) {\n\t\t\tthrow new Error(`Vue 指令名称“${name}”已被其他指令注册。`);\n\t\t}\n\t\tif (existing !== directive) app.directive(name, directive);\n\t};\n\treturn installable;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"install.mjs","names":[],"sources":["../../src/vue/install.ts"],"sourcesContent":["import type { App } from \"vue\";\n\n/** Vue 组件对象、函数组件或指令对象可接受的最小结构类型。 */\nexport type VueInstallValue = object | ((...arguments_: never[]) => unknown);\n\n/** 为 Vue 组件或指令附加供 Vue 3 `app.use()` 调用的安装能力。 */\nexport type Installable<Value> = Value & {\n\t/**\n\t * 把当前组件或指令安装到 Vue 3 App。\n\t * @param app - Vue 3 App 实例。\n\t */\n\tinstall: (app: App) => void;\n};\n\n/** TSX 组件安装类型;与 {@link Installable} 保持同一运行时契约。 */\nexport type TSXWithInstall<Value> = Installable<Value>;\n\n/** 组件、指令注册所需的 Vue 3 App 能力。 */\ninterface VueAppRegistrationTarget {\n\t/**\n\t * 读取或注册全局组件。\n\t *\n\t * @param name - 全局组件名。\n\t * @param component - 注册时传入的组件;省略时读取现有组件。\n\t * @returns Vue App 返回的现有组件、注册结果或 App 自身。\n\t */\n\tcomponent: (name: string, component?: unknown) => unknown;\n\t/**\n\t * 读取或注册全局指令。\n\t *\n\t * @param name - 不带 `v-` 的全局指令名。\n\t * @param directive - 注册时传入的指令;省略时读取现有指令。\n\t * @returns Vue App 返回的现有指令、注册结果或 App 自身。\n\t */\n\tdirective: (name: string, directive?: unknown) => unknown;\n}\n\n/**\n * 校验 Vue 3 插件安装目标。\n *\n * @param value - Vue 3 App 实例。\n * @returns 只包含组件和指令注册能力的 App。\n * @throws `TypeError` 当目标不是对象或缺少 `component`、`directive` 方法。\n */\nconst assertApp = (value: unknown): VueAppRegistrationTarget => {\n\tif (typeof value !== \"object\" || value === null) {\n\t\tthrow new TypeError(\"安装 Vue 插件需要 Vue 3 App 实例。\");\n\t}\n\tconst app = value as Partial<VueAppRegistrationTarget>;\n\tif (typeof app.component !== \"function\" || typeof app.directive !== \"function\") {\n\t\tthrow new TypeError(\"安装 Vue 插件需要 `component()` 和 `directive()` 注册方法。\");\n\t}\n\treturn app as VueAppRegistrationTarget;\n};\n\n/**\n * 提取组件的全局注册名称。\n *\n * @param component - 待注册组件。\n * @returns 经过校验的显式名称。\n * @throws `TypeError` 当组件没有非空字符串名称,或名称包含空白。\n */\nconst getComponentName = (component: VueInstallValue): string => {\n\tconst name = (component as { name?: unknown }).name;\n\tif (typeof name !== \"string\" || name.length === 0 || /\\s/u.test(name)) {\n\t\tthrow new TypeError(\"可安装的 Vue 组件必须公开不含空白的非空名称。\");\n\t}\n\treturn name;\n};\n\n/**\n * 预检单个组件注册。\n *\n * @remarks 先读取同名组件并完成冲突判断,再返回延迟执行动作;调用方可以在所有组件预检通过后统一提交。\n * @param app - 已校验的 Vue 3 App 注册目标。\n * @param component - 待注册组件。\n * @returns 已校验的组件引用、名称和目标中是否已经存在同一引用。\n * @throws `Error` 当同名位置已由其他组件占用。\n */\nconst prepareComponentRegistration = (app: VueAppRegistrationTarget, component: VueInstallValue) => {\n\tconst name = getComponentName(component);\n\tconst existing = app.component(name);\n\tif (existing !== undefined && existing !== component) {\n\t\tthrow new Error(`Vue 组件名称“${name}”已被其他组件注册。`);\n\t}\n\treturn { component, name, registered: existing === component };\n};\n\n/**\n * 为主组件附加 Vue 3 `app.use()` 安装能力。\n *\n * @remarks 函数会直接为 `main` 定义附属组件属性和 `install`。所有组件名称、附属属性\n * 冲突会在修改 `main` 前完成校验;安装到 App 时也会先预检全部全局名称,再统一注册。\n * @param main - 具有非空 `name` 的组件。\n * @param extras - 同时注册并以可枚举属性挂到主组件的附属组件映射。\n * @returns 原始 `main` 引用,并附加类型化的 `install` 与 `extras` 属性。\n * @throws `TypeError` 当组件缺少合法名称、已有 `install`、附属键或名称发生冲突。\n * @throws `Error` 当 App 中同名位置已经注册其他组件。\n */\nexport function withInstall<Main extends VueInstallValue, Extras extends Record<string, VueInstallValue> = Record<never, never>>(\n\tmain: Main,\n\textras?: Extras\n): Installable<Main> & Extras {\n\tconst componentNames = new Set([getComponentName(main)]);\n\tif (\"install\" in Object(main)) throw new TypeError(\"Vue 组件已定义 `install` 属性。\");\n\tconst extraEntries = Object.entries(extras ?? {});\n\tif (extras !== undefined && Object.getOwnPropertySymbols(extras).some((key) => Object.prototype.propertyIsEnumerable.call(extras, key))) {\n\t\tthrow new TypeError(\"Vue 组件附属项必须使用字符串属性名。\");\n\t}\n\tfor (const [key, component] of extraEntries) {\n\t\tconst componentName = getComponentName(component);\n\t\tif (componentNames.has(componentName)) throw new TypeError(`Vue 组件名称“${componentName}”被重复注册。`);\n\t\tcomponentNames.add(componentName);\n\t\tif (key === \"install\" || key in Object(main)) {\n\t\t\tthrow new TypeError(`Vue 组件附属项“${key}”会覆盖主组件上的属性。`);\n\t\t}\n\t}\n\tconst installable = main as Installable<Main> & Extras;\n\tfor (const [key, component] of extraEntries) {\n\t\tObject.defineProperty(installable, key, { configurable: true, enumerable: true, value: component, writable: true });\n\t}\n\tinstallable.install = (value: App) => {\n\t\tconst app = assertApp(value);\n\t\t// 先完成全部冲突检查,再统一注册,避免安装到一半留下部分全局组件。\n\t\tconst registrations = [main, ...extraEntries.map(([, component]) => component)].map((component) =>\n\t\t\tprepareComponentRegistration(app, component)\n\t\t);\n\t\tfor (const registration of registrations) {\n\t\t\tif (!registration.registered) app.component(registration.name, registration.component);\n\t\t}\n\t};\n\treturn installable;\n}\n\n/**\n * 为不需要单独注册的附属组件附加空安装函数。\n *\n * @remarks 适用于只能作为主组件附属属性使用、但仍需满足 Vue Plugin 类型的组件。\n * 函数直接修改并返回传入组件,不会向 Vue 3 App 注册内容。\n * @param component - 尚未定义或继承 `install` 属性的组件。\n * @returns 原组件引用及无副作用的 `install` 方法。\n * @throws `TypeError` 当组件自身或原型链已经存在 `install`。\n */\nexport function withNoopInstall<Value extends VueInstallValue>(component: Value): TSXWithInstall<Value> {\n\tif (\"install\" in Object(component)) throw new TypeError(\"Vue 组件已定义 `install` 属性。\");\n\tconst installable = component as TSXWithInstall<Value>;\n\tinstallable.install = () => undefined;\n\treturn installable;\n}\n\n/**\n * 为 Vue 3 指令附加插件安装能力。\n *\n * @remarks 函数直接修改并返回指令。安装时重复注册同一引用保持幂等,不会覆盖同名的\n * 其他指令。名称只传给 `directive()`,不得包含 `v-` 前缀。\n * @param directive - 尚未定义或继承 `install` 属性的 Vue 指令对象。\n * @param name - 非空、无空白且不以 `v-` 开头的全局指令名。\n * @returns 原指令引用及 Vue Plugin `install` 方法。\n * @throws `TypeError` 当名称非法、指令已有 `install`,或安装目标无效。\n * @throws `Error` 当 App 中同名位置已经注册其他指令。\n */\nexport function withInstallDirective<Value extends VueInstallValue>(directive: Value, name: string): Installable<Value> {\n\tif (name.length === 0 || /\\s/u.test(name) || name.startsWith(\"v-\")) {\n\t\tthrow new TypeError(\"可安装的 Vue 指令名称不能包含空白或 `v-` 前缀。\");\n\t}\n\tif (\"install\" in Object(directive)) throw new TypeError(\"Vue 指令已定义 `install` 属性。\");\n\tconst installable = directive as Installable<Value>;\n\tinstallable.install = (value: App) => {\n\t\tconst app = assertApp(value);\n\t\tconst existing = app.directive(name);\n\t\tif (existing !== undefined && existing !== directive) {\n\t\t\tthrow new Error(`Vue 指令名称“${name}”已被其他指令注册。`);\n\t\t}\n\t\tif (existing !== directive) app.directive(name, directive);\n\t};\n\treturn installable;\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { ShallowRef } from "vue";
2
+ //#region src/vue/now.d.ts
3
+ /**
4
+ * 按固定间隔提供响应式当前时间。
5
+ *
6
+ * @param intervalMilliseconds - 更新时间间隔,默认 `1000` 毫秒。
7
+ * @returns 当前 Date 的只读 ShallowRef;SSR 环境只返回调用时的时间。
8
+ * @throws `Error` 当浏览器或 uni-app 环境中不存在可用于自动清理的 Vue 响应式作用域。
9
+ * @throws `RangeError` 当间隔不是平台计时器支持的非负有限整数。
10
+ */
11
+ export declare function useNow(intervalMilliseconds?: number): Readonly<ShallowRef<Date>>;
12
+ //#endregion
13
+ //# sourceMappingURL=now.d.mts.map
@@ -0,0 +1,29 @@
1
+ import { runtimeGlobals } from "../internal/runtime.mjs";
2
+ import { getCurrentScope, onScopeDispose, readonly, shallowRef } from "vue";
3
+ //#region src/vue/now.ts
4
+ /**
5
+ * 按固定间隔提供响应式当前时间。
6
+ *
7
+ * @param intervalMilliseconds - 更新时间间隔,默认 `1000` 毫秒。
8
+ * @returns 当前 Date 的只读 ShallowRef;SSR 环境只返回调用时的时间。
9
+ * @throws `Error` 当浏览器或 uni-app 环境中不存在可用于自动清理的 Vue 响应式作用域。
10
+ * @throws `RangeError` 当间隔不是平台计时器支持的非负有限整数。
11
+ */
12
+ function useNow(intervalMilliseconds = 1e3) {
13
+ if (!Number.isInteger(intervalMilliseconds) || intervalMilliseconds < 0 || intervalMilliseconds > 2147483647) throw new RangeError("`intervalMilliseconds` 必须是 0 至 2,147,483,647 的整数。");
14
+ const now = shallowRef(/* @__PURE__ */ new Date());
15
+ if (runtimeGlobals.window !== void 0 || runtimeGlobals.uni !== void 0) {
16
+ if (getCurrentScope() === void 0) throw new Error("`useNow` 必须在 Vue 响应式作用域内调用。");
17
+ const timer = setInterval(() => {
18
+ now.value = /* @__PURE__ */ new Date();
19
+ }, intervalMilliseconds);
20
+ onScopeDispose(() => {
21
+ clearInterval(timer);
22
+ });
23
+ }
24
+ return readonly(now);
25
+ }
26
+ //#endregion
27
+ export { useNow };
28
+
29
+ //# sourceMappingURL=now.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"now.mjs","names":[],"sources":["../../src/vue/now.ts"],"sourcesContent":["import { getCurrentScope, onScopeDispose, readonly, shallowRef } from \"vue\";\nimport { runtimeGlobals } from \"../internal/runtime\";\nimport type { ShallowRef } from \"vue\";\n\n/**\n * 按固定间隔提供响应式当前时间。\n *\n * @param intervalMilliseconds - 更新时间间隔,默认 `1000` 毫秒。\n * @returns 当前 Date 的只读 ShallowRef;SSR 环境只返回调用时的时间。\n * @throws `Error` 当浏览器或 uni-app 环境中不存在可用于自动清理的 Vue 响应式作用域。\n * @throws `RangeError` 当间隔不是平台计时器支持的非负有限整数。\n */\nexport function useNow(intervalMilliseconds = 1000): Readonly<ShallowRef<Date>> {\n\tif (!Number.isInteger(intervalMilliseconds) || intervalMilliseconds < 0 || intervalMilliseconds > 2_147_483_647) {\n\t\tthrow new RangeError(\"`intervalMilliseconds` 必须是 0 至 2,147,483,647 的整数。\");\n\t}\n\tconst now = shallowRef(new Date());\n\tif (runtimeGlobals.window !== undefined || runtimeGlobals.uni !== undefined) {\n\t\tif (getCurrentScope() === undefined) throw new Error(\"`useNow` 必须在 Vue 响应式作用域内调用。\");\n\t\tconst timer = setInterval(() => {\n\t\t\tnow.value = new Date();\n\t\t}, intervalMilliseconds);\n\t\tonScopeDispose(() => {\n\t\t\tclearInterval(timer);\n\t\t});\n\t}\n\treturn readonly(now);\n}\n"],"mappings":";;;;;;;;;;;AAYA,SAAgB,OAAO,uBAAuB,KAAkC;CAC/E,IAAI,CAAC,OAAO,UAAU,oBAAoB,KAAK,uBAAuB,KAAK,uBAAuB,YACjG,MAAM,IAAI,WAAW,mDAAmD;CAEzE,MAAM,MAAM,2BAAW,IAAI,KAAK,CAAC;CACjC,IAAI,eAAe,WAAW,KAAA,KAAa,eAAe,QAAQ,KAAA,GAAW;EAC5E,IAAI,gBAAgB,MAAM,KAAA,GAAW,MAAM,IAAI,MAAM,6BAA6B;EAClF,MAAM,QAAQ,kBAAkB;GAC/B,IAAI,wBAAQ,IAAI,KAAK;EACtB,GAAG,oBAAoB;EACvB,qBAAqB;GACpB,cAAc,KAAK;EACpB,CAAC;CACF;CACA,OAAO,SAAS,GAAG;AACpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"render.mjs","names":[],"sources":["../../src/vue/render.ts"],"sourcesContent":["import { getCurrentInstance } from \"vue\";\nimport type { VNode } from \"vue\";\n\n/** `useRender` 需要写入的 Vue 3 内部组件实例字段。 */\ninterface MutableVueComponentInstance {\n\trender?: () => VNode;\n}\n\n/**\n * 在当前 Vue 3 组件实例上安装 TSX 渲染函数。\n * @remarks `setup` 仍可返回状态对象,因此状态能够显示在 Vue Devtools 中。\n * @param render - 当前组件的渲染函数。\n * @throws 不在组件 `setup` 调用栈中使用时抛出 `Error`。\n */\nexport function useRender(render: () => VNode): void {\n\tconst instance = getCurrentInstance();\n\tif (instance === null) throw new Error(\"`useRender` 必须在 `setup` 函数内部调用。\");\n\t(instance as unknown as MutableVueComponentInstance).render = render;\n}\n"],"mappings":";;;;;;;;AAcA,SAAgB,UAAU,QAA2B;CACpD,MAAM,WAAW,mBAAmB;CACpC,IAAI,aAAa,MAAM,MAAM,IAAI,MAAM,iCAAiC;CACxE,SAAqD,SAAS;AAC/D"}
1
+ {"version":3,"file":"render.mjs","names":[],"sources":["../../src/vue/render.ts"],"sourcesContent":["import { getCurrentInstance } from \"vue\";\nimport type { VNode } from \"vue\";\n\n/** `useRender` 需要写入的 Vue 3 内部组件实例字段。 */\ninterface MutableVueComponentInstance {\n\trender?: () => VNode;\n}\n\n/**\n * 在当前 Vue 3 组件实例上安装 TSX 渲染函数。\n * @remarks `setup` 仍可返回状态对象,因此状态能够显示在 Vue Devtools 中。\n * @param render - 当前组件的渲染函数。\n * @throws 不在组件 `setup` 调用栈中使用时抛出 `Error`。\n */\nexport function useRender(render: () => VNode): void {\n\tconst instance = getCurrentInstance();\n\tif (instance === null) throw new Error(\"`useRender` 必须在 `setup` 函数内部调用。\");\n\t(instance as MutableVueComponentInstance).render = render;\n}\n"],"mappings":";;;;;;;;AAcA,SAAgB,UAAU,QAA2B;CACpD,MAAM,WAAW,mBAAmB;CACpC,IAAI,aAAa,MAAM,MAAM,IAAI,MAAM,iCAAiC;CACxE,SAA0C,SAAS;AACpD"}
@@ -0,0 +1,15 @@
1
+ import { MaybeRefOrGetter } from "vue";
2
+ //#region src/vue/resize-observer.d.ts
3
+ /** `useResizeObserver` 接受的元素或响应式元素。 */
4
+ export type ResizeObserverTarget = MaybeRefOrGetter<Element | null | undefined>;
5
+ /**
6
+ * 监听元素尺寸变化,并随响应式目标切换和 Vue 作用域销毁自动断开。
7
+ *
8
+ * @param target - 原生元素、Ref 或 Getter。
9
+ * @param callback - 原生 ResizeObserver 回调。
10
+ * @param options - 原生元素观察选项。
11
+ * @returns 可提前断开观察的停止函数;运行时不支持 ResizeObserver 时为空操作。
12
+ */
13
+ export declare function useResizeObserver(target: ResizeObserverTarget, callback: ResizeObserverCallback, options?: ResizeObserverOptions): () => void;
14
+ //#endregion
15
+ //# sourceMappingURL=resize-observer.d.mts.map
@@ -0,0 +1,31 @@
1
+ import { runtimeGlobals } from "../internal/runtime.mjs";
2
+ import { onScopeDispose, toValue, watch } from "vue";
3
+ //#region src/vue/resize-observer.ts
4
+ /**
5
+ * 监听元素尺寸变化,并随响应式目标切换和 Vue 作用域销毁自动断开。
6
+ *
7
+ * @param target - 原生元素、Ref 或 Getter。
8
+ * @param callback - 原生 ResizeObserver 回调。
9
+ * @param options - 原生元素观察选项。
10
+ * @returns 可提前断开观察的停止函数;运行时不支持 ResizeObserver 时为空操作。
11
+ */
12
+ function useResizeObserver(target, callback, options) {
13
+ const stop = watch(() => toValue(target), (currentTarget, _previousTarget, onCleanup) => {
14
+ const ResizeObserver = runtimeGlobals.ResizeObserver;
15
+ if (currentTarget === null || currentTarget === void 0 || ResizeObserver === void 0) return;
16
+ const observer = new ResizeObserver(callback);
17
+ observer.observe(currentTarget, options);
18
+ onCleanup(() => {
19
+ observer.disconnect();
20
+ });
21
+ }, {
22
+ flush: "sync",
23
+ immediate: true
24
+ });
25
+ onScopeDispose(stop, true);
26
+ return stop;
27
+ }
28
+ //#endregion
29
+ export { useResizeObserver };
30
+
31
+ //# sourceMappingURL=resize-observer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resize-observer.mjs","names":[],"sources":["../../src/vue/resize-observer.ts"],"sourcesContent":["import { onScopeDispose, toValue, watch } from \"vue\";\nimport { runtimeGlobals } from \"../internal/runtime\";\nimport type { MaybeRefOrGetter } from \"vue\";\n\n/** `useResizeObserver` 接受的元素或响应式元素。 */\nexport type ResizeObserverTarget = MaybeRefOrGetter<Element | null | undefined>;\n\n/**\n * 监听元素尺寸变化,并随响应式目标切换和 Vue 作用域销毁自动断开。\n *\n * @param target - 原生元素、Ref 或 Getter。\n * @param callback - 原生 ResizeObserver 回调。\n * @param options - 原生元素观察选项。\n * @returns 可提前断开观察的停止函数;运行时不支持 ResizeObserver 时为空操作。\n */\nexport function useResizeObserver(target: ResizeObserverTarget, callback: ResizeObserverCallback, options?: ResizeObserverOptions): () => void {\n\tconst stop = watch(\n\t\t() => toValue(target),\n\t\t(currentTarget, _previousTarget, onCleanup) => {\n\t\t\tconst ResizeObserver = runtimeGlobals.ResizeObserver;\n\t\t\tif (currentTarget === null || currentTarget === undefined || ResizeObserver === undefined) return;\n\t\t\tconst observer = new ResizeObserver(callback);\n\t\t\tobserver.observe(currentTarget, options);\n\t\t\tonCleanup(() => {\n\t\t\t\tobserver.disconnect();\n\t\t\t});\n\t\t},\n\t\t{ flush: \"sync\", immediate: true }\n\t);\n\tonScopeDispose(stop, true);\n\treturn stop;\n}\n"],"mappings":";;;;;;;;;;;AAeA,SAAgB,kBAAkB,QAA8B,UAAkC,SAA6C;CAC9I,MAAM,OAAO,YACN,QAAQ,MAAM,IACnB,eAAe,iBAAiB,cAAc;EAC9C,MAAM,iBAAiB,eAAe;EACtC,IAAI,kBAAkB,QAAQ,kBAAkB,KAAA,KAAa,mBAAmB,KAAA,GAAW;EAC3F,MAAM,WAAW,IAAI,eAAe,QAAQ;EAC5C,SAAS,QAAQ,eAAe,OAAO;EACvC,gBAAgB;GACf,SAAS,WAAW;EACrB,CAAC;CACF,GACA;EAAE,OAAO;EAAQ,WAAW;CAAK,CAClC;CACA,eAAe,MAAM,IAAI;CACzB,OAAO;AACR"}
@@ -0,0 +1,16 @@
1
+ import { ShallowRef } from "vue";
2
+ //#region src/vue/window-size.d.ts
3
+ /** `useWindowSize` 返回的只读窗口尺寸。 */
4
+ export interface UseWindowSizeReturn {
5
+ readonly width: Readonly<ShallowRef<number>>;
6
+ readonly height: Readonly<ShallowRef<number>>;
7
+ }
8
+ /**
9
+ * 响应式读取浏览器窗口内部尺寸。
10
+ *
11
+ * @returns 随原生 `resize` 事件更新的只读宽度和高度;非浏览器环境均为 `0`。
12
+ * @throws `Error` 当浏览器环境中不存在可用于自动清理的 Vue 响应式作用域。
13
+ */
14
+ export declare function useWindowSize(): UseWindowSizeReturn;
15
+ //#endregion
16
+ //# sourceMappingURL=window-size.d.mts.map
@@ -0,0 +1,32 @@
1
+ import { runtimeGlobals } from "../internal/runtime.mjs";
2
+ import { useEventListener } from "./event-listener.mjs";
3
+ import { getCurrentScope, readonly, shallowRef } from "vue";
4
+ //#region src/vue/window-size.ts
5
+ /**
6
+ * 响应式读取浏览器窗口内部尺寸。
7
+ *
8
+ * @returns 随原生 `resize` 事件更新的只读宽度和高度;非浏览器环境均为 `0`。
9
+ * @throws `Error` 当浏览器环境中不存在可用于自动清理的 Vue 响应式作用域。
10
+ */
11
+ function useWindowSize() {
12
+ const width = shallowRef(0);
13
+ const height = shallowRef(0);
14
+ const window = runtimeGlobals.window;
15
+ if (window !== void 0) {
16
+ if (getCurrentScope() === void 0) throw new Error("`useWindowSize` 必须在 Vue 响应式作用域内调用。");
17
+ const update = () => {
18
+ width.value = window.innerWidth;
19
+ height.value = window.innerHeight;
20
+ };
21
+ update();
22
+ useEventListener(window, "resize", update, { passive: true });
23
+ }
24
+ return {
25
+ height: readonly(height),
26
+ width: readonly(width)
27
+ };
28
+ }
29
+ //#endregion
30
+ export { useWindowSize };
31
+
32
+ //# sourceMappingURL=window-size.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"window-size.mjs","names":[],"sources":["../../src/vue/window-size.ts"],"sourcesContent":["import { getCurrentScope, readonly, shallowRef } from \"vue\";\nimport { runtimeGlobals } from \"../internal/runtime\";\nimport { useEventListener } from \"./event-listener\";\nimport type { ShallowRef } from \"vue\";\n\n/** `useWindowSize` 返回的只读窗口尺寸。 */\nexport interface UseWindowSizeReturn {\n\treadonly width: Readonly<ShallowRef<number>>;\n\treadonly height: Readonly<ShallowRef<number>>;\n}\n\n/**\n * 响应式读取浏览器窗口内部尺寸。\n *\n * @returns 随原生 `resize` 事件更新的只读宽度和高度;非浏览器环境均为 `0`。\n * @throws `Error` 当浏览器环境中不存在可用于自动清理的 Vue 响应式作用域。\n */\nexport function useWindowSize(): UseWindowSizeReturn {\n\tconst width = shallowRef(0);\n\tconst height = shallowRef(0);\n\tconst window = runtimeGlobals.window;\n\tif (window !== undefined) {\n\t\tif (getCurrentScope() === undefined) throw new Error(\"`useWindowSize` 必须在 Vue 响应式作用域内调用。\");\n\t\tconst update = () => {\n\t\t\twidth.value = window.innerWidth;\n\t\t\theight.value = window.innerHeight;\n\t\t};\n\t\tupdate();\n\t\tuseEventListener(window, \"resize\", update, { passive: true });\n\t}\n\treturn { height: readonly(height), width: readonly(width) };\n}\n"],"mappings":";;;;;;;;;;AAiBA,SAAgB,gBAAqC;CACpD,MAAM,QAAQ,WAAW,CAAC;CAC1B,MAAM,SAAS,WAAW,CAAC;CAC3B,MAAM,SAAS,eAAe;CAC9B,IAAI,WAAW,KAAA,GAAW;EACzB,IAAI,gBAAgB,MAAM,KAAA,GAAW,MAAM,IAAI,MAAM,oCAAoC;EACzF,MAAM,eAAe;GACpB,MAAM,QAAQ,OAAO;GACrB,OAAO,QAAQ,OAAO;EACvB;EACA,OAAO;EACP,iBAAiB,QAAQ,UAAU,QAAQ,EAAE,SAAS,KAAK,CAAC;CAC7D;CACA,OAAO;EAAE,QAAQ,SAAS,MAAM;EAAG,OAAO,SAAS,KAAK;CAAE;AAC3D"}
package/docs/API.md CHANGED
@@ -123,7 +123,7 @@ Store passwords with `HashPasswordPBKDF2SHA256` and `VerifyPasswordPBKDF2SHA256`
123
123
 
124
124
  ## Modules
125
125
 
126
- - `array`: `chunk`, `removeNullishValues`, `unique`, `uniqueBy`, `groupBy`, `partition`, `difference`, `intersection`, `hasDuplicatesBy`, and `allEqualBy`.
126
+ - `array`: `chunk`, `removeNullishValues`, `unique`, `uniqueBy`, `groupBy`, `partition`, `difference`, `intersection`, `symmetricDifference`, `hasDuplicatesBy`, and `allEqualBy`.
127
127
  - `async`: abort-aware `sleep`, timeout, retry, bounded concurrent mapping, debounce, and throttle primitives.
128
128
  - `base64`: strict UTF-8 Base64/Base64URL byte functions and chainable text results plus the historical Latin-1 and dictionary-obfuscation functions.
129
129
  - `color`: Hex parsing/formatting/mixing, explicit black/white mixing, luminance, and contrast helpers.
@@ -131,11 +131,12 @@ Store passwords with `HashPasswordPBKDF2SHA256` and `VerifyPasswordPBKDF2SHA256`
131
131
  - `date`: date validation and arithmetic, day ranges, relative formatting, and the seven historical date helpers as named functions.
132
132
  - `dom`: CSS unit and style serialization helpers.
133
133
  - `env`: capability and user-agent detection. Detection does not expand the supported runtime contract.
134
+ - `function`: `once` execution with cached return, Promise identity, and synchronous-error behavior.
134
135
  - `logger`: isolated configurable loggers and the default `logger`.
135
136
  - `number`: ranges, rounding, aggregation, interpolation, byte formatting, and Web Crypto-preferred `randomInt`.
136
- - `object`: prototype-safe selection, comparison, mapping, and query serialization. Style serialization is provided by the `dom` module.
137
+ - `object`: deep cloning and equality, prototype-safe key and predicate selection, mapping, and query serialization. Style serialization is provided by the `dom` module.
137
138
  - `string`: query parsing, casing, grapheme-aware truncation, clipboard copying, UUID, Web Crypto-preferred `randomString`, escaping, and whitespace normalization.
138
- - `vue`: Composition API, type, render, and `app.use()` registration helpers for Vue 3.
139
+ - `vue`: Vue 3 helpers plus native-backed `useEventListener`, `useWindowSize`, `useResizeObserver`, `useElementSize`, `useNow`, and `useBreakpoints` composables. They intentionally cover common browser use rather than the full VueUse option surface.
139
140
 
140
141
  ## Security and limits
141
142
 
package/docs/API.zh-CN.md CHANGED
@@ -122,7 +122,7 @@ const result = plaintext.parseJson<{ id: number }>();
122
122
 
123
123
  ## 模块
124
124
 
125
- - `array`:分块、压缩、去重、分组、分区、差集、交集和一致性判断。
125
+ - `array`:分块、压缩、去重、分组、分区、差集、交集、对称差集和一致性判断。
126
126
  - `async`:支持取消的 Sleep、超时、重试、受限并发映射、防抖和节流。
127
127
  - `base64`:严格 UTF-8 Base64/Base64URL 字节与链式文本结果,以及 Latin-1 和 SecureBase64 兼容函数。
128
128
  - `color`:颜色解析、格式化、混合、明暗、亮度和对比度。
@@ -130,11 +130,12 @@ const result = plaintext.parseJson<{ id: number }>();
130
130
  - `date`:日期校验、加减、日范围、相对时间,以及七个历史日期功能的具名函数。
131
131
  - `dom`:CSS 单位和 Style 序列化。
132
132
  - `env`:能力与 User-Agent 检测;检测函数不扩大运行时支持范围。
133
+ - `function`:最多执行一次并缓存返回值、Promise 引用或同步错误的 `once`。
133
134
  - `logger`:隔离的可配置 Logger 和默认 `logger`。
134
135
  - `number`:范围、舍入、聚合、插值、字节格式化,以及优先使用 Web Crypto 的 `randomInt`。
135
- - `object`:防原型污染的选择、比较、映射和 Query 序列化;Style 序列化由 `dom` 模块提供。
136
+ - `object`:深复制、深度比较、防原型污染的键和条件筛选、映射及 Query 序列化;Style 序列化由 `dom` 模块提供。
136
137
  - `string`:Query 解析、大小写、字素截断、剪贴板复制、UUID、优先使用 Web Crypto 的 `randomString`、转义和空白规范化。
137
- - `vue`:Vue 3 的 Composition API、类型、Render 和 `app.use()` 注册 Helper。
138
+ - `vue`:Vue 3 Helper,以及基于原生能力的 `useEventListener`、`useWindowSize`、`useResizeObserver`、`useElementSize`、`useNow` 和 `useBreakpoints`。这些 Composable 面向常用浏览器场景,不提供 VueUse 的完整选项面。
138
139
 
139
140
  ## 安全与限制
140
141
 
@@ -4,7 +4,8 @@
4
4
 
5
5
  - Runtime platforms: ES2022 modern browsers, WebViews, Vue 3 applications, and uni-app.
6
6
  - Package format: one public named-export ESM entry for package managers and one separately minified IIFE entry for CDN use; CommonJS and UMD are not shipped.
7
- - Framework boundary: Vue remains external to the package-manager build and is a required peer in `^3.3.0`.
7
+ - Framework boundary: Vue remains external to the package-manager build and is a required peer in `^3.5.11`.
8
+ - Vue browser composables: event and observer helpers use native platform APIs, return manual stop handles where exposed, and clean up automatically with the current Vue scope. Window size and breakpoints use `0`/`false` outside browsers; `useNow` returns a non-updating initial Date during SSR.
8
9
  - uni-app boundary: the first Storage operation, or an earlier `configureStorage({ prefix })` call, detects global `uni` and uses its synchronous Storage API.
9
10
  - Browser storage: applications import `Local` and `Session` directly; `configureStorage()` is needed only to override defaults before the first operation.
10
11
  - Storage operation overrides: `set/get({ crypto })` select JSON or Base64 for one operation without mutating global configuration. The v3 envelope does not identify its codec, so callers must use matching options for the same entry.
@@ -28,7 +29,8 @@ Importing a module does not itself read `window`, browser Storage, or `uni`, so
28
29
 
29
30
  - 运行平台:ES2022 现代浏览器、WebView、Vue 3 应用和 uni-app。
30
31
  - 包格式:包管理器使用单一公开具名导出 ESM 入口,CDN 使用单独压缩的 IIFE;不发布 CommonJS 或 UMD。
31
- - Vue 边界:Vue 不会打进包管理器使用的构建产物,是 `^3.3.0` 的必需 Peer。
32
+ - Vue 边界:Vue 不会打进包管理器使用的构建产物,是 `^3.5.11` 的必需 Peer。
33
+ - Vue 浏览器 Composable:事件和观察器 Helper 直接使用原生平台 API,在公开停止函数时支持手动清理,并随当前 Vue 作用域自动清理。非浏览器环境下窗口尺寸和断点状态分别使用 `0` 与 `false`,`useNow` 在 SSR 时只返回调用时的静态 Date。
32
34
  - uni-app:首次 Storage 操作或更早的 `configureStorage({ prefix })` 调用会检测全局 `uni`,并使用其同步 Storage API。
33
35
  - Storage:直接从包导入 `Local` 和 `Session` 即可;只有覆盖默认值时才需在首次操作前调用 `configureStorage()`。
34
36
  - Storage 单次覆盖:`set/get({ crypto })` 只为当前操作选择 JSON 或 Base64,不修改全局配置。v3 包络不记录 Codec,调用方必须对同一条目使用匹配的读写选项。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fast-china/utils",
3
- "version": "2.1.4",
3
+ "version": "2.1.6",
4
4
  "description": "Typed utilities for modern browsers, WebViews, Vue 3, and uni-app applications.",
5
5
  "type": "module",
6
6
  "keywords": [