@portabletext/astro 0.0.0 → 0.2.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 +17 -0
- package/LICENSE +15 -0
- package/README.md +338 -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 +483 -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 +183 -0
- package/lib/types.ts +469 -0
- package/lib/utils.d.ts +26 -0
- package/lib/utils.ts +3 -0
- package/lib/warnings.ts +42 -0
- package/package.json +89 -7
package/lib/internal.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Component,
|
|
3
|
+
ComponentOrRecord,
|
|
4
|
+
NodeType,
|
|
5
|
+
SomePortableTextComponents,
|
|
6
|
+
TypedObject,
|
|
7
|
+
} from './types'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Helper for component to throw an error
|
|
11
|
+
* @param err
|
|
12
|
+
*/
|
|
13
|
+
export function throwError(err: Error | string): never {
|
|
14
|
+
throw err
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Returns true if `it` is component
|
|
19
|
+
*/
|
|
20
|
+
export function isComponent(it: unknown): it is Component {
|
|
21
|
+
return typeof it === 'function'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Merges two {@link SomePortableTextComponents} objects, giving priority to overrides.
|
|
26
|
+
*
|
|
27
|
+
* This function combines two component objects used in Portable Text rendering.
|
|
28
|
+
* If both objects have the same key, the value from `overrides` takes precedence.
|
|
29
|
+
* This is useful for customizing the rendering of specific components while keeping
|
|
30
|
+
* the default behavior for others.
|
|
31
|
+
*
|
|
32
|
+
* @typeParam Components - The type of the base components object.
|
|
33
|
+
* @typeParam Overrides - The type of the overrides components object.
|
|
34
|
+
*
|
|
35
|
+
* @param components - The base components object.
|
|
36
|
+
* @param overrides - The overrides components object.
|
|
37
|
+
*
|
|
38
|
+
* @returns A new object with the merged components.
|
|
39
|
+
*/
|
|
40
|
+
export function mergeComponents<
|
|
41
|
+
Components extends SomePortableTextComponents,
|
|
42
|
+
Overrides extends SomePortableTextComponents,
|
|
43
|
+
>(components: Components, overrides: Overrides) {
|
|
44
|
+
const cmps = {...components} as Record<string, ComponentOrRecord>
|
|
45
|
+
|
|
46
|
+
for (const [key, override] of Object.entries(overrides)) {
|
|
47
|
+
const current = components[key as keyof typeof components]
|
|
48
|
+
|
|
49
|
+
const value =
|
|
50
|
+
!current || isComponent(override) || isComponent(current)
|
|
51
|
+
? override
|
|
52
|
+
: {
|
|
53
|
+
...(current as Record<string, Component>),
|
|
54
|
+
...(override as Record<string, Component>),
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
cmps[key] = value
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return cmps as {
|
|
61
|
+
[Key in keyof (Components & Overrides)]: Key extends keyof (Overrides | Components)
|
|
62
|
+
? Overrides[Key] extends Component
|
|
63
|
+
? Overrides[Key]
|
|
64
|
+
: Components[Key] extends Component
|
|
65
|
+
? Overrides[Key]
|
|
66
|
+
: (Overrides & Components)[Key]
|
|
67
|
+
: (Overrides & Components)[Key]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* =====
|
|
73
|
+
* Slots
|
|
74
|
+
* =====
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A node type that a `PortableText` slot can target. `text` and `hardBreak` have
|
|
79
|
+
* no types of their own, so they round out the scopeable `NodeType`s.
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
export type SlotNodeType = NodeType | 'text' | 'hardBreak'
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Node types that a `PortableText` slot can target, mapped to whether the slot
|
|
86
|
+
* name can be scoped to a specific type, e.g. `block:h1`.
|
|
87
|
+
* @internal
|
|
88
|
+
*
|
|
89
|
+
* @remarks
|
|
90
|
+
* `satisfies` keeps this map exhaustive - adding a `NodeType` will not compile
|
|
91
|
+
* until it is given an entry here.
|
|
92
|
+
*/
|
|
93
|
+
const slotNodeTypes = {
|
|
94
|
+
type: true,
|
|
95
|
+
block: true,
|
|
96
|
+
list: true,
|
|
97
|
+
listItem: true,
|
|
98
|
+
mark: true,
|
|
99
|
+
text: false,
|
|
100
|
+
hardBreak: false,
|
|
101
|
+
} as const satisfies Record<SlotNodeType, boolean>
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The node types that a `PortableText` slot can target.
|
|
105
|
+
* @internal
|
|
106
|
+
*/
|
|
107
|
+
export const slotNames: readonly SlotNodeType[] = Object.keys(slotNodeTypes) as SlotNodeType[]
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Builds the name of the slot that renders the given node type, optionally
|
|
111
|
+
* scoped to a specific `type` such as a block style or a mark type.
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
export function toSlotName(nodeType: string, type?: string): string {
|
|
115
|
+
return type ? `${nodeType}:${type}` : nodeType
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns true if `slotName` targets a node type that is rendered by `PortableText`.
|
|
120
|
+
* @internal
|
|
121
|
+
*
|
|
122
|
+
* @remarks
|
|
123
|
+
* The scope of a scoped slot name, e.g. the `h1` of `block:h1`, cannot be verified
|
|
124
|
+
* upfront as block styles, mark types and custom types are user defined.
|
|
125
|
+
*/
|
|
126
|
+
export function isSlotName(slotName: string): boolean {
|
|
127
|
+
const separator = slotName.indexOf(':')
|
|
128
|
+
|
|
129
|
+
// `Object.hasOwn` rather than `in`, so inherited keys such as `toString` and
|
|
130
|
+
// `constructor` are not mistaken for node types.
|
|
131
|
+
if (separator === -1) {
|
|
132
|
+
return Object.hasOwn(slotNodeTypes, slotName)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const nodeType = slotName.slice(0, separator)
|
|
136
|
+
const scope = slotName.slice(separator + 1)
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
Object.hasOwn(slotNodeTypes, nodeType) &&
|
|
140
|
+
slotNodeTypes[nodeType as SlotNodeType] &&
|
|
141
|
+
scope.length > 0
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* ========================
|
|
147
|
+
* Node Components Registry
|
|
148
|
+
* ========================
|
|
149
|
+
*/
|
|
150
|
+
|
|
151
|
+
type ResolvedComponents = {
|
|
152
|
+
Default: Component
|
|
153
|
+
Unknown: Component
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const nodeComponentsMap = new WeakMap<TypedObject, ResolvedComponents>()
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Binds the resolved components to a specific node object.
|
|
160
|
+
* @internal
|
|
161
|
+
*
|
|
162
|
+
* @remarks
|
|
163
|
+
* This uses the node's _object reference_ as the key. This enables the `Context` API via
|
|
164
|
+
* `usePortableText` to look up which components were assigned to this specific node during rendering.
|
|
165
|
+
*
|
|
166
|
+
* @param node - The node object to be used as the key.
|
|
167
|
+
* @param Default - The resolved default component for this node.
|
|
168
|
+
* @param Unknown - The resolved fallback (unknown) component for this node.
|
|
169
|
+
*/
|
|
170
|
+
export function setNodeComponents(node: TypedObject, Default: Component, Unknown: Component): void {
|
|
171
|
+
nodeComponentsMap.set(node, {Default, Unknown})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Retrieves the components bound to a specific node object.
|
|
176
|
+
* @internal
|
|
177
|
+
*
|
|
178
|
+
* @param node - The node object to look up (by reference).
|
|
179
|
+
* @returns The component pair, or `undefined` if this exact node object was not registered.
|
|
180
|
+
*/
|
|
181
|
+
export function getNodeComponents(node: TypedObject): ResolvedComponents | undefined {
|
|
182
|
+
return nodeComponentsMap.get(node)
|
|
183
|
+
}
|
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