sard-uniapp 1.23.4 → 1.23.5

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## [1.23.5](https://github.com/sutras/sard-uniapp/compare/v1.23.4...v1.23.5) (2025-08-12)
2
+
3
+
4
+ ### Features
5
+
6
+ * **input:** 添加 enableNative 属性以支持支付宝小程序 ([5c8b616](https://github.com/sutras/sard-uniapp/commit/5c8b61624b35a543e87d030266f706eeda819447))
7
+ * **update:** 允许同时选择图片和视频 ([d478208](https://github.com/sutras/sard-uniapp/commit/d4782089767950340448c87bd1bccb43759ede77))
8
+
9
+
10
+
1
11
  ## [1.23.4](https://github.com/sutras/sard-uniapp/compare/v1.23.3...v1.23.4) (2025-08-11)
2
12
 
3
13
 
@@ -231,6 +231,7 @@ export declare const defaultConfig: {
231
231
  hintDuration: number;
232
232
  };
233
233
  input: {
234
+ enableNative: boolean;
234
235
  maxlength: number;
235
236
  adjustPosition: boolean;
236
237
  ignoreCompositionEvent: boolean;
@@ -185,6 +185,7 @@ export const defaultConfig = {
185
185
  hintDuration: 300,
186
186
  },
187
187
  input: {
188
+ enableNative: false,
188
189
  maxlength: 140,
189
190
  adjustPosition: true,
190
191
  ignoreCompositionEvent: true,
@@ -1,5 +1,6 @@
1
1
  import { type StyleValue } from 'vue';
2
2
  export interface InputProps {
3
+ enableNative?: boolean;
3
4
  placeholder?: string;
4
5
  placeholderStyle?: string;
5
6
  placeholderClass?: string;
@@ -49,6 +50,7 @@ export interface InputProps {
49
50
  internalPrepend?: number;
50
51
  }
51
52
  export declare const defaultInputProps: {
53
+ enableNative: boolean;
52
54
  maxlength: number;
53
55
  adjustPosition: boolean;
54
56
  ignoreCompositionEvent: boolean;
@@ -11,6 +11,7 @@ declare const __VLS_component: import("vue").DefineComponent<InputProps, {}, {},
11
11
  confirmType: "send" | "search" | "next" | "go" | "done";
12
12
  inputmode: "none" | "text" | "decimal" | "numeric" | "tel" | "search" | "email" | "url";
13
13
  validateEvent: boolean;
14
+ enableNative: boolean;
14
15
  maxlength: number;
15
16
  cursorSpacing: number;
16
17
  cursor: number;
@@ -16,10 +16,11 @@
16
16
  bem.em('control', 'input-min-height', inputMinHeight),
17
17
  )
18
18
  "
19
+ :enableNative="enableNative"
20
+ :value="innerValue"
19
21
  :placeholder="placeholder"
20
22
  :placeholder-style="mergedPlaceholderStyle"
21
23
  :placeholder-class="placeholderClass"
22
- :value="innerValue"
23
24
  :disabled="isDisabled || isReadonly"
24
25
  :maxlength="maxlength"
25
26
  :focus="focus"
@@ -51,6 +52,7 @@
51
52
  <input
52
53
  v-if="type !== 'textarea' && showPassword"
53
54
  :class="classNames(bem.e('control'), bem.em('control', 'input'))"
55
+ :enableNative="enableNative"
54
56
  :value="innerValue"
55
57
  :placeholder="placeholder"
56
58
  :placeholder-style="mergedPlaceholderStyle"
@@ -91,6 +93,7 @@
91
93
  <input
92
94
  v-if="type !== 'textarea' && !showPassword"
93
95
  :class="classNames(bem.e('control'), bem.em('control', 'input'))"
96
+ :enableNative="enableNative"
94
97
  :value="innerValue"
95
98
  :placeholder="placeholder"
96
99
  :placeholder-style="mergedPlaceholderStyle"
@@ -236,6 +239,7 @@ export default _defineComponent({
236
239
  },
237
240
  __name: "input",
238
241
  props: _mergeDefaults({
242
+ enableNative: { type: Boolean, required: false },
239
243
  placeholder: { type: String, required: false },
240
244
  placeholderStyle: { type: String, required: false },
241
245
  placeholderClass: { type: String, required: false },
@@ -386,10 +390,10 @@ export default _defineComponent({
386
390
  const showPassword = computed(() => {
387
391
  return props.type === "password" && isPlainText.value === false;
388
392
  });
389
- const mergedShowEye = computed(() => props.type === "password" && props.showEye);
390
393
  const mergedType = computed(() => {
391
394
  return showPassword.value ? "password" : props.type === "password" ? "text" : props.type;
392
395
  });
396
+ const mergedShowEye = computed(() => props.type === "password" && props.showEye);
393
397
  const inputClass = computed(() => {
394
398
  return classNames(
395
399
  bem.b(),
@@ -428,7 +432,7 @@ export default _defineComponent({
428
432
  return oldValue;
429
433
  }, set oldValue(v) {
430
434
  oldValue = v;
431
- }, onFocus, onBlur, clearVisible, holdupClear, onClearTouchStart, onClearTouchEnd, onClearMouseDown, onClearClick, onLinechange, onConfirm, onKeyboardheightchange, onClick, isPlainText, eyeIcon, onEyeClick, showPassword, mergedShowEye, mergedType, inputClass, inputStyle, controlStyle, mergedPlaceholderStyle, get classNames() {
435
+ }, onFocus, onBlur, clearVisible, holdupClear, onClearTouchStart, onClearTouchEnd, onClearMouseDown, onClearClick, onLinechange, onConfirm, onKeyboardheightchange, onClick, isPlainText, eyeIcon, onEyeClick, showPassword, mergedType, mergedShowEye, inputClass, inputStyle, controlStyle, mergedPlaceholderStyle, get classNames() {
432
436
  return classNames;
433
437
  }, SarIcon };
434
438
  return __returned__;
@@ -29,6 +29,20 @@ import Upload from 'sard-uniapp/components/upload/upload.vue'
29
29
 
30
30
  @code('${DEMO_PATH}/upload/demo/Video.vue')
31
31
 
32
+ ### 同时上传图片和视频 <sup>1.23.5+</sup>
33
+
34
+ @info
35
+
36
+ 仅 app 和微信支持。
37
+
38
+ 不支持的端,默认回退为选择图片。
39
+
40
+ @endinfo
41
+
42
+ 设置 `:accept="['image', 'video']"` 允许同时选择图片和视频。
43
+
44
+ @code('${DEMO_PATH}/upload/demo/Mix.vue')
45
+
32
46
  ### 限定上传数量
33
47
 
34
48
  通过 `maxCount` 属性可以限制上传文件的数量,上传数量达到限制后,会自动隐藏选择区域。
@@ -99,7 +113,7 @@ import Upload from 'sard-uniapp/components/upload/upload.vue'
99
113
  | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -------------------------- |
100
114
  | root-class | 组件根元素类名 | string | - |
101
115
  | root-style | 组件根元素样式 | StyleValue | - |
102
- | accept | 允许上传的文件类型 | 'image' \| 'video' | 'image' |
116
+ | accept | 允许上传的文件类型 | 'image' \| 'video' \| ('image' \| 'video' )[] | 'image' |
103
117
  | multiple | 是否开启图片多选 | boolean | false |
104
118
  | source-type | 文件选择来源 | ('album' \| 'camera')[] | ['album', 'camera'] |
105
119
  | size-type | 所选的图片的尺寸 | ('original' \| 'compressed')[] | ['original', 'compressed'] |
@@ -26,7 +26,7 @@ export interface UploadSelectOptions {
26
26
  export interface UploadProps {
27
27
  rootStyle?: StyleValue;
28
28
  rootClass?: string;
29
- accept?: 'image' | 'video';
29
+ accept?: 'image' | 'video' | ('image' | 'video')[];
30
30
  multiple?: boolean;
31
31
  sourceType?: ('album' | 'camera')[];
32
32
  sizeType?: ('original' | 'compressed')[];
@@ -45,7 +45,7 @@ export interface UploadProps {
45
45
  beforeRemove?: (index: number, fileItem: UploadFileItem) => boolean | Promise<void>;
46
46
  validateEvent?: boolean;
47
47
  }
48
- export declare const defaultUploadProps: Omit<typeof defaultConfig.upload, "sourceType" | "sizeType">;
48
+ export declare const defaultUploadProps: Omit<typeof defaultConfig.upload, "sourceType" | "sizeType" | "accept">;
49
49
  export interface UploadSlots {
50
50
  default?(props: {
51
51
  list: UploadFileItem[];
@@ -11,7 +11,6 @@ declare const __VLS_component: import("vue").DefineComponent<UploadProps, {}, {}
11
11
  onRemove?: ((index: number, item: UploadFileItem) => any) | undefined;
12
12
  "onItem-click"?: ((item: UploadFileItem, index: number) => any) | undefined;
13
13
  }>, {
14
- accept: "image" | "video";
15
14
  validateEvent: boolean;
16
15
  maxDuration: number;
17
16
  maxCount: number;
@@ -64,7 +64,7 @@ import { useFormContext, useFormItemContext } from "../form/common";
64
64
  /**
65
65
  * @property {string} rootClass 组件根元素类名,默认值:-。
66
66
  * @property {StyleValue} rootStyle 组件根元素样式,默认值:-。
67
- * @property {'image' | 'video'} accept 允许上传的文件类型,默认值:'image'。
67
+ * @property {'image' | 'video' | ('image' | 'video' )[]} accept 允许上传的文件类型,默认值:'image'。
68
68
  * @property {boolean} multiple 是否开启图片多选,默认值:false。
69
69
  * @property {('album' | 'camera')[]} sourceType 文件选择来源,默认值:['album', 'camera']。
70
70
  * @property {('original' | 'compressed')[]} sizeType 所选的图片的尺寸,默认值:['original', 'compressed']。
@@ -102,7 +102,7 @@ export default _defineComponent({
102
102
  props: _mergeDefaults({
103
103
  rootStyle: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
104
104
  rootClass: { type: String, required: false },
105
- accept: { type: String, required: false },
105
+ accept: { type: [String, Array], required: false },
106
106
  multiple: { type: Boolean, required: false },
107
107
  sourceType: { type: Array, required: false },
108
108
  sizeType: { type: Array, required: false },
@@ -1,6 +1,6 @@
1
1
  interface chooseMediaOptions {
2
2
  count?: number;
3
- mediaType?: 'image' | 'video';
3
+ mediaType?: 'image' | 'video' | ('image' | 'video')[];
4
4
  sourceType?: ('album' | 'camera')[];
5
5
  maxDuration?: number;
6
6
  sizeType?: ('original' | 'compressed')[];
@@ -19,7 +19,7 @@ interface chooseMediaResult {
19
19
  fileType: 'image' | 'video';
20
20
  name: string;
21
21
  }[];
22
- type: 'image' | 'video';
22
+ type: 'image' | 'video' | 'mix';
23
23
  }
24
24
  export declare function chooseMedia(options: chooseMediaOptions): void;
25
25
  export {};
@@ -1,7 +1,38 @@
1
1
  import { toArray } from '../../utils';
2
2
  export function chooseMedia(options) {
3
3
  const { count = 9, mediaType = 'image', sourceType = ['album', 'camera'], maxDuration = 10, sizeType = ['original', 'compressed'], camera = 'back', success, fail, complete, } = options;
4
- if (mediaType === 'image') {
4
+ const arrayMediaType = toArray(mediaType);
5
+ const hasImage = arrayMediaType.includes('image');
6
+ const hasVideo = arrayMediaType.includes('video');
7
+ if (hasImage && hasVideo && uni.chooseMedia) {
8
+ return uni.chooseMedia({
9
+ count,
10
+ mediaType: ['image', 'video'],
11
+ sourceType,
12
+ maxDuration,
13
+ sizeType,
14
+ camera,
15
+ success(res) {
16
+ success?.({
17
+ type: res.type,
18
+ tempFiles: toArray(res.tempFiles).map((file) => {
19
+ return {
20
+ tempFilePath: file.tempFilePath,
21
+ size: file.size,
22
+ duration: file.duration,
23
+ height: file.height,
24
+ width: file.width,
25
+ name: '',
26
+ fileType: file.fileType,
27
+ };
28
+ }),
29
+ });
30
+ },
31
+ fail,
32
+ complete,
33
+ });
34
+ }
35
+ else if (hasImage) {
5
36
  return uni.chooseImage({
6
37
  count,
7
38
  sizeType,
@@ -26,7 +57,7 @@ export function chooseMedia(options) {
26
57
  complete,
27
58
  });
28
59
  }
29
- else {
60
+ else if (hasVideo) {
30
61
  return uni.chooseVideo({
31
62
  sourceType,
32
63
  compressed: sizeType.includes('compressed'),
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "id": "sard-uniapp",
3
3
  "name": "sard-uniapp",
4
4
  "displayName": "sard-uniapp",
5
- "version": "1.23.4",
5
+ "version": "1.23.5",
6
6
  "description": "sard-uniapp 是一套基于 Uniapp + Vue3 框架开发的兼容多端的 UI 组件库",
7
7
  "main": "index.js",
8
8
  "scripts": {
package/utils/array.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * @param {any} target
4
4
  * @return {array}
5
5
  */
6
- export declare function toArray(target: any): any[];
6
+ export declare function toArray<T>(target: T | T[]): T[];
7
7
  /**
8
8
  * @description: 扩散性遍历
9
9
  * @param {any[]} array 要遍历的数组
package/utils/object.d.ts CHANGED
@@ -19,14 +19,14 @@ export declare function treeToMap(tree: AnyObject[], keyName: string, childrenNa
19
19
  * @param object
20
20
  * @param chain 通过点分割的字符串或者字符串数组
21
21
  */
22
- export declare function chainGet(object: any, chain?: string | string[]): any;
22
+ export declare function chainGet(object: any, chain?: string | number | (string | number)[]): any;
23
23
  /**
24
24
  * @description: 链式设置对象值
25
25
  * @param object
26
26
  * @param chain 通过点分割的字符串或者字符串数组
27
27
  * @param value 要设置的值
28
28
  */
29
- export declare function chainSet(object: any, chain: string | string[], value: any): void;
29
+ export declare function chainSet(object: any, chain: string | number | (string | number)[], value: any): void;
30
30
  export declare function nestedToMulti(nested: any[], values: (number | string)[], fieldKeys: {
31
31
  value: string;
32
32
  children: string;
package/utils/object.js CHANGED
@@ -89,8 +89,8 @@ export function treeToMap(tree, keyName, childrenName, parentName) {
89
89
  */
90
90
  export function chainGet(object, chain) {
91
91
  let target = object;
92
- if (chain) {
93
- chain = typeof chain === 'string' ? chain.split('.') : chain;
92
+ if (chain || chain === 0) {
93
+ chain = Array.isArray(chain) ? chain : String(chain).split('.');
94
94
  for (const key of chain) {
95
95
  if (target && typeof target === 'object') {
96
96
  target = target[key];
@@ -110,7 +110,7 @@ export function chainGet(object, chain) {
110
110
  */
111
111
  export function chainSet(object, chain, value) {
112
112
  let target = object;
113
- chain = typeof chain === 'string' ? chain.split('.') : chain;
113
+ chain = Array.isArray(chain) ? chain : String(chain).split('.');
114
114
  if (chain.length === 0) {
115
115
  return;
116
116
  }