@brett_lamy/docstream 0.5.7 → 0.6.1
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/README.md +4 -0
- package/package.json +1 -1
- package/src/docs/DocsRenderer.tsx +5 -1
- package/src/docs/reference.tsx +2 -2
- package/src/gitbook/ast.ts +1 -1
- package/src/gitbook/inline.ts +14 -9
- package/src/styles.css +72 -19
package/README.md
CHANGED
|
@@ -32,6 +32,10 @@ Import the package CSS once near your app entrypoint:
|
|
|
32
32
|
import "@brett_lamy/docstream/styles.css"
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
+
The stylesheet provides heading hierarchy and consistent spacing for the
|
|
36
|
+
`DocsRenderer`, `MarkdownContent`, and streaming render paths. Host CSS can
|
|
37
|
+
override those defaults through the normal cascade.
|
|
38
|
+
|
|
35
39
|
If your TypeScript app checks CSS side-effect imports, include Vite's standard environment declaration or an equivalent CSS module declaration:
|
|
36
40
|
|
|
37
41
|
```ts
|
package/package.json
CHANGED
|
@@ -376,7 +376,11 @@ function isReactLanguage(language: string | null): boolean {
|
|
|
376
376
|
|
|
377
377
|
function Blocks({ blocks, inline, liveRenderer, sourceRenderer }: { blocks: Block[]; inline?: boolean } & Renderers) {
|
|
378
378
|
return (
|
|
379
|
-
<div
|
|
379
|
+
<div
|
|
380
|
+
data-docstream-blocks=""
|
|
381
|
+
className={inline ? "docs-blocks-inline" : undefined}
|
|
382
|
+
style={inline ? { display: "inline" } : undefined}
|
|
383
|
+
>
|
|
380
384
|
{blocks.map((b, i) => (
|
|
381
385
|
<BlockView key={i} block={b} liveRenderer={liveRenderer} sourceRenderer={sourceRenderer} />
|
|
382
386
|
))}
|
package/src/docs/reference.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, useContext, useId, useState, type ReactNode } from "react"
|
|
2
|
-
import { ArrowUpRight, AtSign, Globe, Hash } from "lucide-react"
|
|
2
|
+
import { ArrowUpRight, AtSign, FolderGit2, Globe, Hash } from "lucide-react"
|
|
3
3
|
|
|
4
4
|
import type { CitationDef, ReferenceNode } from "../gitbook/ast"
|
|
5
5
|
|
|
@@ -112,7 +112,7 @@ export function InlineReference({ node }: { node: ReferenceNode }) {
|
|
|
112
112
|
)
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
const Icon = node.kind === "mention" ? AtSign : Hash
|
|
115
|
+
const Icon = node.kind === "mention" ? AtSign : node.kind === "codebase" ? FolderGit2 : Hash
|
|
116
116
|
return (
|
|
117
117
|
<button
|
|
118
118
|
type="button"
|
package/src/gitbook/ast.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface InlineImageNode {
|
|
|
23
23
|
link?: string
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export type ReferenceKind = "mention" | "tag" | "citation"
|
|
26
|
+
export type ReferenceKind = "mention" | "tag" | "codebase" | "citation"
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Inline reference chip: `@mention`, `#tag`, or footnote-style citation `[^id]`.
|
package/src/gitbook/inline.ts
CHANGED
|
@@ -10,8 +10,13 @@ export const refDefinitions = new Map<string, string>()
|
|
|
10
10
|
// parseMarkdown and consumed here to resolve [^id] markers.
|
|
11
11
|
export const footnoteDefinitions = new Map<string, { url: string; label?: string }>()
|
|
12
12
|
|
|
13
|
-
// @mention / #tag body: letter/underscore start, then word chars, dots,
|
|
13
|
+
// @mention / #tag / $codebase body: letter/underscore start, then word chars, dots,
|
|
14
|
+
// dashes. Codebase ids may also carry `/` (`$org/repo`). A letter start keeps prices
|
|
15
|
+
// like $5 plain text.
|
|
14
16
|
const REFERENCE_BODY_RE = /^[@#]([A-Za-z_][\w.-]*)/
|
|
17
|
+
const CODEBASE_BODY_RE = /^\$([A-Za-z_][\w.\/-]*)/
|
|
18
|
+
const SIGIL_KIND = { "@": "mention", "#": "tag", $: "codebase" } as const
|
|
19
|
+
const KIND_SIGIL = { mention: "@", tag: "#", codebase: "$" } as const
|
|
15
20
|
// Chips are only recognized at start-of-input or after whitespace/open brackets,
|
|
16
21
|
// so brett@replay.io and C# stay plain text.
|
|
17
22
|
const isReferenceBoundary = (prev: string | undefined) =>
|
|
@@ -131,14 +136,14 @@ export function parseInline(src: string, marks: Marks = {}): Inline[] {
|
|
|
131
136
|
continue
|
|
132
137
|
}
|
|
133
138
|
|
|
134
|
-
// @mention / #tag chips, only at a word boundary
|
|
135
|
-
if ((rest[0] === "@" || rest[0] === "#") && isReferenceBoundary(src[i - 1])) {
|
|
136
|
-
const m = rest.match(REFERENCE_BODY_RE)
|
|
139
|
+
// @mention / #tag / $codebase chips, only at a word boundary
|
|
140
|
+
if ((rest[0] === "@" || rest[0] === "#" || rest[0] === "$") && isReferenceBoundary(src[i - 1])) {
|
|
141
|
+
const m = rest.match(rest[0] === "$" ? CODEBASE_BODY_RE : REFERENCE_BODY_RE)
|
|
137
142
|
if (m) {
|
|
138
|
-
const id = m[1].replace(/[
|
|
143
|
+
const id = m[1].replace(/[./-]+$/, "")
|
|
139
144
|
if (id) {
|
|
140
145
|
flush()
|
|
141
|
-
out.push({ type: "reference", kind: rest[0]
|
|
146
|
+
out.push({ type: "reference", kind: SIGIL_KIND[rest[0] as "@" | "#" | "$"], id })
|
|
142
147
|
i += 1 + id.length
|
|
143
148
|
continue
|
|
144
149
|
}
|
|
@@ -200,14 +205,14 @@ export function parseInline(src: string, marks: Marks = {}): Inline[] {
|
|
|
200
205
|
const escapeText = (t: string) =>
|
|
201
206
|
t
|
|
202
207
|
.replace(/([*_~`[\]\\])/g, "\\$1")
|
|
203
|
-
// Escape
|
|
208
|
+
// Escape @/#/$ only at a chip boundary so emails/C#/$5 survive untouched.
|
|
204
209
|
// Note: node-local — a boundary formed across adjacent inline nodes
|
|
205
210
|
// (previous node ending in whitespace) is not caught; rare, accepted.
|
|
206
|
-
.replace(/(^|[\s([{])([
|
|
211
|
+
.replace(/(^|[\s([{])([@#$])(?=[A-Za-z_])/g, "$1\\$2")
|
|
207
212
|
|
|
208
213
|
export function serializeReference(n: ReferenceNode): string {
|
|
209
214
|
if (n.kind === "citation") return `[^${n.id}]`
|
|
210
|
-
return `${n.kind
|
|
215
|
+
return `${KIND_SIGIL[n.kind]}${n.id}`
|
|
211
216
|
}
|
|
212
217
|
|
|
213
218
|
function serializeImage(n: InlineImageNode): string {
|
package/src/styles.css
CHANGED
|
@@ -68,44 +68,87 @@
|
|
|
68
68
|
white-space: pre-wrap;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
:is([data-docstream], .docs-article) {
|
|
72
|
+
color: var(--foreground, #18181b);
|
|
73
|
+
line-height: 1.65;
|
|
74
|
+
font-size: 15.5px;
|
|
75
|
+
}
|
|
76
|
+
|
|
71
77
|
.docs-article {
|
|
72
78
|
max-width: 760px;
|
|
73
79
|
margin: 0 auto;
|
|
74
80
|
padding: 48px 32px 120px;
|
|
75
|
-
line-height: 1.65;
|
|
76
|
-
font-size: 15.5px;
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
.docs-article
|
|
80
|
-
margin-
|
|
83
|
+
:is([data-docstream], .docs-article) [data-docstream-blocks] > * {
|
|
84
|
+
margin-block: 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
:is([data-docstream], .docs-article) [data-docstream-blocks] > * + * {
|
|
88
|
+
margin-block-start: 0.9em;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
:is([data-docstream], .docs-article) :is(h1, h2, h3, h4, h5, h6) {
|
|
92
|
+
color: inherit;
|
|
93
|
+
display: block;
|
|
94
|
+
font-family: inherit;
|
|
95
|
+
font-weight: 650;
|
|
96
|
+
line-height: 1.25;
|
|
97
|
+
margin-block: 1.6em 0.45em;
|
|
98
|
+
text-wrap: pretty;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
:is([data-docstream], .docs-article) [data-docstream-blocks] > :is(h1, h2, h3, h4, h5, h6) {
|
|
102
|
+
margin-block-start: 1.6em;
|
|
81
103
|
}
|
|
82
104
|
|
|
83
|
-
.docs-article h1 {
|
|
105
|
+
:is([data-docstream], .docs-article) [data-docstream-blocks] > :first-child:is(h1, h2, h3, h4, h5, h6) {
|
|
106
|
+
margin-block-start: 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
:is([data-docstream], .docs-article) h1 {
|
|
84
110
|
font-size: 2.2em;
|
|
85
111
|
font-weight: 700;
|
|
86
|
-
margin-top: 0.6em;
|
|
87
112
|
}
|
|
88
113
|
|
|
89
|
-
.docs-article h2 {
|
|
114
|
+
:is([data-docstream], .docs-article) h2 {
|
|
90
115
|
font-size: 1.5em;
|
|
91
|
-
font-weight:
|
|
92
|
-
margin-top: 1.4em;
|
|
116
|
+
font-weight: 675;
|
|
93
117
|
padding-bottom: 0.2em;
|
|
94
118
|
border-bottom: 1px solid var(--border, #e4e4e7);
|
|
95
119
|
}
|
|
96
120
|
|
|
97
|
-
.docs-article h3 {
|
|
121
|
+
:is([data-docstream], .docs-article) h3 {
|
|
98
122
|
font-size: 1.2em;
|
|
99
123
|
font-weight: 600;
|
|
100
|
-
margin-top: 1.1em;
|
|
101
124
|
}
|
|
102
125
|
|
|
103
|
-
.docs-article
|
|
126
|
+
:is([data-docstream], .docs-article) h4 {
|
|
127
|
+
font-size: 1.08em;
|
|
128
|
+
font-weight: 600;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
:is([data-docstream], .docs-article) h5 {
|
|
132
|
+
font-size: 1em;
|
|
133
|
+
font-weight: 600;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
:is([data-docstream], .docs-article) h6 {
|
|
137
|
+
font-size: 0.92em;
|
|
138
|
+
font-weight: 600;
|
|
139
|
+
letter-spacing: 0.02em;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
:is([data-docstream], .docs-article) p {
|
|
143
|
+
margin-block: 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
:is([data-docstream], .docs-article) a {
|
|
104
147
|
color: var(--gb-primary);
|
|
105
148
|
text-decoration: underline;
|
|
106
149
|
}
|
|
107
150
|
|
|
108
|
-
.docs-article code {
|
|
151
|
+
:is([data-docstream], .docs-article) code {
|
|
109
152
|
background: var(--gb-muted);
|
|
110
153
|
border-radius: 4px;
|
|
111
154
|
padding: 0.15em 0.35em;
|
|
@@ -113,12 +156,12 @@
|
|
|
113
156
|
font-family: ui-monospace, Menlo, monospace;
|
|
114
157
|
}
|
|
115
158
|
|
|
116
|
-
.docs-article ul {
|
|
159
|
+
:is([data-docstream], .docs-article) ul {
|
|
117
160
|
list-style: disc;
|
|
118
161
|
padding-left: 1.5em;
|
|
119
162
|
}
|
|
120
163
|
|
|
121
|
-
.docs-article ol {
|
|
164
|
+
:is([data-docstream], .docs-article) ol {
|
|
122
165
|
list-style: decimal;
|
|
123
166
|
padding-left: 1.5em;
|
|
124
167
|
}
|
|
@@ -148,24 +191,24 @@
|
|
|
148
191
|
margin: 0;
|
|
149
192
|
}
|
|
150
193
|
|
|
151
|
-
.docs-article blockquote {
|
|
194
|
+
:is([data-docstream], .docs-article) blockquote {
|
|
152
195
|
border-left: 3px solid var(--gb-border);
|
|
153
196
|
padding-left: 1em;
|
|
154
197
|
color: var(--gb-muted-foreground);
|
|
155
198
|
}
|
|
156
199
|
|
|
157
|
-
.docs-article hr {
|
|
200
|
+
:is([data-docstream], .docs-article) hr {
|
|
158
201
|
border: none;
|
|
159
202
|
border-top: 1px solid var(--gb-border);
|
|
160
203
|
margin: 2em 0;
|
|
161
204
|
}
|
|
162
205
|
|
|
163
|
-
.docs-article figure img {
|
|
206
|
+
:is([data-docstream], .docs-article) figure img {
|
|
164
207
|
border-radius: 12px;
|
|
165
208
|
max-width: 100%;
|
|
166
209
|
}
|
|
167
210
|
|
|
168
|
-
.docs-article figcaption {
|
|
211
|
+
:is([data-docstream], .docs-article) figcaption {
|
|
169
212
|
text-align: center;
|
|
170
213
|
font-size: 13px;
|
|
171
214
|
color: var(--gb-muted-foreground);
|
|
@@ -1073,6 +1116,16 @@
|
|
|
1073
1116
|
color: var(--gb-accent-foreground);
|
|
1074
1117
|
}
|
|
1075
1118
|
|
|
1119
|
+
.docs-ref-codebase {
|
|
1120
|
+
border: 1px solid rgba(34, 197, 94, 0.45);
|
|
1121
|
+
background: rgba(34, 197, 94, 0.1);
|
|
1122
|
+
color: rgb(74, 222, 128);
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
.docs-ref-codebase:hover {
|
|
1126
|
+
background: rgba(34, 197, 94, 0.18);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1076
1129
|
.docs-cite-wrap {
|
|
1077
1130
|
position: relative;
|
|
1078
1131
|
display: inline-block;
|