@portabletext/astro 0.0.0 → 0.1.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 +7 -0
- package/LICENSE +15 -0
- package/README.md +275 -27
- package/components/Block.astro +36 -0
- package/components/HardBreak.astro +7 -0
- package/components/List.astro +24 -0
- package/components/ListItem.astro +9 -0
- package/components/Mark.astro +32 -0
- package/components/PortableText.astro +393 -0
- package/components/Text.astro +9 -0
- package/components/UnknownBlock.astro +7 -0
- package/components/UnknownList.astro +7 -0
- package/components/UnknownListItem.astro +7 -0
- package/components/UnknownMark.astro +7 -0
- package/components/UnknownType.astro +21 -0
- package/lib/astro.d.ts +9 -0
- package/lib/components.ts +4 -0
- package/lib/context.ts +21 -0
- package/lib/index.ts +2 -0
- package/lib/internal.ts +103 -0
- package/lib/types.ts +469 -0
- package/lib/utils.d.ts +26 -0
- package/lib/utils.ts +3 -0
- package/lib/warnings.ts +32 -0
- package/package.json +89 -7
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @portabletext/astro
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1](https://github.com/portabletext/astro-portabletext/pull/1) [`e3997e2`](https://github.com/portabletext/astro-portabletext/commit/e3997e216c13cd9da693e924c674cfed52a2d002) Thanks [@stipsan](https://github.com/stipsan)! - Initial release of `@portabletext/astro`, forked from [`astro-portabletext`](https://github.com/theisel/astro-portabletext) by Tom Theisel
|
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License (ISC)
|
|
2
|
+
|
|
3
|
+
Copyright 2022 - CURRENT Tom Theisel <tom.theisel@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
11
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
13
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
14
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
15
|
+
THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,45 +1,293 @@
|
|
|
1
1
|
# @portabletext/astro
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@portabletext/astro)
|
|
4
|
+
[](https://www.npmjs.com/package/@portabletext/astro)
|
|
5
|
+

|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Render [Portable Text](https://portabletext.org) with [Astro](https://astro.build).
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
> [!NOTE]
|
|
10
|
+
> This package is a fork of [`astro-portabletext`](https://github.com/theisel/astro-portabletext)
|
|
11
|
+
> by [Tom Theisel](https://github.com/theisel), maintained under the
|
|
12
|
+
> [`@portabletext`](https://github.com/portabletext) organization. All credit for the original
|
|
13
|
+
> design and implementation goes to Tom. It remains distributed under the original
|
|
14
|
+
> [ISC License](./LICENSE). See [Migrating from `astro-portabletext`](#migrating-from-astro-portabletext).
|
|
8
15
|
|
|
9
|
-
##
|
|
16
|
+
## Table of contents
|
|
10
17
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Basic usage](#basic-usage)
|
|
20
|
+
- [Sanity integration](#sanity-integration)
|
|
21
|
+
- [Customizing components](#customizing-components)
|
|
22
|
+
- [Default components](#default-components)
|
|
23
|
+
- [Custom components](#custom-components)
|
|
24
|
+
- [Slots](#slots)
|
|
25
|
+
- [`PortableText` component properties](#portabletext-component-properties)
|
|
26
|
+
- [Utility functions](#utility-functions)
|
|
27
|
+
- [`usePortableText`](#useportabletext)
|
|
28
|
+
- [`mergeComponents`](#mergecomponents)
|
|
29
|
+
- [`toPlainText`](#toplaintext)
|
|
30
|
+
- [Migrating from `astro-portabletext`](#migrating-from-astro-portabletext)
|
|
31
|
+
- [License](#license)
|
|
15
32
|
|
|
16
|
-
##
|
|
33
|
+
## Installation
|
|
17
34
|
|
|
18
|
-
|
|
35
|
+
```bash
|
|
36
|
+
npm install @portabletext/astro
|
|
37
|
+
```
|
|
19
38
|
|
|
20
|
-
|
|
39
|
+
> **Prerequisites:** Astro v4.6 or newer.
|
|
21
40
|
|
|
22
|
-
|
|
41
|
+
## Basic usage
|
|
23
42
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
43
|
+
Import the `PortableText` component and pass it a Portable Text value. The library provides sensible
|
|
44
|
+
defaults for rendering all standard Portable Text elements, which you can override.
|
|
28
45
|
|
|
29
|
-
|
|
46
|
+
```astro
|
|
47
|
+
---
|
|
48
|
+
import {PortableText} from '@portabletext/astro'
|
|
49
|
+
|
|
50
|
+
const portableText = [
|
|
51
|
+
{
|
|
52
|
+
_type: 'block',
|
|
53
|
+
style: 'normal',
|
|
54
|
+
markDefs: [],
|
|
55
|
+
children: [
|
|
56
|
+
{_type: 'span', marks: [], text: 'This is a '},
|
|
57
|
+
{_type: 'span', marks: ['strong'], text: 'bold'},
|
|
58
|
+
{_type: 'span', marks: [], text: ' text example!'},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
]
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
<PortableText value={portableText} />
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Sanity integration
|
|
68
|
+
|
|
69
|
+
This library's predecessor is
|
|
70
|
+
[officially recommended](https://www.sanity.io/plugins/sanity-astro#rendering-rich-text-and-block-content-with-portable-text)
|
|
71
|
+
by [Sanity](https://sanity.io) for rendering Portable Text in Astro projects. Helpful resources:
|
|
72
|
+
|
|
73
|
+
- [Sanity integration for Astro](https://www.sanity.io/plugins/sanity-astro)
|
|
74
|
+
- [Guide: building a blog with Sanity and Astro](https://www.sanity.io/guides/sanity-astro-blog)
|
|
75
|
+
|
|
76
|
+
## Customizing components
|
|
77
|
+
|
|
78
|
+
### Default components
|
|
79
|
+
|
|
80
|
+
Default components are provided for all standard features of the Portable Text spec, with logical
|
|
81
|
+
HTML defaults. Provided components are merged with the defaults, so you only need to provide the
|
|
82
|
+
things you want to override.
|
|
83
|
+
|
|
84
|
+
<details>
|
|
85
|
+
<summary>View the default structure and output</summary>
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
{
|
|
89
|
+
type: {
|
|
90
|
+
/* Custom types go here */
|
|
91
|
+
},
|
|
92
|
+
block: {
|
|
93
|
+
h1: /* <h1 {...attrs}><slot /></h1> */,
|
|
94
|
+
h2: /* <h2 {...attrs}><slot /></h2> */,
|
|
95
|
+
h3: /* <h3 {...attrs}><slot /></h3> */,
|
|
96
|
+
h4: /* <h4 {...attrs}><slot /></h4> */,
|
|
97
|
+
h5: /* <h5 {...attrs}><slot /></h5> */,
|
|
98
|
+
h6: /* <h6 {...attrs}><slot /></h6> */,
|
|
99
|
+
blockquote: /* <blockquote {...attrs}><slot /></blockquote> */,
|
|
100
|
+
normal: /* <p {...attrs}><slot /></p> */
|
|
101
|
+
},
|
|
102
|
+
list: {
|
|
103
|
+
bullet: /* <ul {...attrs}><slot /></ul> */,
|
|
104
|
+
number: /* <ol {...attrs}><slot /></ol> */,
|
|
105
|
+
menu: /* <menu {...attrs}><slot /></menu> */,
|
|
106
|
+
},
|
|
107
|
+
listItem: {
|
|
108
|
+
bullet: /* <li {...attrs}><slot /></li> */,
|
|
109
|
+
number: /* <li {...attrs}><slot /></li> */,
|
|
110
|
+
menu: /* <li {...attrs}><slot /></li> */,
|
|
111
|
+
},
|
|
112
|
+
mark: {
|
|
113
|
+
code: /* <code {...attrs}><slot /></code> */,
|
|
114
|
+
em: /* <em {...attrs}><slot /></em> */,
|
|
115
|
+
link: /* <a {...attrs} href="..."><slot /></a> */,
|
|
116
|
+
'strike-through': /* <del {...attrs}><slot /></del> */,
|
|
117
|
+
strong: /* <strong {...attrs}><slot /></strong> */,
|
|
118
|
+
underline: /* <span {...attrs} style="text-decoration: underline;"><slot /></span> */
|
|
119
|
+
},
|
|
120
|
+
text: /* Renders plain text */,
|
|
121
|
+
hardBreak: /* <br /> */,
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
</details>
|
|
126
|
+
|
|
127
|
+
### Custom components
|
|
128
|
+
|
|
129
|
+
Custom components give you control over how each node is rendered. Map a component to a whole node
|
|
130
|
+
type, or to a specific property (style, mark type, list item type, etc.) of that node type.
|
|
30
131
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
132
|
+
```astro
|
|
133
|
+
---
|
|
134
|
+
import {PortableText} from '@portabletext/astro'
|
|
135
|
+
import Code from '../components/Code.astro'
|
|
136
|
+
import Link from '../components/Link.astro'
|
|
137
|
+
|
|
138
|
+
const portableText = [
|
|
139
|
+
// ... your Portable Text content
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
const components = {
|
|
143
|
+
// Custom object types, keyed by `_type` (or a single component for all types)
|
|
144
|
+
type: {code: Code},
|
|
145
|
+
// Block styles, keyed by `style`
|
|
146
|
+
block: {/* h1, h2, normal, ... */},
|
|
147
|
+
// Lists, keyed by `listItem`
|
|
148
|
+
list: {/* bullet, number, ... */},
|
|
149
|
+
// List items, keyed by `listItem`
|
|
150
|
+
listItem: {/* bullet, number, ... */},
|
|
151
|
+
// Marks (decorators and annotations), keyed by mark type
|
|
152
|
+
mark: {link: Link},
|
|
153
|
+
// Fallbacks for unknown nodes
|
|
154
|
+
unknownType: undefined,
|
|
155
|
+
unknownBlock: undefined,
|
|
156
|
+
unknownList: undefined,
|
|
157
|
+
unknownListItem: undefined,
|
|
158
|
+
unknownMark: undefined,
|
|
159
|
+
// Plain text spans and hard breaks
|
|
160
|
+
text: undefined,
|
|
161
|
+
hardBreak: undefined,
|
|
162
|
+
}
|
|
163
|
+
---
|
|
36
164
|
|
|
37
|
-
|
|
165
|
+
<PortableText value={portableText} components={components} />
|
|
166
|
+
```
|
|
38
167
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
168
|
+
Each custom component receives `node`, `index` and `isInline` props, and renders any children
|
|
169
|
+
through a `<slot />`. For example, a custom `link` mark:
|
|
42
170
|
|
|
171
|
+
```astro
|
|
43
172
|
---
|
|
173
|
+
import type {MarkProps} from '@portabletext/astro/types'
|
|
174
|
+
|
|
175
|
+
export type Props = MarkProps<{href?: string}>
|
|
176
|
+
|
|
177
|
+
const {node} = Astro.props
|
|
178
|
+
const href = node.markDef?.href
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
<a href={href}><slot /></a>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Slots
|
|
185
|
+
|
|
186
|
+
Slots provide a flexible way to enhance rendering by passing additional props to the resolved
|
|
187
|
+
component - for example applying custom classes or wrapping elements - without replacing the default
|
|
188
|
+
component entirely.
|
|
189
|
+
|
|
190
|
+
```astro
|
|
191
|
+
---
|
|
192
|
+
import {PortableText} from '@portabletext/astro'
|
|
193
|
+
|
|
194
|
+
const portableText = [
|
|
195
|
+
// ... your Portable Text content
|
|
196
|
+
]
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
<PortableText value={portableText}>
|
|
200
|
+
<fragment slot="mark">
|
|
201
|
+
{({Component, props, children}) => (
|
|
202
|
+
<Component {...props} class="mark">{children}</Component>
|
|
203
|
+
)}
|
|
204
|
+
</fragment>
|
|
205
|
+
</PortableText>
|
|
206
|
+
|
|
207
|
+
<style>
|
|
208
|
+
.mark:where(strong) {
|
|
209
|
+
/* some styles */
|
|
210
|
+
}
|
|
211
|
+
</style>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## `PortableText` component properties
|
|
215
|
+
|
|
216
|
+
| Property | Type | Description |
|
|
217
|
+
| ------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
218
|
+
| `value` | `array` or `object` | Portable Text payload |
|
|
219
|
+
| `components` (optional) | `object` | Mapping of components to node types or their properties. |
|
|
220
|
+
| `onMissingComponent` (optional) | `function` or `boolean` | Disable warning messages or handle unknown types. **Default** prints to console. |
|
|
221
|
+
| `listNestingMode` (optional) | `"html"` or `"direct"` | List nesting mode. **Default** is `html`. See [ToolkitListNestMode](https://portabletext.github.io/toolkit/types/ToolkitListNestMode.html). |
|
|
222
|
+
|
|
223
|
+
## Utility functions
|
|
224
|
+
|
|
225
|
+
```js
|
|
226
|
+
import {usePortableText, mergeComponents, toPlainText, spanToPlainText} from '@portabletext/astro'
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### `usePortableText`
|
|
230
|
+
|
|
231
|
+
Within a component passed into the `components` prop, `usePortableText(node)` returns rendering
|
|
232
|
+
utilities scoped to that node: `getDefaultComponent()`, `getUnknownComponent()` and `render()`.
|
|
233
|
+
|
|
234
|
+
```astro
|
|
235
|
+
---
|
|
236
|
+
import type {BlockProps} from '@portabletext/astro/types'
|
|
237
|
+
import {usePortableText} from '@portabletext/astro'
|
|
238
|
+
|
|
239
|
+
export type Props = BlockProps
|
|
240
|
+
|
|
241
|
+
const {node} = Astro.props
|
|
242
|
+
const {getDefaultComponent} = usePortableText(node)
|
|
243
|
+
const Default = getDefaultComponent()
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
<Default {...Astro.props}><slot /></Default>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### `mergeComponents`
|
|
250
|
+
|
|
251
|
+
Merges two component maps, giving priority to the overrides. Useful for extending a shared base set
|
|
252
|
+
of components.
|
|
253
|
+
|
|
254
|
+
```js
|
|
255
|
+
import {mergeComponents} from '@portabletext/astro'
|
|
256
|
+
|
|
257
|
+
const components = mergeComponents(baseComponents, {
|
|
258
|
+
block: {h1: MyHeading},
|
|
259
|
+
})
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### `toPlainText`
|
|
263
|
+
|
|
264
|
+
Renders one or more Portable Text blocks as a plain string - handy for meta descriptions or
|
|
265
|
+
generating slugs. `spanToPlainText` does the same for a single span's children.
|
|
266
|
+
|
|
267
|
+
```astro
|
|
268
|
+
---
|
|
269
|
+
import {toPlainText} from '@portabletext/astro'
|
|
270
|
+
|
|
271
|
+
const {node} = Astro.props
|
|
272
|
+
const text = toPlainText(node)
|
|
273
|
+
---
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Migrating from `astro-portabletext`
|
|
277
|
+
|
|
278
|
+
`@portabletext/astro` is a drop-in fork of [`astro-portabletext`](https://github.com/theisel/astro-portabletext).
|
|
279
|
+
To migrate, swap the dependency and update your imports:
|
|
280
|
+
|
|
281
|
+
```diff
|
|
282
|
+
- import {PortableText} from 'astro-portabletext'
|
|
283
|
+
+ import {PortableText} from '@portabletext/astro'
|
|
284
|
+
|
|
285
|
+
- import type {BlockProps} from 'astro-portabletext/types'
|
|
286
|
+
+ import type {BlockProps} from '@portabletext/astro/types'
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
The component API, props and utility functions are unchanged.
|
|
290
|
+
|
|
291
|
+
## License
|
|
44
292
|
|
|
45
|
-
|
|
293
|
+
[ISC](./LICENSE) © [Tom Theisel](https://github.com/theisel) (original author) and the Portable Text authors.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Block, Props as $ } from "../lib/types";
|
|
3
|
+
import { usePortableText } from "../lib/utils";
|
|
4
|
+
|
|
5
|
+
export type Props = $<Block>;
|
|
6
|
+
|
|
7
|
+
const props = Astro.props;
|
|
8
|
+
const { node, index, isInline, ...attrs } = props;
|
|
9
|
+
const styleIs = (style: string) => style === node.style;
|
|
10
|
+
|
|
11
|
+
const { getUnknownComponent } = usePortableText(node);
|
|
12
|
+
|
|
13
|
+
const UnknownStyle = getUnknownComponent();
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
{
|
|
17
|
+
styleIs("h1") ? (
|
|
18
|
+
<h1 {...attrs}><slot /></h1>
|
|
19
|
+
) : styleIs("h2") ? (
|
|
20
|
+
<h2 {...attrs}><slot /></h2>
|
|
21
|
+
) : styleIs("h3") ? (
|
|
22
|
+
<h3 {...attrs}><slot /></h3>
|
|
23
|
+
) : styleIs("h4") ? (
|
|
24
|
+
<h4 {...attrs}><slot /></h4>
|
|
25
|
+
) : styleIs("h5") ? (
|
|
26
|
+
<h5 {...attrs}><slot /></h5>
|
|
27
|
+
) : styleIs("h6") ? (
|
|
28
|
+
<h6 {...attrs}><slot /></h6>
|
|
29
|
+
) : styleIs("blockquote") ? (
|
|
30
|
+
<blockquote {...attrs}><slot /></blockquote>
|
|
31
|
+
) : styleIs("normal") ? (
|
|
32
|
+
<p {...attrs}><slot /></p>
|
|
33
|
+
) : (
|
|
34
|
+
<UnknownStyle {...props}><slot /></UnknownStyle>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { List, Props as $ } from "../lib/types";
|
|
3
|
+
|
|
4
|
+
export type Props = $<List>;
|
|
5
|
+
|
|
6
|
+
const { node, index, isInline, ...attrs } = Astro.props;
|
|
7
|
+
const listItemIs = (listItem: string) => listItem === node.listItem;
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
listItemIs("menu") ? (
|
|
12
|
+
<menu {...attrs}>
|
|
13
|
+
<slot />
|
|
14
|
+
</menu>
|
|
15
|
+
) : listItemIs("number") ? (
|
|
16
|
+
<ol {...attrs}>
|
|
17
|
+
<slot />
|
|
18
|
+
</ol>
|
|
19
|
+
) : (
|
|
20
|
+
<ul {...attrs}>
|
|
21
|
+
<slot />
|
|
22
|
+
</ul>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Mark, Props as $ } from "../lib/types";
|
|
3
|
+
import { usePortableText } from "../lib/utils";
|
|
4
|
+
|
|
5
|
+
export type Props = $<Mark>;
|
|
6
|
+
|
|
7
|
+
const props = Astro.props;
|
|
8
|
+
const { node, index, isInline, ...attrs } = props;
|
|
9
|
+
const markTypeIs = (markType: string) => markType === node.markType;
|
|
10
|
+
|
|
11
|
+
const { getUnknownComponent } = usePortableText(node);
|
|
12
|
+
|
|
13
|
+
const UnknownMarkType = getUnknownComponent();
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
{
|
|
17
|
+
markTypeIs("code") ? (
|
|
18
|
+
<code {...attrs}><slot /></code>
|
|
19
|
+
) : markTypeIs("em") ? (
|
|
20
|
+
<em {...attrs}><slot /></em>
|
|
21
|
+
) : markTypeIs("link") ? (
|
|
22
|
+
<a href={(node as unknown as Mark<{ href: string }>).markDef.href} {...attrs}><slot /></a>
|
|
23
|
+
) : markTypeIs("strike-through") ? (
|
|
24
|
+
<del {...attrs}><slot /></del>
|
|
25
|
+
) : markTypeIs("strong") ? (
|
|
26
|
+
<strong {...attrs}><slot /></strong>
|
|
27
|
+
) : markTypeIs("underline") ? (
|
|
28
|
+
<span style="text-decoration: underline;" {...attrs}><slot /></span>
|
|
29
|
+
) : (
|
|
30
|
+
<UnknownMarkType {...props}><slot /></UnknownMarkType>
|
|
31
|
+
)
|
|
32
|
+
}
|