diff --git a/README.md b/README.md
index fc605ce4..b3fd7603 100755
--- a/README.md
+++ b/README.md
@@ -74,6 +74,29 @@ const MyLoader = () => (
)
```
+**Per-rect color overrides**
+
+```jsx
+import ContentLoader, { Rect } from 'react-content-loader'
+
+const MyLoader = () => (
+
+
+
+
+
+)
+```
+
**Still not clear?** Take a look at this working example at [codesandbox.io](https://codesandbox.io/s/moojk887z9)
Or try the components editable demo hands-on and install it from [bit.dev](https://bit.dev/danilowoz/react-content-loader)
diff --git a/src/native/ContentLoader.tsx b/src/native/ContentLoader.tsx
index e911827e..c9965a81 100644
--- a/src/native/ContentLoader.tsx
+++ b/src/native/ContentLoader.tsx
@@ -1,7 +1,8 @@
import * as React from 'react'
-import { Circle, Path, Rect } from 'react-native-svg'
+import { Circle, Path } from 'react-native-svg'
import { Facebook, IContentLoaderProps } from '.'
+import Rect from './Rect'
import Svg from './Svg'
const ContentLoader: React.FC = props =>
diff --git a/src/native/Rect.tsx b/src/native/Rect.tsx
new file mode 100644
index 00000000..a79b3b61
--- /dev/null
+++ b/src/native/Rect.tsx
@@ -0,0 +1,17 @@
+import * as React from 'react'
+import { Rect as SvgRect } from 'react-native-svg'
+
+export type IRectProps = React.ComponentProps & {
+ foregroundColor?: string
+ backgroundColor?: string
+}
+
+const Rect: React.FC = ({
+ foregroundColor,
+ backgroundColor,
+ ...props
+}) =>
+
+Rect.displayName = 'Rect'
+
+export default Rect
diff --git a/src/native/Svg.tsx b/src/native/Svg.tsx
index 68fbf791..3be18393 100644
--- a/src/native/Svg.tsx
+++ b/src/native/Svg.tsx
@@ -4,12 +4,13 @@ import Svg, {
ClipPath,
Defs,
LinearGradient,
- Rect,
+ Rect as SvgRect,
Stop,
} from 'react-native-svg'
import uid from '../shared/uid'
import { IContentLoaderProps } from './'
+import Rect, { IRectProps } from './Rect'
const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient)
@@ -85,6 +86,36 @@ class NativeSvg extends Component {
...props
} = this.props
+ const clipChildren: React.ReactNode[] = []
+ const overrideRects: Array<{
+ element: React.ReactElement
+ foregroundColor: string
+ backgroundColor: string
+ idClip: string
+ idGradient: string
+ }> = []
+
+ React.Children.forEach(children, child => {
+ if (
+ isValidElement(child) &&
+ child.type === Rect &&
+ (child.props.foregroundColor != null ||
+ child.props.backgroundColor != null)
+ ) {
+ const index = overrideRects.length
+ overrideRects.push({
+ element: child,
+ foregroundColor: child.props.foregroundColor ?? foregroundColor,
+ backgroundColor: child.props.backgroundColor ?? backgroundColor,
+ idClip: `${this.fixedId}-diff-override-${index}`,
+ idGradient: `${this.fixedId}-animated-diff-override-${index}`,
+ })
+ return
+ }
+
+ clipChildren.push(child)
+ })
+
const x1Animation = this.animatedValue.interpolate({
extrapolate: 'clamp',
inputRange: [-1, 2],
@@ -109,7 +140,7 @@ class NativeSvg extends Component {
)
diff --git a/src/native/__tests__/ContentLoader.test.tsx b/src/native/__tests__/ContentLoader.test.tsx
index d269a4c6..eb670bc1 100644
--- a/src/native/__tests__/ContentLoader.test.tsx
+++ b/src/native/__tests__/ContentLoader.test.tsx
@@ -1,6 +1,7 @@
import * as React from 'react'
import * as renderer from 'react-test-renderer'
import * as ShallowRenderer from 'react-test-renderer/shallow'
+import { Rect as SvgRect } from 'react-native-svg'
import ContentLoader, { Circle, Rect } from '../ContentLoader'
@@ -18,9 +19,11 @@ describe('ContentLoader', () => {
it('should render custom element', () => {
const rect = customWrapper.findAllByType(Rect)
+ const svgRect = customWrapper.findAllByType(SvgRect)
const circle = customWrapper.findAllByType(Circle)
- expect(rect.length).toBe(3)
+ expect(rect.length).toBe(2)
+ expect(svgRect.length).toBe(3)
expect(circle.length).toBe(1)
})
})
diff --git a/src/native/__tests__/Svg.test.tsx b/src/native/__tests__/Svg.test.tsx
index 71afb00b..6b2e7143 100644
--- a/src/native/__tests__/Svg.test.tsx
+++ b/src/native/__tests__/Svg.test.tsx
@@ -106,4 +106,60 @@ describe('Svg', () => {
}).toThrow('No instances found with props: {"x":"123"}')
})
})
+
+ describe('rect color overrides', () => {
+ it('uses default colors when no overrides are provided', () => {
+ const wrapperWithDefaults = renderer.create(
+
+
+
+ ).root
+
+ const linearGradient = wrapperWithDefaults.findByType(LinearGradient)
+ const stops = linearGradient.findAllByType(Stop)
+
+ expect(stops[0].props.stopColor).toBe('#222')
+ expect(stops[1].props.stopColor).toBe('#111')
+ expect(stops[2].props.stopColor).toBe('#222')
+ })
+
+ it('allows a rect to override colors without affecting others', () => {
+ const wrapperWithOverrides = renderer.create(
+
+
+
+
+ ).root
+
+ const allLinearGradient =
+ wrapperWithOverrides.findAllByType(LinearGradient)
+ const overrideGradient = allLinearGradient.find(gradient =>
+ gradient.props.id.includes('override')
+ )
+ const defaultGradient = allLinearGradient.find(
+ gradient => !gradient.props.id.includes('override')
+ )
+
+ expect(allLinearGradient.length).toBe(2)
+ expect(overrideGradient).toBeTruthy()
+ expect(defaultGradient).toBeTruthy()
+
+ const defaultStops = defaultGradient!.findAllByType(Stop)
+ const overrideStops = overrideGradient!.findAllByType(Stop)
+
+ expect(defaultStops[0].props.stopColor).toBe('#222')
+ expect(defaultStops[1].props.stopColor).toBe('#111')
+ expect(defaultStops[2].props.stopColor).toBe('#222')
+ expect(overrideStops[0].props.stopColor).toBe('#444')
+ expect(overrideStops[1].props.stopColor).toBe('#333')
+ expect(overrideStops[2].props.stopColor).toBe('#444')
+ })
+ })
})
diff --git a/src/native/index.ts b/src/native/index.ts
index a5c1a842..fd0debc1 100644
--- a/src/native/index.ts
+++ b/src/native/index.ts
@@ -1,6 +1,7 @@
import { SvgProps } from 'react-native-svg'
import ContentLoader from './ContentLoader'
+import Rect, { IRectProps } from './Rect'
export interface IContentLoaderProps extends SvgProps {
animate?: boolean
@@ -21,5 +22,7 @@ export { default as Code } from './presets/CodeStyle'
export { default as List } from './presets/ListStyle'
export { default as BulletList } from './presets/BulletListStyle'
-export { Circle, Rect, Path } from './ContentLoader'
+export { Circle, Path } from './ContentLoader'
+export { Rect }
+export type { IRectProps }
export default ContentLoader
diff --git a/src/web/Rect.tsx b/src/web/Rect.tsx
new file mode 100644
index 00000000..4194b0a7
--- /dev/null
+++ b/src/web/Rect.tsx
@@ -0,0 +1,16 @@
+import * as React from 'react'
+
+export interface IRectProps extends React.SVGAttributes {
+ foregroundColor?: string
+ backgroundColor?: string
+}
+
+const Rect: React.FC = ({
+ foregroundColor,
+ backgroundColor,
+ ...props
+}) =>
+
+Rect.displayName = 'Rect'
+
+export default Rect
diff --git a/src/web/Svg.tsx b/src/web/Svg.tsx
index 749fd0c7..7c847160 100644
--- a/src/web/Svg.tsx
+++ b/src/web/Svg.tsx
@@ -2,6 +2,7 @@ import * as React from 'react'
import uid from '../shared/uid'
import { IContentLoaderProps } from './'
+import Rect, { IRectProps } from './Rect'
const SVG: React.FC = ({
animate = true,
@@ -31,6 +32,36 @@ const SVG: React.FC = ({
const from = `${gradientRatio * -1} 0`
const to = `${gradientRatio} 0`
+ const clipChildren: React.ReactNode[] = []
+ const overrideRects: Array<{
+ element: React.ReactElement
+ foregroundColor: string
+ backgroundColor: string
+ idClip: string
+ idGradient: string
+ }> = []
+
+ React.Children.forEach(children, child => {
+ if (
+ React.isValidElement(child) &&
+ child.type === Rect &&
+ (child.props.foregroundColor != null ||
+ child.props.backgroundColor != null)
+ ) {
+ const index = overrideRects.length
+ overrideRects.push({
+ element: child,
+ foregroundColor: child.props.foregroundColor ?? foregroundColor,
+ backgroundColor: child.props.backgroundColor ?? backgroundColor,
+ idClip: `${fixedId}-diff-override-${index}`,
+ idGradient: `${fixedId}-animated-diff-override-${index}`,
+ })
+ return
+ }
+
+ clipChildren.push(child)
+ })
+
return (
)
diff --git a/src/web/__tests__/Svg.test.tsx b/src/web/__tests__/Svg.test.tsx
index 766cd5d0..2266ae4b 100644
--- a/src/web/__tests__/Svg.test.tsx
+++ b/src/web/__tests__/Svg.test.tsx
@@ -1,7 +1,7 @@
import * as React from 'react'
import * as renderer from 'react-test-renderer'
-import Svg from '..'
+import Svg, { Rect } from '..'
interface PredicateArgs {
type: any
@@ -170,4 +170,60 @@ describe('Svg', () => {
}).toThrow('No instances found with props: {"role":"beforeMask"}')
})
})
+
+ describe('rect color overrides', () => {
+ it('uses default colors when no overrides are provided', () => {
+ const wrapperWithDefaults = renderer.create(
+
+ ).root
+
+ const linearGradient = wrapperWithDefaults.findByType('linearGradient')
+ const stops = linearGradient.findAllByType('stop')
+
+ expect(stops[0].props.stopColor).toBe('#222')
+ expect(stops[1].props.stopColor).toBe('#111')
+ expect(stops[2].props.stopColor).toBe('#222')
+ })
+
+ it('allows a rect to override colors without affecting others', () => {
+ const wrapperWithOverrides = renderer.create(
+
+ ).root
+
+ const allLinearGradient =
+ wrapperWithOverrides.findAllByType('linearGradient')
+ const overrideGradient = allLinearGradient.find(gradient =>
+ gradient.props.id.includes('override')
+ )
+ const defaultGradient = allLinearGradient.find(
+ gradient => !gradient.props.id.includes('override')
+ )
+
+ expect(allLinearGradient.length).toBe(2)
+ expect(overrideGradient).toBeTruthy()
+ expect(defaultGradient).toBeTruthy()
+
+ const defaultStops = defaultGradient!.findAllByType('stop')
+ const overrideStops = overrideGradient!.findAllByType('stop')
+
+ expect(defaultStops[0].props.stopColor).toBe('#222')
+ expect(defaultStops[1].props.stopColor).toBe('#111')
+ expect(defaultStops[2].props.stopColor).toBe('#222')
+ expect(overrideStops[0].props.stopColor).toBe('#444')
+ expect(overrideStops[1].props.stopColor).toBe('#333')
+ expect(overrideStops[2].props.stopColor).toBe('#444')
+ })
+ })
})
diff --git a/src/web/index.ts b/src/web/index.ts
index 37082810..db4fde44 100755
--- a/src/web/index.ts
+++ b/src/web/index.ts
@@ -1,6 +1,7 @@
import { SVGAttributes, ReactElement } from 'react'
import ContentLoader from './ContentLoader'
+import Rect from './Rect'
export interface IContentLoaderProps extends SVGAttributes {
animate?: boolean
@@ -22,5 +23,7 @@ export { default as Instagram } from './presets/InstagramStyle'
export { default as Code } from './presets/CodeStyle'
export { default as List } from './presets/ListStyle'
export { default as BulletList } from './presets/BulletListStyle'
+export { Rect }
+export type { IRectProps } from './Rect'
export default ContentLoader