@hoci/components 0.8.0 → 0.8.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/dist/index.cjs CHANGED
@@ -1266,7 +1266,7 @@ function notUndefined(value, msg) {
1266
1266
  return value;
1267
1267
  }
1268
1268
  }
1269
- const approxEqual = (a, b) => Math.abs(a - b) <= 1;
1269
+ const approxEqual = (a, b) => Math.abs(a - b) < 1.01;
1270
1270
  const debounce = (targetWindow, fn, ms) => {
1271
1271
  let timeoutId;
1272
1272
  return function(...args) {
@@ -1397,7 +1397,6 @@ class Virtualizer {
1397
1397
  this.scrollElement = null;
1398
1398
  this.targetWindow = null;
1399
1399
  this.isScrolling = false;
1400
- this.scrollToIndexTimeoutId = null;
1401
1400
  this.measurementsCache = [];
1402
1401
  this.itemSizeCache = /* @__PURE__ */ new Map();
1403
1402
  this.pendingMeasuredCacheIndexes = [];
@@ -1813,7 +1812,7 @@ class Virtualizer {
1813
1812
  } else if (align === "end") {
1814
1813
  toOffset -= size;
1815
1814
  }
1816
- const maxOffset = this.getTotalSize() - size;
1815
+ const maxOffset = this.getTotalSize() + this.options.scrollMargin - size;
1817
1816
  return Math.max(Math.min(maxOffset, toOffset), 0);
1818
1817
  };
1819
1818
  this.getOffsetForIndex = (index, align = "auto") => {
@@ -1840,14 +1839,7 @@ class Virtualizer {
1840
1839
  ];
1841
1840
  };
1842
1841
  this.isDynamicMode = () => this.elementsCache.size > 0;
1843
- this.cancelScrollToIndex = () => {
1844
- if (this.scrollToIndexTimeoutId !== null && this.targetWindow) {
1845
- this.targetWindow.clearTimeout(this.scrollToIndexTimeoutId);
1846
- this.scrollToIndexTimeoutId = null;
1847
- }
1848
- };
1849
1842
  this.scrollToOffset = (toOffset, { align = "start", behavior } = {}) => {
1850
- this.cancelScrollToIndex();
1851
1843
  if (behavior === "smooth" && this.isDynamicMode()) {
1852
1844
  console.warn(
1853
1845
  "The `smooth` scroll behavior is not fully supported with dynamic size."
@@ -1859,39 +1851,52 @@ class Virtualizer {
1859
1851
  });
1860
1852
  };
1861
1853
  this.scrollToIndex = (index, { align: initialAlign = "auto", behavior } = {}) => {
1862
- index = Math.max(0, Math.min(index, this.options.count - 1));
1863
- this.cancelScrollToIndex();
1864
1854
  if (behavior === "smooth" && this.isDynamicMode()) {
1865
1855
  console.warn(
1866
1856
  "The `smooth` scroll behavior is not fully supported with dynamic size."
1867
1857
  );
1868
1858
  }
1869
- const offsetAndAlign = this.getOffsetForIndex(index, initialAlign);
1870
- if (!offsetAndAlign) return;
1871
- const [offset, align] = offsetAndAlign;
1872
- this._scrollToOffset(offset, { adjustments: void 0, behavior });
1873
- if (behavior !== "smooth" && this.isDynamicMode() && this.targetWindow) {
1874
- this.scrollToIndexTimeoutId = this.targetWindow.setTimeout(() => {
1875
- this.scrollToIndexTimeoutId = null;
1876
- const elementInDOM = this.elementsCache.has(
1877
- this.options.getItemKey(index)
1878
- );
1879
- if (elementInDOM) {
1880
- const [latestOffset] = notUndefined(
1881
- this.getOffsetForIndex(index, align)
1882
- );
1883
- const currentScrollOffset = this.getScrollOffset();
1884
- if (!approxEqual(latestOffset, currentScrollOffset)) {
1885
- this.scrollToIndex(index, { align, behavior });
1886
- }
1887
- } else {
1888
- this.scrollToIndex(index, { align, behavior });
1859
+ index = Math.max(0, Math.min(index, this.options.count - 1));
1860
+ let attempts = 0;
1861
+ const maxAttempts = 10;
1862
+ const tryScroll = (currentAlign) => {
1863
+ if (!this.targetWindow) return;
1864
+ const offsetInfo = this.getOffsetForIndex(index, currentAlign);
1865
+ if (!offsetInfo) {
1866
+ console.warn("Failed to get offset for index:", index);
1867
+ return;
1868
+ }
1869
+ const [offset, align] = offsetInfo;
1870
+ this._scrollToOffset(offset, { adjustments: void 0, behavior });
1871
+ this.targetWindow.requestAnimationFrame(() => {
1872
+ const currentOffset = this.getScrollOffset();
1873
+ const afterInfo = this.getOffsetForIndex(index, align);
1874
+ if (!afterInfo) {
1875
+ console.warn("Failed to get offset for index:", index);
1876
+ return;
1877
+ }
1878
+ if (!approxEqual(afterInfo[0], currentOffset)) {
1879
+ scheduleRetry(align);
1889
1880
  }
1890
1881
  });
1891
- }
1882
+ };
1883
+ const scheduleRetry = (align) => {
1884
+ if (!this.targetWindow) return;
1885
+ attempts++;
1886
+ if (attempts < maxAttempts) {
1887
+ if (process.env.NODE_ENV !== "production" && this.options.debug) {
1888
+ console.info("Schedule retry", attempts, maxAttempts);
1889
+ }
1890
+ this.targetWindow.requestAnimationFrame(() => tryScroll(align));
1891
+ } else {
1892
+ console.warn(
1893
+ `Failed to scroll to index ${index} after ${maxAttempts} attempts.`
1894
+ );
1895
+ }
1896
+ };
1897
+ tryScroll(initialAlign);
1892
1898
  };
1893
1899
  this.scrollBy = (delta, { behavior } = {}) => {
1894
- this.cancelScrollToIndex();
1895
1900
  if (behavior === "smooth" && this.isDynamicMode()) {
1896
1901
  console.warn(
1897
1902
  "The `smooth` scroll behavior is not fully supported with dynamic size."
package/dist/index.d.cts CHANGED
@@ -60,11 +60,11 @@ declare const HiAffix: vue.DefineComponent<vue.ExtractPropTypes<{
60
60
  default: number;
61
61
  };
62
62
  }>> & Readonly<{}>, {
63
+ as: string;
63
64
  fixedClass: string;
64
65
  offset: number;
65
66
  position: "top" | "bottom";
66
67
  zIndex: number;
67
- as: string;
68
68
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
69
69
 
70
70
  declare const HiConfigProvider: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -131,9 +131,9 @@ declare const HiFileUpload: vue.DefineComponent<vue.ExtractPropTypes<{
131
131
  onChange?: ((...args: any[]) => any) | undefined;
132
132
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
133
133
  }>, {
134
- multiple: boolean;
135
- modelValue: File | File[];
136
134
  as: string;
135
+ modelValue: File | File[];
136
+ multiple: boolean;
137
137
  accept: string;
138
138
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
139
139
 
@@ -192,9 +192,9 @@ declare const HiIcon: vue.DefineComponent<vue.ExtractPropTypes<{
192
192
  default: () => "auto";
193
193
  };
194
194
  }>> & Readonly<{}>, {
195
- mask: boolean | "auto";
196
- color: string;
197
195
  as: string;
196
+ color: string;
197
+ mask: boolean | "auto";
198
198
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
199
199
 
200
200
  declare const HiItem: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -248,10 +248,10 @@ declare const HiItem: vue.DefineComponent<vue.ExtractPropTypes<{
248
248
  }>> & Readonly<{
249
249
  onReject?: ((...args: any[]) => any) | undefined;
250
250
  }>, {
251
+ as: string;
251
252
  value: any;
252
253
  disabled: boolean;
253
254
  keepAlive: boolean;
254
- as: string;
255
255
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
256
256
 
257
257
  declare const HiPopover: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -332,14 +332,14 @@ declare const HiPopover: vue.DefineComponent<vue.ExtractPropTypes<{
332
332
  onChange?: ((...args: any[]) => any) | undefined;
333
333
  "onUpdate:visible"?: ((...args: any[]) => any) | undefined;
334
334
  }>, {
335
+ as: string;
335
336
  offset: number;
336
- visible: boolean;
337
337
  disabled: boolean;
338
+ visible: boolean;
338
339
  placement: _hoci_core.Placement;
339
340
  triggerEvent: _hoci_core.TriggerEvent;
340
341
  lazy: boolean;
341
342
  teleport: string | boolean | HTMLElement;
342
- as: string;
343
343
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
344
344
 
345
345
  declare const HiSelection: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -386,7 +386,7 @@ declare const HiSelection: vue.DefineComponent<vue.ExtractPropTypes<{
386
386
  };
387
387
  }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
388
388
  [key: string]: any;
389
- }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("change" | "load" | "unload" | "update:modelValue" | "reject")[], "change" | "load" | "unload" | "update:modelValue" | "reject", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
389
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("change" | "load" | "update:modelValue" | "unload" | "reject")[], "change" | "load" | "update:modelValue" | "unload" | "reject", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
390
390
  as: {
391
391
  type: StringConstructor;
392
392
  default: string;
@@ -432,18 +432,18 @@ declare const HiSelection: vue.DefineComponent<vue.ExtractPropTypes<{
432
432
  onChange?: ((...args: any[]) => any) | undefined;
433
433
  onLoad?: ((...args: any[]) => any) | undefined;
434
434
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
435
- onReject?: ((...args: any[]) => any) | undefined;
436
435
  onUnload?: ((...args: any[]) => any) | undefined;
436
+ onReject?: ((...args: any[]) => any) | undefined;
437
437
  }>, {
438
- multiple: number | boolean | [number, (number | undefined)?];
438
+ as: string;
439
439
  modelValue: any;
440
+ multiple: number | boolean | [number, (number | undefined)?];
440
441
  activeClass: string | string[] | Record<string, boolean>;
441
442
  itemClass: string | string[] | Record<string, boolean>;
442
443
  disabledClass: string | string[] | Record<string, boolean>;
443
444
  unactiveClass: string | string[] | Record<string, boolean>;
444
445
  clearable: boolean;
445
446
  defaultValue: any;
446
- as: string;
447
447
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
448
448
 
449
449
  declare const HiSwitch: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -509,9 +509,9 @@ declare const HiSwitch: vue.DefineComponent<vue.ExtractPropTypes<{
509
509
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
510
510
  onReject?: ((...args: any[]) => any) | undefined;
511
511
  }>, {
512
- disabled: boolean;
513
- modelValue: boolean;
514
512
  as: string;
513
+ modelValue: boolean;
514
+ disabled: boolean;
515
515
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
516
516
 
517
517
  declare const HiTabPane: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -685,8 +685,9 @@ declare const HiTabs: vue.DefineComponent<vue.ExtractPropTypes<{
685
685
  type: PropType<_hoci_shared.ActivateEvent>;
686
686
  };
687
687
  }>> & Readonly<{}>, {
688
- multiple: number | boolean | [number, (number | undefined)?];
688
+ as: string;
689
689
  modelValue: any;
690
+ multiple: number | boolean | [number, (number | undefined)?];
690
691
  activeClass: string | string[] | Record<string, boolean>;
691
692
  itemClass: string | string[] | Record<string, boolean>;
692
693
  disabledClass: string | string[] | Record<string, boolean>;
@@ -694,7 +695,6 @@ declare const HiTabs: vue.DefineComponent<vue.ExtractPropTypes<{
694
695
  clearable: boolean;
695
696
  defaultValue: any;
696
697
  keepAlive: boolean | KeepAliveProps;
697
- as: string;
698
698
  headerAs: string;
699
699
  contentAs: string;
700
700
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
@@ -778,11 +778,11 @@ declare const HiVirtualList: vue.DefineComponent<vue.ExtractPropTypes<{
778
778
  onScrollEnd?: (() => any) | undefined;
779
779
  onScrollStart?: (() => any) | undefined;
780
780
  }>, {
781
+ as: string;
781
782
  horizontal: boolean;
783
+ options: _tanstack_virtual_core.PartialKeys<VirtualizerOptions<HTMLElement, HTMLElement>, "observeElementRect" | "observeElementOffset" | "scrollToFn" | "getScrollElement">;
782
784
  count: number;
783
785
  estimateSize: number | ((index: number) => number);
784
- options: _tanstack_virtual_core.PartialKeys<VirtualizerOptions<HTMLElement, HTMLElement>, "observeElementRect" | "observeElementOffset" | "scrollToFn" | "getScrollElement">;
785
- as: string;
786
786
  wrapperAs: string;
787
787
  wrapperStyle: CSSProperties;
788
788
  wrapperClass: string | string[] | Record<string, boolean>;
package/dist/index.d.mts CHANGED
@@ -60,11 +60,11 @@ declare const HiAffix: vue.DefineComponent<vue.ExtractPropTypes<{
60
60
  default: number;
61
61
  };
62
62
  }>> & Readonly<{}>, {
63
+ as: string;
63
64
  fixedClass: string;
64
65
  offset: number;
65
66
  position: "top" | "bottom";
66
67
  zIndex: number;
67
- as: string;
68
68
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
69
69
 
70
70
  declare const HiConfigProvider: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -131,9 +131,9 @@ declare const HiFileUpload: vue.DefineComponent<vue.ExtractPropTypes<{
131
131
  onChange?: ((...args: any[]) => any) | undefined;
132
132
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
133
133
  }>, {
134
- multiple: boolean;
135
- modelValue: File | File[];
136
134
  as: string;
135
+ modelValue: File | File[];
136
+ multiple: boolean;
137
137
  accept: string;
138
138
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
139
139
 
@@ -192,9 +192,9 @@ declare const HiIcon: vue.DefineComponent<vue.ExtractPropTypes<{
192
192
  default: () => "auto";
193
193
  };
194
194
  }>> & Readonly<{}>, {
195
- mask: boolean | "auto";
196
- color: string;
197
195
  as: string;
196
+ color: string;
197
+ mask: boolean | "auto";
198
198
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
199
199
 
200
200
  declare const HiItem: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -248,10 +248,10 @@ declare const HiItem: vue.DefineComponent<vue.ExtractPropTypes<{
248
248
  }>> & Readonly<{
249
249
  onReject?: ((...args: any[]) => any) | undefined;
250
250
  }>, {
251
+ as: string;
251
252
  value: any;
252
253
  disabled: boolean;
253
254
  keepAlive: boolean;
254
- as: string;
255
255
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
256
256
 
257
257
  declare const HiPopover: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -332,14 +332,14 @@ declare const HiPopover: vue.DefineComponent<vue.ExtractPropTypes<{
332
332
  onChange?: ((...args: any[]) => any) | undefined;
333
333
  "onUpdate:visible"?: ((...args: any[]) => any) | undefined;
334
334
  }>, {
335
+ as: string;
335
336
  offset: number;
336
- visible: boolean;
337
337
  disabled: boolean;
338
+ visible: boolean;
338
339
  placement: _hoci_core.Placement;
339
340
  triggerEvent: _hoci_core.TriggerEvent;
340
341
  lazy: boolean;
341
342
  teleport: string | boolean | HTMLElement;
342
- as: string;
343
343
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
344
344
 
345
345
  declare const HiSelection: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -386,7 +386,7 @@ declare const HiSelection: vue.DefineComponent<vue.ExtractPropTypes<{
386
386
  };
387
387
  }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
388
388
  [key: string]: any;
389
- }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("change" | "load" | "unload" | "update:modelValue" | "reject")[], "change" | "load" | "unload" | "update:modelValue" | "reject", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
389
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("change" | "load" | "update:modelValue" | "unload" | "reject")[], "change" | "load" | "update:modelValue" | "unload" | "reject", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
390
390
  as: {
391
391
  type: StringConstructor;
392
392
  default: string;
@@ -432,18 +432,18 @@ declare const HiSelection: vue.DefineComponent<vue.ExtractPropTypes<{
432
432
  onChange?: ((...args: any[]) => any) | undefined;
433
433
  onLoad?: ((...args: any[]) => any) | undefined;
434
434
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
435
- onReject?: ((...args: any[]) => any) | undefined;
436
435
  onUnload?: ((...args: any[]) => any) | undefined;
436
+ onReject?: ((...args: any[]) => any) | undefined;
437
437
  }>, {
438
- multiple: number | boolean | [number, (number | undefined)?];
438
+ as: string;
439
439
  modelValue: any;
440
+ multiple: number | boolean | [number, (number | undefined)?];
440
441
  activeClass: string | string[] | Record<string, boolean>;
441
442
  itemClass: string | string[] | Record<string, boolean>;
442
443
  disabledClass: string | string[] | Record<string, boolean>;
443
444
  unactiveClass: string | string[] | Record<string, boolean>;
444
445
  clearable: boolean;
445
446
  defaultValue: any;
446
- as: string;
447
447
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
448
448
 
449
449
  declare const HiSwitch: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -509,9 +509,9 @@ declare const HiSwitch: vue.DefineComponent<vue.ExtractPropTypes<{
509
509
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
510
510
  onReject?: ((...args: any[]) => any) | undefined;
511
511
  }>, {
512
- disabled: boolean;
513
- modelValue: boolean;
514
512
  as: string;
513
+ modelValue: boolean;
514
+ disabled: boolean;
515
515
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
516
516
 
517
517
  declare const HiTabPane: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -685,8 +685,9 @@ declare const HiTabs: vue.DefineComponent<vue.ExtractPropTypes<{
685
685
  type: PropType<_hoci_shared.ActivateEvent>;
686
686
  };
687
687
  }>> & Readonly<{}>, {
688
- multiple: number | boolean | [number, (number | undefined)?];
688
+ as: string;
689
689
  modelValue: any;
690
+ multiple: number | boolean | [number, (number | undefined)?];
690
691
  activeClass: string | string[] | Record<string, boolean>;
691
692
  itemClass: string | string[] | Record<string, boolean>;
692
693
  disabledClass: string | string[] | Record<string, boolean>;
@@ -694,7 +695,6 @@ declare const HiTabs: vue.DefineComponent<vue.ExtractPropTypes<{
694
695
  clearable: boolean;
695
696
  defaultValue: any;
696
697
  keepAlive: boolean | KeepAliveProps;
697
- as: string;
698
698
  headerAs: string;
699
699
  contentAs: string;
700
700
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
@@ -778,11 +778,11 @@ declare const HiVirtualList: vue.DefineComponent<vue.ExtractPropTypes<{
778
778
  onScrollEnd?: (() => any) | undefined;
779
779
  onScrollStart?: (() => any) | undefined;
780
780
  }>, {
781
+ as: string;
781
782
  horizontal: boolean;
783
+ options: _tanstack_virtual_core.PartialKeys<VirtualizerOptions<HTMLElement, HTMLElement>, "observeElementRect" | "observeElementOffset" | "scrollToFn" | "getScrollElement">;
782
784
  count: number;
783
785
  estimateSize: number | ((index: number) => number);
784
- options: _tanstack_virtual_core.PartialKeys<VirtualizerOptions<HTMLElement, HTMLElement>, "observeElementRect" | "observeElementOffset" | "scrollToFn" | "getScrollElement">;
785
- as: string;
786
786
  wrapperAs: string;
787
787
  wrapperStyle: CSSProperties;
788
788
  wrapperClass: string | string[] | Record<string, boolean>;
package/dist/index.d.ts CHANGED
@@ -60,11 +60,11 @@ declare const HiAffix: vue.DefineComponent<vue.ExtractPropTypes<{
60
60
  default: number;
61
61
  };
62
62
  }>> & Readonly<{}>, {
63
+ as: string;
63
64
  fixedClass: string;
64
65
  offset: number;
65
66
  position: "top" | "bottom";
66
67
  zIndex: number;
67
- as: string;
68
68
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
69
69
 
70
70
  declare const HiConfigProvider: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -131,9 +131,9 @@ declare const HiFileUpload: vue.DefineComponent<vue.ExtractPropTypes<{
131
131
  onChange?: ((...args: any[]) => any) | undefined;
132
132
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
133
133
  }>, {
134
- multiple: boolean;
135
- modelValue: File | File[];
136
134
  as: string;
135
+ modelValue: File | File[];
136
+ multiple: boolean;
137
137
  accept: string;
138
138
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
139
139
 
@@ -192,9 +192,9 @@ declare const HiIcon: vue.DefineComponent<vue.ExtractPropTypes<{
192
192
  default: () => "auto";
193
193
  };
194
194
  }>> & Readonly<{}>, {
195
- mask: boolean | "auto";
196
- color: string;
197
195
  as: string;
196
+ color: string;
197
+ mask: boolean | "auto";
198
198
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
199
199
 
200
200
  declare const HiItem: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -248,10 +248,10 @@ declare const HiItem: vue.DefineComponent<vue.ExtractPropTypes<{
248
248
  }>> & Readonly<{
249
249
  onReject?: ((...args: any[]) => any) | undefined;
250
250
  }>, {
251
+ as: string;
251
252
  value: any;
252
253
  disabled: boolean;
253
254
  keepAlive: boolean;
254
- as: string;
255
255
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
256
256
 
257
257
  declare const HiPopover: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -332,14 +332,14 @@ declare const HiPopover: vue.DefineComponent<vue.ExtractPropTypes<{
332
332
  onChange?: ((...args: any[]) => any) | undefined;
333
333
  "onUpdate:visible"?: ((...args: any[]) => any) | undefined;
334
334
  }>, {
335
+ as: string;
335
336
  offset: number;
336
- visible: boolean;
337
337
  disabled: boolean;
338
+ visible: boolean;
338
339
  placement: _hoci_core.Placement;
339
340
  triggerEvent: _hoci_core.TriggerEvent;
340
341
  lazy: boolean;
341
342
  teleport: string | boolean | HTMLElement;
342
- as: string;
343
343
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
344
344
 
345
345
  declare const HiSelection: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -386,7 +386,7 @@ declare const HiSelection: vue.DefineComponent<vue.ExtractPropTypes<{
386
386
  };
387
387
  }>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
388
388
  [key: string]: any;
389
- }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("change" | "load" | "unload" | "update:modelValue" | "reject")[], "change" | "load" | "unload" | "update:modelValue" | "reject", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
389
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, ("change" | "load" | "update:modelValue" | "unload" | "reject")[], "change" | "load" | "update:modelValue" | "unload" | "reject", vue.PublicProps, Readonly<vue.ExtractPropTypes<{
390
390
  as: {
391
391
  type: StringConstructor;
392
392
  default: string;
@@ -432,18 +432,18 @@ declare const HiSelection: vue.DefineComponent<vue.ExtractPropTypes<{
432
432
  onChange?: ((...args: any[]) => any) | undefined;
433
433
  onLoad?: ((...args: any[]) => any) | undefined;
434
434
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
435
- onReject?: ((...args: any[]) => any) | undefined;
436
435
  onUnload?: ((...args: any[]) => any) | undefined;
436
+ onReject?: ((...args: any[]) => any) | undefined;
437
437
  }>, {
438
- multiple: number | boolean | [number, (number | undefined)?];
438
+ as: string;
439
439
  modelValue: any;
440
+ multiple: number | boolean | [number, (number | undefined)?];
440
441
  activeClass: string | string[] | Record<string, boolean>;
441
442
  itemClass: string | string[] | Record<string, boolean>;
442
443
  disabledClass: string | string[] | Record<string, boolean>;
443
444
  unactiveClass: string | string[] | Record<string, boolean>;
444
445
  clearable: boolean;
445
446
  defaultValue: any;
446
- as: string;
447
447
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
448
448
 
449
449
  declare const HiSwitch: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -509,9 +509,9 @@ declare const HiSwitch: vue.DefineComponent<vue.ExtractPropTypes<{
509
509
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
510
510
  onReject?: ((...args: any[]) => any) | undefined;
511
511
  }>, {
512
- disabled: boolean;
513
- modelValue: boolean;
514
512
  as: string;
513
+ modelValue: boolean;
514
+ disabled: boolean;
515
515
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
516
516
 
517
517
  declare const HiTabPane: vue.DefineComponent<vue.ExtractPropTypes<{
@@ -685,8 +685,9 @@ declare const HiTabs: vue.DefineComponent<vue.ExtractPropTypes<{
685
685
  type: PropType<_hoci_shared.ActivateEvent>;
686
686
  };
687
687
  }>> & Readonly<{}>, {
688
- multiple: number | boolean | [number, (number | undefined)?];
688
+ as: string;
689
689
  modelValue: any;
690
+ multiple: number | boolean | [number, (number | undefined)?];
690
691
  activeClass: string | string[] | Record<string, boolean>;
691
692
  itemClass: string | string[] | Record<string, boolean>;
692
693
  disabledClass: string | string[] | Record<string, boolean>;
@@ -694,7 +695,6 @@ declare const HiTabs: vue.DefineComponent<vue.ExtractPropTypes<{
694
695
  clearable: boolean;
695
696
  defaultValue: any;
696
697
  keepAlive: boolean | KeepAliveProps;
697
- as: string;
698
698
  headerAs: string;
699
699
  contentAs: string;
700
700
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
@@ -778,11 +778,11 @@ declare const HiVirtualList: vue.DefineComponent<vue.ExtractPropTypes<{
778
778
  onScrollEnd?: (() => any) | undefined;
779
779
  onScrollStart?: (() => any) | undefined;
780
780
  }>, {
781
+ as: string;
781
782
  horizontal: boolean;
783
+ options: _tanstack_virtual_core.PartialKeys<VirtualizerOptions<HTMLElement, HTMLElement>, "observeElementRect" | "observeElementOffset" | "scrollToFn" | "getScrollElement">;
782
784
  count: number;
783
785
  estimateSize: number | ((index: number) => number);
784
- options: _tanstack_virtual_core.PartialKeys<VirtualizerOptions<HTMLElement, HTMLElement>, "observeElementRect" | "observeElementOffset" | "scrollToFn" | "getScrollElement">;
785
- as: string;
786
786
  wrapperAs: string;
787
787
  wrapperStyle: CSSProperties;
788
788
  wrapperClass: string | string[] | Record<string, boolean>;
package/dist/index.mjs CHANGED
@@ -1264,7 +1264,7 @@ function notUndefined(value, msg) {
1264
1264
  return value;
1265
1265
  }
1266
1266
  }
1267
- const approxEqual = (a, b) => Math.abs(a - b) <= 1;
1267
+ const approxEqual = (a, b) => Math.abs(a - b) < 1.01;
1268
1268
  const debounce = (targetWindow, fn, ms) => {
1269
1269
  let timeoutId;
1270
1270
  return function(...args) {
@@ -1395,7 +1395,6 @@ class Virtualizer {
1395
1395
  this.scrollElement = null;
1396
1396
  this.targetWindow = null;
1397
1397
  this.isScrolling = false;
1398
- this.scrollToIndexTimeoutId = null;
1399
1398
  this.measurementsCache = [];
1400
1399
  this.itemSizeCache = /* @__PURE__ */ new Map();
1401
1400
  this.pendingMeasuredCacheIndexes = [];
@@ -1811,7 +1810,7 @@ class Virtualizer {
1811
1810
  } else if (align === "end") {
1812
1811
  toOffset -= size;
1813
1812
  }
1814
- const maxOffset = this.getTotalSize() - size;
1813
+ const maxOffset = this.getTotalSize() + this.options.scrollMargin - size;
1815
1814
  return Math.max(Math.min(maxOffset, toOffset), 0);
1816
1815
  };
1817
1816
  this.getOffsetForIndex = (index, align = "auto") => {
@@ -1838,14 +1837,7 @@ class Virtualizer {
1838
1837
  ];
1839
1838
  };
1840
1839
  this.isDynamicMode = () => this.elementsCache.size > 0;
1841
- this.cancelScrollToIndex = () => {
1842
- if (this.scrollToIndexTimeoutId !== null && this.targetWindow) {
1843
- this.targetWindow.clearTimeout(this.scrollToIndexTimeoutId);
1844
- this.scrollToIndexTimeoutId = null;
1845
- }
1846
- };
1847
1840
  this.scrollToOffset = (toOffset, { align = "start", behavior } = {}) => {
1848
- this.cancelScrollToIndex();
1849
1841
  if (behavior === "smooth" && this.isDynamicMode()) {
1850
1842
  console.warn(
1851
1843
  "The `smooth` scroll behavior is not fully supported with dynamic size."
@@ -1857,39 +1849,52 @@ class Virtualizer {
1857
1849
  });
1858
1850
  };
1859
1851
  this.scrollToIndex = (index, { align: initialAlign = "auto", behavior } = {}) => {
1860
- index = Math.max(0, Math.min(index, this.options.count - 1));
1861
- this.cancelScrollToIndex();
1862
1852
  if (behavior === "smooth" && this.isDynamicMode()) {
1863
1853
  console.warn(
1864
1854
  "The `smooth` scroll behavior is not fully supported with dynamic size."
1865
1855
  );
1866
1856
  }
1867
- const offsetAndAlign = this.getOffsetForIndex(index, initialAlign);
1868
- if (!offsetAndAlign) return;
1869
- const [offset, align] = offsetAndAlign;
1870
- this._scrollToOffset(offset, { adjustments: void 0, behavior });
1871
- if (behavior !== "smooth" && this.isDynamicMode() && this.targetWindow) {
1872
- this.scrollToIndexTimeoutId = this.targetWindow.setTimeout(() => {
1873
- this.scrollToIndexTimeoutId = null;
1874
- const elementInDOM = this.elementsCache.has(
1875
- this.options.getItemKey(index)
1876
- );
1877
- if (elementInDOM) {
1878
- const [latestOffset] = notUndefined(
1879
- this.getOffsetForIndex(index, align)
1880
- );
1881
- const currentScrollOffset = this.getScrollOffset();
1882
- if (!approxEqual(latestOffset, currentScrollOffset)) {
1883
- this.scrollToIndex(index, { align, behavior });
1884
- }
1885
- } else {
1886
- this.scrollToIndex(index, { align, behavior });
1857
+ index = Math.max(0, Math.min(index, this.options.count - 1));
1858
+ let attempts = 0;
1859
+ const maxAttempts = 10;
1860
+ const tryScroll = (currentAlign) => {
1861
+ if (!this.targetWindow) return;
1862
+ const offsetInfo = this.getOffsetForIndex(index, currentAlign);
1863
+ if (!offsetInfo) {
1864
+ console.warn("Failed to get offset for index:", index);
1865
+ return;
1866
+ }
1867
+ const [offset, align] = offsetInfo;
1868
+ this._scrollToOffset(offset, { adjustments: void 0, behavior });
1869
+ this.targetWindow.requestAnimationFrame(() => {
1870
+ const currentOffset = this.getScrollOffset();
1871
+ const afterInfo = this.getOffsetForIndex(index, align);
1872
+ if (!afterInfo) {
1873
+ console.warn("Failed to get offset for index:", index);
1874
+ return;
1875
+ }
1876
+ if (!approxEqual(afterInfo[0], currentOffset)) {
1877
+ scheduleRetry(align);
1887
1878
  }
1888
1879
  });
1889
- }
1880
+ };
1881
+ const scheduleRetry = (align) => {
1882
+ if (!this.targetWindow) return;
1883
+ attempts++;
1884
+ if (attempts < maxAttempts) {
1885
+ if (process.env.NODE_ENV !== "production" && this.options.debug) {
1886
+ console.info("Schedule retry", attempts, maxAttempts);
1887
+ }
1888
+ this.targetWindow.requestAnimationFrame(() => tryScroll(align));
1889
+ } else {
1890
+ console.warn(
1891
+ `Failed to scroll to index ${index} after ${maxAttempts} attempts.`
1892
+ );
1893
+ }
1894
+ };
1895
+ tryScroll(initialAlign);
1890
1896
  };
1891
1897
  this.scrollBy = (delta, { behavior } = {}) => {
1892
- this.cancelScrollToIndex();
1893
1898
  if (behavior === "smooth" && this.isDynamicMode()) {
1894
1899
  console.warn(
1895
1900
  "The `smooth` scroll behavior is not fully supported with dynamic size."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoci/components",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "",
5
5
  "author": "Chizuki <chizukicn@outlook.com>",
6
6
  "license": "MIT",
@@ -30,8 +30,8 @@
30
30
  "dependencies": {
31
31
  "maybe-types": "^0.2.0",
32
32
  "tslx": "^0.1.1",
33
- "@hoci/core": "0.8.0",
34
- "@hoci/shared": "0.8.0"
33
+ "@hoci/core": "0.8.1",
34
+ "@hoci/shared": "0.8.1"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "unbuild",