|
1 | | -import { eventPromise } from '@/src/utils/event-utils'; |
2 | | -import {SearchEngine} from '@coveo/headless'; |
3 | | -import {FunctionalComponent, h} from '@stencil/core'; |
| 1 | +import type {SearchEngine} from '@coveo/headless'; |
| 2 | +import {html} from 'lit'; |
| 3 | +import {ifDefined} from 'lit/directives/if-defined.js'; |
| 4 | +import {ref} from 'lit/directives/ref.js'; |
| 5 | +import {eventPromise} from '@/src/utils/event-utils'; |
| 6 | +import type {FunctionalComponent} from '@/src/utils/functional-component-utils'; |
4 | 7 |
|
5 | 8 | const documentIdentifierInIframe = 'CoveoDocIdentifier'; |
6 | 9 |
|
@@ -68,64 +71,83 @@ const iframeConnectedEvent = async ( |
68 | 71 | }); |
69 | 72 | }; |
70 | 73 |
|
71 | | -/** |
72 | | - * @deprecated should only be used for Stencil components. |
73 | | - */ |
74 | | -export const QuickviewIframe: FunctionalComponent<{ |
| 74 | +export interface QuickviewIframeProps { |
75 | 75 | title: string; |
76 | 76 | content?: string; |
77 | 77 | onSetIframeRef: (ref: HTMLIFrameElement) => void; |
78 | 78 | uniqueIdentifier?: string; |
79 | 79 | sandbox?: string; |
80 | 80 | src?: string; |
81 | 81 | logger?: SearchEngine['logger']; |
82 | | -}> = ({title, onSetIframeRef, uniqueIdentifier, content, sandbox, src, logger}) => { |
| 82 | +} |
| 83 | + |
| 84 | +export const renderQuickviewIframe: FunctionalComponent< |
| 85 | + QuickviewIframeProps |
| 86 | +> = ({props}) => { |
| 87 | + const { |
| 88 | + title, |
| 89 | + onSetIframeRef, |
| 90 | + uniqueIdentifier, |
| 91 | + content, |
| 92 | + sandbox, |
| 93 | + src, |
| 94 | + logger, |
| 95 | + } = props; |
| 96 | + |
83 | 97 | // When a document is written with document.open/document.write/document.close |
84 | 98 | // it is not synchronous and the content of the iframe is only available to be queried at the end of the current call stack. |
85 | 99 | // This add a "wait" (setTimeout 0) before calling the `onSetIframeRef` from the parent modal quickview |
86 | 100 | const waitForIframeContentToBeWritten = () => { |
87 | 101 | return new Promise((resolve) => setTimeout(resolve)); |
88 | 102 | }; |
89 | 103 |
|
90 | | - return ( |
91 | | - <iframe |
92 | | - title={title} |
93 | | - src="about:blank" |
94 | | - class="h-full w-full" |
95 | | - sandbox={sandbox} |
96 | | - ref={async (el) => { |
97 | | - const iframeRef = el as HTMLIFrameElement; |
98 | | - |
99 | | - if (!uniqueIdentifier || !content) { |
100 | | - return; |
101 | | - } |
| 104 | + const handleRef = (el: Element | undefined) => { |
| 105 | + if (!el) return; |
102 | 106 |
|
103 | | - await iframeConnectedEvent(iframeRef, logger); |
| 107 | + const iframeRef = el as HTMLIFrameElement; |
104 | 108 |
|
105 | | - const documentWriter = iframeRef.contentDocument; |
106 | | - if (!documentWriter) { |
107 | | - if (src) { |
108 | | - warnAboutLimitedUsageQuickview(logger); |
109 | | - iframeRef.src = src; |
110 | | - } |
| 109 | + if (!uniqueIdentifier || !content) { |
| 110 | + return; |
| 111 | + } |
111 | 112 |
|
112 | | - return; |
113 | | - } |
114 | | - if ( |
115 | | - currentResultAlreadyWrittenToDocument( |
116 | | - documentWriter, |
117 | | - uniqueIdentifier |
118 | | - ) |
119 | | - ) { |
120 | | - return; |
| 113 | + // Wait for iframe to be ready before accessing contentDocument |
| 114 | + const writeContentWhenReady = async () => { |
| 115 | + await iframeConnectedEvent(iframeRef, logger); |
| 116 | + |
| 117 | + const documentWriter = iframeRef.contentDocument; |
| 118 | + if (!documentWriter) { |
| 119 | + if (src) { |
| 120 | + warnAboutLimitedUsageQuickview(logger); |
| 121 | + iframeRef.src = src; |
121 | 122 | } |
122 | 123 |
|
123 | | - writeDocument(documentWriter, content); |
124 | | - ensureSameResultIsNotOverwritten(documentWriter, uniqueIdentifier); |
| 124 | + return; |
| 125 | + } |
| 126 | + if ( |
| 127 | + currentResultAlreadyWrittenToDocument(documentWriter, uniqueIdentifier) |
| 128 | + ) { |
| 129 | + return; |
| 130 | + } |
125 | 131 |
|
126 | | - await waitForIframeContentToBeWritten(); |
127 | | - onSetIframeRef(iframeRef); |
128 | | - }} |
129 | | - ></iframe> |
130 | | - ); |
| 132 | + writeDocument(documentWriter, content); |
| 133 | + ensureSameResultIsNotOverwritten(documentWriter, uniqueIdentifier); |
| 134 | + |
| 135 | + await waitForIframeContentToBeWritten(); |
| 136 | + onSetIframeRef(iframeRef); |
| 137 | + }; |
| 138 | + |
| 139 | + // Execute async operation without blocking |
| 140 | + writeContentWhenReady(); |
| 141 | + }; |
| 142 | + |
| 143 | + return html`<iframe |
| 144 | + title=${title} |
| 145 | + src="about:blank" |
| 146 | + class="h-full w-full" |
| 147 | + sandbox=${ |
| 148 | + // biome-ignore lint/suspicious/noExplicitAny: ifDefined requires 'any' for optional HTML attributes |
| 149 | + ifDefined(sandbox) as any |
| 150 | + } |
| 151 | + ${ref(handleRef)} |
| 152 | + ></iframe>`; |
131 | 153 | }; |
0 commit comments