@v-c/virtual-list 0.0.1 → 1.0.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.
Files changed (69) hide show
  1. package/dist/Filler.cjs +51 -1
  2. package/dist/Filler.js +47 -56
  3. package/dist/Item.cjs +26 -1
  4. package/dist/Item.js +23 -26
  5. package/dist/List.cjs +412 -1
  6. package/dist/List.d.ts +45 -9
  7. package/dist/List.js +407 -274
  8. package/dist/ScrollBar.cjs +259 -1
  9. package/dist/ScrollBar.d.ts +3 -97
  10. package/dist/ScrollBar.js +254 -191
  11. package/dist/_virtual/rolldown_runtime.cjs +21 -0
  12. package/dist/hooks/useDiffItem.cjs +19 -1
  13. package/dist/hooks/useDiffItem.js +16 -20
  14. package/dist/hooks/useFrameWheel.cjs +63 -1
  15. package/dist/hooks/useFrameWheel.js +60 -51
  16. package/dist/hooks/useGetSize.cjs +29 -1
  17. package/dist/hooks/useGetSize.d.ts +2 -2
  18. package/dist/hooks/useGetSize.js +27 -23
  19. package/dist/hooks/useHeights.cjs +66 -1
  20. package/dist/hooks/useHeights.d.ts +1 -1
  21. package/dist/hooks/useHeights.js +62 -41
  22. package/dist/hooks/useMobileTouchMove.cjs +82 -1
  23. package/dist/hooks/useMobileTouchMove.js +79 -43
  24. package/dist/hooks/useOriginScroll.cjs +23 -1
  25. package/dist/hooks/useOriginScroll.js +20 -16
  26. package/dist/hooks/useScrollDrag.cjs +83 -1
  27. package/dist/hooks/useScrollDrag.js +77 -48
  28. package/dist/hooks/useScrollTo.cjs +97 -0
  29. package/dist/hooks/useScrollTo.d.ts +19 -0
  30. package/dist/hooks/useScrollTo.js +94 -0
  31. package/dist/index.cjs +4 -1
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +3 -4
  34. package/dist/interface.cjs +0 -1
  35. package/dist/interface.d.ts +1 -1
  36. package/dist/interface.js +0 -1
  37. package/dist/utils/CacheMap.cjs +25 -1
  38. package/dist/utils/CacheMap.d.ts +1 -1
  39. package/dist/utils/CacheMap.js +23 -28
  40. package/dist/utils/isFirefox.cjs +4 -1
  41. package/dist/utils/isFirefox.js +2 -4
  42. package/dist/utils/scrollbarUtil.cjs +8 -1
  43. package/dist/utils/scrollbarUtil.js +7 -6
  44. package/package.json +19 -13
  45. package/docs/basic.vue +0 -175
  46. package/docs/height.vue +0 -48
  47. package/docs/nest.vue +0 -60
  48. package/docs/no-virtual.vue +0 -127
  49. package/docs/switch.vue +0 -101
  50. package/docs/virtual-list.stories.vue +0 -31
  51. package/src/Filler.tsx +0 -72
  52. package/src/Item.tsx +0 -34
  53. package/src/List.tsx +0 -577
  54. package/src/ScrollBar.tsx +0 -298
  55. package/src/__tests__/List.test.ts +0 -59
  56. package/src/hooks/useDiffItem.ts +0 -27
  57. package/src/hooks/useFrameWheel.ts +0 -141
  58. package/src/hooks/useGetSize.ts +0 -44
  59. package/src/hooks/useHeights.ts +0 -106
  60. package/src/hooks/useMobileTouchMove.ts +0 -131
  61. package/src/hooks/useOriginScroll.ts +0 -47
  62. package/src/hooks/useScrollDrag.ts +0 -123
  63. package/src/index.ts +0 -5
  64. package/src/interface.ts +0 -32
  65. package/src/utils/CacheMap.ts +0 -42
  66. package/src/utils/isFirefox.ts +0 -3
  67. package/src/utils/scrollbarUtil.ts +0 -10
  68. package/vite.config.ts +0 -18
  69. package/vitest.config.ts +0 -11
