@@ -45,6 +45,13 @@ export function parseValueFromNodes(nodes: NodeListOf<ChildNode>): string[][] {
4545 return result ;
4646}
4747
48+ export function parseValueFromText ( text : string ) : string [ ] [ ] {
49+ return text
50+ . trim ( )
51+ . split ( '\n' )
52+ . map ( row => row . split ( '\t' ) ) ;
53+ }
54+
4855export function parseValueFromElement (
4956 element : HTMLElement
5057) : string | string [ ] [ ] | null {
@@ -104,21 +111,35 @@ class PasteKeyHandler extends KeyHandler {
104111 'clip-path: "inset(50%)"; height: 1px; width: 1px; margin: -1px; overflow: hidden; padding 0; position: absolute;'
105112 ) ;
106113
107- const listener = ( ) : void => {
108- dummyInput . removeEventListener ( 'input' , listener ) ;
114+ const cleanup = ( ) : void => {
115+ dummyInput . removeEventListener ( 'paste' , pasteListener ) ;
116+ dummyInput . removeEventListener ( 'input' , inputListener ) ;
109117 dummyInput . remove ( ) ;
110-
111118 grid . focus ( ) ;
112- const value = parseValueFromElement ( dummyInput ) ;
119+ } ;
120+
121+ let plainText = '' ;
122+
123+ // Capture text/plain from the clipboard during the paste event.
124+ // This is used as a fallback if HTML parsing fails, for cases like pasting from Excel
125+ const pasteListener = ( e : Event ) : void => {
126+ const clipboardEvent = e as ClipboardEvent ;
127+ plainText =
128+ clipboardEvent . clipboardData ?. getData ( 'text/plain' ) ?? '' ;
129+ } ;
130+
131+ const inputListener = ( ) : void => {
132+ cleanup ( ) ;
133+ const value =
134+ parseValueFromElement ( dummyInput ) ??
135+ ( plainText . length > 0 ? parseValueFromText ( plainText ) : null ) ;
113136 if ( value != null ) {
114137 grid . pasteValue ( value ) ;
115138 }
116139 } ;
117140
118- // Listen for the `input` event, when there's a change to the HTML
119- // We could also listen to the `paste` event to get the clipboard data, but that's just text data
120- // By listening to `input`, we can get a table that's already parsed in HTML, which is easier to consume
121- dummyInput . addEventListener ( 'input' , listener ) ;
141+ dummyInput . addEventListener ( 'paste' , pasteListener ) ;
142+ dummyInput . addEventListener ( 'input' , inputListener ) ;
122143
123144 // Focus the element so it receives the paste event
124145 dummyInput . focus ( ) ;
0 commit comments