@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,24 @@
1
+ <template>
2
+ <view class="richtext">
3
+ <snake-parse :content="datas.myValue"></snake-parse>
4
+ </view>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ /**
9
+ * @component RichText
10
+ * @description 渲染 CMS 提供的 HTML 内容。
11
+ */
12
+
13
+ import type { RichTextProps } from './types';
14
+
15
+ defineOptions({ name: 'RichText', options: { virtualHost: true, styleIsolation: 'shared' } });
16
+ withDefaults(defineProps<RichTextProps>(), { datas: () => ({}) });
17
+ </script>
18
+
19
+ <style lang="scss" scoped>
20
+ .richtext {
21
+ padding: 0 20rpx;
22
+ white-space: break-word !important;
23
+ }
24
+ </style>
@@ -0,0 +1,5 @@
1
+ /** RichText 组件的公开属性。 */
2
+ export interface RichTextProps<Data extends Record<string, any> = Record<string, any>> {
3
+ /** CMS 装修组件配置数据。 */
4
+ datas?: Data;
5
+ }
@@ -0,0 +1,92 @@
1
+ <template>
2
+ <!-- #ifdef H5 -->
3
+ <!-- H5 端使用 teleport 把内容传送到 body -->
4
+ <teleport to="body">
5
+ <!-- #endif -->
6
+ <!-- #ifdef MP-WEIXIN || MP-ALIPAY -->
7
+ <!-- #ifndef MP-DINGTALK -->
8
+ <!-- 微信/支付宝小程序使用原生 root-portal 组件传送 -->
9
+ <root-portal>
10
+ <!-- #endif -->
11
+ <!-- #endif -->
12
+ <view
13
+ :class="['snake-root-portal', `snake-theme-${mode}`, props.customClass]"
14
+ :data-snake-theme-mode="mode"
15
+ :style="[themeStyle, props.customStyle]"
16
+ >
17
+ <slot />
18
+ </view>
19
+ <!-- #ifdef MP-WEIXIN || MP-ALIPAY -->
20
+ <!-- #ifndef MP-DINGTALK -->
21
+ </root-portal>
22
+ <!-- #endif -->
23
+ <!-- #endif -->
24
+ <!-- #ifdef H5 -->
25
+ </teleport>
26
+ <!-- #endif -->
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ /**
31
+ * @component RootPortal
32
+ * @description 根节点传送组件:把插槽内容渲染到页面根节点,避免被祖先的 transform、overflow 或层叠上下文影响,解决复杂布局下 fixed 弹层失效的问题。H5 端使用 teleport,微信/支付宝小程序端使用原生 root-portal,App 端通过 renderjs 移动节点,其余平台原位渲染。
33
+ * @see /components/root-portal
34
+ */
35
+ import { computed } from 'vue';
36
+ import { darkMode, systemDark, themeStyle } from '../../libs/config/theme';
37
+ import type { RootPortalProps } from './types';
38
+
39
+ defineOptions({
40
+ name: 'RootPortal',
41
+ options: {
42
+ addGlobalClass: true,
43
+ // #ifndef MP-TOUTIAO
44
+ virtualHost: true,
45
+ // #endif
46
+ styleIsolation: 'shared'
47
+ }
48
+ });
49
+
50
+ const props = defineProps<RootPortalProps>();
51
+
52
+ // 传送后的内容脱离 snake-config-provider 的子树,需在内层容器重新携带主题变量与暗色 class
53
+ const mode = computed<'light' | 'dark'>(() =>
54
+ darkMode.value === 'auto' ? (systemDark.value ? 'dark' : 'light') : darkMode.value
55
+ );
56
+ </script>
57
+
58
+ <!-- #ifdef APP-PLUS -->
59
+ <script module="render" lang="renderjs">
60
+ // renderjs 运行在 webview 的 JS 环境,$ownerInstance 由框架注入,需显式 this 类型 vue-tsc 才能通过
61
+ interface RenderBridge {
62
+ /** renderjs 桥接的宿主组件实例。 */
63
+ $ownerInstance?: { $el?: HTMLElement };
64
+ }
65
+
66
+ /** App 端把组件根节点搬到应用根容器(attach)或移回原位,脱离原父级的 transform/overflow 布局。 */
67
+ function relocate(instance: RenderBridge, attach: boolean): void {
68
+ const ownerInstance = instance.$ownerInstance;
69
+ if (!ownerInstance || !ownerInstance.$el) return;
70
+
71
+ const root = document.querySelector('uni-app') || document.body;
72
+ if (attach) {
73
+ root.appendChild(ownerInstance.$el);
74
+ } else if (ownerInstance.$el.parentNode === root) {
75
+ root.removeChild(ownerInstance.$el);
76
+ }
77
+ }
78
+
79
+ export default {
80
+ mounted(this: RenderBridge) {
81
+ relocate(this, true);
82
+ },
83
+ // renderjs 沿用 Vue2 风格生命周期名(与参考实现一致),Vue3 的 eslint 规则在此不适用
84
+ // eslint-disable-next-line vue/no-deprecated-destroyed-lifecycle
85
+ beforeDestroy(this: RenderBridge) {
86
+ relocate(this, false);
87
+ }
88
+ };
89
+ </script>
90
+ <!-- #endif -->
91
+
92
+ <style lang="scss" scoped></style>
@@ -0,0 +1,9 @@
1
+ import type { StyleValue } from '../../types/global';
2
+
3
+ /** RootPortal 组件的公开属性。 */
4
+ export interface RootPortalProps {
5
+ /** 根节点自定义类名。 */
6
+ customClass?: string;
7
+ /** 根节点自定义样式。 */
8
+ customStyle?: StyleValue;
9
+ }
@@ -0,0 +1,202 @@
1
+ <template>
2
+ <view class="snake-search" :class="customClass" :style="[{ margin: margin }, customStyle]" @click="clickHandler">
3
+ <view
4
+ class="snake-search__content"
5
+ :style="{
6
+ backgroundColor: bgColor,
7
+ borderRadius: shape === 'round' ? '100rpx' : '10rpx',
8
+ border: borderStyle,
9
+ height: `${height}rpx`
10
+ }"
11
+ >
12
+ <view class="snake-search__icon">
13
+ <snake-icon :size="30" :name="searchIcon" :color="searchIconColor || color" />
14
+ </view>
15
+ <input
16
+ confirm-type="search"
17
+ :value="modelValue"
18
+ :focus="focus"
19
+ :maxlength="Number(maxlength)"
20
+ :adjust-position="adjustPosition"
21
+ :placeholder="placeholderText"
22
+ :placeholder-style="`color: ${placeholderColor}`"
23
+ class="snake-search__input"
24
+ type="text"
25
+ :style="[
26
+ {
27
+ textAlign: inputAlign,
28
+ color: color,
29
+ backgroundColor: bgColor,
30
+ pointerEvents: disabled ? 'none' : 'auto'
31
+ },
32
+ inputStyle
33
+ ]"
34
+ @blur="blur"
35
+ @confirm="search"
36
+ @input="inputChange"
37
+ @focus="getFocus"
38
+ />
39
+ <view v-if="keyword && clearabled && focused" class="snake-search__clear" @click="clear">
40
+ <snake-icon name="close-circle-fill" size="34" color="var(--snake-color-text-light, #c0c4cc)" />
41
+ </view>
42
+ </view>
43
+ <view
44
+ :style="[actionStyle]"
45
+ class="snake-search__action"
46
+ :class="{ 'snake-search__action--active': showActionBtn || show }"
47
+ @click.stop.prevent="custom"
48
+ >
49
+ {{ actionTextValue }}
50
+ </view>
51
+ </view>
52
+ </template>
53
+
54
+ <script setup lang="ts">
55
+ /**
56
+ * @component Search
57
+ * @description 搜索框,集成了常用搜索框所需功能,支持圆形/方形、清除控件、右侧操作按钮与聚焦动画。
58
+ * @see /components/search
59
+ */
60
+
61
+ import { computed, nextTick, ref, watch } from 'vue';
62
+ import { useLocale } from '../../libs/hooks/useLocale';
63
+ import Icon from '../snake-icon/snake-icon.vue';
64
+ import { searchProps, type SearchEmits } from './types';
65
+
66
+ defineOptions({ name: 'SnakeSearch', options: { virtualHost: true, styleIsolation: 'shared' } });
67
+ const props = defineProps(searchProps);
68
+ const emit = defineEmits<SearchEmits>();
69
+ const { t } = useLocale('search');
70
+
71
+ // 输入框当前值,v-model 双向同步
72
+ const keyword = ref(props.modelValue);
73
+ // 控制右侧操作按钮动画展开
74
+ const show = ref(false);
75
+ // 输入框是否处于聚焦中,聚焦时才显示清除控件
76
+ const focused = ref(props.focus);
77
+
78
+ watch(
79
+ () => props.modelValue,
80
+ nVal => {
81
+ keyword.value = nVal;
82
+ }
83
+ );
84
+ watch(keyword, nVal => {
85
+ emit('update:modelValue', nVal);
86
+ emit('input', nVal);
87
+ emit('change', nVal);
88
+ });
89
+
90
+ const placeholderText = computed(() => props.placeholder || t('placeholder'));
91
+ const actionTextValue = computed(() => props.actionText || t('actionText'));
92
+ /** 未开启动画时始终显示操作按钮。 */
93
+ const showActionBtn = computed(() => {
94
+ if (!props.animation && props.showAction) return true;
95
+ return false;
96
+ });
97
+ /** 边框样式。 */
98
+ const borderStyle = computed(() => {
99
+ if (props.borderColor) return `1px solid ${props.borderColor}`;
100
+ return 'none';
101
+ });
102
+
103
+ /** 输入事件,同步输入框内容。 */
104
+ function inputChange(event: { detail: unknown }) {
105
+ const detail = event.detail as { value?: string | number };
106
+ keyword.value = String(detail?.value ?? '');
107
+ }
108
+ /** 清空输入,延后发出事件避免父组件读取到更新前的值。 */
109
+ function clear() {
110
+ keyword.value = '';
111
+ nextTick(() => {
112
+ emit('clear');
113
+ });
114
+ }
115
+ /** 确定搜索。 */
116
+ function search(event: { detail: unknown }) {
117
+ const detail = event.detail as { value?: string | number };
118
+ emit('search', String(detail?.value ?? ''));
119
+ try {
120
+ // #ifdef H5 || MP
121
+ uni.hideKeyboard();
122
+ // #endif
123
+ } catch {
124
+ /* 平台不支持时忽略 */
125
+ }
126
+ }
127
+ /** 点击右侧操作按钮。 */
128
+ function custom() {
129
+ emit('custom', keyword.value);
130
+ try {
131
+ // #ifdef H5 || MP
132
+ uni.hideKeyboard();
133
+ // #endif
134
+ } catch {
135
+ /* 平台不支持时忽略 */
136
+ }
137
+ }
138
+ /** 获取焦点。 */
139
+ function getFocus() {
140
+ focused.value = true;
141
+ if (props.animation && props.showAction) show.value = true;
142
+ emit('focus', keyword.value);
143
+ }
144
+ /** 失去焦点,延时隐藏清除图标避免清除点击被 blur 抢先吞掉。 */
145
+ function blur() {
146
+ setTimeout(() => {
147
+ focused.value = false;
148
+ }, 100);
149
+ show.value = false;
150
+ emit('blur', keyword.value);
151
+ }
152
+ /** 点击搜索框,仅在禁用时发出事件,意味着想跳转真正的搜索页。 */
153
+ function clickHandler() {
154
+ if (props.disabled) emit('click');
155
+ }
156
+ </script>
157
+
158
+ <style scoped>
159
+ .snake-search {
160
+ display: flex;
161
+ flex: 1;
162
+ align-items: center;
163
+ }
164
+ .snake-search__content {
165
+ display: flex;
166
+ flex: 1;
167
+ align-items: center;
168
+ padding: 0 18rpx;
169
+ }
170
+ .snake-search__icon {
171
+ display: flex;
172
+ align-items: center;
173
+ }
174
+ .snake-search__input {
175
+ flex: 1;
176
+ margin: 0 10rpx;
177
+ font-size: 28rpx;
178
+ line-height: 1;
179
+ color: var(--snake-color-text-muted, #909399);
180
+ }
181
+ .snake-search__clear {
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: center;
185
+ width: 40rpx;
186
+ height: 100%;
187
+ border-radius: 50%;
188
+ }
189
+ .snake-search__action {
190
+ overflow: hidden;
191
+ width: 0;
192
+ font-size: 28rpx;
193
+ color: var(--snake-color-text, #303133);
194
+ text-align: center;
195
+ white-space: nowrap;
196
+ transition: all 0.3s;
197
+ }
198
+ .snake-search__action--active {
199
+ width: 100rpx;
200
+ margin-left: 10rpx;
201
+ }
202
+ </style>
@@ -0,0 +1,84 @@
1
+ import type { ExtractPropTypes, PropType } from 'vue';
2
+ import type { StyleValue } from '../../types/global';
3
+
4
+ /** SearchShape 类型定义。 */
5
+ export type SearchShape = 'round' | 'square';
6
+ /** SearchInputAlign 类型定义。 */
7
+ export type SearchInputAlign = 'left' | 'center' | 'right';
8
+
9
+ /** searchProps 运行时属性及默认值。 */
10
+ export const searchProps = {
11
+ /** 根节点自定义样式。 */
12
+ customStyle: { type: [String, Object, Array] as PropType<StyleValue>, default: '' },
13
+ /** 根节点自定义类名。 */
14
+ customClass: { type: String, default: '' },
15
+ /** 搜索框形状,round 圆形,square 方形。 */
16
+ shape: { type: String as PropType<SearchShape>, default: 'round' },
17
+ /** 搜索框背景色。 */
18
+ bgColor: { type: String, default: 'var(--snake-color-surface-muted, #f2f3f6)' },
19
+ /** 占位提示文字。 */
20
+ placeholder: { type: String, default: '' },
21
+ /** 是否启用清除控件。 */
22
+ clearabled: { type: Boolean, default: true },
23
+ /** 是否自动聚焦。 */
24
+ focus: { type: Boolean, default: false },
25
+ /** 是否在搜索框右侧显示操作按钮。 */
26
+ showAction: { type: Boolean, default: true },
27
+ /** 右侧操作按钮的样式,对象形式。 */
28
+ actionStyle: { type: [Object, Array] as PropType<StyleValue>, default: () => ({}) },
29
+ /** 右侧操作按钮文字。 */
30
+ actionText: { type: String, default: '' },
31
+ /** 输入框内容水平对齐方式。 */
32
+ inputAlign: { type: String as PropType<SearchInputAlign>, default: 'left' },
33
+ /** 是否禁用输入框。 */
34
+ disabled: { type: Boolean, default: false },
35
+ /** 开启 showAction 时,是否在 input 获取焦点时才显示操作按钮。 */
36
+ animation: { type: Boolean, default: false },
37
+ /** 边框颜色,只要配置了颜色,才会有边框。 */
38
+ borderColor: { type: String, default: 'none' },
39
+ /** 双向绑定的输入值。 */
40
+ modelValue: { type: String, default: '' },
41
+ /** 搜索框高度,数值按 rpx 处理。 */
42
+ height: { type: [Number, String] as PropType<number | string>, default: 64 },
43
+ /** 输入框的样式,可以定义文字颜色、大小等,对象形式。 */
44
+ inputStyle: { type: [Object, Array] as PropType<StyleValue>, default: () => ({}) },
45
+ /** 输入框最大能输入的长度,-1 为不限制长度。 */
46
+ maxlength: { type: [Number, String] as PropType<number | string>, default: '-1' },
47
+ /** 搜索图标的颜色,默认同输入框字体颜色。 */
48
+ searchIconColor: { type: String, default: '' },
49
+ /** 输入框字体颜色。 */
50
+ color: { type: String, default: 'var(--snake-color-text-secondary, #606266)' },
51
+ /** placeholder 的颜色。 */
52
+ placeholderColor: { type: String, default: 'var(--snake-color-text-muted, #909399)' },
53
+ /** 与上下左右元素的间距,带单位的字符串形式。 */
54
+ margin: { type: String, default: '0' },
55
+ /** 左侧输入框的图标,可以为图标名称或图片路径。 */
56
+ searchIcon: { type: String, default: 'search' },
57
+ /** 弹出键盘时是否自动调节高度。 */
58
+ adjustPosition: { type: Boolean, default: true }
59
+ } as const;
60
+
61
+ /** Search 组件的公开属性。 */
62
+ export type SearchProps = ExtractPropTypes<typeof searchProps>;
63
+
64
+ /** Search 组件的事件契约。 */
65
+ export type SearchEmits = {
66
+ /** 双向绑定值更新。 */
67
+ 'update:modelValue': [value: string];
68
+ /** 输入事件,携带输入框内容。 */
69
+ input: [value: string];
70
+ /** 内容变化事件,携带输入框内容。 */
71
+ change: [value: string];
72
+ /** 用户确定搜索时触发。 */
73
+ search: [value: string];
74
+ /** 用户点击右侧操作按钮时触发。 */
75
+ custom: [value: string];
76
+ /** 用户点击清除按钮时触发。 */
77
+ clear: [];
78
+ /** 输入框获得焦点时触发。 */
79
+ focus: [value: string];
80
+ /** 输入框失去焦点时触发。 */
81
+ blur: [value: string];
82
+ /** 禁用状态下点击搜索框时触发。 */
83
+ click: [];
84
+ };