@ariakit/core
Version:
Ariakit core
171 lines (168 loc) • 5.18 kB
JavaScript
"use client";
import {
getDocument,
sortBasedOnDOMPosition
} from "./DTR5TSDJ.js";
import {
batch,
createStore,
init,
setup,
throwOnConflictingProps
} from "./BCALMBPZ.js";
import {
chain,
defaultValue
} from "./PBFD2E7P.js";
import {
__spreadProps,
__spreadValues
} from "./3YLGPPWQ.js";
// src/collection/collection-store.ts
function getCommonParent(items) {
var _a;
const firstItem = items.find((item) => !!item.element);
const lastItem = [...items].reverse().find((item) => !!item.element);
let parentElement = (_a = firstItem == null ? void 0 : firstItem.element) == null ? void 0 : _a.parentElement;
while (parentElement && (lastItem == null ? void 0 : lastItem.element)) {
const parent = parentElement;
if (lastItem && parent.contains(lastItem.element)) {
return parentElement;
}
parentElement = parentElement.parentElement;
}
return getDocument(parentElement).body;
}
function getPrivateStore(store) {
return store == null ? void 0 : store.__unstablePrivateStore;
}
function createCollectionStore(props = {}) {
var _a;
throwOnConflictingProps(props, props.store);
const syncState = (_a = props.store) == null ? void 0 : _a.getState();
const items = defaultValue(
props.items,
syncState == null ? void 0 : syncState.items,
props.defaultItems,
[]
);
const itemsMap = new Map(items.map((item) => [item.id, item]));
const initialState = {
items,
renderedItems: defaultValue(syncState == null ? void 0 : syncState.renderedItems, [])
};
const syncPrivateStore = getPrivateStore(props.store);
const privateStore = createStore(
{ items, renderedItems: initialState.renderedItems },
syncPrivateStore
);
const collection = createStore(initialState, props.store);
const sortItems = (renderedItems) => {
const sortedItems = sortBasedOnDOMPosition(renderedItems, (i) => i.element);
privateStore.setState("renderedItems", sortedItems);
collection.setState("renderedItems", sortedItems);
};
setup(collection, () => init(privateStore));
setup(privateStore, () => {
return batch(privateStore, ["items"], (state) => {
collection.setState("items", state.items);
});
});
setup(privateStore, () => {
return batch(privateStore, ["renderedItems"], (state) => {
let firstRun = true;
let raf = requestAnimationFrame(() => {
const { renderedItems } = collection.getState();
if (state.renderedItems === renderedItems) return;
sortItems(state.renderedItems);
});
if (typeof IntersectionObserver !== "function") {
return () => cancelAnimationFrame(raf);
}
const ioCallback = () => {
if (firstRun) {
firstRun = false;
return;
}
cancelAnimationFrame(raf);
raf = requestAnimationFrame(() => sortItems(state.renderedItems));
};
const root = getCommonParent(state.renderedItems);
const observer = new IntersectionObserver(ioCallback, { root });
for (const item of state.renderedItems) {
if (!item.element) continue;
observer.observe(item.element);
}
return () => {
cancelAnimationFrame(raf);
observer.disconnect();
};
});
});
const mergeItem = (item, setItems, canDeleteFromMap = false) => {
let prevItem;
setItems((items2) => {
const index = items2.findIndex(({ id }) => id === item.id);
const nextItems = items2.slice();
if (index !== -1) {
prevItem = items2[index];
const nextItem = __spreadValues(__spreadValues({}, prevItem), item);
nextItems[index] = nextItem;
itemsMap.set(item.id, nextItem);
} else {
nextItems.push(item);
itemsMap.set(item.id, item);
}
return nextItems;
});
const unmergeItem = () => {
setItems((items2) => {
if (!prevItem) {
if (canDeleteFromMap) {
itemsMap.delete(item.id);
}
return items2.filter(({ id }) => id !== item.id);
}
const index = items2.findIndex(({ id }) => id === item.id);
if (index === -1) return items2;
const nextItems = items2.slice();
nextItems[index] = prevItem;
itemsMap.set(item.id, prevItem);
return nextItems;
});
};
return unmergeItem;
};
const registerItem = (item) => mergeItem(
item,
(getItems) => privateStore.setState("items", getItems),
true
);
return __spreadProps(__spreadValues({}, collection), {
registerItem,
renderItem: (item) => chain(
registerItem(item),
mergeItem(
item,
(getItems) => privateStore.setState("renderedItems", getItems)
)
),
item: (id) => {
if (!id) return null;
let item = itemsMap.get(id);
if (!item) {
const { items: items2 } = privateStore.getState();
item = items2.find((item2) => item2.id === id);
if (item) {
itemsMap.set(id, item);
}
}
return item || null;
},
// @ts-expect-error Internal
__unstablePrivateStore: privateStore
});
}
export {
createCollectionStore
};