dr-data Claude commited on
Commit
96d706b
·
1 Parent(s): bc49fe7

Fix iframe smooth transitions injection error

Browse files

- Add proper null checks for iframe document and head element
- Add document ready state validation before injecting styles
- Implement try-catch error handling for appendChild operations
- Add retry mechanism with multiple timeouts for document readiness
- Improve error logging and warnings for debugging

Fixes: TypeError when doc.head.appendChild(style) fails due to null head element

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

Files changed (1) hide show
  1. components/editor/preview/index.tsx +92 -68
components/editor/preview/index.tsx CHANGED
@@ -137,7 +137,23 @@ export const Preview = forwardRef<
137
 
138
  const injectSmoothTransitions = () => {
139
  const doc = iframe.contentDocument;
140
- if (!doc) return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
 
142
  const existingStyle = doc.getElementById('smooth-transitions');
143
  if (existingStyle) {
@@ -145,85 +161,93 @@ export const Preview = forwardRef<
145
  existingStyle.remove();
146
  }
147
 
148
- const style = doc.createElement('style');
149
- style.id = 'smooth-transitions';
150
- style.textContent = `
151
- /* Enhanced smooth transitions for zero-flash updates */
152
- * {
153
- transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),
154
- background-color 0.2s ease,
155
- color 0.2s ease,
156
- border-color 0.2s ease,
157
- transform 0.2s ease !important;
158
- }
159
-
160
- /* Prevent flash during content updates */
161
- body {
162
- transition: opacity 0.15s ease !important;
163
- will-change: opacity;
164
- }
165
-
166
- /* Smooth content updates */
167
- .content-updating {
168
- animation: contentUpdate 0.3s cubic-bezier(0.4, 0, 0.2, 1);
169
- }
170
-
171
- @keyframes contentUpdate {
172
- 0% {
173
- opacity: 0.9;
174
- transform: translateY(1px);
175
  }
176
- 100% {
177
- opacity: 1;
178
- transform: translateY(0);
 
 
179
  }
180
- }
181
-
182
- /* New element entrance */
183
- .element-entering {
184
- animation: elementEnter 0.4s cubic-bezier(0.4, 0, 0.2, 1);
185
- }
186
-
187
- @keyframes elementEnter {
188
- 0% {
189
- opacity: 0;
190
- transform: translateY(8px) scale(0.98);
191
  }
192
- 100% {
193
- opacity: 1;
194
- transform: translateY(0) scale(1);
 
 
 
 
 
 
 
195
  }
196
- }
197
-
198
- /* Subtle glow for changed content */
199
- .content-changed {
200
- animation: contentGlow 0.6s ease-in-out;
201
- }
202
-
203
- @keyframes contentGlow {
204
- 0%, 100% {
205
- box-shadow: none;
206
- background-color: transparent;
207
  }
208
- 30% {
209
- box-shadow: 0 0 20px rgba(59, 130, 246, 0.2);
210
- background-color: rgba(59, 130, 246, 0.05);
 
 
 
 
 
 
 
211
  }
212
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
- /* Optimize rendering performance */
215
- * {
216
- backface-visibility: hidden;
217
- -webkit-font-smoothing: antialiased;
218
- }
219
- `;
220
- doc.head.appendChild(style);
221
- console.log('✨ Enhanced smooth transitions injected into iframe');
222
  };
223
 
224
  // Inject on iframe load and when content changes
225
  const handleLoad = () => {
 
226
  setTimeout(injectSmoothTransitions, 10);
 
 
227
  };
228
 
229
  iframe.addEventListener('load', handleLoad);
 
137
 
138
  const injectSmoothTransitions = () => {
139
  const doc = iframe.contentDocument;
140
+ if (!doc) {
141
+ console.warn('⚠️ Iframe document not available for smooth transitions');
142
+ return;
143
+ }
144
+
145
+ // Ensure document structure exists
146
+ if (!doc.head) {
147
+ console.warn('⚠️ Iframe document head not available for smooth transitions');
148
+ return;
149
+ }
150
+
151
+ // Check if document is ready
152
+ if (doc.readyState !== 'complete' && doc.readyState !== 'interactive') {
153
+ console.log('⏳ Document not ready, will retry smooth transitions injection');
154
+ setTimeout(injectSmoothTransitions, 50);
155
+ return;
156
+ }
157
 
158
  const existingStyle = doc.getElementById('smooth-transitions');
159
  if (existingStyle) {
 
161
  existingStyle.remove();
162
  }
163
 
164
+ try {
165
+ const style = doc.createElement('style');
166
+ style.id = 'smooth-transitions';
167
+ style.textContent = `
168
+ /* Enhanced smooth transitions for zero-flash updates */
169
+ * {
170
+ transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),
171
+ background-color 0.2s ease,
172
+ color 0.2s ease,
173
+ border-color 0.2s ease,
174
+ transform 0.2s ease !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  }
176
+
177
+ /* Prevent flash during content updates */
178
+ body {
179
+ transition: opacity 0.15s ease !important;
180
+ will-change: opacity;
181
  }
182
+
183
+ /* Smooth content updates */
184
+ .content-updating {
185
+ animation: contentUpdate 0.3s cubic-bezier(0.4, 0, 0.2, 1);
 
 
 
 
 
 
 
186
  }
187
+
188
+ @keyframes contentUpdate {
189
+ 0% {
190
+ opacity: 0.9;
191
+ transform: translateY(1px);
192
+ }
193
+ 100% {
194
+ opacity: 1;
195
+ transform: translateY(0);
196
+ }
197
  }
198
+
199
+ /* New element entrance */
200
+ .element-entering {
201
+ animation: elementEnter 0.4s cubic-bezier(0.4, 0, 0.2, 1);
 
 
 
 
 
 
 
202
  }
203
+
204
+ @keyframes elementEnter {
205
+ 0% {
206
+ opacity: 0;
207
+ transform: translateY(8px) scale(0.98);
208
+ }
209
+ 100% {
210
+ opacity: 1;
211
+ transform: translateY(0) scale(1);
212
+ }
213
  }
214
+
215
+ /* Subtle glow for changed content */
216
+ .content-changed {
217
+ animation: contentGlow 0.6s ease-in-out;
218
+ }
219
+
220
+ @keyframes contentGlow {
221
+ 0%, 100% {
222
+ box-shadow: none;
223
+ background-color: transparent;
224
+ }
225
+ 30% {
226
+ box-shadow: 0 0 20px rgba(59, 130, 246, 0.2);
227
+ background-color: rgba(59, 130, 246, 0.05);
228
+ }
229
+ }
230
+
231
+ /* Optimize rendering performance */
232
+ * {
233
+ backface-visibility: hidden;
234
+ -webkit-font-smoothing: antialiased;
235
+ }
236
+ `;
237
 
238
+ doc.head.appendChild(style);
239
+ console.log('✨ Enhanced smooth transitions injected into iframe');
240
+ } catch (error) {
241
+ console.error('❌ Failed to inject smooth transitions:', error);
242
+ }
 
 
 
243
  };
244
 
245
  // Inject on iframe load and when content changes
246
  const handleLoad = () => {
247
+ // Use multiple timeouts to ensure document is ready
248
  setTimeout(injectSmoothTransitions, 10);
249
+ setTimeout(injectSmoothTransitions, 50);
250
+ setTimeout(injectSmoothTransitions, 100);
251
  };
252
 
253
  iframe.addEventListener('load', handleLoad);