@puresnake/snake-ui 0.0.0-stage → 0.0.2

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 (279) hide show
  1. package/LICENSE +21 -0
  2. package/changelog.md +83 -0
  3. package/components/snake-activity-list/snake-activity-list.vue +365 -0
  4. package/components/snake-activity-list/types.ts +29 -0
  5. package/components/snake-auxiliary-segmentation/snake-auxiliary-segmentation.vue +44 -0
  6. package/components/snake-auxiliary-segmentation/types.ts +5 -0
  7. package/components/snake-button/snake-button.vue +357 -0
  8. package/components/snake-button/types.ts +103 -0
  9. package/components/snake-button-sort/snake-button-sort.vue +72 -0
  10. package/components/snake-button-sort/types.ts +22 -0
  11. package/components/snake-calendar/snake-calendar.vue +998 -0
  12. package/components/snake-calendar/types.ts +189 -0
  13. package/components/snake-cell-group/snake-cell-group.vue +55 -0
  14. package/components/snake-cell-group/types.ts +19 -0
  15. package/components/snake-cell-item/snake-cell-item.vue +159 -0
  16. package/components/snake-cell-item/types.ts +66 -0
  17. package/components/snake-checkbox/snake-checkbox.vue +264 -0
  18. package/components/snake-checkbox/types.ts +70 -0
  19. package/components/snake-checkbox-group/snake-checkbox-group.vue +154 -0
  20. package/components/snake-checkbox-group/types.ts +52 -0
  21. package/components/snake-cms/blocks/v2/cms-v2-carousel.vue +87 -0
  22. package/components/snake-cms/blocks/v2/cms-v2-coupon.vue +25 -0
  23. package/components/snake-cms/blocks/v2/cms-v2-custom.vue +12 -0
  24. package/components/snake-cms/blocks/v2/cms-v2-divider.vue +33 -0
  25. package/components/snake-cms/blocks/v2/cms-v2-floatbutton.vue +28 -0
  26. package/components/snake-cms/blocks/v2/cms-v2-goods-list.vue +150 -0
  27. package/components/snake-cms/blocks/v2/cms-v2-hotzone.vue +41 -0
  28. package/components/snake-cms/blocks/v2/cms-v2-images.vue +41 -0
  29. package/components/snake-cms/blocks/v2/cms-v2-magiccube.vue +93 -0
  30. package/components/snake-cms/blocks/v2/cms-v2-notice.vue +80 -0
  31. package/components/snake-cms/blocks/v2/cms-v2-popup.vue +46 -0
  32. package/components/snake-cms/blocks/v2/cms-v2-richtext.vue +18 -0
  33. package/components/snake-cms/blocks/v2/cms-v2-search.vue +115 -0
  34. package/components/snake-cms/blocks/v2/cms-v2-video.vue +25 -0
  35. package/components/snake-cms/blocks/v2/shared.ts +84 -0
  36. package/components/snake-cms/snake-cms.vue +409 -0
  37. package/components/snake-cms/types.ts +50 -0
  38. package/components/snake-commodity-search/snake-commodity-search.vue +234 -0
  39. package/components/snake-commodity-search/types.ts +11 -0
  40. package/components/snake-config-provider/snake-config-provider.vue +61 -0
  41. package/components/snake-config-provider/types.ts +22 -0
  42. package/components/snake-count-down/snake-count-down.vue +231 -0
  43. package/components/snake-count-down/types.ts +103 -0
  44. package/components/snake-coupon/snake-coupon.vue +209 -0
  45. package/components/snake-coupon/types.ts +21 -0
  46. package/components/snake-custom-module/snake-custom-module.vue +25 -0
  47. package/components/snake-custom-module/types.ts +11 -0
  48. package/components/snake-drop-menu/snake-drop-menu.vue +123 -0
  49. package/components/snake-drop-menu/types.ts +95 -0
  50. package/components/snake-drop-menu-item/snake-drop-menu-item.vue +181 -0
  51. package/components/snake-drop-menu-item/types.ts +48 -0
  52. package/components/snake-empty/snake-empty.vue +100 -0
  53. package/components/snake-empty/types.ts +48 -0
  54. package/components/snake-filter-sorts/filter-page.vue +695 -0
  55. package/components/snake-filter-sorts/snake-filter-sorts.vue +185 -0
  56. package/components/snake-filter-sorts/types.ts +57 -0
  57. package/components/snake-floating-bubble/snake-floating-bubble.vue +157 -0
  58. package/components/snake-floating-bubble/types.ts +43 -0
  59. package/components/snake-follow/snake-follow.vue +18 -0
  60. package/components/snake-follow/types.ts +2 -0
  61. package/components/snake-form/snake-form.vue +124 -0
  62. package/components/snake-form/types.ts +96 -0
  63. package/components/snake-form-item/snake-form-item.vue +331 -0
  64. package/components/snake-form-item/types.ts +70 -0
  65. package/components/snake-goods-list/snake-goods-list.vue +792 -0
  66. package/components/snake-goods-list/types.ts +55 -0
  67. package/components/snake-graphic-navigation/snake-graphic-navigation.vue +198 -0
  68. package/components/snake-graphic-navigation/types.ts +43 -0
  69. package/components/snake-icon/icon-names.ts +222 -0
  70. package/components/snake-icon/snake-icon.vue +220 -0
  71. package/components/snake-icon/types.ts +45 -0
  72. package/components/snake-image/snake-image.vue +230 -0
  73. package/components/snake-image/types.ts +70 -0
  74. package/components/snake-images/snake-images.vue +80 -0
  75. package/components/snake-images/types.ts +5 -0
  76. package/components/snake-index-anchor/snake-index-anchor.vue +83 -0
  77. package/components/snake-index-anchor/types.ts +14 -0
  78. package/components/snake-index-list/anchor-registry.ts +80 -0
  79. package/components/snake-index-list/snake-index-list.vue +259 -0
  80. package/components/snake-index-list/types.ts +115 -0
  81. package/components/snake-index-list-panel/snake-index-list-panel.vue +277 -0
  82. package/components/snake-index-list-panel/types.ts +10 -0
  83. package/components/snake-input/snake-input.vue +225 -0
  84. package/components/snake-input/types.ts +99 -0
  85. package/components/snake-jump-applet/snake-jump-applet.vue +99 -0
  86. package/components/snake-jump-applet/types.ts +17 -0
  87. package/components/snake-line/snake-line.vue +42 -0
  88. package/components/snake-line/types.ts +30 -0
  89. package/components/snake-line-progress/snake-line-progress.vue +105 -0
  90. package/components/snake-line-progress/types.ts +26 -0
  91. package/components/snake-link/snake-link.vue +74 -0
  92. package/components/snake-link/types.ts +30 -0
  93. package/components/snake-list-switching/components/tree-select/index.vue +156 -0
  94. package/components/snake-list-switching/snake-list-switching.vue +1285 -0
  95. package/components/snake-list-switching/types.ts +11 -0
  96. package/components/snake-loading/snake-loading.vue +241 -0
  97. package/components/snake-loading/types.ts +34 -0
  98. package/components/snake-loadmore/snake-loadmore.vue +103 -0
  99. package/components/snake-loadmore/types.ts +56 -0
  100. package/components/snake-magic-cube/snake-magic-cube.vue +622 -0
  101. package/components/snake-magic-cube/types.ts +5 -0
  102. package/components/snake-modal/snake-modal.vue +434 -0
  103. package/components/snake-modal/types.ts +71 -0
  104. package/components/snake-navbar/snake-navbar.vue +194 -0
  105. package/components/snake-navbar/types.ts +54 -0
  106. package/components/snake-no-network/snake-no-network.vue +125 -0
  107. package/components/snake-no-network/types.ts +27 -0
  108. package/components/snake-notice/snake-notice.vue +44 -0
  109. package/components/snake-notice/types.ts +5 -0
  110. package/components/snake-notice-bar/snake-notice-bar.vue +336 -0
  111. package/components/snake-notice-bar/types.ts +82 -0
  112. package/components/snake-overlay/snake-overlay.vue +73 -0
  113. package/components/snake-overlay/types.ts +35 -0
  114. package/components/snake-page-popup/snake-page-popup.vue +146 -0
  115. package/components/snake-page-popup/types.ts +28 -0
  116. package/components/snake-parse/audio/audio.vue +286 -0
  117. package/components/snake-parse/audio/context.js +11 -0
  118. package/components/snake-parse/audio/index.js +34 -0
  119. package/components/snake-parse/node/node.vue +830 -0
  120. package/components/snake-parse/parser.js +1480 -0
  121. package/components/snake-parse/snake-parse.vue +548 -0
  122. package/components/snake-parse/static/app-plus/snake-parse/js/handler.js +109 -0
  123. package/components/snake-parse/static/app-plus/snake-parse/js/uni.webview.js +0 -0
  124. package/components/snake-parse/static/app-plus/snake-parse/js/uni.webview.min.js +1 -0
  125. package/components/snake-parse/static/app-plus/snake-parse/local.html +3 -0
  126. package/components/snake-parse/style/index.js +132 -0
  127. package/components/snake-parse/style/parser.js +175 -0
  128. package/components/snake-parse/types.ts +49 -0
  129. package/components/snake-picture-ads/snake-picture-ads.vue +292 -0
  130. package/components/snake-picture-ads/types.ts +5 -0
  131. package/components/snake-popup/snake-popup.vue +348 -0
  132. package/components/snake-popup/types.ts +88 -0
  133. package/components/snake-qr-code/qrcode.ts +1214 -0
  134. package/components/snake-qr-code/snake-qr-code.vue +408 -0
  135. package/components/snake-qr-code/types.ts +78 -0
  136. package/components/snake-radio/snake-radio.vue +271 -0
  137. package/components/snake-radio/types.ts +64 -0
  138. package/components/snake-radio-group/snake-radio-group.vue +98 -0
  139. package/components/snake-radio-group/types.ts +48 -0
  140. package/components/snake-read-more/snake-read-more.vue +140 -0
  141. package/components/snake-read-more/types.ts +53 -0
  142. package/components/snake-rich-text/snake-rich-text.vue +24 -0
  143. package/components/snake-rich-text/types.ts +5 -0
  144. package/components/snake-root-portal/snake-root-portal.vue +92 -0
  145. package/components/snake-root-portal/types.ts +9 -0
  146. package/components/snake-search/snake-search.vue +202 -0
  147. package/components/snake-search/types.ts +84 -0
  148. package/components/snake-select/snake-select.vue +371 -0
  149. package/components/snake-select/types.ts +75 -0
  150. package/components/snake-skeleton/snake-skeleton.vue +104 -0
  151. package/components/snake-skeleton/types.ts +32 -0
  152. package/components/snake-skeleton-item/snake-skeleton-item.vue +90 -0
  153. package/components/snake-skeleton-item/types.ts +30 -0
  154. package/components/snake-slider/snake-slider.vue +249 -0
  155. package/components/snake-slider/types.ts +59 -0
  156. package/components/snake-sticky/snake-sticky.vue +178 -0
  157. package/components/snake-sticky/types.ts +48 -0
  158. package/components/snake-subsection/snake-subsection.vue +188 -0
  159. package/components/snake-subsection/types.ts +54 -0
  160. package/components/snake-swiper/snake-swiper.vue +229 -0
  161. package/components/snake-swiper/types.ts +79 -0
  162. package/components/snake-switch/snake-switch.vue +100 -0
  163. package/components/snake-switch/types.ts +41 -0
  164. package/components/snake-tabbar/snake-tabbar.vue +306 -0
  165. package/components/snake-tabbar/types.ts +93 -0
  166. package/components/snake-tabs/snake-tabs.vue +305 -0
  167. package/components/snake-tabs/types.ts +79 -0
  168. package/components/snake-text/snake-text.vue +292 -0
  169. package/components/snake-text/types.ts +100 -0
  170. package/components/snake-textarea/snake-textarea.vue +171 -0
  171. package/components/snake-textarea/types.ts +79 -0
  172. package/components/snake-toast/snake-toast.vue +330 -0
  173. package/components/snake-toast/types.ts +55 -0
  174. package/components/snake-tooltip/position.ts +33 -0
  175. package/components/snake-tooltip/snake-tooltip.vue +339 -0
  176. package/components/snake-tooltip/types.ts +80 -0
  177. package/components/snake-transition/snake-transition.vue +315 -0
  178. package/components/snake-transition/types.ts +65 -0
  179. package/components/snake-upload/snake-upload.vue +1801 -0
  180. package/components/snake-upload/types.ts +256 -0
  181. package/components/snake-videos/snake-videos.vue +122 -0
  182. package/components/snake-videos/types.ts +7 -0
  183. package/iconfont.css +881 -0
  184. package/index.d.ts +7 -0
  185. package/index.scss +26 -0
  186. package/index.ts +94 -0
  187. package/libs/cms/blocks.ts +103 -0
  188. package/libs/cms/config.ts +25 -0
  189. package/libs/cms/index.ts +7 -0
  190. package/libs/cms/normalize.ts +135 -0
  191. package/libs/cms/resolve.ts +12 -0
  192. package/libs/cms/types.ts +164 -0
  193. package/libs/cms/use-commerce.ts +385 -0
  194. package/libs/cms/v2.ts +193 -0
  195. package/libs/config/index.ts +4 -0
  196. package/libs/config/modal.ts +93 -0
  197. package/libs/config/state.ts +33 -0
  198. package/libs/config/theme.ts +351 -0
  199. package/libs/config/toast.ts +71 -0
  200. package/libs/config/types.ts +135 -0
  201. package/libs/config/zIndex.ts +44 -0
  202. package/libs/css/color.scss +105 -0
  203. package/libs/css/common.scss +171 -0
  204. package/libs/css/style.h5.scss +7 -0
  205. package/libs/css/style.mp.scss +7 -0
  206. package/libs/css/style.theme.scss +70 -0
  207. package/libs/css/style.vue.scss +140 -0
  208. package/libs/form/async-validator.min.d.ts +75 -0
  209. package/libs/form/async-validator.min.js +3 -0
  210. package/libs/form/index.ts +3 -0
  211. package/libs/form/path.ts +40 -0
  212. package/libs/form/types.ts +51 -0
  213. package/libs/form/validate.ts +149 -0
  214. package/libs/foundation.ts +96 -0
  215. package/libs/function/$parent.ts +33 -0
  216. package/libs/function/clipboard.ts +13 -0
  217. package/libs/function/color.ts +55 -0
  218. package/libs/function/debounce.ts +34 -0
  219. package/libs/function/deepClone.ts +30 -0
  220. package/libs/function/deepMerge.ts +25 -0
  221. package/libs/function/emitter.ts +30 -0
  222. package/libs/function/format.ts +27 -0
  223. package/libs/function/getParent.ts +53 -0
  224. package/libs/function/getRect.ts +29 -0
  225. package/libs/function/guid.ts +11 -0
  226. package/libs/function/index.ts +31 -0
  227. package/libs/function/queryParams.ts +73 -0
  228. package/libs/function/random.ts +6 -0
  229. package/libs/function/randomArray.ts +14 -0
  230. package/libs/function/route.ts +155 -0
  231. package/libs/function/sleep.ts +7 -0
  232. package/libs/function/style.ts +58 -0
  233. package/libs/function/styleUtils.ts +83 -0
  234. package/libs/function/system.ts +14 -0
  235. package/libs/function/test.ts +202 -0
  236. package/libs/function/throttle.ts +36 -0
  237. package/libs/function/timeFormat.ts +27 -0
  238. package/libs/function/timeFrom.ts +27 -0
  239. package/libs/function/toast.ts +10 -0
  240. package/libs/function/trim.ts +11 -0
  241. package/libs/function/type2icon.ts +11 -0
  242. package/libs/function/unit.ts +45 -0
  243. package/libs/hooks/index.ts +11 -0
  244. package/libs/hooks/useChildren.ts +125 -0
  245. package/libs/hooks/useColor.ts +5 -0
  246. package/libs/hooks/useDebounce.ts +5 -0
  247. package/libs/hooks/useLocale.ts +13 -0
  248. package/libs/hooks/useModal.ts +131 -0
  249. package/libs/hooks/useParent.ts +62 -0
  250. package/libs/hooks/useRect.ts +44 -0
  251. package/libs/hooks/useRouter.ts +5 -0
  252. package/libs/hooks/useTheme.ts +31 -0
  253. package/libs/hooks/useThrottle.ts +5 -0
  254. package/libs/hooks/useToast.ts +116 -0
  255. package/libs/index.ts +18 -0
  256. package/libs/request/auto-http.ts +1 -0
  257. package/libs/request/index.ts +343 -0
  258. package/libs/runtime/accessors.ts +55 -0
  259. package/libs/runtime/context.ts +40 -0
  260. package/libs/runtime/index.ts +18 -0
  261. package/libs/runtime/types.ts +49 -0
  262. package/libs/util/calendar.ts +6 -0
  263. package/locale/index.ts +130 -0
  264. package/locale/lang/en-US.ts +67 -0
  265. package/locale/lang/zh-CN.ts +67 -0
  266. package/package.json +134 -5
  267. package/plugins/index.ts +1 -0
  268. package/plugins/root/README.md +86 -0
  269. package/plugins/root/index.ts +123 -0
  270. package/plugins/root/page.ts +77 -0
  271. package/plugins/root/root.ts +53 -0
  272. package/plugins/root/utils.ts +137 -0
  273. package/readme.md +79 -0
  274. package/theme.scss +118 -0
  275. package/types/components.d.ts +236 -0
  276. package/types/global.d.ts +21 -0
  277. package/types/index.d.ts +6 -0
  278. package/types/uni-app.d.ts +16 -0
  279. package/README.md +0 -3
