foundation.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import BaseFoundation, { DefaultAdapter } from '../base/foundation';
  2. import { strings } from './constants';
  3. import { noop, get, cloneDeep } from 'lodash';
  4. const Boundary = strings.BOUNDARY_MAP;
  5. const OverflowDirection = strings.OVERFLOW_DIR;
  6. export interface OverflowListAdapter extends DefaultAdapter {
  7. updateStates: (state: any) => void;
  8. updateVisibleState: (visible: Map<string, boolean>) => void;
  9. notifyIntersect: (res: any) => void;
  10. }
  11. class OverflowListFoundation extends BaseFoundation<OverflowListAdapter> {
  12. constructor(adapter: OverflowListAdapter) {
  13. super({ ...adapter });
  14. }
  15. isScrollMode = (): boolean => {
  16. const { renderMode } = this.getProps();
  17. return renderMode === 'scroll';
  18. };
  19. getOverflowItem(): Array<Array<Record<string, any>>> {
  20. const { items } = this.getProps();
  21. const { visibleState, overflow } = this.getStates();
  22. if (!this.isScrollMode()) {
  23. return overflow;
  24. }
  25. const visibleStateArr = items.map(({ key }: { key: string }) => Boolean(visibleState.get(key)));
  26. const visibleStart = visibleStateArr.indexOf(true);
  27. const visibleEnd = visibleStateArr.lastIndexOf(true);
  28. const overflowList = [];
  29. overflowList[0] = visibleStart >= 0 ? items.slice(0, visibleStart) : [];
  30. overflowList[1] = visibleEnd >= 0 ? items.slice(visibleEnd + 1, items.length) : items;
  31. return overflowList;
  32. }
  33. handleIntersect(entries: Array<IntersectionObserverEntry>): void {
  34. const visibleState = cloneDeep(this.getState('visibleState'));
  35. const res = {};
  36. entries.forEach(entry => {
  37. const itemKey = get(entry, 'target.dataset.scrollkey');
  38. const visible = entry.isIntersecting;
  39. res[itemKey] = entry;
  40. visibleState.set(itemKey, visible);
  41. });
  42. this._adapter.updateVisibleState(visibleState);
  43. this._adapter.notifyIntersect(res);
  44. }
  45. handlePartition(growing: number): void {
  46. const { direction, overflow, lastOverflowCount, visible } = this.getStates();
  47. const { minVisibleItems, collapseFrom, items } = this.getProps();
  48. let updateState = {};
  49. if (growing === OverflowDirection.NONE) {
  50. updateState = { direction: OverflowDirection.NONE };
  51. }
  52. if (growing === OverflowDirection.GROW) {
  53. const updatedOverflowCount = direction === OverflowDirection.NONE ? overflow.length : lastOverflowCount;
  54. updateState = {
  55. direction: OverflowDirection.GROW,
  56. lastOverflowCount: updatedOverflowCount,
  57. overflow: [],
  58. visible: items,
  59. };
  60. }
  61. if (growing === OverflowDirection.SHRINK && visible.length > minVisibleItems) {
  62. const collapseFromStart = collapseFrom === Boundary.START;
  63. const newVisible = visible.slice();
  64. const next = collapseFromStart ? newVisible.shift() : newVisible.pop();
  65. if (next !== undefined) {
  66. updateState = {
  67. // set SHRINK mode unless a GROW is already in progress.
  68. // GROW shows all items then shrinks until it settles, so we
  69. // preserve the fact that the original trigger was a GROW.
  70. direction: direction !== OverflowDirection.GROW ? OverflowDirection.SHRINK : direction,
  71. overflow: collapseFromStart ? [...overflow, next] : [next, ...overflow],
  72. visible: newVisible
  73. };
  74. }
  75. }
  76. this._adapter.updateStates(updateState);
  77. }
  78. }
  79. export default OverflowListFoundation;