Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions packages/editor/biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,6 @@
"rules": {
"complexity": {
"useLiteralKeys": "off"
},
"style": {
"noRestrictedImports": {
"level": "error",
"options": {
"paths": {
"@sanity/types": "Import from 'types/sanity-types' instead to maintain visibility over @sanity/types usage."
}
}
}
}
}
}
Expand Down
4 changes: 0 additions & 4 deletions packages/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@
"@portabletext/patches": "workspace:^",
"@portabletext/schema": "workspace:^",
"@portabletext/to-html": "^5.0.1",
"@sanity/schema": "^5.6.0",
"@sanity/types": "^5.6.0",
"@xstate/react": "^6.0.0",
"debug": "^4.4.3",
"slate": "^0.120.0",
Expand All @@ -100,7 +98,6 @@
"xstate": "^5.25.0"
},
"devDependencies": {
"@portabletext/sanity-bridge": "workspace:*",
"@portabletext/test": "workspace:^",
"@sanity/diff-match-patch": "^3.2.0",
"@sanity/pkg-utils": "^10.2.1",
Expand Down Expand Up @@ -129,7 +126,6 @@
"vitest-browser-react": "^2.0.2"
},
"peerDependencies": {
"@portabletext/sanity-bridge": "workspace:^2.0.0",
"react": "^19.2.3",
"rxjs": "^7.8.2"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import {compileSchemaDefinitionToPortableTextMemberSchemaTypes} from '@portabletext/sanity-bridge'
import {
compileSchema,
defineSchema,
type SchemaDefinition,
} from '@portabletext/schema'
import {describe, expect, test} from 'vitest'
import {createTestSnapshot} from '../internal-utils/create-test-snapshot'
import {createConverterTextHtml} from './converter.text-html'
import {converterTextHtml} from './converter.text-html'

function createSnapshot(schema: SchemaDefinition) {
function createSnapshot(schemaDefinition: SchemaDefinition) {
const schema = compileSchema(schemaDefinition)
return createTestSnapshot({
context: {
converters: [],
schema: compileSchema(schema),
schema,
},
})
}
Expand All @@ -25,12 +25,8 @@ const unorderedList = '<ul><li>foo</li><li>bar</li></ul>'
const orderedList = '<ol><li>foo</li><li>bar</li></ol>'
const nestedList = '<ol><li>foo<ul><li>bar</li></ul></li></ol>'

describe(createConverterTextHtml.name, () => {
describe(converterTextHtml.mimeType, () => {
test('paragraph with unknown decorators', () => {
const converterTextHtml = createConverterTextHtml(
compileSchemaDefinitionToPortableTextMemberSchemaTypes(defineSchema({})),
)

expect(
converterTextHtml.deserialize({
snapshot: createSnapshot(defineSchema({})),
Expand Down Expand Up @@ -60,14 +56,6 @@ describe(createConverterTextHtml.name, () => {
})

test('paragraph with known decorators', () => {
const converterTextHtml = createConverterTextHtml(
compileSchemaDefinitionToPortableTextMemberSchemaTypes(
defineSchema({
decorators: [{name: 'strong'}, {name: 'em'}, {name: 'code'}],
}),
),
)

expect(
converterTextHtml.deserialize({
snapshot: createSnapshot(
Expand Down Expand Up @@ -113,13 +101,6 @@ describe(createConverterTextHtml.name, () => {
})

test('image', () => {
const converterTextHtml = createConverterTextHtml(
compileSchemaDefinitionToPortableTextMemberSchemaTypes(
defineSchema({
blockObjects: [{name: 'image'}],
}),
),
)
expect(
converterTextHtml.deserialize({
snapshot: createSnapshot(
Expand All @@ -138,10 +119,6 @@ describe(createConverterTextHtml.name, () => {
})

test('paragraph with unknown link', () => {
const converterTextHtml = createConverterTextHtml(
compileSchemaDefinitionToPortableTextMemberSchemaTypes(defineSchema({})),
)

expect(
converterTextHtml.deserialize({
snapshot: createSnapshot(defineSchema({})),
Expand Down Expand Up @@ -171,16 +148,6 @@ describe(createConverterTextHtml.name, () => {
})

test('paragraph with known link', () => {
const converterTextHtml = createConverterTextHtml(
compileSchemaDefinitionToPortableTextMemberSchemaTypes(
defineSchema({
annotations: [
{name: 'link', fields: [{name: 'href', type: 'string'}]},
],
}),
),
)

expect(
converterTextHtml.deserialize({
snapshot: createSnapshot(
Expand Down Expand Up @@ -228,14 +195,6 @@ describe(createConverterTextHtml.name, () => {
})

test('unordered list', () => {
const converterTextHtml = createConverterTextHtml(
compileSchemaDefinitionToPortableTextMemberSchemaTypes(
defineSchema({
lists: [{name: 'bullet'}],
}),
),
)

expect(
converterTextHtml.deserialize({
snapshot: createSnapshot(
Expand Down Expand Up @@ -287,14 +246,6 @@ describe(createConverterTextHtml.name, () => {
})

test('ordered list', () => {
const converterTextHtml = createConverterTextHtml(
compileSchemaDefinitionToPortableTextMemberSchemaTypes(
defineSchema({
lists: [{name: 'number'}],
}),
),
)

expect(
converterTextHtml.deserialize({
snapshot: createSnapshot(
Expand Down Expand Up @@ -346,14 +297,6 @@ describe(createConverterTextHtml.name, () => {
})

test('nested list', () => {
const converterTextHtml = createConverterTextHtml(
compileSchemaDefinitionToPortableTextMemberSchemaTypes(
defineSchema({
lists: [{name: 'bullet'}, {name: 'number'}],
}),
),
)

expect(
converterTextHtml.deserialize({
snapshot: createSnapshot(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {compileSchemaDefinitionToPortableTextMemberSchemaTypes} from '@portabletext/sanity-bridge'
import {
compileSchema,
defineSchema,
Expand All @@ -9,7 +8,7 @@ import {
import {describe, expect, test} from 'vitest'
import {createTestSnapshot} from '../internal-utils/create-test-snapshot'
import type {EditorSelection} from '../types/editor'
import {createConverterTextHtml} from './converter.text-html'
import {converterTextHtml} from './converter.text-html'

const decoratedParagraph: PortableTextTextBlock = {
_key: 'k0',
Expand Down Expand Up @@ -76,22 +75,22 @@ const paragraphWithInlineBlock: PortableTextTextBlock = {
],
}

function createSnapshot(schema: SchemaDefinition, selection: EditorSelection) {
function createSnapshot(
schemaDefinition: SchemaDefinition,
selection: EditorSelection,
) {
const schema = compileSchema(schemaDefinition)
return createTestSnapshot({
context: {
converters: [],
schema: compileSchema(schema),
schema,
selection,
value: [decoratedParagraph, image, b2, paragraphWithInlineBlock],
},
})
}

const converterTextHtml = createConverterTextHtml(
compileSchemaDefinitionToPortableTextMemberSchemaTypes(defineSchema({})),
)

describe(converterTextHtml.serialize.name, () => {
describe(converterTextHtml.mimeType, () => {
test('paragraph with decorators', () => {
expect(
converterTextHtml.serialize({
Expand Down Expand Up @@ -183,15 +182,16 @@ describe(converterTextHtml.serialize.name, () => {
})

test('lists', () => {
const schema = compileSchema(
defineSchema({
lists: [{name: 'bullet'}, {name: 'number'}],
}),
)
expect(
converterTextHtml.serialize({
snapshot: createTestSnapshot({
context: {
schema: compileSchema(
defineSchema({
lists: [{name: 'bullet'}, {name: 'number'}],
}),
),
schema,
converters: [],
value: [
{
Expand Down
124 changes: 58 additions & 66 deletions packages/editor/src/converters/converter.text-html.ts
Original file line number Diff line number Diff line change
@@ -1,87 +1,79 @@
import {htmlToBlocks} from '@portabletext/block-tools'
import type {PortableTextBlock} from '@portabletext/schema'
import {toHTML} from '@portabletext/to-html'
import {getSelectedValue} from '../selectors/selector.get-selected-value'
import type {PortableTextMemberSchemaTypes} from '../types/editor'
import {parseBlock} from '../utils/parse-blocks'
import {defineConverter} from './converter.types'

export function createConverterTextHtml(
legacySchema: PortableTextMemberSchemaTypes,
) {
return defineConverter({
mimeType: 'text/html',
serialize: ({snapshot, event}) => {
const selection = snapshot.context.selection
export const converterTextHtml = defineConverter({
mimeType: 'text/html',
serialize: ({snapshot, event}) => {
const selection = snapshot.context.selection

if (!selection) {
return {
type: 'serialization.failure',
mimeType: 'text/html',
originEvent: event.originEvent,
reason: 'No selection',
}
if (!selection) {
return {
type: 'serialization.failure',
mimeType: 'text/html',
originEvent: event.originEvent,
reason: 'No selection',
}
}

const blocks = getSelectedValue(snapshot)

const html = toHTML(blocks, {
onMissingComponent: false,
components: {
unknownType: ({children}) =>
children !== undefined ? `${children}` : '',
},
})
const blocks = getSelectedValue(snapshot)

if (html === '') {
return {
type: 'serialization.failure',
mimeType: 'text/html',
originEvent: event.originEvent,
reason: 'Serialized HTML is empty',
}
}
const html = toHTML(blocks, {
onMissingComponent: false,
components: {
unknownType: ({children}) =>
children !== undefined ? `${children}` : '',
},
})

if (html === '') {
return {
type: 'serialization.success',
data: html,
type: 'serialization.failure',
mimeType: 'text/html',
originEvent: event.originEvent,
reason: 'Serialized HTML is empty',
}
},
deserialize: ({snapshot, event}) => {
const blocks = htmlToBlocks(event.data, legacySchema.portableText, {
keyGenerator: snapshot.context.keyGenerator,
unstable_whitespaceOnPasteMode:
legacySchema.block.options.unstable_whitespaceOnPasteMode,
}) as Array<PortableTextBlock>
}

const parsedBlocks = blocks.flatMap((block) => {
const parsedBlock = parseBlock({
context: snapshot.context,
block,
options: {
normalize: false,
removeUnusedMarkDefs: true,
validateFields: false,
},
})
return parsedBlock ? [parsedBlock] : []
})
return {
type: 'serialization.success',
data: html,
mimeType: 'text/html',
originEvent: event.originEvent,
}
},
deserialize: ({snapshot, event}) => {
const blocks = htmlToBlocks(event.data, snapshot.context.schema, {
keyGenerator: snapshot.context.keyGenerator,
})

if (parsedBlocks.length === 0) {
return {
type: 'deserialization.failure',
mimeType: 'text/html',
reason: 'No blocks deserialized',
}
}
const parsedBlocks = blocks.flatMap((block) => {
const parsedBlock = parseBlock({
context: snapshot.context,
block,
options: {
normalize: false,
removeUnusedMarkDefs: true,
validateFields: false,
},
})
return parsedBlock ? [parsedBlock] : []
})

if (parsedBlocks.length === 0) {
return {
type: 'deserialization.success',
data: parsedBlocks,
type: 'deserialization.failure',
mimeType: 'text/html',
reason: 'No blocks deserialized',
}
},
})
}
}

return {
type: 'deserialization.success',
data: parsedBlocks,
mimeType: 'text/html',
}
},
})
Loading
Loading