@@ -0,0 +1,33 @@
1
+ import { reactive } from 'vue';
2
+ import type { DebugLevel } from './types';
3
+
4
+ export const SNAKE_UI_VERSION = '0.3.0';
5
+
6
+ export interface AppConfig {
7
+ v: string;
8
+ version: string;
9
+ defaultTheme: string;
10
+ defaultDarkMode: 'light' | 'dark' | 'auto';
11
+ defaultLocale: string;
12
+ debugMode: boolean | DebugLevel | DebugLevel[];
13
+ }
14
+
15
+ export const config = reactive<AppConfig>({
16
+ v: SNAKE_UI_VERSION,
17
+ version: SNAKE_UI_VERSION,
18
+ defaultTheme: 'snake',
19
+ defaultDarkMode: 'light',
20
+ defaultLocale: 'zh-CN',
21
+ debugMode: false
22
+ });
23
+
24
+ export function setConfig(options: Partial<AppConfig>): void {
25
+ Object.assign(config, options);
26
+ }
27
+
28
+ export function isDebugMode(level: DebugLevel = 'log'): boolean {
29
+ if (config.debugMode === true) return true;
30
+ if (config.debugMode === false) return false;
31
+ if (Array.isArray(config.debugMode)) return config.debugMode.includes(level);
32
+ return config.debugMode === level;
33
+ }
@@ -0,0 +1,351 @@
1
+ import { computed, reactive, ref } from 'vue';
2
+ import { isDebugMode, config } from './state';
3
+ import type { DarkMode, Theme, ThemeColor, ThemeOption } from './types';
4
+
5
+ const THEME_STORAGE_KEY = 'snake-ui-theme';
6
+ const DARK_MODE_STORAGE_KEY = 'snake-ui-dark-mode';
7
+
8
+ export const lightPalette: ThemeColor = {
9
+ // 品牌绿七档(自有品牌色,保留)
10
+ primary: '#06D290',
11
+ primaryDark: '#2EBD7C',
12
+ primaryDeep: '#26273A',
13
+ primaryDeeper: '#22242E',
14
+ primaryDisabled: '#A6EBD3',
15
+ primaryLight: '#EEFFE0',
16
+ primaryInk: '#FFFFFF',
17
+ // 语义色与中性色默认主题(lightPalette)
18
+ success: '#19BE6B',
19
+ successDark: '#18B566',
20
+ successDisabled: '#71D5A1',
21
+ successLight: '#DBF1E1',
22
+ warning: '#FF9900',
23
+ warningDark: '#F29100',
24
+ warningDisabled: '#FCBD71',
25
+ warningLight: '#FDF6EC',
26
+ error: '#FA3534',
27
+ errorDark: '#DD6161',
28
+ errorDisabled: '#FAB6B6',
29
+ errorLight: '#FEF0F0',
30
+ info: '#909399',
31
+ infoDark: '#82848A',
32
+ infoDisabled: '#C8C9CC',
33
+ infoLight: '#F4F4F5',
34
+ white: '#ffffff',
35
+ black: '#000000',
36
+ // mainColor / contentColor / tipsColor / lightColor
37
+ text: '#303133',
38
+ textSecondary: '#606266',
39
+ textMuted: '#909399',
40
+ textLight: '#C0C4CC',
41
+ // borderColor / dividerColor / maskColor / shadowColor / bgColor / bgWhite / bgGrayLight
42
+ border: '#DCDFE6',
43
+ divider: '#E4E7ED',
44
+ mask: 'rgba(0, 0, 0, 0.4)',
45
+ shadow: 'rgba(0, 0, 0, 0.1)',
46
+ background: '#F6F6F6',
47
+ surface: '#ffffff',
48
+ surfaceMuted: '#F1F1F1',
49
+ notice: '#FF9900',
50
+ noticeBackground: '#FDF6EC'
51
+ };
52
+
53
+ export const darkPalette: ThemeColor = {
54
+ // 品牌绿七档(暗色下仍保持品牌绿,自有体系)
55
+ primary: '#06D290',
56
+ primaryDark: '#2EE6A8',
57
+ primaryDeep: '#1A1B29',
58
+ primaryDeeper: '#14151F',
59
+ primaryDisabled: '#1E3A31',
60
+ primaryLight: '#0C2A1E',
61
+ primaryInk: '#26273A',
62
+ // 语义色与中性色暗色主题(darkPalette)
63
+ success: '#4ADE80',
64
+ successDark: '#1F9D57',
65
+ successDisabled: '#2F4D3D',
66
+ successLight: '#10291F',
67
+ warning: '#FBBF24',
68
+ warningDark: '#C88F00',
69
+ warningDisabled: '#4A3B17',
70
+ warningLight: '#2B1F05',
71
+ error: '#FF6B6B',
72
+ errorDark: '#D83A3A',
73
+ errorDisabled: '#4F2323',
74
+ errorLight: '#2D1414',
75
+ info: '#A0A7B8',
76
+ infoDark: '#7C8394',
77
+ infoDisabled: '#3B3F4C',
78
+ infoLight: '#1D2029',
79
+ white: '#F5F6F7',
80
+ black: '#F5F6F7',
81
+ // mainColor / contentColor / tipsColor / lightColor
82
+ text: '#F5F6F7',
83
+ textSecondary: '#CFD3DC',
84
+ textMuted: '#9AA1AF',
85
+ textLight: '#6B7082',
86
+ // borderColor / dividerColor / maskColor / shadowColor / bgColor / bgWhite / bgGrayLight
87
+ border: '#3A4251',
88
+ divider: '#3A4251',
89
+ mask: 'rgba(0, 0, 0, 0.6)',
90
+ shadow: 'rgba(0, 0, 0, 0.3)',
91
+ background: '#111827',
92
+ surface: '#000000',
93
+ surfaceMuted: '#1A1A1A',
94
+ notice: '#FBBF24',
95
+ noticeBackground: '#2B1F05'
96
+ };
97
+
98
+ export const defaultTheme: Theme = {
99
+ name: 'snake',
100
+ label: 'Snake 绿',
101
+ description: 'Snake UI 默认明暗主题',
102
+ color: lightPalette,
103
+ darkColor: darkPalette
104
+ };
105
+
106
+ export const themes = ref<Theme[]>([defaultTheme]);
107
+ export const currentTheme = ref<Theme>(defaultTheme);
108
+ export const darkMode = ref<DarkMode>('light');
109
+ export const systemDark = ref(false);
110
+ export const color = reactive<ThemeColor>({ ...lightPalette });
111
+ export const cssVars = ref<Record<string, string>>({});
112
+
113
+ let listenersReady = false;
114
+ let initialized = false;
115
+ let lastCssKeys: string[] = [];
116
+
117
+ const tokenNames: Record<keyof ThemeColor, string> = {
118
+ primary: '--snake-color-primary',
119
+ primaryDark: '--snake-color-primary-dark',
120
+ primaryDeep: '--snake-color-primary-deep',
121
+ primaryDeeper: '--snake-color-primary-deeper',
122
+ primaryDisabled: '--snake-color-primary-disabled',
123
+ primaryLight: '--snake-color-primary-light',
124
+ primaryInk: '--snake-color-primary-ink',
125
+ success: '--snake-color-success',
126
+ successDark: '--snake-color-success-dark',
127
+ successDisabled: '--snake-color-success-disabled',
128
+ successLight: '--snake-color-success-light',
129
+ warning: '--snake-color-warning',
130
+ warningDark: '--snake-color-warning-dark',
131
+ warningDisabled: '--snake-color-warning-disabled',
132
+ warningLight: '--snake-color-warning-light',
133
+ error: '--snake-color-error',
134
+ errorDark: '--snake-color-error-dark',
135
+ errorDisabled: '--snake-color-error-disabled',
136
+ errorLight: '--snake-color-error-light',
137
+ info: '--snake-color-info',
138
+ infoDark: '--snake-color-info-dark',
139
+ infoDisabled: '--snake-color-info-disabled',
140
+ infoLight: '--snake-color-info-light',
141
+ white: '--snake-color-white',
142
+ black: '--snake-color-black',
143
+ text: '--snake-color-text',
144
+ textSecondary: '--snake-color-text-secondary',
145
+ textMuted: '--snake-color-text-muted',
146
+ textLight: '--snake-color-text-light',
147
+ border: '--snake-color-border',
148
+ divider: '--snake-color-divider',
149
+ mask: '--snake-color-mask',
150
+ shadow: '--snake-color-shadow',
151
+ background: '--snake-color-background',
152
+ surface: '--snake-color-surface',
153
+ surfaceMuted: '--snake-color-surface-muted',
154
+ notice: '--snake-color-notice',
155
+ noticeBackground: '--snake-color-notice-background'
156
+ };
157
+
158
+ function readStorage<T>(key: string): T | undefined {
159
+ try {
160
+ if (typeof uni === 'undefined' || typeof uni.getStorageSync !== 'function') return undefined;
161
+ const value = uni.getStorageSync(key);
162
+ return value === '' || value == null ? undefined : (value as T);
163
+ } catch (error) {
164
+ if (isDebugMode('warn')) console.warn(`[Snake UI] failed to read ${key}`, error);
165
+ return undefined;
166
+ }
167
+ }
168
+
169
+ function writeStorage(key: string, value: unknown): void {
170
+ try {
171
+ if (typeof uni !== 'undefined' && typeof uni.setStorageSync === 'function') {
172
+ uni.setStorageSync(key, value);
173
+ }
174
+ } catch (error) {
175
+ if (isDebugMode('warn')) console.warn(`[Snake UI] failed to write ${key}`, error);
176
+ }
177
+ }
178
+
179
+ function detectSystemDark(): boolean {
180
+ try {
181
+ if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
182
+ return window.matchMedia('(prefers-color-scheme: dark)').matches;
183
+ }
184
+ if (typeof uni !== 'undefined' && typeof uni.getSystemInfoSync === 'function') {
185
+ return (uni.getSystemInfoSync() as { theme?: string }).theme === 'dark';
186
+ }
187
+ } catch (error) {
188
+ if (isDebugMode('warn')) console.warn('[Snake UI] failed to detect system theme', error);
189
+ }
190
+ return false;
191
+ }
192
+
193
+ function prepareListeners(): void {
194
+ if (listenersReady) return;
195
+ listenersReady = true;
196
+ systemDark.value = detectSystemDark();
197
+ try {
198
+ // H5 与 uni 平台分别监听系统主题;仅 auto 模式跟随变化,手动模式不被系统事件覆盖。
199
+ if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
200
+ const media = window.matchMedia('(prefers-color-scheme: dark)');
201
+ media.addEventListener?.('change', event => {
202
+ systemDark.value = event.matches;
203
+ if (darkMode.value === 'auto') applyTheme();
204
+ });
205
+ }
206
+ if (typeof uni !== 'undefined' && typeof uni.onThemeChange === 'function') {
207
+ uni.onThemeChange(event => {
208
+ systemDark.value = event.theme === 'dark';
209
+ if (darkMode.value === 'auto') applyTheme();
210
+ });
211
+ }
212
+ } catch (error) {
213
+ if (isDebugMode('warn')) console.warn('[Snake UI] failed to watch system theme', error);
214
+ }
215
+ }
216
+
217
+ function normalizeTheme(theme: Theme): Theme {
218
+ return {
219
+ ...theme,
220
+ color: { ...lightPalette, ...theme.color },
221
+ darkColor: { ...darkPalette, ...theme.darkColor }
222
+ };
223
+ }
224
+
225
+ function mergeThemes(custom: Theme[]): Theme[] {
226
+ const map = new Map<string, Theme>([[defaultTheme.name, defaultTheme]]);
227
+ custom.forEach(theme => map.set(theme.name, normalizeTheme(theme)));
228
+ return Array.from(map.values());
229
+ }
230
+
231
+ function activeMode(): 'light' | 'dark' {
232
+ if (darkMode.value === 'auto') return systemDark.value ? 'dark' : 'light';
233
+ return darkMode.value;
234
+ }
235
+
236
+ function toRgbTriplet(value: string): string | undefined {
237
+ const match = /^#([0-9a-f]{6})$/i.exec(value.trim());
238
+ if (!match) return undefined;
239
+ const hex = Number.parseInt(match[1], 16);
240
+ return `${(hex >> 16) & 255}, ${(hex >> 8) & 255}, ${hex & 255}`;
241
+ }
242
+
243
+ function createCssVars(theme: Theme, mode: 'light' | 'dark'): Record<string, string> {
244
+ const palette = (mode === 'dark' ? theme.darkColor : theme.color) as ThemeColor;
245
+ const result: Record<string, string> = { '--snake-theme-mode': mode };
246
+ Object.entries(palette).forEach(([key, value]) => {
247
+ const name = tokenNames[key as keyof ThemeColor];
248
+ if (name && value != null) {
249
+ result[name] = String(value);
250
+ const rgb = toRgbTriplet(String(value));
251
+ if (rgb) result[`${name}-rgb`] = rgb;
252
+ }
253
+ });
254
+ Object.assign(result, mode === 'dark' ? theme.darkCss : theme.css);
255
+ return result;
256
+ }
257
+
258
+ function flushDocument(vars: Record<string, string>, mode: 'light' | 'dark'): void {
259
+ if (typeof document === 'undefined' || !document.documentElement) return;
260
+ const root = document.documentElement;
261
+ // 先移除上一主题独有的变量,防止自定义 css/darkCss 在切换后残留。
262
+ lastCssKeys.forEach(key => root.style.removeProperty(key));
263
+ Object.entries(vars).forEach(([key, value]) => root.style.setProperty(key, value));
264
+ lastCssKeys = Object.keys(vars);
265
+ root.dataset.snakeThemeMode = mode;
266
+ root.classList.remove('snake-theme-light', 'snake-theme-dark');
267
+ root.classList.add(`snake-theme-${mode}`);
268
+ }
269
+
270
+ export function applyTheme(): void {
271
+ const mode = activeMode();
272
+ const palette = (mode === 'dark' ? currentTheme.value.darkColor : currentTheme.value.color) as ThemeColor | undefined;
273
+ Object.assign(color, mode === 'dark' ? darkPalette : lightPalette, palette || {});
274
+ const vars = createCssVars(currentTheme.value, mode);
275
+ cssVars.value = vars;
276
+ flushDocument(vars, mode);
277
+ }
278
+
279
+ export function initTheme(option?: ThemeOption): void {
280
+ prepareListeners();
281
+ let themeEntries: Theme[] = [];
282
+ let defaultThemeName = config.defaultTheme;
283
+ let defaultDarkMode = config.defaultDarkMode;
284
+ let force = false;
285
+
286
+ if (Array.isArray(option)) {
287
+ themeEntries = option;
288
+ } else if (
289
+ option &&
290
+ typeof option === 'object' &&
291
+ ('themes' in option || 'defaultTheme' in option || 'defaultDarkMode' in option || 'force' in option)
292
+ ) {
293
+ themeEntries = option.themes || [];
294
+ defaultThemeName = option.defaultTheme || defaultThemeName;
295
+ defaultDarkMode = option.defaultDarkMode || defaultDarkMode;
296
+ force = Boolean(option.force);
297
+ } else if (option && typeof option === 'object') {
298
+ themeEntries = [{ ...defaultTheme, color: { ...defaultTheme.color, ...option } }];
299
+ }
300
+
301
+ if (!initialized || force || themeEntries.length) themes.value = mergeThemes(themeEntries);
302
+ const savedTheme = force ? undefined : readStorage<string>(THEME_STORAGE_KEY);
303
+ const savedMode = force ? undefined : readStorage<DarkMode>(DARK_MODE_STORAGE_KEY);
304
+ currentTheme.value = themes.value.find(theme => theme.name === (savedTheme || defaultThemeName)) || themes.value[0];
305
+ darkMode.value = savedMode || defaultDarkMode;
306
+ initialized = true;
307
+ applyTheme();
308
+ }
309
+
310
+ export function setTheme(name: string): boolean {
311
+ const theme = themes.value.find(item => item.name === name);
312
+ if (!theme) return false;
313
+ currentTheme.value = theme;
314
+ writeStorage(THEME_STORAGE_KEY, name);
315
+ applyTheme();
316
+ return true;
317
+ }
318
+
319
+ export function setDarkMode(mode: DarkMode): void {
320
+ darkMode.value = mode;
321
+ writeStorage(DARK_MODE_STORAGE_KEY, mode);
322
+ applyTheme();
323
+ }
324
+
325
+ export function toggleDarkMode(): void {
326
+ setDarkMode(activeMode() === 'dark' ? 'light' : 'dark');
327
+ }
328
+
329
+ export function isDarkMode(): boolean {
330
+ return activeMode() === 'dark';
331
+ }
332
+
333
+ export function setThemeColor(colors: Partial<ThemeColor>): void {
334
+ const key = activeMode() === 'dark' ? 'darkColor' : 'color';
335
+ currentTheme.value = {
336
+ ...currentTheme.value,
337
+ [key]: { ...currentTheme.value[key], ...colors }
338
+ };
339
+ applyTheme();
340
+ }
341
+
342
+ export const themeStyle = computed<Record<string, string>>(() => cssVars.value);
343
+
344
+ export function resetTheme(): void {
345
+ initialized = false;
346
+ themes.value = [defaultTheme];
347
+ currentTheme.value = defaultTheme;
348
+ darkMode.value = 'light';
349
+ systemDark.value = false;
350
+ applyTheme();
351
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * snake-toast 函数式调用约定(事件名 + 载荷类型)。
3
+ * @description
4
+ * - useToast() 通过 emitter 派发事件
5
+ * - <snake-toast global /> / <snake-toast page /> 通过 emitter 监听并转调自身 show/hide
6
+ *
7
+ * 该模块放在 libs 层(而非 components),是为了让 `useToast` 组合式函数与
8
+ * `snake-toast` 组件共享同一套事件名与载荷,同时保持「libs 不反向依赖 components」的分层约束。
9
+ */
10
+
11
+ // 普通(页面级)toast 事件
12
+ export const SNAKE_TOAST_EVENT_SHOW = 'snake-ui:toast:show:';
13
+ export const SNAKE_TOAST_EVENT_HIDE = 'snake-ui:toast:hide:';
14
+
15
+ // 全局(App 根部)toast 事件,供 useToast() 使用
16
+ export const SNAKE_TOAST_GLOBAL_EVENT_SHOW = 'snake-ui:toast:global:show';
17
+ export const SNAKE_TOAST_GLOBAL_EVENT_HIDE = 'snake-ui:toast:global:hide';
18
+
19
+ /** 根据当前页面(或显式 pageId)拼接事件名。 */
20
+ export function getEventWithCurrentPage(event: string, page?: string | boolean): string {
21
+ if (page && typeof page === 'string' && page !== '') {
22
+ return event + page;
23
+ }
24
+ return event + getCurrentPage();
25
+ }
26
+
27
+ /** 获取当前页面路由。 */
28
+ function getCurrentPage(): string {
29
+ try {
30
+ const pages = getCurrentPages();
31
+ const currentPage = pages[pages.length - 1].route as string;
32
+ return currentPage || '';
33
+ } catch {
34
+ return '';
35
+ }
36
+ }
37
+
38
+ /**
39
+ * snake-toast 函数式调用载荷类型。
40
+ * @description 与 `snake-toast` 组件的 props 对应(除 modelValue 外),`title` 兼容 `show('文本')` 的字符串形式。
41
+ */
42
+ export interface ToastPayload {
43
+ /** 提示文本。 */
44
+ title?: string;
45
+ /** 提示类型,success/error/warning/info/primary/''(默认空,深色底白字)。 */
46
+ type?: string;
47
+ /** 显示时长,单位 ms;设为 0 或空表示常驻,需手动 close。 */
48
+ duration?: number;
49
+ /** 是否显示图标。 */
50
+ icon?: boolean;
51
+ /** 显示位置,center/top/bottom。 */
52
+ position?: string;
53
+ /** 是否以 loading 形式常驻展示。 */
54
+ loading?: boolean;
55
+ /** 根节点自定义样式。 */
56
+ customStyle?: string | Record<string, any> | unknown[];
57
+ /** 根节点自定义类名。 */
58
+ customClass?: string;
59
+ /** 层级 z-index。 */
60
+ zIndex?: number | string;
61
+ /** 倒计时结束后的回调。 */
62
+ callback?: (() => void) | null;
63
+ /** 倒计时结束后是否返回上一页。 */
64
+ back?: boolean;
65
+ /** 倒计时结束后跳转是否为 tab 页面。 */
66
+ isTab?: boolean;
67
+ /** 倒计时结束后跳转的 url。 */
68
+ url?: string;
69
+ /** 跳转参数对象。 */
70
+ params?: Record<string, any>;
71
+ }
@@ -0,0 +1,135 @@
1
+ export type DarkMode = 'light' | 'dark' | 'auto';
2
+ export type DebugLevel = 'log' | 'warn' | 'error';
3
+
4
+ export interface ThemeColor {
5
+ primary: string;
6
+ primaryDark: string;
7
+ primaryDeep: string;
8
+ primaryDeeper: string;
9
+ primaryDisabled: string;
10
+ primaryLight: string;
11
+ primaryInk: string;
12
+ success: string;
13
+ successDark: string;
14
+ successDisabled: string;
15
+ successLight: string;
16
+ warning: string;
17
+ warningDark: string;
18
+ warningDisabled: string;
19
+ warningLight: string;
20
+ error: string;
21
+ errorDark: string;
22
+ errorDisabled: string;
23
+ errorLight: string;
24
+ info: string;
25
+ infoDark: string;
26
+ infoDisabled: string;
27
+ infoLight: string;
28
+ white: string;
29
+ black: string;
30
+ text: string;
31
+ textSecondary: string;
32
+ textMuted: string;
33
+ textLight: string;
34
+ border: string;
35
+ divider: string;
36
+ mask: string;
37
+ shadow: string;
38
+ background: string;
39
+ surface: string;
40
+ surfaceMuted: string;
41
+ notice: string;
42
+ noticeBackground: string;
43
+ }
44
+
45
+ export interface Theme {
46
+ name: string;
47
+ label?: string;
48
+ description?: string;
49
+ color: Partial<ThemeColor>;
50
+ darkColor?: Partial<ThemeColor>;
51
+ css?: Record<string, string>;
52
+ darkCss?: Record<string, string>;
53
+ }
54
+
55
+ export interface ThemeConfig {
56
+ themes?: Theme[];
57
+ defaultTheme?: string;
58
+ defaultDarkMode?: DarkMode;
59
+ force?: boolean;
60
+ }
61
+
62
+ export type ThemeOption = Partial<ThemeColor> | Theme[] | ThemeConfig;
63
+
64
+ export interface Locale {
65
+ name: string;
66
+ label?: string;
67
+ messages: Record<string, unknown>;
68
+ }
69
+
70
+ export interface LocaleConfig {
71
+ locales?: Locale[];
72
+ defaultLocale?: string;
73
+ force?: boolean;
74
+ }
75
+
76
+ export type LocaleOption = string | Locale[] | LocaleConfig;
77
+
78
+ /** Per-request presentation and response options. */
79
+ export interface RequestMeta {
80
+ loading?: boolean;
81
+ toast?: boolean;
82
+ originalData?: boolean;
83
+ [key: string]: unknown;
84
+ }
85
+
86
+
87
+ export type RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'TRACE' | 'CONNECT';
88
+
89
+ export interface RequestOptions {
90
+ url: string;
91
+ method?: RequestMethod;
92
+ data?: unknown;
93
+ params?: Record<string, unknown>;
94
+ header?: Record<string, unknown>;
95
+ timeout?: number;
96
+ dataType?: string;
97
+ responseType?: string;
98
+ meta?: RequestMeta;
99
+ [key: string]: unknown;
100
+ }
101
+
102
+ export interface RequestResponse<T = unknown> {
103
+ data: T;
104
+ statusCode: number;
105
+ header?: Record<string, unknown>;
106
+ cookies?: string[];
107
+ errMsg?: string;
108
+ config?: RequestOptions;
109
+ [key: string]: unknown;
110
+ }
111
+
112
+ /** Shared request-client defaults. */
113
+ export interface RequestConfig {
114
+ baseUrl?: string;
115
+ method?: RequestMethod;
116
+ header?: Record<string, unknown>;
117
+ timeout?: number;
118
+ dataType?: string;
119
+ responseType?: string;
120
+ meta?: RequestMeta;
121
+ }
122
+
123
+
124
+ export interface RequestInterceptor {
125
+ request?: (options: RequestOptions) => RequestOptions | false | Promise<RequestOptions | false>;
126
+ response?: <T>(response: T, config: RequestOptions) => T | false | Promise<T | false>;
127
+ }
128
+
129
+ export type RequestTransport = (options: RequestOptions) => Promise<RequestResponse | unknown>;
130
+
131
+ export interface RequestSetup {
132
+ config?: RequestConfig;
133
+ interceptor?: RequestInterceptor;
134
+ transport?: RequestTransport;
135
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * 组件层级数值表。
3
+ *
4
+ * 键名保持稳定,便于组件移植时直接引用;
5
+ * 数值以 snake-ui 组件当前生效的默认值为准。
6
+ */
7
+
8
+ export interface ZIndexConfig {
9
+ /** 提示气泡层级。 */
10
+ toast: number;
11
+ /** 无网络提示层级。 */
12
+ noNetwork: number;
13
+ /** 弹窗层级(popup / actionSheet / keyboard / picker 共用)。 */
14
+ popup: number;
15
+ /** 遮罩层级。 */
16
+ mask: number;
17
+ /** 导航栏层级。 */
18
+ navbar: number;
19
+ /** 顶部提示层级。 */
20
+ topTips: number;
21
+ /** 吸顶层级。snake-sticky 当前默认 10(CMS 传 19),有意不采用 970。 */
22
+ sticky: number;
23
+ /** 索引列表锚点吸顶层级。 */
24
+ indexListSticky: number;
25
+ /** 底部标签栏层级。 */
26
+ tabbar: number;
27
+ /** 下拉菜单层级。 */
28
+ dropdown: number;
29
+ }
30
+
31
+ const zIndex: ZIndexConfig = {
32
+ toast: 10090,
33
+ noNetwork: 10080,
34
+ popup: 10075,
35
+ mask: 10070,
36
+ navbar: 980,
37
+ topTips: 975,
38
+ sticky: 10,
39
+ indexListSticky: 965,
40
+ tabbar: 998,
41
+ dropdown: 985
42
+ };
43
+
44
+ export default zIndex;