@xiaohaih/json-form-vant 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 (213) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +807 -0
  3. package/TODO.md +36 -0
  4. package/components/area/index.ts +6 -0
  5. package/components/area/index.vue +120 -0
  6. package/components/area/types.ts +84 -0
  7. package/components/cascader/index.ts +6 -0
  8. package/components/cascader/index.vue +146 -0
  9. package/components/cascader/types.ts +75 -0
  10. package/components/checkbox/index.ts +6 -0
  11. package/components/checkbox/index.vue +59 -0
  12. package/components/checkbox/types.ts +54 -0
  13. package/components/checkbox-group/index.ts +6 -0
  14. package/components/checkbox-group/index.vue +67 -0
  15. package/components/checkbox-group/types.ts +63 -0
  16. package/components/component-definition/components.ts +29 -0
  17. package/components/component-definition/definition.ts +25 -0
  18. package/components/component-definition/index.ts +4 -0
  19. package/components/custom-render/index.ts +6 -0
  20. package/components/custom-render/index.vue +66 -0
  21. package/components/custom-render/types.ts +43 -0
  22. package/components/date-picker/index.ts +6 -0
  23. package/components/date-picker/index.vue +130 -0
  24. package/components/date-picker/types.ts +91 -0
  25. package/components/date-time-picker-group/index.ts +6 -0
  26. package/components/date-time-picker-group/index.vue +158 -0
  27. package/components/date-time-picker-group/types.ts +115 -0
  28. package/components/datetime-picker/index.ts +6 -0
  29. package/components/datetime-picker/index.vue +128 -0
  30. package/components/datetime-picker/types.ts +78 -0
  31. package/components/dynamic-group/index.ts +10 -0
  32. package/components/dynamic-group/index.vue +140 -0
  33. package/components/dynamic-group/types.ts +68 -0
  34. package/components/group/assist.ts +99 -0
  35. package/components/group/index.ts +7 -0
  36. package/components/group/index.vue +117 -0
  37. package/components/group/types.ts +57 -0
  38. package/components/group/virtual-group.vue +38 -0
  39. package/components/index.ts +10 -0
  40. package/components/input/index.ts +6 -0
  41. package/components/input/index.vue +83 -0
  42. package/components/input/types.ts +43 -0
  43. package/components/input-slot/index.ts +6 -0
  44. package/components/input-slot/index.vue +148 -0
  45. package/components/input-slot/types.ts +34 -0
  46. package/components/number-keyboard/index.ts +6 -0
  47. package/components/number-keyboard/index.vue +81 -0
  48. package/components/number-keyboard/types.ts +57 -0
  49. package/components/password-input/index.ts +6 -0
  50. package/components/password-input/index.vue +103 -0
  51. package/components/password-input/types.ts +64 -0
  52. package/components/picker/index.ts +6 -0
  53. package/components/picker/index.vue +136 -0
  54. package/components/picker/types.ts +94 -0
  55. package/components/radio/index.ts +6 -0
  56. package/components/radio/index.vue +68 -0
  57. package/components/radio/types.ts +58 -0
  58. package/components/radio-group/index.ts +6 -0
  59. package/components/radio-group/index.vue +74 -0
  60. package/components/radio-group/types.ts +65 -0
  61. package/components/rate/index.ts +6 -0
  62. package/components/rate/index.vue +63 -0
  63. package/components/rate/types.ts +47 -0
  64. package/components/share.ts +78 -0
  65. package/components/signature/index.ts +6 -0
  66. package/components/signature/index.vue +65 -0
  67. package/components/signature/instance.vue +161 -0
  68. package/components/signature/types.ts +79 -0
  69. package/components/slider/index.ts +6 -0
  70. package/components/slider/index.vue +63 -0
  71. package/components/slider/types.ts +53 -0
  72. package/components/stepper/index.ts +6 -0
  73. package/components/stepper/index.vue +62 -0
  74. package/components/stepper/types.ts +47 -0
  75. package/components/switch/index.ts +6 -0
  76. package/components/switch/index.vue +61 -0
  77. package/components/switch/types.ts +51 -0
  78. package/components/time-picker/index.ts +6 -0
  79. package/components/time-picker/index.vue +130 -0
  80. package/components/time-picker/types.ts +91 -0
  81. package/components/tree-select/index.ts +6 -0
  82. package/components/tree-select/index.vue +160 -0
  83. package/components/tree-select/types.ts +77 -0
  84. package/components/upload/index.ts +6 -0
  85. package/components/upload/index.vue +109 -0
  86. package/components/upload/types.ts +85 -0
  87. package/components/use.ts +45 -0
  88. package/components/utils.ts +52 -0
  89. package/components/wrapper/index.ts +6 -0
  90. package/components/wrapper/index.vue +117 -0
  91. package/components/wrapper/types.ts +94 -0
  92. package/dist/components/area/index.d.ts +5 -0
  93. package/dist/components/area/index.vue.d.ts +1843 -0
  94. package/dist/components/area/types.d.ts +1434 -0
  95. package/dist/components/cascader/index.d.ts +5 -0
  96. package/dist/components/cascader/index.vue.d.ts +2467 -0
  97. package/dist/components/cascader/types.d.ts +1419 -0
  98. package/dist/components/checkbox/index.d.ts +5 -0
  99. package/dist/components/checkbox/index.vue.d.ts +1550 -0
  100. package/dist/components/checkbox/types.d.ts +1313 -0
  101. package/dist/components/checkbox-group/index.d.ts +5 -0
  102. package/dist/components/checkbox-group/index.vue.d.ts +1643 -0
  103. package/dist/components/checkbox-group/types.d.ts +1372 -0
  104. package/dist/components/component-definition/components.d.ts +30 -0
  105. package/dist/components/component-definition/index.d.ts +4 -0
  106. package/dist/components/custom-render/index.d.ts +5 -0
  107. package/dist/components/custom-render/index.vue.d.ts +1473 -0
  108. package/dist/components/custom-render/types.d.ts +1175 -0
  109. package/dist/components/date-picker/index.d.ts +5 -0
  110. package/dist/components/date-picker/index.vue.d.ts +1888 -0
  111. package/dist/components/date-picker/types.d.ts +1458 -0
  112. package/dist/components/date-time-picker-group/index.d.ts +5 -0
  113. package/dist/components/date-time-picker-group/index.vue.d.ts +2181 -0
  114. package/dist/components/date-time-picker-group/types.d.ts +1549 -0
  115. package/dist/components/dynamic-group/index.d.ts +5 -0
  116. package/dist/components/dynamic-group/index.vue.d.ts +457 -0
  117. package/dist/components/dynamic-group/types.d.ts +403 -0
  118. package/dist/components/group/assist.d.ts +58 -0
  119. package/dist/components/group/index.d.ts +6 -0
  120. package/dist/components/group/index.vue.d.ts +139 -0
  121. package/dist/components/group/types.d.ts +189 -0
  122. package/dist/components/group/virtual-group.vue.d.ts +42 -0
  123. package/dist/components/index.d.ts +3 -0
  124. package/dist/components/input/index.d.ts +5 -0
  125. package/dist/components/input/index.vue.d.ts +2229 -0
  126. package/dist/components/input/types.d.ts +1258 -0
  127. package/dist/components/input-slot/index.d.ts +5 -0
  128. package/dist/components/input-slot/index.vue.d.ts +626 -0
  129. package/dist/components/input-slot/types.d.ts +311 -0
  130. package/dist/components/number-keyboard/index.d.ts +5 -0
  131. package/dist/components/number-keyboard/index.vue.d.ts +1643 -0
  132. package/dist/components/number-keyboard/types.d.ts +1324 -0
  133. package/dist/components/password-input/index.d.ts +5 -0
  134. package/dist/components/password-input/index.vue.d.ts +1715 -0
  135. package/dist/components/password-input/types.d.ts +1357 -0
  136. package/dist/components/picker/index.d.ts +5 -0
  137. package/dist/components/picker/index.vue.d.ts +1868 -0
  138. package/dist/components/picker/types.d.ts +1466 -0
  139. package/dist/components/radio/index.d.ts +5 -0
  140. package/dist/components/radio/index.vue.d.ts +1563 -0
  141. package/dist/components/radio/types.d.ts +1327 -0
  142. package/dist/components/radio-group/index.d.ts +5 -0
  143. package/dist/components/radio-group/index.vue.d.ts +1617 -0
  144. package/dist/components/radio-group/types.d.ts +1383 -0
  145. package/dist/components/rate/index.d.ts +5 -0
  146. package/dist/components/rate/index.vue.d.ts +1557 -0
  147. package/dist/components/rate/types.d.ts +1281 -0
  148. package/dist/components/share.d.ts +679 -0
  149. package/dist/components/signature/index.d.ts +5 -0
  150. package/dist/components/signature/index.vue.d.ts +3017 -0
  151. package/dist/components/signature/instance.vue.d.ts +1614 -0
  152. package/dist/components/signature/types.d.ts +1369 -0
  153. package/dist/components/slider/index.d.ts +5 -0
  154. package/dist/components/slider/index.vue.d.ts +1563 -0
  155. package/dist/components/slider/types.d.ts +1302 -0
  156. package/dist/components/stepper/index.d.ts +5 -0
  157. package/dist/components/stepper/index.vue.d.ts +1620 -0
  158. package/dist/components/stepper/types.d.ts +1281 -0
  159. package/dist/components/switch/index.d.ts +5 -0
  160. package/dist/components/switch/index.vue.d.ts +1529 -0
  161. package/dist/components/switch/types.d.ts +1296 -0
  162. package/dist/components/time-picker/index.d.ts +5 -0
  163. package/dist/components/time-picker/index.vue.d.ts +1936 -0
  164. package/dist/components/time-picker/types.d.ts +1458 -0
  165. package/dist/components/tree-select/index.d.ts +5 -0
  166. package/dist/components/tree-select/index.vue.d.ts +1802 -0
  167. package/dist/components/tree-select/types.d.ts +1411 -0
  168. package/dist/components/upload/index.d.ts +5 -0
  169. package/dist/components/upload/index.vue.d.ts +1697 -0
  170. package/dist/components/upload/types.d.ts +1376 -0
  171. package/dist/components/use.d.ts +53 -0
  172. package/dist/components/utils.d.ts +15 -0
  173. package/dist/components/wrapper/index.d.ts +5 -0
  174. package/dist/components/wrapper/index.vue.d.ts +1085 -0
  175. package/dist/components/wrapper/types.d.ts +541 -0
  176. package/dist/docs/.vitepress/config.d.ts +3 -0
  177. package/dist/docs/.vitepress/theme/index.d.ts +2 -0
  178. package/dist/index.cjs.js +5459 -0
  179. package/dist/index.cjs.js.map +1 -0
  180. package/dist/index.cjs.min.js +3568 -0
  181. package/dist/index.cjs.min.js.map +1 -0
  182. package/dist/index.esm.js +5264 -0
  183. package/dist/index.esm.js.map +1 -0
  184. package/dist/index.esm.min.js +3559 -0
  185. package/dist/index.esm.min.js.map +1 -0
  186. package/dist/index.umd.js +5465 -0
  187. package/dist/index.umd.js.map +1 -0
  188. package/dist/index.umd.min.js +3573 -0
  189. package/dist/index.umd.min.js.map +1 -0
  190. package/dist/src/assist.d.ts +32 -0
  191. package/dist/src/index.d.ts +5 -0
  192. package/dist/src/interface.d.ts +129 -0
  193. package/dist/src/utils.d.ts +9 -0
  194. package/dist/src/version.d.ts +2 -0
  195. package/docs/.vitepress/config.ts +99 -0
  196. package/docs/.vitepress/theme/index.ts +5 -0
  197. package/docs/README.md +20 -0
  198. package/docs/index.md +25 -0
  199. package/env.d.ts +8 -0
  200. package/package.json +71 -0
  201. package/scripts/generate-version.mjs +26 -0
  202. package/scripts/postinstall.cjs +13 -0
  203. package/scripts/utils.cjs +67 -0
  204. package/src/assist.ts +40 -0
  205. package/src/index.ts +5 -0
  206. package/src/interface.ts +293 -0
  207. package/src/utils.ts +22 -0
  208. package/src/version.ts +2 -0
  209. package/tsconfig.app.json +41 -0
  210. package/tsconfig.json +7 -0
  211. package/tsconfig.node.json +24 -0
  212. package/tsdown.config.ts +12 -0
  213. package/vite.config.ts +93 -0
