@rootnative/inertia-gradients 0.0.0-alpha.1 → 0.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -138,5 +138,3 @@ function MotionLinearGradient(props) {
138
138
  }
139
139
 
140
140
  exports.MotionLinearGradient = MotionLinearGradient;
141
- //# sourceMappingURL=index.js.map
142
- //# sourceMappingURL=index.js.map
package/dist/index.mjs CHANGED
@@ -132,5 +132,3 @@ function MotionLinearGradient(props) {
132
132
  }
133
133
 
134
134
  export { MotionLinearGradient };
135
- //# sourceMappingURL=index.mjs.map
136
- //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootnative/inertia-gradients",
3
- "version": "0.0.0-alpha.1",
3
+ "version": "0.0.0-alpha.2",
4
4
  "description": "Animated linear gradient primitive for @rootnative/inertia, built on expo-linear-gradient.",
5
5
  "license": "MIT",
6
6
  "author": "RootNative",
@@ -46,10 +46,11 @@
46
46
  "LICENSE",
47
47
  "CHANGELOG.md",
48
48
  "!**/__tests__",
49
+ "!**/__type-tests__",
49
50
  "!**/*.test.*"
50
51
  ],
51
52
  "peerDependencies": {
52
- "@rootnative/inertia": ">=0.0.0-alpha.1",
53
+ "@rootnative/inertia": ">=0.0.0-alpha.2",
53
54
  "expo-linear-gradient": ">=14.0.0",
54
55
  "react": ">=19.0.0",
55
56
  "react-native": ">=0.81.0",
@@ -70,7 +71,7 @@
70
71
  "size-limit": "^11.1.0",
71
72
  "tsup": "^8.3.5",
72
73
  "typescript": "^5.7.3",
73
- "@rootnative/inertia": "0.0.0-alpha.1"
74
+ "@rootnative/inertia": "0.0.0-alpha.2"
74
75
  },
