diff --git a/apps/common-app/package.json b/apps/common-app/package.json index ae4a5e3b1eb0..02060e15968b 100644 --- a/apps/common-app/package.json +++ b/apps/common-app/package.json @@ -41,7 +41,7 @@ "react-native-reanimated": "workspace:*", "react-native-safe-area-context": "5.6.1", "react-native-screens": "4.19.0-nightly-20251125-46052f31e", - "react-native-svg": "15.14.0", + "react-native-svg": "15.15.3", "react-native-worklets": "workspace:*", "react-strict-dom": "0.0.54" }, diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Circle.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Circle.tsx index 953706bf706b..66315c8af02e 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Circle.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Circle.tsx @@ -62,7 +62,7 @@ export default function CircleExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the circle radius is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { r: 10, @@ -106,7 +106,7 @@ export default function CircleExample() { }, { description: - 'Interpolation between absolute and relative values is not supported in SVG, thus the circle position is changed abruptly', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { cx: 50, @@ -145,7 +145,7 @@ export default function CircleExample() { }, { description: - 'Interpolation between absolute and relative values is not supported in SVG, thus the circle position is changed abruptly', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { cy: 50, diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Ellipse.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Ellipse.tsx index a18a4f133aac..ad87228f80d3 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Ellipse.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Ellipse.tsx @@ -51,7 +51,7 @@ export default function EllipseExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the ellipse radii are changed **abruptly**', + 'Smoothly interpolates between absolute and percentage values by resolving them to the same unit', keyframes: { from: { rx: 10, @@ -107,7 +107,7 @@ export default function EllipseExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the horizontal radius is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { rx: 10, @@ -146,7 +146,7 @@ export default function EllipseExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the vertical radius is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { ry: 10, @@ -190,7 +190,7 @@ export default function EllipseExample() { }, { description: - 'Interpolation between absolute and relative values is not supported in SVG, thus the ellipse position is changed abruptly', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { cx: 50, @@ -229,7 +229,7 @@ export default function EllipseExample() { }, { description: - 'Interpolation between absolute and relative values is not supported in SVG, thus the ellipse position is changed abruptly', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { cy: 50, diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Image.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Image.tsx index ed872ecaa154..44d891cf0088 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Image.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Image.tsx @@ -67,7 +67,7 @@ export default function ImageExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the X position is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { x: 20, @@ -107,7 +107,7 @@ export default function ImageExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the Y position is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { y: 20, @@ -159,7 +159,7 @@ export default function ImageExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the width is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { width: 60, @@ -200,7 +200,7 @@ export default function ImageExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the height is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { height: 60, diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Line.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Line.tsx index 017606125f02..da1c91199295 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Line.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Line.tsx @@ -61,7 +61,7 @@ export default function LineExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the start X position is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { x1: 20, @@ -100,7 +100,7 @@ export default function LineExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the start Y position is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { y1: 15, @@ -144,7 +144,7 @@ export default function LineExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the end X position is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { x2: 80, @@ -183,7 +183,7 @@ export default function LineExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the end Y position is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { y2: 85, diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Rect.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Rect.tsx index 8c352ce6c965..dd202171d6ee 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Rect.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/Rect.tsx @@ -61,7 +61,7 @@ export default function RectExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the X position is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { x: 20, @@ -101,7 +101,7 @@ export default function RectExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the Y position is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { y: 20, @@ -153,7 +153,7 @@ export default function RectExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the width is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { width: 60, @@ -194,7 +194,7 @@ export default function RectExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the height is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { height: 60, @@ -239,7 +239,7 @@ export default function RectExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the horizontal radius is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { rx: 5, @@ -279,7 +279,7 @@ export default function RectExample() { }, { description: - 'Interpolation between absolute and relative values is **not supported** in SVG, thus the vertical radius is changed **abruptly**', + 'Smoothly interpolates between an absolute and a percentage value by resolving them to the same unit', keyframes: { from: { ry: 5, diff --git a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/common/Stroke.tsx b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/common/Stroke.tsx index f320bf381e81..cedcb1e17de6 100644 --- a/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/common/Stroke.tsx +++ b/apps/common-app/src/apps/css/examples/animations/screens/animatedProperties/svg/common/Stroke.tsx @@ -171,6 +171,34 @@ export default function StrokeExample() { }, title: 'Array value with different number of elements', }, + { + keyframes: { + from: { + strokeDasharray: ['10%', '5%'], + }, + to: { + strokeDasharray: ['25%', '12%'], + }, + }, + props: { + strokeWidth: 5, + }, + title: 'Percentage values', + }, + { + keyframes: { + from: { + strokeDasharray: [8, '15%'], + }, + to: { + strokeDasharray: ['5%', 5], + }, + }, + props: { + strokeWidth: 5, + }, + title: 'Mixed values (number + percentage)', + }, ], title: 'strokeDasharray', }, diff --git a/docs/docs-reanimated/package.json b/docs/docs-reanimated/package.json index c536cea75027..9c58830f9fd3 100644 --- a/docs/docs-reanimated/package.json +++ b/docs/docs-reanimated/package.json @@ -57,7 +57,7 @@ "react-native": "0.83.0", "react-native-gesture-handler": "2.28.0", "react-native-reanimated": "4.2.0-nightly-20251017-235c127fd", - "react-native-svg": "15.14.0", + "react-native-svg": "15.15.3", "react-native-web": "0.21.2", "react-native-worklets": "0.7.0-nightly-20251015-0297d2990", "source-map": "0.7.4", diff --git a/docs/docs-worklets/package.json b/docs/docs-worklets/package.json index df35d2e52828..dea42c278470 100644 --- a/docs/docs-worklets/package.json +++ b/docs/docs-worklets/package.json @@ -58,7 +58,7 @@ "react-native": "0.83.0", "react-native-gesture-handler": "2.28.0", "react-native-reanimated": "4.2.0-nightly-20251017-235c127fd", - "react-native-svg": "15.14.0", + "react-native-svg": "15.15.3", "react-native-web": "0.21.2", "react-native-worklets": "0.7.0-nightly-20251015-0297d2990", "source-map": "0.7.4", diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp index 830bf7d92041..7a5ea31c9ecf 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/InterpolatorRegistry.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -252,10 +251,10 @@ const InterpolatorFactoriesRecord SVG_COMMON_INTERPOLATORS = { // Stroke {"stroke", value(BLACK)}, - {"strokeWidth", value(1)}, + {"strokeWidth", value(1, {RelativeTo::Parent, "width"})}, {"strokeOpacity", value(1)}, - {"strokeDasharray", value(SVGStrokeDashArray())}, - {"strokeDashoffset", value(0)}, + {"strokeDasharray", value(SVGStrokeDashArray(), {RelativeTo::Parent, "width"})}, + {"strokeDashoffset", value(0, {RelativeTo::Parent, "width"})}, {"strokeLinecap", value(0)}, {"strokeLinejoin", value(0)}, {"strokeMiterlimit", value(4)}, @@ -266,10 +265,10 @@ const InterpolatorFactoriesRecord SVG_COMMON_INTERPOLATORS = { {"clipPath", value("none")}, // Transform - {"translateX", value(0)}, - {"translateY", value(0)}, - {"originX", value(0)}, - {"originY", value(0)}, + {"translateX", value(0, {RelativeTo::Self, "width"})}, + {"translateY", value(0, {RelativeTo::Self, "height"})}, + {"originX", value(0, {RelativeTo::Self, "width"})}, + {"originY", value(0, {RelativeTo::Self, "height"})}, {"scaleX", value(1)}, {"scaleY", value(1)}, {"skewX", value(0)}, @@ -287,27 +286,27 @@ const InterpolatorFactoriesRecord SVG_COMMON_INTERPOLATORS = { const InterpolatorFactoriesRecord SVG_CIRCLE_INTERPOLATORS = mergeInterpolators( {SVG_COMMON_INTERPOLATORS, InterpolatorFactoriesRecord{ - {"cx", value(0)}, - {"cy", value(0)}, - {"r", value(0)}, + {"cx", value(0, {RelativeTo::Parent, "width"})}, + {"cy", value(0, {RelativeTo::Parent, "height"})}, + {"r", value(0, {RelativeTo::Parent, "width"})}, }}); const InterpolatorFactoriesRecord SVG_ELLIPSE_INTERPOLATORS = mergeInterpolators( {SVG_COMMON_INTERPOLATORS, InterpolatorFactoriesRecord{ - {"cx", value(0)}, - {"cy", value(0)}, - {"rx", value(0)}, - {"ry", value(0)}, + {"cx", value(0, {RelativeTo::Parent, "width"})}, + {"cy", value(0, {RelativeTo::Parent, "height"})}, + {"rx", value(0, {RelativeTo::Parent, "width"})}, + {"ry", value(0, {RelativeTo::Parent, "height"})}, }}); const InterpolatorFactoriesRecord SVG_IMAGE_INTERPOLATORS = mergeInterpolators( {SVG_COMMON_INTERPOLATORS, InterpolatorFactoriesRecord{ - {"x", value(0)}, - {"y", value(0)}, - {"width", value(0)}, - {"height", value(0)}, + {"x", value(0, {RelativeTo::Parent, "width"})}, + {"y", value(0, {RelativeTo::Parent, "height"})}, + {"width", value(0, {RelativeTo::Parent, "width"})}, + {"height", value(0, {RelativeTo::Parent, "height"})}, // TODO: Check why this is not supported in RN-SVG and add support // {"align", value("xMidYMid")}, // {"meetOrSlice", value(0)}, @@ -316,19 +315,19 @@ const InterpolatorFactoriesRecord SVG_IMAGE_INTERPOLATORS = mergeInterpolators( const InterpolatorFactoriesRecord SVG_LINE_INTERPOLATORS = mergeInterpolators( {SVG_COMMON_INTERPOLATORS, InterpolatorFactoriesRecord{ - {"x1", value(0)}, - {"y1", value(0)}, - {"x2", value(0)}, - {"y2", value(0)}, + {"x1", value(0, {RelativeTo::Parent, "width"})}, + {"y1", value(0, {RelativeTo::Parent, "height"})}, + {"x2", value(0, {RelativeTo::Parent, "width"})}, + {"y2", value(0, {RelativeTo::Parent, "height"})}, }}); const InterpolatorFactoriesRecord SVG_LINEAR_GRADIENT_INTERPOLATORS = mergeInterpolators( {SVG_COMMON_INTERPOLATORS, InterpolatorFactoriesRecord{ - {"x1", value("0%")}, - {"x2", value("100%")}, - {"y1", value("0%")}, - {"y2", value("0%")}, + {"x1", value("0%", {RelativeTo::Self, "width"})}, + {"x2", value("100%", {RelativeTo::Self, "width"})}, + {"y1", value("0%", {RelativeTo::Self, "height"})}, + {"y2", value("0%", {RelativeTo::Self, "height"})}, {"gradient", value(SVGStops())}, {"gradientUnits", value(0)}, // TODO: Implement 'gradientTransform' @@ -338,12 +337,12 @@ const InterpolatorFactoriesRecord SVG_LINEAR_GRADIENT_INTERPOLATORS = mergeInter const InterpolatorFactoriesRecord SVG_RECT_INTERPOLATORS = mergeInterpolators( {SVG_COMMON_INTERPOLATORS, InterpolatorFactoriesRecord{ - {"x", value(0)}, - {"y", value(0)}, - {"width", value(0)}, - {"height", value(0)}, - {"rx", value(0)}, - {"ry", value(0)}, + {"x", value(0, {RelativeTo::Parent, "width"})}, + {"y", value(0, {RelativeTo::Parent, "height"})}, + {"width", value(0, {RelativeTo::Parent, "width"})}, + {"height", value(0, {RelativeTo::Parent, "height"})}, + {"rx", value(0, {RelativeTo::Self, "width"})}, + {"ry", value(0, {RelativeTo::Self, "height"})}, }}); const InterpolatorFactoriesRecord SVG_PATH_INTERPOLATORS = mergeInterpolators( @@ -355,13 +354,13 @@ const InterpolatorFactoriesRecord SVG_PATH_INTERPOLATORS = mergeInterpolators( const InterpolatorFactoriesRecord SVG_RADIAL_GRADIENT_INTERPOLATORS = mergeInterpolators( {SVG_COMMON_INTERPOLATORS, InterpolatorFactoriesRecord{ - {"r", value("50%")}, - {"fx", value("50%")}, - {"fy", value("50%")}, - {"rx", value("50%")}, - {"ry", value("50%")}, - {"cx", value("50%")}, - {"cy", value("50%")}, + {"r", value("50%", {RelativeTo::Self, "width"})}, + {"fx", value("50%", {RelativeTo::Self, "width"})}, + {"fy", value("50%", {RelativeTo::Self, "height"})}, + {"rx", value("50%", {RelativeTo::Self, "width"})}, + {"ry", value("50%", {RelativeTo::Self, "height"})}, + {"cx", value("50%", {RelativeTo::Self, "width"})}, + {"cy", value("50%", {RelativeTo::Self, "height"})}, {"gradient", value(SVGStops())}, {"gradientUnits", value(0)}, // TODO: Implement 'gradientTransform' diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValue.h b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValue.h index a0cf60fb3be5..d0e9a784ae80 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValue.h +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValue.h @@ -69,7 +69,9 @@ struct CSSResolvableValue : public CSSValue { virtual TDerived interpolate(double progress, const TDerived &to, const ResolvableValueInterpolationContext &context) const = 0; - virtual std::optional resolve(const ResolvableValueInterpolationContext &context) const = 0; + virtual std::optional resolve(const ResolvableValueInterpolationContext &context) const { + return std::nullopt; + } virtual bool canInterpolateTo(const TDerived &to) const { return true; } diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp index 560849390124..db9c67e4b994 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/common/values/CSSValueVariant.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -166,8 +165,6 @@ template class CSSValueVariant; template class CSSValueVariant; template class CSSValueVariant>; -template class CSSValueVariant; -template class CSSValueVariant; template class CSSValueVariant; template class CSSValueVariant; template class CSSValueVariant; diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/InterpolatorFactory.h b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/InterpolatorFactory.h index f19515ff2e00..95600ba347e3 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/InterpolatorFactory.h +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/InterpolatorFactory.h @@ -112,6 +112,11 @@ template auto value(const auto &defaultValue) -> std::enable_if_t< (std::is_constructible_v || ...), std::shared_ptr> { + static_assert( + !(Resolvable || ...), + "Resolvable value types (e.g. CSSLength) require a " + "ResolvableValueInterpolatorConfig — use the value(defaultValue, " + "{RelativeTo::..., \"...\"}) overload instead"); // Create a concrete CSSValue from the defaultValue auto cssValue = createCSSValue(defaultValue); return std::make_shared>(std::move(cssValue)); @@ -121,6 +126,10 @@ template auto value(const auto &defaultValue, ResolvableValueInterpolatorConfig config) -> std::enable_if_t< (std::is_constructible_v || ...), std::shared_ptr> { + static_assert( + (Resolvable || ...), + "None of the value types are resolvable — use the value(defaultValue) " + "overload without ResolvableValueInterpolatorConfig instead"); // Create a concrete CSSValue from the defaultValue auto cssValue = createCSSValue(defaultValue); return std::make_shared>(std::move(cssValue), std::move(config)); diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/ResolvableValueInterpolator.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/ResolvableValueInterpolator.cpp index a8bf3f97aaab..e068843fd160 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/ResolvableValueInterpolator.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/ResolvableValueInterpolator.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -43,5 +44,6 @@ folly::dynamic ResolvableValueInterpolator::interpolateValue( template class ResolvableValueInterpolator; template class ResolvableValueInterpolator; +template class ResolvableValueInterpolator; } // namespace reanimated::css diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/SimpleValueInterpolator.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/SimpleValueInterpolator.cpp index 39cad71f96b8..f1daf09c83ec 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/SimpleValueInterpolator.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/interpolation/values/SimpleValueInterpolator.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -65,8 +64,6 @@ template class SimpleValueInterpolator; template class SimpleValueInterpolator; template class SimpleValueInterpolator>; -template class SimpleValueInterpolator; -template class SimpleValueInterpolator; template class SimpleValueInterpolator; template class SimpleValueInterpolator; template class SimpleValueInterpolator; diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGLength.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGLength.cpp deleted file mode 100644 index 7ea55c58713a..000000000000 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGLength.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include - -#include - -namespace reanimated::css { - -SVGLength::SVGLength() : value(0), isPercentage(false) {} - -SVGLength::SVGLength(const double value) : value(value), isPercentage(false) {} - -SVGLength::SVGLength(const double value, const bool isPercentage) : value(value), isPercentage(isPercentage) {} - -SVGLength::SVGLength(const char *value) { - if (!canConstruct(value)) { - throw std::invalid_argument("[Reanimated] SVGLength: Invalid value: " + std::string(value)); - } - - std::string str = value; - str.pop_back(); - this->value = std::stod(str) / 100; - this->isPercentage = true; -} - -SVGLength::SVGLength(jsi::Runtime &rt, const jsi::Value &jsiValue) { - if (jsiValue.isNumber()) { - this->value = jsiValue.asNumber(); - this->isPercentage = false; - } else { - *this = SVGLength(jsiValue.asString(rt).utf8(rt)); - } -} - -SVGLength::SVGLength(const folly::dynamic &value) { - if (value.isNumber()) { - this->value = value.getDouble(); - this->isPercentage = false; - } else { - *this = SVGLength(value.asString().c_str()); - } -} - -bool SVGLength::canConstruct(const std::string &value) { - return !value.empty() && value.back() == '%'; -} - -bool SVGLength::canConstruct(const char *value) { - return canConstruct(std::string(value)); -} - -bool SVGLength::canConstruct(jsi::Runtime &rt, const jsi::Value &jsiValue) { - return jsiValue.isNumber() || (jsiValue.isString() && canConstruct(jsiValue.getString(rt).utf8(rt))); -} - -bool SVGLength::canConstruct(const folly::dynamic &value) { - return value.isNumber() || (value.isString() && canConstruct(value.getString())); -} - -folly::dynamic SVGLength::toDynamic() const { - if (isPercentage) { - return std::to_string(value * 100) + "%"; - } - return value; -} - -std::string SVGLength::toString() const { - return std::to_string(value * (isPercentage ? 100 : 1)) + "%"; -} - -SVGLength SVGLength::interpolate(const double progress, const SVGLength &to) const { - // We can interpolate SVG length values only if both values are percentages or - // both are numbers. In other cases, we interpolate them as keywords. - if ((isPercentage == to.isPercentage) || (isPercentage && to.value == 0) || (to.isPercentage && value == 0)) { - return SVGLength(value + (to.value - value) * progress, isPercentage || to.isPercentage); - } - - // Otherwise, we interpolate values as discrete values - return progress < 0.5 ? *this : to; -} - -bool SVGLength::operator==(const SVGLength &other) const { - return value == other.value && isPercentage == other.isPercentage; -} - -#ifndef NDEBUG - -std::ostream &operator<<(std::ostream &os, const SVGLength &value) { - os << "SVGLength(" << value.toString() << ")"; - return os; -} - -#endif // NDEBUG - -} // namespace reanimated::css diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGLength.h b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGLength.h deleted file mode 100644 index 421de8869bbf..000000000000 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGLength.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include - -#include - -namespace reanimated::css { - -struct SVGLength : public CSSSimpleValue { - double value; - bool isPercentage; - - SVGLength(); - explicit SVGLength(double value); - explicit SVGLength(double value, bool isPercentage); - explicit SVGLength(const char *value); - explicit SVGLength(jsi::Runtime &rt, const jsi::Value &jsiValue); - explicit SVGLength(const folly::dynamic &value); - - static bool canConstruct(const std::string &value); - static bool canConstruct(const char *value); - static bool canConstruct(jsi::Runtime &rt, const jsi::Value &jsiValue); - static bool canConstruct(const folly::dynamic &value); - - folly::dynamic toDynamic() const override; - std::string toString() const override; - SVGLength interpolate(double progress, const SVGLength &to) const override; - - bool operator==(const SVGLength &other) const; - -#ifndef NDEBUG - friend std::ostream &operator<<(std::ostream &os, const SVGLength &dimension); -#endif // NDEBUG -}; - -} // namespace reanimated::css diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGStrokeDashArray.cpp b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGStrokeDashArray.cpp index 9179f6497918..b24045603d47 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGStrokeDashArray.cpp +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGStrokeDashArray.cpp @@ -7,7 +7,7 @@ namespace reanimated::css { SVGStrokeDashArray::SVGStrokeDashArray() : values() {} -SVGStrokeDashArray::SVGStrokeDashArray(const std::vector &values) : values(values) {} +SVGStrokeDashArray::SVGStrokeDashArray(const std::vector &values) : values(values) {} SVGStrokeDashArray::SVGStrokeDashArray(jsi::Runtime &rt, const jsi::Value &jsiValue) { const auto &array = jsiValue.asObject(rt).asArray(rt); @@ -30,7 +30,7 @@ bool SVGStrokeDashArray::canConstruct(jsi::Runtime &rt, const jsi::Value &jsiVal } const auto &array = jsiValue.asObject(rt).asArray(rt); for (size_t i = 0; i < array.size(rt); ++i) { - if (!SVGLength::canConstruct(rt, array.getValueAtIndex(rt, i))) { + if (!CSSLength::canConstruct(rt, array.getValueAtIndex(rt, i))) { return false; } } @@ -39,7 +39,7 @@ bool SVGStrokeDashArray::canConstruct(jsi::Runtime &rt, const jsi::Value &jsiVal bool SVGStrokeDashArray::canConstruct(const folly::dynamic &value) { return value.isArray() && - std::all_of(value.begin(), value.end(), [](const auto &value) { return SVGLength::canConstruct(value); }); + std::all_of(value.begin(), value.end(), [](const auto &value) { return CSSLength::canConstruct(value); }); } folly::dynamic SVGStrokeDashArray::toDynamic() const { @@ -64,8 +64,11 @@ std::string SVGStrokeDashArray::toString() const { return ss.str(); } -SVGStrokeDashArray SVGStrokeDashArray::interpolate(double progress, const SVGStrokeDashArray &to) const { - std::vector result; +SVGStrokeDashArray SVGStrokeDashArray::interpolate( + double progress, + const SVGStrokeDashArray &to, + const ResolvableValueInterpolationContext &context) const { + std::vector result; auto fromValues = values; auto toValues = to.values; @@ -88,7 +91,7 @@ SVGStrokeDashArray SVGStrokeDashArray::interpolate(double progress, const SVGStr result.reserve(resultSize); for (size_t i = 0; i < resultSize; i++) { - result.emplace_back(fromValues[i % fromSize].interpolate(progress, toValues[i % toSize])); + result.emplace_back(fromValues[i % fromSize].interpolate(progress, toValues[i % toSize], context)); } return SVGStrokeDashArray(result); diff --git a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGStrokeDashArray.h b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGStrokeDashArray.h index 741b2c11182d..88c479f8fb1e 100644 --- a/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGStrokeDashArray.h +++ b/packages/react-native-reanimated/Common/cpp/reanimated/CSS/svg/values/SVGStrokeDashArray.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -8,11 +8,11 @@ namespace reanimated::css { -struct SVGStrokeDashArray : public CSSSimpleValue { - std::vector values; +struct SVGStrokeDashArray : public CSSResolvableValue { + std::vector values; SVGStrokeDashArray(); - explicit SVGStrokeDashArray(const std::vector &values); + explicit SVGStrokeDashArray(const std::vector &values); explicit SVGStrokeDashArray(jsi::Runtime &rt, const jsi::Value &jsiValue); explicit SVGStrokeDashArray(const folly::dynamic &value); @@ -21,7 +21,10 @@ struct SVGStrokeDashArray : public CSSSimpleValue { folly::dynamic toDynamic() const override; std::string toString() const override; - SVGStrokeDashArray interpolate(double progress, const SVGStrokeDashArray &to) const override; + SVGStrokeDashArray interpolate( + double progress, + const SVGStrokeDashArray &to, + const ResolvableValueInterpolationContext &context) const override; bool operator==(const SVGStrokeDashArray &other) const; diff --git a/packages/react-native-reanimated/package.json b/packages/react-native-reanimated/package.json index 3c8606489ae3..b6ee08720478 100644 --- a/packages/react-native-reanimated/package.json +++ b/packages/react-native-reanimated/package.json @@ -130,7 +130,7 @@ "react-dom": "19.2.3", "react-native": "0.84.0", "react-native-builder-bob": "0.40.13", - "react-native-svg": "15.14.0", + "react-native-svg": "15.15.3", "react-native-web": "0.21.1", "react-native-worklets": "workspace:*", "react-test-renderer": "19.2.3", diff --git a/yarn.lock b/yarn.lock index c0d2a8573232..657170b874af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13668,7 +13668,7 @@ __metadata: react-native-reanimated: "workspace:*" react-native-safe-area-context: "npm:5.6.1" react-native-screens: "npm:4.19.0-nightly-20251125-46052f31e" - react-native-svg: "npm:15.14.0" + react-native-svg: "npm:15.15.3" react-native-worklets: "workspace:*" react-strict-dom: "npm:0.0.54" react-test-renderer: "npm:19.2.3" @@ -15415,7 +15415,7 @@ __metadata: react-native: "npm:0.83.0" react-native-gesture-handler: "npm:2.28.0" react-native-reanimated: "npm:4.2.0-nightly-20251017-235c127fd" - react-native-svg: "npm:15.14.0" + react-native-svg: "npm:15.15.3" react-native-web: "npm:0.21.2" react-native-worklets: "npm:0.7.0-nightly-20251015-0297d2990" source-map: "npm:0.7.4" @@ -15479,7 +15479,7 @@ __metadata: react-native: "npm:0.83.0" react-native-gesture-handler: "npm:2.28.0" react-native-reanimated: "npm:4.2.0-nightly-20251017-235c127fd" - react-native-svg: "npm:15.14.0" + react-native-svg: "npm:15.15.3" react-native-web: "npm:0.21.2" react-native-worklets: "npm:0.7.0-nightly-20251015-0297d2990" source-map: "npm:0.7.4" @@ -28050,7 +28050,7 @@ __metadata: react-native: "npm:0.84.0" react-native-builder-bob: "npm:0.40.13" react-native-is-edge-to-edge: "npm:1.2.1" - react-native-svg: "npm:15.14.0" + react-native-svg: "npm:15.15.3" react-native-web: "npm:0.21.1" react-native-worklets: "workspace:*" react-test-renderer: "npm:19.2.3" @@ -28086,9 +28086,9 @@ __metadata: languageName: node linkType: hard -"react-native-svg@npm:15.14.0": - version: 15.14.0 - resolution: "react-native-svg@npm:15.14.0" +"react-native-svg@npm:15.15.3": + version: 15.15.3 + resolution: "react-native-svg@npm:15.15.3" dependencies: css-select: "npm:^5.1.0" css-tree: "npm:^1.1.3" @@ -28096,7 +28096,7 @@ __metadata: peerDependencies: react: "*" react-native: "*" - checksum: 10/8f067e265cd2749a7f0a3a09eccd6a297f1e99d0306e2c630d354e7093c3cb8e47cd054988f832b05ed80509ebdda7422cb407d8dcf851f1d4e8706f14f38c21 + checksum: 10/32254d53ac6d43af1e38011e899ae23ee8a272f1bd8e24fb34f355326cace369cd260331e58a53af3aec67ec8ec40ce6a60e57655259ebd0c32fb156649a4a23 languageName: node linkType: hard