@deot/vc-components 1.0.47 → 1.0.48

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.
@@ -92,6 +92,38 @@
92
92
 
93
93
  const MActionSheet = ActionSheet;
94
94
 
95
+ const props$1s = {
96
+ modelValue: {
97
+ type: Boolean,
98
+ default: false
99
+ },
100
+ zIndex: {
101
+ type: [Number, String],
102
+ default: 1
103
+ },
104
+ // TODO: left/right
105
+ placement: {
106
+ type: String,
107
+ default: "top"
108
+ },
109
+ disabled: {
110
+ type: Boolean,
111
+ default: false
112
+ },
113
+ fixed: {
114
+ type: Boolean,
115
+ default: true
116
+ },
117
+ offset: {
118
+ type: Number,
119
+ default: 0
120
+ },
121
+ // -> 固钉始终保持在容器内, 超过范围则隐藏(请注意容器避免出现滚动条) 仅fixed为true有效
122
+ target: {
123
+ type: String
124
+ }
125
+ };
126
+
95
127
  const IS_SERVER$3 = typeof window === "undefined";
96
128
 
97
129
  const hasClass = (el, cls) => {
@@ -189,7 +221,7 @@
189
221
  return !!(overflow.match(/(scroll|auto)/) || className?.test(el.className));
190
222
  };
191
223
 
