@didaoktv/didaoui-uniapp 1.0.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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +89 -0
  3. package/components/dd-action-sheet/dd-action-sheet.vue +207 -0
  4. package/components/dd-alert/dd-alert.vue +240 -0
  5. package/components/dd-avatar/dd-avatar.vue +168 -0
  6. package/components/dd-backtop/dd-backtop.vue +75 -0
  7. package/components/dd-badge/dd-badge.vue +150 -0
  8. package/components/dd-button/dd-button.vue +215 -0
  9. package/components/dd-capsule-button/dd-capsule-button.vue +109 -0
  10. package/components/dd-card/dd-card.vue +155 -0
  11. package/components/dd-cell/dd-cell.vue +201 -0
  12. package/components/dd-cell-group/dd-cell-group.vue +56 -0
  13. package/components/dd-champion-card/dd-champion-card.vue +258 -0
  14. package/components/dd-checkbox/dd-checkbox.vue +145 -0
  15. package/components/dd-collapse/dd-collapse.vue +63 -0
  16. package/components/dd-collapse-item/dd-collapse-item.vue +154 -0
  17. package/components/dd-count-down/dd-count-down.vue +163 -0
  18. package/components/dd-date-picker/dd-date-picker.vue +253 -0
  19. package/components/dd-dialog/dd-dialog.vue +264 -0
  20. package/components/dd-divider/dd-divider.vue +104 -0
  21. package/components/dd-drawer/dd-drawer.vue +214 -0
  22. package/components/dd-dropdown-item/dd-dropdown-item.vue +203 -0
  23. package/components/dd-dropdown-menu/dd-dropdown-menu.vue +177 -0
  24. package/components/dd-empty-state/dd-empty-state.vue +140 -0
  25. package/components/dd-feature-grid/dd-feature-grid.vue +139 -0
  26. package/components/dd-field/dd-field.vue +240 -0
  27. package/components/dd-icon/dd-icon.vue +464 -0
  28. package/components/dd-image/dd-image.vue +158 -0
  29. package/components/dd-input/dd-input.vue +172 -0
  30. package/components/dd-list-cell/dd-list-cell.vue +152 -0
  31. package/components/dd-loading/dd-loading.vue +187 -0
  32. package/components/dd-loadmore/dd-loadmore.vue +152 -0
  33. package/components/dd-mini-program-navbar/dd-mini-program-navbar.vue +245 -0
  34. package/components/dd-modal/dd-modal.vue +286 -0
  35. package/components/dd-navigation/dd-navigation.vue +134 -0
  36. package/components/dd-overlay/dd-overlay.vue +114 -0
  37. package/components/dd-picker/dd-picker.vue +203 -0
  38. package/components/dd-popover/dd-popover.vue +190 -0
  39. package/components/dd-popover-item/dd-popover-item.vue +88 -0
  40. package/components/dd-popup/dd-popup.vue +243 -0
  41. package/components/dd-progress/dd-progress.vue +255 -0
  42. package/components/dd-pull-refresh/dd-pull-refresh.vue +232 -0
  43. package/components/dd-radio/dd-radio.vue +129 -0
  44. package/components/dd-rate/dd-rate.vue +133 -0
  45. package/components/dd-room-card/dd-room-card.vue +309 -0
  46. package/components/dd-search-bar/dd-search-bar.vue +176 -0
  47. package/components/dd-segmented-tab/dd-segmented-tab.vue +187 -0
  48. package/components/dd-skeleton/dd-skeleton.vue +184 -0
  49. package/components/dd-slider/dd-slider.vue +227 -0
  50. package/components/dd-stat-card/dd-stat-card.vue +174 -0
  51. package/components/dd-step/dd-step.vue +188 -0
  52. package/components/dd-stepper/dd-stepper.vue +171 -0
  53. package/components/dd-steps/dd-steps.vue +61 -0
  54. package/components/dd-sticky/dd-sticky.vue +132 -0
  55. package/components/dd-swipe/dd-swipe.vue +146 -0
  56. package/components/dd-swipe-action/dd-swipe-action.vue +248 -0
  57. package/components/dd-swipe-item/dd-swipe-item.vue +27 -0
  58. package/components/dd-swipeable-tab/dd-swipeable-tab.vue +202 -0
  59. package/components/dd-switch/dd-switch.vue +106 -0
  60. package/components/dd-tabbar/dd-tabbar.vue +112 -0
  61. package/components/dd-tabbar-item/dd-tabbar-item.vue +122 -0
  62. package/components/dd-tag/dd-tag.vue +178 -0
  63. package/components/dd-toast/dd-toast.vue +195 -0
  64. package/components/dd-top-navbar/dd-top-navbar.vue +184 -0
  65. package/components/dd-upload/dd-upload.vue +187 -0
  66. package/index.ts +127 -0
  67. package/libs/utils.ts +106 -0
  68. package/package.json +58 -0
  69. package/scss/_functions.scss +68 -0
  70. package/scss/_mixins.scss +154 -0
  71. package/scss/_reset.scss +30 -0
  72. package/scss/_variables.scss +317 -0
  73. package/uni.scss +4 -0
