wedux-ui 0.1.0

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 (231) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -0
  3. package/miniprogram_dist/behaviors/formField.js +35 -0
  4. package/miniprogram_dist/components/avatar/avatar.js +70 -0
  5. package/miniprogram_dist/components/avatar/avatar.json +4 -0
  6. package/miniprogram_dist/components/avatar/avatar.scss +68 -0
  7. package/miniprogram_dist/components/avatar/avatar.wxml +15 -0
  8. package/miniprogram_dist/components/avatar-group/avatar-group.js +45 -0
  9. package/miniprogram_dist/components/avatar-group/avatar-group.json +7 -0
  10. package/miniprogram_dist/components/avatar-group/avatar-group.scss +4 -0
  11. package/miniprogram_dist/components/avatar-group/avatar-group.wxml +3 -0
  12. package/miniprogram_dist/components/back-top/back-top.js +68 -0
  13. package/miniprogram_dist/components/back-top/back-top.json +4 -0
  14. package/miniprogram_dist/components/back-top/back-top.scss +43 -0
  15. package/miniprogram_dist/components/back-top/back-top.wxml +10 -0
  16. package/miniprogram_dist/components/badge/badge.js +100 -0
  17. package/miniprogram_dist/components/badge/badge.json +4 -0
  18. package/miniprogram_dist/components/badge/badge.scss +98 -0
  19. package/miniprogram_dist/components/badge/badge.wxml +11 -0
  20. package/miniprogram_dist/components/button/button.js +152 -0
  21. package/miniprogram_dist/components/button/button.json +4 -0
  22. package/miniprogram_dist/components/button/button.scss +499 -0
  23. package/miniprogram_dist/components/button/button.wxml +21 -0
  24. package/miniprogram_dist/components/button-group/button-group.js +51 -0
  25. package/miniprogram_dist/components/button-group/button-group.json +4 -0
  26. package/miniprogram_dist/components/button-group/button-group.scss +8 -0
  27. package/miniprogram_dist/components/button-group/button-group.wxml +3 -0
  28. package/miniprogram_dist/components/calendar/calendar.js +308 -0
  29. package/miniprogram_dist/components/calendar/calendar.json +4 -0
  30. package/miniprogram_dist/components/calendar/calendar.scss +141 -0
  31. package/miniprogram_dist/components/calendar/calendar.wxml +47 -0
  32. package/miniprogram_dist/components/card/card.js +44 -0
  33. package/miniprogram_dist/components/card/card.json +4 -0
  34. package/miniprogram_dist/components/card/card.scss +143 -0
  35. package/miniprogram_dist/components/card/card.wxml +31 -0
  36. package/miniprogram_dist/components/checkbox/checkbox.js +43 -0
  37. package/miniprogram_dist/components/checkbox/checkbox.json +4 -0
  38. package/miniprogram_dist/components/checkbox/checkbox.scss +77 -0
  39. package/miniprogram_dist/components/checkbox/checkbox.wxml +13 -0
  40. package/miniprogram_dist/components/checkbox-button/checkbox-button.js +43 -0
  41. package/miniprogram_dist/components/checkbox-button/checkbox-button.json +4 -0
  42. package/miniprogram_dist/components/checkbox-button/checkbox-button.scss +39 -0
  43. package/miniprogram_dist/components/checkbox-button/checkbox-button.wxml +8 -0
  44. package/miniprogram_dist/components/checkbox-group/checkbox-group.js +84 -0
  45. package/miniprogram_dist/components/checkbox-group/checkbox-group.json +4 -0
  46. package/miniprogram_dist/components/checkbox-group/checkbox-group.scss +9 -0
  47. package/miniprogram_dist/components/checkbox-group/checkbox-group.wxml +3 -0
  48. package/miniprogram_dist/components/color-picker/color-picker.js +348 -0
  49. package/miniprogram_dist/components/color-picker/color-picker.json +7 -0
  50. package/miniprogram_dist/components/color-picker/color-picker.scss +383 -0
  51. package/miniprogram_dist/components/color-picker/color-picker.wxml +232 -0
  52. package/miniprogram_dist/components/date-picker/date-picker.js +1289 -0
  53. package/miniprogram_dist/components/date-picker/date-picker.json +7 -0
  54. package/miniprogram_dist/components/date-picker/date-picker.scss +468 -0
  55. package/miniprogram_dist/components/date-picker/date-picker.wxml +214 -0
  56. package/miniprogram_dist/components/divider/divider.js +34 -0
  57. package/miniprogram_dist/components/divider/divider.json +4 -0
  58. package/miniprogram_dist/components/divider/divider.scss +75 -0
  59. package/miniprogram_dist/components/divider/divider.wxml +8 -0
  60. package/miniprogram_dist/components/drawer/drawer.js +104 -0
  61. package/miniprogram_dist/components/drawer/drawer.json +4 -0
  62. package/miniprogram_dist/components/drawer/drawer.scss +171 -0
  63. package/miniprogram_dist/components/drawer/drawer.wxml +22 -0
  64. package/miniprogram_dist/components/ellipsis/ellipsis.js +38 -0
  65. package/miniprogram_dist/components/ellipsis/ellipsis.json +4 -0
  66. package/miniprogram_dist/components/ellipsis/ellipsis.scss +22 -0
  67. package/miniprogram_dist/components/ellipsis/ellipsis.wxml +7 -0
  68. package/miniprogram_dist/components/flex/flex.js +81 -0
  69. package/miniprogram_dist/components/flex/flex.json +4 -0
  70. package/miniprogram_dist/components/flex/flex.scss +4 -0
  71. package/miniprogram_dist/components/flex/flex.wxml +3 -0
  72. package/miniprogram_dist/components/float-button/float-button.js +78 -0
  73. package/miniprogram_dist/components/float-button/float-button.json +4 -0
  74. package/miniprogram_dist/components/float-button/float-button.scss +54 -0
  75. package/miniprogram_dist/components/float-button/float-button.wxml +9 -0
  76. package/miniprogram_dist/components/form/form.js +142 -0
  77. package/miniprogram_dist/components/form/form.json +4 -0
  78. package/miniprogram_dist/components/form/form.scss +11 -0
  79. package/miniprogram_dist/components/form/form.wxml +3 -0
  80. package/miniprogram_dist/components/form/validator.js +220 -0
  81. package/miniprogram_dist/components/form-item/form-item.js +240 -0
  82. package/miniprogram_dist/components/form-item/form-item.json +4 -0
  83. package/miniprogram_dist/components/form-item/form-item.scss +59 -0
  84. package/miniprogram_dist/components/form-item/form-item.wxml +33 -0
  85. package/miniprogram_dist/components/gradient-text/gradient-text.js +54 -0
  86. package/miniprogram_dist/components/gradient-text/gradient-text.json +4 -0
  87. package/miniprogram_dist/components/gradient-text/gradient-text.scss +7 -0
  88. package/miniprogram_dist/components/gradient-text/gradient-text.wxml +1 -0
  89. package/miniprogram_dist/components/h/h.js +60 -0
  90. package/miniprogram_dist/components/h/h.json +4 -0
  91. package/miniprogram_dist/components/h/h.scss +53 -0
  92. package/miniprogram_dist/components/h/h.wxml +1 -0
  93. package/miniprogram_dist/components/highlight/highlight.js +77 -0
  94. package/miniprogram_dist/components/highlight/highlight.json +4 -0
  95. package/miniprogram_dist/components/highlight/highlight.scss +8 -0
  96. package/miniprogram_dist/components/highlight/highlight.wxml +12 -0
  97. package/miniprogram_dist/components/infinite-scroll/infinite-scroll.js +31 -0
  98. package/miniprogram_dist/components/infinite-scroll/infinite-scroll.json +4 -0
  99. package/miniprogram_dist/components/infinite-scroll/infinite-scroll.scss +31 -0
  100. package/miniprogram_dist/components/infinite-scroll/infinite-scroll.wxml +12 -0
  101. package/miniprogram_dist/components/input/input.js +59 -0
  102. package/miniprogram_dist/components/input/input.json +4 -0
  103. package/miniprogram_dist/components/input/input.scss +96 -0
  104. package/miniprogram_dist/components/input/input.wxml +34 -0
  105. package/miniprogram_dist/components/input-otp/input-otp.js +106 -0
  106. package/miniprogram_dist/components/input-otp/input-otp.json +4 -0
  107. package/miniprogram_dist/components/input-otp/input-otp.scss +122 -0
  108. package/miniprogram_dist/components/input-otp/input-otp.wxml +38 -0
  109. package/miniprogram_dist/components/layout/layout.js +50 -0
  110. package/miniprogram_dist/components/layout/layout.json +4 -0
  111. package/miniprogram_dist/components/layout/layout.scss +10 -0
  112. package/miniprogram_dist/components/layout/layout.wxml +3 -0
  113. package/miniprogram_dist/components/layout-content/layout-content.js +47 -0
  114. package/miniprogram_dist/components/layout-content/layout-content.json +4 -0
  115. package/miniprogram_dist/components/layout-content/layout-content.scss +5 -0
  116. package/miniprogram_dist/components/layout-content/layout-content.wxml +13 -0
  117. package/miniprogram_dist/components/layout-footer/layout-footer.js +59 -0
  118. package/miniprogram_dist/components/layout-footer/layout-footer.json +4 -0
  119. package/miniprogram_dist/components/layout-footer/layout-footer.scss +23 -0
  120. package/miniprogram_dist/components/layout-footer/layout-footer.wxml +16 -0
  121. package/miniprogram_dist/components/layout-header/layout-header.js +59 -0
  122. package/miniprogram_dist/components/layout-header/layout-header.json +4 -0
  123. package/miniprogram_dist/components/layout-header/layout-header.scss +23 -0
  124. package/miniprogram_dist/components/layout-header/layout-header.wxml +16 -0
  125. package/miniprogram_dist/components/layout-sider/layout-sider.js +48 -0
  126. package/miniprogram_dist/components/layout-sider/layout-sider.json +4 -0
  127. package/miniprogram_dist/components/layout-sider/layout-sider.scss +13 -0
  128. package/miniprogram_dist/components/layout-sider/layout-sider.wxml +5 -0
  129. package/miniprogram_dist/components/list/list.js +55 -0
  130. package/miniprogram_dist/components/list/list.json +4 -0
  131. package/miniprogram_dist/components/list/list.scss +51 -0
  132. package/miniprogram_dist/components/list/list.wxml +9 -0
  133. package/miniprogram_dist/components/list-item/list-item.js +24 -0
  134. package/miniprogram_dist/components/list-item/list-item.json +4 -0
  135. package/miniprogram_dist/components/list-item/list-item.scss +51 -0
  136. package/miniprogram_dist/components/list-item/list-item.wxml +14 -0
  137. package/miniprogram_dist/components/navigation-bar/navigation-bar.js +77 -0
  138. package/miniprogram_dist/components/navigation-bar/navigation-bar.json +4 -0
  139. package/miniprogram_dist/components/navigation-bar/navigation-bar.scss +63 -0
  140. package/miniprogram_dist/components/navigation-bar/navigation-bar.wxml +35 -0
  141. package/miniprogram_dist/components/number-animation/number-animation.js +124 -0
  142. package/miniprogram_dist/components/number-animation/number-animation.json +4 -0
  143. package/miniprogram_dist/components/number-animation/number-animation.scss +3 -0
  144. package/miniprogram_dist/components/number-animation/number-animation.wxml +1 -0
  145. package/miniprogram_dist/components/popover/popover.js +183 -0
  146. package/miniprogram_dist/components/popover/popover.json +4 -0
  147. package/miniprogram_dist/components/popover/popover.scss +69 -0
  148. package/miniprogram_dist/components/popover/popover.wxml +19 -0
  149. package/miniprogram_dist/components/qr-code/qr-code.js +216 -0
  150. package/miniprogram_dist/components/qr-code/qr-code.json +4 -0
  151. package/miniprogram_dist/components/qr-code/qr-code.scss +8 -0
  152. package/miniprogram_dist/components/qr-code/qr-code.wxml +16 -0
  153. package/miniprogram_dist/components/radio/radio.js +38 -0
  154. package/miniprogram_dist/components/radio/radio.json +4 -0
  155. package/miniprogram_dist/components/radio/radio.scss +50 -0
  156. package/miniprogram_dist/components/radio/radio.wxml +12 -0
  157. package/miniprogram_dist/components/radio-button/radio-button.js +39 -0
  158. package/miniprogram_dist/components/radio-button/radio-button.json +4 -0
  159. package/miniprogram_dist/components/radio-button/radio-button.scss +39 -0
  160. package/miniprogram_dist/components/radio-button/radio-button.wxml +8 -0
  161. package/miniprogram_dist/components/radio-group/radio-group.js +72 -0
  162. package/miniprogram_dist/components/radio-group/radio-group.json +4 -0
  163. package/miniprogram_dist/components/radio-group/radio-group.scss +9 -0
  164. package/miniprogram_dist/components/radio-group/radio-group.wxml +3 -0
  165. package/miniprogram_dist/components/rate/rate.js +90 -0
  166. package/miniprogram_dist/components/rate/rate.json +4 -0
  167. package/miniprogram_dist/components/rate/rate.scss +59 -0
  168. package/miniprogram_dist/components/rate/rate.wxml +16 -0
  169. package/miniprogram_dist/components/select/select.js +201 -0
  170. package/miniprogram_dist/components/select/select.json +7 -0
  171. package/miniprogram_dist/components/select/select.scss +235 -0
  172. package/miniprogram_dist/components/select/select.wxml +79 -0
  173. package/miniprogram_dist/components/stepper/stepper.js +113 -0
  174. package/miniprogram_dist/components/stepper/stepper.json +4 -0
  175. package/miniprogram_dist/components/stepper/stepper.scss +73 -0
  176. package/miniprogram_dist/components/stepper/stepper.wxml +23 -0
  177. package/miniprogram_dist/components/switch/switch.js +42 -0
  178. package/miniprogram_dist/components/switch/switch.json +4 -0
  179. package/miniprogram_dist/components/switch/switch.scss +77 -0
  180. package/miniprogram_dist/components/switch/switch.wxml +10 -0
  181. package/miniprogram_dist/components/tab-bar/tab-bar.js +53 -0
  182. package/miniprogram_dist/components/tab-bar/tab-bar.json +4 -0
  183. package/miniprogram_dist/components/tab-bar/tab-bar.scss +53 -0
  184. package/miniprogram_dist/components/tab-bar/tab-bar.wxml +12 -0
  185. package/miniprogram_dist/components/tag/tag.js +87 -0
  186. package/miniprogram_dist/components/tag/tag.json +4 -0
  187. package/miniprogram_dist/components/tag/tag.scss +138 -0
  188. package/miniprogram_dist/components/tag/tag.wxml +12 -0
  189. package/miniprogram_dist/components/textarea/textarea.js +46 -0
  190. package/miniprogram_dist/components/textarea/textarea.json +4 -0
  191. package/miniprogram_dist/components/textarea/textarea.scss +51 -0
  192. package/miniprogram_dist/components/textarea/textarea.wxml +20 -0
  193. package/miniprogram_dist/components/theme-provider/presets.js +101 -0
  194. package/miniprogram_dist/components/theme-provider/theme-provider.js +34 -0
  195. package/miniprogram_dist/components/theme-provider/theme-provider.json +4 -0
  196. package/miniprogram_dist/components/theme-provider/theme-provider.scss +3 -0
  197. package/miniprogram_dist/components/theme-provider/theme-provider.wxml +3 -0
  198. package/miniprogram_dist/components/time-picker/time-picker.js +136 -0
  199. package/miniprogram_dist/components/time-picker/time-picker.json +7 -0
  200. package/miniprogram_dist/components/time-picker/time-picker.scss +135 -0
  201. package/miniprogram_dist/components/time-picker/time-picker.wxml +47 -0
  202. package/miniprogram_dist/components/tooltip/tooltip.js +179 -0
  203. package/miniprogram_dist/components/tooltip/tooltip.json +4 -0
  204. package/miniprogram_dist/components/tooltip/tooltip.scss +66 -0
  205. package/miniprogram_dist/components/tooltip/tooltip.wxml +17 -0
  206. package/miniprogram_dist/components/tree/tree.js +647 -0
  207. package/miniprogram_dist/components/tree/tree.json +4 -0
  208. package/miniprogram_dist/components/tree/tree.scss +178 -0
  209. package/miniprogram_dist/components/tree/tree.wxml +59 -0
  210. package/miniprogram_dist/components/tree-select/tree-select.js +260 -0
  211. package/miniprogram_dist/components/tree-select/tree-select.json +8 -0
  212. package/miniprogram_dist/components/tree-select/tree-select.scss +250 -0
  213. package/miniprogram_dist/components/tree-select/tree-select.wxml +118 -0
  214. package/miniprogram_dist/components/upload/upload.js +387 -0
  215. package/miniprogram_dist/components/upload/upload.json +4 -0
  216. package/miniprogram_dist/components/upload/upload.scss +258 -0
  217. package/miniprogram_dist/components/upload/upload.wxml +142 -0
  218. package/miniprogram_dist/components/watermark/watermark.js +260 -0
  219. package/miniprogram_dist/components/watermark/watermark.json +4 -0
  220. package/miniprogram_dist/components/watermark/watermark.scss +35 -0
  221. package/miniprogram_dist/components/watermark/watermark.wxml +13 -0
  222. package/miniprogram_dist/libs/qrcodegen.js +714 -0
  223. package/miniprogram_dist/libs/seemly.min.js +547 -0
  224. package/miniprogram_dist/libs/tempo_1_0_0.js +1264 -0
  225. package/miniprogram_dist/libs/validator_13_56_26.min.js +5282 -0
  226. package/miniprogram_dist/styles/demo.scss +96 -0
  227. package/miniprogram_dist/styles/iconfont.scss +91 -0
  228. package/miniprogram_dist/styles/theme.scss +126 -0
  229. package/miniprogram_dist/styles/tokens.scss +292 -0
  230. package/miniprogram_dist/utils/relations.js +21 -0
  231. package/package.json +25 -0
