@hlw-uni-mp/use 1.0.0

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.
@@ -0,0 +1,233 @@
1
+ import { ApiRes } from '@hlw-uni-mp/request';
2
+ import * as pinia from 'pinia';
3
+ import { App, Ref, ComputedRef } from 'vue';
4
+
5
+ /**
6
+ * 提示回调函数类型 (confirm 为 true 表示确定,false 为取消)
7
+ */
8
+ type ToastCallback = (confirm: boolean) => void;
9
+
10
+ /**
11
+ * 消息门面体
12
+ */
13
+ interface HlwMsg {
14
+ /** 显示轻提示或模态确认框 (支持回调与 Promise) */
15
+ toast<T = unknown>(opts: UniApp.ShowToastOptions | ApiRes<T> | string, callback?: ToastCallback): Promise<boolean>;
16
+ /** 成功提示框 */
17
+ success(msg: string): void;
18
+ /** 失败提示框 */
19
+ error(msg: string): void;
20
+ /** 显全局加载 */
21
+ showLoading(msg?: string): void;
22
+ /** 隐全局加载 */
23
+ hideLoading(): void;
24
+ /** 弹出确认框 */
25
+ modal(opts?: UniApp.ShowModalOptions): Promise<boolean>;
26
+ /** 标题进度条 */
27
+ setLoadingBar(progress: number): void;
28
+ }
29
+
30
+ /**
31
+ * 统一的消息提示与弹窗能力 hook。
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const msg = useMsg();
36
+ * msg.toast('操作成功');
37
+ * msg.toast(res, (confirm) => {
38
+ * if (confirm) console.log('点击确定');
39
+ * else console.log('点击取消');
40
+ * });
41
+ * const ok = await msg.modal({ content: '确定删除吗?' });
42
+ * ```
43
+ */
44
+ declare function useMsg(): HlwMsg;
45
+
46
+ /**
47
+ * 外观模式型
48
+ */
49
+ type ThemeMode = "light" | "dark" | "system";
50
+
51
+ /**
52
+ * 字体大小型
53
+ */
54
+ type FontSize = "small" | "standard" | "large" | "extra-large";
55
+
56
+ /**
57
+ * 字体样式型
58
+ */
59
+ type FontFamily = "system" | "sans" | "serif" | "kaiti";
60
+
61
+ /**
62
+ * 主题色彩项
63
+ */
64
+ interface ThemeColor {
65
+ name: string;
66
+ value: string;
67
+ }
68
+
69
+ /**
70
+ * 主题状态表
71
+ */
72
+ interface ThemeState {
73
+ mode: ThemeMode;
74
+ color: string;
75
+ fontSize: FontSize;
76
+ fontFamily: FontFamily;
77
+ }
78
+
79
+ /**
80
+ * 初始配置项
81
+ */
82
+ interface InitThemeOptions {
83
+ sync?: boolean;
84
+ defaultTheme?: Partial<ThemeState>;
85
+ }
86
+
87
+ /**
88
+ * 字体大小项
89
+ */
90
+ interface FontSizePreset {
91
+ id: string;
92
+ name: string;
93
+ class: string;
94
+ }
95
+
96
+ /**
97
+ * 字体样式项
98
+ */
99
+ interface FontFamilyPreset {
100
+ id: string;
101
+ name: string;
102
+ class: string;
103
+ }
104
+
105
+ /**
106
+ * 字体大小表
107
+ */
108
+ declare const fontSizePresets: FontSizePreset[];
109
+ /**
110
+ * 字体样式表
111
+ */
112
+ declare const fontFamilyPresets: FontFamilyPreset[];
113
+ /**
114
+ * 主题状态库
115
+ */
116
+ declare const useThemeStore: pinia.StoreDefinition<"theme", {
117
+ mode: string;
118
+ color: string;
119
+ fontSize: string;
120
+ fontFamily: string;
121
+ }, {}, {}>;
122
+
123
+ /**
124
+ * 默认主题配置
125
+ */
126
+ declare const DEFAULT_THEME: ThemeState;
127
+ /**
128
+ * 预设色彩库
129
+ */
130
+ declare const THEME_COLORS: ThemeColor[];
131
+ /**
132
+ * 获取存储配置
133
+ */
134
+ declare function getTheme(): ThemeState;
135
+ /**
136
+ * 应用主题状态
137
+ */
138
+ declare function applyTheme(themeState: Partial<ThemeState>): void;
139
+ /**
140
+ * 注册主题器
141
+ */
142
+ declare function initTheme(app: App, options?: InitThemeOptions): void;
143
+ /**
144
+ * 主题组合钩子
145
+ */
146
+ declare function useTheme(): {
147
+ mode: Ref<ThemeMode, ThemeMode>;
148
+ color: Ref<string, string>;
149
+ fontSize: Ref<string, string>;
150
+ fontSizeClass: ComputedRef<string>;
151
+ fontFamily: Ref<string, string>;
152
+ fontFamilyClass: ComputedRef<string>;
153
+ colors: ThemeColor[];
154
+ fontSizePresets: FontSizePreset[];
155
+ fontFamilyPresets: FontFamilyPreset[];
156
+ setMode: (targetMode: ThemeMode) => void;
157
+ setColor: (hexColor: string) => void;
158
+ setFontSize: (targetSize: string) => void;
159
+ setFontFamily: (targetFont: string) => void;
160
+ resetTheme: () => void;
161
+ applyTheme: typeof applyTheme;
162
+ getTheme: typeof getTheme;
163
+ initTheme: typeof initTheme;
164
+ store: pinia.Store<"theme", {
165
+ mode: string;
166
+ color: string;
167
+ fontSize: string;
168
+ fontFamily: string;
169
+ }, {}, {}>;
170
+ };
171
+
172
+ /**
173
+ * 分享卡片配置项
174
+ */
175
+ interface ShareConfig {
176
+ /** 分享标题 */
177
+ title?: string;
178
+ /** 分享页面路径 */
179
+ path?: string;
180
+ /** 分享卡片封面图 */
181
+ imageUrl?: string;
182
+ }
183
+
184
+ /**
185
+ * 分享操作句柄
186
+ */
187
+ interface ShareHandlers {
188
+ /** 显式调起分享菜单 */
189
+ showShareMenu: () => void;
190
+ }
191
+
192
+ /**
193
+ * 显式调起分享菜单
194
+ */
195
+ declare function showShareMenu(): void;
196
+ /**
197
+ * 分享组合式函数
198
+ */
199
+ declare function useShare(config?: ShareConfig): ShareHandlers;
200
+
201
+ /**
202
+ * useRefs - 模板 Ref 批量管理
203
+ *
204
+ * 主要用于在 v-for 循环场景下,动态收集一组子元素或子组件的引用实例。
205
+ * 规避了 Vue3 在 v-for 中绑定 ref 时需要手动处理数组收集和清理的冗余逻辑。
206
+ */
207
+
208
+ interface UseRefsReturn<T = unknown> {
209
+ /** 存放动态收集到的所有组件或 DOM 实例的 Key-Value 映射对象 */
210
+ refs: Ref<Record<string, T>>;
211
+ /** 按 key 生成一个 ref 绑定回调函数 */
212
+ setRefs: (key: string) => (element: T | null) => void;
213
+ }
214
+ /**
215
+ * 管理动态 ref 集合的 hook,尤其适合 v-for 列表场景。
216
+ *
217
+ * @example
218
+ * ```vue
219
+ * <template>
220
+ * <view v-for="item in list" :key="item.id" :ref="setRefs(item.id)">
221
+ * {{ item.name }}
222
+ * </view>
223
+ * </template>
224
+ *
225
+ * <script setup>
226
+ * const { refs, setRefs } = useRefs();
227
+ * // 访问特定子项的 DOM/实例: refs.value[itemId]
228
+ * </script>
229
+ * ```
230
+ */
231
+ declare function useRefs<T = unknown>(): UseRefsReturn<T>;
232
+
233
+ export { DEFAULT_THEME, type FontFamily, type FontFamilyPreset, type FontSize, type FontSizePreset, type HlwMsg, type InitThemeOptions, type ShareConfig, type ShareHandlers, THEME_COLORS, type ThemeColor, type ThemeMode, type ThemeState, type ToastCallback, type UseRefsReturn, applyTheme, fontFamilyPresets, fontSizePresets, getTheme, initTheme, showShareMenu, useMsg, useRefs, useShare, useTheme, useThemeStore };
@@ -0,0 +1,233 @@
1
+ import { ApiRes } from '@hlw-uni-mp/request';
2
+ import * as pinia from 'pinia';
3
+ import { App, Ref, ComputedRef } from 'vue';
4
+
5
+ /**
6
+ * 提示回调函数类型 (confirm 为 true 表示确定,false 为取消)
7
+ */
8
+ type ToastCallback = (confirm: boolean) => void;
9
+
10
+ /**
11
+ * 消息门面体
12
+ */
13
+ interface HlwMsg {
14
+ /** 显示轻提示或模态确认框 (支持回调与 Promise) */
15
+ toast<T = unknown>(opts: UniApp.ShowToastOptions | ApiRes<T> | string, callback?: ToastCallback): Promise<boolean>;
16
+ /** 成功提示框 */
17
+ success(msg: string): void;
18
+ /** 失败提示框 */
19
+ error(msg: string): void;
20
+ /** 显全局加载 */
21
+ showLoading(msg?: string): void;
22
+ /** 隐全局加载 */
23
+ hideLoading(): void;
24
+ /** 弹出确认框 */
25
+ modal(opts?: UniApp.ShowModalOptions): Promise<boolean>;
26
+ /** 标题进度条 */
27
+ setLoadingBar(progress: number): void;
28
+ }
29
+
30
+ /**
31
+ * 统一的消息提示与弹窗能力 hook。
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const msg = useMsg();
36
+ * msg.toast('操作成功');
37
+ * msg.toast(res, (confirm) => {
38
+ * if (confirm) console.log('点击确定');
39
+ * else console.log('点击取消');
40
+ * });
41
+ * const ok = await msg.modal({ content: '确定删除吗?' });
42
+ * ```
43
+ */
44
+ declare function useMsg(): HlwMsg;
45
+
46
+ /**
47
+ * 外观模式型
48
+ */
49
+ type ThemeMode = "light" | "dark" | "system";
50
+
51
+ /**
52
+ * 字体大小型
53
+ */
54
+ type FontSize = "small" | "standard" | "large" | "extra-large";
55
+
56
+ /**
57
+ * 字体样式型
58
+ */
59
+ type FontFamily = "system" | "sans" | "serif" | "kaiti";
60
+
61
+ /**
62
+ * 主题色彩项
63
+ */
64
+ interface ThemeColor {
65
+ name: string;
66
+ value: string;
67
+ }
68
+
69
+ /**
70
+ * 主题状态表
71
+ */
72
+ interface ThemeState {
73
+ mode: ThemeMode;
74
+ color: string;
75
+ fontSize: FontSize;
76
+ fontFamily: FontFamily;
77
+ }
78
+
79
+ /**
80
+ * 初始配置项
81
+ */
82
+ interface InitThemeOptions {
83
+ sync?: boolean;
84
+ defaultTheme?: Partial<ThemeState>;
85
+ }
86
+
87
+ /**
88
+ * 字体大小项
89
+ */
90
+ interface FontSizePreset {
91
+ id: string;
92
+ name: string;
93
+ class: string;
94
+ }
95
+
96
+ /**
97
+ * 字体样式项
98
+ */
99
+ interface FontFamilyPreset {
100
+ id: string;
101
+ name: string;
102
+ class: string;
103
+ }
104
+
105
+ /**
106
+ * 字体大小表
107
+ */
108
+ declare const fontSizePresets: FontSizePreset[];
109
+ /**
110
+ * 字体样式表
111
+ */
112
+ declare const fontFamilyPresets: FontFamilyPreset[];
113
+ /**
114
+ * 主题状态库
115
+ */
116
+ declare const useThemeStore: pinia.StoreDefinition<"theme", {
117
+ mode: string;
118
+ color: string;
119
+ fontSize: string;
120
+ fontFamily: string;
121
+ }, {}, {}>;
122
+
123
+ /**
124
+ * 默认主题配置
125
+ */
126
+ declare const DEFAULT_THEME: ThemeState;
127
+ /**
128
+ * 预设色彩库
129
+ */
130
+ declare const THEME_COLORS: ThemeColor[];
131
+ /**
132
+ * 获取存储配置
133
+ */
134
+ declare function getTheme(): ThemeState;
135
+ /**
136
+ * 应用主题状态
137
+ */
138
+ declare function applyTheme(themeState: Partial<ThemeState>): void;
139
+ /**
140
+ * 注册主题器
141
+ */
142
+ declare function initTheme(app: App, options?: InitThemeOptions): void;
143
+ /**
144
+ * 主题组合钩子
145
+ */
146
+ declare function useTheme(): {
147
+ mode: Ref<ThemeMode, ThemeMode>;
148
+ color: Ref<string, string>;
149
+ fontSize: Ref<string, string>;
150
+ fontSizeClass: ComputedRef<string>;
151
+ fontFamily: Ref<string, string>;
152
+ fontFamilyClass: ComputedRef<string>;
153
+ colors: ThemeColor[];
154
+ fontSizePresets: FontSizePreset[];
155
+ fontFamilyPresets: FontFamilyPreset[];
156
+ setMode: (targetMode: ThemeMode) => void;
157
+ setColor: (hexColor: string) => void;
158
+ setFontSize: (targetSize: string) => void;
159
+ setFontFamily: (targetFont: string) => void;
160
+ resetTheme: () => void;
161
+ applyTheme: typeof applyTheme;
162
+ getTheme: typeof getTheme;
163
+ initTheme: typeof initTheme;
164
+ store: pinia.Store<"theme", {
165
+ mode: string;
166
+ color: string;
167
+ fontSize: string;
168
+ fontFamily: string;
169
+ }, {}, {}>;
170
+ };
171
+
172
+ /**
173
+ * 分享卡片配置项
174
+ */
175
+ interface ShareConfig {
176
+ /** 分享标题 */
177
+ title?: string;
178
+ /** 分享页面路径 */
179
+ path?: string;
180
+ /** 分享卡片封面图 */
181
+ imageUrl?: string;
182
+ }
183
+
184
+ /**
185
+ * 分享操作句柄
186
+ */
187
+ interface ShareHandlers {
188
+ /** 显式调起分享菜单 */
189
+ showShareMenu: () => void;
190
+ }
191
+
192
+ /**
193
+ * 显式调起分享菜单
194
+ */
195
+ declare function showShareMenu(): void;
196
+ /**
197
+ * 分享组合式函数
198
+ */
199
+ declare function useShare(config?: ShareConfig): ShareHandlers;
200
+
201
+ /**
202
+ * useRefs - 模板 Ref 批量管理
203
+ *
204
+ * 主要用于在 v-for 循环场景下,动态收集一组子元素或子组件的引用实例。
205
+ * 规避了 Vue3 在 v-for 中绑定 ref 时需要手动处理数组收集和清理的冗余逻辑。
206
+ */
207
+
208
+ interface UseRefsReturn<T = unknown> {
209
+ /** 存放动态收集到的所有组件或 DOM 实例的 Key-Value 映射对象 */
210
+ refs: Ref<Record<string, T>>;
211
+ /** 按 key 生成一个 ref 绑定回调函数 */
212
+ setRefs: (key: string) => (element: T | null) => void;
213
+ }
214
+ /**
215
+ * 管理动态 ref 集合的 hook,尤其适合 v-for 列表场景。
216
+ *
217
+ * @example
218
+ * ```vue
219
+ * <template>
220
+ * <view v-for="item in list" :key="item.id" :ref="setRefs(item.id)">
221
+ * {{ item.name }}
222
+ * </view>
223
+ * </template>
224
+ *
225
+ * <script setup>
226
+ * const { refs, setRefs } = useRefs();
227
+ * // 访问特定子项的 DOM/实例: refs.value[itemId]
228
+ * </script>
229
+ * ```
230
+ */
231
+ declare function useRefs<T = unknown>(): UseRefsReturn<T>;
232
+
233
+ export { DEFAULT_THEME, type FontFamily, type FontFamilyPreset, type FontSize, type FontSizePreset, type HlwMsg, type InitThemeOptions, type ShareConfig, type ShareHandlers, THEME_COLORS, type ThemeColor, type ThemeMode, type ThemeState, type ToastCallback, type UseRefsReturn, applyTheme, fontFamilyPresets, fontSizePresets, getTheme, initTheme, showShareMenu, useMsg, useRefs, useShare, useTheme, useThemeStore };
package/dist/index.js ADDED
@@ -0,0 +1,351 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DEFAULT_THEME: () => DEFAULT_THEME,
24
+ THEME_COLORS: () => THEME_COLORS,
25
+ applyTheme: () => applyTheme,
26
+ fontFamilyPresets: () => fontFamilyPresets,
27
+ fontSizePresets: () => fontSizePresets,
28
+ getTheme: () => getTheme,
29
+ initTheme: () => initTheme,
30
+ showShareMenu: () => showShareMenu,
31
+ useMsg: () => useMsg,
32
+ useRefs: () => useRefs,
33
+ useShare: () => useShare,
34
+ useTheme: () => useTheme,
35
+ useThemeStore: () => useThemeStore
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+
39
+ // src/msg/index.ts
40
+ function useMsg() {
41
+ function toast(opts, callback) {
42
+ let msg = "";
43
+ let isModal = false;
44
+ let modalOptions;
45
+ let toastOptions;
46
+ if (typeof opts === "string") {
47
+ msg = opts;
48
+ } else if ("msg" in opts) {
49
+ msg = opts.msg || "";
50
+ isModal = !!opts.modal;
51
+ modalOptions = opts.modalOptions;
52
+ } else if ("title" in opts) {
53
+ msg = opts.title || "";
54
+ toastOptions = opts;
55
+ }
56
+ if (!msg) {
57
+ callback?.(true);
58
+ return Promise.resolve(true);
59
+ }
60
+ if (isModal) {
61
+ return modal({
62
+ ...modalOptions,
63
+ content: msg
64
+ }).then((confirm) => {
65
+ callback?.(confirm);
66
+ return confirm;
67
+ });
68
+ }
69
+ uni.showToast({
70
+ title: msg,
71
+ icon: toastOptions?.icon || "none",
72
+ image: toastOptions?.image,
73
+ duration: toastOptions?.duration || 2e3,
74
+ mask: toastOptions?.mask || false,
75
+ position: toastOptions?.position || "center"
76
+ });
77
+ callback?.(true);
78
+ return Promise.resolve(true);
79
+ }
80
+ function success(msg) {
81
+ if (!msg) return;
82
+ uni.showToast({ title: msg, icon: "success", duration: 2e3 });
83
+ }
84
+ function error(msg) {
85
+ if (!msg) return;
86
+ uni.showToast({ title: msg, icon: "error", duration: 2e3 });
87
+ }
88
+ function showLoading(msg = "\u52A0\u8F7D\u4E2D...") {
89
+ uni.showLoading({ title: msg, mask: true });
90
+ }
91
+ function hideLoading() {
92
+ uni.hideLoading();
93
+ }
94
+ function modal(opts = {}) {
95
+ return new Promise((resolve) => {
96
+ const {
97
+ title = "\u63D0\u793A",
98
+ content,
99
+ confirmText = "\u786E\u5B9A",
100
+ cancelText = "\u53D6\u6D88",
101
+ confirmColor = "#3b82f6",
102
+ cancelColor = "#999999",
103
+ showCancel = true
104
+ } = opts || {};
105
+ uni.showModal({
106
+ title,
107
+ content,
108
+ confirmText,
109
+ cancelText,
110
+ confirmColor,
111
+ cancelColor,
112
+ showCancel,
113
+ success: (res) => resolve(res.confirm),
114
+ fail: () => resolve(false)
115
+ });
116
+ });
117
+ }
118
+ function setLoadingBar(progress) {
119
+ const clamped = Math.max(0, Math.min(100, progress));
120
+ const filled = Math.round(clamped / 2);
121
+ uni.setNavigationBarTitle({
122
+ title: `${"\u25A0".repeat(filled)}${"\u25A1".repeat(50 - filled)} ${clamped}%`
123
+ });
124
+ }
125
+ return {
126
+ toast,
127
+ success,
128
+ error,
129
+ showLoading,
130
+ hideLoading,
131
+ modal,
132
+ setLoadingBar
133
+ };
134
+ }
135
+
136
+ // src/theme/index.ts
137
+ var import_vue = require("vue");
138
+
139
+ // src/theme/store.ts
140
+ var import_pinia = require("pinia");
141
+ var import_pinia_plugin_storage = require("@hlw-uni-mp/pinia-plugin-storage");
142
+ var fontSizePresets = [
143
+ {
144
+ id: "small",
145
+ name: "\u8F83\u5C0F",
146
+ class: "font-size-small"
147
+ },
148
+ {
149
+ id: "standard",
150
+ name: "\u6807\u51C6",
151
+ class: "font-size-standard"
152
+ },
153
+ {
154
+ id: "large",
155
+ name: "\u8F83\u5927",
156
+ class: "font-size-large"
157
+ },
158
+ {
159
+ id: "extra-large",
160
+ name: "\u8D85\u5927",
161
+ class: "font-size-extra-large"
162
+ }
163
+ ];
164
+ var fontFamilyPresets = [
165
+ {
166
+ id: "system",
167
+ name: "\u7CFB\u7EDF\u9ED8\u8BA4",
168
+ class: "font-family-system"
169
+ },
170
+ {
171
+ id: "sans",
172
+ name: "\u73B0\u4EE3\u9ED1\u4F53",
173
+ class: "font-family-sans"
174
+ },
175
+ {
176
+ id: "serif",
177
+ name: "\u7ECF\u5178\u5B8B\u4F53",
178
+ class: "font-family-serif"
179
+ },
180
+ {
181
+ id: "kaiti",
182
+ name: "\u4F18\u96C5\u6977\u4F53",
183
+ class: "font-family-kaiti"
184
+ }
185
+ ];
186
+ var useThemeStore = (0, import_pinia.defineStore)("theme", {
187
+ state: () => ({
188
+ mode: "light",
189
+ color: "#08c060",
190
+ fontSize: "standard",
191
+ fontFamily: "system"
192
+ }),
193
+ unistorage: true
194
+ });
195
+
196
+ // src/theme/index.ts
197
+ var DEFAULT_THEME = {
198
+ mode: "light",
199
+ color: "#08c060",
200
+ fontSize: "standard",
201
+ fontFamily: "system"
202
+ };
203
+ var THEME_COLORS = [
204
+ { name: "\u9ED8\u8BA4\u7EFF", value: "#08c060" },
205
+ { name: "\u79D1\u6280\u84DD", value: "#3b82f6" },
206
+ { name: "\u7FE1\u7FE0\u7EFF", value: "#10b981" },
207
+ { name: "\u68A6\u5E7B\u7D2B", value: "#8b5cf6" },
208
+ { name: "\u6D3B\u529B\u6A59", value: "#f97316" },
209
+ { name: "\u70ED\u60C5\u7EA2", value: "#ef4444" },
210
+ { name: "\u9752\u84DD", value: "#06b6d4" },
211
+ { name: "\u7ECF\u5178\u9ED1", value: "#334155" },
212
+ { name: "\u8537\u8587\u7C89", value: "#ec4899" }
213
+ ];
214
+ function getTheme() {
215
+ const store = useThemeStore();
216
+ return {
217
+ mode: store.mode || DEFAULT_THEME.mode,
218
+ color: store.color || DEFAULT_THEME.color,
219
+ fontSize: store.fontSize || DEFAULT_THEME.fontSize,
220
+ fontFamily: store.fontFamily || DEFAULT_THEME.fontFamily
221
+ };
222
+ }
223
+ function applyTheme(themeState) {
224
+ const store = useThemeStore();
225
+ if (themeState.mode) store.mode = themeState.mode;
226
+ if (themeState.color) store.color = themeState.color;
227
+ if (themeState.fontSize && ["small", "standard", "large", "extra-large"].includes(themeState.fontSize)) {
228
+ store.fontSize = themeState.fontSize;
229
+ }
230
+ if (themeState.fontFamily && ["system", "sans", "serif", "kaiti"].includes(themeState.fontFamily)) {
231
+ store.fontFamily = themeState.fontFamily;
232
+ }
233
+ }
234
+ function initTheme(app, options = {}) {
235
+ const { sync = true, defaultTheme } = options;
236
+ app.config.globalProperties.$theme = useTheme();
237
+ app.provide("theme", useTheme());
238
+ if (sync) {
239
+ applyTheme({ ...getTheme(), ...defaultTheme });
240
+ }
241
+ }
242
+ function useTheme() {
243
+ const store = useThemeStore();
244
+ const mode = (0, import_vue.toRef)(store, "mode");
245
+ const color = (0, import_vue.toRef)(store, "color");
246
+ const fontSize = (0, import_vue.toRef)(store, "fontSize");
247
+ const fontFamily = (0, import_vue.toRef)(store, "fontFamily");
248
+ const fontSizeClass = (0, import_vue.computed)(() => {
249
+ return fontSizePresets.find((item) => item.id === store.fontSize)?.class || "font-size-standard";
250
+ });
251
+ const fontFamilyClass = (0, import_vue.computed)(() => {
252
+ return fontFamilyPresets.find((item) => item.id === store.fontFamily)?.class || "font-family-system";
253
+ });
254
+ function setMode(targetMode) {
255
+ store.mode = targetMode;
256
+ }
257
+ function setColor(hexColor) {
258
+ store.color = hexColor;
259
+ }
260
+ function setFontSize(targetSize) {
261
+ if (["small", "standard", "large", "extra-large"].includes(targetSize)) {
262
+ store.fontSize = targetSize;
263
+ }
264
+ }
265
+ function setFontFamily(targetFont) {
266
+ if (["system", "sans", "serif", "kaiti"].includes(targetFont)) {
267
+ store.fontFamily = targetFont;
268
+ }
269
+ }
270
+ function resetTheme() {
271
+ store.mode = DEFAULT_THEME.mode;
272
+ store.color = DEFAULT_THEME.color;
273
+ store.fontSize = DEFAULT_THEME.fontSize;
274
+ store.fontFamily = DEFAULT_THEME.fontFamily;
275
+ }
276
+ return {
277
+ mode,
278
+ color,
279
+ fontSize,
280
+ fontSizeClass,
281
+ fontFamily,
282
+ fontFamilyClass,
283
+ colors: THEME_COLORS,
284
+ fontSizePresets,
285
+ fontFamilyPresets,
286
+ setMode,
287
+ setColor,
288
+ setFontSize,
289
+ setFontFamily,
290
+ resetTheme,
291
+ applyTheme,
292
+ getTheme,
293
+ initTheme,
294
+ store
295
+ };
296
+ }
297
+
298
+ // src/share/index.ts
299
+ var import_uni_app = require("@dcloudio/uni-app");
300
+ function showShareMenu() {
301
+ uni.showShareMenu({
302
+ withShareTicket: true,
303
+ menus: ["shareAppMessage", "shareTimeline"]
304
+ });
305
+ }
306
+ function useShare(config = {}) {
307
+ showShareMenu();
308
+ (0, import_uni_app.onShareAppMessage)(() => ({ ...config }));
309
+ (0, import_uni_app.onShareTimeline)(() => {
310
+ return {
311
+ title: config.title,
312
+ query: config.path?.split("?")[1],
313
+ imageUrl: config.imageUrl
314
+ };
315
+ });
316
+ return {
317
+ showShareMenu
318
+ };
319
+ }
320
+
321
+ // src/refs/index.ts
322
+ var import_vue2 = require("vue");
323
+ function useRefs() {
324
+ const refs = (0, import_vue2.ref)({});
325
+ (0, import_vue2.onBeforeUpdate)(() => {
326
+ refs.value = {};
327
+ });
328
+ (0, import_vue2.onUnmounted)(() => {
329
+ refs.value = {};
330
+ });
331
+ const setRefs = (key) => (element) => {
332
+ if (element) refs.value[key] = element;
333
+ };
334
+ return { refs, setRefs };
335
+ }
336
+ // Annotate the CommonJS export names for ESM import in node:
337
+ 0 && (module.exports = {
338
+ DEFAULT_THEME,
339
+ THEME_COLORS,
340
+ applyTheme,
341
+ fontFamilyPresets,
342
+ fontSizePresets,
343
+ getTheme,
344
+ initTheme,
345
+ showShareMenu,
346
+ useMsg,
347
+ useRefs,
348
+ useShare,
349
+ useTheme,
350
+ useThemeStore
351
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,312 @@
1
+ // src/msg/index.ts
2
+ function useMsg() {
3
+ function toast(opts, callback) {
4
+ let msg = "";
5
+ let isModal = false;
6
+ let modalOptions;
7
+ let toastOptions;
8
+ if (typeof opts === "string") {
9
+ msg = opts;
10
+ } else if ("msg" in opts) {
11
+ msg = opts.msg || "";
12
+ isModal = !!opts.modal;
13
+ modalOptions = opts.modalOptions;
14
+ } else if ("title" in opts) {
15
+ msg = opts.title || "";
16
+ toastOptions = opts;
17
+ }
18
+ if (!msg) {
19
+ callback?.(true);
20
+ return Promise.resolve(true);
21
+ }
22
+ if (isModal) {
23
+ return modal({
24
+ ...modalOptions,
25
+ content: msg
26
+ }).then((confirm) => {
27
+ callback?.(confirm);
28
+ return confirm;
29
+ });
30
+ }
31
+ uni.showToast({
32
+ title: msg,
33
+ icon: toastOptions?.icon || "none",
34
+ image: toastOptions?.image,
35
+ duration: toastOptions?.duration || 2e3,
36
+ mask: toastOptions?.mask || false,
37
+ position: toastOptions?.position || "center"
38
+ });
39
+ callback?.(true);
40
+ return Promise.resolve(true);
41
+ }
42
+ function success(msg) {
43
+ if (!msg) return;
44
+ uni.showToast({ title: msg, icon: "success", duration: 2e3 });
45
+ }
46
+ function error(msg) {
47
+ if (!msg) return;
48
+ uni.showToast({ title: msg, icon: "error", duration: 2e3 });
49
+ }
50
+ function showLoading(msg = "\u52A0\u8F7D\u4E2D...") {
51
+ uni.showLoading({ title: msg, mask: true });
52
+ }
53
+ function hideLoading() {
54
+ uni.hideLoading();
55
+ }
56
+ function modal(opts = {}) {
57
+ return new Promise((resolve) => {
58
+ const {
59
+ title = "\u63D0\u793A",
60
+ content,
61
+ confirmText = "\u786E\u5B9A",
62
+ cancelText = "\u53D6\u6D88",
63
+ confirmColor = "#3b82f6",
64
+ cancelColor = "#999999",
65
+ showCancel = true
66
+ } = opts || {};
67
+ uni.showModal({
68
+ title,
69
+ content,
70
+ confirmText,
71
+ cancelText,
72
+ confirmColor,
73
+ cancelColor,
74
+ showCancel,
75
+ success: (res) => resolve(res.confirm),
76
+ fail: () => resolve(false)
77
+ });
78
+ });
79
+ }
80
+ function setLoadingBar(progress) {
81
+ const clamped = Math.max(0, Math.min(100, progress));
82
+ const filled = Math.round(clamped / 2);
83
+ uni.setNavigationBarTitle({
84
+ title: `${"\u25A0".repeat(filled)}${"\u25A1".repeat(50 - filled)} ${clamped}%`
85
+ });
86
+ }
87
+ return {
88
+ toast,
89
+ success,
90
+ error,
91
+ showLoading,
92
+ hideLoading,
93
+ modal,
94
+ setLoadingBar
95
+ };
96
+ }
97
+
98
+ // src/theme/index.ts
99
+ import { computed, toRef } from "vue";
100
+
101
+ // src/theme/store.ts
102
+ import { defineStore } from "pinia";
103
+ import "@hlw-uni-mp/pinia-plugin-storage";
104
+ var fontSizePresets = [
105
+ {
106
+ id: "small",
107
+ name: "\u8F83\u5C0F",
108
+ class: "font-size-small"
109
+ },
110
+ {
111
+ id: "standard",
112
+ name: "\u6807\u51C6",
113
+ class: "font-size-standard"
114
+ },
115
+ {
116
+ id: "large",
117
+ name: "\u8F83\u5927",
118
+ class: "font-size-large"
119
+ },
120
+ {
121
+ id: "extra-large",
122
+ name: "\u8D85\u5927",
123
+ class: "font-size-extra-large"
124
+ }
125
+ ];
126
+ var fontFamilyPresets = [
127
+ {
128
+ id: "system",
129
+ name: "\u7CFB\u7EDF\u9ED8\u8BA4",
130
+ class: "font-family-system"
131
+ },
132
+ {
133
+ id: "sans",
134
+ name: "\u73B0\u4EE3\u9ED1\u4F53",
135
+ class: "font-family-sans"
136
+ },
137
+ {
138
+ id: "serif",
139
+ name: "\u7ECF\u5178\u5B8B\u4F53",
140
+ class: "font-family-serif"
141
+ },
142
+ {
143
+ id: "kaiti",
144
+ name: "\u4F18\u96C5\u6977\u4F53",
145
+ class: "font-family-kaiti"
146
+ }
147
+ ];
148
+ var useThemeStore = defineStore("theme", {
149
+ state: () => ({
150
+ mode: "light",
151
+ color: "#08c060",
152
+ fontSize: "standard",
153
+ fontFamily: "system"
154
+ }),
155
+ unistorage: true
156
+ });
157
+
158
+ // src/theme/index.ts
159
+ var DEFAULT_THEME = {
160
+ mode: "light",
161
+ color: "#08c060",
162
+ fontSize: "standard",
163
+ fontFamily: "system"
164
+ };
165
+ var THEME_COLORS = [
166
+ { name: "\u9ED8\u8BA4\u7EFF", value: "#08c060" },
167
+ { name: "\u79D1\u6280\u84DD", value: "#3b82f6" },
168
+ { name: "\u7FE1\u7FE0\u7EFF", value: "#10b981" },
169
+ { name: "\u68A6\u5E7B\u7D2B", value: "#8b5cf6" },
170
+ { name: "\u6D3B\u529B\u6A59", value: "#f97316" },
171
+ { name: "\u70ED\u60C5\u7EA2", value: "#ef4444" },
172
+ { name: "\u9752\u84DD", value: "#06b6d4" },
173
+ { name: "\u7ECF\u5178\u9ED1", value: "#334155" },
174
+ { name: "\u8537\u8587\u7C89", value: "#ec4899" }
175
+ ];
176
+ function getTheme() {
177
+ const store = useThemeStore();
178
+ return {
179
+ mode: store.mode || DEFAULT_THEME.mode,
180
+ color: store.color || DEFAULT_THEME.color,
181
+ fontSize: store.fontSize || DEFAULT_THEME.fontSize,
182
+ fontFamily: store.fontFamily || DEFAULT_THEME.fontFamily
183
+ };
184
+ }
185
+ function applyTheme(themeState) {
186
+ const store = useThemeStore();
187
+ if (themeState.mode) store.mode = themeState.mode;
188
+ if (themeState.color) store.color = themeState.color;
189
+ if (themeState.fontSize && ["small", "standard", "large", "extra-large"].includes(themeState.fontSize)) {
190
+ store.fontSize = themeState.fontSize;
191
+ }
192
+ if (themeState.fontFamily && ["system", "sans", "serif", "kaiti"].includes(themeState.fontFamily)) {
193
+ store.fontFamily = themeState.fontFamily;
194
+ }
195
+ }
196
+ function initTheme(app, options = {}) {
197
+ const { sync = true, defaultTheme } = options;
198
+ app.config.globalProperties.$theme = useTheme();
199
+ app.provide("theme", useTheme());
200
+ if (sync) {
201
+ applyTheme({ ...getTheme(), ...defaultTheme });
202
+ }
203
+ }
204
+ function useTheme() {
205
+ const store = useThemeStore();
206
+ const mode = toRef(store, "mode");
207
+ const color = toRef(store, "color");
208
+ const fontSize = toRef(store, "fontSize");
209
+ const fontFamily = toRef(store, "fontFamily");
210
+ const fontSizeClass = computed(() => {
211
+ return fontSizePresets.find((item) => item.id === store.fontSize)?.class || "font-size-standard";
212
+ });
213
+ const fontFamilyClass = computed(() => {
214
+ return fontFamilyPresets.find((item) => item.id === store.fontFamily)?.class || "font-family-system";
215
+ });
216
+ function setMode(targetMode) {
217
+ store.mode = targetMode;
218
+ }
219
+ function setColor(hexColor) {
220
+ store.color = hexColor;
221
+ }
222
+ function setFontSize(targetSize) {
223
+ if (["small", "standard", "large", "extra-large"].includes(targetSize)) {
224
+ store.fontSize = targetSize;
225
+ }
226
+ }
227
+ function setFontFamily(targetFont) {
228
+ if (["system", "sans", "serif", "kaiti"].includes(targetFont)) {
229
+ store.fontFamily = targetFont;
230
+ }
231
+ }
232
+ function resetTheme() {
233
+ store.mode = DEFAULT_THEME.mode;
234
+ store.color = DEFAULT_THEME.color;
235
+ store.fontSize = DEFAULT_THEME.fontSize;
236
+ store.fontFamily = DEFAULT_THEME.fontFamily;
237
+ }
238
+ return {
239
+ mode,
240
+ color,
241
+ fontSize,
242
+ fontSizeClass,
243
+ fontFamily,
244
+ fontFamilyClass,
245
+ colors: THEME_COLORS,
246
+ fontSizePresets,
247
+ fontFamilyPresets,
248
+ setMode,
249
+ setColor,
250
+ setFontSize,
251
+ setFontFamily,
252
+ resetTheme,
253
+ applyTheme,
254
+ getTheme,
255
+ initTheme,
256
+ store
257
+ };
258
+ }
259
+
260
+ // src/share/index.ts
261
+ import { onShareAppMessage, onShareTimeline } from "@dcloudio/uni-app";
262
+ function showShareMenu() {
263
+ uni.showShareMenu({
264
+ withShareTicket: true,
265
+ menus: ["shareAppMessage", "shareTimeline"]
266
+ });
267
+ }
268
+ function useShare(config = {}) {
269
+ showShareMenu();
270
+ onShareAppMessage(() => ({ ...config }));
271
+ onShareTimeline(() => {
272
+ return {
273
+ title: config.title,
274
+ query: config.path?.split("?")[1],
275
+ imageUrl: config.imageUrl
276
+ };
277
+ });
278
+ return {
279
+ showShareMenu
280
+ };
281
+ }
282
+
283
+ // src/refs/index.ts
284
+ import { ref, onBeforeUpdate, onUnmounted } from "vue";
285
+ function useRefs() {
286
+ const refs = ref({});
287
+ onBeforeUpdate(() => {
288
+ refs.value = {};
289
+ });
290
+ onUnmounted(() => {
291
+ refs.value = {};
292
+ });
293
+ const setRefs = (key) => (element) => {
294
+ if (element) refs.value[key] = element;
295
+ };
296
+ return { refs, setRefs };
297
+ }
298
+ export {
299
+ DEFAULT_THEME,
300
+ THEME_COLORS,
301
+ applyTheme,
302
+ fontFamilyPresets,
303
+ fontSizePresets,
304
+ getTheme,
305
+ initTheme,
306
+ showShareMenu,
307
+ useMsg,
308
+ useRefs,
309
+ useShare,
310
+ useTheme,
311
+ useThemeStore
312
+ };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@hlw-uni-mp/use",
3
+ "version": "1.0.0",
4
+ "description": "Universal Uni-App Vue 3 stateful composables library",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "dev": "tsup --watch"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "peerDependencies": {
26
+ "@dcloudio/uni-app": ">=3.0.0",
27
+ "pinia": ">=2.0.0",
28
+ "vue": ">=3.4.0"
29
+ },
30
+ "peerDependenciesMeta": {
31
+ "@dcloudio/uni-app": {
32
+ "optional": true
33
+ }
34
+ },
35
+ "dependencies": {
36
+ "@hlw-uni-mp/pinia-plugin-storage": "^1.0.1",
37
+ "@hlw-uni-mp/request": "^1.0.5"
38
+ },
39
+ "devDependencies": {
40
+ "@dcloudio/types": "^3.4.30",
41
+ "@dcloudio/uni-app": "3.0.0-5000720260410001",
42
+ "pinia": "^2.3.1",
43
+ "tsup": "^8.5.1",
44
+ "typescript": "^5.9.3",
45
+ "vue": "^3.5.34"
46
+ }
47
+ }