sard-uniapp 1.1.0-alpha.2 → 1.1.0-beta.1

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/changelog.md CHANGED
@@ -1,4 +1,4 @@
1
- ## 1.1.0-alpha.2 (2024-04-03)
1
+ ## 1.1.0-beta.1 (2024-04-06)
2
2
 
3
3
  * docs: update quickstart.md ([fa280f6](https://github.com/sutras/sard-uniapp/commit/fa280f6))
4
4
  * build: 新增changelog构建流程 ([e1e862d](https://github.com/sutras/sard-uniapp/commit/e1e862d))
@@ -15,7 +15,7 @@
15
15
  )
16
16
  "
17
17
  >
18
- <sar-loading size="inherit" color="inherit" :type="loadingType" />
18
+ <sar-loading :type="loadingType" />
19
19
  </view>
20
20
  <slot></slot>
21
21
  </button>
@@ -56,7 +56,7 @@
56
56
  :several-months="severalMonths"
57
57
  :t="t"
58
58
  :bem="bem"
59
- @day-click="handleDayClick"
59
+ @day-click="onDayClick"
60
60
  />
61
61
  </scroll-view>
62
62
  </view>
@@ -97,6 +97,7 @@ import {
97
97
  sortDates,
98
98
  weeksIndex
99
99
  } from "./common";
100
+ import { useInPopup } from "../popup/common";
100
101
  import SarButton from "../button/button.vue";
101
102
  import SarIcon from "../icon/icon.vue";
102
103
  import { useTranslate } from "../locale";
@@ -220,7 +221,7 @@ export default /* @__PURE__ */ _defineComponent({
220
221
  }
221
222
  return dates;
222
223
  });
223
- const handleDayClick = (date) => {
224
+ const onDayClick = (date) => {
224
225
  let nextValue;
225
226
  if (props.type === "single") {
226
227
  nextValue = date;
@@ -267,17 +268,22 @@ export default /* @__PURE__ */ _defineComponent({
267
268
  emit("update:model-value", nextValue);
268
269
  }
269
270
  };
271
+ const inPopup = useInPopup();
272
+ const preventPageScroll = computed(() => {
273
+ return inPopup && !props.severalMonths;
274
+ });
270
275
  const calendarClass = computed(() => {
271
276
  return classNames(
272
277
  bem.b(),
273
278
  bem.m("several", props.severalMonths),
279
+ bem.m("no-scroll", preventPageScroll.value),
274
280
  props.rootClass
275
281
  );
276
282
  });
277
283
  const calendarStyle = computed(() => {
278
284
  return stringifyStyle(props.rootStyle);
279
285
  });
280
- const __returned__ = { props, emit, bem, t, minDate, maxDate, innerValue, getInitialCurrentDate, innerCurrentDate, startDate, onPrevMonthClick, onNextMonthClick, pickerVisible, pickerValue, onMonthClick, onPickerConfirm, weeks, months, todayNumber, currentDates, handleDayClick, calendarClass, calendarStyle, get toMonthNumber() {
286
+ const __returned__ = { props, emit, bem, t, minDate, maxDate, innerValue, getInitialCurrentDate, innerCurrentDate, startDate, onPrevMonthClick, onNextMonthClick, pickerVisible, pickerValue, onMonthClick, onPickerConfirm, weeks, months, todayNumber, currentDates, onDayClick, inPopup, preventPageScroll, calendarClass, calendarStyle, get toMonthNumber() {
281
287
  return toMonthNumber;
282
288
  }, SarButton, SarIcon, SarCalendarMonth, SarPopout, SarDatetimePicker };
283
289
  return __returned__;
@@ -4,7 +4,10 @@
4
4
  @include b() {
5
5
  @include universal;
6
6
  overflow: hidden;
7
- // touch-action: none;
7
+
8
+ @include m(no-scroll) {
9
+ touch-action: pan-x;
10
+ }
8
11
  }
9
12
 
10
13
  @include e(header) {
@@ -129,6 +129,7 @@ export default /* @__PURE__ */ _defineComponent({
129
129
  currentItemIndex = null;
130
130
  };
131
131
  const onMouseDown = (event) => {
132
+ // #ifdef H5
132
133
  const info = uni.getSystemInfoSync();
133
134
  onTouchStart(toTouchEvent(event, info.windowTop));
134
135
  const moveHandler = (event2) => {
@@ -142,6 +143,7 @@ export default /* @__PURE__ */ _defineComponent({
142
143
  };
143
144
  document.addEventListener("mousemove", moveHandler);
144
145
  document.addEventListener("mouseup", upHandler);
146
+ // #endif
145
147
  };
146
148
  const navClass = computed(() => {
147
149
  return classNames(bem.e("nav"));
@@ -185,12 +185,14 @@ export default /* @__PURE__ */ _defineComponent({
185
185
  holdupClear.value = false;
186
186
  };
187
187
  const onClearMouseDown = () => {
188
+ // #ifdef H5
188
189
  onClearTouchStart();
189
190
  const upHandler = () => {
190
191
  onClearTouchEnd();
191
192
  document.removeEventListener("mouseup", upHandler);
192
193
  };
193
194
  document.addEventListener("mouseup", upHandler);
195
+ // #endif
194
196
  };
195
197
  const onClearClick = () => {
196
198
  setInnerValue("");
@@ -9,6 +9,8 @@ export interface LoadingProps {
9
9
  textColor?: string;
10
10
  textSize?: string;
11
11
  vertical?: boolean;
12
+ animated?: boolean;
13
+ progress?: number;
12
14
  }
13
15
  export declare const loadingProps: {
14
16
  rootStyle: PropType<StyleValue>;
@@ -23,7 +25,16 @@ export declare const loadingProps: {
23
25
  textColor: StringConstructor;
24
26
  textSize: StringConstructor;
25
27
  vertical: BooleanConstructor;
28
+ animated: {
29
+ type: BooleanConstructor;
30
+ default: boolean;
31
+ };
32
+ progress: {
33
+ type: NumberConstructor;
34
+ default: number;
35
+ };
26
36
  };
27
37
  export interface LoadingSlots {
28
38
  default(props: Record<string, never>): any;
39
+ circular(props: Record<string, never>): any;
29
40
  }
@@ -1,6 +1,8 @@
1
1
  import { defaultConfig } from '../config';
2
2
  // const props = withDefaults(defineProps<LoadingProps>(), {
3
3
  // type: 'circular',
4
+ // animated: true,
5
+ // progress: 1,
4
6
  // })
5
7
  export const loadingProps = {
6
8
  rootStyle: [String, Object, Array],
@@ -15,4 +17,12 @@ export const loadingProps = {
15
17
  textColor: String,
16
18
  textSize: String,
17
19
  vertical: Boolean,
20
+ animated: {
21
+ type: Boolean,
22
+ default: true,
23
+ },
24
+ progress: {
25
+ type: Number,
26
+ default: 1,
27
+ },
18
28
  };
@@ -19,21 +19,23 @@ $sar-loading-scale-number: 12;
19
19
 
20
20
  @include e(icon) {
21
21
  @include universal;
22
- width: 1em;
23
- height: 1em;
24
- min-width: var(--sar-loading-icon-min-width);
25
- min-height: var(--sar-loading-icon-min-height);
26
22
 
27
- @include m(circular) {
28
- border: 4rpx solid transparent;
29
- border-radius: 100%;
30
- border-top-color: initial;
23
+ @include m(circular, clock) {
24
+ align-items: center;
25
+ justify-content: center;
26
+ width: 1em;
27
+ height: 1em;
28
+ min-width: var(--sar-loading-icon-min-width);
29
+ min-height: var(--sar-loading-icon-min-height);
30
+ }
31
+
32
+ @include m-intersect(circular, animated) {
31
33
  animation: #{bem-ns(loading-rotate)} var(
32
34
  --sar-loading-icon-animation-duration
33
35
  ) linear infinite;
34
36
  }
35
37
 
36
- @include m(clock) {
38
+ @include m-intersect(clock, animated) {
37
39
  animation: #{bem-ns(loading-rotate)} var(
38
40
  --sar-loading-icon-animation-duration
39
41
  ) steps(#{$sar-loading-scale-number}) infinite;
@@ -49,6 +51,19 @@ $sar-loading-scale-number: 12;
49
51
  }
50
52
  }
51
53
 
54
+ @include e(spinner) {
55
+ width: 100%;
56
+ height: 100%;
57
+ border-radius: 100%;
58
+ background: conic-gradient(
59
+ rgba(255, 255, 255, 0) 0deg,
60
+ rgba(255, 255, 255, 0) 60deg,
61
+ currentColor 330deg,
62
+ rgba(255, 255, 255, 0) 360deg
63
+ );
64
+ -webkit-mask: radial-gradient(transparent calc(55% - 1px), #fff 55%);
65
+ }
66
+
52
67
  @include e(scale) {
53
68
  position: absolute;
54
69
  top: 0;
@@ -60,6 +75,7 @@ $sar-loading-scale-number: 12;
60
75
  display: flex;
61
76
  width: var(--sar-loading-scale-width);
62
77
  min-width: var(--sar-loading-scale-min-width);
78
+ transform: scaleX(var(--sar-loading-scale-scale-x));
63
79
  height: var(--sar-loading-scale-height);
64
80
  margin: 0 auto;
65
81
  border-radius: var(--sar-loading-scale-border-radius);
@@ -68,14 +84,15 @@ $sar-loading-scale-number: 12;
68
84
  }
69
85
 
70
86
  @for $i from 1 through $sar-loading-scale-number {
71
- &:nth-child(#{$i}) {
72
- opacity: tofixed(
73
- 1 - math.div(1, $sar-loading-scale-number) * ($i - 1),
74
- 6
75
- );
87
+ @include m(#{$i}) {
88
+ opacity: tofixed(math.div(1, $sar-loading-scale-number) * $i, 4);
76
89
  transform: rotate(#{math.div(360, $sar-loading-scale-number) * $i}deg);
77
90
  }
78
91
  }
92
+
93
+ @include m(hidden) {
94
+ opacity: 0;
95
+ }
79
96
  }
80
97
 
81
98
  @include e(text) {
@@ -1,8 +1,25 @@
1
1
  <template>
2
2
  <view :class="loadingClass">
3
3
  <view :class="iconClass" :style="iconStyle">
4
- <template v-if="type === 'clock'">
5
- <view v-for="i in 12" :key="i" :class="bem.e('scale')"></view>
4
+ <slot v-if="type === 'circular'" name="circular">
5
+ <view :class="bem.e('spinner')"></view>
6
+ </slot>
7
+ <template v-else-if="type === 'clock'">
8
+ <view
9
+ v-for="i in 12"
10
+ :key="i"
11
+ :class="
12
+ classNames(
13
+ bem.e('scale'),
14
+ bem.em('scale', i),
15
+ !props.animated
16
+ ? {
17
+ [bem.em('scale', 'hidden')]: i > scaleShowNum,
18
+ }
19
+ : null,
20
+ )
21
+ "
22
+ ></view>
6
23
  </template>
7
24
  </view>
8
25
 
@@ -42,11 +59,18 @@ export default /* @__PURE__ */ _defineComponent({
42
59
  __expose();
43
60
  const props = __props;
44
61
  const bem = createBem("loading");
62
+ const scaleShowNum = computed(() => {
63
+ return Math.max(Math.floor(props.progress * 12), 1);
64
+ });
45
65
  const loadingClass = computed(() => {
46
66
  return classNames(bem.b(), bem.m("vertical", props.vertical));
47
67
  });
48
68
  const iconClass = computed(() => {
49
- return classNames(bem.e("icon"), bem.em("icon", props.type));
69
+ return classNames(
70
+ bem.e("icon"),
71
+ bem.em("icon", props.type),
72
+ bem.em("icon", "animated", props.animated)
73
+ );
50
74
  });
51
75
  const iconStyle = computed(() => {
52
76
  return stringifyStyle(
@@ -54,6 +78,9 @@ export default /* @__PURE__ */ _defineComponent({
54
78
  color: props.color,
55
79
  fontSize: props.size
56
80
  },
81
+ props.type === "circular" && !props.animated ? {
82
+ transform: `rotate(${props.progress * 360}deg)`
83
+ } : null,
57
84
  props.rootClass
58
85
  );
59
86
  });
@@ -63,7 +90,9 @@ export default /* @__PURE__ */ _defineComponent({
63
90
  props.rootStyle
64
91
  );
65
92
  });
66
- const __returned__ = { props, bem, loadingClass, iconClass, iconStyle, loadingTextStyle, get isRenderVisible() {
93
+ const __returned__ = { props, bem, scaleShowNum, loadingClass, iconClass, iconStyle, loadingTextStyle, get classNames() {
94
+ return classNames;
95
+ }, get isRenderVisible() {
67
96
  return isRenderVisible;
68
97
  } };
69
98
  return __returned__;
@@ -4,8 +4,9 @@ page {
4
4
  --sar-loading-icon-min-height: 32rpx;
5
5
  --sar-loading-icon-animation-duration: 0.8s;
6
6
 
7
- --sar-loading-scale-width: 8%;
8
- --sar-loading-scale-min-width: 3rpx;
7
+ --sar-loading-scale-width: 9.38%;
8
+ --sar-loading-scale-min-width: 2px;
9
+ --sar-loading-scale-scale-x: 0.75;
9
10
  --sar-loading-scale-height: 28%;
10
11
  --sar-loading-scale-border-radius: 40%;
11
12
 
@@ -100,12 +100,14 @@ export default /* @__PURE__ */ _defineComponent({
100
100
  }
101
101
  };
102
102
  const onSealMouseDown = () => {
103
+ // #ifdef H5
103
104
  onSealTouchStart();
104
105
  const upHandler = () => {
105
106
  onSealTouchEnd();
106
107
  document.removeEventListener("mouseup", upHandler);
107
108
  };
108
109
  document.addEventListener("mouseup", upHandler);
110
+ // #endif
109
111
  };
110
112
  const onClick = (event) => {
111
113
  if (interoperable.value) {
@@ -54,3 +54,4 @@ export interface PopupContext {
54
54
  export declare const popupContextSymbol: unique symbol;
55
55
  export declare function usePopupVisibleHookProvide(): (name: TransitionHookName) => void;
56
56
  export declare function usePopupEnter(callback: () => void): void;
57
+ export declare function useInPopup(): boolean;
@@ -47,3 +47,6 @@ export function usePopupEnter(callback) {
47
47
  });
48
48
  }
49
49
  }
50
+ export function useInPopup() {
51
+ return !!inject(popupContextSymbol, null);
52
+ }
@@ -1 +1 @@
1
- export type { PopupProps, PopupSlots, PopupEmits } from './common';
1
+ export { type PopupProps, type PopupSlots, type PopupEmits, type PopupContext, usePopupVisibleHookProvide, usePopupEnter, useInPopup, } from './common';
@@ -1 +1 @@
1
- export {};
1
+ export { usePopupVisibleHookProvide, usePopupEnter, useInPopup, } from './common';
@@ -0,0 +1,50 @@
1
+ import { type PropType, type StyleValue } from 'vue';
2
+ export type PullDownRefreshStatus = 'initial' | 'unready' | 'ready' | 'loading' | 'done' | 'recovering';
3
+ export interface PullDownRefreshProps {
4
+ rootStyle?: StyleValue;
5
+ rootClass?: string;
6
+ threshold?: number;
7
+ headerHeight?: number;
8
+ loading?: boolean;
9
+ transitionDuration?: number;
10
+ doneDuration?: number;
11
+ }
12
+ export declare const pullDownRefreshProps: {
13
+ rootStyle: PropType<StyleValue>;
14
+ rootClass: StringConstructor;
15
+ threshold: {
16
+ type: NumberConstructor;
17
+ default: number;
18
+ };
19
+ headerHeight: {
20
+ type: NumberConstructor;
21
+ default: number;
22
+ };
23
+ loading: {
24
+ type: BooleanConstructor;
25
+ default: boolean;
26
+ };
27
+ transitionDuration: {
28
+ type: NumberConstructor;
29
+ default: number;
30
+ };
31
+ doneDuration: {
32
+ type: NumberConstructor;
33
+ default: number;
34
+ };
35
+ };
36
+ export interface PullDownRefreshSlots {
37
+ default(props: Record<string, never>): any;
38
+ unready(props: {
39
+ progress: number;
40
+ }): any;
41
+ ready(props: Record<string, never>): any;
42
+ loading(props: Record<string, never>): any;
43
+ done(props: Record<string, never>): any;
44
+ }
45
+ export interface PullDownRefreshEmits {
46
+ (e: 'refresh'): void;
47
+ }
48
+ export interface PullDownRefreshExpose {
49
+ setScrollTop: (scrollTop: number) => void;
50
+ }
@@ -0,0 +1,31 @@
1
+ // const props = withDefaults(defineProps<PullDownRefreshProps>(), {
2
+ // threshold: 50,
3
+ // headerHeight: 50,
4
+ // loading: false,
5
+ // transitionDuration: 300,
6
+ // doneDuration: 0,
7
+ // })
8
+ export const pullDownRefreshProps = {
9
+ rootStyle: [String, Object, Array],
10
+ rootClass: String,
11
+ threshold: {
12
+ type: Number,
13
+ default: 50,
14
+ },
15
+ headerHeight: {
16
+ type: Number,
17
+ default: 50,
18
+ },
19
+ loading: {
20
+ type: Boolean,
21
+ default: false,
22
+ },
23
+ transitionDuration: {
24
+ type: Number,
25
+ default: 300,
26
+ },
27
+ doneDuration: {
28
+ type: Number,
29
+ default: 0,
30
+ },
31
+ };
@@ -0,0 +1 @@
1
+ export type { PullDownRefreshStatus, PullDownRefreshProps, PullDownRefreshSlots, PullDownRefreshEmits, PullDownRefreshExpose, } from './common';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ @use '../style/base' as *;
2
+
3
+ @include bem(pull-down-refresh) {
4
+ @include b() {
5
+ @include universal;
6
+ transition-property: transform;
7
+ }
8
+
9
+ @include e(header) {
10
+ @include universal;
11
+ position: absolute;
12
+ top: 0;
13
+ left: 0;
14
+ width: 100%;
15
+ flex-direction: row;
16
+ justify-content: center;
17
+ align-items: center;
18
+ transform: translateY(-100%);
19
+ font-size: var(--sar-pull-down-refresh-header-font-size);
20
+ color: var(--sar-pull-down-refresh-header-color);
21
+ }
22
+
23
+ @include e(loading) {
24
+ font-size: var(--sar-pull-down-refresh-loading-font-size);
25
+ }
26
+ }
@@ -0,0 +1,261 @@
1
+ <template>
2
+ <!-- #ifndef MP-WEIXIN -->
3
+ <view
4
+ :class="pullDownRefreshClass"
5
+ :style="pullDownRefreshStyle"
6
+ @touchstart="onTouchStart"
7
+ @touchmove="onTouchMove"
8
+ @touchend="onTouchEnd"
9
+ @touchcancel="onTouchEnd"
10
+ @mousedown="onMouseDown"
11
+ >
12
+ <view :class="bem.e('header')" :style="headerStyle">
13
+ <slot v-if="status === 'unready'" name="unready" :progress="progress">
14
+ <sar-loading
15
+ type="clock"
16
+ :class="loadingClass"
17
+ :animated="false"
18
+ :progress="progress"
19
+ />
20
+ </slot>
21
+ <slot v-else-if="status === 'ready'" name="ready">
22
+ <sar-loading type="clock" :class="loadingClass" :animated="false" />
23
+ </slot>
24
+ <slot v-else-if="status === 'loading'" name="loading">
25
+ <sar-loading type="clock" :class="loadingClass" />
26
+ </slot>
27
+ <slot v-else-if="status === 'done'" name="done"></slot>
28
+ </view>
29
+ <slot></slot>
30
+ </view>
31
+ <!-- #endif -->
32
+ <!-- #ifdef MP-WEIXIN -->
33
+ <view
34
+ :class="pullDownRefreshClass"
35
+ :style="pullDownRefreshStyle"
36
+ :prop="status"
37
+ :change:prop="wxsswipe.statusYWatch"
38
+ :data-status="status"
39
+ :data-scrolltop="scrollTop"
40
+ :data-threshold="threshold"
41
+ :data-headerheight="headerHeight"
42
+ :data-duration="transitionDuration"
43
+ @touchstart="wxsswipe.onTouchStart"
44
+ @touchmove="wxsswipe.onTouchMove"
45
+ @touchend="wxsswipe.onTouchEnd"
46
+ @touchcancel="wxsswipe.onTouchEnd"
47
+ >
48
+ <view :class="bem.e('header')" :style="headerStyle">
49
+ <slot v-if="status === 'unready'" name="unready" :progress="progress">
50
+ <sar-loading
51
+ type="clock"
52
+ :class="loadingClass"
53
+ :animated="false"
54
+ :progress="progress"
55
+ />
56
+ </slot>
57
+ <slot v-else-if="status === 'ready'" name="ready">
58
+ <sar-loading type="clock" :class="loadingClass" :animated="false" />
59
+ </slot>
60
+ <slot v-else-if="status === 'loading'" name="loading">
61
+ <sar-loading type="clock" :class="loadingClass" />
62
+ </slot>
63
+ <slot v-else-if="status === 'done'" name="done"></slot>
64
+ </view>
65
+ <slot></slot>
66
+ </view>
67
+ <!-- #endif -->
68
+ </template>
69
+
70
+ <!-- #ifdef MP-WEIXIN -->
71
+ <script src="./wx.wxs" module="wxsswipe" lang="wxs"></script>
72
+ <!-- #endif -->
73
+
74
+ <script lang="ts">
75
+ import { computed, onMounted, ref, watch } from "vue";
76
+ import {
77
+ classNames,
78
+ stringifyStyle,
79
+ createBem,
80
+ toTouchEvent
81
+ } from "../../utils";
82
+ import {
83
+ pullDownRefreshProps
84
+ } from "./common";
85
+ import { useSetTimeout } from "../../use";
86
+ import SarLoading from "../loading/loading.vue";
87
+ export default {
88
+ options: {
89
+ virtualHost: true,
90
+ styleIsolation: "shared"
91
+ },
92
+ components: {
93
+ SarLoading
94
+ },
95
+ props: pullDownRefreshProps,
96
+ emit: ["refresh"],
97
+ setup(props, { emit, expose }) {
98
+ const bem = createBem("pull-down-refresh");
99
+ const status = ref("initial");
100
+ const translateY = ref(0);
101
+ const progress = computed(() => {
102
+ return Math.min(translateY.value / props.threshold, 1);
103
+ });
104
+ const [toInitialLater, cancelToInitial] = useSetTimeout(() => {
105
+ status.value = "initial";
106
+ });
107
+ const [toRecoveringLater, cancelToRecovering] = useSetTimeout(() => {
108
+ toRecovering();
109
+ });
110
+ const toLoading = () => {
111
+ cancelToRecovering();
112
+ cancelToInitial();
113
+ status.value = "loading";
114
+ translateY.value = props.headerHeight;
115
+ };
116
+ const toRecovering = () => {
117
+ status.value = "recovering";
118
+ translateY.value = 0;
119
+ toInitialLater(props.transitionDuration);
120
+ };
121
+ const toDone = () => {
122
+ status.value = "done";
123
+ toRecoveringLater(props.doneDuration);
124
+ };
125
+ watch(
126
+ () => props.loading,
127
+ () => {
128
+ if (props.loading) {
129
+ toLoading();
130
+ } else {
131
+ toDone();
132
+ }
133
+ }
134
+ );
135
+ onMounted(() => {
136
+ if (props.loading) {
137
+ toLoading();
138
+ }
139
+ });
140
+ let startX = 0;
141
+ let startY = 0;
142
+ let movable = false;
143
+ let lockDirection = "";
144
+ const isDragging = ref(false);
145
+ const onTouchStart = (event) => {
146
+ if (status.value !== "initial" || scrollTop.value !== 0) {
147
+ return;
148
+ }
149
+ startX = event.touches[0].clientX;
150
+ startY = event.touches[0].clientY;
151
+ movable = true;
152
+ };
153
+ const onTouchMove = (event) => {
154
+ if (!movable || lockDirection && lockDirection !== "down") {
155
+ return;
156
+ }
157
+ const deltaX = event.touches[0].clientX - startX;
158
+ const deltaY = event.touches[0].clientY - startY;
159
+ if (!lockDirection) {
160
+ const isVertical = Math.abs(deltaY) >= Math.abs(deltaX);
161
+ lockDirection = isVertical && deltaY > 0 ? "down" : "others";
162
+ }
163
+ if (lockDirection === "down") {
164
+ const offsetY = Math.max(deltaY, 0) / 2;
165
+ status.value = offsetY >= props.threshold ? "ready" : "unready";
166
+ translateY.value = offsetY;
167
+ isDragging.value = true;
168
+ event.preventDefault();
169
+ if (event.stopImmediatePropagation) {
170
+ event.stopImmediatePropagation();
171
+ } else if (event.stopPropagation) {
172
+ event.stopPropagation();
173
+ }
174
+ }
175
+ };
176
+ const onTouchEnd = () => {
177
+ movable = false;
178
+ lockDirection = "";
179
+ isDragging.value = false;
180
+ switch (status.value) {
181
+ case "unready":
182
+ toRecovering();
183
+ return;
184
+ case "ready":
185
+ toLoading();
186
+ emit("refresh");
187
+ return;
188
+ }
189
+ };
190
+ const onMouseDown = (event) => {
191
+ // #ifdef H5
192
+ const info = uni.getSystemInfoSync();
193
+ onTouchStart(toTouchEvent(event, info.windowTop));
194
+ const moveHandler = (event2) => {
195
+ onTouchMove(toTouchEvent(event2, info.windowTop));
196
+ };
197
+ const upHandler = () => {
198
+ onTouchEnd();
199
+ document.removeEventListener("mouseup", upHandler);
200
+ document.removeEventListener("mousemove", moveHandler);
201
+ };
202
+ document.addEventListener("mousemove", moveHandler);
203
+ document.addEventListener("mouseup", upHandler);
204
+ // #endif
205
+ };
206
+ const scrollTop = ref(0);
207
+ const setScrollTop = (sTop) => {
208
+ scrollTop.value = sTop;
209
+ };
210
+ expose({
211
+ setScrollTop,
212
+ _setStatus: (newStatus) => {
213
+ status.value = newStatus;
214
+ },
215
+ _emit(event) {
216
+ emit(event.name, event.payload);
217
+ },
218
+ _toRecovering: toRecovering,
219
+ _toLoading: toLoading,
220
+ _setTranslateY: (y) => {
221
+ translateY.value = y;
222
+ }
223
+ });
224
+ const pullDownRefreshClass = computed(() => {
225
+ return classNames(bem.b(), props.rootClass);
226
+ });
227
+ const pullDownRefreshStyle = computed(() => {
228
+ return stringifyStyle(props.rootStyle, {
229
+ transform: `translate3d(0,${translateY.value}px,0)`,
230
+ transitionDuration: (isDragging.value ? 0 : props.transitionDuration) + "ms"
231
+ });
232
+ });
233
+ const headerStyle = computed(() => {
234
+ return stringifyStyle({
235
+ height: props.headerHeight + "px"
236
+ });
237
+ });
238
+ const loadingClass = computed(() => {
239
+ return classNames(bem.e("loading"));
240
+ });
241
+ return {
242
+ onTouchStart,
243
+ onTouchMove,
244
+ onTouchEnd,
245
+ onMouseDown,
246
+ status,
247
+ progress,
248
+ bem,
249
+ pullDownRefreshClass,
250
+ pullDownRefreshStyle,
251
+ headerStyle,
252
+ loadingClass,
253
+ scrollTop
254
+ };
255
+ }
256
+ };
257
+ </script>
258
+
259
+ <style lang="scss">
260
+ @import './index.scss';
261
+ </style>
@@ -0,0 +1,8 @@
1
+ // #variables
2
+ page {
3
+ --sar-pull-down-refresh-header-font-size: var(--sar-text-sm);
4
+ --sar-pull-down-refresh-header-color: var(--sar-tertiary-color);
5
+
6
+ --sar-pull-down-refresh-loading-font-size: 36rpx;
7
+ }
8
+ // #endvariables
@@ -0,0 +1,80 @@
1
+ var startX = 0
2
+ var startY = 0
3
+ var movable = false
4
+ var lockDirection = ''
5
+
6
+ function setStyle(instance, offsetY, duration) {
7
+ instance.setStyle({
8
+ transform: 'translate3d(0,' + offsetY + 'px,0)',
9
+ 'transition-duration': duration + 'ms',
10
+ })
11
+ }
12
+
13
+ function onTouchStart(event) {
14
+ var dataset = event.instance.getDataset()
15
+ if (dataset.status !== 'initial' || dataset.scrolltop !== 0) {
16
+ return
17
+ }
18
+ startX = event.touches[0].clientX
19
+ startY = event.touches[0].clientY
20
+ movable = true
21
+ }
22
+
23
+ function onTouchMove(event, ownerIns) {
24
+ if (!movable || (lockDirection && lockDirection !== 'down')) {
25
+ return
26
+ }
27
+
28
+ var deltaX = event.touches[0].clientX - startX
29
+ var deltaY = event.touches[0].clientY - startY
30
+
31
+ if (!lockDirection) {
32
+ var isVertical = Math.abs(deltaY) >= Math.abs(deltaX)
33
+ lockDirection = isVertical && deltaY > 0 ? 'down' : 'others'
34
+ }
35
+
36
+ if (lockDirection === 'down') {
37
+ var offsetY = Math.max(deltaY, 0) / 2
38
+ var dataset = event.instance.getDataset()
39
+ var status = offsetY >= dataset.threshold ? 'ready' : 'unready'
40
+ ownerIns.callMethod('_setStatus', status)
41
+ setStyle(event.instance, offsetY, 0)
42
+ ownerIns.callMethod('_setTranslateY', offsetY)
43
+
44
+ return false
45
+ }
46
+ }
47
+
48
+ function onTouchEnd(event, ownerIns) {
49
+ var dataset = event.instance.getDataset()
50
+
51
+ movable = false
52
+ lockDirection = ''
53
+
54
+ switch (dataset.status) {
55
+ case 'unready':
56
+ ownerIns.callMethod('_toRecovering')
57
+ return
58
+ case 'ready':
59
+ ownerIns.callMethod('_toLoading')
60
+ ownerIns.callMethod('_emit', {
61
+ name: 'refresh',
62
+ })
63
+ return
64
+ }
65
+ }
66
+
67
+ module.exports = {
68
+ onTouchStart: onTouchStart,
69
+ onTouchMove: onTouchMove,
70
+ onTouchEnd: onTouchEnd,
71
+ statusYWatch: function (newValue, oldValue, ownerInstance, instance) {
72
+ var dataset = instance.getDataset()
73
+ if (newValue === 'loading') {
74
+ setStyle(instance, dataset.headerheight, dataset.duration)
75
+ }
76
+ if (newValue === 'recovering') {
77
+ setStyle(instance, 0, dataset.duration)
78
+ }
79
+ },
80
+ }
@@ -60,7 +60,8 @@ import {
60
60
  stringifyStyle,
61
61
  createBem,
62
62
  uniqid,
63
- getBoundingClientRect
63
+ getBoundingClientRect,
64
+ toTouchEvent
64
65
  } from "../../utils";
65
66
  import SarIcon from "../icon/icon.vue";
66
67
  import { useFormContext, useFormItemContext } from "../form/common";
@@ -159,7 +160,6 @@ export default /* @__PURE__ */ _defineComponent({
159
160
  if (isReadonly.value || isDisabled.value) {
160
161
  return;
161
162
  }
162
- event.preventDefault();
163
163
  if (!rateRect.value || !firstStarRect.value) {
164
164
  return;
165
165
  }
@@ -187,15 +187,12 @@ export default /* @__PURE__ */ _defineComponent({
187
187
  }
188
188
  };
189
189
  const onMouseDown = () => {
190
+ // #ifdef H5
190
191
  onTouchStart();
191
192
  const moveHandler = (event) => {
192
193
  event.preventDefault();
193
- onTouchMove({
194
- touches: [event],
195
- preventDefault: () => {
196
- event.preventDefault();
197
- }
198
- });
194
+ event.stopPropagation();
195
+ onTouchMove(toTouchEvent(event));
199
196
  };
200
197
  const upHandler = () => {
201
198
  document.removeEventListener("mouseup", upHandler);
@@ -203,6 +200,7 @@ export default /* @__PURE__ */ _defineComponent({
203
200
  };
204
201
  document.addEventListener("mousemove", moveHandler);
205
202
  document.addEventListener("mouseup", upHandler);
203
+ // #endif
206
204
  };
207
205
  const rateClass = computed(() => {
208
206
  return classNames(
@@ -252,17 +252,13 @@ export default /* @__PURE__ */ _defineComponent({
252
252
  emit("drag-end", event);
253
253
  };
254
254
  const onMouseDown = (event, index) => {
255
+ // #ifdef H5
255
256
  const info = uni.getSystemInfoSync();
256
- onTouchStart(
257
- toTouchEvent(event, info.windowTop),
258
- index
259
- );
257
+ onTouchStart(toTouchEvent(event, info.windowTop), index);
260
258
  const moveHandler = (event2) => {
261
259
  event2.preventDefault();
262
- onTouchMove(
263
- toTouchEvent(event2, info.windowTop),
264
- index
265
- );
260
+ event2.stopPropagation();
261
+ onTouchMove(toTouchEvent(event2, info.windowTop), index);
266
262
  };
267
263
  const upHandler = () => {
268
264
  onTouchEnd(event);
@@ -271,6 +267,7 @@ export default /* @__PURE__ */ _defineComponent({
271
267
  };
272
268
  document.addEventListener("mousemove", moveHandler);
273
269
  document.addEventListener("mouseup", upHandler);
270
+ // #endif
274
271
  };
275
272
  const rangeValue = computed(() => {
276
273
  let startValue;
@@ -180,12 +180,14 @@ export default /* @__PURE__ */ _defineComponent({
180
180
  isPressing = false;
181
181
  };
182
182
  const onMouseDown = (delta) => {
183
+ // #ifdef H5
183
184
  onTouchStart(delta);
184
185
  const upHandler = () => {
185
186
  onTouchEnd();
186
187
  document.removeEventListener("mouseup", upHandler);
187
188
  };
188
189
  document.addEventListener("mouseup", upHandler);
190
+ // #endif
189
191
  };
190
192
  const stepperClass = computed(() => {
191
193
  return classNames(
package/global.d.ts CHANGED
@@ -53,6 +53,7 @@ import SarPopoverReference from './components/popover-reference/popover-referenc
53
53
  import SarPopup from './components/popup/popup.vue'
54
54
  import SarProgressBar from './components/progress-bar/progress-bar.vue'
55
55
  import SarProgressCircle from './components/progress-circle/progress-circle.vue'
56
+ import SarPullDownRefresh from './components/pull-down-refresh/pull-down-refresh.vue'
56
57
  import SarRadio from './components/radio/radio.vue'
57
58
  import SarRadioGroup from './components/radio-group/radio-group.vue'
58
59
  import SarRate from './components/rate/rate.vue'
@@ -135,6 +136,7 @@ declare module '@vue/runtime-core' {
135
136
  SarPopup: typeof SarPopup
136
137
  SarProgressBar: typeof SarProgressBar
137
138
  SarProgressCircle: typeof SarProgressCircle
139
+ SarPullDownRefresh: typeof SarPullDownRefresh
138
140
  SarRadio: typeof SarRadio
139
141
  SarRadioGroup: typeof SarRadioGroup
140
142
  SarRate: typeof SarRate
package/index.d.ts CHANGED
@@ -45,6 +45,7 @@ export * from './components/popover-reference';
45
45
  export * from './components/popup';
46
46
  export * from './components/progress-bar';
47
47
  export * from './components/progress-circle';
48
+ export * from './components/pull-down-refresh';
48
49
  export * from './components/radio';
49
50
  export * from './components/rate';
50
51
  export * from './components/result';
package/index.js CHANGED
@@ -45,6 +45,7 @@ export * from './components/popover-reference';
45
45
  export * from './components/popup';
46
46
  export * from './components/progress-bar';
47
47
  export * from './components/progress-circle';
48
+ export * from './components/pull-down-refresh';
48
49
  export * from './components/radio';
49
50
  export * from './components/rate';
50
51
  export * from './components/result';
package/index.scss CHANGED
@@ -34,6 +34,7 @@
34
34
  @use './components/popup/variables.scss' as *;
35
35
  @use './components/progress-bar/variables.scss' as *;
36
36
  @use './components/progress-circle/variables.scss' as *;
37
+ @use './components/pull-down-refresh/variables.scss' as *;
37
38
  @use './components/rate/variables.scss' as *;
38
39
  @use './components/radio/variables.scss' as *;
39
40
  @use './components/result/variables.scss' as *;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "id": "sard-uniapp",
3
3
  "name": "sard-uniapp",
4
4
  "displayName": "sard-uniapp",
5
- "version": "1.1.0-alpha.2",
5
+ "version": "1.1.0-beta.1",
6
6
  "description": "sard-uniapp 是一套基于 Uniapp + Vue3 框架开发的兼容多端的 UI 组件库",
7
7
  "keywords": [
8
8
  "uniapp",
package/utils/dom.d.ts CHANGED
@@ -81,57 +81,5 @@ interface MatchScrollVisibleOptions {
81
81
  * @description: 匹配元素列表中第一个位于滚动盒子可视区域的元素
82
82
  */
83
83
  export declare function matchScrollVisible(rects: NodeRect[], callback: (index: number) => unknown, options?: MatchScrollVisibleOptions): Promise<unknown>;
84
- export declare function toTouchEvent(event: MouseEvent | TouchEvent, windowTop: number): TouchEvent | {
85
- touches: {
86
- clientX: number;
87
- clientY: number;
88
- }[];
89
- altKey: boolean;
90
- button: number;
91
- buttons: number;
92
- clientX: number;
93
- clientY: number;
94
- ctrlKey: boolean;
95
- metaKey: boolean;
96
- movementX: number;
97
- movementY: number;
98
- offsetX: number;
99
- offsetY: number;
100
- pageX: number;
101
- pageY: number;
102
- relatedTarget: EventTarget | null;
103
- screenX: number;
104
- screenY: number;
105
- shiftKey: boolean;
106
- x: number;
107
- y: number;
108
- getModifierState(keyArg: string): boolean;
109
- initMouseEvent(typeArg: string, canBubbleArg: boolean, cancelableArg: boolean, viewArg: Window, detailArg: number, screenXArg: number, screenYArg: number, clientXArg: number, clientYArg: number, ctrlKeyArg: boolean, altKeyArg: boolean, shiftKeyArg: boolean, metaKeyArg: boolean, buttonArg: number, relatedTargetArg: EventTarget | null): void;
110
- detail: number;
111
- view: Window | null;
112
- which: number;
113
- initUIEvent(typeArg: string, bubblesArg?: boolean | undefined, cancelableArg?: boolean | undefined, viewArg?: Window | null | undefined, detailArg?: number | undefined): void;
114
- bubbles: boolean;
115
- cancelBubble: boolean;
116
- cancelable: boolean;
117
- composed: boolean;
118
- currentTarget: EventTarget | null;
119
- defaultPrevented: boolean;
120
- eventPhase: number;
121
- isTrusted: boolean;
122
- returnValue: boolean;
123
- srcElement: EventTarget | null;
124
- target: EventTarget | null;
125
- timeStamp: number;
126
- type: string;
127
- composedPath(): EventTarget[];
128
- initEvent(type: string, bubbles?: boolean | undefined, cancelable?: boolean | undefined): void;
129
- preventDefault(): void;
130
- stopImmediatePropagation(): void;
131
- stopPropagation(): void;
132
- NONE: 0;
133
- CAPTURING_PHASE: 1;
134
- AT_TARGET: 2;
135
- BUBBLING_PHASE: 3;
136
- };
84
+ export declare function toTouchEvent(event: MouseEvent | TouchEvent, windowTop?: number): TouchEvent;
137
85
  export {};
package/utils/dom.js CHANGED
@@ -139,16 +139,15 @@ export async function matchScrollVisible(rects, callback, options = {}) {
139
139
  }
140
140
  }
141
141
  }
142
- export function toTouchEvent(event, windowTop) {
143
- return 'touches' in event
144
- ? event
145
- : {
146
- ...event,
147
- touches: [
148
- {
149
- clientX: event.clientX,
150
- clientY: event.clientY - windowTop,
151
- },
152
- ],
153
- };
142
+ export function toTouchEvent(event, windowTop = 0) {
143
+ if (!('touches' in event)) {
144
+ ;
145
+ event.touches = [
146
+ {
147
+ clientX: event.clientX,
148
+ clientY: event.clientY - windowTop,
149
+ },
150
+ ];
151
+ }
152
+ return event;
154
153
  }