UNPKG

react-native-responsive-image-view

Version:

React Native component for scaling an Image within the parent View

230 lines (220 loc) 6.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ResponsiveImageView = ResponsiveImageView; exports.useResponsiveImageView = useResponsiveImageView; var React = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _jsxRuntime = require("react/jsx-runtime"); 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; } // Output // Hook options // Component props // A cancelable version of Image.getSize, adapted from // https://github.com/kodefox/react-native-flex-image function getImageSize(uri, onImageSizeSuccess, onImageSizeFailure) { let totallyCanceled = false; _reactNative.Image.getSize(uri, (width, height) => { if (!totallyCanceled) { onImageSizeSuccess(width, height); } }, err => { if (!totallyCanceled) { onImageSizeFailure?.(err); } }); return { cancel: () => { totallyCanceled = true; } }; } const initialState = { loading: true, error: '', retryCount: 0, aspectRatio: undefined }; function reducer(state, action) { switch (action.type) { case 'SUCCESS': { return { ...initialState, loading: false, retryCount: state.retryCount, aspectRatio: action.payload }; } case 'FAILURE': { return { ...initialState, loading: false, error: action.payload, retryCount: state.retryCount }; } case 'RETRY': { return { ...initialState, retryCount: state.retryCount + 1 }; } /* istanbul ignore next: this will never happen */ default: { throw new Error('Unexpected action type'); } } } function defaultOnLoad() {} function defaultOnError(_) {} function useResponsiveImageView({ aspectRatio: controlledAspectRatio, source: initialSource, onLoad = defaultOnLoad, onError = defaultOnError }) { if (!initialSource) { throw new Error('"source" is required'); } // Latest ref pattern for callbacks const onLoadRef = React.useRef(onLoad); const onErrorRef = React.useRef(onError); React.useEffect(() => { onLoadRef.current = onLoad; onErrorRef.current = onError; }, [onError, onLoad]); // Extract and memoize only the relevant information const imageIdOrUri = React.useMemo(() => { const imgIdOrUri = typeof initialSource === 'number' ? initialSource : initialSource.uri; if (!imgIdOrUri) { throw new Error(`"source" must be a valid URI or resource`); } return imgIdOrUri; }, [initialSource]); const [state, dispatch] = React.useReducer(reducer, initialState); function retry() { dispatch({ type: 'RETRY' }); } function isAspectRatioControlled() { return controlledAspectRatio !== undefined; } function getAspectRatio() { return isAspectRatioControlled() ? controlledAspectRatio : state.aspectRatio; } function getImageProps({ source, style = {}, ...props } = {}) { const imageProps = { source: initialSource, style: [style, { height: '100%', width: '100%' }], ...props }; return imageProps; } function getViewProps({ style = {}, ...props } = {}) { return { style: [style, { aspectRatio: getAspectRatio() }], ...props }; } React.useEffect(() => { let pendingGetImageSize = { cancel: /* istanbul ignore next: just a stub */() => {} }; function handleImageSizeSuccess(width, height) { onLoadRef.current(); dispatch({ type: 'SUCCESS', payload: width / height }); } function handleImageSizeFailure(err) { const errMessage = err instanceof Error ? err.message : /* istanbul ignore next */String(err); onErrorRef.current(errMessage); dispatch({ type: 'FAILURE', payload: errMessage }); } if (typeof imageIdOrUri === 'string') { // Retrieve image dimensions from URI pendingGetImageSize = getImageSize(imageIdOrUri, handleImageSizeSuccess, handleImageSizeFailure); } else { // Retrieve image dimensions from imported resource const imageSource = _reactNative.Image.resolveAssetSource(imageIdOrUri); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (imageSource) { handleImageSizeSuccess(imageSource.width, imageSource.height); } else { handleImageSizeFailure(new Error('Failed to retrieve image dimensions.')); } } return () => { pendingGetImageSize.cancel(); }; }, [imageIdOrUri, state.retryCount]); return { loading: state.loading, error: state.error, retry, getViewProps, getImageProps }; } function ResponsiveImageView({ source, component: Component = undefined, render = undefined, children = undefined, aspectRatio = undefined, onLoad = defaultOnLoad, onError = defaultOnError }) { const bag = useResponsiveImageView({ aspectRatio, source, onLoad, onError }); // component injection if (Component) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(Component, { ...bag }); } // render prop if (typeof render === 'function') { return render(bag); } // function-as-children if (typeof children === 'function') { return children(bag); } // no renderer provided, but children exist - just render the children as-is if (children && React.Children.count(children) > 0) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(React.Fragment, { children: React.Children.only(children) }); } return null; } ResponsiveImageView.displayName = 'ResponsiveImageView'; //# sourceMappingURL=index.js.map