@portabletext/block-tools 2.0.8 → 3.0.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/README.md +1 -31
- package/lib/index.cjs +159 -162
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +24 -39
- package/lib/index.d.ts +24 -39
- package/lib/index.js +159 -162
- package/lib/index.js.map +1 -1
- package/package.json +3 -2
- package/src/HtmlDeserializer/helpers.ts +23 -46
- package/src/HtmlDeserializer/index.ts +15 -27
- package/src/HtmlDeserializer/rules/gdocs.ts +6 -7
- package/src/HtmlDeserializer/rules/html.ts +35 -24
- package/src/HtmlDeserializer/rules/index.ts +7 -7
- package/src/HtmlDeserializer/rules/notion.ts +1 -4
- package/src/index.ts +13 -28
- package/src/types.portable-text.ts +79 -0
- package/src/types.ts +11 -57
- package/src/util/normalizeBlock.ts +21 -7
- package/src/util/{blockContentTypeFeatures.ts → portable-text-schema.ts} +72 -39
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ArraySchemaType,
|
|
3
|
-
PortableTextBlock,
|
|
4
|
-
PortableTextObject,
|
|
5
|
-
PortableTextTextBlock,
|
|
6
|
-
} from '@sanity/types'
|
|
7
1
|
import {flatten} from 'lodash'
|
|
8
2
|
import type {
|
|
9
3
|
ArbitraryTypedObject,
|
|
@@ -13,10 +7,14 @@ import type {
|
|
|
13
7
|
PlaceholderDecorator,
|
|
14
8
|
TypedObject,
|
|
15
9
|
} from '../types'
|
|
16
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
isTextBlock,
|
|
12
|
+
type PortableTextBlock,
|
|
13
|
+
type PortableTextObject,
|
|
14
|
+
} from '../types.portable-text'
|
|
15
|
+
import type {PortableTextSchema} from '../util/portable-text-schema'
|
|
17
16
|
import {resolveJsType} from '../util/resolveJsType'
|
|
18
17
|
import {
|
|
19
|
-
createRuleOptions,
|
|
20
18
|
defaultParseHtml,
|
|
21
19
|
ensureRootIsBlocks,
|
|
22
20
|
flattenNestedBlocks,
|
|
@@ -36,7 +34,7 @@ import {createRules} from './rules'
|
|
|
36
34
|
*
|
|
37
35
|
*/
|
|
38
36
|
export default class HtmlDeserializer {
|
|
39
|
-
|
|
37
|
+
schema: PortableTextSchema
|
|
40
38
|
rules: DeserializerRule[]
|
|
41
39
|
parseHtml: (html: string) => HTMLElement
|
|
42
40
|
_markDefs: PortableTextObject[] = []
|
|
@@ -48,20 +46,16 @@ export default class HtmlDeserializer {
|
|
|
48
46
|
* @param options - Options for the deserialization process
|
|
49
47
|
*/
|
|
50
48
|
constructor(
|
|
51
|
-
|
|
49
|
+
schema: PortableTextSchema,
|
|
52
50
|
options: HtmlDeserializerOptions = {},
|
|
53
51
|
) {
|
|
54
52
|
const {rules = [], unstable_whitespaceOnPasteMode = 'preserve'} = options
|
|
55
|
-
|
|
56
|
-
throw new Error("Parameter 'blockContentType' is required")
|
|
57
|
-
}
|
|
58
|
-
const standardRules = createRules(blockContentType, {
|
|
59
|
-
...createRuleOptions(blockContentType),
|
|
53
|
+
const standardRules = createRules(schema, {
|
|
60
54
|
keyGenerator: options.keyGenerator,
|
|
61
55
|
})
|
|
56
|
+
this.schema = schema
|
|
62
57
|
this.rules = [...rules, ...standardRules]
|
|
63
58
|
const parseHtml = options.parseHtml || defaultParseHtml()
|
|
64
|
-
this.blockContentType = blockContentType
|
|
65
59
|
this.parseHtml = (html) => {
|
|
66
60
|
const doc = preprocess(html, parseHtml, {unstable_whitespaceOnPasteMode})
|
|
67
61
|
return doc.body
|
|
@@ -81,16 +75,16 @@ export default class HtmlDeserializer {
|
|
|
81
75
|
const children = Array.from(fragment.childNodes) as HTMLElement[]
|
|
82
76
|
// Ensure that there are no blocks within blocks, and trim whitespace
|
|
83
77
|
const blocks = trimWhitespace(
|
|
78
|
+
this.schema,
|
|
84
79
|
flattenNestedBlocks(
|
|
85
|
-
|
|
80
|
+
this.schema,
|
|
81
|
+
ensureRootIsBlocks(this.schema, this.deserializeElements(children)),
|
|
86
82
|
),
|
|
87
83
|
)
|
|
88
84
|
|
|
89
85
|
if (this._markDefs.length > 0) {
|
|
90
86
|
blocks
|
|
91
|
-
.filter(
|
|
92
|
-
(block): block is PortableTextTextBlock => block._type === 'block',
|
|
93
|
-
)
|
|
87
|
+
.filter((block) => isTextBlock(this.schema, block))
|
|
94
88
|
.forEach((block) => {
|
|
95
89
|
block.markDefs = block.markDefs || []
|
|
96
90
|
block.markDefs = block.markDefs.concat(
|
|
@@ -103,15 +97,9 @@ export default class HtmlDeserializer {
|
|
|
103
97
|
})
|
|
104
98
|
}
|
|
105
99
|
|
|
106
|
-
// Set back the potentially hoisted block type
|
|
107
|
-
const type = this.blockContentType.of.find(findBlockType)
|
|
108
|
-
if (!type) {
|
|
109
|
-
return blocks
|
|
110
|
-
}
|
|
111
|
-
|
|
112
100
|
return blocks.map((block) => {
|
|
113
101
|
if (block._type === 'block') {
|
|
114
|
-
block._type =
|
|
102
|
+
block._type = this.schema.block.name
|
|
115
103
|
}
|
|
116
104
|
return block
|
|
117
105
|
})
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type {ArraySchemaType} from '@sanity/types'
|
|
2
1
|
import {
|
|
3
2
|
BLOCK_DEFAULT_STYLE,
|
|
4
3
|
DEFAULT_BLOCK,
|
|
@@ -7,7 +6,8 @@ import {
|
|
|
7
6
|
HTML_HEADER_TAGS,
|
|
8
7
|
HTML_LIST_CONTAINER_TAGS,
|
|
9
8
|
} from '../../constants'
|
|
10
|
-
import type {
|
|
9
|
+
import type {DeserializerRule} from '../../types'
|
|
10
|
+
import type {PortableTextSchema} from '../../util/portable-text-schema'
|
|
11
11
|
import {isElement, tagName} from '../helpers'
|
|
12
12
|
|
|
13
13
|
const LIST_CONTAINER_TAGS = Object.keys(HTML_LIST_CONTAINER_TAGS)
|
|
@@ -81,21 +81,20 @@ const blocks: Record<string, {style: string} | undefined> = {
|
|
|
81
81
|
...HTML_HEADER_TAGS,
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
function getBlockStyle(
|
|
84
|
+
function getBlockStyle(schema: PortableTextSchema, el: Node): string {
|
|
85
85
|
const childTag = tagName(el.firstChild)
|
|
86
86
|
const block = childTag && blocks[childTag]
|
|
87
87
|
if (!block) {
|
|
88
88
|
return BLOCK_DEFAULT_STYLE
|
|
89
89
|
}
|
|
90
|
-
if (!
|
|
90
|
+
if (!schema.styles.some((style) => style.name === block.style)) {
|
|
91
91
|
return BLOCK_DEFAULT_STYLE
|
|
92
92
|
}
|
|
93
93
|
return block.style
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
export default function createGDocsRules(
|
|
97
|
-
|
|
98
|
-
options: BlockEnabledFeatures,
|
|
97
|
+
schema: PortableTextSchema,
|
|
99
98
|
): DeserializerRule[] {
|
|
100
99
|
return [
|
|
101
100
|
{
|
|
@@ -130,7 +129,7 @@ export default function createGDocsRules(
|
|
|
130
129
|
...DEFAULT_BLOCK,
|
|
131
130
|
listItem: getListItemStyle(el),
|
|
132
131
|
level: getListItemLevel(el),
|
|
133
|
-
style: getBlockStyle(
|
|
132
|
+
style: getBlockStyle(schema, el),
|
|
134
133
|
children: next(el.firstChild?.childNodes || []),
|
|
135
134
|
}
|
|
136
135
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type {ArraySchemaType, TypedObject} from '@sanity/types'
|
|
2
1
|
import {
|
|
3
2
|
DEFAULT_BLOCK,
|
|
4
3
|
DEFAULT_SPAN,
|
|
@@ -10,27 +9,34 @@ import {
|
|
|
10
9
|
HTML_SPAN_TAGS,
|
|
11
10
|
type PartialBlock,
|
|
12
11
|
} from '../../constants'
|
|
13
|
-
import type {
|
|
12
|
+
import type {DeserializerRule} from '../../types'
|
|
13
|
+
import type {PortableTextSchema} from '../../util/portable-text-schema'
|
|
14
14
|
import {keyGenerator} from '../../util/randomKey'
|
|
15
15
|
import {isElement, tagName} from '../helpers'
|
|
16
16
|
import {whitespaceTextNodeRule} from './whitespace-text-node'
|
|
17
17
|
|
|
18
18
|
export function resolveListItem(
|
|
19
|
+
schema: PortableTextSchema,
|
|
19
20
|
listNodeTagName: string,
|
|
20
|
-
enabledListTypes: string[],
|
|
21
21
|
): string | undefined {
|
|
22
|
-
if (
|
|
22
|
+
if (
|
|
23
|
+
listNodeTagName === 'ul' &&
|
|
24
|
+
schema.lists.some((list) => list.name === 'bullet')
|
|
25
|
+
) {
|
|
23
26
|
return 'bullet'
|
|
24
27
|
}
|
|
25
|
-
if (
|
|
28
|
+
if (
|
|
29
|
+
listNodeTagName === 'ol' &&
|
|
30
|
+
schema.lists.some((list) => list.name === 'number')
|
|
31
|
+
) {
|
|
26
32
|
return 'number'
|
|
27
33
|
}
|
|
28
34
|
return undefined
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
export default function createHTMLRules(
|
|
32
|
-
|
|
33
|
-
options:
|
|
38
|
+
schema: PortableTextSchema,
|
|
39
|
+
options: {keyGenerator?: () => string},
|
|
34
40
|
): DeserializerRule[] {
|
|
35
41
|
return [
|
|
36
42
|
whitespaceTextNodeRule,
|
|
@@ -41,7 +47,9 @@ export default function createHTMLRules(
|
|
|
41
47
|
return undefined
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
const isCodeEnabled =
|
|
50
|
+
const isCodeEnabled = schema.styles.some(
|
|
51
|
+
(style) => style.name === 'code',
|
|
52
|
+
)
|
|
45
53
|
|
|
46
54
|
return {
|
|
47
55
|
_type: 'block',
|
|
@@ -134,8 +142,9 @@ export default function createHTMLRules(
|
|
|
134
142
|
if (el.parentNode && tagName(el.parentNode) === 'li') {
|
|
135
143
|
return next(el.childNodes)
|
|
136
144
|
}
|
|
145
|
+
const blockStyle = block.style
|
|
137
146
|
// If style is not supported, return a defaultBlockType
|
|
138
|
-
if (!
|
|
147
|
+
if (!schema.styles.some((style) => style.name === blockStyle)) {
|
|
139
148
|
block = DEFAULT_BLOCK
|
|
140
149
|
}
|
|
141
150
|
return {
|
|
@@ -194,10 +203,7 @@ export default function createHTMLRules(
|
|
|
194
203
|
) {
|
|
195
204
|
return undefined
|
|
196
205
|
}
|
|
197
|
-
const enabledListItem = resolveListItem(
|
|
198
|
-
parentTag,
|
|
199
|
-
options.enabledListTypes,
|
|
200
|
-
)
|
|
206
|
+
const enabledListItem = resolveListItem(schema, parentTag)
|
|
201
207
|
// If the list item style is not supported, return a new default block
|
|
202
208
|
if (!enabledListItem) {
|
|
203
209
|
return block({_type: 'block', children: next(el.childNodes)})
|
|
@@ -212,7 +218,12 @@ export default function createHTMLRules(
|
|
|
212
218
|
{
|
|
213
219
|
deserialize(el, next) {
|
|
214
220
|
const decorator = HTML_DECORATOR_TAGS[tagName(el) || '']
|
|
215
|
-
if (
|
|
221
|
+
if (
|
|
222
|
+
!decorator ||
|
|
223
|
+
!schema.decorators.some(
|
|
224
|
+
(decoratorType) => decoratorType.name === decorator,
|
|
225
|
+
)
|
|
226
|
+
) {
|
|
216
227
|
return undefined
|
|
217
228
|
}
|
|
218
229
|
return {
|
|
@@ -228,23 +239,23 @@ export default function createHTMLRules(
|
|
|
228
239
|
if (tagName(el) !== 'a') {
|
|
229
240
|
return undefined
|
|
230
241
|
}
|
|
231
|
-
const linkEnabled =
|
|
242
|
+
const linkEnabled = schema.annotations.some(
|
|
243
|
+
(annotation) => annotation.name === 'link',
|
|
244
|
+
)
|
|
232
245
|
const href = isElement(el) && el.getAttribute('href')
|
|
233
246
|
if (!href) {
|
|
234
247
|
return next(el.childNodes)
|
|
235
248
|
}
|
|
236
|
-
let markDef: TypedObject | undefined
|
|
237
249
|
if (linkEnabled) {
|
|
238
|
-
markDef = {
|
|
239
|
-
_key: options.keyGenerator
|
|
240
|
-
? options.keyGenerator()
|
|
241
|
-
: keyGenerator(),
|
|
242
|
-
_type: 'link',
|
|
243
|
-
href: href,
|
|
244
|
-
}
|
|
245
250
|
return {
|
|
246
251
|
_type: '__annotation',
|
|
247
|
-
markDef:
|
|
252
|
+
markDef: {
|
|
253
|
+
_key: options.keyGenerator
|
|
254
|
+
? options.keyGenerator()
|
|
255
|
+
: keyGenerator(),
|
|
256
|
+
_type: 'link',
|
|
257
|
+
href: href,
|
|
258
|
+
},
|
|
248
259
|
children: next(el.childNodes),
|
|
249
260
|
}
|
|
250
261
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type {DeserializerRule} from '../../types'
|
|
2
|
+
import type {PortableTextSchema} from '../../util/portable-text-schema'
|
|
3
3
|
import createGDocsRules from './gdocs'
|
|
4
4
|
import createHTMLRules from './html'
|
|
5
5
|
import createNotionRules from './notion'
|
|
6
6
|
import createWordRules from './word'
|
|
7
7
|
|
|
8
8
|
export function createRules(
|
|
9
|
-
|
|
10
|
-
options:
|
|
9
|
+
schema: PortableTextSchema,
|
|
10
|
+
options: {keyGenerator?: () => string},
|
|
11
11
|
): DeserializerRule[] {
|
|
12
12
|
return [
|
|
13
13
|
...createWordRules(),
|
|
14
|
-
...createNotionRules(
|
|
15
|
-
...createGDocsRules(
|
|
16
|
-
...createHTMLRules(
|
|
14
|
+
...createNotionRules(),
|
|
15
|
+
...createGDocsRules(schema),
|
|
16
|
+
...createHTMLRules(schema, options),
|
|
17
17
|
]
|
|
18
18
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type {ArraySchemaType} from '@sanity/types'
|
|
2
1
|
import {DEFAULT_SPAN} from '../../constants'
|
|
3
2
|
import type {DeserializerRule} from '../../types'
|
|
4
3
|
import {isElement, tagName} from '../helpers'
|
|
@@ -28,9 +27,7 @@ function isNotion(el: Node): boolean {
|
|
|
28
27
|
return isElement(el) && Boolean(el.getAttribute('data-is-notion'))
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
export default function createNotionRules(
|
|
32
|
-
_blockContentType: ArraySchemaType,
|
|
33
|
-
): DeserializerRule[] {
|
|
30
|
+
export default function createNotionRules(): DeserializerRule[] {
|
|
34
31
|
return [
|
|
35
32
|
{
|
|
36
33
|
deserialize(el) {
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import type {ArraySchemaType
|
|
1
|
+
import type {ArraySchemaType} from '@sanity/types'
|
|
2
2
|
import HtmlDeserializer from './HtmlDeserializer'
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
HtmlDeserializerOptions,
|
|
6
|
-
TypedObject,
|
|
7
|
-
} from './types'
|
|
8
|
-
import blockContentTypeFeatures from './util/blockContentTypeFeatures'
|
|
3
|
+
import type {HtmlDeserializerOptions, TypedObject} from './types'
|
|
4
|
+
import type {PortableTextTextBlock} from './types.portable-text'
|
|
9
5
|
import {normalizeBlock} from './util/normalizeBlock'
|
|
6
|
+
import {getPortableTextSchema} from './util/portable-text-schema'
|
|
10
7
|
|
|
11
8
|
/**
|
|
12
9
|
* Convert HTML to blocks respecting the block content type's schema
|
|
@@ -22,33 +19,21 @@ export function htmlToBlocks(
|
|
|
22
19
|
blockContentType: ArraySchemaType,
|
|
23
20
|
options: HtmlDeserializerOptions = {},
|
|
24
21
|
): (TypedObject | PortableTextTextBlock)[] {
|
|
25
|
-
const
|
|
22
|
+
const schema = getPortableTextSchema(blockContentType)
|
|
23
|
+
const deserializer = new HtmlDeserializer(schema, options)
|
|
26
24
|
return deserializer
|
|
27
25
|
.deserialize(html)
|
|
28
26
|
.map((block) => normalizeBlock(block, {keyGenerator: options.keyGenerator}))
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
* Normalize and extract features of an schema type containing a block type
|
|
33
|
-
*
|
|
34
|
-
* @param blockContentType - Schema type for the block type
|
|
35
|
-
* @returns Returns the featureset of a compiled block content type.
|
|
36
|
-
* @public
|
|
37
|
-
*/
|
|
38
|
-
export function getBlockContentFeatures(
|
|
39
|
-
blockContentType: ArraySchemaType,
|
|
40
|
-
): BlockContentFeatures {
|
|
41
|
-
return blockContentTypeFeatures(blockContentType)
|
|
42
|
-
}
|
|
43
|
-
|
|
29
|
+
export type {ArbitraryTypedObject, DeserializerRule, HtmlParser} from './types'
|
|
44
30
|
export type {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
} from './types'
|
|
31
|
+
PortableTextBlock,
|
|
32
|
+
PortableTextObject,
|
|
33
|
+
PortableTextSpan,
|
|
34
|
+
PortableTextTextBlock,
|
|
35
|
+
} from './types.portable-text'
|
|
51
36
|
export type {BlockNormalizationOptions} from './util/normalizeBlock'
|
|
52
37
|
export {randomKey} from './util/randomKey'
|
|
53
38
|
export {normalizeBlock}
|
|
54
|
-
export type {
|
|
39
|
+
export type {HtmlDeserializerOptions, TypedObject}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {isArbitraryTypedObject} from './types'
|
|
2
|
+
import type {PortableTextSchema} from './util/portable-text-schema'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export type PortableTextBlock = PortableTextTextBlock | PortableTextObject
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export interface PortableTextTextBlock<
|
|
13
|
+
TChild = PortableTextSpan | PortableTextObject,
|
|
14
|
+
> {
|
|
15
|
+
_type: string
|
|
16
|
+
_key: string
|
|
17
|
+
children: TChild[]
|
|
18
|
+
markDefs?: PortableTextObject[]
|
|
19
|
+
listItem?: string
|
|
20
|
+
style?: string
|
|
21
|
+
level?: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function isTextBlock(
|
|
25
|
+
schema: PortableTextSchema,
|
|
26
|
+
block: unknown,
|
|
27
|
+
): block is PortableTextTextBlock {
|
|
28
|
+
if (!isArbitraryTypedObject(block)) {
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (block._type !== schema.block.name) {
|
|
33
|
+
return false
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!Array.isArray(block.children)) {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @public
|
|
45
|
+
*/
|
|
46
|
+
export interface PortableTextSpan {
|
|
47
|
+
_key: string
|
|
48
|
+
_type: 'span'
|
|
49
|
+
text: string
|
|
50
|
+
marks?: string[]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function isSpan(
|
|
54
|
+
schema: PortableTextSchema,
|
|
55
|
+
child: unknown,
|
|
56
|
+
): child is PortableTextSpan {
|
|
57
|
+
if (!isArbitraryTypedObject(child)) {
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (child._type !== schema.span.name) {
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (typeof child.text !== 'string') {
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
export interface PortableTextObject {
|
|
76
|
+
_type: string
|
|
77
|
+
_key: string
|
|
78
|
+
[other: string]: unknown
|
|
79
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,47 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ArraySchemaType,
|
|
3
|
-
I18nTitledListValue,
|
|
4
|
-
ObjectSchemaType,
|
|
5
|
-
PortableTextObject,
|
|
6
|
-
SpanSchemaType,
|
|
7
|
-
TitledListValue,
|
|
8
|
-
} from '@sanity/types'
|
|
9
|
-
import type {ComponentType} from 'react'
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @public
|
|
13
|
-
*/
|
|
14
|
-
export interface BlockContentFeatures {
|
|
15
|
-
styles: TitledListValue<string>[]
|
|
16
|
-
decorators: TitledListValue<string>[]
|
|
17
|
-
annotations: ResolvedAnnotationType[]
|
|
18
|
-
lists: I18nTitledListValue<string>[]
|
|
19
|
-
types: {
|
|
20
|
-
block: ArraySchemaType
|
|
21
|
-
span: SpanSchemaType
|
|
22
|
-
inlineObjects: ObjectSchemaType[]
|
|
23
|
-
blockObjects: ObjectSchemaType[]
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* @beta
|
|
29
|
-
*/
|
|
30
|
-
export interface BlockEditorSchemaProps {
|
|
31
|
-
icon?: string | ComponentType
|
|
32
|
-
render?: ComponentType
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @public
|
|
37
|
-
*/
|
|
38
|
-
export interface ResolvedAnnotationType {
|
|
39
|
-
blockEditor?: BlockEditorSchemaProps
|
|
40
|
-
title: string | undefined
|
|
41
|
-
value: string
|
|
42
|
-
type: ObjectSchemaType
|
|
43
|
-
icon: ComponentType | undefined
|
|
44
|
-
}
|
|
1
|
+
import type {PortableTextObject} from './types.portable-text'
|
|
45
2
|
|
|
46
3
|
/**
|
|
47
4
|
* @public
|
|
@@ -58,6 +15,16 @@ export interface ArbitraryTypedObject extends TypedObject {
|
|
|
58
15
|
[key: string]: unknown
|
|
59
16
|
}
|
|
60
17
|
|
|
18
|
+
export function isArbitraryTypedObject(
|
|
19
|
+
object: unknown,
|
|
20
|
+
): object is ArbitraryTypedObject {
|
|
21
|
+
return isRecord(object) && typeof object._type === 'string'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
25
|
+
return !!value && (typeof value === 'object' || typeof value === 'function')
|
|
26
|
+
}
|
|
27
|
+
|
|
61
28
|
export interface MinimalSpan {
|
|
62
29
|
_type: 'span'
|
|
63
30
|
_key?: string
|
|
@@ -106,9 +73,6 @@ export interface HtmlDeserializerOptions {
|
|
|
106
73
|
unstable_whitespaceOnPasteMode?: WhiteSpacePasteMode
|
|
107
74
|
}
|
|
108
75
|
|
|
109
|
-
/**
|
|
110
|
-
* @public
|
|
111
|
-
*/
|
|
112
76
|
export interface HtmlPreprocessorOptions {
|
|
113
77
|
unstable_whitespaceOnPasteMode?: WhiteSpacePasteMode
|
|
114
78
|
}
|
|
@@ -128,13 +92,3 @@ export interface DeserializerRule {
|
|
|
128
92
|
},
|
|
129
93
|
) => TypedObject | TypedObject[] | undefined
|
|
130
94
|
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* @public
|
|
134
|
-
*/
|
|
135
|
-
export interface BlockEnabledFeatures {
|
|
136
|
-
enabledBlockStyles: string[]
|
|
137
|
-
enabledSpanDecorators: string[]
|
|
138
|
-
enabledListTypes: string[]
|
|
139
|
-
enabledBlockAnnotations: string[]
|
|
140
|
-
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import {isEqual} from 'lodash'
|
|
2
|
+
import type {TypedObject} from '../types'
|
|
1
3
|
import {
|
|
2
|
-
|
|
4
|
+
isSpan,
|
|
3
5
|
type PortableTextSpan,
|
|
4
6
|
type PortableTextTextBlock,
|
|
5
|
-
} from '
|
|
6
|
-
import {
|
|
7
|
-
import type {TypedObject} from '../types'
|
|
7
|
+
} from '../types.portable-text'
|
|
8
|
+
import type {PortableTextSchema} from './portable-text-schema'
|
|
8
9
|
import {keyGenerator} from './randomKey'
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -53,6 +54,19 @@ export function normalizeBlock(
|
|
|
53
54
|
> & {
|
|
54
55
|
_key: string
|
|
55
56
|
} {
|
|
57
|
+
const schema: PortableTextSchema = {
|
|
58
|
+
block: {
|
|
59
|
+
name: options.blockTypeName || 'block',
|
|
60
|
+
},
|
|
61
|
+
span: {
|
|
62
|
+
name: 'span',
|
|
63
|
+
},
|
|
64
|
+
styles: [],
|
|
65
|
+
lists: [],
|
|
66
|
+
decorators: [],
|
|
67
|
+
annotations: [],
|
|
68
|
+
}
|
|
69
|
+
|
|
56
70
|
if (node._type !== (options.blockTypeName || 'block')) {
|
|
57
71
|
return '_key' in node
|
|
58
72
|
? (node as TypedObject & {_key: string})
|
|
@@ -99,8 +113,8 @@ export function normalizeBlock(
|
|
|
99
113
|
const previousChild = acc[acc.length - 1]
|
|
100
114
|
if (
|
|
101
115
|
previousChild &&
|
|
102
|
-
|
|
103
|
-
|
|
116
|
+
isSpan(schema, child) &&
|
|
117
|
+
isSpan(schema, previousChild) &&
|
|
104
118
|
isEqual(previousChild.marks, child.marks)
|
|
105
119
|
) {
|
|
106
120
|
if (
|
|
@@ -129,7 +143,7 @@ export function normalizeBlock(
|
|
|
129
143
|
? options.keyGenerator()
|
|
130
144
|
: keyGenerator()
|
|
131
145
|
|
|
132
|
-
if (
|
|
146
|
+
if (isSpan(schema, child)) {
|
|
133
147
|
if (!child.marks) {
|
|
134
148
|
child.marks = []
|
|
135
149
|
} else if (allowedDecorators) {
|