sard-uniapp 1.23.3 → 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,22 @@
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
+
11
+ ## [1.23.4](https://github.com/sutras/sard-uniapp/compare/v1.23.3...v1.23.4) (2025-08-11)
12
+
13
+
14
+ ### Features
15
+
16
+ * **steps:** 新增 reverse 属性 ([0b98b59](https://github.com/sutras/sard-uniapp/commit/0b98b594a94ee5e1968e54d278fb11d683a0514e))
17
+
18
+
19
+
1
20
  ## [1.23.3](https://github.com/sutras/sard-uniapp/compare/v1.23.2...v1.23.3) (2025-08-09)
2
21
 
3
22
 
@@ -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__;
@@ -59,10 +59,11 @@ import Keyboard from 'sard-uniapp/components/keyboard/keyboard.vue'
59
59
 
60
60
  ### KeyboardEmits
61
61
 
62
- | 事件 | 描述 | 类型 |
63
- | ------ | -------------------- | --------------------- |
64
- | input | 可输入按键点击时触发 | (key: string) => void |
65
- | delete | 点击删除按钮时触发 | () => void |
62
+ | 事件 | 描述 | 类型 |
63
+ | ------------------------- | ------------------------ | -------------------------------------- |
64
+ | input | 可输入按键点击时触发 | (key: string) => void |
65
+ | delete | 点击删除按钮时触发 | () => void |
66
+ | toggle <sup>1.23.3+</sup> | 切换车牌号的中英文时触发 | (mode: 'chinese' \| 'english') => void |
66
67
 
67
68
  ### KeyBoardExpose
68
69
 
@@ -123,6 +123,7 @@ import SarIcon from "../icon/icon.vue";
123
123
  * @property {'number' | 'digit' | 'idcard' | 'random' | 'plate'} type 键盘类型,默认值:'number'。
124
124
  * @event {(key: string) => void} input 可输入按键点击时触发
125
125
  * @event {() => void} delete 点击删除按钮时触发
126
+ * @event {(mode: 'chinese' | 'english') => void} toggle 切换车牌号的中英文时触发
126
127
  */
127
128
  export default _defineComponent({
128
129
  components: {
@@ -212,4 +212,8 @@
212
212
  align-items: flex-start;
213
213
  }
214
214
  }
215
+
216
+ @include m-intersect(horizontal, reverse) {
217
+ flex-direction: column-reverse;
218
+ }
215
219
  }
@@ -86,6 +86,7 @@ export default _defineComponent({
86
86
  bem.m(currentStatus.value),
87
87
  bem.m(position.value),
88
88
  bem.m(context.direction),
89
+ bem.m("reverse", context.reverse),
89
90
  props.rootClass
90
91
  );
91
92
  });
@@ -29,6 +29,12 @@ import Steps from 'sard-uniapp/components/steps/steps.vue'
29
29
 
30
30
  @code('${DEMO_PATH}/steps/demo/Center.vue')
31
31
 
32
+ ### 文字在上 <sup>1.23.4+</sup>
33
+
34
+ 可以使用 `reverse` 属性将水平排列时的文字和图标位置调换。
35
+
36
+ @code('${DEMO_PATH}/steps/demo/Reverse.vue')
37
+
32
38
  ### 垂直步骤条
33
39
 
34
40
  设置 `direction="vertical"` 可以垂直排列。
@@ -81,21 +87,22 @@ import Steps from 'sard-uniapp/components/steps/steps.vue'
81
87
 
82
88
  ### StepsProps
83
89
 
84
- | 属性 | 描述 | 类型 | 默认值 |
85
- | ------------ | -------------------- | -------------------------- | ------------ |
86
- | root-class | 组件根元素类名 | string | - |
87
- | root-style | 组件根元素样式 | StyleValue | - |
88
- | current | 当前步骤对应的索引值 | number | 0 |
89
- | item-list | 所有步骤的数据 | StepsItem[] | [] |
90
- | center | 是否居中 | boolean | false |
91
- | direction | 排列方向 | 'vertical' \| 'horizontal' | 'horizontal' |
92
- | status | 指定当前步骤的状态 | StepsStatus | - |
93
- | icon-family | 图标字体 | string | - |
94
- | icon-size | 图标字号 | string | - |
95
- | finish-icon | 已完成状态的图标名称 | string | - |
96
- | process-icon | 处理中状态的图标名称 | string | - |
97
- | wait-icon | 等待中状态的图标名称 | string | - |
98
- | error-icon | 错误状态的图标名称 | string | - |
90
+ | 属性 | 描述 | 类型 | 默认值 |
91
+ | ------------ | ---------------------------------- | -------------------------- | ------------ |
92
+ | root-class | 组件根元素类名 | string | - |
93
+ | root-style | 组件根元素样式 | StyleValue | - |
94
+ | current | 当前步骤对应的索引值 | number | 0 |
95
+ | item-list | 所有步骤的数据 | StepsItem[] | [] |
96
+ | center | 是否居中 | boolean | false |
97
+ | direction | 排列方向 | 'vertical' \| 'horizontal' | 'horizontal' |
98
+ | reverse | 水平排列时,文字和图标是否调换位置 | boolean | false |
99
+ | status | 指定当前步骤的状态 | StepsStatus | - |
100
+ | icon-family | 图标字体 | string | - |
101
+ | icon-size | 图标字号 | string | - |
102
+ | finish-icon | 已完成状态的图标名称 | string | - |
103
+ | process-icon | 处理中状态的图标名称 | string | - |
104
+ | wait-icon | 等待中状态的图标名称 | string | - |
105
+ | error-icon | 错误状态的图标名称 | string | - |
99
106
 
100
107
  ### StepsSlots
101
108
 
@@ -12,6 +12,7 @@ export interface StepsProps {
12
12
  itemList?: StepsItem[];
13
13
  center?: boolean;
14
14
  direction?: 'vertical' | 'horizontal';
15
+ reverse?: boolean;
15
16
  status?: StepsStatus;
16
17
  iconFamily?: string;
17
18
  iconSize?: string;
@@ -44,5 +45,6 @@ export interface StepsContext {
44
45
  waitIcon?: string;
45
46
  errorIcon?: string;
46
47
  status?: StepsStatus;
48
+ reverse?: boolean;
47
49
  }
48
50
  export declare const stepsContextSymbol: InjectionKey<StepsContext>;
@@ -29,6 +29,7 @@ import {
29
29
  * @property {StepsItem[]} itemList 所有步骤的数据,默认值:[]。
30
30
  * @property {boolean} center 是否居中,默认值:false。
31
31
  * @property {'vertical' | 'horizontal'} direction 排列方向,默认值:'horizontal'。
32
+ * @property {boolean} reverse 水平排列时,文字和图标是否调换位置,默认值:false。
32
33
  * @property {StepsStatus} status 指定当前步骤的状态,默认值:-。
33
34
  * @property {string} iconFamily 图标字体,默认值:-。
34
35
  * @property {string} iconSize 图标字号,默认值:-。
@@ -55,6 +56,7 @@ export default _defineComponent({
55
56
  itemList: { type: Array, required: false },
56
57
  center: { type: Boolean, required: false },
57
58
  direction: { type: String, required: false },
59
+ reverse: { type: Boolean, required: false },
58
60
  status: { type: String, required: false },
59
61
  iconFamily: { type: String, required: false },
60
62
  iconSize: { type: String, required: false },
@@ -79,7 +81,8 @@ export default _defineComponent({
79
81
  processIcon: toRef(() => props.processIcon),
80
82
  waitIcon: toRef(() => props.waitIcon),
81
83
  errorIcon: toRef(() => props.errorIcon),
82
- status: toRef(() => props.status)
84
+ status: toRef(() => props.status),
85
+ reverse: toRef(() => props.reverse)
83
86
  })
84
87
  );
85
88
  const stepsClass = computed(() => {
@@ -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.3",
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
  }
@@ -1,14 +0,0 @@
1
- {
2
- "format": 2,
3
- "compileOptions": {
4
- "component2": true,
5
- "enableNodeModuleBabelTransform": true
6
- },
7
- "unknownConfig": {
8
- "appid": "touristappid",
9
- "projectname": "SardUniapp"
10
- },
11
- "developOptions": {
12
- "skipTranspile": true
13
- }
14
- }