uview-ultra-plus 1.12.2 → 1.14.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.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uview-ultra-plus",
3
- "version": "1.12.2",
3
+ "version": "1.14.0",
4
4
  "workspaces": [
5
5
  "packages/*",
6
6
  "examples/*"
@@ -20,7 +20,8 @@
20
20
  "build": "node scripts/build.js",
21
21
  "docs:dev": "vitepress dev docs",
22
22
  "docs:build": "vitepress build docs",
23
- "docs:preview": "vitepress preview docs",
23
+ "docs:serve": "vitepress preview docs",
24
+ "icons:build": "node packages/uview-ultra-icons/scripts/build.js",
24
25
  "watch:examples": "node scripts/build.js --watch",
25
26
  "rollup": "rollup -c rollup.config.mjs",
26
27
  "test": "echo \"No test specified\""
@@ -58,9 +59,13 @@
58
59
  "@rollup/plugin-commonjs": "^29.0.0",
59
60
  "@rollup/plugin-node-resolve": "^16.0.3",
60
61
  "@rollup/plugin-terser": "^0.4.4",
62
+ "case": "^1.6.3",
61
63
  "chokidar": "^5.0.0",
64
+ "figma-api": "^2.1.2-beta",
62
65
  "release-it": "^19.2.4",
63
66
  "rollup": "^4.59.0",
67
+ "svgo": "^4.0.0",
68
+ "svgtofont": "^6.5.1",
64
69
  "vitepress": "^1.6.4",
65
70
  "vue": "^3.5.29"
66
71
  },
@@ -53,6 +53,51 @@ function runRollup() {
53
53
  execSync('npm run rollup', { stdio: 'inherit', cwd: projectRoot });
54
54
  }
55
55
 
