react-native-indicate
Version:
Enhanced ScrollView with elements indicating scrollable overflow.
243 lines (237 loc) • 7.6 kB
JavaScript
// 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