@@ -0,0 +1,54 @@
1
+ .w-fab {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ justify-content: center;
6
+ width: 96rpx;
7
+ height: 96rpx;
8
+ box-shadow: var(--shadow-float);
9
+ transition: opacity 0.2s;
10
+ position: relative;
11
+ overflow: hidden;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ .w-fab--circle {
16
+ border-radius: 50%;
17
+ }
18
+
19
+ .w-fab--square {
20
+ border-radius: var(--radius-md);
21
+ }
22
+
23
+ /* Types */
24
+ .w-fab--primary {
25
+ background: var(--color-brand);
26
+ color: #ffffff;
27
+ }
28
+
29
+ .w-fab--default {
30
+ background: var(--color-bg-elevated);
31
+ color: var(--color-text-primary);
32
+ }
33
+
34
+ /* Press overlay */
35
+ .w-fab--active::after {
36
+ content: '';
37
+ position: absolute;
38
+ top: 0;
39
+ left: 0;
40
+ right: 0;
41
+ bottom: 0;
42
+ background: var(--color-press-overlay);
43
+ border-radius: inherit;
44
+ }
45
+
46
+ .w-fab--default.w-fab--active::after {
47
+ background: var(--color-press-overlay-light);
48
+ }
49
+
50
+ /* Disabled */
51
+ .w-fab--disabled {
52
+ opacity: 0.4;
53
+ pointer-events: none;
54
+ }
@@ -0,0 +1,9 @@
1
+ <view
2
+ class="w-fab w-fab--{{shape}} w-fab--{{type}} {{disabled ? 'w-fab--disabled' : ''}}"
3
+ style="{{_style}}"
4
+ hover-class="{{disabled ? '' : 'w-fab--active'}}"
5
+ hover-stay-time="70"
6
+ bindtap="handleTap"
7
+ >
8
+ <slot></slot>
9
+ </view>
@@ -0,0 +1,142 @@
1
+ Component({
2
+ behaviors: ['wx://form-field-group'],
3
+
4
+ relations: {
5
+ '../form-item/form-item': {
6
+ type: 'descendant',
7
+ linked() {
8
+ this._updateChildren();
9
+ },
10
+ linkChanged() {
11
+ this._updateChildren();
12
+ },
13
+ unlinked() {
14
+ this._updateChildren();
15
+ },
16
+ },
17
+ },
18
+
19
+ properties: {
20
+ model: { type: Object, value: {} },
21
+ rules: { type: Object, value: {} },
22
+ size: { type: String, value: 'medium' },
23
+ disabled: { type: Boolean, value: false },
24
+ labelPlacement: { type: String, value: 'top' },
25
+ labelWidth: { type: String, value: '' },
26
+ showFeedback: { type: Boolean, value: true },
27
+ showLabel: { type: Boolean, value: true },
28
+ showRequireMark: { type: Boolean, value: true },
29
+ requireMarkPlacement: { type: String, value: 'right' },
30
+ inline: { type: Boolean, value: false },
31
+ },
32
+
33
+ observers: {
34
+ 'model, rules, size, disabled, labelPlacement, labelWidth, showFeedback, showLabel, showRequireMark, requireMarkPlacement'() {
35
+ this._updateChildren();
36
+ },
37
+ },
38
+
39
+ lifetimes: {
40
+ created() {
41
+ // Store rules with functions here (not in data, to survive serialization)
42
+ this._rules = null;
43
+ },
44
+ },
45
+
46
+ methods: {
47
+ /**
48
+ * Set rules with custom validator functions.
49
+ * Use this instead of the rules property when rules contain functions,
50
+ * because setData/WXML data binding strips functions.
51
+ *
52
+ * Usage (in page's onReady):
53
+ * this.selectComponent('#form').setRules({
54
+ * age: [{ validator(rule, value) { ... }, trigger: 'blur' }]
55
+ * })
56
+ */
57
+ setRules(rules) {
58
+ this._rules = rules || null;
59
+ this._updateChildren();
60
+ },
61
+
62
+ /**
63
+ * Get the effective rules (setRules > property).
64
+ */
65
+ _getEffectiveRules() {
66
+ return this._rules || this.data.rules || {};
67
+ },
68
+
69
+ _updateChildren() {
70
+ const children = this.getRelationNodes('../form-item/form-item');
71
+ if (!children) return;
72
+ const ctx = {
73
+ size: this.data.size,
74
+ disabled: this.data.disabled,
75
+ labelPlacement: this.data.labelPlacement,
76
+ labelWidth: this.data.labelWidth,
77
+ showFeedback: this.data.showFeedback,
78
+ showLabel: this.data.showLabel,
79
+ showRequireMark: this.data.showRequireMark,
80
+ requireMarkPlacement: this.data.requireMarkPlacement,
81
+ model: this.data.model,
82
+ rules: this._getEffectiveRules(),
83
+ };
84
+ children.forEach((child) => {
85
+ child._setFormContext(ctx);
86
+ });
87
+ },
88
+
89
+ getFieldValue(path) {
90
+ if (!path || !this.data.model) return undefined;
91
+ return this.data.model[path];
92
+ },
93
+
94
+ getRulesForPath(path) {
95
+ const rules = this._getEffectiveRules();
96
+ if (!path || !rules) return [];
97
+ const r = rules[path];
98
+ if (!r) return [];
99
+ return Array.isArray(r) ? r : [r];
100
+ },
101
+
102
+ /**
103
+ * Validate all form items (naive-ui style).
104
+ * @param {Function} [callback] - callback(errors)
105
+ * errors: undefined if all valid, Array<{ field, message }> if invalid
106
+ *
107
+ * Usage:
108
+ * form.validate((errors) => {
109
+ * if (!errors) { // success }
110
+ * else { console.log(errors) }
111
+ * })
112
+ */
113
+ validate(callback) {
114
+ const children = this.getRelationNodes('../form-item/form-item');
115
+ if (!children || children.length === 0) {
116
+ callback && callback(undefined);
117
+ return;
118
+ }
119
+ const errors = [];
120
+ children.forEach((child) => {
121
+ const result = child._validate();
122
+ if (!result.valid) {
123
+ result.errors.forEach((error) => {
124
+ errors.push({
125
+ field: child.data.path,
126
+ message: error.message,
127
+ });
128
+ });
129
+ }
130
+ });
131
+ callback && callback(errors.length > 0 ? errors : undefined);
132
+ },
133
+
134
+ restoreValidation() {
135
+ const children = this.getRelationNodes('../form-item/form-item');
136
+ if (!children) return;
137
+ children.forEach((child) => {
138
+ child._restoreValidation();
139
+ });
140
+ },
141
+ },
142
+ });
@@ -0,0 +1,4 @@
1
+ {
2
+ "component": true,
3
+ "styleIsolation": "apply-shared"
4
+ }
@@ -0,0 +1,11 @@
1
+ .w-form {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--spacing-md);
5
+ }
6
+
7
+ .w-form--inline {
8
+ flex-direction: row;
9
+ flex-wrap: wrap;
10
+ gap: var(--spacing-sm);
11
+ }
@@ -0,0 +1,3 @@
1
+ <view class="w-form {{inline ? 'w-form--inline' : ''}}">
2
+ <slot></slot>
3
+ </view>
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Form validation engine - powered by validator.js
3
+ * style: validator(rule, value) => true | new Error('msg') | false
4
+ * API: validateField(value, rules) => { valid, errors }
5
+ */
6
+
7
+ import validatorLib from '../../libs/validator_13_56_26.min.js';
8
+
9
+ // Map rule.type to validator.js method + default message
10
+ var typeMap = {
11
+ // Basic types
12
+ string: {
13
+ check(v) {
14
+ return typeof v === 'string';
15
+ },
16
+ msg: '请输入字符串',
17
+ },
18
+ number: {
19
+ check(v) {
20
+ return !isNaN(Number(v));
21
+ },
22
+ msg: '请输入数字',
23
+ },
24
+ integer: { fn: 'isInt', msg: '请输入整数' },
25
+ float: { fn: 'isFloat', msg: '请输入数字' },
26
+ boolean: {
27
+ check(v) {
28
+ return v === true || v === false || v === 'true' || v === 'false';
29
+ },
30
+ msg: '请输入布尔值',
31
+ },
32
+
33
+ // Format types
34
+ email: { fn: 'isEmail', msg: '邮箱格式不正确' },
35
+ url: { fn: 'isURL', msg: 'URL 格式不正确' },
36
+ phone: { fn: 'isMobilePhone', args: ['zh-CN'], msg: '手机号格式不正确' },
37
+ ip: { fn: 'isIP', msg: 'IP 地址格式不正确' },
38
+ date: { fn: 'isDate', msg: '日期格式不正确' },
39
+ hex: { fn: 'isHexadecimal', msg: '十六进制格式不正确' },
40
+ json: { fn: 'isJSON', msg: 'JSON 格式不正确' },
41
+ ascii: { fn: 'isAscii', msg: '请输入 ASCII 字符' },
42
+ alpha: { fn: 'isAlpha', msg: '请输入字母' },
43
+ alphanumeric: { fn: 'isAlphanumeric', msg: '请输入字母或数字' },
44
+ numeric: { fn: 'isNumeric', msg: '请输入数字' },
45
+ uuid: { fn: 'isUUID', msg: 'UUID 格式不正确' },
46
+ creditCard: { fn: 'isCreditCard', msg: '信用卡号格式不正确' },
47
+ postalCode: { fn: 'isPostalCode', args: ['CN'], msg: '邮编格式不正确' },
48
+ idCard: { fn: 'isIdentityCard', args: ['zh-CN'], msg: '身份证号格式不正确' },
49
+ hexColor: { fn: 'isHexColor', msg: '颜色格式不正确' },
50
+ lowercase: { fn: 'isLowercase', msg: '请输入小写字母' },
51
+ uppercase: { fn: 'isUppercase', msg: '请输入大写字母' },
52
+ };
53
+
54
+ function isEmpty(value) {
55
+ if (value === null || value === undefined) return true;
56
+ if (typeof value === 'string' && value.trim() === '') return true;
57
+ if (Array.isArray(value) && value.length === 0) return true;
58
+ return false;
59
+ }
60
+
61
+ /**
62
+ * Extract error message from validator result.
63
+ * style: new Error('msg'), string, false, true
64
+ */
65
+ function extractError(result, fallbackMsg) {
66
+ if (result === true) return null;
67
+ if (result === false) return fallbackMsg || '校验失败';
68
+ if (result instanceof Error) return result.message || fallbackMsg || '校验失败';
69
+ if (typeof result === 'string') return result;
70
+ return fallbackMsg || '校验失败';
71
+ }
72
+
73
+ function validateRule(value, rule) {
74
+ // Custom validator takes priority
75
+ if (typeof rule.validator === 'function') {
76
+ var result = rule.validator(rule, value);
77
+ var err = extractError(result, rule.message);
78
+ if (err) return err;
79
+ return null;
80
+ }
81
+
82
+ // Required check
83
+ if (rule.required && isEmpty(value)) {
84
+ return rule.message || '此项为必填';
85
+ }
86
+
87
+ // Skip remaining rules if value is empty and not required
88
+ if (isEmpty(value)) return null;
89
+
90
+ var strVal = String(value);
91
+
92
+ // Type check via validator.js
93
+ if (rule.type) {
94
+ var typeDef = typeMap[rule.type];
95
+ if (typeDef) {
96
+ var passed = false;
97
+ if (typeDef.check) {
98
+ passed = typeDef.check(value);
99
+ } else if (typeDef.fn && typeof validatorLib[typeDef.fn] === 'function') {
100
+ var args = rule.validatorArgs || typeDef.args || [];
101
+ passed = validatorLib[typeDef.fn].apply(validatorLib, [strVal].concat(args));
102
+ }
103
+ if (!passed) {
104
+ return rule.message || typeDef.msg;
105
+ }
106
+ }
107
+ }
108
+
109
+ // Direct validator.js method: rule.validatorFn = 'isEmail' etc.
110
+ if (rule.validatorFn && typeof validatorLib[rule.validatorFn] === 'function') {
111
+ var fnArgs = rule.validatorArgs || [];
112
+ if (!validatorLib[rule.validatorFn].apply(validatorLib, [strVal].concat(fnArgs))) {
113
+ return rule.message || '格式不正确';
114
+ }
115
+ }
116
+
117
+ // Pattern check
118
+ if (rule.pattern) {
119
+ var patternReg = typeof rule.pattern === 'string' ? new RegExp(rule.pattern) : rule.pattern;
120
+ if (!patternReg.test(strVal)) {
121
+ return rule.message || '格式不正确';
122
+ }
123
+ }
124
+
125
+ // Length / range check
126
+ if (typeof rule.min === 'number' || typeof rule.max === 'number') {
127
+ if (rule.type === 'number' || rule.type === 'integer' || rule.type === 'float') {
128
+ var numVal = Number(value);
129
+ if (typeof rule.min === 'number' && numVal < rule.min) {
130
+ return rule.message || '不能小于 ' + rule.min;
131
+ }
132
+ if (typeof rule.max === 'number' && numVal > rule.max) {
133
+ return rule.message || '不能大于 ' + rule.max;
134
+ }
135
+ } else {
136
+ var lenOpts = {};
137
+ if (typeof rule.min === 'number') lenOpts.min = rule.min;
138
+ if (typeof rule.max === 'number') lenOpts.max = rule.max;
139
+ if (!validatorLib.isLength(strVal, lenOpts)) {
140
+ if (typeof rule.min === 'number' && typeof rule.max === 'number') {
141
+ return rule.message || '长度应在 ' + rule.min + '-' + rule.max + ' 之间';
142
+ }
143
+ if (typeof rule.min === 'number') {
144
+ return rule.message || '长度不能少于 ' + rule.min;
145
+ }
146
+ return rule.message || '长度不能超过 ' + rule.max;
147
+ }
148
+ }
149
+ }
150
+
151
+ // Whitelist / enum check
152
+ if (rule.enum && Array.isArray(rule.enum)) {
153
+ if (rule.enum.indexOf(value) === -1 && rule.enum.indexOf(strVal) === -1) {
154
+ return rule.message || '值不在允许范围内';
155
+ }
156
+ }
157
+
158
+ return null;
159
+ }
160
+
161
+ /**
162
+ * Filter rules by trigger.
163
+ * @param {Array} rules
164
+ * @param {String} trigger
165
+ * @returns {Array}
166
+ */
167
+ function filterByTrigger(rules, trigger) {
168
+ if (!trigger) return rules;
169
+ var filtered = [];
170
+ for (var i = 0; i < rules.length; i++) {
171
+ var r = rules[i];
172
+ if (!r.trigger) {
173
+ filtered.push(r);
174
+ continue;
175
+ }
176
+ var triggers = Array.isArray(r.trigger) ? r.trigger : [r.trigger];
177
+ if (triggers.indexOf(trigger) >= 0) {
178
+ filtered.push(r);
179
+ }
180
+ }
181
+ return filtered;
182
+ }
183
+
184
+ /**
185
+ * Validate a value against an array of rules.
186
+ * @param {*} value
187
+ * @param {Array|Object} rules - single rule or array of rules
188
+ * @param {Object} [options]
189
+ * @param {String} [options.trigger] - filter rules by trigger
190
+ * @param {Boolean} [options.first] - stop at first error
191
+ * @returns {{ valid: Boolean, errors: Array<{ message: String }> }}
192
+ */
193
+ function validateField(value, rules, options) {
194
+ if (!rules) return { valid: true, errors: [] };
195
+ var ruleList = Array.isArray(rules) ? rules : [rules];
196
+ var opts = options || {};
197
+
198
+ if (opts.trigger) {
199
+ ruleList = filterByTrigger(ruleList, opts.trigger);
200
+ }
201
+
202
+ if (ruleList.length === 0) return { valid: true, errors: [] };
203
+
204
+ var errors = [];
205
+ for (var i = 0; i < ruleList.length; i++) {
206
+ var msg = validateRule(value, ruleList[i]);
207
+ if (msg) {
208
+ errors.push({ message: msg });
209
+ if (opts.first) break;
210
+ }
211
+ }
212
+ return {
213
+ valid: errors.length === 0,
214
+ errors: errors,
215
+ };
216
+ }
217
+
218
+ module.exports = {
219
+ validateField: validateField,
220
+ };
@@ -0,0 +1,240 @@
1
+ const validator = require('../form/validator');
2
+ const { makeDescendantRelations } = require('../../utils/relations');
3
+
4
+ const FIELD_PATHS = [
5
+ '../input/input',
6
+ '../textarea/textarea',
7
+ '../switch/switch',
8
+ '../radio-group/radio-group',
9
+ '../checkbox-group/checkbox-group',
10
+ '../time-picker/time-picker',
11
+ '../date-picker/date-picker',
12
+ '../color-picker/color-picker',
13
+ '../rate/rate',
14
+ '../select/select',
15
+ '../upload/upload',
16
+ '../tree-select/tree-select',
17
+ '../input-otp/input-otp',
18
+ '../stepper/stepper',
19
+ ];
20
+
21
+ Component({
22
+ options: {
23
+ multipleSlots: true,
24
+ },
25
+
26
+ relations: {
27
+ '../form/form': {
28
+ type: 'ancestor',
29
+ },
30
+ ...makeDescendantRelations(FIELD_PATHS, {
31
+ linked() {
32
+ this._updateFieldChildren();
33
+ },
34
+ linkChanged() {
35
+ this._updateFieldChildren();
36
+ },
37
+ unlinked() {
38
+ this._updateFieldChildren();
39
+ },
40
+ }),
41
+ },
42
+
43
+ properties: {
44
+ label: { type: String, value: '' },
45
+ path: { type: String, value: '' },
46
+ rule: { type: null, value: null },
47
+ required: { type: Boolean, value: false },
48
+ first: { type: Boolean, value: false },
49
+ size: { type: String, value: '' },
50
+ showFeedback: { type: null, value: null },
51
+ validationStatus: { type: String, value: '' },
52
+ feedback: { type: String, value: '' },
53
+ labelWidth: { type: String, value: '' },
54
+ requireMarkPlacement: { type: String, value: '' },
55
+ },
56
+
57
+ observers: {
58
+ 'required, path, rule'() {
59
+ this._updateIsRequired();
60
+ },
61
+ },
62
+
63
+ lifetimes: {
64
+ created() {
65
+ this._rule = null;
66
+ // Store form rules as instance property to preserve function references
67
+ this._formRulesRef = {};
68
+ },
69
+ },
70
+
71
+ data: {
72
+ _validationMessage: '',
73
+ _validationStatus: '',
74
+ _formSize: 'medium',
75
+ _formDisabled: false,
76
+ _formLabelPlacement: 'top',
77
+ _formLabelWidth: '',
78
+ _formShowFeedback: true,
79
+ _formShowLabel: true,
80
+ _formShowRequireMark: true,
81
+ _formRequireMarkPlacement: 'right',
82
+ _formModel: {},
83
+ _isRequired: false,
84
+ },
85
+
86
+ methods: {
87
+ _setFormContext(ctx) {
88
+ // Store rules as instance property to preserve function references
89
+ this._formRulesRef = ctx.rules || {};
90
+ this.setData({
91
+ _formSize: ctx.size,
92
+ _formDisabled: ctx.disabled,
93
+ _formLabelPlacement: ctx.labelPlacement,
94
+ _formLabelWidth: ctx.labelWidth,
95
+ _formShowFeedback: ctx.showFeedback,
96
+ _formShowLabel: ctx.showLabel,
97
+ _formShowRequireMark: ctx.showRequireMark,
98
+ _formRequireMarkPlacement: ctx.requireMarkPlacement || 'right',
99
+ _formModel: ctx.model,
100
+ });
101
+ this._updateIsRequired();
102
+ this._updateFieldChildren();
103
+ },
104
+
105
+ _updateFieldChildren() {
106
+ const size = this.data.size || this.data._formSize;
107
+ const disabled = this.data._formDisabled;
108
+ const ctx = { size, disabled };
109
+ FIELD_PATHS.forEach((type) => {
110
+ const nodes = this.getRelationNodes(type);
111
+ if (nodes) {
112
+ nodes.forEach((node) => {
113
+ node._setFormItemContext(ctx);
114
+ });
115
+ }
116
+ });
117
+ },
118
+
119
+ _updateIsRequired() {
120
+ if (this.data.required) {
121
+ this.setData({ _isRequired: true });
122
+ return;
123
+ }
124
+ const rules = this._getRules();
125
+ let isRequired = false;
126
+ for (let i = 0; i < rules.length; i++) {
127
+ if (rules[i].required) {
128
+ isRequired = true;
129
+ break;
130
+ }
131
+ }
132
+ this.setData({ _isRequired: isRequired });
133
+ },
134
+
135
+ /**
136
+ * Set rules with custom validator functions on this form-item.
137
+ * Use this instead of the rule property when rules contain functions.
138
+ */
139
+ setRule(rule) {
140
+ this._rule = rule || null;
141
+ this._updateIsRequired();
142
+ },
143
+
144
+ _getRules() {
145
+ const rules = [];
146
+ // Form-level rules (from instance ref, preserves function references)
147
+ const path = this.data.path;
148
+ const formRulesObj = this._formRulesRef || {};
149
+ if (path && formRulesObj[path]) {
150
+ const formRules = formRulesObj[path];
151
+ rules.push(...(Array.isArray(formRules) ? formRules : [formRules]));
152
+ }
153
+ // Component-level rules (setRule > property)
154
+ const itemRule = this._rule || this.data.rule;
155
+ if (itemRule) {
156
+ rules.push(...(Array.isArray(itemRule) ? itemRule : [itemRule]));
157
+ }
158
+ // Auto-add required rule
159
+ if (this.data.required) {
160
+ let hasRequired = false;
161
+ for (let i = 0; i < rules.length; i++) {
162
+ if (rules[i].required) {
163
+ hasRequired = true;
164
+ break;
165
+ }
166
+ }
167
+ if (!hasRequired) {
168
+ rules.unshift({ required: true, message: '此项为必填' });
169
+ }
170
+ }
171
+ return rules;
172
+ },
173
+
174
+ _getValue() {
175
+ const path = this.data.path;
176
+ if (path && this.data._formModel) {
177
+ return this.data._formModel[path];
178
+ }
179
+ return undefined;
180
+ },
181
+
182
+ /**
183
+ * Public validate method (naive-ui style).
184
+ * Usage:
185
+ * formItem.validate()
186
+ * formItem.validate({ trigger: 'blur' })
187
+ * formItem.validate({ trigger: 'password-input' })
188
+ * @param {Object} [options]
189
+ * @param {String} [options.trigger] - filter rules by trigger
190
+ * @returns {{ valid: Boolean, errors: Array }}
191
+ */
192
+ validate(options) {
193
+ const opts = options || {};
194
+ return this._validate(opts.trigger);
195
+ },
196
+
197
+ _validate(trigger) {
198
+ // Manual status overrides
199
+ if (this.data.validationStatus) {
200
+ return {
201
+ valid: this.data.validationStatus !== 'error',
202
+ errors: this.data.feedback ? [{ message: this.data.feedback }] : [],
203
+ };
204
+ }
205
+ const rules = this._getRules();
206
+ const value = this._getValue();
207
+ const result = validator.validateField(value, rules, {
208
+ trigger,
209
+ first: this.data.first,
210
+ });
211
+ this.setData({
212
+ _validationStatus: result.valid ? '' : 'error',
213
+ _validationMessage: result.errors.length > 0 ? result.errors[0].message : '',
214
+ });
215
+ return result;
216
+ },
217
+
218
+ _restoreValidation() {
219
+ this.setData({
220
+ _validationStatus: '',
221
+ _validationMessage: '',
222
+ });
223
+ },
224
+
225
+ /**
226
+ * Public alias for _restoreValidation.
227
+ */
228
+ restoreValidation() {
229
+ this._restoreValidation();
230
+ },
231
+
232
+ _handleFieldChange() {
233
+ this._validate('input');
234
+ },
235
+
236
+ _handleFieldBlur() {
237
+ this._validate('blur');
238
+ },
239
+ },
240
+ });
@@ -0,0 +1,4 @@
1
+ {
2
+ "component": true,
3
+ "styleIsolation": "apply-shared"
4
+ }