192
- const getScroller = (el, options) => {
224
+ const getScroller$1 = (el, options) => {
193
225
  if (IS_SERVER$3 || !el) return null;
194
226
  let parent = el;
195
227
  while (parent) {
@@ -308,44 +340,45 @@
308
340
  return target;
309
341
  };
310
342
 
311
- const props$1s = {
312
- zIndex: {
313
- type: [Number, String],
314
- default: 1
315
- },
316
- // TODO: left/right
317
- placement: {
318
- type: String,
319
- default: "top"
320
- },
321
- disabled: {
322
- type: Boolean,
323
- default: false
324
- },
325
- fixed: {
326
- type: Boolean,
327
- default: true
328
- },
329
- offset: {
330
- type: Number,
331
- default: 0
332
- },
333
- // -> 固钉始终保持在容器内, 超过范围则隐藏(请注意容器避免出现滚动条) 仅fixed为true有效
334
- target: {
335
- type: String
336
- }
343
+ let scrollBarWidth;
344
+ const getScrollBarWidth = () => {
345
+ if (scrollBarWidth !== void 0) return scrollBarWidth;
346
+ const outer = document.createElement("div");
347
+ outer.className = "vc-scrollbar__wrap";
348
+ outer.style.visibility = "hidden";
349
+ outer.style.width = "100px";
350
+ outer.style.position = "absolute";
351
+ outer.style.top = "-9999px";
352
+ document.body.appendChild(outer);
353
+ const widthNoScroll = outer.offsetWidth;
354
+ outer.style.overflow = "scroll";
355
+ const inner = document.createElement("div");
356
+ inner.style.width = "100%";
357
+ outer.appendChild(inner);
358
+ const widthWithScroll = inner.offsetWidth;
359
+ outer.parentNode?.removeChild?.(outer);
360
+ scrollBarWidth = widthNoScroll - widthWithScroll;
361
+ return scrollBarWidth;
362
+ };
363
+ const SCROLLER_WHEEL_REG = /vc-scroller-wheel/;
364
+ const getScroller = (el) => {
365
+ return getScroller$1(el, { className: SCROLLER_WHEEL_REG });
366
+ };
367
+ const isWheel = (el) => {
368
+ return SCROLLER_WHEEL_REG.test(el?.className || "");
337
369
  };
338
370
 
339
371
  /** @jsxImportSource vue */
340
372
 
341
373
  const COMPONENT_NAME$27 = 'vc-affix';
342
- const SCROLLER_WHEEL_REG = /vc-scroller-wheel/;
343
374
  const Affix = /* @__PURE__ */ vue.defineComponent({
344
375
  name: COMPONENT_NAME$27,
376
+ emits: ['update:modelValue'],
345
377
  props: props$1s,
346
378
  setup(props, {
347
379
  slots,
348
- expose
380
+ expose,
381
+ emit
349
382
  }) {
350
383
  const scrollerInstance = vue.inject('vc-scroller', null);
351
384
  const scroller = vue.shallowRef(); // 当前元素所在的滚动容器
@@ -361,9 +394,7 @@
361
394
  const isActive = vue.ref(false);
362
395
  const transformY = vue.ref(0);
363
396
  const windowHeight = vue.ref(window.innerHeight);
364
- const isVcScrollerWheel = vue.computed(() => {
365
- return SCROLLER_WHEEL_REG.test(scroller.value?.className || '');
366
- });
397
+ const isVcScrollerWheel = vue.computed(() => isWheel(scroller.value));
367
398
  const currentStyle = vue.computed(() => {
368
399
  if (!isActive.value) return {};
369
400
  return {
@@ -384,7 +415,8 @@
384
415
  };
385
416
  });
386
417
  const setCurrentRect = () => {
387
- const rect = current.value.getBoundingClientRect();
418
+ const rect = current.value?.getBoundingClientRect?.();
419
+ if (!rect) return;
388
420
  Object.assign(currentRect, {
389
421
  top: rect.top,
390
422
  bottom: rect.bottom,
@@ -411,7 +443,7 @@
411
443
  transformY.value = Math.min(containerRect.bottom - currentHeightOffset, 0) + transformOffsetY;
412
444
  } else {
413
445
  isActive.value = currentRect.bottom - containerRect.top >= containerRect.height - props.offset;
414
- transformY.value = Math.max(containerRect.height - containerRect.top - currentHeightOffset, 0) + transformOffsetY;
446
+ transformY.value = transformOffsetY;
415
447
  }
416
448
  };
417
449
  const setFixedStatus = () => {
@@ -438,36 +470,58 @@
438
470
  }
439
471
  }
440
472
  };
473
+ const offScroll = handler => {
474
+ if (isVcScrollerWheel.value) {
475
+ scrollerInstance?.off(handler);
476
+ } else {
477
+ scroller.value?.removeEventListener('scroll', handler);
478
+ }
479
+ };
480
+ const onScroll = (handler, options) => {
481
+ // nextTick目的在与onMounted后执行
482
+ vue.nextTick(() => {
483
+ if (isVcScrollerWheel.value) {
484
+ scrollerInstance?.on(handler);
485
+ } else {
486
+ scroller.value?.addEventListener('scroll', handler);
487
+ }
488
+ options?.first && handler();
489
+ });
490
+ return () => offScroll(handler);
491
+ };
441
492
  const refresh = () => {
493
+ if (props.disabled) return;
442
494
  setCurrentRect();
443
495
  scroller.value instanceof Window || props.fixed ? setFixedStatus() : setAbsoluteStatus();
496
+ emit('update:modelValue', isActive.value);
444
497
  };
445
498
  vue.onMounted(() => {
446
499
  if (typeof props.target === 'string') {
447
500
  base.value = document.querySelector(props.target) ?? void 0;
448
501
  }
449
502
  !base.value && (base.value = document.documentElement);
450
- scroller.value = getScroller(current.value, {
451
- className: SCROLLER_WHEEL_REG
503
+ scroller.value = getScroller(current.value);
504
+ onScroll(refresh, {
505
+ first: true
452
506
  });
453
- if (isVcScrollerWheel.value) {
454
- scrollerInstance?.on(refresh);
455
- } else {
456
- scroller.value?.addEventListener('scroll', refresh);
457
- }
458
- refresh();
459
- });
460
- vue.onBeforeUnmount(() => {
461
- if (isVcScrollerWheel.value) {
462
- scrollerInstance?.off(refresh);
463
- } else {
464
- scroller.value?.removeEventListener('scroll', refresh);
465
- }
466
507
  });
508
+ vue.onBeforeUnmount(() => offScroll(refresh));
467
509
  expose({
468
- refresh
510
+ refresh,
511
+ onScroll,
512
+ offScroll
513
+ });
514
+ vue.provide('vc-affix', {
515
+ props,
516
+ isActive,
517
+ refresh,
518
+ onScroll,
519
+ offScroll
469
520
  });
470
521
  return () => {
522
+ if (props.disabled) return slots?.default?.({
523
+ active: false
524
+ });
471
525
  return vue.createVNode("div", {
472
526
  "ref": current,
473
527
  "class": "vc-affix",
@@ -14394,27 +14448,6 @@
14394
14448
  }
14395
14449
  };
14396
14450
 
14397
- let scrollBarWidth;
14398
- const getScrollBarWidth = () => {
14399
- if (scrollBarWidth !== void 0) return scrollBarWidth;
14400
- const outer = document.createElement("div");
14401
- outer.className = "vc-scrollbar__wrap";
14402
- outer.style.visibility = "hidden";
14403
- outer.style.width = "100px";
14404
- outer.style.position = "absolute";
14405
- outer.style.top = "-9999px";
14406
- document.body.appendChild(outer);
14407
- const widthNoScroll = outer.offsetWidth;
14408
- outer.style.overflow = "scroll";
14409
- const inner = document.createElement("div");
14410
- inner.style.width = "100%";
14411
- outer.appendChild(inner);
14412
- const widthWithScroll = inner.offsetWidth;
14413
- outer.parentNode?.removeChild?.(outer);
14414
- scrollBarWidth = widthNoScroll - widthWithScroll;
14415
- return scrollBarWidth;
14416
- };
14417
-
14418
14451
  const barKeys$1 = [
14419
14452
  "always",
14420
14453
  "thumbMinSize",
@@ -21131,7 +21164,7 @@
21131
21164
  } else if (typeof wrapper === 'string') {
21132
21165
  scroller.value = document.querySelector(wrapper);
21133
21166
  } else {
21134
- scroller.value = getScroller(instance.vnode.el);
21167
+ scroller.value = getScroller$1(instance.vnode.el);
21135
21168
  }
21136
21169
  };
21137
21170
  const initPlaceholder = () => {
@@ -23267,13 +23300,13 @@
23267
23300
  "readonly": true,
23268
23301
  "placeholder": its.value.attrs?.placeholder || '请选择'
23269
23302
  }, {
23270
- prepend: () => {
23271
- if (slots.prepend) return slots.prepend?.();
23272
- if (!props.label) return null;
23273
- return vue.createVNode("span", {
23303
+ prepend: slots.prepend || props.label ? () => {
23304
+ slots.prepend ? slots.prepend() : vue.createVNode("div", {
23305
+ "class": "vc-select__prepend"
23306
+ }, [vue.createVNode("span", {
23274
23307
  "class": "vc-select__label"
23275
- }, [props.label]);
23276
- },
23308
+ }, [props.label])]);
23309
+ } : null,
23277
23310
  content: multiple.value && currentValue.value && currentValue.value.length > 0 ? () => {
23278
23311
  return vue.createVNode("div", {
23279
23312
  "class": [classes.value, 'vc-select__tags']
@@ -29029,10 +29062,13 @@
29029
29062
  barStyle: [Object, String],
29030
29063
  contentStyle: [Object, String],
29031
29064
  barClass: [Object, String],
29032
- contentClass: [Object, String]
29065
+ contentClass: [Object, String],
29066
+ affixable: Boolean,
29067
+ affixOptions: Object
29033
29068
  };
29034
29069
 
29035
29070
  const useTabs = (options = {}) => {
29071
+ const affix = vue.inject("vc-affix", null);
29036
29072
  const instance = vue.getCurrentInstance();
29037
29073
  const { props, emit } = instance;
29038
29074
  const tabsId = vue.ref(getUid("tabs"));
@@ -29074,10 +29110,56 @@
29074
29110
  [`is-${props.theme}`]: !!props.theme
29075
29111
  };
29076
29112
  });
29113
+ const hasAnchor = vue.computed(() => {
29114
+ return list.value.some((item) => !!item.anchor);
29115
+ });
29077
29116
  const refresh = () => {
29078
29117
  options?.refreshAfloat?.();
29079
29118
  };
29080
- const handleChange = (index) => {
29119
+ let scrollToAnchorTimer;
29120
+ const scrollToAnchor = (anchor) => {
29121
+ if (!anchor) return;
29122
+ const el = document.querySelector(anchor);
29123
+ if (!el) return;
29124
+ const scroller = getScroller(instance.vnode.el);
29125
+ scrollIntoView(scroller, {
29126
+ duration: 250,
29127
+ from: scroller.scrollTop,
29128
+ to: scroller.scrollTop + el.getBoundingClientRect().top - scroller.getBoundingClientRect().top - (!affix || affix.props.placement !== "bottom" ? instance.vnode.el.offsetHeight : 0) - (affix && affix.props.placement !== "bottom" ? affix.props.offset : 0)
29129
+ });
29130
+ scrollToAnchorTimer && clearTimeout(scrollToAnchorTimer);
29131
+ scrollToAnchorTimer = setTimeout(() => scrollToAnchorTimer = null, 300);
29132
+ };
29133
+ const handleAffixScroll = () => {
29134
+ if (!hasAnchor.value || scrollToAnchorTimer) return;
29135
+ const scroller = getScroller(instance.vnode.el);
29136
+ const scrollTop = scroller?.scrollTop;
29137
+ if (typeof scrollTop !== "number") return;
29138
+ for (let i = 0; i < list.value.length; i++) {
29139
+ const nav = list.value[i];
29140
+ const anchor = nav.anchor;
29141
+ if (!anchor) continue;
29142
+ const el = document.querySelector(anchor);
29143
+ if (!el) continue;
29144
+ const elTop = el.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop;
29145
+ const nextNav = list.value[i + 1];
29146
+ let nextElTop;
29147
+ if (nextNav && nextNav.anchor) {
29148
+ const nextEl = document.querySelector(nextNav.anchor);
29149
+ if (nextEl) {
29150
+ nextElTop = nextEl.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop;
29151
+ }
29152
+ }
29153
+ const allowDistance = 2;
29154
+ if (scrollTop >= elTop - allowDistance && (typeof nextElTop === "undefined" || scrollTop < nextElTop - allowDistance)) {
29155
+ if (getTabIndex(currentValue.value) !== i) {
29156
+ handleChange(i, false);
29157
+ }
29158
+ break;
29159
+ }
29160
+ }
29161
+ };
29162
+ const handleChange = (index, scrollTo = true) => {
29081
29163
  if (timer.value) return;
29082
29164
  timer.value = setTimeout(() => timer.value = null, 300);
29083
29165
  const nav = list.value[index];
@@ -29086,7 +29168,7 @@
29086
29168
  emit("update:modelValue", currentValue.value);
29087
29169
  emit("change", currentValue.value);
29088
29170
  emit("click", currentValue.value);
29089
- nav.anchor && document.querySelector(nav.anchor)?.scrollIntoView?.({ behavior: "smooth" });
29171
+ scrollTo && scrollToAnchor(nav.anchor);
29090
29172
  };
29091
29173
  const handleResize = () => {
29092
29174
  if (instance.isUnmounted) return;
@@ -29096,10 +29178,13 @@
29096
29178
  vue.onMounted(() => {
29097
29179
  Resize.on(options.wrapper.value, handleResize);
29098
29180
  options.scrollToActive && vue.nextTick(options.scrollToActive);
29181
+ affix?.onScroll?.(handleAffixScroll);
29099
29182
  });
29100
29183
  vue.onBeforeUnmount(() => {
29101
29184
  Resize.off(options.wrapper.value, handleResize);
29102
29185
  timer.value && clearTimeout(timer.value);
29186
+ affix?.offScroll?.(handleAffixScroll);
29187
+ scrollToAnchorTimer && clearTimeout(scrollToAnchorTimer);
29103
29188
  });
29104
29189
  const add = (item, setValue) => {
29105
29190
  if (!item) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deot/vc-components",
3
- "version": "1.0.47",
3
+ "version": "1.0.48",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",