sard 1.0.4 → 1.0.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sard",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "sard 是基于 Vue3 的 Web 移动端 UI 组件库",
5
5
  "keywords": [
6
6
  "UI",
@@ -7,10 +7,10 @@ function useResizeObserver(target, callback, disabled) {
7
7
  });
8
8
  const observer = new ResizeObserver((entries) => {
9
9
  for (const entry of entries) {
10
- const contentSize = entry.contentBoxSize[0];
10
+ const contentSize = entry.contentRect;
11
11
  Object.assign(size, {
12
- width: contentSize.inlineSize,
13
- height: contentSize.blockSize
12
+ width: contentSize.width,
13
+ height: contentSize.height
14
14
  });
15
15
  callback?.(size);
16
16
  }
@@ -54,14 +54,14 @@ var Scroll = class {
54
54
  this.spring.snap(e);
55
55
  this.spring.setEnd(-this.extent);
56
56
  } else this.springing = false;
57
- this.startTime = (/* @__PURE__ */ new Date()).getTime();
57
+ this.startTime = Date.now();
58
58
  }
59
59
  /**
60
60
  * 计算当前时间点的位置,如果超出边界则切换到弹簧回弹模式。
61
61
  */
62
62
  position(e) {
63
63
  if (!this.startTime) return 0;
64
- if (!e) e = ((/* @__PURE__ */ new Date()).getTime() - this.startTime) / 1e3;
64
+ if (!e) e = (Date.now() - this.startTime) / 1e3;
65
65
  if (this.springing) return this.spring.position() + this.springOffset;
66
66
  let t = this.friction.position(e);
67
67
  const n = this.velocity(e);
@@ -1,39 +1,23 @@
1
- import { type Ref } from 'vue';
2
1
  import type { Friction } from './Friction';
3
2
  import type { Spring } from './Spring';
4
- interface OnScrollEvent {
5
- target: {
6
- scrollLeft: number;
7
- scrollTop: number;
8
- scrollHeight: number;
9
- scrollWidth: number;
10
- offsetHeight: number;
11
- offsetWidth: number;
12
- };
13
- }
14
3
  export interface ScrollerOptions {
15
- enableSnap?: boolean;
16
4
  itemSize?: number;
17
- enableX?: boolean;
18
- enableY?: boolean;
19
5
  scrollWidth?: number;
20
6
  scrollHeight?: number;
21
7
  friction?: Friction;
22
8
  spring?: Spring;
23
- onScroll?: (event: OnScrollEvent) => void;
24
- onSnap?: (index: number) => void;
9
+ onSnap: (index: number) => void;
25
10
  onTap?: (event: TouchEvent) => void;
26
11
  }
27
12
  /**
28
13
  * 触摸滚动器,负责处理触摸/鼠标滚动交互、惯性滚动、越界回弹和 snap 对齐。
29
- * @param element 滚动的 DOM 容器元素
30
14
  */
31
- export declare function useScroller(element: Ref<HTMLElement | null>, options: ScrollerOptions): {
32
- update: (height?: number, _scrollHeight?: number, _itemSize?: number) => void;
15
+ export declare function useScroller(options: ScrollerOptions): {
16
+ position: import("vue").ComputedRef<number>;
17
+ update: (height: number, _itemSize: number, containerHeight: number, contentHeight: number) => void;
33
18
  scrollTo: (_position: number, time?: number) => Promise<void>;
34
19
  isIdle: () => boolean;
35
20
  handleTouchStart: (event: TouchEvent) => void;
36
21
  handleTouchMove: (event: TouchEvent) => void;
37
22
  handleTouchEnd: (event: TouchEvent) => void;
38
23
  };
39
- export {};
@@ -1,9 +1,9 @@
1
- import { isFunction } from "../is.js";
1
+ import { clamp } from "../number.js";
2
2
  import { useScrollBinding } from "./useScrollBinding.js";
3
3
  import { Scroll } from "./Scroll.js";
4
4
  import { useEasingAnimation } from "./useEasingAnimation.js";
5
5
  import { useScrollAnimation } from "./useScrollAnimation.js";
6
- import { computed, ref, watch, watchPostEffect } from "vue";
6
+ import { computed, ref } from "vue";
7
7
  //#region packages/sard/utils/scroller/useScroller.ts
8
8
  /**
9
9
  * 计算当前滚动位置对应的 snap 索引。
@@ -16,23 +16,12 @@ function calculateSnapIndex(position, itemSize) {
16
16
  }
17
17
  /**
18
18
  * 触摸滚动器,负责处理触摸/鼠标滚动交互、惯性滚动、越界回弹和 snap 对齐。
19
- * @param element 滚动的 DOM 容器元素
20
19
  */
21
- function useScroller(element, options) {
20
+ function useScroller(options) {
22
21
  /** 单项尺寸,用于 snap 计算 */
23
22
  let itemSize = options.itemSize || 0;
24
- /** 是否启用 snap 对齐 */
25
- const enableSnap = computed(() => options.enableSnap);
26
- /** 是否启用水平滚动 */
27
- const enableX = computed(() => options.enableX);
28
- /** 是否启用垂直滚动 */
29
- const enableY = computed(() => options.enableY);
30
23
  /** 可滚动范围大小 */
31
24
  let extent = 0;
32
- /** 可滚动内容宽度 */
33
- let scrollWidth = 0;
34
- /** 可滚动内容高度 */
35
- let scrollHeight = 0;
36
25
  /** 当前滚动偏移位置 */
37
26
  const position = ref(0);
38
27
  /** 滚动物理模型 */
@@ -53,7 +42,7 @@ function useScroller(element, options) {
53
42
  const _position = position.value % _itemSize;
54
43
  const i = Math.abs(_position) > _itemSize / 2 ? position.value - (_itemSize - Math.abs(_position)) : position.value - _position;
55
44
  if (position.value !== i) scrollTo(-i, time).then(() => {
56
- if (isFunction(options.onSnap)) options.onSnap(Math.round(Math.abs(position.value) / _itemSize));
45
+ options.onSnap(Math.round(Math.abs(position.value) / _itemSize));
57
46
  });
58
47
  else status = "idle";
59
48
  };
@@ -71,45 +60,17 @@ function useScroller(element, options) {
71
60
  });
72
61
  };
73
62
  /**
74
- * 触发 onScroll 回调,仅在位置实际变化时执行。
75
- */
76
- const dispatchScroll = () => {
77
- const el = element.value;
78
- if (!el) return;
79
- if (isFunction(options.onScroll)) {
80
- const event = { target: {
81
- scrollLeft: enableX.value ? -position.value : 0,
82
- scrollTop: enableY.value ? -position.value : 0,
83
- scrollHeight: scrollHeight || el.offsetHeight,
84
- scrollWidth: scrollWidth || el.offsetWidth,
85
- offsetHeight: el.parentElement.offsetHeight,
86
- offsetWidth: el.parentElement.offsetWidth
87
- } };
88
- options.onScroll(event);
89
- }
90
- };
91
- /**
92
63
  * 更新滚动范围、位置、itemSize,并根据变化派发事件与 snap 回调。
93
64
  */
94
- const update = (height, _scrollHeight, _itemSize) => {
95
- const el = element.value;
96
- if (!el) return;
65
+ const update = (height, _itemSize, containerHeight, contentHeight) => {
97
66
  let nextExtent = 0;
98
67
  const _position = position.value;
99
- if (enableX.value) {
100
- nextExtent = el.childNodes.length ? (_scrollHeight || el.offsetWidth) - el.parentElement.offsetWidth : 0;
101
- scrollWidth = _scrollHeight || 0;
102
- } else {
103
- nextExtent = el.childNodes.length ? (_scrollHeight || el.offsetHeight) - el.parentElement.offsetHeight : 0;
104
- scrollHeight = _scrollHeight || 0;
105
- }
106
- if (typeof height === "number") position.value = -height;
68
+ nextExtent = contentHeight - containerHeight;
69
+ position.value = -height;
107
70
  if (position.value < -nextExtent) position.value = -nextExtent;
108
71
  else if (position.value > 0) position.value = 0;
109
- itemSize = _itemSize || itemSize;
110
- if (_position !== position.value) {
111
- if (isFunction(options.onSnap)) options.onSnap(Math.round(Math.abs(position.value) / itemSize));
112
- }
72
+ itemSize = _itemSize;
73
+ if (_position !== position.value) options.onSnap(Math.round(Math.abs(position.value) / itemSize));
113
74
  extent = nextExtent;
114
75
  scroll.extent = nextExtent;
115
76
  };
@@ -133,11 +94,10 @@ function useScroller(element, options) {
133
94
  /**
134
95
  * 根据手势移动距离更新当前位置,并触发滚动事件。
135
96
  */
136
- const onTouchMove = (x, y) => {
97
+ const onTouchMove = (_x, y) => {
137
98
  status = "drag";
138
99
  let nextPos = startPosition;
139
- if (enableX.value) nextPos += x;
140
- else if (enableY.value) nextPos += y;
100
+ nextPos += y;
141
101
  if (nextPos > 0) nextPos *= .5;
142
102
  else if (nextPos < -extent) nextPos = .5 * (nextPos + extent) - extent;
143
103
  position.value = nextPos;
@@ -150,54 +110,34 @@ function useScroller(element, options) {
150
110
  options.onTap?.(event);
151
111
  return;
152
112
  }
153
- if (enableSnap.value && position.value > -extent && position.value < 0) {
154
- if (enableY.value && (Math.abs(y) < itemSize && Math.abs(o.y) < 300 || Math.abs(o.y) < 150)) {
155
- snap();
156
- return;
157
- }
158
- if (enableX.value && (Math.abs(x) < itemSize && Math.abs(o.x) < 300 || Math.abs(o.x) < 150)) {
113
+ if (position.value > -extent && position.value < 0) {
114
+ if (Math.abs(y) < itemSize && Math.abs(o.y) < 300 || Math.abs(o.y) < 150) {
159
115
  snap();
160
116
  return;
161
117
  }
162
118
  }
163
- if (enableX.value) scroll.set(position.value, o.x);
164
- else if (enableY.value) scroll.set(position.value, o.y);
165
- let c;
166
- if (enableSnap.value) {
167
- const s = scroll.friction.position(100);
168
- const l = s % itemSize;
169
- c = Math.abs(l) > itemSize / 2 ? s - (itemSize - Math.abs(l)) : s - l;
170
- if (c <= 0 && c >= -extent) scroll.setVelocityByEnd(c);
171
- }
119
+ scroll.set(position.value, o.y);
120
+ const s = scroll.friction.position(100);
121
+ const l = s % itemSize;
122
+ const c = Math.abs(l) > itemSize / 2 ? s - (itemSize - Math.abs(l)) : s - l;
123
+ if (c <= 0 && c >= -extent) scroll.setVelocityByEnd(c);
172
124
  status = "scroll";
173
125
  scrollAnim.play(() => {
174
126
  const pos = scroll.position((Date.now() - scroll.startTime) / 1e3);
175
127
  position.value = pos;
176
128
  }, () => {
177
129
  status = "idle";
178
- if (enableSnap.value) {
179
- if (c <= 0 && c >= -extent) {
180
- scroll.setVelocityByEnd(c);
181
- position.value = c;
182
- }
183
- if (isFunction(options.onSnap)) options.onSnap(calculateSnapIndex(position.value, itemSize));
130
+ if (c <= 0 && c >= -extent) {
131
+ scroll.setVelocityByEnd(c);
132
+ position.value = c;
184
133
  }
134
+ position.value = clamp(position.value, -extent, 0);
135
+ options.onSnap(calculateSnapIndex(position.value, itemSize));
185
136
  });
186
137
  };
187
138
  const { handleTouchStart, handleTouchMove, handleTouchEnd } = useScrollBinding(onTouchStart, onTouchMove, onTouchEnd);
188
- watchPostEffect(() => {
189
- const el = element.value;
190
- if (el) {
191
- let transform = "";
192
- if (enableX.value) transform = "translateX(" + position.value + "px) translateZ(0)";
193
- else if (enableY.value) transform = "translateY(" + position.value + "px) translateZ(0)";
194
- el.style.transform = transform;
195
- }
196
- });
197
- watch(position, () => {
198
- dispatchScroll();
199
- });
200
139
  return {
140
+ position: computed(() => position.value),
201
141
  update,
202
142
  scrollTo,
203
143
  isIdle,