UNPKG

flash-section-list

Version:
297 lines (296 loc) 13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FlashSectionListBuilder = FlashSectionListBuilder; exports.default = void 0; var _flashList = require("@shopify/flash-list"); var _react = _interopRequireWildcard(require("react")); var _utils = require("./utils.js"); var _reactNative = require("react-native"); var _useDummy = require("./useDummy.js"); var _Dummy = _interopRequireDefault(require("./Dummy.js")); var _LayoutManager = _interopRequireDefault(require("./LayoutManager.js")); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } const methodNames = ['prepareForLayoutAnimationRender', 'recordInteraction', 'recomputeViewableItems', 'scrollToEnd', 'scrollToIndex', 'scrollToItem', 'scrollToOffset']; const isElementSection = section => { return /*#__PURE__*/_react.default.isValidElement(section.element); }; const convertDataSectionFrom = section => { return { data: [0], renderItem: () => { return section.element; }, stickyHeaderIndices: section.sticky ? [0] : undefined, type: section.type }; }; const flex1 = { flex: 1 }; const omitProps = ['data', 'renderItem', 'getItemType', 'getItemLayout', 'overrideItemLayout', 'stickyHeaderIndices', 'ListHeaderComponent', 'ListHeaderComponentStyle', 'ListFooterComponent', 'ListFooterComponentStyle', 'numOfColumns']; function FlashSectionListBuilder() { const buildProps = { FlashListComponent: _flashList.FlashList, DummyClass: _Dummy.default, LayoutManagerClass: _LayoutManager.default }; return { build: () => { const FlashListComponent = buildProps.FlashListComponent; const DummyClass = buildProps.DummyClass; const LayoutManagerClass = buildProps.LayoutManagerClass; function FlashSectionList(propsOrigin, ref) { const flashlist = (0, _react.useRef)(null); const [containerWidth, setContainerWidth] = (0, _react.useState)(undefined); let { sections, ...props } = propsOrigin; props = (0, _utils.omit)(propsOrigin, omitProps, false); const contentContainerPaddingHorizontal = (0, _react.useMemo)(() => { const paddingHorizontal = (0, _utils.findFirstProp)(props.contentContainerStyle, ['paddingHorizontal', 'paddingLeft']); return typeof paddingHorizontal === 'number' ? paddingHorizontal * 2 : 0; }, [props.contentContainerStyle]); const Dummy = (0, _useDummy.useDummy)({ horizontal: props.horizontal, DummyClass, LayoutManagerClass }); const { dataSections, sectionStartIndices, serializedData, stickyHeaderIndices, numOfColumns } = (0, _react.useMemo)(() => { const dataSections = []; const numOfColumnArray = []; const stickyHeaderIndices = []; let index = 0; const sectionStartIndices = []; const serializedData = sections.reduce((acc, cur) => { const section = isElementSection(cur) ? convertDataSectionFrom(cur) : cur; dataSections.push(section); const { data, header, footer, stickyHeaderIndices: stickyHeaderIndicesOfSection, numOfColumns = 1 } = section; let length = data.length; sectionStartIndices.push(index); numOfColumnArray.push(numOfColumns); if (header) { if (header.sticky) { stickyHeaderIndices.push(index); } length += 1; acc.push(header); } acc.push(...data); if (stickyHeaderIndicesOfSection) { stickyHeaderIndices.push(...stickyHeaderIndicesOfSection.map(indexWithinSection => indexWithinSection + index + (header ? 1 : 0))); } const dummyCount = data.length % numOfColumns !== 0 ? numOfColumns - data.length % numOfColumns : 0; length += dummyCount; section.dummyCount = dummyCount; for (let i = 0; i < dummyCount; i++) { acc.push(Dummy); } if (footer) { if (footer.sticky) { stickyHeaderIndices.push(index + length); } length += 1; acc.push(footer); } index += length; return acc; }, []); return { dataSections, sectionStartIndices, serializedData, stickyHeaderIndices, numOfColumns: (0, _utils.lcm)(numOfColumnArray) }; }, [Dummy, sections]); (0, _react.useImperativeHandle)(ref, () => { const mothods = methodNames.reduce((acc, cur) => { acc[cur] = (...props) => { flashlist.current?.[cur](...props); }; return acc; }, {}); return { ...flashlist.current, ...mothods, scrollToSection: params => { if (!Array.isArray(sectionStartIndices) || sectionStartIndices.length === 0) { return; } const index = sectionStartIndices[params.sectionIndex]; if (index === undefined) { return; } flashlist.current?.scrollToIndex?.({ ...params, index }); } }; }, [sectionStartIndices]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(FlashListComponent, { ...props, ref: flashlist, onLayout: !props.horizontal ? e => { setContainerWidth(e.nativeEvent?.layout?.width); props.onLayout?.(e); } : props.onLayout, data: serializedData, stickyHeaderIndices: stickyHeaderIndices, numColumns: numOfColumns, renderItem: ({ index, item, ...etc }) => { const sectionIndex = (0, _utils.binarySearchClosestIndex)(sectionStartIndices, index); const section = dataSections[sectionIndex]; const sectionStartIndex = sectionStartIndices[sectionIndex]; if (!section || sectionStartIndex === undefined) { return null; } const headerOffset = section.header ? 1 : 0; const dataLastIndex = section.data.length - 1; const localIndex = index - sectionStartIndex - headerOffset; if (item === Dummy) { const isLastDummy = localIndex === dataLastIndex + (section.dummyCount ?? 0); return /*#__PURE__*/(0, _jsxRuntime.jsx)(Dummy.View, { sectionIndex: sectionIndex, disabled: !isLastDummy }); } const isHeader = section.header && index === sectionStartIndex; if (isHeader) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: flex1, children: section.header.element }); } const isFooter = section.footer && index === sectionStartIndex + section.data.length + headerOffset + (section.dummyCount ?? 0); if (isFooter) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { style: flex1, children: section.footer.element }); } let style; if (section.gap && containerWidth) { const sectionNumOfColumns = section.numOfColumns ?? 1; const numOfRows = Math.floor((section.data.length - 1) / (section.numOfColumns ?? 1)); const includeEdge = !(typeof section.gap === 'number') && !!section.gap.includeEdge; const gap = typeof section.gap === 'number' ? section.gap : section.gap.size; const numOfGaps = includeEdge ? sectionNumOfColumns + 1 : sectionNumOfColumns - 1; const itemWidth = (containerWidth - contentContainerPaddingHorizontal - numOfGaps * gap) / sectionNumOfColumns; style = { width: itemWidth }; const indexInRow = localIndex % sectionNumOfColumns; style.marginLeft = includeEdge ? gap - gap * indexInRow / sectionNumOfColumns : gap * indexInRow / sectionNumOfColumns; if (numOfRows > 0) { const isLastRow = Math.floor(localIndex / sectionNumOfColumns) === numOfRows; if (!isLastRow) { style.marginBottom = gap; } } } else if (numOfColumns > 1) { style = flex1; } return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { onLayout: e => { const layout = e.nativeEvent?.layout; if (!layout) return; const { width, height } = layout; if (!width && !height) return; Dummy.emitSize(sectionIndex, localIndex, { width, height }); }, style: style, children: section.renderItem({ index: localIndex, item, ...etc }) }); }, getItemType: (item, index) => { const sectionIndex = (0, _utils.binarySearchClosestIndex)(sectionStartIndices, index); const section = dataSections[sectionIndex]; const sectionStartIndex = sectionStartIndices[sectionIndex]; if (!section || sectionStartIndex === undefined) { return -1; } if (item === Dummy) { return Dummy.type; } const headerOffset = section.header ? 1 : 0; const isHeader = section.header && index === sectionStartIndex; if (isHeader) { return section.header.type ?? `header-${sectionIndex}`; } const isFooter = section.footer && index === sectionStartIndex + section.data.length + headerOffset + (section.dummyCount ?? 0); if (isFooter) { return section.footer.type ?? `footer-${sectionIndex}`; } return section.type ?? sectionIndex; }, overrideItemLayout: (layout, _, index) => { const sectionIndex = (0, _utils.binarySearchClosestIndex)(sectionStartIndices, index); const section = dataSections[sectionIndex]; const sectionStartIndex = sectionStartIndices[sectionIndex]; if (!section || sectionStartIndex === undefined) { return; } const headerOffset = section.header ? 1 : 0; const isHeader = section.header && index === sectionStartIndex; const isFooter = section.footer && index === sectionStartIndex + section.data.length + headerOffset + (section.dummyCount ?? 0); if (isHeader) { layout.span = numOfColumns; layout.size = section.header.size; } else if (isFooter) { layout.span = numOfColumns; layout.size = section.footer.size; } else { layout.span = section.numOfColumns ? numOfColumns / section.numOfColumns : numOfColumns; layout.size = section.itemSize; } } }); } return /*#__PURE__*/_react.default.forwardRef(FlashSectionList); }, setFlashList: FlashListComponent => { buildProps.FlashListComponent = FlashListComponent; }, setDummy: DummyClass => { buildProps.DummyClass = DummyClass; }, setLayoutManager: LayoutManagerClass => { buildProps.LayoutManagerClass = LayoutManagerClass; } }; } var _default = exports.default = FlashSectionListBuilder().build(); //# sourceMappingURL=FlashSectionList.js.map