@owomark/view
v0.1.4
Published
Rendering engine, preview engine, DOM view layer, and official base theme for OwoMark.
Maintainers
Readme
@owomark/view
Rendering engine and interactive view layer for OwoMark. Provides the Gold Processor Factory for Markdown → HTML rendering, an incremental preview engine, and a DOM-backed editor view.
Install the official package: @owomark/view.
Install
npm install @owomark/viewFor MDX support, also install the optional peer dependencies:
npm install @mdx-js/mdx react react-domQuick Start
Official CSS Entry
import '@owomark/view/style.css';style.css is the official base theme bundle. It includes the structural CSS, built-in MDX component styles, side-annotation/slash-menu styles, and the light/dark preset token values. New users should start here.
Markdown → HTML (Static Rendering)
import { createOwoMarkProcessor } from '@owomark/view/static';
const processor = createOwoMarkProcessor();
const result = await processor.process('# Hello\n\nA paragraph with **bold**.');
console.log(String(result));
// <h1 id="hello">Hello</h1>\n<p>A paragraph with <strong>bold</strong>.</p>MDX → HTML
Enable MDX to render JSX components and expressions at build time:
import { createOwoMarkProcessor } from '@owomark/view/static';
const processor = createOwoMarkProcessor({ enableMdx: true });
const result = await processor.process(`
<Callout type="info">
Today is {new Date().getFullYear()}. MDX expressions just work.
</Callout>
`);
console.log(String(result));
// Built-in Callout component renders to styled HTMLWith Custom Components
import { createElement } from 'react';
import { createOwoMarkProcessor } from '@owomark/view/static';
const Chart = ({ data }) => createElement('div', { className: 'chart' }, `Chart: ${data}`);
const processor = createOwoMarkProcessor({
enableMdx: true,
mdxComponents: {
Chart, // Add your own component
// Callout, // Built-ins are still available unless you override them
},
});
const result = await processor.process('<Chart data="revenue" />');Gold Processor Factory
The Gold Processor Factory is the single source of truth for OwoMark's rendering pipeline. Both preview and production consume the same factory.
createOwoMarkProcessor(options?)
Returns an OwoMarkProcessor with a single process(source) → Promise<{ value, toString }> method.
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| mode | 'preview' \| 'production' | 'preview' | Rendering mode |
| enableMdx | boolean | false | Enable MDX rendering (JSX components + expressions) |
| mdxComponents | Record<string, ComponentType> | {} | Additional/override components (merged with built-ins) |
| enableMath | boolean | true | Enable KaTeX math rendering ($...$, $$...$$) |
| enableSideAnnotation | boolean | true | Enable side annotation syntax |
| preserveSoftLineBreaks | boolean | false | When false, plain newlines become <br> |
| codeTheme | string | 'vitesse-light' | Shiki theme for code highlighting |
| extraRemarkPlugins | PluginEntry[] | [] | Additional remark plugins |
| extraRehypePlugins | PluginEntry[] | [] | Additional rehype plugins |
getOwoMarkPlugins(options?)
Returns { remarkPlugins, rehypePlugins } arrays for use with @mdx-js/mdx compile paths directly. Excludes remark-parse and remark-mdx (MDX manages its own parser).
Theme Packages
@owomark/view owns the official base theme. Third-party themes should layer on top of it instead of replacing it.
Using a Third-Party Theme
import '@owomark/view/style.css';
import 'owomark-theme-acme/style.css';Load @owomark/view/style.css first, then the theme package. The theme package should override --owo-* tokens and only add narrowly scoped visual overrides when tokens are not enough.
Authoring owomark-theme-xxx
A theme package should:
- depend on
@owomark/viewand require consumers to import@owomark/view/style.cssfirst - publish token overrides and theme classes, not a copy of OwoMark's structural CSS
- target the public
--owo-*token contract instead of private internal selectors - treat
@owomark/view/style.css,@owomark/view/owomark.css,@owomark/view/mdx-components.css, and exported theme helpers as the supported extension surface
Minimal example:
.owo-theme-acme {
--owo-brand: #0f766e;
--owo-text: #123047;
--owo-surface: #f6fffb;
--owo-surface-raised: #ecfdf5;
--owo-border: #99f6e4;
--owo-border-strong: #5eead4;
}Then pass the class to OwoMark:
import { OwoMarkEditor } from '@owomark/react';
import '@owomark/view/style.css';
import 'owomark-theme-acme/style.css';
<OwoMarkEditor value={md} onChange={setMd} theme="owo-theme-acme" />;Compatibility rules for third-party themes:
- Do not re-implement editor layout, MDX component skeletons, or side-annotation structure unless you are intentionally shipping a full replacement theme.
- Do not assume private DOM structure is stable beyond documented classes and token hooks.
- Prefer base tokens such as
--owo-brand,--owo-text, and--owo-border; only override component-level tokens when the editor needs to diverge from the shared base theme.
Stable token families:
--owo-*: shared base tokens for brand, text, surface, border, semantic colors, and mono font--owo-editor-*: editor-only tokens such as caret, selection, heading, placeholder, and editor surfaces--owo-syntax-*: syntax-highlight tokens--owo-toolbar-*: toolbar tokens--owo-panel-*: panel/popover tokens
MDX Support
When enableMdx: true, the processor delegates to @mdx-js/mdx evaluate() + renderToStaticMarkup(). The output is still an HTML string — callers see no difference.
Built-in Components
Import the base styles for built-in components:
import '@owomark/view/mdx-components.css';Theming
MDX component styles consume --owo-* base tokens with hardcoded fallbacks. This means:
- Zero-config: Components render correctly without any theme import (fallback colors are embedded).
- With theme: Import
@owomark/view/style.cssand components automatically adapt to light/dark mode. - Custom brand: Set
--owo-brandon a wrapper element to change the accent color across Callout (info), Steps, and Tabs simultaneously.
| Component | Props | Description |
|-----------|-------|-------------|
| <Callout> | type?: 'info' \| 'warn' \| 'error' \| 'success' | Styled callout box with icon |
| <CodeDemo> | title?: string, language?: string, code: string | Code demonstration block |
| <Steps> | (children: <Step>) | Numbered step-by-step guide with vertical line |
| <Step> | title?: string | Single step within <Steps> |
| <Tabs> | (children: <Tab>) | CSS-only tab switcher (no JS runtime) |
| <Tab> | label?: string | Single tab panel within <Tabs> |
| <FileTree> | (children: indented text) | Directory tree visualization |
| <Kbd> | (children: key name) | Keyboard key indicator |
<Callout type="warn">
Watch out — this is a warning.
</Callout>
<Steps>
<Step title="Install">Run `npm install @owomark/view`</Step>
<Step title="Configure">Enable MDX in your processor options</Step>
</Steps>
<Tabs>
<Tab label="npm">`npm install @owomark/view`</Tab>
<Tab label="pnpm">`pnpm add @owomark/view`</Tab>
</Tabs>
<FileTree>
{`src/
components/
lib/
styles/
package.json`}
</FileTree>
Press <Kbd>Ctrl</Kbd> + <Kbd>S</Kbd> to save.
<CodeDemo title="Hello World" language="python" code="print('hello')" />Component Override
User-provided components override built-ins with the same name:
import { createElement } from 'react';
const MyCallout = ({ type, children }) =>
createElement('aside', { className: `my-callout-${type}` }, children);
const processor = createOwoMarkProcessor({
enableMdx: true,
mdxComponents: { Callout: MyCallout }, // Replaces built-in Callout
});Unregistered Components
Components used in MDX but not registered (built-in or user-provided) will:
- Print a
[owomark-mdx] Unregistered MDX component: <Name>warning - Render as
<div data-mdx-missing="Name">children</div> - Not interrupt the build
MDX + Side Annotations
The { and => side annotation types conflict with MDX expression syntax. Use keyword forms instead:
| Symbol | Keyword | Example |
|--------|---------|---------|
| { | left-brace | (>left-brace annotation text) |
| => | fat-arrow | (>fat-arrow annotation text) |
All other side annotation types (}, ], ->, etc.) work unchanged in MDX mode.
Peer Dependencies
MDX support requires these optional peer dependencies:
@mdx-js/mdx^3.0.0react^18.0.0 or ^19.0.0react-dom^18.0.0 or ^19.0.0
When enableMdx is false (default), these are not needed.
Plugin Chain
The Gold Processor applies plugins in this order:
Remark (Markdown → mdast):
remark-parse → remark-gfm → remark-math* → remark-directive → remark-mdx† → soft-breaks‡ → remark-side-annotation* → extras
Rehype (hast → HTML):
rehype-katex* → rehype-math-display-fix* → rehype-slug → rehype-pretty-code → rehype-side-annotation* → extras → rehype-stringify
* = gated by feature flag · † = production mode only · ‡ = when preserveSoftLineBreaks is false
Exports
@owomark/view/static (SSR-safe)
import {
createOwoMarkProcessor,
getOwoMarkPlugins,
// Built-in MDX components
DEFAULT_MDX_COMPONENTS,
Callout, CodeDemo, Steps, Step, Tabs, Tab, FileTree, Kbd,
// Internal plugins (for advanced use)
remarkSideAnnotation,
rehypeSideAnnotation,
remarkConvertSoftBreaksToHardBreaks,
rehypeMathDisplayFix,
} from '@owomark/view/static';@owomark/view (Full — includes editor + preview engine)
All static exports plus the interactive view engine, preview engine, DOM patcher, and side annotation positioner.
