@adobe/uxp-optimized
Version:
Library of react components optimized for Adobe's Unified Extensibility Platform
178 lines (176 loc) • 7.94 kB
JavaScript
;
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 : {})));
});