From 469d5838fb3f9387e21a9f21a6f262e83a960484 Mon Sep 17 00:00:00 2001 From: EQuimper Date: Sat, 14 Mar 2026 08:03:53 -0400 Subject: [PATCH 1/7] feat: add per-property transition support to EaseView --- README.md | 57 + android/src/main/java/com/ease/EaseView.kt | 256 +- .../src/main/java/com/ease/EaseViewManager.kt | 64 + example/pnpm-lock.yaml | 5986 +++++++++++++++++ example/src/demos/PerPropertyDemo.tsx | 50 + example/src/demos/index.ts | 2 + ios/EaseView.mm | 287 +- src/EaseView.tsx | 221 +- src/EaseViewNativeComponent.ts | 11 + src/__tests__/EaseView.test.tsx | 142 + src/index.tsx | 2 + src/types.ts | 16 +- 12 files changed, 6945 insertions(+), 149 deletions(-) create mode 100644 example/pnpm-lock.yaml create mode 100644 example/src/demos/PerPropertyDemo.tsx diff --git a/README.md b/README.md index f80a357..424d56c 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,42 @@ Use `{ type: 'none' }` to apply values immediately without animation. Useful for `onTransitionEnd` fires immediately with `{ finished: true }`. +### Per-Property Transitions + +Pass a map instead of a single config to use different transition types per property. This lets you mix timing and spring animations, or use different durations for different properties. + +```tsx + +``` + +Use `default` as a fallback for properties not explicitly listed: + +```tsx + +``` + +The `scale` key applies to both `scaleX` and `scaleY`. A specific `scaleX` or `scaleY` key takes priority over `scale`. + +When no `default` key is provided, library defaults apply by category: +- **Transforms** (translateX/Y, scaleX/Y, rotate, rotateX/Y): spring with damping=15, stiffness=120 +- **Other** (opacity, borderRadius, backgroundColor): timing 300ms easeInOut + +> **iOS note:** iOS composes all transform sub-properties into a single `CATransform3D` animation. If your map specifies conflicting configs for different transform properties (e.g. spring for `translateX` and timing for `scaleX`), the config from the lowest-index changed property is used. +> +> **Android note:** Android animates `backgroundColor` with `ValueAnimator` (timing only). If a per-property map specifies `type: 'spring'` for `backgroundColor`, it silently falls back to timing 300ms. + ### Border Radius `borderRadius` can be animated just like other properties. It uses hardware-accelerated platform APIs — `ViewOutlineProvider` + `clipToOutline` on Android and `layer.cornerRadius` + `layer.masksToBounds` on iOS. Unlike RN's style-based `borderRadius` (which uses a Canvas drawable on Android), this clips children properly and is GPU-accelerated. @@ -400,6 +436,27 @@ Properties not specified in `animate` default to their identity values. Applies values instantly with no animation. `onTransitionEnd` fires immediately with `{ finished: true }`. +### `TransitionMap` + +```tsx +{ + default?: SingleTransition; // fallback for unlisted properties + opacity?: SingleTransition; + translateX?: SingleTransition; + translateY?: SingleTransition; + scale?: SingleTransition; // shorthand for scaleX + scaleY + scaleX?: SingleTransition; + scaleY?: SingleTransition; + rotate?: SingleTransition; + rotateX?: SingleTransition; + rotateY?: SingleTransition; + borderRadius?: SingleTransition; + backgroundColor?: SingleTransition; +} +``` + +`Transition` is `SingleTransition | TransitionMap`. The `transition` prop accepts either form. + ## Hardware Layers (Android) Setting `useHardwareLayer` rasterizes the view into a GPU texture for the duration of the animation. This means animated property changes (opacity, scale, rotation) are composited on the RenderThread without redrawing the view hierarchy — useful for complex views with many children. diff --git a/android/src/main/java/com/ease/EaseView.kt b/android/src/main/java/com/ease/EaseView.kt index aebb135..3896441 100644 --- a/android/src/main/java/com/ease/EaseView.kt +++ b/android/src/main/java/com/ease/EaseView.kt @@ -44,6 +44,90 @@ class EaseView(context: Context) : ReactViewGroup(context) { var transitionLoop: String = "none" var transitionDelay: Long = 0L + // --- Per-property transition arrays (set by ViewManager) --- + var perPropertyTransitionTypes: Array? = null + var perPropertyTransitionDurations: IntArray? = null + var perPropertyTransitionDampings: FloatArray? = null + var perPropertyTransitionStiffnesses: FloatArray? = null + var perPropertyTransitionMasses: FloatArray? = null + var perPropertyTransitionLoops: Array? = null + var perPropertyTransitionEasingBeziers: FloatArray? = null + + data class TransitionConfig( + val type: String, + val duration: Int, + val easingBezier: FloatArray, + val damping: Float, + val stiffness: Float, + val mass: Float, + val loop: String + ) + + fun getTransitionConfigForProperty(index: Int): TransitionConfig { + val types = perPropertyTransitionTypes + if (types != null && index < types.size) { + val durations = perPropertyTransitionDurations + val dampings = perPropertyTransitionDampings + val stiffnesses = perPropertyTransitionStiffnesses + val masses = perPropertyTransitionMasses + val loops = perPropertyTransitionLoops + val beziers = perPropertyTransitionEasingBeziers + + val bIdx = index * 4 + val bezier = if (beziers != null && bIdx + 3 < beziers.size) { + floatArrayOf(beziers[bIdx], beziers[bIdx + 1], beziers[bIdx + 2], beziers[bIdx + 3]) + } else { + floatArrayOf(0.42f, 0f, 0.58f, 1.0f) + } + + return TransitionConfig( + type = types[index], + duration = if (durations != null && index < durations.size) durations[index] else 300, + easingBezier = bezier, + damping = if (dampings != null && index < dampings.size) dampings[index] else 15.0f, + stiffness = if (stiffnesses != null && index < stiffnesses.size) stiffnesses[index] else 120.0f, + mass = if (masses != null && index < masses.size) masses[index] else 1.0f, + loop = if (loops != null && index < loops.size) loops[index] else "none" + ) + } + // Fallback to scalar props + return TransitionConfig( + type = transitionType, + duration = transitionDuration, + easingBezier = transitionEasingBezier, + damping = transitionDamping, + stiffness = transitionStiffness, + mass = transitionMass, + loop = transitionLoop + ) + } + + // Property indices matching JS constants + companion object { + // Bitmask flags — must match JS constants + const val MASK_OPACITY = 1 shl 0 + const val MASK_TRANSLATE_X = 1 shl 1 + const val MASK_TRANSLATE_Y = 1 shl 2 + const val MASK_SCALE_X = 1 shl 3 + const val MASK_SCALE_Y = 1 shl 4 + const val MASK_ROTATE = 1 shl 5 + const val MASK_ROTATE_X = 1 shl 6 + const val MASK_ROTATE_Y = 1 shl 7 + const val MASK_BORDER_RADIUS = 1 shl 8 + const val MASK_BACKGROUND_COLOR = 1 shl 9 + + const val PROP_INDEX_OPACITY = 0 + const val PROP_INDEX_TRANSLATE_X = 1 + const val PROP_INDEX_TRANSLATE_Y = 2 + const val PROP_INDEX_SCALE_X = 3 + const val PROP_INDEX_SCALE_Y = 4 + const val PROP_INDEX_ROTATE = 5 + const val PROP_INDEX_ROTATE_X = 6 + const val PROP_INDEX_ROTATE_Y = 7 + const val PROP_INDEX_BORDER_RADIUS = 8 + const val PROP_INDEX_BACKGROUND_COLOR = 9 + } + // --- Transform origin (0–1 fractions) --- var transformOriginX: Float = 0.5f set(value) { @@ -118,20 +202,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { // --- Animated properties bitmask (set by ViewManager) --- var animatedProperties: Int = 0 - // --- Easing interpolators (lazy singletons shared across all instances) --- - companion object { - // Bitmask flags — must match JS constants - const val MASK_OPACITY = 1 shl 0 - const val MASK_TRANSLATE_X = 1 shl 1 - const val MASK_TRANSLATE_Y = 1 shl 2 - const val MASK_SCALE_X = 1 shl 3 - const val MASK_SCALE_Y = 1 shl 4 - const val MASK_ROTATE = 1 shl 5 - const val MASK_ROTATE_X = 1 shl 6 - const val MASK_ROTATE_Y = 1 shl 7 - const val MASK_BORDER_RADIUS = 1 shl 8 - const val MASK_BACKGROUND_COLOR = 1 shl 9 - } + private fun hasPerPropertyArrays(): Boolean = perPropertyTransitionTypes != null init { // Set camera distance for 3D perspective rotations (rotateX/rotateY) @@ -236,34 +307,34 @@ class EaseView(context: Context) : ReactViewGroup(context) { // Animate properties that differ from initial to target if (mask and MASK_OPACITY != 0 && initialAnimateOpacity != opacity) { - animateProperty("alpha", DynamicAnimation.ALPHA, initialAnimateOpacity, opacity, loop = true) + animateProperty("alpha", DynamicAnimation.ALPHA, initialAnimateOpacity, opacity, getTransitionConfigForProperty(PROP_INDEX_OPACITY), loop = true) } if (mask and MASK_TRANSLATE_X != 0 && initialAnimateTranslateX != translateX) { - animateProperty("translationX", DynamicAnimation.TRANSLATION_X, initialAnimateTranslateX, translateX, loop = true) + animateProperty("translationX", DynamicAnimation.TRANSLATION_X, initialAnimateTranslateX, translateX, getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_X), loop = true) } if (mask and MASK_TRANSLATE_Y != 0 && initialAnimateTranslateY != translateY) { - animateProperty("translationY", DynamicAnimation.TRANSLATION_Y, initialAnimateTranslateY, translateY, loop = true) + animateProperty("translationY", DynamicAnimation.TRANSLATION_Y, initialAnimateTranslateY, translateY, getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_Y), loop = true) } if (mask and MASK_SCALE_X != 0 && initialAnimateScaleX != scaleX) { - animateProperty("scaleX", DynamicAnimation.SCALE_X, initialAnimateScaleX, scaleX, loop = true) + animateProperty("scaleX", DynamicAnimation.SCALE_X, initialAnimateScaleX, scaleX, getTransitionConfigForProperty(PROP_INDEX_SCALE_X), loop = true) } if (mask and MASK_SCALE_Y != 0 && initialAnimateScaleY != scaleY) { - animateProperty("scaleY", DynamicAnimation.SCALE_Y, initialAnimateScaleY, scaleY, loop = true) + animateProperty("scaleY", DynamicAnimation.SCALE_Y, initialAnimateScaleY, scaleY, getTransitionConfigForProperty(PROP_INDEX_SCALE_Y), loop = true) } if (mask and MASK_ROTATE != 0 && initialAnimateRotate != rotate) { - animateProperty("rotation", DynamicAnimation.ROTATION, initialAnimateRotate, rotate, loop = true) + animateProperty("rotation", DynamicAnimation.ROTATION, initialAnimateRotate, rotate, getTransitionConfigForProperty(PROP_INDEX_ROTATE), loop = true) } if (mask and MASK_ROTATE_X != 0 && initialAnimateRotateX != rotateX) { - animateProperty("rotationX", DynamicAnimation.ROTATION_X, initialAnimateRotateX, rotateX, loop = true) + animateProperty("rotationX", DynamicAnimation.ROTATION_X, initialAnimateRotateX, rotateX, getTransitionConfigForProperty(PROP_INDEX_ROTATE_X), loop = true) } if (mask and MASK_ROTATE_Y != 0 && initialAnimateRotateY != rotateY) { - animateProperty("rotationY", DynamicAnimation.ROTATION_Y, initialAnimateRotateY, rotateY, loop = true) + animateProperty("rotationY", DynamicAnimation.ROTATION_Y, initialAnimateRotateY, rotateY, getTransitionConfigForProperty(PROP_INDEX_ROTATE_Y), loop = true) } if (mask and MASK_BORDER_RADIUS != 0 && initialAnimateBorderRadius != borderRadius) { - animateProperty("animateBorderRadius", null, initialAnimateBorderRadius, borderRadius, loop = true) + animateProperty("animateBorderRadius", null, initialAnimateBorderRadius, borderRadius, getTransitionConfigForProperty(PROP_INDEX_BORDER_RADIUS), loop = true) } if (mask and MASK_BACKGROUND_COLOR != 0 && initialAnimateBackgroundColor != backgroundColor) { - animateBackgroundColor(initialAnimateBackgroundColor, backgroundColor, loop = true) + animateBackgroundColor(initialAnimateBackgroundColor, backgroundColor, getTransitionConfigForProperty(PROP_INDEX_BACKGROUND_COLOR), loop = true) } } else { // No initial animation — set target values directly (skip non-animated) @@ -278,8 +349,8 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (mask and MASK_BORDER_RADIUS != 0) setAnimateBorderRadius(borderRadius) if (mask and MASK_BACKGROUND_COLOR != 0) applyBackgroundColor(backgroundColor) } - } else if (transitionType == "none") { - // No transition — set values immediately, cancel running animations + } else if (!hasPerPropertyArrays() && transitionType == "none") { + // No transition (scalar) — set values immediately, cancel running animations cancelAllAnimations() if (mask and MASK_OPACITY != 0) this.alpha = opacity if (mask and MASK_TRANSLATE_X != 0) this.translationX = translateX @@ -295,52 +366,102 @@ class EaseView(context: Context) : ReactViewGroup(context) { } else { // Subsequent updates: animate changed properties (skip non-animated) if (prevOpacity != null && mask and MASK_OPACITY != 0 && prevOpacity != opacity) { - val from = getCurrentValue("alpha") - animateProperty("alpha", DynamicAnimation.ALPHA, from, opacity) + val config = getTransitionConfigForProperty(PROP_INDEX_OPACITY) + if (config.type == "none") { + this.alpha = opacity + } else { + val from = getCurrentValue("alpha") + animateProperty("alpha", DynamicAnimation.ALPHA, from, opacity, config) + } } if (prevTranslateX != null && mask and MASK_TRANSLATE_X != 0 && prevTranslateX != translateX) { - val from = getCurrentValue("translationX") - animateProperty("translationX", DynamicAnimation.TRANSLATION_X, from, translateX) + val config = getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_X) + if (config.type == "none") { + this.translationX = translateX + } else { + val from = getCurrentValue("translationX") + animateProperty("translationX", DynamicAnimation.TRANSLATION_X, from, translateX, config) + } } if (prevTranslateY != null && mask and MASK_TRANSLATE_Y != 0 && prevTranslateY != translateY) { - val from = getCurrentValue("translationY") - animateProperty("translationY", DynamicAnimation.TRANSLATION_Y, from, translateY) + val config = getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_Y) + if (config.type == "none") { + this.translationY = translateY + } else { + val from = getCurrentValue("translationY") + animateProperty("translationY", DynamicAnimation.TRANSLATION_Y, from, translateY, config) + } } if (prevScaleX != null && mask and MASK_SCALE_X != 0 && prevScaleX != scaleX) { - val from = getCurrentValue("scaleX") - animateProperty("scaleX", DynamicAnimation.SCALE_X, from, scaleX) + val config = getTransitionConfigForProperty(PROP_INDEX_SCALE_X) + if (config.type == "none") { + this.scaleX = scaleX + } else { + val from = getCurrentValue("scaleX") + animateProperty("scaleX", DynamicAnimation.SCALE_X, from, scaleX, config) + } } if (prevScaleY != null && mask and MASK_SCALE_Y != 0 && prevScaleY != scaleY) { - val from = getCurrentValue("scaleY") - animateProperty("scaleY", DynamicAnimation.SCALE_Y, from, scaleY) + val config = getTransitionConfigForProperty(PROP_INDEX_SCALE_Y) + if (config.type == "none") { + this.scaleY = scaleY + } else { + val from = getCurrentValue("scaleY") + animateProperty("scaleY", DynamicAnimation.SCALE_Y, from, scaleY, config) + } } if (prevRotate != null && mask and MASK_ROTATE != 0 && prevRotate != rotate) { - val from = getCurrentValue("rotation") - animateProperty("rotation", DynamicAnimation.ROTATION, from, rotate) + val config = getTransitionConfigForProperty(PROP_INDEX_ROTATE) + if (config.type == "none") { + this.rotation = rotate + } else { + val from = getCurrentValue("rotation") + animateProperty("rotation", DynamicAnimation.ROTATION, from, rotate, config) + } } if (prevRotateX != null && mask and MASK_ROTATE_X != 0 && prevRotateX != rotateX) { - val from = getCurrentValue("rotationX") - animateProperty("rotationX", DynamicAnimation.ROTATION_X, from, rotateX) + val config = getTransitionConfigForProperty(PROP_INDEX_ROTATE_X) + if (config.type == "none") { + this.rotationX = rotateX + } else { + val from = getCurrentValue("rotationX") + animateProperty("rotationX", DynamicAnimation.ROTATION_X, from, rotateX, config) + } } if (prevRotateY != null && mask and MASK_ROTATE_Y != 0 && prevRotateY != rotateY) { - val from = getCurrentValue("rotationY") - animateProperty("rotationY", DynamicAnimation.ROTATION_Y, from, rotateY) + val config = getTransitionConfigForProperty(PROP_INDEX_ROTATE_Y) + if (config.type == "none") { + this.rotationY = rotateY + } else { + val from = getCurrentValue("rotationY") + animateProperty("rotationY", DynamicAnimation.ROTATION_Y, from, rotateY, config) + } } if (prevBorderRadius != null && mask and MASK_BORDER_RADIUS != 0 && prevBorderRadius != borderRadius) { - val from = getCurrentValue("animateBorderRadius") - animateProperty("animateBorderRadius", null, from, borderRadius) + val config = getTransitionConfigForProperty(PROP_INDEX_BORDER_RADIUS) + if (config.type == "none") { + setAnimateBorderRadius(borderRadius) + } else { + val from = getCurrentValue("animateBorderRadius") + animateProperty("animateBorderRadius", null, from, borderRadius, config) + } } if (prevBackgroundColor != null && mask and MASK_BACKGROUND_COLOR != 0 && prevBackgroundColor != backgroundColor) { - animateBackgroundColor(getCurrentBackgroundColor(), backgroundColor) + val config = getTransitionConfigForProperty(PROP_INDEX_BACKGROUND_COLOR) + if (config.type == "none") { + applyBackgroundColor(backgroundColor) + } else { + animateBackgroundColor(getCurrentBackgroundColor(), backgroundColor, config) + } } } @@ -378,7 +499,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { setBackgroundColor(color) } - private fun animateBackgroundColor(fromColor: Int, toColor: Int, loop: Boolean = false) { + private fun animateBackgroundColor(fromColor: Int, toColor: Int, config: TransitionConfig, loop: Boolean = false) { runningAnimators["backgroundColor"]?.cancel() val batchId = animationBatchId @@ -387,13 +508,15 @@ class EaseView(context: Context) : ReactViewGroup(context) { val animator = ValueAnimator.ofArgb(fromColor, toColor).apply { duration = transitionDuration.toLong() startDelay = transitionDelay + duration = config.duration.toLong() + interpolator = PathInterpolator( - transitionEasingBezier[0], transitionEasingBezier[1], - transitionEasingBezier[2], transitionEasingBezier[3] + config.easingBezier[0], config.easingBezier[1], + config.easingBezier[2], config.easingBezier[3] ) - if (loop && transitionLoop != "none") { + if (loop && config.loop != "none") { repeatCount = ValueAnimator.INFINITE - repeatMode = if (transitionLoop == "reverse") ValueAnimator.REVERSE else ValueAnimator.RESTART + repeatMode = if (config.loop == "reverse") ValueAnimator.REVERSE else ValueAnimator.RESTART } addUpdateListener { animation -> val color = animation.animatedValue as Int @@ -428,16 +551,17 @@ class EaseView(context: Context) : ReactViewGroup(context) { viewProperty: DynamicAnimation.ViewProperty?, fromValue: Float, toValue: Float, + config: TransitionConfig, loop: Boolean = false ) { - if (transitionType == "spring" && viewProperty != null) { - animateSpring(viewProperty, toValue) + if (config.type == "spring" && viewProperty != null) { + animateSpring(viewProperty, toValue, config) } else { - animateTiming(propertyName, fromValue, toValue, loop) + animateTiming(propertyName, fromValue, toValue, config, loop) } } - private fun animateTiming(propertyName: String, fromValue: Float, toValue: Float, loop: Boolean = false) { + private fun animateTiming(propertyName: String, fromValue: Float, toValue: Float, config: TransitionConfig, loop: Boolean = false) { cancelSpringForProperty(propertyName) runningAnimators[propertyName]?.cancel() @@ -447,13 +571,15 @@ class EaseView(context: Context) : ReactViewGroup(context) { val animator = ObjectAnimator.ofFloat(this, propertyName, fromValue, toValue).apply { duration = transitionDuration.toLong() startDelay = transitionDelay + duration = config.duration.toLong() + interpolator = PathInterpolator( - transitionEasingBezier[0], transitionEasingBezier[1], - transitionEasingBezier[2], transitionEasingBezier[3] + config.easingBezier[0], config.easingBezier[1], + config.easingBezier[2], config.easingBezier[3] ) - if (loop && transitionLoop != "none") { + if (loop && config.loop != "none") { repeatCount = ObjectAnimator.INFINITE - repeatMode = if (transitionLoop == "reverse") { + repeatMode = if (config.loop == "reverse") { ObjectAnimator.REVERSE } else { ObjectAnimator.RESTART @@ -484,7 +610,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { animator.start() } - private fun animateSpring(viewProperty: DynamicAnimation.ViewProperty, toValue: Float) { + private fun animateSpring(viewProperty: DynamicAnimation.ViewProperty, toValue: Float, config: TransitionConfig) { cancelTimingForViewProperty(viewProperty) val existingSpring = runningSpringAnimations[viewProperty] @@ -496,13 +622,13 @@ class EaseView(context: Context) : ReactViewGroup(context) { val batchId = animationBatchId pendingBatchAnimationCount++ - val dampingRatio = (transitionDamping / (2.0f * sqrt(transitionStiffness * transitionMass))) + val dampingRatio = (config.damping / (2.0f * sqrt(config.stiffness * config.mass))) .coerceAtLeast(0.01f) val spring = SpringAnimation(this, viewProperty).apply { spring = SpringForce(toValue).apply { this.dampingRatio = dampingRatio - this.stiffness = transitionStiffness + this.stiffness = config.stiffness } addUpdateListener { _, _, _ -> // First update — enable hardware layer @@ -632,5 +758,13 @@ class EaseView(context: Context) : ReactViewGroup(context) { isFirstMount = true transitionLoop = "none" + + perPropertyTransitionTypes = null + perPropertyTransitionDurations = null + perPropertyTransitionDampings = null + perPropertyTransitionStiffnesses = null + perPropertyTransitionMasses = null + perPropertyTransitionLoops = null + perPropertyTransitionEasingBeziers = null } } diff --git a/android/src/main/java/com/ease/EaseViewManager.kt b/android/src/main/java/com/ease/EaseViewManager.kt index 5c426e5..fa5aafc 100644 --- a/android/src/main/java/com/ease/EaseViewManager.kt +++ b/android/src/main/java/com/ease/EaseViewManager.kt @@ -176,6 +176,70 @@ class EaseViewManager : ReactViewManager() { @ReactProp(name = "transitionDelay", defaultInt = 0) fun setTransitionDelay(view: EaseView, value: Int) { view.transitionDelay = value.toLong() + // --- Per-property transition arrays --- + + @ReactProp(name = "perPropertyTransitionTypes") + fun setPerPropertyTransitionTypes(view: EaseView, value: ReadableArray?) { + if (value != null && value.size() == 10) { + view.perPropertyTransitionTypes = Array(10) { value.getString(it) ?: "" } + } else { + view.perPropertyTransitionTypes = null + } + } + + @ReactProp(name = "perPropertyTransitionDurations") + fun setPerPropertyTransitionDurations(view: EaseView, value: ReadableArray?) { + if (value != null && value.size() == 10) { + view.perPropertyTransitionDurations = IntArray(10) { value.getInt(it) } + } else { + view.perPropertyTransitionDurations = null + } + } + + @ReactProp(name = "perPropertyTransitionDampings") + fun setPerPropertyTransitionDampings(view: EaseView, value: ReadableArray?) { + if (value != null && value.size() == 10) { + view.perPropertyTransitionDampings = FloatArray(10) { value.getDouble(it).toFloat() } + } else { + view.perPropertyTransitionDampings = null + } + } + + @ReactProp(name = "perPropertyTransitionStiffnesses") + fun setPerPropertyTransitionStiffnesses(view: EaseView, value: ReadableArray?) { + if (value != null && value.size() == 10) { + view.perPropertyTransitionStiffnesses = FloatArray(10) { value.getDouble(it).toFloat() } + } else { + view.perPropertyTransitionStiffnesses = null + } + } + + @ReactProp(name = "perPropertyTransitionMasses") + fun setPerPropertyTransitionMasses(view: EaseView, value: ReadableArray?) { + if (value != null && value.size() == 10) { + view.perPropertyTransitionMasses = FloatArray(10) { value.getDouble(it).toFloat() } + } else { + view.perPropertyTransitionMasses = null + } + } + + @ReactProp(name = "perPropertyTransitionLoops") + fun setPerPropertyTransitionLoops(view: EaseView, value: ReadableArray?) { + if (value != null && value.size() == 10) { + view.perPropertyTransitionLoops = Array(10) { value.getString(it) ?: "" } + } else { + view.perPropertyTransitionLoops = null + } + } + + @ReactProp(name = "perPropertyTransitionEasingBeziers") + fun setPerPropertyTransitionEasingBeziers(view: EaseView, value: ReadableArray?) { + if (value != null && value.size() == 40) { + view.perPropertyTransitionEasingBeziers = FloatArray(40) { value.getDouble(it).toFloat() } + } else { + view.perPropertyTransitionEasingBeziers = null + } + } // --- Border radius --- diff --git a/example/pnpm-lock.yaml b/example/pnpm-lock.yaml new file mode 100644 index 0000000..4b369d7 --- /dev/null +++ b/example/pnpm-lock.yaml @@ -0,0 +1,5986 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + react: + specifier: 19.2.0 + version: 19.2.0 + react-native: + specifier: 0.83.0 + version: 0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0) + react-native-reanimated: + specifier: ^4.2.2 + version: 4.2.2(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react-native-safe-area-context: + specifier: ^5.7.0 + version: 5.7.0(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react-native-worklets: + specifier: ^0.7.4 + version: 0.7.4(@babel/core@7.29.0)(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + devDependencies: + '@babel/core': + specifier: ^7.25.2 + version: 7.29.0 + '@babel/preset-env': + specifier: ^7.25.3 + version: 7.29.0(@babel/core@7.29.0) + '@babel/runtime': + specifier: ^7.25.0 + version: 7.28.6 + '@react-native-community/cli': + specifier: 20.0.0 + version: 20.0.0 + '@react-native-community/cli-platform-android': + specifier: 20.0.0 + version: 20.0.0 + '@react-native-community/cli-platform-ios': + specifier: 20.0.0 + version: 20.0.0 + '@react-native/babel-preset': + specifier: 0.83.0 + version: 0.83.0(@babel/core@7.29.0) + '@react-native/metro-config': + specifier: 0.83.0 + version: 0.83.0(@babel/core@7.29.0) + '@react-native/typescript-config': + specifier: 0.83.0 + version: 0.83.0 + '@types/react': + specifier: ^19.2.0 + version: 19.2.14 + react-native-builder-bob: + specifier: ^0.40.18 + version: 0.40.18 + react-native-monorepo-config: + specifier: ^0.3.3 + version: 0.3.3 + +packages: + + '@ark/schema@0.56.0': + resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==} + + '@ark/util@0.56.0': + resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-define-polyfill-provider@0.6.7': + resolution: {integrity: sha512-6Fqi8MtQ/PweQ9xvux65emkLQ83uB+qAVtfHkC9UodyHMIZdxNI01HjLCLUtybElp2KY2XNE0nOgyP1E1vXw9w==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-remap-async-to-generator@7.27.1': + resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-wrap-function@7.28.6': + resolution: {integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': + resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': + resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': + resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6': + resolution: {integrity: sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-proposal-export-default-from@7.27.1': + resolution: {integrity: sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-dynamic-import@7.8.3': + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-export-default-from@7.28.6': + resolution: {integrity: sha512-Svlx1fjJFnNz0LZeUaybRukSxZI3KkpApUmIRzEdXC5k8ErTOz0OD0kNrICi5Vc3GlpP5ZCeRyRO+mfWTSz+iQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-flow@7.28.6': + resolution: {integrity: sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-assertions@7.28.6': + resolution: {integrity: sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-arrow-functions@7.27.1': + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-generator-functions@7.29.0': + resolution: {integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-to-generator@7.28.6': + resolution: {integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoped-functions@7.27.1': + resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoping@7.28.6': + resolution: {integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-properties@7.27.1': + resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-properties@7.28.6': + resolution: {integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-static-block@7.28.6': + resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + + '@babel/plugin-transform-classes@7.28.4': + resolution: {integrity: sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-classes@7.28.6': + resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-computed-properties@7.28.6': + resolution: {integrity: sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-dotall-regex@7.28.6': + resolution: {integrity: sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-keys@7.27.1': + resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-dynamic-import@7.27.1': + resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-explicit-resource-management@7.28.6': + resolution: {integrity: sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-exponentiation-operator@7.28.6': + resolution: {integrity: sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-export-namespace-from@7.27.1': + resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-flow-strip-types@7.27.1': + resolution: {integrity: sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-for-of@7.27.1': + resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-function-name@7.27.1': + resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-json-strings@7.28.6': + resolution: {integrity: sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-literals@7.27.1': + resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-logical-assignment-operators@7.28.6': + resolution: {integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-member-expression-literals@7.27.1': + resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-amd@7.27.1': + resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.28.6': + resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-systemjs@7.29.0': + resolution: {integrity: sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-umd@7.27.1': + resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-new-target@7.27.1': + resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': + resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6': + resolution: {integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-numeric-separator@7.28.6': + resolution: {integrity: sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-rest-spread@7.28.6': + resolution: {integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-super@7.27.1': + resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-catch-binding@7.28.6': + resolution: {integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.27.1': + resolution: {integrity: sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.28.6': + resolution: {integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.27.7': + resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.28.6': + resolution: {integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.28.6': + resolution: {integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-property-literals@7.27.1': + resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-display-name@7.28.0': + resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-development@7.27.1': + resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx@7.28.6': + resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-pure-annotations@7.27.1': + resolution: {integrity: sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.29.0': + resolution: {integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.28.6': + resolution: {integrity: sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.27.1': + resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-runtime@7.29.0': + resolution: {integrity: sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.27.1': + resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.28.6': + resolution: {integrity: sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.27.1': + resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-strict-mode@7.27.1': + resolution: {integrity: sha512-cdA1TyX9NfOaV8PILyNSrzJxXnjk4UeAgSwSLDCepfOg9AlxCg5al0KWsFh0ZJRzp6k5gwpSlJ4auWT+gx46ig==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-template-literals@7.27.1': + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typeof-symbol@7.27.1': + resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-escapes@7.27.1': + resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-property-regex@7.28.6': + resolution: {integrity: sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.27.1': + resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-sets-regex@7.28.6': + resolution: {integrity: sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/preset-env@7.29.0': + resolution: {integrity: sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-modules@0.1.6-no-external-plugins': + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + + '@babel/preset-react@7.28.5': + resolution: {integrity: sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.27.1': + resolution: {integrity: sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/ttlcache@1.4.1': + resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} + engines: {node: '>=12'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/create-cache-key-function@29.7.0': + resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@react-native-community/cli-clean@20.0.0': + resolution: {integrity: sha512-YmdNRcT+Dp8lC7CfxSDIfPMbVPEXVFzBH62VZNbYGxjyakqAvoQUFTYPgM2AyFusAr4wDFbDOsEv88gCDwR3ig==} + + '@react-native-community/cli-config-android@20.0.0': + resolution: {integrity: sha512-asv60qYCnL1v0QFWcG9r1zckeFlKG+14GGNyPXY72Eea7RX5Cxdx8Pb6fIPKroWH1HEWjYH9KKHksMSnf9FMKw==} + + '@react-native-community/cli-config-apple@20.0.0': + resolution: {integrity: sha512-PS1gNOdpeQ6w7dVu1zi++E+ix2D0ZkGC2SQP6Y/Qp002wG4se56esLXItYiiLrJkhH21P28fXdmYvTEkjSm9/Q==} + + '@react-native-community/cli-config@20.0.0': + resolution: {integrity: sha512-5Ky9ceYuDqG62VIIpbOmkg8Lybj2fUjf/5wK4UO107uRqejBgNgKsbGnIZgEhREcaSEOkujWrroJ9gweueLfBg==} + + '@react-native-community/cli-doctor@20.0.0': + resolution: {integrity: sha512-cPHspi59+Fy41FDVxt62ZWoicCZ1o34k8LAl64NVSY0lwPl+CEi78jipXJhtfkVqSTetloA8zexa/vSAcJy57Q==} + + '@react-native-community/cli-platform-android@20.0.0': + resolution: {integrity: sha512-th3ji1GRcV6ACelgC0wJtt9daDZ+63/52KTwL39xXGoqczFjml4qERK90/ppcXU0Ilgq55ANF8Pr+UotQ2AB/A==} + + '@react-native-community/cli-platform-apple@20.0.0': + resolution: {integrity: sha512-rZZCnAjUHN1XBgiWTAMwEKpbVTO4IHBSecdd1VxJFeTZ7WjmstqA6L/HXcnueBgxrzTCRqvkRIyEQXxC1OfhGw==} + + '@react-native-community/cli-platform-ios@20.0.0': + resolution: {integrity: sha512-Z35M+4gUJgtS4WqgpKU9/XYur70nmj3Q65c9USyTq6v/7YJ4VmBkmhC9BticPs6wuQ9Jcv0NyVCY0Wmh6kMMYw==} + + '@react-native-community/cli-server-api@20.0.0': + resolution: {integrity: sha512-Ves21bXtjUK3tQbtqw/NdzpMW1vR2HvYCkUQ/MXKrJcPjgJnXQpSnTqHXz6ZdBlMbbwLJXOhSPiYzxb5/v4CDg==} + + '@react-native-community/cli-tools@20.0.0': + resolution: {integrity: sha512-akSZGxr1IajJ8n0YCwQoA3DI0HttJ0WB7M3nVpb0lOM+rJpsBN7WG5Ft+8ozb6HyIPX+O+lLeYazxn5VNG/Xhw==} + + '@react-native-community/cli-types@20.0.0': + resolution: {integrity: sha512-7J4hzGWOPTBV1d30Pf2NidV+bfCWpjfCOiGO3HUhz1fH4MvBM0FbbBmE9LE5NnMz7M8XSRSi68ZGYQXgLBB2Qw==} + + '@react-native-community/cli@20.0.0': + resolution: {integrity: sha512-/cMnGl5V1rqnbElY1Fvga1vfw0d3bnqiJLx2+2oh7l9ulnXfVRWb5tU2kgBqiMxuDOKA+DQoifC9q/tvkj5K2w==} + engines: {node: '>=18'} + hasBin: true + + '@react-native/assets-registry@0.83.0': + resolution: {integrity: sha512-EmGSKDvmnEnBrTK75T+0Syt6gy/HACOTfziw5+392Kr1Bb28Rv26GyOIkvptnT+bb2VDHU0hx9G0vSy5/S3rmQ==} + engines: {node: '>= 20.19.4'} + + '@react-native/babel-plugin-codegen@0.83.0': + resolution: {integrity: sha512-H5K0hnv9EhcenojZb9nUMIKPvHZ7ba9vpCyQIeGJmUTDYwZqjmXXyH73+uZo+GHjCIq1n0eF/soC5HJQzalh/Q==} + engines: {node: '>= 20.19.4'} + + '@react-native/babel-preset@0.83.0': + resolution: {integrity: sha512-v20aTae9+aergUgRQSiy3CLqRSJu5VrHLpPpyYcAkTJ2JWTbtTlKfYuEw0V/WMFpeYZnZ7IVtu/6gTISVV74UQ==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@babel/core': '*' + + '@react-native/codegen@0.83.0': + resolution: {integrity: sha512-3fvMi/pSJHhikjwMZQplU4Ar9ANoR2GSBxotbkKIMI6iNduh+ln1FTvB2me69FA68aHtVZOO+cO+QpGCcvgaMA==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@babel/core': '*' + + '@react-native/community-cli-plugin@0.83.0': + resolution: {integrity: sha512-bJD5pLURgKY2YK0R6gUsFWHiblSAFt1Xyc2fsyCL8XBnB7kJfVhLAKGItk6j1QZbwm1Io41ekZxBmZdyQqIDrg==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@react-native-community/cli': '*' + '@react-native/metro-config': '*' + peerDependenciesMeta: + '@react-native-community/cli': + optional: true + '@react-native/metro-config': + optional: true + + '@react-native/debugger-frontend@0.83.0': + resolution: {integrity: sha512-7XVbkH8nCjLKLe8z5DS37LNP62/QNNya/YuLlVoLfsiB54nR/kNZij5UU7rS0npAZ3WN7LR0anqLlYnzDd0JHA==} + engines: {node: '>= 20.19.4'} + + '@react-native/debugger-shell@0.83.0': + resolution: {integrity: sha512-rJJxRRLLsKW+cqd0ALSBoqwL5SQTmwpd5SGl6rq9sY+fInCUKfkLEIc5HWQ0ppqoPyDteQVWbQ3a5VN84aJaNg==} + engines: {node: '>= 20.19.4'} + + '@react-native/dev-middleware@0.83.0': + resolution: {integrity: sha512-HWn42tbp0h8RWttua6d6PjseaSr3IdwkaoqVxhiM9kVDY7Ro00eO7tdlVgSzZzhIibdVS2b2C3x+sFoWhag1fA==} + engines: {node: '>= 20.19.4'} + + '@react-native/gradle-plugin@0.83.0': + resolution: {integrity: sha512-BXZRmfsbgPhEPkrRPjk2njA2AzhSelBqhuoklnv3DdLTdxaRjKYW+LW0zpKo1k3qPKj7kG1YGI3miol6l1GB5g==} + engines: {node: '>= 20.19.4'} + + '@react-native/js-polyfills@0.83.0': + resolution: {integrity: sha512-cVB9BMqlfbQR0v4Wxi5M2yDhZoKiNqWgiEXpp7ChdZIXI0SEnj8WwLwE3bDkyOfF8tCHdytpInXyg/al2O+dLQ==} + engines: {node: '>= 20.19.4'} + + '@react-native/metro-babel-transformer@0.83.0': + resolution: {integrity: sha512-hB5kpR5Ho9l9xKuh5uHZEIFqnuaW8T7rDYwqf1j0xvTZu88KwaHAXya2IpDZsjlWzVMCl50cAwPkVZOlEOfJvw==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@babel/core': '*' + + '@react-native/metro-config@0.83.0': + resolution: {integrity: sha512-7mWZNZOJJLMJ8adBrAgAXcwtyn8PtPjAGavK8k3/mtsWYm79ncf5PD8D9puh6wBHCYwPu2ff/l23nNV8JsqLyg==} + engines: {node: '>= 20.19.4'} + + '@react-native/normalize-colors@0.83.0': + resolution: {integrity: sha512-DG1ELOqQ6RS82R1zEUGTWa/pfSPOf+vwAnQB7Ao1vRuhW/xdd2OPQJyqx5a5QWMYpGrlkCb7ERxEVX6p2QODCA==} + + '@react-native/typescript-config@0.83.0': + resolution: {integrity: sha512-8IcgamT0qoBDL3D8Ho6YHkQrxUMf3fKHkRd6MYDjVKNamz0XtfXNLY/FNnUOolx1HbgMkkwKFcbP3AbIKFxirQ==} + + '@react-native/virtualized-lists@0.83.0': + resolution: {integrity: sha512-AVnDppwPidQrPrzA4ETr4o9W+40yuijg3EVgFt2hnMldMZkqwPRrgJL2GSreQjCYe1NfM5Yn4Egyy4Kd0yp4Lw==} + engines: {node: '>= 20.19.4'} + peerDependencies: + '@types/react': ^19.2.0 + react: '*' + react-native: '*' + peerDependenciesMeta: + '@types/react': + optional: true + + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + + '@types/react@19.2.14': + resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + + '@vscode/sudo-prompt@9.3.2': + resolution: {integrity: sha512-gcXoCN00METUNFeQOFJ+C9xUI0DKB+0EGMVg7wbVYRHBw2Eq3fKisDZOkRdOz3kqXRKOENMfShPOmypw1/8nOw==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + anser@1.4.10: + resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} + + ansi-fragments@0.2.1: + resolution: {integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==} + + ansi-regex@4.1.1: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + appdirsjs@1.2.7: + resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + arkregex@0.0.5: + resolution: {integrity: sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==} + + arktype@2.2.0: + resolution: {integrity: sha512-t54MZ7ti5BhOEvzEkgKnWvqj+UbDfWig+DHr5I34xatymPusKLS0lQpNJd8M6DzmIto2QGszHfNKoFIT8tMCZQ==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + astral-regex@1.0.0: + resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} + engines: {node: '>=4'} + + async-limiter@1.0.1: + resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-plugin-polyfill-corejs2@0.4.16: + resolution: {integrity: sha512-xaVwwSfebXf0ooE11BJovZYKhFjIvQo7TsyVpETuIeH2JHv0k/T6Y5j22pPTvqYqmpkxdlPAJlyJ0tfOJAoMxw==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.13.0: + resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.14.1: + resolution: {integrity: sha512-ENp89vM9Pw4kv/koBb5N2f9bDZsR0hpf3BdPMOg/pkS3pwO4dzNnQZVXtBbeyAadgm865DmQG2jMMLqmZXvuCw==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.7: + resolution: {integrity: sha512-OTYbUlSwXhNgr4g6efMZgsO8//jA61P7ZbRX3iTT53VON8l+WQS8IAUEVo4a4cWknrg2W8Cj4gQhRYNCJ8GkAA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-syntax-hermes-parser@0.28.1: + resolution: {integrity: sha512-meT17DOuUElMNsL5LZN56d+KBp22hb0EfxWfuPUeoSi54e40v1W4C2V36P75FpsH9fVEfDKpw5Nnkahc8haSsQ==} + + babel-plugin-syntax-hermes-parser@0.32.0: + resolution: {integrity: sha512-m5HthL++AbyeEA2FcdwOLfVFvWYECOBObLHNqdR8ceY4TsEdn4LdX2oTvbB2QJSSElE2AWA/b2MXZ/PF/CqLZg==} + + babel-plugin-transform-flow-enums@0.0.2: + resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} + + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} + peerDependencies: + '@babel/core': ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.10.8: + resolution: {integrity: sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + body-parser@1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001779: + resolution: {integrity: sha512-U5og2PN7V4DMgF50YPNtnZJGWVLFjjsN3zb6uMT5VGYIewieDj1upwfuVNXf4Kor+89c3iCRJnSzMD5LmTvsfA==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chrome-launcher@0.15.2: + resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} + engines: {node: '>=12.13.0'} + hasBin: true + + chromium-edge-launcher@0.2.0: + resolution: {integrity: sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==} + + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + + command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + + compression@1.8.1: + resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} + engines: {node: '>= 0.8.0'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + core-js-compat@3.48.0: + resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} + + cosmiconfig@9.0.1: + resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + dedent@0.7.0: + resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + + del@6.1.1: + resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} + engines: {node: '>=10'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.313: + resolution: {integrity: sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + envinfo@7.21.0: + resolution: {integrity: sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==} + engines: {node: '>=4'} + hasBin: true + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + + errorhandler@1.5.2: + resolution: {integrity: sha512-kNAL7hESndBCrWwS72QyV3IVOTrVmj9D062FV5BQswNL5zEdeRmz/WJFyh6Aj/plvvSOrzddkxW57HgkZcR9Fw==} + engines: {node: '>= 0.8'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + execa@4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-xml-parser@4.5.4: + resolution: {integrity: sha512-jE8ugADnYOBsu1uaoayVl1tVKAMNOXyjwvv2U6udEA2ORBhDooJDWoGxTkhd4Qn4yh59JVVt/pKXtjPwx9OguQ==} + hasBin: true + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fb-dotslash@0.5.8: + resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} + engines: {node: '>=20'} + hasBin: true + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flow-enums-runtime@0.0.6: + resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hermes-compiler@0.14.0: + resolution: {integrity: sha512-clxa193o+GYYwykWVFfpHduCATz8fR5jvU7ngXpfKHj+E9hr9vjLNtdLSEe8MUbObvVexV3wcyxQ00xTPIrB1Q==} + + hermes-estree@0.28.1: + resolution: {integrity: sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==} + + hermes-estree@0.32.0: + resolution: {integrity: sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==} + + hermes-estree@0.33.3: + resolution: {integrity: sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==} + + hermes-parser@0.28.1: + resolution: {integrity: sha512-nf8o+hE8g7UJWParnccljHumE9Vlq8F7MqIdeahl+4x0tvCUJYRrT0L7h0MMg/X9YJmkNwsfbaNNrzPtFXOscg==} + + hermes-parser@0.32.0: + resolution: {integrity: sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==} + + hermes-parser@0.33.3: + resolution: {integrity: sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + human-signals@1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + image-size@1.2.1: + resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} + engines: {node: '>=16.x'} + hasBin: true + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + + is-absolute@1.0.0: + resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==} + engines: {node: '>=0.10.0'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-git-dirty@2.0.2: + resolution: {integrity: sha512-U3YCo+GKR/rDsY7r0v/LBICbQwsx859tDQnAT+v0E/zCDeWbQ1TUt1FtyExeyik7VIJlYOLHCIifLdz71HDalg==} + engines: {node: '>=10'} + + is-git-repository@2.0.0: + resolution: {integrity: sha512-HDO50CG5suIAcmqG4F1buqVXEZRPn+RaXIn9pFKq/947FBo2bCRwK7ZluEVZOy99a4IQyqsjbKEpAiOXCccOHQ==} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-cwd@2.2.0: + resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} + engines: {node: '>=6'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-relative@1.0.0: + resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==} + engines: {node: '>=0.10.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-unc-path@1.0.0: + resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==} + engines: {node: '>=0.10.0'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + joi@17.13.3: + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsc-safe-url@0.2.4: + resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + launch-editor@2.13.1: + resolution: {integrity: sha512-lPSddlAAluRKJ7/cjRFoXUFzaX7q/YKI7yPHuEvSJVqoXvFnJov1/Ud87Aa4zULIbA9Nja4mSPK8l0z/7eV2wA==} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + lighthouse-logger@1.4.2: + resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + + lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + logkitty@0.7.1: + resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} + hasBin: true + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + marky@1.3.0: + resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + metro-babel-transformer@0.83.5: + resolution: {integrity: sha512-d9FfmgUEVejTiSb7bkQeLRGl6aeno2UpuPm3bo3rCYwxewj03ymvOn8s8vnS4fBqAPQ+cE9iQM40wh7nGXR+eA==} + engines: {node: '>=20.19.4'} + + metro-cache-key@0.83.5: + resolution: {integrity: sha512-Ycl8PBajB7bhbAI7Rt0xEyiF8oJ0RWX8EKkolV1KfCUlC++V/GStMSGpPLwnnBZXZWkCC5edBPzv1Hz1Yi0Euw==} + engines: {node: '>=20.19.4'} + + metro-cache@0.83.5: + resolution: {integrity: sha512-oH+s4U+IfZyg8J42bne2Skc90rcuESIYf86dYittcdWQtPfcaFXWpByPyTuWk3rR1Zz3Eh5HOrcVImfEhhJLng==} + engines: {node: '>=20.19.4'} + + metro-config@0.83.5: + resolution: {integrity: sha512-JQ/PAASXH7yczgV6OCUSRhZYME+NU8NYjI2RcaG5ga4QfQ3T/XdiLzpSb3awWZYlDCcQb36l4Vl7i0Zw7/Tf9w==} + engines: {node: '>=20.19.4'} + + metro-core@0.83.5: + resolution: {integrity: sha512-YcVcLCrf0ed4mdLa82Qob0VxYqfhmlRxUS8+TO4gosZo/gLwSvtdeOjc/Vt0pe/lvMNrBap9LlmvZM8FIsMgJQ==} + engines: {node: '>=20.19.4'} + + metro-file-map@0.83.5: + resolution: {integrity: sha512-ZEt8s3a1cnYbn40nyCD+CsZdYSlwtFh2kFym4lo+uvfM+UMMH+r/BsrC6rbNClSrt+B7rU9T+Te/sh/NL8ZZKQ==} + engines: {node: '>=20.19.4'} + + metro-minify-terser@0.83.5: + resolution: {integrity: sha512-Toe4Md1wS1PBqbvB0cFxBzKEVyyuYTUb0sgifAZh/mSvLH84qA1NAWik9sISWatzvfWf3rOGoUoO5E3f193a3Q==} + engines: {node: '>=20.19.4'} + + metro-resolver@0.83.5: + resolution: {integrity: sha512-7p3GtzVUpbAweJeCcUJihJeOQl1bDuimO5ueo1K0BUpUtR41q5EilbQ3klt16UTPPMpA+tISWBtsrqU556mY1A==} + engines: {node: '>=20.19.4'} + + metro-runtime@0.83.5: + resolution: {integrity: sha512-f+b3ue9AWTVlZe2Xrki6TAoFtKIqw30jwfk7GQ1rDUBQaE0ZQ+NkiMEtb9uwH7uAjJ87U7Tdx1Jg1OJqUfEVlA==} + engines: {node: '>=20.19.4'} + + metro-source-map@0.83.5: + resolution: {integrity: sha512-VT9bb2KO2/4tWY9Z2yeZqTUao7CicKAOps9LUg2aQzsz+04QyuXL3qgf1cLUVRjA/D6G5u1RJAlN1w9VNHtODQ==} + engines: {node: '>=20.19.4'} + + metro-symbolicate@0.83.5: + resolution: {integrity: sha512-EMIkrjNRz/hF+p0RDdxoE60+dkaTLPN3vaaGkFmX5lvFdO6HPfHA/Ywznzkev+za0VhPQ5KSdz49/MALBRteHA==} + engines: {node: '>=20.19.4'} + hasBin: true + + metro-transform-plugins@0.83.5: + resolution: {integrity: sha512-KxYKzZL+lt3Os5H2nx7YkbkWVduLZL5kPrE/Yq+Prm/DE1VLhpfnO6HtPs8vimYFKOa58ncl60GpoX0h7Wm0Vw==} + engines: {node: '>=20.19.4'} + + metro-transform-worker@0.83.5: + resolution: {integrity: sha512-8N4pjkNXc6ytlP9oAM6MwqkvUepNSW39LKYl9NjUMpRDazBQ7oBpQDc8Sz4aI8jnH6AGhF7s1m/ayxkN1t04yA==} + engines: {node: '>=20.19.4'} + + metro@0.83.5: + resolution: {integrity: sha512-BgsXevY1MBac/3ZYv/RfNFf/4iuW9X7f4H8ZNkiH+r667HD9sVujxcmu4jvEzGCAm4/WyKdZCuyhAcyhTHOucQ==} + engines: {node: '>=20.19.4'} + hasBin: true + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + nocache@3.0.4: + resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==} + engines: {node: '>=12.0.0'} + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + + node-stream-zip@1.15.0: + resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} + engines: {node: '>=0.12.0'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + + ob1@0.83.5: + resolution: {integrity: sha512-vNKPYC8L5ycVANANpF/S+WZHpfnRWKx/F3AYP4QMn6ZJTh+l2HOrId0clNkEmua58NB9vmI9Qh7YOoV/4folYg==} + engines: {node: '>=20.19.4'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + on-headers@1.1.0: + resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + open@6.4.0: + resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} + engines: {node: '>=8'} + + open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + promise@8.3.0: + resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + qs@6.14.2: + resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + + react-devtools-core@6.1.5: + resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-native-builder-bob@0.40.18: + resolution: {integrity: sha512-vGd6l/iaMirnVucQlm2OJWTDQjxbYxHNmqXtDRWXMRubwotKKycx1ARj/aJYbzbCdzHBB00bGzYEhUcq4sbGog==} + engines: {node: ^20.19.0 || ^22.12.0 || >= 23.4.0} + hasBin: true + + react-native-is-edge-to-edge@1.2.1: + resolution: {integrity: sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==} + peerDependencies: + react: '*' + react-native: '*' + + react-native-monorepo-config@0.3.3: + resolution: {integrity: sha512-d1kjHRVsbd/yVkFb5rYxWYiWVzCqJgUzcc499ejfc8jH6q6XYB4U+dNpX/HsxdXZLpzEhmKvgq0PsjRAIdAVeA==} + + react-native-reanimated@4.2.2: + resolution: {integrity: sha512-o3kKvdD8cVlg12Z4u3jv0MFAt53QV4k7gD9OLwQqU8eZLyd8QvaOjVZIghMZhC2pjP93uUU44PlO5JgF8S4Vxw==} + peerDependencies: + react: '*' + react-native: '*' + react-native-worklets: '>=0.7.0' + + react-native-safe-area-context@5.7.0: + resolution: {integrity: sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ==} + peerDependencies: + react: '*' + react-native: '*' + + react-native-worklets@0.7.4: + resolution: {integrity: sha512-NYOdM1MwBb3n+AtMqy1tFy3Mn8DliQtd8sbzAVRf9Gc+uvQ0zRfxN7dS8ZzoyX7t6cyQL5THuGhlnX+iFlQTag==} + peerDependencies: + '@babel/core': '*' + react: '*' + react-native: '*' + + react-native@0.83.0: + resolution: {integrity: sha512-a8wPjGfkktb1+Mjvzkky3d0u6j6zdWAzftZ2LdQtgRgqkMMfgQxD9S+ri3RNlfAFQpuCAOYUIyrNHiVkUQChxA==} + engines: {node: '>= 20.19.4'} + hasBin: true + peerDependencies: + '@types/react': ^19.1.1 + react: ^19.2.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} + engines: {node: '>=4'} + + regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} + engines: {node: '>=4'} + + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.13.0: + resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} + hasBin: true + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} + engines: {node: '>= 0.8.0'} + + serialize-error@2.1.0: + resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} + engines: {node: '>=0.10.0'} + + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} + engines: {node: '>= 0.8.0'} + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slice-ansi@2.1.0: + resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} + engines: {node: '>=6'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + stacktrace-parser@0.1.11: + resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} + engines: {node: '>=6'} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@5.2.0: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strnum@1.1.2: + resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + terser@5.46.0: + resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} + engines: {node: '>=10'} + hasBin: true + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + throat@5.0.0: + resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + unc-path-regex@0.1.2: + resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==} + engines: {node: '>=0.10.0'} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + + unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} + engines: {node: '>=4'} + + unicode-property-aliases-ecmascript@2.2.0: + resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} + engines: {node: '>=4'} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vlq@1.0.1: + resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + ws@6.2.3: + resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ark/schema@0.56.0': + dependencies: + '@ark/util': 0.56.0 + + '@ark/util@0.56.0': {} + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + regexpu-core: 6.4.0 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.6.7(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + debug: 4.4.3 + lodash.debounce: 4.0.8 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-wrap-function': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helper-wrap-function@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-export-default-from@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-export-default-from@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-flow@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.28.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/template': 7.28.6 + + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-flow-strip-types@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-flow': 7.28.6(@babel/core@7.29.0) + + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-runtime@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + babel-plugin-polyfill-corejs2: 0.4.16(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.7(@babel/core@7.29.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-strict-mode@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/preset-env@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) + '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-systemjs': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.29.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0) + babel-plugin-polyfill-corejs2: 0.4.16(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.14.1(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.7(@babel/core@7.29.0) + core-js-compat: 3.48.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.0 + esutils: 2.0.3 + + '@babel/preset-react@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/runtime@7.28.6': {} + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@hapi/hoek@9.3.0': {} + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/ttlcache@1.4.1': {} + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.2 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/create-cache-key-function@29.7.0': + dependencies: + '@jest/types': 29.6.3 + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 25.5.0 + jest-mock: 29.7.0 + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 25.5.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.10 + + '@jest/transform@29.7.0': + dependencies: + '@babel/core': 7.29.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 25.5.0 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@react-native-community/cli-clean@20.0.0': + dependencies: + '@react-native-community/cli-tools': 20.0.0 + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.3 + + '@react-native-community/cli-config-android@20.0.0': + dependencies: + '@react-native-community/cli-tools': 20.0.0 + chalk: 4.1.2 + fast-glob: 3.3.3 + fast-xml-parser: 4.5.4 + + '@react-native-community/cli-config-apple@20.0.0': + dependencies: + '@react-native-community/cli-tools': 20.0.0 + chalk: 4.1.2 + execa: 5.1.1 + fast-glob: 3.3.3 + + '@react-native-community/cli-config@20.0.0': + dependencies: + '@react-native-community/cli-tools': 20.0.0 + chalk: 4.1.2 + cosmiconfig: 9.0.1 + deepmerge: 4.3.1 + fast-glob: 3.3.3 + joi: 17.13.3 + transitivePeerDependencies: + - typescript + + '@react-native-community/cli-doctor@20.0.0': + dependencies: + '@react-native-community/cli-config': 20.0.0 + '@react-native-community/cli-platform-android': 20.0.0 + '@react-native-community/cli-platform-apple': 20.0.0 + '@react-native-community/cli-platform-ios': 20.0.0 + '@react-native-community/cli-tools': 20.0.0 + chalk: 4.1.2 + command-exists: 1.2.9 + deepmerge: 4.3.1 + envinfo: 7.21.0 + execa: 5.1.1 + node-stream-zip: 1.15.0 + ora: 5.4.1 + semver: 7.7.4 + wcwidth: 1.0.1 + yaml: 2.8.2 + transitivePeerDependencies: + - typescript + + '@react-native-community/cli-platform-android@20.0.0': + dependencies: + '@react-native-community/cli-config-android': 20.0.0 + '@react-native-community/cli-tools': 20.0.0 + chalk: 4.1.2 + execa: 5.1.1 + logkitty: 0.7.1 + + '@react-native-community/cli-platform-apple@20.0.0': + dependencies: + '@react-native-community/cli-config-apple': 20.0.0 + '@react-native-community/cli-tools': 20.0.0 + chalk: 4.1.2 + execa: 5.1.1 + fast-xml-parser: 4.5.4 + + '@react-native-community/cli-platform-ios@20.0.0': + dependencies: + '@react-native-community/cli-platform-apple': 20.0.0 + + '@react-native-community/cli-server-api@20.0.0': + dependencies: + '@react-native-community/cli-tools': 20.0.0 + body-parser: 1.20.4 + compression: 1.8.1 + connect: 3.7.0 + errorhandler: 1.5.2 + nocache: 3.0.4 + open: 6.4.0 + pretty-format: 29.7.0 + serve-static: 1.16.3 + ws: 6.2.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native-community/cli-tools@20.0.0': + dependencies: + '@vscode/sudo-prompt': 9.3.2 + appdirsjs: 1.2.7 + chalk: 4.1.2 + execa: 5.1.1 + find-up: 5.0.0 + launch-editor: 2.13.1 + mime: 2.6.0 + ora: 5.4.1 + prompts: 2.4.2 + semver: 7.7.4 + + '@react-native-community/cli-types@20.0.0': + dependencies: + joi: 17.13.3 + + '@react-native-community/cli@20.0.0': + dependencies: + '@react-native-community/cli-clean': 20.0.0 + '@react-native-community/cli-config': 20.0.0 + '@react-native-community/cli-doctor': 20.0.0 + '@react-native-community/cli-server-api': 20.0.0 + '@react-native-community/cli-tools': 20.0.0 + '@react-native-community/cli-types': 20.0.0 + chalk: 4.1.2 + commander: 9.5.0 + deepmerge: 4.3.1 + execa: 5.1.1 + find-up: 5.0.0 + fs-extra: 8.1.0 + graceful-fs: 4.2.11 + prompts: 2.4.2 + semver: 7.7.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - typescript + - utf-8-validate + + '@react-native/assets-registry@0.83.0': {} + + '@react-native/babel-plugin-codegen@0.83.0(@babel/core@7.29.0)': + dependencies: + '@babel/traverse': 7.29.0 + '@react-native/codegen': 0.83.0(@babel/core@7.29.0) + transitivePeerDependencies: + - '@babel/core' + - supports-color + + '@react-native/babel-preset@0.83.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-export-default-from': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/template': 7.28.6 + '@react-native/babel-plugin-codegen': 0.83.0(@babel/core@7.29.0) + babel-plugin-syntax-hermes-parser: 0.32.0 + babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.0) + react-refresh: 0.14.2 + transitivePeerDependencies: + - supports-color + + '@react-native/codegen@0.83.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + glob: 7.2.3 + hermes-parser: 0.32.0 + invariant: 2.2.4 + nullthrows: 1.1.1 + yargs: 17.7.2 + + '@react-native/community-cli-plugin@0.83.0(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))': + dependencies: + '@react-native/dev-middleware': 0.83.0 + debug: 4.4.3 + invariant: 2.2.4 + metro: 0.83.5 + metro-config: 0.83.5 + metro-core: 0.83.5 + semver: 7.7.4 + optionalDependencies: + '@react-native-community/cli': 20.0.0 + '@react-native/metro-config': 0.83.0(@babel/core@7.29.0) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/debugger-frontend@0.83.0': {} + + '@react-native/debugger-shell@0.83.0': + dependencies: + cross-spawn: 7.0.6 + fb-dotslash: 0.5.8 + + '@react-native/dev-middleware@0.83.0': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.83.0 + '@react-native/debugger-shell': 0.83.0 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 0.2.0 + connect: 3.7.0 + debug: 4.4.3 + invariant: 2.2.4 + nullthrows: 1.1.1 + open: 7.4.2 + serve-static: 1.16.3 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/gradle-plugin@0.83.0': {} + + '@react-native/js-polyfills@0.83.0': {} + + '@react-native/metro-babel-transformer@0.83.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@react-native/babel-preset': 0.83.0(@babel/core@7.29.0) + hermes-parser: 0.32.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + '@react-native/metro-config@0.83.0(@babel/core@7.29.0)': + dependencies: + '@react-native/js-polyfills': 0.83.0 + '@react-native/metro-babel-transformer': 0.83.0(@babel/core@7.29.0) + metro-config: 0.83.5 + metro-runtime: 0.83.5 + transitivePeerDependencies: + - '@babel/core' + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/normalize-colors@0.83.0': {} + + '@react-native/typescript-config@0.83.0': {} + + '@react-native/virtualized-lists@0.83.0(@types/react@19.2.14)(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.0 + react-native: 0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.14 + + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} + + '@sinclair/typebox@0.27.10': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 25.5.0 + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/node@25.5.0': + dependencies: + undici-types: 7.18.2 + + '@types/react@19.2.14': + dependencies: + csstype: 3.2.3 + + '@types/stack-utils@2.0.3': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@vscode/sudo-prompt@9.3.2': {} + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + acorn@8.16.0: {} + + agent-base@7.1.4: {} + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + anser@1.4.10: {} + + ansi-fragments@0.2.1: + dependencies: + colorette: 1.4.0 + slice-ansi: 2.1.0 + strip-ansi: 5.2.0 + + ansi-regex@4.1.1: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.3: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + appdirsjs@1.2.7: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + arkregex@0.0.5: + dependencies: + '@ark/util': 0.56.0 + + arktype@2.2.0: + dependencies: + '@ark/schema': 0.56.0 + '@ark/util': 0.56.0 + arkregex: 0.0.5 + + array-union@2.1.0: {} + + asap@2.0.6: {} + + astral-regex@1.0.0: {} + + async-limiter@1.0.1: {} + + babel-jest@29.7.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.29.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.28.6 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.28.0 + + babel-plugin-polyfill-corejs2@0.4.16(@babel/core@7.29.0): + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.7(@babel/core@7.29.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.7(@babel/core@7.29.0) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.14.1(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.7(@babel/core@7.29.0) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.7(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.7(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + babel-plugin-syntax-hermes-parser@0.28.1: + dependencies: + hermes-parser: 0.28.1 + + babel-plugin-syntax-hermes-parser@0.32.0: + dependencies: + hermes-parser: 0.32.0 + + babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.29.0): + dependencies: + '@babel/plugin-syntax-flow': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - '@babel/core' + + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) + + babel-preset-jest@29.6.3(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.10.8: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + body-parser@1.20.4: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.14.2 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.8 + caniuse-lite: 1.0.30001779 + electron-to-chromium: 1.5.313 + node-releases: 2.0.36 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001779: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chrome-launcher@0.15.2: + dependencies: + '@types/node': 25.5.0 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + transitivePeerDependencies: + - supports-color + + chromium-edge-launcher@0.2.0: + dependencies: + '@types/node': 25.5.0 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + mkdirp: 1.0.4 + rimraf: 3.0.2 + transitivePeerDependencies: + - supports-color + + ci-info@2.0.0: {} + + ci-info@3.9.0: {} + + clean-stack@2.2.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-spinners@2.9.2: {} + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone@1.0.4: {} + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + colorette@1.4.0: {} + + command-exists@1.2.9: {} + + commander@12.1.0: {} + + commander@2.20.3: {} + + commander@9.5.0: {} + + compressible@2.0.18: + dependencies: + mime-db: 1.54.0 + + compression@1.8.1: + dependencies: + bytes: 3.1.2 + compressible: 2.0.18 + debug: 2.6.9 + negotiator: 0.6.4 + on-headers: 1.1.0 + safe-buffer: 5.2.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + concat-map@0.0.1: {} + + connect@3.7.0: + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + + content-type@1.0.5: {} + + convert-source-map@2.0.0: {} + + core-js-compat@3.48.0: + dependencies: + browserslist: 4.28.1 + + cosmiconfig@9.0.1: + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + dayjs@1.11.20: {} + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decamelize@1.2.0: {} + + dedent@0.7.0: {} + + deepmerge@4.3.1: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + del@6.1.1: + dependencies: + globby: 11.1.0 + graceful-fs: 4.2.11 + is-glob: 4.0.3 + is-path-cwd: 2.2.0 + is-path-inside: 3.0.3 + p-map: 4.0.0 + rimraf: 3.0.2 + slash: 3.0.0 + + depd@2.0.0: {} + + destroy@1.2.0: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.313: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + env-paths@2.2.1: {} + + envinfo@7.21.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + + errorhandler@1.5.2: + dependencies: + accepts: 1.3.8 + escape-html: 1.0.3 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + esprima@4.0.1: {} + + esutils@2.0.3: {} + + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + + execa@4.1.0: + dependencies: + cross-spawn: 7.0.6 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exponential-backoff@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-xml-parser@4.5.4: + dependencies: + strnum: 1.1.2 + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fb-dotslash@0.5.8: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@1.1.2: + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flow-enums-runtime@0.0.6: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fresh@0.5.2: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-package-type@0.1.0: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@5.2.0: + dependencies: + pump: 3.0.4 + + get-stream@6.0.1: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hermes-compiler@0.14.0: {} + + hermes-estree@0.28.1: {} + + hermes-estree@0.32.0: {} + + hermes-estree@0.33.3: {} + + hermes-parser@0.28.1: + dependencies: + hermes-estree: 0.28.1 + + hermes-parser@0.32.0: + dependencies: + hermes-estree: 0.32.0 + + hermes-parser@0.33.3: + dependencies: + hermes-estree: 0.33.3 + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + human-signals@1.1.1: {} + + human-signals@2.1.0: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + image-size@1.2.1: + dependencies: + queue: 6.0.2 + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + + is-absolute@1.0.0: + dependencies: + is-relative: 1.0.0 + is-windows: 1.0.2 + + is-arrayish@0.2.1: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-docker@2.2.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@2.0.0: {} + + is-fullwidth-code-point@3.0.0: {} + + is-git-dirty@2.0.2: + dependencies: + execa: 4.1.0 + is-git-repository: 2.0.0 + + is-git-repository@2.0.0: + dependencies: + execa: 4.1.0 + is-absolute: 1.0.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-interactive@1.0.0: {} + + is-number@7.0.0: {} + + is-path-cwd@2.2.0: {} + + is-path-inside@3.0.3: {} + + is-relative@1.0.0: + dependencies: + is-unc-path: 1.0.0 + + is-stream@2.0.1: {} + + is-unc-path@1.0.0: + dependencies: + unc-path-regex: 0.1.2 + + is-unicode-supported@0.1.0: {} + + is-windows@1.0.2: {} + + is-wsl@1.1.0: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jest-environment-node@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 25.5.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 25.5.0 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.29.0 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 25.5.0 + jest-util: 29.7.0 + + jest-regex-util@29.6.3: {} + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 25.5.0 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-worker@29.7.0: + dependencies: + '@types/node': 25.5.0 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + joi@17.13.3: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + + js-tokens@4.0.0: {} + + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsc-safe-url@0.2.4: {} + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json5@2.2.3: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + kleur@3.0.3: {} + + kleur@4.1.5: {} + + launch-editor@2.13.1: + dependencies: + picocolors: 1.1.1 + shell-quote: 1.8.3 + + leven@3.1.0: {} + + lighthouse-logger@1.4.2: + dependencies: + debug: 2.6.9 + marky: 1.3.0 + transitivePeerDependencies: + - supports-color + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.debounce@4.0.8: {} + + lodash.throttle@4.1.1: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + logkitty@0.7.1: + dependencies: + ansi-fragments: 0.2.1 + dayjs: 1.11.20 + yargs: 15.4.1 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + marky@1.3.0: {} + + math-intrinsics@1.1.0: {} + + media-typer@0.3.0: {} + + memoize-one@5.2.1: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + metro-babel-transformer@0.83.5: + dependencies: + '@babel/core': 7.29.0 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.33.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-cache-key@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-cache@0.83.5: + dependencies: + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.83.5 + transitivePeerDependencies: + - supports-color + + metro-config@0.83.5: + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.83.5 + metro-cache: 0.83.5 + metro-core: 0.83.5 + metro-runtime: 0.83.5 + yaml: 2.8.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro-core@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.83.5 + + metro-file-map@0.83.5: + dependencies: + debug: 4.4.3 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + + metro-minify-terser@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.46.0 + + metro-resolver@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-runtime@0.83.5: + dependencies: + '@babel/runtime': 7.28.6 + flow-enums-runtime: 0.0.6 + + metro-source-map@0.83.5: + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.83.5 + nullthrows: 1.1.1 + ob1: 0.83.5 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-symbolicate@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.83.5 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-transform-plugins@0.83.5: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-transform-worker@0.83.5: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + metro: 0.83.5 + metro-babel-transformer: 0.83.5 + metro-cache: 0.83.5 + metro-cache-key: 0.83.5 + metro-minify-terser: 0.83.5 + metro-source-map: 0.83.5 + metro-transform-plugins: 0.83.5 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro@0.83.5: + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + accepts: 2.0.0 + chalk: 4.1.2 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 4.4.3 + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.33.3 + image-size: 1.2.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.83.5 + metro-cache: 0.83.5 + metro-cache-key: 0.83.5 + metro-config: 0.83.5 + metro-core: 0.83.5 + metro-file-map: 0.83.5 + metro-resolver: 0.83.5 + metro-runtime: 0.83.5 + metro-source-map: 0.83.5 + metro-symbolicate: 0.83.5 + metro-transform-plugins: 0.83.5 + metro-transform-worker: 0.83.5 + mime-types: 3.0.2 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.10 + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mime@1.6.0: {} + + mime@2.6.0: {} + + mimic-fn@2.1.0: {} + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.0.2 + + minipass@7.1.3: {} + + mkdirp@1.0.4: {} + + ms@2.0.0: {} + + ms@2.1.3: {} + + negotiator@0.6.3: {} + + negotiator@0.6.4: {} + + negotiator@1.0.0: {} + + nocache@3.0.4: {} + + node-int64@0.4.0: {} + + node-releases@2.0.36: {} + + node-stream-zip@1.15.0: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + nullthrows@1.1.1: {} + + ob1@0.83.5: + dependencies: + flow-enums-runtime: 0.0.6 + + object-inspect@1.13.4: {} + + on-finished@2.3.0: + dependencies: + ee-first: 1.1.1 + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + on-headers@1.1.0: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + open@6.4.0: + dependencies: + is-wsl: 1.1.0 + + open@7.4.2: + dependencies: + is-docker: 2.2.1 + is-wsl: 2.2.0 + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-type@4.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pirates@4.0.7: {} + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + promise@8.3.0: + dependencies: + asap: 2.0.6 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + qs@6.14.2: + dependencies: + side-channel: 1.1.0 + + queue-microtask@1.2.3: {} + + queue@6.0.2: + dependencies: + inherits: 2.0.4 + + range-parser@1.2.1: {} + + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + react-devtools-core@6.1.5: + dependencies: + shell-quote: 1.8.3 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + react-is@18.3.1: {} + + react-native-builder-bob@0.40.18: + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-strict-mode': 7.27.1(@babel/core@7.29.0) + '@babel/preset-env': 7.29.0(@babel/core@7.29.0) + '@babel/preset-react': 7.28.5(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + arktype: 2.2.0 + babel-plugin-syntax-hermes-parser: 0.28.1 + browserslist: 4.28.1 + cross-spawn: 7.0.6 + dedent: 0.7.0 + del: 6.1.1 + escape-string-regexp: 4.0.0 + fs-extra: 10.1.0 + glob: 10.5.0 + is-git-dirty: 2.0.2 + json5: 2.2.3 + kleur: 4.1.5 + prompts: 2.4.2 + react-native-monorepo-config: 0.3.3 + which: 2.0.2 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + + react-native-is-edge-to-edge@1.2.1(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-native: 0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0) + + react-native-monorepo-config@0.3.3: + dependencies: + escape-string-regexp: 5.0.0 + fast-glob: 3.3.3 + + react-native-reanimated@4.2.2(react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-native: 0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0) + react-native-is-edge-to-edge: 1.2.1(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + react-native-worklets: 0.7.4(@babel/core@7.29.0)(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + semver: 7.7.3 + + react-native-safe-area-context@5.7.0(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-native: 0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0) + + react-native-worklets@0.7.4(@babel/core@7.29.0)(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/preset-typescript': 7.27.1(@babel/core@7.29.0) + convert-source-map: 2.0.0 + react: 19.2.0 + react-native: 0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0) + semver: 7.7.3 + transitivePeerDependencies: + - supports-color + + react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0): + dependencies: + '@jest/create-cache-key-function': 29.7.0 + '@react-native/assets-registry': 0.83.0 + '@react-native/codegen': 0.83.0(@babel/core@7.29.0) + '@react-native/community-cli-plugin': 0.83.0(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0)) + '@react-native/gradle-plugin': 0.83.0 + '@react-native/js-polyfills': 0.83.0 + '@react-native/normalize-colors': 0.83.0 + '@react-native/virtualized-lists': 0.83.0(@types/react@19.2.14)(react-native@0.83.0(@babel/core@7.29.0)(@react-native-community/cli@20.0.0)(@react-native/metro-config@0.83.0(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.0))(react@19.2.0) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-jest: 29.7.0(@babel/core@7.29.0) + babel-plugin-syntax-hermes-parser: 0.32.0 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + glob: 7.2.3 + hermes-compiler: 0.14.0 + invariant: 2.2.4 + jest-environment-node: 29.7.0 + memoize-one: 5.2.1 + metro-runtime: 0.83.5 + metro-source-map: 0.83.5 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.0 + react-devtools-core: 6.1.5 + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.7.4 + stacktrace-parser: 0.1.11 + whatwg-fetch: 3.6.20 + ws: 7.5.10 + yargs: 17.7.2 + optionalDependencies: + '@types/react': 19.2.14 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate + + react-refresh@0.14.2: {} + + react@19.2.0: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + regenerate-unicode-properties@10.2.2: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + + regenerator-runtime@0.13.11: {} + + regexpu-core@6.4.0: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.0 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.1 + + regjsgen@0.8.0: {} + + regjsparser@0.13.0: + dependencies: + jsesc: 3.1.0 + + require-directory@2.1.1: {} + + require-main-filename@2.0.0: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + reusify@1.1.0: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.7.3: {} + + semver@7.7.4: {} + + send@0.19.2: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serialize-error@2.1.0: {} + + serve-static@1.16.3: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2 + transitivePeerDependencies: + - supports-color + + set-blocking@2.0.0: {} + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.8.3: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + slice-ansi@2.1.0: + dependencies: + ansi-styles: 3.2.1 + astral-regex: 1.0.0 + is-fullwidth-code-point: 2.0.0 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.5.7: {} + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + stackframe@1.3.4: {} + + stacktrace-parser@0.1.11: + dependencies: + type-fest: 0.7.1 + + statuses@1.5.0: {} + + statuses@2.0.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@5.2.0: + dependencies: + ansi-regex: 4.1.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-final-newline@2.0.0: {} + + strnum@1.1.2: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + terser@5.46.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.16.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.5 + + throat@5.0.0: {} + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + type-detect@4.0.8: {} + + type-fest@0.7.1: {} + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + unc-path-regex@0.1.2: {} + + undici-types@7.18.2: {} + + unicode-canonical-property-names-ecmascript@2.0.1: {} + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.2.0 + + unicode-match-property-value-ecmascript@2.2.1: {} + + unicode-property-aliases-ecmascript@2.2.0: {} + + universalify@0.1.2: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + util-deprecate@1.0.2: {} + + utils-merge@1.0.1: {} + + vary@1.1.2: {} + + vlq@1.0.1: {} + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + whatwg-fetch@3.6.20: {} + + which-module@2.0.1: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + ws@6.2.3: + dependencies: + async-limiter: 1.0.1 + + ws@7.5.10: {} + + y18n@4.0.3: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yaml@2.8.2: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs-parser@21.1.1: {} + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} diff --git a/example/src/demos/PerPropertyDemo.tsx b/example/src/demos/PerPropertyDemo.tsx new file mode 100644 index 0000000..4c7609d --- /dev/null +++ b/example/src/demos/PerPropertyDemo.tsx @@ -0,0 +1,50 @@ +import { useState } from 'react'; +import { Text, StyleSheet } from 'react-native'; +import { EaseView } from 'react-native-ease'; + +import { Section } from '../components/Section'; +import { Button } from '../components/Button'; + +export function PerPropertyDemo() { + const [active, setActive] = useState(false); + return ( +
+ + Opacity fades with timing 150ms, translateX springs independently + + +
+ ); +} + +const styles = StyleSheet.create({ + box: { + width: 80, + height: 80, + backgroundColor: '#4a90d9', + borderRadius: 12, + borderWidth: 2, + borderColor: '#7ab8ff', + alignItems: 'center', + justifyContent: 'center', + }, + hint: { + fontSize: 13, + color: '#8888aa', + marginBottom: 12, + }, +}); diff --git a/example/src/demos/index.ts b/example/src/demos/index.ts index c97dd27..4f35bfd 100644 --- a/example/src/demos/index.ts +++ b/example/src/demos/index.ts @@ -19,6 +19,7 @@ import { SlideDemo } from './SlideDemo'; import { StyleReRenderDemo } from './StyleReRenderDemo'; import { StyledCardDemo } from './StyledCardDemo'; import { TransformOriginDemo } from './TransformOriginDemo'; +import { PerPropertyDemo } from './PerPropertyDemo'; interface DemoEntry { component: ComponentType; @@ -35,6 +36,7 @@ export const demos: Record = { 'rotate': { component: RotateDemo, title: 'Rotate', section: 'Transform' }, 'scale': { component: ScaleDemo, title: 'Scale', section: 'Transform' }, 'transform-origin': { + 'per-property': { component: PerPropertyDemo, title: 'Per-Property', section: 'Advanced' }, component: TransformOriginDemo, title: 'Transform Origin', section: 'Transform', diff --git a/ios/EaseView.mm b/ios/EaseView.mm index 684958f..753729e 100644 --- a/ios/EaseView.mm +++ b/ios/EaseView.mm @@ -58,6 +58,124 @@ static CATransform3D composeTransform(CGFloat scaleX, CGFloat scaleY, kMaskScaleX | kMaskScaleY | kMaskRotate | kMaskRotateX | kMaskRotateY; +// Per-property transition config resolved from arrays or scalar fallback +struct EaseTransitionConfig { + EaseViewTransitionType type; + int duration; + float bezier[4]; + float damping; + float stiffness; + float mass; + EaseViewTransitionLoop loop; +}; + +static EaseTransitionConfig +transitionConfigForPropertyIndex(int index, const EaseViewProps &props) { + const auto &types = props.perPropertyTransitionTypes; + if (!types.empty() && index < (int)types.size()) { + EaseTransitionConfig config; + // Type + const auto &typeStr = types[index]; + if (typeStr == "spring") { + config.type = EaseViewTransitionType::Spring; + } else if (typeStr == "none") { + config.type = EaseViewTransitionType::None; + } else { + config.type = EaseViewTransitionType::Timing; + } + // Duration + const auto &durations = props.perPropertyTransitionDurations; + config.duration = (index < (int)durations.size()) ? durations[index] : 300; + // Bezier (4 values per property) + const auto &beziers = props.perPropertyTransitionEasingBeziers; + int bIdx = index * 4; + if (bIdx + 3 < (int)beziers.size()) { + config.bezier[0] = beziers[bIdx]; + config.bezier[1] = beziers[bIdx + 1]; + config.bezier[2] = beziers[bIdx + 2]; + config.bezier[3] = beziers[bIdx + 3]; + } else { + config.bezier[0] = 0.42f; + config.bezier[1] = 0.0f; + config.bezier[2] = 0.58f; + config.bezier[3] = 1.0f; + } + // Damping + const auto &dampings = props.perPropertyTransitionDampings; + config.damping = (index < (int)dampings.size()) ? dampings[index] : 15.0f; + // Stiffness + const auto &stiffnesses = props.perPropertyTransitionStiffnesses; + config.stiffness = + (index < (int)stiffnesses.size()) ? stiffnesses[index] : 120.0f; + // Mass + const auto &masses = props.perPropertyTransitionMasses; + config.mass = (index < (int)masses.size()) ? masses[index] : 1.0f; + // Loop + const auto &loops = props.perPropertyTransitionLoops; + if (index < (int)loops.size()) { + const auto &loopStr = loops[index]; + if (loopStr == "repeat") { + config.loop = EaseViewTransitionLoop::Repeat; + } else if (loopStr == "reverse") { + config.loop = EaseViewTransitionLoop::Reverse; + } else { + config.loop = EaseViewTransitionLoop::None; + } + } else { + config.loop = EaseViewTransitionLoop::None; + } + return config; + } + // Fallback to scalar props + EaseTransitionConfig config; + config.type = props.transitionType; + config.duration = props.transitionDuration; + const auto &b = props.transitionEasingBezier; + if (b.size() == 4) { + config.bezier[0] = b[0]; + config.bezier[1] = b[1]; + config.bezier[2] = b[2]; + config.bezier[3] = b[3]; + } else { + config.bezier[0] = 0.42f; + config.bezier[1] = 0.0f; + config.bezier[2] = 0.58f; + config.bezier[3] = 1.0f; + } + config.damping = props.transitionDamping; + config.stiffness = props.transitionStiffness; + config.mass = props.transitionMass; + config.loop = props.transitionLoop; + return config; +} + +// Property indices matching JS constants +static const int kPropIndexOpacity = 0; +static const int kPropIndexTranslateX = 1; +// static const int kPropIndexTranslateY = 2; +// static const int kPropIndexScaleX = 3; +// static const int kPropIndexScaleY = 4; +// static const int kPropIndexRotate = 5; +// static const int kPropIndexRotateX = 6; +// static const int kPropIndexRotateY = 7; +static const int kPropIndexBorderRadius = 8; +static const int kPropIndexBackgroundColor = 9; + +// Check if per-property arrays are populated +static BOOL hasPerPropertyArrays(const EaseViewProps &props) { + return !props.perPropertyTransitionTypes.empty(); +} + +// Find lowest property index with a set mask bit among transform properties +static int lowestTransformPropertyIndex(int mask) { + for (int i = 1; i <= 7; i++) { + if (mask & (1 << i)) { + return i; + } + } + return 1; // fallback to translateX +} + @implementation EaseView { BOOL _isFirstMount; NSInteger _animationBatchId; @@ -139,16 +257,16 @@ - (NSValue *)presentationValueForKeyPath:(NSString *)keyPath { - (CAAnimation *)createAnimationForKeyPath:(NSString *)keyPath fromValue:(NSValue *)fromValue toValue:(NSValue *)toValue - props:(const EaseViewProps &)props + config:(EaseTransitionConfig)config loop:(BOOL)loop { - if (props.transitionType == EaseViewTransitionType::Spring) { + if (config.type == EaseViewTransitionType::Spring) { CASpringAnimation *spring = [CASpringAnimation animationWithKeyPath:keyPath]; spring.fromValue = fromValue; spring.toValue = toValue; - spring.damping = props.transitionDamping; - spring.stiffness = props.transitionStiffness; - spring.mass = props.transitionMass; + spring.damping = config.damping; + spring.stiffness = config.stiffness; + spring.mass = config.mass; spring.initialVelocity = 0; spring.duration = spring.settlingDuration; return spring; @@ -156,23 +274,14 @@ - (CAAnimation *)createAnimationForKeyPath:(NSString *)keyPath CABasicAnimation *timing = [CABasicAnimation animationWithKeyPath:keyPath]; timing.fromValue = fromValue; timing.toValue = toValue; - timing.duration = props.transitionDuration / 1000.0; - { - const auto &b = props.transitionEasingBezier; - if (b.size() == 4) { - timing.timingFunction = [CAMediaTimingFunction - functionWithControlPoints:(float)b[0]:(float)b[1]:(float)b[2 - ]:(float)b[3]]; - } else { - // Fallback: easeInOut - timing.timingFunction = - [CAMediaTimingFunction functionWithControlPoints:0.42:0.0:0.58:1.0]; - } - } + timing.duration = config.duration / 1000.0; + timing.timingFunction = [CAMediaTimingFunction + functionWithControlPoints:config.bezier[0]:config.bezier[1 + ]:config.bezier[2]:config.bezier[3]]; if (loop) { - if (props.transitionLoop == EaseViewTransitionLoop::Repeat) { + if (config.loop == EaseViewTransitionLoop::Repeat) { timing.repeatCount = HUGE_VALF; - } else if (props.transitionLoop == EaseViewTransitionLoop::Reverse) { + } else if (config.loop == EaseViewTransitionLoop::Reverse) { timing.repeatCount = HUGE_VALF; timing.autoreverses = YES; } @@ -185,14 +294,14 @@ - (void)applyAnimationForKeyPath:(NSString *)keyPath animationKey:(NSString *)animationKey fromValue:(NSValue *)fromValue toValue:(NSValue *)toValue - props:(const EaseViewProps &)props + config:(EaseTransitionConfig)config loop:(BOOL)loop { _pendingAnimationCount++; CAAnimation *animation = [self createAnimationForKeyPath:keyPath fromValue:fromValue toValue:toValue - props:props + config:config loop:loop]; if (props.transitionDelay > 0) { animation.beginTime = @@ -257,6 +366,8 @@ - (void)updateProps:(const Props::Shared &)props int mask = newViewProps.animatedProperties; BOOL hasTransform = (mask & kMaskAnyTransform) != 0; + BOOL perProp = hasPerPropertyArrays(newViewProps); + if (_isFirstMount) { _isFirstMount = NO; @@ -305,34 +416,43 @@ - (void)updateProps:(const Props::Shared &)props // Animate from initial to target if (hasInitialOpacity) { + EaseTransitionConfig opacityConfig = + transitionConfigForPropertyIndex(kPropIndexOpacity, newViewProps); self.layer.opacity = newViewProps.animateOpacity; [self applyAnimationForKeyPath:@"opacity" animationKey:kAnimKeyOpacity fromValue:@(newViewProps.initialAnimateOpacity) toValue:@(newViewProps.animateOpacity) - props:newViewProps + config:opacityConfig loop:YES]; } if (hasInitialTransform) { + int transformIdx = lowestTransformPropertyIndex(mask); + EaseTransitionConfig transformConfig = + transitionConfigForPropertyIndex(transformIdx, newViewProps); self.layer.transform = targetT; [self applyAnimationForKeyPath:@"transform" animationKey:kAnimKeyTransform fromValue:[NSValue valueWithCATransform3D:initialT] toValue:[NSValue valueWithCATransform3D:targetT] - props:newViewProps + config:transformConfig loop:YES]; } if (hasInitialBorderRadius) { + EaseTransitionConfig brConfig = transitionConfigForPropertyIndex( + kPropIndexBorderRadius, newViewProps); self.layer.cornerRadius = newViewProps.animateBorderRadius; [self applyAnimationForKeyPath:@"cornerRadius" animationKey:kAnimKeyCornerRadius fromValue:@(newViewProps.initialAnimateBorderRadius) toValue:@(newViewProps.animateBorderRadius) - props:newViewProps + config:brConfig loop:YES]; } if (hasInitialBackgroundColor) { + EaseTransitionConfig bgConfig = transitionConfigForPropertyIndex( + kPropIndexBackgroundColor, newViewProps); self.layer.backgroundColor = RCTUIColorFromSharedColor(newViewProps.animateBackgroundColor) .CGColor; @@ -345,7 +465,7 @@ - (void)updateProps:(const Props::Shared &)props toValue:(__bridge id)RCTUIColorFromSharedColor( newViewProps.animateBackgroundColor) .CGColor - props:newViewProps + config:bgConfig loop:YES]; } } else { @@ -363,8 +483,9 @@ - (void)updateProps:(const Props::Shared &)props RCTUIColorFromSharedColor(newViewProps.animateBackgroundColor) .CGColor; } - } else if (newViewProps.transitionType == EaseViewTransitionType::None) { - // No transition — set values immediately + } else if (!perProp && + newViewProps.transitionType == EaseViewTransitionType::None) { + // No transition (scalar) — set values immediately [self.layer removeAllAnimations]; if (mask & kMaskOpacity) self.layer.opacity = newViewProps.animateOpacity; @@ -392,14 +513,22 @@ - (void)updateProps:(const Props::Shared &)props if ((mask & kMaskOpacity) && oldViewProps.animateOpacity != newViewProps.animateOpacity) { - self.layer.opacity = newViewProps.animateOpacity; - [self - applyAnimationForKeyPath:@"opacity" - animationKey:kAnimKeyOpacity - fromValue:[self presentationValueForKeyPath:@"opacity"] - toValue:@(newViewProps.animateOpacity) - props:newViewProps - loop:NO]; + EaseTransitionConfig opacityConfig = + transitionConfigForPropertyIndex(kPropIndexOpacity, newViewProps); + if (opacityConfig.type == EaseViewTransitionType::None) { + self.layer.opacity = newViewProps.animateOpacity; + [self.layer removeAnimationForKey:kAnimKeyOpacity]; + } else { + self.layer.opacity = newViewProps.animateOpacity; + [self + applyAnimationForKeyPath:@"opacity" + animationKey:kAnimKeyOpacity + fromValue:[self + presentationValueForKeyPath:@"opacity"] + toValue:@(newViewProps.animateOpacity) + config:opacityConfig + loop:NO]; + } } // Check if ANY transform-related property changed @@ -414,46 +543,84 @@ - (void)updateProps:(const Props::Shared &)props oldViewProps.animateRotateY != newViewProps.animateRotateY; if (anyTransformChanged) { - CATransform3D fromT = [self presentationTransform]; - CATransform3D toT = [self targetTransformFromProps:newViewProps]; - self.layer.transform = toT; - [self applyAnimationForKeyPath:@"transform" - animationKey:kAnimKeyTransform - fromValue:[NSValue valueWithCATransform3D:fromT] - toValue:[NSValue valueWithCATransform3D:toT] - props:newViewProps - loop:NO]; + // Determine which transform sub-properties changed for config selection + int changedTransformMask = 0; + if (oldViewProps.animateTranslateX != newViewProps.animateTranslateX) + changedTransformMask |= kMaskTranslateX; + if (oldViewProps.animateTranslateY != newViewProps.animateTranslateY) + changedTransformMask |= kMaskTranslateY; + if (oldViewProps.animateScaleX != newViewProps.animateScaleX) + changedTransformMask |= kMaskScaleX; + if (oldViewProps.animateScaleY != newViewProps.animateScaleY) + changedTransformMask |= kMaskScaleY; + if (oldViewProps.animateRotate != newViewProps.animateRotate) + changedTransformMask |= kMaskRotate; + if (oldViewProps.animateRotateX != newViewProps.animateRotateX) + changedTransformMask |= kMaskRotateX; + if (oldViewProps.animateRotateY != newViewProps.animateRotateY) + changedTransformMask |= kMaskRotateY; + + int transformIdx = lowestTransformPropertyIndex(changedTransformMask); + EaseTransitionConfig transformConfig = + transitionConfigForPropertyIndex(transformIdx, newViewProps); + + if (transformConfig.type == EaseViewTransitionType::None) { + self.layer.transform = [self targetTransformFromProps:newViewProps]; + [self.layer removeAnimationForKey:kAnimKeyTransform]; + } else { + CATransform3D fromT = [self presentationTransform]; + CATransform3D toT = [self targetTransformFromProps:newViewProps]; + self.layer.transform = toT; + [self applyAnimationForKeyPath:@"transform" + animationKey:kAnimKeyTransform + fromValue:[NSValue valueWithCATransform3D:fromT] + toValue:[NSValue valueWithCATransform3D:toT] + config:transformConfig + loop:NO]; + } } } if ((mask & kMaskBorderRadius) && oldViewProps.animateBorderRadius != newViewProps.animateBorderRadius) { + EaseTransitionConfig brConfig = transitionConfigForPropertyIndex( + kPropIndexBorderRadius, newViewProps); self.layer.cornerRadius = newViewProps.animateBorderRadius; self.layer.masksToBounds = newViewProps.animateBorderRadius > 0; - [self applyAnimationForKeyPath:@"cornerRadius" - animationKey:kAnimKeyCornerRadius - fromValue:[self presentationValueForKeyPath: - @"cornerRadius"] - toValue:@(newViewProps.animateBorderRadius) - props:newViewProps - loop:NO]; + if (brConfig.type == EaseViewTransitionType::None) { + [self.layer removeAnimationForKey:kAnimKeyCornerRadius]; + } else { + [self applyAnimationForKeyPath:@"cornerRadius" + animationKey:kAnimKeyCornerRadius + fromValue:[self presentationValueForKeyPath: + @"cornerRadius"] + toValue:@(newViewProps.animateBorderRadius) + config:brConfig + loop:NO]; + } } if ((mask & kMaskBackgroundColor) && oldViewProps.animateBackgroundColor != newViewProps.animateBackgroundColor) { - CGColorRef fromColor = (__bridge CGColorRef) - [self presentationValueForKeyPath:@"backgroundColor"]; + EaseTransitionConfig bgConfig = transitionConfigForPropertyIndex( + kPropIndexBackgroundColor, newViewProps); CGColorRef toColor = RCTUIColorFromSharedColor(newViewProps.animateBackgroundColor) .CGColor; self.layer.backgroundColor = toColor; - [self applyAnimationForKeyPath:@"backgroundColor" - animationKey:kAnimKeyBackgroundColor - fromValue:(__bridge id)fromColor - toValue:(__bridge id)toColor - props:newViewProps - loop:NO]; + if (bgConfig.type == EaseViewTransitionType::None) { + [self.layer removeAnimationForKey:kAnimKeyBackgroundColor]; + } else { + CGColorRef fromColor = (__bridge CGColorRef) + [self presentationValueForKeyPath:@"backgroundColor"]; + [self applyAnimationForKeyPath:@"backgroundColor" + animationKey:kAnimKeyBackgroundColor + fromValue:(__bridge id)fromColor + toValue:(__bridge id)toColor + config:bgConfig + loop:NO]; + } } } diff --git a/src/EaseView.tsx b/src/EaseView.tsx index bb34193..a40789e 100644 --- a/src/EaseView.tsx +++ b/src/EaseView.tsx @@ -3,6 +3,7 @@ import NativeEaseView from './EaseViewNativeComponent'; import type { AnimateProps, CubicBezier, + SingleTransition, Transition, TransitionEndEvent, TransformOrigin, @@ -58,6 +59,125 @@ const EASING_PRESETS: Record = { easeInOut: [0.42, 0, 0.58, 1], }; +/** Property index order for per-property arrays. */ +const PROPERTY_KEYS: (keyof AnimateProps)[] = [ + 'opacity', + 'translateX', + 'translateY', + 'scaleX', + 'scaleY', + 'rotate', + 'rotateX', + 'rotateY', + 'borderRadius', + 'backgroundColor', +]; + +const PROPERTY_COUNT = PROPERTY_KEYS.length; + +/** Returns true if the transition is a SingleTransition (has a `type` field). */ +function isSingleTransition(t: Transition): t is SingleTransition { + return 'type' in t; +} + +/** Library defaults: spring for transforms (indices 1-7), timing 300ms easeInOut for others. */ +const TIMING_DEFAULT: SingleTransition = { + type: 'timing', + duration: 300, + easing: 'easeInOut', +}; +const SPRING_DEFAULT: SingleTransition = { + type: 'spring', + damping: 15, + stiffness: 120, + mass: 1, +}; + +function getLibraryDefault(index: number): SingleTransition { + // Indices 1-7 are transforms → spring default + // Indices 0,8,9 are opacity, borderRadius, backgroundColor → timing default + return index >= 1 && index <= 7 ? SPRING_DEFAULT : TIMING_DEFAULT; +} + +/** Resolve a SingleTransition into flat scalar values. */ +function resolveSingleConfig(config: SingleTransition) { + const type = config.type as 'timing' | 'spring' | 'none'; + const duration = config.type === 'timing' ? config.duration ?? 300 : 300; + const rawEasing = + config.type === 'timing' ? config.easing ?? 'easeInOut' : 'easeInOut'; + const bezier: CubicBezier = Array.isArray(rawEasing) + ? rawEasing + : EASING_PRESETS[rawEasing]!; + const damping = config.type === 'spring' ? config.damping ?? 15 : 15; + const stiffness = config.type === 'spring' ? config.stiffness ?? 120 : 120; + const mass = config.type === 'spring' ? config.mass ?? 1 : 1; + const loop: 'none' | 'repeat' | 'reverse' = + config.type === 'timing' ? config.loop ?? 'none' : 'none'; + return { type, duration, bezier, damping, stiffness, mass, loop }; +} + +interface PerPropertyArrays { + types: string[]; + durations: number[]; + dampings: number[]; + stiffnesses: number[]; + masses: number[]; + loops: string[]; + easingBeziers: number[]; +} + +function resolvePerPropertyTransitions( + transitionMap: Exclude, +): { + scalars: ReturnType; + arrays: PerPropertyArrays; +} { + const arrays: PerPropertyArrays = { + types: [], + durations: [], + dampings: [], + stiffnesses: [], + masses: [], + loops: [], + easingBeziers: [], + }; + + const defaultConfig = transitionMap.default; + + for (let i = 0; i < PROPERTY_COUNT; i++) { + const key = PROPERTY_KEYS[i]!; + // Resolution order: specific key → scale shorthand (for scaleX/scaleY) → default → library default + let config: SingleTransition; + if (transitionMap[key] != null) { + config = transitionMap[key]!; + } else if ( + (key === 'scaleX' || key === 'scaleY') && + transitionMap.scale != null + ) { + config = transitionMap.scale!; + } else if (defaultConfig != null) { + config = defaultConfig; + } else { + config = getLibraryDefault(i); + } + + const resolved = resolveSingleConfig(config); + arrays.types.push(resolved.type); + arrays.durations.push(resolved.duration); + arrays.dampings.push(resolved.damping); + arrays.stiffnesses.push(resolved.stiffness); + arrays.masses.push(resolved.mass); + arrays.loops.push(resolved.loop); + arrays.easingBeziers.push(...resolved.bezier); + } + + // Scalar props = default key values (or library defaults for opacity category) + const scalarConfig = defaultConfig ?? TIMING_DEFAULT; + const scalars = resolveSingleConfig(scalarConfig); + + return { scalars, arrays }; +} + export type EaseViewProps = ViewProps & { /** Target values for animated properties. */ animate?: AnimateProps; @@ -179,34 +299,74 @@ export function EaseView({ } } - // Resolve transition config - const transitionType = transition?.type ?? 'timing'; - const transitionDuration = - transition?.type === 'timing' ? transition.duration ?? 300 : 300; - const rawEasing = - transition?.type === 'timing' - ? transition.easing ?? 'easeInOut' - : 'easeInOut'; - if (__DEV__) { - if (Array.isArray(rawEasing)) { - if ((rawEasing as number[]).length !== 4) { - console.warn( - 'react-native-ease: Custom easing must be a [x1, y1, x2, y2] tuple (got length ' + - (rawEasing as number[]).length + - ').', - ); - } - if ( - rawEasing[0] < 0 || - rawEasing[0] > 1 || - rawEasing[2] < 0 || - rawEasing[2] > 1 - ) { - console.warn( - 'react-native-ease: Easing x-values (x1, x2) must be between 0 and 1.', - ); + // Resolve transition config — single config or per-property map + const isMap = transition != null && !isSingleTransition(transition); + const singleTransition = transition == null || isMap ? undefined : transition; + + // Single config resolution (used when single transition or as scalars for map) + let transitionType: 'timing' | 'spring' | 'none'; + let transitionDuration: number; + let bezier: CubicBezier; + let transitionDamping: number; + let transitionStiffness: number; + let transitionMass: number; + let transitionLoop: 'none' | 'repeat' | 'reverse'; + let perPropertyArrays: PerPropertyArrays | undefined; + + if (isMap) { + const { scalars, arrays } = resolvePerPropertyTransitions(transition); + transitionType = scalars.type; + transitionDuration = scalars.duration; + bezier = scalars.bezier; + transitionDamping = scalars.damping; + transitionStiffness = scalars.stiffness; + transitionMass = scalars.mass; + transitionLoop = scalars.loop; + perPropertyArrays = arrays; + } else { + transitionType = singleTransition?.type ?? 'timing'; + transitionDuration = + singleTransition?.type === 'timing' + ? singleTransition.duration ?? 300 + : 300; + const rawEasing = + singleTransition?.type === 'timing' + ? singleTransition.easing ?? 'easeInOut' + : 'easeInOut'; + if (__DEV__) { + if (Array.isArray(rawEasing)) { + if ((rawEasing as number[]).length !== 4) { + console.warn( + 'react-native-ease: Custom easing must be a [x1, y1, x2, y2] tuple (got length ' + + (rawEasing as number[]).length + + ').', + ); + } + if ( + rawEasing[0] < 0 || + rawEasing[0] > 1 || + rawEasing[2] < 0 || + rawEasing[2] > 1 + ) { + console.warn( + 'react-native-ease: Easing x-values (x1, x2) must be between 0 and 1.', + ); + } } } + bezier = Array.isArray(rawEasing) ? rawEasing : EASING_PRESETS[rawEasing]!; + transitionDamping = + singleTransition?.type === 'spring' ? singleTransition.damping ?? 15 : 15; + transitionStiffness = + singleTransition?.type === 'spring' + ? singleTransition.stiffness ?? 120 + : 120; + transitionMass = + singleTransition?.type === 'spring' ? singleTransition.mass ?? 1 : 1; + transitionLoop = + singleTransition?.type === 'timing' + ? singleTransition.loop ?? 'none' + : 'none'; } const bezier: CubicBezier = Array.isArray(rawEasing) ? rawEasing @@ -224,6 +384,7 @@ export function EaseView({ ? transition.delay ?? 0 : 0; + const handleTransitionEnd = onTransitionEnd ? (event: { nativeEvent: { finished: boolean } }) => onTransitionEnd(event.nativeEvent) @@ -262,6 +423,14 @@ export function EaseView({ transitionMass={transitionMass} transitionLoop={transitionLoop} transitionDelay={transitionDelay} + perPropertyTransitionTypes={perPropertyArrays?.types} + perPropertyTransitionDurations={perPropertyArrays?.durations} + perPropertyTransitionDampings={perPropertyArrays?.dampings} + perPropertyTransitionStiffnesses={perPropertyArrays?.stiffnesses} + perPropertyTransitionMasses={perPropertyArrays?.masses} + perPropertyTransitionLoops={perPropertyArrays?.loops} + perPropertyTransitionEasingBeziers={perPropertyArrays?.easingBeziers} + useHardwareLayer={useHardwareLayer} transformOriginX={transformOrigin?.x ?? 0.5} transformOriginY={transformOrigin?.y ?? 0.5} diff --git a/src/EaseViewNativeComponent.ts b/src/EaseViewNativeComponent.ts index ad9e313..d12190e 100644 --- a/src/EaseViewNativeComponent.ts +++ b/src/EaseViewNativeComponent.ts @@ -54,6 +54,17 @@ export interface NativeProps extends ViewProps { >; transitionDelay?: CodegenTypes.WithDefault; + // Per-property transition arrays (10 elements each, one per animatable property) + // Index order: 0=opacity, 1=translateX, 2=translateY, 3=scaleX, 4=scaleY, + // 5=rotate, 6=rotateX, 7=rotateY, 8=borderRadius, 9=backgroundColor + perPropertyTransitionTypes?: ReadonlyArray; + perPropertyTransitionDurations?: ReadonlyArray; + perPropertyTransitionDampings?: ReadonlyArray; + perPropertyTransitionStiffnesses?: ReadonlyArray; + perPropertyTransitionMasses?: ReadonlyArray; + perPropertyTransitionLoops?: ReadonlyArray; + perPropertyTransitionEasingBeziers?: ReadonlyArray; // 40 elements (4 per property) + // Transform origin (0–1 fractions, default center) transformOriginX?: CodegenTypes.WithDefault; transformOriginY?: CodegenTypes.WithDefault; diff --git a/src/__tests__/EaseView.test.tsx b/src/__tests__/EaseView.test.tsx index 7d3bc18..dfc3526 100644 --- a/src/__tests__/EaseView.test.tsx +++ b/src/__tests__/EaseView.test.tsx @@ -458,4 +458,146 @@ describe('EaseView', () => { ); }); }); + + describe('per-property transition map', () => { + it('does not pass arrays for single transition (backward compat)', () => { + render( + , + ); + const props = getNativeProps(); + expect(props.perPropertyTransitionTypes).toBeUndefined(); + expect(props.perPropertyTransitionDurations).toBeUndefined(); + expect(props.perPropertyTransitionDampings).toBeUndefined(); + expect(props.perPropertyTransitionStiffnesses).toBeUndefined(); + expect(props.perPropertyTransitionMasses).toBeUndefined(); + expect(props.perPropertyTransitionLoops).toBeUndefined(); + expect(props.perPropertyTransitionEasingBeziers).toBeUndefined(); + }); + + it('populates arrays with default-only map (all slots same)', () => { + render( + , + ); + const props = getNativeProps(); + expect(props.perPropertyTransitionTypes).toHaveLength(10); + expect(props.perPropertyTransitionTypes).toEqual( + Array(10).fill('timing'), + ); + expect(props.perPropertyTransitionDurations).toEqual(Array(10).fill(500)); + // Scalar props should match default + expect(props.transitionType).toBe('timing'); + expect(props.transitionDuration).toBe(500); + }); + + it('applies property-specific overrides', () => { + render( + , + ); + const props = getNativeProps(); + // Index 0 = opacity: timing 150ms + expect(props.perPropertyTransitionTypes[0]).toBe('timing'); + expect(props.perPropertyTransitionDurations[0]).toBe(150); + // Index 2 = translateY: spring + expect(props.perPropertyTransitionTypes[2]).toBe('spring'); + expect(props.perPropertyTransitionDampings[2]).toBe(20); + expect(props.perPropertyTransitionStiffnesses[2]).toBe(200); + // Index 1 = translateX: default timing 300ms + expect(props.perPropertyTransitionTypes[1]).toBe('timing'); + expect(props.perPropertyTransitionDurations[1]).toBe(300); + }); + + it('applies scale shorthand to scaleX and scaleY', () => { + render( + , + ); + const props = getNativeProps(); + // Index 3 = scaleX, Index 4 = scaleY + expect(props.perPropertyTransitionTypes[3]).toBe('spring'); + expect(props.perPropertyTransitionTypes[4]).toBe('spring'); + expect(props.perPropertyTransitionDampings[3]).toBe(10); + expect(props.perPropertyTransitionDampings[4]).toBe(10); + }); + + it('allows scaleX to override scale shorthand', () => { + render( + , + ); + const props = getNativeProps(); + // scaleX (index 3) uses specific override + expect(props.perPropertyTransitionTypes[3]).toBe('timing'); + expect(props.perPropertyTransitionDurations[3]).toBe(200); + // scaleY (index 4) falls back to scale shorthand + expect(props.perPropertyTransitionTypes[4]).toBe('spring'); + expect(props.perPropertyTransitionDampings[4]).toBe(10); + }); + + it('uses library defaults by category when no default key', () => { + render( + , + ); + const props = getNativeProps(); + // opacity (index 0) is explicitly set + expect(props.perPropertyTransitionTypes[0]).toBe('timing'); + expect(props.perPropertyTransitionDurations[0]).toBe(150); + // translateX (index 1) — transform category → spring default + expect(props.perPropertyTransitionTypes[1]).toBe('spring'); + expect(props.perPropertyTransitionDampings[1]).toBe(15); + expect(props.perPropertyTransitionStiffnesses[1]).toBe(120); + // borderRadius (index 8) — non-transform → timing default + expect(props.perPropertyTransitionTypes[8]).toBe('timing'); + expect(props.perPropertyTransitionDurations[8]).toBe(300); + // backgroundColor (index 9) — non-transform → timing default + expect(props.perPropertyTransitionTypes[9]).toBe('timing'); + }); + + it('flattens easing beziers into 40-element array', () => { + render( + , + ); + const props = getNativeProps(); + expect(props.perPropertyTransitionEasingBeziers).toHaveLength(40); + // linear = [0, 0, 1, 1] repeated 10 times + for (let i = 0; i < 10; i++) { + expect(props.perPropertyTransitionEasingBeziers[i * 4]).toBe(0); + expect(props.perPropertyTransitionEasingBeziers[i * 4 + 1]).toBe(0); + expect(props.perPropertyTransitionEasingBeziers[i * 4 + 2]).toBe(1); + expect(props.perPropertyTransitionEasingBeziers[i * 4 + 3]).toBe(1); + } + }); + }); }); diff --git a/src/index.tsx b/src/index.tsx index 739b0d6..0f260e2 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,6 +4,8 @@ export type { AnimateProps, CubicBezier, Transition, + SingleTransition, + TransitionMap, TimingTransition, SpringTransition, NoneTransition, diff --git a/src/types.ts b/src/types.ts index f1b35a2..69cfee4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -42,8 +42,20 @@ export type NoneTransition = { type: 'none'; }; -/** Animation transition configuration. */ -export type Transition = TimingTransition | SpringTransition | NoneTransition; +/** A single animation transition configuration. */ +export type SingleTransition = + | TimingTransition + | SpringTransition + | NoneTransition; + +/** Per-property transition map. Each key overrides the transition for that animatable property. */ +export type TransitionMap = { + /** Fallback config for properties not explicitly listed. */ + default?: SingleTransition; +} & Partial>; + +/** Animation transition configuration — either a single config or a per-property map. */ +export type Transition = SingleTransition | TransitionMap; /** Event fired when the animation ends. */ export type TransitionEndEvent = { From 70e348914870ab2c15aae0db3077b3a89289d191 Mon Sep 17 00:00:00 2001 From: EQuimper Date: Sat, 14 Mar 2026 09:51:18 -0400 Subject: [PATCH 2/7] feat: implement immediate transition end for 'none' config in per-property animations --- android/src/main/java/com/ease/EaseView.kt | 73 +++++++++++++++++- ios/EaseView.mm | 88 +++++++++++++++++----- 2 files changed, 140 insertions(+), 21 deletions(-) diff --git a/android/src/main/java/com/ease/EaseView.kt b/android/src/main/java/com/ease/EaseView.kt index 3896441..1c4cf39 100644 --- a/android/src/main/java/com/ease/EaseView.kt +++ b/android/src/main/java/com/ease/EaseView.kt @@ -336,6 +336,12 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (mask and MASK_BACKGROUND_COLOR != 0 && initialAnimateBackgroundColor != backgroundColor) { animateBackgroundColor(initialAnimateBackgroundColor, backgroundColor, getTransitionConfigForProperty(PROP_INDEX_BACKGROUND_COLOR), loop = true) } + + // If all per-property configs were 'none', no animations were queued. + // Fire onTransitionEnd immediately to match the scalar 'none' contract. + if (pendingBatchAnimationCount == 0) { + onTransitionEnd?.invoke(true) + } } else { // No initial animation — set target values directly (skip non-animated) if (mask and MASK_OPACITY != 0) this.alpha = opacity @@ -365,9 +371,15 @@ class EaseView(context: Context) : ReactViewGroup(context) { onTransitionEnd?.invoke(true) } else { // Subsequent updates: animate changed properties (skip non-animated) + var anyPropertyChanged = false + if (prevOpacity != null && mask and MASK_OPACITY != 0 && prevOpacity != opacity) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_OPACITY) if (config.type == "none") { + cancelSpringForProperty("alpha") + runningAnimators["alpha"]?.cancel() + runningAnimators.remove("alpha") this.alpha = opacity } else { val from = getCurrentValue("alpha") @@ -376,8 +388,12 @@ class EaseView(context: Context) : ReactViewGroup(context) { } if (prevTranslateX != null && mask and MASK_TRANSLATE_X != 0 && prevTranslateX != translateX) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_X) if (config.type == "none") { + cancelSpringForProperty("translationX") + runningAnimators["translationX"]?.cancel() + runningAnimators.remove("translationX") this.translationX = translateX } else { val from = getCurrentValue("translationX") @@ -386,8 +402,12 @@ class EaseView(context: Context) : ReactViewGroup(context) { } if (prevTranslateY != null && mask and MASK_TRANSLATE_Y != 0 && prevTranslateY != translateY) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_Y) if (config.type == "none") { + cancelSpringForProperty("translationY") + runningAnimators["translationY"]?.cancel() + runningAnimators.remove("translationY") this.translationY = translateY } else { val from = getCurrentValue("translationY") @@ -396,8 +416,12 @@ class EaseView(context: Context) : ReactViewGroup(context) { } if (prevScaleX != null && mask and MASK_SCALE_X != 0 && prevScaleX != scaleX) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_SCALE_X) if (config.type == "none") { + cancelSpringForProperty("scaleX") + runningAnimators["scaleX"]?.cancel() + runningAnimators.remove("scaleX") this.scaleX = scaleX } else { val from = getCurrentValue("scaleX") @@ -406,8 +430,12 @@ class EaseView(context: Context) : ReactViewGroup(context) { } if (prevScaleY != null && mask and MASK_SCALE_Y != 0 && prevScaleY != scaleY) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_SCALE_Y) if (config.type == "none") { + cancelSpringForProperty("scaleY") + runningAnimators["scaleY"]?.cancel() + runningAnimators.remove("scaleY") this.scaleY = scaleY } else { val from = getCurrentValue("scaleY") @@ -416,8 +444,12 @@ class EaseView(context: Context) : ReactViewGroup(context) { } if (prevRotate != null && mask and MASK_ROTATE != 0 && prevRotate != rotate) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_ROTATE) if (config.type == "none") { + cancelSpringForProperty("rotation") + runningAnimators["rotation"]?.cancel() + runningAnimators.remove("rotation") this.rotation = rotate } else { val from = getCurrentValue("rotation") @@ -426,8 +458,12 @@ class EaseView(context: Context) : ReactViewGroup(context) { } if (prevRotateX != null && mask and MASK_ROTATE_X != 0 && prevRotateX != rotateX) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_ROTATE_X) if (config.type == "none") { + cancelSpringForProperty("rotationX") + runningAnimators["rotationX"]?.cancel() + runningAnimators.remove("rotationX") this.rotationX = rotateX } else { val from = getCurrentValue("rotationX") @@ -436,8 +472,12 @@ class EaseView(context: Context) : ReactViewGroup(context) { } if (prevRotateY != null && mask and MASK_ROTATE_Y != 0 && prevRotateY != rotateY) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_ROTATE_Y) if (config.type == "none") { + cancelSpringForProperty("rotationY") + runningAnimators["rotationY"]?.cancel() + runningAnimators.remove("rotationY") this.rotationY = rotateY } else { val from = getCurrentValue("rotationY") @@ -446,8 +486,11 @@ class EaseView(context: Context) : ReactViewGroup(context) { } if (prevBorderRadius != null && mask and MASK_BORDER_RADIUS != 0 && prevBorderRadius != borderRadius) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_BORDER_RADIUS) if (config.type == "none") { + runningAnimators["animateBorderRadius"]?.cancel() + runningAnimators.remove("animateBorderRadius") setAnimateBorderRadius(borderRadius) } else { val from = getCurrentValue("animateBorderRadius") @@ -456,13 +499,22 @@ class EaseView(context: Context) : ReactViewGroup(context) { } if (prevBackgroundColor != null && mask and MASK_BACKGROUND_COLOR != 0 && prevBackgroundColor != backgroundColor) { + anyPropertyChanged = true val config = getTransitionConfigForProperty(PROP_INDEX_BACKGROUND_COLOR) if (config.type == "none") { + runningAnimators["backgroundColor"]?.cancel() + runningAnimators.remove("backgroundColor") applyBackgroundColor(backgroundColor) } else { animateBackgroundColor(getCurrentBackgroundColor(), backgroundColor, config) } } + + // If per-property arrays are populated and all changed properties resolved + // to 'none', no animations were queued. Fire onTransitionEnd immediately. + if (hasPerPropertyArrays() && anyPropertyChanged && pendingBatchAnimationCount == 0) { + onTransitionEnd?.invoke(true) + } } prevOpacity = opacity @@ -554,6 +606,17 @@ class EaseView(context: Context) : ReactViewGroup(context) { config: TransitionConfig, loop: Boolean = false ) { + if (config.type == "none") { + // Set immediately — cancel any running animation for this property + cancelSpringForProperty(propertyName) + runningAnimators[propertyName]?.cancel() + runningAnimators.remove(propertyName) + ObjectAnimator.ofFloat(this, propertyName, toValue).apply { + duration = 0 + start() + } + return + } if (config.type == "spring" && viewProperty != null) { animateSpring(viewProperty, toValue, config) } else { @@ -613,11 +676,13 @@ class EaseView(context: Context) : ReactViewGroup(context) { private fun animateSpring(viewProperty: DynamicAnimation.ViewProperty, toValue: Float, config: TransitionConfig) { cancelTimingForViewProperty(viewProperty) - val existingSpring = runningSpringAnimations[viewProperty] - if (existingSpring != null && existingSpring.isRunning) { - existingSpring.animateToFinalPosition(toValue) - return + // Cancel any existing spring so we get a fresh end listener with the current batchId. + runningSpringAnimations[viewProperty]?.let { existing -> + if (existing.isRunning) { + existing.cancel() + } } + runningSpringAnimations.remove(viewProperty) val batchId = animationBatchId pendingBatchAnimationCount++ diff --git a/ios/EaseView.mm b/ios/EaseView.mm index 753729e..37b83c9 100644 --- a/ios/EaseView.mm +++ b/ios/EaseView.mm @@ -414,41 +414,66 @@ - (void)updateProps:(const Props::Shared &)props newViewProps.initialAnimateBackgroundColor) .CGColor; - // Animate from initial to target + // Animate from initial to target (skip if config is 'none') if (hasInitialOpacity) { EaseTransitionConfig opacityConfig = transitionConfigForPropertyIndex(kPropIndexOpacity, newViewProps); self.layer.opacity = newViewProps.animateOpacity; - [self applyAnimationForKeyPath:@"opacity" - animationKey:kAnimKeyOpacity - fromValue:@(newViewProps.initialAnimateOpacity) - toValue:@(newViewProps.animateOpacity) - config:opacityConfig - loop:YES]; + if (opacityConfig.type != EaseViewTransitionType::None) { + [self applyAnimationForKeyPath:@"opacity" + animationKey:kAnimKeyOpacity + fromValue:@(newViewProps.initialAnimateOpacity) + toValue:@(newViewProps.animateOpacity) + config:opacityConfig + loop:YES]; + } } if (hasInitialTransform) { - int transformIdx = lowestTransformPropertyIndex(mask); + // Build mask of which transform sub-properties actually changed + int changedInitTransform = 0; + if (newViewProps.initialAnimateTranslateX != + newViewProps.animateTranslateX) + changedInitTransform |= kMaskTranslateX; + if (newViewProps.initialAnimateTranslateY != + newViewProps.animateTranslateY) + changedInitTransform |= kMaskTranslateY; + if (newViewProps.initialAnimateScaleX != newViewProps.animateScaleX) + changedInitTransform |= kMaskScaleX; + if (newViewProps.initialAnimateScaleY != newViewProps.animateScaleY) + changedInitTransform |= kMaskScaleY; + if (newViewProps.initialAnimateRotate != newViewProps.animateRotate) + changedInitTransform |= kMaskRotate; + if (newViewProps.initialAnimateRotateX != newViewProps.animateRotateX) + changedInitTransform |= kMaskRotateX; + if (newViewProps.initialAnimateRotateY != newViewProps.animateRotateY) + changedInitTransform |= kMaskRotateY; + int transformIdx = lowestTransformPropertyIndex(changedInitTransform); EaseTransitionConfig transformConfig = transitionConfigForPropertyIndex(transformIdx, newViewProps); self.layer.transform = targetT; - [self applyAnimationForKeyPath:@"transform" + if (transformConfig.type != EaseViewTransitionType::None) { + [self + applyAnimationForKeyPath:@"transform" animationKey:kAnimKeyTransform fromValue:[NSValue valueWithCATransform3D:initialT] toValue:[NSValue valueWithCATransform3D:targetT] config:transformConfig loop:YES]; + } } if (hasInitialBorderRadius) { EaseTransitionConfig brConfig = transitionConfigForPropertyIndex( kPropIndexBorderRadius, newViewProps); self.layer.cornerRadius = newViewProps.animateBorderRadius; - [self - applyAnimationForKeyPath:@"cornerRadius" - animationKey:kAnimKeyCornerRadius - fromValue:@(newViewProps.initialAnimateBorderRadius) - toValue:@(newViewProps.animateBorderRadius) - config:brConfig - loop:YES]; + if (brConfig.type != EaseViewTransitionType::None) { + [self applyAnimationForKeyPath:@"cornerRadius" + animationKey:kAnimKeyCornerRadius + fromValue:@(newViewProps + .initialAnimateBorderRadius) + toValue:@(newViewProps.animateBorderRadius) + config:brConfig + loop:YES]; + } } if (hasInitialBackgroundColor) { EaseTransitionConfig bgConfig = transitionConfigForPropertyIndex( @@ -456,7 +481,9 @@ - (void)updateProps:(const Props::Shared &)props self.layer.backgroundColor = RCTUIColorFromSharedColor(newViewProps.animateBackgroundColor) .CGColor; - [self applyAnimationForKeyPath:@"backgroundColor" + if (bgConfig.type != EaseViewTransitionType::None) { + [self + applyAnimationForKeyPath:@"backgroundColor" animationKey:kAnimKeyBackgroundColor fromValue:(__bridge id)RCTUIColorFromSharedColor( newViewProps @@ -467,6 +494,17 @@ - (void)updateProps:(const Props::Shared &)props .CGColor config:bgConfig loop:YES]; + } + } + + // If all per-property configs were 'none', no animations were queued. + // Fire onTransitionEnd immediately to match the scalar 'none' contract. + if (_pendingAnimationCount == 0 && _eventEmitter) { + auto emitter = + std::static_pointer_cast(_eventEmitter); + emitter->onTransitionEnd(EaseViewEventEmitter::OnTransitionEnd{ + .finished = true, + }); } } else { // No initial animation — set target values directly @@ -510,9 +548,11 @@ - (void)updateProps:(const Props::Shared &)props // Subsequent updates: animate changed properties const auto &oldViewProps = *std::static_pointer_cast(oldProps); + BOOL anyPropertyChanged = NO; if ((mask & kMaskOpacity) && oldViewProps.animateOpacity != newViewProps.animateOpacity) { + anyPropertyChanged = YES; EaseTransitionConfig opacityConfig = transitionConfigForPropertyIndex(kPropIndexOpacity, newViewProps); if (opacityConfig.type == EaseViewTransitionType::None) { @@ -543,6 +583,7 @@ - (void)updateProps:(const Props::Shared &)props oldViewProps.animateRotateY != newViewProps.animateRotateY; if (anyTransformChanged) { + anyPropertyChanged = YES; // Determine which transform sub-properties changed for config selection int changedTransformMask = 0; if (oldViewProps.animateTranslateX != newViewProps.animateTranslateX) @@ -583,6 +624,7 @@ - (void)updateProps:(const Props::Shared &)props if ((mask & kMaskBorderRadius) && oldViewProps.animateBorderRadius != newViewProps.animateBorderRadius) { + anyPropertyChanged = YES; EaseTransitionConfig brConfig = transitionConfigForPropertyIndex( kPropIndexBorderRadius, newViewProps); self.layer.cornerRadius = newViewProps.animateBorderRadius; @@ -603,6 +645,7 @@ - (void)updateProps:(const Props::Shared &)props if ((mask & kMaskBackgroundColor) && oldViewProps.animateBackgroundColor != newViewProps.animateBackgroundColor) { + anyPropertyChanged = YES; EaseTransitionConfig bgConfig = transitionConfigForPropertyIndex( kPropIndexBackgroundColor, newViewProps); CGColorRef toColor = @@ -622,6 +665,17 @@ - (void)updateProps:(const Props::Shared &)props loop:NO]; } } + + // If per-property arrays are populated and all changed properties resolved + // to 'none', no animations were queued. Fire onTransitionEnd immediately. + if (perProp && anyPropertyChanged && _pendingAnimationCount == 0 && + _eventEmitter) { + auto emitter = + std::static_pointer_cast(_eventEmitter); + emitter->onTransitionEnd(EaseViewEventEmitter::OnTransitionEnd{ + .finished = true, + }); + } } [CATransaction commit]; From ebc3676db4608b2be780650a3ec7bd1e1e51111b Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sun, 15 Mar 2026 21:20:20 -0400 Subject: [PATCH 3/7] fix: resolve rebase merge conflicts - fix duplicate vars, missing braces, delay prop --- android/src/main/java/com/ease/EaseViewManager.kt | 2 ++ ios/EaseView.mm | 5 +++-- src/EaseView.tsx | 15 +-------------- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/android/src/main/java/com/ease/EaseViewManager.kt b/android/src/main/java/com/ease/EaseViewManager.kt index fa5aafc..4ae1bcd 100644 --- a/android/src/main/java/com/ease/EaseViewManager.kt +++ b/android/src/main/java/com/ease/EaseViewManager.kt @@ -176,6 +176,8 @@ class EaseViewManager : ReactViewManager() { @ReactProp(name = "transitionDelay", defaultInt = 0) fun setTransitionDelay(view: EaseView, value: Int) { view.transitionDelay = value.toLong() + } + // --- Per-property transition arrays --- @ReactProp(name = "perPropertyTransitionTypes") diff --git a/ios/EaseView.mm b/ios/EaseView.mm index 37b83c9..d9ea2c2 100644 --- a/ios/EaseView.mm +++ b/ios/EaseView.mm @@ -303,9 +303,10 @@ - (void)applyAnimationForKeyPath:(NSString *)keyPath toValue:toValue config:config loop:loop]; - if (props.transitionDelay > 0) { + const auto &easeProps = *std::static_pointer_cast(_props); + if (easeProps.transitionDelay > 0) { animation.beginTime = - CACurrentMediaTime() + (props.transitionDelay / 1000.0); + CACurrentMediaTime() + (easeProps.transitionDelay / 1000.0); animation.fillMode = kCAFillModeBackwards; } [animation setValue:@(_animationBatchId) forKey:@"easeBatchId"]; diff --git a/src/EaseView.tsx b/src/EaseView.tsx index a40789e..8f5f9ae 100644 --- a/src/EaseView.tsx +++ b/src/EaseView.tsx @@ -368,23 +368,11 @@ export function EaseView({ ? singleTransition.loop ?? 'none' : 'none'; } - const bezier: CubicBezier = Array.isArray(rawEasing) - ? rawEasing - : EASING_PRESETS[rawEasing]!; - const transitionDamping = - transition?.type === 'spring' ? transition.damping ?? 15 : 15; - const transitionStiffness = - transition?.type === 'spring' ? transition.stiffness ?? 120 : 120; - const transitionMass = - transition?.type === 'spring' ? transition.mass ?? 1 : 1; - const transitionLoop = - transition?.type === 'timing' ? transition.loop ?? 'none' : 'none'; const transitionDelay = transition?.type === 'timing' || transition?.type === 'spring' - ? transition.delay ?? 0 + ? (transition as any).delay ?? 0 : 0; - const handleTransitionEnd = onTransitionEnd ? (event: { nativeEvent: { finished: boolean } }) => onTransitionEnd(event.nativeEvent) @@ -430,7 +418,6 @@ export function EaseView({ perPropertyTransitionMasses={perPropertyArrays?.masses} perPropertyTransitionLoops={perPropertyArrays?.loops} perPropertyTransitionEasingBeziers={perPropertyArrays?.easingBeziers} - useHardwareLayer={useHardwareLayer} transformOriginX={transformOrigin?.x ?? 0.5} transformOriginY={transformOrigin?.y ?? 0.5} From 9cbf079e30bf4031811abf2c4fd4b5567677e4ce Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sun, 15 Mar 2026 21:40:13 -0400 Subject: [PATCH 4/7] fix: resolve type errors for TransitionMap union and clang-format --- ios/EaseView.mm | 3 ++- src/EaseView.tsx | 6 ++++-- src/EaseView.web.tsx | 25 +++++++++++++++++++------ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/ios/EaseView.mm b/ios/EaseView.mm index d9ea2c2..ed1420a 100644 --- a/ios/EaseView.mm +++ b/ios/EaseView.mm @@ -303,7 +303,8 @@ - (void)applyAnimationForKeyPath:(NSString *)keyPath toValue:toValue config:config loop:loop]; - const auto &easeProps = *std::static_pointer_cast(_props); + const auto &easeProps = + *std::static_pointer_cast(_props); if (easeProps.transitionDelay > 0) { animation.beginTime = CACurrentMediaTime() + (easeProps.transitionDelay / 1000.0); diff --git a/src/EaseView.tsx b/src/EaseView.tsx index 8f5f9ae..ca0287f 100644 --- a/src/EaseView.tsx +++ b/src/EaseView.tsx @@ -368,9 +368,11 @@ export function EaseView({ ? singleTransition.loop ?? 'none' : 'none'; } + const singleTrans = + transition && 'type' in transition ? transition : undefined; const transitionDelay = - transition?.type === 'timing' || transition?.type === 'spring' - ? (transition as any).delay ?? 0 + singleTrans?.type === 'timing' || singleTrans?.type === 'spring' + ? singleTrans.delay ?? 0 : 0; const handleTransitionEnd = onTransitionEnd diff --git a/src/EaseView.web.tsx b/src/EaseView.web.tsx index a1e872b..c088785 100644 --- a/src/EaseView.web.tsx +++ b/src/EaseView.web.tsx @@ -3,6 +3,7 @@ import { View, type ViewStyle, type StyleProp } from 'react-native'; import type { AnimateProps, CubicBezier, + SingleTransition, Transition, TransitionEndEvent, TransformOrigin, @@ -81,7 +82,17 @@ function buildTransform(vals: ReturnType): string { return parts.length > 0 ? parts.join(' ') : 'none'; } -function resolveEasing(transition: Transition | undefined): string { +/** For web, resolve a Transition (which may be a TransitionMap) to a SingleTransition. */ +function resolveSingleTransition( + transition: Transition | undefined, +): SingleTransition | undefined { + if (!transition) return undefined; + if ('type' in transition) return transition as SingleTransition; + // TransitionMap — use the default config + return (transition as any).default as SingleTransition | undefined; +} + +function resolveEasing(transition: SingleTransition | undefined): string { if (!transition || transition.type !== 'timing') { return 'cubic-bezier(0.42, 0, 0.58, 1)'; } @@ -92,7 +103,7 @@ function resolveEasing(transition: Transition | undefined): string { return `cubic-bezier(${bezier[0]}, ${bezier[1]}, ${bezier[2]}, ${bezier[3]})`; } -function resolveDuration(transition: Transition | undefined): number { +function resolveDuration(transition: SingleTransition | undefined): number { if (!transition) return 300; if (transition.type === 'timing') return transition.duration ?? 300; if (transition.type === 'none') return 0; @@ -146,14 +157,16 @@ export function EaseView({ const displayValues = !mounted && hasInitial ? resolveAnimateValues(initialAnimate) : resolved; - const duration = resolveDuration(transition); - const easing = resolveEasing(transition); + const singleTransition = resolveSingleTransition(transition); + const duration = resolveDuration(singleTransition); + const easing = resolveEasing(singleTransition); const originX = ((transformOrigin?.x ?? 0.5) * 100).toFixed(1); const originY = ((transformOrigin?.y ?? 0.5) * 100).toFixed(1); - const transitionType = transition?.type ?? 'timing'; - const loopMode = transition?.type === 'timing' ? transition.loop : undefined; + const transitionType = singleTransition?.type ?? 'timing'; + const loopMode = + singleTransition?.type === 'timing' ? singleTransition.loop : undefined; const transitionCss = transitionType === 'none' || (!mounted && hasInitial) From 772755ea0e5e089d92ac6c5d7b47f6fe8527887f Mon Sep 17 00:00:00 2001 From: EQuimper Date: Mon, 16 Mar 2026 13:19:06 -0400 Subject: [PATCH 5/7] fix: changes how props is present --- android/src/main/java/com/ease/EaseView.kt | 184 +++++------ .../src/main/java/com/ease/EaseViewManager.kt | 120 +------ example/src/demos/index.ts | 6 +- ios/EaseView.mm | 232 ++++++------- src/EaseView.tsx | 306 +++++++++--------- src/EaseViewNativeComponent.ts | 57 ++-- src/__tests__/EaseView.test.tsx | 226 +++++++------ 7 files changed, 494 insertions(+), 637 deletions(-) diff --git a/android/src/main/java/com/ease/EaseView.kt b/android/src/main/java/com/ease/EaseView.kt index 1c4cf39..68635c4 100644 --- a/android/src/main/java/com/ease/EaseView.kt +++ b/android/src/main/java/com/ease/EaseView.kt @@ -13,6 +13,7 @@ import android.view.animation.PathInterpolator import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce +import com.facebook.react.bridge.ReadableMap import com.facebook.react.views.view.ReactViewGroup import kotlin.math.sqrt @@ -34,24 +35,8 @@ class EaseView(context: Context) : ReactViewGroup(context) { // --- First mount tracking --- private var isFirstMount: Boolean = true - // --- Transition config (set by ViewManager) --- - var transitionType: String = "timing" - var transitionDuration: Int = 300 - var transitionEasingBezier: FloatArray = floatArrayOf(0.42f, 0f, 0.58f, 1.0f) - var transitionDamping: Float = 15.0f - var transitionStiffness: Float = 120.0f - var transitionMass: Float = 1.0f - var transitionLoop: String = "none" - var transitionDelay: Long = 0L - - // --- Per-property transition arrays (set by ViewManager) --- - var perPropertyTransitionTypes: Array? = null - var perPropertyTransitionDurations: IntArray? = null - var perPropertyTransitionDampings: FloatArray? = null - var perPropertyTransitionStiffnesses: FloatArray? = null - var perPropertyTransitionMasses: FloatArray? = null - var perPropertyTransitionLoops: Array? = null - var perPropertyTransitionEasingBeziers: FloatArray? = null + // --- Transition configs (set by ViewManager via ReadableMap) --- + private var transitionConfigs: Map = emptyMap() data class TransitionConfig( val type: String, @@ -60,49 +45,57 @@ class EaseView(context: Context) : ReactViewGroup(context) { val damping: Float, val stiffness: Float, val mass: Float, - val loop: String + val loop: String, + val delay: Long ) - fun getTransitionConfigForProperty(index: Int): TransitionConfig { - val types = perPropertyTransitionTypes - if (types != null && index < types.size) { - val durations = perPropertyTransitionDurations - val dampings = perPropertyTransitionDampings - val stiffnesses = perPropertyTransitionStiffnesses - val masses = perPropertyTransitionMasses - val loops = perPropertyTransitionLoops - val beziers = perPropertyTransitionEasingBeziers - - val bIdx = index * 4 - val bezier = if (beziers != null && bIdx + 3 < beziers.size) { - floatArrayOf(beziers[bIdx], beziers[bIdx + 1], beziers[bIdx + 2], beziers[bIdx + 3]) - } else { - floatArrayOf(0.42f, 0f, 0.58f, 1.0f) + fun setTransitionsFromMap(map: ReadableMap?) { + if (map == null) { + transitionConfigs = emptyMap() + return + } + val configs = mutableMapOf() + val keys = listOf("defaultConfig", "opacity", "translateX", "translateY", "scaleX", "scaleY", "rotate", "rotateX", "rotateY", "borderRadius", "backgroundColor") + for (key in keys) { + if (map.hasKey(key)) { + val configMap = map.getMap(key) ?: continue + val bezierArray = configMap.getArray("easingBezier") + val bezier = if (bezierArray != null && bezierArray.size() == 4) { + floatArrayOf( + bezierArray.getDouble(0).toFloat(), + bezierArray.getDouble(1).toFloat(), + bezierArray.getDouble(2).toFloat(), + bezierArray.getDouble(3).toFloat() + ) + } else { + floatArrayOf(0.42f, 0f, 0.58f, 1.0f) + } + configs[key] = TransitionConfig( + type = configMap.getString("type") ?: "timing", + duration = if (configMap.hasKey("duration")) configMap.getInt("duration") else 300, + easingBezier = bezier, + damping = if (configMap.hasKey("damping")) configMap.getDouble("damping").toFloat() else 15.0f, + stiffness = if (configMap.hasKey("stiffness")) configMap.getDouble("stiffness").toFloat() else 120.0f, + mass = if (configMap.hasKey("mass")) configMap.getDouble("mass").toFloat() else 1.0f, + loop = configMap.getString("loop") ?: "none", + delay = if (configMap.hasKey("delay")) configMap.getInt("delay").toLong() else 0L + ) } - - return TransitionConfig( - type = types[index], - duration = if (durations != null && index < durations.size) durations[index] else 300, - easingBezier = bezier, - damping = if (dampings != null && index < dampings.size) dampings[index] else 15.0f, - stiffness = if (stiffnesses != null && index < stiffnesses.size) stiffnesses[index] else 120.0f, - mass = if (masses != null && index < masses.size) masses[index] else 1.0f, - loop = if (loops != null && index < loops.size) loops[index] else "none" - ) } - // Fallback to scalar props - return TransitionConfig( - type = transitionType, - duration = transitionDuration, - easingBezier = transitionEasingBezier, - damping = transitionDamping, - stiffness = transitionStiffness, - mass = transitionMass, - loop = transitionLoop - ) + transitionConfigs = configs + } + + fun getTransitionConfig(name: String): TransitionConfig { + return transitionConfigs[name] + ?: transitionConfigs["defaultConfig"] + ?: TransitionConfig("timing", 300, floatArrayOf(0.42f, 0f, 0.58f, 1.0f), 15.0f, 120.0f, 1.0f, "none", 0L) + } + + private fun allTransitionsNone(): Boolean { + val keys = listOf("opacity", "translateX", "translateY", "scaleX", "scaleY", "rotate", "rotateX", "rotateY", "borderRadius", "backgroundColor") + return keys.all { getTransitionConfig(it).type == "none" } } - // Property indices matching JS constants companion object { // Bitmask flags — must match JS constants const val MASK_OPACITY = 1 shl 0 @@ -115,17 +108,6 @@ class EaseView(context: Context) : ReactViewGroup(context) { const val MASK_ROTATE_Y = 1 shl 7 const val MASK_BORDER_RADIUS = 1 shl 8 const val MASK_BACKGROUND_COLOR = 1 shl 9 - - const val PROP_INDEX_OPACITY = 0 - const val PROP_INDEX_TRANSLATE_X = 1 - const val PROP_INDEX_TRANSLATE_Y = 2 - const val PROP_INDEX_SCALE_X = 3 - const val PROP_INDEX_SCALE_Y = 4 - const val PROP_INDEX_ROTATE = 5 - const val PROP_INDEX_ROTATE_X = 6 - const val PROP_INDEX_ROTATE_Y = 7 - const val PROP_INDEX_BORDER_RADIUS = 8 - const val PROP_INDEX_BACKGROUND_COLOR = 9 } // --- Transform origin (0–1 fractions) --- @@ -202,8 +184,6 @@ class EaseView(context: Context) : ReactViewGroup(context) { // --- Animated properties bitmask (set by ViewManager) --- var animatedProperties: Int = 0 - private fun hasPerPropertyArrays(): Boolean = perPropertyTransitionTypes != null - init { // Set camera distance for 3D perspective rotations (rotateX/rotateY) cameraDistance = resources.displayMetrics.density * 850f @@ -307,34 +287,34 @@ class EaseView(context: Context) : ReactViewGroup(context) { // Animate properties that differ from initial to target if (mask and MASK_OPACITY != 0 && initialAnimateOpacity != opacity) { - animateProperty("alpha", DynamicAnimation.ALPHA, initialAnimateOpacity, opacity, getTransitionConfigForProperty(PROP_INDEX_OPACITY), loop = true) + animateProperty("alpha", DynamicAnimation.ALPHA, initialAnimateOpacity, opacity, getTransitionConfig("opacity"), loop = true) } if (mask and MASK_TRANSLATE_X != 0 && initialAnimateTranslateX != translateX) { - animateProperty("translationX", DynamicAnimation.TRANSLATION_X, initialAnimateTranslateX, translateX, getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_X), loop = true) + animateProperty("translationX", DynamicAnimation.TRANSLATION_X, initialAnimateTranslateX, translateX, getTransitionConfig("translateX"), loop = true) } if (mask and MASK_TRANSLATE_Y != 0 && initialAnimateTranslateY != translateY) { - animateProperty("translationY", DynamicAnimation.TRANSLATION_Y, initialAnimateTranslateY, translateY, getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_Y), loop = true) + animateProperty("translationY", DynamicAnimation.TRANSLATION_Y, initialAnimateTranslateY, translateY, getTransitionConfig("translateY"), loop = true) } if (mask and MASK_SCALE_X != 0 && initialAnimateScaleX != scaleX) { - animateProperty("scaleX", DynamicAnimation.SCALE_X, initialAnimateScaleX, scaleX, getTransitionConfigForProperty(PROP_INDEX_SCALE_X), loop = true) + animateProperty("scaleX", DynamicAnimation.SCALE_X, initialAnimateScaleX, scaleX, getTransitionConfig("scaleX"), loop = true) } if (mask and MASK_SCALE_Y != 0 && initialAnimateScaleY != scaleY) { - animateProperty("scaleY", DynamicAnimation.SCALE_Y, initialAnimateScaleY, scaleY, getTransitionConfigForProperty(PROP_INDEX_SCALE_Y), loop = true) + animateProperty("scaleY", DynamicAnimation.SCALE_Y, initialAnimateScaleY, scaleY, getTransitionConfig("scaleY"), loop = true) } if (mask and MASK_ROTATE != 0 && initialAnimateRotate != rotate) { - animateProperty("rotation", DynamicAnimation.ROTATION, initialAnimateRotate, rotate, getTransitionConfigForProperty(PROP_INDEX_ROTATE), loop = true) + animateProperty("rotation", DynamicAnimation.ROTATION, initialAnimateRotate, rotate, getTransitionConfig("rotate"), loop = true) } if (mask and MASK_ROTATE_X != 0 && initialAnimateRotateX != rotateX) { - animateProperty("rotationX", DynamicAnimation.ROTATION_X, initialAnimateRotateX, rotateX, getTransitionConfigForProperty(PROP_INDEX_ROTATE_X), loop = true) + animateProperty("rotationX", DynamicAnimation.ROTATION_X, initialAnimateRotateX, rotateX, getTransitionConfig("rotateX"), loop = true) } if (mask and MASK_ROTATE_Y != 0 && initialAnimateRotateY != rotateY) { - animateProperty("rotationY", DynamicAnimation.ROTATION_Y, initialAnimateRotateY, rotateY, getTransitionConfigForProperty(PROP_INDEX_ROTATE_Y), loop = true) + animateProperty("rotationY", DynamicAnimation.ROTATION_Y, initialAnimateRotateY, rotateY, getTransitionConfig("rotateY"), loop = true) } if (mask and MASK_BORDER_RADIUS != 0 && initialAnimateBorderRadius != borderRadius) { - animateProperty("animateBorderRadius", null, initialAnimateBorderRadius, borderRadius, getTransitionConfigForProperty(PROP_INDEX_BORDER_RADIUS), loop = true) + animateProperty("animateBorderRadius", null, initialAnimateBorderRadius, borderRadius, getTransitionConfig("borderRadius"), loop = true) } if (mask and MASK_BACKGROUND_COLOR != 0 && initialAnimateBackgroundColor != backgroundColor) { - animateBackgroundColor(initialAnimateBackgroundColor, backgroundColor, getTransitionConfigForProperty(PROP_INDEX_BACKGROUND_COLOR), loop = true) + animateBackgroundColor(initialAnimateBackgroundColor, backgroundColor, getTransitionConfig("backgroundColor"), loop = true) } // If all per-property configs were 'none', no animations were queued. @@ -355,7 +335,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (mask and MASK_BORDER_RADIUS != 0) setAnimateBorderRadius(borderRadius) if (mask and MASK_BACKGROUND_COLOR != 0) applyBackgroundColor(backgroundColor) } - } else if (!hasPerPropertyArrays() && transitionType == "none") { + } else if (allTransitionsNone()) { // No transition (scalar) — set values immediately, cancel running animations cancelAllAnimations() if (mask and MASK_OPACITY != 0) this.alpha = opacity @@ -375,7 +355,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevOpacity != null && mask and MASK_OPACITY != 0 && prevOpacity != opacity) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_OPACITY) + val config = getTransitionConfig("opacity") if (config.type == "none") { cancelSpringForProperty("alpha") runningAnimators["alpha"]?.cancel() @@ -389,7 +369,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevTranslateX != null && mask and MASK_TRANSLATE_X != 0 && prevTranslateX != translateX) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_X) + val config = getTransitionConfig("translateX") if (config.type == "none") { cancelSpringForProperty("translationX") runningAnimators["translationX"]?.cancel() @@ -403,7 +383,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevTranslateY != null && mask and MASK_TRANSLATE_Y != 0 && prevTranslateY != translateY) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_TRANSLATE_Y) + val config = getTransitionConfig("translateY") if (config.type == "none") { cancelSpringForProperty("translationY") runningAnimators["translationY"]?.cancel() @@ -417,7 +397,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevScaleX != null && mask and MASK_SCALE_X != 0 && prevScaleX != scaleX) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_SCALE_X) + val config = getTransitionConfig("scaleX") if (config.type == "none") { cancelSpringForProperty("scaleX") runningAnimators["scaleX"]?.cancel() @@ -431,7 +411,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevScaleY != null && mask and MASK_SCALE_Y != 0 && prevScaleY != scaleY) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_SCALE_Y) + val config = getTransitionConfig("scaleY") if (config.type == "none") { cancelSpringForProperty("scaleY") runningAnimators["scaleY"]?.cancel() @@ -445,7 +425,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevRotate != null && mask and MASK_ROTATE != 0 && prevRotate != rotate) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_ROTATE) + val config = getTransitionConfig("rotate") if (config.type == "none") { cancelSpringForProperty("rotation") runningAnimators["rotation"]?.cancel() @@ -459,7 +439,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevRotateX != null && mask and MASK_ROTATE_X != 0 && prevRotateX != rotateX) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_ROTATE_X) + val config = getTransitionConfig("rotateX") if (config.type == "none") { cancelSpringForProperty("rotationX") runningAnimators["rotationX"]?.cancel() @@ -473,7 +453,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevRotateY != null && mask and MASK_ROTATE_Y != 0 && prevRotateY != rotateY) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_ROTATE_Y) + val config = getTransitionConfig("rotateY") if (config.type == "none") { cancelSpringForProperty("rotationY") runningAnimators["rotationY"]?.cancel() @@ -487,7 +467,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevBorderRadius != null && mask and MASK_BORDER_RADIUS != 0 && prevBorderRadius != borderRadius) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_BORDER_RADIUS) + val config = getTransitionConfig("borderRadius") if (config.type == "none") { runningAnimators["animateBorderRadius"]?.cancel() runningAnimators.remove("animateBorderRadius") @@ -500,7 +480,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { if (prevBackgroundColor != null && mask and MASK_BACKGROUND_COLOR != 0 && prevBackgroundColor != backgroundColor) { anyPropertyChanged = true - val config = getTransitionConfigForProperty(PROP_INDEX_BACKGROUND_COLOR) + val config = getTransitionConfig("backgroundColor") if (config.type == "none") { runningAnimators["backgroundColor"]?.cancel() runningAnimators.remove("backgroundColor") @@ -510,9 +490,9 @@ class EaseView(context: Context) : ReactViewGroup(context) { } } - // If per-property arrays are populated and all changed properties resolved - // to 'none', no animations were queued. Fire onTransitionEnd immediately. - if (hasPerPropertyArrays() && anyPropertyChanged && pendingBatchAnimationCount == 0) { + // If all changed properties resolved to 'none', no animations were queued. + // Fire onTransitionEnd immediately. + if (anyPropertyChanged && pendingBatchAnimationCount == 0) { onTransitionEnd?.invoke(true) } } @@ -558,9 +538,8 @@ class EaseView(context: Context) : ReactViewGroup(context) { pendingBatchAnimationCount++ val animator = ValueAnimator.ofArgb(fromColor, toColor).apply { - duration = transitionDuration.toLong() - startDelay = transitionDelay duration = config.duration.toLong() + startDelay = config.delay interpolator = PathInterpolator( config.easingBezier[0], config.easingBezier[1], @@ -632,9 +611,8 @@ class EaseView(context: Context) : ReactViewGroup(context) { pendingBatchAnimationCount++ val animator = ObjectAnimator.ofFloat(this, propertyName, fromValue, toValue).apply { - duration = transitionDuration.toLong() - startDelay = transitionDelay duration = config.duration.toLong() + startDelay = config.delay interpolator = PathInterpolator( config.easingBezier[0], config.easingBezier[1], @@ -715,10 +693,10 @@ class EaseView(context: Context) : ReactViewGroup(context) { onEaseAnimationStart() runningSpringAnimations[viewProperty] = spring - if (transitionDelay > 0) { + if (config.delay > 0) { val runnable = Runnable { spring.start() } pendingDelayedRunnables.add(runnable) - postDelayed(runnable, transitionDelay) + postDelayed(runnable, config.delay) } else { spring.start() } @@ -822,14 +800,6 @@ class EaseView(context: Context) : ReactViewGroup(context) { applyBackgroundColor(Color.TRANSPARENT) isFirstMount = true - transitionLoop = "none" - - perPropertyTransitionTypes = null - perPropertyTransitionDurations = null - perPropertyTransitionDampings = null - perPropertyTransitionStiffnesses = null - perPropertyTransitionMasses = null - perPropertyTransitionLoops = null - perPropertyTransitionEasingBeziers = null + transitionConfigs = emptyMap() } } diff --git a/android/src/main/java/com/ease/EaseViewManager.kt b/android/src/main/java/com/ease/EaseViewManager.kt index 4ae1bcd..4282310 100644 --- a/android/src/main/java/com/ease/EaseViewManager.kt +++ b/android/src/main/java/com/ease/EaseViewManager.kt @@ -3,6 +3,7 @@ package com.ease import android.graphics.Color import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.WritableMap import com.facebook.react.module.annotations.ReactModule import com.facebook.react.uimanager.PixelUtil @@ -126,122 +127,11 @@ class EaseViewManager : ReactViewManager() { view.initialAnimateBorderRadius = PixelUtil.toPixelFromDIP(value) } - // --- Transition config setters --- - - @ReactProp(name = "transitionType") - fun setTransitionType(view: EaseView, value: String?) { - view.transitionType = value ?: "timing" - } - - @ReactProp(name = "transitionDuration", defaultInt = 300) - fun setTransitionDuration(view: EaseView, value: Int) { - view.transitionDuration = value - } - - @ReactProp(name = "transitionEasingBezier") - fun setTransitionEasingBezier(view: EaseView, value: ReadableArray?) { - if (value != null && value.size() == 4) { - view.transitionEasingBezier = floatArrayOf( - value.getDouble(0).toFloat(), - value.getDouble(1).toFloat(), - value.getDouble(2).toFloat(), - value.getDouble(3).toFloat() - ) - } else { - // Fallback: easeInOut - view.transitionEasingBezier = floatArrayOf(0.42f, 0f, 0.58f, 1.0f) - } - } - - @ReactProp(name = "transitionDamping", defaultFloat = 15f) - fun setTransitionDamping(view: EaseView, value: Float) { - view.transitionDamping = value - } - - @ReactProp(name = "transitionStiffness", defaultFloat = 120f) - fun setTransitionStiffness(view: EaseView, value: Float) { - view.transitionStiffness = value - } - - @ReactProp(name = "transitionMass", defaultFloat = 1f) - fun setTransitionMass(view: EaseView, value: Float) { - view.transitionMass = value - } - - @ReactProp(name = "transitionLoop") - fun setTransitionLoop(view: EaseView, value: String?) { - view.transitionLoop = value ?: "none" - } - - @ReactProp(name = "transitionDelay", defaultInt = 0) - fun setTransitionDelay(view: EaseView, value: Int) { - view.transitionDelay = value.toLong() - } - - // --- Per-property transition arrays --- - - @ReactProp(name = "perPropertyTransitionTypes") - fun setPerPropertyTransitionTypes(view: EaseView, value: ReadableArray?) { - if (value != null && value.size() == 10) { - view.perPropertyTransitionTypes = Array(10) { value.getString(it) ?: "" } - } else { - view.perPropertyTransitionTypes = null - } - } - - @ReactProp(name = "perPropertyTransitionDurations") - fun setPerPropertyTransitionDurations(view: EaseView, value: ReadableArray?) { - if (value != null && value.size() == 10) { - view.perPropertyTransitionDurations = IntArray(10) { value.getInt(it) } - } else { - view.perPropertyTransitionDurations = null - } - } - - @ReactProp(name = "perPropertyTransitionDampings") - fun setPerPropertyTransitionDampings(view: EaseView, value: ReadableArray?) { - if (value != null && value.size() == 10) { - view.perPropertyTransitionDampings = FloatArray(10) { value.getDouble(it).toFloat() } - } else { - view.perPropertyTransitionDampings = null - } - } - - @ReactProp(name = "perPropertyTransitionStiffnesses") - fun setPerPropertyTransitionStiffnesses(view: EaseView, value: ReadableArray?) { - if (value != null && value.size() == 10) { - view.perPropertyTransitionStiffnesses = FloatArray(10) { value.getDouble(it).toFloat() } - } else { - view.perPropertyTransitionStiffnesses = null - } - } - - @ReactProp(name = "perPropertyTransitionMasses") - fun setPerPropertyTransitionMasses(view: EaseView, value: ReadableArray?) { - if (value != null && value.size() == 10) { - view.perPropertyTransitionMasses = FloatArray(10) { value.getDouble(it).toFloat() } - } else { - view.perPropertyTransitionMasses = null - } - } - - @ReactProp(name = "perPropertyTransitionLoops") - fun setPerPropertyTransitionLoops(view: EaseView, value: ReadableArray?) { - if (value != null && value.size() == 10) { - view.perPropertyTransitionLoops = Array(10) { value.getString(it) ?: "" } - } else { - view.perPropertyTransitionLoops = null - } - } - - @ReactProp(name = "perPropertyTransitionEasingBeziers") - fun setPerPropertyTransitionEasingBeziers(view: EaseView, value: ReadableArray?) { - if (value != null && value.size() == 40) { - view.perPropertyTransitionEasingBeziers = FloatArray(40) { value.getDouble(it).toFloat() } - } else { - view.perPropertyTransitionEasingBeziers = null - } + // --- Transitions config (single ReadableMap) --- + @ReactProp(name = "transitions") + fun setTransitions(view: EaseView, value: ReadableMap?) { + view.setTransitionsFromMap(value) } // --- Border radius --- diff --git a/example/src/demos/index.ts b/example/src/demos/index.ts index 4f35bfd..9f39566 100644 --- a/example/src/demos/index.ts +++ b/example/src/demos/index.ts @@ -36,7 +36,6 @@ export const demos: Record = { 'rotate': { component: RotateDemo, title: 'Rotate', section: 'Transform' }, 'scale': { component: ScaleDemo, title: 'Scale', section: 'Transform' }, 'transform-origin': { - 'per-property': { component: PerPropertyDemo, title: 'Per-Property', section: 'Advanced' }, component: TransformOriginDemo, title: 'Transform Origin', section: 'Transform', @@ -80,6 +79,11 @@ export const demos: Record = { title: 'Comparison', section: 'Advanced', }, + 'per-property': { + component: PerPropertyDemo, + title: 'Per-Property', + section: 'Advanced', + }, }; interface SectionData { diff --git a/ios/EaseView.mm b/ios/EaseView.mm index ed1420a..b4eea9f 100644 --- a/ios/EaseView.mm +++ b/ios/EaseView.mm @@ -58,79 +58,26 @@ static CATransform3D composeTransform(CGFloat scaleX, CGFloat scaleY, kMaskScaleX | kMaskScaleY | kMaskRotate | kMaskRotateX | kMaskRotateY; -// Per-property transition config resolved from arrays or scalar fallback +// Per-property transition config resolved from the transitions struct struct EaseTransitionConfig { - EaseViewTransitionType type; + std::string type; int duration; float bezier[4]; float damping; float stiffness; float mass; - EaseViewTransitionLoop loop; + std::string loop; + int delay; }; -static EaseTransitionConfig -transitionConfigForPropertyIndex(int index, const EaseViewProps &props) { - const auto &types = props.perPropertyTransitionTypes; - if (!types.empty() && index < (int)types.size()) { - EaseTransitionConfig config; - // Type - const auto &typeStr = types[index]; - if (typeStr == "spring") { - config.type = EaseViewTransitionType::Spring; - } else if (typeStr == "none") { - config.type = EaseViewTransitionType::None; - } else { - config.type = EaseViewTransitionType::Timing; - } - // Duration - const auto &durations = props.perPropertyTransitionDurations; - config.duration = (index < (int)durations.size()) ? durations[index] : 300; - // Bezier (4 values per property) - const auto &beziers = props.perPropertyTransitionEasingBeziers; - int bIdx = index * 4; - if (bIdx + 3 < (int)beziers.size()) { - config.bezier[0] = beziers[bIdx]; - config.bezier[1] = beziers[bIdx + 1]; - config.bezier[2] = beziers[bIdx + 2]; - config.bezier[3] = beziers[bIdx + 3]; - } else { - config.bezier[0] = 0.42f; - config.bezier[1] = 0.0f; - config.bezier[2] = 0.58f; - config.bezier[3] = 1.0f; - } - // Damping - const auto &dampings = props.perPropertyTransitionDampings; - config.damping = (index < (int)dampings.size()) ? dampings[index] : 15.0f; - // Stiffness - const auto &stiffnesses = props.perPropertyTransitionStiffnesses; - config.stiffness = - (index < (int)stiffnesses.size()) ? stiffnesses[index] : 120.0f; - // Mass - const auto &masses = props.perPropertyTransitionMasses; - config.mass = (index < (int)masses.size()) ? masses[index] : 1.0f; - // Loop - const auto &loops = props.perPropertyTransitionLoops; - if (index < (int)loops.size()) { - const auto &loopStr = loops[index]; - if (loopStr == "repeat") { - config.loop = EaseViewTransitionLoop::Repeat; - } else if (loopStr == "reverse") { - config.loop = EaseViewTransitionLoop::Reverse; - } else { - config.loop = EaseViewTransitionLoop::None; - } - } else { - config.loop = EaseViewTransitionLoop::None; - } - return config; - } - // Fallback to scalar props +// Convert from a codegen-generated transition config struct to our local +// EaseTransitionConfig +template +static EaseTransitionConfig transitionConfigFromStruct(const T &src) { EaseTransitionConfig config; - config.type = props.transitionType; - config.duration = props.transitionDuration; - const auto &b = props.transitionEasingBezier; + config.type = src.type; + config.duration = src.duration; + const auto &b = src.easingBezier; if (b.size() == 4) { config.bezier[0] = b[0]; config.bezier[1] = b[1]; @@ -142,38 +89,59 @@ static CATransform3D composeTransform(CGFloat scaleX, CGFloat scaleY, config.bezier[2] = 0.58f; config.bezier[3] = 1.0f; } - config.damping = props.transitionDamping; - config.stiffness = props.transitionStiffness; - config.mass = props.transitionMass; - config.loop = props.transitionLoop; + config.damping = src.damping; + config.stiffness = src.stiffness; + config.mass = src.mass; + config.loop = src.loop; + config.delay = src.delay; return config; } -// Property indices matching JS constants -static const int kPropIndexOpacity = 0; -static const int kPropIndexTranslateX = 1; -// static const int kPropIndexTranslateY = 2; -// static const int kPropIndexScaleX = 3; -// static const int kPropIndexScaleY = 4; -// static const int kPropIndexRotate = 5; -// static const int kPropIndexRotateX = 6; -// static const int kPropIndexRotateY = 7; -static const int kPropIndexBorderRadius = 8; -static const int kPropIndexBackgroundColor = 9; - -// Check if per-property arrays are populated -static BOOL hasPerPropertyArrays(const EaseViewProps &props) { - return !props.perPropertyTransitionTypes.empty(); +static EaseTransitionConfig +transitionConfigForProperty(const std::string &name, + const EaseViewProps &props) { + if (name == "opacity") { + return transitionConfigFromStruct(props.transitions.opacity); + } else if (name == "translateX") { + return transitionConfigFromStruct(props.transitions.translateX); + } else if (name == "translateY") { + return transitionConfigFromStruct(props.transitions.translateY); + } else if (name == "scaleX") { + return transitionConfigFromStruct(props.transitions.scaleX); + } else if (name == "scaleY") { + return transitionConfigFromStruct(props.transitions.scaleY); + } else if (name == "rotate") { + return transitionConfigFromStruct(props.transitions.rotate); + } else if (name == "rotateX") { + return transitionConfigFromStruct(props.transitions.rotateX); + } else if (name == "rotateY") { + return transitionConfigFromStruct(props.transitions.rotateY); + } else if (name == "borderRadius") { + return transitionConfigFromStruct(props.transitions.borderRadius); + } else if (name == "backgroundColor") { + return transitionConfigFromStruct(props.transitions.backgroundColor); + } + // Fallback to defaultConfig + return transitionConfigFromStruct(props.transitions.defaultConfig); } -// Find lowest property index with a set mask bit among transform properties -static int lowestTransformPropertyIndex(int mask) { - for (int i = 1; i <= 7; i++) { - if (mask & (1 << i)) { - return i; - } - } - return 1; // fallback to translateX +// Find lowest property name with a set mask bit among transform properties +static std::string lowestTransformPropertyName(int mask) { + if (mask & kMaskTranslateX) + return "translateX"; + if (mask & kMaskTranslateY) + return "translateY"; + if (mask & kMaskScaleX) + return "scaleX"; + if (mask & kMaskScaleY) + return "scaleY"; + if (mask & kMaskRotate) + return "rotate"; + if (mask & kMaskRotateX) + return "rotateX"; + if (mask & kMaskRotateY) + return "rotateY"; + return "translateX"; // fallback } @implementation EaseView { @@ -259,7 +227,7 @@ - (CAAnimation *)createAnimationForKeyPath:(NSString *)keyPath toValue:(NSValue *)toValue config:(EaseTransitionConfig)config loop:(BOOL)loop { - if (config.type == EaseViewTransitionType::Spring) { + if (config.type == "spring") { CASpringAnimation *spring = [CASpringAnimation animationWithKeyPath:keyPath]; spring.fromValue = fromValue; @@ -279,9 +247,9 @@ - (CAAnimation *)createAnimationForKeyPath:(NSString *)keyPath functionWithControlPoints:config.bezier[0]:config.bezier[1 ]:config.bezier[2]:config.bezier[3]]; if (loop) { - if (config.loop == EaseViewTransitionLoop::Repeat) { + if (config.loop == "repeat") { timing.repeatCount = HUGE_VALF; - } else if (config.loop == EaseViewTransitionLoop::Reverse) { + } else if (config.loop == "reverse") { timing.repeatCount = HUGE_VALF; timing.autoreverses = YES; } @@ -303,11 +271,8 @@ - (void)applyAnimationForKeyPath:(NSString *)keyPath toValue:toValue config:config loop:loop]; - const auto &easeProps = - *std::static_pointer_cast(_props); - if (easeProps.transitionDelay > 0) { - animation.beginTime = - CACurrentMediaTime() + (easeProps.transitionDelay / 1000.0); + if (config.delay > 0) { + animation.beginTime = CACurrentMediaTime() + (config.delay / 1000.0); animation.fillMode = kCAFillModeBackwards; } [animation setValue:@(_animationBatchId) forKey:@"easeBatchId"]; @@ -368,8 +333,6 @@ - (void)updateProps:(const Props::Shared &)props int mask = newViewProps.animatedProperties; BOOL hasTransform = (mask & kMaskAnyTransform) != 0; - BOOL perProp = hasPerPropertyArrays(newViewProps); - if (_isFirstMount) { _isFirstMount = NO; @@ -419,9 +382,9 @@ - (void)updateProps:(const Props::Shared &)props // Animate from initial to target (skip if config is 'none') if (hasInitialOpacity) { EaseTransitionConfig opacityConfig = - transitionConfigForPropertyIndex(kPropIndexOpacity, newViewProps); + transitionConfigForProperty("opacity", newViewProps); self.layer.opacity = newViewProps.animateOpacity; - if (opacityConfig.type != EaseViewTransitionType::None) { + if (opacityConfig.type != "none") { [self applyAnimationForKeyPath:@"opacity" animationKey:kAnimKeyOpacity fromValue:@(newViewProps.initialAnimateOpacity) @@ -449,11 +412,12 @@ - (void)updateProps:(const Props::Shared &)props changedInitTransform |= kMaskRotateX; if (newViewProps.initialAnimateRotateY != newViewProps.animateRotateY) changedInitTransform |= kMaskRotateY; - int transformIdx = lowestTransformPropertyIndex(changedInitTransform); + std::string transformName = + lowestTransformPropertyName(changedInitTransform); EaseTransitionConfig transformConfig = - transitionConfigForPropertyIndex(transformIdx, newViewProps); + transitionConfigForProperty(transformName, newViewProps); self.layer.transform = targetT; - if (transformConfig.type != EaseViewTransitionType::None) { + if (transformConfig.type != "none") { [self applyAnimationForKeyPath:@"transform" animationKey:kAnimKeyTransform @@ -464,10 +428,10 @@ - (void)updateProps:(const Props::Shared &)props } } if (hasInitialBorderRadius) { - EaseTransitionConfig brConfig = transitionConfigForPropertyIndex( - kPropIndexBorderRadius, newViewProps); + EaseTransitionConfig brConfig = + transitionConfigForProperty("borderRadius", newViewProps); self.layer.cornerRadius = newViewProps.animateBorderRadius; - if (brConfig.type != EaseViewTransitionType::None) { + if (brConfig.type != "none") { [self applyAnimationForKeyPath:@"cornerRadius" animationKey:kAnimKeyCornerRadius fromValue:@(newViewProps @@ -478,12 +442,12 @@ - (void)updateProps:(const Props::Shared &)props } } if (hasInitialBackgroundColor) { - EaseTransitionConfig bgConfig = transitionConfigForPropertyIndex( - kPropIndexBackgroundColor, newViewProps); + EaseTransitionConfig bgConfig = + transitionConfigForProperty("backgroundColor", newViewProps); self.layer.backgroundColor = RCTUIColorFromSharedColor(newViewProps.animateBackgroundColor) .CGColor; - if (bgConfig.type != EaseViewTransitionType::None) { + if (bgConfig.type != "none") { [self applyAnimationForKeyPath:@"backgroundColor" animationKey:kAnimKeyBackgroundColor @@ -523,9 +487,17 @@ - (void)updateProps:(const Props::Shared &)props RCTUIColorFromSharedColor(newViewProps.animateBackgroundColor) .CGColor; } - } else if (!perProp && - newViewProps.transitionType == EaseViewTransitionType::None) { - // No transition (scalar) — set values immediately + } else if (newViewProps.transitions.opacity.type == "none" && + newViewProps.transitions.translateX.type == "none" && + newViewProps.transitions.translateY.type == "none" && + newViewProps.transitions.scaleX.type == "none" && + newViewProps.transitions.scaleY.type == "none" && + newViewProps.transitions.rotate.type == "none" && + newViewProps.transitions.rotateX.type == "none" && + newViewProps.transitions.rotateY.type == "none" && + newViewProps.transitions.borderRadius.type == "none" && + newViewProps.transitions.backgroundColor.type == "none") { + // All transitions are 'none' — set values immediately [self.layer removeAllAnimations]; if (mask & kMaskOpacity) self.layer.opacity = newViewProps.animateOpacity; @@ -556,8 +528,8 @@ - (void)updateProps:(const Props::Shared &)props oldViewProps.animateOpacity != newViewProps.animateOpacity) { anyPropertyChanged = YES; EaseTransitionConfig opacityConfig = - transitionConfigForPropertyIndex(kPropIndexOpacity, newViewProps); - if (opacityConfig.type == EaseViewTransitionType::None) { + transitionConfigForProperty("opacity", newViewProps); + if (opacityConfig.type == "none") { self.layer.opacity = newViewProps.animateOpacity; [self.layer removeAnimationForKey:kAnimKeyOpacity]; } else { @@ -603,11 +575,12 @@ - (void)updateProps:(const Props::Shared &)props if (oldViewProps.animateRotateY != newViewProps.animateRotateY) changedTransformMask |= kMaskRotateY; - int transformIdx = lowestTransformPropertyIndex(changedTransformMask); + std::string transformName = + lowestTransformPropertyName(changedTransformMask); EaseTransitionConfig transformConfig = - transitionConfigForPropertyIndex(transformIdx, newViewProps); + transitionConfigForProperty(transformName, newViewProps); - if (transformConfig.type == EaseViewTransitionType::None) { + if (transformConfig.type == "none") { self.layer.transform = [self targetTransformFromProps:newViewProps]; [self.layer removeAnimationForKey:kAnimKeyTransform]; } else { @@ -627,11 +600,11 @@ - (void)updateProps:(const Props::Shared &)props if ((mask & kMaskBorderRadius) && oldViewProps.animateBorderRadius != newViewProps.animateBorderRadius) { anyPropertyChanged = YES; - EaseTransitionConfig brConfig = transitionConfigForPropertyIndex( - kPropIndexBorderRadius, newViewProps); + EaseTransitionConfig brConfig = + transitionConfigForProperty("borderRadius", newViewProps); self.layer.cornerRadius = newViewProps.animateBorderRadius; self.layer.masksToBounds = newViewProps.animateBorderRadius > 0; - if (brConfig.type == EaseViewTransitionType::None) { + if (brConfig.type == "none") { [self.layer removeAnimationForKey:kAnimKeyCornerRadius]; } else { [self applyAnimationForKeyPath:@"cornerRadius" @@ -648,13 +621,13 @@ - (void)updateProps:(const Props::Shared &)props oldViewProps.animateBackgroundColor != newViewProps.animateBackgroundColor) { anyPropertyChanged = YES; - EaseTransitionConfig bgConfig = transitionConfigForPropertyIndex( - kPropIndexBackgroundColor, newViewProps); + EaseTransitionConfig bgConfig = + transitionConfigForProperty("backgroundColor", newViewProps); CGColorRef toColor = RCTUIColorFromSharedColor(newViewProps.animateBackgroundColor) .CGColor; self.layer.backgroundColor = toColor; - if (bgConfig.type == EaseViewTransitionType::None) { + if (bgConfig.type == "none") { [self.layer removeAnimationForKey:kAnimKeyBackgroundColor]; } else { CGColorRef fromColor = (__bridge CGColorRef) @@ -668,10 +641,9 @@ - (void)updateProps:(const Props::Shared &)props } } - // If per-property arrays are populated and all changed properties resolved - // to 'none', no animations were queued. Fire onTransitionEnd immediately. - if (perProp && anyPropertyChanged && _pendingAnimationCount == 0 && - _eventEmitter) { + // If all changed properties resolved to 'none', no animations were queued. + // Fire onTransitionEnd immediately. + if (anyPropertyChanged && _pendingAnimationCount == 0 && _eventEmitter) { auto emitter = std::static_pointer_cast(_eventEmitter); emitter->onTransitionEnd(EaseViewEventEmitter::OnTransitionEnd{ diff --git a/src/EaseView.tsx b/src/EaseView.tsx index ca0287f..f1c60e8 100644 --- a/src/EaseView.tsx +++ b/src/EaseView.tsx @@ -59,8 +59,8 @@ const EASING_PRESETS: Record = { easeInOut: [0.42, 0, 0.58, 1], }; -/** Property index order for per-property arrays. */ -const PROPERTY_KEYS: (keyof AnimateProps)[] = [ +/** Transition struct field names (matches NativeTransitions keys). */ +const TRANSITION_KEYS = [ 'opacity', 'translateX', 'translateY', @@ -71,111 +71,190 @@ const PROPERTY_KEYS: (keyof AnimateProps)[] = [ 'rotateY', 'borderRadius', 'backgroundColor', -]; +] as const; -const PROPERTY_COUNT = PROPERTY_KEYS.length; +type TransitionKey = (typeof TRANSITION_KEYS)[number]; + +/** Transform property keys (indices 1-7) get spring defaults; others get timing. */ +const TRANSFORM_KEYS = new Set([ + 'translateX', + 'translateY', + 'scaleX', + 'scaleY', + 'rotate', + 'rotateX', + 'rotateY', +]); /** Returns true if the transition is a SingleTransition (has a `type` field). */ function isSingleTransition(t: Transition): t is SingleTransition { return 'type' in t; } -/** Library defaults: spring for transforms (indices 1-7), timing 300ms easeInOut for others. */ -const TIMING_DEFAULT: SingleTransition = { +/** Resolved native transition config for a single property. */ +type NativeTransitionConfig = { + type: string; + duration: number; + easingBezier: number[]; + damping: number; + stiffness: number; + mass: number; + loop: string; + delay: number; +}; + +/** Full transitions struct passed to native. */ +type NativeTransitions = { + defaultConfig: NativeTransitionConfig; + opacity: NativeTransitionConfig; + translateX: NativeTransitionConfig; + translateY: NativeTransitionConfig; + scaleX: NativeTransitionConfig; + scaleY: NativeTransitionConfig; + rotate: NativeTransitionConfig; + rotateX: NativeTransitionConfig; + rotateY: NativeTransitionConfig; + borderRadius: NativeTransitionConfig; + backgroundColor: NativeTransitionConfig; +}; + +/** Library defaults: spring for transforms, timing 300ms easeInOut for others. */ +const TIMING_DEFAULT_CONFIG: NativeTransitionConfig = { type: 'timing', duration: 300, - easing: 'easeInOut', + easingBezier: [0.42, 0, 0.58, 1], + damping: 15, + stiffness: 120, + mass: 1, + loop: 'none', + delay: 0, }; -const SPRING_DEFAULT: SingleTransition = { + +const SPRING_DEFAULT_CONFIG: NativeTransitionConfig = { type: 'spring', + duration: 300, + easingBezier: [0.42, 0, 0.58, 1], damping: 15, stiffness: 120, mass: 1, + loop: 'none', + delay: 0, }; -function getLibraryDefault(index: number): SingleTransition { - // Indices 1-7 are transforms → spring default - // Indices 0,8,9 are opacity, borderRadius, backgroundColor → timing default - return index >= 1 && index <= 7 ? SPRING_DEFAULT : TIMING_DEFAULT; +function getLibraryDefault(key: TransitionKey): NativeTransitionConfig { + return TRANSFORM_KEYS.has(key) + ? SPRING_DEFAULT_CONFIG + : TIMING_DEFAULT_CONFIG; } -/** Resolve a SingleTransition into flat scalar values. */ -function resolveSingleConfig(config: SingleTransition) { - const type = config.type as 'timing' | 'spring' | 'none'; +/** Resolve a SingleTransition into a native config object. */ +function resolveSingleConfig(config: SingleTransition): NativeTransitionConfig { + const type = config.type as string; const duration = config.type === 'timing' ? config.duration ?? 300 : 300; const rawEasing = config.type === 'timing' ? config.easing ?? 'easeInOut' : 'easeInOut'; - const bezier: CubicBezier = Array.isArray(rawEasing) + if (__DEV__) { + if (Array.isArray(rawEasing)) { + if ((rawEasing as number[]).length !== 4) { + console.warn( + 'react-native-ease: Custom easing must be a [x1, y1, x2, y2] tuple (got length ' + + (rawEasing as number[]).length + + ').', + ); + } + if ( + rawEasing[0] < 0 || + rawEasing[0] > 1 || + rawEasing[2] < 0 || + rawEasing[2] > 1 + ) { + console.warn( + 'react-native-ease: Easing x-values (x1, x2) must be between 0 and 1.', + ); + } + } + } + const easingBezier: number[] = Array.isArray(rawEasing) ? rawEasing : EASING_PRESETS[rawEasing]!; const damping = config.type === 'spring' ? config.damping ?? 15 : 15; const stiffness = config.type === 'spring' ? config.stiffness ?? 120 : 120; const mass = config.type === 'spring' ? config.mass ?? 1 : 1; - const loop: 'none' | 'repeat' | 'reverse' = + const loop: string = config.type === 'timing' ? config.loop ?? 'none' : 'none'; - return { type, duration, bezier, damping, stiffness, mass, loop }; + const delay = + config.type === 'timing' || config.type === 'spring' + ? config.delay ?? 0 + : 0; + return { + type, + duration, + easingBezier, + damping, + stiffness, + mass, + loop, + delay, + }; } -interface PerPropertyArrays { - types: string[]; - durations: number[]; - dampings: number[]; - stiffnesses: number[]; - masses: number[]; - loops: string[]; - easingBeziers: number[]; -} +/** Resolve the transition prop into a fully-populated NativeTransitions struct. */ +function resolveTransitions(transition?: Transition): NativeTransitions { + // Single transition: apply the same config to all 11 slots + if (transition != null && isSingleTransition(transition)) { + const config = resolveSingleConfig(transition); + const result = { defaultConfig: config } as Record< + string, + NativeTransitionConfig + >; + for (const key of TRANSITION_KEYS) { + result[key] = config; + } + return result as unknown as NativeTransitions; + } -function resolvePerPropertyTransitions( - transitionMap: Exclude, -): { - scalars: ReturnType; - arrays: PerPropertyArrays; -} { - const arrays: PerPropertyArrays = { - types: [], - durations: [], - dampings: [], - stiffnesses: [], - masses: [], - loops: [], - easingBeziers: [], - }; + // No transition: use library defaults per category + if (transition == null) { + const result = { defaultConfig: TIMING_DEFAULT_CONFIG } as Record< + string, + NativeTransitionConfig + >; + for (const key of TRANSITION_KEYS) { + result[key] = getLibraryDefault(key); + } + return result as unknown as NativeTransitions; + } - const defaultConfig = transitionMap.default; + // TransitionMap: resolve per property + const transitionMap = transition; + const defaultSingle = transitionMap.default; + const defaultNative = defaultSingle + ? resolveSingleConfig(defaultSingle) + : undefined; + + const result = { + defaultConfig: defaultNative ?? TIMING_DEFAULT_CONFIG, + } as Record; - for (let i = 0; i < PROPERTY_COUNT; i++) { - const key = PROPERTY_KEYS[i]!; - // Resolution order: specific key → scale shorthand (for scaleX/scaleY) → default → library default - let config: SingleTransition; - if (transitionMap[key] != null) { - config = transitionMap[key]!; + for (const key of TRANSITION_KEYS) { + const specific = transitionMap[key as keyof typeof transitionMap] as + | SingleTransition + | undefined; + if (specific != null) { + result[key] = resolveSingleConfig(specific); } else if ( (key === 'scaleX' || key === 'scaleY') && transitionMap.scale != null ) { - config = transitionMap.scale!; - } else if (defaultConfig != null) { - config = defaultConfig; + result[key] = resolveSingleConfig(transitionMap.scale!); + } else if (defaultNative) { + result[key] = defaultNative; } else { - config = getLibraryDefault(i); + result[key] = getLibraryDefault(key); } - - const resolved = resolveSingleConfig(config); - arrays.types.push(resolved.type); - arrays.durations.push(resolved.duration); - arrays.dampings.push(resolved.damping); - arrays.stiffnesses.push(resolved.stiffness); - arrays.masses.push(resolved.mass); - arrays.loops.push(resolved.loop); - arrays.easingBeziers.push(...resolved.bezier); } - // Scalar props = default key values (or library defaults for opacity category) - const scalarConfig = defaultConfig ?? TIMING_DEFAULT; - const scalars = resolveSingleConfig(scalarConfig); - - return { scalars, arrays }; + return result as unknown as NativeTransitions; } export type EaseViewProps = ViewProps & { @@ -299,81 +378,8 @@ export function EaseView({ } } - // Resolve transition config — single config or per-property map - const isMap = transition != null && !isSingleTransition(transition); - const singleTransition = transition == null || isMap ? undefined : transition; - - // Single config resolution (used when single transition or as scalars for map) - let transitionType: 'timing' | 'spring' | 'none'; - let transitionDuration: number; - let bezier: CubicBezier; - let transitionDamping: number; - let transitionStiffness: number; - let transitionMass: number; - let transitionLoop: 'none' | 'repeat' | 'reverse'; - let perPropertyArrays: PerPropertyArrays | undefined; - - if (isMap) { - const { scalars, arrays } = resolvePerPropertyTransitions(transition); - transitionType = scalars.type; - transitionDuration = scalars.duration; - bezier = scalars.bezier; - transitionDamping = scalars.damping; - transitionStiffness = scalars.stiffness; - transitionMass = scalars.mass; - transitionLoop = scalars.loop; - perPropertyArrays = arrays; - } else { - transitionType = singleTransition?.type ?? 'timing'; - transitionDuration = - singleTransition?.type === 'timing' - ? singleTransition.duration ?? 300 - : 300; - const rawEasing = - singleTransition?.type === 'timing' - ? singleTransition.easing ?? 'easeInOut' - : 'easeInOut'; - if (__DEV__) { - if (Array.isArray(rawEasing)) { - if ((rawEasing as number[]).length !== 4) { - console.warn( - 'react-native-ease: Custom easing must be a [x1, y1, x2, y2] tuple (got length ' + - (rawEasing as number[]).length + - ').', - ); - } - if ( - rawEasing[0] < 0 || - rawEasing[0] > 1 || - rawEasing[2] < 0 || - rawEasing[2] > 1 - ) { - console.warn( - 'react-native-ease: Easing x-values (x1, x2) must be between 0 and 1.', - ); - } - } - } - bezier = Array.isArray(rawEasing) ? rawEasing : EASING_PRESETS[rawEasing]!; - transitionDamping = - singleTransition?.type === 'spring' ? singleTransition.damping ?? 15 : 15; - transitionStiffness = - singleTransition?.type === 'spring' - ? singleTransition.stiffness ?? 120 - : 120; - transitionMass = - singleTransition?.type === 'spring' ? singleTransition.mass ?? 1 : 1; - transitionLoop = - singleTransition?.type === 'timing' - ? singleTransition.loop ?? 'none' - : 'none'; - } - const singleTrans = - transition && 'type' in transition ? transition : undefined; - const transitionDelay = - singleTrans?.type === 'timing' || singleTrans?.type === 'spring' - ? singleTrans.delay ?? 0 - : 0; + // Resolve transition config into a fully-populated struct + const transitions = resolveTransitions(transition); const handleTransitionEnd = onTransitionEnd ? (event: { nativeEvent: { finished: boolean } }) => @@ -405,21 +411,7 @@ export function EaseView({ initialAnimateRotateY={resolvedInitial.rotateY} initialAnimateBorderRadius={resolvedInitial.borderRadius} initialAnimateBackgroundColor={initialBgColor} - transitionType={transitionType} - transitionDuration={transitionDuration} - transitionEasingBezier={bezier} - transitionDamping={transitionDamping} - transitionStiffness={transitionStiffness} - transitionMass={transitionMass} - transitionLoop={transitionLoop} - transitionDelay={transitionDelay} - perPropertyTransitionTypes={perPropertyArrays?.types} - perPropertyTransitionDurations={perPropertyArrays?.durations} - perPropertyTransitionDampings={perPropertyArrays?.dampings} - perPropertyTransitionStiffnesses={perPropertyArrays?.stiffnesses} - perPropertyTransitionMasses={perPropertyArrays?.masses} - perPropertyTransitionLoops={perPropertyArrays?.loops} - perPropertyTransitionEasingBeziers={perPropertyArrays?.easingBeziers} + transitions={transitions} useHardwareLayer={useHardwareLayer} transformOriginX={transformOrigin?.x ?? 0.5} transformOriginY={transformOrigin?.y ?? 0.5} diff --git a/src/EaseViewNativeComponent.ts b/src/EaseViewNativeComponent.ts index d12190e..c0a3c4b 100644 --- a/src/EaseViewNativeComponent.ts +++ b/src/EaseViewNativeComponent.ts @@ -6,6 +6,34 @@ import { type ColorValue, } from 'react-native'; +type Float = CodegenTypes.Float; +type Int32 = CodegenTypes.Int32; + +type NativeTransitionConfig = Readonly<{ + type: string; + duration: Int32; + easingBezier: ReadonlyArray; + damping: Float; + stiffness: Float; + mass: Float; + loop: string; + delay: Int32; +}>; + +type NativeTransitions = Readonly<{ + defaultConfig: NativeTransitionConfig; + opacity: NativeTransitionConfig; + translateX: NativeTransitionConfig; + translateY: NativeTransitionConfig; + scaleX: NativeTransitionConfig; + scaleY: NativeTransitionConfig; + rotate: NativeTransitionConfig; + rotateX: NativeTransitionConfig; + rotateY: NativeTransitionConfig; + borderRadius: NativeTransitionConfig; + backgroundColor: NativeTransitionConfig; +}>; + export interface NativeProps extends ViewProps { // Bitmask of which properties are animated (0 = none, let style handle all) animatedProperties?: CodegenTypes.WithDefault; @@ -37,33 +65,8 @@ export interface NativeProps extends ViewProps { >; initialAnimateBackgroundColor?: ColorValue; - // Transition config - transitionType?: CodegenTypes.WithDefault< - 'timing' | 'spring' | 'none', - 'timing' - >; - transitionDuration?: CodegenTypes.WithDefault; - // Easing cubic bezier control points [x1, y1, x2, y2] (default: easeInOut) - transitionEasingBezier?: ReadonlyArray; - transitionDamping?: CodegenTypes.WithDefault; - transitionStiffness?: CodegenTypes.WithDefault; - transitionMass?: CodegenTypes.WithDefault; - transitionLoop?: CodegenTypes.WithDefault< - 'none' | 'repeat' | 'reverse', - 'none' - >; - transitionDelay?: CodegenTypes.WithDefault; - - // Per-property transition arrays (10 elements each, one per animatable property) - // Index order: 0=opacity, 1=translateX, 2=translateY, 3=scaleX, 4=scaleY, - // 5=rotate, 6=rotateX, 7=rotateY, 8=borderRadius, 9=backgroundColor - perPropertyTransitionTypes?: ReadonlyArray; - perPropertyTransitionDurations?: ReadonlyArray; - perPropertyTransitionDampings?: ReadonlyArray; - perPropertyTransitionStiffnesses?: ReadonlyArray; - perPropertyTransitionMasses?: ReadonlyArray; - perPropertyTransitionLoops?: ReadonlyArray; - perPropertyTransitionEasingBeziers?: ReadonlyArray; // 40 elements (4 per property) + // Unified transition config — one struct with per-property configs + transitions?: NativeTransitions; // Transform origin (0–1 fractions, default center) transformOriginX?: CodegenTypes.WithDefault; diff --git a/src/__tests__/EaseView.test.tsx b/src/__tests__/EaseView.test.tsx index dfc3526..49ab262 100644 --- a/src/__tests__/EaseView.test.tsx +++ b/src/__tests__/EaseView.test.tsx @@ -127,16 +127,25 @@ describe('EaseView', () => { }); describe('transition defaults', () => { - it('defaults to timing with standard values', () => { + it('uses library defaults per category when no transition', () => { render(); const props = getNativeProps(); - expect(props.transitionType).toBe('timing'); - expect(props.transitionDuration).toBe(300); - expect(props.transitionEasingBezier).toEqual([0.42, 0, 0.58, 1]); - expect(props.transitionLoop).toBe('none'); - }); - - it('resolves timing transition props', () => { + const t = props.transitions; + // defaultConfig = timing (library default for non-transform) + expect(t.defaultConfig.type).toBe('timing'); + expect(t.defaultConfig.duration).toBe(300); + expect(t.defaultConfig.easingBezier).toEqual([0.42, 0, 0.58, 1]); + expect(t.defaultConfig.loop).toBe('none'); + expect(t.defaultConfig.delay).toBe(0); + // opacity (non-transform) → timing default + expect(t.opacity.type).toBe('timing'); + // translateX (transform) → spring default + expect(t.translateX.type).toBe('spring'); + expect(t.translateX.damping).toBe(15); + expect(t.translateX.stiffness).toBe(120); + }); + + it('resolves timing transition to all slots', () => { render( { }} />, ); - const props = getNativeProps(); - expect(props.transitionType).toBe('timing'); - expect(props.transitionDuration).toBe(500); - expect(props.transitionEasingBezier).toEqual([0, 0, 1, 1]); - expect(props.transitionLoop).toBe('reverse'); + const t = getNativeProps().transitions; + expect(t.defaultConfig.type).toBe('timing'); + expect(t.defaultConfig.duration).toBe(500); + expect(t.defaultConfig.easingBezier).toEqual([0, 0, 1, 1]); + expect(t.defaultConfig.loop).toBe('reverse'); + // All properties get the same config + expect(t.opacity.type).toBe('timing'); + expect(t.opacity.duration).toBe(500); + expect(t.translateX.type).toBe('timing'); + expect(t.translateX.duration).toBe(500); }); - it('resolves spring transition props with timing defaults for unused fields', () => { + it('resolves spring transition with defaults for unused fields', () => { render( , ); - const props = getNativeProps(); - expect(props.transitionType).toBe('spring'); - expect(props.transitionDamping).toBe(20); - expect(props.transitionStiffness).toBe(200); - expect(props.transitionMass).toBe(2); - // Timing-specific fields get defaults (easeInOut bezier) - expect(props.transitionDuration).toBe(300); - expect(props.transitionEasingBezier).toEqual([0.42, 0, 0.58, 1]); - expect(props.transitionLoop).toBe('none'); + const t = getNativeProps().transitions; + expect(t.defaultConfig.type).toBe('spring'); + expect(t.defaultConfig.damping).toBe(20); + expect(t.defaultConfig.stiffness).toBe(200); + expect(t.defaultConfig.mass).toBe(2); + // Timing-specific fields get defaults + expect(t.defaultConfig.duration).toBe(300); + expect(t.defaultConfig.easingBezier).toEqual([0.42, 0, 0.58, 1]); + expect(t.defaultConfig.loop).toBe('none'); }); it('uses spring defaults when only type is specified', () => { render(); - const props = getNativeProps(); - expect(props.transitionDamping).toBe(15); - expect(props.transitionStiffness).toBe(120); - expect(props.transitionMass).toBe(1); + const t = getNativeProps().transitions; + expect(t.defaultConfig.damping).toBe(15); + expect(t.defaultConfig.stiffness).toBe(120); + expect(t.defaultConfig.mass).toBe(1); }); - it('passes none transition type', () => { + it('passes none transition type to all slots', () => { render(); - expect(getNativeProps().transitionType).toBe('none'); + const t = getNativeProps().transitions; + expect(t.defaultConfig.type).toBe('none'); + expect(t.opacity.type).toBe('none'); + expect(t.translateX.type).toBe('none'); }); it('passes custom cubic bezier control points', () => { @@ -197,8 +214,8 @@ describe('EaseView', () => { }} />, ); - const props = getNativeProps(); - expect(props.transitionEasingBezier).toEqual([0.25, 0.1, 0.25, 1.0]); + const t = getNativeProps().transitions; + expect(t.defaultConfig.easingBezier).toEqual([0.25, 0.1, 0.25, 1.0]); }); it('warns for invalid array length', () => { @@ -234,6 +251,23 @@ describe('EaseView', () => { ); spy.mockRestore(); }); + + it('passes delay for timing transition', () => { + render( + , + ); + const t = getNativeProps().transitions; + expect(t.defaultConfig.delay).toBe(200); + expect(t.opacity.delay).toBe(200); + }); + + it('passes delay for spring transition', () => { + render( + , + ); + const t = getNativeProps().transitions; + expect(t.defaultConfig.delay).toBe(150); + }); }); describe('useHardwareLayer', () => { @@ -460,21 +494,20 @@ describe('EaseView', () => { }); describe('per-property transition map', () => { - it('does not pass arrays for single transition (backward compat)', () => { + it('populates all slots from single transition', () => { render( , ); - const props = getNativeProps(); - expect(props.perPropertyTransitionTypes).toBeUndefined(); - expect(props.perPropertyTransitionDurations).toBeUndefined(); - expect(props.perPropertyTransitionDampings).toBeUndefined(); - expect(props.perPropertyTransitionStiffnesses).toBeUndefined(); - expect(props.perPropertyTransitionMasses).toBeUndefined(); - expect(props.perPropertyTransitionLoops).toBeUndefined(); - expect(props.perPropertyTransitionEasingBeziers).toBeUndefined(); + const t = getNativeProps().transitions; + // All slots get the same config + expect(t.opacity.type).toBe('spring'); + expect(t.opacity.damping).toBe(20); + expect(t.translateX.type).toBe('spring'); + expect(t.translateX.damping).toBe(20); + expect(t.backgroundColor.type).toBe('spring'); }); - it('populates arrays with default-only map (all slots same)', () => { + it('populates all slots with default-only map', () => { render( { }} />, ); - const props = getNativeProps(); - expect(props.perPropertyTransitionTypes).toHaveLength(10); - expect(props.perPropertyTransitionTypes).toEqual( - Array(10).fill('timing'), - ); - expect(props.perPropertyTransitionDurations).toEqual(Array(10).fill(500)); - // Scalar props should match default - expect(props.transitionType).toBe('timing'); - expect(props.transitionDuration).toBe(500); + const t = getNativeProps().transitions; + expect(t.defaultConfig.type).toBe('timing'); + expect(t.defaultConfig.duration).toBe(500); + expect(t.opacity.type).toBe('timing'); + expect(t.opacity.duration).toBe(500); + expect(t.translateX.type).toBe('timing'); + expect(t.translateX.duration).toBe(500); }); it('applies property-specific overrides', () => { @@ -505,17 +536,17 @@ describe('EaseView', () => { }} />, ); - const props = getNativeProps(); - // Index 0 = opacity: timing 150ms - expect(props.perPropertyTransitionTypes[0]).toBe('timing'); - expect(props.perPropertyTransitionDurations[0]).toBe(150); - // Index 2 = translateY: spring - expect(props.perPropertyTransitionTypes[2]).toBe('spring'); - expect(props.perPropertyTransitionDampings[2]).toBe(20); - expect(props.perPropertyTransitionStiffnesses[2]).toBe(200); - // Index 1 = translateX: default timing 300ms - expect(props.perPropertyTransitionTypes[1]).toBe('timing'); - expect(props.perPropertyTransitionDurations[1]).toBe(300); + const t = getNativeProps().transitions; + // opacity: timing 150ms + expect(t.opacity.type).toBe('timing'); + expect(t.opacity.duration).toBe(150); + // translateY: spring + expect(t.translateY.type).toBe('spring'); + expect(t.translateY.damping).toBe(20); + expect(t.translateY.stiffness).toBe(200); + // translateX: default timing 300ms + expect(t.translateX.type).toBe('timing'); + expect(t.translateX.duration).toBe(300); }); it('applies scale shorthand to scaleX and scaleY', () => { @@ -528,12 +559,11 @@ describe('EaseView', () => { }} />, ); - const props = getNativeProps(); - // Index 3 = scaleX, Index 4 = scaleY - expect(props.perPropertyTransitionTypes[3]).toBe('spring'); - expect(props.perPropertyTransitionTypes[4]).toBe('spring'); - expect(props.perPropertyTransitionDampings[3]).toBe(10); - expect(props.perPropertyTransitionDampings[4]).toBe(10); + const t = getNativeProps().transitions; + expect(t.scaleX.type).toBe('spring'); + expect(t.scaleY.type).toBe('spring'); + expect(t.scaleX.damping).toBe(10); + expect(t.scaleY.damping).toBe(10); }); it('allows scaleX to override scale shorthand', () => { @@ -547,13 +577,13 @@ describe('EaseView', () => { }} />, ); - const props = getNativeProps(); - // scaleX (index 3) uses specific override - expect(props.perPropertyTransitionTypes[3]).toBe('timing'); - expect(props.perPropertyTransitionDurations[3]).toBe(200); - // scaleY (index 4) falls back to scale shorthand - expect(props.perPropertyTransitionTypes[4]).toBe('spring'); - expect(props.perPropertyTransitionDampings[4]).toBe(10); + const t = getNativeProps().transitions; + // scaleX uses specific override + expect(t.scaleX.type).toBe('timing'); + expect(t.scaleX.duration).toBe(200); + // scaleY falls back to scale shorthand + expect(t.scaleY.type).toBe('spring'); + expect(t.scaleY.damping).toBe(10); }); it('uses library defaults by category when no default key', () => { @@ -565,39 +595,35 @@ describe('EaseView', () => { }} />, ); - const props = getNativeProps(); - // opacity (index 0) is explicitly set - expect(props.perPropertyTransitionTypes[0]).toBe('timing'); - expect(props.perPropertyTransitionDurations[0]).toBe(150); - // translateX (index 1) — transform category → spring default - expect(props.perPropertyTransitionTypes[1]).toBe('spring'); - expect(props.perPropertyTransitionDampings[1]).toBe(15); - expect(props.perPropertyTransitionStiffnesses[1]).toBe(120); - // borderRadius (index 8) — non-transform → timing default - expect(props.perPropertyTransitionTypes[8]).toBe('timing'); - expect(props.perPropertyTransitionDurations[8]).toBe(300); - // backgroundColor (index 9) — non-transform → timing default - expect(props.perPropertyTransitionTypes[9]).toBe('timing'); - }); - - it('flattens easing beziers into 40-element array', () => { + const t = getNativeProps().transitions; + // opacity is explicitly set + expect(t.opacity.type).toBe('timing'); + expect(t.opacity.duration).toBe(150); + // translateX — transform category → spring default + expect(t.translateX.type).toBe('spring'); + expect(t.translateX.damping).toBe(15); + expect(t.translateX.stiffness).toBe(120); + // borderRadius — non-transform → timing default + expect(t.borderRadius.type).toBe('timing'); + expect(t.borderRadius.duration).toBe(300); + // backgroundColor — non-transform → timing default + expect(t.backgroundColor.type).toBe('timing'); + }); + + it('supports per-property delay in transition map', () => { render( , ); - const props = getNativeProps(); - expect(props.perPropertyTransitionEasingBeziers).toHaveLength(40); - // linear = [0, 0, 1, 1] repeated 10 times - for (let i = 0; i < 10; i++) { - expect(props.perPropertyTransitionEasingBeziers[i * 4]).toBe(0); - expect(props.perPropertyTransitionEasingBeziers[i * 4 + 1]).toBe(0); - expect(props.perPropertyTransitionEasingBeziers[i * 4 + 2]).toBe(1); - expect(props.perPropertyTransitionEasingBeziers[i * 4 + 3]).toBe(1); - } + const t = getNativeProps().transitions; + expect(t.opacity.delay).toBe(50); + expect(t.translateX.delay).toBe(100); + expect(t.scaleX.delay).toBe(100); }); }); }); From 7146763390301ef9f712dd4697b4f544ce00ed10 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Mon, 16 Mar 2026 19:09:53 -0400 Subject: [PATCH 6/7] fix(example): slow down per-property demo for clearer video --- example/src/demos/PerPropertyDemo.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/example/src/demos/PerPropertyDemo.tsx b/example/src/demos/PerPropertyDemo.tsx index 4c7609d..6ecc6ba 100644 --- a/example/src/demos/PerPropertyDemo.tsx +++ b/example/src/demos/PerPropertyDemo.tsx @@ -10,16 +10,17 @@ export function PerPropertyDemo() { return (
- Opacity fades with timing 150ms, translateX springs independently + Opacity fades slowly (1.5s timing), translateX slides with a bouncy + spring — each property animates independently From 20eaa2ae703460f8325cca380225ab6d1d54e9bd Mon Sep 17 00:00:00 2001 From: EQuimper Date: Thu, 19 Mar 2026 12:36:13 -0400 Subject: [PATCH 7/7] feat: refactor transition handling to use category-based keys for improved clarity and flexibility --- android/src/main/java/com/ease/EaseView.kt | 26 +++- example/src/demos/PerPropertyDemo.tsx | 6 +- ios/EaseView.mm | 61 ++++---- src/EaseView.tsx | 124 +++++---------- src/EaseViewNativeComponent.ts | 14 +- src/__tests__/EaseView.test.tsx | 168 ++++++++++----------- src/types.ts | 12 +- 7 files changed, 186 insertions(+), 225 deletions(-) diff --git a/android/src/main/java/com/ease/EaseView.kt b/android/src/main/java/com/ease/EaseView.kt index 68635c4..0f21bdb 100644 --- a/android/src/main/java/com/ease/EaseView.kt +++ b/android/src/main/java/com/ease/EaseView.kt @@ -55,7 +55,7 @@ class EaseView(context: Context) : ReactViewGroup(context) { return } val configs = mutableMapOf() - val keys = listOf("defaultConfig", "opacity", "translateX", "translateY", "scaleX", "scaleY", "rotate", "rotateX", "rotateY", "borderRadius", "backgroundColor") + val keys = listOf("defaultConfig", "transform", "opacity", "borderRadius", "backgroundColor") for (key in keys) { if (map.hasKey(key)) { val configMap = map.getMap(key) ?: continue @@ -85,15 +85,31 @@ class EaseView(context: Context) : ReactViewGroup(context) { transitionConfigs = configs } + /** Map property name to category key, then fall back to defaultConfig. */ fun getTransitionConfig(name: String): TransitionConfig { - return transitionConfigs[name] - ?: transitionConfigs["defaultConfig"] + val categoryKey = when (name) { + "opacity" -> "opacity" + "translateX", "translateY", "scaleX", "scaleY", + "rotate", "rotateX", "rotateY" -> "transform" + "borderRadius" -> "borderRadius" + "backgroundColor" -> "backgroundColor" + else -> null + } + if (categoryKey != null) { + transitionConfigs[categoryKey]?.let { return it } + } + return transitionConfigs["defaultConfig"] ?: TransitionConfig("timing", 300, floatArrayOf(0.42f, 0f, 0.58f, 1.0f), 15.0f, 120.0f, 1.0f, "none", 0L) } private fun allTransitionsNone(): Boolean { - val keys = listOf("opacity", "translateX", "translateY", "scaleX", "scaleY", "rotate", "rotateX", "rotateY", "borderRadius", "backgroundColor") - return keys.all { getTransitionConfig(it).type == "none" } + val defaultConfig = transitionConfigs["defaultConfig"] + if (defaultConfig == null || defaultConfig.type != "none") return false + val categories = listOf("transform", "opacity", "borderRadius", "backgroundColor") + return categories.all { key -> + val config = transitionConfigs[key] + config == null || config.type == "none" + } } companion object { diff --git a/example/src/demos/PerPropertyDemo.tsx b/example/src/demos/PerPropertyDemo.tsx index 6ecc6ba..e8c5a7d 100644 --- a/example/src/demos/PerPropertyDemo.tsx +++ b/example/src/demos/PerPropertyDemo.tsx @@ -10,8 +10,8 @@ export function PerPropertyDemo() { return (
- Opacity fades slowly (1.5s timing), translateX slides with a bouncy - spring — each property animates independently + Opacity fades slowly (1.5s timing), transforms slide with a bouncy + spring — each category animates independently diff --git a/ios/EaseView.mm b/ios/EaseView.mm index b4eea9f..8bb12ae 100644 --- a/ios/EaseView.mm +++ b/ios/EaseView.mm @@ -97,32 +97,32 @@ static EaseTransitionConfig transitionConfigFromStruct(const T &src) { return config; } +// Check if a category config was explicitly set (non-empty type means JS sent +// it) +template static bool hasConfig(const T &cfg) { + return !cfg.type.empty(); +} + static EaseTransitionConfig transitionConfigForProperty(const std::string &name, const EaseViewProps &props) { - if (name == "opacity") { - return transitionConfigFromStruct(props.transitions.opacity); - } else if (name == "translateX") { - return transitionConfigFromStruct(props.transitions.translateX); - } else if (name == "translateY") { - return transitionConfigFromStruct(props.transitions.translateY); - } else if (name == "scaleX") { - return transitionConfigFromStruct(props.transitions.scaleX); - } else if (name == "scaleY") { - return transitionConfigFromStruct(props.transitions.scaleY); - } else if (name == "rotate") { - return transitionConfigFromStruct(props.transitions.rotate); - } else if (name == "rotateX") { - return transitionConfigFromStruct(props.transitions.rotateX); - } else if (name == "rotateY") { - return transitionConfigFromStruct(props.transitions.rotateY); - } else if (name == "borderRadius") { - return transitionConfigFromStruct(props.transitions.borderRadius); - } else if (name == "backgroundColor") { - return transitionConfigFromStruct(props.transitions.backgroundColor); + const auto &t = props.transitions; + + // Map property name to category, check if category override exists + if (name == "opacity" && hasConfig(t.opacity)) { + return transitionConfigFromStruct(t.opacity); + } else if ((name == "translateX" || name == "translateY" || + name == "scaleX" || name == "scaleY" || name == "rotate" || + name == "rotateX" || name == "rotateY") && + hasConfig(t.transform)) { + return transitionConfigFromStruct(t.transform); + } else if (name == "borderRadius" && hasConfig(t.borderRadius)) { + return transitionConfigFromStruct(t.borderRadius); + } else if (name == "backgroundColor" && hasConfig(t.backgroundColor)) { + return transitionConfigFromStruct(t.backgroundColor); } // Fallback to defaultConfig - return transitionConfigFromStruct(props.transitions.defaultConfig); + return transitionConfigFromStruct(t.defaultConfig); } // Find lowest property name with a set mask bit among transform properties @@ -487,16 +487,15 @@ - (void)updateProps:(const Props::Shared &)props RCTUIColorFromSharedColor(newViewProps.animateBackgroundColor) .CGColor; } - } else if (newViewProps.transitions.opacity.type == "none" && - newViewProps.transitions.translateX.type == "none" && - newViewProps.transitions.translateY.type == "none" && - newViewProps.transitions.scaleX.type == "none" && - newViewProps.transitions.scaleY.type == "none" && - newViewProps.transitions.rotate.type == "none" && - newViewProps.transitions.rotateX.type == "none" && - newViewProps.transitions.rotateY.type == "none" && - newViewProps.transitions.borderRadius.type == "none" && - newViewProps.transitions.backgroundColor.type == "none") { + } else if (newViewProps.transitions.defaultConfig.type == "none" && + (!hasConfig(newViewProps.transitions.transform) || + newViewProps.transitions.transform.type == "none") && + (!hasConfig(newViewProps.transitions.opacity) || + newViewProps.transitions.opacity.type == "none") && + (!hasConfig(newViewProps.transitions.borderRadius) || + newViewProps.transitions.borderRadius.type == "none") && + (!hasConfig(newViewProps.transitions.backgroundColor) || + newViewProps.transitions.backgroundColor.type == "none")) { // All transitions are 'none' — set values immediately [self.layer removeAllAnimations]; if (mask & kMaskOpacity) diff --git a/src/EaseView.tsx b/src/EaseView.tsx index f1c60e8..bfdb293 100644 --- a/src/EaseView.tsx +++ b/src/EaseView.tsx @@ -59,33 +59,6 @@ const EASING_PRESETS: Record = { easeInOut: [0.42, 0, 0.58, 1], }; -/** Transition struct field names (matches NativeTransitions keys). */ -const TRANSITION_KEYS = [ - 'opacity', - 'translateX', - 'translateY', - 'scaleX', - 'scaleY', - 'rotate', - 'rotateX', - 'rotateY', - 'borderRadius', - 'backgroundColor', -] as const; - -type TransitionKey = (typeof TRANSITION_KEYS)[number]; - -/** Transform property keys (indices 1-7) get spring defaults; others get timing. */ -const TRANSFORM_KEYS = new Set([ - 'translateX', - 'translateY', - 'scaleX', - 'scaleY', - 'rotate', - 'rotateX', - 'rotateY', -]); - /** Returns true if the transition is a SingleTransition (has a `type` field). */ function isSingleTransition(t: Transition): t is SingleTransition { return 'type' in t; @@ -106,20 +79,14 @@ type NativeTransitionConfig = { /** Full transitions struct passed to native. */ type NativeTransitions = { defaultConfig: NativeTransitionConfig; - opacity: NativeTransitionConfig; - translateX: NativeTransitionConfig; - translateY: NativeTransitionConfig; - scaleX: NativeTransitionConfig; - scaleY: NativeTransitionConfig; - rotate: NativeTransitionConfig; - rotateX: NativeTransitionConfig; - rotateY: NativeTransitionConfig; - borderRadius: NativeTransitionConfig; - backgroundColor: NativeTransitionConfig; + transform?: NativeTransitionConfig; + opacity?: NativeTransitionConfig; + borderRadius?: NativeTransitionConfig; + backgroundColor?: NativeTransitionConfig; }; -/** Library defaults: spring for transforms, timing 300ms easeInOut for others. */ -const TIMING_DEFAULT_CONFIG: NativeTransitionConfig = { +/** Default config: timing 300ms easeInOut. */ +const DEFAULT_CONFIG: NativeTransitionConfig = { type: 'timing', duration: 300, easingBezier: [0.42, 0, 0.58, 1], @@ -130,6 +97,7 @@ const TIMING_DEFAULT_CONFIG: NativeTransitionConfig = { delay: 0, }; +/** Default config for transform properties: spring. */ const SPRING_DEFAULT_CONFIG: NativeTransitionConfig = { type: 'spring', duration: 300, @@ -141,12 +109,6 @@ const SPRING_DEFAULT_CONFIG: NativeTransitionConfig = { delay: 0, }; -function getLibraryDefault(key: TransitionKey): NativeTransitionConfig { - return TRANSFORM_KEYS.has(key) - ? SPRING_DEFAULT_CONFIG - : TIMING_DEFAULT_CONFIG; -} - /** Resolve a SingleTransition into a native config object. */ function resolveSingleConfig(config: SingleTransition): NativeTransitionConfig { const type = config.type as string; @@ -198,63 +160,47 @@ function resolveSingleConfig(config: SingleTransition): NativeTransitionConfig { }; } -/** Resolve the transition prop into a fully-populated NativeTransitions struct. */ +/** Category keys that map to optional NativeTransitions fields. */ +const CATEGORY_KEYS = [ + 'transform', + 'opacity', + 'borderRadius', + 'backgroundColor', +] as const; + +/** Resolve the transition prop into a NativeTransitions struct. */ function resolveTransitions(transition?: Transition): NativeTransitions { - // Single transition: apply the same config to all 11 slots + // Single transition: set as defaultConfig, no category overrides needed if (transition != null && isSingleTransition(transition)) { - const config = resolveSingleConfig(transition); - const result = { defaultConfig: config } as Record< - string, - NativeTransitionConfig - >; - for (const key of TRANSITION_KEYS) { - result[key] = config; - } - return result as unknown as NativeTransitions; + return { defaultConfig: resolveSingleConfig(transition) }; } - // No transition: use library defaults per category + // No transition: timing default + spring for transforms if (transition == null) { - const result = { defaultConfig: TIMING_DEFAULT_CONFIG } as Record< - string, - NativeTransitionConfig - >; - for (const key of TRANSITION_KEYS) { - result[key] = getLibraryDefault(key); - } - return result as unknown as NativeTransitions; + return { defaultConfig: DEFAULT_CONFIG, transform: SPRING_DEFAULT_CONFIG }; } - // TransitionMap: resolve per property - const transitionMap = transition; - const defaultSingle = transitionMap.default; - const defaultNative = defaultSingle - ? resolveSingleConfig(defaultSingle) - : undefined; + // TransitionMap: resolve defaultConfig + only specified category keys + const defaultConfig = transition.default + ? resolveSingleConfig(transition.default) + : DEFAULT_CONFIG; - const result = { - defaultConfig: defaultNative ?? TIMING_DEFAULT_CONFIG, - } as Record; + const result: NativeTransitions = { defaultConfig }; - for (const key of TRANSITION_KEYS) { - const specific = transitionMap[key as keyof typeof transitionMap] as - | SingleTransition - | undefined; + for (const key of CATEGORY_KEYS) { + const specific = transition[key]; if (specific != null) { - result[key] = resolveSingleConfig(specific); - } else if ( - (key === 'scaleX' || key === 'scaleY') && - transitionMap.scale != null - ) { - result[key] = resolveSingleConfig(transitionMap.scale!); - } else if (defaultNative) { - result[key] = defaultNative; - } else { - result[key] = getLibraryDefault(key); + (result as Record)[key] = + resolveSingleConfig(specific); } } - return result as unknown as NativeTransitions; + // Preserve spring default for transforms when not explicitly set + if (result.transform == null && transition.default == null) { + result.transform = SPRING_DEFAULT_CONFIG; + } + + return result; } export type EaseViewProps = ViewProps & { diff --git a/src/EaseViewNativeComponent.ts b/src/EaseViewNativeComponent.ts index c0a3c4b..48aad0e 100644 --- a/src/EaseViewNativeComponent.ts +++ b/src/EaseViewNativeComponent.ts @@ -22,16 +22,10 @@ type NativeTransitionConfig = Readonly<{ type NativeTransitions = Readonly<{ defaultConfig: NativeTransitionConfig; - opacity: NativeTransitionConfig; - translateX: NativeTransitionConfig; - translateY: NativeTransitionConfig; - scaleX: NativeTransitionConfig; - scaleY: NativeTransitionConfig; - rotate: NativeTransitionConfig; - rotateX: NativeTransitionConfig; - rotateY: NativeTransitionConfig; - borderRadius: NativeTransitionConfig; - backgroundColor: NativeTransitionConfig; + transform?: NativeTransitionConfig; + opacity?: NativeTransitionConfig; + borderRadius?: NativeTransitionConfig; + backgroundColor?: NativeTransitionConfig; }>; export interface NativeProps extends ViewProps { diff --git a/src/__tests__/EaseView.test.tsx b/src/__tests__/EaseView.test.tsx index 49ab262..fa92747 100644 --- a/src/__tests__/EaseView.test.tsx +++ b/src/__tests__/EaseView.test.tsx @@ -127,25 +127,25 @@ describe('EaseView', () => { }); describe('transition defaults', () => { - it('uses library defaults per category when no transition', () => { + it('uses timing default with spring for transforms when no transition', () => { render(); - const props = getNativeProps(); - const t = props.transitions; - // defaultConfig = timing (library default for non-transform) + const t = getNativeProps().transitions; expect(t.defaultConfig.type).toBe('timing'); expect(t.defaultConfig.duration).toBe(300); expect(t.defaultConfig.easingBezier).toEqual([0.42, 0, 0.58, 1]); expect(t.defaultConfig.loop).toBe('none'); expect(t.defaultConfig.delay).toBe(0); - // opacity (non-transform) → timing default - expect(t.opacity.type).toBe('timing'); - // translateX (transform) → spring default - expect(t.translateX.type).toBe('spring'); - expect(t.translateX.damping).toBe(15); - expect(t.translateX.stiffness).toBe(120); + // Transform gets spring default + expect(t.transform.type).toBe('spring'); + expect(t.transform.damping).toBe(15); + expect(t.transform.stiffness).toBe(120); + // Other categories not set + expect(t.opacity).toBeUndefined(); + expect(t.borderRadius).toBeUndefined(); + expect(t.backgroundColor).toBeUndefined(); }); - it('resolves timing transition to all slots', () => { + it('resolves timing transition to defaultConfig only', () => { render( { expect(t.defaultConfig.duration).toBe(500); expect(t.defaultConfig.easingBezier).toEqual([0, 0, 1, 1]); expect(t.defaultConfig.loop).toBe('reverse'); - // All properties get the same config - expect(t.opacity.type).toBe('timing'); - expect(t.opacity.duration).toBe(500); - expect(t.translateX.type).toBe('timing'); - expect(t.translateX.duration).toBe(500); + // No category overrides — native falls back to defaultConfig + expect(t.opacity).toBeUndefined(); + expect(t.transform).toBeUndefined(); }); it('resolves spring transition with defaults for unused fields', () => { @@ -195,12 +193,13 @@ describe('EaseView', () => { expect(t.defaultConfig.mass).toBe(1); }); - it('passes none transition type to all slots', () => { + it('passes none transition type to defaultConfig', () => { render(); const t = getNativeProps().transitions; expect(t.defaultConfig.type).toBe('none'); - expect(t.opacity.type).toBe('none'); - expect(t.translateX.type).toBe('none'); + // No category overrides + expect(t.opacity).toBeUndefined(); + expect(t.transform).toBeUndefined(); }); it('passes custom cubic bezier control points', () => { @@ -258,7 +257,6 @@ describe('EaseView', () => { ); const t = getNativeProps().transitions; expect(t.defaultConfig.delay).toBe(200); - expect(t.opacity.delay).toBe(200); }); it('passes delay for spring transition', () => { @@ -494,20 +492,20 @@ describe('EaseView', () => { }); describe('per-property transition map', () => { - it('populates all slots from single transition', () => { + it('sets only defaultConfig from single transition', () => { render( , ); const t = getNativeProps().transitions; - // All slots get the same config - expect(t.opacity.type).toBe('spring'); - expect(t.opacity.damping).toBe(20); - expect(t.translateX.type).toBe('spring'); - expect(t.translateX.damping).toBe(20); - expect(t.backgroundColor.type).toBe('spring'); + expect(t.defaultConfig.type).toBe('spring'); + expect(t.defaultConfig.damping).toBe(20); + // No category overrides — native falls back to defaultConfig + expect(t.opacity).toBeUndefined(); + expect(t.transform).toBeUndefined(); + expect(t.backgroundColor).toBeUndefined(); }); - it('populates all slots with default-only map', () => { + it('sets defaultConfig with default-only map', () => { render( { const t = getNativeProps().transitions; expect(t.defaultConfig.type).toBe('timing'); expect(t.defaultConfig.duration).toBe(500); - expect(t.opacity.type).toBe('timing'); - expect(t.opacity.duration).toBe(500); - expect(t.translateX.type).toBe('timing'); - expect(t.translateX.duration).toBe(500); + // No category overrides + expect(t.opacity).toBeUndefined(); + expect(t.transform).toBeUndefined(); }); - it('applies property-specific overrides', () => { + it('applies category-specific overrides', () => { render( , ); const t = getNativeProps().transitions; - // opacity: timing 150ms - expect(t.opacity.type).toBe('timing'); - expect(t.opacity.duration).toBe(150); - // translateY: spring - expect(t.translateY.type).toBe('spring'); - expect(t.translateY.damping).toBe(20); - expect(t.translateY.stiffness).toBe(200); - // translateX: default timing 300ms - expect(t.translateX.type).toBe('timing'); - expect(t.translateX.duration).toBe(300); - }); - - it('applies scale shorthand to scaleX and scaleY', () => { + // opacity override + expect(t.opacity!.type).toBe('timing'); + expect(t.opacity!.duration).toBe(150); + // transform override + expect(t.transform!.type).toBe('spring'); + expect(t.transform!.damping).toBe(20); + expect(t.transform!.stiffness).toBe(200); + // defaultConfig for non-overridden categories + expect(t.defaultConfig.type).toBe('timing'); + expect(t.defaultConfig.duration).toBe(300); + // borderRadius/backgroundColor not set — native uses defaultConfig + expect(t.borderRadius).toBeUndefined(); + expect(t.backgroundColor).toBeUndefined(); + }); + + it('preserves spring default for transforms when no default key', () => { render( , ); const t = getNativeProps().transitions; - expect(t.scaleX.type).toBe('spring'); - expect(t.scaleY.type).toBe('spring'); - expect(t.scaleX.damping).toBe(10); - expect(t.scaleY.damping).toBe(10); + // opacity is explicitly set + expect(t.opacity!.type).toBe('timing'); + expect(t.opacity!.duration).toBe(150); + // defaultConfig is timing 300ms (library default) + expect(t.defaultConfig.type).toBe('timing'); + expect(t.defaultConfig.duration).toBe(300); + // transform gets spring default (no explicit default or transform key) + expect(t.transform!.type).toBe('spring'); + expect(t.transform!.damping).toBe(15); + expect(t.transform!.stiffness).toBe(120); + // Other categories not set + expect(t.borderRadius).toBeUndefined(); + expect(t.backgroundColor).toBeUndefined(); }); - it('allows scaleX to override scale shorthand', () => { + it('does not inject spring transform when default key is provided', () => { render( , ); const t = getNativeProps().transitions; - // scaleX uses specific override - expect(t.scaleX.type).toBe('timing'); - expect(t.scaleX.duration).toBe(200); - // scaleY falls back to scale shorthand - expect(t.scaleY.type).toBe('spring'); - expect(t.scaleY.damping).toBe(10); + // explicit default overrides library defaults + expect(t.defaultConfig.type).toBe('timing'); + expect(t.defaultConfig.duration).toBe(500); + // transform not injected — user opted into explicit default + expect(t.transform).toBeUndefined(); }); - it('uses library defaults by category when no default key', () => { + it('supports per-category delay in transition map', () => { render( , ); const t = getNativeProps().transitions; - // opacity is explicitly set - expect(t.opacity.type).toBe('timing'); - expect(t.opacity.duration).toBe(150); - // translateX — transform category → spring default - expect(t.translateX.type).toBe('spring'); - expect(t.translateX.damping).toBe(15); - expect(t.translateX.stiffness).toBe(120); - // borderRadius — non-transform → timing default - expect(t.borderRadius.type).toBe('timing'); - expect(t.borderRadius.duration).toBe(300); - // backgroundColor — non-transform → timing default - expect(t.backgroundColor.type).toBe('timing'); - }); - - it('supports per-property delay in transition map', () => { + expect(t.opacity!.delay).toBe(50); + // defaultConfig has delay 100 — native uses this for non-overridden categories + expect(t.defaultConfig.delay).toBe(100); + }); + + it('supports transform category for all transform properties', () => { render( , ); const t = getNativeProps().transitions; - expect(t.opacity.delay).toBe(50); - expect(t.translateX.delay).toBe(100); - expect(t.scaleX.delay).toBe(100); + expect(t.transform!.type).toBe('spring'); + expect(t.transform!.damping).toBe(10); + expect(t.transform!.stiffness).toBe(100); }); }); }); diff --git a/src/types.ts b/src/types.ts index 69cfee4..312f727 100644 --- a/src/types.ts +++ b/src/types.ts @@ -48,11 +48,19 @@ export type SingleTransition = | SpringTransition | NoneTransition; -/** Per-property transition map. Each key overrides the transition for that animatable property. */ +/** Per-property transition map with category-based keys. */ export type TransitionMap = { /** Fallback config for properties not explicitly listed. */ default?: SingleTransition; -} & Partial>; + /** Config for all transform properties (translateX/Y, scaleX/Y, rotate, rotateX/Y). */ + transform?: SingleTransition; + /** Config for opacity. */ + opacity?: SingleTransition; + /** Config for borderRadius. */ + borderRadius?: SingleTransition; + /** Config for backgroundColor. */ + backgroundColor?: SingleTransition; +}; /** Animation transition configuration — either a single config or a per-property map. */ export type Transition = SingleTransition | TransitionMap;