mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
removing custom implementation of virtuallist now that i discovered flex-column-reverse (DUH!)
This commit is contained in:
parent
5ce0c4ad75
commit
4fdba26371
@ -44,6 +44,7 @@ export function useConversationContext() {
|
|||||||
const profile = useContext(ProfileContext);
|
const profile = useContext(ProfileContext);
|
||||||
const topics = useRef(new Map());
|
const topics = useRef(new Map());
|
||||||
const view = useRef(0);
|
const view = useRef(0);
|
||||||
|
const more = useRef(true);
|
||||||
const serialize = useRef(0);
|
const serialize = useRef(0);
|
||||||
|
|
||||||
const updateState = (value) => {
|
const updateState = (value) => {
|
||||||
@ -268,9 +269,15 @@ export function useConversationContext() {
|
|||||||
updateConversation();
|
updateConversation();
|
||||||
},
|
},
|
||||||
addHistory: () => {
|
addHistory: () => {
|
||||||
|
if (more.current && !state.loadingMore) {
|
||||||
|
more.current = false;
|
||||||
updateState({ loadingMore: true });
|
updateState({ loadingMore: true });
|
||||||
events.current.push({ type: EVENT_MORE });
|
events.current.push({ type: EVENT_MORE });
|
||||||
updateConversation();
|
updateConversation();
|
||||||
|
setTimeout(() => {
|
||||||
|
more.current = true;
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setChannelSubject: async (subject) => {
|
setChannelSubject: async (subject) => {
|
||||||
return await channel.actions.setChannelSubject(channelView.current.channelId, subject);
|
return await channel.actions.setChannelSubject(channelView.current.channelId, subject);
|
||||||
|
@ -1,20 +1,31 @@
|
|||||||
|
import { useRef } from 'react';
|
||||||
import { ConversationWrapper, StatusError } from './Conversation.styled';
|
import { ConversationWrapper, StatusError } from './Conversation.styled';
|
||||||
import { ExclamationCircleOutlined, SettingOutlined, CloseOutlined } from '@ant-design/icons';
|
import { ExclamationCircleOutlined, SettingOutlined, CloseOutlined } from '@ant-design/icons';
|
||||||
import { useConversation } from './useConversation.hook';
|
import { useConversation } from './useConversation.hook';
|
||||||
import { Logo } from 'logo/Logo';
|
import { Logo } from 'logo/Logo';
|
||||||
import { AddTopic } from './addTopic/AddTopic';
|
import { AddTopic } from './addTopic/AddTopic';
|
||||||
import { VirtualList } from './virtualList/VirtualList';
|
|
||||||
import { TopicItem } from './topicItem/TopicItem';
|
import { TopicItem } from './topicItem/TopicItem';
|
||||||
import { Spin, Tooltip } from 'antd';
|
import { List, Spin, Tooltip } from 'antd';
|
||||||
|
|
||||||
export function Conversation({ closeConversation, openDetails, cardId, channelId }) {
|
export function Conversation({ closeConversation, openDetails, cardId, channelId }) {
|
||||||
|
|
||||||
const { state, actions } = useConversation(cardId, channelId);
|
const { state, actions } = useConversation(cardId, channelId);
|
||||||
|
const thread = useRef(null);
|
||||||
|
|
||||||
const topicRenderer = (topic) => {
|
const topicRenderer = (topic) => {
|
||||||
return (<TopicItem host={cardId == null} topic={topic} />)
|
return (<TopicItem host={cardId == null} topic={topic} />)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollThread = (e) => {
|
||||||
|
const content = thread.current?.scrollHeight;
|
||||||
|
const frame = thread.current?.clientHeight;
|
||||||
|
const position = e.target.scrollTop;
|
||||||
|
const above = content - (Math.abs(position) + frame);
|
||||||
|
if (above < 1024) {
|
||||||
|
actions.more();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConversationWrapper>
|
<ConversationWrapper>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
@ -47,9 +58,9 @@ export function Conversation({ closeConversation, openDetails, cardId, channelId
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div class="thread">
|
<div class="thread" ref={thread} onScroll={scrollThread}>
|
||||||
<VirtualList id={`${cardId}:${channelId}`}
|
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.topics} gutter="0"
|
||||||
items={state.topics} itemRenderer={topicRenderer} loadMore={actions.more} />
|
renderItem={topicRenderer} />
|
||||||
{ state.loadingInit && (
|
{ state.loadingInit && (
|
||||||
<div class="loading">
|
<div class="loading">
|
||||||
<Spin size="large" delay={250} />
|
<Spin size="large" delay={250} />
|
||||||
|
@ -54,6 +54,9 @@ export const ConversationWrapper = styled.div`
|
|||||||
position: relative;
|
position: relative;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
overflow: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -105,6 +105,7 @@ export function useConversation(cardId, channelId) {
|
|||||||
}, [cardId, channelId, card, channel]);
|
}, [cardId, channelId, card, channel]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
updateState({ topics: [] });
|
||||||
conversation.actions.setConversationId(cardId, channelId);
|
conversation.actions.setConversationId(cardId, channelId);
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, [cardId, channelId]);
|
}, [cardId, channelId]);
|
||||||
|
@ -1,392 +0,0 @@
|
|||||||
import React, { useRef, useState, useEffect } from 'react';
|
|
||||||
import { VirtualListWrapper, VirtualItem } from './VirtualList.styled';
|
|
||||||
import ReactResizeDetector from 'react-resize-detector';
|
|
||||||
import { useVirtualList } from './useVirtualList.hook';
|
|
||||||
|
|
||||||
export function VirtualList({ id, items, itemRenderer, loadMore }) {
|
|
||||||
|
|
||||||
const redZone = 1024;
|
|
||||||
const holdZone = 2048;
|
|
||||||
const fillZone = 1024;
|
|
||||||
|
|
||||||
const pushDelay = 250;
|
|
||||||
const moreDelay = 2000;
|
|
||||||
const latchDelay = 500;
|
|
||||||
|
|
||||||
const pad = 4;
|
|
||||||
const defaultHeight = 128;
|
|
||||||
const rollHeight = 16384;
|
|
||||||
|
|
||||||
const { state, actions } = useVirtualList();
|
|
||||||
const containers = useRef([]);
|
|
||||||
const itemView = useRef([]);
|
|
||||||
const debounce = useRef([]);
|
|
||||||
const nomore = useRef(false);
|
|
||||||
const nolatch = useRef(false);
|
|
||||||
const list = useRef(null);
|
|
||||||
const scrollTop = useRef(0);
|
|
||||||
const latched = useRef(true);
|
|
||||||
|
|
||||||
const [scrollPos, setScrollPos] = useState(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
latched.current = true;
|
|
||||||
actions.clearSlots();
|
|
||||||
scrollTop.current = 8192;
|
|
||||||
list.current.scrollTo({ top: 8192, left: 0 });
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [id]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
// reference copy
|
|
||||||
itemView.current = items;
|
|
||||||
|
|
||||||
// genearte set of active ids
|
|
||||||
let ids = new Map();
|
|
||||||
for (let i = 0; i < itemView.current.length; i++) {
|
|
||||||
ids.set(getItemKey(itemView.current[i]), i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove any deleted items
|
|
||||||
let slots = [];
|
|
||||||
containers.current.forEach((container) => {
|
|
||||||
if (!ids.has(container.key)) {
|
|
||||||
actions.removeSlot(container.key);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
container.index = ids.get(container.key);
|
|
||||||
container.item = itemView.current[container.index];
|
|
||||||
slots.push(container);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
containers.current = slots;
|
|
||||||
|
|
||||||
// sort by index
|
|
||||||
containers.current.sort((a, b) => {
|
|
||||||
if (a.index < b.index) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
// rerender list
|
|
||||||
layoutItems();
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [items]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
layoutItems();
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [scrollPos, state.listHeight, state.view]);
|
|
||||||
|
|
||||||
const layoutItems = () => {
|
|
||||||
alignSlots();
|
|
||||||
loadSlots();
|
|
||||||
releaseSlots();
|
|
||||||
centerSlots();
|
|
||||||
latchSlots();
|
|
||||||
pushSlots();
|
|
||||||
};
|
|
||||||
|
|
||||||
const latchSlots = () => {
|
|
||||||
if (containers.current.length > 0 && latched.current && state.listHeight > 0) {
|
|
||||||
if (!nolatch.current) {
|
|
||||||
const last = containers.current[containers.current.length - 1];
|
|
||||||
const bottom = last.top + last.height;
|
|
||||||
if (last.heightSet && scrollTop.current < bottom - (state.listHeight - pad)) {
|
|
||||||
list.current.scrollTo({ top: bottom - (state.listHeight - pad), left: 0, behavior: 'smooth' });
|
|
||||||
nolatch.current = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
nolatch.current = false;
|
|
||||||
latchSlots();
|
|
||||||
}, latchDelay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const pushSlots = () => {
|
|
||||||
if (debounce.current != null) {
|
|
||||||
clearTimeout(debounce.current);
|
|
||||||
};
|
|
||||||
debounce.current = setTimeout(() => {
|
|
||||||
if (containers.current.length > 0) {
|
|
||||||
const range = getContainerRange();
|
|
||||||
if (range.bottom - range.top < (state.listHeight - pad)) {
|
|
||||||
if (scrollTop.current + (state.listHeight - pad) !== range.bottom) {
|
|
||||||
list.current.scrollTo({ top: range.bottom - (state.listHeight - pad), left: 0 });
|
|
||||||
latched.current = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (scrollTop.current + (state.listHeight - pad) > range.bottom) {
|
|
||||||
list.current.scrollTo({ top: range.bottom - (state.listHeight - pad), left: 0 });
|
|
||||||
latched.current = true;
|
|
||||||
}
|
|
||||||
else if (scrollTop.current < range.top) {
|
|
||||||
list.current.scrollTo({ top: range.top, left: 0 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, pushDelay);
|
|
||||||
};
|
|
||||||
|
|
||||||
const alignSlots = () => {
|
|
||||||
if (containers.current.length > 1) {
|
|
||||||
if (latched.current) {
|
|
||||||
const index = containers.current.length - 1;
|
|
||||||
const last = containers.current[index];
|
|
||||||
let bottom = last.top + last.height;
|
|
||||||
for (let i = index; i >= 0; i--) {
|
|
||||||
let container = containers.current[i];
|
|
||||||
if (container.top + container.height !== bottom) {
|
|
||||||
container.top = bottom - container.height;
|
|
||||||
actions.updateSlot(container.key, getSlot(container));
|
|
||||||
}
|
|
||||||
bottom -= container.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const index = Math.floor(containers.current.length / 2);
|
|
||||||
const mid = containers.current[index];
|
|
||||||
let top = mid.top;
|
|
||||||
for (let i = index; i < containers.current.length; i++) {
|
|
||||||
let container = containers.current[i];
|
|
||||||
if (container.top !== top) {
|
|
||||||
container.top = top;
|
|
||||||
actions.updateSlot(container.key, getSlot(container));
|
|
||||||
}
|
|
||||||
top += container.height;
|
|
||||||
}
|
|
||||||
let bottom = mid.top + mid.height;
|
|
||||||
for (let i = index; i >= 0; i--) {
|
|
||||||
let container = containers.current[i];
|
|
||||||
if (container.top + container.height !== bottom) {
|
|
||||||
container.top = bottom - container.height;
|
|
||||||
actions.updateSlot(container.key, getSlot(container));
|
|
||||||
}
|
|
||||||
bottom -= container.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadSlots = () => {
|
|
||||||
|
|
||||||
if (state.listHeight === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (containers.current.length === 0) {
|
|
||||||
// add the first slot
|
|
||||||
if (itemView.current.length > 0) {
|
|
||||||
let item = itemView.current[itemView.current.length - 1];
|
|
||||||
let slot = {
|
|
||||||
top: rollHeight / 2 + (state.listHeight - pad),
|
|
||||||
height: defaultHeight,
|
|
||||||
heightSet: false,
|
|
||||||
key: getItemKey(item),
|
|
||||||
index: itemView.current.length - 1,
|
|
||||||
item: item,
|
|
||||||
}
|
|
||||||
containers.current.push(slot);
|
|
||||||
actions.addSlot(slot.key, getSlot(slot));
|
|
||||||
list.current.scrollTo({ top: rollHeight / 2, left: 0 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// fill in any missing slots
|
|
||||||
let index = containers.current[0].index;
|
|
||||||
for (let i = 1; i < containers.current.length; i++) {
|
|
||||||
let container = containers.current[i];
|
|
||||||
if (container.index !== index + i) {
|
|
||||||
const item = itemView.current[index + i];
|
|
||||||
let slot = {
|
|
||||||
top: container.top - defaultHeight,
|
|
||||||
height: defaultHeight,
|
|
||||||
heightSet: false,
|
|
||||||
index: index + i,
|
|
||||||
item: item,
|
|
||||||
key: getItemKey(item),
|
|
||||||
}
|
|
||||||
containers.current.splice(i, 0, slot);
|
|
||||||
actions.addSlot(slot.key, getSlot(slot));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadSlotAbove();
|
|
||||||
loadSlotBelow();
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadSlotAbove = () => {
|
|
||||||
if (containers.current.length > 0) {
|
|
||||||
const range = getContainerRange();
|
|
||||||
if (scrollTop.current - fillZone < range.top) {
|
|
||||||
const container = containers.current[0];
|
|
||||||
if (container.index > 0) {
|
|
||||||
const index = container.index - 1;
|
|
||||||
const item = itemView.current[index];
|
|
||||||
let slot = {
|
|
||||||
top: container.top - defaultHeight,
|
|
||||||
height: defaultHeight,
|
|
||||||
heightSet: false,
|
|
||||||
index: index,
|
|
||||||
item: item,
|
|
||||||
key: getItemKey(item),
|
|
||||||
}
|
|
||||||
containers.current.unshift(slot);
|
|
||||||
actions.addSlot(slot.key, getSlot(slot));
|
|
||||||
loadSlotAbove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadSlotBelow = () => {
|
|
||||||
if (containers.current.length > 0) {
|
|
||||||
const container = containers.current[containers.current.length - 1];
|
|
||||||
if (container.index + 1 < itemView.current.length) {
|
|
||||||
const range = getContainerRange();
|
|
||||||
if (scrollTop.current + (state.listHeight - pad) + fillZone > range.bottom) {
|
|
||||||
const index = container.index + 1;
|
|
||||||
const item = itemView.current[index];
|
|
||||||
let slot = {
|
|
||||||
top: container.top + container.height,
|
|
||||||
height: defaultHeight,
|
|
||||||
heightSet: false,
|
|
||||||
index: index,
|
|
||||||
item: item,
|
|
||||||
key: getItemKey(item),
|
|
||||||
}
|
|
||||||
containers.current.push(slot);
|
|
||||||
actions.addSlot(slot.key, getSlot(slot));
|
|
||||||
loadSlotBelow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const releaseSlots = () => {
|
|
||||||
releaseSlotAbove();
|
|
||||||
releaseSlotBelow();
|
|
||||||
};
|
|
||||||
|
|
||||||
const releaseSlotAbove = () => {
|
|
||||||
if (containers.current.length > 1) {
|
|
||||||
const container = containers.current[0];
|
|
||||||
if (container.top + container.height < scrollTop.current - holdZone) {
|
|
||||||
actions.removeSlot(container.key);
|
|
||||||
containers.current.shift();
|
|
||||||
releaseSlotAbove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const releaseSlotBelow = () => {
|
|
||||||
if (containers.current.length > 1) {
|
|
||||||
const container = containers.current[containers.current.length - 1];
|
|
||||||
if (container.top > scrollTop.current + state.listHeight + holdZone) {
|
|
||||||
actions.removeSlot(container.key);
|
|
||||||
containers.current.pop();
|
|
||||||
releaseSlotBelow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const centerSlots = () => {
|
|
||||||
if (containers.current.length > 0) {
|
|
||||||
const top = containers.current[0];
|
|
||||||
if (top.top < redZone) {
|
|
||||||
containers.current.forEach(container => {
|
|
||||||
container.top += rollHeight / 2;
|
|
||||||
actions.updateSlot(container.key, getSlot(container));
|
|
||||||
});
|
|
||||||
list.current.scrollTo({ top: scrollTop.current + rollHeight / 2, left: 0 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const bottom = containers.current[containers.current.length - 1];
|
|
||||||
if (bottom.top + bottom.height > rollHeight - redZone) {
|
|
||||||
containers.current.forEach(container => {
|
|
||||||
container.top -= rollHeight / 2;
|
|
||||||
actions.updateSlot(container.key, getSlot(container));
|
|
||||||
});
|
|
||||||
list.current.scrollTo({ top: scrollTop.current - rollHeight / 2, left: 0 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getItemKey = (item) => {
|
|
||||||
return `${id}.${item.id}.${item.revision}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const getSlot = (item) => {
|
|
||||||
const container = item;
|
|
||||||
return (
|
|
||||||
<VirtualItem style={{ top: container.top, key: container.key }}>
|
|
||||||
<ReactResizeDetector handleHeight={true}>
|
|
||||||
{({ height }) => {
|
|
||||||
if (typeof height !== 'undefined' && container.height !== height) {
|
|
||||||
container.height = height;
|
|
||||||
container.heightSet = true;
|
|
||||||
layoutItems();
|
|
||||||
}
|
|
||||||
return itemRenderer(container.item);
|
|
||||||
}}
|
|
||||||
</ReactResizeDetector>
|
|
||||||
</VirtualItem>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getContainerRange = () => {
|
|
||||||
let top = rollHeight;
|
|
||||||
let bottom = 0;
|
|
||||||
containers.current.forEach((c) => {
|
|
||||||
if (c.top < top) {
|
|
||||||
top = c.top;
|
|
||||||
}
|
|
||||||
if (c.top + c.height > bottom) {
|
|
||||||
bottom = c.top + c.height;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return { top, bottom };
|
|
||||||
}
|
|
||||||
|
|
||||||
const scrollView = (e) => {
|
|
||||||
if (containers.current.length > 0 && containers.current[0].index === 0 && !nomore.current) {
|
|
||||||
loadMore();
|
|
||||||
nomore.current = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
nomore.current = false;
|
|
||||||
}, moreDelay);
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollTop.current = e.target.scrollTop;
|
|
||||||
setScrollPos(e.target.scrollTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
const unlatch = () => {
|
|
||||||
latched.current = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ position: 'relative', height: '100%' }}>
|
|
||||||
<ReactResizeDetector handleHeight={true} handleWidth={false}>
|
|
||||||
{({ height }) => {
|
|
||||||
if (height && state.listHeight !== height) {
|
|
||||||
actions.setListHeight(height);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<VirtualListWrapper onScroll={scrollView}
|
|
||||||
onWheel={unlatch} onTouchStart={unlatch} >
|
|
||||||
<div class="rollview" ref={list} onScroll={scrollView}>
|
|
||||||
<div class="roll" style={{ height: rollHeight }}>
|
|
||||||
{ state.slots }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</VirtualListWrapper>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</ReactResizeDetector>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
export const VirtualListWrapper = styled.div`
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.rollview {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
/* hide scrollbar for IE, Edge and Firefox */
|
|
||||||
-ms-overflow-style: none;
|
|
||||||
scrollbar-width: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rollview::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.roll {
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const VirtualItem = styled.div`
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
max-height: 1024px;
|
|
||||||
`;
|
|
@ -1,48 +0,0 @@
|
|||||||
import { useState, useRef } from 'react';
|
|
||||||
|
|
||||||
export function useVirtualList(id) {
|
|
||||||
|
|
||||||
const [state, setState] = useState({
|
|
||||||
view: null,
|
|
||||||
listHeight: 0,
|
|
||||||
slots: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const slots = useRef(new Map());
|
|
||||||
|
|
||||||
const updateState = (value) => {
|
|
||||||
setState((s) => ({ ...s, ...value }));
|
|
||||||
}
|
|
||||||
|
|
||||||
const actions = {
|
|
||||||
setView: (view) => {
|
|
||||||
updateState({ view });
|
|
||||||
},
|
|
||||||
setListHeight: (listHeight) => {
|
|
||||||
updateState({ listHeight: listHeight });
|
|
||||||
},
|
|
||||||
addSlot: (id, slot) => {
|
|
||||||
slots.current.set(id, slot);
|
|
||||||
let items = Array.from(slots.current.values());
|
|
||||||
updateState({ slots: items });
|
|
||||||
},
|
|
||||||
updateSlot: (id, slot) => {
|
|
||||||
slots.current.set(id, slot);
|
|
||||||
let items = Array.from(slots.current.values());
|
|
||||||
updateState({ slots: items });
|
|
||||||
},
|
|
||||||
removeSlot: (id) => {
|
|
||||||
slots.current.set(id, (<></>));
|
|
||||||
let items = Array.from(slots.current.values());
|
|
||||||
updateState({ slots: items });
|
|
||||||
},
|
|
||||||
clearSlots: () => {
|
|
||||||
slots.current = new Map();
|
|
||||||
let items = Array.from(slots.current.values());
|
|
||||||
updateState({ slots: items });
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return { state, actions };
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user