@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 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
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ [![npm version](https://img.shields.io/npm/v/@portabletext/astro.svg?style=flat-square)](https://www.npmjs.com/package/@portabletext/astro)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@portabletext/astro.svg?style=flat-square)](https://www.npmjs.com/package/@portabletext/astro)
5
+ ![license](https://img.shields.io/npm/l/@portabletext/astro?style=flat-square)
4
6
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
7
+ Render [Portable Text](https://portabletext.org) with [Astro](https://astro.build).
6
8
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
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
- ## Purpose
16
+ ## Table of contents
10
17
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@portabletext/astro`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
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
- ## What is OIDC Trusted Publishing?
33
+ ## Installation
17
34
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
35
+ ```bash
36
+ npm install @portabletext/astro
37
+ ```
19
38
 
20
- ## Setup Instructions
39
+ > **Prerequisites:** Astro v4.6 or newer.
21
40
 
22
- To properly configure OIDC trusted publishing for this package:
41
+ ## Basic usage
23
42
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
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
- ## DO NOT USE THIS PACKAGE
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
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
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
- ## More Information
165
+ <PortableText value={portableText} components={components} />
166
+ ```
38
167
 
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
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
- **Maintained for OIDC setup purposes only**
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,7 @@
1
+ ---
2
+ import type { TextNode, Props as $ } from "../lib/types";
3
+
4
+ export type Props = $<TextNode>;
5
+ ---
6
+
7
+ <br />
@@ -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,9 @@
1
+ ---
2
+ import type { ListItem, Props as $ } from "../lib/types";
3
+
4
+ export type Props = $<ListItem>;
5
+
6
+ const { node, index, isInline, ...attrs } = Astro.props;
7
+ ---
8
+
9
+ <li {...attrs}><slot /></li>
@@ -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
+ }