master c8a6b6c6669d cached
74 files
122.8 KB
36.4k tokens
9 symbols
1 requests
Download .txt
Repository: danilowoz/react-content-loader
Branch: master
Commit: c8a6b6c6669d
Files: 74
Total size: 122.8 KB

Directory structure:
gitextract_btxfd3lk/

├── .codesandbox/
│   └── tasks.json
├── .devcontainer/
│   └── devcontainer.json
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── .gitignore
├── .prettierrc.js
├── .storybook/
│   ├── main.ts
│   ├── preview-head.html
│   └── preview.tsx
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── __mocks__/
│   └── react-native-svg.js
├── babel.config.js
├── docs/
│   └── index.stories.tsx
├── jest.native.config.js
├── jest.web.config.js
├── package.json
├── rollup.config.js
├── src/
│   ├── native/
│   │   ├── ContentLoader.tsx
│   │   ├── Svg.tsx
│   │   ├── __tests__/
│   │   │   ├── ContentLoader.test.tsx
│   │   │   ├── Svg.test.tsx
│   │   │   ├── __snapshots__/
│   │   │   │   └── snapshots.test.tsx.snap
│   │   │   ├── presets/
│   │   │   │   ├── BulletListStyle.test.tsx
│   │   │   │   ├── CodeStyle.test.tsx
│   │   │   │   ├── FacebookStyle.test.tsx
│   │   │   │   ├── InstagramStyle.test.tsx
│   │   │   │   ├── ListStyle.test.tsx
│   │   │   │   └── __snapshots__/
│   │   │   │       ├── BulletListStyle.test.tsx.snap
│   │   │   │       ├── CodeStyle.test.tsx.snap
│   │   │   │       ├── FacebookStyle.test.tsx.snap
│   │   │   │       ├── InstagramStyle.test.tsx.snap
│   │   │   │       └── ListStyle.test.tsx.snap
│   │   │   └── snapshots.test.tsx
│   │   ├── index.ts
│   │   ├── package.json
│   │   └── presets/
│   │       ├── BulletListStyle.tsx
│   │       ├── CodeStyle.tsx
│   │       ├── FacebookStyle.tsx
│   │       ├── InstagramStyle.tsx
│   │       └── ListStyle.tsx
│   ├── shared/
│   │   └── uid.ts
│   └── web/
│       ├── ContentLoader.tsx
│       ├── Svg.tsx
│       ├── __tests__/
│       │   ├── ContentLoader.test.tsx
│       │   ├── Svg.test.tsx
│       │   ├── __snapshots__/
│       │   │   └── snapshots.test.tsx.snap
│       │   ├── index.test.tsx
│       │   ├── presets/
│       │   │   ├── BulletListStyle.test.tsx
│       │   │   ├── CodeStyle.test.tsx
│       │   │   ├── FacebookStyle.test.tsx
│       │   │   ├── InstagramStyle.test.tsx
│       │   │   ├── ListStyle.test.tsx
│       │   │   └── __snapshots__/
│       │   │       ├── BulletListStyle.test.tsx.snap
│       │   │       ├── CodeStyle.test.tsx.snap
│       │   │       ├── FacebookStyle.test.tsx.snap
│       │   │       ├── InstagramStyle.test.tsx.snap
│       │   │       └── ListStyle.test.tsx.snap
│       │   ├── snapshots.test.tsx
│       │   └── uid.test.tsx
│       ├── index.ts
│       └── presets/
│           ├── BulletListStyle.tsx
│           ├── CodeStyle.tsx
│           ├── FacebookStyle.tsx
│           ├── InstagramStyle.tsx
│           └── ListStyle.tsx
├── tsconfig.base.json
├── tsconfig.json
└── tsconfig.test.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .codesandbox/tasks.json
================================================
{
  // These tasks will run in order when initializing your CodeSandbox project.
  "setupTasks": [
    {
      "name": "Install Dependencies",
      "command": "pnpm install"
    }
  ],

  // These tasks can be run from CodeSandbox. Running one will open a log in the app.
  "tasks": {
    "dev": {
      "name": "dev",
      "command": "pnpm run dev",
      "runAtStart": true
    },
    "build": {
      "name": "build",
      "command": "pnpm run build",
      "runAtStart": false
    },
    "build:docs": {
      "name": "build:docs",
      "command": "pnpm run build:docs",
      "runAtStart": false
    },
    "test": {
      "name": "test",
      "command": "pnpm run test",
      "runAtStart": false
    },
    "test:unit": {
      "name": "test:unit",
      "command": "pnpm run test:unit",
      "runAtStart": false
    },
    "test:unit:web": {
      "name": "test:unit:web",
      "command": "pnpm run test:unit:web",
      "runAtStart": false
    },
    "test:unit:native": {
      "name": "test:unit:native",
      "command": "pnpm run test:unit:native",
      "runAtStart": false
    },
    "test:watch": {
      "name": "test:watch",
      "command": "pnpm run test:watch",
      "runAtStart": false
    },
    "test:tsc": {
      "name": "test:tsc",
      "command": "pnpm run test:tsc",
      "runAtStart": false
    },
    "test:tsc:watch": {
      "name": "test:tsc:watch",
      "command": "pnpm run test:tsc:watch",
      "runAtStart": false
    },
    "commit": {
      "name": "commit",
      "command": "pnpm run commit",
      "runAtStart": false
    },
    "format": {
      "name": "format",
      "command": "pnpm run format",
      "runAtStart": false
    },
    "release": {
      "name": "release",
      "command": "pnpm run release",
      "runAtStart": false
    }
  }
}


================================================
FILE: .devcontainer/devcontainer.json
================================================
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
	"name": "Node.js & TypeScript",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	"image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye"

	// Features to add to the dev container. More info: https://containers.dev/features.
	// "features": {},

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [],

	// Use 'postCreateCommand' to run commands after the container is created.
	// "postCreateCommand": "yarn install",

	// Configure tool-specific properties.
	// "customizations": {},

	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [danilowoz]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
## What did you do? 
Please include the actual source code causing the issue.

## What did you expect to happen?
Please mention the expected behaviour.

## What happened actually?

### Which versions of react-content-loader, and which browser are affected by this issue?
Please also mention the version of react.


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## Summary
In this section, you should give the overview of the problem and the proposed changes.

## Related Issue #[issue number]
If this PR is fixing any issue, then please include - Related Issue #[issue number]

## Any Breaking Changes
If this PR is introducing any breaking changes then mention them in this section.

## Checklist
- [] Are all the test cases passing?
- [] If any new feature has been added, then are the test cases updated/added?
- [] Has the documentation been updated for the proposed change, if required?

================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for more information:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# https://containers.dev/guide/dependabot

version: 2
updates:
 - package-ecosystem: "devcontainers"
   directory: "/"
   schedule:
     interval: weekly


================================================
FILE: .github/workflows/ci.yml
================================================
name: Continuous Integration

on:
  pull_request:
  push:
    branches:
      - master

jobs:
  check:
    runs-on: ubuntu-latest
    name: Lint, typecheck and test

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - uses: pnpm/action-setup@v3
        with:
          version: 8

      - name: Use Node.js 20
        uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm i 

      - name: Run tests
        run: pnpm run test

      - name: Build
        run: pnpm run build


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    branches:
      - master

jobs:
  prepare:
    runs-on: ubuntu-latest
    name: Checks

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - uses: pnpm/action-setup@v3
        with:
          version: 8

      - name: Use Node.js 20
        uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm i 

      - name: Run tests
        run: pnpm run test

  build-and-release:
    runs-on: ubuntu-latest
    needs: prepare
    name: Release

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - uses: pnpm/action-setup@v3
        with:
          version: 8

      - name: Use Node.js 20
        uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm i 

      - name: Build
        run: pnpm run build

      - name: Release
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: pnpm run release


================================================
FILE: .gitignore
================================================
*.swp
*~
*.iml
.*.haste_cache.*
.DS_Store
.idea
npm-debug.log
yarn-error.log
node_modules
dist
coverage
/native
.docz/
.rpt2_cache
settings.json
*.code-workspace
yarn.lock
yarn-error.log
docs-build

================================================
FILE: .prettierrc.js
================================================
module.exports = require("@significa/prettier-config");


================================================
FILE: .storybook/main.ts
================================================
import type { StorybookConfig } from "@storybook/react-vite";
const config: StorybookConfig = {
  stories: ["../docs/**/*.mdx", "../docs/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
   
  ],
  framework: {
    name: "@storybook/react-vite",
    options: {},
  },
};
export default config;


================================================
FILE: .storybook/preview-head.html
================================================
<script>
    window.global = window;
</script>

================================================
FILE: .storybook/preview.tsx
================================================
import React from "react";

import type { Preview } from "@storybook/react";

const preview: Preview = {
  parameters: {
   
  },
  decorators: [
    (Story) => (
      <div>
        <Story />
      </div>
    ),
  ],
};

export default preview;


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at danilowoz@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2015 Julian Ćwirko <julian.io>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

================================================
FILE: README.md
================================================
<p align="center">
  <img width="350" alt="react-content-loader" src="https://user-images.githubusercontent.com/4838076/34419335-5669c3f8-ebea-11e7-9668-c47b7846970b.png"/>
</p>
<p align="center">
  <img width="400" alt="Example's react-content-loader" src="https://user-images.githubusercontent.com/4838076/34308760-ec55df82-e735-11e7-843b-2e311fa7b7d0.gif" />
</p>

