@kine-design/core 0.0.1-beta.1 → 0.0.1-beta.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 (300) hide show
  1. package/assets/style/global.css +1 -0
  2. package/assets/style/var/Wuxing.css +71 -0
  3. package/assets/style/var.css +23 -0
  4. package/components/base/affix/api.ts +16 -0
  5. package/components/base/affix/index.ts +15 -0
  6. package/components/base/affix/props.d.ts +34 -0
  7. package/components/base/affix/useAffix.ts +123 -0
  8. package/components/base/alert/api.ts +18 -0
  9. package/components/base/alert/index.ts +15 -0
  10. package/components/base/alert/props.d.ts +50 -0
  11. package/components/base/anchor/api.ts +20 -0
  12. package/components/base/anchor/index.ts +16 -0
  13. package/components/base/anchor/props.d.ts +46 -0
  14. package/components/base/anchor/useAnchor.ts +83 -0
  15. package/components/base/autoComplete/api.ts +24 -0
  16. package/components/base/autoComplete/index.ts +17 -0
  17. package/components/base/autoComplete/props.d.ts +75 -0
  18. package/components/base/autoComplete/useAutoComplete.ts +149 -0
  19. package/components/base/avatar/api.ts +17 -0
  20. package/components/base/avatar/avatar.css +61 -0
  21. package/components/base/avatar/index.ts +14 -0
  22. package/components/base/avatar/props.d.ts +37 -0
  23. package/components/base/backTop/api.ts +17 -0
  24. package/components/base/backTop/index.ts +15 -0
  25. package/components/base/backTop/props.d.ts +38 -0
  26. package/components/base/backTop/useBackTop.ts +62 -0
  27. package/components/base/badge/api.ts +22 -0
  28. package/components/base/badge/index.ts +15 -0
  29. package/components/base/badge/props.d.ts +50 -0
  30. package/components/base/button/api.ts +28 -0
  31. package/components/base/button/button.css +34 -0
  32. package/components/base/button/index.ts +16 -0
  33. package/components/base/button/props.d.ts +64 -0
  34. package/components/base/button/useButton.ts +37 -0
  35. package/components/base/card/api.ts +17 -0
  36. package/components/base/card/index.ts +15 -0
  37. package/components/base/card/props.d.ts +37 -0
  38. package/components/base/carousel/api.ts +28 -0
  39. package/components/base/carousel/index.ts +17 -0
  40. package/components/base/carousel/props.d.ts +72 -0
  41. package/components/base/carousel/useCarousel.ts +151 -0
  42. package/components/base/cascader/api.ts +23 -0
  43. package/components/base/cascader/index.ts +18 -0
  44. package/components/base/cascader/props.d.ts +103 -0
  45. package/components/base/cascader/useCascader.ts +334 -0
  46. package/components/base/checkbox/api.ts +24 -0
  47. package/components/base/checkbox/checkbox.css +0 -0
  48. package/components/base/checkbox/index.ts +16 -0
  49. package/components/base/checkbox/props.d.ts +77 -0
  50. package/components/base/checkbox/useCheckbox.ts +42 -0
  51. package/components/base/collapse/api.ts +21 -0
  52. package/components/base/collapse/index.ts +16 -0
  53. package/components/base/collapse/props.d.ts +45 -0
  54. package/components/base/collapse/useCollapse.ts +80 -0
  55. package/components/base/datePicker/api.ts +18 -0
  56. package/components/base/datePicker/index.ts +19 -0
  57. package/components/base/datePicker/props.d.ts +60 -0
  58. package/components/base/datePicker/useDatePicker.ts +392 -0
  59. package/components/base/divider/api.ts +15 -0
  60. package/components/base/divider/divider.css +11 -0
  61. package/components/base/divider/index.ts +15 -0
  62. package/components/base/divider/props.d.ts +30 -0
  63. package/components/base/dropdown/api.ts +33 -0
  64. package/components/base/dropdown/index.ts +16 -0
  65. package/components/base/dropdown/props.d.ts +60 -0
  66. package/components/base/dropdown/useDropdown.ts +123 -0
  67. package/components/base/empty/api.ts +15 -0
  68. package/components/base/empty/index.ts +15 -0
  69. package/components/base/empty/props.d.ts +26 -0
  70. package/components/base/image/api.ts +25 -0
  71. package/components/base/image/index.ts +18 -0
  72. package/components/base/image/props.d.ts +67 -0
  73. package/components/base/image/useImage.ts +119 -0
  74. package/components/base/input/api.ts +19 -0
  75. package/components/base/input/index.ts +16 -0
  76. package/components/base/input/input.css +19 -0
  77. package/components/base/input/props.d.ts +60 -0
  78. package/components/base/input/useInput.ts +53 -0
  79. package/components/base/inputNumber/api.ts +21 -0
  80. package/components/base/inputNumber/index.ts +15 -0
  81. package/components/base/inputNumber/props.d.ts +64 -0
  82. package/components/base/inputNumber/useInputNumber.ts +140 -0
  83. package/components/base/li/api.ts +15 -0
  84. package/components/base/li/index.ts +13 -0
  85. package/components/base/li/props.d.ts +30 -0
  86. package/components/base/list/api.ts +16 -0
  87. package/components/base/list/index.ts +15 -0
  88. package/components/base/list/props.d.ts +33 -0
  89. package/components/base/list/useList.ts +36 -0
  90. package/components/base/loading/api.ts +17 -0
  91. package/components/base/loading/index.ts +15 -0
  92. package/components/base/loading/props.d.ts +38 -0
  93. package/components/base/popover/api.ts +28 -0
  94. package/components/base/popover/index.ts +15 -0
  95. package/components/base/popover/props.d.ts +73 -0
  96. package/components/base/popover/usePopover.ts +188 -0
  97. package/components/base/progress/api.ts +18 -0
  98. package/components/base/progress/index.ts +15 -0
  99. package/components/base/progress/props.d.ts +53 -0
  100. package/components/base/progress/useProgress.ts +28 -0
  101. package/components/base/radio/api.ts +19 -0
  102. package/components/base/radio/index.ts +19 -0
  103. package/components/base/radio/props.d.ts +59 -0
  104. package/components/base/radio/useRadio.ts +11 -0
  105. package/components/base/rate/api.ts +18 -0
  106. package/components/base/rate/index.ts +15 -0
  107. package/components/base/rate/props.d.ts +49 -0
  108. package/components/base/rate/useRate.ts +75 -0
  109. package/components/base/result/api.ts +20 -0
  110. package/components/base/result/index.ts +15 -0
  111. package/components/base/result/props.d.ts +36 -0
  112. package/components/base/select/api.ts +31 -0
  113. package/components/base/select/index.ts +18 -0
  114. package/components/base/select/props.d.ts +132 -0
  115. package/components/base/select/select.css +7 -0
  116. package/components/base/select/useSelect.ts +280 -0
  117. package/components/base/select/useSelectTools.ts +60 -0
  118. package/components/base/skeleton/api.ts +18 -0
  119. package/components/base/skeleton/index.ts +15 -0
  120. package/components/base/skeleton/props.d.ts +41 -0
  121. package/components/base/slider/api.ts +20 -0
  122. package/components/base/slider/index.ts +15 -0
  123. package/components/base/slider/props.d.ts +65 -0
  124. package/components/base/slider/useSlider.ts +83 -0
  125. package/components/base/space/api.ts +17 -0
  126. package/components/base/space/index.ts +15 -0
  127. package/components/base/space/props.d.ts +39 -0
  128. package/components/base/steps/api.ts +30 -0
  129. package/components/base/steps/index.ts +22 -0
  130. package/components/base/steps/props.d.ts +88 -0
  131. package/components/base/steps/useSteps.ts +101 -0
  132. package/components/base/switch/api.ts +22 -0
  133. package/components/base/switch/index.ts +17 -0
  134. package/components/base/switch/props.d.ts +66 -0
  135. package/components/base/switch/useSwitch.tsx +79 -0
  136. package/components/base/tabs/api.ts +23 -0
  137. package/components/base/tabs/index.ts +18 -0
  138. package/components/base/tabs/props.d.ts +41 -0
  139. package/components/base/tabs/useTabs.ts +66 -0
  140. package/components/base/tag/api.ts +17 -0
  141. package/components/base/tag/index.ts +13 -0
  142. package/components/base/tag/props.d.ts +49 -0
  143. package/components/base/timePicker/api.ts +21 -0
  144. package/components/base/timePicker/index.ts +18 -0
  145. package/components/base/timePicker/props.d.ts +66 -0
  146. package/components/base/timePicker/useTimePicker.ts +161 -0
  147. package/components/base/timeline/api.ts +24 -0
  148. package/components/base/timeline/index.ts +16 -0
  149. package/components/base/timeline/props.d.ts +60 -0
  150. package/components/base/tooltip/api.ts +19 -0
  151. package/components/base/tooltip/index.ts +17 -0
  152. package/components/base/tooltip/props.d.ts +34 -0
  153. package/components/base/tooltip/useTooltip.ts +89 -0
  154. package/components/base/transfer/api.ts +18 -0
  155. package/components/base/transfer/index.ts +17 -0
  156. package/components/base/transfer/props.d.ts +63 -0
  157. package/components/base/transfer/useTransfer.ts +207 -0
  158. package/components/base/tree/api.ts +47 -0
  159. package/components/base/tree/index.ts +29 -0
  160. package/components/base/tree/props.d.ts +108 -0
  161. package/components/base/tree/tree.ts +263 -0
  162. package/components/base/tree/useTree.ts +114 -0
  163. package/components/message/confirm/api.ts +21 -0
  164. package/components/message/confirm/index.ts +15 -0
  165. package/components/message/confirm/props.d.ts +69 -0
  166. package/components/message/dialog/api.ts +19 -0
  167. package/components/message/dialog/index.ts +15 -0
  168. package/components/message/dialog/props.d.ts +55 -0
  169. package/components/message/drawer/api.ts +32 -0
  170. package/components/message/drawer/index.ts +15 -0
  171. package/components/message/drawer/props.d.ts +73 -0
  172. package/components/message/message/api.ts +27 -0
  173. package/components/message/message/index.ts +20 -0
  174. package/components/message/message/props.d.ts +54 -0
  175. package/components/message/message/useMessage.ts +61 -0
  176. package/components/message/notification/api.ts +23 -0
  177. package/components/message/notification/index.ts +19 -0
  178. package/components/message/notification/props.d.ts +64 -0
  179. package/components/message/notification/useNotification.ts +79 -0
  180. package/components/message/popover/MPopover.tsx +94 -0
  181. package/components/message/popover/api.ts +54 -0
  182. package/components/message/popover/index.ts +17 -0
  183. package/components/message/popover/popover.css +21 -0
  184. package/components/message/popover/props.d.ts +76 -0
  185. package/components/message/popover/usePopover.ts +230 -0
  186. package/components/other/darkMode/api.ts +17 -0
  187. package/components/other/darkMode/index.ts +17 -0
  188. package/components/other/darkMode/props.d.ts +37 -0
  189. package/components/other/darkMode/useDarkMode.ts +129 -0
  190. package/components/template/border/api.ts +18 -0
  191. package/components/template/border/index.ts +15 -0
  192. package/components/template/border/props.d.ts +41 -0
  193. package/components/template/breadcrumb/api.ts +15 -0
  194. package/components/template/breadcrumb/index.ts +15 -0
  195. package/components/template/breadcrumb/props.d.ts +45 -0
  196. package/components/template/descriptions/api.ts +23 -0
  197. package/components/template/descriptions/index.ts +16 -0
  198. package/components/template/descriptions/props.d.ts +54 -0
  199. package/components/template/form/api.ts +23 -0
  200. package/components/template/form/index.ts +20 -0
  201. package/components/template/form/props.d.ts +60 -0
  202. package/components/template/grid/api.ts +20 -0
  203. package/components/template/grid/index.ts +15 -0
  204. package/components/template/grid/props.d.ts +48 -0
  205. package/components/template/menu/api.ts +26 -0
  206. package/components/template/menu/index.ts +19 -0
  207. package/components/template/menu/props.d.ts +93 -0
  208. package/components/template/menu/useMenu.ts +155 -0
  209. package/components/template/pagination/api.ts +22 -0
  210. package/components/template/pagination/index.ts +18 -0
  211. package/components/template/pagination/props.d.ts +65 -0
  212. package/components/template/pagination/usePagination.ts +186 -0
  213. package/components/template/table/api.ts +18 -0
  214. package/components/template/table/index.ts +18 -0
  215. package/components/template/table/props.d.ts +36 -0
  216. package/components/template/table/useTable.ts +138 -0
  217. package/components/template/tableColumn/api.ts +17 -0
  218. package/components/template/tableColumn/index.ts +15 -0
  219. package/components/template/tableColumn/props.d.ts +32 -0
  220. package/components/template/virtualList/api.ts +16 -0
  221. package/components/template/virtualList/index.ts +18 -0
  222. package/components/template/virtualList/props.d.ts +25 -0
  223. package/components/template/virtualList/useVirtualList.ts +237 -0
  224. package/components/types/hook.d.ts +13 -0
  225. package/components/types/props.d.ts +52 -0
  226. package/components/types/template.d.ts +59 -0
  227. package/compositions/common/defineCore.ts +55 -0
  228. package/compositions/common/useDebounceFn.ts +27 -0
  229. package/compositions/common/useDrag.ts +65 -0
  230. package/compositions/common/useElementSize.ts +37 -0
  231. package/compositions/common/useEventListener.ts +48 -0
  232. package/compositions/common/usePopover.ts +45 -0
  233. package/compositions/common/useResizeObserver.ts +43 -0
  234. package/compositions/common/useTeleport.ts +24 -0
  235. package/compositions/input/useBooleanInput.ts +52 -0
  236. package/compositions/modal/useModal.ts +72 -0
  237. package/compositions/popper/useClickAway.ts +41 -0
  238. package/compositions/popper/usePopper.ts +63 -0
  239. package/compositions/utils/filters.ts +135 -0
  240. package/compositions/virtualList/enums.ts +52 -0
  241. package/compositions/virtualList/useContainerObserver.ts +82 -0
  242. package/compositions/virtualList/useEntries.ts +248 -0
  243. package/compositions/virtualList/useHeightCache.ts +83 -0
  244. package/compositions/virtualList/useSentinelObserver.ts +81 -0
  245. package/dist/components/base/affix/useAffix.d.ts +5 -4
  246. package/dist/components/base/anchor/useAnchor.d.ts +1 -1
  247. package/dist/components/base/autoComplete/useAutoComplete.d.ts +12 -4
  248. package/dist/components/base/backTop/useBackTop.d.ts +1 -1
  249. package/dist/components/base/button/index.d.ts +11 -2
  250. package/dist/components/base/button/useButton.d.ts +11 -2
  251. package/dist/components/base/carousel/useCarousel.d.ts +6 -3
  252. package/dist/components/base/cascader/useCascader.d.ts +23 -11
  253. package/dist/components/base/checkbox/useCheckbox.d.ts +4 -3
  254. package/dist/components/base/collapse/useCollapse.d.ts +2 -2
  255. package/dist/components/base/datePicker/useDatePicker.d.ts +140 -8
  256. package/dist/components/base/dropdown/useDropdown.d.ts +11 -5
  257. package/dist/components/base/image/useImage.d.ts +5 -5
  258. package/dist/components/base/input/useInput.d.ts +1 -2
  259. package/dist/components/base/inputNumber/useInputNumber.d.ts +2 -2
  260. package/dist/components/base/popover/usePopover.d.ts +8 -8
  261. package/dist/components/base/progress/useProgress.d.ts +1 -1
  262. package/dist/components/base/rate/useRate.d.ts +1 -1
  263. package/dist/components/base/select/useSelect.d.ts +8 -8
  264. package/dist/components/base/slider/useSlider.d.ts +3 -3
  265. package/dist/components/base/steps/index.d.ts +1 -1
  266. package/dist/components/base/steps/useSteps.d.ts +5 -5
  267. package/dist/components/base/switch/useSwitch.d.ts +8 -3
  268. package/dist/components/base/tabs/useTabs.d.ts +2 -2
  269. package/dist/components/base/timePicker/useTimePicker.d.ts +14 -6
  270. package/dist/components/base/tooltip/useTooltip.d.ts +14 -4
  271. package/dist/components/base/transfer/useTransfer.d.ts +15 -15
  272. package/dist/components/base/tree/index.d.ts +1 -1
  273. package/dist/components/base/tree/useTree.d.ts +2 -1
  274. package/dist/components/message/message/useMessage.d.ts +11 -1
  275. package/dist/components/message/notification/useNotification.d.ts +17 -1
  276. package/dist/components/message/popover/MPopover.d.ts +6 -1
  277. package/dist/components/message/popover/usePopover.d.ts +6 -6
  278. package/dist/components/other/darkMode/useDarkMode.d.ts +1 -1
  279. package/dist/components/template/menu/useMenu.d.ts +1 -0
  280. package/dist/components/template/virtualList/useVirtualList.d.ts +10 -7
  281. package/dist/compositions/common/useDrag.d.ts +1 -1
  282. package/dist/compositions/common/useElementSize.d.ts +2 -2
  283. package/dist/compositions/common/useTeleport.d.ts +4 -2
  284. package/dist/compositions/modal/useModal.d.ts +1 -1
  285. package/dist/core.js +6137 -4186
  286. package/dist/runtime/defineHook.d.ts +1 -1
  287. package/index.css +1 -0
  288. package/index.ts +71 -0
  289. package/package.json +19 -16
  290. package/runtime/defineHook.ts +21 -0
  291. package/tools/empty.ts +81 -0
  292. package/tools/index.ts +15 -0
  293. package/tools/types.ts +11 -0
  294. package/tsconfig.json +8 -0
  295. package/types/common/common.d.ts +25 -0
  296. package/types/common/model.d.ts +25 -0
  297. package/types/index.d.ts +11 -0
  298. package/types/props.d.ts +13 -0
  299. package/vite.config.build.ts +41 -0
  300. package/dist/vite.config.build.d.ts +0 -2