@@ -0,0 +1,232 @@
1
+ <template>
2
+ <view class="dd-pull-refresh">
3
+ <view
4
+ class="dd-pull-refresh__track"
5
+ :class="{ 'dd-pull-refresh__track--anim': !pulling }"
6
+ :style="{ transform: `translateY(${distance}px)` }"
7
+ >
8
+ <view class="dd-pull-refresh__head" :style="{ height: headHeightPx + 'px' }">
9
+ <view class="dd-pull-refresh__head-inner">
10
+ <view v-if="status === 'loading'" class="dd-pull-refresh__spinner"></view>
11
+ <text class="dd-pull-refresh__text">{{ statusText }}</text>
12
+ </view>
13
+ </view>
14
+ <scroll-view
15
+ class="dd-pull-refresh__scroll"
16
+ scroll-y
17
+ :scroll-top="scrollTop"
18
+ :lower-threshold="lowerThresholdPx"
19
+ :style="{ height: '100%' }"
20
+ @scroll="onScroll"
21
+ @scrolltolower="onScrollToLower"
22
+ @touchstart="onTouchStart"
23
+ @touchmove="onTouchMove"
24
+ @touchend="onTouchEnd"
25
+ @touchcancel="onTouchEnd"
26
+ >
27
+ <slot></slot>
28
+ </scroll-view>
29
+ </view>
30
+ </view>
31
+ </template>
32
+
33
+ <script setup lang="ts">
34
+ import { computed, ref, watch } from 'vue'
35
+
36
+ type Status = 'pulling' | 'loosing' | 'loading' | 'success'
37
+
38
+ interface Props {
39
+ modelValue?: boolean
40
+ headHeight?: number // rpx
41
+ pullingText?: string
42
+ loosingText?: string
43
+ loadingText?: string
44
+ successText?: string
45
+ successDuration?: number
46
+ damping?: number
47
+ lowerThreshold?: number // rpx,距底部小于该值触发 loadmore
48
+ }
49
+
50
+ const props = withDefaults(defineProps<Props>(), {
51
+ modelValue: false,
52
+ headHeight: 100,
53
+ pullingText: '下拉即可刷新...',
54
+ loosingText: '释放即可刷新...',
55
+ loadingText: '加载中...',
56
+ successText: '',
57
+ successDuration: 500,
58
+ damping: 0.5,
59
+ lowerThreshold: 100,
60
+ })
61
+
62
+ const emit = defineEmits<{
63
+ (e: 'update:modelValue', val: boolean): void
64
+ (e: 'refresh'): void
65
+ (e: 'loadmore'): void
66
+ }>()
67
+
68
+ const distance = ref(0)
69
+ const pulling = ref(false)
70
+ const status = ref<Status>('pulling')
71
+ const scrollTop = ref(0)
72
+
73
+ let startY = 0
74
+ let startTop = 0
75
+ let successTimer: ReturnType<typeof setTimeout> | null = null
76
+
77
+ function rpxToPx(rpx: number): number {
78
+ try {
79
+ const info = uni.getWindowInfo()
80
+ return (rpx / 750) * info.windowWidth
81
+ } catch {
82
+ return rpx / 2
83
+ }
84
+ }
85
+
86
+ const headHeightPx = computed(() => rpxToPx(props.headHeight))
87
+ const maxStretchPx = computed(() => headHeightPx.value * 1.5)
88
+ const lowerThresholdPx = computed(() => rpxToPx(props.lowerThreshold))
89
+
90
+ const statusText = computed(() => {
91
+ switch (status.value) {
92
+ case 'pulling': return props.pullingText
93
+ case 'loosing': return props.loosingText
94
+ case 'loading': return props.loadingText
95
+ case 'success': return props.successText || props.pullingText
96
+ default: return props.pullingText
97
+ }
98
+ })
99
+
100
+ function onScroll(e: any) {
101
+ scrollTop.value = e?.detail?.scrollTop ?? 0
102
+ }
103
+
104
+ function onScrollToLower() {
105
+ emit('loadmore')
106
+ }
107
+
108
+ function onTouchStart(e: any) {
109
+ if (props.modelValue) return
110
+ if (scrollTop.value > 0) return
111
+ pulling.value = true
112
+ startY = e.touches?.[0]?.clientY ?? 0
113
+ startTop = scrollTop.value
114
+ }
115
+
116
+ function onTouchMove(e: any) {
117
+ if (!pulling.value || props.modelValue) return
118
+ const y = e.touches?.[0]?.clientY ?? 0
119
+ let delta = y - startY
120
+ if (delta <= 0) {
121
+ distance.value = 0
122
+ return
123
+ }
124
+ // 阻止页面跟随滚动
125
+ if (e.preventDefault) e.preventDefault()
126
+ if (e.stopPropagation) e.stopPropagation()
127
+ // 0.5 阻尼,封顶 1.5x headHeight
128
+ let d = delta * props.damping
129
+ if (d > maxStretchPx.value) d = maxStretchPx.value
130
+ distance.value = d
131
+ status.value = d >= headHeightPx.value ? 'loosing' : 'pulling'
132
+ }
133
+
134
+ function onTouchEnd() {
135
+ if (!pulling.value) return
136
+ pulling.value = false
137
+ if (distance.value >= headHeightPx.value) {
138
+ // 触发刷新
139
+ distance.value = headHeightPx.value
140
+ status.value = 'loading'
141
+ emit('update:modelValue', true)
142
+ emit('refresh')
143
+ } else {
144
+ distance.value = 0
145
+ status.value = 'pulling'
146
+ }
147
+ }
148
+
149
+ // modelValue 驱动 loading 锁与 success 反馈序列
150
+ watch(
151
+ () => props.modelValue,
152
+ (val) => {
153
+ if (val) {
154
+ distance.value = headHeightPx.value
155
+ status.value = 'loading'
156
+ } else {
157
+ if (props.successText) {
158
+ status.value = 'success'
159
+ if (successTimer) clearTimeout(successTimer)
160
+ successTimer = setTimeout(() => {
161
+ distance.value = 0
162
+ status.value = 'pulling'
163
+ }, props.successDuration)
164
+ } else {
165
+ distance.value = 0
166
+ status.value = 'pulling'
167
+ }
168
+ }
169
+ }
170
+ )
171
+ </script>
172
+
173
+ <style lang="scss" scoped>
174
+ @import '../../scss/variables';
175
+ @import '../../scss/mixins';
176
+
177
+ .dd-pull-refresh {
178
+ position: relative;
179
+ height: 100%;
180
+ overflow: hidden;
181
+
182
+ &__track {
183
+ position: relative;
184
+ height: 100%;
185
+ z-index: 1;
186
+ background: $dd-bg;
187
+
188
+ &--anim {
189
+ transition: transform 300ms ease;
190
+ }
191
+ }
192
+
193
+ &__head {
194
+ position: absolute;
195
+ top: 0;
196
+ left: 0;
197
+ right: 0;
198
+ overflow: hidden;
199
+ transform: translateY(-100%);
200
+ z-index: 0;
201
+ }
202
+
203
+ &__head-inner {
204
+ height: 100%;
205
+ @include dd-flex-center;
206
+ gap: 16rpx;
207
+ }
208
+
209
+ &__spinner {
210
+ width: 32rpx;
211
+ height: 32rpx;
212
+ border: 4rpx solid $dd-border-default;
213
+ border-top-color: $dd-primary-500;
214
+ border-radius: 50%;
215
+ animation: dd-pr-spin 0.8s linear infinite;
216
+ }
217
+
218
+ &__text {
219
+ font-size: $dd-font-size-body;
220
+ color: $dd-text-tertiary;
221
+ }
222
+
223
+ &__scroll {
224
+ width: 100%;
225
+ overscroll-behavior-y: contain;
226
+ }
227
+ }
228
+
229
+ @keyframes dd-pr-spin {
230
+ to { transform: rotate(360deg); }
231
+ }
232
+ </style>
@@ -0,0 +1,129 @@
1
+ <template>
2
+ <view
3
+ class="dd-radio"
4
+ :class="[
5
+ `dd-radio--${size}`,
6
+ {
7
+ 'dd-radio--checked': isChecked,
8
+ 'dd-radio--disabled': disabled,
9
+ },
10
+ ]"
11
+ @click="onToggle"
12
+ >
13
+ <view class="dd-radio__outer">
14
+ <view class="dd-radio__inner"></view>
15
+ </view>
16
+ <text v-if="label || $slots.default" class="dd-radio__label">
17
+ <slot>{{ label }}</slot>
18
+ </text>
19
+ </view>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { computed } from 'vue'
24
+
25
+ interface Props {
26
+ modelValue?: any
27
+ value?: any
28
+ disabled?: boolean
29
+ size?: 'md' | 'sm'
30
+ label?: string
31
+ }
32
+
33
+ const props = withDefaults(defineProps<Props>(), {
34
+ modelValue: null,
35
+ value: null,
36
+ disabled: false,
37
+ size: 'md',
38
+ label: '',
39
+ })
40
+
41
+ const emit = defineEmits<{
42
+ (e: 'update:modelValue', val: any): void
43
+ (e: 'change', val: any): void
44
+ }>()
45
+
46
+ const isChecked = computed(() => props.modelValue === props.value)
47
+
48
+ function onToggle() {
49
+ if (props.disabled) return
50
+ if (isChecked.value) return
51
+ emit('update:modelValue', props.value)
52
+ emit('change', props.value)
53
+ }
54
+ </script>
55
+
56
+ <style lang="scss" scoped>
57
+ @import '../../scss/variables';
58
+ @import '../../scss/mixins';
59
+
60
+ .dd-radio {
61
+ display: inline-flex;
62
+ align-items: center;
63
+ gap: 16rpx;
64
+ user-select: none;
65
+
66
+ &__outer {
67
+ @include dd-flex-center;
68
+ flex-shrink: 0;
69
+ border-radius: $dd-radius-full;
70
+ border: 3rpx solid $dd-neutral-700;
71
+ background: transparent;
72
+ box-sizing: border-box;
73
+ @include dd-transition(all 0.2s);
74
+ }
75
+
76
+ &__inner {
77
+ border-radius: 50%;
78
+ background: #ffffff;
79
+ transform: scale(0);
80
+ opacity: 0;
81
+ @include dd-transition(transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.3s);
82
+ }
83
+
84
+ &__label {
85
+ font-size: 28rpx;
86
+ color: $dd-text-primary;
87
+ }
88
+
89
+ &--checked .dd-radio__outer {
90
+ background: $dd-gradient-primary;
91
+ border-color: $dd-primary-500;
92
+ box-shadow: $dd-shadow-glow-gold-lg;
93
+ }
94
+
95
+ &--checked .dd-radio__inner {
96
+ transform: scale(1);
97
+ opacity: 1;
98
+ }
99
+
100
+ &--disabled {
101
+ opacity: 0.4;
102
+ @include dd-no-touch;
103
+ }
104
+ }
105
+
106
+ .dd-radio--md {
107
+ .dd-radio__outer {
108
+ width: 40rpx;
109
+ height: 40rpx;
110
+ }
111
+ .dd-radio__inner {
112
+ width: 20rpx;
113
+ height: 20rpx;
114
+ }
115
+ }
116
+ .dd-radio--sm {
117
+ .dd-radio__outer {
118
+ width: 32rpx;
119
+ height: 32rpx;
120
+ }
121
+ .dd-radio__inner {
122
+ width: 14rpx;
123
+ height: 14rpx;
124
+ }
125
+ .dd-radio__label {
126
+ font-size: 28rpx;
127
+ }
128
+ }
129
+ </style>
@@ -0,0 +1,133 @@
1
+ <template>
2
+ <view class="dd-rate" :class="{ 'dd-rate--readonly': readonly, 'dd-rate--disabled': disabled }">
3
+ <view
4
+ v-for="i in count"
5
+ :key="i"
6
+ class="dd-rate__item"
7
+ :style="{ width: starSize, height: starSize }"
8
+ >
9
+ <dd-icon name="star" class="dd-rate__void" :style="{ fontSize: starSize, color: voidColor }" />
10
+ <view class="dd-rate__fill" :style="{ width: fillPercent(i) + '%' }">
11
+ <dd-icon name="star" class="dd-rate__star" :style="{ fontSize: starSize, color: fullColor, width: starSize }" />
12
+ </view>
13
+ <view v-if="!readonly && !disabled" class="dd-rate__hit">
14
+ <template v-if="allowHalf">
15
+ <view class="dd-rate__hit-left" @click="select(i - 0.5)"></view>
16
+ <view class="dd-rate__hit-right" @click="select(i)"></view>
17
+ </template>
18
+ <view v-else class="dd-rate__hit-full" @click="select(i)"></view>
19
+ </view>
20
+ </view>
21
+ </view>
22
+ </template>
23
+
24
+ <script setup lang="ts">
25
+ import { computed } from 'vue'
26
+
27
+ interface Props {
28
+ modelValue?: number
29
+ count?: number
30
+ size?: number
31
+ allowHalf?: boolean
32
+ readonly?: boolean
33
+ disabled?: boolean
34
+ color?: string
35
+ voidColor?: string
36
+ }
37
+
38
+ const props = withDefaults(defineProps<Props>(), {
39
+ modelValue: 0,
40
+ count: 5,
41
+ size: 20,
42
+ allowHalf: false,
43
+ readonly: false,
44
+ disabled: false,
45
+ color: '',
46
+ voidColor: '',
47
+ })
48
+
49
+ const emit = defineEmits<{
50
+ (e: 'update:modelValue', val: number): void
51
+ (e: 'change', val: number): void
52
+ }>()
53
+
54
+ const starSize = computed(() => props.size * 2 + 'rpx')
55
+ const fullColor = computed(() => props.color || '#F5A623')
56
+ const voidColor = computed(() => props.voidColor || '#2A2A2A')
57
+
58
+ function fillPercent(i: number) {
59
+ const v = props.modelValue
60
+ if (v >= i) return 100
61
+ if (props.allowHalf && v >= i - 0.5) return 50
62
+ return 0
63
+ }
64
+
65
+ function select(val: number) {
66
+ if (props.readonly || props.disabled) return
67
+ emit('update:modelValue', val)
68
+ emit('change', val)
69
+ }
70
+ </script>
71
+
72
+ <style lang="scss" scoped>
73
+ @import '../../scss/variables';
74
+ @import '../../scss/mixins';
75
+
76
+ .dd-rate {
77
+ display: inline-flex;
78
+ align-items: center;
79
+ gap: 8rpx;
80
+
81
+ &__item {
82
+ position: relative;
83
+ display: inline-flex;
84
+ align-items: center;
85
+ justify-content: center;
86
+ font-family: serif;
87
+ }
88
+
89
+ &__void {
90
+ line-height: 1;
91
+ }
92
+
93
+ &__fill {
94
+ position: absolute;
95
+ left: 0;
96
+ top: 0;
97
+ height: 100%;
98
+ overflow: hidden;
99
+ pointer-events: none;
100
+ }
101
+
102
+ &__star {
103
+ display: block;
104
+ line-height: 1;
105
+ white-space: nowrap;
106
+ }
107
+
108
+ &__hit {
109
+ position: absolute;
110
+ inset: 0;
111
+ display: flex;
112
+ }
113
+ &__hit-left,
114
+ &__hit-right,
115
+ &__hit-full {
116
+ height: 100%;
117
+ }
118
+ &__hit-left {
119
+ width: 50%;
120
+ }
121
+ &__hit-right {
122
+ width: 50%;
123
+ }
124
+ &__hit-full {
125
+ width: 100%;
126
+ }
127
+
128
+ &--disabled {
129
+ opacity: 0.4;
130
+ @include dd-no-touch;
131
+ }
132
+ }
133
+ </style>