SVG-Powered component to easily create placeholder loadings (like Facebook's cards loading).

## Features

- :gear: **Customizable:** Feel free to change the colors, speed, sizes, and even **RTL**;
- :ok_hand: **Plug and play:** with many presets to use, see the [examples](http://danilowoz.com/create-content-loader/#gallery);
- :pencil2: **DIY:** use the [create-content-loader](https://danilowoz.com/create-content-loader) to create your own custom loaders easily;
- 📱 **React Native support**: same API, as same powerful features;
- ⚛️ **Really lightweight:** less than **2kB** and **0 dependencies** for web version;

## Index

- [Getting Started](#gettingstarted)
- [Usage](#usage)
  - [Native](#native)
- [Options](#options)
- [Examples](#examples)
- [Troubleshooting](#troubleshooting)
- [Similar packages](#similarpackages)
- [Development](#development)

## Getting Started

```sh
npm i react-content-loader --save
```

```sh
yarn add react-content-loader
```

### For React Native

```sh
npm i react-content-loader react-native-svg --save
```

```sh
yarn add react-content-loader react-native-svg
```

CDN from [JSDELIVR](https://www.jsdelivr.com/package/npm/react-content-loader)

## Usage

There are two ways to use it:

**1. Presets, see the [examples](https://danilowoz.com/react-content-loader/):**

```jsx
import ContentLoader, { Facebook } from 'react-content-loader'

const MyLoader = () => <ContentLoader />
const MyFacebookLoader = () => <Facebook />
```

**2. Custom mode, see the [online tool](https://danilowoz.com/create-content-loader)**

```jsx
const MyLoader = () => (
  <ContentLoader viewBox="0 0 380 70">
    {/* Only SVG shapes */}    
    <rect x="0" y="0" rx="5" ry="5" width="70" height="70" />
    <rect x="80" y="17" rx="4" ry="4" width="300" height="13" />
    <rect x="80" y="40" rx="3" ry="3" width="250" height="10" />
  </ContentLoader>
)
```

**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)

## Native

`react-content-loader` can be used with React Native in the same way as web version with the same import:

**1. Presets, see the [examples](#examples):**

```jsx
import ContentLoader, { Facebook } from 'react-content-loader/native'

const MyLoader = () => <ContentLoader />
const MyFacebookLoader = () => <Facebook />
```

**2. Custom mode**

**To create custom loaders there is an important difference:** as React Native doesn't have any native module for SVG components, it's necessary to import the shapes from [react-native-svg](https://github.com/react-native-community/react-native-svg) or use the named export Rect and Circle from `react-content-loader` import:

```jsx
import ContentLoader, { Rect, Circle } from 'react-content-loader/native'

const MyLoader = () => (
  <ContentLoader viewBox="0 0 380 70">
    <Circle cx="30" cy="30" r="30" />
    <Rect x="80" y="17" rx="4" ry="4" width="300" height="13" />
    <Rect x="80" y="40" rx="3" ry="3" width="250" height="10" />
  </ContentLoader>
)
```

## Options

| <div style="width:250px">Prop name and type</div>                | Environment                | Description                                                                                                                                                                                                                                                                                         |
| ---------------------------------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`animate?: boolean`** <br/> Defaults to `true`                 | React DOM<br/>React Native | Opt-out of animations with `false`                                                                                                                                                                                                                                                                  |
| **`title?: string`** <br/> Defaults to `Loading...`              | React DOM only             | It's used to describe what element it is. <br />Use `''` (empty string) to remove.                                                                                                                                                                                                                  |
| **`baseUrl?: string`**<br /> Defaults to an empty string         | React DOM only             | Required if you're using `<base url="/" />` document `<head/>`. <br/>This prop is common used as: <br/>`<ContentLoader baseUrl={window.location.pathname} />` which will fill the SVG attribute with the relative path. Related [#93](https://github.com/danilowoz/react-content-loader/issues/93). |
| **`speed?: number`** <br /> Defaults to `1.2`                    | React DOM<br/>React Native | Animation speed in seconds.                                                                                                                                                                                                                                                                         |
| **`viewBox?: string`** <br /> Defaults to `undefined`            | React DOM<br/>React Native | Use viewBox props to set a custom viewBox value, <br/>for more information about how to use it, <br/>read the article [How to Scale SVG](https://css-tricks.com/scale-svg/).                                                                                                                        |
| **`gradientRatio?: number`** <br /> Defaults to `1.2`            | React DOM only             | Width of the animated gradient as a fraction of the view box width.                                                                                                                                                                                                                                 |
| **`rtl?: boolean`** <br /> Defaults to `false`                   | React DOM<br/>React Native | Content right-to-left.                                                                                                                                                                                                                                                                              |
| **`backgroundColor?: string`** <br /> Defaults to `#f5f6f7`      | React DOM<br/>React Native | Used as background of animation.                                                                                                                                                                                                                                                                    |
| **`foregroundColor?: string`** <br /> Defaults to `#eee`         | React DOM<br/>React Native | Used as the foreground of animation.                                                                                                                                                                                                                                                                |
| **`backgroundOpacity?: number`** <br /> Defaults to `1`          | React DOM<br/>React Native | Background opacity (0 = transparent, 1 = opaque)<br/>used to solve an issue in [Safari](#safari--ios)                                                                                                                                                                                               |
| **`foregroundOpacity?: number`** <br /> Defaults to `1`          | React DOM<br/>React Native | Animation opacity (0 = transparent, 1 = opaque)<br/>used to solve an issue in [Safari](#safari--ios)                                                                                                                                                                                                |
| **`style?: React.CSSProperties`** <br /> Defaults to `{}`        | React DOM only             |                                                                                                                                                                                                                                                                                                     |
| **`uniqueKey?: string`** <br /> Defaults to random unique id     | React DOM only             | Use the same value of prop key, <br/>that will solve inconsistency on the SSR, see more [here](https://github.com/danilowoz/react-content-loader/issues/78).                                                                                                                                        |
| **`beforeMask?: JSX.Element`** <br /> Defaults to null           | React DOM<br/>React Native | Define custom shapes before content, <br/>see more [here](https://github.com/danilowoz/react-content-loader/issues/266).                                                                                                                                                                            |

See all options [live](https://danilowoz.com/react-content-loader/)

## Examples

##### Facebook Style

```jsx
import { Facebook } from 'react-content-loader'

const MyFacebookLoader = () => <Facebook />
```

<img alt="Facebook Style" src="https://user-images.githubusercontent.com/4838076/73212460-328f7500-4146-11ea-99e7-e19cd4e07a51.png" width="500px" />

##### Instagram Style

```jsx
import { Instagram } from 'react-content-loader'

const MyInstagramLoader = () => <Instagram />
```

<img alt="Instagram Style" src="https://user-images.githubusercontent.com/4838076/73212462-328f7500-4146-11ea-98dc-3a6aeafd4a26.png" width="500px" />

##### Code Style

```jsx
import { Code } from 'react-content-loader'

const MyCodeLoader = () => <Code />
```

<img alt="Code Style" src="https://user-images.githubusercontent.com/4838076/73212459-328f7500-4146-11ea-89b0-1b7bbae8047b.png" width="500px" />

##### List Style

```jsx
import { List } from 'react-content-loader'

const MyListLoader = () => <List />
```

<img alt="List Style" src="https://user-images.githubusercontent.com/4838076/73212463-33280b80-4146-11ea-9f93-95c2cbdef17b.png" width="500px" />

##### Bullet list Style

```jsx
import { BulletList } from 'react-content-loader'

const MyBulletListLoader = () => <BulletList />
```

<img alt="Bullet list Style" src="https://user-images.githubusercontent.com/4838076/73212458-328f7500-4146-11ea-826f-576059c4644e.png" width="500px" />

### Custom Style

For the custom mode, use the
[online tool](https://danilowoz.com/create-content-loader).

```jsx
const MyLoader = () => (
  <ContentLoader
    height={140}
    speed={1}
    backgroundColor={'#333'}
    foregroundColor={'#999'}
    viewBox="0 0 380 70"
  >
    {/* Only SVG shapes */}
    <rect x="0" y="0" rx="5" ry="5" width="70" height="70" />
    <rect x="80" y="17" rx="4" ry="4" width="300" height="13" />
    <rect x="80" y="40" rx="3" ry="3" width="250" height="10" />
  </ContentLoader>
)
```

![Custom](https://user-images.githubusercontent.com/4838076/36352947-b87019a8-149e-11e8-99ba-c71c2bcf8733.gif)

## Troubleshooting

#### Responsive - Mobile version

In order to avoid unexpected behavior, the package doesn't have opinioned settings. So if it needs to be responsive, have in mind that the output of the package is a regular SVG, so it just needs the same attributes to become a regular SVG responsive, which means:

```jsx
import { Code } from 'react-content-loader'

const MyCodeLoader = () => (
  <Code
    width={100}
    height={100}
    viewBox="0 0 100 100"
    style={{ width: '100%' }}
  />
)
```

#### Server-side rendering (SSR) - Match snapshot

As the main component generates random values to match the id of the SVG element with background style, it can encounter unexpected errors and unmatching warning on render, once the random value of id will be generated twice, in case of SSR: server and client; or in case of snapshot test: on the first match and re-running the test.

To fix it, set the prop [`uniqueKey`](https://github.com/danilowoz/react-content-loader#uniquekey-string---web-only), then the id will not be random anymore:

```jsx
import { Facebook } from 'react-content-loader'

const MyFacebookLoader = () => <Facebook uniqueKey="my-random-value" />
```

#### **Alpha is not working: Safari / iOS**

When using `rgba` as a `backgroundColor` or `foregroundColor` value, [Safari does not respect the alpha channel](https://github.com/w3c/svgwg/issues/180), meaning that the color will be opaque. To prevent this, instead of using a `rgba` value for `backgroundColor`/`foregroundColor`, use the `rgb` equivalent and move the alpha channel value to the `backgroundOpacity`/`foregroundOpacity` props.

```jsx
{/* Opaque color in Safari and iOS */}
<ContentLoader
  backgroundColor="rgba(0,0,0,0.06)"
  foregroundColor="rgba(0,0,0,0.12)">


{/_ Semi-transparent color in Safari and iOS _/}
<ContentLoader
    backgroundColor="rgb(0,0,0)"
    foregroundColor="rgb(0,0,0)"
    backgroundOpacity={0.06}
    foregroundOpacity={0.12}>


```

#### **Black box in Safari / iOS (again)**

Using the base tag on a page that contains SVG elements fails to render and it looks like a black box. Just remove the **base-href** tag from the `<head />` and the issue has been solved.

<img width="350" src="https://user-images.githubusercontent.com/11562881/39406054-2f308de6-4bce-11e8-91fb-bbb35e29fc10.png" alt="black box" />

See: [#93](https://github.com/danilowoz/react-content-loader/issues/93) / [109](https://github.com/danilowoz/react-content-loader/issues/109)

#### Browser supports SVG-Animate

Old browsers don't support animation in SVG ([compatibility list](https://caniuse.com/#search=SVGAnimateElement)), and if your project must support IE, for examples, here's a couple of ways to make sure that browser supports SVG Animate:

- `window.SVGAnimateElement`
- `document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#SVG-Animation", "1.1")`
- Or even use https://modernizr.com/

## Similar packages

- React Native: [rn-placeholder](https://github.com/mfrachet/rn-placeholder), [react-native-svg-animated-linear-gradient](https://github.com/virusvn/react-native-svg-animated-linear-gradient);
- [Preact](https://github.com/bonitasoft/preact-content-loader);
- Vue.js: [vue-content-loading](https://github.com/LucasLeandro1204/vue-content-loading), [vue-content-loader](https://github.com/egoist/vue-content-loader);
- Angular: [ngx-content-loading](https://github.com/Gbuomprisco/ngx-content-loading), [ngx-content-loader](https://github.com/NetanelBasal/ngx-content-loader).

---

## Development

Fork the repo and then clone it

```
$ git clone git@github.com:YourUsername/react-content-loader.git && cd react-content-loader
```

`$ npm i`: Install the dependencies;

`$ npm run build`: Build to production;

`$ npm run dev`: Run the Storybook to see your changes;

`$ npm run test`: Run all tests: type checking, unit tests on web and native;

`$ npm run test:watch`: Watch unit tests;

### React Native

As React Native doesn't support symbolic links (to link the dependency to another folder) and as there is no playground to check your contributions (like storybook), this is recommended strategy to run the project locally:

1. Create a new React Native from scratch, either Metro or create-react-native-app;
2. Install the dependency to your root project:
   `yarn add react-content-loader react-native-svg`
3. Open the project just created and clone this repository there;
4. Create your loading component and point the `react-content-loader` to the project just cloned, like:
   `import ContentLoader, { Rect, Circle } from './react-content-loader/native'`

### Commit messages

Commit messages should follow the [commit message convention](https://conventionalcommits.org/) so, changelogs could be generated automatically by that. Commit messages are validated automatically upon commit. If you aren't familiar with the commit message convention, you can use yarn commit (or `npm run commit`) instead of git commit, which provides an interactive CLI for generating proper commit messages.

## License

[MIT](https://github.com/danilowoz/react-content-loader/blob/master/LICENSE)


================================================
FILE: __mocks__/react-native-svg.js
================================================
import React from 'react';

const createComponent = function(name) {
  return class extends React.Component {
    // overwrite the displayName, since this is a class created dynamically
    static displayName = name;

    render() {
      return React.createElement(name, this.props, this.props.children);
    }
  };
};

// Mock all react-native-svg exports
// from https://github.com/magicismight/react-native-svg/blob/master/index.js
const Svg = createComponent('Svg');
const Circle = createComponent('Circle');
const Ellipse = createComponent('Ellipse');
const G = createComponent('G');
const Text = createComponent('Text');
const TextPath = createComponent('TextPath');
const TSpan = createComponent('TSpan');
const Path = createComponent('Path');
const Polygon = createComponent('Polygon');
const Polyline = createComponent('Polyline');
const Line = createComponent('Line');
const Rect = createComponent('Rect');
const Use = createComponent('Use');
const Image = createComponent('Image');
const Symbol = createComponent('Symbol');
const Defs = createComponent('Defs');
const LinearGradient = createComponent('LinearGradient');
const RadialGradient = createComponent('RadialGradient');
const Stop = createComponent('Stop');
const ClipPath = createComponent('ClipPath');
const Pattern = createComponent('Pattern');
const Mask = createComponent('Mask');

export {
  Svg,
  Circle,
  Ellipse,
  G,
  Text,
  TextPath,
  TSpan,
  Path,
  Polygon,
  Polyline,
  Line,
  Rect,
  Use,
  Image,
  Symbol,
  Defs,
  LinearGradient,
  RadialGradient,
  Stop,
  ClipPath,
  Pattern,
  Mask,
};

export default Svg;

================================================
FILE: babel.config.js
================================================
module.exports = {
  presets: [
    'module:metro-react-native-babel-preset',
    '@babel/preset-typescript',
  ],
  plugins: [['@babel/plugin-transform-private-methods', { loose: true }]],
}


================================================
FILE: docs/index.stories.tsx
================================================
import React from 'react'
import SyntaxHighlighter from 'react-syntax-highlighter'
import { docco } from 'react-syntax-highlighter/dist/esm/styles/hljs'

import ContentLoader, {
  BulletList,
  Code,
  Facebook,
  Instagram,
  List,
} from '../src/web'

export default {
  title: 'React Content Loader',
}

const SyntaxCode = ({ children }) => {
  return (
    <SyntaxHighlighter language="jsx" style={docco}>
      {children}
    </SyntaxHighlighter>
  )
}

/**
 * Animated
 */
export const animate = () => {
  return (
    <>
      <SyntaxCode>{'<ContentLoader  />'}</SyntaxCode>
      <ContentLoader backgroundColor="red" />

      <SyntaxCode>{'<ContentLoader animate={false} />'}</SyntaxCode>
      <ContentLoader animate={false} />
    </>
  )
}

animate.story = {
  parameters: {
    notes: `##\`animate?: boolean\` 
    
    Defaults to \`true\`. Opt-out of animations with \`false\``,
  },
}

/**
 * Background color
 */
export const backgroundColor = () => {
  return (
    <>
      <SyntaxCode>{'<ContentLoader backgroundColor="#333" />'}</SyntaxCode>
      <ContentLoader backgroundColor="#333" />
    </>
  )
}

backgroundColor.story = {
  parameters: {
    notes: `## \`backgroundColor?: string\`

    Defaults to \`#f5f6f7\` which is used as background of animation.`,
  },
}

/**
 * Foreground color
 */
export const foregroundColor = () => {
  return (
    <>
      <SyntaxCode>{'<ContentLoader foregroundColor="#333" />'}</SyntaxCode>
      <ContentLoader foregroundColor="#333" />
    </>
  )
}

foregroundColor.story = {
  parameters: {
    notes: `## \`foregroundColor?: string\`

    Defaults to \`#eee\` which is used as foreground of animation.`,
  },
}

/**
 * Background opacity
 */
export const backgroundOpacity = () => {
  return (
    <>
      <SyntaxCode>{'<ContentLoader backgroundOpacity="#333" />'}</SyntaxCode>
      <ContentLoader backgroundOpacity={0.06} />
    </>
  )
}

backgroundOpacity.story = {
  parameters: {
    notes: `## \`backgroundOpacity?: number\`

    Defaults to \`1\`. Background opacity (0 = transparent, 1 = opaque) used to solve a issue in [Safari](#bugfix-in-safari)`,
  },
}

/**
 * Foreground opacity
 */
export const foregroundOpacity = () => {
  return (
    <>
      <SyntaxCode>{'<ContentLoader foregroundOpacity={0.06} />'}</SyntaxCode>
      <ContentLoader foregroundOpacity={0.06} />
    </>
  )
}

foregroundOpacity.story = {
  parameters: {
    notes: `## \`foregroundOpacity?: number\`

    Defaults to \`1\`. Animation opacity (0 = transparent, 1 = opaque) used to solve a issue in [Safari](#bugfix-in-safari)`,
  },
}

/**
 * Base URL
 */
export const baseURL = () => {
  return (
    <>
      <SyntaxCode>{'<ContentLoader baseUrl="" />'}</SyntaxCode>
      <ContentLoader baseUrl="" />
    </>
  )
}

baseURL.story = {
  parameters: {
    notes: `## \`baseUrl?: string\`

    Required if you're using \`<base url="/" />\` in the \`<head/>\`. Defaults to an empty string. This prop is common used as: \`<ContentLoader baseUrl={window.location.pathname} />\` which will fill the SVG attribute with the relative path. Related [#93](https://github.com/danilowoz/react-content-loader/issues/93).
    `,
  },
}

/**
 * Children
 */
export const children = () => {
  return (
    <>
      <p>Custom</p>
      <SyntaxCode>{`<ContentLoader>
  <rect x="0" y="0" rx="5" ry="5" width="70" height="70" />
  <rect x="80" y="17" rx="4" ry="4" width="300" height="13" />
  <rect x="80" y="40" rx="3" ry="3" width="250" height="10" />
</ContentLoader>`}</SyntaxCode>
      <ContentLoader>
        <rect x="0" y="0" rx="5" ry="5" width="70" height="70" />
        <rect x="80" y="17" rx="4" ry="4" width="300" height="13" />
        <rect x="80" y="40" rx="3" ry="3" width="250" height="10" />
      </ContentLoader>

      <p>Default</p>
      <SyntaxCode>{`<ContentLoader />`}</SyntaxCode>
      <ContentLoader />
    </>
  )
}

children.story = { parameters: { notes: `## \`children?: ReactNode\`` } }

/**
 * Gradient Ratio
 */
export const gradientRatio = () => {
  return (
    <>
      <SyntaxCode>{`<ContentLoader
  gradientRatio={0.2}
  backgroundColor={'#333'}
  foregroundColor={'#999'}
/>`}</SyntaxCode>
      <ContentLoader
        gradientRatio={0.2}
        backgroundColor={'#333'}
        foregroundColor={'#999'}
      />

      <SyntaxCode>{`<ContentLoader
  gradientRatio={4}
  backgroundColor={'#333'}
  foregroundColor={'#999'}
/>`}</SyntaxCode>
      <ContentLoader
        gradientRatio={4}
        backgroundColor={'#333'}
        foregroundColor={'#999'}
      />
    </>
  )
}

gradientRatio.story = {
  parameters: {
    notes: `## \`gradientRatio?: number\`

    Defaults to \`2\`. Width of the animated gradient as a fraction of the viewbox width.`,
  },
}

/**
 * Gradient Direction
 */
export const gradientDirection = () => {
  return (
    <>
      <SyntaxCode>{`<BulletList gradientDirection="left-right" />`}</SyntaxCode>
      <BulletList gradientDirection="left-right" />

      <SyntaxCode>{`<BulletList gradientDirection="top-bottom" />`}</SyntaxCode>
      <BulletList gradientDirection="top-bottom" />
    </>
  )
}

gradientDirection.story = {
  parameters: {
    notes: `## \`gradientDirection?: 'left-right' | 'top-bottom' \`

    Defaults to \`left-right\`. Direction in which the gradient is animated. Useful to implement top-down animations`,
  },
}

/**
 * Speed
 */
export const speed = () => {
  return (
    <>
      <SyntaxCode>{`<ContentLoader speed={4} />`}</SyntaxCode>
      <ContentLoader speed={4} />
      <SyntaxCode>{`<ContentLoader speed={1} />`}</SyntaxCode>
      <ContentLoader speed={1} />
    </>
  )
}

speed.story = {
  parameters: {
    notes: `## \`speed?: number\`

    Defaults to \`1.2\`. Animation speed in seconds.`,
  },
}

/**
 * RTL
 */
export const RTL = () => {
  return (
    <>
      <SyntaxCode>{`<ContentLoader rtl />`}</SyntaxCode>
      <ContentLoader rtl />
    </>
  )
}

RTL.story = {
  parameters: {
    notes: `## \`rtl?: boolean\`

    Defaults to \`false\`. Content right-to-left.`,
  },
}

/**
 * Unique key
 */
export const uniqueKey = () => {
  return (
    <>
      <SyntaxCode>{`<ContentLoader uniqueKey="my-uniqye-key" />`}</SyntaxCode>
      <ContentLoader uniqueKey="my-uniqye-key" />
    </>
  )
}

uniqueKey.story = {
  parameters: {
    notes: `## \`uniqueKey?: string\`
    
    Defaults to random unique id. Use the same value of prop key, that will solve inconsistency on the SSR, see more [here](https://github.com/danilowoz/react-content-loader/issues/78).`,
  },
}

/**
 * Responsive
 */
export const responsive = () => {
  return (
    <div style={{ width: 200, border: '1px solid #eee' }}>
      <SyntaxCode>{"<ContentLoader style={{ width: '100%' }} />'"}</SyntaxCode>
      <ContentLoader />
    </div>
  )
}

/**
 * Title
 */
export const title = () => {
  return (
    <>
      <SyntaxCode>{`<ContentLoader  title="Loading interface..." />`}</SyntaxCode>
      <ContentLoader title="Loading interface..." />
    </>
  )
}

title.story = {
  parameters: {
    notes: `## \`title?: string | boolean\`

    Defaults to \`Loading interface...\`. It's used to describe what element it is. Use \`false\` to remove.
    `,
  },
}

/**
 * View box
 */
export const viewBox = () => {
  return (
    <>
      <SyntaxCode>{'<ContentLoader />'}</SyntaxCode>
      <ContentLoader />

      <SyntaxCode>{'<ContentLoader viewBox="" />'}</SyntaxCode>
      <ContentLoader viewBox="" />
    </>
  )
}

viewBox.story = {
  parameters: {
    notes: `## \`viewBox?: string\`

    Use viewbox props to set viewbox value.
    Additionally, pass viewBox props as empty string to remove viewBox.`,
  },
}

/**
 * Presets
 */
export const presets = () => {
  return (
    <>
      <SyntaxCode>{'<Facebook />'}</SyntaxCode>
      <Facebook />

      <SyntaxCode>{'<Instagram />'}</SyntaxCode>
      <Instagram />

      <SyntaxCode>{'<Code />'}</SyntaxCode>
      <Code />

      <SyntaxCode>{'<List />'}</SyntaxCode>
      <List />

      <SyntaxCode>{'<BulletList />'}</SyntaxCode>
      <BulletList />
    </>
  )
}

/**
 * Content loader vs SVG
 */
export const contentLoaderVsSVG = () => {
  return (
    <>
      <ContentLoader viewBox="0 0 636 566">
        <rect x="0" y="2" rx="4" ry="4" width="634" height="374" />
        <rect x="12" y="404" rx="3" ry="3" width="259" height="18" />
        <rect x="294" y="404" rx="3" ry="3" width="163" height="18" />
        <rect x="12" y="441" rx="3" ry="3" width="575" height="18" />
        <rect x="12" y="473" rx="3" ry="3" width="350" height="18" />
        <rect x="70" y="523" rx="3" ry="3" width="251" height="18" />
        <circle cx="37" cy="532" r="25" />
      </ContentLoader>

      <svg viewBox="0 0 636 566">
        <rect x="0" y="2" rx="4" ry="4" width="634" height="374" />
        <rect x="12" y="404" rx="3" ry="3" width="259" height="18" />
        <rect x="294" y="404" rx="3" ry="3" width="163" height="18" />
        <rect x="12" y="441" rx="3" ry="3" width="575" height="18" />
        <rect x="12" y="473" rx="3" ry="3" width="350" height="18" />
        <rect x="70" y="523" rx="3" ry="3" width="251" height="18" />
        <circle cx="37" cy="532" r="25" />
      </svg>
    </>
  )
}

/**
 * beforeMask
 */
export const BeforeMask = () => {
  return (
    <>
      <SyntaxCode>
        {`<ContentLoader
  viewBox="0 0 308 88"
  beforeMask={
    <rect width="306" height="86" y="1" x="1" stroke="#dee0e3" strokeWidth="1" fill="#fff" />
  }
>
  <rect x="12" y="13" rx="4" ry="4" width="20" height="20"></rect>
  <rect x="40" y="16" rx="4" ry="4" width="80" height="14"></rect>
  <rect x="12" y="41" rx="4" ry="4" width="270" height="12"></rect>
  <rect x="12" y="61" rx="4" ry="4" width="270" height="12"></rect>
</ContentLoader>`}
      </SyntaxCode>
      <ContentLoader
        viewBox="0 0 300 88"
        beforeMask={
          <rect
            width="298"
            height="86"
            y="1"
            x="1"
            stroke="#dee0e3"
            strokeWidth="1"
            fill="#fff"
          />
        }
      >
        <rect x="12" y="13" rx="4" ry="4" width="20" height="20"></rect>
        <rect x="40" y="16" rx="4" ry="4" width="80" height="14"></rect>
        <rect x="12" y="41" rx="4" ry="4" width="270" height="12"></rect>
        <rect x="12" y="61" rx="4" ry="4" width="270" height="12"></rect>
      </ContentLoader>
    </>
  )
}


================================================
FILE: jest.native.config.js
================================================
module.exports = {
  preset: 'react-native',
  transformIgnorePatterns: [
    'node_modules/.pnpm/(?!react-native-payfort-sdk|react-native)/',
  ],
  testRegex: '/src/native/__tests__/.*(\\.|/)(test|spec)\\.[jt]sx?$',
}


================================================
FILE: jest.web.config.js
================================================
module.exports = {
  verbose: true,
  transform: {
    '^.+\\.(t|j)sx?$': 'ts-jest',
  },
  testRegex: '/src/web/__tests__/.*(\\.|/)(test|spec)\\.[jt]sx?$',
  roots: ['<rootDir>/src'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
  preset: 'ts-jest',
}


================================================
FILE: package.json
================================================
{
  "name": "react-content-loader",
  "version": "6.2.1",
  "description": "SVG-Powered component to easily create placeholder loadings (like Facebook cards loading)",
  "repository": {
    "type": "git",
    "url": "https://github.com/danilowoz/react-content-loader"
  },
  "author": "Danilo Woznica <danilowoz@gmail.com>",
  "license": "MIT",
  "main": "dist/react-content-loader.cjs.js",
  "module": "dist/react-content-loader.es.js",
  "jsnext:main": "dist/react-content-loader.es.js",
  "types": "dist/web/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/web/index.d.ts",
      "require": "./dist/react-content-loader.cjs.js",
      "import": "./dist/react-content-loader.es.js",
      "default": "./dist/react-content-loader.cjs.js"
    },
    "./native": {
      "types": "./native/native/index.d.ts",
      "require": "./native/react-content-loader.native.cjs.js",
      "import": "./native/react-content-loader.native.es.js",
      "default": "./native/react-content-loader.native.cjs.js"
    }
  },
  "bugs": {
    "url": "https://github.com/danilowoz/react-content-loader/issues"
  },
  "homepage": "https://github.com/danilowoz/react-content-loader",
  "keywords": [
    "react",
    "react-native",
    "skeleton",
    "placeholder",
    "loader",
    "loading",
    "content",
    "svg"
  ],
  "files": [
    "dist",
    "native"
  ],
  "sideEffects": false,
  "scripts": {
    "dev": "storybook dev -p 6006",
    "build": "rm -fr ./dist ./native && rollup -c",
    "build:docs": "build-storybook -o docs-build",
    "test": "npm run test:tsc && npm run test:unit",
    "test:unit": "npm run test:unit:web && npm run test:unit:native",
    "test:unit:web": "jest -c jest.web.config.js",
    "test:unit:native": "jest -c jest.native.config.js",
    "test:watch": "npm run test:unit -- --watch",
    "test:tsc": "tsc",
    "test:tsc:watch": "npm run tsc -- --watch",
    "commit": "git-cz",
    "format": "prettier --write \"src/**/*.{ts,tsx}\"",
    "release": "semantic-release"
  },
  "devDependencies": {
    "@babel/plugin-transform-private-methods": "^7.23.3",
    "@babel/preset-react": "^7.23.3",
    "@babel/preset-typescript": "^7.23.3",
    "@babel/runtime": "^7.24.0",
    "@commitlint/cli": "^11.0.0",
    "@commitlint/config-conventional": "8.2.0",
    "@significa/prettier-config": "0.0.9",
    "@storybook/react": "^7.6.17",
    "@storybook/react-vite": "^7.6.17",
    "@storybook/storybook-deployer": "^2.8.6",
    "@types/jest": "24.0.24",
    "@types/react": "18.2.64",
    "@types/react-dom": "18.2.21",
    "@types/react-test-renderer": "18.0.7",
    "@typescript-eslint/eslint-plugin": "2.13.0",
    "awesome-typescript-loader": "5.2.1",
    "commitizen": "^4.2.1",
    "cz-conventional-changelog": "3.0.2",
    "husky": "3.1.0",
    "jest": "29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "metro-react-native-babel-preset": "^0.77.0",
    "prettier": "1.19.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-native": "^0.73.3",
    "react-native-svg": "15.1.0",
    "react-syntax-highlighter": "^12.2.1",
    "react-test-renderer": "18.2.0",
    "rollup": "1.27.14",
    "rollup-plugin-copy": "3.1.0",
    "rollup-plugin-replace": "2.2.0",
    "rollup-plugin-typescript2": "0.25.3",
    "rollup-plugin-uglify": "6.0.4",
    "semantic-release": "^17.4.2",
    "storybook": "^7.6.17",
    "ts-jest": "^29.1.2",
    "tslib": "^2.6.2",
    "typescript": "5.4.2"
  },
  "peerDependencies": {
    "react": ">=18.0.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm run format",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },
  "commitlint": {
    "extends": [
      "@commitlint/config-conventional"
    ]
  },
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-conventional-changelog"
    }
  },
  "engines": {
    "node": ">=10"
  }
}


================================================
FILE: rollup.config.js
================================================
/* eslint-disable @typescript-eslint/camelcase */
import replace from 'rollup-plugin-replace'
import { uglify } from 'rollup-plugin-uglify'
import typescript from 'rollup-plugin-typescript2'
import copy from 'rollup-plugin-copy'

import pkg from './package.json'

const mergeAll = objs => Object.assign({}, ...objs)

const cjs = {
  exports: 'named',
  format: 'cjs',
  sourcemap: true,
}

const esm = {
  format: 'es',
  sourcemap: true,
}

const globals = { react: 'React', 'react-dom': 'ReactDOM' }

const commonPlugins = [
  typescript({
    typescript: require('typescript'),
  }),
]

const configBase = {
  output: {
    exports: 'named',
  },
  external: [
    ...Object.keys(pkg.dependencies || {}),
    ...Object.keys(pkg.peerDependencies || {}),
  ],
  plugins: commonPlugins,
}

const umdConfig = mergeAll([
  configBase,
  {
    input: 'src/web/index.ts',
    output: mergeAll([
      configBase.output,
      {
        file: `dist/${pkg.name}.js`,
        format: 'umd',
        name: 'ContentLoader',
        globals,
      },
    ]),
    external: Object.keys(pkg.peerDependencies || {}),
  },
])

const devUmdConfig = mergeAll([
  umdConfig,
  {
    input: 'src/web/index.ts',
    plugins: umdConfig.plugins.concat(
      replace({
        'process.env.NODE_ENV': JSON.stringify('development'),
      })
    ),
  },
])

const prodUmdConfig = mergeAll([
  umdConfig,
  {
    input: 'src/web/index.ts',
    output: mergeAll([
      umdConfig.output,
      { file: umdConfig.output.file.replace(/\.js$/, '.min.js') },
    ]),
  },
  {
    plugins: umdConfig.plugins.concat(
      replace({
        'process.env.NODE_ENV': JSON.stringify('production'),
      }),
      uglify({
        compress: {
          pure_getters: true,
          unsafe: true,
          unsafe_comps: true,
        },
      })
    ),
  },
])

const webConfig = mergeAll([
  configBase,
  {
    input: 'src/web/index.ts',
    output: [
      mergeAll([configBase.output, { ...esm, file: pkg.module }]),
      mergeAll([configBase.output, { ...cjs, file: pkg.main }]),
    ],
    plugins: configBase.plugins.concat(),
  },
])

const nativeConfig = mergeAll([
  configBase,
  {
    input: './src/native/index.ts',
    output: [
      mergeAll([
        configBase.output,
        { ...esm, file: `native/${pkg.name}.native.es.js` },
      ]),
      mergeAll([
        configBase.output,
        { ...cjs, file: `native/${pkg.name}.native.cjs.js` },
      ]),
    ],
    plugins: configBase.plugins.concat(
      copy({
        targets: [{ src: 'src/native/package.json', dest: 'native' }],
      })
    ),
  },
])

export default [devUmdConfig, prodUmdConfig, webConfig, nativeConfig]


================================================
FILE: src/native/ContentLoader.tsx
================================================
import * as React from 'react'
import { Circle, Path, Rect } from 'react-native-svg'

import { Facebook, IContentLoaderProps } from '.'
import Svg from './Svg'

const ContentLoader: React.FC<IContentLoaderProps> = props =>
  props.children ? <Svg {...props} /> : <Facebook {...props} />

export { Circle, Rect, Path }

export default ContentLoader


================================================
FILE: src/native/Svg.tsx
================================================
import React, { Component, isValidElement } from 'react'
import { Animated } from 'react-native'
import Svg, {
  ClipPath,
  Defs,
  LinearGradient,
  Rect,
  Stop,
} from 'react-native-svg'

import uid from '../shared/uid'
import { IContentLoaderProps } from './'

const AnimatedLinearGradient = Animated.createAnimatedComponent(LinearGradient)

class NativeSvg extends Component<IContentLoaderProps> {
  static defaultProps = {
    animate: true,
    backgroundColor: '#f5f6f7',
    backgroundOpacity: 1,
    foregroundColor: '#eee',
    foregroundOpacity: 1,
    rtl: false,
    speed: 1.2,
    interval: 0.25,
    style: {},
    beforeMask: null,
  }

  animatedValue = new Animated.Value(-1)

  fixedId = this.props.uniqueKey || uid()

  idClip = `${this.fixedId}-diff`

  idGradient = `${this.fixedId}-animated-diff`

  unmounted = false

  setAnimation = () => {
    // props.speed is in seconds as it is compatible with web
    // convert to milliseconds
    const durMs = this.props.speed * 1000
    const delay = durMs * this.props.interval

    Animated.timing(this.animatedValue, {
      toValue: 2,
      delay: delay,
      duration: durMs,
      useNativeDriver: true,
    }).start(() => {
      if (!this.unmounted && this.props.animate) {
        this.animatedValue.setValue(-1)
        this.setAnimation()
      }
    })
  }

  componentDidMount = () => {
    if (this.props.animate) {
      this.setAnimation()
    }
  }

  componentDidUpdate(prevProps: IContentLoaderProps) {
    if (!prevProps.animate && this.props.animate) {
      this.setAnimation()
    }
  }

  componentWillUnmount() {
    this.unmounted = true
  }

  render() {
    const {
      children,
      backgroundColor,
      backgroundOpacity,
      foregroundColor,
      foregroundOpacity,
      rtl,
      style,
      beforeMask,
      ...props
    } = this.props

    const x1Animation = this.animatedValue.interpolate({
      extrapolate: 'clamp',
      inputRange: [-1, 2],
      outputRange: ['-100%', '100%'],
    })

    const x2Animation = this.animatedValue.interpolate({
      extrapolate: 'clamp',
      inputRange: [-1, 2],
      outputRange: ['0%', '200%'],
    })

    const rtlStyle: object = rtl ? { transform: [{ rotateY: '180deg' }] } : {}
    const svgStyle = Object.assign(Object.assign({}, style), rtlStyle)

    // Remove unnecessary keys
    delete props.uniqueKey
    delete props.animate
    delete props.speed

    return (
      <Svg style={svgStyle} {...props}>
        {beforeMask && isValidElement(beforeMask) ? beforeMask : null}

        <Rect
          x="0"
          y="0"
          width="100%"
          height="100%"
          fill={`url(#${this.idClip})`}
          clipPath={`url(#${this.idGradient})`}
        />

        <Defs>
          <ClipPath id={this.idGradient}>{children}</ClipPath>

          <AnimatedLinearGradient
            id={this.idClip}
            x1={x1Animation}
            x2={x2Animation}
            y1={0}
            y2={0}
          >
            <Stop offset={0} stopColor={backgroundColor} stopOpacity={backgroundOpacity} />
            <Stop offset={0.5} stopColor={foregroundColor} stopOpacity={foregroundOpacity} />
            <Stop offset={1} stopColor={backgroundColor} stopOpacity={backgroundOpacity} />
          </AnimatedLinearGradient>
        </Defs>
      </Svg>
    )
  }
}

export default NativeSvg


================================================
FILE: src/native/__tests__/ContentLoader.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'
import * as ShallowRenderer from 'react-test-renderer/shallow'

import ContentLoader, { Circle, Rect } from '../ContentLoader'

jest.useFakeTimers()

describe('ContentLoader', () => {
  describe('when type is custom', () => {
    const customWrapper = renderer.create(
      <ContentLoader animate={false}>
        <Rect x="80" y="17" rx="4" ry="4" width="300" height="13" />
        <Rect x="82" y="44" rx="3" ry="3" width="250" height="10" />
        <Circle cx="35" cy="35" r="35" />
      </ContentLoader>
    ).root

    it('should render custom element', () => {
      const rect = customWrapper.findAllByType(Rect)
      const circle = customWrapper.findAllByType(Circle)

      expect(rect.length).toBe(3)
      expect(circle.length).toBe(1)
    })
  })

  describe('Props are propagated', () => {
    const noPropsComponent = ShallowRenderer.createRenderer()
    noPropsComponent.render(
      <ContentLoader>
        <Rect />
      </ContentLoader>
    )

    const withPropsComponent = ShallowRenderer.createRenderer()
    withPropsComponent.render(
      <ContentLoader
        animate={false}
        height={200}
        preserveAspectRatio="xMaxYMax meet"
        backgroundColor="#000"
        rtl
        foregroundColor="#fff"
        speed={10}
        style={{ marginBottom: 10 }}
        width={200}
        beforeMask={<Rect />}
      >
        <Rect />
      </ContentLoader>
    )

    const { props: propsFromEmpty } = noPropsComponent.getRenderOutput()
    const { props: propsFromFullField } = withPropsComponent.getRenderOutput()

    it("`speed` is a number and it's used", () => {
      // defaultProps
      expect(typeof propsFromEmpty.speed).toBe('number')
      expect(propsFromEmpty.speed).toBe(1.2)
      // custom props
      expect(typeof propsFromFullField.speed).toBe('number')
      expect(propsFromFullField.speed).toBe(10)
    })

    it("`height` is a number and it's used", () => {
      // custom props
      expect(typeof propsFromFullField.height).toBe('number')
      expect(propsFromFullField.height).toBe(200)
    })

    it("`width` is a number and it's used", () => {
      // custom props
      expect(typeof propsFromFullField.width).toBe('number')
      expect(propsFromFullField.width).toBe(200)
    })

    it("`animate` is a boolean and it's used", () => {
      // defaultProps
      expect(typeof propsFromEmpty.animate).toBe('boolean')
      expect(propsFromEmpty.animate).toBe(true)
      // custom props
      expect(typeof propsFromFullField.animate).toBe('boolean')
      expect(propsFromFullField.animate).toBe(false)
    })

    it("`backgroundColor` is a string and it's used", () => {
      // defaultProps
      expect(typeof propsFromEmpty.backgroundColor).toBe('string')
      expect(propsFromEmpty.backgroundColor).toBe('#f5f6f7')
      // custom props
      expect(typeof propsFromFullField.backgroundColor).toBe('string')
      expect(propsFromFullField.backgroundColor).toBe('#000')
    })

    it("`foregroundColor` is a string and it's used", () => {
      // defaultProps
      expect(typeof propsFromEmpty.foregroundColor).toBe('string')
      expect(propsFromEmpty.foregroundColor).toBe('#eee')
      // custom props
      expect(typeof propsFromFullField.foregroundColor).toBe('string')
      expect(propsFromFullField.foregroundColor).toBe('#fff')
    })

    it("`preserveAspectRatio` is a string and it's used", () => {
      // custom props
      expect(typeof propsFromFullField.preserveAspectRatio).toBe('string')
      expect(propsFromFullField.preserveAspectRatio).toBe('xMaxYMax meet')
    })

    it("`style` is an object and it's used", () => {
      // defaultProps
      expect(propsFromEmpty.style).toMatchObject({})
      // custom props
      expect(propsFromFullField.style).toMatchObject({ marginBottom: 10 })
    })

    it("`rtl` is a boolean and it's used", () => {
      // defaultProps
      expect(typeof propsFromEmpty.rtl).toBe('boolean')
      expect(propsFromEmpty.rtl).toBe(false)
      // custom props
      expect(typeof propsFromFullField.rtl).toBe('boolean')
      expect(propsFromFullField.rtl).toBe(true)
    })

    it("`beforeMask` is a JSX Element and it's used", () => {
      // defaultProps
      expect(typeof propsFromEmpty.beforeMask).toBe('object')
      expect(propsFromEmpty.beforeMask).toBe(null)
      // custom props
      expect(typeof propsFromFullField.beforeMask).toBe('object')
      expect(propsFromFullField.beforeMask).toEqual(<Rect />)
    })
  })
})


================================================
FILE: src/native/__tests__/Svg.test.tsx
================================================
import * as React from 'react'
import Svg, { ClipPath, LinearGradient, Stop } from 'react-native-svg'
import * as renderer from 'react-test-renderer'

import ContentLoader, { Rect } from '..'

interface IPredicateArgs {
  type: any
  props: any
}

jest.useFakeTimers()

describe('Svg', () => {
  const wrapper = renderer.create(<ContentLoader animate={false} />).root
  const predicateRectClipPath = ({ type, props }: IPredicateArgs) =>
    type === 'Rect' && props.clipPath
  const partsOfComponent = {
    allLinearGradient: wrapper.findAllByType(LinearGradient),
    allRectClipPath: wrapper.findAll(predicateRectClipPath),
    allStops: wrapper.findAllByType(Stop),
    clipPath: wrapper.findByType(ClipPath),
    linearGradient: wrapper.findByType(LinearGradient),
    rectClipPath: wrapper.find(predicateRectClipPath),
    svg: wrapper.findByType(Svg),
  }

  describe('it has basic elements necessary to work ', () => {
    it('has a `rect` with `clipPath`', () => {
      const { allRectClipPath } = partsOfComponent

      expect(allRectClipPath.length).toBe(1)
    })

    it('has a `linearGradient`', () => {
      const { allLinearGradient } = partsOfComponent

      expect(allLinearGradient.length).toBe(1)
    })

    it('has three `stop`', () => {
      const { allStops } = partsOfComponent

      expect(allStops.length).toBe(3)
    })

    it('has `stop` inside the `linearGradient`', () => {
      const { linearGradient } = partsOfComponent
      const stopsIntoLinearGradient = linearGradient.findAllByType(Stop)

      expect(stopsIntoLinearGradient.length).toBe(3)
    })
  })

  describe('unique key', () => {
    it('render two components with different ids', () => {
      // Wrapper
      const { clipPath, linearGradient } = partsOfComponent

      // Another component
      const anotherComp = renderer.create(<ContentLoader animate={false} />)
        .root
      const anotherClipPath = anotherComp.findByType(ClipPath)
      const anotherLinearGradient = anotherComp.findByType(LinearGradient)

      expect(clipPath.props.id).not.toBe(anotherClipPath.props.id)
      expect(linearGradient.props.id).not.toBe(anotherLinearGradient.props.id)
    })

    it('clipPath id and rect clipPath url are the same', () => {
      const { clipPath, rectClipPath } = partsOfComponent

      expect(rectClipPath.props.clipPath).toBe(`url(#${clipPath.props.id})`)
    })

    it('linearGradient id and rect clipPath fill are the same', () => {
      const { linearGradient, rectClipPath } = partsOfComponent

      expect(rectClipPath.props.fill).toBe(`url(#${linearGradient.props.id})`)
    })
  })

  describe('beforeMask', () => {
    it('beforeMask is used', () => {
      const wrapperWithBeforeMask = renderer.create(
        <ContentLoader beforeMask={<Rect x="123" />} />
      ).root

      const beforeMask = wrapperWithBeforeMask.findByProps({
        x: '123',
      })

      expect(beforeMask.props.x).toBe('123')
    })

    it('beforeMask should be a JSX Element', () => {
      const wrapperWithBeforeMask = renderer.create(
        // @ts-ignore
        <ContentLoader beforeMask={() => <Rect x="123" />} />
      ).root

      expect(() => {
        wrapperWithBeforeMask.findByProps({
          x: '123',
        })
      }).toThrow('No instances found with props: {"x":"123"}')
    })
  })
})


================================================
FILE: src/native/__tests__/__snapshots__/snapshots.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ContentLoader snapshots renders correctly the basic version 1`] = `
<Svg
  height={124}
  interval={0.25}
  style={{}}
  viewBox="0 0 476 124"
  width={476}
>
  <Rect
    clipPath="url(#snapshots-animated-diff)"
    fill="url(#snapshots-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="snapshots-animated-diff"
    >
      <Rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <Rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <Rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <Rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <Rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <Circle
        cx="20"
        cy="20"
        r="20"
      />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="snapshots-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;

exports[`ContentLoader snapshots renders correctly with beforeMask 1`] = `
<Svg
  interval={0.25}
  style={{}}
>
  <Rect
    x="123"
  />
  <Rect
    x="456"
  />
  <Rect
    clipPath="url(#snapshots-animated-diff)"
    fill="url(#snapshots-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="snapshots-animated-diff"
    >
      <Rect />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="snapshots-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;

exports[`ContentLoader snapshots renders correctly with beforeMask 2`] = `
<Svg
  interval={0.25}
  style={{}}
>
  <Rect
    clipPath="url(#snapshots-animated-diff)"
    fill="url(#snapshots-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="snapshots-animated-diff"
    >
      <Rect />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="snapshots-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;

exports[`ContentLoader snapshots renders correctly with viewBox defined 1`] = `
<Svg
  height={124}
  interval={0.25}
  style={{}}
  viewBox="0 0 100 100"
  width={476}
>
  <Rect
    clipPath="url(#snapshots-animated-diff)"
    fill="url(#snapshots-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="snapshots-animated-diff"
    >
      <Rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <Rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <Rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <Rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <Rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <Circle
        cx="20"
        cy="20"
        r="20"
      />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="snapshots-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;

exports[`ContentLoader snapshots renders correctly with viewBox defined and sizes defined too 1`] = `
<Svg
  height={100}
  interval={0.25}
  style={{}}
  viewBox="0 0 100 100"
  width={100}
>
  <Rect
    clipPath="url(#snapshots-animated-diff)"
    fill="url(#snapshots-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="snapshots-animated-diff"
    >
      <Rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <Rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <Rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <Rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <Rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <Circle
        cx="20"
        cy="20"
        r="20"
      />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="snapshots-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;

exports[`ContentLoader snapshots renders correctly with viewBox empty 1`] = `
<Svg
  height={124}
  interval={0.25}
  style={{}}
  viewBox=""
  width={476}
>
  <Rect
    clipPath="url(#snapshots-animated-diff)"
    fill="url(#snapshots-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="snapshots-animated-diff"
    >
      <Rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <Rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <Rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <Rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <Rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <Circle
        cx="20"
        cy="20"
        r="20"
      />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="snapshots-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;


================================================
FILE: src/native/__tests__/presets/BulletListStyle.test.tsx
================================================
import 'react-native'

import * as React from 'react'
import * as renderer from 'react-test-renderer'

import BulletListStyle from '../../presets/BulletListStyle'

jest.useFakeTimers()

describe('BulletListStyle', () => {
  const wrapper = renderer.create(
    <BulletListStyle uniqueKey="BulletListStyle" animate={false} speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
  })
})


================================================
FILE: src/native/__tests__/presets/CodeStyle.test.tsx
================================================
import 'react-native'

import * as React from 'react'
import * as renderer from 'react-test-renderer'

import CodeStyle from '../../presets/CodeStyle'

jest.useFakeTimers()

describe('CodeStyle', () => {
  const wrapper = renderer.create(
    <CodeStyle uniqueKey="CodeStyle" animate={false} speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
  })
})


================================================
FILE: src/native/__tests__/presets/FacebookStyle.test.tsx
================================================
import 'react-native'

import * as React from 'react'
import * as renderer from 'react-test-renderer'

import FacebookStyle from '../../presets/FacebookStyle'

jest.useFakeTimers()

describe('FacebookStyle', () => {
  const wrapper = renderer.create(
    <FacebookStyle uniqueKey="FacebookStyle" animate={false} speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
  })
})


================================================
FILE: src/native/__tests__/presets/InstagramStyle.test.tsx
================================================
import 'react-native'

import * as React from 'react'
import * as renderer from 'react-test-renderer'

import InstagramStyle from '../../presets/InstagramStyle'

jest.useFakeTimers()

describe('InstagramStyle', () => {
  const wrapper = renderer.create(
    <InstagramStyle uniqueKey="InstagramStyle" animate={false} speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
  })
})


================================================
FILE: src/native/__tests__/presets/ListStyle.test.tsx
================================================
import 'react-native'

import * as React from 'react'
import * as renderer from 'react-test-renderer'

import ListStyle from '../../presets/ListStyle'

jest.useFakeTimers()

describe('ListStyle', () => {
  const wrapper = renderer.create(
    <ListStyle uniqueKey="ListStyle" animate={false} speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
  })
})


================================================
FILE: src/native/__tests__/presets/__snapshots__/BulletListStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`BulletListStyle renders correctly 1`] = `
<Svg
  height={125}
  interval={0.25}
  style={{}}
  viewBox="0 0 245 125"
  width={245}
>
  <Rect
    clipPath="url(#BulletListStyle-animated-diff)"
    fill="url(#BulletListStyle-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="BulletListStyle-animated-diff"
    >
      <Circle
        cx="10"
        cy="20"
        r="8"
      />
      <Rect
        height="10"
        rx="5"
        ry="5"
        width="220"
        x="25"
        y="15"
      />
      <Circle
        cx="10"
        cy="50"
        r="8"
      />
      <Rect
        height="10"
        rx="5"
        ry="5"
        width="220"
        x="25"
        y="45"
      />
      <Circle
        cx="10"
        cy="80"
        r="8"
      />
      <Rect
        height="10"
        rx="5"
        ry="5"
        width="220"
        x="25"
        y="75"
      />
      <Circle
        cx="10"
        cy="110"
        r="8"
      />
      <Rect
        height="10"
        rx="5"
        ry="5"
        width="220"
        x="25"
        y="105"
      />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="BulletListStyle-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;


================================================
FILE: src/native/__tests__/presets/__snapshots__/CodeStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CodeStyle renders correctly 1`] = `
<Svg
  height={84}
  interval={0.25}
  style={{}}
  viewBox="0 0 340 84"
  width={340}
>
  <Rect
    clipPath="url(#CodeStyle-animated-diff)"
    fill="url(#CodeStyle-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="CodeStyle-animated-diff"
    >
      <Rect
        height="11"
        rx="3"
        width="67"
        x="0"
        y="0"
      />
      <Rect
        height="11"
        rx="3"
        width="140"
        x="76"
        y="0"
      />
      <Rect
        height="11"
        rx="3"
        width="53"
        x="127"
        y="48"
      />
      <Rect
        height="11"
        rx="3"
        width="72"
        x="187"
        y="48"
      />
      <Rect
        height="11"
        rx="3"
        width="100"
        x="18"
        y="48"
      />
      <Rect
        height="11"
        rx="3"
        width="37"
        x="0"
        y="71"
      />
      <Rect
        height="11"
        rx="3"
        width="140"
        x="18"
        y="23"
      />
      <Rect
        height="11"
        rx="3"
        width="173"
        x="166"
        y="23"
      />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="CodeStyle-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;


================================================
FILE: src/native/__tests__/presets/__snapshots__/FacebookStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`FacebookStyle renders correctly 1`] = `
<Svg
  height={124}
  interval={0.25}
  style={{}}
  viewBox="0 0 476 124"
  width={476}
>
  <Rect
    clipPath="url(#FacebookStyle-animated-diff)"
    fill="url(#FacebookStyle-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="FacebookStyle-animated-diff"
    >
      <Rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <Rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <Rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <Rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <Rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <Circle
        cx="20"
        cy="20"
        r="20"
      />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="FacebookStyle-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;


================================================
FILE: src/native/__tests__/presets/__snapshots__/InstagramStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`InstagramStyle renders correctly 1`] = `
<Svg
  height={460}
  interval={0.25}
  style={{}}
  viewBox="0 0 400 460"
  width={400}
>
  <Rect
    clipPath="url(#InstagramStyle-animated-diff)"
    fill="url(#InstagramStyle-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="InstagramStyle-animated-diff"
    >
      <Circle
        cx="31"
        cy="31"
        r="15"
      />
      <Rect
        height="10"
        rx="2"
        ry="2"
        width="140"
        x="58"
        y="18"
      />
      <Rect
        height="10"
        rx="2"
        ry="2"
        width="140"
        x="58"
        y="34"
      />
      <Rect
        height="400"
        rx="2"
        ry="2"
        width="400"
        x="0"
        y="60"
      />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="InstagramStyle-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;


================================================
FILE: src/native/__tests__/presets/__snapshots__/ListStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ListStyle renders correctly 1`] = `
<Svg
  height={110}
  interval={0.25}
  style={{}}
  viewBox="0 0 400 110"
  width={400}
>
  <Rect
    clipPath="url(#ListStyle-animated-diff)"
    fill="url(#ListStyle-diff)"
    height="100%"
    width="100%"
    x="0"
    y="0"
  />
  <Defs>
    <ClipPath
      id="ListStyle-animated-diff"
    >
      <Rect
        height="10"
        rx="3"
        ry="3"
        width="250"
        x="0"
        y="0"
      />
      <Rect
        height="10"
        rx="3"
        ry="3"
        width="220"
        x="20"
        y="20"
      />
      <Rect
        height="10"
        rx="3"
        ry="3"
        width="170"
        x="20"
        y="40"
      />
      <Rect
        height="10"
        rx="3"
        ry="3"
        width="250"
        x="0"
        y="60"
      />
      <Rect
        height="10"
        rx="3"
        ry="3"
        width="200"
        x="20"
        y="80"
      />
      <Rect
        height="10"
        rx="3"
        ry="3"
        width="80"
        x="20"
        y="100"
      />
    </ClipPath>
    <LinearGradient
      collapsable={false}
      id="ListStyle-diff"
      style={{}}
      x1="-100%"
      x2="0%"
      y1={0}
      y2={0}
    >
      <Stop
        offset={0}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <Stop
        offset={0.5}
        stopColor="#eee"
        stopOpacity={1}
      />
      <Stop
        offset={1}
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
    </LinearGradient>
  </Defs>
</Svg>
`;


================================================
FILE: src/native/__tests__/snapshots.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'

import ContentLoader, { Rect } from '../ContentLoader'

jest.useFakeTimers()

describe('ContentLoader snapshots', () => {
  test('renders correctly the basic version', () => {
    const wrapper = renderer.create(
      <ContentLoader animate={false} uniqueKey="snapshots" />
    )
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('renders correctly with viewBox empty', () => {
    const wrapper = renderer.create(
      <ContentLoader animate={false} uniqueKey="snapshots" viewBox="" />
    )
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('renders correctly with viewBox defined', () => {
    const wrapper = renderer.create(
      <ContentLoader
        animate={false}
        uniqueKey="snapshots"
        viewBox="0 0 100 100"
      />
    )
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('renders correctly with viewBox defined and sizes defined too', () => {
    const wrapper = renderer.create(
      <ContentLoader
        animate={false}
        uniqueKey="snapshots"
        width={100}
        height={100}
        viewBox="0 0 100 100"
      />
    )
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('renders correctly with beforeMask', () => {
    let wrapper = renderer.create(
      <ContentLoader
        uniqueKey="snapshots"
        beforeMask={
          <>
            <Rect x="123" />
            <Rect x="456" />
          </>
        }
      >
        <Rect />
      </ContentLoader>
    )
    let tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()

    // with wrong type
    wrapper = renderer.create(
      // @ts-ignore
      <ContentLoader uniqueKey="snapshots" beforeMask={() => <Rect />}>
        <Rect />
      </ContentLoader>
    )
    tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })
})


================================================
FILE: src/native/index.ts
================================================
import { SvgProps } from 'react-native-svg'

import ContentLoader from './ContentLoader'

export interface IContentLoaderProps extends SvgProps {
  animate?: boolean
  backgroundColor?: string
  backgroundOpacity?: number
  foregroundColor?: string
  foregroundOpacity?: number
  rtl?: boolean
  speed?: number
  interval?: number
  uniqueKey?: string
  beforeMask?: JSX.Element
}

export { default as Facebook } from './presets/FacebookStyle'
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 { Circle, Rect, Path } from './ContentLoader'
export default ContentLoader


================================================
FILE: src/native/package.json
================================================
{
  "name": "react-content-loader/native",
  "private": true,
  "main": "./react-content-loader.native.cjs.js",
  "module": "./react-content-loader.native.es.js",
  "jsnext:main": "./react-content-loader.native.es.js",
  "types": "./native/index.d.ts",
  "dependencies": {
    "react-native-svg": "9.6.4"
  },
  "peerDependencies": {
    "react": "^16.0.0",
    "react-native": "^0.60.5"
  }
}


================================================
FILE: src/native/presets/BulletListStyle.tsx
================================================
import * as React from 'react'
import { IContentLoaderProps } from '..'
import ContentLoader, { Circle, Rect } from '../ContentLoader'

const ReactContentLoaderBulletList: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 245 125" width={245} height={125} {...props}>
    <Circle cx="10" cy="20" r="8" />
    <Rect x="25" y="15" rx="5" ry="5" width="220" height="10" />
    <Circle cx="10" cy="50" r="8" />
    <Rect x="25" y="45" rx="5" ry="5" width="220" height="10" />
    <Circle cx="10" cy="80" r="8" />
    <Rect x="25" y="75" rx="5" ry="5" width="220" height="10" />
    <Circle cx="10" cy="110" r="8" />
    <Rect x="25" y="105" rx="5" ry="5" width="220" height="10" />
  </ContentLoader>
)

export default ReactContentLoaderBulletList


================================================
FILE: src/native/presets/CodeStyle.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from '..'
import ContentLoader, { Rect } from '../ContentLoader'

const ReactContentLoaderCode: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 340 84" width={340} height={84} {...props}>
    <Rect x="0" y="0" width="67" height="11" rx="3" />
    <Rect x="76" y="0" width="140" height="11" rx="3" />
    <Rect x="127" y="48" width="53" height="11" rx="3" />
    <Rect x="187" y="48" width="72" height="11" rx="3" />
    <Rect x="18" y="48" width="100" height="11" rx="3" />
    <Rect x="0" y="71" width="37" height="11" rx="3" />
    <Rect x="18" y="23" width="140" height="11" rx="3" />
    <Rect x="166" y="23" width="173" height="11" rx="3" />
  </ContentLoader>
)

export default ReactContentLoaderCode


================================================
FILE: src/native/presets/FacebookStyle.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from '..'
import ContentLoader, { Circle, Rect } from '../ContentLoader'

const ReactContentLoaderFacebook: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 476 124" width={476} height={124} {...props}>
    <Rect x="48" y="8" width="88" height="6" rx="3" />
    <Rect x="48" y="26" width="52" height="6" rx="3" />
    <Rect x="0" y="56" width="410" height="6" rx="3" />
    <Rect x="0" y="72" width="380" height="6" rx="3" />
    <Rect x="0" y="88" width="178" height="6" rx="3" />
    <Circle cx="20" cy="20" r="20" />
  </ContentLoader>
)

export default ReactContentLoaderFacebook


================================================
FILE: src/native/presets/InstagramStyle.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from '..'
import ContentLoader, { Circle, Rect } from '../ContentLoader'

const ReactContentLoaderInstagram: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 400 460" width={400} height={460} {...props}>
    <Circle cx="31" cy="31" r="15" />
    <Rect x="58" y="18" rx="2" ry="2" width="140" height="10" />
    <Rect x="58" y="34" rx="2" ry="2" width="140" height="10" />
    <Rect x="0" y="60" rx="2" ry="2" width="400" height="400" />
  </ContentLoader>
)

export default ReactContentLoaderInstagram


================================================
FILE: src/native/presets/ListStyle.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from '..'
import ContentLoader, { Rect } from '../ContentLoader'

const ReactContentLoaderListStyle: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 400 110" width={400} height={110} {...props}>
    <Rect x="0" y="0" rx="3" ry="3" width="250" height="10" />
    <Rect x="20" y="20" rx="3" ry="3" width="220" height="10" />
    <Rect x="20" y="40" rx="3" ry="3" width="170" height="10" />
    <Rect x="0" y="60" rx="3" ry="3" width="250" height="10" />
    <Rect x="20" y="80" rx="3" ry="3" width="200" height="10" />
    <Rect x="20" y="100" rx="3" ry="3" width="80" height="10" />
  </ContentLoader>
)

export default ReactContentLoaderListStyle


================================================
FILE: src/shared/uid.ts
================================================
export default (): string =>
  Math.random()
    .toString(36)
    .substring(6)


================================================
FILE: src/web/ContentLoader.tsx
================================================
import * as React from 'react'

import { Facebook, IContentLoaderProps } from '.'
import Svg from './Svg'

const ContentLoader: React.FC<IContentLoaderProps> = props =>
  props.children ? <Svg {...props} /> : <Facebook {...props} />

export default ContentLoader


================================================
FILE: src/web/Svg.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from './'

const SVG: React.FC<IContentLoaderProps> = ({
  animate = true,
  backgroundColor = '#f5f6f7',
  backgroundOpacity = 1,
  baseUrl = '',
  children,
  foregroundColor = '#eee',
  foregroundOpacity = 1,
  gradientRatio = 2,
  uniqueKey,
  rtl = false,
  speed = 1.2,
  style = {},
  title = 'Loading...',
  beforeMask = null,
  ...props
}) => {
  let fixedId = React.useId()
  if (uniqueKey) fixedId = uniqueKey
  const idClip = `${fixedId}-diff`
  const idGradient = `${fixedId}-animated-diff`
  const idAria = `${fixedId}-aria`

  const rtlStyle = rtl ? { transform: 'scaleX(-1)' } : null
  const dur = `${speed}s`

  const from = `${gradientRatio * -1} 0`
  const to = `${gradientRatio} 0`

  return (
    <svg
      aria-labelledby={idAria}
      role="img"
      style={{ ...style, ...rtlStyle }}
      {...props}
    >
      {title ? <title id={idAria}>{title}</title> : null}
      {beforeMask && React.isValidElement(beforeMask) ? beforeMask : null}
      <rect
        role="presentation"
        x="0"
        y="0"
        width="100%"
        height="100%"
        clipPath={`url(${baseUrl}#${idClip})`}
        style={{ fill: `url(${baseUrl}#${idGradient})` }}
      />

      <defs>
        <clipPath id={idClip}>{children}</clipPath>

        <linearGradient
          id={idGradient}
          gradientTransform={`translate(${from})`}
        >
          <stop
            offset="0%"
            stopColor={backgroundColor}
            stopOpacity={backgroundOpacity}
          />

          <stop
            offset="50%"
            stopColor={foregroundColor}
            stopOpacity={foregroundOpacity}
          />

          <stop
            offset="100%"
            stopColor={backgroundColor}
            stopOpacity={backgroundOpacity}
          />

          {animate && (
            <animateTransform
              attributeName="gradientTransform"
              type="translate"
              values={`${from}; 0 0; ${to}`}
              dur={dur}
              repeatCount="indefinite"
            />
          )}
        </linearGradient>
      </defs>
    </svg>
  )
}

export default SVG


================================================
FILE: src/web/__tests__/ContentLoader.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'
import * as ShallowRenderer from 'react-test-renderer/shallow'

import ContentLoader from '../ContentLoader'

describe('ContentLoader', () => {
  describe('when type is custom', () => {
    const customWrapper = renderer.create(
      <ContentLoader>
        <rect x="80" y="17" rx="4" ry="4" width="300" height="13" />
        <rect x="82" y="44" rx="3" ry="3" width="250" height="10" />
        <circle cx="35" cy="35" r="35" />
      </ContentLoader>
    ).root

    it('should render custom element', () => {
      const rect = customWrapper.findAllByType('rect')
      const circle = customWrapper.findAllByType('circle')

      expect(rect.length).toBe(3)
      expect(circle.length).toBe(1)
    })
  })

  describe('Props are propagated', () => {
    const noPropsComponent = ShallowRenderer.createRenderer()
    noPropsComponent.render(
      <ContentLoader>
        <rect />
      </ContentLoader>
    )

    const withPropsComponent = ShallowRenderer.createRenderer()
    withPropsComponent.render(
      <ContentLoader
        animate={false}
        backgroundColor="#000"
        backgroundOpacity={0.06}
        baseUrl="/mypage"
        foregroundColor="#fff"
        foregroundOpacity={0.12}
        gradientRatio={0.5}
        height={200}
        preserveAspectRatio="xMaxYMax meet"
        rtl
        speed={10}
        style={{ marginBottom: '10px' }}
        title="My custom loading title"
        uniqueKey="my-id"
        width={200}
        beforeMask={<rect />}
      >
        <rect />
      </ContentLoader>
    )

    const { props: propsFromFullfield } = withPropsComponent.getRenderOutput()

    it("`speed` is a number and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.speed).toBe('number')
      expect(propsFromFullfield.speed).toBe(10)
    })

    it("`height` is a number and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.height).toBe('number')
      expect(propsFromFullfield.height).toBe(200)
    })

    it("`width` is a number and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.width).toBe('number')
      expect(propsFromFullfield.width).toBe(200)
    })

    it("`gradientRatio` is a number and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.gradientRatio).toBe('number')
      expect(propsFromFullfield.gradientRatio).toBe(0.5)
    })

    it("`animate` is a boolean and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.animate).toBe('boolean')
      expect(propsFromFullfield.animate).toBe(false)
    })

    it("`backgroundColor` is a string and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.backgroundColor).toBe('string')
      expect(propsFromFullfield.backgroundColor).toBe('#000')
    })

    it("`foregroundColor` is a string and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.foregroundColor).toBe('string')
      expect(propsFromFullfield.foregroundColor).toBe('#fff')
    })

    it("`backgroundOpacity` is a number and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.backgroundOpacity).toBe('number')
      expect(propsFromFullfield.backgroundOpacity).toBe(0.06)
    })

    it("`foregroundOpacity` is a number and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.foregroundOpacity).toBe('number')
      expect(propsFromFullfield.foregroundOpacity).toBe(0.12)
    })

    it("`preserveAspectRatio` is a string and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.preserveAspectRatio).toBe('string')
      expect(propsFromFullfield.preserveAspectRatio).toBe('xMaxYMax meet')
    })

    it("`style` is an object and it's used", () => {
      // custom props
      expect(propsFromFullfield.style).toMatchObject({ marginBottom: '10px' })
    })

    it("`rtl` is a boolean and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.rtl).toBe('boolean')
      expect(propsFromFullfield.rtl).toBe(true)
    })

    it("`title` is a string and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.title).toBe('string')
      expect(propsFromFullfield.title).toBe('My custom loading title')
    })

    it("`baseUrl` is a string and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.baseUrl).toBe('string')
      expect(propsFromFullfield.baseUrl).toBe('/mypage')
    })

    it("`uniqueKey` is a string and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.uniqueKey).toBe('string')
      expect(propsFromFullfield.uniqueKey).toBe('my-id')
    })

    it("`beforeMask` is a JSX Element and it's used", () => {
      // custom props
      expect(typeof propsFromFullfield.beforeMask).toBe('object')
      expect(propsFromFullfield.beforeMask).toEqual(<rect />)
    })
  })
})


================================================
FILE: src/web/__tests__/Svg.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'

import Svg from '..'

interface PredicateArgs {
  type: any
  props: any
}

describe('Svg', () => {
  const wrapper = renderer.create(<Svg />).root
  const predicateRectClipPath = ({ type, props }: PredicateArgs) =>
    type === 'rect' && props.clipPath
  const partsOfComponent = {
    allLinearGradient: wrapper.findAllByType('linearGradient'),
    allRectClipPath: wrapper.findAll(predicateRectClipPath),
    allStops: wrapper.findAllByType('stop'),
    clipPath: wrapper.findByType('clipPath'),
    linearGradient: wrapper.findByType('linearGradient'),
    rectClipPath: wrapper.find(predicateRectClipPath),
    svg: wrapper.findByType('svg'),
    title: wrapper.findByType('title'),
  }

  it('`baseUrl` is used correctly', () => {
    const baseUrl = '/page-path'
    const wrapperWithBaseUrl = renderer.create(<Svg baseUrl={baseUrl} />).root

    const clipPath = wrapperWithBaseUrl.findByType('clipPath')
    const linearGradient = wrapperWithBaseUrl.findByType('linearGradient')
    const rectClipPath = wrapperWithBaseUrl.find(predicateRectClipPath)

    expect(rectClipPath.props.clipPath).toBe(
      `url(${baseUrl}#${clipPath.props.id})`
    )
    expect(rectClipPath.props.style.fill).toBe(
      `url(${baseUrl}#${linearGradient.props.id})`
    )
  })

  describe('it has basic elements necessary to work ', () => {
    it('has a `rect` with `clipPath`', () => {
      const { allRectClipPath } = partsOfComponent

      expect(allRectClipPath.length).toBe(1)
    })

    it('has a `linearGradient`', () => {
      const { allLinearGradient } = partsOfComponent

      expect(allLinearGradient.length).toBe(1)
    })

    it('has three `stop`', () => {
      const { allStops } = partsOfComponent

      expect(allStops.length).toBe(3)
    })

    it('has `stop` inside the `linearGradient`', () => {
      const { linearGradient } = partsOfComponent
      const stopsIntoLinearGradient = linearGradient.findAllByType('stop')

      expect(stopsIntoLinearGradient.length).toBe(3)
    })
  })

  describe('unique key', () => {
    it('`id` does not generate undefined `id` values for SVG', () => {
      const { clipPath, linearGradient } = partsOfComponent

      expect(clipPath.props.id).not.toBe(undefined)
      expect(linearGradient.props.id).not.toBe(undefined)
    })

    it('custom `id` is used', () => {
      const id = 'my-unique-key'
      const wrapperid = renderer.create(<Svg uniqueKey={id} />)

      const clipPath = wrapperid.root.findByType('clipPath')
      const linearGradient = wrapperid.root.findByType('linearGradient')

      expect(clipPath.props.id).toBe(`${id}-diff`)
      expect(linearGradient.props.id).toBe(`${id}-animated-diff`)
    })

    it('render two components with different ids', () => {
      // Wrapper
      const { clipPath, linearGradient } = partsOfComponent

      // Another component
      const anotherComp = renderer.create(<Svg />).root
      const anotherClipPath = anotherComp.findByType('clipPath')
      const anotherLinearGradient = anotherComp.findByType('linearGradient')

      expect(clipPath.props.id).not.toBe(anotherClipPath.props.id)
      expect(linearGradient.props.id).not.toBe(anotherLinearGradient.props.id)
    })

    it('clipPath id and rect clipPath url are the same', () => {
      const { clipPath, rectClipPath } = partsOfComponent

      expect(rectClipPath.props.clipPath).toBe(`url(#${clipPath.props.id})`)
    })

    it('linearGradient id and rect clipPath fill are the same', () => {
      const { linearGradient, rectClipPath } = partsOfComponent

      expect(rectClipPath.props.style.fill).toBe(
        `url(#${linearGradient.props.id})`
      )
    })
  })

  describe('a11y', () => {
    it('svg has aria-labelledby', () => {
      const { svg } = partsOfComponent

      expect(typeof svg.props['aria-labelledby']).toBe('string')
      expect(svg.props['aria-labelledby'].length).not.toBe(0)
    })

    it('aria-labelledby point to title', () => {
      const { svg } = partsOfComponent
      const ariaId = svg.props['aria-labelledby']

      const title = wrapper.findByType('title')
      expect(title.props.id).toBe(ariaId)
    })

    it('svg has role', () => {
      const { svg } = partsOfComponent

      expect(typeof svg.props['role']).toBe('string')
      expect(svg.props['role']).toBe('img')
    })

    it('svg has a title', () => {
      const { title } = partsOfComponent

      expect(typeof title.props.children).toBe('string')
      expect(title.props.children.length).not.toBe(0)
    })
  })

  describe('beforeMask', () => {
    it('beforeMask is used', () => {
      const wrapperWithBeforeMask = renderer.create(
        <Svg beforeMask={<rect role="beforeMask" />} />
      ).root

      const beforeMask = wrapperWithBeforeMask.findByProps({
        role: 'beforeMask',
      })

      expect(beforeMask.props.role).toBe('beforeMask')
    })

    it('beforeMask should be a JSX Element', () => {
      const wrapperWithBeforeMask = renderer.create(
        // @ts-ignore
        <Svg beforeMask={() => <rect role="beforeMask" />} />
      ).root

      expect(() => {
        wrapperWithBeforeMask.findByProps({
          role: 'beforeMask',
        })
      }).toThrow('No instances found with props: {"role":"beforeMask"}')
    })
  })
})


================================================
FILE: src/web/__tests__/__snapshots__/snapshots.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ContentLoader snapshots renders correctly the basic version 1`] = `
<svg
  aria-labelledby="snapshots-aria"
  role="img"
  style={{}}
  viewBox="0 0 476 124"
>
  <title
    id="snapshots-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#snapshots-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#snapshots-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="snapshots-diff"
    >
      <rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <circle
        cx="20"
        cy="20"
        r="20"
      />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="snapshots-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="1.2s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;

exports[`ContentLoader snapshots renders correctly with beforeMask 1`] = `
<svg
  aria-labelledby="snapshots-aria"
  role="img"
  style={{}}
>
  <title
    id="snapshots-aria"
  >
    Loading...
  </title>
  <rect
    role="outline1"
  />
  <rect
    role="outline2"
  />
  <rect
    clipPath="url(#snapshots-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#snapshots-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="snapshots-diff"
    >
      <rect />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="snapshots-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="1.2s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;

exports[`ContentLoader snapshots renders correctly with beforeMask 2`] = `
<svg
  aria-labelledby="snapshots-aria"
  role="img"
  style={{}}
>
  <title
    id="snapshots-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#snapshots-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#snapshots-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="snapshots-diff"
    >
      <rect />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="snapshots-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="1.2s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;

exports[`ContentLoader snapshots renders correctly with viewBox defined 1`] = `
<svg
  aria-labelledby="snapshots-aria"
  role="img"
  style={{}}
  viewBox="0 0 100 100"
>
  <title
    id="snapshots-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#snapshots-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#snapshots-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="snapshots-diff"
    >
      <rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <circle
        cx="20"
        cy="20"
        r="20"
      />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="snapshots-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="1.2s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;

exports[`ContentLoader snapshots renders correctly with viewBox defined and sizes defined too 1`] = `
<svg
  aria-labelledby="snapshots-aria"
  height={100}
  role="img"
  style={{}}
  viewBox="0 0 100 100"
  width={100}
>
  <title
    id="snapshots-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#snapshots-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#snapshots-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="snapshots-diff"
    >
      <rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <circle
        cx="20"
        cy="20"
        r="20"
      />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="snapshots-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="1.2s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;

exports[`ContentLoader snapshots renders correctly with viewBox empty 1`] = `
<svg
  aria-labelledby="snapshots-aria"
  role="img"
  style={{}}
  viewBox=""
>
  <title
    id="snapshots-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#snapshots-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#snapshots-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="snapshots-diff"
    >
      <rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <circle
        cx="20"
        cy="20"
        r="20"
      />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="snapshots-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="1.2s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;


================================================
FILE: src/web/__tests__/index.test.tsx
================================================
/**
 * @jest-environment jsdom
 */

import * as React from 'react'
import * as ReactDOM from 'react-dom'

import ContentLoader from '..'

describe('index', () => {
  const div = document.createElement('div')
  div.id = 'root'
  document.body.appendChild(div)

  it('renders', () => {
    ReactDOM.render(<ContentLoader />, document.getElementById('root'))
  })

  it('renders a SVG as root element ', () => {
    ReactDOM.render(<ContentLoader />, document.getElementById('root'))
    const svgElement = document
      .getElementById('root')
      .getElementsByTagName('svg')

    expect(svgElement.length).toBe(1)
  })
})


================================================
FILE: src/web/__tests__/presets/BulletListStyle.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'

import BulletListStyle from '../../presets/BulletListStyle'

describe('BulletListStyle', () => {
  const wrapper = renderer.create(
    <BulletListStyle uniqueKey="BulletListStyle" speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
    expect(wrapper.root.props.uniqueKey).toEqual('BulletListStyle')
  })
})


================================================
FILE: src/web/__tests__/presets/CodeStyle.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'

import CodeStyle from '../../presets/CodeStyle'

describe('CodeStyle', () => {
  const wrapper = renderer.create(
    <CodeStyle uniqueKey="CodeStyle" speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
    expect(wrapper.root.props.uniqueKey).toEqual('CodeStyle')
  })
})


================================================
FILE: src/web/__tests__/presets/FacebookStyle.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'

import FacebookStyle from '../../presets/FacebookStyle'

describe('FacebookStyle', () => {
  const wrapper = renderer.create(
    <FacebookStyle uniqueKey="FacebookStyle" speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
    expect(wrapper.root.props.uniqueKey).toEqual('FacebookStyle')
  })
})


================================================
FILE: src/web/__tests__/presets/InstagramStyle.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'

import InstagramStyle from '../../presets/InstagramStyle'

describe('InstagramStyle', () => {
  const wrapper = renderer.create(
    <InstagramStyle uniqueKey="InstagramStyle" speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
    expect(wrapper.root.props.uniqueKey).toEqual('InstagramStyle')
  })
})


================================================
FILE: src/web/__tests__/presets/ListStyle.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'

import ListStyle from '../../presets/ListStyle'

describe('ListStyle', () => {
  const wrapper = renderer.create(
    <ListStyle uniqueKey="ListStyle" speed={20} />
  )

  test('renders correctly', () => {
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('props are propagated ', () => {
    expect(wrapper.root.props.speed).toEqual(20)
    expect(wrapper.root.props.uniqueKey).toEqual('ListStyle')
  })
})


================================================
FILE: src/web/__tests__/presets/__snapshots__/BulletListStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`BulletListStyle renders correctly 1`] = `
<svg
  aria-labelledby="BulletListStyle-aria"
  role="img"
  style={{}}
  viewBox="0 0 245 125"
>
  <title
    id="BulletListStyle-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#BulletListStyle-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#BulletListStyle-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="BulletListStyle-diff"
    >
      <circle
        cx="10"
        cy="20"
        r="8"
      />
      <rect
        height="10"
        rx="5"
        ry="5"
        width="220"
        x="25"
        y="15"
      />
      <circle
        cx="10"
        cy="50"
        r="8"
      />
      <rect
        height="10"
        rx="5"
        ry="5"
        width="220"
        x="25"
        y="45"
      />
      <circle
        cx="10"
        cy="80"
        r="8"
      />
      <rect
        height="10"
        rx="5"
        ry="5"
        width="220"
        x="25"
        y="75"
      />
      <circle
        cx="10"
        cy="110"
        r="8"
      />
      <rect
        height="10"
        rx="5"
        ry="5"
        width="220"
        x="25"
        y="105"
      />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="BulletListStyle-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="20s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;


================================================
FILE: src/web/__tests__/presets/__snapshots__/CodeStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CodeStyle renders correctly 1`] = `
<svg
  aria-labelledby="CodeStyle-aria"
  role="img"
  style={{}}
  viewBox="0 0 340 84"
>
  <title
    id="CodeStyle-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#CodeStyle-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#CodeStyle-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="CodeStyle-diff"
    >
      <rect
        height="11"
        rx="3"
        width="67"
        x="0"
        y="0"
      />
      <rect
        height="11"
        rx="3"
        width="140"
        x="76"
        y="0"
      />
      <rect
        height="11"
        rx="3"
        width="53"
        x="127"
        y="48"
      />
      <rect
        height="11"
        rx="3"
        width="72"
        x="187"
        y="48"
      />
      <rect
        height="11"
        rx="3"
        width="100"
        x="18"
        y="48"
      />
      <rect
        height="11"
        rx="3"
        width="37"
        x="0"
        y="71"
      />
      <rect
        height="11"
        rx="3"
        width="140"
        x="18"
        y="23"
      />
      <rect
        height="11"
        rx="3"
        width="173"
        x="166"
        y="23"
      />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="CodeStyle-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="20s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;


================================================
FILE: src/web/__tests__/presets/__snapshots__/FacebookStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`FacebookStyle renders correctly 1`] = `
<svg
  aria-labelledby="FacebookStyle-aria"
  role="img"
  style={{}}
  viewBox="0 0 476 124"
>
  <title
    id="FacebookStyle-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#FacebookStyle-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#FacebookStyle-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="FacebookStyle-diff"
    >
      <rect
        height="6"
        rx="3"
        width="88"
        x="48"
        y="8"
      />
      <rect
        height="6"
        rx="3"
        width="52"
        x="48"
        y="26"
      />
      <rect
        height="6"
        rx="3"
        width="410"
        x="0"
        y="56"
      />
      <rect
        height="6"
        rx="3"
        width="380"
        x="0"
        y="72"
      />
      <rect
        height="6"
        rx="3"
        width="178"
        x="0"
        y="88"
      />
      <circle
        cx="20"
        cy="20"
        r="20"
      />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="FacebookStyle-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="20s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;


================================================
FILE: src/web/__tests__/presets/__snapshots__/InstagramStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`InstagramStyle renders correctly 1`] = `
<svg
  aria-labelledby="InstagramStyle-aria"
  role="img"
  style={{}}
  viewBox="0 0 400 460"
>
  <title
    id="InstagramStyle-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#InstagramStyle-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#InstagramStyle-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="InstagramStyle-diff"
    >
      <circle
        cx="31"
        cy="31"
        r="15"
      />
      <rect
        height="10"
        rx="2"
        ry="2"
        width="140"
        x="58"
        y="18"
      />
      <rect
        height="10"
        rx="2"
        ry="2"
        width="140"
        x="58"
        y="34"
      />
      <rect
        height="400"
        rx="2"
        ry="2"
        width="400"
        x="0"
        y="60"
      />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="InstagramStyle-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="20s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;


================================================
FILE: src/web/__tests__/presets/__snapshots__/ListStyle.test.tsx.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ListStyle renders correctly 1`] = `
<svg
  aria-labelledby="ListStyle-aria"
  role="img"
  style={{}}
  viewBox="0 0 400 110"
>
  <title
    id="ListStyle-aria"
  >
    Loading...
  </title>
  <rect
    clipPath="url(#ListStyle-diff)"
    height="100%"
    role="presentation"
    style={
      {
        "fill": "url(#ListStyle-animated-diff)",
      }
    }
    width="100%"
    x="0"
    y="0"
  />
  <defs>
    <clipPath
      id="ListStyle-diff"
    >
      <rect
        height="10"
        rx="3"
        ry="3"
        width="250"
        x="0"
        y="0"
      />
      <rect
        height="10"
        rx="3"
        ry="3"
        width="220"
        x="20"
        y="20"
      />
      <rect
        height="10"
        rx="3"
        ry="3"
        width="170"
        x="20"
        y="40"
      />
      <rect
        height="10"
        rx="3"
        ry="3"
        width="250"
        x="0"
        y="60"
      />
      <rect
        height="10"
        rx="3"
        ry="3"
        width="200"
        x="20"
        y="80"
      />
      <rect
        height="10"
        rx="3"
        ry="3"
        width="80"
        x="20"
        y="100"
      />
    </clipPath>
    <linearGradient
      gradientTransform="translate(-2 0)"
      id="ListStyle-animated-diff"
    >
      <stop
        offset="0%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <stop
        offset="50%"
        stopColor="#eee"
        stopOpacity={1}
      />
      <stop
        offset="100%"
        stopColor="#f5f6f7"
        stopOpacity={1}
      />
      <animateTransform
        attributeName="gradientTransform"
        dur="20s"
        repeatCount="indefinite"
        type="translate"
        values="-2 0; 0 0; 2 0"
      />
    </linearGradient>
  </defs>
</svg>
`;


================================================
FILE: src/web/__tests__/snapshots.test.tsx
================================================
import * as React from 'react'
import * as renderer from 'react-test-renderer'

import ContentLoader from '../ContentLoader'

describe('ContentLoader snapshots', () => {
  test('renders correctly the basic version', () => {
    const wrapper = renderer.create(<ContentLoader uniqueKey="snapshots" />)
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('renders correctly with viewBox empty', () => {
    const wrapper = renderer.create(
      <ContentLoader uniqueKey="snapshots" viewBox="" />
    )
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('renders correctly with viewBox defined', () => {
    const wrapper = renderer.create(
      <ContentLoader uniqueKey="snapshots" viewBox="0 0 100 100" />
    )
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('renders correctly with viewBox defined and sizes defined too', () => {
    const wrapper = renderer.create(
      <ContentLoader
        uniqueKey="snapshots"
        width={100}
        height={100}
        viewBox="0 0 100 100"
      />
    )
    const tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })

  test('renders correctly with beforeMask', () => {
    let wrapper = renderer.create(
      <ContentLoader
        uniqueKey="snapshots"
        beforeMask={
          <>
            <rect role="outline1" />
            <rect role="outline2" />
          </>
        }
      >
        <rect />
      </ContentLoader>
    )
    let tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()

    // with wrong type
    wrapper = renderer.create(
      // @ts-ignore
      <ContentLoader uniqueKey="snapshots" beforeMask={() => <rect />}>
        <rect />
      </ContentLoader>
    )
    tree = wrapper.toJSON()

    expect(tree).toMatchSnapshot()
  })
})


================================================
FILE: src/web/__tests__/uid.test.tsx
================================================
import uid from '../../shared/uid'

describe('unique id', () => {
  const options = 100
  // @ts-ignore To avoid adding polyfill for `fill` becoz fill is ES6 feature and our target is ES5
  const ids = new Array(options).fill(' ').map(() => uid())
  // @ts-ignore To avoid adding polyfill for `from`
  const unique = Array.from(new Set(ids))

  it(`should have ${options} diferents ids`, () => {
    expect(unique.length).toBe(options)
  })

  it(`return a string`, () => {
    expect(typeof uid()).toBe('string')
  })
})


================================================
FILE: src/web/index.ts
================================================
import { SVGAttributes, ReactElement } from 'react'

import ContentLoader from './ContentLoader'

export interface IContentLoaderProps extends SVGAttributes<SVGElement> {
  animate?: boolean
  backgroundColor?: string
  backgroundOpacity?: number
  baseUrl?: string
  foregroundColor?: string
  foregroundOpacity?: number
  gradientRatio?: number
  rtl?: boolean
  speed?: number
  title?: string
  uniqueKey?: string
  beforeMask?: ReactElement
}

export { default as Facebook } from './presets/FacebookStyle'
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 default ContentLoader


================================================
FILE: src/web/presets/BulletListStyle.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from '..'
import ContentLoader from '../ContentLoader'

const ReactContentLoaderBulletList: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 245 125" {...props}>
    <circle cx="10" cy="20" r="8" />
    <rect x="25" y="15" rx="5" ry="5" width="220" height="10" />
    <circle cx="10" cy="50" r="8" />
    <rect x="25" y="45" rx="5" ry="5" width="220" height="10" />
    <circle cx="10" cy="80" r="8" />
    <rect x="25" y="75" rx="5" ry="5" width="220" height="10" />
    <circle cx="10" cy="110" r="8" />
    <rect x="25" y="105" rx="5" ry="5" width="220" height="10" />
  </ContentLoader>
)

export default ReactContentLoaderBulletList


================================================
FILE: src/web/presets/CodeStyle.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from '..'
import ContentLoader from '../ContentLoader'

const ReactContentLoaderCode: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 340 84" {...props}>
    <rect x="0" y="0" width="67" height="11" rx="3" />
    <rect x="76" y="0" width="140" height="11" rx="3" />
    <rect x="127" y="48" width="53" height="11" rx="3" />
    <rect x="187" y="48" width="72" height="11" rx="3" />
    <rect x="18" y="48" width="100" height="11" rx="3" />
    <rect x="0" y="71" width="37" height="11" rx="3" />
    <rect x="18" y="23" width="140" height="11" rx="3" />
    <rect x="166" y="23" width="173" height="11" rx="3" />
  </ContentLoader>
)

export default ReactContentLoaderCode


================================================
FILE: src/web/presets/FacebookStyle.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from '..'
import ContentLoader from '../ContentLoader'

const ReactContentLoaderFacebook: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 476 124" {...props}>
    <rect x="48" y="8" width="88" height="6" rx="3" />
    <rect x="48" y="26" width="52" height="6" rx="3" />
    <rect x="0" y="56" width="410" height="6" rx="3" />
    <rect x="0" y="72" width="380" height="6" rx="3" />
    <rect x="0" y="88" width="178" height="6" rx="3" />
    <circle cx="20" cy="20" r="20" />
  </ContentLoader>
)

export default ReactContentLoaderFacebook


================================================
FILE: src/web/presets/InstagramStyle.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from '..'
import ContentLoader from '../ContentLoader'

const ReactContentLoaderInstagram: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 400 460" {...props}>
    <circle cx="31" cy="31" r="15" />
    <rect x="58" y="18" rx="2" ry="2" width="140" height="10" />
    <rect x="58" y="34" rx="2" ry="2" width="140" height="10" />
    <rect x="0" y="60" rx="2" ry="2" width="400" height="400" />
  </ContentLoader>
)

export default ReactContentLoaderInstagram


================================================
FILE: src/web/presets/ListStyle.tsx
================================================
import * as React from 'react'

import { IContentLoaderProps } from '..'
import ContentLoader from '../ContentLoader'

const ReactContentLoaderListStyle: React.FC<IContentLoaderProps> = props => (
  <ContentLoader viewBox="0 0 400 110" {...props}>
    <rect x="0" y="0" rx="3" ry="3" width="250" height="10" />
    <rect x="20" y="20" rx="3" ry="3" width="220" height="10" />
    <rect x="20" y="40" rx="3" ry="3" width="170" height="10" />
    <rect x="0" y="60" rx="3" ry="3" width="250" height="10" />
    <rect x="20" y="80" rx="3" ry="3" width="200" height="10" />
    <rect x="20" y="100" rx="3" ry="3" width="80" height="10" />
  </ContentLoader>
)

export default ReactContentLoaderListStyle


================================================
FILE: tsconfig.base.json
================================================
{
  "compilerOptions": {
    "declaration": true,
    "declarationDir": "./dist/types",
    "declarationMap": true,
    "esModuleInterop": true,
    "jsx": "react",
    "lib": ["es6", "dom"],
    "noEmit": true,
    "noImplicitAny": false,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "target": "es5"
  },
  "include": ["./src/**/*"],
  "exclude": ["node_modules", "src/web/__tests__"]
}


================================================
FILE: tsconfig.json
================================================
{
  "extends": "./tsconfig.base.json"
}


================================================
FILE: tsconfig.test.json
================================================
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "lib": ["dom"]
  }
}
Download .txt
gitextract_btxfd3lk/

├── .codesandbox/
│   └── tasks.json
├── .devcontainer/
│   └── devcontainer.json
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── .gitignore
├── .prettierrc.js
├── .storybook/
│   ├── main.ts
│   ├── preview-head.html
│   └── preview.tsx
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── __mocks__/
│   └── react-native-svg.js
├── babel.config.js
├── docs/
│   └── index.stories.tsx
├── jest.native.config.js
├── jest.web.config.js
├── package.json
├── rollup.config.js
├── src/
│   ├── native/
│   │   ├── ContentLoader.tsx
│   │   ├── Svg.tsx
│   │   ├── __tests__/
│   │   │   ├── ContentLoader.test.tsx
│   │   │   ├── Svg.test.tsx
│   │   │   ├── __snapshots__/
│   │   │   │   └── snapshots.test.tsx.snap
│   │   │   ├── presets/
│   │   │   │   ├── BulletListStyle.test.tsx
│   │   │   │   ├── CodeStyle.test.tsx
│   │   │   │   ├── FacebookStyle.test.tsx
│   │   │   │   ├── InstagramStyle.test.tsx
│   │   │   │   ├── ListStyle.test.tsx
│   │   │   │   └── __snapshots__/
│   │   │   │       ├── BulletListStyle.test.tsx.snap
│   │   │   │       ├── CodeStyle.test.tsx.snap
│   │   │   │       ├── FacebookStyle.test.tsx.snap
│   │   │   │       ├── InstagramStyle.test.tsx.snap
│   │   │   │       └── ListStyle.test.tsx.snap
│   │   │   └── snapshots.test.tsx
│   │   ├── index.ts
│   │   ├── package.json
│   │   └── presets/
│   │       ├── BulletListStyle.tsx
│   │       ├── CodeStyle.tsx
│   │       ├── FacebookStyle.tsx
│   │       ├── InstagramStyle.tsx
│   │       └── ListStyle.tsx
│   ├── shared/
│   │   └── uid.ts
│   └── web/
│       ├── ContentLoader.tsx
│       ├── Svg.tsx
│       ├── __tests__/
│       │   ├── ContentLoader.test.tsx
│       │   ├── Svg.test.tsx
│       │   ├── __snapshots__/
│       │   │   └── snapshots.test.tsx.snap
│       │   ├── index.test.tsx
│       │   ├── presets/
│       │   │   ├── BulletListStyle.test.tsx
│       │   │   ├── CodeStyle.test.tsx
│       │   │   ├── FacebookStyle.test.tsx
│       │   │   ├── InstagramStyle.test.tsx
│       │   │   ├── ListStyle.test.tsx
│       │   │   └── __snapshots__/
│       │   │       ├── BulletListStyle.test.tsx.snap
│       │   │       ├── CodeStyle.test.tsx.snap
│       │   │       ├── FacebookStyle.test.tsx.snap
│       │   │       ├── InstagramStyle.test.tsx.snap
│       │   │       └── ListStyle.test.tsx.snap
│       │   ├── snapshots.test.tsx
│       │   └── uid.test.tsx
│       ├── index.ts
│       └── presets/
│           ├── BulletListStyle.tsx
│           ├── CodeStyle.tsx
│           ├── FacebookStyle.tsx
│           ├── InstagramStyle.tsx
│           └── ListStyle.tsx
├── tsconfig.base.json
├── tsconfig.json
└── tsconfig.test.json
Download .txt
SYMBOL INDEX (9 symbols across 6 files)

FILE: __mocks__/react-native-svg.js
  method render (line 8) | render() {

FILE: src/native/Svg.tsx
  class NativeSvg (line 16) | class NativeSvg extends Component<IContentLoaderProps> {
    method componentDidUpdate (line 65) | componentDidUpdate(prevProps: IContentLoaderProps) {
    method componentWillUnmount (line 71) | componentWillUnmount() {
    method render (line 75) | render() {

FILE: src/native/__tests__/Svg.test.tsx
  type IPredicateArgs (line 7) | interface IPredicateArgs {

FILE: src/native/index.ts
  type IContentLoaderProps (line 5) | interface IContentLoaderProps extends SvgProps {

FILE: src/web/__tests__/Svg.test.tsx
  type PredicateArgs (line 6) | interface PredicateArgs {

FILE: src/web/index.ts
  type IContentLoaderProps (line 5) | interface IContentLoaderProps extends SVGAttributes<SVGElement> {
Condensed preview — 74 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (140K chars).
[
  {
    "path": ".codesandbox/tasks.json",
    "chars": 1806,
    "preview": "{\n  // These tasks will run in order when initializing your CodeSandbox project.\n  \"setupTasks\": [\n    {\n      \"name\": \""
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "chars": 909,
    "preview": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the\n// README at: https://github.co"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 645,
    "preview": "# These are supported funding model platforms\n\ngithub: [danilowoz]\npatreon: # Replace with a single Patreon username\nope"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "chars": 313,
    "preview": "## What did you do? \nPlease include the actual source code causing the issue.\n\n## What did you expect to happen?\nPlease "
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 530,
    "preview": "## Summary\nIn this section, you should give the overview of the problem and the proposed changes.\n\n## Related Issue #[is"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 467,
    "preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 599,
    "preview": "name: Continuous Integration\n\non:\n  pull_request:\n  push:\n    branches:\n      - master\n\njobs:\n  check:\n    runs-on: ubun"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 1135,
    "preview": "name: Release\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  prepare:\n    runs-on: ubuntu-latest\n    name: Checks\n\n "
  },
  {
    "path": ".gitignore",
    "chars": 197,
    "preview": "*.swp\n*~\n*.iml\n.*.haste_cache.*\n.DS_Store\n.idea\nnpm-debug.log\nyarn-error.log\nnode_modules\ndist\ncoverage\n/native\n.docz/\n."
  },
  {
    "path": ".prettierrc.js",
    "chars": 56,
    "preview": "module.exports = require(\"@significa/prettier-config\");\n"
  },
  {
    "path": ".storybook/main.ts",
    "chars": 289,
    "preview": "import type { StorybookConfig } from \"@storybook/react-vite\";\nconst config: StorybookConfig = {\n  stories: [\"../docs/**/"
  },
  {
    "path": ".storybook/preview-head.html",
    "chars": 46,
    "preview": "<script>\n    window.global = window;\n</script>"
  },
  {
    "path": ".storybook/preview.tsx",
    "chars": 246,
    "preview": "import React from \"react\";\n\nimport type { Preview } from \"@storybook/react\";\n\nconst preview: Preview = {\n  parameters: {"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3216,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "LICENSE",
    "chars": 1091,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Julian Ćwirko <julian.io>\n\nPermission is hereby granted, free of charge, to an"
  },
  {
    "path": "README.md",
    "chars": 17008,
    "preview": "<p align=\"center\">\n  <img width=\"350\" alt=\"react-content-loader\" src=\"https://user-images.githubusercontent.com/4838076/"
  },
  {
    "path": "__mocks__/react-native-svg.js",
    "chars": 1607,
    "preview": "import React from 'react';\n\nconst createComponent = function(name) {\n  return class extends React.Component {\n    // ove"
  },
  {
    "path": "babel.config.js",
    "chars": 192,
    "preview": "module.exports = {\n  presets: [\n    'module:metro-react-native-babel-preset',\n    '@babel/preset-typescript',\n  ],\n  plu"
  },
  {
    "path": "docs/index.stories.tsx",
    "chars": 10394,
    "preview": "import React from 'react'\nimport SyntaxHighlighter from 'react-syntax-highlighter'\nimport { docco } from 'react-syntax-h"
  },
  {
    "path": "jest.native.config.js",
    "chars": 220,
    "preview": "module.exports = {\n  preset: 'react-native',\n  transformIgnorePatterns: [\n    'node_modules/.pnpm/(?!react-native-payfor"
  },
  {
    "path": "jest.web.config.js",
    "chars": 276,
    "preview": "module.exports = {\n  verbose: true,\n  transform: {\n    '^.+\\\\.(t|j)sx?$': 'ts-jest',\n  },\n  testRegex: '/src/web/__tests"
  },
  {
    "path": "package.json",
    "chars": 3845,
    "preview": "{\n  \"name\": \"react-content-loader\",\n  \"version\": \"6.2.1\",\n  \"description\": \"SVG-Powered component to easily create place"
  },
  {
    "path": "rollup.config.js",
    "chars": 2669,
    "preview": "/* eslint-disable @typescript-eslint/camelcase */\nimport replace from 'rollup-plugin-replace'\nimport { uglify } from 'ro"
  },
  {
    "path": "src/native/ContentLoader.tsx",
    "chars": 348,
    "preview": "import * as React from 'react'\nimport { Circle, Path, Rect } from 'react-native-svg'\n\nimport { Facebook, IContentLoaderP"
  },
  {
    "path": "src/native/Svg.tsx",
    "chars": 3377,
    "preview": "import React, { Component, isValidElement } from 'react'\nimport { Animated } from 'react-native'\nimport Svg, {\n  ClipPat"
  },
  {
    "path": "src/native/__tests__/ContentLoader.test.tsx",
    "chars": 4572,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\nimport * as ShallowRenderer from 'react-t"
  },
  {
    "path": "src/native/__tests__/Svg.test.tsx",
    "chars": 3334,
    "preview": "import * as React from 'react'\nimport Svg, { ClipPath, LinearGradient, Stop } from 'react-native-svg'\nimport * as render"
  },
  {
    "path": "src/native/__tests__/__snapshots__/snapshots.test.tsx.snap",
    "chars": 7565,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`ContentLoader snapshots renders correctly the basic version 1`] = `"
  },
  {
    "path": "src/native/__tests__/presets/BulletListStyle.test.tsx",
    "chars": 550,
    "preview": "import 'react-native'\n\nimport * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport BulletList"
  },
  {
    "path": "src/native/__tests__/presets/CodeStyle.test.tsx",
    "chars": 520,
    "preview": "import 'react-native'\n\nimport * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport CodeStyle "
  },
  {
    "path": "src/native/__tests__/presets/FacebookStyle.test.tsx",
    "chars": 540,
    "preview": "import 'react-native'\n\nimport * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport FacebookSt"
  },
  {
    "path": "src/native/__tests__/presets/InstagramStyle.test.tsx",
    "chars": 545,
    "preview": "import 'react-native'\n\nimport * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport InstagramS"
  },
  {
    "path": "src/native/__tests__/presets/ListStyle.test.tsx",
    "chars": 520,
    "preview": "import 'react-native'\n\nimport * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport ListStyle "
  },
  {
    "path": "src/native/__tests__/presets/__snapshots__/BulletListStyle.test.tsx.snap",
    "chars": 1666,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`BulletListStyle renders correctly 1`] = `\n<Svg\n  height={125}\n  int"
  },
  {
    "path": "src/native/__tests__/presets/__snapshots__/CodeStyle.test.tsx.snap",
    "chars": 1715,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`CodeStyle renders correctly 1`] = `\n<Svg\n  height={84}\n  interval={"
  },
  {
    "path": "src/native/__tests__/presets/__snapshots__/FacebookStyle.test.tsx.snap",
    "chars": 1483,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`FacebookStyle renders correctly 1`] = `\n<Svg\n  height={124}\n  inter"
  },
  {
    "path": "src/native/__tests__/presets/__snapshots__/InstagramStyle.test.tsx.snap",
    "chars": 1332,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`InstagramStyle renders correctly 1`] = `\n<Svg\n  height={460}\n  inte"
  },
  {
    "path": "src/native/__tests__/presets/__snapshots__/ListStyle.test.tsx.snap",
    "chars": 1597,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`ListStyle renders correctly 1`] = `\n<Svg\n  height={110}\n  interval="
  },
  {
    "path": "src/native/__tests__/snapshots.test.tsx",
    "chars": 1968,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport ContentLoader, { Rect } from '../"
  },
  {
    "path": "src/native/index.ts",
    "chars": 765,
    "preview": "import { SvgProps } from 'react-native-svg'\n\nimport ContentLoader from './ContentLoader'\n\nexport interface IContentLoade"
  },
  {
    "path": "src/native/package.json",
    "chars": 394,
    "preview": "{\n  \"name\": \"react-content-loader/native\",\n  \"private\": true,\n  \"main\": \"./react-content-loader.native.cjs.js\",\n  \"modul"
  },
  {
    "path": "src/native/presets/BulletListStyle.tsx",
    "chars": 767,
    "preview": "import * as React from 'react'\nimport { IContentLoaderProps } from '..'\nimport ContentLoader, { Circle, Rect } from '../"
  },
  {
    "path": "src/native/presets/CodeStyle.tsx",
    "chars": 795,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from '..'\nimport ContentLoader, { Rect } from '../Content"
  },
  {
    "path": "src/native/presets/FacebookStyle.tsx",
    "chars": 671,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from '..'\nimport ContentLoader, { Circle, Rect } from '.."
  },
  {
    "path": "src/native/presets/InstagramStyle.tsx",
    "chars": 589,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from '..'\nimport ContentLoader, { Circle, Rect } from '.."
  },
  {
    "path": "src/native/presets/ListStyle.tsx",
    "chars": 735,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from '..'\nimport ContentLoader, { Rect } from '../Content"
  },
  {
    "path": "src/shared/uid.ts",
    "chars": 81,
    "preview": "export default (): string =>\n  Math.random()\n    .toString(36)\n    .substring(6)\n"
  },
  {
    "path": "src/web/ContentLoader.tsx",
    "chars": 263,
    "preview": "import * as React from 'react'\n\nimport { Facebook, IContentLoaderProps } from '.'\nimport Svg from './Svg'\n\nconst Content"
  },
  {
    "path": "src/web/Svg.tsx",
    "chars": 2196,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from './'\n\nconst SVG: React.FC<IContentLoaderProps> = ({\n"
  },
  {
    "path": "src/web/__tests__/ContentLoader.test.tsx",
    "chars": 5057,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\nimport * as ShallowRenderer from 'react-t"
  },
  {
    "path": "src/web/__tests__/Svg.test.tsx",
    "chars": 5356,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport Svg from '..'\n\ninterface Predicat"
  },
  {
    "path": "src/web/__tests__/__snapshots__/snapshots.test.tsx.snap",
    "chars": 9228,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`ContentLoader snapshots renders correctly the basic version 1`] = `"
  },
  {
    "path": "src/web/__tests__/index.test.tsx",
    "chars": 625,
    "preview": "/**\n * @jest-environment jsdom\n */\n\nimport * as React from 'react'\nimport * as ReactDOM from 'react-dom'\n\nimport Content"
  },
  {
    "path": "src/web/__tests__/presets/BulletListStyle.test.tsx",
    "chars": 557,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport BulletListStyle from '../../prese"
  },
  {
    "path": "src/web/__tests__/presets/CodeStyle.test.tsx",
    "chars": 521,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport CodeStyle from '../../presets/Cod"
  },
  {
    "path": "src/web/__tests__/presets/FacebookStyle.test.tsx",
    "chars": 545,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport FacebookStyle from '../../presets"
  },
  {
    "path": "src/web/__tests__/presets/InstagramStyle.test.tsx",
    "chars": 551,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport InstagramStyle from '../../preset"
  },
  {
    "path": "src/web/__tests__/presets/ListStyle.test.tsx",
    "chars": 521,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport ListStyle from '../../presets/Lis"
  },
  {
    "path": "src/web/__tests__/presets/__snapshots__/BulletListStyle.test.tsx.snap",
    "chars": 1937,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`BulletListStyle renders correctly 1`] = `\n<svg\n  aria-labelledby=\"B"
  },
  {
    "path": "src/web/__tests__/presets/__snapshots__/CodeStyle.test.tsx.snap",
    "chars": 1975,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`CodeStyle renders correctly 1`] = `\n<svg\n  aria-labelledby=\"CodeSty"
  },
  {
    "path": "src/web/__tests__/presets/__snapshots__/FacebookStyle.test.tsx.snap",
    "chars": 1750,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`FacebookStyle renders correctly 1`] = `\n<svg\n  aria-labelledby=\"Fac"
  },
  {
    "path": "src/web/__tests__/presets/__snapshots__/InstagramStyle.test.tsx.snap",
    "chars": 1601,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`InstagramStyle renders correctly 1`] = `\n<svg\n  aria-labelledby=\"In"
  },
  {
    "path": "src/web/__tests__/presets/__snapshots__/ListStyle.test.tsx.snap",
    "chars": 1856,
    "preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`ListStyle renders correctly 1`] = `\n<svg\n  aria-labelledby=\"ListSty"
  },
  {
    "path": "src/web/__tests__/snapshots.test.tsx",
    "chars": 1838,
    "preview": "import * as React from 'react'\nimport * as renderer from 'react-test-renderer'\n\nimport ContentLoader from '../ContentLoa"
  },
  {
    "path": "src/web/__tests__/uid.test.tsx",
    "chars": 522,
    "preview": "import uid from '../../shared/uid'\n\ndescribe('unique id', () => {\n  const options = 100\n  // @ts-ignore To avoid adding "
  },
  {
    "path": "src/web/index.ts",
    "chars": 779,
    "preview": "import { SVGAttributes, ReactElement } from 'react'\n\nimport ContentLoader from './ContentLoader'\n\nexport interface ICont"
  },
  {
    "path": "src/web/presets/BulletListStyle.tsx",
    "chars": 725,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from '..'\nimport ContentLoader from '../ContentLoader'\n\nc"
  },
  {
    "path": "src/web/presets/CodeStyle.tsx",
    "chars": 761,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from '..'\nimport ContentLoader from '../ContentLoader'\n\nc"
  },
  {
    "path": "src/web/presets/FacebookStyle.tsx",
    "chars": 628,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from '..'\nimport ContentLoader from '../ContentLoader'\n\nc"
  },
  {
    "path": "src/web/presets/InstagramStyle.tsx",
    "chars": 546,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from '..'\nimport ContentLoader from '../ContentLoader'\n\nc"
  },
  {
    "path": "src/web/presets/ListStyle.tsx",
    "chars": 700,
    "preview": "import * as React from 'react'\n\nimport { IContentLoaderProps } from '..'\nimport ContentLoader from '../ContentLoader'\n\nc"
  },
  {
    "path": "tsconfig.base.json",
    "chars": 427,
    "preview": "{\n  \"compilerOptions\": {\n    \"declaration\": true,\n    \"declarationDir\": \"./dist/types\",\n    \"declarationMap\": true,\n    "
  },
  {
    "path": "tsconfig.json",
    "chars": 40,
    "preview": "{\n  \"extends\": \"./tsconfig.base.json\"\n}\n"
  },
  {
    "path": "tsconfig.test.json",
    "chars": 87,
    "preview": "{\n  \"extends\": \"./tsconfig.base.json\",\n  \"compilerOptions\": {\n    \"lib\": [\"dom\"]\n  }\n}\n"
  }
]

About this extraction

This page contains the full source code of the danilowoz/react-content-loader GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 74 files (122.8 KB), approximately 36.4k tokens, and a symbol index with 9 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!