tang-ui-x 1.1.4 → 1.1.6

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.
@@ -5,6 +5,7 @@
5
5
  import TSwitch from '../TSwitch/index.uvue'
6
6
  import TRate from '../TRate/index.uvue'
7
7
  import TSlider from '../TSlider/index.uvue'
8
+ import TSelect from '../TSelect/index.uvue'
8
9
  import type { FormOption, FormSchema, TFormProps, ComponentProps } from './type.uts'
9
10
  import { useI18n } from '../../composables/useI18n.uts'
10
11
 
@@ -52,23 +53,9 @@
52
53
  return $t('form.inputPlaceholder', { label: item.label })
53
54
  }
54
55
 
55
- const handleRange = (item : FormSchema) => {
56
+ const getSelectOptions = (item : FormSchema) => {
56
57
  const options = item.componentProps?.options as FormOption[] | undefined
57
- return options?.map(o => o.label) || []
58
- }
59
-
60
- const getSelectLabel = (item : FormSchema) => {
61
- const options = item.componentProps?.options as FormOption[] | undefined
62
- const opt = options?.find(o => o.value === model.value[item.field])
63
- return opt?.label || ''
64
- }
65
-
66
- const onSelectChange = (e : any, item : FormSchema) => {
67
- const index = e.detail.value as number
68
- const options = item.componentProps?.options as FormOption[] | undefined
69
- const value = options?.[index]?.value ?? ''
70
- model.value[item.field] = value
71
- validateField(item)
58
+ return options?.map(o => ({ label: o.label, value: o.value })) || []
72
59
  }
73
60
 
74
61
  const onTimeChange = (e : any, item : FormSchema) => {
@@ -79,11 +66,23 @@
79
66
  const validateField = (item : FormSchema) => {
80
67
  if (item.required && !model.value[item.field]) {
81
68
  errors[item.field] = $t('form.requiredError', { label: item.label })
69
+ // 触发抖动动画
70
+ triggerShake(item.field)
82
71
  } else {
83
72
  delete errors[item.field]
84
73
  }
85
74
  }
86
75
 
76
+ // 抖动动画状态
77
+ const shakeFields = reactive<Record<string, boolean>>({})
78
+
79
+ const triggerShake = (field : string) => {
80
+ shakeFields[field] = true
81
+ setTimeout(() => {
82
+ shakeFields[field] = false
83
+ }, 500)
84
+ }
85
+
87
86
  const onRadioChange = (value : string | number) => {
88
87
  // 值已通过 v-model 更新,只需验证
89
88
  }
@@ -164,7 +163,9 @@
164
163
  <template>
165
164
  <view class="t-form">
166
165
  <form @submit="onFormSubmit" @reset="onFormReset">
167
- <view v-for="(item, index) in schemas" class="form-item" :key="index">
166
+ <view v-for="(item, index) in schemas" class="form-item"
167
+ :class="{ 'form-item-error': errors[item.field], 'form-item-shake': shakeFields[item.field] }"
168
+ :key="index">
168
169
  <view class="form-item-content" :class="`form-item--${getItemLayout(item)}`">
169
170
  <view class="form-label" >
170
171
  <text class="text" :style="{ width: getItemLayout(item) === 'horizontal' ? getItemLabelWidth(item) : labelWidth }">{{ item.label }}</text>
@@ -192,13 +193,12 @@
192
193
  v-bind="item.componentProps || {}" @input="validateField(item)"></textarea>
193
194
 
194
195
  <!-- 下拉选择 -->
195
- <picker v-else-if="item.component === 'Select'" mode="selector" :name="item.field"
196
- :range="handleRange(item)" v-bind="item.componentProps || {}"
197
- @change="onSelectChange($event, item)">
198
- <view class="picker">
199
- {{ getSelectLabel(item) || $t('form.selectPlaceholder') }}
200
- </view>
201
- </picker>
196
+ <TSelect v-else-if="item.component === 'Select'"
197
+ v-model="model[item.field]"
198
+ :options="getSelectOptions(item)"
199
+ :placeholder="item.componentProps?.placeholder || $t('form.selectPlaceholder')"
200
+ v-bind="item.componentProps || {}"
201
+ @change="validateField(item)" />
202
202
 
203
203
  <!-- 日期选择 -->
204
204
  <picker v-else-if="item.component === 'Date'" mode="date" :name="item.field"
@@ -245,7 +245,7 @@
245
245
 
246
246
  <!-- 错误提示 -->
247
247
  <view v-if="errors[item.field]" class="error-message">
248
- <text>{{ errors[item.field] }}</text>
248
+ <text class="error-text">{{ errors[item.field] }}</text>
249
249
  </view>
250
250
  </view>
251
251
 
@@ -264,10 +264,36 @@
264
264
  }
265
265
 
266
266
  .form-item {
267
- margin-bottom: 32rpx;
267
+ padding: 24rpx;
268
+ border-radius: 12rpx;
269
+ border: 2rpx solid transparent;
270
+ transition: all 0.3s ease;
271
+ overflow:visible;
272
+
273
+ &.form-item-error {
274
+ border-color: #ff4d4f;
275
+ background-color: #fff1f0;
276
+ }
277
+
278
+ &.form-item-shake {
279
+ animation: shake 0.5s ease-in-out;
280
+ }
281
+ }
282
+
283
+ @keyframes shake {
284
+ 0%, 100% {
285
+ transform: translateX(0);
286
+ }
287
+ 10%, 30%, 50%, 70%, 90% {
288
+ transform: translateX(-8rpx);
289
+ }
290
+ 20%, 40%, 60%, 80% {
291
+ transform: translateX(8rpx);
292
+ }
268
293
  }
269
294
 
270
295
  .form-item-content {
296
+ overflow:visible;
271
297
  &.form-item--horizontal {
272
298
  display: flex;
273
299
  flex-direction: row;
@@ -317,6 +343,7 @@
317
343
  .form-control {
318
344
  flex: 1;
319
345
  width: 100%;
346
+ overflow: visible;
320
347
 
321
348
  .form-item-content.form-item--horizontal & {
322
349
  width: auto;
@@ -324,8 +351,7 @@
324
351
  }
325
352
 
326
353
  .input,
327
- .textarea,
328
- .picker {
354
+ .textarea {
329
355
  width: 100%;
330
356
  padding: 20rpx 24rpx;
331
357
  font-size: 28rpx;
@@ -346,13 +372,6 @@
346
372
  min-height: 120rpx;
347
373
  }
348
374
 
349
- .picker {
350
- display: flex;
351
- align-items: center;
352
- }
353
-
354
-
355
-
356
375
  .error-message {
357
376
  margin-top: 8rpx;
358
377
  font-size: 24rpx;
@@ -306,14 +306,11 @@
306
306
 
307
307
 
308
308
  /* 基础容器样式 */
309
- .select-root,
310
- uni-view {
311
- overflow: visible;
312
- }
313
-
309
+
314
310
  .select-container {
315
311
  position: relative;
316
312
  width: 100%;
313
+ overflow: visible;
317
314
  }
318
315
 
319
316
  /* 选择框样式 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tang-ui-x",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "UniApp X UI 组件库 - 基于 uni-app x 的移动端 UI 组件库",
5
5
  "main": "index.uts",
6
6
  "module": "index.uts",
package/style/index.scss CHANGED
@@ -137,9 +137,9 @@ $z-index-toast: 1080 !default;
137
137
  visibility: hidden !important;
138
138
  }
139
139
 
140
- uni-view {
141
- overflow: visible;
142
- }
140
+ // uni-view {
141
+ // overflow: visible;
142
+ // }
143
143
 
144
144
  // Flex 布局
145
145
  .flex {
@@ -232,79 +232,78 @@ uni-view {
232
232
  }
233
233
 
234
234
  // 字体大小
235
- @each $name, $size in (
236
- 'xs': $font-size-xs,
235
+ @each $name, $size in ('xs': $font-size-xs,
237
236
  'sm': $font-size-sm,
238
237
  'base': $font-size-base,
239
238
  'md': $font-size-md,
240
239
  'lg': $font-size-lg,
241
240
  'xl': $font-size-xl,
242
- 'xxl': $font-size-xxl
243
- ) {
241
+ 'xxl': $font-size-xxl) {
244
242
  .text-#{$name} {
245
243
  font-size: $size !important;
246
244
  }
247
245
  }
248
246
 
249
247
  // 字体粗细
250
- @each $name, $weight in (
251
- 'light': $font-weight-light,
248
+ @each $name, $weight in ('light': $font-weight-light,
252
249
  'normal': $font-weight-normal,
253
250
  'medium': $font-weight-medium,
254
251
  'semibold': $font-weight-semibold,
255
- 'bold': $font-weight-bold
256
- ) {
252
+ 'bold': $font-weight-bold) {
257
253
  .font-#{$name} {
258
254
  font-weight: $weight !important;
259
255
  }
260
256
  }
261
257
 
262
258
  // 圆角
263
- @each $name, $radius in (
264
- 'none': $border-radius-none,
259
+ @each $name, $radius in ('none': $border-radius-none,
265
260
  'sm': $border-radius-sm,
266
261
  'base': $border-radius-base,
267
262
  'md': $border-radius-md,
268
263
  'lg': $border-radius-lg,
269
264
  'xl': $border-radius-xl,
270
- 'full': $border-radius-full
271
- ) {
265
+ 'full': $border-radius-full) {
272
266
  .rounded-#{$name} {
273
267
  border-radius: $radius !important;
274
268
  }
275
269
  }
276
270
 
277
271
  // 间距(内边距和外边距)
278
- @each $name, $space in (
279
- 'xs': $spacing-xs,
272
+ @each $name, $space in ('xs': $spacing-xs,
280
273
  'sm': $spacing-sm,
281
274
  'base': $spacing-base,
282
275
  'md': $spacing-md,
283
276
  'lg': $spacing-lg,
284
277
  'xl': $spacing-xl,
285
- 'xxl': $spacing-xxl
286
- ) {
278
+ 'xxl': $spacing-xxl) {
279
+
287
280
  // 内边距
288
281
  .p-#{$name} {
289
282
  padding: $space !important;
290
283
  }
284
+
291
285
  .px-#{$name} {
292
286
  padding-left: $space !important;
293
287
  padding-right: $space !important;
294
288
  }
289
+
295
290
  .py-#{$name} {
296
291
  padding-top: $space !important;
297
292
  padding-bottom: $space !important;
298
293
  }
294
+
299
295
  .pt-#{$name} {
300
296
  padding-top: $space !important;
301
297
  }
298
+
302
299
  .pr-#{$name} {
303
300
  padding-right: $space !important;
304
301
  }
302
+
305
303
  .pb-#{$name} {
306
304
  padding-bottom: $space !important;
307
305
  }
306
+
308
307
  .pl-#{$name} {
309
308
  padding-left: $space !important;
310
309
  }
@@ -313,23 +312,29 @@ uni-view {
313
312
  .m-#{$name} {
314
313
  margin: $space !important;
315
314
  }
315
+
316
316
  .mx-#{$name} {
317
317
  margin-left: $space !important;
318
318
  margin-right: $space !important;
319
319
  }
320
+
320
321
  .my-#{$name} {
321
322
  margin-top: $space !important;
322
323
  margin-bottom: $space !important;
323
324
  }
325
+
324
326
  .mt-#{$name} {
325
327
  margin-top: $space !important;
326
328
  }
329
+
327
330
  .mr-#{$name} {
328
331
  margin-right: $space !important;
329
332
  }
333
+
330
334
  .mb-#{$name} {
331
335
  margin-bottom: $space !important;
332
336
  }
337
+
333
338
  .ml-#{$name} {
334
339
  margin-left: $space !important;
335
340
  }
@@ -373,13 +378,11 @@ uni-view {
373
378
  }
374
379
 
375
380
  // 阴影
376
- @each $name, $shadow in (
377
- 'sm': $shadow-sm,
381
+ @each $name, $shadow in ('sm': $shadow-sm,
378
382
  'base': $shadow-base,
379
383
  'md': $shadow-md,
380
384
  'lg': $shadow-lg,
381
- 'xl': $shadow-xl
382
- ) {
385
+ 'xl': $shadow-xl) {
383
386
  .shadow-#{$name} {
384
387
  box-shadow: $shadow !important;
385
388
  }