@hlw-uni/mp-vue 1.1.8 → 1.1.12

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/README.md CHANGED
@@ -32,7 +32,7 @@ pnpm add @hlw-uni/mp-vue
32
32
 
33
33
  ```ts
34
34
  import { HlwAd, HlwAvatar, HlwEmpty, HlwLoading, HlwMenuList } from '@hlw-uni/mp-vue';
35
- import type { MenuItem } from '@hlw-uni/mp-vue';
35
+ import type { MenuItem, HlwPagingRef } from '@hlw-uni/mp-vue';
36
36
  ```
37
37
 
38
38
  可在页面或组件中直接注册并使用:
@@ -288,6 +288,95 @@ mp-vue/
288
288
  └── vite.config.ts
289
289
  ```
290
290
 
291
+ ## HlwPaging
292
+
293
+ 基于 `z-paging` 的包装组件。保留 `z-paging` 原始 props、事件和大部分插槽,同时默认接入 `hlw-loading` 和 `hlw-empty` 作为加载态与空态展示。
294
+
295
+ **额外 Props**
296
+
297
+ | 属性 | 类型 | 默认值 | 说明 |
298
+ | --- | --- | --- | --- |
299
+ | `loadingText` | `string` | `'加载中...'` | 默认 loading 文案 |
300
+ | `emptyText` | `string` | `'暂无数据'` | 默认空态文案 |
301
+ | `errorText` | `string` | `'加载失败,请稍后重试'` | 默认失败文案 |
302
+ | `emptyImage` | `string` | `''` | 自定义空态图片 |
303
+ | `useDefaultLoading` | `boolean` | `true` | 是否启用默认 loading 插槽 |
304
+ | `useDefaultEmpty` | `boolean` | `true` | 是否启用默认 empty 插槽 |
305
+
306
+ **插槽**
307
+
308
+ - 继续支持 `z-paging` 的原始插槽,如 `loading`、`empty`、`refresher`、`top`、`bottom`
309
+ - 额外支持 `empty-extra`,用于在默认空态下方插入自定义内容
310
+
311
+ **Ref 类型**
312
+
313
+ ```ts
314
+ import type { HlwPagingRef } from '@hlw-uni/mp-vue';
315
+ ```
316
+
317
+ **基础示例**
318
+
319
+ ```vue
320
+ <script setup lang="ts">
321
+ import { ref } from 'vue';
322
+ import type { HlwPagingRef } from '@hlw-uni/mp-vue';
323
+
324
+ interface ListItem {
325
+ id: number;
326
+ title: string;
327
+ }
328
+
329
+ const paging = ref<HlwPagingRef<ListItem> | null>(null);
330
+ const dataList = ref<ListItem[]>([]);
331
+
332
+ const queryList = async (pageNo: number, pageSize: number) => {
333
+ const list = Array.from({ length: pageSize }, (_, index) => ({
334
+ id: (pageNo - 1) * pageSize + index + 1,
335
+ title: `第 ${pageNo} 页数据 ${index + 1}`,
336
+ }));
337
+
338
+ paging.value?.completeByNoMore(list, pageNo >= 3);
339
+ };
340
+ </script>
341
+
342
+ <template>
343
+ <hlw-paging
344
+ ref="paging"
345
+ v-model="dataList"
346
+ @query="queryList"
347
+ loading-text="正在同步数据"
348
+ empty-text="还没有任何记录"
349
+ >
350
+ <view v-for="item in dataList" :key="item.id" class="demo-row">
351
+ {{ item.title }}
352
+ </view>
353
+ </hlw-paging>
354
+ </template>
355
+ ```
356
+
357
+ **自定义空态**
358
+
359
+ ```vue
360
+ <hlw-paging v-model="dataList" @query="queryList" :use-default-empty="false">
361
+ <template #empty="{ isLoadFailed }">
362
+ <hlw-empty :text="isLoadFailed ? '请求失败,请重试' : '这里暂时还是空的'" />
363
+ </template>
364
+ </hlw-paging>
365
+ ```
366
+
367
+ **常用 Ref 方法**
368
+
369
+ - `reload(animate?)`
370
+ - `refresh()`
371
+ - `complete(list)`
372
+ - `completeByTotal(list, total)`
373
+ - `completeByNoMore(list, noMore)`
374
+ - `completeByError(cause)`
375
+ - `clear()`
376
+ - `scrollToTop()`
377
+
378
+ 更多分页能力和原始参数可参考 `z-paging` 文档:https://z-paging.zxlee.cn
379
+
291
380
  ## License
292
381
 
293
382
  内部组件库,仅供 hlw-uni 项目使用。
@@ -0,0 +1,49 @@
1
+ export interface HlwPagingReturnData<T = any> {
2
+ totalList: T[];
3
+ noMore: boolean;
4
+ }
5
+ export interface HlwPagingRef<T = any> {
6
+ reload: (animate?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
7
+ refresh: () => Promise<HlwPagingReturnData<T>> | undefined;
8
+ refreshToPage: (page: number) => Promise<HlwPagingReturnData<T>> | undefined;
9
+ complete: (data?: T[] | false, success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
10
+ completeByTotal: (data: T[], total: number, success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
11
+ completeByNoMore: (data: T[], noMore: boolean, success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
12
+ completeByError: (cause: string) => Promise<HlwPagingReturnData<T>> | undefined;
13
+ completeByKey: (data: T[], key: string, success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
14
+ clear: () => void;
15
+ addDataFromTop: (data: T | T[], scrollToTop?: boolean, animate?: boolean) => void;
16
+ resetTotalData: (data: T[]) => void;
17
+ endRefresh: () => void;
18
+ updateCustomRefresherHeight: () => void;
19
+ goF2: () => void;
20
+ closeF2: () => void;
21
+ doLoadMore: (source?: "click" | "toBottom") => void;
22
+ updatePageScrollTop: (scrollTop: number) => void;
23
+ updatePageScrollTopHeight: () => void;
24
+ updatePageScrollBottomHeight: () => void;
25
+ updateLeftAndRightWidth: () => void;
26
+ updateFixedLayout: () => void;
27
+ doInsertVirtualListItem: (item: T, index: number) => void;
28
+ didUpdateVirtualListCell: (index: number) => void;
29
+ didDeleteVirtualListCell: (index: number) => void;
30
+ updateVirtualListRender: () => void;
31
+ setLocalPaging: (data: T[], success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
32
+ doChatRecordLoadMore: () => void;
33
+ addChatRecordData: (data: T | T[], scrollToBottom?: boolean, animate?: boolean) => void;
34
+ addKeyboardHeightChangeListener: () => void;
35
+ scrollToTop: (animate?: boolean) => void;
36
+ scrollToBottom: (animate?: boolean) => void;
37
+ scrollIntoViewById: (id: string, offset?: number, animate?: boolean) => void;
38
+ scrollIntoViewByNodeTop: (top: number, offset?: number, animate?: boolean) => void;
39
+ scrollToY: (y: number, offset?: number, animate?: boolean) => void;
40
+ scrollToX: (x: number, offset?: number, animate?: boolean) => void;
41
+ scrollIntoViewByIndex: (index: number, offset?: number, animate?: boolean) => void;
42
+ scrollIntoViewByView: (view: unknown, offset?: number, animate?: boolean) => void;
43
+ setSpecialEffects: (args: Record<string, any>) => void;
44
+ setListSpecialEffects: (args: Record<string, any>) => void;
45
+ updateCache: () => void;
46
+ getVersion: () => string | undefined;
47
+ }
48
+ export interface HlwPagingInstance<T = any> extends HlwPagingRef<T> {
49
+ }
@@ -7,4 +7,4 @@ export declare function useThemePageStyle(): {
7
7
  export type { FontScale, FontPreset } from './font';
8
8
  export { FONT_SCALE_KEY, FONT_PRESETS, getCurrentFontScale, getCurrentFontVars } from './font';
9
9
  export type { ThemeColor } from './palette';
10
- export { THEME_COLOR_KEY, DEFAULT_THEMES, getCurrentThemeColor, getCurrentThemeVars } from './palette';
10
+ export { THEME_COLOR_KEY, THEME_SEMANTIC_COLORS, DEFAULT_THEMES, getCurrentThemeColor, getCurrentThemeVars, } from './palette';
@@ -3,6 +3,12 @@ export interface ThemeColor {
3
3
  value: string;
4
4
  }
5
5
  export declare const THEME_COLOR_KEY = "hlw_theme_color";
6
+ export declare const THEME_SEMANTIC_COLORS: {
7
+ readonly success: "#10b981";
8
+ readonly warning: "#f59e0b";
9
+ readonly error: "#ef4444";
10
+ readonly info: "#64748b";
11
+ };
6
12
  export declare const DEFAULT_THEMES: ThemeColor[];
7
13
  export declare function getCurrentThemeColor(): string;
8
14
  export declare function getCurrentThemeVars(): Record<string, string>;
package/dist/index.d.ts CHANGED
@@ -8,5 +8,6 @@
8
8
  */
9
9
  export type { FontScale, FontPreset, ThemeColor } from './composables/theme';
10
10
  export type { HlwMenuItem } from './components/hlw-menu/types';
11
- export { FONT_PRESETS, FONT_SCALE_KEY, DEFAULT_THEMES, THEME_COLOR_KEY, THEME_CHANGE_EVENT, getCurrentFontScale, getCurrentFontVars, getCurrentThemeColor, getCurrentThemeVars, buildThemeStyle, useThemePageStyle, } from './composables/theme';
11
+ export type { HlwPagingRef, HlwPagingInstance } from './components/hlw-paging/types';
12
+ export { FONT_PRESETS, FONT_SCALE_KEY, DEFAULT_THEMES, THEME_COLOR_KEY, THEME_SEMANTIC_COLORS, THEME_CHANGE_EVENT, getCurrentFontScale, getCurrentFontVars, getCurrentThemeColor, getCurrentThemeVars, buildThemeStyle, useThemePageStyle, } from './composables/theme';
12
13
  export { useThemeStore } from './stores/theme';
package/dist/index.js CHANGED
@@ -63,11 +63,17 @@
63
63
  }
64
64
  const { hexToRgba, darkenHex } = mpCore.useColor();
65
65
  const THEME_COLOR_KEY = "hlw_theme_color";
66
+ const THEME_SEMANTIC_COLORS = {
67
+ success: "#10b981",
68
+ warning: "#f59e0b",
69
+ error: "#ef4444",
70
+ info: "#64748b"
71
+ };
66
72
  const DEFAULT_THEMES = [
67
- { label: "默认蓝", value: "#3b82f6" },
68
- { label: "活力橙", value: "#f97316" },
69
73
  { label: "翡翠绿", value: "#10b981" },
70
- { label: "玫瑰红", value: "#f43f5e" },
74
+ { label: "活力橙", value: "#f97316" },
75
+ { label: "默认蓝", value: "#3b82f6" },
76
+ { label: "玫瑰粉", value: "#f43f5e" },
71
77
  { label: "紫罗兰", value: "#8b5cf6" },
72
78
  { label: "青石灰", value: "#64748b" }
73
79
  ];
@@ -85,7 +91,31 @@
85
91
  return {
86
92
  "--primary-color": color,
87
93
  "--primary-light": hexToRgba(color, 0.12),
88
- "--primary-dark": darkenHex(color)
94
+ "--primary-dark": darkenHex(color),
95
+ "--primary-success": THEME_SEMANTIC_COLORS.success,
96
+ "--primary-success-light": hexToRgba(THEME_SEMANTIC_COLORS.success, 0.12),
97
+ "--primary-success-dark": darkenHex(THEME_SEMANTIC_COLORS.success),
98
+ "--primary-warning": THEME_SEMANTIC_COLORS.warning,
99
+ "--primary-warning-light": hexToRgba(THEME_SEMANTIC_COLORS.warning, 0.12),
100
+ "--primary-warning-dark": darkenHex(THEME_SEMANTIC_COLORS.warning),
101
+ "--primary-error": THEME_SEMANTIC_COLORS.error,
102
+ "--primary-error-light": hexToRgba(THEME_SEMANTIC_COLORS.error, 0.12),
103
+ "--primary-error-dark": darkenHex(THEME_SEMANTIC_COLORS.error),
104
+ "--primary-info": THEME_SEMANTIC_COLORS.info,
105
+ "--primary-info-light": hexToRgba(THEME_SEMANTIC_COLORS.info, 0.12),
106
+ "--primary-info-dark": darkenHex(THEME_SEMANTIC_COLORS.info),
107
+ "--success-color": THEME_SEMANTIC_COLORS.success,
108
+ "--success-light": hexToRgba(THEME_SEMANTIC_COLORS.success, 0.12),
109
+ "--success-dark": darkenHex(THEME_SEMANTIC_COLORS.success),
110
+ "--warning-color": THEME_SEMANTIC_COLORS.warning,
111
+ "--warning-light": hexToRgba(THEME_SEMANTIC_COLORS.warning, 0.12),
112
+ "--warning-dark": darkenHex(THEME_SEMANTIC_COLORS.warning),
113
+ "--error-color": THEME_SEMANTIC_COLORS.error,
114
+ "--error-light": hexToRgba(THEME_SEMANTIC_COLORS.error, 0.12),
115
+ "--error-dark": darkenHex(THEME_SEMANTIC_COLORS.error),
116
+ "--info-color": THEME_SEMANTIC_COLORS.info,
117
+ "--info-light": hexToRgba(THEME_SEMANTIC_COLORS.info, 0.12),
118
+ "--info-dark": darkenHex(THEME_SEMANTIC_COLORS.info)
89
119
  };
90
120
  }
91
121
  const { varsToStyle } = mpCore.useColor();
@@ -147,6 +177,7 @@
147
177
  exports2.FONT_SCALE_KEY = FONT_SCALE_KEY;
148
178
  exports2.THEME_CHANGE_EVENT = THEME_CHANGE_EVENT;
149
179
  exports2.THEME_COLOR_KEY = THEME_COLOR_KEY;
180
+ exports2.THEME_SEMANTIC_COLORS = THEME_SEMANTIC_COLORS;
150
181
  exports2.buildThemeStyle = buildThemeStyle;
151
182
  exports2.getCurrentFontScale = getCurrentFontScale;
152
183
  exports2.getCurrentFontVars = getCurrentFontVars;
package/dist/index.mjs CHANGED
@@ -62,11 +62,17 @@ function getCurrentFontVars() {
62
62
  }
63
63
  const { hexToRgba, darkenHex } = useColor();
64
64
  const THEME_COLOR_KEY = "hlw_theme_color";
65
+ const THEME_SEMANTIC_COLORS = {
66
+ success: "#10b981",
67
+ warning: "#f59e0b",
68
+ error: "#ef4444",
69
+ info: "#64748b"
70
+ };
65
71
  const DEFAULT_THEMES = [
66
- { label: "默认蓝", value: "#3b82f6" },
67
- { label: "活力橙", value: "#f97316" },
68
72
  { label: "翡翠绿", value: "#10b981" },
69
- { label: "玫瑰红", value: "#f43f5e" },
73
+ { label: "活力橙", value: "#f97316" },
74
+ { label: "默认蓝", value: "#3b82f6" },
75
+ { label: "玫瑰粉", value: "#f43f5e" },
70
76
  { label: "紫罗兰", value: "#8b5cf6" },
71
77
  { label: "青石灰", value: "#64748b" }
72
78
  ];
@@ -84,7 +90,31 @@ function getCurrentThemeVars() {
84
90
  return {
85
91
  "--primary-color": color,
86
92
  "--primary-light": hexToRgba(color, 0.12),
87
- "--primary-dark": darkenHex(color)
93
+ "--primary-dark": darkenHex(color),
94
+ "--primary-success": THEME_SEMANTIC_COLORS.success,
95
+ "--primary-success-light": hexToRgba(THEME_SEMANTIC_COLORS.success, 0.12),
96
+ "--primary-success-dark": darkenHex(THEME_SEMANTIC_COLORS.success),
97
+ "--primary-warning": THEME_SEMANTIC_COLORS.warning,
98
+ "--primary-warning-light": hexToRgba(THEME_SEMANTIC_COLORS.warning, 0.12),
99
+ "--primary-warning-dark": darkenHex(THEME_SEMANTIC_COLORS.warning),
100
+ "--primary-error": THEME_SEMANTIC_COLORS.error,
101
+ "--primary-error-light": hexToRgba(THEME_SEMANTIC_COLORS.error, 0.12),
102
+ "--primary-error-dark": darkenHex(THEME_SEMANTIC_COLORS.error),
103
+ "--primary-info": THEME_SEMANTIC_COLORS.info,
104
+ "--primary-info-light": hexToRgba(THEME_SEMANTIC_COLORS.info, 0.12),
105
+ "--primary-info-dark": darkenHex(THEME_SEMANTIC_COLORS.info),
106
+ "--success-color": THEME_SEMANTIC_COLORS.success,
107
+ "--success-light": hexToRgba(THEME_SEMANTIC_COLORS.success, 0.12),
108
+ "--success-dark": darkenHex(THEME_SEMANTIC_COLORS.success),
109
+ "--warning-color": THEME_SEMANTIC_COLORS.warning,
110
+ "--warning-light": hexToRgba(THEME_SEMANTIC_COLORS.warning, 0.12),
111
+ "--warning-dark": darkenHex(THEME_SEMANTIC_COLORS.warning),
112
+ "--error-color": THEME_SEMANTIC_COLORS.error,
113
+ "--error-light": hexToRgba(THEME_SEMANTIC_COLORS.error, 0.12),
114
+ "--error-dark": darkenHex(THEME_SEMANTIC_COLORS.error),
115
+ "--info-color": THEME_SEMANTIC_COLORS.info,
116
+ "--info-light": hexToRgba(THEME_SEMANTIC_COLORS.info, 0.12),
117
+ "--info-dark": darkenHex(THEME_SEMANTIC_COLORS.info)
88
118
  };
89
119
  }
90
120
  const { varsToStyle } = useColor();
@@ -147,6 +177,7 @@ export {
147
177
  FONT_SCALE_KEY,
148
178
  THEME_CHANGE_EVENT,
149
179
  THEME_COLOR_KEY,
180
+ THEME_SEMANTIC_COLORS,
150
181
  buildThemeStyle,
151
182
  getCurrentFontScale,
152
183
  getCurrentFontVars,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hlw-uni/mp-vue",
3
- "version": "1.1.8",
3
+ "version": "1.1.12",
4
4
  "description": "hlw-uni Vue 组件库 — 供小程序业务方使用的 UI 组件集合",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -40,6 +40,7 @@
40
40
  "vue": "^3.5.32"
41
41
  },
42
42
  "dependencies": {
43
- "@hlw-uni/mp-core": "^1.0.28"
43
+ "@hlw-uni/mp-core": "^1.0.28",
44
+ "z-paging": "^2.8.8"
44
45
  }
45
46
  }
@@ -124,12 +124,12 @@ const handleTap = () => {
124
124
 
125
125
  <style lang="scss" scoped>
126
126
  $semantic-colors: (
127
- primary: var(--primary-color),
128
- success: #10b981,
129
- warning: #f59e0b,
130
- danger: #ef4444,
131
- error: #ef4444,
132
- info: #64748b,
127
+ primary: var(--primary-color, #3b82f6),
128
+ success: var(--primary-success, #10b981),
129
+ warning: var(--primary-warning, #f59e0b),
130
+ danger: var(--primary-error, #ef4444),
131
+ error: var(--primary-error, #ef4444),
132
+ info: var(--primary-info, #64748b),
133
133
  );
134
134
 
135
135
  .hlw-btn {
@@ -118,7 +118,20 @@ const emit = defineEmits<{
118
118
 
119
119
  const handleBack = () => {
120
120
  emit("back");
121
- uni.navigateBack({ delta: 1 });
121
+
122
+ const pages = getCurrentPages();
123
+ if (pages.length > 1) {
124
+ uni.navigateBack({ delta: 1 });
125
+ return;
126
+ }
127
+
128
+ const homeUrl = "/pages/index/index";
129
+ uni.switchTab({
130
+ url: homeUrl,
131
+ fail: () => {
132
+ uni.reLaunch({ url: homeUrl });
133
+ },
134
+ });
122
135
  };
123
136
 
124
137
  const titleStyle = computed(() => ({
@@ -180,7 +193,7 @@ const totalNavBarHeight = computed(() => statusBarHeight.value + NAV_BAR_CONTENT
180
193
  }
181
194
 
182
195
  .header-back-icon {
183
- font-size: var(--font-md, 32rpx);
196
+ font-size: var(--font-base, 28rpx);
184
197
  color: inherit;
185
198
  }
186
199
 
@@ -10,7 +10,42 @@
10
10
  />
11
11
  </slot>
12
12
  </view>
13
+
14
+ <hlw-paging
15
+ v-if="props.usePaging"
16
+ ref="pagingRef"
17
+ class="hlw-page-content hlw-page-content--paging"
18
+ :model-value="props.modelValue"
19
+ :fixed="false"
20
+ :use-page-scroll="false"
21
+ :height="'100%'"
22
+ :refresher-enabled="props.refresherEnabled"
23
+ :loading-more-enabled="props.loadingMoreEnabled"
24
+ :default-page-size="props.defaultPageSize"
25
+ :loading-text="props.loadingText"
26
+ :empty-text="props.emptyText"
27
+ :error-text="props.errorText"
28
+ :empty-image="props.emptyImage"
29
+ :use-default-loading="props.useDefaultLoading"
30
+ :use-default-empty="props.useDefaultEmpty"
31
+ @update:model-value="handleUpdateModelValue"
32
+ @query="handleQuery"
33
+ >
34
+ <slot />
35
+
36
+ <template v-if="$slots.loading" #loading="slotProps">
37
+ <slot name="loading" :isLoadFailed="slotProps && slotProps.isLoadFailed" />
38
+ </template>
39
+ <template v-if="$slots.empty" #empty="slotProps">
40
+ <slot name="empty" :isLoadFailed="slotProps && slotProps.isLoadFailed" />
41
+ </template>
42
+ <template v-if="$slots['empty-extra']" #empty-extra="slotProps">
43
+ <slot name="empty-extra" :isLoadFailed="slotProps && slotProps.isLoadFailed" />
44
+ </template>
45
+ </hlw-paging>
46
+
13
47
  <scroll-view
48
+ v-else
14
49
  class="hlw-page-content"
15
50
  :scroll-y="true"
16
51
  :enable-flex="true"
@@ -18,53 +53,131 @@
18
53
  :show-scrollbar="false"
19
54
  :style="themePageStyle"
20
55
  >
21
- <slot></slot>
56
+ <slot />
22
57
  </scroll-view>
58
+
23
59
  <view class="hlw-page-footer">
24
- <slot name="footer"></slot>
60
+ <slot name="footer" />
25
61
  </view>
26
62
  </view>
27
63
  </template>
28
64
 
29
65
  <script setup lang="ts">
66
+ import { ref } from "vue";
67
+ import type { HlwPagingRef } from "../hlw-paging/types";
30
68
  import { useThemePageStyle } from "../../composables/theme";
31
- /**
32
- * HlwPage — 页面布局容器
33
- *
34
- * 全屏 flex 布局:固定 header + 可滚动 content + 固定 footer。
35
- * 传入 title/isBack 自动渲染 HlwHeader,也可通过 header 插槽完全自定义。
36
- *
37
- * @props
38
- * title - 页面标题(自动渲染 HlwHeader)
39
- * isBack - 是否显示返回按钮,默认 false
40
- * bgClass - header 背景 CSS class
41
- *
42
- * @slots
43
- * header - 自定义顶部(覆盖默认 HlwHeader)
44
- * default - 主体可滚动内容
45
- * footer - 固定底部
46
- *
47
- * @example
48
- * ```vue
49
- * <HlwPage title="首页" bg-class="header-bg">
50
- * <view>页面内容</view>
51
- * <template #footer><view>底部栏</view></template>
52
- * </HlwPage>
53
- * ```
54
- */
69
+
70
+ defineOptions({
71
+ name: "HlwPage",
72
+ inheritAttrs: false,
73
+ });
74
+
55
75
  interface Props {
56
76
  title?: string;
57
77
  isBack?: boolean;
58
78
  bgClass?: string;
79
+ usePaging?: boolean;
80
+ modelValue?: any[];
81
+ refresherEnabled?: boolean;
82
+ loadingMoreEnabled?: boolean;
83
+ defaultPageSize?: number;
84
+ loadingText?: string;
85
+ emptyText?: string;
86
+ errorText?: string;
87
+ emptyImage?: string;
88
+ useDefaultLoading?: boolean;
89
+ useDefaultEmpty?: boolean;
59
90
  }
60
91
 
61
92
  const props = withDefaults(defineProps<Props>(), {
62
93
  title: "",
63
94
  isBack: false,
64
95
  bgClass: "",
96
+ usePaging: false,
97
+ modelValue: () => [],
98
+ useDefaultLoading: true,
99
+ useDefaultEmpty: true,
65
100
  });
66
101
 
102
+ const emit = defineEmits<{
103
+ "update:modelValue": [value: any[]];
104
+ query: [pageNo: number, pageSize: number, ...args: any[]];
105
+ }>();
106
+
107
+ const pagingRef = ref<HlwPagingRef<any> | null>(null);
67
108
  const { themePageStyle } = useThemePageStyle();
109
+
110
+ function handleUpdateModelValue(value: any[]) {
111
+ emit("update:modelValue", value ?? []);
112
+ }
113
+
114
+ function handleQuery(pageNo: number, pageSize: number, ...args: any[]) {
115
+ emit("query", pageNo, pageSize, ...args);
116
+ }
117
+
118
+ const getPagingRef = () => pagingRef.value;
119
+
120
+ const pagingMethodNames = [
121
+ "reload",
122
+ "refresh",
123
+ "refreshToPage",
124
+ "complete",
125
+ "completeByTotal",
126
+ "completeByNoMore",
127
+ "completeByError",
128
+ "completeByKey",
129
+ "clear",
130
+ "addDataFromTop",
131
+ "resetTotalData",
132
+ "endRefresh",
133
+ "updateCustomRefresherHeight",
134
+ "goF2",
135
+ "closeF2",
136
+ "doLoadMore",
137
+ "updatePageScrollTop",
138
+ "updatePageScrollTopHeight",
139
+ "updatePageScrollBottomHeight",
140
+ "updateLeftAndRightWidth",
141
+ "updateFixedLayout",
142
+ "doInsertVirtualListItem",
143
+ "didUpdateVirtualListCell",
144
+ "didDeleteVirtualListCell",
145
+ "updateVirtualListRender",
146
+ "setLocalPaging",
147
+ "doChatRecordLoadMore",
148
+ "addChatRecordData",
149
+ "addKeyboardHeightChangeListener",
150
+ "scrollToTop",
151
+ "scrollToBottom",
152
+ "scrollIntoViewById",
153
+ "scrollIntoViewByNodeTop",
154
+ "scrollToY",
155
+ "scrollToX",
156
+ "scrollIntoViewByIndex",
157
+ "scrollIntoViewByView",
158
+ "setSpecialEffects",
159
+ "setListSpecialEffects",
160
+ "updateCache",
161
+ "getVersion",
162
+ ] as const;
163
+
164
+ type PagingMethodName = (typeof pagingMethodNames)[number];
165
+
166
+ const exposed = pagingMethodNames.reduce((result, methodName) => {
167
+ result[methodName] = (...args: any[]) => {
168
+ return pagingRef.value?.[methodName]?.(...args);
169
+ };
170
+
171
+ return result;
172
+ }, {
173
+ pagingRef,
174
+ getPagingRef,
175
+ } as Record<string, any>);
176
+
177
+ defineExpose(exposed as {
178
+ pagingRef: typeof pagingRef;
179
+ getPagingRef: () => HlwPagingRef<any> | null;
180
+ } & Record<PagingMethodName, (...args: any[]) => any>);
68
181
  </script>
69
182
 
70
183
  <style lang="scss" scoped>
@@ -86,6 +199,10 @@ const { themePageStyle } = useThemePageStyle();
86
199
  width: 100%;
87
200
  }
88
201
 
202
+ .hlw-page-content--paging {
203
+ min-height: 0;
204
+ }
205
+
89
206
  .hlw-page-footer {
90
207
  flex-shrink: 0;
91
208
  }
@@ -0,0 +1,192 @@
1
+ <template>
2
+ <z-paging
3
+ ref="pagingRef"
4
+ class="hlw-paging"
5
+ :model-value="props.modelValue"
6
+ :fixed="props.fixed"
7
+ :use-page-scroll="props.usePageScroll"
8
+ :height="props.height"
9
+ :refresher-enabled="props.refresherEnabled"
10
+ :loading-more-enabled="props.loadingMoreEnabled"
11
+ :default-page-size="props.defaultPageSize"
12
+ @update:model-value="handleUpdateModelValue"
13
+ @query="handleQuery"
14
+ >
15
+ <slot />
16
+
17
+ <template v-if="$slots.loading && !showDefaultLoading" #loading="slotProps">
18
+ <slot name="loading" :isLoadFailed="slotProps && slotProps.isLoadFailed" />
19
+ </template>
20
+
21
+ <template v-if="$slots.empty && !showDefaultEmpty" #empty="slotProps">
22
+ <slot name="empty" :isLoadFailed="slotProps && slotProps.isLoadFailed" />
23
+ </template>
24
+
25
+ <template v-if="$slots['empty-extra']" #empty-extra="slotProps">
26
+ <slot name="empty-extra" :isLoadFailed="slotProps && slotProps.isLoadFailed" />
27
+ </template>
28
+
29
+ <template v-if="showDefaultLoading" #loading>
30
+ <view class="hlw-paging__state hlw-paging__state--loading">
31
+ <hlw-loading :text="props.loadingText" />
32
+ </view>
33
+ </template>
34
+
35
+ <template v-if="showDefaultEmpty" #empty="{ isLoadFailed }">
36
+ <view class="hlw-paging__state hlw-paging__state--empty">
37
+ <hlw-empty
38
+ :image="props.emptyImage"
39
+ :text="isLoadFailed ? props.errorText : props.emptyText"
40
+ >
41
+ <slot name="empty-extra" :isLoadFailed="isLoadFailed" />
42
+ </hlw-empty>
43
+ </view>
44
+ </template>
45
+ </z-paging>
46
+ </template>
47
+
48
+ <script setup lang="ts">
49
+ import { computed, ref, useSlots } from "vue";
50
+ import ZPaging from "z-paging/components/z-paging/z-paging.vue";
51
+ import type { HlwPagingRef } from "./types";
52
+
53
+ defineOptions({
54
+ name: "HlwPaging",
55
+ inheritAttrs: false,
56
+ });
57
+
58
+ interface Props {
59
+ modelValue?: any[];
60
+ fixed?: boolean;
61
+ usePageScroll?: boolean;
62
+ height?: string;
63
+ refresherEnabled?: boolean;
64
+ loadingMoreEnabled?: boolean;
65
+ defaultPageSize?: number;
66
+ loadingText?: string;
67
+ emptyText?: string;
68
+ errorText?: string;
69
+ emptyImage?: string;
70
+ useDefaultLoading?: boolean;
71
+ useDefaultEmpty?: boolean;
72
+ }
73
+
74
+ const props = withDefaults(defineProps<Props>(), {
75
+ modelValue: () => [],
76
+ loadingText: "加载中...",
77
+ emptyText: "暂无数据",
78
+ errorText: "加载失败,请稍后重试",
79
+ emptyImage: "",
80
+ useDefaultLoading: true,
81
+ useDefaultEmpty: true,
82
+ });
83
+
84
+ const emit = defineEmits<{
85
+ "update:modelValue": [value: any[]];
86
+ query: [pageNo: number, pageSize: number, ...args: any[]];
87
+ }>();
88
+
89
+ const slots = useSlots();
90
+ const pagingRef = ref<HlwPagingRef<any> | null>(null);
91
+
92
+ function handleUpdateModelValue(value: any[]) {
93
+ emit("update:modelValue", value ?? []);
94
+ }
95
+
96
+ function handleQuery(pageNo: number, pageSize: number, ...args: any[]) {
97
+ emit("query", pageNo, pageSize, ...args);
98
+ }
99
+
100
+ const showDefaultLoading = computed(() => {
101
+ return props.useDefaultLoading && !slots.loading;
102
+ });
103
+
104
+ const showDefaultEmpty = computed(() => {
105
+ return props.useDefaultEmpty && !slots.empty;
106
+ });
107
+
108
+ const getPagingRef = () => pagingRef.value;
109
+
110
+ const pagingMethodNames = [
111
+ "reload",
112
+ "refresh",
113
+ "refreshToPage",
114
+ "complete",
115
+ "completeByTotal",
116
+ "completeByNoMore",
117
+ "completeByError",
118
+ "completeByKey",
119
+ "clear",
120
+ "addDataFromTop",
121
+ "resetTotalData",
122
+ "endRefresh",
123
+ "updateCustomRefresherHeight",
124
+ "goF2",
125
+ "closeF2",
126
+ "doLoadMore",
127
+ "updatePageScrollTop",
128
+ "updatePageScrollTopHeight",
129
+ "updatePageScrollBottomHeight",
130
+ "updateLeftAndRightWidth",
131
+ "updateFixedLayout",
132
+ "doInsertVirtualListItem",
133
+ "didUpdateVirtualListCell",
134
+ "didDeleteVirtualListCell",
135
+ "updateVirtualListRender",
136
+ "setLocalPaging",
137
+ "doChatRecordLoadMore",
138
+ "addChatRecordData",
139
+ "addKeyboardHeightChangeListener",
140
+ "scrollToTop",
141
+ "scrollToBottom",
142
+ "scrollIntoViewById",
143
+ "scrollIntoViewByNodeTop",
144
+ "scrollToY",
145
+ "scrollToX",
146
+ "scrollIntoViewByIndex",
147
+ "scrollIntoViewByView",
148
+ "setSpecialEffects",
149
+ "setListSpecialEffects",
150
+ "updateCache",
151
+ "getVersion",
152
+ ] as const;
153
+
154
+ type PagingMethodName = (typeof pagingMethodNames)[number];
155
+
156
+ const exposed = pagingMethodNames.reduce((result, methodName) => {
157
+ result[methodName] = (...args: any[]) => {
158
+ return pagingRef.value?.[methodName]?.(...args);
159
+ };
160
+
161
+ return result;
162
+ }, {
163
+ pagingRef,
164
+ getPagingRef,
165
+ } as Record<string, any>);
166
+
167
+ defineExpose(exposed as {
168
+ pagingRef: typeof pagingRef;
169
+ getPagingRef: () => HlwPagingRef<any> | null;
170
+ } & Record<PagingMethodName, (...args: any[]) => any>);
171
+ </script>
172
+
173
+ <style scoped lang="scss">
174
+ .hlw-paging {
175
+ width: 100%;
176
+ }
177
+
178
+ .hlw-paging__state {
179
+ width: 100%;
180
+ display: flex;
181
+ justify-content: center;
182
+ }
183
+
184
+ .hlw-paging__state--loading {
185
+ padding: 24rpx 0;
186
+ }
187
+
188
+ .hlw-paging__state--empty {
189
+ min-height: 360rpx;
190
+ padding: 32rpx 0;
191
+ }
192
+ </style>
@@ -0,0 +1,50 @@
1
+ export interface HlwPagingReturnData<T = any> {
2
+ totalList: T[];
3
+ noMore: boolean;
4
+ }
5
+
6
+ export interface HlwPagingRef<T = any> {
7
+ reload: (animate?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
8
+ refresh: () => Promise<HlwPagingReturnData<T>> | undefined;
9
+ refreshToPage: (page: number) => Promise<HlwPagingReturnData<T>> | undefined;
10
+ complete: (data?: T[] | false, success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
11
+ completeByTotal: (data: T[], total: number, success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
12
+ completeByNoMore: (data: T[], noMore: boolean, success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
13
+ completeByError: (cause: string) => Promise<HlwPagingReturnData<T>> | undefined;
14
+ completeByKey: (data: T[], key: string, success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
15
+ clear: () => void;
16
+ addDataFromTop: (data: T | T[], scrollToTop?: boolean, animate?: boolean) => void;
17
+ resetTotalData: (data: T[]) => void;
18
+ endRefresh: () => void;
19
+ updateCustomRefresherHeight: () => void;
20
+ goF2: () => void;
21
+ closeF2: () => void;
22
+ doLoadMore: (source?: "click" | "toBottom") => void;
23
+ updatePageScrollTop: (scrollTop: number) => void;
24
+ updatePageScrollTopHeight: () => void;
25
+ updatePageScrollBottomHeight: () => void;
26
+ updateLeftAndRightWidth: () => void;
27
+ updateFixedLayout: () => void;
28
+ doInsertVirtualListItem: (item: T, index: number) => void;
29
+ didUpdateVirtualListCell: (index: number) => void;
30
+ didDeleteVirtualListCell: (index: number) => void;
31
+ updateVirtualListRender: () => void;
32
+ setLocalPaging: (data: T[], success?: boolean) => Promise<HlwPagingReturnData<T>> | undefined;
33
+ doChatRecordLoadMore: () => void;
34
+ addChatRecordData: (data: T | T[], scrollToBottom?: boolean, animate?: boolean) => void;
35
+ addKeyboardHeightChangeListener: () => void;
36
+ scrollToTop: (animate?: boolean) => void;
37
+ scrollToBottom: (animate?: boolean) => void;
38
+ scrollIntoViewById: (id: string, offset?: number, animate?: boolean) => void;
39
+ scrollIntoViewByNodeTop: (top: number, offset?: number, animate?: boolean) => void;
40
+ scrollToY: (y: number, offset?: number, animate?: boolean) => void;
41
+ scrollToX: (x: number, offset?: number, animate?: boolean) => void;
42
+ scrollIntoViewByIndex: (index: number, offset?: number, animate?: boolean) => void;
43
+ scrollIntoViewByView: (view: unknown, offset?: number, animate?: boolean) => void;
44
+ setSpecialEffects: (args: Record<string, any>) => void;
45
+ setListSpecialEffects: (args: Record<string, any>) => void;
46
+ updateCache: () => void;
47
+ getVersion: () => string | undefined;
48
+ }
49
+
50
+ export interface HlwPagingInstance<T = any> extends HlwPagingRef<T> {}
@@ -0,0 +1,263 @@
1
+ <template>
2
+ <view v-if="visible" class="hlw-sheet-root" :class="{ show: shown }">
3
+ <view class="hlw-sheet-overlay" @tap="handleMaskTap" />
4
+ <view class="hlw-sheet-panel" :style="{ maxHeight }" @tap.stop>
5
+ <view class="hlw-sheet-header">
6
+ <view v-if="showHandle" class="hlw-sheet-handle" />
7
+ <text v-if="title" class="hlw-sheet-title">{{ title }}</text>
8
+ <view v-if="showClose" class="hlw-sheet-close" @tap="handleClose">
9
+ <text class="i-fa6-solid-xmark" />
10
+ </view>
11
+ </view>
12
+
13
+ <scroll-view class="hlw-sheet-body" scroll-y :show-scrollbar="false">
14
+ <view class="hlw-sheet-body-inner">
15
+ <slot />
16
+ <view v-if="showCta" class="hlw-sheet-cta" @tap="handleCta">
17
+ <text class="hlw-sheet-cta-text">{{ ctaText }}</text>
18
+ </view>
19
+ <slot name="footer" />
20
+ </view>
21
+ </scroll-view>
22
+ </view>
23
+ </view>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ /**
28
+ * HlwSheet — 通用底部弹窗(Bottom Sheet)
29
+ *
30
+ * 单根模板 + position:fixed 覆盖视口,内部 overlay 与 panel 使用 absolute 定位。
31
+ * 自管入场/出场动画时序(16ms 入场,300ms 出场),父组件只需 v-model 控制显隐。
32
+ *
33
+ * @props
34
+ * modelValue - 是否显示(v-model)
35
+ * title - 标题文字
36
+ * showHandle - 是否显示顶部拖拽条,默认 true
37
+ * showClose - 是否显示关闭按钮,默认 true
38
+ * closeOnMask - 点击遮罩是否关闭,默认 true
39
+ * showCta - 是否显示底部主按钮,默认 false
40
+ * ctaText - 底部按钮文字,默认 "确定"
41
+ * maxHeight - 最大高度,默认 "85vh"
42
+ *
43
+ * @events
44
+ * update:modelValue - v-model 更新
45
+ * close - 关闭触发
46
+ * cta - 点击底部按钮
47
+ *
48
+ * @slots
49
+ * default - 主内容(自动在 scroll-view 中滚动)
50
+ * footer - 自定义底部区(紧跟 CTA 按钮之后)
51
+ *
52
+ * @example
53
+ * ```vue
54
+ * <hlw-sheet v-model="visible" title="标题" show-cta cta-text="确定" @cta="handleOk">
55
+ * <view>内容区</view>
56
+ * </hlw-sheet>
57
+ * ```
58
+ */
59
+ import { ref, watch, onBeforeUnmount } from "vue";
60
+
61
+ interface Props {
62
+ modelValue: boolean;
63
+ title?: string;
64
+ showHandle?: boolean;
65
+ showClose?: boolean;
66
+ closeOnMask?: boolean;
67
+ showCta?: boolean;
68
+ ctaText?: string;
69
+ maxHeight?: string;
70
+ }
71
+
72
+ const props = withDefaults(defineProps<Props>(), {
73
+ modelValue: false,
74
+ title: "",
75
+ showHandle: true,
76
+ showClose: true,
77
+ closeOnMask: true,
78
+ showCta: false,
79
+ ctaText: "确定",
80
+ maxHeight: "85vh",
81
+ });
82
+
83
+ const emit = defineEmits<{
84
+ (e: "update:modelValue", value: boolean): void;
85
+ (e: "close"): void;
86
+ (e: "cta"): void;
87
+ }>();
88
+
89
+ const visible = ref(false);
90
+ const shown = ref(false);
91
+
92
+ let closeTimer: ReturnType<typeof setTimeout> | null = null;
93
+ let openTimer: ReturnType<typeof setTimeout> | null = null;
94
+
95
+ const clearTimers = () => {
96
+ if (closeTimer) {
97
+ clearTimeout(closeTimer);
98
+ closeTimer = null;
99
+ }
100
+ if (openTimer) {
101
+ clearTimeout(openTimer);
102
+ openTimer = null;
103
+ }
104
+ };
105
+
106
+ watch(
107
+ () => props.modelValue,
108
+ (val) => {
109
+ clearTimers();
110
+ if (val) {
111
+ visible.value = true;
112
+ openTimer = setTimeout(() => {
113
+ shown.value = true;
114
+ }, 16);
115
+ } else if (visible.value) {
116
+ shown.value = false;
117
+ closeTimer = setTimeout(() => {
118
+ visible.value = false;
119
+ }, 300);
120
+ }
121
+ },
122
+ { immediate: true }
123
+ );
124
+
125
+ const handleClose = () => {
126
+ emit("update:modelValue", false);
127
+ emit("close");
128
+ };
129
+
130
+ const handleMaskTap = () => {
131
+ if (props.closeOnMask) handleClose();
132
+ };
133
+
134
+ const handleCta = () => {
135
+ emit("cta");
136
+ emit("update:modelValue", false);
137
+ };
138
+
139
+ onBeforeUnmount(() => {
140
+ clearTimers();
141
+ });
142
+ </script>
143
+
144
+ <style lang="scss" scoped>
145
+ .hlw-sheet-root {
146
+ position: fixed;
147
+ top: 0;
148
+ left: 0;
149
+ right: 0;
150
+ bottom: 0;
151
+ z-index: 1000;
152
+ }
153
+
154
+ .hlw-sheet-overlay {
155
+ position: absolute;
156
+ top: 0;
157
+ left: 0;
158
+ right: 0;
159
+ bottom: 0;
160
+ background: rgba(0, 0, 0, 0.55);
161
+ opacity: 0;
162
+ transition: opacity 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
163
+ }
164
+
165
+ .hlw-sheet-root.show .hlw-sheet-overlay {
166
+ opacity: 1;
167
+ }
168
+
169
+ .hlw-sheet-panel {
170
+ position: absolute;
171
+ left: 0;
172
+ right: 0;
173
+ bottom: 0;
174
+ background: #ffffff;
175
+ border-radius: var(--radius-xl, 32rpx) var(--radius-xl, 32rpx) 0 0;
176
+ display: flex;
177
+ flex-direction: column;
178
+ transform: translateY(100%);
179
+ transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
180
+ box-shadow: 0 -12rpx 48rpx rgba(15, 23, 42, 0.15);
181
+ }
182
+
183
+ .hlw-sheet-root.show .hlw-sheet-panel {
184
+ transform: translateY(0);
185
+ }
186
+
187
+ .hlw-sheet-header {
188
+ position: relative;
189
+ display: flex;
190
+ flex-direction: column;
191
+ align-items: center;
192
+ padding: 20rpx 0 24rpx;
193
+ }
194
+
195
+ .hlw-sheet-handle {
196
+ width: 72rpx;
197
+ height: 8rpx;
198
+ border-radius: 999rpx;
199
+ background: var(--border-color, #e2e8f0);
200
+ margin-bottom: 20rpx;
201
+ }
202
+
203
+ .hlw-sheet-title {
204
+ font-size: var(--font-md, 32rpx);
205
+ font-weight: 700;
206
+ color: #0f172a;
207
+ }
208
+
209
+ .hlw-sheet-close {
210
+ position: absolute;
211
+ right: 24rpx;
212
+ top: 24rpx;
213
+ width: 56rpx;
214
+ height: 56rpx;
215
+ border-radius: 50%;
216
+ background: var(--border-color-light, #f1f5f9);
217
+ color: #64748b;
218
+ display: flex;
219
+ align-items: center;
220
+ justify-content: center;
221
+ font-size: var(--font-sm, 24rpx);
222
+ transition: background 0.2s ease;
223
+
224
+ &:active {
225
+ background: var(--border-color, #e2e8f0);
226
+ }
227
+ }
228
+
229
+ .hlw-sheet-body {
230
+ flex: 1;
231
+ height: 0;
232
+ width: 100%;
233
+ }
234
+
235
+ .hlw-sheet-body-inner {
236
+ padding: 16rpx 36rpx 48rpx;
237
+ display: flex;
238
+ flex-direction: column;
239
+ gap: 32rpx;
240
+ }
241
+
242
+ .hlw-sheet-cta {
243
+ padding: 28rpx;
244
+ background: #0f172a;
245
+ border-radius: var(--radius-md, 16rpx);
246
+ display: flex;
247
+ align-items: center;
248
+ justify-content: center;
249
+ box-shadow: 0 8rpx 20rpx rgba(15, 23, 42, 0.2);
250
+ transition: transform 0.15s ease;
251
+
252
+ &:active {
253
+ transform: scale(0.98);
254
+ }
255
+ }
256
+
257
+ .hlw-sheet-cta-text {
258
+ font-size: var(--font-base, 28rpx);
259
+ font-weight: 600;
260
+ color: #ffffff;
261
+ letter-spacing: 1rpx;
262
+ }
263
+ </style>
@@ -14,7 +14,7 @@
14
14
  import { computed } from "vue";
15
15
 
16
16
  interface Props {
17
- type?: "primary" | "success" | "warning" | "danger" | "info";
17
+ type?: "primary" | "success" | "warning" | "danger" | "error" | "info";
18
18
  plain?: boolean;
19
19
  closable?: boolean;
20
20
  size?: "small" | "medium";
@@ -44,10 +44,11 @@ const customStyle = computed(() => {
44
44
  <style lang="scss" scoped>
45
45
  $colors: (
46
46
  primary: var(--primary-color, #3b82f6),
47
- success: #10b981,
48
- warning: #f59e0b,
49
- danger: #ef4444,
50
- info: #64748b,
47
+ success: var(--primary-success, #10b981),
48
+ warning: var(--primary-warning, #f59e0b),
49
+ danger: var(--primary-error, #ef4444),
50
+ error: var(--primary-error, #ef4444),
51
+ info: var(--primary-info, #64748b),
51
52
  );
52
53
 
53
54
  .hlw-tag {
@@ -30,4 +30,10 @@ export function useThemePageStyle() {
30
30
  export type { FontScale, FontPreset } from "./font";
31
31
  export { FONT_SCALE_KEY, FONT_PRESETS, getCurrentFontScale, getCurrentFontVars } from "./font";
32
32
  export type { ThemeColor } from "./palette";
33
- export { THEME_COLOR_KEY, DEFAULT_THEMES, getCurrentThemeColor, getCurrentThemeVars } from "./palette";
33
+ export {
34
+ THEME_COLOR_KEY,
35
+ THEME_SEMANTIC_COLORS,
36
+ DEFAULT_THEMES,
37
+ getCurrentThemeColor,
38
+ getCurrentThemeVars,
39
+ } from "./palette";
@@ -9,11 +9,18 @@ export interface ThemeColor {
9
9
 
10
10
  export const THEME_COLOR_KEY = "hlw_theme_color";
11
11
 
12
+ export const THEME_SEMANTIC_COLORS = {
13
+ success: "#10b981",
14
+ warning: "#f59e0b",
15
+ error: "#ef4444",
16
+ info: "#64748b",
17
+ } as const;
18
+
12
19
  export const DEFAULT_THEMES: ThemeColor[] = [
13
- { label: "默认蓝", value: "#3b82f6" },
14
- { label: "活力橙", value: "#f97316" },
15
20
  { label: "翡翠绿", value: "#10b981" },
16
- { label: "玫瑰红", value: "#f43f5e" },
21
+ { label: "活力橙", value: "#f97316" },
22
+ { label: "默认蓝", value: "#3b82f6" },
23
+ { label: "玫瑰粉", value: "#f43f5e" },
17
24
  { label: "紫罗兰", value: "#8b5cf6" },
18
25
  { label: "青石灰", value: "#64748b" },
19
26
  ];
@@ -32,5 +39,29 @@ export function getCurrentThemeVars(): Record<string, string> {
32
39
  "--primary-color": color,
33
40
  "--primary-light": hexToRgba(color, 0.12),
34
41
  "--primary-dark": darkenHex(color),
42
+ "--primary-success": THEME_SEMANTIC_COLORS.success,
43
+ "--primary-success-light": hexToRgba(THEME_SEMANTIC_COLORS.success, 0.12),
44
+ "--primary-success-dark": darkenHex(THEME_SEMANTIC_COLORS.success),
45
+ "--primary-warning": THEME_SEMANTIC_COLORS.warning,
46
+ "--primary-warning-light": hexToRgba(THEME_SEMANTIC_COLORS.warning, 0.12),
47
+ "--primary-warning-dark": darkenHex(THEME_SEMANTIC_COLORS.warning),
48
+ "--primary-error": THEME_SEMANTIC_COLORS.error,
49
+ "--primary-error-light": hexToRgba(THEME_SEMANTIC_COLORS.error, 0.12),
50
+ "--primary-error-dark": darkenHex(THEME_SEMANTIC_COLORS.error),
51
+ "--primary-info": THEME_SEMANTIC_COLORS.info,
52
+ "--primary-info-light": hexToRgba(THEME_SEMANTIC_COLORS.info, 0.12),
53
+ "--primary-info-dark": darkenHex(THEME_SEMANTIC_COLORS.info),
54
+ "--success-color": THEME_SEMANTIC_COLORS.success,
55
+ "--success-light": hexToRgba(THEME_SEMANTIC_COLORS.success, 0.12),
56
+ "--success-dark": darkenHex(THEME_SEMANTIC_COLORS.success),
57
+ "--warning-color": THEME_SEMANTIC_COLORS.warning,
58
+ "--warning-light": hexToRgba(THEME_SEMANTIC_COLORS.warning, 0.12),
59
+ "--warning-dark": darkenHex(THEME_SEMANTIC_COLORS.warning),
60
+ "--error-color": THEME_SEMANTIC_COLORS.error,
61
+ "--error-light": hexToRgba(THEME_SEMANTIC_COLORS.error, 0.12),
62
+ "--error-dark": darkenHex(THEME_SEMANTIC_COLORS.error),
63
+ "--info-color": THEME_SEMANTIC_COLORS.info,
64
+ "--info-light": hexToRgba(THEME_SEMANTIC_COLORS.info, 0.12),
65
+ "--info-dark": darkenHex(THEME_SEMANTIC_COLORS.info),
35
66
  };
36
67
  }
package/src/index.ts CHANGED
@@ -9,11 +9,13 @@
9
9
 
10
10
  export type { FontScale, FontPreset, ThemeColor } from "./composables/theme";
11
11
  export type { HlwMenuItem } from "./components/hlw-menu/types";
12
+ export type { HlwPagingRef, HlwPagingInstance } from "./components/hlw-paging/types";
12
13
  export {
13
14
  FONT_PRESETS,
14
15
  FONT_SCALE_KEY,
15
16
  DEFAULT_THEMES,
16
17
  THEME_COLOR_KEY,
18
+ THEME_SEMANTIC_COLORS,
17
19
  THEME_CHANGE_EVENT,
18
20
  getCurrentFontScale,
19
21
  getCurrentFontVars,