From 360e0ee01ad044e52222191e4cc4604dbf16c359 Mon Sep 17 00:00:00 2001 From: Joshua Yoes <37849890+joshuayoes@users.noreply.github.com> Date: Mon, 29 Jul 2024 04:06:19 -0700 Subject: [PATCH] fix(xml): extract tags map to separate entry point for mobile & web (#1916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Summary **What issues does the pull request solve? Please tag them so that they will get automatically closed once the PR is merged** When utilizing with `react-native-web`: SvgXml and SvgUri are not exported in the `src/ReactNativeSVG.web.ts` extension. The logic for SvgXml and SvgUri do not have native dependencies, so they are safe to consume on web. Issues: - https://github.com/software-mansion/react-native-svg/issues/1279 - https://github.com/software-mansion/react-native-svg/issues/1742 **What is the feature? (if applicable)** Add SvgXml and SvgUri as consumable exports for `react-native-web` **How did you implement the solution?** Extract `tags` to shapes map into separate `tags.tsx` file, where native shape elements and web shape elements can be provided to their respective envs. **What areas of the library does it impact?** `src` directory ## Test Plan Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. ### What's required for testing (prerequisites)? n/a ### What are the steps to reproduce (after prerequisites)? n/a ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ✅ | ## Checklist - [x] I have tested this on a device and a simulator - [x] I added documentation in `README.md` - [x] I updated the typed files (typescript) - [ ] I added a test for the API in the `__tests__` folder --------- Co-authored-by: bohdanprog --- src/elements/filters/FeColorMatrix.tsx | 2 +- src/elements/filters/FeGaussianBlur.tsx | 2 +- src/elements/filters/FeOffset.tsx | 2 +- src/elements/filters/Filter.tsx | 2 +- src/elements/filters/FilterPrimitive.tsx | 2 +- src/filter-image/extract/extractFilters.ts | 2 +- src/tags.tsx | 57 +++++++++++++++++ src/tags.web.tsx | 50 +++++++++++++++ src/xml.tsx | 71 +++------------------- 9 files changed, 123 insertions(+), 67 deletions(-) create mode 100644 src/tags.tsx create mode 100644 src/tags.web.tsx diff --git a/src/elements/filters/FeColorMatrix.tsx b/src/elements/filters/FeColorMatrix.tsx index caa06199..e40d4db2 100644 --- a/src/elements/filters/FeColorMatrix.tsx +++ b/src/elements/filters/FeColorMatrix.tsx @@ -17,7 +17,7 @@ export type FeColorMatrixProps = { export default class FeColorMatrix extends FilterPrimitive { static displayName = 'FeColorMatrix'; - static defaultProps = { + static defaultProps: React.ComponentProps = { ...this.defaultPrimitiveProps, type: 'matrix', values: '', diff --git a/src/elements/filters/FeGaussianBlur.tsx b/src/elements/filters/FeGaussianBlur.tsx index 6ae09725..4158c02e 100644 --- a/src/elements/filters/FeGaussianBlur.tsx +++ b/src/elements/filters/FeGaussianBlur.tsx @@ -20,7 +20,7 @@ export interface FeGaussianBlurProps { export default class FeGaussianBlur extends FilterPrimitive { static displayName = 'FeGaussianBlur'; - static defaultProps = { + static defaultProps: React.ComponentProps = { ...this.defaultPrimitiveProps, stdDeviation: 0, edgeMode: 'none', diff --git a/src/elements/filters/FeOffset.tsx b/src/elements/filters/FeOffset.tsx index f7f04e1d..14703fd6 100644 --- a/src/elements/filters/FeOffset.tsx +++ b/src/elements/filters/FeOffset.tsx @@ -14,7 +14,7 @@ export interface FeOffsetProps { export default class FeOffset extends FilterPrimitive { static displayName = 'FeOffset'; - static defaultProps = { + static defaultProps: React.ComponentProps = { ...this.defaultPrimitiveProps, dx: 0, dy: 0, diff --git a/src/elements/filters/Filter.tsx b/src/elements/filters/Filter.tsx index a0d4dbf6..c2d6f8d0 100644 --- a/src/elements/filters/Filter.tsx +++ b/src/elements/filters/Filter.tsx @@ -20,7 +20,7 @@ export interface FilterProps { export default class Filter extends Shape { static displayName = 'Filter'; - static defaultProps = { + static defaultProps: React.ComponentProps = { x: '-10%', y: '-10%', width: '120%', diff --git a/src/elements/filters/FilterPrimitive.tsx b/src/elements/filters/FilterPrimitive.tsx index 567666d6..8675b8cc 100644 --- a/src/elements/filters/FilterPrimitive.tsx +++ b/src/elements/filters/FilterPrimitive.tsx @@ -16,7 +16,7 @@ export default class FilterPrimitive

extends Component< [x: string]: unknown; root: (FilterPrimitive

& NativeMethods) | null = null; - static defaultPrimitiveProps = { + static defaultPrimitiveProps: React.ComponentProps = { x: '0%', y: '0%', width: '100%', diff --git a/src/filter-image/extract/extractFilters.ts b/src/filter-image/extract/extractFilters.ts index 8335a604..44a18c50 100644 --- a/src/filter-image/extract/extractFilters.ts +++ b/src/filter-image/extract/extractFilters.ts @@ -1,5 +1,5 @@ import React from 'react'; -import { tags } from '../../xml'; +import { tags } from '../../tags'; import { FilterElement, Filters } from '../types'; import { parse } from './extractFiltersString'; diff --git a/src/tags.tsx b/src/tags.tsx new file mode 100644 index 00000000..5eacb608 --- /dev/null +++ b/src/tags.tsx @@ -0,0 +1,57 @@ +import Rect from './elements/Rect'; +import Circle from './elements/Circle'; +import Ellipse from './elements/Ellipse'; +import Polygon from './elements/Polygon'; +import Polyline from './elements/Polyline'; +import Line from './elements/Line'; +import Svg from './elements/Svg'; +import Path from './elements/Path'; +import G from './elements/G'; +import Text from './elements/Text'; +import TSpan from './elements/TSpan'; +import TextPath from './elements/TextPath'; +import Use from './elements/Use'; +import Image from './elements/Image'; +import Symbol from './elements/Symbol'; +import Defs from './elements/Defs'; +import LinearGradient from './elements/LinearGradient'; +import RadialGradient from './elements/RadialGradient'; +import Stop from './elements/Stop'; +import ClipPath from './elements/ClipPath'; +import Pattern from './elements/Pattern'; +import Mask from './elements/Mask'; +import Marker from './elements/Marker'; +import Filter from './elements/filters/Filter'; +import FeColorMatrix from './elements/filters/FeColorMatrix'; +import FeGaussianBlur from './elements/filters/FeGaussianBlur'; +import FeOffset from './elements/filters/FeOffset'; + +export const tags = { + circle: Circle, + clipPath: ClipPath, + defs: Defs, + ellipse: Ellipse, + filter: Filter, + feColorMatrix: FeColorMatrix, + feGaussianBlur: FeGaussianBlur, + feOffset: FeOffset, + g: G, + image: Image, + line: Line, + linearGradient: LinearGradient, + marker: Marker, + mask: Mask, + path: Path, + pattern: Pattern, + polygon: Polygon, + polyline: Polyline, + radialGradient: RadialGradient, + rect: Rect, + stop: Stop, + svg: Svg, + symbol: Symbol, + text: Text, + textPath: TextPath, + tspan: TSpan, + use: Use, +} as const; diff --git a/src/tags.web.tsx b/src/tags.web.tsx new file mode 100644 index 00000000..025c7a5d --- /dev/null +++ b/src/tags.web.tsx @@ -0,0 +1,50 @@ +import Svg, { + Circle, + ClipPath, + Defs, + Ellipse, + G, + Image, + Line, + LinearGradient, + Marker, + Mask, + Path, + Pattern, + Polygon, + Polyline, + RadialGradient, + Rect, + Stop, + Text, + TextPath, + TSpan, + Use, + Symbol, +} from './ReactNativeSVG.web'; + +export const tags = { + circle: Circle, + clipPath: ClipPath, + defs: Defs, + ellipse: Ellipse, + g: G, + image: Image, + line: Line, + linearGradient: LinearGradient, + marker: Marker, + mask: Mask, + path: Path, + pattern: Pattern, + polygon: Polygon, + polyline: Polyline, + radialGradient: RadialGradient, + rect: Rect, + stop: Stop, + svg: Svg, + symbol: Symbol, + text: Text, + textPath: TextPath, + tspan: TSpan, + use: Use, +} as const; diff --git a/src/xml.tsx b/src/xml.tsx index 901d97e9..d0bb5e08 100644 --- a/src/xml.tsx +++ b/src/xml.tsx @@ -1,69 +1,14 @@ -import type { ComponentType } from 'react'; +import type { ComponentType, ComponentProps } from 'react'; import * as React from 'react'; import { Component, useEffect, useMemo, useState } from 'react'; -import Rect from './elements/Rect'; -import Circle from './elements/Circle'; -import Ellipse from './elements/Ellipse'; -import Polygon from './elements/Polygon'; -import Polyline from './elements/Polyline'; -import Line from './elements/Line'; import type { SvgProps } from './elements/Svg'; -import Svg from './elements/Svg'; -import Path from './elements/Path'; -import G from './elements/G'; -import Text from './elements/Text'; -import TSpan from './elements/TSpan'; -import TextPath from './elements/TextPath'; -import Use from './elements/Use'; -import Image from './elements/Image'; -import Symbol from './elements/Symbol'; -import Defs from './elements/Defs'; -import LinearGradient from './elements/LinearGradient'; -import RadialGradient from './elements/RadialGradient'; -import Stop from './elements/Stop'; -import ClipPath from './elements/ClipPath'; -import Pattern from './elements/Pattern'; -import Mask from './elements/Mask'; -import Marker from './elements/Marker'; -import Filter from './elements/filters/Filter'; -import FeColorMatrix from './elements/filters/FeColorMatrix'; -import FeGaussianBlur from './elements/filters/FeGaussianBlur'; -import FeOffset from './elements/filters/FeOffset'; - -export const tags: { [tag: string]: ComponentType } = { - svg: Svg, - circle: Circle, - ellipse: Ellipse, - g: G, - text: Text, - tspan: TSpan, - textPath: TextPath, - path: Path, - polygon: Polygon, - polyline: Polyline, - line: Line, - rect: Rect, - use: Use, - image: Image, - symbol: Symbol, - defs: Defs, - linearGradient: LinearGradient, - radialGradient: RadialGradient, - stop: Stop, - clipPath: ClipPath, - pattern: Pattern, - mask: Mask, - marker: Marker, - filter: Filter, - feColorMatrix: FeColorMatrix, - feGaussianBlur: FeGaussianBlur, - feOffset: FeOffset, -}; +import { tags } from './tags'; function missingTag() { return null; } +type Tag = ComponentType>; export interface AST { tag: string; style?: Styles; @@ -74,7 +19,7 @@ export interface AST { props: { [prop: string]: Styles | string | undefined; }; - Tag: ComponentType; + Tag: Tag; } export interface XmlAST extends AST { @@ -106,6 +51,9 @@ export function SvgAst({ ast, override }: AstProps) { return null; } const { props, children } = ast; + + const Svg = tags.svg; + return ( {children} @@ -385,14 +333,14 @@ export function parse(source: string, middleware?: Middleware): JsxAST | null { return closingTag; } - const tag = getName(); + const tag = getName() as keyof typeof tags; const props: { [prop: string]: Styles | string | undefined } = {}; const element: XmlAST = { tag, props, children: [], parent: currentElement, - Tag: tags[tag] || missingTag, + Tag: (tags[tag] || missingTag) as Tag, }; if (currentElement) { @@ -594,3 +542,4 @@ export function parse(source: string, middleware?: Middleware): JsxAST | null { return null; } +export { tags };