@datocms/astro 0.3.3 → 0.3.5
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/Image/Image.astro +31 -1
- package/src/StructuredText/Node.astro +24 -11
- package/src/StructuredText/README.md +14 -13
- package/src/StructuredText/StructuredText.astro +18 -4
- package/src/StructuredText/nodes/InlineItem.astro +5 -5
- package/src/StructuredText/nodes/ItemLink.astro +5 -5
- package/src/StructuredText/nodes/Span.astro +31 -38
- package/src/StructuredText/types.ts +6 -4
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
👉 [Visit the DatoCMS homepage](https://www.datocms.com) or see [What is DatoCMS?](#what-is-datocms)
|
|
6
6
|
|
|
7
|
+
---
|
|
8
|
+
|
|
7
9
|
<!--datocms-autoinclude-header end-->
|
|
8
10
|
|
|
9
11
|
# @datocms/astro
|
|
@@ -38,6 +40,8 @@ npm install @datocms/astro
|
|
|
38
40
|
|
|
39
41
|
<!--datocms-autoinclude-footer start-->
|
|
40
42
|
|
|
43
|
+
---
|
|
44
|
+
|
|
41
45
|
# What is DatoCMS?
|
|
42
46
|
|
|
43
47
|
<a href="https://www.datocms.com/"><img src="https://www.datocms.com/images/full_logo.svg" height="60"></a>
|
package/package.json
CHANGED
package/src/Image/Image.astro
CHANGED
|
@@ -41,7 +41,7 @@ const sizingStyle = {
|
|
|
41
41
|
};
|
|
42
42
|
---
|
|
43
43
|
|
|
44
|
-
<picture class={pictureClass} style={pictureStyle}>
|
|
44
|
+
<picture class={pictureClass} style={pictureStyle} data-datocms-image="true">
|
|
45
45
|
{
|
|
46
46
|
data.webpSrcSet && (
|
|
47
47
|
<source srcset={data.webpSrcSet} sizes={sizes ?? data.sizes ?? null} type="image/webp" />
|
|
@@ -70,3 +70,33 @@ const sizingStyle = {
|
|
|
70
70
|
)
|
|
71
71
|
}
|
|
72
72
|
</picture>
|
|
73
|
+
|
|
74
|
+
<script>
|
|
75
|
+
function removeBackgroundStyles(element: HTMLElement) {
|
|
76
|
+
element.style.backgroundColor = '';
|
|
77
|
+
element.style.backgroundImage = '';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function setup() {
|
|
81
|
+
for (const pictureEl of [...document.querySelectorAll('picture[data-datocms-image=true]')]) {
|
|
82
|
+
const imgEl = pictureEl.querySelector('img');
|
|
83
|
+
|
|
84
|
+
if (!imgEl) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (imgEl.complete) {
|
|
89
|
+
removeBackgroundStyles(imgEl);
|
|
90
|
+
} else {
|
|
91
|
+
imgEl.addEventListener('load', () => removeBackgroundStyles(imgEl));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
document.addEventListener('DOMContentLoaded', setup);
|
|
97
|
+
document.addEventListener('astro:page-load', setup);
|
|
98
|
+
|
|
99
|
+
if (document.readyState === 'complete') {
|
|
100
|
+
setup();
|
|
101
|
+
}
|
|
102
|
+
</script>
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
isItemLink,
|
|
12
12
|
RenderError,
|
|
13
13
|
type NodeType,
|
|
14
|
+
isSpan,
|
|
14
15
|
} from 'datocms-structured-text-utils';
|
|
15
16
|
|
|
16
17
|
import Blockquote from './nodes/Blockquote.astro';
|
|
@@ -29,10 +30,11 @@ import ItemLinkComponent from './nodes/ItemLink.astro';
|
|
|
29
30
|
|
|
30
31
|
import type {
|
|
31
32
|
BlockComponents,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
InlineRecordComponents,
|
|
34
|
+
LinkToRecordComponents,
|
|
35
|
+
NodeOverrides,
|
|
35
36
|
AstroComponent,
|
|
37
|
+
MarkOverrides,
|
|
36
38
|
} from './types';
|
|
37
39
|
|
|
38
40
|
interface Props {
|
|
@@ -42,15 +44,24 @@ interface Props {
|
|
|
42
44
|
links?: DatocmsRecord[];
|
|
43
45
|
|
|
44
46
|
blockComponents?: BlockComponents<DatocmsRecord, DatocmsRecord>;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
linkToRecordComponents?: LinkToRecordComponents<DatocmsRecord, DatocmsRecord>;
|
|
48
|
+
inlineRecordComponents?: InlineRecordComponents<DatocmsRecord, DatocmsRecord>;
|
|
49
|
+
|
|
50
|
+
nodeOverrides?: NodeOverrides;
|
|
51
|
+
markOverrides?: MarkOverrides;
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
const { node, ...rest } = Astro.props;
|
|
51
55
|
|
|
52
|
-
const {
|
|
53
|
-
|
|
56
|
+
const {
|
|
57
|
+
blocks,
|
|
58
|
+
links,
|
|
59
|
+
blockComponents,
|
|
60
|
+
linkToRecordComponents,
|
|
61
|
+
inlineRecordComponents,
|
|
62
|
+
nodeOverrides,
|
|
63
|
+
markOverrides,
|
|
64
|
+
} = rest;
|
|
54
65
|
|
|
55
66
|
function findRecordInBlocks(node: Block) {
|
|
56
67
|
const record = (blocks || []).find(({ id }) => id === node.item);
|
|
@@ -96,7 +107,7 @@ const defaultComponents: Record<NodeType, AstroComponent> = {
|
|
|
96
107
|
|
|
97
108
|
const otherNodeComponents: Record<NodeType, AstroComponent> = {
|
|
98
109
|
...defaultComponents,
|
|
99
|
-
...
|
|
110
|
+
...nodeOverrides,
|
|
100
111
|
};
|
|
101
112
|
|
|
102
113
|
const Component = otherNodeComponents[node.type];
|
|
@@ -107,13 +118,15 @@ const Component = otherNodeComponents[node.type];
|
|
|
107
118
|
isBlock(node) ? (
|
|
108
119
|
<Component {node} block={findRecordInBlocks(node)} {blockComponents} />
|
|
109
120
|
) : isInlineItem(node) ? (
|
|
110
|
-
<Component {node} record={findRecordInLinks(node)} {
|
|
121
|
+
<Component {node} record={findRecordInLinks(node)} {inlineRecordComponents} />
|
|
111
122
|
) : isItemLink(node) ? (
|
|
112
|
-
<Component {node} record={findRecordInLinks(node)} {
|
|
123
|
+
<Component {node} record={findRecordInLinks(node)} {linkToRecordComponents}>
|
|
113
124
|
{node.children.map((child) => (
|
|
114
125
|
<Astro.self node={child} {...rest} />
|
|
115
126
|
))}
|
|
116
127
|
</Component>
|
|
128
|
+
) : isSpan(node) ? (
|
|
129
|
+
<Component {node} {markOverrides} />
|
|
117
130
|
) : (
|
|
118
131
|
<Component {node}>
|
|
119
132
|
{hasChildren(node) && node.children.map((child) => <Astro.self node={child} {...rest} />)}
|
|
@@ -63,8 +63,8 @@ You need to use custom components in the following cases:
|
|
|
63
63
|
### Custom components for blocks, inline records or links to records
|
|
64
64
|
|
|
65
65
|
- Astro components passed in `blockComponents` will be used to render blocks and will receive a `block` prop containing the actual block data.
|
|
66
|
-
- Astro components passed in `
|
|
67
|
-
- Astro components passed in `
|
|
66
|
+
- Astro components passed in `inlineRecordComponents` will be used to render inline records and will receive a `record` prop containing the actual record.
|
|
67
|
+
- Astro components passed in `linkToRecordComponents` will be used to render links to records and will receive the following props: `node` (the actual `'inlineItem'` node), `record` (the record linked to the node), and `attrs` (the custom attributes for the link specified by the node).
|
|
68
68
|
|
|
69
69
|
```astro
|
|
70
70
|
---
|
|
@@ -122,10 +122,10 @@ const { blogPost } = await executeQuery(query, { token: '<YOUR-API-TOKEN>' });
|
|
|
122
122
|
CtaRecord: Cta,
|
|
123
123
|
NewsletterSignupRecord: NewsletterSignup,
|
|
124
124
|
}}
|
|
125
|
-
|
|
125
|
+
inlineRecordComponents={{
|
|
126
126
|
TeamMemberRecord: InlineTeamMember,
|
|
127
127
|
}}
|
|
128
|
-
|
|
128
|
+
linkToRecordComponents={{
|
|
129
129
|
TeamMemberRecord: LinkToTeamMember,
|
|
130
130
|
}}
|
|
131
131
|
/>
|
|
@@ -139,7 +139,7 @@ const { blogPost } = await executeQuery(query, { token: '<YOUR-API-TOKEN>' });
|
|
|
139
139
|
- For `heading` nodes, you might want to add an anchor;
|
|
140
140
|
- For `code` nodes, you might want to use a custom syntax highlighting component;
|
|
141
141
|
|
|
142
|
-
In this case, you can easily override default rendering rules with the `
|
|
142
|
+
In this case, you can easily override default rendering rules with the `nodeOverrides` prop.
|
|
143
143
|
|
|
144
144
|
```astro
|
|
145
145
|
---
|
|
@@ -150,7 +150,7 @@ import Code from '~/components/Code/index.astro';
|
|
|
150
150
|
|
|
151
151
|
<StructuredText
|
|
152
152
|
data={blogPost.content}
|
|
153
|
-
|
|
153
|
+
nodeOverrides={{
|
|
154
154
|
heading: HeadingWithAnchorLink,
|
|
155
155
|
code: Code,
|
|
156
156
|
}}
|
|
@@ -159,10 +159,11 @@ import Code from '~/components/Code/index.astro';
|
|
|
159
159
|
|
|
160
160
|
## Props
|
|
161
161
|
|
|
162
|
-
| prop
|
|
163
|
-
|
|
|
164
|
-
| data
|
|
165
|
-
| blockComponents
|
|
166
|
-
|
|
|
167
|
-
|
|
|
168
|
-
|
|
|
162
|
+
| prop | type | required | description |
|
|
163
|
+
| ---------------------- | -------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
|
|
164
|
+
| data | `StructuredText \| DastNode` | :white_check_mark: | The actual [field value](https://www.datocms.com/docs/structured-text/dast) you get from DatoCMS |
|
|
165
|
+
| blockComponents | `Record<string, AstroComponent>` | | An object in which the keys are the `__typename` of the blocks to be rendered, and the values are the Astro components |
|
|
166
|
+
| linkToRecordComponents | `Record<string, AstroComponent>` | | An object in which the keys are the `__typename` of the records to be rendered, and the values are the Astro components |
|
|
167
|
+
| inlineRecordComponents | `Record<string, AstroComponent>` | | An object in which the keys are the `__typename` of the records to be rendered, and the values are the Astro components |
|
|
168
|
+
| nodeOverrides | `Record<string, AstroComponent>` | | An object in which the keys are the types of DAST nodes to override, and the values are the Astro components |
|
|
169
|
+
| markOverrides | `Record<string, AstroComponent>` | | An object in which the keys are the types of `span` node marks to override, and the values are the Astro components |
|
|
@@ -10,7 +10,13 @@ import {
|
|
|
10
10
|
} from 'datocms-structured-text-utils';
|
|
11
11
|
|
|
12
12
|
import Node from './Node.astro';
|
|
13
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
BlockComponents,
|
|
15
|
+
InlineRecordComponents,
|
|
16
|
+
LinkToRecordComponents,
|
|
17
|
+
NodeOverrides,
|
|
18
|
+
MarkOverrides,
|
|
19
|
+
} from './types';
|
|
14
20
|
|
|
15
21
|
// It would be better to type this as:
|
|
16
22
|
//
|
|
@@ -19,12 +25,20 @@ import type { BlockComponents, InlineItemComponents, ItemLinkComponents, Overrid
|
|
|
19
25
|
// but it's currently not possible: https://github.com/withastro/roadmap/discussions/601#discussioncomment-10333959
|
|
20
26
|
|
|
21
27
|
interface Props {
|
|
28
|
+
/** The actual [field value](https://www.datocms.com/docs/structured-text/dast) you get from a DatoCMS Structured Text field */
|
|
22
29
|
data: StructuredText<DatocmsRecord, DatocmsRecord> | Document | DastNode | null | undefined;
|
|
23
30
|
|
|
31
|
+
/** An object in which the keys are the `__typename` of the blocks to be rendered, and the values are the Astro components */
|
|
24
32
|
blockComponents?: BlockComponents<DatocmsRecord, DatocmsRecord>;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
/** An object in which the keys are the `__typename` of the records to be rendered, and the values are the Astro components */
|
|
34
|
+
linkToRecordComponents?: LinkToRecordComponents<DatocmsRecord, DatocmsRecord>;
|
|
35
|
+
/** An object in which the keys are the `__typename` of the records to be rendered, and the values are the Astro components */
|
|
36
|
+
inlineRecordComponents?: InlineRecordComponents<DatocmsRecord, DatocmsRecord>;
|
|
37
|
+
|
|
38
|
+
/** An object in which the keys are the types of DAST nodes to override, and the values are the Astro components */
|
|
39
|
+
nodeOverrides?: NodeOverrides;
|
|
40
|
+
/** An object in which the keys are the types of `span` node marks to override, and the values are the Astro components */
|
|
41
|
+
markOverrides?: MarkOverrides;
|
|
28
42
|
}
|
|
29
43
|
|
|
30
44
|
const { data, ...rest } = Astro.props;
|
|
@@ -4,21 +4,21 @@ import {
|
|
|
4
4
|
RenderError,
|
|
5
5
|
type InlineItem,
|
|
6
6
|
} from 'datocms-structured-text-utils';
|
|
7
|
-
import type {
|
|
7
|
+
import type { InlineRecordComponents } from '../types';
|
|
8
8
|
|
|
9
9
|
interface Props {
|
|
10
10
|
node: InlineItem;
|
|
11
11
|
record: DatocmsRecord;
|
|
12
|
-
|
|
12
|
+
inlineRecordComponents?: InlineRecordComponents<DatocmsRecord, DatocmsRecord>;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const { node, record,
|
|
15
|
+
const { node, record, inlineRecordComponents } = Astro.props;
|
|
16
16
|
|
|
17
|
-
const Component =
|
|
17
|
+
const Component = inlineRecordComponents?.[record.__typename];
|
|
18
18
|
|
|
19
19
|
if (!Component) {
|
|
20
20
|
throw new RenderError(
|
|
21
|
-
`The Structured Text document contains an 'inlineItem' node, but no component for rendering it is specified in the
|
|
21
|
+
`The Structured Text document contains an 'inlineItem' node, but no component for rendering it is specified in the inlineRecordComponents prop!`,
|
|
22
22
|
node,
|
|
23
23
|
);
|
|
24
24
|
}
|
|
@@ -5,23 +5,23 @@ import {
|
|
|
5
5
|
type ItemLink,
|
|
6
6
|
} from 'datocms-structured-text-utils';
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type { LinkToRecordComponents } from '../types';
|
|
9
9
|
|
|
10
10
|
import { defaultMetaTransformer } from 'datocms-structured-text-generic-html-renderer';
|
|
11
11
|
|
|
12
12
|
interface Props {
|
|
13
13
|
node: ItemLink;
|
|
14
14
|
record: DatocmsRecord;
|
|
15
|
-
|
|
15
|
+
linkToRecordComponents?: LinkToRecordComponents<DatocmsRecord, DatocmsRecord>;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const { node, record,
|
|
18
|
+
const { node, record, linkToRecordComponents } = Astro.props;
|
|
19
19
|
|
|
20
|
-
const Component =
|
|
20
|
+
const Component = linkToRecordComponents?.[record.__typename];
|
|
21
21
|
|
|
22
22
|
if (!Component) {
|
|
23
23
|
throw new RenderError(
|
|
24
|
-
`The Structured Text document contains an 'itemLink' node, but no component for rendering it is specified in the
|
|
24
|
+
`The Structured Text document contains an 'itemLink' node, but no component for rendering it is specified in the linkToRecordComponents prop!`,
|
|
25
25
|
node,
|
|
26
26
|
);
|
|
27
27
|
}
|
|
@@ -1,56 +1,49 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { Span } from 'datocms-structured-text-utils';
|
|
2
|
+
import type { Mark, Span } from 'datocms-structured-text-utils';
|
|
3
3
|
import Lines from '../Lines.astro';
|
|
4
|
+
import type { MarkOverrides } from '../types';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
node: Span;
|
|
8
|
+
markOverrides?: MarkOverrides;
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
const { node } = Astro.props;
|
|
11
|
+
const { node, markOverrides } = Astro.props;
|
|
10
12
|
|
|
11
13
|
const { type, value, marks } = node;
|
|
12
14
|
|
|
13
15
|
const [mark, ...otherMarks] = marks ?? [];
|
|
16
|
+
|
|
17
|
+
function markToComponent(mark: Mark) {
|
|
18
|
+
if (markOverrides && mark in markOverrides) {
|
|
19
|
+
return markOverrides[mark];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
switch (mark) {
|
|
23
|
+
case 'emphasis':
|
|
24
|
+
return 'em';
|
|
25
|
+
case 'underline':
|
|
26
|
+
return 'u';
|
|
27
|
+
case 'strikethrough':
|
|
28
|
+
return 's';
|
|
29
|
+
case 'highlight':
|
|
30
|
+
return 'mark';
|
|
31
|
+
default:
|
|
32
|
+
return mark;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const MarkComponent = mark ? markToComponent(mark) : null;
|
|
14
37
|
---
|
|
15
38
|
|
|
16
39
|
{
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
) : mark === 'emphasis' ? (
|
|
20
|
-
<em>
|
|
21
|
-
<Astro.self node={{ type, value, marks: otherMarks }}>
|
|
22
|
-
<slot />
|
|
23
|
-
</Astro.self>
|
|
24
|
-
</em>
|
|
25
|
-
) : mark === 'highlight' ? (
|
|
26
|
-
<mark>
|
|
27
|
-
<Astro.self node={{ type, value, marks: otherMarks }}>
|
|
28
|
-
<slot />
|
|
29
|
-
</Astro.self>
|
|
30
|
-
</mark>
|
|
31
|
-
) : mark === 'strikethrough' ? (
|
|
32
|
-
<del>
|
|
40
|
+
MarkComponent ? (
|
|
41
|
+
<MarkComponent>
|
|
33
42
|
<Astro.self node={{ type, value, marks: otherMarks }}>
|
|
34
43
|
<slot />
|
|
35
44
|
</Astro.self>
|
|
36
|
-
</
|
|
37
|
-
) :
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
<slot />
|
|
41
|
-
</Astro.self>
|
|
42
|
-
</strong>
|
|
43
|
-
) : mark === 'underline' ? (
|
|
44
|
-
<u>
|
|
45
|
-
<Astro.self node={{ type, value, marks: otherMarks }}>
|
|
46
|
-
<slot />
|
|
47
|
-
</Astro.self>
|
|
48
|
-
</u>
|
|
49
|
-
) : mark === 'code' ? (
|
|
50
|
-
<code>
|
|
51
|
-
<Astro.self node={{ type, value, marks: otherMarks }}>
|
|
52
|
-
<slot />
|
|
53
|
-
</Astro.self>
|
|
54
|
-
</code>
|
|
55
|
-
) : undefined
|
|
45
|
+
</MarkComponent>
|
|
46
|
+
) : (
|
|
47
|
+
<Lines lines={node.value.split(/\n/)} />
|
|
48
|
+
)
|
|
56
49
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Record as DatocmsRecord, NodeType } from 'datocms-structured-text-utils';
|
|
1
|
+
import type { Record as DatocmsRecord, Mark, NodeType } from 'datocms-structured-text-utils';
|
|
2
2
|
|
|
3
3
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
4
4
|
export type AstroComponent = (props: any) => any;
|
|
@@ -8,14 +8,16 @@ export type BlockComponents<R1 extends DatocmsRecord, R2 extends DatocmsRecord>
|
|
|
8
8
|
AstroComponent
|
|
9
9
|
>;
|
|
10
10
|
|
|
11
|
-
export type
|
|
11
|
+
export type LinkToRecordComponents<R1 extends DatocmsRecord, R2 extends DatocmsRecord> = Record<
|
|
12
12
|
R2['__typename'],
|
|
13
13
|
AstroComponent
|
|
14
14
|
>;
|
|
15
15
|
|
|
16
|
-
export type
|
|
16
|
+
export type InlineRecordComponents<R1 extends DatocmsRecord, R2 extends DatocmsRecord> = Record<
|
|
17
17
|
R2['__typename'],
|
|
18
18
|
AstroComponent
|
|
19
19
|
>;
|
|
20
20
|
|
|
21
|
-
export type
|
|
21
|
+
export type NodeOverrides = Partial<Record<NodeType, AstroComponent>>;
|
|
22
|
+
|
|
23
|
+
export type MarkOverrides = Partial<Record<Mark, AstroComponent>>;
|