# remark-react-liquid-tag

This is a [remark](https://github.com/remarkjs/remark) plugin that allows the usage of liquid tags.

This idea came from the usage of liquid tags in [dev.to (DEV COMMUNITY)](https://dev.to/) platform for embedding services in markdowns. [This documented page](https://docs.dev.to/frontend/liquid-tags/) shows their idea behind liquid tags and the tags available.

## Liquid tags

Liquid tags are special elements to use in markdown. They are custom embeds that are added via a `{% %}` syntax. [Liquid](https://shopify.github.io/liquid/) is a templating language developed by Shopify.

## Installation

```bash
npm install remark-react-liquid-tag
```

## Usage

The plugin follows the [unified](https://github.com/unifiedjs/unified) ecosystem.

### Example with react-markdown

Here is an example using [react-markdown](https://github.com/remarkjs/react-markdown) to render markdown in React.

```tsx
import React from 'react';
import Markdown from 'react-markdown';
import remarkReactLiquidTag, { RemarkReactLiquidTagProps } from 'remark-react-liquid-tag';

const LiquidTag: React.FC<RemarkReactLiquidTagProps> = (props) => {
  switch (props.type) {
    case 'youtube':
      return (
        <iframe
          width="560"
          height="315"
          src={`https://www.youtube.com/embed/${props.url}`}
          title="YouTube video player"
          frameBorder="0"
          allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
          allowFullScreen
        />
      );
    default:
      return null;
  }
};

const markdown = `
# Hello World
This is an example youtube video:
{% youtube dQw4w9WgXcQ %}
`;

export function App() {
  return (
    <Markdown
      remarkPlugins={[
        [remarkReactLiquidTag, { component: LiquidTag }],
      ]}
    >
      {markdown}
    </Markdown>
  );
}
```

### Example with unified + rehype-react

Here is an example using [rehype-react](https://github.com/rehypejs/rehype-react) to render the markdown in React.


```tsx
import * as prod from 'react/jsx-runtime';
import { renderToString } from 'react-dom/server';
import rehypeReact from 'rehype-react';
import remarkParse from 'remark-parse';
import remarkToRehype from 'remark-rehype';
import { unified } from 'unified';
import remarkReactLiquidTag, { RemarkReactLiquidTagProps } from 'remark-react-liquid-tag';

const LiquidTag: React.FC<RemarkReactLiquidTagProps> = (props) => {
  switch (props.type) {
    case 'youtube':
      return (
        <iframe
          width="560"
          height="315"
          src={`https://www.youtube.com/embed/${props.url}`}
          title="YouTube video player"
          frameBorder="0"
          allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
          allowFullScreen
        />
      );
    default:
      return null;
  }
}

const markdown = `
# Hello World
This is an example youtube video:
{% youtube dQw4w9WgXcQ %}

This is a unsupported tag:
{% unsupported_tag %}
`;

const { result } = unified()
  .use(remarkParse)
  .use(remarkReactLiquidTag, {
    component: LiquidTag,
  })
  .use(remarkToRehype)
  .use(rehypeReact, prod)
  .processSync(markdown);

// ...
```

## Options

- `component`: React component to render the liquid tag. It receives the following props:
  - `type`: The type of the liquid tag (e.g., `youtube`).
  - `url`: The main value/url of the liquid tag.
  - `options`: Key-value pairs of additional options passed in the tag (e.g., `{% type url key=value %}`).
  - `config`: Configuration specific to this tag type, passed via the `config` option.
- `config`: An object where keys are tag types and values are configuration objects passed to the component.

### Example with config and options

```tsx
const { result } = unified()
  .use(remarkParse)
  .use(remarkReactLiquidTag, {
    component: MyComponent,
    config: {
      youtube: {
        autoplay: true
      }
    }
  })
  .use(remarkToRehype)
  .use(rehypeReact, prod)
  .processSync('{% youtube dQw4w9WgXcQ theme=dark %}');
```

In this case, `MyComponent` will receive:
- `type`: `'youtube'`
- `url`: `'dQw4w9WgXcQ'`
- `options`: `{ theme: 'dark' }`
- `config`: `{ autoplay: true }`

## TypeScript

The plugin is written in TypeScript and exports types for your components.

```tsx
import { RemarkReactLiquidTagProps } from 'remark-react-liquid-tag';

type MyYoutubeConfig = {
  autoplay: boolean;
};

type MyYoutubeOptions = {
  theme: string;
};

const MyComponent: React.FC<RemarkReactLiquidTagProps<MyYoutubeOptions, MyYoutubeConfig>> = (props) => {
  // ...
};
```

