@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,253 @@
1
+ <template>
2
+ <view class="dd-dp" :class="{ 'dd-dp--open': show }">
3
+ <view class="dd-dp__mask" @click="onMaskClick"></view>
4
+ <view class="dd-dp__sheet">
5
+ <view class="dd-dp__toolbar">
6
+ <text class="dd-dp__cancel" @click="onCancel">取消</text>
7
+ <text class="dd-dp__title">{{ title }}</text>
8
+ <text class="dd-dp__confirm" @click="onConfirm">确定</text>
9
+ </view>
10
+ <picker-view
11
+ class="dd-dp__wheels"
12
+ :value="indexes"
13
+ :indicator-style="indicatorStyle"
14
+ @change="onPickerChange"
15
+ >
16
+ <picker-view-column v-for="(col, ci) in columns" :key="ci">
17
+ <view v-for="(item, ii) in col" :key="ii" class="dd-dp__item">
18
+ <text class="dd-dp__item-text">{{ item }}</text>
19
+ </view>
20
+ </picker-view-column>
21
+ </picker-view>
22
+ </view>
23
+ </view>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { computed, ref, watch } from 'vue'
28
+
29
+ interface Props {
30
+ show?: boolean
31
+ type?: 'date' | 'time' | 'datetime' | 'range'
32
+ modelValue?: string
33
+ title?: string
34
+ }
35
+
36
+ const props = withDefaults(defineProps<Props>(), {
37
+ show: false,
38
+ type: 'date',
39
+ modelValue: '',
40
+ title: '选择日期',
41
+ })
42
+
43
+ const emit = defineEmits<{
44
+ (e: 'update:modelValue', val: string): void
45
+ (e: 'update:show', val: boolean): void
46
+ (e: 'confirm', val: string): void
47
+ (e: 'cancel'): void
48
+ }>()
49
+
50
+ // ponytail: 年份范围固定为当前年±10 年;range 类型按单日期格式输出(规格声明未完整实现)
51
+ const currentYear = new Date().getFullYear()
52
+ const startYear = currentYear - 10
53
+ const endYear = currentYear + 10
54
+
55
+ const indicatorStyle =
56
+ 'height:80rpx;background:rgba(255,193,7,0.08);border-top:1px solid rgba(255,193,7,0.3);border-bottom:1px solid rgba(255,193,7,0.3);box-shadow:0 0 20rpx rgba(255,193,7,0.15);'
57
+
58
+ const indexes = ref<number[]>([])
59
+
60
+ const yearList = computed(() => {
61
+ const arr: string[] = []
62
+ for (let y = startYear; y <= endYear; y++) arr.push(`${y}年`)
63
+ return arr
64
+ })
65
+ const monthList = Array.from({ length: 12 }, (_, i) => `${i + 1}月`)
66
+ const hourList = Array.from({ length: 24 }, (_, i) => `${i}时`)
67
+ const minuteList = Array.from({ length: 60 }, (_, i) => `${i}分`)
68
+
69
+ function daysInMonth(y: number, m: number) {
70
+ return new Date(y, m, 0).getDate()
71
+ }
72
+ function dayListFor(y: number, m: number) {
73
+ return Array.from({ length: daysInMonth(y, m) }, (_, i) => `${i + 1}日`)
74
+ }
75
+
76
+ const columns = computed<string[][]>(() => {
77
+ const y = startYear + (indexes.value[0] ?? 0)
78
+ const m = (indexes.value[1] ?? 0) + 1
79
+ switch (props.type) {
80
+ case 'time':
81
+ return [hourList, minuteList]
82
+ case 'datetime':
83
+ return [yearList.value, monthList, dayListFor(y, m), hourList, minuteList]
84
+ case 'range':
85
+ case 'date':
86
+ default:
87
+ return [yearList.value, monthList, dayListFor(y, m)]
88
+ }
89
+ })
90
+
91
+ function parseValue(val: string) {
92
+ const now = new Date()
93
+ const base = {
94
+ y: now.getFullYear(),
95
+ m: now.getMonth() + 1,
96
+ d: now.getDate(),
97
+ h: now.getHours(),
98
+ min: now.getMinutes(),
99
+ }
100
+ if (!val) return base
101
+ try {
102
+ if (props.type === 'time') {
103
+ const [h, min] = val.split(':').map(Number)
104
+ return { ...base, h: h || 0, min: min || 0 }
105
+ }
106
+ const [datePart, timePart] = val.split(' ')
107
+ const [y, m, d] = datePart.split('-').map(Number)
108
+ let h = base.h
109
+ let min = base.min
110
+ if (timePart && props.type === 'datetime') {
111
+ const [hh, mm] = timePart.split(':').map(Number)
112
+ h = hh || 0
113
+ min = mm || 0
114
+ }
115
+ return { y: y || base.y, m: m || 1, d: d || 1, h, min }
116
+ } catch {
117
+ return base
118
+ }
119
+ }
120
+
121
+ function initIndexes() {
122
+ const p = parseValue(String(props.modelValue ?? ''))
123
+ const yi = Math.max(0, yearList.value.indexOf(`${p.y}年`))
124
+ const mi = Math.max(0, p.m - 1)
125
+ const di = Math.max(0, p.d - 1)
126
+ if (props.type === 'time') indexes.value = [p.h, p.min]
127
+ else if (props.type === 'datetime') indexes.value = [yi, mi, di, p.h, p.min]
128
+ else indexes.value = [yi, mi, di]
129
+ }
130
+
131
+ watch(() => props.show, (v) => {
132
+ if (v) initIndexes()
133
+ })
134
+
135
+ function onPickerChange(e: any) {
136
+ const val = (e?.detail?.value ?? []).slice()
137
+ const dayIdx = props.type === 'date' || props.type === 'range' ? 2 : props.type === 'datetime' ? 3 : -1
138
+ if (dayIdx >= 0) {
139
+ const y = startYear + (val[0] ?? 0)
140
+ const m = (val[1] ?? 0) + 1
141
+ const maxDay = daysInMonth(y, m)
142
+ if ((val[dayIdx] ?? 0) > maxDay - 1) {
143
+ val[dayIdx] = maxDay - 1
144
+ }
145
+ }
146
+ indexes.value = val
147
+ }
148
+
149
+ function buildOutput() {
150
+ const v = indexes.value
151
+ const pad = (n: number) => String(n).padStart(2, '0')
152
+ if (props.type === 'time') return `${pad(v[0] ?? 0)}:${pad(v[1] ?? 0)}`
153
+ const y = startYear + (v[0] ?? 0)
154
+ const m = (v[1] ?? 0) + 1
155
+ const d = (v[2] ?? 0) + 1
156
+ if (props.type === 'datetime') return `${y}-${pad(m)}-${pad(d)} ${pad(v[3] ?? 0)}:${pad(v[4] ?? 0)}`
157
+ return `${y}-${pad(m)}-${pad(d)}`
158
+ }
159
+
160
+ function close() {
161
+ emit('update:show', false)
162
+ }
163
+ function onMaskClick() {
164
+ onCancel()
165
+ }
166
+ function onCancel() {
167
+ emit('cancel')
168
+ close()
169
+ }
170
+ function onConfirm() {
171
+ const out = buildOutput()
172
+ emit('update:modelValue', out)
173
+ emit('confirm', out)
174
+ close()
175
+ }
176
+ </script>
177
+
178
+ <style lang="scss" scoped>
179
+ @import '../../scss/variables';
180
+ @import '../../scss/mixins';
181
+
182
+ :deep(.uni-picker-view-mask) {
183
+ background-image: linear-gradient(180deg, hsl(0deg 0% 9% / 95%), hsl(0deg 0% 9% / 60%)), linear-gradient(0deg, hsl(0deg 0% 9% / 95%), hsl(0deg 0% 9% / 60%));
184
+ }
185
+ .dd-dp {
186
+ &__mask {
187
+ position: fixed;
188
+ inset: 0;
189
+ z-index: $dd-z-index-overlay;
190
+ background: $dd-color-overlay-strong;
191
+ opacity: 0;
192
+ pointer-events: none;
193
+ @include dd-transition(opacity 0.3s);
194
+ }
195
+
196
+ &__sheet {
197
+ position: fixed;
198
+ left: 0;
199
+ right: 0;
200
+ bottom: 0;
201
+ z-index: $dd-z-index-popup;
202
+ background: $dd-neutral-800;
203
+ border-radius: $dd-radius-2xl $dd-radius-2xl 0 0;
204
+ transform: translateY(100%);
205
+ @include dd-transition(transform 0.3s);
206
+ @include dd-safe-area-bottom;
207
+ }
208
+
209
+ &--open &__mask {
210
+ opacity: 1;
211
+ pointer-events: auto;
212
+ }
213
+ &--open &__sheet {
214
+ transform: translateY(0);
215
+ }
216
+
217
+ &__toolbar {
218
+ @include dd-flex-between;
219
+ height: 96rpx;
220
+ padding: 0 32rpx;
221
+ @include dd-hairline-bottom($dd-border-default);
222
+ }
223
+ &__cancel {
224
+ font-size: 28rpx;
225
+ color: $dd-text-secondary;
226
+ }
227
+ &__title {
228
+ font-size: 32rpx;
229
+ font-weight: 600;
230
+ color: $dd-text-primary;
231
+ @include dd-ellipsis(1);
232
+ }
233
+ &__confirm {
234
+ font-size: 28rpx;
235
+ font-weight: 600;
236
+ color: $dd-primary-400;
237
+ }
238
+
239
+ &__wheels {
240
+ width: 100%;
241
+ height: 400rpx;
242
+ }
243
+
244
+ &__item {
245
+ @include dd-flex-center;
246
+ height: 80rpx;
247
+ }
248
+ &__item-text {
249
+ font-size: 32rpx;
250
+ color: $dd-text-primary;
251
+ }
252
+ }
253
+ </style>
@@ -0,0 +1,264 @@
1
+ <template>
2
+ <view class="dd-dialog">
3
+ <view
4
+ class="dd-dialog__mask"
5
+ :class="{ 'dd-dialog__mask--show': modelValue }"
6
+ @click="onOverlayClick"
7
+ ></view>
8
+ <view
9
+ class="dd-dialog__card"
10
+ :class="[{ 'dd-dialog__card--show': modelValue }, `dd-dialog__card--${theme}`]"
11
+ :style="{ width: widthValue, maxWidth: '92vw' }"
12
+ >
13
+ <view v-if="title" class="dd-dialog__header">
14
+ <text class="dd-dialog__title">{{ title }}</text>
15
+ </view>
16
+ <view class="dd-dialog__body" :class="{ 'dd-dialog__body--isolated': !title }">
17
+ <text v-if="message" class="dd-dialog__message">{{ message }}</text>
18
+ <slot v-else></slot>
19
+ </view>
20
+ <view v-if="showConfirmButton || showCancelButton" class="dd-dialog__footer" :class="`dd-dialog__footer--${theme}`">
21
+ <template v-if="theme === 'round-button'">
22
+ <view
23
+ v-if="showCancelButton"
24
+ class="dd-dialog__pill dd-dialog__pill--cancel"
25
+ :style="cancelStyle"
26
+ @click="onCancel"
27
+ >
28
+ <text class="dd-dialog__pill-text">{{ cancelButtonText }}</text>
29
+ </view>
30
+ <view
31
+ v-if="showConfirmButton"
32
+ class="dd-dialog__pill dd-dialog__pill--confirm"
33
+ :style="confirmStyle"
34
+ @click="onConfirm"
35
+ >
36
+ <text class="dd-dialog__pill-text dd-dialog__pill-text--confirm">{{ confirmButtonText }}</text>
37
+ </view>
38
+ </template>
39
+ <template v-else>
40
+ <view
41
+ v-if="showCancelButton"
42
+ class="dd-dialog__btn dd-dialog__btn--cancel"
43
+ @click="onCancel"
44
+ >
45
+ <text class="dd-dialog__btn-text" :style="cancelStyle">{{ cancelButtonText }}</text>
46
+ </view>
47
+ <view
48
+ v-if="showConfirmButton"
49
+ class="dd-dialog__btn dd-dialog__btn--confirm"
50
+ @click="onConfirm"
51
+ >
52
+ <text class="dd-dialog__btn-text" :style="confirmStyle">{{ confirmButtonText }}</text>
53
+ </view>
54
+ </template>
55
+ </view>
56
+ </view>
57
+ </view>
58
+ </template>
59
+
60
+ <script setup lang="ts">
61
+ import { computed } from 'vue'
62
+
63
+ interface Props {
64
+ modelValue?: boolean
65
+ title?: string
66
+ message?: string
67
+ theme?: 'default' | 'round-button'
68
+ showConfirmButton?: boolean
69
+ showCancelButton?: boolean
70
+ confirmButtonText?: string
71
+ cancelButtonText?: string
72
+ confirmColor?: string
73
+ cancelColor?: string
74
+ width?: string | number
75
+ closeOnClickOverlay?: boolean
76
+ }
77
+
78
+ const props = withDefaults(defineProps<Props>(), {
79
+ modelValue: false,
80
+ title: '',
81
+ message: '',
82
+ theme: 'default',
83
+ showConfirmButton: true,
84
+ showCancelButton: false,
85
+ confirmButtonText: '确认',
86
+ cancelButtonText: '取消',
87
+ confirmColor: '',
88
+ cancelColor: '',
89
+ width: '640rpx',
90
+ closeOnClickOverlay: false,
91
+ })
92
+
93
+ const emit = defineEmits<{
94
+ (e: 'update:modelValue', val: boolean): void
95
+ (e: 'confirm'): void
96
+ (e: 'cancel'): void
97
+ (e: 'close'): void
98
+ }>()
99
+
100
+ const widthValue = computed(() =>
101
+ typeof props.width === 'number' ? `${props.width}rpx` : props.width
102
+ )
103
+
104
+ const confirmStyle = computed(() => {
105
+ if (props.theme === 'round-button') {
106
+ return props.confirmColor ? { background: props.confirmColor } : {}
107
+ }
108
+ return props.confirmColor ? { color: props.confirmColor } : {}
109
+ })
110
+
111
+ const cancelStyle = computed(() => {
112
+ if (props.theme === 'round-button') {
113
+ return {}
114
+ }
115
+ return props.cancelColor ? { color: props.cancelColor } : {}
116
+ })
117
+
118
+ function close() {
119
+ emit('update:modelValue', false)
120
+ emit('close')
121
+ }
122
+
123
+ function onOverlayClick() {
124
+ if (!props.closeOnClickOverlay) return
125
+ emit('cancel')
126
+ close()
127
+ }
128
+
129
+ function onConfirm() {
130
+ emit('confirm')
131
+ close()
132
+ }
133
+
134
+ function onCancel() {
135
+ emit('cancel')
136
+ close()
137
+ }
138
+ </script>
139
+
140
+ <style lang="scss" scoped>
141
+ @import '../../scss/variables';
142
+ @import '../../scss/mixins';
143
+
144
+ .dd-dialog {
145
+ &__mask {
146
+ position: fixed;
147
+ inset: 0;
148
+ background: rgba(0, 0, 0, 0.7);
149
+ opacity: 0;
150
+ visibility: hidden;
151
+ z-index: 2000;
152
+ @include dd-transition(opacity 0.3s ease, visibility 0.3s);
153
+
154
+ &--show {
155
+ opacity: 1;
156
+ visibility: visible;
157
+ }
158
+ }
159
+
160
+ &__card {
161
+ position: fixed;
162
+ top: 50%;
163
+ left: 50%;
164
+ transform: translate(-50%, -50%) scale(0.9);
165
+ opacity: 0;
166
+ visibility: hidden;
167
+ z-index: 2001;
168
+ background: $dd-bg-elevated;
169
+ border: 1px solid $dd-border-default;
170
+ border-radius: $dd-radius-lg;
171
+ box-shadow: $dd-shadow-4;
172
+ overflow: hidden;
173
+ @include dd-transition(transform 0.3s ease, opacity 0.3s ease, visibility 0.3s);
174
+
175
+ &--show {
176
+ transform: translate(-50%, -50%) scale(1);
177
+ opacity: 1;
178
+ visibility: visible;
179
+ }
180
+ }
181
+
182
+ &__header {
183
+ padding: $dd-space-5 $dd-space-5 $dd-space-2;
184
+ text-align: center;
185
+ }
186
+
187
+ &__title {
188
+ font-size: $dd-font-size-h4;
189
+ font-weight: $dd-font-weight-h4;
190
+ color: $dd-text-primary;
191
+ line-height: 1.3;
192
+ }
193
+
194
+ &__body {
195
+ padding: $dd-space-2 $dd-space-5 $dd-space-5;
196
+ text-align: center;
197
+
198
+ &--isolated {
199
+ padding-top: $dd-space-5;
200
+ }
201
+ }
202
+
203
+ &__message {
204
+ font-size: $dd-font-size-body;
205
+ color: $dd-text-secondary;
206
+ line-height: $dd-line-height-body;
207
+ }
208
+
209
+ &__footer {
210
+ &--default {
211
+ display: flex;
212
+ border-top: 1px solid $dd-border-subtle;
213
+ }
214
+
215
+ &--round-button {
216
+ display: flex;
217
+ flex-direction: column;
218
+ gap: $dd-space-3;
219
+ padding: 0 $dd-space-5 $dd-space-5;
220
+ }
221
+ }
222
+
223
+ &__btn {
224
+ flex: 1;
225
+ @include dd-flex-center;
226
+ height: 96rpx;
227
+
228
+ &--cancel {
229
+ border-right: 1px solid $dd-border-subtle;
230
+ }
231
+ }
232
+
233
+ &__btn-text {
234
+ font-size: $dd-font-size-body;
235
+ font-weight: 500;
236
+ color: $dd-text-secondary;
237
+ }
238
+
239
+ &__pill {
240
+ height: 80rpx;
241
+ border-radius: $dd-radius-full;
242
+ @include dd-flex-center;
243
+ @include dd-transition(background 0.2s ease);
244
+
245
+ &--cancel {
246
+ background: $dd-surface-container;
247
+ }
248
+
249
+ &--confirm {
250
+ background: $dd-primary-500;
251
+ }
252
+ }
253
+
254
+ &__pill-text {
255
+ font-size: $dd-font-size-body;
256
+ font-weight: 600;
257
+ color: $dd-text-secondary;
258
+
259
+ &--confirm {
260
+ color: $dd-color-white;
261
+ }
262
+ }
263
+ }
264
+ </style>
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <view class="dd-divider" :class="[`dd-divider--${contentPosition}`]">
3
+ <view
4
+ class="dd-divider__line"
5
+ :class="[
6
+ `dd-divider__line--left`,
7
+ `dd-divider__line--${lineStyle}`,
8
+ { 'dd-divider__line--hairline': effectiveHairline },
9
+ ]"
10
+ ></view>
11
+ <view v-if="hasContent" class="dd-divider__content">
12
+ <slot></slot>
13
+ </view>
14
+ <view
15
+ class="dd-divider__line"
16
+ :class="[
17
+ `dd-divider__line--right`,
18
+ `dd-divider__line--${lineStyle}`,
19
+ { 'dd-divider__line--hairline': effectiveHairline },
20
+ ]"
21
+ ></view>
22
+ </view>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import { computed, useSlots } from 'vue'
27
+
28
+ interface Props {
29
+ contentPosition?: 'left' | 'center' | 'right'
30
+ dashed?: boolean
31
+ /** true=1px hairline; false=4rpx (dashed 归一化为 1px) */
32
+ hairline?: boolean
33
+ }
34
+
35
+ const props = withDefaults(defineProps<Props>(), {
36
+ contentPosition: 'center',
37
+ dashed: false,
38
+ hairline: true,
39
+ })
40
+
41
+ const slots = useSlots()
42
+ const hasContent = computed(() => !!slots.default)
43
+
44
+ const lineStyle = computed(() => (props.dashed ? 'dashed' : 'solid'))
45
+ // ponytail: dashed 非 hairline 归一化回 1px,避免 4rpx 粗虚线显得笨重
46
+ const effectiveHairline = computed(() => props.hairline || props.dashed)
47
+ </script>
48
+
49
+ <style lang="scss" scoped>
50
+ @import '../../scss/variables';
51
+ @import '../../scss/mixins';
52
+
53
+ .dd-divider {
54
+ display: flex;
55
+ align-items: center;
56
+ width: 100%;
57
+ height: 48rpx; // 24px
58
+
59
+ &__content {
60
+ flex: none;
61
+ padding: 0 $dd-space-2;
62
+ color: $dd-text-tertiary;
63
+ font-size: $dd-font-size-caption;
64
+ line-height: 1.5;
65
+ }
66
+
67
+ &__line {
68
+ flex: 1;
69
+ border-top-color: $dd-border-default;
70
+
71
+ &--left {
72
+ flex: 1;
73
+ }
74
+
75
+ &--right {
76
+ flex: 1;
77
+ }
78
+
79
+ &--hairline {
80
+ border-top-width: 1px;
81
+ }
82
+
83
+ &--solid {
84
+ border-top-style: solid;
85
+ }
86
+
87
+ &--dashed {
88
+ border-top-style: dashed;
89
+ }
90
+
91
+ &:not(.dd-divider__line--hairline) {
92
+ border-top-width: 4rpx;
93
+ }
94
+ }
95
+ }
96
+
97
+ // contentPosition 折叠单行:left 折叠左线,right 折叠右线
98
+ .dd-divider--left .dd-divider__line--left {
99
+ flex: 0 0 $dd-space-3;
100
+ }
101
+ .dd-divider--right .dd-divider__line--right {
102
+ flex: 0 0 $dd-space-3;
103
+ }
104
+ </style>