@rchat/react
Advanced tools
+0
-0
@@ -0,0 +0,0 @@ MIT License |
+1
-1
| { | ||
| "name": "@rchat/react", | ||
| "description": "Awesome React chat", | ||
| "version": "0.12.1", | ||
| "version": "0.12.2", | ||
| "main": "./dist/src/index.js", | ||
@@ -6,0 +6,0 @@ "types": "./dist/src/index.d.ts", |
+0
-0
@@ -0,0 +0,0 @@ export * from './EndlessList'; |
| 'use strict' | ||
| if(process.env.NODE_ENV === 'production') { | ||
| module.exports = require('./rchat-react.cjs.production.min.js'); | ||
| } else { | ||
| module.exports = require('./rchat-react.cjs.development.js'); | ||
| } |
| import React from 'react'; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
| var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
| var __spreadValues = (a, b) => { | ||
| for (var prop in b || (b = {})) | ||
| if (__hasOwnProp.call(b, prop)) | ||
| __defNormalProp(a, prop, b[prop]); | ||
| if (__getOwnPropSymbols) | ||
| for (var prop of __getOwnPropSymbols(b)) { | ||
| if (__propIsEnum.call(b, prop)) | ||
| __defNormalProp(a, prop, b[prop]); | ||
| } | ||
| return a; | ||
| }; | ||
| var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); | ||
| var __objRest = (source, exclude) => { | ||
| var target = {}; | ||
| for (var prop in source) | ||
| if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) | ||
| target[prop] = source[prop]; | ||
| if (source != null && __getOwnPropSymbols) | ||
| for (var prop of __getOwnPropSymbols(source)) { | ||
| if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) | ||
| target[prop] = source[prop]; | ||
| } | ||
| return target; | ||
| }; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| // src/index.ts | ||
| var src_exports = {}; | ||
| __export(src_exports, { | ||
| Chat: () => Chat, | ||
| EndlessList: () => EndlessList, | ||
| MessageList: () => MessageList, | ||
| Room: () => Room, | ||
| useEndlessList: () => useEndlessList, | ||
| useMessages: () => useMessages, | ||
| useVisibleItems: () => useVisibleItems | ||
| }); | ||
| module.exports = __toCommonJS(src_exports); | ||
| // src/EndlessList/EndlessList.tsx | ||
| var import_react8 = require("react"); | ||
| // src/internal/mergeReferences.ts | ||
| var mergeReferences = /* @__PURE__ */ __name((...inputReferences) => { | ||
| const filteredInputReferences = inputReferences.filter(Boolean); | ||
| if (filteredInputReferences.length <= 1) { | ||
| return filteredInputReferences[0]; | ||
| } | ||
| return /* @__PURE__ */ __name(function mergedReferences(reference) { | ||
| for (const inputReference of filteredInputReferences) { | ||
| if (typeof inputReference === "function") { | ||
| inputReference(reference); | ||
| } else if (inputReference) { | ||
| inputReference.current = reference; | ||
| } | ||
| } | ||
| }, "mergedReferences"); | ||
| }, "mergeReferences"); | ||
| // src/internal/smoothScrollToCenter.ts | ||
| var smoothScrollToCenter = /* @__PURE__ */ __name(async (container, element, parameters, controller) => { | ||
| const elementRect = element.getBoundingClientRect(); | ||
| const containerRect = container.getBoundingClientRect(); | ||
| const top = elementRect.top - containerRect.top - containerRect.height / 2 + elementRect.height / 2; | ||
| const startPos = container.scrollTop; | ||
| const clientHeight = container.clientHeight; | ||
| const maxScroll = container.scrollHeight - clientHeight; | ||
| const scrollIntendedDestination = startPos + top; | ||
| const scrollEndValue = Math.min(Math.max(scrollIntendedDestination, 0), maxScroll); | ||
| let startTime = 0; | ||
| const duration = parameters.duration(scrollEndValue - startPos); | ||
| return new Promise((resolve, reject) => { | ||
| const scroll = /* @__PURE__ */ __name((timestamp) => { | ||
| if (controller == null ? void 0 : controller.signal.aborted) { | ||
| reject(controller.signal.reason); | ||
| return; | ||
| } | ||
| startTime = startTime || timestamp; | ||
| const elapsed = timestamp - startTime; | ||
| container.scrollTop = startPos + (scrollEndValue - startPos) * parameters.easing(elapsed / duration); | ||
| if (elapsed <= duration) { | ||
| window.requestAnimationFrame(scroll); | ||
| } else { | ||
| resolve(); | ||
| } | ||
| }, "scroll"); | ||
| if (startPos !== scrollEndValue) { | ||
| window.requestAnimationFrame(scroll); | ||
| } else { | ||
| resolve(); | ||
| } | ||
| }); | ||
| }, "smoothScrollToCenter"); | ||
| // src/internal/useEvent.ts | ||
| var import_react = require("react"); | ||
| var useEvent = /* @__PURE__ */ __name((handler) => { | ||
| const handlerReference = (0, import_react.useRef)(handler); | ||
| handlerReference.current = handler; | ||
| return (0, import_react.useCallback)((...parameters) => { | ||
| return handlerReference.current(...parameters); | ||
| }, []); | ||
| }, "useEvent"); | ||
| // src/internal/useScheduleOnNextRender.tsx | ||
| var import_react2 = require("react"); | ||
| var useScheduleOnNextRender = /* @__PURE__ */ __name((handler) => { | ||
| const unresolvedHandle = (0, import_react2.useRef)(); | ||
| (0, import_react2.useLayoutEffect)(() => { | ||
| const currentHandle = unresolvedHandle.current; | ||
| unresolvedHandle.current = void 0; | ||
| if (currentHandle) { | ||
| handler(...currentHandle.parameters).then(currentHandle.resolve).catch(currentHandle.reject); | ||
| } | ||
| }); | ||
| const wrappedFunction = (0, import_react2.useCallback)((...parameters) => { | ||
| return new Promise((resolve, reject) => { | ||
| unresolvedHandle.current = { | ||
| parameters, | ||
| resolve, | ||
| reject | ||
| }; | ||
| }); | ||
| }, []); | ||
| const isScheduled = (0, import_react2.useCallback)(() => { | ||
| return unresolvedHandle.current !== void 0; | ||
| }, []); | ||
| return [wrappedFunction, isScheduled]; | ||
| }, "useScheduleOnNextRender"); | ||
| // src/internal/useToggleEvent.ts | ||
| var import_react3 = require("react"); | ||
| var useToggleEvent = /* @__PURE__ */ __name((onTurnedOn) => { | ||
| const value = (0, import_react3.useRef)(false); | ||
| const toggle = (0, import_react3.useCallback)( | ||
| (newValue) => { | ||
| if (!value.current && newValue) { | ||
| onTurnedOn(); | ||
| } | ||
| value.current = newValue; | ||
| }, | ||
| [onTurnedOn] | ||
| ); | ||
| return toggle; | ||
| }, "useToggleEvent"); | ||
| // src/EndlessList/EndlessListItemView.tsx | ||
| var import_react4 = require("react"); | ||
| var EndlessListItemView = /* @__PURE__ */ __name((_a) => { | ||
| var _b = _a, { | ||
| ItemComponent, | ||
| PlaceholderComponent, | ||
| itemObserver, | ||
| focusElementReference | ||
| } = _b, item = __objRest(_b, [ | ||
| "ItemComponent", | ||
| "PlaceholderComponent", | ||
| "itemObserver", | ||
| "focusElementReference" | ||
| ]); | ||
| const itemReference = (0, import_react4.useRef)(null); | ||
| (0, import_react4.useEffect)(() => { | ||
| const currentElement = itemReference.current; | ||
| if (currentElement && itemObserver) { | ||
| itemObserver.observe(currentElement); | ||
| return () => itemObserver.unobserve(currentElement); | ||
| } | ||
| }, [itemObserver]); | ||
| if (item.type === "placeholder") { | ||
| return /* @__PURE__ */ React.createElement(PlaceholderComponent, { ref: itemReference, itemKey: item.itemKey }); | ||
| } | ||
| return /* @__PURE__ */ React.createElement(ItemComponent, __spreadValues({ ref: mergeReferences(itemReference, item.focused && focusElementReference) }, item)); | ||
| }, "EndlessListItemView"); | ||
| // src/EndlessList/useEndlessList.tsx | ||
| var import_react6 = require("react"); | ||
| var import_use_isomorphic_layout_effect = __toESM(require("use-isomorphic-layout-effect")); | ||
| // src/internal/binarySearch.ts | ||
| var binarySearch = /* @__PURE__ */ __name((array, value, comparator) => { | ||
| let low = 0; | ||
| let high = array.length; | ||
| if (high === 0) { | ||
| return 0; | ||
| } | ||
| while (low < high) { | ||
| const middle = Math.floor((low + high) / 2); | ||
| if (comparator(value, { value: array[middle], index: middle }) > 0) { | ||
| low = middle + 1; | ||
| } else { | ||
| high = middle; | ||
| } | ||
| } | ||
| return high; | ||
| }, "binarySearch"); | ||
| // src/internal/useIdGenerator.ts | ||
| var import_react5 = require("react"); | ||
| var useIdGenerator = /* @__PURE__ */ __name(() => { | ||
| const counter = (0, import_react5.useRef)(0); | ||
| return (0, import_react5.useCallback)(() => `:rchat:-${++counter.current}`, []); | ||
| }, "useIdGenerator"); | ||
| // src/EndlessList/useEndlessList.tsx | ||
| var valueToEndlessListItem = /* @__PURE__ */ __name((getKey, focusItemKey) => { | ||
| return (value, index, array) => { | ||
| const key = getKey(value); | ||
| return { | ||
| type: "real", | ||
| value, | ||
| index, | ||
| array, | ||
| focused: key === focusItemKey, | ||
| itemKey: key | ||
| }; | ||
| }; | ||
| }, "valueToEndlessListItem"); | ||
| var useEndlessList = /* @__PURE__ */ __name(({ | ||
| initialItems, | ||
| items, | ||
| getKey, | ||
| focusedItem, | ||
| compareItems, | ||
| handleJump, | ||
| visibleItemKeys, | ||
| lastScrolledItem | ||
| }) => { | ||
| const focusedItemKey = focusedItem === void 0 ? void 0 : getKey(focusedItem); | ||
| const defaultConvertItem = (0, import_react6.useMemo)(() => valueToEndlessListItem(getKey, focusedItemKey), [getKey, focusedItemKey]); | ||
| const [renderedItems, setRenderedItems] = (0, import_react6.useState)(() => items.map(defaultConvertItem)); | ||
| const jumpAbortController = (0, import_react6.useRef)(); | ||
| const initialItemsReference = (0, import_react6.useRef)(initialItems); | ||
| const hasMounted = (0, import_react6.useRef)(false); | ||
| const getUniquePlaceholderKey = useIdGenerator(); | ||
| const performFixup = useEvent(() => { | ||
| const visibleItems = renderedItems.filter(({ itemKey, type }, index, array) => { | ||
| if (visibleItemKeys.current.has(itemKey)) { | ||
| return true; | ||
| } | ||
| if (type === "placeholder") { | ||
| return false; | ||
| } | ||
| const previousItem = array[index - 1]; | ||
| if (previousItem && previousItem.type !== "placeholder" && visibleItemKeys.current.has(previousItem.itemKey)) { | ||
| return true; | ||
| } | ||
| const nextItem = array[index + 1]; | ||
| if (nextItem && nextItem.type !== "placeholder" && visibleItemKeys.current.has(nextItem.itemKey)) { | ||
| return true; | ||
| } | ||
| return false; | ||
| }).map((item) => { | ||
| if (item.type === "real" && item.focused) { | ||
| item.focused = false; | ||
| } | ||
| return item; | ||
| }); | ||
| const keys = new Set(items.map(getKey)); | ||
| if (visibleItems.every((item) => !keys.has(item.itemKey))) { | ||
| return [visibleItems, true]; | ||
| } | ||
| const comparator = /* @__PURE__ */ __name((a, b) => { | ||
| if (b.value.type === "placeholder") { | ||
| const nextValue = visibleItems[b.index + 1]; | ||
| if (nextValue !== void 0 && nextValue.type !== "placeholder") { | ||
| return compareItems(nextValue.value, a.value); | ||
| } | ||
| return 1; | ||
| } | ||
| return compareItems(a.value, b.value.value); | ||
| }, "comparator"); | ||
| const jumpKey = focusedItemKey != null ? focusedItemKey : getKey(items[Math.floor(items.length / 2)]); | ||
| const convertedItems = [...items.map(valueToEndlessListItem(getKey, jumpKey))]; | ||
| let pivotIndex = visibleItems.findIndex((item) => keys.has(item.itemKey)); | ||
| if (pivotIndex === -1) { | ||
| pivotIndex = binarySearch(visibleItems, convertedItems.at(0), comparator); | ||
| } | ||
| visibleItems.splice(pivotIndex, 1, ...convertedItems); | ||
| const dedupedKeys = /* @__PURE__ */ new Set(); | ||
| const filteredItems = visibleItems.filter((item) => { | ||
| if (dedupedKeys.has(item.itemKey)) { | ||
| return false; | ||
| } | ||
| dedupedKeys.add(item.itemKey); | ||
| return true; | ||
| }); | ||
| return [filteredItems, false]; | ||
| }); | ||
| const update = useEvent(async () => { | ||
| var _a, _b; | ||
| if (jumpAbortController.current) { | ||
| jumpAbortController.current.abort(); | ||
| jumpAbortController.current = void 0; | ||
| } | ||
| if (renderedItems.length === 0 || items.length === 0 || initialItemsReference.current !== initialItems) { | ||
| setRenderedItems(items.map(defaultConvertItem)); | ||
| initialItemsReference.current = initialItems; | ||
| return; | ||
| } | ||
| const isAbortedPreviousJump = renderedItems.some((item) => item.type === "placeholder"); | ||
| let oldItems; | ||
| let constructItems = true; | ||
| if (isAbortedPreviousJump) { | ||
| [oldItems, constructItems] = performFixup(); | ||
| let array = []; | ||
| let index = 0; | ||
| for (const item of oldItems) { | ||
| if (item.type === "placeholder") { | ||
| index = 0; | ||
| array = []; | ||
| } else { | ||
| item.index = index; | ||
| item.array = array; | ||
| array.push(item.value); | ||
| ++index; | ||
| } | ||
| } | ||
| } else { | ||
| const keys = items.map(getKey); | ||
| const oldKeys = renderedItems.map((item) => item.itemKey); | ||
| const mustMoveForward = !oldKeys.includes(keys[0]) && !keys.includes(oldKeys.at(-1)); | ||
| const mustMoveBack = !keys.includes(oldKeys[0]) && !oldKeys.includes(keys.at(-1)); | ||
| const mustJump = mustMoveForward && mustMoveBack; | ||
| if (!mustJump) { | ||
| setRenderedItems(items.map(defaultConvertItem)); | ||
| return; | ||
| } | ||
| oldItems = renderedItems.map((item) => { | ||
| if (item.type === "real" && item.focused) { | ||
| item.focused = false; | ||
| } | ||
| return item; | ||
| }); | ||
| } | ||
| let constructedItems; | ||
| if (constructItems) { | ||
| const firstItem = oldItems.find((item) => item.type === "real"); | ||
| let jumpDirection = "forward"; | ||
| if (firstItem) { | ||
| jumpDirection = compareItems(items[0], firstItem.value) < 0 ? "forward" : "back"; | ||
| } | ||
| const jumpKey = focusedItemKey != null ? focusedItemKey : getKey(items[Math.floor(items.length / 2)]); | ||
| let nextItems; | ||
| let previousItems; | ||
| const convertItem = valueToEndlessListItem(getKey, jumpKey); | ||
| if (jumpDirection === "forward") { | ||
| nextItems = items.map(convertItem); | ||
| previousItems = oldItems; | ||
| } else { | ||
| nextItems = oldItems; | ||
| previousItems = items.map(convertItem); | ||
| } | ||
| const alreadyHasPlaceholder = ((_a = nextItems.at(-1)) == null ? void 0 : _a.type) === "placeholder" || ((_b = previousItems.at(0)) == null ? void 0 : _b.type) === "placeholder"; | ||
| constructedItems = [ | ||
| ...nextItems, | ||
| ...alreadyHasPlaceholder ? [] : [{ type: "placeholder", itemKey: getUniquePlaceholderKey() }], | ||
| ...previousItems | ||
| ]; | ||
| } else { | ||
| constructedItems = oldItems; | ||
| } | ||
| lastScrolledItem.current = items[Math.floor(items.length / 2)]; | ||
| setRenderedItems(constructedItems); | ||
| const newController = new AbortController(); | ||
| jumpAbortController.current = newController; | ||
| try { | ||
| if (hasMounted.current) { | ||
| await handleJump(newController); | ||
| } | ||
| setRenderedItems(items.map(defaultConvertItem)); | ||
| } catch (e) { | ||
| } finally { | ||
| jumpAbortController.current = void 0; | ||
| } | ||
| }); | ||
| (0, import_use_isomorphic_layout_effect.default)(() => { | ||
| update(); | ||
| hasMounted.current = true; | ||
| }, [update, items]); | ||
| (0, import_react6.useEffect)(() => { | ||
| return () => { | ||
| hasMounted.current = false; | ||
| }; | ||
| }, []); | ||
| return renderedItems; | ||
| }, "useEndlessList"); | ||
| // src/EndlessList/useVisibleFrame.tsx | ||
| var useVisibleFrame = /* @__PURE__ */ __name(({ | ||
| items, | ||
| getKey, | ||
| onVisibleFrameUpdated | ||
| }) => { | ||
| const updateVisibleFrame = useEvent((visibleItemKeys) => { | ||
| let begin = -1; | ||
| for (const [index, item] of items.entries()) { | ||
| if (visibleItemKeys.has(getKey(item))) { | ||
| begin = index; | ||
| break; | ||
| } | ||
| } | ||
| let end = -1; | ||
| for (let index = 0; index <= items.length; ++index) { | ||
| const item = items.at(-index - 1); | ||
| if (item && visibleItemKeys.has(getKey(item))) { | ||
| end = index; | ||
| break; | ||
| } | ||
| } | ||
| onVisibleFrameUpdated({ begin, end }); | ||
| }); | ||
| return updateVisibleFrame; | ||
| }, "useVisibleFrame"); | ||
| // src/EndlessList/useVisibleItems.tsx | ||
| var import_react7 = require("react"); | ||
| var useVisibleItems = /* @__PURE__ */ __name((containerReference, onVisibleItemsChange) => { | ||
| const [observer, setObserver] = (0, import_react7.useState)(); | ||
| const visibleItemKeysReference = (0, import_react7.useRef)(/* @__PURE__ */ new Set()); | ||
| const updateVisibleFrame = useEvent((entries) => { | ||
| for (const { target, isIntersecting } of entries) { | ||
| const key = target.dataset.key; | ||
| if (!key) { | ||
| console.warn(`Item component doesn't have "data-key" attribute.`); | ||
| } else if (isIntersecting) { | ||
| visibleItemKeysReference.current.add(key); | ||
| } else { | ||
| visibleItemKeysReference.current.delete(key); | ||
| } | ||
| } | ||
| onVisibleItemsChange == null ? void 0 : onVisibleItemsChange(visibleItemKeysReference.current); | ||
| }); | ||
| (0, import_react7.useEffect)(() => { | ||
| const containerElement = containerReference.current; | ||
| if (containerElement) { | ||
| const observer2 = new IntersectionObserver(updateVisibleFrame, { root: containerElement, threshold: 0 }); | ||
| setObserver(observer2); | ||
| } | ||
| }, [containerReference, updateVisibleFrame]); | ||
| return { observer, visibleItemKeys: visibleItemKeysReference }; | ||
| }, "useVisibleItems"); | ||
| // src/EndlessList/EndlessList.tsx | ||
| var noop = /* @__PURE__ */ __name(() => { | ||
| }, "noop"); | ||
| var defaultAnimationParameters = { | ||
| duration: () => 500, | ||
| easing: (t) => t | ||
| }; | ||
| var EndlessList = /* @__PURE__ */ __name(({ | ||
| ItemComponent, | ||
| initialItems, | ||
| items, | ||
| itemKey, | ||
| triggerDistance, | ||
| onTopReached, | ||
| onBottomReached, | ||
| compareItems, | ||
| PlaceholderComponent, | ||
| jumpAnimation = defaultAnimationParameters, | ||
| focusedItem, | ||
| ContainerComponent, | ||
| canStickToBottom, | ||
| onVisibleFrameChange, | ||
| containerReference: propsContainerReference | ||
| }) => { | ||
| const containerReference = (0, import_react8.useRef)(null); | ||
| const focusElementReference = (0, import_react8.useRef)(null); | ||
| const stickToBottomReached = (0, import_react8.useRef)(false); | ||
| const isScrolling = (0, import_react8.useRef)(false); | ||
| const visibleFrame = (0, import_react8.useRef)({ begin: -1, end: -1 }); | ||
| const hasMounted = (0, import_react8.useRef)(false); | ||
| const setBottomReached = useToggleEvent(onBottomReached != null ? onBottomReached : noop); | ||
| const setTopReached = useToggleEvent(onTopReached != null ? onTopReached : noop); | ||
| const getKey = (0, import_react8.useMemo)(() => { | ||
| return typeof itemKey === "function" ? itemKey : (value) => value[itemKey]; | ||
| }, [itemKey]); | ||
| (0, import_react8.useEffect)(() => { | ||
| setBottomReached(false); | ||
| setTopReached(false); | ||
| }, [items, setBottomReached, setTopReached]); | ||
| const checkBounds = useEvent((frame = visibleFrame.current) => { | ||
| onVisibleFrameChange == null ? void 0 : onVisibleFrameChange(frame); | ||
| visibleFrame.current = frame; | ||
| if (frame.begin === -1 || frame.end === -1 || isScrolling.current) { | ||
| return; | ||
| } | ||
| setBottomReached(frame.end <= triggerDistance); | ||
| setTopReached(frame.begin <= triggerDistance); | ||
| stickToBottomReached.current = frame.end === 0; | ||
| }); | ||
| const smoothScrolling = useEvent((container, item, abortController) => { | ||
| return smoothScrollToCenter(container, item, jumpAnimation, abortController); | ||
| }); | ||
| const abortControllerReference = (0, import_react8.useRef)(); | ||
| const handleJumpScroll = (0, import_react8.useCallback)( | ||
| async (abortController = new AbortController()) => { | ||
| if (abortControllerReference.current) { | ||
| abortControllerReference.current.abort(); | ||
| } | ||
| if (!containerReference.current || !focusElementReference.current) { | ||
| return; | ||
| } | ||
| abortControllerReference.current = abortController; | ||
| isScrolling.current = true; | ||
| if (hasMounted.current) { | ||
| await smoothScrolling(containerReference.current, focusElementReference.current, abortController); | ||
| } else { | ||
| focusElementReference.current.scrollIntoView({ behavior: "auto", block: "center" }); | ||
| } | ||
| isScrolling.current = false; | ||
| checkBounds(); | ||
| }, | ||
| [checkBounds, smoothScrolling] | ||
| ); | ||
| const onVisibleItemsChange = useVisibleFrame({ | ||
| getKey, | ||
| items, | ||
| onVisibleFrameUpdated: checkBounds | ||
| }); | ||
| const { observer, visibleItemKeys } = useVisibleItems(containerReference, onVisibleItemsChange); | ||
| const [scheduleJumpScroll, isJumpScheduled] = useScheduleOnNextRender(handleJumpScroll); | ||
| const lastScrolledItem = (0, import_react8.useRef)(); | ||
| const handleScrollToFocusItem = useEvent(() => { | ||
| if (focusedItem === lastScrolledItem.current) { | ||
| return; | ||
| } | ||
| lastScrolledItem.current = focusedItem; | ||
| if (focusedItem && !isJumpScheduled()) { | ||
| handleJumpScroll().catch(() => { | ||
| }); | ||
| } | ||
| }); | ||
| const itemsToRender = useEndlessList({ | ||
| getKey, | ||
| initialItems, | ||
| items, | ||
| compareItems, | ||
| handleJump: scheduleJumpScroll, | ||
| focusedItem, | ||
| visibleItemKeys, | ||
| lastScrolledItem | ||
| }); | ||
| (0, import_react8.useEffect)(() => { | ||
| handleScrollToFocusItem(); | ||
| hasMounted.current = true; | ||
| }, [handleScrollToFocusItem, itemsToRender]); | ||
| (0, import_react8.useEffect)(() => { | ||
| return () => { | ||
| hasMounted.current = false; | ||
| }; | ||
| }, []); | ||
| const handleStickToBottom = useEvent(() => { | ||
| const container = containerReference.current; | ||
| if (container && stickToBottomReached.current && !focusedItem) { | ||
| container.scrollTo({ top: container.scrollHeight }); | ||
| } | ||
| }); | ||
| (0, import_react8.useLayoutEffect)(() => { | ||
| if (canStickToBottom) { | ||
| handleStickToBottom(); | ||
| } | ||
| }, [itemsToRender, canStickToBottom, handleStickToBottom]); | ||
| return /* @__PURE__ */ React.createElement(ContainerComponent, { ref: mergeReferences(containerReference, propsContainerReference) }, itemsToRender.map((item) => /* @__PURE__ */ React.createElement( | ||
| EndlessListItemView, | ||
| __spreadValues({ | ||
| key: item.itemKey, | ||
| focusElementReference, | ||
| ItemComponent, | ||
| PlaceholderComponent, | ||
| itemObserver: observer | ||
| }, item) | ||
| ))); | ||
| }, "EndlessList"); | ||
| // src/internal/RChatContext.tsx | ||
| var import_safe_context = require("@sirse-dev/safe-context"); | ||
| var RChatContext = (0, import_safe_context.createSafeContext)(); | ||
| // src/Chat.tsx | ||
| var Chat = /* @__PURE__ */ __name((_a) => { | ||
| var _b = _a, { children } = _b, context = __objRest(_b, ["children"]); | ||
| return /* @__PURE__ */ React.createElement(RChatContext.Provider, { value: __spreadValues({}, context) }, children); | ||
| }, "Chat"); | ||
| // src/MessageList.tsx | ||
| var import_safe_context3 = require("@sirse-dev/safe-context"); | ||
| // src/internal/RoomContext.tsx | ||
| var import_safe_context2 = require("@sirse-dev/safe-context"); | ||
| var RoomContext = (0, import_safe_context2.createSafeContext)(); | ||
| // src/useMessages.tsx | ||
| var import_react10 = require("react"); | ||
| // src/internal/clamp.ts | ||
| var clamp = /* @__PURE__ */ __name((value, min, max) => Math.max(Math.min(value, max), min), "clamp"); | ||
| // src/internal/useBoundedArray.tsx | ||
| var import_react9 = require("react"); | ||
| var getClippedArray = /* @__PURE__ */ __name((items, maxSize, keep) => { | ||
| if (items.length <= maxSize) { | ||
| return items; | ||
| } | ||
| if (keep === "beginning") { | ||
| return items.slice(0, maxSize); | ||
| } | ||
| if (keep === "ending") { | ||
| return items.slice(-maxSize); | ||
| } | ||
| throw new Error(`Unrecognized "keep" option value: "${keep}"`); | ||
| }, "getClippedArray"); | ||
| var useBoundedArray = /* @__PURE__ */ __name((initial, maxChunkSize) => { | ||
| const [itemsState, setItemsState] = (0, import_react9.useState)(initial); | ||
| const itemsReference = (0, import_react9.useRef)(initial); | ||
| const setItems = (0, import_react9.useCallback)( | ||
| (items, keep) => { | ||
| const clippedItems = getClippedArray(items, maxChunkSize, keep); | ||
| setItemsState(clippedItems); | ||
| itemsReference.current = clippedItems; | ||
| return items.length > clippedItems.length; | ||
| }, | ||
| [maxChunkSize] | ||
| ); | ||
| const unshift = (0, import_react9.useCallback)( | ||
| (items) => { | ||
| return setItems([...items, ...itemsReference.current], "beginning"); | ||
| }, | ||
| [setItems] | ||
| ); | ||
| const push = (0, import_react9.useCallback)( | ||
| (items) => { | ||
| return setItems([...itemsReference.current, ...items], "ending"); | ||
| }, | ||
| [setItems] | ||
| ); | ||
| const at = (0, import_react9.useCallback)((index) => { | ||
| return itemsReference.current.at(index); | ||
| }, []); | ||
| const insert = (0, import_react9.useCallback)( | ||
| (item, index, keep) => { | ||
| itemsReference.current.splice(index, 0, item); | ||
| return setItems([...itemsReference.current], keep); | ||
| }, | ||
| [setItems] | ||
| ); | ||
| const getAll = (0, import_react9.useCallback)(() => itemsReference.current, []); | ||
| const refresh = (0, import_react9.useCallback)(() => setItemsState((old) => [...old]), []); | ||
| return [itemsState, { push, unshift, set: setItems, at, getAll, insert, refresh }]; | ||
| }, "useBoundedArray"); | ||
| // src/useMessages.tsx | ||
| var findNewElementIndex = /* @__PURE__ */ __name((elements, element, compare) => { | ||
| return elements.length - 1 - [...elements].reverse().findIndex((a) => { | ||
| return compare(element, a) > 0; | ||
| }); | ||
| }, "findNewElementIndex"); | ||
| var useMessages = /* @__PURE__ */ __name(({ | ||
| maxChunkSize, | ||
| additionalChunkSize, | ||
| chatClient, | ||
| roomIdentifier, | ||
| compareItems, | ||
| initialMessagesState, | ||
| initialSearchResult | ||
| }) => { | ||
| const isFetching = (0, import_react10.useRef)(false); | ||
| const visibleFrame = (0, import_react10.useRef)({ begin: -1, end: -1 }); | ||
| const containerReference = (0, import_react10.useRef)(null); | ||
| const searchResults = (0, import_react10.useRef)(initialSearchResult); | ||
| const selectedSearchResult = (0, import_react10.useRef)(0); | ||
| const focusedItem = (0, import_react10.useRef)(initialSearchResult == null ? void 0 : initialSearchResult.results[0]); | ||
| const [ | ||
| messages, | ||
| { | ||
| push: pushMessages, | ||
| unshift: unshiftMessages, | ||
| set: setMessages, | ||
| insert: insertMessage, | ||
| at: getMessage, | ||
| getAll: getAllMessages, | ||
| refresh | ||
| } | ||
| ] = useBoundedArray([...initialMessagesState.messages], maxChunkSize); | ||
| const messagesState = (0, import_react10.useRef)(initialMessagesState); | ||
| const handleIncomingMessage = (0, import_react10.useCallback)( | ||
| (message, messageRoomIdentifier) => { | ||
| if (messageRoomIdentifier === roomIdentifier && messagesState.current.noMessagesAfter) { | ||
| const incomingMessageIndex = findNewElementIndex(getAllMessages(), message, compareItems); | ||
| const keepDirection = visibleFrame.current.begin < visibleFrame.current.end ? "beginning" : "ending"; | ||
| const clipped = insertMessage(message, incomingMessageIndex + 1, keepDirection); | ||
| if (clipped) { | ||
| if (keepDirection === "beginning") { | ||
| messagesState.current.noMessagesAfter = false; | ||
| } else { | ||
| messagesState.current.noMessagesBefore = false; | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| [roomIdentifier, getAllMessages, compareItems, insertMessage] | ||
| ); | ||
| const focusItem = (0, import_react10.useCallback)( | ||
| async (item) => { | ||
| if (!item) { | ||
| if (focusedItem.current) { | ||
| refresh(); | ||
| } | ||
| focusedItem.current = item; | ||
| return; | ||
| } | ||
| focusedItem.current = item; | ||
| const [previousChunk, nextChunk] = await Promise.all([ | ||
| chatClient.fetchMessages(roomIdentifier, additionalChunkSize, item, void 0), | ||
| chatClient.fetchMessages(roomIdentifier, additionalChunkSize, void 0, item) | ||
| ]); | ||
| messagesState.current = { | ||
| noMessagesBefore: previousChunk.noMessagesBefore, | ||
| noMessagesAfter: nextChunk.noMessagesAfter | ||
| }; | ||
| setMessages([...previousChunk.messages, item, ...nextChunk.messages], "beginning"); | ||
| }, | ||
| [additionalChunkSize, chatClient, roomIdentifier, setMessages, refresh] | ||
| ); | ||
| const handleSearch = (0, import_react10.useCallback)( | ||
| (searchRoomIdentifier, searchResult, focusIndex) => { | ||
| if (searchRoomIdentifier === roomIdentifier) { | ||
| searchResults.current = searchResult; | ||
| focusIndex = Math.min(focusIndex, searchResult.results.length - 1); | ||
| selectedSearchResult.current = focusIndex; | ||
| focusItem(searchResult.results[focusIndex]); | ||
| } | ||
| }, | ||
| [focusItem, roomIdentifier] | ||
| ); | ||
| const handlePreviousSearchResult = (0, import_react10.useCallback)( | ||
| (searchRoomIdentifier) => { | ||
| if (searchResults.current && searchRoomIdentifier === roomIdentifier) { | ||
| selectedSearchResult.current = clamp( | ||
| selectedSearchResult.current - 1, | ||
| 0, | ||
| Math.max(searchResults.current.results.length - 1, 0) | ||
| ); | ||
| focusItem(searchResults.current.results[selectedSearchResult.current]); | ||
| } | ||
| }, | ||
| [focusItem, roomIdentifier] | ||
| ); | ||
| const handleNextSearchResult = (0, import_react10.useCallback)( | ||
| (searchRoomIdentifier) => { | ||
| if (searchResults.current && searchRoomIdentifier === roomIdentifier) { | ||
| selectedSearchResult.current = clamp( | ||
| selectedSearchResult.current + 1, | ||
| 0, | ||
| Math.max(searchResults.current.results.length - 1, 0) | ||
| ); | ||
| focusItem(searchResults.current.results[selectedSearchResult.current]); | ||
| } | ||
| }, | ||
| [focusItem, roomIdentifier] | ||
| ); | ||
| (0, import_react10.useEffect)(() => { | ||
| chatClient.addEventListener("receiveMessage", handleIncomingMessage); | ||
| chatClient.addEventListener("receiveSearchResults", handleSearch); | ||
| chatClient.addEventListener("nextSearchResult", handleNextSearchResult); | ||
| chatClient.addEventListener("previousSearchResult", handlePreviousSearchResult); | ||
| return () => { | ||
| chatClient.removeEventListener("receiveMessage", handleIncomingMessage); | ||
| chatClient.removeEventListener("receiveSearchResults", handleSearch); | ||
| chatClient.removeEventListener("nextSearchResult", handleNextSearchResult); | ||
| chatClient.removeEventListener("previousSearchResult", handlePreviousSearchResult); | ||
| }; | ||
| }, [chatClient, handleIncomingMessage, handleNextSearchResult, handlePreviousSearchResult, handleSearch]); | ||
| (0, import_react10.useEffect)(() => { | ||
| if (!initialSearchResult) { | ||
| const container = containerReference.current; | ||
| if (container) { | ||
| container.scrollTo({ top: container.scrollHeight }); | ||
| } else { | ||
| console.warn( | ||
| "RChat: container reference wasn't passed into EndlessList, so scrolling to the bottom after initial chat load failed. This may cause inconsistent behavior" | ||
| ); | ||
| } | ||
| } | ||
| }, [initialSearchResult]); | ||
| (0, import_react10.useEffect)(() => { | ||
| setMessages([...initialMessagesState.messages], "beginning"); | ||
| messagesState.current = initialMessagesState; | ||
| }, [initialMessagesState, setMessages]); | ||
| (0, import_react10.useEffect)(() => { | ||
| searchResults.current = initialSearchResult; | ||
| focusedItem.current = initialSearchResult == null ? void 0 : initialSearchResult.results[0]; | ||
| }, [initialSearchResult]); | ||
| const handleTopReached = useEvent(async () => { | ||
| if (messagesState.current.noMessagesBefore || isFetching.current) { | ||
| return; | ||
| } | ||
| isFetching.current = true; | ||
| const { messages: fetchedMessages, noMessagesBefore } = await chatClient.fetchMessages( | ||
| roomIdentifier, | ||
| additionalChunkSize, | ||
| getMessage(0), | ||
| void 0 | ||
| ); | ||
| const clipped = unshiftMessages(fetchedMessages); | ||
| const newState = { | ||
| noMessagesBefore, | ||
| noMessagesAfter: !clipped && messagesState.current.noMessagesAfter | ||
| }; | ||
| messagesState.current = newState; | ||
| isFetching.current = false; | ||
| }); | ||
| const handleBottomReached = useEvent(async () => { | ||
| if (messagesState.current.noMessagesAfter || isFetching.current) { | ||
| return; | ||
| } | ||
| isFetching.current = true; | ||
| const { messages: fetchedMessages, noMessagesAfter } = await chatClient.fetchMessages( | ||
| roomIdentifier, | ||
| additionalChunkSize, | ||
| void 0, | ||
| getMessage(-1) | ||
| ); | ||
| const clipped = pushMessages(fetchedMessages); | ||
| const newState = { | ||
| noMessagesAfter, | ||
| noMessagesBefore: !clipped && messagesState.current.noMessagesBefore | ||
| }; | ||
| messagesState.current = newState; | ||
| isFetching.current = false; | ||
| }); | ||
| const onVisibleFrameChange = /* @__PURE__ */ __name((frame) => { | ||
| visibleFrame.current = frame; | ||
| }, "onVisibleFrameChange"); | ||
| return { | ||
| messages, | ||
| onTopReached: handleTopReached, | ||
| onBottomReached: handleBottomReached, | ||
| noMessagesBefore: messagesState.current.noMessagesBefore, | ||
| noMessagesAfter: messagesState.current.noMessagesAfter, | ||
| onVisibleFrameChange, | ||
| containerReference, | ||
| focusedItem: focusedItem.current | ||
| }; | ||
| }, "useMessages"); | ||
| // src/MessageList.tsx | ||
| var MessageList = /* @__PURE__ */ __name(({ | ||
| jumpAnimation, | ||
| initialMessagesState, | ||
| initialSearchResult | ||
| }) => { | ||
| const { | ||
| client, | ||
| MessageComponent, | ||
| PlaceholderComponent, | ||
| ContainerComponent, | ||
| triggerDistance, | ||
| compareItems, | ||
| itemKey | ||
| } = (0, import_safe_context3.useSafeContext)(RChatContext); | ||
| const { roomIdentifier } = (0, import_safe_context3.useSafeContext)(RoomContext); | ||
| const { | ||
| messages, | ||
| onBottomReached, | ||
| onTopReached, | ||
| noMessagesAfter, | ||
| onVisibleFrameChange, | ||
| containerReference, | ||
| focusedItem | ||
| } = useMessages({ | ||
| chatClient: client, | ||
| additionalChunkSize: 20, | ||
| maxChunkSize: 100, | ||
| roomIdentifier, | ||
| compareItems, | ||
| initialMessagesState, | ||
| initialSearchResult | ||
| }); | ||
| return /* @__PURE__ */ React.createElement( | ||
| EndlessList, | ||
| { | ||
| initialItems: initialMessagesState.messages, | ||
| items: messages, | ||
| onTopReached, | ||
| onBottomReached, | ||
| triggerDistance, | ||
| ContainerComponent, | ||
| ItemComponent: MessageComponent, | ||
| PlaceholderComponent, | ||
| compareItems, | ||
| itemKey, | ||
| onVisibleFrameChange, | ||
| canStickToBottom: noMessagesAfter, | ||
| containerReference, | ||
| focusedItem, | ||
| jumpAnimation | ||
| } | ||
| ); | ||
| }, "MessageList"); | ||
| // src/Room.tsx | ||
| var Room = /* @__PURE__ */ __name(({ identifier, children }) => { | ||
| return /* @__PURE__ */ React.createElement(RoomContext.Provider, { value: { roomIdentifier: identifier } }, children); | ||
| }, "Room"); |
| { | ||
| "version": 3, | ||
| "sources": ["../src/index.ts", "../src/EndlessList/EndlessList.tsx", "../src/internal/mergeReferences.ts", "../src/internal/smoothScrollToCenter.ts", "../src/internal/useEvent.ts", "../src/internal/useScheduleOnNextRender.tsx", "../src/internal/useToggleEvent.ts", "../src/EndlessList/EndlessListItemView.tsx", "../src/EndlessList/useEndlessList.tsx", "../src/internal/binarySearch.ts", "../src/internal/useIdGenerator.ts", "../src/EndlessList/useVisibleFrame.tsx", "../src/EndlessList/useVisibleItems.tsx", "../src/internal/RChatContext.tsx", "../src/Chat.tsx", "../src/MessageList.tsx", "../src/internal/RoomContext.tsx", "../src/useMessages.tsx", "../src/internal/clamp.ts", "../src/internal/useBoundedArray.tsx", "../src/Room.tsx"], | ||
| "sourcesContent": ["export * from './EndlessList';\r\nexport * from './Chat';\r\nexport * from './MessageList';\r\nexport * from './Room';\r\nexport * from './useMessages';\r\nexport { type AnimationParameters } from './internal/smoothScrollToCenter';\r\n", "import {\r\n\tComponentType,\r\n\tPropsWithChildren,\r\n\tRef,\r\n\tRefAttributes,\r\n\tuseCallback,\r\n\tuseEffect,\r\n\tuseLayoutEffect,\r\n\tuseMemo,\r\n\tuseRef,\r\n} from 'react';\r\n\r\nimport { mergeReferences } from '../internal/mergeReferences';\r\nimport { AnimationParameters, smoothScrollToCenter } from '../internal/smoothScrollToCenter';\r\nimport { useEvent } from '../internal/useEvent';\r\nimport { useScheduleOnNextRender } from '../internal/useScheduleOnNextRender';\r\nimport { useToggleEvent } from '../internal/useToggleEvent';\r\n\r\nimport { EndlessListItemView } from './EndlessListItemView';\r\nimport { ItemComponentType } from './ItemComponentType';\r\nimport { PlaceholderComponentType } from './PlaceholderComponentType';\r\nimport { useEndlessList } from './useEndlessList';\r\nimport { Frame, useVisibleFrame } from './useVisibleFrame';\r\nimport { useVisibleItems } from './useVisibleItems';\r\nimport type { KeysOfType } from '../internal/KeysOfType';\r\n\r\nexport type ContainerComponentProps = PropsWithChildren<RefAttributes<HTMLElement>>;\r\n\r\nexport type ItemKey<T> = KeysOfType<T, string> | ((value: T) => string);\r\n\r\nexport type EndlessListProps<TItemType> = {\r\n\tItemComponent: ItemComponentType<TItemType>;\r\n\tPlaceholderComponent: PlaceholderComponentType;\r\n\tContainerComponent: ComponentType<ContainerComponentProps>;\r\n\tinitialItems: TItemType[];\r\n\titems: TItemType[];\r\n\titemKey: ItemKey<TItemType>;\r\n\ttriggerDistance: number;\r\n\tonTopReached?: () => void;\r\n\tonBottomReached?: () => void;\r\n\tcompareItems: (first: TItemType, second: TItemType) => number;\r\n\tfocusedItem?: TItemType;\r\n\tjumpAnimation?: AnimationParameters;\r\n\tcanStickToBottom?: boolean;\r\n\tonVisibleFrameChange?: (frame: Frame) => void;\r\n\tcontainerReference?: Ref<HTMLElement>;\r\n};\r\n\r\nconst noop = () => {\r\n\t/** No operation */\r\n};\r\n\r\nconst defaultAnimationParameters: AnimationParameters = {\r\n\t// Constant duration\r\n\tduration: () => 500,\r\n\t// Linear easing\r\n\teasing: (t) => t,\r\n};\r\n\r\nexport const EndlessList = <T,>({\r\n\tItemComponent,\r\n\tinitialItems,\r\n\titems,\r\n\titemKey,\r\n\ttriggerDistance,\r\n\tonTopReached,\r\n\tonBottomReached,\r\n\tcompareItems,\r\n\tPlaceholderComponent,\r\n\tjumpAnimation = defaultAnimationParameters,\r\n\tfocusedItem,\r\n\tContainerComponent,\r\n\tcanStickToBottom,\r\n\tonVisibleFrameChange,\r\n\tcontainerReference: propsContainerReference,\r\n}: EndlessListProps<T>) => {\r\n\tconst containerReference = useRef<HTMLElement>(null);\r\n\tconst focusElementReference = useRef<HTMLElement>(null);\r\n\tconst stickToBottomReached = useRef(false);\r\n\tconst isScrolling = useRef(false);\r\n\tconst visibleFrame = useRef<Frame>({ begin: -1, end: -1 });\r\n\tconst hasMounted = useRef(false);\r\n\r\n\tconst setBottomReached = useToggleEvent(onBottomReached ?? noop);\r\n\tconst setTopReached = useToggleEvent(onTopReached ?? noop);\r\n\r\n\tconst getKey = useMemo(() => {\r\n\t\treturn typeof itemKey === 'function' ? itemKey : (value: T) => value[itemKey] as unknown as string;\r\n\t}, [itemKey]);\r\n\r\n\tuseEffect(() => {\r\n\t\tsetBottomReached(false);\r\n\t\tsetTopReached(false);\r\n\t}, [items, setBottomReached, setTopReached]);\r\n\r\n\tconst checkBounds = useEvent((frame: Frame = visibleFrame.current) => {\r\n\t\tonVisibleFrameChange?.(frame);\r\n\t\tvisibleFrame.current = frame;\r\n\t\tif (frame.begin === -1 || frame.end === -1 || isScrolling.current) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tsetBottomReached(frame.end <= triggerDistance);\r\n\t\tsetTopReached(frame.begin <= triggerDistance);\r\n\t\tstickToBottomReached.current = frame.end === 0;\r\n\t});\r\n\r\n\tconst smoothScrolling = useEvent((container: HTMLElement, item: HTMLElement, abortController?: AbortController) => {\r\n\t\treturn smoothScrollToCenter(container, item, jumpAnimation, abortController);\r\n\t});\r\n\r\n\tconst abortControllerReference = useRef<AbortController>();\r\n\tconst handleJumpScroll = useCallback(\r\n\t\tasync (abortController = new AbortController()) => {\r\n\t\t\tif (abortControllerReference.current) {\r\n\t\t\t\tabortControllerReference.current.abort();\r\n\t\t\t}\r\n\r\n\t\t\tif (!containerReference.current || !focusElementReference.current) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tabortControllerReference.current = abortController;\r\n\t\t\tisScrolling.current = true;\r\n\r\n\t\t\tif (hasMounted.current) {\r\n\t\t\t\tawait smoothScrolling(containerReference.current, focusElementReference.current, abortController);\r\n\t\t\t} else {\r\n\t\t\t\tfocusElementReference.current.scrollIntoView({ behavior: 'auto', block: 'center' });\r\n\t\t\t}\r\n\r\n\t\t\tisScrolling.current = false;\r\n\r\n\t\t\tcheckBounds();\r\n\t\t},\r\n\t\t[checkBounds, smoothScrolling],\r\n\t);\r\n\r\n\tconst onVisibleItemsChange = useVisibleFrame({\r\n\t\tgetKey,\r\n\t\titems,\r\n\t\tonVisibleFrameUpdated: checkBounds,\r\n\t});\r\n\tconst { observer, visibleItemKeys } = useVisibleItems(containerReference, onVisibleItemsChange);\r\n\tconst [scheduleJumpScroll, isJumpScheduled] = useScheduleOnNextRender(handleJumpScroll);\r\n\r\n\tconst lastScrolledItem = useRef<T | undefined>();\r\n\tconst handleScrollToFocusItem = useEvent(() => {\r\n\t\tif (focusedItem === lastScrolledItem.current) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlastScrolledItem.current = focusedItem;\r\n\t\tif (focusedItem && !isJumpScheduled()) {\r\n\t\t\thandleJumpScroll().catch(() => {\r\n\t\t\t\t/* Ignore aborted jump error */\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\tconst itemsToRender = useEndlessList({\r\n\t\tgetKey,\r\n\t\tinitialItems,\r\n\t\titems,\r\n\t\tcompareItems,\r\n\t\thandleJump: scheduleJumpScroll,\r\n\t\tfocusedItem,\r\n\t\tvisibleItemKeys,\r\n\t\tlastScrolledItem,\r\n\t});\r\n\r\n\tuseEffect(() => {\r\n\t\thandleScrollToFocusItem();\r\n\t\thasMounted.current = true;\r\n\t}, [handleScrollToFocusItem, itemsToRender]);\r\n\r\n\tuseEffect(() => {\r\n\t\treturn () => {\r\n\t\t\thasMounted.current = false;\r\n\t\t};\r\n\t}, []);\r\n\r\n\tconst handleStickToBottom = useEvent(() => {\r\n\t\tconst container = containerReference.current;\r\n\t\tif (container && stickToBottomReached.current && !focusedItem) {\r\n\t\t\tcontainer.scrollTo({ top: container.scrollHeight });\r\n\t\t}\r\n\t});\r\n\r\n\tuseLayoutEffect(() => {\r\n\t\tif (canStickToBottom) {\r\n\t\t\thandleStickToBottom();\r\n\t\t}\r\n\t}, [itemsToRender, canStickToBottom, handleStickToBottom]);\r\n\r\n\treturn (\r\n\t\t<ContainerComponent ref={mergeReferences(containerReference, propsContainerReference)}>\r\n\t\t\t{itemsToRender.map((item) => (\r\n\t\t\t\t<EndlessListItemView\r\n\t\t\t\t\tkey={item.itemKey}\r\n\t\t\t\t\tfocusElementReference={focusElementReference}\r\n\t\t\t\t\tItemComponent={ItemComponent}\r\n\t\t\t\t\tPlaceholderComponent={PlaceholderComponent}\r\n\t\t\t\t\titemObserver={observer}\r\n\t\t\t\t\t{...item}\r\n\t\t\t\t/>\r\n\t\t\t))}\r\n\t\t</ContainerComponent>\r\n\t);\r\n};\r\n", "import { Ref, MutableRefObject } from 'react';\r\n\r\nexport const mergeReferences = <T>(\r\n\t...inputReferences: Array<Ref<T> | MutableRefObject<T> | undefined | false>\r\n): Ref<T> | undefined => {\r\n\tconst filteredInputReferences = inputReferences.filter(Boolean as unknown as (value: unknown) => value is Ref<T>);\r\n\r\n\tif (filteredInputReferences.length <= 1) {\r\n\t\treturn filteredInputReferences[0];\r\n\t}\r\n\treturn function mergedReferences(reference: T | null) {\r\n\t\tfor (const inputReference of filteredInputReferences) {\r\n\t\t\tif (typeof inputReference === 'function') {\r\n\t\t\t\tinputReference(reference);\r\n\t\t\t} else if (inputReference) {\r\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n\t\t\t\t(inputReference as any).current = reference;\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n};\r\n", "export type AnimationParameters = {\r\n\t/**\r\n\t * Easing function.\r\n\t * Takes an argument in range [0, 1] and returns value in range [0, 1].\r\n\t */\r\n\teasing: (t: number) => number;\r\n\r\n\t/**\r\n\t * Animation duration function.\r\n\t * Takes distance in pixels and returns duration in milliseconds.\r\n\t */\r\n\tduration: (distance: number) => number;\r\n};\r\n\r\nexport const smoothScrollToCenter = async (\r\n\tcontainer: HTMLElement,\r\n\telement: HTMLElement,\r\n\tparameters: AnimationParameters,\r\n\tcontroller?: AbortController,\r\n) => {\r\n\tconst elementRect = element.getBoundingClientRect();\r\n\tconst containerRect = container.getBoundingClientRect();\r\n\r\n\tconst top = elementRect.top - containerRect.top - containerRect.height / 2 + elementRect.height / 2;\r\n\r\n\tconst startPos = container.scrollTop;\r\n\tconst clientHeight = container.clientHeight;\r\n\tconst maxScroll = container.scrollHeight - clientHeight;\r\n\tconst scrollIntendedDestination = startPos + top;\r\n\tconst scrollEndValue = Math.min(Math.max(scrollIntendedDestination, 0), maxScroll);\r\n\tlet startTime = 0;\r\n\r\n\tconst duration = parameters.duration(scrollEndValue - startPos);\r\n\r\n\treturn new Promise<void>((resolve, reject) => {\r\n\t\tconst scroll = (timestamp: number) => {\r\n\t\t\tif (controller?.signal.aborted) {\r\n\t\t\t\treject(controller.signal.reason);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tstartTime = startTime || timestamp;\r\n\t\t\tconst elapsed = timestamp - startTime;\r\n\t\t\tcontainer.scrollTop = startPos + (scrollEndValue - startPos) * parameters.easing(elapsed / duration);\r\n\t\t\tif (elapsed <= duration) {\r\n\t\t\t\twindow.requestAnimationFrame(scroll);\r\n\t\t\t} else {\r\n\t\t\t\tresolve();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tif (startPos !== scrollEndValue) {\r\n\t\t\twindow.requestAnimationFrame(scroll);\r\n\t\t} else {\r\n\t\t\tresolve();\r\n\t\t}\r\n\t});\r\n};\r\n", "import { useCallback, useRef } from 'react';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ntype AnyFunction = (...arguments_: any[]) => any;\r\n\r\nexport const useEvent = <T extends AnyFunction>(handler: T): T => {\r\n\tconst handlerReference = useRef(handler);\r\n\thandlerReference.current = handler;\r\n\r\n\treturn useCallback((...parameters: Parameters<T>): ReturnType<T> => {\r\n\t\treturn handlerReference.current(...parameters);\r\n\t}, []) as T;\r\n};\r\n", "import { useCallback, useLayoutEffect, useRef } from 'react';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ntype AnyAsyncFunction = (...arguments_: any[]) => Promise<any>;\r\n\r\nexport const useScheduleOnNextRender = <T extends AnyAsyncFunction>(\r\n\thandler: T,\r\n): [schedule: (...parameters: Parameters<T>) => ReturnType<T>, isScheduled: () => boolean] => {\r\n\ttype PromiseHandle = {\r\n\t\tparameters: Parameters<T>;\r\n\t\tresolve: (value: ReturnType<Awaited<T>>) => void;\r\n\t\treject: (reason: unknown) => void;\r\n\t};\r\n\tconst unresolvedHandle = useRef<PromiseHandle>();\r\n\r\n\tuseLayoutEffect(() => {\r\n\t\tconst currentHandle = unresolvedHandle.current;\r\n\t\tunresolvedHandle.current = undefined;\r\n\t\tif (currentHandle) {\r\n\t\t\thandler(...currentHandle.parameters)\r\n\t\t\t\t.then(currentHandle.resolve)\r\n\t\t\t\t.catch(currentHandle.reject);\r\n\t\t}\r\n\t});\r\n\r\n\tconst wrappedFunction = useCallback((...parameters: Parameters<T>): ReturnType<T> => {\r\n\t\treturn new Promise<Awaited<ReturnType<T>>>((resolve, reject) => {\r\n\t\t\tunresolvedHandle.current = {\r\n\t\t\t\tparameters,\r\n\t\t\t\tresolve,\r\n\t\t\t\treject,\r\n\t\t\t};\r\n\t\t}) as ReturnType<T>;\r\n\t}, []);\r\n\r\n\tconst isScheduled = useCallback(() => {\r\n\t\treturn unresolvedHandle.current !== undefined;\r\n\t}, []);\r\n\r\n\treturn [wrappedFunction, isScheduled];\r\n};\r\n", "import { useCallback, useRef } from 'react';\r\n\r\nexport const useToggleEvent = (onTurnedOn: () => void): ((value: boolean) => void) => {\r\n\tconst value = useRef(false);\r\n\r\n\tconst toggle = useCallback(\r\n\t\t(newValue: boolean) => {\r\n\t\t\tif (!value.current && newValue) {\r\n\t\t\t\tonTurnedOn();\r\n\t\t\t}\r\n\r\n\t\t\tvalue.current = newValue;\r\n\t\t},\r\n\t\t[onTurnedOn],\r\n\t);\r\n\r\n\treturn toggle;\r\n};\r\n", "import { RefObject, useEffect, useRef } from 'react';\r\nimport { mergeReferences } from '../internal/mergeReferences';\r\nimport { ItemComponentType } from './ItemComponentType';\r\nimport { PlaceholderComponentType } from './PlaceholderComponentType';\r\nimport type { EndlessListItem } from './useEndlessList';\r\n\r\nexport type EndlessListItemViewProps<TMessageType> = EndlessListItem<TMessageType> & {\r\n\tItemComponent: ItemComponentType<TMessageType>;\r\n\tPlaceholderComponent: PlaceholderComponentType;\r\n\titemObserver: IntersectionObserver | undefined;\r\n\tfocusElementReference: RefObject<HTMLElement>;\r\n};\r\n\r\nexport const EndlessListItemView = <TMessageType,>({\r\n\tItemComponent,\r\n\tPlaceholderComponent,\r\n\titemObserver,\r\n\tfocusElementReference,\r\n\t...item\r\n}: EndlessListItemViewProps<TMessageType>) => {\r\n\tconst itemReference = useRef<HTMLElement>(null);\r\n\r\n\tuseEffect(() => {\r\n\t\tconst currentElement = itemReference.current;\r\n\t\tif (currentElement && itemObserver) {\r\n\t\t\titemObserver.observe(currentElement);\r\n\r\n\t\t\treturn () => itemObserver.unobserve(currentElement);\r\n\t\t}\r\n\t}, [itemObserver]);\r\n\r\n\tif (item.type === 'placeholder') {\r\n\t\treturn <PlaceholderComponent ref={itemReference} itemKey={item.itemKey} />;\r\n\t}\r\n\r\n\treturn <ItemComponent ref={mergeReferences(itemReference, item.focused && focusElementReference)} {...item} />;\r\n};\r\n", "import { Key, useMemo, useRef, useState, MutableRefObject, useEffect } from 'react';\r\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect';\r\nimport { binarySearch } from '../internal/binarySearch';\r\nimport { useEvent } from '../internal/useEvent';\r\nimport { useIdGenerator } from '../internal/useIdGenerator';\r\n\r\nexport type UseEndlessListConfig<T> = {\r\n\tinitialItems: T[];\r\n\titems: T[];\r\n\tgetKey: (item: T) => string;\r\n\tcompareItems: (a: T, b: T) => number;\r\n\thandleJump: (abortController: AbortController) => Promise<void>;\r\n\tfocusedItem?: T;\r\n\tvisibleItemKeys: MutableRefObject<Set<string>>;\r\n\tlastScrolledItem: MutableRefObject<T | undefined>;\r\n};\r\n\r\nexport type EndlessListRealItem<TValue> = {\r\n\ttype: 'real';\r\n\tvalue: TValue;\r\n\tindex: number;\r\n\tarray: TValue[];\r\n\titemKey: string;\r\n\tfocused: boolean;\r\n};\r\n\r\nexport type EndlessListPlaceholderItem = {\r\n\ttype: 'placeholder';\r\n\titemKey: string;\r\n};\r\n\r\nexport type EndlessListItem<TValue> = EndlessListRealItem<TValue> | EndlessListPlaceholderItem;\r\n\r\nconst valueToEndlessListItem = <T,>(getKey: (value: T) => string, focusItemKey: string | undefined) => {\r\n\treturn (value: T, index: number, array: T[]): EndlessListRealItem<T> => {\r\n\t\tconst key = getKey(value);\r\n\r\n\t\treturn {\r\n\t\t\ttype: 'real',\r\n\t\t\tvalue,\r\n\t\t\tindex,\r\n\t\t\tarray,\r\n\t\t\tfocused: key === focusItemKey,\r\n\t\t\titemKey: key,\r\n\t\t};\r\n\t};\r\n};\r\n\r\nexport const useEndlessList = <T,>({\r\n\tinitialItems,\r\n\titems,\r\n\tgetKey,\r\n\tfocusedItem,\r\n\tcompareItems,\r\n\thandleJump,\r\n\tvisibleItemKeys,\r\n\tlastScrolledItem,\r\n}: UseEndlessListConfig<T>): Array<EndlessListItem<T>> => {\r\n\tconst focusedItemKey = focusedItem === undefined ? undefined : getKey(focusedItem);\r\n\tconst defaultConvertItem = useMemo(() => valueToEndlessListItem(getKey, focusedItemKey), [getKey, focusedItemKey]);\r\n\tconst [renderedItems, setRenderedItems] = useState<Array<EndlessListItem<T>>>(() => items.map(defaultConvertItem));\r\n\tconst jumpAbortController = useRef<AbortController>();\r\n\tconst initialItemsReference = useRef(initialItems);\r\n\tconst hasMounted = useRef(false);\r\n\r\n\tconst getUniquePlaceholderKey = useIdGenerator();\r\n\r\n\tconst performFixup = useEvent((): [items: Array<EndlessListItem<T>>, constructItems: boolean] => {\r\n\t\t/**\r\n\t\t * Visible items fixup algorithm.\r\n\t\t *\r\n\t\t * Firstly, take all items, which are displayed on the screen.\r\n\t\t */\r\n\r\n\t\tconst visibleItems = renderedItems\r\n\t\t\t.filter(({ itemKey, type }, index, array) => {\r\n\t\t\t\tif (visibleItemKeys.current.has(itemKey)) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (type === 'placeholder') {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst previousItem = array[index - 1];\r\n\t\t\t\tif (\r\n\t\t\t\t\tpreviousItem &&\r\n\t\t\t\t\tpreviousItem.type !== 'placeholder' &&\r\n\t\t\t\t\tvisibleItemKeys.current.has(previousItem.itemKey)\r\n\t\t\t\t) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst nextItem = array[index + 1];\r\n\t\t\t\tif (nextItem && nextItem.type !== 'placeholder' && visibleItemKeys.current.has(nextItem.itemKey)) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn false;\r\n\t\t\t})\r\n\t\t\t.map((item) => {\r\n\t\t\t\tif (item.type === 'real' && item.focused) {\r\n\t\t\t\t\titem.focused = false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn item;\r\n\t\t\t});\r\n\r\n\t\tconst keys = new Set(items.map(getKey));\r\n\t\tif (visibleItems.every((item) => !keys.has(item.itemKey))) {\r\n\t\t\treturn [visibleItems, true];\r\n\t\t}\r\n\r\n\t\tconst comparator = (a: EndlessListRealItem<T>, b: { value: EndlessListItem<T>; index: number }): number => {\r\n\t\t\tif (b.value.type === 'placeholder') {\r\n\t\t\t\tconst nextValue = visibleItems[b.index + 1];\r\n\r\n\t\t\t\tif (nextValue !== undefined && nextValue.type !== 'placeholder') {\r\n\t\t\t\t\treturn compareItems(nextValue.value, a.value);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn 1;\r\n\t\t\t}\r\n\r\n\t\t\treturn compareItems(a.value, b.value.value);\r\n\t\t};\r\n\r\n\t\tconst jumpKey = focusedItemKey ?? getKey(items[Math.floor(items.length / 2)]);\r\n\t\tconst convertedItems = [...items.map(valueToEndlessListItem(getKey, jumpKey))];\r\n\r\n\t\tlet pivotIndex = visibleItems.findIndex((item) => keys.has(item.itemKey));\r\n\r\n\t\tif (pivotIndex === -1) {\r\n\t\t\tpivotIndex = binarySearch(visibleItems, convertedItems.at(0)!, comparator);\r\n\t\t}\r\n\t\tvisibleItems.splice(pivotIndex, 1, ...convertedItems);\r\n\r\n\t\tconst dedupedKeys = new Set<Key>();\r\n\t\tconst filteredItems = visibleItems.filter((item) => {\r\n\t\t\tif (dedupedKeys.has(item.itemKey)) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tdedupedKeys.add(item.itemKey);\r\n\t\t\treturn true;\r\n\t\t});\r\n\r\n\t\treturn [filteredItems, false];\r\n\t});\r\n\r\n\tconst update = useEvent(async () => {\r\n\t\tif (jumpAbortController.current) {\r\n\t\t\tjumpAbortController.current.abort();\r\n\t\t\tjumpAbortController.current = undefined;\r\n\t\t}\r\n\r\n\t\tif (renderedItems.length === 0 || items.length === 0 || initialItemsReference.current !== initialItems) {\r\n\t\t\t/**\r\n\t\t\t * There is nothing to do:\r\n\t\t\t * 1. If renderedItems array is empty, it means that there is nothing on the screen - render all items.\r\n\t\t\t * 2. If items array is empty, it means that all items must disappear from the screen.\r\n\t\t\t * \t 3. If initial items has been changed\r\n\t\t\t */\r\n\t\t\tsetRenderedItems(items.map(defaultConvertItem));\r\n\t\t\tinitialItemsReference.current = initialItems;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t * Determine, if current update call has aborted previous jump.\r\n\t\t */\r\n\t\tconst isAbortedPreviousJump = renderedItems.some((item) => item.type === 'placeholder');\r\n\r\n\t\tlet oldItems: Array<EndlessListItem<T>>;\r\n\t\tlet constructItems = true;\r\n\t\tif (isAbortedPreviousJump) {\r\n\t\t\t/**\r\n\t\t\t * Previous jump was terminated by current state update.\r\n\t\t\t * Must perform one-time fixup.\r\n\t\t\t */\r\n\t\t\t[oldItems, constructItems] = performFixup();\r\n\r\n\t\t\tlet array = [];\r\n\t\t\tlet index = 0;\r\n\t\t\tfor (const item of oldItems) {\r\n\t\t\t\tif (item.type === 'placeholder') {\r\n\t\t\t\t\tindex = 0;\r\n\t\t\t\t\tarray = [];\r\n\t\t\t\t} else {\r\n\t\t\t\t\titem.index = index;\r\n\t\t\t\t\titem.array = array;\r\n\t\t\t\t\tarray.push(item.value);\r\n\t\t\t\t\t++index;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst keys = items.map(getKey);\r\n\t\t\tconst oldKeys = renderedItems.map((item) => item.itemKey);\r\n\r\n\t\t\tconst mustMoveForward = !oldKeys.includes(keys[0]) && !keys.includes(oldKeys.at(-1)!);\r\n\t\t\tconst mustMoveBack = !keys.includes(oldKeys[0]) && !oldKeys.includes(keys.at(-1)!);\r\n\r\n\t\t\tconst mustJump = mustMoveForward && mustMoveBack;\r\n\r\n\t\t\tif (!mustJump) {\r\n\t\t\t\tsetRenderedItems(items.map(defaultConvertItem));\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\toldItems = renderedItems.map((item) => {\r\n\t\t\t\tif (item.type === 'real' && item.focused) {\r\n\t\t\t\t\titem.focused = false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn item;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tlet constructedItems: Array<EndlessListItem<T>>;\r\n\t\tif (constructItems) {\r\n\t\t\tconst firstItem = oldItems.find((item): item is EndlessListRealItem<T> => item.type === 'real');\r\n\t\t\tlet jumpDirection = 'forward';\r\n\t\t\tif (firstItem) {\r\n\t\t\t\tjumpDirection = compareItems(items[0], firstItem.value) < 0 ? 'forward' : 'back';\r\n\t\t\t}\r\n\r\n\t\t\tconst jumpKey = focusedItemKey ?? getKey(items[Math.floor(items.length / 2)]);\r\n\r\n\t\t\tlet nextItems: Array<EndlessListItem<T>> | undefined;\r\n\t\t\tlet previousItems: Array<EndlessListItem<T>> | undefined;\r\n\r\n\t\t\tconst convertItem = valueToEndlessListItem(getKey, jumpKey);\r\n\t\t\tif (jumpDirection === 'forward') {\r\n\t\t\t\tnextItems = items.map(convertItem);\r\n\t\t\t\tpreviousItems = oldItems;\r\n\t\t\t} else {\r\n\t\t\t\tnextItems = oldItems;\r\n\t\t\t\tpreviousItems = items.map(convertItem);\r\n\t\t\t}\r\n\r\n\t\t\tconst alreadyHasPlaceholder =\r\n\t\t\t\tnextItems.at(-1)?.type === 'placeholder' || previousItems.at(0)?.type === 'placeholder';\r\n\r\n\t\t\tconstructedItems = [\r\n\t\t\t\t...nextItems,\r\n\t\t\t\t...(alreadyHasPlaceholder\r\n\t\t\t\t\t? []\r\n\t\t\t\t\t: [{ type: 'placeholder' as const, itemKey: getUniquePlaceholderKey() }]),\r\n\t\t\t\t...previousItems,\r\n\t\t\t];\r\n\t\t} else {\r\n\t\t\tconstructedItems = oldItems;\r\n\t\t}\r\n\r\n\t\tlastScrolledItem.current = items[Math.floor(items.length / 2)];\r\n\r\n\t\tsetRenderedItems(constructedItems);\r\n\t\tconst newController = new AbortController();\r\n\t\tjumpAbortController.current = newController;\r\n\r\n\t\ttry {\r\n\t\t\tif (hasMounted.current) {\r\n\t\t\t\tawait handleJump(newController);\r\n\t\t\t}\r\n\r\n\t\t\tsetRenderedItems(items.map(defaultConvertItem));\r\n\t\t} catch {\r\n\t\t\t/* Noop */\r\n\t\t} finally {\r\n\t\t\tjumpAbortController.current = undefined;\r\n\t\t}\r\n\t});\r\n\r\n\tuseIsomorphicLayoutEffect(() => {\r\n\t\tupdate();\r\n\t\thasMounted.current = true;\r\n\t}, [update, items]);\r\n\r\n\tuseEffect(() => {\r\n\t\treturn () => {\r\n\t\t\thasMounted.current = false;\r\n\t\t};\r\n\t}, []);\r\n\r\n\treturn renderedItems;\r\n};\r\n", "export const binarySearch = <TItem, TValue extends TItem = TItem>(\r\n\tarray: TItem[],\r\n\tvalue: TValue,\r\n\tcomparator: (a: TValue, b: { value: TItem; index: number }) => number,\r\n): number => {\r\n\tlet low = 0;\r\n\tlet high = array.length;\r\n\r\n\tif (high === 0) {\r\n\t\treturn 0;\r\n\t}\r\n\r\n\twhile (low < high) {\r\n\t\tconst middle = Math.floor((low + high) / 2);\r\n\r\n\t\tif (comparator(value, { value: array[middle], index: middle }) > 0) {\r\n\t\t\tlow = middle + 1;\r\n\t\t} else {\r\n\t\t\thigh = middle;\r\n\t\t}\r\n\t}\r\n\r\n\treturn high;\r\n};\r\n", "import { useCallback, useRef } from 'react';\r\n\r\nexport const useIdGenerator = (): (() => string) => {\r\n\tconst counter = useRef(0);\r\n\r\n\treturn useCallback(() => `:rchat:-${++counter.current}`, []);\r\n};\r\n", "import { useEvent } from '../internal/useEvent';\r\n\r\nexport type UseVisibleFrameConfig<TValue> = {\r\n\titems: TValue[];\r\n\tgetKey: (item: TValue) => string;\r\n\tonVisibleFrameUpdated: (frame: Frame) => void;\r\n};\r\n\r\nexport type Frame = {\r\n\tbegin: number;\r\n\tend: number;\r\n};\r\n\r\nexport const useVisibleFrame = <TValue,>({\r\n\titems,\r\n\tgetKey,\r\n\tonVisibleFrameUpdated,\r\n}: UseVisibleFrameConfig<TValue>): ((keys: Set<string>) => void) => {\r\n\tconst updateVisibleFrame = useEvent((visibleItemKeys: Set<string>) => {\r\n\t\tlet begin = -1;\r\n\t\tfor (const [index, item] of items.entries()) {\r\n\t\t\tif (visibleItemKeys.has(getKey(item))) {\r\n\t\t\t\tbegin = index;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet end = -1;\r\n\t\tfor (let index = 0; index <= items.length; ++index) {\r\n\t\t\tconst item = items.at(-index - 1);\r\n\t\t\tif (item && visibleItemKeys.has(getKey(item))) {\r\n\t\t\t\tend = index;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tonVisibleFrameUpdated({ begin, end });\r\n\t});\r\n\r\n\treturn updateVisibleFrame;\r\n};\r\n", "import { RefObject, useEffect, useState, MutableRefObject, useRef } from 'react';\r\nimport { useEvent } from '../internal/useEvent';\r\n\r\nexport type VisibleItemsBag = {\r\n\tobserver: IntersectionObserver | undefined;\r\n\tvisibleItemKeys: MutableRefObject<Set<string>>;\r\n};\r\n\r\nexport const useVisibleItems = (\r\n\tcontainerReference: RefObject<HTMLElement>,\r\n\tonVisibleItemsChange?: (items: Set<string>) => void,\r\n): VisibleItemsBag => {\r\n\tconst [observer, setObserver] = useState<IntersectionObserver>();\r\n\tconst visibleItemKeysReference = useRef(new Set<string>());\r\n\r\n\tconst updateVisibleFrame = useEvent((entries: IntersectionObserverEntry[]) => {\r\n\t\tfor (const { target, isIntersecting } of entries) {\r\n\t\t\tconst key = (target as HTMLElement).dataset.key;\r\n\r\n\t\t\tif (!key) {\r\n\t\t\t\t// eslint-disable-next-line no-console\r\n\t\t\t\tconsole.warn('Item component doesn\\'t have \"data-key\" attribute.');\r\n\t\t\t} else if (isIntersecting) {\r\n\t\t\t\tvisibleItemKeysReference.current.add(key);\r\n\t\t\t} else {\r\n\t\t\t\tvisibleItemKeysReference.current.delete(key);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tonVisibleItemsChange?.(visibleItemKeysReference.current);\r\n\t});\r\n\r\n\tuseEffect(() => {\r\n\t\tconst containerElement = containerReference.current;\r\n\t\tif (containerElement) {\r\n\t\t\tconst observer = new IntersectionObserver(updateVisibleFrame, { root: containerElement, threshold: 0 });\r\n\r\n\t\t\tsetObserver(observer);\r\n\t\t}\r\n\t}, [containerReference, updateVisibleFrame]);\r\n\r\n\treturn { observer, visibleItemKeys: visibleItemKeysReference };\r\n};\r\n", "import { ChatClient } from '@rchat/client';\r\nimport { createSafeContext } from '@sirse-dev/safe-context';\r\nimport type { ContainerComponentProps, ItemComponentType, ItemKey, PlaceholderComponentType } from '../EndlessList';\r\nimport type { ComponentType } from 'react';\r\n\r\nexport type RChatContextType<TMessageType> = {\r\n\tclient: ChatClient<TMessageType>;\r\n\tMessageComponent: ItemComponentType<TMessageType>;\r\n\tPlaceholderComponent: PlaceholderComponentType;\r\n\tContainerComponent: ComponentType<ContainerComponentProps>;\r\n\ttriggerDistance: number;\r\n\titemKey: ItemKey<TMessageType>;\r\n\tcompareItems: (first: TMessageType, second: TMessageType) => number;\r\n};\r\n\r\nexport const RChatContext = createSafeContext<RChatContextType<unknown>>();\r\n", "import { PropsWithChildren } from 'react';\r\n\r\nimport { RChatContext, RChatContextType } from './internal/RChatContext';\r\n\r\nexport type ChatProps<TMessageType> = PropsWithChildren<RChatContextType<TMessageType>>;\r\n\r\nexport const Chat = <TMessageType,>({ children, ...context }: ChatProps<TMessageType>) => (\r\n\t<RChatContext.Provider value={{ ...(context as RChatContextType<unknown>) }}>{children}</RChatContext.Provider>\r\n);\r\n", "import { MessageFetchResult, MessageSearchResult } from '@rchat/client';\r\nimport { useSafeContext } from '@sirse-dev/safe-context';\r\nimport { EndlessList } from './EndlessList';\r\nimport { RChatContext } from './internal/RChatContext';\r\nimport { RoomContext } from './internal/RoomContext';\r\nimport { AnimationParameters } from './internal/smoothScrollToCenter';\r\nimport { useMessages } from './useMessages';\r\n\r\nexport type MessageListProps<TMessage> = {\r\n\tinitialMessagesState: MessageFetchResult<TMessage>;\r\n\tinitialSearchResult?: MessageSearchResult<TMessage>;\r\n\tjumpAnimation?: AnimationParameters;\r\n};\r\n\r\nexport const MessageList = <TMessage,>({\r\n\tjumpAnimation,\r\n\tinitialMessagesState,\r\n\tinitialSearchResult,\r\n}: MessageListProps<TMessage>) => {\r\n\tconst {\r\n\t\tclient,\r\n\t\tMessageComponent,\r\n\t\tPlaceholderComponent,\r\n\t\tContainerComponent,\r\n\t\ttriggerDistance,\r\n\t\tcompareItems,\r\n\t\titemKey,\r\n\t} = useSafeContext(RChatContext);\r\n\tconst { roomIdentifier } = useSafeContext(RoomContext);\r\n\r\n\tconst {\r\n\t\tmessages,\r\n\t\tonBottomReached,\r\n\t\tonTopReached,\r\n\t\tnoMessagesAfter,\r\n\t\tonVisibleFrameChange,\r\n\t\tcontainerReference,\r\n\t\tfocusedItem,\r\n\t} = useMessages({\r\n\t\tchatClient: client,\r\n\t\tadditionalChunkSize: 20,\r\n\t\tmaxChunkSize: 100,\r\n\t\troomIdentifier,\r\n\t\tcompareItems,\r\n\t\tinitialMessagesState,\r\n\t\tinitialSearchResult,\r\n\t});\r\n\r\n\treturn (\r\n\t\t<EndlessList\r\n\t\t\tinitialItems={initialMessagesState.messages}\r\n\t\t\titems={messages}\r\n\t\t\tonTopReached={onTopReached}\r\n\t\t\tonBottomReached={onBottomReached}\r\n\t\t\ttriggerDistance={triggerDistance}\r\n\t\t\tContainerComponent={ContainerComponent}\r\n\t\t\tItemComponent={MessageComponent}\r\n\t\t\tPlaceholderComponent={PlaceholderComponent}\r\n\t\t\tcompareItems={compareItems}\r\n\t\t\titemKey={itemKey}\r\n\t\t\tonVisibleFrameChange={onVisibleFrameChange}\r\n\t\t\tcanStickToBottom={noMessagesAfter}\r\n\t\t\tcontainerReference={containerReference}\r\n\t\t\tfocusedItem={focusedItem}\r\n\t\t\tjumpAnimation={jumpAnimation}\r\n\t\t/>\r\n\t);\r\n};\r\n", "import { createSafeContext } from '@sirse-dev/safe-context';\r\n\r\nexport type RoomContextType = {\r\n\troomIdentifier: string;\r\n};\r\n\r\nexport const RoomContext = createSafeContext<RoomContextType>();\r\n", "import { MessageFetchResult, MessageSearchResult } from '@rchat/client';\r\nimport { ChatClient } from '@rchat/client';\r\nimport { Ref, useCallback, useEffect, useRef } from 'react';\r\nimport { Frame } from './EndlessList/useVisibleFrame';\r\nimport { clamp } from './internal/clamp';\r\nimport { KeepDirection, useBoundedArray } from './internal/useBoundedArray';\r\nimport { useEvent } from './internal/useEvent';\r\n\r\nexport type UseMessagesBag<T> = {\r\n\tmessages: T[];\r\n\tonTopReached: () => void;\r\n\tonBottomReached: () => void;\r\n\tnoMessagesBefore: boolean;\r\n\tnoMessagesAfter: boolean;\r\n\tonVisibleFrameChange: (frame: Frame) => void;\r\n\tcontainerReference: Ref<HTMLElement>;\r\n\tfocusedItem?: T;\r\n};\r\n\r\nexport type UseMessagesConfig<T> = {\r\n\tinitialMessagesState: MessageFetchResult<T>;\r\n\tinitialSearchResult?: MessageSearchResult<T>;\r\n\tcompareItems: (a: T, b: T) => number;\r\n\tmaxChunkSize: number;\r\n\tadditionalChunkSize: number;\r\n\tchatClient: ChatClient<T>;\r\n\troomIdentifier: string;\r\n};\r\n\r\n// TODO: replace with binary search\r\nconst findNewElementIndex = <T,>(elements: readonly T[], element: T, compare: (a: T, b: T) => number): number => {\r\n\treturn (\r\n\t\telements.length -\r\n\t\t1 -\r\n\t\t[...elements].reverse().findIndex((a) => {\r\n\t\t\treturn compare(element, a) > 0;\r\n\t\t})\r\n\t);\r\n};\r\n\r\nexport const useMessages = <TMessage,>({\r\n\tmaxChunkSize,\r\n\tadditionalChunkSize,\r\n\tchatClient,\r\n\troomIdentifier,\r\n\tcompareItems,\r\n\tinitialMessagesState,\r\n\tinitialSearchResult,\r\n}: UseMessagesConfig<TMessage>): UseMessagesBag<TMessage> => {\r\n\tconst isFetching = useRef(false);\r\n\tconst visibleFrame = useRef<Frame>({ begin: -1, end: -1 });\r\n\tconst containerReference = useRef<HTMLElement>(null);\r\n\tconst searchResults = useRef<MessageSearchResult<TMessage> | undefined>(initialSearchResult);\r\n\tconst selectedSearchResult = useRef(0);\r\n\tconst focusedItem = useRef<TMessage | undefined>(initialSearchResult?.results[0]);\r\n\r\n\tconst [\r\n\t\tmessages,\r\n\t\t{\r\n\t\t\tpush: pushMessages,\r\n\t\t\tunshift: unshiftMessages,\r\n\t\t\tset: setMessages,\r\n\t\t\tinsert: insertMessage,\r\n\t\t\tat: getMessage,\r\n\t\t\tgetAll: getAllMessages,\r\n\t\t\trefresh,\r\n\t\t},\r\n\t] = useBoundedArray<TMessage>([...initialMessagesState.messages], maxChunkSize);\r\n\r\n\tconst messagesState = useRef<Omit<MessageFetchResult<TMessage>, 'messages'>>(initialMessagesState);\r\n\r\n\tconst handleIncomingMessage = useCallback(\r\n\t\t(message: TMessage, messageRoomIdentifier: string) => {\r\n\t\t\tif (messageRoomIdentifier === roomIdentifier && messagesState.current.noMessagesAfter) {\r\n\t\t\t\tconst incomingMessageIndex = findNewElementIndex(getAllMessages(), message, compareItems);\r\n\r\n\t\t\t\tconst keepDirection: KeepDirection =\r\n\t\t\t\t\tvisibleFrame.current.begin < visibleFrame.current.end ? 'beginning' : 'ending';\r\n\r\n\t\t\t\tconst clipped = insertMessage(message, incomingMessageIndex + 1, keepDirection);\r\n\r\n\t\t\t\tif (clipped) {\r\n\t\t\t\t\tif (keepDirection === 'beginning') {\r\n\t\t\t\t\t\tmessagesState.current.noMessagesAfter = false;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tmessagesState.current.noMessagesBefore = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\t[roomIdentifier, getAllMessages, compareItems, insertMessage],\r\n\t);\r\n\r\n\tconst focusItem = useCallback(\r\n\t\tasync (item: TMessage | undefined) => {\r\n\t\t\tif (!item) {\r\n\t\t\t\tif (focusedItem.current) {\r\n\t\t\t\t\trefresh();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfocusedItem.current = item;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tfocusedItem.current = item;\r\n\r\n\t\t\tconst [previousChunk, nextChunk] = await Promise.all([\r\n\t\t\t\tchatClient.fetchMessages(roomIdentifier, additionalChunkSize, item, undefined),\r\n\t\t\t\tchatClient.fetchMessages(roomIdentifier, additionalChunkSize, undefined, item),\r\n\t\t\t]);\r\n\r\n\t\t\tmessagesState.current = {\r\n\t\t\t\tnoMessagesBefore: previousChunk.noMessagesBefore,\r\n\t\t\t\tnoMessagesAfter: nextChunk.noMessagesAfter,\r\n\t\t\t};\r\n\r\n\t\t\tsetMessages([...previousChunk.messages, item, ...nextChunk.messages], 'beginning');\r\n\t\t},\r\n\t\t[additionalChunkSize, chatClient, roomIdentifier, setMessages, refresh],\r\n\t);\r\n\r\n\tconst handleSearch = useCallback(\r\n\t\t(searchRoomIdentifier: string, searchResult: MessageSearchResult<TMessage>, focusIndex: number) => {\r\n\t\t\tif (searchRoomIdentifier === roomIdentifier) {\r\n\t\t\t\tsearchResults.current = searchResult;\r\n\t\t\t\tfocusIndex = Math.min(focusIndex, searchResult.results.length - 1);\r\n\t\t\t\tselectedSearchResult.current = focusIndex;\r\n\t\t\t\tfocusItem(searchResult.results[focusIndex]);\r\n\t\t\t}\r\n\t\t},\r\n\t\t[focusItem, roomIdentifier],\r\n\t);\r\n\r\n\tconst handlePreviousSearchResult = useCallback(\r\n\t\t(searchRoomIdentifier: string) => {\r\n\t\t\tif (searchResults.current && searchRoomIdentifier === roomIdentifier) {\r\n\t\t\t\tselectedSearchResult.current = clamp(\r\n\t\t\t\t\tselectedSearchResult.current - 1,\r\n\t\t\t\t\t0,\r\n\t\t\t\t\tMath.max(searchResults.current.results.length - 1, 0),\r\n\t\t\t\t);\r\n\t\t\t\tfocusItem(searchResults.current.results[selectedSearchResult.current]);\r\n\t\t\t}\r\n\t\t},\r\n\t\t[focusItem, roomIdentifier],\r\n\t);\r\n\r\n\tconst handleNextSearchResult = useCallback(\r\n\t\t(searchRoomIdentifier: string) => {\r\n\t\t\tif (searchResults.current && searchRoomIdentifier === roomIdentifier) {\r\n\t\t\t\tselectedSearchResult.current = clamp(\r\n\t\t\t\t\tselectedSearchResult.current + 1,\r\n\t\t\t\t\t0,\r\n\t\t\t\t\tMath.max(searchResults.current.results.length - 1, 0),\r\n\t\t\t\t);\r\n\t\t\t\tfocusItem(searchResults.current.results[selectedSearchResult.current]);\r\n\t\t\t}\r\n\t\t},\r\n\t\t[focusItem, roomIdentifier],\r\n\t);\r\n\r\n\tuseEffect(() => {\r\n\t\tchatClient.addEventListener('receiveMessage', handleIncomingMessage);\r\n\t\tchatClient.addEventListener('receiveSearchResults', handleSearch);\r\n\t\tchatClient.addEventListener('nextSearchResult', handleNextSearchResult);\r\n\t\tchatClient.addEventListener('previousSearchResult', handlePreviousSearchResult);\r\n\r\n\t\treturn () => {\r\n\t\t\tchatClient.removeEventListener('receiveMessage', handleIncomingMessage);\r\n\t\t\tchatClient.removeEventListener('receiveSearchResults', handleSearch);\r\n\t\t\tchatClient.removeEventListener('nextSearchResult', handleNextSearchResult);\r\n\t\t\tchatClient.removeEventListener('previousSearchResult', handlePreviousSearchResult);\r\n\t\t};\r\n\t}, [chatClient, handleIncomingMessage, handleNextSearchResult, handlePreviousSearchResult, handleSearch]);\r\n\r\n\t// Scroll to bottom if there was no initial search\r\n\tuseEffect(() => {\r\n\t\tif (!initialSearchResult) {\r\n\t\t\tconst container = containerReference.current;\r\n\t\t\tif (container) {\r\n\t\t\t\tcontainer.scrollTo({ top: container.scrollHeight });\r\n\t\t\t} else {\r\n\t\t\t\t// eslint-disable-next-line no-console\r\n\t\t\t\tconsole.warn(\r\n\t\t\t\t\t\"RChat: container reference wasn't passed into EndlessList,\" +\r\n\t\t\t\t\t\t' so scrolling to the bottom after initial chat load failed.' +\r\n\t\t\t\t\t\t' This may cause inconsistent behavior',\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\t}, [initialSearchResult]);\r\n\r\n\tuseEffect(() => {\r\n\t\tsetMessages([...initialMessagesState.messages], 'beginning');\r\n\t\tmessagesState.current = initialMessagesState;\r\n\t}, [initialMessagesState, setMessages]);\r\n\r\n\tuseEffect(() => {\r\n\t\tsearchResults.current = initialSearchResult;\r\n\t\tfocusedItem.current = initialSearchResult?.results[0];\r\n\t}, [initialSearchResult]);\r\n\r\n\tconst handleTopReached = useEvent(async () => {\r\n\t\tif (messagesState.current.noMessagesBefore || isFetching.current) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tisFetching.current = true;\r\n\t\tconst { messages: fetchedMessages, noMessagesBefore } = await chatClient.fetchMessages(\r\n\t\t\troomIdentifier,\r\n\t\t\tadditionalChunkSize,\r\n\t\t\tgetMessage(0),\r\n\t\t\tundefined,\r\n\t\t);\r\n\r\n\t\tconst clipped = unshiftMessages(fetchedMessages);\r\n\r\n\t\tconst newState = {\r\n\t\t\tnoMessagesBefore,\r\n\t\t\tnoMessagesAfter: !clipped && messagesState.current.noMessagesAfter,\r\n\t\t};\r\n\t\tmessagesState.current = newState;\r\n\t\tisFetching.current = false;\r\n\t});\r\n\r\n\tconst handleBottomReached = useEvent(async () => {\r\n\t\tif (messagesState.current.noMessagesAfter || isFetching.current) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tisFetching.current = true;\r\n\t\tconst { messages: fetchedMessages, noMessagesAfter } = await chatClient.fetchMessages(\r\n\t\t\troomIdentifier,\r\n\t\t\tadditionalChunkSize,\r\n\t\t\tundefined,\r\n\t\t\tgetMessage(-1),\r\n\t\t);\r\n\r\n\t\tconst clipped = pushMessages(fetchedMessages);\r\n\t\tconst newState = {\r\n\t\t\tnoMessagesAfter,\r\n\t\t\tnoMessagesBefore: !clipped && messagesState.current.noMessagesBefore,\r\n\t\t};\r\n\r\n\t\tmessagesState.current = newState;\r\n\t\tisFetching.current = false;\r\n\t});\r\n\r\n\tconst onVisibleFrameChange = (frame: Frame) => {\r\n\t\tvisibleFrame.current = frame;\r\n\t};\r\n\r\n\treturn {\r\n\t\tmessages,\r\n\t\tonTopReached: handleTopReached,\r\n\t\tonBottomReached: handleBottomReached,\r\n\t\tnoMessagesBefore: messagesState.current.noMessagesBefore,\r\n\t\tnoMessagesAfter: messagesState.current.noMessagesAfter,\r\n\t\tonVisibleFrameChange,\r\n\t\tcontainerReference,\r\n\t\tfocusedItem: focusedItem.current,\r\n\t};\r\n};\r\n", "export const clamp = (value: number, min: number, max: number) => Math.max(Math.min(value, max), min);\r\n", "import { useCallback, useRef, useState } from 'react';\r\n\r\nexport type KeepDirection = 'beginning' | 'ending';\r\n\r\nexport type BoundedArrayControl<T> = {\r\n\t/**\r\n\t * Add elements to the end of the array.\r\n\t * Clips array by specified \"maxSize\".\r\n\t * Ensures, that last item won't be clipped.\r\n\t */\r\n\tpush: (items: T[]) => boolean;\r\n\t/**\r\n\t * Add elements to the beginning of the array.\r\n\t * Clips array by specified \"maxSize\".\r\n\t * Ensures, that first item won't be clipped.\r\n\t */\r\n\tunshift: (items: T[]) => boolean;\r\n\t/**\r\n\t * Set all elements to the array.\r\n\t * Clips array by specified \"maxSize\".\r\n\t * Keeps elements according to \"keep\" argument's value:\r\n\t * beginning - array will be clipped from the end.\r\n\t * ending - array will be clipped from the beginning.\r\n\t */\r\n\tset: (items: T[], keep: KeepDirection) => boolean;\r\n\r\n\tinsert: (item: T, index: number, keep: KeepDirection) => boolean;\r\n\t/**\r\n\t * Works exactly like \"Array.prototype.at\".\r\n\t */\r\n\tat: (index: number) => T | undefined;\r\n\t/**\r\n\t * Returns reference to current array.\r\n\t */\r\n\tgetAll: () => readonly T[];\r\n\t/**\r\n\t * Sets state to the old one in order to rerender.\r\n\t */\r\n\trefresh: () => void;\r\n};\r\n\r\nconst getClippedArray = <T,>(items: T[], maxSize: number, keep: KeepDirection) => {\r\n\tif (items.length <= maxSize) {\r\n\t\treturn items;\r\n\t}\r\n\r\n\tif (keep === 'beginning') {\r\n\t\treturn items.slice(0, maxSize);\r\n\t}\r\n\r\n\tif (keep === 'ending') {\r\n\t\treturn items.slice(-maxSize);\r\n\t}\r\n\r\n\tthrow new Error(`Unrecognized \"keep\" option value: \"${keep}\"`);\r\n};\r\n\r\nexport const useBoundedArray = <T,>(\r\n\tinitial: T[],\r\n\tmaxChunkSize: number,\r\n): [items: T[], control: BoundedArrayControl<T>] => {\r\n\tconst [itemsState, setItemsState] = useState(initial);\r\n\tconst itemsReference = useRef(initial);\r\n\r\n\tconst setItems = useCallback(\r\n\t\t(items: T[], keep: KeepDirection) => {\r\n\t\t\tconst clippedItems = getClippedArray(items, maxChunkSize, keep);\r\n\t\t\tsetItemsState(clippedItems);\r\n\t\t\titemsReference.current = clippedItems;\r\n\r\n\t\t\treturn items.length > clippedItems.length;\r\n\t\t},\r\n\t\t[maxChunkSize],\r\n\t);\r\n\r\n\tconst unshift = useCallback(\r\n\t\t(items: T[]) => {\r\n\t\t\treturn setItems([...items, ...itemsReference.current], 'beginning');\r\n\t\t},\r\n\t\t[setItems],\r\n\t);\r\n\r\n\tconst push = useCallback(\r\n\t\t(items: T[]) => {\r\n\t\t\treturn setItems([...itemsReference.current, ...items], 'ending');\r\n\t\t},\r\n\t\t[setItems],\r\n\t);\r\n\r\n\tconst at = useCallback((index: number) => {\r\n\t\treturn itemsReference.current.at(index);\r\n\t}, []);\r\n\r\n\tconst insert = useCallback(\r\n\t\t(item: T, index: number, keep: KeepDirection) => {\r\n\t\t\titemsReference.current.splice(index, 0, item);\r\n\t\t\treturn setItems([...itemsReference.current], keep);\r\n\t\t},\r\n\t\t[setItems],\r\n\t);\r\n\r\n\tconst getAll = useCallback(() => itemsReference.current, []);\r\n\r\n\tconst refresh = useCallback(() => setItemsState((old) => [...old]), []);\r\n\r\n\treturn [itemsState, { push, unshift, set: setItems, at, getAll, insert, refresh }];\r\n};\r\n", "import { PropsWithChildren } from 'react';\r\nimport { RoomContext } from './internal/RoomContext';\r\n\r\nexport type RoomProps = PropsWithChildren<{\r\n\tidentifier: string;\r\n}>;\r\n\r\nexport const Room = ({ identifier, children }: RoomProps) => {\r\n\treturn <RoomContext.Provider value={{ roomIdentifier: identifier }}>{children}</RoomContext.Provider>;\r\n};\r\n"], | ||
| "mappings": "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", | ||
| "names": ["import_react", "import_react", "import_react", "import_react", "import_react", "import_react", "useIsomorphicLayoutEffect", "import_react", "observer", "import_safe_context", "import_safe_context", "import_react", "import_react"] | ||
| } |
| import React from 'react'; | ||
| var Ae=Object.create;var J=Object.defineProperty;var Le=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames,q=Object.getOwnPropertySymbols,Fe=Object.getPrototypeOf,re=Object.prototype.hasOwnProperty,fe=Object.prototype.propertyIsEnumerable;var pe=(t,e,r)=>e in t?J(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,W=(t,e)=>{for(var r in e||(e={}))re.call(e,r)&&pe(t,r,e[r]);if(q)for(var r of q(e))fe.call(e,r)&&pe(t,r,e[r]);return t};var o=(t,e)=>J(t,"name",{value:e,configurable:!0});var G=(t,e)=>{var r={};for(var n in t)re.call(t,n)&&e.indexOf(n)<0&&(r[n]=t[n]);if(t!=null&&q)for(var n of q(t))e.indexOf(n)<0&&fe.call(t,n)&&(r[n]=t[n]);return r};var Se=(t,e)=>{for(var r in e)J(t,r,{get:e[r],enumerable:!0})},de=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of we(e))!re.call(t,s)&&s!==r&&J(t,s,{get:()=>e[s],enumerable:!(n=Le(e,s))||n.enumerable});return t};var ke=(t,e,r)=>(r=t!=null?Ae(Fe(t)):{},de(e||!t||!t.__esModule?J(r,"default",{value:t,enumerable:!0}):r,t)),Ke=t=>de(J({},"__esModule",{value:!0}),t);var Ue={};Se(Ue,{Chat:()=>Be,EndlessList:()=>ce,MessageList:()=>je,Room:()=>De,useEndlessList:()=>oe,useMessages:()=>ie,useVisibleItems:()=>ae});module.exports=Ke(Ue);var R=require("react");var _=o((...t)=>{let e=t.filter(Boolean);return e.length<=1?e[0]:o(function(n){for(let s of e)typeof s=="function"?s(n):s&&(s.current=n)},"mergedReferences")},"mergeReferences");var Te=o(async(t,e,r,n)=>{let s=e.getBoundingClientRect(),a=t.getBoundingClientRect(),u=s.top-a.top-a.height/2+s.height/2,l=t.scrollTop,p=t.clientHeight,b=t.scrollHeight-p,f=l+u,T=Math.min(Math.max(f,0),b),m=0,I=r.duration(T-l);return new Promise((x,S)=>{let A=o(k=>{if(n!=null&&n.signal.aborted){S(n.signal.reason);return}m=m||k;let M=k-m;t.scrollTop=l+(T-l)*r.easing(M/I),M<=I?window.requestAnimationFrame(A):x()},"scroll");l!==T?window.requestAnimationFrame(A):x()})},"smoothScrollToCenter");var $=require("react");var F=o(t=>{let e=(0,$.useRef)(t);return e.current=t,(0,$.useCallback)((...r)=>e.current(...r),[])},"useEvent");var U=require("react");var ge=o(t=>{let e=(0,U.useRef)();(0,U.useLayoutEffect)(()=>{let s=e.current;e.current=void 0,s&&t(...s.parameters).then(s.resolve).catch(s.reject)});let r=(0,U.useCallback)((...s)=>new Promise((a,u)=>{e.current={parameters:s,resolve:a,reject:u}}),[]),n=(0,U.useCallback)(()=>e.current!==void 0,[]);return[r,n]},"useScheduleOnNextRender");var Q=require("react");var ne=o(t=>{let e=(0,Q.useRef)(!1);return(0,Q.useCallback)(n=>{!e.current&&n&&t(),e.current=n},[t])},"useToggleEvent");var X=require("react");var ye=o(a=>{var u=a,{ItemComponent:t,PlaceholderComponent:e,itemObserver:r,focusElementReference:n}=u,s=G(u,["ItemComponent","PlaceholderComponent","itemObserver","focusElementReference"]);let l=(0,X.useRef)(null);return(0,X.useEffect)(()=>{let p=l.current;if(p&&r)return r.observe(p),()=>r.unobserve(p)},[r]),s.type==="placeholder"?React.createElement(e,{ref:l,itemKey:s.itemKey}):React.createElement(t,W({ref:_(l,s.focused&&n)},s))},"EndlessListItemView");var D=require("react"),Me=ke(require("use-isomorphic-layout-effect"));var he=o((t,e,r)=>{let n=0,s=t.length;if(s===0)return 0;for(;n<s;){let a=Math.floor((n+s)/2);r(e,{value:t[a],index:a})>0?n=a+1:s=a}return s},"binarySearch");var Y=require("react");var be=o(()=>{let t=(0,Y.useRef)(0);return(0,Y.useCallback)(()=>`:rchat:-${++t.current}`,[])},"useIdGenerator");var se=o((t,e)=>(r,n,s)=>{let a=t(r);return{type:"real",value:r,index:n,array:s,focused:a===e,itemKey:a}},"valueToEndlessListItem"),oe=o(({initialItems:t,items:e,getKey:r,focusedItem:n,compareItems:s,handleJump:a,visibleItemKeys:u,lastScrolledItem:l})=>{let p=n===void 0?void 0:r(n),b=(0,D.useMemo)(()=>se(r,p),[r,p]),[f,T]=(0,D.useState)(()=>e.map(b)),m=(0,D.useRef)(),I=(0,D.useRef)(t),x=(0,D.useRef)(!1),S=be(),A=F(()=>{let M=f.filter(({itemKey:i,type:C},E,B)=>{if(u.current.has(i))return!0;if(C==="placeholder")return!1;let c=B[E-1];if(c&&c.type!=="placeholder"&&u.current.has(c.itemKey))return!0;let h=B[E+1];return!!(h&&h.type!=="placeholder"&&u.current.has(h.itemKey))}).map(i=>(i.type==="real"&&i.focused&&(i.focused=!1),i)),L=new Set(e.map(r));if(M.every(i=>!L.has(i.itemKey)))return[M,!0];let O=o((i,C)=>{if(C.value.type==="placeholder"){let E=M[C.index+1];return E!==void 0&&E.type!=="placeholder"?s(E.value,i.value):1}return s(i.value,C.value.value)},"comparator"),d=p!=null?p:r(e[Math.floor(e.length/2)]),K=[...e.map(se(r,d))],w=M.findIndex(i=>L.has(i.itemKey));w===-1&&(w=he(M,K.at(0),O)),M.splice(w,1,...K);let V=new Set;return[M.filter(i=>V.has(i.itemKey)?!1:(V.add(i.itemKey),!0)),!1]}),k=F(async()=>{var w,V;if(m.current&&(m.current.abort(),m.current=void 0),f.length===0||e.length===0||I.current!==t){T(e.map(b)),I.current=t;return}let M=f.some(g=>g.type==="placeholder"),L,O=!0;if(M){[L,O]=A();let g=[],i=0;for(let C of L)C.type==="placeholder"?(i=0,g=[]):(C.index=i,C.array=g,g.push(C.value),++i)}else{let g=e.map(r),i=f.map(c=>c.itemKey),C=!i.includes(g[0])&&!g.includes(i.at(-1)),E=!g.includes(i[0])&&!i.includes(g.at(-1));if(!(C&&E)){T(e.map(b));return}L=f.map(c=>(c.type==="real"&&c.focused&&(c.focused=!1),c))}let d;if(O){let g=L.find(P=>P.type==="real"),i="forward";g&&(i=s(e[0],g.value)<0?"forward":"back");let C=p!=null?p:r(e[Math.floor(e.length/2)]),E,B,c=se(r,C);i==="forward"?(E=e.map(c),B=L):(E=L,B=e.map(c));let h=((w=E.at(-1))==null?void 0:w.type)==="placeholder"||((V=B.at(0))==null?void 0:V.type)==="placeholder";d=[...E,...h?[]:[{type:"placeholder",itemKey:S()}],...B]}else d=L;l.current=e[Math.floor(e.length/2)],T(d);let K=new AbortController;m.current=K;try{x.current&&await a(K),T(e.map(b))}catch(g){}finally{m.current=void 0}});return(0,Me.default)(()=>{k(),x.current=!0},[k,e]),(0,D.useEffect)(()=>()=>{x.current=!1},[]),f},"useEndlessList");var Ce=o(({items:t,getKey:e,onVisibleFrameUpdated:r})=>F(s=>{let a=-1;for(let[l,p]of t.entries())if(s.has(e(p))){a=l;break}let u=-1;for(let l=0;l<=t.length;++l){let p=t.at(-l-1);if(p&&s.has(e(p))){u=l;break}}r({begin:a,end:u})}),"useVisibleFrame");var N=require("react");var ae=o((t,e)=>{let[r,n]=(0,N.useState)(),s=(0,N.useRef)(new Set),a=F(u=>{for(let{target:l,isIntersecting:p}of u){let b=l.dataset.key;b?p?s.current.add(b):s.current.delete(b):console.warn(`Item component doesn't have "data-key" attribute.`)}e==null||e(s.current)});return(0,N.useEffect)(()=>{let u=t.current;if(u){let l=new IntersectionObserver(a,{root:u,threshold:0});n(l)}},[t,a]),{observer:r,visibleItemKeys:s}},"useVisibleItems");var Re=o(()=>{},"noop"),Ve={duration:()=>500,easing:t=>t},ce=o(({ItemComponent:t,initialItems:e,items:r,itemKey:n,triggerDistance:s,onTopReached:a,onBottomReached:u,compareItems:l,PlaceholderComponent:p,jumpAnimation:b=Ve,focusedItem:f,ContainerComponent:T,canStickToBottom:m,onVisibleFrameChange:I,containerReference:x})=>{let S=(0,R.useRef)(null),A=(0,R.useRef)(null),k=(0,R.useRef)(!1),M=(0,R.useRef)(!1),L=(0,R.useRef)({begin:-1,end:-1}),O=(0,R.useRef)(!1),d=ne(u!=null?u:Re),K=ne(a!=null?a:Re),w=(0,R.useMemo)(()=>typeof n=="function"?n:y=>y[n],[n]);(0,R.useEffect)(()=>{d(!1),K(!1)},[r,d,K]);let V=F((y=L.current)=>{I==null||I(y),L.current=y,!(y.begin===-1||y.end===-1||M.current)&&(d(y.end<=s),K(y.begin<=s),k.current=y.end===0)}),g=F((y,Ee,Pe)=>Te(y,Ee,b,Pe)),i=(0,R.useRef)(),C=(0,R.useCallback)(async(y=new AbortController)=>{i.current&&i.current.abort(),!(!S.current||!A.current)&&(i.current=y,M.current=!0,O.current?await g(S.current,A.current,y):A.current.scrollIntoView({behavior:"auto",block:"center"}),M.current=!1,V())},[V,g]),E=Ce({getKey:w,items:r,onVisibleFrameUpdated:V}),{observer:B,visibleItemKeys:c}=ae(S,E),[h,P]=ge(C),j=(0,R.useRef)(),ee=F(()=>{f!==j.current&&(j.current=f,f&&!P()&&C().catch(()=>{}))}),te=oe({getKey:w,initialItems:e,items:r,compareItems:l,handleJump:h,focusedItem:f,visibleItemKeys:c,lastScrolledItem:j});(0,R.useEffect)(()=>{ee(),O.current=!0},[ee,te]),(0,R.useEffect)(()=>()=>{O.current=!1},[]);let me=F(()=>{let y=S.current;y&&k.current&&!f&&y.scrollTo({top:y.scrollHeight})});return(0,R.useLayoutEffect)(()=>{m&&me()},[te,m,me]),React.createElement(T,{ref:_(S,x)},te.map(y=>React.createElement(ye,W({key:y.itemKey,focusElementReference:A,ItemComponent:t,PlaceholderComponent:p,itemObserver:B},y))))},"EndlessList");var ve=require("@sirse-dev/safe-context"),Z=(0,ve.createSafeContext)();var Be=o(r=>{var n=r,{children:t}=n,e=G(n,["children"]);return React.createElement(Z.Provider,{value:W({},e)},t)},"Chat");var le=require("@sirse-dev/safe-context");var xe=require("@sirse-dev/safe-context"),z=(0,xe.createSafeContext)();var v=require("react");var ue=o((t,e,r)=>Math.max(Math.min(t,r),e),"clamp");var H=require("react");var He=o((t,e,r)=>{if(t.length<=e)return t;if(r==="beginning")return t.slice(0,e);if(r==="ending")return t.slice(-e);throw new Error(`Unrecognized "keep" option value: "${r}"`)},"getClippedArray"),Ie=o((t,e)=>{let[r,n]=(0,H.useState)(t),s=(0,H.useRef)(t),a=(0,H.useCallback)((m,I)=>{let x=He(m,e,I);return n(x),s.current=x,m.length>x.length},[e]),u=(0,H.useCallback)(m=>a([...m,...s.current],"beginning"),[a]),l=(0,H.useCallback)(m=>a([...s.current,...m],"ending"),[a]),p=(0,H.useCallback)(m=>s.current.at(m),[]),b=(0,H.useCallback)((m,I,x)=>(s.current.splice(I,0,m),a([...s.current],x)),[a]),f=(0,H.useCallback)(()=>s.current,[]),T=(0,H.useCallback)(()=>n(m=>[...m]),[]);return[r,{push:l,unshift:u,set:a,at:p,getAll:f,insert:b,refresh:T}]},"useBoundedArray");var Oe=o((t,e,r)=>t.length-1-[...t].reverse().findIndex(n=>r(e,n)>0),"findNewElementIndex"),ie=o(({maxChunkSize:t,additionalChunkSize:e,chatClient:r,roomIdentifier:n,compareItems:s,initialMessagesState:a,initialSearchResult:u})=>{let l=(0,v.useRef)(!1),p=(0,v.useRef)({begin:-1,end:-1}),b=(0,v.useRef)(null),f=(0,v.useRef)(u),T=(0,v.useRef)(0),m=(0,v.useRef)(u==null?void 0:u.results[0]),[I,{push:x,unshift:S,set:A,insert:k,at:M,getAll:L,refresh:O}]=Ie([...a.messages],t),d=(0,v.useRef)(a),K=(0,v.useCallback)((c,h)=>{if(h===n&&d.current.noMessagesAfter){let P=Oe(L(),c,s),j=p.current.begin<p.current.end?"beginning":"ending";k(c,P+1,j)&&(j==="beginning"?d.current.noMessagesAfter=!1:d.current.noMessagesBefore=!1)}},[n,L,s,k]),w=(0,v.useCallback)(async c=>{if(!c){m.current&&O(),m.current=c;return}m.current=c;let[h,P]=await Promise.all([r.fetchMessages(n,e,c,void 0),r.fetchMessages(n,e,void 0,c)]);d.current={noMessagesBefore:h.noMessagesBefore,noMessagesAfter:P.noMessagesAfter},A([...h.messages,c,...P.messages],"beginning")},[e,r,n,A,O]),V=(0,v.useCallback)((c,h,P)=>{c===n&&(f.current=h,P=Math.min(P,h.results.length-1),T.current=P,w(h.results[P]))},[w,n]),g=(0,v.useCallback)(c=>{f.current&&c===n&&(T.current=ue(T.current-1,0,Math.max(f.current.results.length-1,0)),w(f.current.results[T.current]))},[w,n]),i=(0,v.useCallback)(c=>{f.current&&c===n&&(T.current=ue(T.current+1,0,Math.max(f.current.results.length-1,0)),w(f.current.results[T.current]))},[w,n]);(0,v.useEffect)(()=>(r.addEventListener("receiveMessage",K),r.addEventListener("receiveSearchResults",V),r.addEventListener("nextSearchResult",i),r.addEventListener("previousSearchResult",g),()=>{r.removeEventListener("receiveMessage",K),r.removeEventListener("receiveSearchResults",V),r.removeEventListener("nextSearchResult",i),r.removeEventListener("previousSearchResult",g)}),[r,K,i,g,V]),(0,v.useEffect)(()=>{if(!u){let c=b.current;c?c.scrollTo({top:c.scrollHeight}):console.warn("RChat: container reference wasn't passed into EndlessList, so scrolling to the bottom after initial chat load failed. This may cause inconsistent behavior")}},[u]),(0,v.useEffect)(()=>{A([...a.messages],"beginning"),d.current=a},[a,A]),(0,v.useEffect)(()=>{f.current=u,m.current=u==null?void 0:u.results[0]},[u]);let C=F(async()=>{if(d.current.noMessagesBefore||l.current)return;l.current=!0;let{messages:c,noMessagesBefore:h}=await r.fetchMessages(n,e,M(0),void 0),P=S(c),j={noMessagesBefore:h,noMessagesAfter:!P&&d.current.noMessagesAfter};d.current=j,l.current=!1}),E=F(async()=>{if(d.current.noMessagesAfter||l.current)return;l.current=!0;let{messages:c,noMessagesAfter:h}=await r.fetchMessages(n,e,void 0,M(-1)),P=x(c),j={noMessagesAfter:h,noMessagesBefore:!P&&d.current.noMessagesBefore};d.current=j,l.current=!1}),B=o(c=>{p.current=c},"onVisibleFrameChange");return{messages:I,onTopReached:C,onBottomReached:E,noMessagesBefore:d.current.noMessagesBefore,noMessagesAfter:d.current.noMessagesAfter,onVisibleFrameChange:B,containerReference:b,focusedItem:m.current}},"useMessages");var je=o(({jumpAnimation:t,initialMessagesState:e,initialSearchResult:r})=>{let{client:n,MessageComponent:s,PlaceholderComponent:a,ContainerComponent:u,triggerDistance:l,compareItems:p,itemKey:b}=(0,le.useSafeContext)(Z),{roomIdentifier:f}=(0,le.useSafeContext)(z),{messages:T,onBottomReached:m,onTopReached:I,noMessagesAfter:x,onVisibleFrameChange:S,containerReference:A,focusedItem:k}=ie({chatClient:n,additionalChunkSize:20,maxChunkSize:100,roomIdentifier:f,compareItems:p,initialMessagesState:e,initialSearchResult:r});return React.createElement(ce,{initialItems:e.messages,items:T,onTopReached:I,onBottomReached:m,triggerDistance:l,ContainerComponent:u,ItemComponent:s,PlaceholderComponent:a,compareItems:p,itemKey:b,onVisibleFrameChange:S,canStickToBottom:x,containerReference:A,focusedItem:k,jumpAnimation:t})},"MessageList");var De=o(({identifier:t,children:e})=>React.createElement(z.Provider,{value:{roomIdentifier:t}},e),"Room"); |
Sorry, the diff of this file is too big to display
| // Generated by dts-bundle-generator v6.13.0 | ||
| import { ComponentType, MutableRefObject, PropsWithChildren, Ref, RefAttributes, RefObject } from 'react'; | ||
| export type AnimationParameters = { | ||
| /** | ||
| * Easing function. | ||
| * Takes an argument in range [0, 1] and returns value in range [0, 1]. | ||
| */ | ||
| easing: (t: number) => number; | ||
| /** | ||
| * Animation duration function. | ||
| * Takes distance in pixels and returns duration in milliseconds. | ||
| */ | ||
| duration: (distance: number) => number; | ||
| }; | ||
| export type UseEndlessListConfig<T> = { | ||
| initialItems: T[]; | ||
| items: T[]; | ||
| getKey: (item: T) => string; | ||
| compareItems: (a: T, b: T) => number; | ||
| handleJump: (abortController: AbortController) => Promise<void>; | ||
| focusedItem?: T; | ||
| visibleItemKeys: MutableRefObject<Set<string>>; | ||
| lastScrolledItem: MutableRefObject<T | undefined>; | ||
| }; | ||
| export type EndlessListRealItem<TValue> = { | ||
| type: "real"; | ||
| value: TValue; | ||
| index: number; | ||
| array: TValue[]; | ||
| itemKey: string; | ||
| focused: boolean; | ||
| }; | ||
| export type EndlessListPlaceholderItem = { | ||
| type: "placeholder"; | ||
| itemKey: string; | ||
| }; | ||
| export type EndlessListItem<TValue> = EndlessListRealItem<TValue> | EndlessListPlaceholderItem; | ||
| export declare const useEndlessList: <T>({ initialItems, items, getKey, focusedItem, compareItems, handleJump, visibleItemKeys, lastScrolledItem, }: UseEndlessListConfig<T>) => EndlessListItem<T>[]; | ||
| export type ItemComponentProps<TMessageType> = Omit<EndlessListRealItem<TMessageType>, "type">; | ||
| export type ItemComponentType<TMessageType> = ComponentType<ItemComponentProps<TMessageType> & RefAttributes<HTMLElement>>; | ||
| export type PlaceholderComponentProps = { | ||
| itemKey: string; | ||
| }; | ||
| export type PlaceholderComponentType = ComponentType<PlaceholderComponentProps & RefAttributes<HTMLElement>>; | ||
| export type Frame = { | ||
| begin: number; | ||
| end: number; | ||
| }; | ||
| export type KeysOfType<T, V> = { | ||
| [K in keyof T]: T[K] extends V ? K : never; | ||
| }[keyof T]; | ||
| export type ContainerComponentProps = PropsWithChildren<RefAttributes<HTMLElement>>; | ||
| export type ItemKey<T> = KeysOfType<T, string> | ((value: T) => string); | ||
| export type EndlessListProps<TItemType> = { | ||
| ItemComponent: ItemComponentType<TItemType>; | ||
| PlaceholderComponent: PlaceholderComponentType; | ||
| ContainerComponent: ComponentType<ContainerComponentProps>; | ||
| initialItems: TItemType[]; | ||
| items: TItemType[]; | ||
| itemKey: ItemKey<TItemType>; | ||
| triggerDistance: number; | ||
| onTopReached?: () => void; | ||
| onBottomReached?: () => void; | ||
| compareItems: (first: TItemType, second: TItemType) => number; | ||
| focusedItem?: TItemType; | ||
| jumpAnimation?: AnimationParameters; | ||
| canStickToBottom?: boolean; | ||
| onVisibleFrameChange?: (frame: Frame) => void; | ||
| containerReference?: Ref<HTMLElement>; | ||
| }; | ||
| export declare const EndlessList: <T>({ ItemComponent, initialItems, items, itemKey, triggerDistance, onTopReached, onBottomReached, compareItems, PlaceholderComponent, jumpAnimation, focusedItem, ContainerComponent, canStickToBottom, onVisibleFrameChange, containerReference: propsContainerReference, }: EndlessListProps<T>) => import("react/jsx-runtime").JSX.Element; | ||
| export type VisibleItemsBag = { | ||
| observer: IntersectionObserver | undefined; | ||
| visibleItemKeys: MutableRefObject<Set<string>>; | ||
| }; | ||
| export declare const useVisibleItems: (containerReference: RefObject<HTMLElement>, onVisibleItemsChange?: ((items: Set<string>) => void) | undefined) => VisibleItemsBag; | ||
| export type RChatContextType<TMessageType> = { | ||
| client: ChatClient<TMessageType>; | ||
| MessageComponent: ItemComponentType<TMessageType>; | ||
| PlaceholderComponent: PlaceholderComponentType; | ||
| ContainerComponent: ComponentType<ContainerComponentProps>; | ||
| triggerDistance: number; | ||
| itemKey: ItemKey<TMessageType>; | ||
| compareItems: (first: TMessageType, second: TMessageType) => number; | ||
| }; | ||
| export type ChatProps<TMessageType> = PropsWithChildren<RChatContextType<TMessageType>>; | ||
| export declare const Chat: <TMessageType>({ children, ...context }: ChatProps<TMessageType>) => import("react/jsx-runtime").JSX.Element; | ||
| export type MessageListProps<TMessage> = { | ||
| initialMessagesState: MessageFetchResult<TMessage>; | ||
| initialSearchResult?: MessageSearchResult<TMessage>; | ||
| jumpAnimation?: AnimationParameters; | ||
| }; | ||
| export declare const MessageList: <TMessage>({ jumpAnimation, initialMessagesState, initialSearchResult, }: MessageListProps<TMessage>) => import("react/jsx-runtime").JSX.Element; | ||
| export type RoomProps = PropsWithChildren<{ | ||
| identifier: string; | ||
| }>; | ||
| export declare const Room: ({ identifier, children }: RoomProps) => import("react/jsx-runtime").JSX.Element; | ||
| export type UseMessagesBag<T> = { | ||
| messages: T[]; | ||
| onTopReached: () => void; | ||
| onBottomReached: () => void; | ||
| noMessagesBefore: boolean; | ||
| noMessagesAfter: boolean; | ||
| onVisibleFrameChange: (frame: Frame) => void; | ||
| containerReference: Ref<HTMLElement>; | ||
| focusedItem?: T; | ||
| }; | ||
| export type UseMessagesConfig<T> = { | ||
| initialMessagesState: MessageFetchResult<T>; | ||
| initialSearchResult?: MessageSearchResult<T>; | ||
| compareItems: (a: T, b: T) => number; | ||
| maxChunkSize: number; | ||
| additionalChunkSize: number; | ||
| chatClient: ChatClient<T>; | ||
| roomIdentifier: string; | ||
| }; | ||
| export declare const useMessages: <TMessage>({ maxChunkSize, additionalChunkSize, chatClient, roomIdentifier, compareItems, initialMessagesState, initialSearchResult, }: UseMessagesConfig<TMessage>) => UseMessagesBag<TMessage>; | ||
| export {}; |
| import React from 'react'; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
| var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
| var __spreadValues = (a, b) => { | ||
| for (var prop in b || (b = {})) | ||
| if (__hasOwnProp.call(b, prop)) | ||
| __defNormalProp(a, prop, b[prop]); | ||
| if (__getOwnPropSymbols) | ||
| for (var prop of __getOwnPropSymbols(b)) { | ||
| if (__propIsEnum.call(b, prop)) | ||
| __defNormalProp(a, prop, b[prop]); | ||
| } | ||
| return a; | ||
| }; | ||
| var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); | ||
| var __objRest = (source, exclude) => { | ||
| var target = {}; | ||
| for (var prop in source) | ||
| if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) | ||
| target[prop] = source[prop]; | ||
| if (source != null && __getOwnPropSymbols) | ||
| for (var prop of __getOwnPropSymbols(source)) { | ||
| if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) | ||
| target[prop] = source[prop]; | ||
| } | ||
| return target; | ||
| }; | ||
| // src/EndlessList/EndlessList.tsx | ||
| import { | ||
| useCallback as useCallback5, | ||
| useEffect as useEffect4, | ||
| useLayoutEffect as useLayoutEffect2, | ||
| useMemo as useMemo2, | ||
| useRef as useRef8 | ||
| } from "react"; | ||
| // src/internal/mergeReferences.ts | ||
| var mergeReferences = /* @__PURE__ */ __name((...inputReferences) => { | ||
| const filteredInputReferences = inputReferences.filter(Boolean); | ||
| if (filteredInputReferences.length <= 1) { | ||
| return filteredInputReferences[0]; | ||
| } | ||
| return /* @__PURE__ */ __name(function mergedReferences(reference) { | ||
| for (const inputReference of filteredInputReferences) { | ||
| if (typeof inputReference === "function") { | ||
| inputReference(reference); | ||
| } else if (inputReference) { | ||
| inputReference.current = reference; | ||
| } | ||
| } | ||
| }, "mergedReferences"); | ||
| }, "mergeReferences"); | ||
| // src/internal/smoothScrollToCenter.ts | ||
| var smoothScrollToCenter = /* @__PURE__ */ __name(async (container, element, parameters, controller) => { | ||
| const elementRect = element.getBoundingClientRect(); | ||
| const containerRect = container.getBoundingClientRect(); | ||
| const top = elementRect.top - containerRect.top - containerRect.height / 2 + elementRect.height / 2; | ||
| const startPos = container.scrollTop; | ||
| const clientHeight = container.clientHeight; | ||
| const maxScroll = container.scrollHeight - clientHeight; | ||
| const scrollIntendedDestination = startPos + top; | ||
| const scrollEndValue = Math.min(Math.max(scrollIntendedDestination, 0), maxScroll); | ||
| let startTime = 0; | ||
| const duration = parameters.duration(scrollEndValue - startPos); | ||
| return new Promise((resolve, reject) => { | ||
| const scroll = /* @__PURE__ */ __name((timestamp) => { | ||
| if (controller == null ? void 0 : controller.signal.aborted) { | ||
| reject(controller.signal.reason); | ||
| return; | ||
| } | ||
| startTime = startTime || timestamp; | ||
| const elapsed = timestamp - startTime; | ||
| container.scrollTop = startPos + (scrollEndValue - startPos) * parameters.easing(elapsed / duration); | ||
| if (elapsed <= duration) { | ||
| window.requestAnimationFrame(scroll); | ||
| } else { | ||
| resolve(); | ||
| } | ||
| }, "scroll"); | ||
| if (startPos !== scrollEndValue) { | ||
| window.requestAnimationFrame(scroll); | ||
| } else { | ||
| resolve(); | ||
| } | ||
| }); | ||
| }, "smoothScrollToCenter"); | ||
| // src/internal/useEvent.ts | ||
| import { useCallback, useRef } from "react"; | ||
| var useEvent = /* @__PURE__ */ __name((handler) => { | ||
| const handlerReference = useRef(handler); | ||
| handlerReference.current = handler; | ||
| return useCallback((...parameters) => { | ||
| return handlerReference.current(...parameters); | ||
| }, []); | ||
| }, "useEvent"); | ||
| // src/internal/useScheduleOnNextRender.tsx | ||
| import { useCallback as useCallback2, useLayoutEffect, useRef as useRef2 } from "react"; | ||
| var useScheduleOnNextRender = /* @__PURE__ */ __name((handler) => { | ||
| const unresolvedHandle = useRef2(); | ||
| useLayoutEffect(() => { | ||
| const currentHandle = unresolvedHandle.current; | ||
| unresolvedHandle.current = void 0; | ||
| if (currentHandle) { | ||
| handler(...currentHandle.parameters).then(currentHandle.resolve).catch(currentHandle.reject); | ||
| } | ||
| }); | ||
| const wrappedFunction = useCallback2((...parameters) => { | ||
| return new Promise((resolve, reject) => { | ||
| unresolvedHandle.current = { | ||
| parameters, | ||
| resolve, | ||
| reject | ||
| }; | ||
| }); | ||
| }, []); | ||
| const isScheduled = useCallback2(() => { | ||
| return unresolvedHandle.current !== void 0; | ||
| }, []); | ||
| return [wrappedFunction, isScheduled]; | ||
| }, "useScheduleOnNextRender"); | ||
| // src/internal/useToggleEvent.ts | ||
| import { useCallback as useCallback3, useRef as useRef3 } from "react"; | ||
| var useToggleEvent = /* @__PURE__ */ __name((onTurnedOn) => { | ||
| const value = useRef3(false); | ||
| const toggle = useCallback3( | ||
| (newValue) => { | ||
| if (!value.current && newValue) { | ||
| onTurnedOn(); | ||
| } | ||
| value.current = newValue; | ||
| }, | ||
| [onTurnedOn] | ||
| ); | ||
| return toggle; | ||
| }, "useToggleEvent"); | ||
| // src/EndlessList/EndlessListItemView.tsx | ||
| import { useEffect, useRef as useRef4 } from "react"; | ||
| var EndlessListItemView = /* @__PURE__ */ __name((_a) => { | ||
| var _b = _a, { | ||
| ItemComponent, | ||
| PlaceholderComponent, | ||
| itemObserver, | ||
| focusElementReference | ||
| } = _b, item = __objRest(_b, [ | ||
| "ItemComponent", | ||
| "PlaceholderComponent", | ||
| "itemObserver", | ||
| "focusElementReference" | ||
| ]); | ||
| const itemReference = useRef4(null); | ||
| useEffect(() => { | ||
| const currentElement = itemReference.current; | ||
| if (currentElement && itemObserver) { | ||
| itemObserver.observe(currentElement); | ||
| return () => itemObserver.unobserve(currentElement); | ||
| } | ||
| }, [itemObserver]); | ||
| if (item.type === "placeholder") { | ||
| return /* @__PURE__ */ React.createElement(PlaceholderComponent, { ref: itemReference, itemKey: item.itemKey }); | ||
| } | ||
| return /* @__PURE__ */ React.createElement(ItemComponent, __spreadValues({ ref: mergeReferences(itemReference, item.focused && focusElementReference) }, item)); | ||
| }, "EndlessListItemView"); | ||
| // src/EndlessList/useEndlessList.tsx | ||
| import { useMemo, useRef as useRef6, useState, useEffect as useEffect2 } from "react"; | ||
| import useIsomorphicLayoutEffect from "use-isomorphic-layout-effect"; | ||
| // src/internal/binarySearch.ts | ||
| var binarySearch = /* @__PURE__ */ __name((array, value, comparator) => { | ||
| let low = 0; | ||
| let high = array.length; | ||
| if (high === 0) { | ||
| return 0; | ||
| } | ||
| while (low < high) { | ||
| const middle = Math.floor((low + high) / 2); | ||
| if (comparator(value, { value: array[middle], index: middle }) > 0) { | ||
| low = middle + 1; | ||
| } else { | ||
| high = middle; | ||
| } | ||
| } | ||
| return high; | ||
| }, "binarySearch"); | ||
| // src/internal/useIdGenerator.ts | ||
| import { useCallback as useCallback4, useRef as useRef5 } from "react"; | ||
| var useIdGenerator = /* @__PURE__ */ __name(() => { | ||
| const counter = useRef5(0); | ||
| return useCallback4(() => `:rchat:-${++counter.current}`, []); | ||
| }, "useIdGenerator"); | ||
| // src/EndlessList/useEndlessList.tsx | ||
| var valueToEndlessListItem = /* @__PURE__ */ __name((getKey, focusItemKey) => { | ||
| return (value, index, array) => { | ||
| const key = getKey(value); | ||
| return { | ||
| type: "real", | ||
| value, | ||
| index, | ||
| array, | ||
| focused: key === focusItemKey, | ||
| itemKey: key | ||
| }; | ||
| }; | ||
| }, "valueToEndlessListItem"); | ||
| var useEndlessList = /* @__PURE__ */ __name(({ | ||
| initialItems, | ||
| items, | ||
| getKey, | ||
| focusedItem, | ||
| compareItems, | ||
| handleJump, | ||
| visibleItemKeys, | ||
| lastScrolledItem | ||
| }) => { | ||
| const focusedItemKey = focusedItem === void 0 ? void 0 : getKey(focusedItem); | ||
| const defaultConvertItem = useMemo(() => valueToEndlessListItem(getKey, focusedItemKey), [getKey, focusedItemKey]); | ||
| const [renderedItems, setRenderedItems] = useState(() => items.map(defaultConvertItem)); | ||
| const jumpAbortController = useRef6(); | ||
| const initialItemsReference = useRef6(initialItems); | ||
| const hasMounted = useRef6(false); | ||
| const getUniquePlaceholderKey = useIdGenerator(); | ||
| const performFixup = useEvent(() => { | ||
| const visibleItems = renderedItems.filter(({ itemKey, type }, index, array) => { | ||
| if (visibleItemKeys.current.has(itemKey)) { | ||
| return true; | ||
| } | ||
| if (type === "placeholder") { | ||
| return false; | ||
| } | ||
| const previousItem = array[index - 1]; | ||
| if (previousItem && previousItem.type !== "placeholder" && visibleItemKeys.current.has(previousItem.itemKey)) { | ||
| return true; | ||
| } | ||
| const nextItem = array[index + 1]; | ||
| if (nextItem && nextItem.type !== "placeholder" && visibleItemKeys.current.has(nextItem.itemKey)) { | ||
| return true; | ||
| } | ||
| return false; | ||
| }).map((item) => { | ||
| if (item.type === "real" && item.focused) { | ||
| item.focused = false; | ||
| } | ||
| return item; | ||
| }); | ||
| const keys = new Set(items.map(getKey)); | ||
| if (visibleItems.every((item) => !keys.has(item.itemKey))) { | ||
| return [visibleItems, true]; | ||
| } | ||
| const comparator = /* @__PURE__ */ __name((a, b) => { | ||
| if (b.value.type === "placeholder") { | ||
| const nextValue = visibleItems[b.index + 1]; | ||
| if (nextValue !== void 0 && nextValue.type !== "placeholder") { | ||
| return compareItems(nextValue.value, a.value); | ||
| } | ||
| return 1; | ||
| } | ||
| return compareItems(a.value, b.value.value); | ||
| }, "comparator"); | ||
| const jumpKey = focusedItemKey != null ? focusedItemKey : getKey(items[Math.floor(items.length / 2)]); | ||
| const convertedItems = [...items.map(valueToEndlessListItem(getKey, jumpKey))]; | ||
| let pivotIndex = visibleItems.findIndex((item) => keys.has(item.itemKey)); | ||
| if (pivotIndex === -1) { | ||
| pivotIndex = binarySearch(visibleItems, convertedItems.at(0), comparator); | ||
| } | ||
| visibleItems.splice(pivotIndex, 1, ...convertedItems); | ||
| const dedupedKeys = /* @__PURE__ */ new Set(); | ||
| const filteredItems = visibleItems.filter((item) => { | ||
| if (dedupedKeys.has(item.itemKey)) { | ||
| return false; | ||
| } | ||
| dedupedKeys.add(item.itemKey); | ||
| return true; | ||
| }); | ||
| return [filteredItems, false]; | ||
| }); | ||
| const update = useEvent(async () => { | ||
| var _a, _b; | ||
| if (jumpAbortController.current) { | ||
| jumpAbortController.current.abort(); | ||
| jumpAbortController.current = void 0; | ||
| } | ||
| if (renderedItems.length === 0 || items.length === 0 || initialItemsReference.current !== initialItems) { | ||
| setRenderedItems(items.map(defaultConvertItem)); | ||
| initialItemsReference.current = initialItems; | ||
| return; | ||
| } | ||
| const isAbortedPreviousJump = renderedItems.some((item) => item.type === "placeholder"); | ||
| let oldItems; | ||
| let constructItems = true; | ||
| if (isAbortedPreviousJump) { | ||
| [oldItems, constructItems] = performFixup(); | ||
| let array = []; | ||
| let index = 0; | ||
| for (const item of oldItems) { | ||
| if (item.type === "placeholder") { | ||
| index = 0; | ||
| array = []; | ||
| } else { | ||
| item.index = index; | ||
| item.array = array; | ||
| array.push(item.value); | ||
| ++index; | ||
| } | ||
| } | ||
| } else { | ||
| const keys = items.map(getKey); | ||
| const oldKeys = renderedItems.map((item) => item.itemKey); | ||
| const mustMoveForward = !oldKeys.includes(keys[0]) && !keys.includes(oldKeys.at(-1)); | ||
| const mustMoveBack = !keys.includes(oldKeys[0]) && !oldKeys.includes(keys.at(-1)); | ||
| const mustJump = mustMoveForward && mustMoveBack; | ||
| if (!mustJump) { | ||
| setRenderedItems(items.map(defaultConvertItem)); | ||
| return; | ||
| } | ||
| oldItems = renderedItems.map((item) => { | ||
| if (item.type === "real" && item.focused) { | ||
| item.focused = false; | ||
| } | ||
| return item; | ||
| }); | ||
| } | ||
| let constructedItems; | ||
| if (constructItems) { | ||
| const firstItem = oldItems.find((item) => item.type === "real"); | ||
| let jumpDirection = "forward"; | ||
| if (firstItem) { | ||
| jumpDirection = compareItems(items[0], firstItem.value) < 0 ? "forward" : "back"; | ||
| } | ||
| const jumpKey = focusedItemKey != null ? focusedItemKey : getKey(items[Math.floor(items.length / 2)]); | ||
| let nextItems; | ||
| let previousItems; | ||
| const convertItem = valueToEndlessListItem(getKey, jumpKey); | ||
| if (jumpDirection === "forward") { | ||
| nextItems = items.map(convertItem); | ||
| previousItems = oldItems; | ||
| } else { | ||
| nextItems = oldItems; | ||
| previousItems = items.map(convertItem); | ||
| } | ||
| const alreadyHasPlaceholder = ((_a = nextItems.at(-1)) == null ? void 0 : _a.type) === "placeholder" || ((_b = previousItems.at(0)) == null ? void 0 : _b.type) === "placeholder"; | ||
| constructedItems = [ | ||
| ...nextItems, | ||
| ...alreadyHasPlaceholder ? [] : [{ type: "placeholder", itemKey: getUniquePlaceholderKey() }], | ||
| ...previousItems | ||
| ]; | ||
| } else { | ||
| constructedItems = oldItems; | ||
| } | ||
| lastScrolledItem.current = items[Math.floor(items.length / 2)]; | ||
| setRenderedItems(constructedItems); | ||
| const newController = new AbortController(); | ||
| jumpAbortController.current = newController; | ||
| try { | ||
| if (hasMounted.current) { | ||
| await handleJump(newController); | ||
| } | ||
| setRenderedItems(items.map(defaultConvertItem)); | ||
| } catch (e) { | ||
| } finally { | ||
| jumpAbortController.current = void 0; | ||
| } | ||
| }); | ||
| useIsomorphicLayoutEffect(() => { | ||
| update(); | ||
| hasMounted.current = true; | ||
| }, [update, items]); | ||
| useEffect2(() => { | ||
| return () => { | ||
| hasMounted.current = false; | ||
| }; | ||
| }, []); | ||
| return renderedItems; | ||
| }, "useEndlessList"); | ||
| // src/EndlessList/useVisibleFrame.tsx | ||
| var useVisibleFrame = /* @__PURE__ */ __name(({ | ||
| items, | ||
| getKey, | ||
| onVisibleFrameUpdated | ||
| }) => { | ||
| const updateVisibleFrame = useEvent((visibleItemKeys) => { | ||
| let begin = -1; | ||
| for (const [index, item] of items.entries()) { | ||
| if (visibleItemKeys.has(getKey(item))) { | ||
| begin = index; | ||
| break; | ||
| } | ||
| } | ||
| let end = -1; | ||
| for (let index = 0; index <= items.length; ++index) { | ||
| const item = items.at(-index - 1); | ||
| if (item && visibleItemKeys.has(getKey(item))) { | ||
| end = index; | ||
| break; | ||
| } | ||
| } | ||
| onVisibleFrameUpdated({ begin, end }); | ||
| }); | ||
| return updateVisibleFrame; | ||
| }, "useVisibleFrame"); | ||
| // src/EndlessList/useVisibleItems.tsx | ||
| import { useEffect as useEffect3, useState as useState2, useRef as useRef7 } from "react"; | ||
| var useVisibleItems = /* @__PURE__ */ __name((containerReference, onVisibleItemsChange) => { | ||
| const [observer, setObserver] = useState2(); | ||
| const visibleItemKeysReference = useRef7(/* @__PURE__ */ new Set()); | ||
| const updateVisibleFrame = useEvent((entries) => { | ||
| for (const { target, isIntersecting } of entries) { | ||
| const key = target.dataset.key; | ||
| if (!key) { | ||
| console.warn(`Item component doesn't have "data-key" attribute.`); | ||
| } else if (isIntersecting) { | ||
| visibleItemKeysReference.current.add(key); | ||
| } else { | ||
| visibleItemKeysReference.current.delete(key); | ||
| } | ||
| } | ||
| onVisibleItemsChange == null ? void 0 : onVisibleItemsChange(visibleItemKeysReference.current); | ||
| }); | ||
| useEffect3(() => { | ||
| const containerElement = containerReference.current; | ||
| if (containerElement) { | ||
| const observer2 = new IntersectionObserver(updateVisibleFrame, { root: containerElement, threshold: 0 }); | ||
| setObserver(observer2); | ||
| } | ||
| }, [containerReference, updateVisibleFrame]); | ||
| return { observer, visibleItemKeys: visibleItemKeysReference }; | ||
| }, "useVisibleItems"); | ||
| // src/EndlessList/EndlessList.tsx | ||
| var noop = /* @__PURE__ */ __name(() => { | ||
| }, "noop"); | ||
| var defaultAnimationParameters = { | ||
| duration: () => 500, | ||
| easing: (t) => t | ||
| }; | ||
| var EndlessList = /* @__PURE__ */ __name(({ | ||
| ItemComponent, | ||
| initialItems, | ||
| items, | ||
| itemKey, | ||
| triggerDistance, | ||
| onTopReached, | ||
| onBottomReached, | ||
| compareItems, | ||
| PlaceholderComponent, | ||
| jumpAnimation = defaultAnimationParameters, | ||
| focusedItem, | ||
| ContainerComponent, | ||
| canStickToBottom, | ||
| onVisibleFrameChange, | ||
| containerReference: propsContainerReference | ||
| }) => { | ||
| const containerReference = useRef8(null); | ||
| const focusElementReference = useRef8(null); | ||
| const stickToBottomReached = useRef8(false); | ||
| const isScrolling = useRef8(false); | ||
| const visibleFrame = useRef8({ begin: -1, end: -1 }); | ||
| const hasMounted = useRef8(false); | ||
| const setBottomReached = useToggleEvent(onBottomReached != null ? onBottomReached : noop); | ||
| const setTopReached = useToggleEvent(onTopReached != null ? onTopReached : noop); | ||
| const getKey = useMemo2(() => { | ||
| return typeof itemKey === "function" ? itemKey : (value) => value[itemKey]; | ||
| }, [itemKey]); | ||
| useEffect4(() => { | ||
| setBottomReached(false); | ||
| setTopReached(false); | ||
| }, [items, setBottomReached, setTopReached]); | ||
| const checkBounds = useEvent((frame = visibleFrame.current) => { | ||
| onVisibleFrameChange == null ? void 0 : onVisibleFrameChange(frame); | ||
| visibleFrame.current = frame; | ||
| if (frame.begin === -1 || frame.end === -1 || isScrolling.current) { | ||
| return; | ||
| } | ||
| setBottomReached(frame.end <= triggerDistance); | ||
| setTopReached(frame.begin <= triggerDistance); | ||
| stickToBottomReached.current = frame.end === 0; | ||
| }); | ||
| const smoothScrolling = useEvent((container, item, abortController) => { | ||
| return smoothScrollToCenter(container, item, jumpAnimation, abortController); | ||
| }); | ||
| const abortControllerReference = useRef8(); | ||
| const handleJumpScroll = useCallback5( | ||
| async (abortController = new AbortController()) => { | ||
| if (abortControllerReference.current) { | ||
| abortControllerReference.current.abort(); | ||
| } | ||
| if (!containerReference.current || !focusElementReference.current) { | ||
| return; | ||
| } | ||
| abortControllerReference.current = abortController; | ||
| isScrolling.current = true; | ||
| if (hasMounted.current) { | ||
| await smoothScrolling(containerReference.current, focusElementReference.current, abortController); | ||
| } else { | ||
| focusElementReference.current.scrollIntoView({ behavior: "auto", block: "center" }); | ||
| } | ||
| isScrolling.current = false; | ||
| checkBounds(); | ||
| }, | ||
| [checkBounds, smoothScrolling] | ||
| ); | ||
| const onVisibleItemsChange = useVisibleFrame({ | ||
| getKey, | ||
| items, | ||
| onVisibleFrameUpdated: checkBounds | ||
| }); | ||
| const { observer, visibleItemKeys } = useVisibleItems(containerReference, onVisibleItemsChange); | ||
| const [scheduleJumpScroll, isJumpScheduled] = useScheduleOnNextRender(handleJumpScroll); | ||
| const lastScrolledItem = useRef8(); | ||
| const handleScrollToFocusItem = useEvent(() => { | ||
| if (focusedItem === lastScrolledItem.current) { | ||
| return; | ||
| } | ||
| lastScrolledItem.current = focusedItem; | ||
| if (focusedItem && !isJumpScheduled()) { | ||
| handleJumpScroll().catch(() => { | ||
| }); | ||
| } | ||
| }); | ||
| const itemsToRender = useEndlessList({ | ||
| getKey, | ||
| initialItems, | ||
| items, | ||
| compareItems, | ||
| handleJump: scheduleJumpScroll, | ||
| focusedItem, | ||
| visibleItemKeys, | ||
| lastScrolledItem | ||
| }); | ||
| useEffect4(() => { | ||
| handleScrollToFocusItem(); | ||
| hasMounted.current = true; | ||
| }, [handleScrollToFocusItem, itemsToRender]); | ||
| useEffect4(() => { | ||
| return () => { | ||
| hasMounted.current = false; | ||
| }; | ||
| }, []); | ||
| const handleStickToBottom = useEvent(() => { | ||
| const container = containerReference.current; | ||
| if (container && stickToBottomReached.current && !focusedItem) { | ||
| container.scrollTo({ top: container.scrollHeight }); | ||
| } | ||
| }); | ||
| useLayoutEffect2(() => { | ||
| if (canStickToBottom) { | ||
| handleStickToBottom(); | ||
| } | ||
| }, [itemsToRender, canStickToBottom, handleStickToBottom]); | ||
| return /* @__PURE__ */ React.createElement(ContainerComponent, { ref: mergeReferences(containerReference, propsContainerReference) }, itemsToRender.map((item) => /* @__PURE__ */ React.createElement( | ||
| EndlessListItemView, | ||
| __spreadValues({ | ||
| key: item.itemKey, | ||
| focusElementReference, | ||
| ItemComponent, | ||
| PlaceholderComponent, | ||
| itemObserver: observer | ||
| }, item) | ||
| ))); | ||
| }, "EndlessList"); | ||
| // src/internal/RChatContext.tsx | ||
| import { createSafeContext } from "@sirse-dev/safe-context"; | ||
| var RChatContext = createSafeContext(); | ||
| // src/Chat.tsx | ||
| var Chat = /* @__PURE__ */ __name((_a) => { | ||
| var _b = _a, { children } = _b, context = __objRest(_b, ["children"]); | ||
| return /* @__PURE__ */ React.createElement(RChatContext.Provider, { value: __spreadValues({}, context) }, children); | ||
| }, "Chat"); | ||
| // src/MessageList.tsx | ||
| import { useSafeContext } from "@sirse-dev/safe-context"; | ||
| // src/internal/RoomContext.tsx | ||
| import { createSafeContext as createSafeContext2 } from "@sirse-dev/safe-context"; | ||
| var RoomContext = createSafeContext2(); | ||
| // src/useMessages.tsx | ||
| import { useCallback as useCallback7, useEffect as useEffect5, useRef as useRef10 } from "react"; | ||
| // src/internal/clamp.ts | ||
| var clamp = /* @__PURE__ */ __name((value, min, max) => Math.max(Math.min(value, max), min), "clamp"); | ||
| // src/internal/useBoundedArray.tsx | ||
| import { useCallback as useCallback6, useRef as useRef9, useState as useState3 } from "react"; | ||
| var getClippedArray = /* @__PURE__ */ __name((items, maxSize, keep) => { | ||
| if (items.length <= maxSize) { | ||
| return items; | ||
| } | ||
| if (keep === "beginning") { | ||
| return items.slice(0, maxSize); | ||
| } | ||
| if (keep === "ending") { | ||
| return items.slice(-maxSize); | ||
| } | ||
| throw new Error(`Unrecognized "keep" option value: "${keep}"`); | ||
| }, "getClippedArray"); | ||
| var useBoundedArray = /* @__PURE__ */ __name((initial, maxChunkSize) => { | ||
| const [itemsState, setItemsState] = useState3(initial); | ||
| const itemsReference = useRef9(initial); | ||
| const setItems = useCallback6( | ||
| (items, keep) => { | ||
| const clippedItems = getClippedArray(items, maxChunkSize, keep); | ||
| setItemsState(clippedItems); | ||
| itemsReference.current = clippedItems; | ||
| return items.length > clippedItems.length; | ||
| }, | ||
| [maxChunkSize] | ||
| ); | ||
| const unshift = useCallback6( | ||
| (items) => { | ||
| return setItems([...items, ...itemsReference.current], "beginning"); | ||
| }, | ||
| [setItems] | ||
| ); | ||
| const push = useCallback6( | ||
| (items) => { | ||
| return setItems([...itemsReference.current, ...items], "ending"); | ||
| }, | ||
| [setItems] | ||
| ); | ||
| const at = useCallback6((index) => { | ||
| return itemsReference.current.at(index); | ||
| }, []); | ||
| const insert = useCallback6( | ||
| (item, index, keep) => { | ||
| itemsReference.current.splice(index, 0, item); | ||
| return setItems([...itemsReference.current], keep); | ||
| }, | ||
| [setItems] | ||
| ); | ||
| const getAll = useCallback6(() => itemsReference.current, []); | ||
| const refresh = useCallback6(() => setItemsState((old) => [...old]), []); | ||
| return [itemsState, { push, unshift, set: setItems, at, getAll, insert, refresh }]; | ||
| }, "useBoundedArray"); | ||
| // src/useMessages.tsx | ||
| var findNewElementIndex = /* @__PURE__ */ __name((elements, element, compare) => { | ||
| return elements.length - 1 - [...elements].reverse().findIndex((a) => { | ||
| return compare(element, a) > 0; | ||
| }); | ||
| }, "findNewElementIndex"); | ||
| var useMessages = /* @__PURE__ */ __name(({ | ||
| maxChunkSize, | ||
| additionalChunkSize, | ||
| chatClient, | ||
| roomIdentifier, | ||
| compareItems, | ||
| initialMessagesState, | ||
| initialSearchResult | ||
| }) => { | ||
| const isFetching = useRef10(false); | ||
| const visibleFrame = useRef10({ begin: -1, end: -1 }); | ||
| const containerReference = useRef10(null); | ||
| const searchResults = useRef10(initialSearchResult); | ||
| const selectedSearchResult = useRef10(0); | ||
| const focusedItem = useRef10(initialSearchResult == null ? void 0 : initialSearchResult.results[0]); | ||
| const [ | ||
| messages, | ||
| { | ||
| push: pushMessages, | ||
| unshift: unshiftMessages, | ||
| set: setMessages, | ||
| insert: insertMessage, | ||
| at: getMessage, | ||
| getAll: getAllMessages, | ||
| refresh | ||
| } | ||
| ] = useBoundedArray([...initialMessagesState.messages], maxChunkSize); | ||
| const messagesState = useRef10(initialMessagesState); | ||
| const handleIncomingMessage = useCallback7( | ||
| (message, messageRoomIdentifier) => { | ||
| if (messageRoomIdentifier === roomIdentifier && messagesState.current.noMessagesAfter) { | ||
| const incomingMessageIndex = findNewElementIndex(getAllMessages(), message, compareItems); | ||
| const keepDirection = visibleFrame.current.begin < visibleFrame.current.end ? "beginning" : "ending"; | ||
| const clipped = insertMessage(message, incomingMessageIndex + 1, keepDirection); | ||
| if (clipped) { | ||
| if (keepDirection === "beginning") { | ||
| messagesState.current.noMessagesAfter = false; | ||
| } else { | ||
| messagesState.current.noMessagesBefore = false; | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| [roomIdentifier, getAllMessages, compareItems, insertMessage] | ||
| ); | ||
| const focusItem = useCallback7( | ||
| async (item) => { | ||
| if (!item) { | ||
| if (focusedItem.current) { | ||
| refresh(); | ||
| } | ||
| focusedItem.current = item; | ||
| return; | ||
| } | ||
| focusedItem.current = item; | ||
| const [previousChunk, nextChunk] = await Promise.all([ | ||
| chatClient.fetchMessages(roomIdentifier, additionalChunkSize, item, void 0), | ||
| chatClient.fetchMessages(roomIdentifier, additionalChunkSize, void 0, item) | ||
| ]); | ||
| messagesState.current = { | ||
| noMessagesBefore: previousChunk.noMessagesBefore, | ||
| noMessagesAfter: nextChunk.noMessagesAfter | ||
| }; | ||
| setMessages([...previousChunk.messages, item, ...nextChunk.messages], "beginning"); | ||
| }, | ||
| [additionalChunkSize, chatClient, roomIdentifier, setMessages, refresh] | ||
| ); | ||
| const handleSearch = useCallback7( | ||
| (searchRoomIdentifier, searchResult, focusIndex) => { | ||
| if (searchRoomIdentifier === roomIdentifier) { | ||
| searchResults.current = searchResult; | ||
| focusIndex = Math.min(focusIndex, searchResult.results.length - 1); | ||
| selectedSearchResult.current = focusIndex; | ||
| focusItem(searchResult.results[focusIndex]); | ||
| } | ||
| }, | ||
| [focusItem, roomIdentifier] | ||
| ); | ||
| const handlePreviousSearchResult = useCallback7( | ||
| (searchRoomIdentifier) => { | ||
| if (searchResults.current && searchRoomIdentifier === roomIdentifier) { | ||
| selectedSearchResult.current = clamp( | ||
| selectedSearchResult.current - 1, | ||
| 0, | ||
| Math.max(searchResults.current.results.length - 1, 0) | ||
| ); | ||
| focusItem(searchResults.current.results[selectedSearchResult.current]); | ||
| } | ||
| }, | ||
| [focusItem, roomIdentifier] | ||
| ); | ||
| const handleNextSearchResult = useCallback7( | ||
| (searchRoomIdentifier) => { | ||
| if (searchResults.current && searchRoomIdentifier === roomIdentifier) { | ||
| selectedSearchResult.current = clamp( | ||
| selectedSearchResult.current + 1, | ||
| 0, | ||
| Math.max(searchResults.current.results.length - 1, 0) | ||
| ); | ||
| focusItem(searchResults.current.results[selectedSearchResult.current]); | ||
| } | ||
| }, | ||
| [focusItem, roomIdentifier] | ||
| ); | ||
| useEffect5(() => { | ||
| chatClient.addEventListener("receiveMessage", handleIncomingMessage); | ||
| chatClient.addEventListener("receiveSearchResults", handleSearch); | ||
| chatClient.addEventListener("nextSearchResult", handleNextSearchResult); | ||
| chatClient.addEventListener("previousSearchResult", handlePreviousSearchResult); | ||
| return () => { | ||
| chatClient.removeEventListener("receiveMessage", handleIncomingMessage); | ||
| chatClient.removeEventListener("receiveSearchResults", handleSearch); | ||
| chatClient.removeEventListener("nextSearchResult", handleNextSearchResult); | ||
| chatClient.removeEventListener("previousSearchResult", handlePreviousSearchResult); | ||
| }; | ||
| }, [chatClient, handleIncomingMessage, handleNextSearchResult, handlePreviousSearchResult, handleSearch]); | ||
| useEffect5(() => { | ||
| if (!initialSearchResult) { | ||
| const container = containerReference.current; | ||
| if (container) { | ||
| container.scrollTo({ top: container.scrollHeight }); | ||
| } else { | ||
| console.warn( | ||
| "RChat: container reference wasn't passed into EndlessList, so scrolling to the bottom after initial chat load failed. This may cause inconsistent behavior" | ||
| ); | ||
| } | ||
| } | ||
| }, [initialSearchResult]); | ||
| useEffect5(() => { | ||
| setMessages([...initialMessagesState.messages], "beginning"); | ||
| messagesState.current = initialMessagesState; | ||
| }, [initialMessagesState, setMessages]); | ||
| useEffect5(() => { | ||
| searchResults.current = initialSearchResult; | ||
| focusedItem.current = initialSearchResult == null ? void 0 : initialSearchResult.results[0]; | ||
| }, [initialSearchResult]); | ||
| const handleTopReached = useEvent(async () => { | ||
| if (messagesState.current.noMessagesBefore || isFetching.current) { | ||
| return; | ||
| } | ||
| isFetching.current = true; | ||
| const { messages: fetchedMessages, noMessagesBefore } = await chatClient.fetchMessages( | ||
| roomIdentifier, | ||
| additionalChunkSize, | ||
| getMessage(0), | ||
| void 0 | ||
| ); | ||
| const clipped = unshiftMessages(fetchedMessages); | ||
| const newState = { | ||
| noMessagesBefore, | ||
| noMessagesAfter: !clipped && messagesState.current.noMessagesAfter | ||
| }; | ||
| messagesState.current = newState; | ||
| isFetching.current = false; | ||
| }); | ||
| const handleBottomReached = useEvent(async () => { | ||
| if (messagesState.current.noMessagesAfter || isFetching.current) { | ||
| return; | ||
| } | ||
| isFetching.current = true; | ||
| const { messages: fetchedMessages, noMessagesAfter } = await chatClient.fetchMessages( | ||
| roomIdentifier, | ||
| additionalChunkSize, | ||
| void 0, | ||
| getMessage(-1) | ||
| ); | ||
| const clipped = pushMessages(fetchedMessages); | ||
| const newState = { | ||
| noMessagesAfter, | ||
| noMessagesBefore: !clipped && messagesState.current.noMessagesBefore | ||
| }; | ||
| messagesState.current = newState; | ||
| isFetching.current = false; | ||
| }); | ||
| const onVisibleFrameChange = /* @__PURE__ */ __name((frame) => { | ||
| visibleFrame.current = frame; | ||
| }, "onVisibleFrameChange"); | ||
| return { | ||
| messages, | ||
| onTopReached: handleTopReached, | ||
| onBottomReached: handleBottomReached, | ||
| noMessagesBefore: messagesState.current.noMessagesBefore, | ||
| noMessagesAfter: messagesState.current.noMessagesAfter, | ||
| onVisibleFrameChange, | ||
| containerReference, | ||
| focusedItem: focusedItem.current | ||
| }; | ||
| }, "useMessages"); | ||
| // src/MessageList.tsx | ||
| var MessageList = /* @__PURE__ */ __name(({ | ||
| jumpAnimation, | ||
| initialMessagesState, | ||
| initialSearchResult | ||
| }) => { | ||
| const { | ||
| client, | ||
| MessageComponent, | ||
| PlaceholderComponent, | ||
| ContainerComponent, | ||
| triggerDistance, | ||
| compareItems, | ||
| itemKey | ||
| } = useSafeContext(RChatContext); | ||
| const { roomIdentifier } = useSafeContext(RoomContext); | ||
| const { | ||
| messages, | ||
| onBottomReached, | ||
| onTopReached, | ||
| noMessagesAfter, | ||
| onVisibleFrameChange, | ||
| containerReference, | ||
| focusedItem | ||
| } = useMessages({ | ||
| chatClient: client, | ||
| additionalChunkSize: 20, | ||
| maxChunkSize: 100, | ||
| roomIdentifier, | ||
| compareItems, | ||
| initialMessagesState, | ||
| initialSearchResult | ||
| }); | ||
| return /* @__PURE__ */ React.createElement( | ||
| EndlessList, | ||
| { | ||
| initialItems: initialMessagesState.messages, | ||
| items: messages, | ||
| onTopReached, | ||
| onBottomReached, | ||
| triggerDistance, | ||
| ContainerComponent, | ||
| ItemComponent: MessageComponent, | ||
| PlaceholderComponent, | ||
| compareItems, | ||
| itemKey, | ||
| onVisibleFrameChange, | ||
| canStickToBottom: noMessagesAfter, | ||
| containerReference, | ||
| focusedItem, | ||
| jumpAnimation | ||
| } | ||
| ); | ||
| }, "MessageList"); | ||
| // src/Room.tsx | ||
| var Room = /* @__PURE__ */ __name(({ identifier, children }) => { | ||
| return /* @__PURE__ */ React.createElement(RoomContext.Provider, { value: { roomIdentifier: identifier } }, children); | ||
| }, "Room"); | ||
| export { | ||
| Chat, | ||
| EndlessList, | ||
| MessageList, | ||
| Room, | ||
| useEndlessList, | ||
| useMessages, | ||
| useVisibleItems | ||
| }; |
| { | ||
| "version": 3, | ||
| "sources": ["../src/EndlessList/EndlessList.tsx", "../src/internal/mergeReferences.ts", "../src/internal/smoothScrollToCenter.ts", "../src/internal/useEvent.ts", "../src/internal/useScheduleOnNextRender.tsx", "../src/internal/useToggleEvent.ts", "../src/EndlessList/EndlessListItemView.tsx", "../src/EndlessList/useEndlessList.tsx", "../src/internal/binarySearch.ts", "../src/internal/useIdGenerator.ts", "../src/EndlessList/useVisibleFrame.tsx", "../src/EndlessList/useVisibleItems.tsx", "../src/internal/RChatContext.tsx", "../src/Chat.tsx", "../src/MessageList.tsx", "../src/internal/RoomContext.tsx", "../src/useMessages.tsx", "../src/internal/clamp.ts", "../src/internal/useBoundedArray.tsx", "../src/Room.tsx"], | ||
| "sourcesContent": ["import {\r\n\tComponentType,\r\n\tPropsWithChildren,\r\n\tRef,\r\n\tRefAttributes,\r\n\tuseCallback,\r\n\tuseEffect,\r\n\tuseLayoutEffect,\r\n\tuseMemo,\r\n\tuseRef,\r\n} from 'react';\r\n\r\nimport { mergeReferences } from '../internal/mergeReferences';\r\nimport { AnimationParameters, smoothScrollToCenter } from '../internal/smoothScrollToCenter';\r\nimport { useEvent } from '../internal/useEvent';\r\nimport { useScheduleOnNextRender } from '../internal/useScheduleOnNextRender';\r\nimport { useToggleEvent } from '../internal/useToggleEvent';\r\n\r\nimport { EndlessListItemView } from './EndlessListItemView';\r\nimport { ItemComponentType } from './ItemComponentType';\r\nimport { PlaceholderComponentType } from './PlaceholderComponentType';\r\nimport { useEndlessList } from './useEndlessList';\r\nimport { Frame, useVisibleFrame } from './useVisibleFrame';\r\nimport { useVisibleItems } from './useVisibleItems';\r\nimport type { KeysOfType } from '../internal/KeysOfType';\r\n\r\nexport type ContainerComponentProps = PropsWithChildren<RefAttributes<HTMLElement>>;\r\n\r\nexport type ItemKey<T> = KeysOfType<T, string> | ((value: T) => string);\r\n\r\nexport type EndlessListProps<TItemType> = {\r\n\tItemComponent: ItemComponentType<TItemType>;\r\n\tPlaceholderComponent: PlaceholderComponentType;\r\n\tContainerComponent: ComponentType<ContainerComponentProps>;\r\n\tinitialItems: TItemType[];\r\n\titems: TItemType[];\r\n\titemKey: ItemKey<TItemType>;\r\n\ttriggerDistance: number;\r\n\tonTopReached?: () => void;\r\n\tonBottomReached?: () => void;\r\n\tcompareItems: (first: TItemType, second: TItemType) => number;\r\n\tfocusedItem?: TItemType;\r\n\tjumpAnimation?: AnimationParameters;\r\n\tcanStickToBottom?: boolean;\r\n\tonVisibleFrameChange?: (frame: Frame) => void;\r\n\tcontainerReference?: Ref<HTMLElement>;\r\n};\r\n\r\nconst noop = () => {\r\n\t/** No operation */\r\n};\r\n\r\nconst defaultAnimationParameters: AnimationParameters = {\r\n\t// Constant duration\r\n\tduration: () => 500,\r\n\t// Linear easing\r\n\teasing: (t) => t,\r\n};\r\n\r\nexport const EndlessList = <T,>({\r\n\tItemComponent,\r\n\tinitialItems,\r\n\titems,\r\n\titemKey,\r\n\ttriggerDistance,\r\n\tonTopReached,\r\n\tonBottomReached,\r\n\tcompareItems,\r\n\tPlaceholderComponent,\r\n\tjumpAnimation = defaultAnimationParameters,\r\n\tfocusedItem,\r\n\tContainerComponent,\r\n\tcanStickToBottom,\r\n\tonVisibleFrameChange,\r\n\tcontainerReference: propsContainerReference,\r\n}: EndlessListProps<T>) => {\r\n\tconst containerReference = useRef<HTMLElement>(null);\r\n\tconst focusElementReference = useRef<HTMLElement>(null);\r\n\tconst stickToBottomReached = useRef(false);\r\n\tconst isScrolling = useRef(false);\r\n\tconst visibleFrame = useRef<Frame>({ begin: -1, end: -1 });\r\n\tconst hasMounted = useRef(false);\r\n\r\n\tconst setBottomReached = useToggleEvent(onBottomReached ?? noop);\r\n\tconst setTopReached = useToggleEvent(onTopReached ?? noop);\r\n\r\n\tconst getKey = useMemo(() => {\r\n\t\treturn typeof itemKey === 'function' ? itemKey : (value: T) => value[itemKey] as unknown as string;\r\n\t}, [itemKey]);\r\n\r\n\tuseEffect(() => {\r\n\t\tsetBottomReached(false);\r\n\t\tsetTopReached(false);\r\n\t}, [items, setBottomReached, setTopReached]);\r\n\r\n\tconst checkBounds = useEvent((frame: Frame = visibleFrame.current) => {\r\n\t\tonVisibleFrameChange?.(frame);\r\n\t\tvisibleFrame.current = frame;\r\n\t\tif (frame.begin === -1 || frame.end === -1 || isScrolling.current) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tsetBottomReached(frame.end <= triggerDistance);\r\n\t\tsetTopReached(frame.begin <= triggerDistance);\r\n\t\tstickToBottomReached.current = frame.end === 0;\r\n\t});\r\n\r\n\tconst smoothScrolling = useEvent((container: HTMLElement, item: HTMLElement, abortController?: AbortController) => {\r\n\t\treturn smoothScrollToCenter(container, item, jumpAnimation, abortController);\r\n\t});\r\n\r\n\tconst abortControllerReference = useRef<AbortController>();\r\n\tconst handleJumpScroll = useCallback(\r\n\t\tasync (abortController = new AbortController()) => {\r\n\t\t\tif (abortControllerReference.current) {\r\n\t\t\t\tabortControllerReference.current.abort();\r\n\t\t\t}\r\n\r\n\t\t\tif (!containerReference.current || !focusElementReference.current) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tabortControllerReference.current = abortController;\r\n\t\t\tisScrolling.current = true;\r\n\r\n\t\t\tif (hasMounted.current) {\r\n\t\t\t\tawait smoothScrolling(containerReference.current, focusElementReference.current, abortController);\r\n\t\t\t} else {\r\n\t\t\t\tfocusElementReference.current.scrollIntoView({ behavior: 'auto', block: 'center' });\r\n\t\t\t}\r\n\r\n\t\t\tisScrolling.current = false;\r\n\r\n\t\t\tcheckBounds();\r\n\t\t},\r\n\t\t[checkBounds, smoothScrolling],\r\n\t);\r\n\r\n\tconst onVisibleItemsChange = useVisibleFrame({\r\n\t\tgetKey,\r\n\t\titems,\r\n\t\tonVisibleFrameUpdated: checkBounds,\r\n\t});\r\n\tconst { observer, visibleItemKeys } = useVisibleItems(containerReference, onVisibleItemsChange);\r\n\tconst [scheduleJumpScroll, isJumpScheduled] = useScheduleOnNextRender(handleJumpScroll);\r\n\r\n\tconst lastScrolledItem = useRef<T | undefined>();\r\n\tconst handleScrollToFocusItem = useEvent(() => {\r\n\t\tif (focusedItem === lastScrolledItem.current) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlastScrolledItem.current = focusedItem;\r\n\t\tif (focusedItem && !isJumpScheduled()) {\r\n\t\t\thandleJumpScroll().catch(() => {\r\n\t\t\t\t/* Ignore aborted jump error */\r\n\t\t\t});\r\n\t\t}\r\n\t});\r\n\r\n\tconst itemsToRender = useEndlessList({\r\n\t\tgetKey,\r\n\t\tinitialItems,\r\n\t\titems,\r\n\t\tcompareItems,\r\n\t\thandleJump: scheduleJumpScroll,\r\n\t\tfocusedItem,\r\n\t\tvisibleItemKeys,\r\n\t\tlastScrolledItem,\r\n\t});\r\n\r\n\tuseEffect(() => {\r\n\t\thandleScrollToFocusItem();\r\n\t\thasMounted.current = true;\r\n\t}, [handleScrollToFocusItem, itemsToRender]);\r\n\r\n\tuseEffect(() => {\r\n\t\treturn () => {\r\n\t\t\thasMounted.current = false;\r\n\t\t};\r\n\t}, []);\r\n\r\n\tconst handleStickToBottom = useEvent(() => {\r\n\t\tconst container = containerReference.current;\r\n\t\tif (container && stickToBottomReached.current && !focusedItem) {\r\n\t\t\tcontainer.scrollTo({ top: container.scrollHeight });\r\n\t\t}\r\n\t});\r\n\r\n\tuseLayoutEffect(() => {\r\n\t\tif (canStickToBottom) {\r\n\t\t\thandleStickToBottom();\r\n\t\t}\r\n\t}, [itemsToRender, canStickToBottom, handleStickToBottom]);\r\n\r\n\treturn (\r\n\t\t<ContainerComponent ref={mergeReferences(containerReference, propsContainerReference)}>\r\n\t\t\t{itemsToRender.map((item) => (\r\n\t\t\t\t<EndlessListItemView\r\n\t\t\t\t\tkey={item.itemKey}\r\n\t\t\t\t\tfocusElementReference={focusElementReference}\r\n\t\t\t\t\tItemComponent={ItemComponent}\r\n\t\t\t\t\tPlaceholderComponent={PlaceholderComponent}\r\n\t\t\t\t\titemObserver={observer}\r\n\t\t\t\t\t{...item}\r\n\t\t\t\t/>\r\n\t\t\t))}\r\n\t\t</ContainerComponent>\r\n\t);\r\n};\r\n", "import { Ref, MutableRefObject } from 'react';\r\n\r\nexport const mergeReferences = <T>(\r\n\t...inputReferences: Array<Ref<T> | MutableRefObject<T> | undefined | false>\r\n): Ref<T> | undefined => {\r\n\tconst filteredInputReferences = inputReferences.filter(Boolean as unknown as (value: unknown) => value is Ref<T>);\r\n\r\n\tif (filteredInputReferences.length <= 1) {\r\n\t\treturn filteredInputReferences[0];\r\n\t}\r\n\treturn function mergedReferences(reference: T | null) {\r\n\t\tfor (const inputReference of filteredInputReferences) {\r\n\t\t\tif (typeof inputReference === 'function') {\r\n\t\t\t\tinputReference(reference);\r\n\t\t\t} else if (inputReference) {\r\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n\t\t\t\t(inputReference as any).current = reference;\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n};\r\n", "export type AnimationParameters = {\r\n\t/**\r\n\t * Easing function.\r\n\t * Takes an argument in range [0, 1] and returns value in range [0, 1].\r\n\t */\r\n\teasing: (t: number) => number;\r\n\r\n\t/**\r\n\t * Animation duration function.\r\n\t * Takes distance in pixels and returns duration in milliseconds.\r\n\t */\r\n\tduration: (distance: number) => number;\r\n};\r\n\r\nexport const smoothScrollToCenter = async (\r\n\tcontainer: HTMLElement,\r\n\telement: HTMLElement,\r\n\tparameters: AnimationParameters,\r\n\tcontroller?: AbortController,\r\n) => {\r\n\tconst elementRect = element.getBoundingClientRect();\r\n\tconst containerRect = container.getBoundingClientRect();\r\n\r\n\tconst top = elementRect.top - containerRect.top - containerRect.height / 2 + elementRect.height / 2;\r\n\r\n\tconst startPos = container.scrollTop;\r\n\tconst clientHeight = container.clientHeight;\r\n\tconst maxScroll = container.scrollHeight - clientHeight;\r\n\tconst scrollIntendedDestination = startPos + top;\r\n\tconst scrollEndValue = Math.min(Math.max(scrollIntendedDestination, 0), maxScroll);\r\n\tlet startTime = 0;\r\n\r\n\tconst duration = parameters.duration(scrollEndValue - startPos);\r\n\r\n\treturn new Promise<void>((resolve, reject) => {\r\n\t\tconst scroll = (timestamp: number) => {\r\n\t\t\tif (controller?.signal.aborted) {\r\n\t\t\t\treject(controller.signal.reason);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tstartTime = startTime || timestamp;\r\n\t\t\tconst elapsed = timestamp - startTime;\r\n\t\t\tcontainer.scrollTop = startPos + (scrollEndValue - startPos) * parameters.easing(elapsed / duration);\r\n\t\t\tif (elapsed <= duration) {\r\n\t\t\t\twindow.requestAnimationFrame(scroll);\r\n\t\t\t} else {\r\n\t\t\t\tresolve();\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tif (startPos !== scrollEndValue) {\r\n\t\t\twindow.requestAnimationFrame(scroll);\r\n\t\t} else {\r\n\t\t\tresolve();\r\n\t\t}\r\n\t});\r\n};\r\n", "import { useCallback, useRef } from 'react';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ntype AnyFunction = (...arguments_: any[]) => any;\r\n\r\nexport const useEvent = <T extends AnyFunction>(handler: T): T => {\r\n\tconst handlerReference = useRef(handler);\r\n\thandlerReference.current = handler;\r\n\r\n\treturn useCallback((...parameters: Parameters<T>): ReturnType<T> => {\r\n\t\treturn handlerReference.current(...parameters);\r\n\t}, []) as T;\r\n};\r\n", "import { useCallback, useLayoutEffect, useRef } from 'react';\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ntype AnyAsyncFunction = (...arguments_: any[]) => Promise<any>;\r\n\r\nexport const useScheduleOnNextRender = <T extends AnyAsyncFunction>(\r\n\thandler: T,\r\n): [schedule: (...parameters: Parameters<T>) => ReturnType<T>, isScheduled: () => boolean] => {\r\n\ttype PromiseHandle = {\r\n\t\tparameters: Parameters<T>;\r\n\t\tresolve: (value: ReturnType<Awaited<T>>) => void;\r\n\t\treject: (reason: unknown) => void;\r\n\t};\r\n\tconst unresolvedHandle = useRef<PromiseHandle>();\r\n\r\n\tuseLayoutEffect(() => {\r\n\t\tconst currentHandle = unresolvedHandle.current;\r\n\t\tunresolvedHandle.current = undefined;\r\n\t\tif (currentHandle) {\r\n\t\t\thandler(...currentHandle.parameters)\r\n\t\t\t\t.then(currentHandle.resolve)\r\n\t\t\t\t.catch(currentHandle.reject);\r\n\t\t}\r\n\t});\r\n\r\n\tconst wrappedFunction = useCallback((...parameters: Parameters<T>): ReturnType<T> => {\r\n\t\treturn new Promise<Awaited<ReturnType<T>>>((resolve, reject) => {\r\n\t\t\tunresolvedHandle.current = {\r\n\t\t\t\tparameters,\r\n\t\t\t\tresolve,\r\n\t\t\t\treject,\r\n\t\t\t};\r\n\t\t}) as ReturnType<T>;\r\n\t}, []);\r\n\r\n\tconst isScheduled = useCallback(() => {\r\n\t\treturn unresolvedHandle.current !== undefined;\r\n\t}, []);\r\n\r\n\treturn [wrappedFunction, isScheduled];\r\n};\r\n", "import { useCallback, useRef } from 'react';\r\n\r\nexport const useToggleEvent = (onTurnedOn: () => void): ((value: boolean) => void) => {\r\n\tconst value = useRef(false);\r\n\r\n\tconst toggle = useCallback(\r\n\t\t(newValue: boolean) => {\r\n\t\t\tif (!value.current && newValue) {\r\n\t\t\t\tonTurnedOn();\r\n\t\t\t}\r\n\r\n\t\t\tvalue.current = newValue;\r\n\t\t},\r\n\t\t[onTurnedOn],\r\n\t);\r\n\r\n\treturn toggle;\r\n};\r\n", "import { RefObject, useEffect, useRef } from 'react';\r\nimport { mergeReferences } from '../internal/mergeReferences';\r\nimport { ItemComponentType } from './ItemComponentType';\r\nimport { PlaceholderComponentType } from './PlaceholderComponentType';\r\nimport type { EndlessListItem } from './useEndlessList';\r\n\r\nexport type EndlessListItemViewProps<TMessageType> = EndlessListItem<TMessageType> & {\r\n\tItemComponent: ItemComponentType<TMessageType>;\r\n\tPlaceholderComponent: PlaceholderComponentType;\r\n\titemObserver: IntersectionObserver | undefined;\r\n\tfocusElementReference: RefObject<HTMLElement>;\r\n};\r\n\r\nexport const EndlessListItemView = <TMessageType,>({\r\n\tItemComponent,\r\n\tPlaceholderComponent,\r\n\titemObserver,\r\n\tfocusElementReference,\r\n\t...item\r\n}: EndlessListItemViewProps<TMessageType>) => {\r\n\tconst itemReference = useRef<HTMLElement>(null);\r\n\r\n\tuseEffect(() => {\r\n\t\tconst currentElement = itemReference.current;\r\n\t\tif (currentElement && itemObserver) {\r\n\t\t\titemObserver.observe(currentElement);\r\n\r\n\t\t\treturn () => itemObserver.unobserve(currentElement);\r\n\t\t}\r\n\t}, [itemObserver]);\r\n\r\n\tif (item.type === 'placeholder') {\r\n\t\treturn <PlaceholderComponent ref={itemReference} itemKey={item.itemKey} />;\r\n\t}\r\n\r\n\treturn <ItemComponent ref={mergeReferences(itemReference, item.focused && focusElementReference)} {...item} />;\r\n};\r\n", "import { Key, useMemo, useRef, useState, MutableRefObject, useEffect } from 'react';\r\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect';\r\nimport { binarySearch } from '../internal/binarySearch';\r\nimport { useEvent } from '../internal/useEvent';\r\nimport { useIdGenerator } from '../internal/useIdGenerator';\r\n\r\nexport type UseEndlessListConfig<T> = {\r\n\tinitialItems: T[];\r\n\titems: T[];\r\n\tgetKey: (item: T) => string;\r\n\tcompareItems: (a: T, b: T) => number;\r\n\thandleJump: (abortController: AbortController) => Promise<void>;\r\n\tfocusedItem?: T;\r\n\tvisibleItemKeys: MutableRefObject<Set<string>>;\r\n\tlastScrolledItem: MutableRefObject<T | undefined>;\r\n};\r\n\r\nexport type EndlessListRealItem<TValue> = {\r\n\ttype: 'real';\r\n\tvalue: TValue;\r\n\tindex: number;\r\n\tarray: TValue[];\r\n\titemKey: string;\r\n\tfocused: boolean;\r\n};\r\n\r\nexport type EndlessListPlaceholderItem = {\r\n\ttype: 'placeholder';\r\n\titemKey: string;\r\n};\r\n\r\nexport type EndlessListItem<TValue> = EndlessListRealItem<TValue> | EndlessListPlaceholderItem;\r\n\r\nconst valueToEndlessListItem = <T,>(getKey: (value: T) => string, focusItemKey: string | undefined) => {\r\n\treturn (value: T, index: number, array: T[]): EndlessListRealItem<T> => {\r\n\t\tconst key = getKey(value);\r\n\r\n\t\treturn {\r\n\t\t\ttype: 'real',\r\n\t\t\tvalue,\r\n\t\t\tindex,\r\n\t\t\tarray,\r\n\t\t\tfocused: key === focusItemKey,\r\n\t\t\titemKey: key,\r\n\t\t};\r\n\t};\r\n};\r\n\r\nexport const useEndlessList = <T,>({\r\n\tinitialItems,\r\n\titems,\r\n\tgetKey,\r\n\tfocusedItem,\r\n\tcompareItems,\r\n\thandleJump,\r\n\tvisibleItemKeys,\r\n\tlastScrolledItem,\r\n}: UseEndlessListConfig<T>): Array<EndlessListItem<T>> => {\r\n\tconst focusedItemKey = focusedItem === undefined ? undefined : getKey(focusedItem);\r\n\tconst defaultConvertItem = useMemo(() => valueToEndlessListItem(getKey, focusedItemKey), [getKey, focusedItemKey]);\r\n\tconst [renderedItems, setRenderedItems] = useState<Array<EndlessListItem<T>>>(() => items.map(defaultConvertItem));\r\n\tconst jumpAbortController = useRef<AbortController>();\r\n\tconst initialItemsReference = useRef(initialItems);\r\n\tconst hasMounted = useRef(false);\r\n\r\n\tconst getUniquePlaceholderKey = useIdGenerator();\r\n\r\n\tconst performFixup = useEvent((): [items: Array<EndlessListItem<T>>, constructItems: boolean] => {\r\n\t\t/**\r\n\t\t * Visible items fixup algorithm.\r\n\t\t *\r\n\t\t * Firstly, take all items, which are displayed on the screen.\r\n\t\t */\r\n\r\n\t\tconst visibleItems = renderedItems\r\n\t\t\t.filter(({ itemKey, type }, index, array) => {\r\n\t\t\t\tif (visibleItemKeys.current.has(itemKey)) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (type === 'placeholder') {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst previousItem = array[index - 1];\r\n\t\t\t\tif (\r\n\t\t\t\t\tpreviousItem &&\r\n\t\t\t\t\tpreviousItem.type !== 'placeholder' &&\r\n\t\t\t\t\tvisibleItemKeys.current.has(previousItem.itemKey)\r\n\t\t\t\t) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst nextItem = array[index + 1];\r\n\t\t\t\tif (nextItem && nextItem.type !== 'placeholder' && visibleItemKeys.current.has(nextItem.itemKey)) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn false;\r\n\t\t\t})\r\n\t\t\t.map((item) => {\r\n\t\t\t\tif (item.type === 'real' && item.focused) {\r\n\t\t\t\t\titem.focused = false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn item;\r\n\t\t\t});\r\n\r\n\t\tconst keys = new Set(items.map(getKey));\r\n\t\tif (visibleItems.every((item) => !keys.has(item.itemKey))) {\r\n\t\t\treturn [visibleItems, true];\r\n\t\t}\r\n\r\n\t\tconst comparator = (a: EndlessListRealItem<T>, b: { value: EndlessListItem<T>; index: number }): number => {\r\n\t\t\tif (b.value.type === 'placeholder') {\r\n\t\t\t\tconst nextValue = visibleItems[b.index + 1];\r\n\r\n\t\t\t\tif (nextValue !== undefined && nextValue.type !== 'placeholder') {\r\n\t\t\t\t\treturn compareItems(nextValue.value, a.value);\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn 1;\r\n\t\t\t}\r\n\r\n\t\t\treturn compareItems(a.value, b.value.value);\r\n\t\t};\r\n\r\n\t\tconst jumpKey = focusedItemKey ?? getKey(items[Math.floor(items.length / 2)]);\r\n\t\tconst convertedItems = [...items.map(valueToEndlessListItem(getKey, jumpKey))];\r\n\r\n\t\tlet pivotIndex = visibleItems.findIndex((item) => keys.has(item.itemKey));\r\n\r\n\t\tif (pivotIndex === -1) {\r\n\t\t\tpivotIndex = binarySearch(visibleItems, convertedItems.at(0)!, comparator);\r\n\t\t}\r\n\t\tvisibleItems.splice(pivotIndex, 1, ...convertedItems);\r\n\r\n\t\tconst dedupedKeys = new Set<Key>();\r\n\t\tconst filteredItems = visibleItems.filter((item) => {\r\n\t\t\tif (dedupedKeys.has(item.itemKey)) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tdedupedKeys.add(item.itemKey);\r\n\t\t\treturn true;\r\n\t\t});\r\n\r\n\t\treturn [filteredItems, false];\r\n\t});\r\n\r\n\tconst update = useEvent(async () => {\r\n\t\tif (jumpAbortController.current) {\r\n\t\t\tjumpAbortController.current.abort();\r\n\t\t\tjumpAbortController.current = undefined;\r\n\t\t}\r\n\r\n\t\tif (renderedItems.length === 0 || items.length === 0 || initialItemsReference.current !== initialItems) {\r\n\t\t\t/**\r\n\t\t\t * There is nothing to do:\r\n\t\t\t * 1. If renderedItems array is empty, it means that there is nothing on the screen - render all items.\r\n\t\t\t * 2. If items array is empty, it means that all items must disappear from the screen.\r\n\t\t\t * \t 3. If initial items has been changed\r\n\t\t\t */\r\n\t\t\tsetRenderedItems(items.map(defaultConvertItem));\r\n\t\t\tinitialItemsReference.current = initialItems;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t * Determine, if current update call has aborted previous jump.\r\n\t\t */\r\n\t\tconst isAbortedPreviousJump = renderedItems.some((item) => item.type === 'placeholder');\r\n\r\n\t\tlet oldItems: Array<EndlessListItem<T>>;\r\n\t\tlet constructItems = true;\r\n\t\tif (isAbortedPreviousJump) {\r\n\t\t\t/**\r\n\t\t\t * Previous jump was terminated by current state update.\r\n\t\t\t * Must perform one-time fixup.\r\n\t\t\t */\r\n\t\t\t[oldItems, constructItems] = performFixup();\r\n\r\n\t\t\tlet array = [];\r\n\t\t\tlet index = 0;\r\n\t\t\tfor (const item of oldItems) {\r\n\t\t\t\tif (item.type === 'placeholder') {\r\n\t\t\t\t\tindex = 0;\r\n\t\t\t\t\tarray = [];\r\n\t\t\t\t} else {\r\n\t\t\t\t\titem.index = index;\r\n\t\t\t\t\titem.array = array;\r\n\t\t\t\t\tarray.push(item.value);\r\n\t\t\t\t\t++index;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tconst keys = items.map(getKey);\r\n\t\t\tconst oldKeys = renderedItems.map((item) => item.itemKey);\r\n\r\n\t\t\tconst mustMoveForward = !oldKeys.includes(keys[0]) && !keys.includes(oldKeys.at(-1)!);\r\n\t\t\tconst mustMoveBack = !keys.includes(oldKeys[0]) && !oldKeys.includes(keys.at(-1)!);\r\n\r\n\t\t\tconst mustJump = mustMoveForward && mustMoveBack;\r\n\r\n\t\t\tif (!mustJump) {\r\n\t\t\t\tsetRenderedItems(items.map(defaultConvertItem));\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\toldItems = renderedItems.map((item) => {\r\n\t\t\t\tif (item.type === 'real' && item.focused) {\r\n\t\t\t\t\titem.focused = false;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn item;\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tlet constructedItems: Array<EndlessListItem<T>>;\r\n\t\tif (constructItems) {\r\n\t\t\tconst firstItem = oldItems.find((item): item is EndlessListRealItem<T> => item.type === 'real');\r\n\t\t\tlet jumpDirection = 'forward';\r\n\t\t\tif (firstItem) {\r\n\t\t\t\tjumpDirection = compareItems(items[0], firstItem.value) < 0 ? 'forward' : 'back';\r\n\t\t\t}\r\n\r\n\t\t\tconst jumpKey = focusedItemKey ?? getKey(items[Math.floor(items.length / 2)]);\r\n\r\n\t\t\tlet nextItems: Array<EndlessListItem<T>> | undefined;\r\n\t\t\tlet previousItems: Array<EndlessListItem<T>> | undefined;\r\n\r\n\t\t\tconst convertItem = valueToEndlessListItem(getKey, jumpKey);\r\n\t\t\tif (jumpDirection === 'forward') {\r\n\t\t\t\tnextItems = items.map(convertItem);\r\n\t\t\t\tpreviousItems = oldItems;\r\n\t\t\t} else {\r\n\t\t\t\tnextItems = oldItems;\r\n\t\t\t\tpreviousItems = items.map(convertItem);\r\n\t\t\t}\r\n\r\n\t\t\tconst alreadyHasPlaceholder =\r\n\t\t\t\tnextItems.at(-1)?.type === 'placeholder' || previousItems.at(0)?.type === 'placeholder';\r\n\r\n\t\t\tconstructedItems = [\r\n\t\t\t\t...nextItems,\r\n\t\t\t\t...(alreadyHasPlaceholder\r\n\t\t\t\t\t? []\r\n\t\t\t\t\t: [{ type: 'placeholder' as const, itemKey: getUniquePlaceholderKey() }]),\r\n\t\t\t\t...previousItems,\r\n\t\t\t];\r\n\t\t} else {\r\n\t\t\tconstructedItems = oldItems;\r\n\t\t}\r\n\r\n\t\tlastScrolledItem.current = items[Math.floor(items.length / 2)];\r\n\r\n\t\tsetRenderedItems(constructedItems);\r\n\t\tconst newController = new AbortController();\r\n\t\tjumpAbortController.current = newController;\r\n\r\n\t\ttry {\r\n\t\t\tif (hasMounted.current) {\r\n\t\t\t\tawait handleJump(newController);\r\n\t\t\t}\r\n\r\n\t\t\tsetRenderedItems(items.map(defaultConvertItem));\r\n\t\t} catch {\r\n\t\t\t/* Noop */\r\n\t\t} finally {\r\n\t\t\tjumpAbortController.current = undefined;\r\n\t\t}\r\n\t});\r\n\r\n\tuseIsomorphicLayoutEffect(() => {\r\n\t\tupdate();\r\n\t\thasMounted.current = true;\r\n\t}, [update, items]);\r\n\r\n\tuseEffect(() => {\r\n\t\treturn () => {\r\n\t\t\thasMounted.current = false;\r\n\t\t};\r\n\t}, []);\r\n\r\n\treturn renderedItems;\r\n};\r\n", "export const binarySearch = <TItem, TValue extends TItem = TItem>(\r\n\tarray: TItem[],\r\n\tvalue: TValue,\r\n\tcomparator: (a: TValue, b: { value: TItem; index: number }) => number,\r\n): number => {\r\n\tlet low = 0;\r\n\tlet high = array.length;\r\n\r\n\tif (high === 0) {\r\n\t\treturn 0;\r\n\t}\r\n\r\n\twhile (low < high) {\r\n\t\tconst middle = Math.floor((low + high) / 2);\r\n\r\n\t\tif (comparator(value, { value: array[middle], index: middle }) > 0) {\r\n\t\t\tlow = middle + 1;\r\n\t\t} else {\r\n\t\t\thigh = middle;\r\n\t\t}\r\n\t}\r\n\r\n\treturn high;\r\n};\r\n", "import { useCallback, useRef } from 'react';\r\n\r\nexport const useIdGenerator = (): (() => string) => {\r\n\tconst counter = useRef(0);\r\n\r\n\treturn useCallback(() => `:rchat:-${++counter.current}`, []);\r\n};\r\n", "import { useEvent } from '../internal/useEvent';\r\n\r\nexport type UseVisibleFrameConfig<TValue> = {\r\n\titems: TValue[];\r\n\tgetKey: (item: TValue) => string;\r\n\tonVisibleFrameUpdated: (frame: Frame) => void;\r\n};\r\n\r\nexport type Frame = {\r\n\tbegin: number;\r\n\tend: number;\r\n};\r\n\r\nexport const useVisibleFrame = <TValue,>({\r\n\titems,\r\n\tgetKey,\r\n\tonVisibleFrameUpdated,\r\n}: UseVisibleFrameConfig<TValue>): ((keys: Set<string>) => void) => {\r\n\tconst updateVisibleFrame = useEvent((visibleItemKeys: Set<string>) => {\r\n\t\tlet begin = -1;\r\n\t\tfor (const [index, item] of items.entries()) {\r\n\t\t\tif (visibleItemKeys.has(getKey(item))) {\r\n\t\t\t\tbegin = index;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlet end = -1;\r\n\t\tfor (let index = 0; index <= items.length; ++index) {\r\n\t\t\tconst item = items.at(-index - 1);\r\n\t\t\tif (item && visibleItemKeys.has(getKey(item))) {\r\n\t\t\t\tend = index;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tonVisibleFrameUpdated({ begin, end });\r\n\t});\r\n\r\n\treturn updateVisibleFrame;\r\n};\r\n", "import { RefObject, useEffect, useState, MutableRefObject, useRef } from 'react';\r\nimport { useEvent } from '../internal/useEvent';\r\n\r\nexport type VisibleItemsBag = {\r\n\tobserver: IntersectionObserver | undefined;\r\n\tvisibleItemKeys: MutableRefObject<Set<string>>;\r\n};\r\n\r\nexport const useVisibleItems = (\r\n\tcontainerReference: RefObject<HTMLElement>,\r\n\tonVisibleItemsChange?: (items: Set<string>) => void,\r\n): VisibleItemsBag => {\r\n\tconst [observer, setObserver] = useState<IntersectionObserver>();\r\n\tconst visibleItemKeysReference = useRef(new Set<string>());\r\n\r\n\tconst updateVisibleFrame = useEvent((entries: IntersectionObserverEntry[]) => {\r\n\t\tfor (const { target, isIntersecting } of entries) {\r\n\t\t\tconst key = (target as HTMLElement).dataset.key;\r\n\r\n\t\t\tif (!key) {\r\n\t\t\t\t// eslint-disable-next-line no-console\r\n\t\t\t\tconsole.warn('Item component doesn\\'t have \"data-key\" attribute.');\r\n\t\t\t} else if (isIntersecting) {\r\n\t\t\t\tvisibleItemKeysReference.current.add(key);\r\n\t\t\t} else {\r\n\t\t\t\tvisibleItemKeysReference.current.delete(key);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tonVisibleItemsChange?.(visibleItemKeysReference.current);\r\n\t});\r\n\r\n\tuseEffect(() => {\r\n\t\tconst containerElement = containerReference.current;\r\n\t\tif (containerElement) {\r\n\t\t\tconst observer = new IntersectionObserver(updateVisibleFrame, { root: containerElement, threshold: 0 });\r\n\r\n\t\t\tsetObserver(observer);\r\n\t\t}\r\n\t}, [containerReference, updateVisibleFrame]);\r\n\r\n\treturn { observer, visibleItemKeys: visibleItemKeysReference };\r\n};\r\n", "import { ChatClient } from '@rchat/client';\r\nimport { createSafeContext } from '@sirse-dev/safe-context';\r\nimport type { ContainerComponentProps, ItemComponentType, ItemKey, PlaceholderComponentType } from '../EndlessList';\r\nimport type { ComponentType } from 'react';\r\n\r\nexport type RChatContextType<TMessageType> = {\r\n\tclient: ChatClient<TMessageType>;\r\n\tMessageComponent: ItemComponentType<TMessageType>;\r\n\tPlaceholderComponent: PlaceholderComponentType;\r\n\tContainerComponent: ComponentType<ContainerComponentProps>;\r\n\ttriggerDistance: number;\r\n\titemKey: ItemKey<TMessageType>;\r\n\tcompareItems: (first: TMessageType, second: TMessageType) => number;\r\n};\r\n\r\nexport const RChatContext = createSafeContext<RChatContextType<unknown>>();\r\n", "import { PropsWithChildren } from 'react';\r\n\r\nimport { RChatContext, RChatContextType } from './internal/RChatContext';\r\n\r\nexport type ChatProps<TMessageType> = PropsWithChildren<RChatContextType<TMessageType>>;\r\n\r\nexport const Chat = <TMessageType,>({ children, ...context }: ChatProps<TMessageType>) => (\r\n\t<RChatContext.Provider value={{ ...(context as RChatContextType<unknown>) }}>{children}</RChatContext.Provider>\r\n);\r\n", "import { MessageFetchResult, MessageSearchResult } from '@rchat/client';\r\nimport { useSafeContext } from '@sirse-dev/safe-context';\r\nimport { EndlessList } from './EndlessList';\r\nimport { RChatContext } from './internal/RChatContext';\r\nimport { RoomContext } from './internal/RoomContext';\r\nimport { AnimationParameters } from './internal/smoothScrollToCenter';\r\nimport { useMessages } from './useMessages';\r\n\r\nexport type MessageListProps<TMessage> = {\r\n\tinitialMessagesState: MessageFetchResult<TMessage>;\r\n\tinitialSearchResult?: MessageSearchResult<TMessage>;\r\n\tjumpAnimation?: AnimationParameters;\r\n};\r\n\r\nexport const MessageList = <TMessage,>({\r\n\tjumpAnimation,\r\n\tinitialMessagesState,\r\n\tinitialSearchResult,\r\n}: MessageListProps<TMessage>) => {\r\n\tconst {\r\n\t\tclient,\r\n\t\tMessageComponent,\r\n\t\tPlaceholderComponent,\r\n\t\tContainerComponent,\r\n\t\ttriggerDistance,\r\n\t\tcompareItems,\r\n\t\titemKey,\r\n\t} = useSafeContext(RChatContext);\r\n\tconst { roomIdentifier } = useSafeContext(RoomContext);\r\n\r\n\tconst {\r\n\t\tmessages,\r\n\t\tonBottomReached,\r\n\t\tonTopReached,\r\n\t\tnoMessagesAfter,\r\n\t\tonVisibleFrameChange,\r\n\t\tcontainerReference,\r\n\t\tfocusedItem,\r\n\t} = useMessages({\r\n\t\tchatClient: client,\r\n\t\tadditionalChunkSize: 20,\r\n\t\tmaxChunkSize: 100,\r\n\t\troomIdentifier,\r\n\t\tcompareItems,\r\n\t\tinitialMessagesState,\r\n\t\tinitialSearchResult,\r\n\t});\r\n\r\n\treturn (\r\n\t\t<EndlessList\r\n\t\t\tinitialItems={initialMessagesState.messages}\r\n\t\t\titems={messages}\r\n\t\t\tonTopReached={onTopReached}\r\n\t\t\tonBottomReached={onBottomReached}\r\n\t\t\ttriggerDistance={triggerDistance}\r\n\t\t\tContainerComponent={ContainerComponent}\r\n\t\t\tItemComponent={MessageComponent}\r\n\t\t\tPlaceholderComponent={PlaceholderComponent}\r\n\t\t\tcompareItems={compareItems}\r\n\t\t\titemKey={itemKey}\r\n\t\t\tonVisibleFrameChange={onVisibleFrameChange}\r\n\t\t\tcanStickToBottom={noMessagesAfter}\r\n\t\t\tcontainerReference={containerReference}\r\n\t\t\tfocusedItem={focusedItem}\r\n\t\t\tjumpAnimation={jumpAnimation}\r\n\t\t/>\r\n\t);\r\n};\r\n", "import { createSafeContext } from '@sirse-dev/safe-context';\r\n\r\nexport type RoomContextType = {\r\n\troomIdentifier: string;\r\n};\r\n\r\nexport const RoomContext = createSafeContext<RoomContextType>();\r\n", "import { MessageFetchResult, MessageSearchResult } from '@rchat/client';\r\nimport { ChatClient } from '@rchat/client';\r\nimport { Ref, useCallback, useEffect, useRef } from 'react';\r\nimport { Frame } from './EndlessList/useVisibleFrame';\r\nimport { clamp } from './internal/clamp';\r\nimport { KeepDirection, useBoundedArray } from './internal/useBoundedArray';\r\nimport { useEvent } from './internal/useEvent';\r\n\r\nexport type UseMessagesBag<T> = {\r\n\tmessages: T[];\r\n\tonTopReached: () => void;\r\n\tonBottomReached: () => void;\r\n\tnoMessagesBefore: boolean;\r\n\tnoMessagesAfter: boolean;\r\n\tonVisibleFrameChange: (frame: Frame) => void;\r\n\tcontainerReference: Ref<HTMLElement>;\r\n\tfocusedItem?: T;\r\n};\r\n\r\nexport type UseMessagesConfig<T> = {\r\n\tinitialMessagesState: MessageFetchResult<T>;\r\n\tinitialSearchResult?: MessageSearchResult<T>;\r\n\tcompareItems: (a: T, b: T) => number;\r\n\tmaxChunkSize: number;\r\n\tadditionalChunkSize: number;\r\n\tchatClient: ChatClient<T>;\r\n\troomIdentifier: string;\r\n};\r\n\r\n// TODO: replace with binary search\r\nconst findNewElementIndex = <T,>(elements: readonly T[], element: T, compare: (a: T, b: T) => number): number => {\r\n\treturn (\r\n\t\telements.length -\r\n\t\t1 -\r\n\t\t[...elements].reverse().findIndex((a) => {\r\n\t\t\treturn compare(element, a) > 0;\r\n\t\t})\r\n\t);\r\n};\r\n\r\nexport const useMessages = <TMessage,>({\r\n\tmaxChunkSize,\r\n\tadditionalChunkSize,\r\n\tchatClient,\r\n\troomIdentifier,\r\n\tcompareItems,\r\n\tinitialMessagesState,\r\n\tinitialSearchResult,\r\n}: UseMessagesConfig<TMessage>): UseMessagesBag<TMessage> => {\r\n\tconst isFetching = useRef(false);\r\n\tconst visibleFrame = useRef<Frame>({ begin: -1, end: -1 });\r\n\tconst containerReference = useRef<HTMLElement>(null);\r\n\tconst searchResults = useRef<MessageSearchResult<TMessage> | undefined>(initialSearchResult);\r\n\tconst selectedSearchResult = useRef(0);\r\n\tconst focusedItem = useRef<TMessage | undefined>(initialSearchResult?.results[0]);\r\n\r\n\tconst [\r\n\t\tmessages,\r\n\t\t{\r\n\t\t\tpush: pushMessages,\r\n\t\t\tunshift: unshiftMessages,\r\n\t\t\tset: setMessages,\r\n\t\t\tinsert: insertMessage,\r\n\t\t\tat: getMessage,\r\n\t\t\tgetAll: getAllMessages,\r\n\t\t\trefresh,\r\n\t\t},\r\n\t] = useBoundedArray<TMessage>([...initialMessagesState.messages], maxChunkSize);\r\n\r\n\tconst messagesState = useRef<Omit<MessageFetchResult<TMessage>, 'messages'>>(initialMessagesState);\r\n\r\n\tconst handleIncomingMessage = useCallback(\r\n\t\t(message: TMessage, messageRoomIdentifier: string) => {\r\n\t\t\tif (messageRoomIdentifier === roomIdentifier && messagesState.current.noMessagesAfter) {\r\n\t\t\t\tconst incomingMessageIndex = findNewElementIndex(getAllMessages(), message, compareItems);\r\n\r\n\t\t\t\tconst keepDirection: KeepDirection =\r\n\t\t\t\t\tvisibleFrame.current.begin < visibleFrame.current.end ? 'beginning' : 'ending';\r\n\r\n\t\t\t\tconst clipped = insertMessage(message, incomingMessageIndex + 1, keepDirection);\r\n\r\n\t\t\t\tif (clipped) {\r\n\t\t\t\t\tif (keepDirection === 'beginning') {\r\n\t\t\t\t\t\tmessagesState.current.noMessagesAfter = false;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tmessagesState.current.noMessagesBefore = false;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t},\r\n\t\t[roomIdentifier, getAllMessages, compareItems, insertMessage],\r\n\t);\r\n\r\n\tconst focusItem = useCallback(\r\n\t\tasync (item: TMessage | undefined) => {\r\n\t\t\tif (!item) {\r\n\t\t\t\tif (focusedItem.current) {\r\n\t\t\t\t\trefresh();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfocusedItem.current = item;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tfocusedItem.current = item;\r\n\r\n\t\t\tconst [previousChunk, nextChunk] = await Promise.all([\r\n\t\t\t\tchatClient.fetchMessages(roomIdentifier, additionalChunkSize, item, undefined),\r\n\t\t\t\tchatClient.fetchMessages(roomIdentifier, additionalChunkSize, undefined, item),\r\n\t\t\t]);\r\n\r\n\t\t\tmessagesState.current = {\r\n\t\t\t\tnoMessagesBefore: previousChunk.noMessagesBefore,\r\n\t\t\t\tnoMessagesAfter: nextChunk.noMessagesAfter,\r\n\t\t\t};\r\n\r\n\t\t\tsetMessages([...previousChunk.messages, item, ...nextChunk.messages], 'beginning');\r\n\t\t},\r\n\t\t[additionalChunkSize, chatClient, roomIdentifier, setMessages, refresh],\r\n\t);\r\n\r\n\tconst handleSearch = useCallback(\r\n\t\t(searchRoomIdentifier: string, searchResult: MessageSearchResult<TMessage>, focusIndex: number) => {\r\n\t\t\tif (searchRoomIdentifier === roomIdentifier) {\r\n\t\t\t\tsearchResults.current = searchResult;\r\n\t\t\t\tfocusIndex = Math.min(focusIndex, searchResult.results.length - 1);\r\n\t\t\t\tselectedSearchResult.current = focusIndex;\r\n\t\t\t\tfocusItem(searchResult.results[focusIndex]);\r\n\t\t\t}\r\n\t\t},\r\n\t\t[focusItem, roomIdentifier],\r\n\t);\r\n\r\n\tconst handlePreviousSearchResult = useCallback(\r\n\t\t(searchRoomIdentifier: string) => {\r\n\t\t\tif (searchResults.current && searchRoomIdentifier === roomIdentifier) {\r\n\t\t\t\tselectedSearchResult.current = clamp(\r\n\t\t\t\t\tselectedSearchResult.current - 1,\r\n\t\t\t\t\t0,\r\n\t\t\t\t\tMath.max(searchResults.current.results.length - 1, 0),\r\n\t\t\t\t);\r\n\t\t\t\tfocusItem(searchResults.current.results[selectedSearchResult.current]);\r\n\t\t\t}\r\n\t\t},\r\n\t\t[focusItem, roomIdentifier],\r\n\t);\r\n\r\n\tconst handleNextSearchResult = useCallback(\r\n\t\t(searchRoomIdentifier: string) => {\r\n\t\t\tif (searchResults.current && searchRoomIdentifier === roomIdentifier) {\r\n\t\t\t\tselectedSearchResult.current = clamp(\r\n\t\t\t\t\tselectedSearchResult.current + 1,\r\n\t\t\t\t\t0,\r\n\t\t\t\t\tMath.max(searchResults.current.results.length - 1, 0),\r\n\t\t\t\t);\r\n\t\t\t\tfocusItem(searchResults.current.results[selectedSearchResult.current]);\r\n\t\t\t}\r\n\t\t},\r\n\t\t[focusItem, roomIdentifier],\r\n\t);\r\n\r\n\tuseEffect(() => {\r\n\t\tchatClient.addEventListener('receiveMessage', handleIncomingMessage);\r\n\t\tchatClient.addEventListener('receiveSearchResults', handleSearch);\r\n\t\tchatClient.addEventListener('nextSearchResult', handleNextSearchResult);\r\n\t\tchatClient.addEventListener('previousSearchResult', handlePreviousSearchResult);\r\n\r\n\t\treturn () => {\r\n\t\t\tchatClient.removeEventListener('receiveMessage', handleIncomingMessage);\r\n\t\t\tchatClient.removeEventListener('receiveSearchResults', handleSearch);\r\n\t\t\tchatClient.removeEventListener('nextSearchResult', handleNextSearchResult);\r\n\t\t\tchatClient.removeEventListener('previousSearchResult', handlePreviousSearchResult);\r\n\t\t};\r\n\t}, [chatClient, handleIncomingMessage, handleNextSearchResult, handlePreviousSearchResult, handleSearch]);\r\n\r\n\t// Scroll to bottom if there was no initial search\r\n\tuseEffect(() => {\r\n\t\tif (!initialSearchResult) {\r\n\t\t\tconst container = containerReference.current;\r\n\t\t\tif (container) {\r\n\t\t\t\tcontainer.scrollTo({ top: container.scrollHeight });\r\n\t\t\t} else {\r\n\t\t\t\t// eslint-disable-next-line no-console\r\n\t\t\t\tconsole.warn(\r\n\t\t\t\t\t\"RChat: container reference wasn't passed into EndlessList,\" +\r\n\t\t\t\t\t\t' so scrolling to the bottom after initial chat load failed.' +\r\n\t\t\t\t\t\t' This may cause inconsistent behavior',\r\n\t\t\t\t);\r\n\t\t\t}\r\n\t\t}\r\n\t}, [initialSearchResult]);\r\n\r\n\tuseEffect(() => {\r\n\t\tsetMessages([...initialMessagesState.messages], 'beginning');\r\n\t\tmessagesState.current = initialMessagesState;\r\n\t}, [initialMessagesState, setMessages]);\r\n\r\n\tuseEffect(() => {\r\n\t\tsearchResults.current = initialSearchResult;\r\n\t\tfocusedItem.current = initialSearchResult?.results[0];\r\n\t}, [initialSearchResult]);\r\n\r\n\tconst handleTopReached = useEvent(async () => {\r\n\t\tif (messagesState.current.noMessagesBefore || isFetching.current) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tisFetching.current = true;\r\n\t\tconst { messages: fetchedMessages, noMessagesBefore } = await chatClient.fetchMessages(\r\n\t\t\troomIdentifier,\r\n\t\t\tadditionalChunkSize,\r\n\t\t\tgetMessage(0),\r\n\t\t\tundefined,\r\n\t\t);\r\n\r\n\t\tconst clipped = unshiftMessages(fetchedMessages);\r\n\r\n\t\tconst newState = {\r\n\t\t\tnoMessagesBefore,\r\n\t\t\tnoMessagesAfter: !clipped && messagesState.current.noMessagesAfter,\r\n\t\t};\r\n\t\tmessagesState.current = newState;\r\n\t\tisFetching.current = false;\r\n\t});\r\n\r\n\tconst handleBottomReached = useEvent(async () => {\r\n\t\tif (messagesState.current.noMessagesAfter || isFetching.current) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tisFetching.current = true;\r\n\t\tconst { messages: fetchedMessages, noMessagesAfter } = await chatClient.fetchMessages(\r\n\t\t\troomIdentifier,\r\n\t\t\tadditionalChunkSize,\r\n\t\t\tundefined,\r\n\t\t\tgetMessage(-1),\r\n\t\t);\r\n\r\n\t\tconst clipped = pushMessages(fetchedMessages);\r\n\t\tconst newState = {\r\n\t\t\tnoMessagesAfter,\r\n\t\t\tnoMessagesBefore: !clipped && messagesState.current.noMessagesBefore,\r\n\t\t};\r\n\r\n\t\tmessagesState.current = newState;\r\n\t\tisFetching.current = false;\r\n\t});\r\n\r\n\tconst onVisibleFrameChange = (frame: Frame) => {\r\n\t\tvisibleFrame.current = frame;\r\n\t};\r\n\r\n\treturn {\r\n\t\tmessages,\r\n\t\tonTopReached: handleTopReached,\r\n\t\tonBottomReached: handleBottomReached,\r\n\t\tnoMessagesBefore: messagesState.current.noMessagesBefore,\r\n\t\tnoMessagesAfter: messagesState.current.noMessagesAfter,\r\n\t\tonVisibleFrameChange,\r\n\t\tcontainerReference,\r\n\t\tfocusedItem: focusedItem.current,\r\n\t};\r\n};\r\n", "export const clamp = (value: number, min: number, max: number) => Math.max(Math.min(value, max), min);\r\n", "import { useCallback, useRef, useState } from 'react';\r\n\r\nexport type KeepDirection = 'beginning' | 'ending';\r\n\r\nexport type BoundedArrayControl<T> = {\r\n\t/**\r\n\t * Add elements to the end of the array.\r\n\t * Clips array by specified \"maxSize\".\r\n\t * Ensures, that last item won't be clipped.\r\n\t */\r\n\tpush: (items: T[]) => boolean;\r\n\t/**\r\n\t * Add elements to the beginning of the array.\r\n\t * Clips array by specified \"maxSize\".\r\n\t * Ensures, that first item won't be clipped.\r\n\t */\r\n\tunshift: (items: T[]) => boolean;\r\n\t/**\r\n\t * Set all elements to the array.\r\n\t * Clips array by specified \"maxSize\".\r\n\t * Keeps elements according to \"keep\" argument's value:\r\n\t * beginning - array will be clipped from the end.\r\n\t * ending - array will be clipped from the beginning.\r\n\t */\r\n\tset: (items: T[], keep: KeepDirection) => boolean;\r\n\r\n\tinsert: (item: T, index: number, keep: KeepDirection) => boolean;\r\n\t/**\r\n\t * Works exactly like \"Array.prototype.at\".\r\n\t */\r\n\tat: (index: number) => T | undefined;\r\n\t/**\r\n\t * Returns reference to current array.\r\n\t */\r\n\tgetAll: () => readonly T[];\r\n\t/**\r\n\t * Sets state to the old one in order to rerender.\r\n\t */\r\n\trefresh: () => void;\r\n};\r\n\r\nconst getClippedArray = <T,>(items: T[], maxSize: number, keep: KeepDirection) => {\r\n\tif (items.length <= maxSize) {\r\n\t\treturn items;\r\n\t}\r\n\r\n\tif (keep === 'beginning') {\r\n\t\treturn items.slice(0, maxSize);\r\n\t}\r\n\r\n\tif (keep === 'ending') {\r\n\t\treturn items.slice(-maxSize);\r\n\t}\r\n\r\n\tthrow new Error(`Unrecognized \"keep\" option value: \"${keep}\"`);\r\n};\r\n\r\nexport const useBoundedArray = <T,>(\r\n\tinitial: T[],\r\n\tmaxChunkSize: number,\r\n): [items: T[], control: BoundedArrayControl<T>] => {\r\n\tconst [itemsState, setItemsState] = useState(initial);\r\n\tconst itemsReference = useRef(initial);\r\n\r\n\tconst setItems = useCallback(\r\n\t\t(items: T[], keep: KeepDirection) => {\r\n\t\t\tconst clippedItems = getClippedArray(items, maxChunkSize, keep);\r\n\t\t\tsetItemsState(clippedItems);\r\n\t\t\titemsReference.current = clippedItems;\r\n\r\n\t\t\treturn items.length > clippedItems.length;\r\n\t\t},\r\n\t\t[maxChunkSize],\r\n\t);\r\n\r\n\tconst unshift = useCallback(\r\n\t\t(items: T[]) => {\r\n\t\t\treturn setItems([...items, ...itemsReference.current], 'beginning');\r\n\t\t},\r\n\t\t[setItems],\r\n\t);\r\n\r\n\tconst push = useCallback(\r\n\t\t(items: T[]) => {\r\n\t\t\treturn setItems([...itemsReference.current, ...items], 'ending');\r\n\t\t},\r\n\t\t[setItems],\r\n\t);\r\n\r\n\tconst at = useCallback((index: number) => {\r\n\t\treturn itemsReference.current.at(index);\r\n\t}, []);\r\n\r\n\tconst insert = useCallback(\r\n\t\t(item: T, index: number, keep: KeepDirection) => {\r\n\t\t\titemsReference.current.splice(index, 0, item);\r\n\t\t\treturn setItems([...itemsReference.current], keep);\r\n\t\t},\r\n\t\t[setItems],\r\n\t);\r\n\r\n\tconst getAll = useCallback(() => itemsReference.current, []);\r\n\r\n\tconst refresh = useCallback(() => setItemsState((old) => [...old]), []);\r\n\r\n\treturn [itemsState, { push, unshift, set: setItems, at, getAll, insert, refresh }];\r\n};\r\n", "import { PropsWithChildren } from 'react';\r\nimport { RoomContext } from './internal/RoomContext';\r\n\r\nexport type RoomProps = PropsWithChildren<{\r\n\tidentifier: string;\r\n}>;\r\n\r\nexport const Room = ({ identifier, children }: RoomProps) => {\r\n\treturn <RoomContext.Provider value={{ roomIdentifier: identifier }}>{children}</RoomContext.Provider>;\r\n};\r\n"], | ||
| "mappings": "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", | ||
| "names": ["useCallback", "useEffect", "useLayoutEffect", "useMemo", "useRef", "useCallback", "useRef", "useRef", "useCallback", "useCallback", "useRef", "useRef", "useCallback", "useRef", "useRef", "useRef", "useEffect", "useCallback", "useRef", "useRef", "useCallback", "useRef", "useEffect", "useEffect", "useState", "useRef", "useState", "useRef", "useEffect", "observer", "useRef", "useMemo", "useEffect", "useCallback", "useLayoutEffect", "createSafeContext", "useCallback", "useEffect", "useRef", "useCallback", "useRef", "useState", "useState", "useRef", "useCallback", "useRef", "useCallback", "useEffect"] | ||
| } |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
1
-50%2
-66.67%98634
-73.68%80
-9.09%2297
-46.19%1
Infinity%