comark 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/devtools/index.d.ts +1 -0
- package/dist/devtools/index.js +1 -0
- package/dist/devtools/register.d.ts +1 -0
- package/dist/devtools/register.js +1 -0
- package/dist/devtools/registry.d.ts +1 -0
- package/dist/devtools/registry.js +1 -0
- package/dist/devtools/vite.d.ts +1 -0
- package/dist/devtools/vite.js +1 -0
- package/dist/internal/frontmatter.d.ts +1 -0
- package/dist/internal/frontmatter.js +4 -2
- package/dist/internal/parse/auto-close/index.js +25 -13
- package/dist/internal/parse/auto-close/table.js +12 -9
- package/dist/internal/parse/auto-unwrap.js +2 -10
- package/dist/internal/parse/html/html_block_rule.js +1 -1
- package/dist/internal/parse/html/html_inline_rule.js +3 -7
- package/dist/internal/parse/html/html_re.js +1 -1
- package/dist/internal/parse/html/index.js +14 -2
- package/dist/internal/parse/syntax/block-params.d.ts +9 -0
- package/dist/internal/parse/syntax/block-params.js +48 -0
- package/dist/internal/parse/syntax/brackets.d.ts +8 -0
- package/dist/internal/parse/syntax/brackets.js +20 -0
- package/dist/internal/parse/syntax/props.d.ts +5 -0
- package/dist/internal/parse/syntax/props.js +119 -0
- package/dist/internal/parse/token-processor.js +25 -24
- package/dist/internal/props-validation.js +4 -9
- package/dist/internal/stringify/attributes.js +4 -1
- package/dist/internal/stringify/handlers/a.js +1 -3
- package/dist/internal/stringify/handlers/blockquote.js +2 -4
- package/dist/internal/stringify/handlers/code.js +1 -3
- package/dist/internal/stringify/handlers/emphesis.js +1 -3
- package/dist/internal/stringify/handlers/html.js +26 -16
- package/dist/internal/stringify/handlers/img.js +1 -3
- package/dist/internal/stringify/handlers/li.js +14 -8
- package/dist/internal/stringify/handlers/mdc.js +2 -3
- package/dist/internal/stringify/handlers/ol.js +1 -1
- package/dist/internal/stringify/handlers/p.d.ts +1 -1
- package/dist/internal/stringify/handlers/p.js +4 -1
- package/dist/internal/stringify/handlers/pre.js +10 -13
- package/dist/internal/stringify/handlers/strong.js +1 -3
- package/dist/internal/stringify/handlers/table.js +7 -5
- package/dist/internal/stringify/handlers/template.js +1 -1
- package/dist/internal/stringify/handlers/ul.js +1 -1
- package/dist/internal/stringify/indent.d.ts +1 -5
- package/dist/internal/stringify/indent.js +1 -9
- package/dist/internal/stringify/state.js +1 -1
- package/dist/internal/yaml.js +1 -1
- package/dist/parse.js +14 -8
- package/dist/plugins/alert.js +1 -1
- package/dist/plugins/binding.js +1 -3
- package/dist/plugins/breaks.js +1 -1
- package/dist/plugins/emoji.js +8 -8
- package/dist/plugins/footnotes.js +19 -13
- package/dist/plugins/headings.js +2 -4
- package/dist/plugins/highlight.d.ts +1 -11
- package/dist/plugins/highlight.js +198 -103
- package/dist/plugins/json-render.js +5 -9
- package/dist/plugins/math.js +4 -6
- package/dist/plugins/mermaid.js +6 -20
- package/dist/plugins/punctuation.js +5 -6
- package/dist/plugins/security.js +2 -2
- package/dist/plugins/syntax.d.ts +49 -0
- package/dist/plugins/syntax.js +522 -0
- package/dist/plugins/task-list.d.ts +1 -1
- package/dist/plugins/task-list.js +11 -8
- package/dist/plugins/toc.js +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/utils/comark.tmLanguage.d.ts +335 -0
- package/dist/utils/comark.tmLanguage.js +597 -0
- package/dist/utils/helpers.js +1 -3
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +25 -3
- package/package.json +49 -51
- package/skills/skills/comark/AGENTS.md +0 -261
- package/skills/skills/comark/SKILL.md +0 -489
- package/skills/skills/comark/references/markdown-syntax.md +0 -599
- package/skills/skills/comark/references/parsing-ast.md +0 -378
- package/skills/skills/comark/references/rendering-react.md +0 -445
- package/skills/skills/comark/references/rendering-svelte.md +0 -453
- package/skills/skills/comark/references/rendering-vue.md +0 -462
- /package/skills/{skills/migrate-mdc-to-comark → migrate-mdc-to-comark}/SKILL.md +0 -0
|
@@ -1,445 +0,0 @@
|
|
|
1
|
-
# React Rendering Guide
|
|
2
|
-
|
|
3
|
-
Complete guide for rendering Comark AST in React applications.
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Basic Usage](#basic-usage)
|
|
8
|
-
- [Custom Components](#custom-components)
|
|
9
|
-
- [Dynamic Component Resolution](#dynamic-component-resolution)
|
|
10
|
-
- [Props Conversion](#props-conversion)
|
|
11
|
-
- [Streaming Mode](#streaming-mode)
|
|
12
|
-
- [Prose Components](#prose-components)
|
|
13
|
-
- [Custom Props Handling](#custom-props-handling)
|
|
14
|
-
- [CSS Class Name](#css-class-name)
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## Basic Usage
|
|
19
|
-
|
|
20
|
-
Use the `Comark` component to render markdown:
|
|
21
|
-
|
|
22
|
-
```tsx
|
|
23
|
-
import { Comark } from '@comark/react'
|
|
24
|
-
|
|
25
|
-
const content = `
|
|
26
|
-
# Hello World
|
|
27
|
-
|
|
28
|
-
This is **markdown** content.
|
|
29
|
-
|
|
30
|
-
::alert{type="info"}
|
|
31
|
-
Important message
|
|
32
|
-
::
|
|
33
|
-
`
|
|
34
|
-
|
|
35
|
-
export default function App() {
|
|
36
|
-
return <Comark>{content}</Comark>
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
---
|
|
41
|
-
|
|
42
|
-
## Custom Components
|
|
43
|
-
|
|
44
|
-
Map custom React components to Comark elements:
|
|
45
|
-
|
|
46
|
-
```tsx
|
|
47
|
-
import { Comark } from '@comark/react'
|
|
48
|
-
import CustomHeading from './CustomHeading'
|
|
49
|
-
import CustomAlert from './CustomAlert'
|
|
50
|
-
import CustomCard from './CustomCard'
|
|
51
|
-
|
|
52
|
-
const customComponents = {
|
|
53
|
-
h1: CustomHeading,
|
|
54
|
-
h2: CustomHeading,
|
|
55
|
-
alert: CustomAlert,
|
|
56
|
-
card: CustomCard,
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export default function App({ content }) {
|
|
60
|
-
return (
|
|
61
|
-
<Comark
|
|
62
|
-
components={customComponents}
|
|
63
|
-
>{content}</Comark>
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Custom Component Example
|
|
69
|
-
|
|
70
|
-
```tsx
|
|
71
|
-
// CustomHeading.tsx
|
|
72
|
-
import React from 'react'
|
|
73
|
-
|
|
74
|
-
interface Props {
|
|
75
|
-
__node: any // Comark node
|
|
76
|
-
id?: string
|
|
77
|
-
children: React.ReactNode
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export default function CustomHeading({ __node, id, children }: Props) {
|
|
81
|
-
const tag = __node[0] // h1, h2, etc.
|
|
82
|
-
const Component = tag as keyof JSX.IntrinsicElements
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<Component id={id} className="custom-heading">
|
|
86
|
-
{children}
|
|
87
|
-
</Component>
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
**Styled Component:**
|
|
93
|
-
|
|
94
|
-
```tsx
|
|
95
|
-
import styled from 'styled-components'
|
|
96
|
-
|
|
97
|
-
const StyledHeading = styled.h1<{ level: number }>`
|
|
98
|
-
font-family: 'Inter', sans-serif;
|
|
99
|
-
font-weight: 700;
|
|
100
|
-
font-size: ${props => 3 - props.level * 0.25}rem;
|
|
101
|
-
margin-bottom: 1rem;
|
|
102
|
-
color: #1a202c;
|
|
103
|
-
`
|
|
104
|
-
|
|
105
|
-
export default function CustomHeading({ __node, children }: Props) {
|
|
106
|
-
const tag = __node[0]
|
|
107
|
-
const level = parseInt(tag[1]) // Extract level from 'h1', 'h2', etc.
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<StyledHeading as={tag} level={level}>
|
|
111
|
-
{children}
|
|
112
|
-
</StyledHeading>
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Alert Component Example
|
|
118
|
-
|
|
119
|
-
```tsx
|
|
120
|
-
// CustomAlert.tsx
|
|
121
|
-
import React from 'react'
|
|
122
|
-
import './Alert.css'
|
|
123
|
-
|
|
124
|
-
interface AlertProps {
|
|
125
|
-
type?: 'info' | 'warning' | 'error' | 'success'
|
|
126
|
-
children: React.ReactNode
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export default function CustomAlert({ type = 'info', children }: AlertProps) {
|
|
130
|
-
const icons = {
|
|
131
|
-
info: 'ℹ️',
|
|
132
|
-
warning: '⚠️',
|
|
133
|
-
error: '❌',
|
|
134
|
-
success: '✅',
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return (
|
|
138
|
-
<div className={`alert alert-${type}`} role="alert">
|
|
139
|
-
<div className="alert-icon">{icons[type]}</div>
|
|
140
|
-
<div className="alert-content">{children}</div>
|
|
141
|
-
</div>
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
---
|
|
147
|
-
|
|
148
|
-
## Dynamic Component Resolution
|
|
149
|
-
|
|
150
|
-
Load components dynamically using `componentsManifest`:
|
|
151
|
-
|
|
152
|
-
```tsx
|
|
153
|
-
import { Comark } from '@comark/react'
|
|
154
|
-
|
|
155
|
-
const componentMap = {
|
|
156
|
-
'alert': () => import('./Alert'),
|
|
157
|
-
'card': () => import('./Card'),
|
|
158
|
-
'button': () => import('./Button'),
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async function loadComponent(name: string) {
|
|
162
|
-
if (componentMap[name]) {
|
|
163
|
-
return componentMap[name]()
|
|
164
|
-
}
|
|
165
|
-
throw new Error(`Component ${name} not found`)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export default function App({ content }) {
|
|
169
|
-
return (
|
|
170
|
-
<Comark
|
|
171
|
-
componentsManifest={loadComponent}
|
|
172
|
-
>{content}</Comark>
|
|
173
|
-
)
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
## Props Conversion
|
|
180
|
-
|
|
181
|
-
React renderer handles HTML attribute conversion automatically:
|
|
182
|
-
|
|
183
|
-
### Attribute Mapping
|
|
184
|
-
|
|
185
|
-
```tsx
|
|
186
|
-
// Markdown attribute → React prop
|
|
187
|
-
{class="foo"} → className="foo"
|
|
188
|
-
{tabindex="0"} → tabIndex={0}
|
|
189
|
-
{style="..."} → style={{...}} (converted to object)
|
|
190
|
-
{:bool="true"} → bool={true} (parsed from string)
|
|
191
|
-
{:count="5"} → count={5} (parsed as number)
|
|
192
|
-
{:data='{"key":"val"}'} → data={{key:"val"}} (parsed as object)
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### Style Conversion
|
|
196
|
-
|
|
197
|
-
```tsx
|
|
198
|
-
// Input: style="color: red; font-size: 16px"
|
|
199
|
-
// Output: style={{ color: 'red', fontSize: '16px' }}
|
|
200
|
-
|
|
201
|
-
// Custom CSS properties preserved:
|
|
202
|
-
// Input: style="--custom-color: blue"
|
|
203
|
-
// Output: style={{ '--custom-color': 'blue' }}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Boolean Props
|
|
207
|
-
|
|
208
|
-
```tsx
|
|
209
|
-
// Markdown: **text**{:disabled}
|
|
210
|
-
// React prop: disabled={true}
|
|
211
|
-
|
|
212
|
-
// Markdown: [link](url){:external}
|
|
213
|
-
// React prop: external={true}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Number Props
|
|
217
|
-
|
|
218
|
-
```tsx
|
|
219
|
-
// Markdown: ::component{:count="5"}
|
|
220
|
-
// React prop: count={5}
|
|
221
|
-
|
|
222
|
-
// Markdown: ::component{:max="100"}
|
|
223
|
-
// React prop: max={100}
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
### Object/Array Props
|
|
227
|
-
|
|
228
|
-
```tsx
|
|
229
|
-
// Markdown: ::component{:config='{"theme":"dark"}'}
|
|
230
|
-
// React prop: config={{theme:"dark"}}
|
|
231
|
-
|
|
232
|
-
// Markdown: ::component{:items='["a","b","c"]'}
|
|
233
|
-
// React prop: items={["a","b","c"]}
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
## Streaming Mode
|
|
239
|
-
|
|
240
|
-
Use the `Comark` component with reactive state for streaming content:
|
|
241
|
-
|
|
242
|
-
```tsx
|
|
243
|
-
import { useState, useEffect } from 'react'
|
|
244
|
-
import { Comark } from '@comark/react'
|
|
245
|
-
|
|
246
|
-
export default function StreamingContent() {
|
|
247
|
-
const [content, setContent] = useState('')
|
|
248
|
-
const [isLoading, setIsLoading] = useState(true)
|
|
249
|
-
|
|
250
|
-
useEffect(() => {
|
|
251
|
-
async function loadContent() {
|
|
252
|
-
const response = await fetch('/api/content.md')
|
|
253
|
-
const reader = response.body!.getReader()
|
|
254
|
-
const decoder = new TextDecoder()
|
|
255
|
-
|
|
256
|
-
while (true) {
|
|
257
|
-
const { done, value } = await reader.read()
|
|
258
|
-
if (done) break
|
|
259
|
-
setContent(prev => prev + decoder.decode(value))
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
setIsLoading(false)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
loadContent()
|
|
266
|
-
}, [])
|
|
267
|
-
|
|
268
|
-
return (
|
|
269
|
-
<>
|
|
270
|
-
{isLoading && <div>Loading...</div>}
|
|
271
|
-
<Comark>{content}</Comark>
|
|
272
|
-
</>
|
|
273
|
-
)
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
## Prose Components
|
|
280
|
-
|
|
281
|
-
The `Comark` component uses built-in prose styling automatically. You can override with custom components:
|
|
282
|
-
|
|
283
|
-
```tsx
|
|
284
|
-
import { Comark } from '@comark/react'
|
|
285
|
-
import CustomAlert from './CustomAlert'
|
|
286
|
-
|
|
287
|
-
const components = {
|
|
288
|
-
alert: CustomAlert, // Override or add custom components
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export default function App({ content }) {
|
|
292
|
-
return <Comark components={components}>{content}</Comark>
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### Tailwind CSS Prose
|
|
297
|
-
|
|
298
|
-
```tsx
|
|
299
|
-
import { Comark } from '@comark/react'
|
|
300
|
-
|
|
301
|
-
export default function App({ content }) {
|
|
302
|
-
return (
|
|
303
|
-
<article className="prose prose-lg dark:prose-dark max-w-none">
|
|
304
|
-
<Comark>{content}</Comark>
|
|
305
|
-
</article>
|
|
306
|
-
)
|
|
307
|
-
}
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
---
|
|
311
|
-
|
|
312
|
-
## Custom Props Handling
|
|
313
|
-
|
|
314
|
-
Access props in custom components:
|
|
315
|
-
|
|
316
|
-
```tsx
|
|
317
|
-
// CustomAlert.tsx
|
|
318
|
-
interface AlertProps {
|
|
319
|
-
type?: string // From {type="info"}
|
|
320
|
-
bool?: boolean // From {bool} → :bool="true"
|
|
321
|
-
count?: number // From {:count="5"}
|
|
322
|
-
data?: object // From {:data='{"key":"val"}'}
|
|
323
|
-
__node?: any // Original Comark node
|
|
324
|
-
children: React.ReactNode
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
export default function CustomAlert({
|
|
328
|
-
type = 'info',
|
|
329
|
-
bool,
|
|
330
|
-
count,
|
|
331
|
-
data,
|
|
332
|
-
__node,
|
|
333
|
-
children
|
|
334
|
-
}: AlertProps) {
|
|
335
|
-
return (
|
|
336
|
-
<div
|
|
337
|
-
className={`alert alert-${type}`}
|
|
338
|
-
data-bool={bool}
|
|
339
|
-
data-count={count}
|
|
340
|
-
data-info={JSON.stringify(data)}
|
|
341
|
-
role="alert"
|
|
342
|
-
>
|
|
343
|
-
{children}
|
|
344
|
-
</div>
|
|
345
|
-
)
|
|
346
|
-
}
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
### Property Types
|
|
350
|
-
|
|
351
|
-
- `:bool="true"` → `bool={true}` (boolean)
|
|
352
|
-
- `:count="5"` → `count={5}` (number)
|
|
353
|
-
- `:obj='{"key":"val"}'` → `obj={{key:"val"}}` (object)
|
|
354
|
-
- `attr="value"` → `attr="value"` (string)
|
|
355
|
-
|
|
356
|
-
### Accessing Node Structure
|
|
357
|
-
|
|
358
|
-
```tsx
|
|
359
|
-
interface Props {
|
|
360
|
-
__node?: any
|
|
361
|
-
children: React.ReactNode
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
export default function Component({ __node, children }: Props) {
|
|
365
|
-
// Node structure: [tag, props, ...children]
|
|
366
|
-
const tag = __node?.[0]
|
|
367
|
-
const nodeProps = __node?.[1] || {}
|
|
368
|
-
const nodeChildren = __node?.slice(2) || []
|
|
369
|
-
|
|
370
|
-
return (
|
|
371
|
-
<div data-tag={tag}>
|
|
372
|
-
{children}
|
|
373
|
-
</div>
|
|
374
|
-
)
|
|
375
|
-
}
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
### Working with Complex Props
|
|
379
|
-
|
|
380
|
-
```tsx
|
|
381
|
-
// DataTable.tsx
|
|
382
|
-
interface DataTableProps {
|
|
383
|
-
columns?: string[] // From {:columns='["Name","Age"]'}
|
|
384
|
-
sortable?: boolean // From {sortable}
|
|
385
|
-
striped?: boolean // From {striped}
|
|
386
|
-
children: React.ReactNode
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
export default function DataTable({
|
|
390
|
-
columns = [],
|
|
391
|
-
sortable = false,
|
|
392
|
-
striped = false,
|
|
393
|
-
children
|
|
394
|
-
}: DataTableProps) {
|
|
395
|
-
return (
|
|
396
|
-
<table className={striped ? 'table-striped' : ''}>
|
|
397
|
-
{columns.length > 0 && (
|
|
398
|
-
<thead>
|
|
399
|
-
<tr>
|
|
400
|
-
{columns.map((col, i) => (
|
|
401
|
-
<th key={i}>
|
|
402
|
-
{col}
|
|
403
|
-
{sortable && <button>↕</button>}
|
|
404
|
-
</th>
|
|
405
|
-
))}
|
|
406
|
-
</tr>
|
|
407
|
-
</thead>
|
|
408
|
-
)}
|
|
409
|
-
<tbody>{children}</tbody>
|
|
410
|
-
</table>
|
|
411
|
-
)
|
|
412
|
-
}
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
**Usage in Markdown:**
|
|
416
|
-
|
|
417
|
-
```markdown
|
|
418
|
-
::data-table{:columns='["Name", "Age", "Email"]' sortable striped}
|
|
419
|
-
Table content here
|
|
420
|
-
::
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
---
|
|
424
|
-
|
|
425
|
-
## CSS Class Name
|
|
426
|
-
|
|
427
|
-
Add custom wrapper class:
|
|
428
|
-
|
|
429
|
-
```tsx
|
|
430
|
-
<Comark
|
|
431
|
-
className="prose dark:prose-dark"
|
|
432
|
-
>{content}</Comark>
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### With Tailwind CSS
|
|
436
|
-
|
|
437
|
-
```tsx
|
|
438
|
-
<Comark
|
|
439
|
-
className="prose prose-slate lg:prose-xl dark:prose-invert max-w-none"
|
|
440
|
-
>{content}</Comark>
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
---
|
|
444
|
-
|
|
445
|
-
[← Back to Main Skills Guide](../SKILL.md)
|