@opensaas/stack-tiptap
v0.18.2
Published
Tiptap rich text editor integration for OpenSaas Stack
Maintainers
Readme
@opensaas/stack-tiptap
Rich text editor integration for OpenSaas Stack using Tiptap.
Features
- ✅ Rich text editing with Tiptap editor
- ✅ JSON storage in database
- ✅ SSR-safe Next.js integration
- ✅ Edit and read-only modes
- ✅ Customizable toolbar and UI options
- ✅ Full TypeScript support
- ✅ Integrates with OpenSaas access control
Installation
This package is designed as a separate optional dependency to keep the core stack lightweight.
pnpm add @opensaas/stack-tiptapThe following peer dependencies are required:
@opensaas/stack-core@opensaas/stack-uinextreactreact-dom
Usage
Basic Setup
- Register the field component on the client side:
// lib/register-fields.ts
'use client'
import { registerFieldComponent } from '@opensaas/stack-ui'
import { TiptapField } from '@opensaas/stack-tiptap'
registerFieldComponent('richText', TiptapField)- Import the registration in your admin page:
// app/admin/[[...admin]]/page.tsx
import { AdminUI } from "@opensaas/stack-ui";
import config from "../../../opensaas.config";
import "../../../lib/register-fields"; // Import to trigger registration
export default async function AdminPage() {
// ... your code
return <AdminUI config={config} />;
}- Define your schema with the
richTextfield builder:
// opensaas.config.ts
import { config, list } from '@opensaas/stack-core'
import { text } from '@opensaas/stack-core/fields'
import { richText } from '@opensaas/stack-tiptap/fields'
export default config({
db: {
provider: 'sqlite',
url: 'file:./dev.db',
},
lists: {
Article: list({
fields: {
title: text({ validation: { isRequired: true } }),
content: richText({
validation: { isRequired: true },
}),
},
}),
},
})- Generate Prisma schema:
pnpm generateThis will create a Prisma field with type Json:
model Article {
id String @id @default(cuid())
title String
content Json // Tiptap JSON content
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}Field Options
Validation
content: richText({
validation: {
isRequired: true, // Make field required
},
})UI Customization
content: richText({
ui: {
placeholder: 'Start writing...',
minHeight: 200, // Minimum editor height in pixels
maxHeight: 800, // Maximum editor height (scrollable)
},
})Access Control
Rich text fields work seamlessly with OpenSaas access control:
Article: list({
fields: {
content: richText({
validation: { isRequired: true },
access: {
read: () => true,
create: isSignedIn,
update: isAuthor,
},
}),
},
})Database Operations
Content is stored as JSON and can be queried using Prisma's JSON operations:
import { prisma } from './lib/context'
// Create article with rich text
const article = await prisma.article.create({
data: {
title: 'My Article',
content: {
type: 'doc',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Hello world!' }],
},
],
},
},
})
// Query articles
const articles = await prisma.article.findMany({
select: {
title: true,
content: true,
},
})Component Features
The TiptapField component includes:
Text Formatting
- Bold
- Italic
- ~~Strike-through~~
Headings
- H1, H2, H3
Lists
- Bullet lists
- Ordered lists
Blockquotes
- Quote blocks
Modes
- Edit mode: Full toolbar with all formatting options
- Read mode: Render-only view (no toolbar)
Advanced Usage
Custom Field Component
Create a custom Tiptap component with additional extensions:
// components/CustomTiptapField.tsx
"use client";
import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import Link from "@tiptap/extension-link";
import Image from "@tiptap/extension-image";
export function CustomTiptapField(props) {
const editor = useEditor({
extensions: [
StarterKit,
Link,
Image,
],
content: props.value,
immediatelyRender: false,
onUpdate: ({ editor }) => {
props.onChange(editor.getJSON());
},
});
return <EditorContent editor={editor} />;
}Then use it in your config:
import { registerFieldComponent } from '@opensaas/stack-ui'
import { CustomTiptapField } from './components/CustomTiptapField'
// Global registration
registerFieldComponent('richTextExtended', CustomTiptapField)
// Use in config
fields: {
content: richText({
ui: { fieldType: 'richTextExtended' },
})
}
// Or per-field override
fields: {
content: richText({
ui: { component: CustomTiptapField },
})
}Architecture
This package follows OpenSaas's extensibility pattern:
Field Builder (
richText()) - Defines field configuration- Returns
RichTextFieldtype - Implements
getZodSchema(),getPrismaType(),getTypeScriptType() - Stores data as
Jsonin Prisma
- Returns
React Component (
TiptapField) - UI implementation- Client component with
"use client"directive - SSR-safe with
immediatelyRender: false - Supports edit and read modes
- Client component with
No Core Modifications - Extends stack without changes
- Uses
BaseFieldConfigextension point - Compatible with access control system
- Works with hooks and validation
- Uses
Example
See examples/tiptap-demo for a complete working example demonstrating:
- Multiple rich text fields
- Custom UI options
- Access control integration
- Database operations
API Reference
richText(options?)
Creates a rich text field configuration.
Options:
validation.isRequired- Make field required (default:false)ui.placeholder- Placeholder text (default:"Start writing...")ui.minHeight- Minimum editor height in pixels (default:200)ui.maxHeight- Maximum editor height in pixels (default:undefined)ui.component- Custom React componentui.fieldType- Global field type nameaccess- Field-level access control
Returns: RichTextField
TiptapField Component
React component for rendering the Tiptap editor.
Props:
name: string- Field namevalue: any- JSON content valueonChange: (value: any) => void- Change handlerlabel: string- Field labelerror?: string- Validation error messagedisabled?: boolean- Disable editingrequired?: boolean- Show required indicatormode?: "read" | "edit"- Display modeplaceholder?: string- Placeholder textminHeight?: number- Minimum heightmaxHeight?: number- Maximum height
Contributing
Contributions are welcome! This package is part of the OpenSaas Stack monorepo.
License
MIT
