@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/lib/types.ts ADDED
@@ -0,0 +1,469 @@
1
+ import type {
2
+ ToolkitListNestMode,
3
+ ToolkitNestedPortableTextSpan,
4
+ ToolkitPortableTextList,
5
+ ToolkitPortableTextListItem,
6
+ ToolkitTextNode,
7
+ } from '@portabletext/toolkit'
8
+ import type {
9
+ ArbitraryTypedObject,
10
+ PortableTextBlock,
11
+ PortableTextBlockStyle,
12
+ PortableTextMarkDefinition,
13
+ TypedObject,
14
+ } from '@portabletext/types'
15
+
16
+ export type {TypedObject} from '@portabletext/types'
17
+
18
+ /**
19
+ * Properties for the `PortableText` component
20
+ *
21
+ * @typeParam Value - Type of Portable Text payload
22
+ */
23
+ export interface PortableTextProps<
24
+ Value extends TypedObject = PortableTextBlock | ArbitraryTypedObject,
25
+ > {
26
+ /**
27
+ * Portable Text payload
28
+ */
29
+ value: Value | Value[]
30
+
31
+ /**
32
+ * Components for rendering
33
+ */
34
+ components?: SomePortableTextComponents
35
+
36
+ /**
37
+ * Function to call when faced with unknown types.
38
+ *
39
+ * @remarks
40
+ * - Prints a warning message to the console by default.
41
+ * - Use `false` to disable.
42
+ */
43
+ onMissingComponent?: MissingComponentHandler | boolean
44
+
45
+ /**
46
+ * Defines the nesting mode for lists. The value can be `html` or `direct`, and defaults to `html`.
47
+ *
48
+ * @remarks
49
+ * - `html` - Deeper list nodes will appear as a child of the last list item in the parent list
50
+ * - `direct` - Deeper list nodes will appear as a direct child of the parent list
51
+ *
52
+ * @see {@link https://portabletext.github.io/toolkit/types/ToolkitListNestMode.html ToolkitListNestMode}
53
+ */
54
+ listNestingMode?: ToolkitListNestMode
55
+ }
56
+
57
+ /**
58
+ * Defines how Portable Text types should be rendered.
59
+ */
60
+ export interface PortableTextComponents {
61
+ /**
62
+ * Component or mapping of components for rendering `custom` types.
63
+ */
64
+ type: ComponentOrRecord
65
+ /**
66
+ * Used when a {@link PortableTextComponents.type type} component isn't found.
67
+ */
68
+ unknownType: Component
69
+ /**
70
+ * Component or mapping of components for rendering `block` styles.
71
+ */
72
+ block: ComponentOrRecord<Block>
73
+ /**
74
+ * Used when a {@link PortableTextComponents.block block} component isn't found.
75
+ */
76
+ unknownBlock: Component<Block>
77
+ /**
78
+ * Component or mapping of components for rendering `list` item type.
79
+ */
80
+ list: ComponentOrRecord<List>
81
+ /**
82
+ * Used when a {@link PortableTextComponents.list list} component isn't found.
83
+ */
84
+ unknownList: Component<List>
85
+ /**
86
+ * Component or mapping of components for rendering `list` item type.
87
+ */
88
+ listItem: ComponentOrRecord<ListItem>
89
+ /**
90
+ * Used when a {@link PortableTextComponents.listItem listItem} component isn't found.
91
+ */
92
+ unknownListItem: Component<ListItem>
93
+ /**
94
+ * Component or mapping of components for rendering `mark` definition type.
95
+ */
96
+ mark: ComponentOrRecord<Mark<never>>
97
+ /**
98
+ * Used when a {@link PortableTextComponents.mark mark} component isn't found.
99
+ */
100
+ unknownMark: Component<Mark<never>>
101
+ /**
102
+ * Component for rendering `spans` of text.
103
+ * @remarks Added in: `v0.11.0`
104
+ */
105
+ text: Component<TextNode>
106
+ /**
107
+ * Component for rendering a newline `\n` of text.
108
+ */
109
+ hardBreak: Component<TextNode>
110
+ }
111
+
112
+ /**
113
+ * Defines how some Portable Text types should be rendered.
114
+ */
115
+ export type SomePortableTextComponents = Partial<PortableTextComponents>
116
+
117
+ /**
118
+ * Component Props
119
+ *
120
+ * @typeParam N - Type of Portable Text payload that this component will receive on its `node` property
121
+ */
122
+ export interface Props<N extends TypedObject> {
123
+ /**
124
+ * Portable Text data for this node
125
+ */
126
+ node: N
127
+ /**
128
+ * Index of the current node within its parent's child list
129
+ */
130
+ index: number
131
+ /**
132
+ * Indicates whether the node should render as an inline or block element
133
+ */
134
+ isInline: boolean
135
+ }
136
+
137
+ /**
138
+ * Alias to {@link https://portabletext.github.io/types/interfaces/PortableTextBlock.html PortableTextBlock}
139
+ * with `style` set to `normal` when undefined
140
+ *
141
+ * @example
142
+ * ```ts
143
+ * ---
144
+ * import type { Block, Props as $ } from "@portabletext/astro/types";
145
+ *
146
+ * type Props = $<Block>;
147
+ * ---
148
+ * ```
149
+ *
150
+ * @remarks To concisely achieve the same result in the example, use the convenience type {@link BlockProps} instead.
151
+ */
152
+ export interface Block extends PortableTextBlock {
153
+ style: 'normal' | PortableTextBlockStyle
154
+ }
155
+
156
+ /**
157
+ * Convenience type for {@link Block} component props
158
+ *
159
+ * @remarks
160
+ * Added in: `v0.11.0`
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * ---
165
+ * import type { BlockProps } from "@portabletext/astro/types";
166
+ *
167
+ * type Props = BlockProps;
168
+ * ---
169
+ * ```
170
+ */
171
+ export type BlockProps = Props<Block>
172
+
173
+ /**
174
+ * Alias to {@link https://portabletext.github.io/toolkit/types/ToolkitPortableTextList.html ToolkitPortableTextList}
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * ---
179
+ * import type { List, Props as $ } from "@portabletext/astro/types";
180
+ *
181
+ * type Props = $<List>;
182
+ * ---
183
+ * ```
184
+ *
185
+ * @remarks To concisely achieve the same result in the example, use the convenience type {@link ListProps} instead.
186
+ */
187
+ export type List = ToolkitPortableTextList
188
+
189
+ /**
190
+ * Convenience type for {@link List} component props
191
+ *
192
+ * @remarks
193
+ * Added in: `v0.11.0`
194
+ *
195
+ * @example
196
+ * ```ts
197
+ * ---
198
+ * import type { ListProps } from "@portabletext/astro/types";
199
+ *
200
+ * type Props = ListProps;
201
+ * ---
202
+ * ```
203
+ */
204
+ export type ListProps = Props<List>
205
+
206
+ /**
207
+ * Alias to {@link https://portabletext.github.io/toolkit/interfaces/ToolkitPortableTextListItem.html ToolkitPortableTextListItem}
208
+ *
209
+ * @example
210
+ * ```ts
211
+ * ---
212
+ * import type { ListItem, Props as $ } from "@portabletext/astro/types";
213
+ *
214
+ * type Props = $<ListItem>;
215
+ * ---
216
+ * ```
217
+ *
218
+ * @remarks To concisely achieve the same result in the example, use the convenience type {@link ListItemProps} instead.
219
+ */
220
+ export type ListItem = ToolkitPortableTextListItem
221
+
222
+ /**
223
+ * Convenience type for {@link ListItem} component props
224
+ *
225
+ * @remarks
226
+ * Added in: `v0.11.0`
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * ---
231
+ * import type { ListItemProps } from "@portabletext/astro/types";
232
+ *
233
+ * type Props = ListItemProps;
234
+ * ---
235
+ * ```
236
+ */
237
+ export type ListItemProps = Props<ListItem>
238
+
239
+ /**
240
+ * Extends {@link https://portabletext.github.io/toolkit/interfaces/ToolkitNestedPortableTextSpan.html ToolkitNestedPortableTextSpan}
241
+ * with consisting `markDef` and `markKey` properties
242
+ *
243
+ * @typeParam MarkDef - Defines the shape of `markDef` property
244
+ *
245
+ * @remarks
246
+ * To concisely achieve the same result in the example, use the convenience type {@link MarkProps} instead.
247
+ *
248
+ * @example
249
+ * ```ts
250
+ * ---
251
+ * import type { Mark, Props as $ } from "@portabletext/astro/types";
252
+ *
253
+ * type Greet = { msg: string };
254
+ * type Props = $<Mark<Greet>>;
255
+ * ---
256
+ * ```
257
+ */
258
+ export interface Mark<
259
+ MarkDef extends Record<string, unknown> | undefined = undefined,
260
+ > extends ToolkitNestedPortableTextSpan {
261
+ markDef: MarkDef & PortableTextMarkDefinition
262
+ markKey: string
263
+ }
264
+
265
+ /**
266
+ * Convenience type for {@link Mark} component props
267
+ *
268
+ * @remarks
269
+ * Added in: `v0.11.0`
270
+ *
271
+ * @example
272
+ * ```ts
273
+ * ---
274
+ * import type { MarkProps } from "@portabletext/astro/types";
275
+ *
276
+ * type Greet = { msg: string };
277
+ * type Props = MarkProps<Greet>;
278
+ * ---
279
+ * ```
280
+ */
281
+ export type MarkProps<MarkDef extends Record<string, unknown> | undefined = undefined> = Props<
282
+ Mark<MarkDef>
283
+ >
284
+
285
+ /**
286
+ * Alias to {@link https://portabletext.github.io/toolkit/interfaces/ToolkitTextNode.html ToolkitTextNode}
287
+ *
288
+ * @example
289
+ * ```ts
290
+ * ---
291
+ * import type { TextNode, Props as $ } from "@portabletext/astro/types";
292
+ *
293
+ * type Props = $<TextNode>;
294
+ * ---
295
+ * ```
296
+ *
297
+ * @remarks To concisely achieve the same result in the example, use the convenience type {@link TextNodeProps} instead.
298
+ */
299
+ export type TextNode = ToolkitTextNode
300
+
301
+ /**
302
+ * Convenience type for {@link TextNode} component props
303
+ *
304
+ * @remarks
305
+ * Added in: `v0.11.0`
306
+ *
307
+ * @example
308
+ * ```ts
309
+ * ---
310
+ * import type { TextNodeProps } from "@portabletext/astro/types";
311
+ *
312
+ * type Props = TextNodeProps;
313
+ * ---
314
+ * ```
315
+ */
316
+ export type TextNodeProps = Props<TextNode>
317
+
318
+ /**
319
+ * The shape of the {@link PortableTextProps.onMissingComponent onMissingComponent} function
320
+ */
321
+ export type MissingComponentHandler = (
322
+ message: string,
323
+ context: {type: string; nodeType: NodeType},
324
+ ) => void
325
+
326
+ /**
327
+ * Properties for the `RenderHandler` function
328
+ *
329
+ * @typeParam T - Type of Portable Text payload
330
+ * @typeParam Children - Type of children
331
+ */
332
+ export type RenderHandlerProps<T extends TypedObject = TypedObject, Children = unknown> = {
333
+ /**
334
+ * The component that is associated with the Portable Text node.
335
+ */
336
+ Component: Component<T>
337
+ /**
338
+ * The component props
339
+ */
340
+ props: Props<T>
341
+ /**
342
+ * The children related to the Portable Text node.
343
+ * If the node is a custom {@link PortableTextComponents.type type} or a {@link TextNode}, then children will be `undefined`.
344
+ */
345
+ children?: Children
346
+ }
347
+
348
+ /**
349
+ * The shape of the render component function
350
+ *
351
+ * @typeParam T - Type of Portable Text payload
352
+ * @typeParam Children - Type of children
353
+ */
354
+ export type RenderHandler<T extends TypedObject = TypedObject, Children = unknown> = (
355
+ props: RenderHandlerProps<T, Children>,
356
+ ) => any
357
+
358
+ /**
359
+ * Options for the `render` function accessed via `usePortableText`
360
+ */
361
+ export type RenderOptions = {
362
+ type?: RenderHandler<TypedObject, never>
363
+ block?: RenderHandler<Block>
364
+ list?: RenderHandler<List>
365
+ listItem?: RenderHandler<ListItem>
366
+ mark?: RenderHandler<Mark>
367
+ text?: RenderHandler<TextNode, never>
368
+ hardBreak?: RenderHandler<TextNode, never>
369
+ }
370
+
371
+ /**
372
+ * Context object returned by `usePortableText`, providing utilities for rendering and customizing Portable Text components.
373
+ *
374
+ * The `Context` type includes functions to retrieve default or unknown components and
375
+ * to customize rendering behavior for specific node types.
376
+ */
377
+ export interface Context {
378
+ /**
379
+ * Retrieves the default `@portabletext/astro` component associated with a Portable Text node.
380
+ *
381
+ * @returns The default component for the node, such as `Block`, `List`, etc.
382
+ *
383
+ * @example
384
+ * ```ts
385
+ * ---
386
+ * const { getDefaultComponent } = usePortableText(node);
387
+ * const Component = getDefaultComponent();
388
+ * ---
389
+ * <Component {...Astro.props}>
390
+ * <slot />
391
+ * </Component>
392
+ * ```
393
+ */
394
+ getDefaultComponent: () => Component
395
+ /**
396
+ * Retrieves the `unknown` component associated with a Portable Text node.
397
+ *
398
+ * @returns The component used for unknown nodes, such as `unknownBlock` or `unknownList`.
399
+ *
400
+ * @example
401
+ * ```ts
402
+ * ---
403
+ * const { getUnknownComponent } = usePortableText(node);
404
+ * const Component = getUnknownComponent();
405
+ * ---
406
+ * <Component {...Astro.props}>
407
+ * <slot />
408
+ * </Component>
409
+ * ```
410
+ */
411
+ getUnknownComponent: () => Component
412
+ /**
413
+ * Customizes rendering for specific Portable Text node types.
414
+ *
415
+ * The `render` function enables developers to define custom behavior for specific node types,
416
+ * such as overriding the default text or mark rendering.
417
+ *
418
+ * @remarks
419
+ * Added in: `v0.11.0`
420
+ *
421
+ * @param options {@link RenderOptions} - Configuration for customizing node rendering
422
+ * @returns The desired output for the Portable Text node
423
+ *
424
+ * @example Basic usage
425
+ * ```ts
426
+ * ---
427
+ * import { usePortableText } from "@portabletext/astro";
428
+ *
429
+ * const { node } = Astro.props;
430
+ * const { getDefaultComponent, render } = usePortableText(node);
431
+ * const Component = getDefaultComponent();
432
+ * ---
433
+ * <Component {...Astro.props}>
434
+ * {render({
435
+ * text: ({ props }) => props.node.text.toUpperCase(),
436
+ * mark: ({ Component, props, children }) => (
437
+ * <Component {...props} class="custom-mark">{children}</Component>
438
+ * ),
439
+ * </Component>
440
+ *
441
+ * <style>
442
+ * .custom-mark {
443
+ * // some styles
444
+ * }
445
+ * </style>
446
+ * ```
447
+ */
448
+ render: (options: RenderOptions) => any
449
+ }
450
+
451
+ /**
452
+ * Generic Portable Text component
453
+ * @internal
454
+ */
455
+ export type Component<T extends TypedObject = any> = (props: Props<T>) => any
456
+
457
+ /**
458
+ * Defines a component or a mapping of components
459
+ * @internal
460
+ */
461
+ export type ComponentOrRecord<T extends TypedObject = any> =
462
+ | Component<T>
463
+ | Record<string, Component<T>>
464
+
465
+ /**
466
+ * Defines the type of Portable Text node
467
+ * @internal
468
+ */
469
+ export type NodeType = 'type' | 'block' | 'list' | 'listItem' | 'mark'
package/lib/utils.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ declare module '@portabletext/astro/utils' {
2
+ /**
3
+ * @deprecated Use `toPlainText` from `@portabletext/astro` instead
4
+ */
5
+ export function toPlainText(
6
+ ...args: Parameters<typeof import('@portabletext/toolkit').toPlainText>
7
+ ): ReturnType<typeof import('@portabletext/toolkit').toPlainText>
8
+ /**
9
+ * @deprecated Use `spanToPlainText` from `@portabletext/astro` instead
10
+ */
11
+ export function spanToPlainText(
12
+ ...args: Parameters<typeof import('@portabletext/toolkit').spanToPlainText>
13
+ ): ReturnType<typeof import('@portabletext/toolkit').spanToPlainText>
14
+ /**
15
+ * @deprecated Use `mergeComponents` from `@portabletext/astro` instead
16
+ */
17
+ export function mergeComponents(
18
+ ...args: Parameters<typeof import('./utils').mergeComponents>
19
+ ): ReturnType<typeof import('./utils').mergeComponents>
20
+ /**
21
+ * @deprecated Use `usePortableText` from `@portabletext/astro` instead
22
+ */
23
+ export function usePortableText(
24
+ ...args: Parameters<typeof import('./utils').usePortableText>
25
+ ): ReturnType<typeof import('./utils').usePortableText>
26
+ }
package/lib/utils.ts ADDED
@@ -0,0 +1,3 @@
1
+ export {toPlainText, spanToPlainText} from '@portabletext/toolkit'
2
+ export {mergeComponents} from './internal'
3
+ export {usePortableText} from './context'
@@ -0,0 +1,32 @@
1
+ import type {NodeType} from './types'
2
+
3
+ const getTemplate = (prop: string, type: string): string =>
4
+ `PortableText [components.${prop}] is missing "${type}"`
5
+
6
+ export const unknownTypeWarning = (type: string): string => getTemplate('type', type)
7
+
8
+ export const unknownMarkWarning = (markType: string): string => getTemplate('mark', markType)
9
+
10
+ export const unknownBlockWarning = (style: string): string => getTemplate('block', style)
11
+
12
+ export const unknownListWarning = (listItem: string): string => getTemplate('list', listItem)
13
+
14
+ export const unknownListItemWarning = (listStyle: string): string =>
15
+ getTemplate('listItem', listStyle)
16
+
17
+ export const getWarningMessage = (nodeType: NodeType, type: string) => {
18
+ const fncs = {
19
+ block: unknownBlockWarning,
20
+ list: unknownListWarning,
21
+ listItem: unknownListItemWarning,
22
+ mark: unknownMarkWarning,
23
+ type: unknownTypeWarning,
24
+ }
25
+
26
+ return fncs[nodeType](type)
27
+ }
28
+
29
+ export function printWarning(message: string): void {
30
+ // oxlint-disable-next-line no-console
31
+ console.warn(message)
32
+ }
package/package.json CHANGED
@@ -1,10 +1,92 @@
1
1
  {
2
2
  "name": "@portabletext/astro",
3
- "version": "0.0.0",
4
- "description": "OIDC trusted publishing setup package for @portabletext/astro",
3
+ "version": "0.1.0",
4
+ "description": "Render Portable Text with Astro",
5
5
  "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
10
- }
6
+ "astro",
7
+ "astro-component",
8
+ "portable-text",
9
+ "sanity",
10
+ "withastro"
11
+ ],
12
+ "homepage": "https://github.com/portabletext/astro-portabletext#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/portabletext/astro-portabletext/issues"
15
+ },
16
+ "license": "ISC",
17
+ "author": "Sanity.io <hello@sanity.io>",
18
+ "contributors": [
19
+ "Tom Theisel <tom.theisel@gmail.com> (original author of astro-portabletext)"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+ssh://git@github.com/portabletext/astro-portabletext.git"
24
+ },
25
+ "files": [
26
+ "CHANGELOG.md",
27
+ "components",
28
+ "lib"
29
+ ],
30
+ "type": "module",
31
+ "typesVersions": {
32
+ "*": {
33
+ "*": [
34
+ "lib/*"
35
+ ]
36
+ }
37
+ },
38
+ "exports": {
39
+ ".": "./lib/index.ts",
40
+ "./components": "./lib/components.ts",
41
+ "./types": "./lib/types.ts",
42
+ "./utils": {
43
+ "types": "./lib/utils.d.ts",
44
+ "import": "./lib/utils.ts",
45
+ "default": "./lib/utils.ts"
46
+ },
47
+ "./package.json": "./package.json"
48
+ },
49
+ "dependencies": {
50
+ "@portabletext/toolkit": "^6.0.0",
51
+ "@portabletext/types": "^4.0.2"
52
+ },
53
+ "devDependencies": {
54
+ "@astrojs/check": "^0.9.10",
55
+ "@changesets/changelog-github": "^0.7.0",
56
+ "@changesets/cli": "^2.31.1",
57
+ "@types/leaflet": "^1.9.21",
58
+ "@types/node": "^26.2.0",
59
+ "astro": "^7.2.1",
60
+ "cheerio": "^1.2.0",
61
+ "leaflet": "^1.9.4",
62
+ "oxfmt": "^0.63.0",
63
+ "oxlint": "^1.78.0",
64
+ "oxlint-tsgolint": "^7.0.2001",
65
+ "rimraf": "^5.0.1",
66
+ "typescript": "^6.0.3",
67
+ "vitest": "^4.1.10"
68
+ },
69
+ "peerDependencies": {
70
+ "astro": ">=4.6.0"
71
+ },
72
+ "lint-staged": {
73
+ "*": [
74
+ "oxfmt"
75
+ ]
76
+ },
77
+ "engines": {
78
+ "node": ">=22.12"
79
+ },
80
+ "scripts": {
81
+ "prebuild:demo": "pnpm clean",
82
+ "build:demo": "astro build --root demo",
83
+ "clean": "rimraf demo/dist test/dist",
84
+ "dev": "astro dev --root demo",
85
+ "format": "oxfmt .",
86
+ "lint": "oxlint",
87
+ "release": "changeset publish",
88
+ "start": "pnpm dev",
89
+ "test": "vitest",
90
+ "type-check": "astro check"
91
+ }
92
+ }