UNPKG

react-native-inner-shadow

Version:

react native inner shadows with linear gradient design UI

231 lines (218 loc) 7.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.computeShadowProperties = computeShadowProperties; exports.getBackgroundColor = getBackgroundColor; exports.getBorderRadius = getBorderRadius; exports.getLinearDirection = getLinearDirection; exports.getOuterShadowOffset = getOuterShadowOffset; exports.isLinearProps = isLinearProps; exports.numerify = numerify; var _reactNativeSkia = require("@shopify/react-native-skia"); var _constants = require("./constants.js"); /** * Converts a value to a number, returning a default value if the conversion fails. * * @privateRemarks * At this time(17.Feb.2025), we do not support the way to convert the string (percentage) to a number. * * @template T - The type of the default value. * * @param value - The value to convert to a number. * * @returns The converted number, or the default value if the conversion fails. */ function numerify(value, defaultValue) { const num = Number(value); // if value === null return 0 return Number.isNaN(num) ? defaultValue : num; } function getBorderRadius(style) { const borderRadius = numerify(style?.borderRadius, null); const topStartRadius = numerify(style?.borderTopStartRadius, borderRadius); const topLeftRadius = numerify(style?.borderTopLeftRadius, topStartRadius ?? 0); const topEndRadius = numerify(style?.borderTopEndRadius, borderRadius); const topRightRadius = numerify(style?.borderTopRightRadius, topEndRadius ?? 0); const bottomEndRadius = numerify(style?.borderBottomEndRadius, borderRadius); const bottomRightRadius = numerify(style?.borderBottomRightRadius, bottomEndRadius ?? 0); const bottomStartRadius = numerify(style?.borderBottomStartRadius, borderRadius); const bottomLeftRadius = numerify(style?.borderBottomLeftRadius, bottomStartRadius ?? 0); return { borderRadius, topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius }; } /** * getBackgroundColor retrieves the final background color * from either: * 1) props.backgroundColor * 2) props.style.backgroundColor * 3) BACKGROUND_COLOR * * This ensures there is always a valid color for the component’s background. * * {@link GetBackgroundColorProps | props} - The props object containing background color settings. * * @returns The final background color for the component. */ function getBackgroundColor({ backgroundColor, styleBackground }) { const bgColor = backgroundColor ?? styleBackground ?? _constants.BACKGROUND_COLOR; return bgColor; } /** * computeShadowProperties determines the final configuration for both * the main shadow and any reflected light. It merges default values * with provided props to form a complete “shadow settings” object. * * - `shadowOffset` / `reflectedLightOffset`: how far the shadows/highlights * are shifted in x and y. * - `shadowColor` / `reflectedLightColor`: colors used for each effect. * - `shadowBlur` / `reflectedLightBlur`: blur radius for the softness/spread * of the shadow or highlight. * * {@link ShadowPropertyConfig} - The props object containing shadow-related settings. * * @returns `{ * shadowOffset, reflectedLightOffset, shadowColor, reflectedLightColor, shadowBlur, reflectedLightBlur }` */ function computeShadowProperties({ inset, shadowOffset, shadowBlur, shadowColor, reflectedLightOffset, reflectedLightBlur, reflectedLightColor }) { const shadowOffsetX = numerify(shadowOffset?.width, _constants.SHADOW_OFFSET_SCALE); const shadowOffsetY = numerify(shadowOffset?.height, _constants.SHADOW_OFFSET_SCALE); // By default, the reflected light offset is the inverse of the main shadow // so it appears on the opposite corner/side. // when `inset` property is `true`, the reflected light offset is opposite to the shadow offset const reflectedLightOffsetX = calculateReflectedLightPosition({ inset, reflectedLightScale: reflectedLightOffset?.width, baseShadowOffset: shadowOffsetX }); const reflectedLightOffsetY = calculateReflectedLightPosition({ inset, reflectedLightScale: reflectedLightOffset?.height, baseShadowOffset: shadowOffsetY }); // "Blur" here maps to how soft or large the shadow/highlight is. // The higher the number, the more diffuse the effect. const finalShadowBlur = Math.max(shadowBlur ?? _constants.SHADOW_BLUR, 0); const finalReflectedLightBlur = Math.max(reflectedLightBlur ?? _constants.REFLECTED_LIGHT_BLUR, 0); // Fallback to the provided defaults if the user doesn't specify a color. const finalShadowColor = shadowColor ?? _constants.SHADOW_COLOR; const finalReflectedLightColor = reflectedLightColor ?? _constants.REFLECTED_LIGHT_COLOR; // Construct the final offsets as objects for clarity. const finalShadowOffset = { width: shadowOffsetX, height: shadowOffsetY }; const finalReflectedLightOffset = { width: reflectedLightOffsetX, height: reflectedLightOffsetY }; return { shadowOffset: finalShadowOffset, reflectedLightOffset: finalReflectedLightOffset, shadowColor: finalShadowColor, reflectedLightColor: finalReflectedLightColor, shadowBlur: finalShadowBlur, reflectedLightBlur: finalReflectedLightBlur }; } function calculateReflectedLightPosition({ inset, reflectedLightScale, baseShadowOffset }) { // When user provides a reflected light offset, use that. - which allows `0` and `null` if (reflectedLightScale !== undefined) return reflectedLightScale; // When shadow is 0, reflected light should be 0. if (baseShadowOffset === 0) return 0; // for matching reflected light offset direction based on inset const scaleFactor = (baseShadowOffset + _constants.REFLECTED_LIGHT_OFFSET_SCALE) / 2; // When inset is true, the reflected light should be opposite the shadow. return inset ? -scaleFactor : scaleFactor; } /** * `getOuterShadowOffset` calculates the outer shadow offset properties. * * {@link GetOuterShadowOffsetProps} - The props object containing outer shadow offset settings. * * @returns `{ shadowColor, shadowOffset, shadowBlur, shadowOpacity, shadowRadius, elevation, boxShadow }` */ function getOuterShadowOffset({ inset, shadowColor, shadowOffset, shadowBlur, shadowOpacity = _constants.SHADOW_OPACITY, shadowRadius = _constants.SHADOW_RADIUS, elevation = _constants.SHADOW_ELEVATION, boxShadow }) { if (inset) return {}; return { shadowColor, shadowOffset, shadowBlur, shadowOpacity, shadowRadius, elevation, boxShadow }; } /** * `getLinearDirection` calculates the start and end points for a linear gradient * based on the provided direction (from, to). * * - The direction is specified as a string, e.g., 'top', 'bottom', 'left', 'right'. * - The width and height are used to calculate the midpoints for each direction. * * {@link GetLinearDirectionProps} - The props object containing linear direction settings. * * @returns `{ start, end }` */ function getLinearDirection({ width, height, from, to }) { const top = (0, _reactNativeSkia.vec)(width / 2, 0); const bottom = (0, _reactNativeSkia.vec)(width / 2, height); const left = (0, _reactNativeSkia.vec)(0, height / 2); const right = (0, _reactNativeSkia.vec)(width, height / 2); const direction = { top, bottom, left, right }; return { start: direction[from], end: direction[to] }; } /** * `isLinearProps` checks if the provided props are for a linear gradient. * If the `colors` property is an array, we assume it's a linear gradient. * * @param props - see {@link InnerShadowProps} and {@link LinearInnerShadowProps} * * @returns `true` if the props are for a linear gradient, `false` otherwise. */ function isLinearProps(props) { return 'colors' in props && Array.isArray(props.colors); } //# sourceMappingURL=utils.js.map