@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,134 @@
1
+ <template>
2
+ <view
3
+ class="dd-nav"
4
+ :class="{
5
+ 'dd-nav--fixed': fixed,
6
+ 'dd-nav--border': border,
7
+ }"
8
+ >
9
+ <view
10
+ v-for="(item, index) in items"
11
+ :key="index"
12
+ class="dd-nav__item"
13
+ :class="{ 'dd-nav__item--active': index === modelValue }"
14
+ @click="onSelect(index)"
15
+ >
16
+ <view
17
+ v-if="index === modelValue"
18
+ class="dd-nav__indicator"
19
+ ></view>
20
+ <slot name="icon" :item="item" :index="index" :active="index === modelValue">
21
+ <dd-icon :name="item.icon" class="dd-nav__icon" />
22
+ </slot>
23
+ <text class="dd-nav__label">{{ item.label }}</text>
24
+ </view>
25
+ </view>
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ import DdIcon from '../dd-icon/dd-icon.vue'
30
+
31
+ interface NavItem {
32
+ icon: string
33
+ label: string
34
+ [key: string]: any
35
+ }
36
+
37
+ interface Props {
38
+ modelValue?: number
39
+ items?: NavItem[]
40
+ fixed?: boolean
41
+ border?: boolean
42
+ }
43
+
44
+ const props = withDefaults(defineProps<Props>(), {
45
+ modelValue: 0,
46
+ items: () => [],
47
+ fixed: true,
48
+ border: true,
49
+ })
50
+
51
+ const emit = defineEmits<{
52
+ (e: 'update:modelValue', val: number): void
53
+ (e: 'change', val: number): void
54
+ }>()
55
+
56
+ function onSelect(index: number) {
57
+ if (index === props.modelValue) return
58
+ emit('update:modelValue', index)
59
+ emit('change', index)
60
+ }
61
+ </script>
62
+
63
+ <style lang="scss" scoped>
64
+ @import '../../scss/variables';
65
+ @import '../../scss/mixins';
66
+
67
+ .dd-nav {
68
+ display: flex;
69
+ flex-direction: row;
70
+ justify-content: space-around;
71
+ align-items: center;
72
+ width: 100%;
73
+ height: 112rpx;
74
+ background: $dd-surface;
75
+ box-sizing: border-box;
76
+
77
+ &--border {
78
+ @include dd-hairline-top($dd-border-subtle);
79
+ }
80
+
81
+ &--fixed {
82
+ position: fixed;
83
+ left: 0;
84
+ right: 0;
85
+ bottom: 0;
86
+ z-index: $dd-z-index-sticky;
87
+ @include dd-safe-area-bottom;
88
+ }
89
+
90
+ &__item {
91
+ position: relative;
92
+ flex: 1;
93
+ height: 100%;
94
+ @include dd-flex-center;
95
+ flex-direction: column;
96
+ gap: 4rpx;
97
+ color: $dd-text-tertiary;
98
+ @include dd-transition(color 0.3s);
99
+
100
+ &--active {
101
+ color: $dd-primary-400;
102
+ .dd-nav__icon {
103
+ text-shadow: 0 0 12px rgba(245, 166, 35, 0.5);
104
+ }
105
+ .dd-nav__label {
106
+ font-weight: 500;
107
+ }
108
+ }
109
+ }
110
+
111
+ &__indicator {
112
+ position: absolute;
113
+ top: 0;
114
+ left: 50%;
115
+ transform: translateX(-50%);
116
+ width: 48rpx;
117
+ height: 4rpx;
118
+ border-radius: 0 0 $dd-radius-sm $dd-radius-sm;
119
+ background: $dd-gradient-primary-h;
120
+ box-shadow: $dd-shadow-glow-gold-sm;
121
+ }
122
+
123
+ &__icon {
124
+ font-size: 40rpx;
125
+ line-height: 1;
126
+ }
127
+
128
+ &__label {
129
+ font-size: 24rpx;
130
+ line-height: 1.2;
131
+ @include dd-ellipsis(1);
132
+ }
133
+ }
134
+ </style>
@@ -0,0 +1,114 @@
1
+ <template>
2
+ <view
3
+ class="dd-overlay"
4
+ :class="{ 'dd-overlay--show': modelValue }"
5
+ :style="{ zIndex: zIndex, '--dd-overlay-duration': `${duration}s` }"
6
+ @click="onClick"
7
+ @touchmove="onTouchMove"
8
+ @touchmove.stop.prevent="onTouchMove"
9
+ >
10
+ <slot></slot>
11
+ </view>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { watch } from 'vue'
16
+
17
+ interface Props {
18
+ modelValue?: boolean
19
+ lockScroll?: boolean
20
+ zIndex?: number
21
+ duration?: number
22
+ closeOnClickOverlay?: boolean
23
+ }
24
+
25
+ const props = withDefaults(defineProps<Props>(), {
26
+ modelValue: false,
27
+ lockScroll: true,
28
+ zIndex: 2000,
29
+ duration: 0.3,
30
+ closeOnClickOverlay: true,
31
+ })
32
+
33
+ const emit = defineEmits<{
34
+ (e: 'update:modelValue', val: boolean): void
35
+ (e: 'click'): void
36
+ }>()
37
+
38
+ // 模块级引用计数器:堆叠 overlay 时正确解锁 (ponytail: 全局计数,多实例共享)
39
+ let ddOverlayLockCount = 0
40
+ // 确保多组件实例共享同一计数:挂在全局对象上
41
+ const g: any = typeof globalThis !== 'undefined' ? globalThis : ({} as any)
42
+ if (g.__DD_OVERLAY_LOCK_COUNT__ === undefined) {
43
+ g.__DD_OVERLAY_LOCK_COUNT__ = 0
44
+ }
45
+
46
+ function lockScroll() {
47
+ if (!props.lockScroll) return
48
+ if (g.__DD_OVERLAY_LOCK_COUNT__ === 0) {
49
+ // #ifdef H5
50
+ document.body.style.overflow = 'hidden'
51
+ // #endif
52
+ }
53
+ g.__DD_OVERLAY_LOCK_COUNT__++
54
+ }
55
+
56
+ function unlockScroll() {
57
+ if (!props.lockScroll) return
58
+ if (g.__DD_OVERLAY_LOCK_COUNT__ > 0) {
59
+ g.__DD_OVERLAY_LOCK_COUNT__--
60
+ if (g.__DD_OVERLAY_LOCK_COUNT__ === 0) {
61
+ // #ifdef H5
62
+ document.body.style.overflow = ''
63
+ // #endif
64
+ }
65
+ }
66
+ }
67
+
68
+ watch(
69
+ () => props.modelValue,
70
+ (val) => {
71
+ if (val) lockScroll()
72
+ else unlockScroll()
73
+ }
74
+ )
75
+
76
+ function onClick() {
77
+ emit('click')
78
+ if (props.closeOnClickOverlay) {
79
+ emit('update:modelValue', false)
80
+ }
81
+ }
82
+
83
+ function onTouchMove() {
84
+ // MP: catch touchmove 阻止背景滚动穿透 (touchmove.stop.prevent 已在模板处理)
85
+ }
86
+ </script>
87
+
88
+ <style lang="scss" scoped>
89
+ @import '../../scss/variables';
90
+ @import '../../scss/mixins';
91
+
92
+ .dd-overlay {
93
+ position: fixed;
94
+ inset: 0;
95
+ background: rgba(0, 0, 0, 0.7);
96
+ display: flex;
97
+ align-items: center;
98
+ justify-content: center;
99
+ opacity: 0;
100
+ visibility: hidden;
101
+ pointer-events: none;
102
+ // visibility 延迟过渡:opacity 先淡出,再隐藏 (ponytail: 离散属性需 transition-delay)
103
+ transition: opacity var(--dd-overlay-duration, 0.3s) ease,
104
+ visibility 0s linear var(--dd-overlay-duration, 0.3s);
105
+
106
+ &--show {
107
+ opacity: 1;
108
+ visibility: visible;
109
+ pointer-events: auto;
110
+ transition: opacity var(--dd-overlay-duration, 0.3s) ease,
111
+ visibility 0s linear 0s;
112
+ }
113
+ }
114
+ </style>
@@ -0,0 +1,203 @@
1
+ <template>
2
+ <view class="dd-picker" :class="{ 'dd-picker--open': show }">
3
+ <view class="dd-picker__mask" @click="onMaskClick"></view>
4
+ <view class="dd-picker__sheet">
5
+ <view class="dd-picker__toolbar">
6
+ <text class="dd-picker__cancel" @click="onCancel">取消</text>
7
+ <text class="dd-picker__title">{{ title }}</text>
8
+ <text class="dd-picker__confirm" @click="onConfirm">确定</text>
9
+ </view>
10
+ <view class="dd-picker__body">
11
+ <picker-view
12
+ class="dd-picker__wheels"
13
+ :value="indexes"
14
+ @change="onPickerChange"
15
+ >
16
+ <picker-view-column v-for="(col, ci) in normalizedColumns" :key="ci">
17
+ <view v-for="(item, ii) in col" :key="ii" class="dd-picker__item">
18
+ <text class="dd-picker__item-text">{{ item.text }}</text>
19
+ </view>
20
+ </picker-view-column>
21
+ </picker-view>
22
+ <view v-if="loading" class="dd-picker__layer">
23
+ <text class="dd-picker__layer-text">加载中...</text>
24
+ </view>
25
+ <view v-else-if="readonly" class="dd-picker__layer"></view>
26
+ </view>
27
+ </view>
28
+ </view>
29
+ </template>
30
+
31
+ <script setup lang="ts">
32
+ import { computed, ref, watch } from 'vue'
33
+
34
+ interface PickerItem {
35
+ text: string
36
+ value: any
37
+ }
38
+
39
+ interface Props {
40
+ show?: boolean
41
+ columns?: PickerItem[] | PickerItem[][]
42
+ title?: string
43
+ loading?: boolean
44
+ readonly?: boolean
45
+ }
46
+
47
+ const props = withDefaults(defineProps<Props>(), {
48
+ show: false,
49
+ columns: () => [],
50
+ title: '',
51
+ loading: false,
52
+ readonly: false,
53
+ })
54
+
55
+ const emit = defineEmits<{
56
+ (e: 'update:show', val: boolean): void
57
+ (e: 'confirm', val: { values: any[]; indexes: number[]; items: PickerItem[] }): void
58
+ (e: 'cancel'): void
59
+ (e: 'change', val: { values: any[]; indexes: number[] }): void
60
+ }>()
61
+
62
+ const normalizedColumns = computed<PickerItem[][]>(() => {
63
+ const c = props.columns as any
64
+ if (!c || !c.length) return []
65
+ if (Array.isArray(c[0])) return c as PickerItem[][]
66
+ return [c as PickerItem[]]
67
+ })
68
+
69
+ const indexes = ref<number[]>([])
70
+
71
+ watch(
72
+ () => normalizedColumns.value,
73
+ (cols) => {
74
+ const next = cols.map((_, i) => indexes.value[i] ?? 0)
75
+ indexes.value = next
76
+ },
77
+ { immediate: true }
78
+ )
79
+
80
+ function emitChange() {
81
+ const items = normalizedColumns.value.map((col, i) => col[indexes.value[i] ?? 0] || { text: '', value: null })
82
+ return {
83
+ values: items.map((it) => it.value),
84
+ indexes: indexes.value.slice(),
85
+ items,
86
+ }
87
+ }
88
+
89
+ function onPickerChange(e: any) {
90
+ indexes.value = (e?.detail?.value ?? []).slice()
91
+ const data = emitChange()
92
+ emit('change', { values: data.values, indexes: data.indexes })
93
+ }
94
+
95
+ function close() {
96
+ emit('update:show', false)
97
+ }
98
+ function onMaskClick() {
99
+ onCancel()
100
+ }
101
+ function onCancel() {
102
+ emit('cancel')
103
+ close()
104
+ }
105
+ function onConfirm() {
106
+ if (props.loading || props.readonly) return
107
+ emit('confirm', emitChange())
108
+ close()
109
+ }
110
+ </script>
111
+
112
+ <style lang="scss" scoped>
113
+ @import '../../scss/variables';
114
+ @import '../../scss/mixins';
115
+ :deep(.uni-picker-view-mask) {
116
+ 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%));
117
+ }
118
+ .dd-picker {
119
+ &__mask {
120
+ position: fixed;
121
+ inset: 0;
122
+ z-index: $dd-z-index-overlay;
123
+ background: rgba(0, 0, 0, 0.7);
124
+ opacity: 0;
125
+ pointer-events: none;
126
+ @include dd-transition(opacity 0.3s);
127
+ }
128
+
129
+ &__sheet {
130
+ position: fixed;
131
+ left: 0;
132
+ right: 0;
133
+ bottom: 0;
134
+ z-index: $dd-z-index-popup;
135
+ background: $dd-neutral-800;
136
+ border-radius: $dd-radius-lg $dd-radius-lg 0 0;
137
+ transform: translateY(100%);
138
+ @include dd-transition(transform 0.3s);
139
+ @include dd-safe-area-bottom;
140
+ }
141
+
142
+ &--open &__mask {
143
+ opacity: 1;
144
+ pointer-events: auto;
145
+ }
146
+ &--open &__sheet {
147
+ transform: translateY(0);
148
+ }
149
+
150
+ &__toolbar {
151
+ @include dd-flex-between;
152
+ height: 96rpx;
153
+ padding: 0 32rpx;
154
+ @include dd-hairline-bottom($dd-border-default);
155
+ }
156
+ &__cancel {
157
+ font-size: 28rpx;
158
+ color: $dd-text-secondary;
159
+ }
160
+ &__title {
161
+ flex: 1;
162
+ text-align: center;
163
+ font-size: 32rpx;
164
+ font-weight: 600;
165
+ color: $dd-text-primary;
166
+ @include dd-ellipsis(1);
167
+ }
168
+ &__confirm {
169
+ font-size: 28rpx;
170
+ font-weight: 600;
171
+ color: $dd-primary-500;
172
+ }
173
+
174
+ &__body {
175
+ position: relative;
176
+ }
177
+ &__wheels {
178
+ width: 100%;
179
+ height: 440rpx;
180
+ }
181
+
182
+ &__item {
183
+ @include dd-flex-center;
184
+ height: 88rpx;
185
+ }
186
+ &__item-text {
187
+ font-size: 28rpx;
188
+ color: $dd-text-primary;
189
+ @include dd-ellipsis(1);
190
+ }
191
+
192
+ &__layer {
193
+ position: absolute;
194
+ inset: 0;
195
+ @include dd-flex-center;
196
+ background: rgba($dd-neutral-800, 0.6);
197
+ }
198
+ &__layer-text {
199
+ font-size: 24rpx;
200
+ color: $dd-text-tertiary;
201
+ }
202
+ }
203
+ </style>
@@ -0,0 +1,190 @@
1
+ <template>
2
+ <view class="dd-popover" :class="`dd-popover--${theme}`">
3
+ <view class="dd-popover__trigger" @click="onTriggerClick">
4
+ <slot></slot>
5
+ </view>
6
+ <view
7
+ v-if="modelValue"
8
+ class="dd-popover__mask"
9
+ :style="{ zIndex: maskZIndex }"
10
+ @click="onMaskClick"
11
+ ></view>
12
+ <view
13
+ v-if="modelValue"
14
+ class="dd-popover__panel"
15
+ :class="[`dd-popover__panel--${placement}`, `dd-popover__panel--${theme}`]"
16
+ :style="panelStyle"
17
+ >
18
+ <view class="dd-popover__arrow" :class="`dd-popover__arrow--${placement}`"></view>
19
+ <view class="dd-popover__content">
20
+ <slot name="actions"></slot>
21
+ </view>
22
+ </view>
23
+ </view>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { computed, provide } from 'vue'
28
+
29
+ interface Props {
30
+ modelValue?: boolean
31
+ placement?: 'top' | 'bottom' | 'left' | 'right'
32
+ theme?: 'light' | 'dark'
33
+ closeOnClickAction?: boolean
34
+ closeOnClickOverlay?: boolean
35
+ offset?: number
36
+ zIndex?: number
37
+ }
38
+
39
+ const props = withDefaults(defineProps<Props>(), {
40
+ modelValue: false,
41
+ placement: 'bottom',
42
+ theme: 'light',
43
+ closeOnClickAction: true,
44
+ closeOnClickOverlay: true,
45
+ offset: 16,
46
+ zIndex: 2000,
47
+ })
48
+
49
+ const emit = defineEmits<{
50
+ (e: 'update:modelValue', val: boolean): void
51
+ (e: 'select', value: any): void
52
+ (e: 'open'): void
53
+ (e: 'close'): void
54
+ }>()
55
+
56
+ const maskZIndex = computed(() => props.zIndex - 1)
57
+
58
+ const panelStyle = computed(() => {
59
+ const offsetRpx = `${props.offset}rpx`
60
+ const s: Record<string, string> = { zIndex: String(props.zIndex) }
61
+ // 偏移通过 margin 表达,避免覆盖 transform
62
+ if (props.placement === 'top') s.marginBottom = offsetRpx
63
+ if (props.placement === 'bottom') s.marginTop = offsetRpx
64
+ if (props.placement === 'left') s.marginRight = offsetRpx
65
+ if (props.placement === 'right') s.marginLeft = offsetRpx
66
+ return s
67
+ })
68
+
69
+ function close() {
70
+ emit('update:modelValue', false)
71
+ emit('close')
72
+ }
73
+
74
+ function onTriggerClick() {
75
+ if (props.modelValue) {
76
+ close()
77
+ } else {
78
+ emit('update:modelValue', true)
79
+ emit('open')
80
+ }
81
+ }
82
+
83
+ function onMaskClick() {
84
+ if (props.closeOnClickOverlay) close()
85
+ }
86
+
87
+ // provide 给 dd-popover-item 调用,中继点击
88
+ provide('ddPopover', {
89
+ onSelect(value: any) {
90
+ emit('select', value)
91
+ if (props.closeOnClickAction) close()
92
+ },
93
+ })
94
+ </script>
95
+
96
+ <style lang="scss" scoped>
97
+ @import '../../scss/variables';
98
+ @import '../../scss/mixins';
99
+
100
+ .dd-popover {
101
+ position: relative;
102
+ display: inline-flex;
103
+
104
+ &__trigger {
105
+ display: inline-flex;
106
+ }
107
+
108
+ &__mask {
109
+ position: fixed;
110
+ inset: 0;
111
+ background: transparent;
112
+ }
113
+
114
+ &__panel {
115
+ position: absolute;
116
+ min-width: 240rpx;
117
+ max-width: 480rpx;
118
+ border-radius: $dd-radius-lg;
119
+ box-shadow: $dd-shadow-2;
120
+ overflow: visible;
121
+ z-index: 2000;
122
+
123
+ &--light {
124
+ background: $dd-bg-elevated;
125
+ color: $dd-text-primary;
126
+ .dd-popover__arrow { background: $dd-bg-elevated; }
127
+ }
128
+ &--dark {
129
+ background: $dd-neutral-700;
130
+ color: $dd-color-white;
131
+ .dd-popover__arrow { background: $dd-neutral-700; }
132
+ }
133
+
134
+ &--bottom {
135
+ top: 100%;
136
+ left: 50%;
137
+ transform: translateX(-50%);
138
+ }
139
+ &--top {
140
+ bottom: 100%;
141
+ left: 50%;
142
+ transform: translateX(-50%);
143
+ }
144
+ &--left {
145
+ right: 100%;
146
+ top: 50%;
147
+ transform: translateY(-50%);
148
+ }
149
+ &--right {
150
+ left: 100%;
151
+ top: 50%;
152
+ transform: translateY(-50%);
153
+ }
154
+ }
155
+
156
+ &__arrow {
157
+ position: absolute;
158
+ width: 16rpx;
159
+ height: 16rpx;
160
+ transform: rotate(45deg);
161
+
162
+ &--bottom {
163
+ top: -8rpx;
164
+ left: 50%;
165
+ margin-left: -8rpx;
166
+ }
167
+ &--top {
168
+ bottom: -8rpx;
169
+ left: 50%;
170
+ margin-left: -8rpx;
171
+ }
172
+ &--left {
173
+ right: -8rpx;
174
+ top: 50%;
175
+ margin-top: -8rpx;
176
+ }
177
+ &--right {
178
+ left: -8rpx;
179
+ top: 50%;
180
+ margin-top: -8rpx;
181
+ }
182
+ }
183
+
184
+ &__content {
185
+ position: relative;
186
+ border-radius: $dd-radius-lg;
187
+ overflow: hidden;
188
+ }
189
+ }
190
+ </style>