11import { htmlToBlocks } from "@portabletext/block-tools" ;
22import { micromark } from "micromark" ;
3+ import { gfmTable , gfmTableHtml } from "micromark-extension-gfm-table" ;
34
45interface Input {
56 event : ClipboardEvent ;
@@ -31,7 +32,10 @@ export async function handlePaste(
3132 const json = event . clipboardData ?. getData ( "application/json" ) ;
3233
3334 if ( text && ! json ) {
34- const html = micromark ( text ) ;
35+ const html = micromark ( text , {
36+ extensions : [ gfmTable ( ) ] ,
37+ htmlExtensions : [ gfmTableHtml ( ) ] ,
38+ } ) ;
3539 return html
3640 ? convertHtmlToSanityPortableTextPatch ( html , schemaTypes , path )
3741 : undefined ;
@@ -45,18 +49,32 @@ function convertHtmlToSanityPortableTextPatch(
4549 schemaTypes : SchemaTypes ,
4650 path : Array < any > ,
4751) : InsertPatch | undefined {
48- if ( ! isCodeTypeAvailable ( schemaTypes ) || ! html ) return undefined ;
52+ if ( ! isCodeTypeAvailable ( schemaTypes ) || ! isTableTypeAvailable ( schemaTypes ) || ! html ) return undefined ;
4953
5054 const blocks = htmlToBlocks ( html , schemaTypes . portableText , {
5155 rules : [
5256 // @ts -ignore
5357 { deserialize : deserializeCodeBlockElement } ,
58+ // @ts -ignore
59+ { deserialize : deserializeTableElement } ,
5460 ] ,
5561 } ) ;
5662
5763 return blocks ? { insert : blocks , path } : undefined ;
5864}
5965
66+ function isTableTypeAvailable ( schemaTypes : SchemaTypes ) : boolean {
67+ const hasTableType = schemaTypes . blockObjects . some (
68+ ( type ) => type . name === "table" ,
69+ ) ;
70+ if ( ! hasTableType ) {
71+ console . warn (
72+ 'A table type is not defined in the schema. This is required to paste tables.' ,
73+ ) ;
74+ }
75+ return hasTableType ;
76+ }
77+
6078function isCodeTypeAvailable ( schemaTypes : SchemaTypes ) : boolean {
6179 const hasCodeType = schemaTypes . blockObjects . some (
6280 ( type ) => type . name === "code" ,
@@ -125,3 +143,26 @@ function mapLanguageAliasToActualLanguage(languageAlias: string): string {
125143 ( languageAlias as string )
126144 ) ;
127145}
146+
147+ function deserializeTableElement (
148+ el : Element ,
149+ next : any ,
150+ block : ( block : any ) => any ,
151+ ) {
152+ if ( el ?. tagName ?. toLowerCase ( ) !== 'table' ) {
153+ return undefined ;
154+ }
155+
156+ const rows = Array . from ( el . querySelectorAll ( 'tr' ) ) . map ( ( tr ) => {
157+ const cells = Array . from ( tr . querySelectorAll ( 'th, td' ) ) . map ( ( td ) => td . textContent ) ;
158+ return {
159+ _type : 'row' ,
160+ cells,
161+ } ;
162+ } ) ;
163+
164+ return block ( {
165+ _type : 'table' ,
166+ rows,
167+ } ) ;
168+ }
0 commit comments