@@ -0,0 +1,334 @@
1
+ /**
2
+ * @description Cascader 组件核心 composable
3
+ * @author 阿怪
4
+ * @date 2026/2/26
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ *
9
+ * 核心逻辑:
10
+ * - 面板展开:按层级维护 activePath(当前激活的选项路径)
11
+ * - 路径追踪:selectedPath 记录已选中的完整路径节点
12
+ * - 搜索过滤:filterable 模式下递归扁平化所有叶子路径进行匹配
13
+ * - 多选:selectedPaths 记录多条已选路径
14
+ */
15
+ import { computed, ref, toRef, watch } from 'vue';
16
+ import { CascaderOption, CascaderProps } from './props';
17
+
18
+ /** 扁平化后的叶子路径,用于搜索 */
19
+ export interface FlatCascaderOption {
20
+ /** 从根到当前节点的完整路径节点列表 */
21
+ path: CascaderOption[];
22
+ /** 路径标签拼接(用于搜索匹配) */
23
+ pathLabel: string;
24
+ }
25
+
26
+ /**
27
+ * 递归扁平化选项树,收集所有叶子节点路径
28
+ */
29
+ const flattenOptions = (
30
+ options: CascaderOption[],
31
+ path: CascaderOption[] = [],
32
+ ): FlatCascaderOption[] => {
33
+ const result: FlatCascaderOption[] = [];
34
+ for (const option of options) {
35
+ const currentPath = [...path, option];
36
+ if (!option.children || option.children.length === 0 || option.leaf) {
37
+ // 叶子节点
38
+ result.push({
39
+ path: currentPath,
40
+ pathLabel: currentPath.map(o => o.label).join(' '),
41
+ });
42
+ } else {
43
+ // 非叶子节点,继续递归
44
+ result.push(...flattenOptions(option.children, currentPath));
45
+ }
46
+ }
47
+ return result;
48
+ };
49
+
50
+ /**
51
+ * 根据值路径从选项树中找到对应节点路径
52
+ */
53
+ const findPathByValues = (
54
+ options: CascaderOption[],
55
+ values: (string | number)[],
56
+ ): CascaderOption[] | null => {
57
+ if (!values.length) return null;
58
+ const [head, ...rest] = values;
59
+ const found = options.find(o => o.value === head);
60
+ if (!found) return null;
61
+ if (!rest.length) return [found];
62
+ if (!found.children?.length) return null;
63
+ const subPath = findPathByValues(found.children, rest);
64
+ return subPath ? [found, ...subPath] : null;
65
+ };
66
+
67
+ export function useCascader(props: CascaderProps, ctx: any) {
68
+ const optionsRef = toRef(() => props.options ?? []);
69
+ const modelValueRef = toRef(() => props.modelValue ?? []);
70
+ const multipleRef = toRef(() => props.multiple ?? false);
71
+
72
+ // --- 状态 ---
73
+ /** 下拉面板是否展开 */
74
+ const isOpen = ref(false);
75
+ /** 搜索关键词 */
76
+ const searchQuery = ref('');
77
+ /** 当前各列激活的选项(hover/click 展开下一列用) */
78
+ const activePath = ref<CascaderOption[]>([]);
79
+
80
+ // --- 计算属性 ---
81
+
82
+ /**
83
+ * 各列可见的选项列表
84
+ * 第 0 列 = 根选项,第 N 列 = activePath[N-1].children
85
+ */
86
+ const columns = computed<CascaderOption[][]>(() => {
87
+ const cols: CascaderOption[][] = [optionsRef.value];
88
+ for (const node of activePath.value) {
89
+ if (node.children?.length) {
90
+ cols.push(node.children);
91
+ }
92
+ }
93
+ return cols;
94
+ });
95
+
96
+ /** 扁平化叶子路径(filterable 模式下使用) */
97
+ const flatOptions = computed<FlatCascaderOption[]>(() => {
98
+ if (!props.filterable) return [];
99
+ return flattenOptions(optionsRef.value);
100
+ });
101
+
102
+ /** 过滤后的扁平选项(搜索模式下显示) */
103
+ const filteredOptions = computed<FlatCascaderOption[]>(() => {
104
+ if (!searchQuery.value) return flatOptions.value;
105
+ const q = searchQuery.value.toLowerCase();
106
+ return flatOptions.value.filter(item =>
107
+ item.pathLabel.toLowerCase().includes(q),
108
+ );
109
+ });
110
+
111
+ /** 是否处于搜索模式 */
112
+ const isSearching = computed(() => props.filterable && searchQuery.value.length > 0);
113
+
114
+ /** 单选:当前已选路径的节点列表 */
115
+ const selectedPath = computed<CascaderOption[]>(() => {
116
+ if (multipleRef.value) return [];
117
+ const mv = modelValueRef.value as (string | number)[];
118
+ if (!mv.length) return [];
119
+ return findPathByValues(optionsRef.value, mv) ?? [];
120
+ });
121
+
122
+ /** 多选:当前已选的路径列表 */
123
+ const selectedPaths = computed<CascaderOption[][]>(() => {
124
+ if (!multipleRef.value) return [];
125
+ const mv = modelValueRef.value as (string | number)[][];
126
+ return mv
127
+ .map(vals => findPathByValues(optionsRef.value, vals))
128
+ .filter((p): p is CascaderOption[] => p !== null);
129
+ });
130
+
131
+ /** 触发器展示文字 */
132
+ const displayLabel = computed<string>(() => {
133
+ if (multipleRef.value) return '';
134
+ if (!selectedPath.value.length) return '';
135
+ if (props.showAllLevels) {
136
+ return selectedPath.value.map(o => o.label).join(` ${props.separator ?? '/'} `);
137
+ }
138
+ return selectedPath.value[selectedPath.value.length - 1]?.label ?? '';
139
+ });
140
+
141
+ /** 多选标签列表 */
142
+ const selectedTags = computed<string[]>(() => {
143
+ if (!multipleRef.value) return [];
144
+ return selectedPaths.value.map(path => {
145
+ if (props.showAllLevels) {
146
+ return path.map(o => o.label).join(` ${props.separator ?? '/'} `);
147
+ }
148
+ return path[path.length - 1]?.label ?? '';
149
+ });
150
+ });
151
+
152
+ // --- 事件处理 ---
153
+
154
+ /** 打开面板时,用已选路径初始化 activePath */
155
+ const initActivePath = () => {
156
+ if (multipleRef.value || !selectedPath.value.length) {
157
+ activePath.value = [];
158
+ return;
159
+ }
160
+ // 已选路径去掉最后一个叶子节点(只保留展开路径)
161
+ activePath.value = selectedPath.value.slice(0, -1);
162
+ };
163
+
164
+ /** 打开下拉面板 */
165
+ const open = () => {
166
+ if (props.disabled) return;
167
+ initActivePath();
168
+ isOpen.value = true;
169
+ };
170
+
171
+ /** 关闭下拉面板 */
172
+ const close = () => {
173
+ isOpen.value = false;
174
+ searchQuery.value = '';
175
+ };
176
+
177
+ /** 点击触发器 */
178
+ const onTriggerClick = () => {
179
+ if (isOpen.value) {
180
+ close();
181
+ } else {
182
+ open();
183
+ }
184
+ };
185
+
186
+ /**
187
+ * 悬停/点击某列的某个选项,展开下一列
188
+ * @param option 被激活的选项
189
+ * @param colIndex 所在列的索引
190
+ */
191
+ const onOptionEnter = (option: CascaderOption, colIndex: number) => {
192
+ if (option.disabled) return;
193
+ // 截断 activePath 到当前列
194
+ activePath.value = [...activePath.value.slice(0, colIndex), option];
195
+ };
196
+
197
+ /**
198
+ * 点击选项(单选叶子节点 → 选中并关闭;多选叶子节点 → 切换选中)
199
+ */
200
+ const onOptionClick = (option: CascaderOption, colIndex: number) => {
201
+ if (option.disabled) return;
202
+
203
+ // 先更新展开路径
204
+ onOptionEnter(option, colIndex);
205
+
206
+ const isLeaf = !option.children?.length || option.leaf;
207
+ if (!isLeaf) return; // 非叶子节点只展开,不选中
208
+
209
+ // 构造完整的值路径
210
+ const fullPath = [...activePath.value.slice(0, colIndex), option];
211
+ const valuePath = fullPath.map(o => o.value);
212
+
213
+ if (multipleRef.value) {
214
+ // 多选:切换
215
+ const currentMv = (modelValueRef.value as (string | number)[][]) ?? [];
216
+ const existIndex = currentMv.findIndex(
217
+ p => p.length === valuePath.length && p.every((v, i) => v === valuePath[i]),
218
+ );
219
+ let newMv: (string | number)[][];
220
+ if (existIndex >= 0) {
221
+ newMv = currentMv.filter((_, i) => i !== existIndex);
222
+ } else {
223
+ newMv = [...currentMv, valuePath];
224
+ }
225
+ ctx.emit('update:modelValue', newMv);
226
+ ctx.emit('change', newMv);
227
+ } else {
228
+ // 单选:选中并关闭
229
+ ctx.emit('update:modelValue', valuePath);
230
+ ctx.emit('change', valuePath);
231
+ close();
232
+ }
233
+ };
234
+
235
+ /** 搜索模式下点击扁平选项 */
236
+ const onFlatOptionClick = (item: FlatCascaderOption) => {
237
+ const valuePath = item.path.map(o => o.value);
238
+
239
+ if (multipleRef.value) {
240
+ const currentMv = (modelValueRef.value as (string | number)[][]) ?? [];
241
+ const existIndex = currentMv.findIndex(
242
+ p => p.length === valuePath.length && p.every((v, i) => v === valuePath[i]),
243
+ );
244
+ let newMv: (string | number)[][];
245
+ if (existIndex >= 0) {
246
+ newMv = currentMv.filter((_, i) => i !== existIndex);
247
+ } else {
248
+ newMv = [...currentMv, valuePath];
249
+ }
250
+ ctx.emit('update:modelValue', newMv);
251
+ ctx.emit('change', newMv);
252
+ } else {
253
+ ctx.emit('update:modelValue', valuePath);
254
+ ctx.emit('change', valuePath);
255
+ close();
256
+ }
257
+ };
258
+
259
+ /** 删除多选标签 */
260
+ const onDeleteTag = (tagIndex: number) => {
261
+ const currentMv = (modelValueRef.value as (string | number)[][]) ?? [];
262
+ const newMv = currentMv.filter((_, i) => i !== tagIndex);
263
+ ctx.emit('update:modelValue', newMv);
264
+ ctx.emit('change', newMv);
265
+ };
266
+
267
+ /** 清空选中值 */
268
+ const onClear = (e: MouseEvent) => {
269
+ e.stopPropagation();
270
+ const emptyValue = multipleRef.value ? [] : [];
271
+ ctx.emit('update:modelValue', emptyValue);
272
+ ctx.emit('change', emptyValue);
273
+ close();
274
+ };
275
+
276
+ /** 判断某个选项是否在当前激活路径中 */
277
+ const isActiveOption = (option: CascaderOption, colIndex: number) => {
278
+ return activePath.value[colIndex]?.value === option.value;
279
+ };
280
+
281
+ /** 判断某个选项是否为已选路径的一部分(高亮) */
282
+ const isSelectedOption = (option: CascaderOption, colIndex: number) => {
283
+ if (multipleRef.value) {
284
+ return selectedPaths.value.some(path => path[colIndex]?.value === option.value);
285
+ }
286
+ return selectedPath.value[colIndex]?.value === option.value;
287
+ };
288
+
289
+ /** 判断扁平选项是否被选中(多选) */
290
+ const isFlatOptionSelected = (item: FlatCascaderOption) => {
291
+ const valuePath = item.path.map(o => o.value);
292
+ if (multipleRef.value) {
293
+ const currentMv = (modelValueRef.value as (string | number)[][]) ?? [];
294
+ return currentMv.some(
295
+ p => p.length === valuePath.length && p.every((v, i) => v === valuePath[i]),
296
+ );
297
+ }
298
+ const mv = modelValueRef.value as (string | number)[];
299
+ return mv.length === valuePath.length && valuePath.every((v, i) => v === mv[i]);
300
+ };
301
+
302
+ // options 变化时触发 expandChange
303
+ watch(activePath, (newPath) => {
304
+ ctx.emit('expandChange', newPath.map(o => o.value));
305
+ });
306
+
307
+ return {
308
+ // 状态
309
+ isOpen,
310
+ searchQuery,
311
+ activePath,
312
+ // 计算
313
+ columns,
314
+ filteredOptions,
315
+ isSearching,
316
+ selectedPath,
317
+ selectedPaths,
318
+ displayLabel,
319
+ selectedTags,
320
+ // 事件
321
+ open,
322
+ close,
323
+ onTriggerClick,
324
+ onOptionEnter,
325
+ onOptionClick,
326
+ onFlatOptionClick,
327
+ onDeleteTag,
328
+ onClear,
329
+ // 工具
330
+ isActiveOption,
331
+ isSelectedOption,
332
+ isFlatOptionSelected,
333
+ };
334
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @description checkbox api
3
+ * @author 阿怪
4
+ * @date 2023/4/20 21:55
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ import { MCOPO, MPropType } from '../../types/props';
10
+ import { CheckboxGroupProps, CheckboxProps } from './props';
11
+
12
+ export const props: MCOPO<CheckboxProps> = {
13
+ label: { type: String, default: '' },
14
+ checked: { type: Boolean, default: undefined },
15
+ value: { type: null, default: undefined },
16
+ modelValue: { type: null, default: undefined },
17
+ indeterminate: { type: Boolean, default: false },
18
+ disabled: { type: Boolean, default: false },
19
+ };
20
+
21
+ export const checkboxGroupProps: MCOPO<CheckboxGroupProps> = {
22
+ value: { type: Array, default: () => [] },
23
+ type: { type: String as MPropType<'single' | 'multiple'>, default: 'single' },
24
+ };
File without changes
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @description
3
+ * @author 阿怪
4
+ * @date 2024/12/24 10:59
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ import { props } from './api.ts';
10
+ import useCheckbox from './useCheckbox';
11
+
12
+
13
+ export const CheckboxCore = {
14
+ props,
15
+ useCheckbox
16
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @description checkbox api type
3
+ * @author youus
4
+ * @date 2022/4/7 00:02
5
+ * @version v1.0.0
6
+ *
7
+ * @name m-checkbox
8
+ * @docDescription Checkbox component with shuimo-ui style.
9
+ * 水墨组件的复选框组件。
10
+ * @docUrl https://shuimo.design/checkbox
11
+ *
12
+ * Hello, humor
13
+ */
14
+ import { HTMLElementEvent } from '../../../types/common/common';
15
+
16
+ export declare type CheckboxProps = {
17
+ /**
18
+ * @description checkbox label text, will replace slot
19
+ * 文本 会覆盖slot
20
+ * @type string
21
+ * @default ''
22
+ */
23
+ label?: string,
24
+ /**
25
+ * @description checkbox checked
26
+ * 是否选中
27
+ * @default undefined
28
+ */
29
+ checked?: boolean | undefined | null,
30
+ /**
31
+ * @description checkbox value
32
+ * @default undefined
33
+ */
34
+ value?: any,
35
+ /**
36
+ * @description value
37
+ * 绑定值
38
+ * @type any
39
+ * @default ''
40
+ */
41
+ modelValue?: any,
42
+ /**
43
+ * @description checkbox indeterminate
44
+ * 是否为不确定状态
45
+ * @default undefined
46
+ */
47
+ indeterminate?: boolean,
48
+ /**
49
+ * @description checkbox disabled
50
+ * 是否禁用 todo 暂未支持
51
+ * @type boolean
52
+ * @default false
53
+ */
54
+ disabled?: boolean
55
+ };
56
+
57
+
58
+ export declare type CheckboxEvents = {
59
+ onChange?: (e: HTMLElementEvent<HTMLInputElement>) => void,
60
+ onInput?: (value: any) => void
61
+ };
62
+
63
+ export declare type CheckboxGroupProps = {
64
+ /**
65
+ * @description checkbox value group
66
+ * @type array
67
+ * @default []
68
+ */
69
+ value?: any[],
70
+ /**
71
+ * @description type
72
+ * @type string
73
+ * @default single
74
+ * @enum 'single' | 'multiple'
75
+ */
76
+ type?: 'single' | 'multiple'
77
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @description
3
+ * @author 阿怪
4
+ * @date 2024/12/24 10:58
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ import { ref, watch } from 'vue';
10
+ import { getNewModelValue, initChecked } from '../../../compositions/input/useBooleanInput.ts';
11
+ import { CheckboxProps } from './props';
12
+
13
+
14
+ export default function useCheckbox<
15
+ Props extends Required<CheckboxProps>,
16
+ >(props: Props, ctx: any) {
17
+ const checkboxClass = ['m-checkbox', { 'm-disabled': props.disabled, 'm-indeterminate': props.indeterminate }];
18
+
19
+ const checked = ref(initChecked(props));
20
+
21
+ watch(() => props.modelValue, () => {
22
+ checked.value = initChecked(props);
23
+ });
24
+
25
+ const onClick = (e: MouseEvent) => {
26
+ e.stopPropagation();
27
+ if (props.disabled) {
28
+ return;
29
+ }
30
+ checked.value = !checked.value;
31
+ const newVal = getNewModelValue(props, checked.value);
32
+ ctx.emit('change', newVal);
33
+ ctx.emit('update:modelValue', newVal);
34
+ }
35
+
36
+ return {
37
+ checkboxClass,
38
+ checked,
39
+ indeterminate: props.indeterminate,
40
+ onClick
41
+ };
42
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @description collapse 运行时 props
3
+ * @author 阿怪
4
+ * @date 2026/2/26
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ import { MCOPO } from '../../types/props';
10
+ import { CollapseItemProps, CollapseProps } from './props';
11
+
12
+ export const props: MCOPO<CollapseProps> = {
13
+ modelValue: { type: [Array, String, Number], required: true },
14
+ accordion: { type: Boolean, default: false },
15
+ };
16
+
17
+ export const itemProps: MCOPO<CollapseItemProps> = {
18
+ name: { type: [String, Number], required: true },
19
+ title: { type: String, default: '' },
20
+ disabled: { type: Boolean, default: false },
21
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @description collapse core 导出
3
+ * @author 阿怪
4
+ * @date 2026/2/26
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ import { props, itemProps } from './api.ts';
10
+ import useCollapse from './useCollapse.ts';
11
+
12
+ export const CollapseCore = {
13
+ props,
14
+ itemProps,
15
+ useCollapse,
16
+ };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @description collapse api type
3
+ * @author 阿怪
4
+ * @date 2026/2/26
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+
10
+ export declare type CollapseProps = {
11
+ /**
12
+ * @description 当前展开的面板名,手风琴模式为单值,普通模式为数组
13
+ * @type (string | number)[] | string | number
14
+ */
15
+ modelValue: (string | number)[] | string | number;
16
+ /**
17
+ * @description 是否开启手风琴模式(同时只允许一个面板展开)
18
+ * @type boolean
19
+ * @default false
20
+ */
21
+ accordion?: boolean;
22
+ };
23
+
24
+ export declare type CollapseItemProps = {
25
+ /**
26
+ * @description 面板唯一标识
27
+ * @type string | number
28
+ */
29
+ name: string | number;
30
+ /**
31
+ * @description 面板标题
32
+ * @type string
33
+ */
34
+ title?: string;
35
+ /**
36
+ * @description 是否禁用该面板
37
+ * @type boolean
38
+ * @default false
39
+ */
40
+ disabled?: boolean;
41
+ };
42
+
43
+ export declare type CollapseEvents = {
44
+ onChange?: (activeNames: (string | number)[]) => void;
45
+ };
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @description collapse composable
3
+ * @author 阿怪
4
+ * @date 2026/2/26
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ import { computed } from 'vue';
10
+ import { CollapseProps } from './props';
11
+
12
+ export default function useCollapse(props: Required<CollapseProps>, ctx: any) {
13
+ const { emit } = ctx;
14
+
15
+ /**
16
+ * 将 modelValue 规范化为数组,统一内部处理
17
+ */
18
+ const activeNames = computed<(string | number)[]>(() => {
19
+ const val = props.modelValue;
20
+ if (Array.isArray(val)) { return val; }
21
+ if (val === undefined || val === null || val === '') { return []; }
22
+ return [val];
23
+ });
24
+
25
+ /**
26
+ * 判断指定面板是否处于展开状态
27
+ */
28
+ const isActive = (name: string | number): boolean => {
29
+ return activeNames.value.includes(name);
30
+ };
31
+
32
+ /**
33
+ * 切换面板展开/收起
34
+ * - 手风琴模式:同时只允许一个展开
35
+ * - 普通模式:在数组中添加/移除
36
+ */
37
+ const toggle = (name: string | number, disabled: boolean) => {
38
+ if (disabled) { return; }
39
+
40
+ let next: (string | number)[];
41
+
42
+ if (props.accordion) {
43
+ // 手风琴:已展开则收起,否则切换为仅展开当前
44
+ next = isActive(name) ? [] : [name];
45
+ } else {
46
+ if (isActive(name)) {
47
+ next = activeNames.value.filter(n => n !== name);
48
+ } else {
49
+ next = [...activeNames.value, name];
50
+ }
51
+ }
52
+
53
+ // 向父组件同步值
54
+ emit('update:modelValue', props.accordion ? (next[0] ?? '') : next);
55
+ emit('change', next);
56
+ };
57
+
58
+ // ---- class 计算 ----
59
+
60
+ const collapseClass = computed(() => ['m-collapse']);
61
+
62
+ const getItemClass = (name: string | number, disabled: boolean) => [
63
+ 'm-collapse-item',
64
+ { 'm-collapse-item-active': isActive(name) },
65
+ { 'm-collapse-item-disabled': disabled },
66
+ ];
67
+
68
+ const headerClass = ['m-collapse-header'];
69
+ const contentClass = ['m-collapse-content'];
70
+
71
+ return {
72
+ activeNames,
73
+ isActive,
74
+ toggle,
75
+ collapseClass,
76
+ getItemClass,
77
+ headerClass,
78
+ contentClass,
79
+ };
80
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @description datePicker api
3
+ * @author 阿怪
4
+ * @date 2026/2/25
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ import { MCOPO, MPropType } from '../../types/props';
10
+ import { DatePickerProps } from './props';
11
+
12
+ export const props: MCOPO<DatePickerProps> = {
13
+ modelValue: { type: [String, Date], default: '' },
14
+ placeholder: { type: String, default: '请选择日期...' },
15
+ format: { type: String, default: undefined },
16
+ type: { type: String as MPropType<'date' | 'month' | 'datetime'>, default: 'date' },
17
+ disabled: { type: Boolean, default: false },
18
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @description datePicker core 导出
3
+ * @author 阿怪
4
+ * @date 2026/2/25
5
+ * @version v1.0.0
6
+ *
7
+ * 江湖的业务千篇一律,复杂的代码好几百行。
8
+ */
9
+ import { props } from './api';
10
+ import { useDatePicker } from './useDatePicker';
11
+
12
+ export const DatePickerCore = {
13
+ props,
14
+ useDatePicker,
15
+ };
16
+
17
+ export type { DatePickerProps, CalendarType, DateRefType, CalendarItem } from './props';
18
+ export { useDatePicker, toDayjs, BASE_WEEK_NAME, BASE_MONTH_NAME, generateTimeColumn } from './useDatePicker';
19
+ export type { TimeRefType } from './useDatePicker';