A TypeScript implementation of JSON-DOC, a standardized format for storing structured content in JSON files, inspired by Notion's data model.
- Programmatically Generated Types: All TypeScript interfaces are automatically generated from JSON schemas
- React Renderer: Complete React component library for rendering JSON-DOC content
- Rich Content Support: Supports all major block types including paragraphs, headings, lists, tables, images, and more
- Recursive Rendering: Handles nested blocks at arbitrary depth
- Notion-like Styling: CSS styling inspired by Notion's visual design
npm install @textcortex/jsondocimport React from "react";
import { JsonDocRenderer } from "@textcortex/jsondoc";
import * as fs from "fs";
import * as JSON5 from "json5";
// Load JSON-DOC data (with comment support)
const pageData = JSON5.parse(fs.readFileSync("document.json", "utf-8"));
// Render the document
function App() {
return (
<div>
<JsonDocRenderer page={pageData} />
</div>
);
}import React from "react";
import { BlockRenderer } from "@textcortex/jsondoc";
function MyComponent({ block }) {
return (
<div>
<BlockRenderer block={block} depth={0} />
</div>
);
}View any JSON-DOC file directly in your browser with a single command:
# View a JSON-DOC file
npm run view path/to/your/document.json
# Example: View the test document
npm run view ../schema/page/ex1_success.jsonThis will:
- Start a local server at
http://localhost:3000 - Automatically open your browser
- Render the JSON-DOC file with full styling
- Support all block types including nested structures
The viewer includes:
- Live rendering of all supported block types
- Notion-like styling with responsive design
- Automatic browser opening for convenience
- File information in the header (filename, block count)
- Comment support using JSON5 parsing
The renderer supports all major JSON-DOC block types:
- Text Blocks:
paragraph,heading_1,heading_2,heading_3 - List Blocks:
bulleted_list_item,numbered_list_item - Rich Content:
code,quote,equation - Media:
image(both external URLs and file references) - Layout:
table,table_row,column_list,column - Interactive:
to_do,toggle - Utility:
divider
Rich text content supports:
- Formatting: Bold, italic, strikethrough, underline, code
- Colors: All Notion color options
- Links: External links with proper
target="_blank" - Equations: Inline mathematical expressions
# Install dependencies
npm install
# Generate TypeScript types from JSON schemas
npm run generate-types
# Build the project
npm run build
# Run tests
npm test
# View example JSON-DOC file in browser
npm run view ../schema/page/ex1_success.jsonThe test suite includes:
# Run all tests
npm test
# Tests cover:
# - JSON utility functions (loadJson, deepClone)
# - Example file loading with comment support
# - Block type detection and validationThe tests verify:
- ✅ JSON loading and parsing functionality
- ✅ Deep cloning of complex objects
- ✅ Loading of the comprehensive example file (47 blocks, 16 types)
- ✅ Block type enumeration and structure validation
src/models/: TypeScript type definitions (generated from schemas)src/renderer/: React components for rendering JSON-DOCsrc/utils/: Helper functionstests/: Test suite
JSON-DOC uses a hierarchical structure similar to Notion:
{
"object": "page",
"id": "page-id",
"properties": {
"title": {
"title": [
{
"type": "text",
"text": { "content": "Document Title" }
}
]
}
},
"children": [
{
"object": "block",
"type": "paragraph",
"id": "block-id",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": { "content": "Hello, world!" },
"annotations": {
"bold": true,
"color": "blue"
}
}
]
},
"children": []
}
]
}JsonDocRenderer
├── Page (icon, title, properties)
└── BlockRenderer (recursive)
├── ParagraphBlockRenderer
├── HeadingBlockRenderer
├── ListItemBlockRenderer
├── CodeBlockRenderer
├── ImageBlockRenderer
├── TableBlockRenderer
├── QuoteBlockRenderer
├── DividerBlockRenderer
├── ToDoBlockRenderer
├── ToggleBlockRenderer
├── ColumnListBlockRenderer
└── EquationBlockRenderer
- Recursive Rendering: All block renderers support children blocks with proper nesting
- Type Safety: Full TypeScript support with generated types
- Accessibility: Proper ARIA attributes and semantic HTML
- Responsive Design: Mobile-friendly layout with responsive columns
- Interactive Elements: Toggle blocks can be expanded/collapsed, to-do items show state
The renderer uses Notion-inspired CSS classes for styling:
.json-doc-renderer- Main container.notion-selectable- Individual blocks.notion-text-block,.notion-header-block- Block types.notion-list-item-box-left- List item bullets/numbers.notion-table-content- Table containers.notion-inline-code- Inline code formatting
MIT
- TypeScript configuration follows best practices from Total TypeScript
We use bumpp to automatically bump package.json and lock files, create git tags and commits
- Run:
npx bumpp
- You should see:
4 Commits since the last version:
5217cd1 : update readme
7a3c03d : Expose page delimiter
e2791a4 : Merge branch 'main' of github.com:textcortex/JSON-DOC
b7b30c1 : Make more typesafe
✔ Current version 0.2.0-alpha.3 › next 0.2.0-alpha.4
files package-lock.json
package.json
commit chore: release v0.2.0-alpha.4
tag typescript-v0.2.0-alpha.4
from 0.2.0-alpha.3
to 0.2.0-alpha.4
You can choose a different version from the list or create new one. But bumpp is smart enough to use appropriate next version.
- Verify and confirm
- Push commit and tag
git push --follow-tags
- The new tag will trigger a release on github actions.
- Go to github and create release using the new tag. Make sure you set the correct previous tag prefixed with
typescript-v
-
setup eslint
-
improve tsconfig
-
setup lint staged and husky
-
setup prettier
-
standardize styling (css)
-
fix styling for elements
- headings
- paragraph
- code
- table
- to-do items
- equation
- image
- blockquote
-
fix ts and eslint errors in these dirs and remove from ignore list of ts and eslint
"**/generated/**", "src/serialization/**", -
add counter for numbered lists
-
setup up bumpp: https://www.npmjs.com/package/bumpp
-
migrate test runner to vitest
-
move vite app to typescript root examples dir
-
setup monorepo tooling
-
fix model generation for Image and RichText, then type renderers
-
use katex or similar package for equations
-
add error boundry
-
add page title highlighting
-
validate page prop somehow. not clear how to do yet. we can't use the /schema because it's HUGE and also because it's outside of /typescript. Will need to think about this.
maybe do something like this?
import type { Page } from "../models/generated/page/page";
import { isPage } from "../models/generated/essential-types";
export function validatePage(obj: unknown): obj is Page {
console.log("isPage(obj) ", isPage(obj));
return (
isPage(obj) &&
typeof (obj as any).id === "string" &&
Array.isArray((obj as any).children)
);
}
export function validatePageWithError(obj: unknown): {
valid: boolean;
error?: string;
} {
if (!isPage(obj)) {
return { valid: false, error: "Not a valid page object" };
}
if (typeof (obj as any).id !== "string") {
return { valid: false, error: "Page id must be a string" };
}
if (!Array.isArray((obj as any).children)) {
return { valid: false, error: "Page children must be an array" };
}
return { valid: true };
}
will require us to write a validator and we won't benefit from the defined schema jsons.
- make error boundary catch errors in JsonDocRenderer.tsx body