@datocms/svelte 4.2.1 → 4.2.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/package/components/Head/serializeTag.d.ts +1 -1
- package/package/components/Head/serializeTag.js +8 -8
- package/package/components/Image/README.md +1 -0
- package/package/components/StructuredText/Node.svelte +20 -30
- package/package/components/StructuredText/Node.svelte.d.ts +1 -0
- package/package/components/StructuredText/README.md +16 -6
- package/package/components/StructuredText/StructuredText.svelte +3 -1
- package/package.json +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GenericTag, SeoOrFaviconTag } from
|
|
1
|
+
import type { GenericTag, SeoOrFaviconTag } from './Head.svelte';
|
|
2
2
|
/** Replaces special chars (&<>"') with HTML entities */
|
|
3
3
|
export declare const escapeHtml: (html: string) => string;
|
|
4
4
|
export declare const serializeTag: (metaTag: GenericTag | SeoOrFaviconTag) => string;
|
|
@@ -3,27 +3,27 @@ export const escapeHtml = (html) => {
|
|
|
3
3
|
return (html
|
|
4
4
|
.replace(/[<>"']/g, (match) => {
|
|
5
5
|
switch (match) {
|
|
6
|
-
case
|
|
7
|
-
return
|
|
8
|
-
case
|
|
9
|
-
return
|
|
6
|
+
case '<':
|
|
7
|
+
return '<';
|
|
8
|
+
case '>':
|
|
9
|
+
return '>';
|
|
10
10
|
case '"':
|
|
11
|
-
return
|
|
11
|
+
return '"';
|
|
12
12
|
case "'":
|
|
13
|
-
return
|
|
13
|
+
return ''';
|
|
14
14
|
default:
|
|
15
15
|
return match;
|
|
16
16
|
}
|
|
17
17
|
})
|
|
18
18
|
// ensure existing HTML entities (like © or ©) are left untouched
|
|
19
|
-
.replace(/&(?!#?[a-z0-9]+;)/gi,
|
|
19
|
+
.replace(/&(?!#?[a-z0-9]+;)/gi, '&'));
|
|
20
20
|
};
|
|
21
21
|
export const serializeTag = (metaTag) => {
|
|
22
22
|
const { tag, attributes, content } = metaTag;
|
|
23
23
|
const serializedAttributes = attributes
|
|
24
24
|
? Object.entries(attributes).flatMap(([key, value]) => value ? `${escapeHtml(key)}="${escapeHtml(value)}"` : [])
|
|
25
25
|
: [];
|
|
26
|
-
const attributesString = serializedAttributes.length > 0 ? ` ${serializedAttributes.join(
|
|
26
|
+
const attributesString = serializedAttributes.length > 0 ? ` ${serializedAttributes.join(' ')}` : '';
|
|
27
27
|
return content
|
|
28
28
|
? `<${tag}${attributesString}>${content}</${tag}>`
|
|
29
29
|
: `<${tag}${attributesString}/>`;
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
|
20
20
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
|
21
21
|
|
|
22
|
+
- [Setup](#setup)
|
|
22
23
|
- [Usage](#usage)
|
|
23
24
|
- [`<Image />` vs `<NakedImage />`](#image--vs-nakedimage-)
|
|
24
25
|
- [Example](#example)
|
|
@@ -38,30 +38,10 @@ export const DEFAULT_COMPONENTS = [
|
|
|
38
38
|
[isCode, Code]
|
|
39
39
|
];
|
|
40
40
|
const throwRenderErrorForMissingComponent = (node) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
if (isItemLink(node)) {
|
|
48
|
-
throw new RenderError(
|
|
49
|
-
`The Structured Text document contains an 'itemLink' node, but no component for rendering is specified!`,
|
|
50
|
-
node
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
if (isBlock(node)) {
|
|
54
|
-
throw new RenderError(
|
|
55
|
-
`The Structured Text document contains a 'block' node, but no component for rendering is specified!`,
|
|
56
|
-
node
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
if (isInlineBlock(node)) {
|
|
60
|
-
throw new RenderError(
|
|
61
|
-
`The Structured Text document contains an 'inlineBlock' node, but no component for rendering is specified!`,
|
|
62
|
-
node
|
|
63
|
-
);
|
|
64
|
-
}
|
|
41
|
+
throw new RenderError(
|
|
42
|
+
`The Structured Text document contains an '${node.type}' node, but no component for rendering is specified!`,
|
|
43
|
+
node
|
|
44
|
+
);
|
|
65
45
|
};
|
|
66
46
|
const throwRenderErrorForMissingBlock = (node) => {
|
|
67
47
|
throw new RenderError(
|
|
@@ -69,6 +49,12 @@ const throwRenderErrorForMissingBlock = (node) => {
|
|
|
69
49
|
node
|
|
70
50
|
);
|
|
71
51
|
};
|
|
52
|
+
const throwRenderErrorForMissingInlineBlock = (node) => {
|
|
53
|
+
throw new RenderError(
|
|
54
|
+
`The Structured Text document contains a '${node.type}' node, but cannot find a record with ID ${node.item} inside data.inlineBlocks!`,
|
|
55
|
+
node
|
|
56
|
+
);
|
|
57
|
+
};
|
|
72
58
|
const throwRenderErrorForMissingLink = (node) => {
|
|
73
59
|
throw new RenderError(
|
|
74
60
|
`The Structured Text document contains an 'itemLink' node, but cannot find a record with ID ${node.item} inside data.links!`,
|
|
@@ -76,20 +62,24 @@ const throwRenderErrorForMissingLink = (node) => {
|
|
|
76
62
|
);
|
|
77
63
|
};
|
|
78
64
|
const findBlock = (node, blocks) => (blocks || []).find(({ id }) => id === node.item);
|
|
65
|
+
const findInlineBlock = (node, inlineBlocks) => (inlineBlocks || []).find(({ id }) => id === node.item);
|
|
79
66
|
const findLink = (node, links) => (links || []).find(({ id }) => id === node.item);
|
|
80
67
|
</script>
|
|
81
68
|
|
|
82
69
|
<script>import { hasChildren } from "datocms-structured-text-utils";
|
|
83
70
|
export let node;
|
|
84
71
|
export let blocks;
|
|
72
|
+
export let inlineBlocks;
|
|
85
73
|
export let links;
|
|
86
74
|
export let components = [];
|
|
87
75
|
$:
|
|
88
|
-
|
|
76
|
+
predicateComponentTuple = [...components, ...DEFAULT_COMPONENTS].find(([predicate, component2]) => predicate(node)) || throwRenderErrorForMissingComponent(node);
|
|
89
77
|
$:
|
|
90
|
-
|
|
78
|
+
block = isBlock(node) && (findBlock(node, blocks) || throwRenderErrorForMissingBlock(node));
|
|
91
79
|
$:
|
|
92
|
-
|
|
80
|
+
inlineBlock = isInlineBlock(node) && (findInlineBlock(node, inlineBlocks) || throwRenderErrorForMissingInlineBlock(node));
|
|
81
|
+
$:
|
|
82
|
+
link = isItemLink(node) && (findLink(node, links) || throwRenderErrorForMissingLink(node)) || isInlineItem(node) && (findLink(node, links) || throwRenderErrorForMissingLink(node));
|
|
93
83
|
$:
|
|
94
84
|
component = (predicateComponentTuple ?? [])[1];
|
|
95
85
|
</script>
|
|
@@ -98,14 +88,14 @@ $:
|
|
|
98
88
|
{#if isBlock(node)}
|
|
99
89
|
<svelte:component this={component} {node} {block} />
|
|
100
90
|
{:else if isInlineBlock(node)}
|
|
101
|
-
<svelte:component this={component} {node} {
|
|
91
|
+
<svelte:component this={component} {node} block={inlineBlock} />
|
|
102
92
|
{:else if isInlineItem(node)}
|
|
103
93
|
<svelte:component this={component} {node} {link} />
|
|
104
94
|
{:else if isItemLink(node)}
|
|
105
95
|
<svelte:component this={component} {node} {link}>
|
|
106
96
|
{#if hasChildren(node)}
|
|
107
97
|
{#each node.children as child}
|
|
108
|
-
<svelte:self node={child} {blocks} {links} {components} />
|
|
98
|
+
<svelte:self node={child} {blocks} {inlineBlocks} {links} {components} />
|
|
109
99
|
{/each}
|
|
110
100
|
{/if}
|
|
111
101
|
</svelte:component>
|
|
@@ -113,7 +103,7 @@ $:
|
|
|
113
103
|
<svelte:component this={component} {node}>
|
|
114
104
|
{#if hasChildren(node)}
|
|
115
105
|
{#each node.children as child}
|
|
116
|
-
<svelte:self node={child} {blocks} {links} {components} />
|
|
106
|
+
<svelte:self node={child} {blocks} {inlineBlocks} {links} {components} />
|
|
117
107
|
{/each}
|
|
118
108
|
{/if}
|
|
119
109
|
</svelte:component>
|
|
@@ -82,7 +82,7 @@ You need to use custom components in the following cases:
|
|
|
82
82
|
|
|
83
83
|
### Custom components for blocks
|
|
84
84
|
|
|
85
|
-
Here is an example using custom components for blocks, inline and
|
|
85
|
+
Here is an example using custom components for blocks, inline blocks, inline records and links to records. Take a look at the [test fixtures](https://github.com/datocms/datocms-svelte/tree/main/src/lib/components/StructuredText/__tests__/__fixtures__) to see examples on how to implement these components.
|
|
86
86
|
|
|
87
87
|
```svelte
|
|
88
88
|
<script>
|
|
@@ -123,6 +123,15 @@ const query = `
|
|
|
123
123
|
url
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
+
inlineBlocks {
|
|
127
|
+
... on RecordInterface {
|
|
128
|
+
id
|
|
129
|
+
__typename
|
|
130
|
+
}
|
|
131
|
+
... on MentionRecord {
|
|
132
|
+
username
|
|
133
|
+
}
|
|
134
|
+
}
|
|
126
135
|
}
|
|
127
136
|
}
|
|
128
137
|
}
|
|
@@ -145,6 +154,7 @@ onMount(async () => {
|
|
|
145
154
|
[isInlineItem, InlineItem],
|
|
146
155
|
[isItemLink, ItemLink],
|
|
147
156
|
[isBlock, Block]
|
|
157
|
+
[isInlineBlock, InlineBlock]
|
|
148
158
|
]}
|
|
149
159
|
/>
|
|
150
160
|
{/if}
|
|
@@ -153,7 +163,7 @@ onMount(async () => {
|
|
|
153
163
|
|
|
154
164
|
### Override default rendering of nodes
|
|
155
165
|
|
|
156
|
-
`<StructuredText />` automatically renders all nodes (except for `
|
|
166
|
+
`<StructuredText />` automatically renders all nodes (except for `inlineItem`, `itemLink`, `block` and `inlineBlock`) using a set of default components, that you might want to customize. For example:
|
|
157
167
|
|
|
158
168
|
- For `heading` nodes, you might want to add an anchor;
|
|
159
169
|
- For `code` nodes, you might want to use a custom syntax highlighting component;
|
|
@@ -181,7 +191,7 @@ In this case, you can easily override default rendering rules with the `componen
|
|
|
181
191
|
|
|
182
192
|
## Props
|
|
183
193
|
|
|
184
|
-
| prop | type | required
|
|
185
|
-
| ---------- | ----------------------------------------------------------------------------------------------------------- |
|
|
186
|
-
| data | `StructuredText \| DastNode` | :white_check_mark:
|
|
187
|
-
| components | [`PredicateComponentTuple[] \| null`](https://github.com/datocms/datocms-svelte/blob/main/src/lib/index.ts) | Only required if data
|
|
194
|
+
| prop | type | required | description | default |
|
|
195
|
+
| ---------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ------- |
|
|
196
|
+
| data | `StructuredText \| DastNode` | :white_check_mark: | The actual [field value](https://www.datocms.com/docs/structured-text/dast) you get from DatoCMS | |
|
|
197
|
+
| components | [`PredicateComponentTuple[] \| null`](https://github.com/datocms/datocms-svelte/blob/main/src/lib/index.ts) | Only required if data contains `block`, `inlineBlock`, `inlineItem` or `itemLink` nodes | Array of tuples formed by a predicate function and custom component | `[]` |
|
|
@@ -10,10 +10,12 @@ $:
|
|
|
10
10
|
node = !data ? null : isStructuredText(data) && isDocument(data.value) ? data.value.document : isDocument(data) ? data.document : isNode(data) ? data : void 0;
|
|
11
11
|
$:
|
|
12
12
|
blocks = isStructuredText(data) ? data?.blocks : void 0;
|
|
13
|
+
$:
|
|
14
|
+
inlineBlocks = isStructuredText(data) ? data?.inlineBlocks : void 0;
|
|
13
15
|
$:
|
|
14
16
|
links = isStructuredText(data) ? data?.links : void 0;
|
|
15
17
|
</script>
|
|
16
18
|
|
|
17
19
|
{#if node}
|
|
18
|
-
<Node {node} {blocks} {links} {components} />
|
|
20
|
+
<Node {node} {blocks} {inlineBlocks} {links} {components} />
|
|
19
21
|
{/if}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datocms/svelte",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.2",
|
|
4
4
|
"description": "A set of components and utilities to work faster with DatoCMS in Svelte",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"prepublishOnly": "npm run build",
|
|
20
20
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
21
21
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
22
|
-
"test:unit": "vitest",
|
|
22
|
+
"test:unit": "vitest --run",
|
|
23
23
|
"test": "npm run test:unit",
|
|
24
24
|
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
|
25
25
|
"format": "npm run toc && prettier --plugin-search-dir . --write .",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
47
47
|
"@typescript-eslint/parser": "^5.62.0",
|
|
48
48
|
"csstype": "^3.1.3",
|
|
49
|
-
"datocms-structured-text-generic-html-renderer": "^
|
|
49
|
+
"datocms-structured-text-generic-html-renderer": "^5.0.0",
|
|
50
50
|
"doctoc": "^2.0.0",
|
|
51
51
|
"eslint": "^8.56.0",
|
|
52
52
|
"eslint-config-prettier": "^8.10.0",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"type": "module",
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"datocms-listen": "^0.1.15",
|
|
69
|
-
"datocms-structured-text-utils": "^
|
|
69
|
+
"datocms-structured-text-utils": "^5.0.0",
|
|
70
70
|
"svelte-intersection-observer": "^1.0.0"
|
|
71
71
|
},
|
|
72
72
|
"exports": {
|