<!-- @format -->

# Liquid Editor React

A powerful React component library for building interactive Liquid template expressions with visual editing capabilities.

![Liquid Editor Demo](https://img.shields.io/badge/React-61DAFB?logo=react&logoColor=white)
![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=white)
![MIT License](https://img.shields.io/badge/License-MIT-green.svg)

## 🚀 Live Demo

Check out the interactive demo: [https://apphud.github.io/liquid-editor/](https://apphud.github.io/liquid-editor/)

## Features

- 🎨 **Visual Expression Builder** - Interactive UI for building Liquid expressions
- 🔧 **Rich Text Editor** - Content-editable text with embedded Liquid expressions
- 🎯 **Type-aware Filters** - Only show applicable filters based on data type
- 📝 **Autocomplete** - Smart suggestions for variables and filters
- 🏗️ **Hierarchical Navigation** - Browse nested object properties
- ⚡ **Real-time Parsing** - Live preview of expression output
- 🎭 **Dual Modes** - Visual editor and text-only output
- 🎨 **Customizable Styling** - Flexible theming options

## Installation

```bash
npm install liquid-editor-react
```

## Quick Start

```tsx
import React, { useState } from "react";
import { LiquidExpression, LiquidEditor } from "liquid-editor-react";
import "liquid-editor-react/styles";

const jsonSchema = {
  user: {
    name: { type: "string" },
    email: { type: "string" },
    age: { type: "number" },
  },
  product: {
    price: { type: "number" },
    title: { type: "string" },
  },
};

const liquidFilters = {
  upcase: {
    name: "upcase",
    description: "Convert to uppercase",
    applies_to: ["string"],
  },
  round: {
    name: "round",
    description: "Round number",
    applies_to: ["number"],
    parameters: [{ name: "precision", type: "number", default: 0 }],
  },
};

function App() {
  const [expression, setExpression] = useState("{{ user.name | upcase }}");
  const [editorContent, setEditorContent] = useState("Hello {{ user.name }}!");

  return (
    <div>
      {/* Individual Expression Builder */}
      <LiquidExpression
        isVisual={true}
        liquidExpression={expression}
        jsonSchema={jsonSchema}
        liquidFilters={liquidFilters}
        onChange={setExpression}
      />

      {/* Rich Text Editor */}
      <LiquidEditor
        initialValue={editorContent}
        onChange={setEditorContent}
        jsonSchema={jsonSchema}
        liquidFilters={liquidFilters}
        placeholder="Start typing..."
        showInsertButton={true}
      />
    </div>
  );
}
```

## Components

### LiquidExpression

A component for building individual Liquid expressions with a visual interface.

#### Props

| Prop               | Type                      | Required | Description                                  |
| ------------------ | ------------------------- | -------- | -------------------------------------------- |
| `isVisual`         | `boolean`                 | Yes      | Whether to show visual editor or text output |
| `liquidExpression` | `string`                  | Yes      | Current Liquid expression string             |
| `jsonSchema`       | `object`                  | Yes      | JSON schema defining available variables     |
| `liquidFilters`    | `object`                  | Yes      | Available Liquid filters configuration       |
| `onChange`         | `(value: string) => void` | Yes      | Callback when expression changes             |

#### Example

```tsx
<LiquidExpression
  isVisual={true}
  liquidExpression="{{ product.price | round: 2 }}"
  jsonSchema={schema}
  liquidFilters={filters}
  onChange={(newExpression) => console.log(newExpression)}
/>
```

### LiquidEditor

A rich text editor that supports embedded Liquid expressions.

#### Props

| Prop                | Type                      | Required | Description                                  |
| ------------------- | ------------------------- | -------- | -------------------------------------------- |
| `initialValue`      | `string`                  | Yes      | Initial text content with Liquid expressions |
| `onChange`          | `(value: string) => void` | Yes      | Callback when content changes                |
| `jsonSchema`        | `object`                  | Yes      | JSON schema defining available variables     |
| `liquidFilters`     | `object`                  | Yes      | Available Liquid filters configuration       |
| `placeholder`       | `string`                  | No       | Placeholder text when empty                  |
| `showInsertButton`  | `boolean`                 | No       | Whether to show the insert button            |
| `insertButtonStyle` | `CSSProperties`           | No       | Custom styling for insert button             |
| `style`             | `CSSProperties`           | No       | Custom styling for the editor                |

#### Example

```tsx
<LiquidEditor
  initialValue="Hello {{ user.name | upcase }}!"
  onChange={(content) => setEditorContent(content)}
  jsonSchema={schema}
  liquidFilters={filters}
  placeholder="Start typing your message..."
  showInsertButton={true}
  insertButtonStyle={{
    backgroundColor: "#10b981",
    color: "white",
    borderRadius: "8px",
  }}
/>
```

### Autocomplete

A reusable autocomplete component for variable and filter selection.

#### Props

| Prop          | Type                      | Required | Description                          |
| ------------- | ------------------------- | -------- | ------------------------------------ |
| `suggestions` | `string[]`                | Yes      | Array of suggestion strings          |
| `onSelect`    | `(value: string) => void` | Yes      | Callback when suggestion is selected |
| `placeholder` | `string`                  | No       | Input placeholder text               |

## Data Schemas

### JSON Schema Format

Define your data structure with types:

```javascript
const jsonSchema = {
  user: {
    name: { type: "string" },
    email: { type: "string" },
    age: { type: "number" },
    preferences: {
      theme: { type: "string" },
      notifications: { type: "boolean" },
    },
  },
  order: {
    total: { type: "number" },
    items: {
      type: "array",
      items: {
        name: { type: "string" },
        price: { type: "number" },
      },
    },
  },
};
```

### Liquid Filters Format

Define available filters with their constraints:

```javascript
const liquidFilters = {
  upcase: {
    name: "upcase",
    description: "Convert text to uppercase",
    applies_to: ["string"],
  },
  downcase: {
    name: "downcase",
    description: "Convert text to lowercase",
    applies_to: ["string"],
  },
  round: {
    name: "round",
    description: "Round number to specified precision",
    applies_to: ["number"],
    parameters: [
      {
        name: "precision",
        type: "number",
        default: 0,
        description: "Number of decimal places",
      },
    ],
  },
  minus: {
    name: "minus",
    description: "Subtract a number",
    applies_to: ["number"],
    parameters: [
      {
        name: "value",
        type: "number",
        required: true,
        description: "Number to subtract",
      },
    ],
  },
};
```

## Styling

Import the default styles:

```tsx
import "liquid-editor-react/styles";
```

Or customize with your own CSS:

```css
.liquid-expression {
  /* Your custom styles */
}

.liquid-editor {
  /* Your custom editor styles */
}
```

## TypeScript Support

Full TypeScript support with exported types:

```tsx
import type {
  LiquidExpressionProps,
  LiquidEditorProps,
  JsonSchema,
  LiquidFilters,
} from "liquid-editor-react";
```

## Browser Support

- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Links

- [GitHub Repository](https://github.com/apphud/liquid-editor)
- [NPM Package](https://www.npmjs.com/package/liquid-editor-react)
- [Live Demo](https://apphud.github.io/liquid-editor/)
- [Issue Tracker](https://github.com/apphud/liquid-editor/issues)