package/dist/Filler.cjs CHANGED
@@ -1 +1,51 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const t=require("vue"),o=require("@v-c/resize-observer"),f=t.defineComponent({name:"Filler",props:{prefixCls:String,height:Number,offsetY:Number,offsetX:Number,scrollWidth:Number,onInnerResize:Function,innerProps:Object,rtl:Boolean,extra:Object},setup(e,{slots:r}){return()=>{let n={},i={display:"flex",flexDirection:"column"};return e.offsetY!==void 0&&(n={height:`${e.height}px`,position:"relative",overflow:"hidden"},i={...i,transform:`translateY(${e.offsetY}px)`,[e.rtl?"marginRight":"marginLeft"]:`-${e.offsetX||0}px`,position:"absolute",left:0,right:0,top:0}),t.createVNode("div",{style:n},[t.createVNode(o,{onResize:({offsetHeight:l})=>{l&&e.onInnerResize&&e.onInnerResize()}},{default:()=>[t.createVNode("div",t.mergeProps({style:i,class:e.prefixCls?`${e.prefixCls}-holder-inner`:void 0},e.innerProps),[r.default?.(),e.extra])]})])}}});exports.default=f;
1
+ Object.defineProperty(exports, "__esModule", { value: true });
2
+ const require_rolldown_runtime = require("./_virtual/rolldown_runtime.cjs");
3
+ let vue = require("vue");
4
+ let __v_c_resize_observer = require("@v-c/resize-observer");
5
+ __v_c_resize_observer = require_rolldown_runtime.__toESM(__v_c_resize_observer);
6
+ var Filler_default = /* @__PURE__ */ (0, vue.defineComponent)({
7
+ name: "Filler",
8
+ props: {
9
+ prefixCls: String,
10
+ height: Number,
11
+ offsetY: Number,
12
+ offsetX: Number,
13
+ scrollWidth: Number,
14
+ onInnerResize: Function,
15
+ innerProps: Object,
16
+ rtl: Boolean,
17
+ extra: Object
18
+ },
19
+ setup(props, { slots }) {
20
+ return () => {
21
+ let outerStyle = {};
22
+ let innerStyle = {
23
+ display: "flex",
24
+ flexDirection: "column"
25
+ };
26
+ if (props.offsetY !== void 0) {
27
+ outerStyle = {
28
+ height: `${props.height}px`,
29
+ position: "relative",
30
+ overflow: "hidden"
31
+ };
32
+ innerStyle = {
33
+ ...innerStyle,
34
+ transform: `translateY(${props.offsetY}px)`,
35
+ [props.rtl ? "marginRight" : "marginLeft"]: `-${props.offsetX || 0}px`,
36
+ position: "absolute",
37
+ left: 0,
38
+ right: 0,
39
+ top: 0
40
+ };
41
+ }
42
+ return (0, vue.createVNode)("div", { "style": outerStyle }, [(0, vue.createVNode)(__v_c_resize_observer.default, { "onResize": ({ offsetHeight }) => {
43
+ if (offsetHeight && props.onInnerResize) props.onInnerResize();
44
+ } }, { default: () => [(0, vue.createVNode)("div", (0, vue.mergeProps)({
45
+ "style": innerStyle,
46
+ "class": props.prefixCls ? `${props.prefixCls}-holder-inner` : void 0
47
+ }, props.innerProps), [slots.default?.(), props.extra])] })]);
48
+ };
49
+ }
50
+ });
51
+ exports.default = Filler_default;
package/dist/Filler.js CHANGED
@@ -1,57 +1,48 @@
1
- import { defineComponent as f, createVNode as i, mergeProps as o } from "vue";
2
- import s from "@v-c/resize-observer";
3
- const u = /* @__PURE__ */ f({
4
- name: "Filler",
5
- props: {
6
- prefixCls: String,
7
- /** Virtual filler height. Should be `count * itemMinHeight` */
8
- height: Number,
9
- /** Set offset of visible items. Should be the top of start item position */
10
- offsetY: Number,
11
- offsetX: Number,
12
- scrollWidth: Number,
13
- onInnerResize: Function,
14
- innerProps: Object,
15
- rtl: Boolean,
16
- extra: Object
17
- },
18
- setup(e, {
19
- slots: r
20
- }) {
21
- return () => {
22
- let n = {}, t = {
23
- display: "flex",
24
- flexDirection: "column"
25
- };
26
- return e.offsetY !== void 0 && (n = {
27
- height: `${e.height}px`,
28
- position: "relative",
29
- overflow: "hidden"
30
- }, t = {
31
- ...t,
32
- transform: `translateY(${e.offsetY}px)`,
33
- [e.rtl ? "marginRight" : "marginLeft"]: `-${e.offsetX || 0}px`,
34
- position: "absolute",
35
- left: 0,
36
- right: 0,
37
- top: 0
38
- }), i("div", {
39
- style: n
40
- }, [i(s, {
41
- onResize: ({
42
- offsetHeight: l
43
- }) => {
44
- l && e.onInnerResize && e.onInnerResize();
45
- }
46
- }, {
47
- default: () => [i("div", o({
48
- style: t,
49
- class: e.prefixCls ? `${e.prefixCls}-holder-inner` : void 0
50
- }, e.innerProps), [r.default?.(), e.extra])]
51
- })]);
52
- };
53
- }
1
+ import { createVNode, defineComponent, mergeProps } from "vue";
2
+ import ResizeObserver from "@v-c/resize-observer";
3
+ var Filler_default = /* @__PURE__ */ defineComponent({
4
+ name: "Filler",
5
+ props: {
6
+ prefixCls: String,
7
+ height: Number,
8
+ offsetY: Number,
9
+ offsetX: Number,
10
+ scrollWidth: Number,
11
+ onInnerResize: Function,
12
+ innerProps: Object,
13
+ rtl: Boolean,
14
+ extra: Object
15
+ },
16
+ setup(props, { slots }) {
17
+ return () => {
18
+ let outerStyle = {};
19
+ let innerStyle = {
20
+ display: "flex",
21
+ flexDirection: "column"
22
+ };
23
+ if (props.offsetY !== void 0) {
24
+ outerStyle = {
25
+ height: `${props.height}px`,
26
+ position: "relative",
27
+ overflow: "hidden"
28
+ };
29
+ innerStyle = {
30
+ ...innerStyle,
31
+ transform: `translateY(${props.offsetY}px)`,
32
+ [props.rtl ? "marginRight" : "marginLeft"]: `-${props.offsetX || 0}px`,
33
+ position: "absolute",
34
+ left: 0,
35
+ right: 0,
36
+ top: 0
37
+ };
38
+ }
39
+ return createVNode("div", { "style": outerStyle }, [createVNode(ResizeObserver, { "onResize": ({ offsetHeight }) => {
40
+ if (offsetHeight && props.onInnerResize) props.onInnerResize();
41
+ } }, { default: () => [createVNode("div", mergeProps({
42
+ "style": innerStyle,
43
+ "class": props.prefixCls ? `${props.prefixCls}-holder-inner` : void 0
44
+ }, props.innerProps), [slots.default?.(), props.extra])] })]);
45
+ };
46
+ }
54
47
  });
55
- export {
56
- u as default
57
- };
48
+ export { Filler_default as default };
package/dist/Item.cjs CHANGED
@@ -1 +1,26 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const o=require("@v-c/util/dist/props-util"),t=require("vue"),s=t.defineComponent({name:"Item",props:{setRef:{type:Function,required:!0}},setup(u,{slots:n}){const r=t.shallowRef(null),l=e=>{r.value!==e&&(r.value=e,u.setRef(e))};return()=>{const e=o.filterEmpty(n.default?.()??[])[0];return e?t.cloneVNode(e,{ref:l}):null}}});exports.default=s;
1
+ Object.defineProperty(exports, "__esModule", { value: true });
2
+ const require_rolldown_runtime = require("./_virtual/rolldown_runtime.cjs");
3
+ let vue = require("vue");
4
+ let __v_c_util_dist_props_util = require("@v-c/util/dist/props-util");
5
+ var Item_default = /* @__PURE__ */ (0, vue.defineComponent)({
6
+ name: "Item",
7
+ props: { setRef: {
8
+ type: Function,
9
+ required: true
10
+ } },
11
+ setup(props, { slots }) {
12
+ const currentElement = (0, vue.shallowRef)(null);
13
+ const refFunc = (node) => {
14
+ if (currentElement.value !== node) {
15
+ currentElement.value = node;
16
+ props.setRef(node);
17
+ }
18
+ };
19
+ return () => {
20
+ const child = (0, __v_c_util_dist_props_util.filterEmpty)(slots.default?.() ?? [])[0];
21
+ if (!child) return null;
22
+ return (0, vue.cloneVNode)(child, { ref: refFunc });
23
+ };
24
+ }
25
+ });
26
+ exports.default = Item_default;
package/dist/Item.js CHANGED
@@ -1,27 +1,24 @@
1
- import { filterEmpty as l } from "@v-c/util/dist/props-util";
2
- import { defineComponent as o, shallowRef as f, cloneVNode as m } from "vue";
3
- const i = /* @__PURE__ */ o({
4
- name: "Item",
5
- props: {
6
- setRef: {
7
- type: Function,
8
- required: !0
9
- }
10
- },
11
- setup(r, {
12
- slots: n
13
- }) {
14
- const t = f(null), u = (e) => {
15
- t.value !== e && (t.value = e, r.setRef(e));
16
- };
17
- return () => {
18
- const e = l(n.default?.() ?? [])[0];
19
- return e ? m(e, {
20
- ref: u
21
- }) : null;
22
- };
23
- }
1
+ import { cloneVNode, defineComponent, shallowRef } from "vue";
2
+ import { filterEmpty } from "@v-c/util/dist/props-util";
3
+ var Item_default = /* @__PURE__ */ defineComponent({
4
+ name: "Item",
5
+ props: { setRef: {
6
+ type: Function,
7
+ required: true
8
+ } },
9
+ setup(props, { slots }) {
10
+ const currentElement = shallowRef(null);
11
+ const refFunc = (node) => {
12
+ if (currentElement.value !== node) {
13
+ currentElement.value = node;
14
+ props.setRef(node);
15
+ }
16
+ };
17
+ return () => {
18
+ const child = filterEmpty(slots.default?.() ?? [])[0];
19
+ if (!child) return null;
20
+ return cloneVNode(child, { ref: refFunc });
21
+ };
22
+ }
24
23
  });
25
- export {
26
- i as default
27
- };
24
+ export { Item_default as default };
package/dist/List.cjs CHANGED
@@ -1 +1,412 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const n=require("vue"),ne=require("@v-c/resize-observer"),ie=require("./Filler.cjs"),ae=require("./hooks/useDiffItem.cjs"),oe=require("./hooks/useFrameWheel.cjs"),ue=require("./hooks/useGetSize.cjs"),re=require("./hooks/useHeights.cjs"),ce=require("./hooks/useMobileTouchMove.cjs"),se=require("./hooks/useScrollDrag.cjs"),fe=require("./Item.cjs"),de=require("./ScrollBar.cjs"),ve=require("./utils/scrollbarUtil.cjs");function j(l){return typeof l=="function"||Object.prototype.toString.call(l)==="[object Object]"&&!n.isVNode(l)}const he=[],ge={overflowY:"auto",overflowAnchor:"none"},me=n.defineComponent({name:"VirtualList",props:{prefixCls:{type:String,default:"vc-virtual-list"},data:{type:Array},height:Number,itemHeight:Number,fullHeight:{type:Boolean,default:!0},itemKey:{type:[String,Number,Function],required:!0},component:{type:String,default:"div"},virtual:{type:Boolean,default:!0},onScroll:Function,onVirtualScroll:Function,onVisibleChange:Function,innerProps:Object,extraRender:Function},setup(l,{expose:F,attrs:q,slots:K}){const v=e=>typeof l.itemKey=="function"?l.itemKey(e):e?.[l.itemKey],[_,L,g,P]=re.default(v,void 0,void 0),o=n.computed(()=>l.data||he),V=n.computed(()=>!!(l.virtual!==!1&&l.height&&l.itemHeight)),W=n.computed(()=>Object.values(g.maps).reduce((e,t)=>e+t,0)),h=n.computed(()=>{const e=o.value;return V.value&&e&&Math.max(l.itemHeight*e.length,W.value)>l.height}),H=n.ref(),z=n.ref(),O=n.ref(),A=n.shallowRef(),f=n.ref(0),y=n.ref(0),M=n.ref(!1),k=n.ref(0),B=n.ref(0);function m(e){let t;typeof e=="function"?t=e(f.value):t=e;const a=c.value-l.height,i=Math.max(0,Math.min(t,a||0));H.value&&(H.value.scrollTop=i),f.value=i}ae.default(o,v);const c=n.ref(0),S=n.ref(0),x=n.ref(0),b=n.ref(void 0);n.watch([()=>h.value,()=>V.value,()=>f.value,()=>o.value,()=>P.value,()=>l.height],()=>{if(!V.value){c.value=0,S.value=0,x.value=o.value.length-1,b.value=void 0;return}if(!h.value){c.value=z.value?.offsetHeight||0,S.value=0,x.value=o.value.length-1,b.value=void 0;return}let e=0,t,a,i;const r=o.value.length,d=o.value;for(let u=0;u<r;u+=1){const s=d[u],I=v(s),N=g.get(I),w=e+(N===void 0?l.itemHeight:N);w>=f.value&&t===void 0&&(t=u,a=e),w>f.value+l.height&&i===void 0&&(i=u),e=w}t===void 0&&(t=0,a=0,i=Math.ceil(l.height/l.itemHeight)),i===void 0&&(i=o.value.length-1),i=Math.min(i+1,o.value.length-1),c.value=e,S.value=t,x.value=i,b.value=a},{immediate:!0}),n.watch(()=>c.value,()=>{const e=g.getRecord();if(e.size===1){const t=Array.from(e.keys())[0],a=e.get(t),i=o.value[S.value];if(i&&a===void 0&&v(i)===t){const u=g.get(t)-l.itemHeight;m(s=>s+u)}}g.resetRecord()});const R=n.ref({width:0,height:l.height||0}),Y=e=>{R.value={width:e.offsetWidth,height:e.offsetHeight}},T=()=>({x:y.value,y:f.value}),C=n.ref(T()),D=e=>{if(l.onVirtualScroll){const t={...T(),...e};(C.value.x!==t.x||C.value.y!==t.y)&&(l.onVirtualScroll(t),C.value=t)}},X=n.computed(()=>f.value===0),E=n.computed(()=>f.value+l.height>=c.value),G=n.computed(()=>y.value===0),U=n.computed(()=>y.value+R.value.width>=B.value),$=()=>{A.value?.delayHidden()},[J]=oe.default(h,X,E,G,U,!1,(e,t)=>{t||m(a=>a+e)});ce.default(h,H,(e,t,a,i)=>e?!1:(m(r=>r+t),!0)),se.default(h,H,e=>{m(t=>t+e)});const Q=(e,t)=>{t||m(e)},Z=()=>{M.value=!0},p=()=>{M.value=!1};n.watch([()=>l.height,()=>c.value,()=>h.value,()=>R.value.height],()=>{h.value&&l.height&&c.value&&(k.value=ve.getSpinSize(R.value.height,c.value))},{immediate:!0});function ee(e){const a=e.currentTarget.scrollTop;a!==f.value&&m(a),l.onScroll?.(e),D()}F({nativeElement:O,getScrollInfo:T,scrollTo:e=>{if(e!=null){if(typeof e=="number")m(e);else if(e&&typeof e=="object"){let t;if("left"in e&&(y.value=e.left||0),"top"in e)t=e.top;else if("index"in e){const a=e.index||0;if(o.value[a]){let r=0;for(let d=0;d<a;d+=1){const u=v(o.value[d]),s=g.get(u);r+=s===void 0?l.itemHeight:s}t=r}}else if("key"in e){const a=o.value.findIndex(i=>v(i)===e.key);if(a>=0){let i=0;for(let r=0;r<a;r+=1){const d=v(o.value[r]),u=g.get(d);i+=u===void 0?l.itemHeight:u}t=i}}t!==void 0&&m(t)}}}}),n.watch([()=>S.value,()=>x.value,()=>o.value],()=>{if(l.onVisibleChange){const e=o.value.slice(S.value,x.value+1);l.onVisibleChange(e,o.value)}});const te=()=>{const e=[],t=o.value,a=K.default;if(!a)return e;for(let i=S.value;i<=x.value;i+=1){const r=t[i],d=v(r),u=a({item:r,index:i,style:{},offsetX:y.value}),s=Array.isArray(u)?u[0]:u;s&&e.push(n.createVNode(fe.default,{key:d,setRef:I=>_(r,I)},j(s)?s:{default:()=>[s]}))}return e},le=ue.useGetSize(o,v,g,l.itemHeight);return()=>{let e;const t={};l.height&&(t[l.fullHeight?"height":"maxHeight"]=`${l.height}px`,Object.assign(t,ge),V.value&&(t.overflowY="hidden",B.value&&(t.overflowX="hidden"),M.value&&(t.pointerEvents="none")));const a=l.extraRender?.({start:S.value,end:x.value,virtual:h.value,offsetX:y.value,offsetY:b.value||0,rtl:!1,getSize:le.value}),i=l.component;return n.createVNode("div",{ref:O,style:{position:"relative",...q.style},class:[l.prefixCls,q.class]},[n.createVNode(ne,{onResize:Y},{default:()=>[n.createVNode(i,{class:`${l.prefixCls}-holder`,style:t,ref:H,onScroll:ee,onWheel:J,onMouseenter:$},{default:()=>[n.createVNode(ie.default,{prefixCls:l.prefixCls,height:c.value,offsetX:y.value,offsetY:b.value,onInnerResize:L,ref:z,innerProps:l.innerProps,rtl:!1,extra:a},j(e=te())?e:{default:()=>[e]})]})]}),h.value&&c.value>(l.height||0)&&n.createVNode(de.default,{ref:A,prefixCls:l.prefixCls,scrollOffset:f.value,scrollRange:c.value,rtl:!1,onScroll:Q,onStartMove:Z,onStopMove:p,spinSize:k.value,containerSize:R.value.height,showScrollBar:"optional"},null)])}}});exports.default=me;
1
+ Object.defineProperty(exports, "__esModule", { value: true });
2
+ const require_rolldown_runtime = require("./_virtual/rolldown_runtime.cjs");
3
+ const require_Filler = require("./Filler.cjs");
4
+ const require_Item = require("./Item.cjs");
5
+ const require_useDiffItem = require("./hooks/useDiffItem.cjs");
6
+ const require_useFrameWheel = require("./hooks/useFrameWheel.cjs");
7
+ const require_useGetSize = require("./hooks/useGetSize.cjs");
8
+ const require_useHeights = require("./hooks/useHeights.cjs");
9
+ const require_useMobileTouchMove = require("./hooks/useMobileTouchMove.cjs");
10
+ const require_useScrollDrag = require("./hooks/useScrollDrag.cjs");
11
+ const require_useScrollTo = require("./hooks/useScrollTo.cjs");
12
+ const require_ScrollBar = require("./ScrollBar.cjs");
13
+ const require_scrollbarUtil = require("./utils/scrollbarUtil.cjs");
14
+ let vue = require("vue");
15
+ let __v_c_resize_observer = require("@v-c/resize-observer");
16
+ __v_c_resize_observer = require_rolldown_runtime.__toESM(__v_c_resize_observer);
17
+ let __v_c_util_dist_props_util = require("@v-c/util/dist/props-util");
18
+ function _isSlot(s) {
19
+ return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !(0, vue.isVNode)(s);
20
+ }
21
+ var EMPTY_DATA = [];
22
+ var ScrollStyle = {
23
+ overflowY: "auto",
24
+ overflowAnchor: "none"
25
+ };
26
+ var List_default = /* @__PURE__ */ (0, vue.defineComponent)({
27
+ name: "VirtualList",
28
+ props: {
29
+ prefixCls: {
30
+ type: String,
31
+ default: "vc-virtual-list"
32
+ },
33
+ data: { type: Array },
34
+ height: Number,
35
+ itemHeight: Number,
36
+ fullHeight: {
37
+ type: Boolean,
38
+ default: true
39
+ },
40
+ itemKey: {
41
+ type: [
42
+ String,
43
+ Number,
44
+ Function
45
+ ],
46
+ required: true
47
+ },
48
+ component: {
49
+ type: String,
50
+ default: "div"
51
+ },
52
+ direction: { type: String },
53
+ scrollWidth: Number,
54
+ styles: Object,
55
+ showScrollBar: {
56
+ type: [Boolean, String],
57
+ default: "optional"
58
+ },
59
+ virtual: {
60
+ type: Boolean,
61
+ default: true
62
+ },
63
+ onScroll: Function,
64
+ onVirtualScroll: Function,
65
+ onVisibleChange: Function,
66
+ innerProps: Object,
67
+ extraRender: Function
68
+ },
69
+ inheritAttrs: false,
70
+ setup(props, { expose, attrs, slots }) {
71
+ const itemHeight = (0, vue.computed)(() => props.itemHeight);
72
+ const itemKey = (0, vue.toRef)(props, "itemKey");
73
+ const getKey = (item) => {
74
+ item = (0, vue.toRaw)(item);
75
+ const _itemKey = itemKey.value;
76
+ if (typeof _itemKey === "function") return _itemKey(item);
77
+ return item?.[_itemKey];
78
+ };
79
+ const [setInstanceRef, collectHeight, heights, heightUpdatedMark] = require_useHeights.default(getKey, void 0, void 0);
80
+ const mergedData = (0, vue.computed)(() => props.data || EMPTY_DATA);
81
+ const useVirtual = (0, vue.computed)(() => !!(props.virtual !== false && props.height && props.itemHeight));
82
+ const containerHeight = (0, vue.computed)(() => Object.values(heights.maps).reduce((total, curr) => total + curr, 0));
83
+ const inVirtual = (0, vue.computed)(() => {
84
+ const data = mergedData.value;
85
+ return useVirtual.value && data && (Math.max(props.itemHeight * data.length, containerHeight.value) > props.height || !!props.scrollWidth);
86
+ });
87
+ const componentRef = (0, vue.ref)();
88
+ const fillerInnerRef = (0, vue.ref)();
89
+ const containerRef = (0, vue.ref)();
90
+ const verticalScrollBarRef = (0, vue.shallowRef)();
91
+ const horizontalScrollBarRef = (0, vue.shallowRef)();
92
+ const offsetTop = (0, vue.ref)(0);
93
+ const offsetLeft = (0, vue.ref)(0);
94
+ const scrollMoving = (0, vue.ref)(false);
95
+ const verticalScrollBarSpinSize = (0, vue.ref)(0);
96
+ const horizontalScrollBarSpinSize = (0, vue.ref)(0);
97
+ const contentScrollWidth = (0, vue.ref)(props.scrollWidth || 0);
98
+ const scrollHeight = (0, vue.ref)(0);
99
+ const start = (0, vue.ref)(0);
100
+ const end = (0, vue.ref)(0);
101
+ const fillerOffset = (0, vue.ref)(void 0);
102
+ function syncScrollTop(newTop) {
103
+ let value;
104
+ if (typeof newTop === "function") value = newTop(offsetTop.value);
105
+ else value = newTop;
106
+ const maxScrollHeight = scrollHeight.value - props.height;
107
+ const alignedTop = Math.max(0, Math.min(value, maxScrollHeight || 0));
108
+ if (componentRef.value) componentRef.value.scrollTop = alignedTop;
109
+ offsetTop.value = alignedTop;
110
+ }
111
+ require_useDiffItem.default(mergedData, getKey);
112
+ (0, vue.watch)([
113
+ inVirtual,
114
+ useVirtual,
115
+ offsetTop,
116
+ mergedData,
117
+ heightUpdatedMark,
118
+ () => props.height
119
+ ], () => {
120
+ if (!useVirtual.value) {
121
+ scrollHeight.value = 0;
122
+ start.value = 0;
123
+ end.value = mergedData.value.length - 1;
124
+ fillerOffset.value = void 0;
125
+ return;
126
+ }
127
+ const { itemHeight: itemHeight$1, height } = props;
128
+ if (!inVirtual.value) {
129
+ scrollHeight.value = fillerInnerRef.value?.offsetHeight || 0;
130
+ start.value = 0;
131
+ end.value = mergedData.value.length - 1;
132
+ fillerOffset.value = void 0;
133
+ return;
134
+ }
135
+ let itemTop = 0;
136
+ let startIndex;
137
+ let startOffset;
138
+ let endIndex;
139
+ const dataLen = mergedData.value.length;
140
+ const data = (0, vue.toRaw)(mergedData.value);
141
+ for (let i = 0; i < dataLen; i += 1) {
142
+ const item = data[i];
143
+ const key = getKey(item);
144
+ const cacheHeight = heights.get(key);
145
+ const currentItemBottom = itemTop + (cacheHeight === void 0 ? itemHeight$1 : cacheHeight);
146
+ if (currentItemBottom >= offsetTop.value && startIndex === void 0) {
147
+ startIndex = i;
148
+ startOffset = itemTop;
149
+ }
150
+ if (currentItemBottom > offsetTop.value + height && endIndex === void 0) endIndex = i;
151
+ itemTop = currentItemBottom;
152
+ }
153
+ if (startIndex === void 0) {
154
+ startIndex = 0;
155
+ startOffset = 0;
156
+ endIndex = Math.ceil(height / itemHeight$1);
157
+ }
158
+ if (endIndex === void 0) endIndex = mergedData.value.length - 1;
159
+ endIndex = Math.min(endIndex + 1, mergedData.value.length - 1);
160
+ scrollHeight.value = itemTop;
161
+ start.value = startIndex;
162
+ end.value = endIndex;
163
+ fillerOffset.value = startOffset;
164
+ }, { immediate: true });
165
+ (0, vue.watch)(scrollHeight, () => {
166
+ const changedRecord = heights.getRecord();
167
+ if (changedRecord.size === 1) {
168
+ const recordKey = Array.from(changedRecord.keys())[0];
169
+ const prevCacheHeight = changedRecord.get(recordKey);
170
+ const startItem = mergedData.value[start.value];
171
+ if (startItem && prevCacheHeight === void 0) {
172
+ if (getKey(startItem) === recordKey) {
173
+ const diffHeight = heights.get(recordKey) - props.itemHeight;
174
+ syncScrollTop((ori) => ori + diffHeight);
175
+ }
176
+ }
177
+ }
178
+ heights.resetRecord();
179
+ });
180
+ const size = (0, vue.ref)({
181
+ width: 0,
182
+ height: props.height || 0
183
+ });
184
+ const onHolderResize = (sizeInfo) => {
185
+ size.value = {
186
+ width: sizeInfo.offsetWidth,
187
+ height: sizeInfo.offsetHeight
188
+ };
189
+ contentScrollWidth.value = props.scrollWidth ?? sizeInfo.offsetWidth;
190
+ };
191
+ const isRTL = (0, vue.computed)(() => props.direction === "rtl");
192
+ const getVirtualScrollInfo = () => ({
193
+ x: isRTL.value ? -offsetLeft.value : offsetLeft.value,
194
+ y: offsetTop.value
195
+ });
196
+ const lastVirtualScrollInfo = (0, vue.ref)(getVirtualScrollInfo());
197
+ const triggerScroll = (params) => {
198
+ if (props.onVirtualScroll) {
199
+ const nextInfo = {
200
+ ...getVirtualScrollInfo(),
201
+ ...params
202
+ };
203
+ if (lastVirtualScrollInfo.value.x !== nextInfo.x || lastVirtualScrollInfo.value.y !== nextInfo.y) {
204
+ props.onVirtualScroll(nextInfo);
205
+ lastVirtualScrollInfo.value = nextInfo;
206
+ }
207
+ }
208
+ };
209
+ const horizontalRange = (0, vue.computed)(() => Math.max(0, (contentScrollWidth.value || 0) - size.value.width));
210
+ const isScrollAtTop = (0, vue.computed)(() => offsetTop.value === 0);
211
+ const isScrollAtBottom = (0, vue.computed)(() => offsetTop.value + props.height >= scrollHeight.value);
212
+ const isScrollAtLeft = (0, vue.computed)(() => offsetLeft.value === 0);
213
+ const isScrollAtRight = (0, vue.computed)(() => offsetLeft.value >= horizontalRange.value);
214
+ const keepInHorizontalRange = (nextOffsetLeft) => {
215
+ const max = horizontalRange.value;
216
+ return Math.max(0, Math.min(nextOffsetLeft, max));
217
+ };
218
+ const delayHideScrollBar = () => {
219
+ verticalScrollBarRef.value?.delayHidden();
220
+ horizontalScrollBarRef.value?.delayHidden();
221
+ };
222
+ const [onWheel] = require_useFrameWheel.default(inVirtual, isScrollAtTop, isScrollAtBottom, isScrollAtLeft, isScrollAtRight, horizontalRange.value > 0, (offsetY, isHorizontal) => {
223
+ if (isHorizontal) {
224
+ const aligned = keepInHorizontalRange(isRTL.value ? offsetLeft.value - offsetY : offsetLeft.value + offsetY);
225
+ offsetLeft.value = aligned;
226
+ triggerScroll({ x: isRTL.value ? -aligned : aligned });
227
+ } else syncScrollTop((top) => top + offsetY);
228
+ });
229
+ require_useMobileTouchMove.default(inVirtual, componentRef, (isHorizontal, offset, _smoothOffset, _e) => {
230
+ if (isHorizontal) {
231
+ const aligned = keepInHorizontalRange(isRTL.value ? offsetLeft.value - offset : offsetLeft.value + offset);
232
+ offsetLeft.value = aligned;
233
+ triggerScroll({ x: isRTL.value ? -aligned : aligned });
234
+ return true;
235
+ } else {
236
+ syncScrollTop((top) => top + offset);
237
+ return true;
238
+ }
239
+ });
240
+ require_useScrollDrag.default(inVirtual, componentRef, (offset) => {
241
+ syncScrollTop((top) => top + offset);
242
+ });
243
+ const onScrollBar = (newScrollOffset, horizontal) => {
244
+ const newOffset = newScrollOffset;
245
+ if (horizontal) {
246
+ offsetLeft.value = newOffset;
247
+ triggerScroll({ x: isRTL.value ? -newOffset : newOffset });
248
+ } else syncScrollTop(newOffset);
249
+ };
250
+ const onScrollbarStartMove = () => {
251
+ scrollMoving.value = true;
252
+ };
253
+ const onScrollbarStopMove = () => {
254
+ scrollMoving.value = false;
255
+ };
256
+ (0, vue.watch)([
257
+ () => props.height,
258
+ scrollHeight,
259
+ inVirtual,
260
+ () => size.value.height
261
+ ], () => {
262
+ if (inVirtual.value && props.height && scrollHeight.value) verticalScrollBarSpinSize.value = require_scrollbarUtil.getSpinSize(size.value.height, scrollHeight.value);
263
+ }, { immediate: true });
264
+ (0, vue.watch)([() => size.value.width, () => contentScrollWidth.value], () => {
265
+ if (inVirtual.value && contentScrollWidth.value) horizontalScrollBarSpinSize.value = require_scrollbarUtil.getSpinSize(size.value.width, contentScrollWidth.value);
266
+ }, { immediate: true });
267
+ (0, vue.watch)(() => props.scrollWidth, (val) => {
268
+ contentScrollWidth.value = val ?? size.value.width;
269
+ offsetLeft.value = keepInHorizontalRange(offsetLeft.value);
270
+ }, { immediate: true });
271
+ function onFallbackScroll(e) {
272
+ const newScrollTop = e.currentTarget.scrollTop;
273
+ if (newScrollTop !== offsetTop.value) syncScrollTop(newScrollTop);
274
+ props.onScroll?.(e);
275
+ triggerScroll();
276
+ }
277
+ const scrollTo = require_useScrollTo.default(componentRef, mergedData, heights, itemHeight, getKey, () => collectHeight(true), syncScrollTop, delayHideScrollBar);
278
+ expose({
279
+ nativeElement: containerRef,
280
+ getScrollInfo: getVirtualScrollInfo,
281
+ scrollTo: (config) => {
282
+ function isPosScroll(arg) {
283
+ return arg && typeof arg === "object" && ("left" in arg || "top" in arg);
284
+ }
285
+ if (isPosScroll(config)) {
286
+ if (config.left !== void 0) offsetLeft.value = keepInHorizontalRange(config.left);
287
+ scrollTo(config.top);
288
+ } else scrollTo(config);
289
+ }
290
+ });
291
+ (0, vue.watch)([
292
+ start,
293
+ end,
294
+ mergedData
295
+ ], () => {
296
+ if (props.onVisibleChange) {
297
+ const renderList = mergedData.value.slice(start.value, end.value + 1);
298
+ props.onVisibleChange(renderList, mergedData.value);
299
+ }
300
+ });
301
+ const getSize = require_useGetSize.useGetSize(mergedData, getKey, heights, itemHeight);
302
+ return () => {
303
+ let _slot;
304
+ const renderChildren = () => {
305
+ const children = [];
306
+ const data = mergedData.value;
307
+ const defaultSlot = slots.default;
308
+ if (!defaultSlot) return children;
309
+ for (let i = start.value; i <= end.value; i += 1) {
310
+ const item = data[i];
311
+ const key = getKey(item);
312
+ const nodes = defaultSlot({
313
+ item,
314
+ index: i,
315
+ style: {},
316
+ offsetX: offsetLeft.value
317
+ });
318
+ const node = Array.isArray(nodes) ? nodes[0] : nodes;
319
+ if (node) children.push((0, vue.createVNode)(require_Item.default, {
320
+ "key": key,
321
+ "setRef": (ele) => setInstanceRef(item, ele)
322
+ }, _isSlot(node) ? node : { default: () => [node] }));
323
+ }
324
+ return children;
325
+ };
326
+ const componentStyle = {};
327
+ if (props.height) {
328
+ componentStyle[props.fullHeight ? "height" : "maxHeight"] = `${props.height}px`;
329
+ Object.assign(componentStyle, ScrollStyle);
330
+ if (useVirtual.value) {
331
+ componentStyle.overflowY = "hidden";
332
+ if (horizontalRange.value > 0) componentStyle.overflowX = "hidden";
333
+ if (scrollMoving.value) componentStyle.pointerEvents = "none";
334
+ }
335
+ }
336
+ const extraContent = props.extraRender?.({
337
+ start: start.value,
338
+ end: end.value,
339
+ virtual: inVirtual.value,
340
+ offsetX: offsetLeft.value,
341
+ offsetY: fillerOffset.value || 0,
342
+ rtl: isRTL.value,
343
+ getSize: getSize.value
344
+ });
345
+ const Component = props.component;
346
+ return (0, vue.createVNode)("div", (0, vue.mergeProps)({ "ref": containerRef }, (0, __v_c_util_dist_props_util.pureAttrs)(attrs), {
347
+ "style": {
348
+ position: "relative",
349
+ ...attrs.style
350
+ },
351
+ "dir": isRTL.value ? "rtl" : void 0,
352
+ "class": [
353
+ props.prefixCls,
354
+ { [`${props.prefixCls}-rtl`]: isRTL.value },
355
+ attrs.class
356
+ ]
357
+ }), [
358
+ (0, vue.createVNode)(__v_c_resize_observer.default, { "onResize": onHolderResize }, { default: () => [(0, vue.createVNode)(Component, {
359
+ "class": `${props.prefixCls}-holder`,
360
+ "style": componentStyle,
361
+ "ref": componentRef,
362
+ "onScroll": onFallbackScroll,
363
+ "onWheel": onWheel,
364
+ "onMouseenter": delayHideScrollBar
365
+ }, { default: () => [(0, vue.createVNode)(require_Filler.default, {
366
+ "prefixCls": props.prefixCls,
367
+ "height": scrollHeight.value,
368
+ "offsetX": offsetLeft.value,
369
+ "offsetY": fillerOffset.value,
370
+ "scrollWidth": contentScrollWidth.value,
371
+ "onInnerResize": collectHeight,
372
+ "ref": fillerInnerRef,
373
+ "innerProps": props.innerProps,
374
+ "rtl": isRTL.value,
375
+ "extra": extraContent
376
+ }, _isSlot(_slot = renderChildren()) ? _slot : { default: () => [_slot] })] })] }),
377
+ inVirtual.value && scrollHeight.value > (props.height || 0) && (0, vue.createVNode)(require_ScrollBar.default, {
378
+ "ref": verticalScrollBarRef,
379
+ "prefixCls": props.prefixCls,
380
+ "scrollOffset": offsetTop.value,
381
+ "scrollRange": scrollHeight.value,
382
+ "rtl": isRTL.value,
383
+ "onScroll": onScrollBar,
384
+ "onStartMove": onScrollbarStartMove,
385
+ "onStopMove": onScrollbarStopMove,
386
+ "spinSize": verticalScrollBarSpinSize.value,
387
+ "containerSize": size.value.height,
388
+ "showScrollBar": props.showScrollBar,
389
+ "style": props.styles?.verticalScrollBar,
390
+ "thumbStyle": props.styles?.verticalScrollBarThumb
391
+ }, null),
392
+ inVirtual.value && contentScrollWidth.value > size.value.width && (0, vue.createVNode)(require_ScrollBar.default, {
393
+ "ref": horizontalScrollBarRef,
394
+ "prefixCls": props.prefixCls,
395
+ "scrollOffset": offsetLeft.value,
396
+ "scrollRange": contentScrollWidth.value,
397
+ "rtl": isRTL.value,
398
+ "onScroll": onScrollBar,
399
+ "onStartMove": onScrollbarStartMove,
400
+ "onStopMove": onScrollbarStopMove,
401
+ "spinSize": horizontalScrollBarSpinSize.value,
402
+ "containerSize": size.value.width,
403
+ "horizontal": true,
404
+ "showScrollBar": props.showScrollBar,
405
+ "style": props.styles?.horizontalScrollBar,
406
+ "thumbStyle": props.styles?.horizontalScrollBarThumb
407
+ }, null)
408
+ ]);
409
+ };
410
+ }
411
+ });
412
+ exports.default = List_default;