@relyio/sdk 0.12.0 → 0.14.0
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/CHANGELOG.md +228 -0
- package/dist/{chunk-3DRDHXLY.js → chunk-5UMY6CS4.js} +435 -23
- package/dist/{chunk-FRJEUAAF.js → chunk-DBBZVZOS.js} +968 -2670
- package/dist/{chunk-DXCVO6M5.cjs → chunk-GUPV2M3X.cjs} +969 -2680
- package/dist/{chunk-POEEDYFM.js → chunk-PCFTJLEP.js} +543 -260
- package/dist/{chunk-FI5VIF4M.cjs → chunk-RSHMA4KT.cjs} +442 -22
- package/dist/{chunk-3MSFWXQL.cjs → chunk-X4KSS7PP.cjs} +542 -260
- package/dist/client/index.cjs +3 -3
- package/dist/client/index.d.cts +4 -5
- package/dist/client/index.d.ts +4 -5
- package/dist/client/index.js +1 -1
- package/dist/{include-paths-CL4gHv6I.d.cts → define-content-type-BUZeWtpk.d.cts} +4458 -1312
- package/dist/{include-paths-CrJNTsMl.d.ts → define-content-type-DOrZb_a_.d.ts} +4458 -1312
- package/dist/define-schema-5aHmsA8j.d.ts +699 -0
- package/dist/define-schema-nCfZeboB.d.cts +699 -0
- package/dist/index-B97ZDj44.d.ts +507 -0
- package/dist/index-C-pcllqY.d.cts +507 -0
- package/dist/index-DOhFQbv7.d.ts +3065 -0
- package/dist/index-DgVV5Nj7.d.cts +3065 -0
- package/dist/index.cjs +114 -147
- package/dist/index.d.cts +49 -87
- package/dist/index.d.ts +49 -87
- package/dist/index.js +5 -29
- package/dist/markdown/index.cjs +13750 -0
- package/dist/markdown/index.d.cts +111 -0
- package/dist/markdown/index.d.ts +111 -0
- package/dist/markdown/index.js +13742 -0
- package/dist/rich-text/index.cjs +26 -6
- package/dist/rich-text/index.d.cts +3 -148
- package/dist/rich-text/index.d.ts +3 -148
- package/dist/rich-text/index.js +1 -1
- package/dist/rich-text.d-BWc-5gX1.d.cts +326 -0
- package/dist/rich-text.d-BWc-5gX1.d.ts +326 -0
- package/dist/schema/index.cjs +33 -37
- package/dist/schema/index.d.cts +37 -191
- package/dist/schema/index.d.ts +37 -191
- package/dist/schema/index.js +1 -1
- package/dist/types/index.d.cts +2 -3
- package/dist/types/index.d.ts +2 -3
- package/package.json +14 -3
- package/dist/define-schema-DgctHlI2.d.cts +0 -1034
- package/dist/define-schema-mrEZbY1h.d.ts +0 -1034
- package/dist/index-B9RfZVF1.d.ts +0 -861
- package/dist/index-BrvEg6-A.d.cts +0 -3729
- package/dist/index-Pw0onkJe.d.ts +0 -3729
- package/dist/index-b-AkfTUv.d.cts +0 -861
- package/dist/rich-text.d-rKmpgdGd.d.cts +0 -200
- package/dist/rich-text.d-rKmpgdGd.d.ts +0 -200
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
import { k as RichTextHeading, b as RichTextValue, y as RichTextTable, h as RichTextCodeGroup, e as RichTextBlock, l as RichTextInline, t as RichTextNode, w as RichTextSpan, r as RichTextMark, A as AnyRichTextEntryLink, c as RichTextShapeValue } from './rich-text.d-BWc-5gX1.cjs';
|
|
2
|
+
import { cs as BaseContent } from './define-content-type-BUZeWtpk.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The DOM↔field binding contract, as the one pure helper that emits it.
|
|
6
|
+
*
|
|
7
|
+
* Spread onto the element that renders a field, it stamps which entry, content type, field and
|
|
8
|
+
* locale produced that element, so an editing surface can find the field by scanning the DOM
|
|
9
|
+
* rather than by guessing (`INV-TB-BINDING`). The contract is `toolbar-spec.md` §DOM↔field; this
|
|
10
|
+
* file is its only implementation.
|
|
11
|
+
*
|
|
12
|
+
* **Frozen** (`INV-SS-BINDING-FROZEN`). The attribute set is exactly the five below. Adding,
|
|
13
|
+
* renaming or dropping one is a new contract, and a new contract is a bump of `data-relyio-v` — a
|
|
14
|
+
* page built against version 1 keeps being read as version 1 by any surface that scans it.
|
|
15
|
+
*
|
|
16
|
+
* **Pure** (`INV-TB-SDK-PURE`). It reads the entry it is handed and returns attributes. It imports
|
|
17
|
+
* nothing but the SDK's own types: no realtime, no AI, no first-party code, no framework. That is
|
|
18
|
+
* what lets it live in the customer SDK and run on a server render as happily as in a browser.
|
|
19
|
+
*
|
|
20
|
+
* **Every value comes from the entry.** The id, the content type and the locale are the ones the
|
|
21
|
+
* API reported in `_metadata` — the locale is the one the payload's field values were composed
|
|
22
|
+
* for. There is deliberately no `locale` argument: a caller-supplied locale could bind a node to a
|
|
23
|
+
* locale whose value it is not rendering, which is the silently inferred binding `INV-TB-BINDING`
|
|
24
|
+
* forbids.
|
|
25
|
+
*
|
|
26
|
+
* **The field is a path** (REL-1814). `data-relyio-field` has always named the binding's field path
|
|
27
|
+
* (`toolbar-spec.md`'s `(entryId, fieldPath, locale)`); it reaches into structure by key — a block of
|
|
28
|
+
* a page builder, a field of it, a declared Block in rich text — in the spelling every other surface
|
|
29
|
+
* names such a value by (`./key-path.ts`), so the attribute set and the version are unchanged. A
|
|
30
|
+
* binding continues into what it binds (`relyioField(binding, 'heading')`, `relyioField(binding,
|
|
31
|
+
* item)`), which is how `@relyio/react`'s `<Blocks>` and `<RichText>` stamp each item they render.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/** The version of the binding contract this helper emits. */
|
|
35
|
+
declare const BINDING_VERSION = "1";
|
|
36
|
+
/** The attributes `relyioField` returns — the whole of binding contract version 1. */
|
|
37
|
+
interface RelyIOFieldAttributes {
|
|
38
|
+
/** The entry's id (`_metadata.id`). */
|
|
39
|
+
readonly 'data-relyio-entry': string;
|
|
40
|
+
/** The entry's content type (`_metadata.type`); every customer read is keyed by it. */
|
|
41
|
+
readonly 'data-relyio-type': string;
|
|
42
|
+
/**
|
|
43
|
+
* The field the element renders: its id, or a key path into it — `sections[_key=="k1"].heading`
|
|
44
|
+
* (REL-1814).
|
|
45
|
+
*/
|
|
46
|
+
readonly 'data-relyio-field': string;
|
|
47
|
+
/** The locale the entry's field values were composed for (`_metadata.locale`). */
|
|
48
|
+
readonly 'data-relyio-locale': string;
|
|
49
|
+
/** The binding contract's version. */
|
|
50
|
+
readonly 'data-relyio-v': typeof BINDING_VERSION;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The field names `relyioField` accepts for an entry of type `T`.
|
|
54
|
+
*
|
|
55
|
+
* A schema-typed entry narrows to its declared field names, so they autocomplete and a misspelt
|
|
56
|
+
* one does not compile. An entry with no declared fields — `BaseContent`, which is what an
|
|
57
|
+
* un-generated client returns — has none to narrow to, and `keyof` of it is `never`; that would
|
|
58
|
+
* make the helper uncallable for every untyped customer, so it accepts any field name instead.
|
|
59
|
+
*/
|
|
60
|
+
type RelyIOFieldName<T extends BaseContent> = [Exclude<keyof T, '_metadata'>] extends [never] ? string : string & Exclude<keyof T, '_metadata'>;
|
|
61
|
+
/**
|
|
62
|
+
* The fields of `T` a key path may reach into: those holding a list, an object's value or rich text —
|
|
63
|
+
* each a value that names its shape in `_type`, or an array of items. A text, number or reference
|
|
64
|
+
* field holds nothing a path can name.
|
|
65
|
+
*/
|
|
66
|
+
type StructuredFieldName<T extends BaseContent> = {
|
|
67
|
+
[Name in Exclude<keyof T, '_metadata'> & string]: [NonNullable<T[Name]>] extends [
|
|
68
|
+
ReadonlyArray<unknown> | {
|
|
69
|
+
readonly _type: string;
|
|
70
|
+
}
|
|
71
|
+
] ? Name : never;
|
|
72
|
+
}[Exclude<keyof T, '_metadata'> & string];
|
|
73
|
+
/**
|
|
74
|
+
* What `relyioField(entry, path)` accepts for an entry of type `T` (REL-1814): a field's name, or a
|
|
75
|
+
* key path into a field holding structure — `sections[_key=="k1"].heading`, `hero.title`,
|
|
76
|
+
* `body[_key=="c1"]`. Its first step is held to `T`'s fields; what follows is checked when it runs,
|
|
77
|
+
* and an editor's resolver refuses a path the entry's schema does not know.
|
|
78
|
+
*/
|
|
79
|
+
type RelyIOFieldPath<T extends BaseContent> = [Exclude<keyof T, '_metadata'>] extends [never] ? string : RelyIOFieldName<T> | `${StructuredFieldName<T>}.${string}` | `${StructuredFieldName<T>}[_key==${string}`;
|
|
80
|
+
/** An item a binding continues to: anything carrying its `_key`, as every list item and block does. */
|
|
81
|
+
interface RelyIOKeyed {
|
|
82
|
+
readonly _key: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Binding attributes for one field of one entry, or for a value inside it by key path.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* import { relyioField } from '@relyio/sdk'
|
|
90
|
+
*
|
|
91
|
+
* <h1 {...relyioField(post, 'title')}>{post.title}</h1>
|
|
92
|
+
* // → data-relyio-entry="6710f…" data-relyio-type="post" data-relyio-field="title"
|
|
93
|
+
* // data-relyio-locale="en-US" data-relyio-v="1"
|
|
94
|
+
*
|
|
95
|
+
* <h2 {...relyioField(page, 'sections[_key=="f2k6ub9s"].heading')}>…</h2>
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* @throws {TypeError} when the entry's `_metadata` lacks its id, content type or locale. Every
|
|
99
|
+
* entry the API returns carries all three, so this is reached only by a value that was not read
|
|
100
|
+
* from RelyIO. It throws rather than emitting a partial binding: a node stamped with no locale, or
|
|
101
|
+
* none at all, is a binding a surface would have to guess the rest of. And when `path` is not a
|
|
102
|
+
* field or a key path — an index (`sections[0]`) names another item once the list is reordered.
|
|
103
|
+
*/
|
|
104
|
+
declare function relyioField<T extends BaseContent>(entry: T, path: RelyIOFieldPath<T>): RelyIOFieldAttributes;
|
|
105
|
+
/**
|
|
106
|
+
* The binding of a value inside one `relyioField` returned (REL-1814): a field below it — `heading`,
|
|
107
|
+
* `actions[_key=="b"].label` — or an item of the list (or rich text) it binds. What `<Blocks>` and
|
|
108
|
+
* `<RichText>` stamp each item with, and how a component binds what it renders inside its block:
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```tsx
|
|
112
|
+
* <Blocks
|
|
113
|
+
* value={page.sections}
|
|
114
|
+
* field={relyioField(page, 'sections')}
|
|
115
|
+
* components={{
|
|
116
|
+
* hero: (block, field) => (
|
|
117
|
+
* <header>
|
|
118
|
+
* <h1 {...relyioField(field, 'headline')}>{block.headline}</h1>
|
|
119
|
+
* </header>
|
|
120
|
+
* ),
|
|
121
|
+
* }}
|
|
122
|
+
* />
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* No binding — a renderer handed none — binds nothing: `undefined`, which spreads as no attribute.
|
|
126
|
+
*
|
|
127
|
+
* @throws {TypeError} when `binding` is not one `relyioField` returned, or the path it makes is not a
|
|
128
|
+
* key path — an item of an item, an item with no key.
|
|
129
|
+
*/
|
|
130
|
+
declare function relyioField(binding: RelyIOFieldAttributes, path: string | RelyIOKeyed): RelyIOFieldAttributes;
|
|
131
|
+
declare function relyioField(binding: RelyIOFieldAttributes | undefined, path: string | RelyIOKeyed): RelyIOFieldAttributes | undefined;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* A heading's anchor (REL-1808): the `id` every renderer gives a heading, and what an entry link's
|
|
135
|
+
* `anchor` names — so a site's `#anchor` lands on it.
|
|
136
|
+
*
|
|
137
|
+
* The rule is `@relyio/schema`'s `richTextHeadingSlug` and `richTextEntryHeadingAnchors`, restated
|
|
138
|
+
* here because this package takes no runtime from that one (it is build-inlined for types only);
|
|
139
|
+
* `devtools/verification`'s `rich-text-anchors-sdk.test.ts` holds the two to one corpus, as the server
|
|
140
|
+
* checks an entry link's anchor against the schema's on publish. GitHub's: the heading's text
|
|
141
|
+
* (a line break a space) trimmed and lower-cased, every character that is not a letter, a digit, a
|
|
142
|
+
* combining mark, a space, a hyphen or an underscore removed, each space a hyphen; a second heading
|
|
143
|
+
* of one text `setup-1`, a third `setup-2`; a heading with no such character has no anchor.
|
|
144
|
+
*
|
|
145
|
+
* Anchors are unique **per entry** (REL-2110): the headings of an entry's top-level rich-text fields
|
|
146
|
+
* are numbered across them in the order its type declares the fields — `intro`'s "Overview" is
|
|
147
|
+
* `overview`, `body`'s `overview-1` — and a read returns an entry's fields in that order, so
|
|
148
|
+
* {@link entryHeadingAnchors} needs nothing but the entry.
|
|
149
|
+
*/
|
|
150
|
+
|
|
151
|
+
/** A heading's anchor from its text, `''` when it has none: `UI options` is `ui-options`. */
|
|
152
|
+
declare function richTextHeadingSlug(text: string): string;
|
|
153
|
+
/**
|
|
154
|
+
* Every heading of one rich-text value with its anchor, in document order, numbered within that
|
|
155
|
+
* value alone — the tree's own headings at any depth, not those inside a declared block, whose
|
|
156
|
+
* component draws them. What a field rendered with no entry around it gives its headings; for an
|
|
157
|
+
* entry with several rich-text fields, {@link entryHeadingAnchors} numbers them across the fields.
|
|
158
|
+
*/
|
|
159
|
+
declare function richTextHeadingAnchors(value: unknown): ReadonlyMap<RichTextHeading<never, never>, string>;
|
|
160
|
+
/**
|
|
161
|
+
* Every heading of an entry's rich-text fields with its anchor (REL-2110): each top-level field
|
|
162
|
+
* holding a rich-text value, in the order the entry holds them — a read returns an entry's fields in
|
|
163
|
+
* the order its type declares them — and each value's document order, numbered across the entry. So
|
|
164
|
+
* `intro`'s "Overview" is `overview` and `body`'s `overview-1`, the anchors the server checks an
|
|
165
|
+
* entry link's `anchor` against. Hand it to `<RichText anchors>` or `richTextToHtml`'s `anchors` for
|
|
166
|
+
* each field of the entry, and read a heading's `id` from it where you draw headings yourself.
|
|
167
|
+
*
|
|
168
|
+
* Pass the entry as the read returned it, in one locale and with every rich-text field before the
|
|
169
|
+
* one you render: a field left out of the read, or a value moved, numbers the headings after it
|
|
170
|
+
* differently.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* const anchors = entryHeadingAnchors(page)
|
|
175
|
+
* const html = richTextToHtml(page.intro, { anchors }) + richTextToHtml(page.body, { anchors })
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
declare function entryHeadingAnchors(entry: object | null | undefined): ReadonlyMap<RichTextHeading<never, never>, string>;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The one walk of a rich-text tree into elements, for every output (REL-1804).
|
|
182
|
+
*
|
|
183
|
+
* Rich text is a versioned tree (ADR 0013, `RichTextValue`). What each built-in looks like by
|
|
184
|
+
* default — which element a node or a mark becomes, with which attributes, holding what — is
|
|
185
|
+
* written here once, generic over the output: {@link richTextToHtml} hands it a target that builds
|
|
186
|
+
* strings, `@relyio/react`'s `<RichText>` one that builds React elements. So the HTML a server
|
|
187
|
+
* writes and the markup `<RichText>` renders are one rendering by construction, not two kept equal
|
|
188
|
+
* by hand; a test over the corpus holds them byte for byte.
|
|
189
|
+
*
|
|
190
|
+
* Three rules every output inherits from this walk:
|
|
191
|
+
*
|
|
192
|
+
* - **Every tag is a literal here, never data.** A heading's level picks from a fixed table, and a
|
|
193
|
+
* level the table lacks renders as a paragraph. An attribute's name is a literal too; its value is
|
|
194
|
+
* the target's to escape.
|
|
195
|
+
* - **A link to an unsafe scheme is not a link.** An `href` is drawn only when it is relative or
|
|
196
|
+
* `http:`, `https:`, `mailto:` or `tel:` ({@link safeRichTextHref}); any other scheme —
|
|
197
|
+
* `javascript:`, `data:`, `vbscript:`, … — renders the link's text with no anchor, and a site's
|
|
198
|
+
* own `link` renderer is never handed one.
|
|
199
|
+
* - **Version 1 grows by addition** (`rich-text-format.md`). The switches below cover every node
|
|
200
|
+
* and mark of the vocabulary this build knows, with no fallback: a type added to it fails to
|
|
201
|
+
* compile here until it is drawn. At run time a newer server can still send a `_type` this build
|
|
202
|
+
* does not know; such a node renders nothing, and such a mark renders its text unformatted. Never
|
|
203
|
+
* an error.
|
|
204
|
+
* - **A declared Block or Inline element is the site's to draw** (REL-1807): RelyIO cannot know what a
|
|
205
|
+
* callout or a glossary term looks like, so the walk hands each to the target's `declared` — a
|
|
206
|
+
* node whose `_type` is no built-in's — and draws what it returns, nothing for `undefined`.
|
|
207
|
+
* `<RichText>` requires a component for every one the field declares; `richTextToHtml` and
|
|
208
|
+
* `richTextToMarkdown` take a function for each, likewise required.
|
|
209
|
+
* - **An entry link is the site's to draw too** (REL-1808): only the site knows its own URLs, so the
|
|
210
|
+
* walk hands each, with the runs it covers drawn, to the target's `entryLink`. Every output
|
|
211
|
+
* requires one wherever the field declares `links`.
|
|
212
|
+
* - **A heading carries its anchor as its `id`** (REL-1808, `./anchors.ts`): the slug of its text,
|
|
213
|
+
* deduplicated across the entry, the very anchor an entry link names — so a link's `#anchor`
|
|
214
|
+
* lands. A walk handed `anchors` (`entryHeadingAnchors(entry)`, REL-2110) reads each heading's
|
|
215
|
+
* there; one handed none numbers the value's own headings alone.
|
|
216
|
+
*/
|
|
217
|
+
|
|
218
|
+
/** Every element the default rendering of rich text uses. A tag is always one of these literals. */
|
|
219
|
+
type RichTextTag = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'blockquote' | 'ul' | 'ol' | 'li' | 'input' | 'pre' | 'code' | 'figure' | 'figcaption' | 'div' | 'table' | 'thead' | 'tbody' | 'tr' | 'th' | 'td' | 'hr' | 'br' | 'a' | 'strong' | 'em' | 'u' | 's' | 'mark' | 'sub' | 'sup';
|
|
220
|
+
/** The elements that hold nothing and have no closing tag. */
|
|
221
|
+
declare const RICH_TEXT_VOID_TAGS: ReadonlySet<RichTextTag>;
|
|
222
|
+
/**
|
|
223
|
+
* An element's attributes, in the order they are written. A value is a string or a number, or
|
|
224
|
+
* `true` for a boolean attribute that is present. `style` is a CSS declaration list (`text-align:center`).
|
|
225
|
+
*/
|
|
226
|
+
type RichTextAttributes = Readonly<Record<string, string | number | true>>;
|
|
227
|
+
/** Every node a site may draw itself: all of them but a run of text, whose marks are drawn instead. */
|
|
228
|
+
type RichTextReplaceableNode = Exclude<RichTextNode, RichTextSpan>;
|
|
229
|
+
/** Where a node stands, for a renderer that draws it differently there. */
|
|
230
|
+
interface RichTextNodeContext {
|
|
231
|
+
/** Whether a table row or cell is in the table's header row; `false` for every other node. */
|
|
232
|
+
readonly header: boolean;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* What a walk of the tree builds with. {@link renderRichText} decides what each built-in becomes and
|
|
236
|
+
* calls `element` and `text` for it; `node` and `mark` are where an output may draw a node or a mark
|
|
237
|
+
* its own way, handed the default drawing to fall back on.
|
|
238
|
+
*/
|
|
239
|
+
interface RichTextTarget<Out> {
|
|
240
|
+
/** An element of the default rendering. `key` is the node's `_key` when the element is a node's own. */
|
|
241
|
+
element(tag: RichTextTag, attributes: RichTextAttributes | undefined, children: readonly Out[], key: string | undefined): Out;
|
|
242
|
+
/** Text, exactly as the tree holds it: the target escapes it. */
|
|
243
|
+
text(text: string): Out;
|
|
244
|
+
/**
|
|
245
|
+
* A node, given what it holds already drawn (`contents`) and the default drawing of it (`draw`).
|
|
246
|
+
* Return `draw(contents)` to draw it the default way.
|
|
247
|
+
*/
|
|
248
|
+
node(node: RichTextReplaceableNode, contents: readonly Out[], draw: (contents: readonly Out[]) => Out, context: RichTextNodeContext): Out;
|
|
249
|
+
/**
|
|
250
|
+
* A mark around `contents`, the runs it covers already drawn. A link reaches it only with a safe
|
|
251
|
+
* `href`. Return `draw(contents)` to draw it the default way.
|
|
252
|
+
*/
|
|
253
|
+
mark(mark: RichTextMark, contents: readonly Out[], draw: (contents: readonly Out[]) => Out): Out;
|
|
254
|
+
/**
|
|
255
|
+
* An entry link around `contents`, the runs it covers already drawn (REL-1808): the site's own
|
|
256
|
+
* drawing — RelyIO cannot know its URLs. `to` is the linked entry's id, or the entry where the read
|
|
257
|
+
* included the field.
|
|
258
|
+
*/
|
|
259
|
+
entryLink(link: AnyRichTextEntryLink, contents: readonly Out[]): Out;
|
|
260
|
+
/**
|
|
261
|
+
* A declared Block (`block`, where blocks go) or Inline element (`inline`, beside a paragraph's
|
|
262
|
+
* text) — REL-1807: the site's own drawing of it, or `undefined` to draw nothing.
|
|
263
|
+
*/
|
|
264
|
+
declared(node: RichTextShapeValue, place: 'block' | 'inline'): Out | undefined;
|
|
265
|
+
}
|
|
266
|
+
/** Whether a node is a declared Block or Inline element: an object whose `_type` no built-in takes. */
|
|
267
|
+
declare function isDeclaredRichTextNode(node: unknown): boolean;
|
|
268
|
+
type ChildrenOf<V> = V extends {
|
|
269
|
+
readonly children: ReadonlyArray<infer Child>;
|
|
270
|
+
} ? Child : never;
|
|
271
|
+
/** A rich-text field's tree, of a union holding one; a `table` or `code` field's value is not. */
|
|
272
|
+
type TreeOf<V> = Extract<V, {
|
|
273
|
+
readonly _type: 'richText';
|
|
274
|
+
}>;
|
|
275
|
+
/**
|
|
276
|
+
* The declared Blocks a rich-text value may hold (REL-1807): its children that are no built-in —
|
|
277
|
+
* the fieldsets its field's `blocks` names, each its value. `never` for a field that declares none.
|
|
278
|
+
*/
|
|
279
|
+
type RichTextBlocksOf<V> = Exclude<ChildrenOf<TreeOf<V>>, {
|
|
280
|
+
readonly _type: RichTextBlock['_type'];
|
|
281
|
+
}>;
|
|
282
|
+
/** The declared Inline elements a rich-text value's paragraphs may hold (REL-1807); `never` for none. */
|
|
283
|
+
type RichTextInlineOf<V> = Exclude<ChildrenOf<Extract<ChildrenOf<TreeOf<V>>, {
|
|
284
|
+
readonly _type: 'paragraph';
|
|
285
|
+
}>>, {
|
|
286
|
+
readonly _type: RichTextInline['_type'];
|
|
287
|
+
}>;
|
|
288
|
+
/** Every declared Block and Inline element a rich-text value may hold, as one union. */
|
|
289
|
+
type RichTextDeclaredOf<V> = RichTextBlocksOf<V> | RichTextInlineOf<V>;
|
|
290
|
+
/** The `_type`s of {@link RichTextDeclaredOf}. */
|
|
291
|
+
type DeclaredTypeOf<V> = RichTextDeclaredOf<V> extends infer Node ? Node extends {
|
|
292
|
+
readonly _type: infer Type extends string;
|
|
293
|
+
} ? Type : never : never;
|
|
294
|
+
/**
|
|
295
|
+
* A function for every declared Block and Inline element a value may hold, keyed by its `_type` and
|
|
296
|
+
* handed exactly its value — what `richTextToHtml` and `richTextToMarkdown` take as `declared`.
|
|
297
|
+
*/
|
|
298
|
+
type RichTextDeclaredWriters<V, Out> = {
|
|
299
|
+
readonly [Type in DeclaredTypeOf<V>]: (value: Extract<RichTextDeclaredOf<V>, {
|
|
300
|
+
readonly _type: Type;
|
|
301
|
+
}>) => Out;
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* What the walk renders: a `richText` field's tree, or a `table` or `code` field's value — exactly
|
|
305
|
+
* one of the tree's built-ins (REL-1806), drawn as the same block is inside a tree, so a table field
|
|
306
|
+
* on a page and a table in a doc render the same markup.
|
|
307
|
+
*/
|
|
308
|
+
type RichTextRenderable = RichTextValue | RichTextTable | RichTextCodeGroup;
|
|
309
|
+
/**
|
|
310
|
+
* A renderable value of any field, its declared Blocks and Inline elements whatever they are: what a
|
|
311
|
+
* walk takes, and what `<RichText>`'s value is held to.
|
|
312
|
+
*/
|
|
313
|
+
type RichTextRenderableOf = RichTextValue<any, any, any> | RichTextTable<any, any> | RichTextCodeGroup;
|
|
314
|
+
/**
|
|
315
|
+
* The entry link a rich-text value's runs may carry (REL-1808): the mark, its `to` an id or — where the
|
|
316
|
+
* read included the field — the entry. `never` for a field that declares no `links`.
|
|
317
|
+
*/
|
|
318
|
+
type RichTextEntryLinkOf<V> = [TreeOf<V>] extends [never] ? never : TreeOf<V> extends RichTextValue<infer _B, infer _I, infer L> ? L : never;
|
|
319
|
+
/**
|
|
320
|
+
* What an output takes for an entry link (REL-1808): nothing for a value whose field declares no
|
|
321
|
+
* `links`; for one that does, `entryLink` — the site's drawing of a link, handed the link and what it
|
|
322
|
+
* covers already written, since only the site knows its URLs. The compiler requires it there.
|
|
323
|
+
*/
|
|
324
|
+
type RichTextEntryLinkOption<V, Out> = [RichTextEntryLinkOf<V>] extends [never] ? {
|
|
325
|
+
readonly entryLink?: never;
|
|
326
|
+
} : {
|
|
327
|
+
readonly entryLink: (link: RichTextEntryLinkOf<V>, contents: Out) => Out;
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* What every output takes to give a field's headings the anchors of the entry it belongs to
|
|
331
|
+
* (REL-2110): an entry's headings are numbered across its rich-text fields, so `body`'s "Overview"
|
|
332
|
+
* is `overview-1` where `intro` already has one.
|
|
333
|
+
*/
|
|
334
|
+
interface RichTextAnchorsOption {
|
|
335
|
+
/**
|
|
336
|
+
* Each heading's anchor, by the heading — `entryHeadingAnchors(entry)` for the entry the value
|
|
337
|
+
* belongs to. A heading it does not hold renders with no `id`. Absent, the value's own headings
|
|
338
|
+
* are numbered alone (`richTextHeadingAnchors(value)`), which is right for an entry with one
|
|
339
|
+
* rich-text field.
|
|
340
|
+
*/
|
|
341
|
+
readonly anchors?: ReadonlyMap<object, string>;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Walk `value` into `target`'s output: one entry per block the tree holds, in order — or, for a
|
|
345
|
+
* `table` or `code` field's value, the one block it is. A block of a `_type` this build does not
|
|
346
|
+
* know adds nothing. `options.anchors` gives the headings their entry's anchors.
|
|
347
|
+
*/
|
|
348
|
+
declare function renderRichText<Out>(value: RichTextRenderableOf, target: RichTextTarget<Out>, options?: RichTextAnchorsOption): Out[];
|
|
349
|
+
/**
|
|
350
|
+
* `href` as a link may carry it, or `undefined` when it must not be one: not a string, empty, or
|
|
351
|
+
* naming a scheme outside `http:`, `https:`, `mailto:` and `tel:`. The scheme is read the way a
|
|
352
|
+
* browser reads it — leading and trailing controls and spaces stripped, tabs and newlines removed
|
|
353
|
+
* anywhere — so `" java\tscript:"` is the `javascript:` it runs as. The `href` returned is the one
|
|
354
|
+
* given; escaping it is the output's.
|
|
355
|
+
*/
|
|
356
|
+
declare function safeRichTextHref(href: unknown): string | undefined;
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Rich text as HTML (REL-1804): the default rendering ({@link renderRichText}) written as a string.
|
|
360
|
+
* No DOM and no dependency, so it runs the same in a browser, Node and a Worker.
|
|
361
|
+
*
|
|
362
|
+
* **Each declared Block and Inline element carries its key path** (REL-2142), as `<RichText>` from
|
|
363
|
+
* `@relyio/react` stamps it (REL-1814). Handed the field's binding — `field: relyioField(post,
|
|
364
|
+
* 'body')` — each declared node's writer is handed that node's binding, `body[_key=="c1"]`, and the
|
|
365
|
+
* HTML it returns is stamped with it when it is exactly one element: the binding's attributes after
|
|
366
|
+
* the element's own, as React writes the props `<RichText>` stamps. Anything else — text, several
|
|
367
|
+
* elements, a comment — is written as it is, and the writer, holding the binding, writes it where it
|
|
368
|
+
* belongs; a root carrying `data-relyio-entry` already was bound by its writer and keeps its own.
|
|
369
|
+
*/
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* `text` with every character HTML gives a meaning escaped — `&`, `<`, `>`, `"` and `'` — as React
|
|
373
|
+
* escapes them, so this file's output and `<RichText>`'s server render are the same bytes.
|
|
374
|
+
*/
|
|
375
|
+
declare function escapeHtml(text: string): string;
|
|
376
|
+
/**
|
|
377
|
+
* What `richTextToHtml` takes beside the value: nothing for a field that declares no Block or Inline
|
|
378
|
+
* element; for one that does, `declared` — a function per declared `_type`, each returning that
|
|
379
|
+
* node's HTML (REL-1807). RelyIO cannot know what a callout looks like, so the compiler holds the
|
|
380
|
+
* map to every one the field declares, and to none it does not. What it returns is written as it is,
|
|
381
|
+
* stamped with the node's key path when `field` is given (REL-2142): escaping text the node holds is
|
|
382
|
+
* the function's ({@link escapeHtml}).
|
|
383
|
+
*/
|
|
384
|
+
type RichTextHtmlOptions<V> = [RichTextDeclaredOf<V> | RichTextEntryLinkOf<V>] extends [
|
|
385
|
+
never
|
|
386
|
+
] ? [
|
|
387
|
+
options?: {
|
|
388
|
+
readonly declared?: Record<string, never>;
|
|
389
|
+
readonly entryLink?: never;
|
|
390
|
+
} & RichTextAnchorsOption & RichTextHtmlFieldOption
|
|
391
|
+
] : [
|
|
392
|
+
options: DeclaredHtmlOption<V> & RichTextEntryLinkOption<V, string> & RichTextAnchorsOption & RichTextHtmlFieldOption
|
|
393
|
+
];
|
|
394
|
+
/** The binding of the field the value is (REL-2142), which each declared node's key path continues. */
|
|
395
|
+
interface RichTextHtmlFieldOption {
|
|
396
|
+
/**
|
|
397
|
+
* The field's binding — `relyioField(post, 'body')`, or `relyioField(field, 'body')` inside a
|
|
398
|
+
* declared node's writer — so each declared Block and Inline element is stamped with its key path.
|
|
399
|
+
* Absent, nothing is stamped and each writer is handed `undefined`.
|
|
400
|
+
*/
|
|
401
|
+
readonly field?: RelyIOFieldAttributes;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* A function for every declared Block and Inline element a value may hold, keyed by its `_type`:
|
|
405
|
+
* handed exactly its value, and its binding — `body[_key=="c1"]` — when `richTextToHtml` was handed
|
|
406
|
+
* the field's (REL-2142), `undefined` otherwise. What it writes inside itself binds below it:
|
|
407
|
+
* `richTextToHtml(value.body, { field: relyioField(field, 'body') })`.
|
|
408
|
+
*/
|
|
409
|
+
type RichTextHtmlDeclaredWriters<V> = {
|
|
410
|
+
readonly [Type in DeclaredTypeOf<V>]: (value: Extract<RichTextDeclaredOf<V>, {
|
|
411
|
+
readonly _type: Type;
|
|
412
|
+
}>, field: RelyIOFieldAttributes | undefined) => string;
|
|
413
|
+
};
|
|
414
|
+
type DeclaredHtmlOption<V> = [RichTextDeclaredOf<V>] extends [never] ? {
|
|
415
|
+
readonly declared?: Record<string, never>;
|
|
416
|
+
} : {
|
|
417
|
+
readonly declared: RichTextHtmlDeclaredWriters<V>;
|
|
418
|
+
};
|
|
419
|
+
/**
|
|
420
|
+
* A rich-text value as HTML: every built-in drawn the way `<RichText>` from `@relyio/react` draws it
|
|
421
|
+
* with no components given, text and attributes escaped. `''` for an absent value. A `table` or
|
|
422
|
+
* `code` field's value — one of the tree's built-ins — is drawn as the same block inside a tree.
|
|
423
|
+
*
|
|
424
|
+
* - A link keeps its `href` only when it is relative or `http:`, `https:`, `mailto:` or `tel:`;
|
|
425
|
+
* one to any other scheme (`javascript:`, `data:`, …) renders its text with no anchor.
|
|
426
|
+
* - A declared Block or Inline element (REL-1807) is written by `options.declared`, which a field
|
|
427
|
+
* declaring any requires; a value built by hand holding one no function names writes nothing.
|
|
428
|
+
* Handed `options.field` — `relyioField(post, 'body')` — each is stamped with its key path, and its
|
|
429
|
+
* writer handed the node's binding (REL-2142).
|
|
430
|
+
* - An entry link (REL-1808) is written by `options.entryLink`, handed the link — `to` an id, or the
|
|
431
|
+
* entry where the read included the field — and the HTML of the text it covers; a field declaring
|
|
432
|
+
* `links` requires it, since only your site knows its URLs.
|
|
433
|
+
* - A heading carries its anchor as its `id`: the slug of its text, the anchor an entry link names.
|
|
434
|
+
* `options.anchors` — `entryHeadingAnchors(entry)` — numbers the field's headings after those of
|
|
435
|
+
* the entry's fields before it (REL-2110); absent, the value's headings are numbered alone.
|
|
436
|
+
* - A node of a `_type` this version of the SDK does not know — content a newer server sends —
|
|
437
|
+
* renders nothing, and a mark it does not know leaves its text unformatted.
|
|
438
|
+
*
|
|
439
|
+
* @example
|
|
440
|
+
* ```ts
|
|
441
|
+
* import { richTextToHtml } from '@relyio/sdk'
|
|
442
|
+
*
|
|
443
|
+
* const post = await relyio.content('post').get('hello')
|
|
444
|
+
* const html = richTextToHtml(post?.body) // '<h2>Getting started</h2><p>Install the <code>SDK</code>…</p>'
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
447
|
+
declare function richTextToHtml<V extends RichTextRenderableOf | undefined>(value: V, ...[options]: RichTextHtmlOptions<V>): string;
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Rich text as plain Markdown (REL-1804): GitHub Flavored Markdown — CommonMark with tables, task
|
|
451
|
+
* lists and strikethrough — which drops what it cannot hold. RelyIO Markdown, the form that
|
|
452
|
+
* round-trips through directives for what plain Markdown lacks, is a separate serializer (REL-1809).
|
|
453
|
+
*
|
|
454
|
+
* What plain Markdown cannot hold, and what becomes of it:
|
|
455
|
+
*
|
|
456
|
+
* - The marks `underline`, `highlight`, `subscript` and `superscript`: their text, unformatted.
|
|
457
|
+
* - A code block's `filename`, `label` and line range: dropped; a code group's tabs follow one
|
|
458
|
+
* another as fenced blocks.
|
|
459
|
+
* - A table's per-cell alignment: a column takes its first row's; a table with no header row gets
|
|
460
|
+
* an empty one, since a Markdown table has to have one; a cell's paragraphs and line breaks join
|
|
461
|
+
* with spaces.
|
|
462
|
+
* - A line break in a heading: a space. An empty paragraph or heading: nothing.
|
|
463
|
+
* - A link to a scheme other than `http:`, `https:`, `mailto:` and `tel:`: its text, as in HTML.
|
|
464
|
+
* - A declared Block or Inline element (REL-1807): what `options.declared` writes for it — required
|
|
465
|
+
* for a field that declares any, since plain Markdown has no way to say a callout; a value built
|
|
466
|
+
* by hand holding one no function names writes nothing.
|
|
467
|
+
* - An entry link (REL-1808): what `options.entryLink` writes for it, handed the link and its text's
|
|
468
|
+
* Markdown — required for a field that declares `links`, since only your site knows its URLs. A
|
|
469
|
+
* heading's anchor is the one GitHub gives it, which is the anchor an entry link names.
|
|
470
|
+
* - A node of a `_type` this version of the SDK does not know: nothing. A mark it does not know:
|
|
471
|
+
* its text, unformatted.
|
|
472
|
+
*
|
|
473
|
+
* Text is escaped so it reads back as the same text: `*`, `_`, a bracket or a backtick in a
|
|
474
|
+
* sentence is a character, not syntax.
|
|
475
|
+
*/
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* What `richTextToMarkdown` takes beside the value: nothing for a field that declares no Block or
|
|
479
|
+
* Inline element; for one that does, `declared` — a function per declared `_type` returning its
|
|
480
|
+
* Markdown (REL-1807), held by the compiler to every one the field declares and to none other.
|
|
481
|
+
*/
|
|
482
|
+
type RichTextMarkdownOptions<V> = [RichTextDeclaredOf<V> | RichTextEntryLinkOf<V>] extends [
|
|
483
|
+
never
|
|
484
|
+
] ? [options?: {
|
|
485
|
+
readonly declared?: Record<string, never>;
|
|
486
|
+
readonly entryLink?: never;
|
|
487
|
+
}] : [options: DeclaredMarkdownOption<V> & RichTextEntryLinkOption<V, string>];
|
|
488
|
+
type DeclaredMarkdownOption<V> = [RichTextDeclaredOf<V>] extends [never] ? {
|
|
489
|
+
readonly declared?: Record<string, never>;
|
|
490
|
+
} : {
|
|
491
|
+
readonly declared: RichTextDeclaredWriters<V, string>;
|
|
492
|
+
};
|
|
493
|
+
/**
|
|
494
|
+
* A rich-text value as plain Markdown, ending in a newline; `''` for an absent or empty value. What
|
|
495
|
+
* Markdown cannot hold is dropped, its text kept (see the module's notes). A `table` or `code`
|
|
496
|
+
* field's value — one of the tree's built-ins — is written as the same block inside a tree.
|
|
497
|
+
*
|
|
498
|
+
* @example
|
|
499
|
+
* ```ts
|
|
500
|
+
* import { richTextToMarkdown } from '@relyio/sdk'
|
|
501
|
+
*
|
|
502
|
+
* richTextToMarkdown(post.body) // '## Getting started\n\nInstall the `SDK`, then read the [**guide**](/docs/guide).\n'
|
|
503
|
+
* ```
|
|
504
|
+
*/
|
|
505
|
+
declare function richTextToMarkdown<V extends RichTextRenderableOf | undefined>(value: V, ...[options]: RichTextMarkdownOptions<V>): string;
|
|
506
|
+
|
|
507
|
+
export { type RichTextNodeContext as A, type RichTextRenderable as B, type RichTextRenderableOf as C, type RichTextReplaceableNode as D, type RichTextTag as E, type RichTextTarget as F, type RelyIOFieldAttributes as R, type RelyIOFieldName as a, type RelyIOFieldPath as b, type RelyIOKeyed as c, richTextHeadingAnchors as d, entryHeadingAnchors as e, richTextHeadingSlug as f, escapeHtml as g, richTextToHtml as h, richTextToMarkdown as i, type RichTextHtmlDeclaredWriters as j, type RichTextHtmlFieldOption as k, type RichTextHtmlOptions as l, type RichTextMarkdownOptions as m, RICH_TEXT_VOID_TAGS as n, isDeclaredRichTextNode as o, renderRichText as p, type RichTextAnchorsOption as q, relyioField as r, safeRichTextHref as s, type RichTextAttributes as t, type RichTextBlocksOf as u, type RichTextDeclaredOf as v, type RichTextDeclaredWriters as w, type RichTextEntryLinkOf as x, type RichTextEntryLinkOption as y, type RichTextInlineOf as z };
|