UNPKG

react-native-indicate

Version:

Enhanced ScrollView with elements indicating scrollable overflow.

243 lines (237 loc) 7.6 kB
// index.tsx import React2, { useState } from "react"; import { ScrollView, SafeAreaView } from "react-native"; // direction.ts var getDirectionFromBoolean = (horizontal, vertical) => { if (typeof horizontal === "undefined" && typeof vertical === "undefined") { return "both"; } if (horizontal && vertical) { return "both"; } if (vertical) { return "vertical"; } return "horizontal"; }; // Fade.tsx import React from "react"; import { StyleSheet, View, ImageBackground } from "react-native"; // gradient.png var gradient_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAABCAYAAACc0f2yAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAxSURBVHgBlYs5DgBACALZ//9YSdjGghgtLAjhmCeJALIpymmZ1qftsbDbb9onlpfvB0nnNAIsq01NAAAAAElFTkSuQmCC"; // Fade.tsx var rotateGradient = (side) => { if (side === "right") { return "180deg"; } if (side === "top") { return "90deg"; } if (side === "bottom") { return "270deg"; } return "0deg"; }; var leftPosition = (side, view, width) => { if (side === "left") { return 0; } if (side === "top" || side === "bottom") { return view.width / 2 - width / 2; } return "auto"; }; var topPosition = (side, view, width) => { if (side === "top") { return -view.width / 2 + width / 2; } if (side === "bottom") { return -view.width / 2 - width / 2 + view.height; } return "auto"; }; var createStyles = (side, view, width) => StyleSheet.create({ fade: { position: "absolute" }, view: { left: leftPosition(side, view, width), right: side === "right" ? 0 : "auto", top: topPosition(side, view, width), height: side === "left" || side === "right" ? "100%" : view.width, width: side === "bottom" || side === "top" ? width : width }, image: { width: "100%", height: "100%" }, backgroundImage: { resizeMode: "stretch", transform: [{ rotate: rotateGradient(side) }] } }); var toImageSource = (input) => { if (typeof input === "string") { return { uri: input }; } return input; }; var Fade = ({ side, show, width, view, gradient }) => { if (!show) { return null; } const styles = createStyles(side, view, width); return /* @__PURE__ */ React.createElement(View, { pointerEvents: "none", style: [styles.fade, styles.view] }, /* @__PURE__ */ React.createElement( ImageBackground, { source: toImageSource(gradient || gradient_default), style: styles.image, imageStyle: styles.backgroundImage } )); }; // index.tsx function omit(input, fields) { const shallowCopy = Object.assign({}, input); for (let i = 0; i < fields.length; i += 1) { const key = fields[i]; delete shallowCopy[key]; } return shallowCopy; } var handleLayout = (state, event) => { const newFade = { ...state.fade }; const newView = { ...state.view }; const layout = event.nativeEvent.layout; if (state.view.width < layout.width) { newView.width = layout.width; } if (state.content.width) { newFade.right = state.content.width > state.view.width; } if (state.view.height < layout.height) { newView.height = layout.height; } if (state.content.height) { newFade.bottom = state.content.height > state.view.height; } state.setFade(newFade); state.setView(newView); }; var handleScroll = (props, state, direction, event) => { const newFade = { ...state.fade }; const offset = event.nativeEvent.contentOffset; if (direction === "horizontal" || direction === "both") { newFade.right = offset.x + state.view.width + props.appearanceOffset < state.content.width; newFade.left = offset.x > props.appearanceOffset; } if (direction === "vertical" || direction === "both") { newFade.top = offset.y > props.appearanceOffset; newFade.bottom = offset.y + state.view.height + props.appearanceOffset < state.content.height; } state.setFade(newFade); }; var handleContentSizeChange = (state, direction, width, height) => { const newContent = { ...state.content }; const newFade = { ...state.fade }; if (direction === "horizontal" || direction === "both") { newContent.width = width; if (state.view.width) { newFade.right = newContent.width > state.view.width; } } if (direction === "vertical" || direction === "both") { newContent.height = height; if (state.view.height) { newFade.bottom = newContent.height > state.view.height; } } state.setFade(newFade); state.setContent(newContent); }; var renderInnerScrollView = (viewCompatibleProps, props, state, direction) => { if (direction !== "both") { return props.children; } return /* @__PURE__ */ React2.createElement( ScrollView, { style: [props.innerViewStyle], contentContainerStyle: [props.contentContainerStyle], onContentSizeChange: (width, height) => handleContentSizeChange(state, "vertical", width, height), scrollEventThrottle: 300, onScroll: (event) => handleScroll(props, state, "vertical", event), vertical: true, ...viewCompatibleProps }, props.children ); }; var addDefaults = (props) => { const allProps = { ...props }; if (!props.appearanceOffset) { allProps.appearanceOffset = 10; } if (!props.fadeWidth) { allProps.fadeWidth = 20; } const result = allProps; return result; }; var react_native_indicate_default = (props) => { const allProps = addDefaults(props); const { horizontal, vertical, fadeWidth, gradient } = allProps; const [direction, setDirection] = useState( getDirectionFromBoolean(horizontal, vertical) ); const [fade, setFade] = useState({ top: false, right: getDirectionFromBoolean(horizontal, vertical) !== "vertical", bottom: getDirectionFromBoolean(horizontal, vertical) !== "horizontal", left: false }); const [view, setView] = useState({ width: 0, height: 0 }); const [content, setContent] = useState({ width: 0, height: 0 }); const state = { direction, setDirection, fade, setFade, view, setView, content, setContent }; const viewCompatibleProps = omit(allProps, [ "style", "contentContainerStyle", "horizontal", "vertical" ]); return /* @__PURE__ */ React2.createElement(SafeAreaView, { style: [allProps.wrapperStyle] }, /* @__PURE__ */ React2.createElement( ScrollView, { style: [allProps.style], contentContainerStyle: [allProps.contentContainerStyle], onContentSizeChange: (width, height) => handleContentSizeChange( state, direction === "both" ? "horizontal" : direction, width, height ), scrollEventThrottle: 300, onScroll: (event) => handleScroll(allProps, state, direction === "both" ? "horizontal" : direction, event), onLayout: (event) => handleLayout(state, event), horizontal: direction === "both" || direction === "horizontal", ...viewCompatibleProps }, renderInnerScrollView(viewCompatibleProps, allProps, state, direction) ), /* @__PURE__ */ React2.createElement(Fade, { side: "top", show: fade.top, width: fadeWidth, view, gradient }), /* @__PURE__ */ React2.createElement(Fade, { side: "right", show: fade.right, width: fadeWidth, view, gradient }), /* @__PURE__ */ React2.createElement(Fade, { side: "bottom", show: fade.bottom, width: fadeWidth, view, gradient }), /* @__PURE__ */ React2.createElement(Fade, { side: "left", show: fade.left, width: fadeWidth, view, gradient })); }; export { react_native_indicate_default as default }; //# sourceMappingURL=index.js.map