@puresnake/snake-ui 0.0.0-stage → 0.0.1

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 +1 -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 +130 -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,77 @@
1
+ import { parseSFC, findNode } from './utils';
2
+
3
+ /**
4
+ * 页面模板转换:将页面内容包裹在 <global-root-view> 中
5
+ *
6
+ * <global-root-view> 是 App.root.vue 注册的全局组件,
7
+ * 其模板中包含 <slot />,页面内容通过插槽传入。
8
+ *
9
+ * 处理逻辑:
10
+ * 1. 解析 SFC,定位 <template> 标签的起止位置
11
+ * 2. 提取模板内容,查找 PageMeta 节点(如有则提取到包裹层外部)
12
+ * 3. 将剩余内容包裹在 <global-root-view>...</global-root-view> 中
13
+ *
14
+ * 降级机制:当 vue/compiler-sfc 不可用(如 HBuilderX 项目)时,
15
+ * 使用正则匹配 <page-meta> 标签替代 AST 解析。
16
+ */
17
+ export async function transformPage(code: string) {
18
+ const sfc = await parseSFC(code);
19
+
20
+ // 用正则定位 <template> 开头标签
21
+ const openMatch = code.match(/<template\b[^>]*>/);
22
+ if (!openMatch) return null;
23
+
24
+ // 使用 lastIndexOf 定位最后一个 </template>,即根 <template> 的闭合标签
25
+ // 避免匹配到模板内具名插槽 <template #slot> 的闭合标签
26
+ const closeTagStart = code.lastIndexOf('</template>');
27
+ if (closeTagStart === -1) return null;
28
+
29
+ const openTagEnd = openMatch.index! + openMatch[0].length;
30
+ const content = code.slice(openTagEnd, closeTagStart);
31
+
32
+ let pageMetaSource = '';
33
+ let newContent = content;
34
+
35
+ if (sfc?.template) {
36
+ // AST 模式:通过 vue/compiler-sfc 解析,精确定位 PageMeta 节点
37
+ const pageMetaNode = findNode(sfc, 'PageMeta');
38
+ if (pageMetaNode) {
39
+ pageMetaSource = pageMetaNode.loc.source;
40
+ const metaStart = pageMetaNode.loc.start.offset;
41
+ const metaEnd = pageMetaNode.loc.end.offset;
42
+
43
+ // pageMetaNode.loc 的 offset 是相对于整个文件的,转换为相对于 content 的位置
44
+ const metaStartInContent = metaStart - openTagEnd;
45
+ const metaEndInContent = metaEnd - openTagEnd;
46
+
47
+ newContent = content.slice(0, metaStartInContent) + content.slice(metaEndInContent);
48
+ }
49
+ } else {
50
+ // 降级模式:vue/compiler-sfc 不可用,用正则匹配 <page-meta> 标签
51
+ const pageMetaMatch = content.match(/<page-meta\b[^>]*>[\s\S]*?<\/page-meta>/);
52
+ if (pageMetaMatch) {
53
+ pageMetaSource = pageMetaMatch[0];
54
+ newContent = content.replace(pageMetaMatch[0], '');
55
+ } else {
56
+ // 也匹配自闭合的 <page-meta ... />
57
+ const selfClosingMatch = content.match(/<page-meta\b[^>]*\/>/);
58
+ if (selfClosingMatch) {
59
+ pageMetaSource = selfClosingMatch[0];
60
+ newContent = content.replace(selfClosingMatch[0], '');
61
+ }
62
+ }
63
+ }
64
+
65
+ // page-meta 放在包裹层外部,内容包裹在 <global-root-view> 中
66
+ const wrappedContent = `\n${pageMetaSource}\n<global-root-view>${newContent}</global-root-view>\n`;
67
+
68
+ return {
69
+ code: code.slice(0, openTagEnd) + wrappedContent + code.slice(closeTagStart),
70
+ map: {
71
+ version: 3 as const,
72
+ sources: [] as string[],
73
+ names: [] as string[],
74
+ mappings: ''
75
+ }
76
+ };
77
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * 创建一个最小的 sourcemap,用于满足 Vite/Rollup 的 sourcemap 要求。
3
+ *
4
+ * 这是一个空映射的 sourcemap(mappings 为空字符串),不提供精确的源码映射,
5
+ * 但可以避免 "Sourcemap is likely to be incorrect" 警告。
6
+ * 调试器会回退到显示转换后的代码,不影响功能。
7
+ *
8
+ * 纯 JS 实现,无需第三方依赖。
9
+ */
10
+ function createEmptySourcemap() {
11
+ return {
12
+ version: 3 as const,
13
+ sources: [] as string[],
14
+ names: [] as string[],
15
+ mappings: ''
16
+ };
17
+ }
18
+
19
+ /**
20
+ * 向 main.ts 注入 App.root.vue 的导入和全局注册
21
+ *
22
+ * 流程:
23
+ * 1. 在文件顶部插入 `import GlobalRootView from "./App.root.vue"`
24
+ * 2. 在 createSSRApp 之后插入 `app.component("global-root-view", GlobalRootView)`
25
+ *
26
+ * 注:GlobalRootView 仅为 main.ts 中的局部变量名,
27
+ * 实际组件就是 App.root.vue,页面通过 <global-root-view> 标签使用。
28
+ */
29
+ export function registerRootApp(code: string, fileName: string = 'App.root') {
30
+ const importCode = `import GlobalRootView from "./${fileName}.vue";`;
31
+ const vueUseComponentCode = `app.component("global-root-view", GlobalRootView);`;
32
+
33
+ let newCode = importCode + '\n' + code;
34
+
35
+ // 在 createSSRApp 赋值语句之后插入组件注册代码
36
+ const ssrAppMatch = newCode.match(/(const\s+app\s*=\s*createSSRApp\([^)]+\);)/);
37
+ if (ssrAppMatch) {
38
+ newCode = newCode.replace(/(const\s+app\s*=\s*createSSRApp\([^)]+\);)/, `$1\n ${vueUseComponentCode}`);
39
+ } else {
40
+ // 兜底:在 return { 之前插入
41
+ newCode = newCode.replace(/(createApp[\s\S]*?)(return\s*\{)/, `$1${vueUseComponentCode}\n $2`);
42
+ }
43
+
44
+ return { code: newCode, map: createEmptySourcemap() };
45
+ }
46
+
47
+ /**
48
+ * App.root.vue 模板中已使用 <slot /> 作为子内容插槽,
49
+ * 无需替换,直接透传。
50
+ */
51
+ export function rebuildRootApp(code: string) {
52
+ return { code, map: createEmptySourcemap() };
53
+ }
@@ -0,0 +1,137 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { normalizePath } from 'vite';
4
+
5
+ /**
6
+ * Parse Vue SFC file, return descriptor
7
+ *
8
+ * When vue/compiler-sfc is not available (e.g. HBuilderX projects where
9
+ * vue is not in node_modules), returns null instead of throwing.
10
+ * Callers should fall back to regex-based matching.
11
+ */
12
+ export async function parseSFC(code: string) {
13
+ try {
14
+ const { parse } = await import('vue/compiler-sfc');
15
+ return parse(code, { pad: 'space' }).descriptor;
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Strip JSON comments (single-line and multi-line)
23
+ */
24
+ export function stripJsonComments(str: string): string {
25
+ return str.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
26
+ }
27
+
28
+ /**
29
+ * Convert pages.json path to absolute file path
30
+ */
31
+ export function formatPagePath(root: string, path: string) {
32
+ return normalizePath(`${join(root, path)}.vue`).replace(/^[A-Z]:/, match => match.toLowerCase());
33
+ }
34
+
35
+ /**
36
+ * Load pages.json and resolve all page paths (main + subPackages)
37
+ */
38
+ export function loadPagesJson(path: string, rootPath: string): string[] {
39
+ const raw = readFileSync(path, 'utf-8');
40
+ const { pages = [], subPackages = [] } = JSON.parse(stripJsonComments(raw));
41
+
42
+ return [
43
+ ...pages.map((page: any) => formatPagePath(rootPath, page.path)),
44
+ ...subPackages
45
+ .map(({ pages: subPages = [], root = '' }: any) => {
46
+ return subPages.map((page: any) => formatPagePath(join(rootPath, root), page.path));
47
+ })
48
+ .flat()
49
+ ];
50
+ }
51
+
52
+ /**
53
+ * camelCase to kebab-case: PageMeta -> page-meta
54
+ */
55
+ export function toKebabCase(str: string) {
56
+ return str
57
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
58
+ .replace(/[_\s]+/g, '-')
59
+ .toLowerCase();
60
+ }
61
+
62
+ /**
63
+ * kebab-case to PascalCase: page-meta -> PageMeta
64
+ */
65
+ export function toPascalCase(str: string) {
66
+ return str.replace(/(^\w|-+\w)/g, match => match.toUpperCase().replace(/-/g, ''));
67
+ }
68
+
69
+ interface TagNode {
70
+ loc: {
71
+ source: string;
72
+ start: { offset: number };
73
+ end: { offset: number };
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Find a tag node in SFC template AST by tag name
79
+ * Supports both kebab-case and PascalCase
80
+ */
81
+ export function findNode(sfc: any, rawTagName: string): TagNode | undefined {
82
+ const templateSource = sfc.template?.content;
83
+ if (!templateSource) return;
84
+
85
+ let tagName = '';
86
+ if (templateSource.includes(`<${toKebabCase(rawTagName)}`)) {
87
+ tagName = toKebabCase(rawTagName);
88
+ } else if (templateSource.includes(`<${toPascalCase(rawTagName)}`)) {
89
+ tagName = toPascalCase(rawTagName);
90
+ }
91
+
92
+ if (!tagName) return;
93
+
94
+ const nodeAst = sfc.template?.ast;
95
+ if (!nodeAst) return;
96
+
97
+ // Recursively traverse AST to find the target node
98
+ const traverse = (nodes: any): TagNode | undefined => {
99
+ for (const node of nodes) {
100
+ if (node.type === 1) {
101
+ if (node.tag === tagName) return node;
102
+ if (node.children?.length) {
103
+ const found = traverse(node.children);
104
+ if (found) return found;
105
+ }
106
+ }
107
+ }
108
+ return undefined;
109
+ };
110
+
111
+ return traverse(nodeAst.children);
112
+ }
113
+
114
+ /**
115
+ * Normalize platform-specific page paths (.mp-weixin.vue -> .vue)
116
+ */
117
+ export function normalizePlatformPath(id: string) {
118
+ const platform = process.env.UNI_PLATFORM;
119
+ if (!platform) return id;
120
+
121
+ const regex = new RegExp(`\\.${platform}\\.vue$`);
122
+ if (regex.test(id)) {
123
+ return id.replace(`.${platform}.`, '.');
124
+ }
125
+ return id;
126
+ }
127
+
128
+ /**
129
+ * Debounce utility
130
+ */
131
+ export function debounce<T extends (...args: any[]) => void>(fn: T, delay: number) {
132
+ let timer: ReturnType<typeof setTimeout> | null = null;
133
+ return (...args: Parameters<T>) => {
134
+ if (timer) clearTimeout(timer);
135
+ timer = setTimeout(() => fn(...args), delay);
136
+ };
137
+ }
package/readme.md ADDED
@@ -0,0 +1,79 @@
1
+ # Snake UI
2
+
3
+ Snake UI 是面向 uni-app 商城与 CMS 场景的 Vue 3 组件库,支持 H5、微信小程序和 App。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ pnpm add @puresnake/snake-ui
9
+ ```
10
+
11
+ 在 `main.ts` 安装组件库,并按业务需要传入适配器:
12
+
13
+ ```ts
14
+ import SnakeUI from '@puresnake/snake-ui';
15
+
16
+ app.use(SnakeUI, {
17
+ theme: { defaultDarkMode: 'auto' },
18
+ locale: { defaultLocale: 'zh-CN' },
19
+ http: { config: { baseUrl: '/api' } },
20
+ request: { get, post },
21
+ cache: { get, set, delete: remove },
22
+ config: { baseUrl: '/api' }
23
+ });
24
+ ```
25
+
26
+ Snake UI 不依赖其他 UI 组件库,不需要额外导入第三方主题样式。底座内置 Snake 绿色明暗主题、`zh-CN` / `en-US`、基于 `uni.request` 的 HTTP 客户端和常用 hooks / 工具。
27
+
28
+ ```ts
29
+ import { http, setDarkMode, setLocale } from '@puresnake/snake-ui';
30
+
31
+ setDarkMode('auto');
32
+ setLocale('en-US');
33
+ const data = await http.get('/goods');
34
+ ```
35
+
36
+ 如需统一覆盖品牌色、文字色和圆角,可在应用入口导入可选主题变量:
37
+
38
+ ```scss
39
+ @import '@puresnake/snake-ui/theme.scss';
40
+
41
+ :root,
42
+ page {
43
+ --snake-color-primary: #06d290;
44
+ }
45
+ ```
46
+
47
+ ## easycom
48
+
49
+ ```json
50
+ {
51
+ "easycom": {
52
+ "autoscan": true,
53
+ "custom": {
54
+ "^snake-(.*)": "@puresnake/snake-ui/components/snake-$1/snake-$1.vue"
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ ```vue
61
+ <snake-button type="primary">确定</snake-button>
62
+ <snake-popup v-model="visible" mode="bottom">...</snake-popup>
63
+ ```
64
+
65
+ ## 手动导入
66
+
67
+ 组件推荐使用 easycom 标签;如需手动导入,按组件路径引入:
68
+
69
+ ```ts
70
+ import Button from '@puresnake/snake-ui/components/snake-button/snake-button.vue';
71
+ import type { ButtonProps, PopupMode } from '@puresnake/snake-ui';
72
+ import { addUnit, navTo, sleep, toast } from '@puresnake/snake-ui/libs';
73
+ ```
74
+
75
+ ## 公开基础组件
76
+
77
+ `snake-icon`、`snake-popup`、`snake-overlay`、`snake-button`、`snake-image`、`snake-tabs`、`snake-sticky`、`snake-notice-bar`、`snake-loadmore`、`snake-empty`、`snake-swiper`、`snake-button-sort`、`snake-drop-menu`、`snake-drop-menu-item`、`snake-index-list`、`snake-index-list-panel`、`snake-index-anchor`、`snake-form`、`snake-form-item`、`snake-input`、`snake-textarea`、`snake-checkbox`、`snake-checkbox-group`、`snake-radio`、`snake-radio-group`、`snake-switch`、`snake-slider`。
78
+
79
+ CMS 商品、优惠券和跳转能力通过 `app.use(SnakeUI, { cms: { services: ... } })` 显式注入。纯展示 CMS 不要求请求适配器。
package/theme.scss ADDED
@@ -0,0 +1,118 @@
1
+ /* Snake UI theme tokens. Import from uni.scss for SCSS variables. */
2
+ /* 品牌绿七档自有体系 + 语义色与中性色默认主题 */
3
+ :root,
4
+ page {
5
+ --snake-color-primary: #06d290;
6
+ --snake-color-primary-rgb: 6, 210, 144;
7
+ --snake-color-primary-dark: #2ebd7c;
8
+ --snake-color-primary-dark-rgb: 46, 189, 124;
9
+ --snake-color-primary-deep: #26273a;
10
+ --snake-color-primary-deep-rgb: 38, 39, 58;
11
+ --snake-color-primary-deeper: #22242e;
12
+ --snake-color-primary-deeper-rgb: 34, 36, 46;
13
+ --snake-color-primary-disabled: #a6ebd3;
14
+ --snake-color-primary-light: #eeffe0;
15
+ --snake-color-primary-light-rgb: 238, 255, 224;
16
+ --snake-color-primary-ink: #ffffff;
17
+ --snake-color-success: #19be6b;
18
+ --snake-color-success-rgb: 25, 190, 107;
19
+ --snake-color-success-dark: #18b566;
20
+ --snake-color-success-disabled: #71d5a1;
21
+ --snake-color-success-light: #dbf1e1;
22
+ --snake-color-warning: #ff9900;
23
+ --snake-color-warning-rgb: 255, 153, 0;
24
+ --snake-color-warning-dark: #f29100;
25
+ --snake-color-warning-disabled: #fcbd71;
26
+ --snake-color-warning-light: #fdf6ec;
27
+ --snake-color-error: #fa3534;
28
+ --snake-color-error-rgb: 250, 53, 52;
29
+ --snake-color-error-dark: #dd6161;
30
+ --snake-color-error-disabled: #fab6b6;
31
+ --snake-color-error-light: #fef0f0;
32
+ --snake-color-info: #909399;
33
+ --snake-color-info-rgb: 144, 147, 153;
34
+ --snake-color-info-dark: #82848a;
35
+ --snake-color-info-disabled: #c8c9cc;
36
+ --snake-color-info-light: #f4f4f5;
37
+ --snake-color-white: #ffffff;
38
+ --snake-color-black: #000000;
39
+ --snake-color-text: #303133;
40
+ --snake-color-text-rgb: 48, 49, 51;
41
+ --snake-color-text-secondary: #606266;
42
+ --snake-color-text-secondary-rgb: 96, 98, 102;
43
+ --snake-color-text-muted: #909399;
44
+ --snake-color-text-light: #c0c4cc;
45
+ --snake-color-border: #dcdfe6;
46
+ --snake-color-border-rgb: 220, 223, 230;
47
+ --snake-color-divider: #e4e7ed;
48
+ --snake-color-mask: rgba(0, 0, 0, 0.4);
49
+ --snake-color-shadow: rgba(0, 0, 0, 0.1);
50
+ --snake-color-background: #f6f6f6;
51
+ --snake-color-surface: #ffffff;
52
+ --snake-color-surface-rgb: 255, 255, 255;
53
+ --snake-color-surface-muted: #f1f1f1;
54
+ --snake-color-disabled-bg: #f1f1f1;
55
+ --snake-color-form-error: #fa3534;
56
+ --snake-control-height-small: 64rpx;
57
+ --snake-control-height: 80rpx;
58
+ --snake-control-height-large: 92rpx;
59
+ --snake-color-notice: #ff9900;
60
+ --snake-color-notice-background: #fdf6ec;
61
+ --snake-radius-small: 8rpx;
62
+ --snake-radius-base: 12rpx;
63
+ --snake-radius-large: 20rpx;
64
+ --snake-duration-fast: 180ms;
65
+ --snake-duration-base: 300ms;
66
+ --snake-easing-standard: cubic-bezier(0.2, 0.8, 0.2, 1);
67
+ --snake-z-index-overlay: 10070;
68
+ --snake-z-index-popup: 10075;
69
+ }
70
+
71
+ $snake-color-primary: var(--snake-color-primary) !default;
72
+ $snake-color-primary-dark: var(--snake-color-primary-dark) !default;
73
+ $snake-color-primary-deep: var(--snake-color-primary-deep) !default;
74
+ $snake-color-primary-deeper: var(--snake-color-primary-deeper) !default;
75
+ $snake-color-primary-disabled: var(--snake-color-primary-disabled) !default;
76
+ $snake-color-primary-light: var(--snake-color-primary-light) !default;
77
+ $snake-color-primary-ink: var(--snake-color-primary-ink) !default;
78
+ $snake-color-success: var(--snake-color-success) !default;
79
+ $snake-color-success-dark: var(--snake-color-success-dark) !default;
80
+ $snake-color-success-disabled: var(--snake-color-success-disabled) !default;
81
+ $snake-color-success-light: var(--snake-color-success-light) !default;
82
+ $snake-color-warning: var(--snake-color-warning) !default;
83
+ $snake-color-warning-dark: var(--snake-color-warning-dark) !default;
84
+ $snake-color-warning-disabled: var(--snake-color-warning-disabled) !default;
85
+ $snake-color-warning-light: var(--snake-color-warning-light) !default;
86
+ $snake-color-error: var(--snake-color-error) !default;
87
+ $snake-color-error-dark: var(--snake-color-error-dark) !default;
88
+ $snake-color-error-disabled: var(--snake-color-error-disabled) !default;
89
+ $snake-color-error-light: var(--snake-color-error-light) !default;
90
+ $snake-color-info: var(--snake-color-info) !default;
91
+ $snake-color-info-dark: var(--snake-color-info-dark) !default;
92
+ $snake-color-info-disabled: var(--snake-color-info-disabled) !default;
93
+ $snake-color-info-light: var(--snake-color-info-light) !default;
94
+ $snake-color-white: var(--snake-color-white) !default;
95
+ $snake-color-black: var(--snake-color-black) !default;
96
+ $snake-color-text: var(--snake-color-text) !default;
97
+ $snake-color-text-secondary: var(--snake-color-text-secondary) !default;
98
+ $snake-color-text-muted: var(--snake-color-text-muted) !default;
99
+ $snake-color-text-light: var(--snake-color-text-light) !default;
100
+ $snake-color-border: var(--snake-color-border) !default;
101
+ $snake-color-divider: var(--snake-color-divider) !default;
102
+ $snake-color-mask: var(--snake-color-mask) !default;
103
+ $snake-color-shadow: var(--snake-color-shadow) !default;
104
+ $snake-color-background: var(--snake-color-background) !default;
105
+ $snake-color-surface: var(--snake-color-surface) !default;
106
+ $snake-color-surface-muted: var(--snake-color-surface-muted) !default;
107
+ $snake-color-disabled-bg: var(--snake-color-disabled-bg) !default;
108
+ $snake-color-form-error: var(--snake-color-form-error) !default;
109
+ $snake-color-notice: var(--snake-color-notice) !default;
110
+ $snake-color-notice-background: var(--snake-color-notice-background) !default;
111
+ $snake-radius-small: 8rpx !default;
112
+ $snake-radius-base: 12rpx !default;
113
+ $snake-radius-large: 20rpx !default;
114
+ $snake-duration-fast: 180ms !default;
115
+ $snake-duration-base: 300ms !default;
116
+ $snake-easing-standard: cubic-bezier(0.2, 0.8, 0.2, 1) !default;
117
+ $snake-z-index-overlay: 10070 !default;
118
+ $snake-z-index-popup: 10075 !default;