75
76
  "publishConfig": {
76
77
  "access": "public"
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/MotionLinearGradient.tsx"],"names":["Animated","LinearGradient","useRef","useSharedValue","useShouldReduceMotion","useEffect","resolveTransition","useAnimatedProps","jsx"],"mappings":"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","file":"index.js","sourcesContent":["import { useEffect, useRef } from 'react'\nimport { LinearGradient, type LinearGradientProps } from 'expo-linear-gradient'\nimport Animated, {\n useAnimatedProps,\n useSharedValue,\n type SharedValue,\n} from 'react-native-reanimated'\nimport {\n resolveTransition,\n useShouldReduceMotion,\n type TransitionConfig,\n} from '@rootnative/inertia'\nimport type {\n GradientPoint,\n LinearGradientAnimate,\n LinearGradientPerPropertyTransition,\n LinearGradientTransition,\n} from './types'\n\nconst AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient)\n\nconst NO_ANIMATION: TransitionConfig = { type: 'no-animation' }\nconst DEFAULT_START: GradientPoint = { x: 0, y: 0 }\nconst DEFAULT_END: GradientPoint = { x: 1, y: 0 }\n\n/**\n * Extract the per-key transition for `key`, falling back to the top-level\n * transition if the user passed `transition` as a single `TransitionConfig`\n * rather than a per-property map. Mirrors the precedence rule used by the\n * core factory: per-key wins, top-level fills, library default below that.\n */\nfunction pickTransition(\n per: LinearGradientTransition | undefined,\n key: keyof LinearGradientPerPropertyTransition,\n): TransitionConfig | undefined {\n if (!per) return undefined\n if ('type' in per) return per as TransitionConfig\n return (per as LinearGradientPerPropertyTransition)[key]\n}\n\ntype AtLeastTwoStrings = readonly [string, string, ...string[]]\n\nexport interface MotionLinearGradientProps extends Omit<\n LinearGradientProps,\n 'colors' | 'start' | 'end' | 'locations'\n> {\n /**\n * Initial color stops, in order. At least two are required. The array's\n * length is **locked at first render** — to change the number of stops,\n * remount with a new `key`.\n */\n colors: AtLeastTwoStrings\n /** Start point in normalized `[0, 1]` coordinates. Defaults to `{x:0,y:0}`. */\n start?: GradientPoint\n /** End point in normalized `[0, 1]` coordinates. Defaults to `{x:1,y:0}`. */\n end?: GradientPoint\n /**\n * Optional stop positions. If supplied at mount, must remain supplied (and\n * the same length as `colors`) for the lifetime of the component.\n */\n locations?: readonly number[]\n /**\n * Initial frame override. When present, the component mounts displaying\n * these values, then animates to `animate` on the next effect. Pass `false`\n * to skip the initial-mount animation entirely.\n */\n initial?: LinearGradientAnimate | false\n /** Target animation state. */\n animate?: LinearGradientAnimate\n /**\n * Transition config — either a single `TransitionConfig` applied to every\n * animated dimension, or a per-property map (`{ colors, start, end,\n * locations }`). Per-property entries win over the top-level transition.\n */\n transition?: LinearGradientTransition\n}\n\n/**\n * Animatable `LinearGradient`. Wraps `expo-linear-gradient`'s `LinearGradient`\n * with declarative `initial` / `animate` / `transition` props.\n *\n * Animatable dimensions:\n * - `colors` — array of color strings, element-wise interpolated. Slot count\n * is locked at mount.\n * - `start` / `end` — `{ x, y }` points; x and y animate independently.\n * - `locations` — array of stop positions, element-wise interpolated. Locked\n * to the same length as `colors` (and to its presence at mount).\n *\n * Example:\n * ```tsx\n * <MotionLinearGradient\n * colors={['#0f172a', '#1e293b']}\n * animate={{ colors: ['#7c3aed', '#0ea5e9'] }}\n * transition={{ type: 'timing', duration: 600 }}\n * style={StyleSheet.absoluteFill}\n * />\n * ```\n */\nexport function MotionLinearGradient(props: MotionLinearGradientProps) {\n const {\n colors,\n start = DEFAULT_START,\n end = DEFAULT_END,\n locations,\n initial,\n animate,\n transition,\n ...rest\n } = props\n\n // Slot count is locked at first render; subsequent renders must keep\n // `colors.length` constant so the hook order (one `useSharedValue` per slot\n // below) stays stable. `locations` presence is similarly locked because we\n // allocate its shared-value table on the same path.\n const slotCountRef = useRef(colors.length)\n const hasLocationsRef = useRef(locations !== undefined)\n\n if (__DEV__) {\n if (slotCountRef.current !== colors.length) {\n throw new Error(\n `[inertia-gradients] colors length changed from ${slotCountRef.current} to ${colors.length} — colors length is locked at mount; remount via key={...} to resize.`,\n )\n }\n if (hasLocationsRef.current !== (locations !== undefined)) {\n throw new Error(\n `[inertia-gradients] locations presence changed — locations must be either always present or always absent (locked at mount).`,\n )\n }\n if (locations !== undefined && locations.length !== slotCountRef.current) {\n throw new Error(\n `[inertia-gradients] locations length (${locations.length}) must match colors length (${slotCountRef.current}).`,\n )\n }\n }\n\n // `initial: false` means \"start at the animate target — no mount animation\".\n // `initial: {...}` overrides the static prop with explicit initial values.\n // `initial: undefined` (default) seeds from the static props.\n const seedSource = initial === false ? animate : (initial ?? undefined)\n const seedColors = seedSource?.colors ?? colors\n const seedStart = seedSource?.start ?? start\n const seedEnd = seedSource?.end ?? end\n const seedLocations = seedSource?.locations ?? locations\n\n // Loop-of-hooks pattern: safe because slotCountRef enforces a constant\n // length. ESLint can't see the invariant, so we suppress per call site.\n const colorSvs: SharedValue<string>[] = []\n for (let i = 0; i < slotCountRef.current; i++) {\n // Slot `i` is in-bounds for `colors` by the length lock, but TS sees a\n // generic `readonly string[]` index so coerce via a non-null fallback.\n const seed = seedColors[i] ?? colors[i] ?? ''\n // eslint-disable-next-line react-hooks/rules-of-hooks\n colorSvs.push(useSharedValue<string>(seed))\n }\n\n const startX = useSharedValue(seedStart.x)\n const startY = useSharedValue(seedStart.y)\n const endX = useSharedValue(seedEnd.x)\n const endY = useSharedValue(seedEnd.y)\n\n const locationSvs: SharedValue<number>[] = []\n for (let i = 0; i < slotCountRef.current; i++) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n locationSvs.push(useSharedValue<number>(seedLocations?.[i] ?? 0))\n }\n\n const reduce = useShouldReduceMotion()\n\n // Serialize targets into scalar keys so effects re-run on value change, not\n // on every parent re-render (a fresh `animate` literal each render is the\n // common case in callers).\n const colorsKey = animate?.colors ? animate.colors.join('|') : ''\n const startKey = animate?.start ? `${animate.start.x},${animate.start.y}` : ''\n const endKey = animate?.end ? `${animate.end.x},${animate.end.y}` : ''\n const locationsKey = animate?.locations ? animate.locations.join('|') : ''\n\n const animateColors = animate?.colors\n const animateStart = animate?.start\n const animateEnd = animate?.end\n const animateLocations = animate?.locations\n\n useEffect(() => {\n if (!animateColors) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'colors')\n for (let i = 0; i < colorSvs.length; i++) {\n const target = animateColors[i] ?? colors[i] ?? ''\n colorSvs[i]!.value = resolveTransition(cfg, target) as string\n }\n // colorSvs / colors are stable across renders by the length-lock above.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [colorsKey, reduce, transition])\n\n useEffect(() => {\n if (!animateStart) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'start')\n startX.value = resolveTransition(cfg, animateStart.x) as number\n startY.value = resolveTransition(cfg, animateStart.y) as number\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [startKey, reduce, transition])\n\n useEffect(() => {\n if (!animateEnd) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'end')\n endX.value = resolveTransition(cfg, animateEnd.x) as number\n endY.value = resolveTransition(cfg, animateEnd.y) as number\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [endKey, reduce, transition])\n\n useEffect(() => {\n if (!animateLocations) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'locations')\n for (let i = 0; i < locationSvs.length; i++) {\n const target = animateLocations[i]\n if (target !== undefined) {\n locationSvs[i]!.value = resolveTransition(cfg, target) as number\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [locationsKey, reduce, transition])\n\n const animatedProps = useAnimatedProps(() => {\n 'worklet'\n const colorsOut = new Array<string>(colorSvs.length)\n for (let i = 0; i < colorSvs.length; i++) colorsOut[i] = colorSvs[i]!.value\n const out: {\n colors: string[]\n start: GradientPoint\n end: GradientPoint\n locations?: number[]\n } = {\n colors: colorsOut,\n start: { x: startX.value, y: startY.value },\n end: { x: endX.value, y: endY.value },\n }\n if (hasLocationsRef.current) {\n const locsOut = new Array<number>(locationSvs.length)\n for (let i = 0; i < locationSvs.length; i++)\n locsOut[i] = locationSvs[i]!.value\n out.locations = locsOut\n }\n return out\n })\n\n return (\n <AnimatedLinearGradient\n // `animatedProps` overrides the static `colors` / `start` / `end` /\n // `locations` each frame; the static props below are the first-render\n // seeds so the gradient renders before the first effect tick. The cast\n // sheds Reanimated's strict-tuple constraint that the worklet's return\n // type can't express — the runtime value is the same shape.\n animatedProps={animatedProps as never}\n colors={colors}\n start={start}\n end={end}\n locations={locations as never}\n {...rest}\n />\n )\n}\n\ndeclare const __DEV__: boolean\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/MotionLinearGradient.tsx"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { useEffect, useRef } from 'react'\nimport { LinearGradient, type LinearGradientProps } from 'expo-linear-gradient'\nimport Animated, {\n useAnimatedProps,\n useSharedValue,\n type SharedValue,\n} from 'react-native-reanimated'\nimport {\n resolveTransition,\n useShouldReduceMotion,\n type TransitionConfig,\n} from '@rootnative/inertia'\nimport type {\n GradientPoint,\n LinearGradientAnimate,\n LinearGradientPerPropertyTransition,\n LinearGradientTransition,\n} from './types'\n\nconst AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient)\n\nconst NO_ANIMATION: TransitionConfig = { type: 'no-animation' }\nconst DEFAULT_START: GradientPoint = { x: 0, y: 0 }\nconst DEFAULT_END: GradientPoint = { x: 1, y: 0 }\n\n/**\n * Extract the per-key transition for `key`, falling back to the top-level\n * transition if the user passed `transition` as a single `TransitionConfig`\n * rather than a per-property map. Mirrors the precedence rule used by the\n * core factory: per-key wins, top-level fills, library default below that.\n */\nfunction pickTransition(\n per: LinearGradientTransition | undefined,\n key: keyof LinearGradientPerPropertyTransition,\n): TransitionConfig | undefined {\n if (!per) return undefined\n if ('type' in per) return per as TransitionConfig\n return (per as LinearGradientPerPropertyTransition)[key]\n}\n\ntype AtLeastTwoStrings = readonly [string, string, ...string[]]\n\nexport interface MotionLinearGradientProps extends Omit<\n LinearGradientProps,\n 'colors' | 'start' | 'end' | 'locations'\n> {\n /**\n * Initial color stops, in order. At least two are required. The array's\n * length is **locked at first render** — to change the number of stops,\n * remount with a new `key`.\n */\n colors: AtLeastTwoStrings\n /** Start point in normalized `[0, 1]` coordinates. Defaults to `{x:0,y:0}`. */\n start?: GradientPoint\n /** End point in normalized `[0, 1]` coordinates. Defaults to `{x:1,y:0}`. */\n end?: GradientPoint\n /**\n * Optional stop positions. If supplied at mount, must remain supplied (and\n * the same length as `colors`) for the lifetime of the component.\n */\n locations?: readonly number[]\n /**\n * Initial frame override. When present, the component mounts displaying\n * these values, then animates to `animate` on the next effect. Pass `false`\n * to skip the initial-mount animation entirely.\n */\n initial?: LinearGradientAnimate | false\n /** Target animation state. */\n animate?: LinearGradientAnimate\n /**\n * Transition config — either a single `TransitionConfig` applied to every\n * animated dimension, or a per-property map (`{ colors, start, end,\n * locations }`). Per-property entries win over the top-level transition.\n */\n transition?: LinearGradientTransition\n}\n\n/**\n * Animatable `LinearGradient`. Wraps `expo-linear-gradient`'s `LinearGradient`\n * with declarative `initial` / `animate` / `transition` props.\n *\n * Animatable dimensions:\n * - `colors` — array of color strings, element-wise interpolated. Slot count\n * is locked at mount.\n * - `start` / `end` — `{ x, y }` points; x and y animate independently.\n * - `locations` — array of stop positions, element-wise interpolated. Locked\n * to the same length as `colors` (and to its presence at mount).\n *\n * Example:\n * ```tsx\n * <MotionLinearGradient\n * colors={['#0f172a', '#1e293b']}\n * animate={{ colors: ['#7c3aed', '#0ea5e9'] }}\n * transition={{ type: 'timing', duration: 600 }}\n * style={StyleSheet.absoluteFill}\n * />\n * ```\n */\nexport function MotionLinearGradient(props: MotionLinearGradientProps) {\n const {\n colors,\n start = DEFAULT_START,\n end = DEFAULT_END,\n locations,\n initial,\n animate,\n transition,\n ...rest\n } = props\n\n // Slot count is locked at first render; subsequent renders must keep\n // `colors.length` constant so the hook order (one `useSharedValue` per slot\n // below) stays stable. `locations` presence is similarly locked because we\n // allocate its shared-value table on the same path.\n const slotCountRef = useRef(colors.length)\n const hasLocationsRef = useRef(locations !== undefined)\n\n if (__DEV__) {\n if (slotCountRef.current !== colors.length) {\n throw new Error(\n `[inertia-gradients] colors length changed from ${slotCountRef.current} to ${colors.length} — colors length is locked at mount; remount via key={...} to resize.`,\n )\n }\n if (hasLocationsRef.current !== (locations !== undefined)) {\n throw new Error(\n `[inertia-gradients] locations presence changed — locations must be either always present or always absent (locked at mount).`,\n )\n }\n if (locations !== undefined && locations.length !== slotCountRef.current) {\n throw new Error(\n `[inertia-gradients] locations length (${locations.length}) must match colors length (${slotCountRef.current}).`,\n )\n }\n }\n\n // `initial: false` means \"start at the animate target — no mount animation\".\n // `initial: {...}` overrides the static prop with explicit initial values.\n // `initial: undefined` (default) seeds from the static props.\n const seedSource = initial === false ? animate : (initial ?? undefined)\n const seedColors = seedSource?.colors ?? colors\n const seedStart = seedSource?.start ?? start\n const seedEnd = seedSource?.end ?? end\n const seedLocations = seedSource?.locations ?? locations\n\n // Loop-of-hooks pattern: safe because slotCountRef enforces a constant\n // length. ESLint can't see the invariant, so we suppress per call site.\n const colorSvs: SharedValue<string>[] = []\n for (let i = 0; i < slotCountRef.current; i++) {\n // Slot `i` is in-bounds for `colors` by the length lock, but TS sees a\n // generic `readonly string[]` index so coerce via a non-null fallback.\n const seed = seedColors[i] ?? colors[i] ?? ''\n // eslint-disable-next-line react-hooks/rules-of-hooks\n colorSvs.push(useSharedValue<string>(seed))\n }\n\n const startX = useSharedValue(seedStart.x)\n const startY = useSharedValue(seedStart.y)\n const endX = useSharedValue(seedEnd.x)\n const endY = useSharedValue(seedEnd.y)\n\n const locationSvs: SharedValue<number>[] = []\n for (let i = 0; i < slotCountRef.current; i++) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n locationSvs.push(useSharedValue<number>(seedLocations?.[i] ?? 0))\n }\n\n const reduce = useShouldReduceMotion()\n\n // Serialize targets into scalar keys so effects re-run on value change, not\n // on every parent re-render (a fresh `animate` literal each render is the\n // common case in callers).\n const colorsKey = animate?.colors ? animate.colors.join('|') : ''\n const startKey = animate?.start ? `${animate.start.x},${animate.start.y}` : ''\n const endKey = animate?.end ? `${animate.end.x},${animate.end.y}` : ''\n const locationsKey = animate?.locations ? animate.locations.join('|') : ''\n\n const animateColors = animate?.colors\n const animateStart = animate?.start\n const animateEnd = animate?.end\n const animateLocations = animate?.locations\n\n useEffect(() => {\n if (!animateColors) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'colors')\n for (let i = 0; i < colorSvs.length; i++) {\n const target = animateColors[i] ?? colors[i] ?? ''\n colorSvs[i]!.value = resolveTransition(cfg, target) as string\n }\n // colorSvs / colors are stable across renders by the length-lock above.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [colorsKey, reduce, transition])\n\n useEffect(() => {\n if (!animateStart) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'start')\n startX.value = resolveTransition(cfg, animateStart.x) as number\n startY.value = resolveTransition(cfg, animateStart.y) as number\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [startKey, reduce, transition])\n\n useEffect(() => {\n if (!animateEnd) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'end')\n endX.value = resolveTransition(cfg, animateEnd.x) as number\n endY.value = resolveTransition(cfg, animateEnd.y) as number\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [endKey, reduce, transition])\n\n useEffect(() => {\n if (!animateLocations) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'locations')\n for (let i = 0; i < locationSvs.length; i++) {\n const target = animateLocations[i]\n if (target !== undefined) {\n locationSvs[i]!.value = resolveTransition(cfg, target) as number\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [locationsKey, reduce, transition])\n\n const animatedProps = useAnimatedProps(() => {\n 'worklet'\n const colorsOut = new Array<string>(colorSvs.length)\n for (let i = 0; i < colorSvs.length; i++) colorsOut[i] = colorSvs[i]!.value\n const out: {\n colors: string[]\n start: GradientPoint\n end: GradientPoint\n locations?: number[]\n } = {\n colors: colorsOut,\n start: { x: startX.value, y: startY.value },\n end: { x: endX.value, y: endY.value },\n }\n if (hasLocationsRef.current) {\n const locsOut = new Array<number>(locationSvs.length)\n for (let i = 0; i < locationSvs.length; i++)\n locsOut[i] = locationSvs[i]!.value\n out.locations = locsOut\n }\n return out\n })\n\n return (\n <AnimatedLinearGradient\n // `animatedProps` overrides the static `colors` / `start` / `end` /\n // `locations` each frame; the static props below are the first-render\n // seeds so the gradient renders before the first effect tick. The cast\n // sheds Reanimated's strict-tuple constraint that the worklet's return\n // type can't express — the runtime value is the same shape.\n animatedProps={animatedProps as never}\n colors={colors}\n start={start}\n end={end}\n locations={locations as never}\n {...rest}\n />\n )\n}\n\ndeclare const __DEV__: boolean\n"]}