@@ -0,0 +1,148 @@
1
+ <template>
2
+ <textarea v-if="type === 'textarea'" ref="inputRef" v-bind="inputAttrs" @focus="focusHandle" @blur="blurHandle" @keypress="keypressHandle" />
3
+ <input v-else ref="inputRef" v-bind="inputAttrs" @focus="focusHandle" @blur="blurHandle" @keypress="keypressHandle">
4
+ </template>
5
+
6
+ <script lang="ts">
7
+ import { computed, defineComponent, nextTick, ref } from 'vue';
8
+ import type { ComponentExposed } from 'vue-component-type-helpers';
9
+ import { inputSlotEmits as emits, inputSlotProps as props } from './types';
10
+
11
+ /**
12
+ * @file 输入框 - 该组件提供 vant 输入框的样式, 便于覆盖 Field.input 插槽
13
+ */
14
+ export default defineComponent({
15
+ name: 'HInputSlot',
16
+ components: { },
17
+ inheritAttrs: false,
18
+ props,
19
+ emits,
20
+ setup(props, ctx) {
21
+ const id = '';
22
+ const inputRef = ref<ComponentExposed<typeof HTMLInputElement | typeof HTMLTextAreaElement>>();
23
+ const inputAttrs = computed(() => {
24
+ const { rows, label, disabled, readonly } = props;
25
+ return {
26
+ ...ctx.attrs,
27
+ 'rows': rows !== undefined ? +rows : undefined,
28
+ 'aria-labelledby': label ? `${id}-label` : undefined,
29
+ 'data-allow-mismatch': 'attribute',
30
+ 'class': 'van-field__control',
31
+ disabled,
32
+ readonly,
33
+ // onBlur,
34
+ // onFocus,
35
+ // onKeypress,
36
+ };
37
+ });
38
+
39
+ function blur() {
40
+ inputRef.value?.blur();
41
+ }
42
+ function focus() {
43
+ inputRef.value?.focus();
44
+ }
45
+ function focusHandle(event: Event) {
46
+ nextTick(adjustTextareaSize);
47
+ // readonly not work in legacy mobile safari
48
+ props.readonly && blur();
49
+ };
50
+ function blurHandle() {
51
+ if (props.readonly) return;
52
+ nextTick(adjustTextareaSize);
53
+ resetScroll();
54
+ }
55
+ function keypressHandle(event: KeyboardEvent) {
56
+ // const ENTER_CODE = 13;
57
+ // if (event.keyCode === ENTER_CODE) {
58
+ // // trigger blur after click keyboard search button
59
+ // props.type === 'search' && blur();
60
+ // }
61
+
62
+ };
63
+
64
+ const adjustTextareaSize = () => {
65
+ const input = inputRef.value;
66
+ if (props.type === 'textarea' && props.autosize && input) {
67
+ resizeTextarea(input as HTMLInputElement, props.autosize);
68
+ }
69
+ };
70
+ function resetScroll() {
71
+ if (isIOS_) {
72
+ setRootScrollTop(getRootScrollTop());
73
+ }
74
+ }
75
+
76
+ const inBrowser = typeof window !== 'undefined';
77
+ const isIOS = (): boolean =>
78
+ inBrowser
79
+ ? /ios|iphone|ipad|ipod/.test(navigator.userAgent.toLowerCase())
80
+ : false;
81
+ const isIOS_ = isIOS();
82
+ const isObject = (val: unknown): val is Record<any, any> =>
83
+ val !== null && typeof val === 'object';
84
+
85
+ function resizeTextarea(
86
+ input: HTMLInputElement,
87
+ autosize: true | {
88
+ maxHeight?: number;
89
+ minHeight?: number;
90
+ },
91
+ ) {
92
+ const scrollTop = getRootScrollTop();
93
+ input.style.height = 'auto';
94
+
95
+ let height = input.scrollHeight;
96
+ if (isObject(autosize)) {
97
+ const { maxHeight, minHeight } = autosize;
98
+ if (maxHeight !== undefined) {
99
+ height = Math.min(height, maxHeight);
100
+ }
101
+ if (minHeight !== undefined) {
102
+ height = Math.max(height, minHeight);
103
+ }
104
+ }
105
+
106
+ if (height) {
107
+ input.style.height = `${height}px`;
108
+ // https://github.com/vant-ui/vant/issues/9178
109
+ setRootScrollTop(scrollTop);
110
+ }
111
+ }
112
+
113
+ type ScrollElement = Element | Window;
114
+ function setScrollTop(el: ScrollElement, value: number) {
115
+ if ('scrollTop' in el) {
116
+ el.scrollTop = value;
117
+ }
118
+ else {
119
+ el.scrollTo(el.scrollX, value);
120
+ }
121
+ }
122
+
123
+ function getRootScrollTop(): number {
124
+ return (
125
+ window.pageYOffset
126
+ || document.documentElement.scrollTop
127
+ || document.body.scrollTop
128
+ || 0
129
+ );
130
+ }
131
+ function setRootScrollTop(value: number) {
132
+ setScrollTop(window, value);
133
+ setScrollTop(document.body, value);
134
+ }
135
+
136
+ return {
137
+ inputRef,
138
+ inputAttrs,
139
+ focusHandle,
140
+ blurHandle,
141
+ keypressHandle,
142
+ };
143
+ },
144
+ });
145
+ </script>
146
+
147
+ <style lang="scss" scoped>
148
+ </style>
@@ -0,0 +1,34 @@
1
+ import type { Obj2Props, usePlain } from '@xiaohaih/json-form-core';
2
+ import { emits2props, plainProps } from '@xiaohaih/json-form-core';
3
+ import type { Field as VanField } from 'vant';
4
+ import type { ExtractPublicPropTypes, Prop, PropType } from 'vue';
5
+ import type { ComponentProps } from 'vue-component-type-helpers';
6
+
7
+ type VanFieldProps = Obj2Props<ComponentProps<typeof VanField>>;
8
+
9
+ /** 组件传参 */
10
+ export const inputSlotProps = {
11
+ ...{
12
+ // 这些属性不需要传到组件上
13
+ t: { type: String as PropType<string> },
14
+ rules: { type: [Array, Object] as PropType<any> },
15
+ name: { type: [String] as PropType<string> },
16
+ } as unknown as typeof VanField.props as unknown as VanFieldProps,
17
+ /** 输入框类型(input/textarea) */
18
+ type: { type: String } as unknown as VanFieldProps['type'],
19
+ /** 输入框行数 */
20
+ rows: { type: [Number, String] as PropType<number | string> },
21
+ /** 禁用 */
22
+ disabled: { type: [Boolean] as PropType<boolean> },
23
+ /** 只读 */
24
+ readonly: { type: [Boolean] as PropType<boolean> },
25
+ /** 文本信息 */
26
+ label: { type: [String] as PropType<string> },
27
+ };
28
+ export type InputSlotProps = ExtractPublicPropTypes<typeof inputSlotProps>;
29
+
30
+ /** 组件事件 */
31
+ export const inputSlotEmits = {
32
+ };
33
+
34
+ export type InputSlotEmits = typeof inputSlotEmits;
@@ -0,0 +1,6 @@
1
+ import type { ComponentExposed } from 'vue-component-type-helpers';
2
+ import HNumberKeyboard from './index.vue';
3
+
4
+ export { HNumberKeyboard };
5
+ export type HNumberKeyboardInstance = ComponentExposed<typeof HNumberKeyboard>;
6
+ export * from './types';
@@ -0,0 +1,81 @@
1
+ <template>
2
+ <VanField
3
+ v-if="!hide"
4
+ :name="field"
5
+ :model-value="(checked as string)"
6
+ :disabled="globalDisabled || disabled"
7
+ :readonly="true" :is-link="isLink"
8
+ v-bind="$attrs"
9
+ @click.stop="clickHandle"
10
+ >
11
+ <template #extra>
12
+ <VanNumberKeyboard
13
+ :model-value="(checked as string)"
14
+ :show="popupInfo.visible"
15
+ v-bind="numberKeyboardProps" v-on="numberKeyboardOn"
16
+ @update:model-value="change" @blur="popupInfo.close"
17
+ >
18
+ <template v-for="(item, slotName) of numberKeyboardSlots" :key="slotName" #[hyphenate(slotName)]="row">
19
+ <component :is="getNode(item)" v-bind="slotProps" v-bind.prop="row" />
20
+ </template>
21
+ </VanNumberKeyboard>
22
+ </template>
23
+ <template v-for="(item, slotName) of slots" :key="slotName" #[hyphenate(slotName)]="row">
24
+ <component :is="getNode(item)" v-bind="slotProps" v-bind.prop="row" />
25
+ </template>
26
+ </VanField>
27
+ </template>
28
+
29
+ <script lang="ts">
30
+ import { getNode, hyphenate, usePlain } from '@xiaohaih/json-form-core';
31
+ import { Field as VanField, NumberKeyboard as VanNumberKeyboard } from 'vant';
32
+ import type { SlotsType } from 'vue';
33
+ import { defineComponent, ref } from 'vue';
34
+ import { useCommonSetup } from '../use';
35
+ import type { NumberKeyboardSlots } from './types';
36
+ import { numberKeyboardEmitsPrivate as emits, numberKeyboardPropsPrivate as props } from './types';
37
+
38
+ /**
39
+ * @file 数字键盘
40
+ */
41
+ export default defineComponent({
42
+ name: 'HNumberKeyboard',
43
+ components: { VanField, VanNumberKeyboard },
44
+ inheritAttrs: false,
45
+ props,
46
+ emits,
47
+ slots: Object as SlotsType<NumberKeyboardSlots>,
48
+ setup(props, ctx) {
49
+ const plain = usePlain(props);
50
+ const { slotProps } = useCommonSetup(props, ctx, plain);
51
+
52
+ /** 点击事件 */
53
+ function clickHandle(ev: MouseEvent) {
54
+ if (plain.globalDisabled.value || props.disabled || plain.globalReadonly.value || props.readonly) return;
55
+ props.onRowClick ? props.onRowClick(popupInfo.value, ev) : popupInfo.value.open();
56
+ }
57
+ /** 弹窗显示状态 */
58
+ const popupInfo = ref({
59
+ visible: false,
60
+ open() {
61
+ popupInfo.value.visible = true;
62
+ },
63
+ close() {
64
+ popupInfo.value.visible = false;
65
+ },
66
+ });
67
+
68
+ return {
69
+ hyphenate,
70
+ getNode,
71
+ ...plain,
72
+ slotProps,
73
+ clickHandle,
74
+ popupInfo,
75
+ };
76
+ },
77
+ });
78
+ </script>
79
+
80
+ <style lang="scss" scoped>
81
+ </style>
@@ -0,0 +1,57 @@
1
+ import type { emits2obj, PlainProps } from '@xiaohaih/json-form-core';
2
+ import { emits2props, plainProps } from '@xiaohaih/json-form-core';
3
+ import { Field as VanField, NumberKeyboard as VanNumberKeyboard } from 'vant';
4
+ import type { ExtractPublicPropTypes, PropType } from 'vue';
5
+ import type { ComponentProps } from 'vue-component-type-helpers';
6
+ import type { CommonProps, CommonSlots, CommonSlotsProps, ComponentType } from '../share';
7
+ import { commonProps } from '../share';
8
+
9
+ /** 组件传参 - 私有 */
10
+ export function numberKeyboardPropsGeneric<Query extends Record<string, any>, OptionQuery extends Record<string, any>>() {
11
+ return {
12
+ ...commonProps as CommonProps<Query, OptionQuery>,
13
+ ...plainProps as PlainProps<Query, OptionQuery>,
14
+ /** VanNumberKeyboard 组件的属性 */
15
+ numberKeyboardProps: { type: Object as PropType<Partial<ComponentProps<typeof VanNumberKeyboard>>> },
16
+ /** VanNumberKeyboard 组件的事件 - 兼容 vue2 版本 */
17
+ numberKeyboardOn: { type: Object as PropType<Partial<ReturnType<typeof emits2obj<NonNullable<typeof VanNumberKeyboard.emits>>>>>, default: () => ({}) },
18
+ /** VanNumberKeyboard 组件的插槽 */
19
+ numberKeyboardSlots: { type: Object as PropType<{
20
+ /** 自定义删除按键内容 */
21
+ delete: ComponentType<CommonSlotsProps<any, any>>;
22
+ /** 自定义左下角按键内容 */
23
+ extraKey: ComponentType<CommonSlotsProps<any, any>>;
24
+ /** 自定义标题栏左侧内容 */
25
+ titleLeft: ComponentType<CommonSlotsProps<any, any>>;
26
+ }> },
27
+ /** 是否展示右侧箭头并开启点击反馈 - Field 字段, 调整默认值 */
28
+ isLink: { type: Boolean, default: true },
29
+ /** 点击事件, 当传递了此事件时, 会忽略内部打开弹窗操作 */
30
+ onRowClick: { type: Function as PropType<(option: { open: () => void; close: () => void }, ev: MouseEvent) => void> },
31
+ } as const;
32
+ }
33
+ /** 组件传参 - 私有 */
34
+ export const numberKeyboardPropsPrivate = numberKeyboardPropsGeneric();
35
+ /** 组件传参 - 外部调用 */
36
+ export const numberKeyboardProps = {
37
+ ...VanField.props as unknown as {},
38
+ ...numberKeyboardPropsPrivate,
39
+ };
40
+ export type NumberKeyboardProps<Query extends Record<string, any>, OptionQuery extends Record<string, any>> = ExtractPublicPropTypes<ReturnType<typeof numberKeyboardPropsGeneric<Query, OptionQuery>>>;
41
+
42
+ /** 组件事件 - 私有 */
43
+ export function numberKeyboardEmitsGeneric<T>() {
44
+ return {};
45
+ }
46
+ /** 组件事件 - 私有 */
47
+ export const numberKeyboardEmitsPrivate = numberKeyboardEmitsGeneric();
48
+ /** 组件事件 - 外部调用 */
49
+ export const numberKeyboardEmits = {
50
+ ...VanField.emits,
51
+ ...numberKeyboardEmitsPrivate,
52
+ };
53
+
54
+ export type NumberKeyboardEmits<T> = ReturnType<typeof numberKeyboardEmitsGeneric<T>>;
55
+
56
+ export interface NumberKeyboardSlots extends CommonSlots<any> {
57
+ }
@@ -0,0 +1,6 @@
1
+ import type { ComponentExposed } from 'vue-component-type-helpers';
2
+ import HPasswordInput from './index.vue';
3
+
4
+ export { HPasswordInput };
5
+ export type HPasswordInputInstance = ComponentExposed<typeof HPasswordInput>;
6
+ export * from './types';
@@ -0,0 +1,103 @@
1
+ <template>
2
+ <VanField
3
+ v-if="!hide"
4
+ :name="field" :label="label"
5
+ :model-value="(checked as string)"
6
+ :disabled="globalDisabled || disabled"
7
+ :readonly="globalReadonly || readonly"
8
+ v-bind="$attrs"
9
+ @click.stop="clickHandle"
10
+ >
11
+ <template #input>
12
+ <VanPasswordInput
13
+ style="width: 100%"
14
+ :value="(checked as string)"
15
+ :focused="popupInfo.visible"
16
+ v-bind="passwordInputProps" v-on="passwordInputOn"
17
+ @focus="clickHandle"
18
+ >
19
+ <template v-for="(item, slotName) of passwordInputSlots" :key="slotName" #[hyphenate(slotName)]="row">
20
+ <component :is="getNode(item)" v-bind="slotProps" v-bind.prop="row" />
21
+ </template>
22
+ </VanPasswordInput>
23
+ </template>
24
+ <template #extra>
25
+ <VanNumberKeyboard
26
+ :model-value="(checked as string)"
27
+ :show="popupInfo.visible"
28
+ v-bind="numberKeyboardProps"
29
+ v-on="numberKeyboardOn"
30
+ @update:model-value="customChange"
31
+ @blur="popupInfo.close"
32
+ >
33
+ <template v-for="(item, slotName) of numberKeyboardSlots" :key="slotName" #[hyphenate(slotName)]="row">
34
+ <component :is="getNode(item)" v-bind="slotProps" v-bind.prop="row" />
35
+ </template>
36
+ </VanNumberKeyboard>
37
+ </template>
38
+ <template v-for="(item, slotName) of slots" :key="slotName" #[hyphenate(slotName)]="row">
39
+ <component :is="getNode(item)" v-bind="slotProps" v-bind.prop="row" />
40
+ </template>
41
+ </VanField>
42
+ </template>
43
+
44
+ <script lang="ts">
45
+ import { getNode, hyphenate, usePlain } from '@xiaohaih/json-form-core';
46
+ import { Field as VanField, NumberKeyboard as VanNumberKeyboard, PasswordInput as VanPasswordInput } from 'vant';
47
+ import type { SlotsType } from 'vue';
48
+ import { computed, defineComponent, ref } from 'vue';
49
+ import { useCommonSetup } from '../use';
50
+ import type { PasswordInputSlots } from './types';
51
+ import { passwordInputEmitsPrivate as emits, passwordInputPropsPrivate as props } from './types';
52
+
53
+ /**
54
+ * @file 密码输入框
55
+ */
56
+ export default defineComponent({
57
+ name: 'HPasswordInput',
58
+ components: { VanField, VanNumberKeyboard, VanPasswordInput },
59
+ inheritAttrs: false,
60
+ props,
61
+ emits,
62
+ slots: Object as SlotsType<PasswordInputSlots>,
63
+ setup(props, ctx) {
64
+ const plain = usePlain(props);
65
+ const { slotProps } = useCommonSetup(props, ctx, plain);
66
+
67
+ /** 点击事件 */
68
+ function clickHandle(ev: MouseEvent) {
69
+ if (plain.globalDisabled.value || props.disabled || plain.globalReadonly.value || props.readonly) return;
70
+ props.onRowClick ? props.onRowClick(popupInfo.value, ev) : popupInfo.value.open();
71
+ }
72
+ /** 重写 change 事件 */
73
+ function customChange(value: string) {
74
+ const len = Number(props.passwordInputProps?.length) || 6;
75
+ if (value.length === len) popupInfo.value.close();
76
+ plain.change(value);
77
+ }
78
+ /** 弹窗显示状态 */
79
+ const popupInfo = ref({
80
+ visible: false,
81
+ open() {
82
+ popupInfo.value.visible = true;
83
+ },
84
+ close() {
85
+ popupInfo.value.visible = false;
86
+ },
87
+ });
88
+
89
+ return {
90
+ hyphenate,
91
+ getNode,
92
+ ...plain,
93
+ slotProps,
94
+ clickHandle,
95
+ customChange,
96
+ popupInfo,
97
+ };
98
+ },
99
+ });
100
+ </script>
101
+
102
+ <style lang="scss" scoped>
103
+ </style>
@@ -0,0 +1,64 @@
1
+ import type { emits2obj, PlainProps } from '@xiaohaih/json-form-core';
2
+ import { emits2props, plainProps } from '@xiaohaih/json-form-core';
3
+ import { Field as VanField, NumberKeyboard as VanNumberKeyboard, PasswordInput as VanPasswordInput } from 'vant';
4
+ import type { ExtractPublicPropTypes, PropType } from 'vue';
5
+ import type { ComponentProps } from 'vue-component-type-helpers';
6
+ import type { CommonProps, CommonSlots, CommonSlotsProps, ComponentType } from '../share';
7
+ import { commonProps } from '../share';
8
+
9
+ /** 组件传参 - 私有 */
10
+ export function passwordInputPropsGeneric<Query extends Record<string, any>, OptionQuery extends Record<string, any>>() {
11
+ return {
12
+ ...commonProps as CommonProps<Query, OptionQuery>,
13
+ ...plainProps as PlainProps<Query, OptionQuery>,
14
+ /** 输入框左侧文本 */
15
+ label: { type: String },
16
+ /** VanPasswordInput 组件的属性 */
17
+ passwordInputProps: { type: Object as PropType<Partial<ComponentProps<typeof VanPasswordInput>>> },
18
+ /** VanPasswordInput 组件的事件 - 兼容 vue2 版本 */
19
+ passwordInputOn: { type: Object as PropType<Partial<ReturnType<typeof emits2obj<NonNullable<typeof VanPasswordInput.emits>>>>>, default: () => ({}) },
20
+ /** VanPasswordInput 组件的插槽 */
21
+ passwordInputSlots: { type: Object as PropType<{
22
+ }> },
23
+ /** 点击事件, 当传递了此事件时, 会忽略内部打开弹窗操作 */
24
+ onRowClick: { type: Function as PropType<(option: { open: () => void; close: () => void }, ev: MouseEvent) => void> },
25
+ /** VanNumberKeyboard 组件的属性 */
26
+ numberKeyboardProps: { type: Object as PropType<Partial<ComponentProps<typeof VanNumberKeyboard>>> },
27
+ /** VanNumberKeyboard 组件的事件 - 兼容 vue2 版本 */
28
+ numberKeyboardOn: { type: Object as PropType<Partial<ReturnType<typeof emits2obj<NonNullable<typeof VanNumberKeyboard.emits>>>>>, default: () => ({}) },
29
+ /** VanNumberKeyboard 组件的插槽 */
30
+ numberKeyboardSlots: { type: Object as PropType<{
31
+ /** 自定义删除按键内容 */
32
+ delete: ComponentType<CommonSlotsProps<any, any>>;
33
+ /** 自定义左下角按键内容 */
34
+ extraKey: ComponentType<CommonSlotsProps<any, any>>;
35
+ /** 自定义标题栏左侧内容 */
36
+ titleLeft: ComponentType<CommonSlotsProps<any, any>>;
37
+ }> },
38
+ } as const;
39
+ }
40
+ /** 组件传参 - 私有 */
41
+ export const passwordInputPropsPrivate = passwordInputPropsGeneric();
42
+ /** 组件传参 - 外部调用 */
43
+ export const passwordInputProps = {
44
+ ...VanField.props as unknown as {},
45
+ ...passwordInputPropsPrivate,
46
+ };
47
+ export type PasswordInputProps<Query extends Record<string, any>, OptionQuery extends Record<string, any>> = ExtractPublicPropTypes<ReturnType<typeof passwordInputPropsGeneric<Query, OptionQuery>>>;
48
+
49
+ /** 组件事件 - 私有 */
50
+ export function passwordInputEmitsGeneric<T>() {
51
+ return {};
52
+ }
53
+ /** 组件事件 - 私有 */
54
+ export const passwordInputEmitsPrivate = passwordInputEmitsGeneric();
55
+ /** 组件事件 - 外部调用 */
56
+ export const passwordInputEmits = {
57
+ ...VanField.emits,
58
+ ...passwordInputEmitsPrivate,
59
+ };
60
+
61
+ export type PasswordInputEmits<T> = ReturnType<typeof passwordInputEmitsGeneric<T>>;
62
+
63
+ export interface PasswordInputSlots extends CommonSlots<any> {
64
+ }
@@ -0,0 +1,6 @@
1
+ import type { ComponentExposed } from 'vue-component-type-helpers';
2
+ import HPicker from './index.vue';
3
+
4
+ export { HPicker };
5
+ export type HPickerInstance = ComponentExposed<typeof HPicker>;
6
+ export * from './types';
@@ -0,0 +1,136 @@
1
+ <template>
2
+ <VanField
3
+ v-if="!hide"
4
+ :name="field"
5
+ :disabled="globalDisabled || disabled"
6
+ :readonly="true"
7
+ :is-link="isLink"
8
+ :model-value="showText"
9
+ v-bind="$attrs"
10
+ @click="clickHandle"
11
+ >
12
+ <template #extra>
13
+ <VanPopup v-model:show="popupInfo.visible" teleport="body" round position="bottom" v-bind="popupProps" v-on="popupOn" @close="popupInfo.close">
14
+ <VanPicker
15
+ :model-value="checked"
16
+ :columns="finalOption"
17
+ v-bind="pickerProps" v-on="pickerOn"
18
+ @change="pickerHandle('change', $event)" @confirm="pickerHandle('confirm', $event)" @cancel="pickerHandle('cancel', $event)"
19
+ >
20
+ <template v-for="(item, slotName) of pickerSlots" :key="slotName" #[hyphenate(slotName)]="row">
21
+ <component :is="getNode(item)" v-bind="slotProps" v-bind.prop="row" />
22
+ </template>
23
+ </VanPicker>
24
+ </VanPopup>
25
+ </template>
26
+ <template v-for="(item, slotName) of slots" :key="slotName" #[hyphenate(slotName)]="row">
27
+ <component :is="getNode(item)" v-bind="slotProps" v-bind.prop="row" />
28
+ </template>
29
+ </VanField>
30
+ </template>
31
+
32
+ <script lang="ts">
33
+ import { getNode, hyphenate, usePlain } from '@xiaohaih/json-form-core';
34
+ import { Field as VanField, Picker as VanPicker, Popup as VanPopup } from 'vant';
35
+ import type { SlotsType } from 'vue';
36
+ import { computed, defineComponent, ref, watch } from 'vue';
37
+ import { useCommonSetup } from '../use';
38
+ import type { PickerOption, PickerSlots } from './types';
39
+ import { pickerEmitsPrivate as emits, pickerPropsPrivate as props } from './types';
40
+
41
+ /**
42
+ * @file 选择框
43
+ */
44
+ export default defineComponent({
45
+ name: 'HPicker',
46
+ components: { VanPicker, VanField, VanPopup },
47
+ inheritAttrs: false,
48
+ props,
49
+ emits,
50
+ slots: Object as SlotsType<PickerSlots>,
51
+ setup(props, ctx) {
52
+ const plain = usePlain(props);
53
+ const { slotProps } = useCommonSetup(props, ctx, plain);
54
+ /** 展示在页面上的值 */
55
+ const showText = computed(() => {
56
+ const value = plain.checked.value as string[];
57
+ if (!value || !value.length) return '';
58
+ const { format, showAllLevels, separator } = props;
59
+ const source = (props.pickerProps?.columns || plain.finalOption.value) as Record<string, any>[];
60
+ const _columnsFieldNames = (props.pickerProps || {}).columnsFieldNames || {};
61
+ const columnsFieldNames = { text: _columnsFieldNames.text || 'text', value: _columnsFieldNames.value || 'value', children: _columnsFieldNames.children || 'children' };
62
+ if (format) return format({ source, value, columnsFieldNames, showAllLevels, separator });
63
+
64
+ // 判断是否为扁平多列结构(source 中的元素是数组)
65
+ const isMultiColumnFlat = source.length > 0 && Array.isArray(source[0]);
66
+
67
+ if (isMultiColumnFlat) {
68
+ // 1. 扁平的多列:每列独立查找
69
+ return value.map((val, i) => {
70
+ const column = source[i] || [];
71
+ const item = column.find((opt: Record<string, any>) => opt[columnsFieldNames.value] === val);
72
+ return item ? item[columnsFieldNames.text] : '';
73
+ }).filter(Boolean).join(separator);
74
+ }
75
+ // 2. 树形级联或单列:逐级查找
76
+ const texts: string[] = [];
77
+ let currentOptions = source;
78
+ for (const val of value) {
79
+ const item = currentOptions.find((opt: Record<string, any>) => opt[columnsFieldNames.value] === val);
80
+ if (!item) break;
81
+ texts.push(item[columnsFieldNames.text]);
82
+ currentOptions = item[columnsFieldNames.children] || [];
83
+ }
84
+ return showAllLevels ? texts.join(separator) : texts[texts.length - 1];
85
+ });
86
+
87
+ /** 点击事件 */
88
+ function clickHandle(ev: MouseEvent) {
89
+ if (plain.globalDisabled.value || props.disabled || plain.globalReadonly.value || props.readonly) return;
90
+ props.onRowClick ? props.onRowClick(popupInfo.value, ev) : popupInfo.value.open();
91
+ }
92
+ /**
93
+ * 日期更改事件
94
+ * @param {string} type 事件类型
95
+ * @param {string} value 日期值
96
+ */
97
+ function pickerHandle(type: string, value: PickerOption) {
98
+ (props.valueTrigger === type || props.pickerProps?.showToolbar === false) && plain.change(value.selectedValues);
99
+ switch (type) {
100
+ case 'confirm':
101
+ case 'cancel':
102
+ {
103
+ popupInfo.value.close();
104
+ break;
105
+ }
106
+ default: break;
107
+ }
108
+ }
109
+
110
+ /** 弹窗显示状态 */
111
+ const popupInfo = ref({
112
+ visible: false,
113
+ open() {
114
+ popupInfo.value.visible = true;
115
+ },
116
+ close() {
117
+ popupInfo.value.visible = false;
118
+ },
119
+ });
120
+
121
+ return {
122
+ hyphenate,
123
+ getNode,
124
+ ...plain,
125
+ slotProps,
126
+ showText,
127
+ clickHandle,
128
+ pickerHandle,
129
+ popupInfo,
130
+ };
131
+ },
132
+ });
133
+ </script>
134
+
135
+ <style lang="scss" scoped>
136
+ </style>