UNPKG

@adobe/uxp-optimized

Version:

Library of react components optimized for Adobe's Unified Extensibility Platform

178 lines (176 loc) 7.94 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* Copyright 2019 Adobe All Rights Reserved. NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms of the Adobe license agreement accompanying it. If you have received this file from a source other than Adobe, then your use, modification, or distribution of it requires the prior written permission of Adobe. */ const react_1 = __importStar(require("react")); const VirtualManager_1 = __importDefault(require("./VirtualManager")); const memoize_1 = __importDefault(require("../common/memoize")); require("../common/shims"); function createPropertyGetter(property, defaultValue, validator) { if (property == null) { return typeof defaultValue === "function" ? defaultValue() : undefined; } if (typeof property === "function") { return (item) => { const result = property(item); if (validator) { validator(result, item); } return result; }; } if (typeof property === "string" || typeof property === "symbol") { return (item) => item[property]; } throw new Error(`Unsupported property: ${String(property)}`); } exports.default = (0, react_1.forwardRef)(function Virtualizer(properties, ref) { let { items, itemKey, itemType, itemRect, scrollToItem, onLayout, cacheElements = true, style, children: factory, ...otherProps } = properties; let horizontal = properties.direction === "horizontal"; const itemKeyFunction = (0, react_1.useMemo)(() => (0, memoize_1.default)(createPropertyGetter(itemKey, () => { // if user provides no key property/function // then we use the item index as key const itemToIndex = new Map(items.map((item, index) => [item, String(index)])); return (item) => itemToIndex.get(item); }, (value, item) => { if (typeof value !== 'string' || value.length === 0) { throw new Error(`Invalid key, expected a unique string, actual: (${JSON.stringify(value || null)}) for item: ${JSON.stringify(item)}`); } })), [itemKey, items]); const itemTypeFunction = (0, react_1.useMemo)(() => (0, memoize_1.default)(createPropertyGetter(itemType, () => () => "default")), [itemType, items]); const itemRectFunction = (0, react_1.useMemo)(() => createPropertyGetter(itemRect), [itemRect, items]); let [renderKeys, setRenderKeys] = (0, react_1.useState)(new Array()); // we use a ref so we can persist the manager between calls to this component function. const cache = (0, react_1.useRef)(); if (cache.current == null) { cache.current = {}; } function scrollByFunction(x, y) { const container = cache.current.container; // x is ignored, since we only scroll vertically if (container && y) { // Would be cleaner to use container.scrollBy, but UXP doesn't support this // Instead, we need to compute the scrollTop to set based on the passed in offset const clientHeight = container.clientHeight; const scrollHeight = container.scrollHeight; const maxScrollTop = Math.max(0, scrollHeight - clientHeight); const scrollTop = Math.max(0, Math.min(maxScrollTop, container.scrollTop + y)); container.scrollTo({ top: scrollTop }); } } function scrollToItemFunction(key, options) { let container = cache.current.container; if (container) { let manager = VirtualManager_1.default.instance(container); manager === null || manager === void 0 ? void 0 : manager.scrollToItem(key, options); } } function getManager() { var _a; let container = (_a = cache.current) === null || _a === void 0 ? void 0 : _a.container; return container ? VirtualManager_1.default.instance(container) : null; } function getRenderKeys() { return renderKeys; } function getItemRect(key) { let manager = getManager(); if (manager) { let rect = manager.getItemRect(null, key); if (rect) { // we remove just the properties we want since the manager stores extra information // on the rect structure. let { x, y, width, height } = rect; return { x, y, width, height }; } } return { x: 0, y: 0, width: 0, height: 0 }; } function getVisibleRect() { var _a; return ((_a = getManager()) === null || _a === void 0 ? void 0 : _a.getVisibleRect()) || { x: 0, y: 0, width: 0, height: 0 }; } (0, react_1.useImperativeHandle)(ref, () => ({ scrollToItem: scrollToItemFunction, scrollBy: scrollByFunction, getRenderKeys, getItemRect, getVisibleRect, container: cache.current.container, }), [cache.current.container]); function setContainer(container) { if (container) { cache.current.container = container; // we also update the renderKeys immediately // this matters for future renders where // we are calling setContainer with the cached container // we want the correct renderKeys BEFORE we hit this functions element declaration. renderKeys = VirtualManager_1.default.update({ container, horizontal, items, renderKeys, setRenderKeys, itemKey: itemKeyFunction, itemType: itemTypeFunction, itemRect: itemRectFunction, onLayout, }); // if we have a scrollToItem then we scroll to it now. if (scrollToItem) { scrollToItemFunction(scrollToItem); } } } // There is a delay between future renders and calling setContainer. // if we know the Container already, we call setContainer now if (cache.current.container) { setContainer(cache.current.container); } style = Object.assign({ position: "relative", overflowX: horizontal ? "scroll" : "hidden", overflowY: horizontal ? "hidden" : "scroll", flex: "1 1 auto", zIndex: 0 }, style); return (react_1.default.createElement("div", { ref: setContainer, style: style, ...otherProps }, VirtualManager_1.default.getReactElements(items, renderKeys, itemKeyFunction, itemTypeFunction, factory, // if we aren't caching elements then we return a new cache object each time // which effectively disables caching cacheElements ? cache.current : {}))); });