56
+ function collectIconAssets() {
57
+ console.log('[Build] Collecting icon assets from @uview-ultra/icons...');
58
+ const iconDist = path.join(projectRoot, 'packages/uview-ultra-icons/dist/uniapp');
59
+ const targetStatic = path.join(distPath, 'uview-ultra/static/uview-ultra');
60
+ const targetVendor = path.join(distPath, 'uview-ultra/vendor/icons');
61
+
62
+ if (!fs.existsSync(targetStatic)) fs.mkdirSync(targetStatic, { recursive: true });
63
+ if (!fs.existsSync(targetVendor)) fs.mkdirSync(targetVendor, { recursive: true });
64
+
65
+ if (fs.existsSync(iconDist)) {
66
+ // 1. Copy Binary Assets (TTF)
67
+ const fontFile = path.join(iconDist, 'upicon-custom.ttf');
68
+ if (fs.existsSync(fontFile)) {
69
+ fs.copyFileSync(fontFile, path.join(targetStatic, 'upicon-custom.ttf'));
70
+ }
71
+
72
+ // 2. Copy Images
73
+ const imgDist = path.join(iconDist, 'images');
74
+ if (fs.existsSync(imgDist)) {
75
+ const imgTarget = path.join(targetStatic, 'images');
76
+ if (!fs.existsSync(imgTarget)) fs.mkdirSync(imgTarget, { recursive: true });
77
+ execSync(`rsync -aq "${imgDist}/" "${imgTarget}/"`);
78
+ }
79
+
80
+ // 3. Copy Metadata for local distribution (Self-contained uni_modules)
81
+ const metadataFiles = ['icons-svg.js', 'icons-custom.json', 'icons-multicolor.json', 'icons-generated.js', 'icons-generated.uts'];
82
+ metadataFiles.forEach(file => {
83
+ const src = path.join(iconDist, file);
84
+ if (fs.existsSync(src)) {
85
+ fs.copyFileSync(src, path.join(targetVendor, file));
86
+ }
87
+ });
88
+
89
+ // 4. Copy SVG Chunks for dynamic loading
90
+ const svgsSrc = path.join(iconDist, 'svgs');
91
+ if (fs.existsSync(svgsSrc)) {
92
+ const svgsTarget = path.join(targetVendor, 'svgs');
93
+ if (!fs.existsSync(svgsTarget)) fs.mkdirSync(svgsTarget, { recursive: true });
94
+ execSync(`rsync -aq "${svgsSrc}/" "${svgsTarget}/"`);
95
+ }
96
+ } else {
97
+ console.warn('[Build] @uview-ultra/icons dist not found. Did you run icons:build?');
98
+ }
99
+ }
100
+
56
101
  function patchImports() {
57
102
  console.log('[Build] Patching imports in dist...');
58
103
  require('./patch-imports.js');
@@ -70,6 +115,7 @@ function fullBuild() {
70
115
 
71
116
  runRollup();
72
117
  patchImports();
118
+ collectIconAssets();
73
119
  syncExamples(); // Sync from dist/uview-ultra to examples
74
120
  console.log('[Build] Successfully completed!');
75
121
  }
@@ -97,6 +143,7 @@ function watch() {
97
143
  // Rollup (vendor) usually doesn't need to re-run unless dependencies change
98
144
  syncSourceToDist();
99
145
  patchImports();
146
+ collectIconAssets();
100
147
  syncExamples();
101
148
  console.log('[Watch] Sync completed. Waiting for changes...');
102
149
  } catch (e) {
@@ -39,6 +39,18 @@ const replacements = [
39
39
  // In dist, lime-dayuts is a peer of uview-ultra
40
40
  return `./${relToDist}/lime-dayuts`;
41
41
  }
42
+ },
43
+ {
44
+ pattern: /import (.*) from ['"]@uview-ultra\/icons\/dist\/uniapp\/(.*)['"]/g,
45
+ replacement: (filePath) => {
46
+ return (match, p1, p2) => {
47
+ const target = path.join(distUViewPath, 'vendor/icons', p2);
48
+ const relPath = path.relative(path.dirname(filePath), target);
49
+ // Ensure we use ./ for adjacent files
50
+ const finalPath = relPath.startsWith('.') ? relPath : `./${relPath}`;
51
+ return `import ${p1} from '${finalPath}'`;
52
+ }
53
+ }
42
54
  }
43
55
  ];
44
56
 
@@ -1,22 +1,8 @@
1
- /*
2
- * @Author : LQ,jry
3
- * @Description :
4
- * @version : 3.0
5
- * @Date : 2021-08-20 16:44:21
6
- * @LastAuthor : jry
7
- * @lastTime : 2024-08-20 14:20:58
8
- * @FilePath : /uview-ultra/libs/config/props/icon.js
9
- */
10
- import config from '../../libs/config/config.js'
11
-
12
- const {
13
- color
14
- } = config
15
1
  export default {
16
2
  // icon组件
17
3
  icon: {
18
4
  name: '',
19
- color: color['up-content-color'],
5
+ color: '',
20
6
  size: '16px',
21
7
  bold: false,
22
8
  index: '',
@@ -25,12 +11,12 @@ export default {
25
11
  label: '',
26
12
  labelPos: 'right',
27
13
  labelSize: '15px',
28
- labelColor: color['up-content-color'],
14
+ labelColor: '',
29
15
  space: '3px',
30
16
  imgMode: '',
31
17
  width: '',
32
18
  height: '',
33
- top: '0',
19
+ top: 0,
34
20
  stop: false
35
21
  }
36
22
  }
@@ -1,19 +1,8 @@
1
- /*
2
- * @Author : jry
3
- * @Description :
4
- * @version : 4.0
5
- * @Date : 2024-04-22 16:44:21
6
- * @LastAuthor : jry
7
- * @lastTime : 2024-08-28 18:00:14
8
- * @FilePath : /uview-ultra/libs/config/props/icon.js
9
- */
10
- import config from '../../libs/config/config.uts'
11
-
12
1
  export default {
13
2
  // icon组件
14
3
  icon: {
15
4
  name: '',
16
- color: config.getString('color.up-content-color'),
5
+ color: '',
17
6
  size: '16px',
18
7
  bold: false,
19
8
  index: '',
@@ -22,12 +11,12 @@ export default {
22
11
  label: '',
23
12
  labelPos: 'right',
24
13
  labelSize: '15px',
25
- labelColor: config.getString('color.up-content-color'),
14
+ labelColor: '',
26
15
  space: '3px',
27
16
  imgMode: '',
28
17
  width: '',
29
18
  height: '',
30
- top: '0',
19
+ top: 0,
31
20
  stop: false
32
21
  }
33
22
  } as UTSJSONObject
@@ -9,13 +9,20 @@
9
9
  v-if="isImg"
10
10
  :src="name"
11
11
  :mode="imgMode"
12
- :style="[imgStyle, $up.addStyle(customStyle)]"
12
+ :style="[imgStyle, addStyle(customStyle)]"
13
+ ></image>
14
+ <image
15
+ class="up-icon__img"
16
+ v-else-if="isMultiColor"
17
+ :src="imgSrc"
18
+ :mode="imgMode"
19
+ :style="[imgStyle, addStyle(customStyle)]"
13
20
  ></image>
14
21
  <text
15
22
  v-else
16
23
  class="up-icon__icon"
17
24
  :class="uClasses"
18
- :style="[iconStyle, $up.addStyle(customStyle)]"
25
+ :style="[iconStyle, addStyle(customStyle)]"
19
26
  :hover-class="hoverClass"
20
27
  >{{icon}}</text>
21
28
  <!-- 这里进行空字符串判断,如果仅仅是v-if="label",可能会出现传递0的时候,结果也无法显示 -->
@@ -24,204 +31,236 @@
24
31
  class="up-icon__label"
25
32
  :style="{
26
33
  color: labelColor,
27
- fontSize: $up.addUnit(labelSize),
28
- marginLeft: labelPos == 'right' ? $up.addUnit(space) : 0,
29
- marginTop: labelPos == 'bottom' ? $up.addUnit(space) : 0,
30
- marginRight: labelPos == 'left' ? $up.addUnit(space) : 0,
31
- marginBottom: labelPos == 'top' ? $up.addUnit(space) : 0,
34
+ fontSize: addUnit(labelSize),
35
+ marginLeft: labelPos == 'right' ? addUnit(space) : 0,
36
+ marginTop: labelPos == 'bottom' ? addUnit(space) : 0,
37
+ marginRight: labelPos == 'left' ? addUnit(space) : 0,
38
+ marginBottom: labelPos == 'top' ? addUnit(space) : 0,
32
39
  }"
33
40
  >{{ label }}</text>
34
41
  </view>
35
42
  </template>
36
43
 
37
44
  <script setup lang="uts">
38
- import icons from './icons.uts'
45
+ import customIcons from '../../vendor/icons/icons-custom.json'
46
+ import multiColorIcons from '../../vendor/icons/icons-multicolor.json'
47
+ import iconsSvg from '../../vendor/icons/icons-svg.js'
48
+ import generatedIcons from '../../vendor/icons/icons-generated.uts'
39
49
  import { addUnit, addStyle } from '../../libs/function/index'
40
50
  import { commonProps, useUltraUI } from '../../libs/composable/useUltraUI'
41
51
  import config from '../../libs/config/config';
42
- import defProps from './icon'
43
- import { computed } from 'vue'
44
- const { preventEvent } = useUltraUI()
45
-
46
- // 定义props
52
+
47
53
  const props = defineProps({
48
- // 图标类名
54
+ // 每个组件都有的父组件传递的样式,可以为字符串或者对象形式
55
+ customStyle: {
56
+ type: [UTSJSONObject, String],
57
+ default: () : UTSJSONObject => ({})
58
+ },
59
+ customClass: {
60
+ type: String,
61
+ default: ''
62
+ },
63
+ // 跳转的页面路径
64
+ url: {
65
+ type: String,
66
+ default: ''
67
+ },
68
+ // 页面跳转的类型
69
+ linkType: {
70
+ type: String,
71
+ default: 'navigateTo'
72
+ },
73
+ // 图标名称,见示例图标集
49
74
  name: {
50
75
  type: String,
51
- default: () => defProps.getString('icon.name')
76
+ default: ''
52
77
  },
53
- // 图标颜色,可接受主题色
78
+ // 图标颜色,可接受主题色
54
79
  color: {
55
80
  type: String,
56
- default: () => defProps.getString('icon.color')
81
+ default: ''
57
82
  },
58
- // 字体大小,单位px
83
+ // 图标字体大小,单位px
59
84
  size: {
60
85
  type: [String, Number],
61
- default: () => defProps.getString('icon.size')
86
+ default: '16px'
62
87
  },
63
88
  // 是否显示粗体
64
89
  bold: {
65
90
  type: Boolean,
66
- default: () => defProps.getBoolean('icon.bold')
91
+ default: false
67
92
  },
68
93
  // 点击图标的时候传递事件出去的index(用于区分点击了哪一个)
69
94
  index: {
70
- type: [String],
71
- default: () => defProps.getString('icon.index')
95
+ type: [String, Number],
96
+ default: ''
72
97
  },
73
- // 触摸图标时的类名
98
+ // 图标按下去的样式类,用法同uni的view组件的hoverClass参数,详情见官网
74
99
  hoverClass: {
75
100
  type: String,
76
- default: () => defProps.getString('icon.hoverClass')
101
+ default: ''
77
102
  },
78
103
  // 自定义扩展前缀,方便用户扩展自己的图标库
79
104
  customPrefix: {
80
105
  type: String,
81
- default: () => defProps.getString('icon.customPrefix')
106
+ default: 'upicon'
82
107
  },
83
- // 图标右边或者下面的文字
108
+ // 图标右侧的label文字
84
109
  label: {
85
- type: [String],
86
- default: () => defProps.getString('icon.label')
110
+ type: [String, Number],
111
+ default: ''
87
112
  },
88
- // label的位置,只能右边或者下边
113
+ // label相对于图标的位置,只能right或bottom
89
114
  labelPos: {
90
115
  type: String,
91
- default: () => defProps.getString('icon.labelPos')
116
+ default: 'right'
92
117
  },
93
- // label的大小
118
+ // label字体大小,单位px
94
119
  labelSize: {
95
120
  type: [String, Number],
96
- default: () => defProps.getArray('icon.labelSize')
121
+ default: '15px'
97
122
  },
98
- // label的颜色
123
+ // 图标右侧的label文字颜色
99
124
  labelColor: {
100
125
  type: String,
101
- default: () => defProps.getString('icon.labelColor')
126
+ default: ''
102
127
  },
103
- // label与图标的距离
128
+ // label与图标的距离,单位px
104
129
  space: {
105
130
  type: [String, Number],
106
- default: () => defProps.getArray('icon.space')
131
+ default: '3px'
107
132
  },
108
133
  // 图片的mode
109
134
  imgMode: {
110
135
  type: String,
111
- default: () => defProps.getString('icon.imgMode')
136
+ default: ''
112
137
  },
113
- // 用于显示图片小图标时,图片的宽度
138
+ // 显示图片小图标时的宽度
114
139
  width: {
115
140
  type: [String, Number],
116
- default: () => defProps.getArray('icon.width')
141
+ default: ''
117
142
  },
118
- // 用于显示图片小图标时,图片的高度
143
+ // 显示图片小图标时的高度
119
144
  height: {
120
145
  type: [String, Number],
121
- default: () => defProps.getArray('icon.height')
146
+ default: ''
122
147
  },
123
- // 用于解决某些情况下,让图标垂直居中的用途
148
+ // 图标在垂直方向上的定位 用于解决某些情况下,让图标垂直居中的用途
124
149
  top: {
125
150
  type: [String, Number],
126
- default: () => defProps.getArray('icon.top')
151
+ default: 0
127
152
  },
128
153
  // 是否阻止事件传播
129
154
  stop: {
130
155
  type: Boolean,
131
- default: () => defProps.getBoolean('icon.stop')
132
- }
156
+ default: false
157
+ },
133
158
  })
134
159
 
135
160
  const emit = defineEmits(['click'])
136
-
137
- // 计算属性
138
- const uClasses = computed(() => {
139
- let classes: Array<string> = []
161
+
162
+
163
+ const uClasses = computed(() : string[] => {
164
+ let classes = [] as string[]
140
165
  classes.push(props.customPrefix + '-' + props.name)
141
- // uview-plus的自定义图标类名为up-iconfont
142
166
  if (props.customPrefix == 'upicon') {
143
- classes.push('up-iconfont')
167
+ classes.push('up-icon-custom')
144
168
  } else {
145
- // 不能缺少这一步,否则自定义图标会无效
146
169
  classes.push(props.customPrefix)
147
170
  }
148
- // 主题色,通过类配置。
149
- let types: Array<string>|null = config.getArray('type') as Array<string>
150
- if (props.color.toString() != '' && types != null
151
- && types?.includes(props.color.toString()) as boolean
152
- ) classes.push('up-icon__icon--' + props.color.toString())
153
- // 阿里,头条,百度小程序通过数组绑定类名时,无法直接使用[a, b, c]的形式,否则无法识别
154
- // 故需将其拆成一个字符串的形式,通过空格隔开各个类名
155
- return classes.join(' ')
171
+ // 主题色,通过类配置
172
+ const themes = config['type'] as string[]
173
+ if (props.color != '' && themes.includes(props.color)) {
174
+ classes.push('up-icon__icon--' + props.color)
175
+ }
176
+ return classes
156
177
  })
157
178
 
158
- const iconStyle = computed(() => {
179
+ const iconStyle = computed(() : UTSJSONObject => {
180
+ const themes = config['type'] as string[]
159
181
  let style = {
160
- fontSize: addUnit(props.size.toString()),
161
- lineHeight: addUnit(props.size.toString()),
162
- fontWeight: (props.bold as boolean) ? 'bold' : 'normal',
163
- // 某些特殊情况需要设置一个到顶部的距离,才能更好的垂直居中
182
+ fontSize: addUnit(props.size),
183
+ lineHeight: addUnit(props.size),
184
+ fontWeight: props.bold ? 'bold' : 'normal',
185
+ // 某些特殊情况 need to set a distance to the top to better center vertically
164
186
  top: addUnit(props.top)
165
- }
187
+ } as UTSJSONObject
166
188
  // 非主题色值时,才当作颜色值
167
- let types: Array<string>|null = config.getArray('type') as Array<string>
168
- if (props.color.toString() != '' && types != null && !types.includes(props.color.toString())) {
169
- style['color'] = props.color.toString()
189
+ if (props.color != '' && !themes.includes(props.color)) {
190
+ style['color'] = props.color
170
191
  }
171
-
192
+
172
193
  return style
173
194
  })
174
195
 
175
196
  // 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式
176
- const isImg = computed(() => {
177
- return props.name.toString().indexOf('/') != -1
197
+ const isImg = computed(() : boolean => {
198
+ return props.name.indexOf('/') !== -1
178
199
  })
179
200
 
180
- const imgStyle = computed(() => {
181
- let style = {}
201
+ const imgStyle = computed(() : UTSJSONObject => {
202
+ let style = {} as UTSJSONObject
182
203
  // 如果设置width和height属性,则优先使用,否则使用size属性
183
- style['width'] = props.width != '' ? addUnit(props.width) : addUnit(props.size!!.toString())
184
- style['height'] = props.height != '' ? addUnit(props.height) : addUnit(props.size!!.toString())
204
+ style['width'] = props.width != '' ? addUnit(props.width) : addUnit(props.size)
205
+ style['height'] = props.height != '' ? addUnit(props.height) : addUnit(props.size)
185
206
  return style
186
207
  })
187
208
 
188
209
  // 通过图标名,查找对应的图标
189
- const icon = computed(() => {
210
+ const icon = computed(() : string => {
190
211
  // 使用自定义图标的时候页面上会把name属性也展示出来,所以在这里处理一下
191
212
  if (props.customPrefix !== "upicon") return "";
192
213
  // 如果内置的图标中找不到对应的图标,就直接返回name值,因为用户可能传入的是unicode代码
193
- if (icons['upicon-' + props.name] != null) {
194
- return icons['upicon-' + props.name] as string
214
+ if (generatedIcons[props.name] != null) {
215
+ return generatedIcons[props.name] as string
195
216
  } else {
196
217
  return props.name.toString()
197
218
  }
198
219
  })
220
+
221
+ const isMultiColor = computed(() : boolean => {
222
+ if (iconsSvg[props.name] != null) {
223
+ const item = iconsSvg[props.name] as UTSJSONObject
224
+ if (item['multi'] == true) return true
225
+ }
226
+ const multicolorList = multiColorIcons as string[]
227
+ return multicolorList.includes(props.name)
228
+ })
229
+
230
+ const imgSrc = computed(() : string => {
231
+ // 使用 uni_modules 绝对路径确保在各端加载正常
232
+ return `/uni_modules/uview-ultra/static/uview-ultra/images/${props.name}.svg`
233
+ })
199
234
 
200
235
  // 方法
201
236
  function clickHandler(e: UniPointerEvent) {
202
237
  emit('click', props.index)
203
238
  // 是否阻止事件冒泡
204
- if (props.stop as boolean) {
205
- preventEvent(e)
239
+ if (props.stop) {
240
+ e.stopPropagation()
206
241
  }
207
242
  }
208
243
  </script>
209
244
 
210
245
  <style lang="scss" scoped>
211
- @import "../../libs/css/components.scss";
212
246
 
213
247
  // 变量定义
214
- $up-icon-primary: $up-primary !default;
215
- $up-icon-success: $up-success !default;
216
- $up-icon-info: $up-info !default;
217
- $up-icon-warning: $up-warning !default;
218
- $up-icon-error: $up-error !default;
248
+ $up-icon-primary: #3c9cff !default;
249
+ $up-icon-success: #5ac725 !default;
250
+ $up-icon-info: #909193 !default;
251
+ $up-icon-warning: #f9ae3d !default;
252
+ $up-icon-error: #f56c6c !default;
219
253
  $up-icon-label-line-height:1 !default;
220
254
 
221
255
  .up-icon {
222
256
  display: flex;
223
257
  align-items: center;
224
258
 
259
+ @font-face {
260
+ font-family: 'upicon-custom';
261
+ src: url('../../static/uview-ultra/upicon-custom.ttf') format('truetype');
262
+ }
263
+
225
264
  &--left {
226
265
  flex-direction: row-reverse;
227
266
  align-items: center;
@@ -243,8 +282,8 @@
243
282
  }
244
283
 
245
284
  &__icon {
246
- font-family: iconfont;
247
285
  position: relative;
286
+ font-family: upicon-custom;
248
287
 
249
288
  &--primary {
250
289
  color: $up-icon-primary;