@growgroup/visual-editor 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/editor.css +1 -1
- package/package.json +1 -1
- package/src/editor/EditorContext.tsx +3 -2
- package/src/editor/EditorToolbar.tsx +8 -2
- package/src/editor/FrontendVisualEditor.tsx +114 -44
- package/src/editor/components/EditorCanvas.tsx +73 -15
- package/src/editor/components/EditorFooter.tsx +2 -0
- package/src/editor/components/EditorHeader.tsx +3 -2
- package/src/editor/components/FigmaColorPicker.tsx +2 -1
- package/src/editor/components/JsEditorDialog.tsx +1 -0
- package/src/editor/components/PageSettingsDialog.tsx +1 -0
- package/src/editor/components/comments/CommentBoard.tsx +9 -6
- package/src/editor/components/multi-page/CanvasFrameDecor.tsx +172 -0
- package/src/editor/components/multi-page/MultiPageCanvasView.tsx +173 -77
- package/src/editor/components/multi-page/PageFramePreview.tsx +96 -20
- package/src/editor/components/multi-page/index.ts +1 -0
- package/src/editor/components/ppt/PptChrome.tsx +6 -2
- package/src/editor/components/ppt/PptComments.tsx +411 -71
- package/src/editor/constants.ts +16 -1
- package/src/editor/contexts/EditorArtboardContext.tsx +8 -0
- package/src/editor/contexts/EditorComponentsContext.tsx +31 -27
- package/src/editor/contexts/EditorUIStateContext.tsx +4 -3
- package/src/editor/contexts/EditorVariablesContext.tsx +5 -4
- package/src/editor/contexts/MultiPageCanvasContext.tsx +26 -2
- package/src/editor/hooks/useAiReplace.ts +4 -3
- package/src/editor/hooks/useBrowserZoomPrevention.ts +2 -1
- package/src/editor/hooks/useComponentEditMode.ts +27 -26
- package/src/editor/hooks/useEditorMessages.ts +3 -2
- package/src/editor/hooks/useElementActions.ts +27 -26
- package/src/editor/hooks/useElementSelection.ts +19 -16
- package/src/editor/hooks/useFocusManagement.ts +7 -6
- package/src/editor/hooks/useGoogleFonts.ts +3 -2
- package/src/editor/hooks/useIframeInitializer.ts +6 -3
- package/src/editor/hooks/useIframeSetup.ts +4 -3
- package/src/editor/hooks/useImageUpload.ts +4 -3
- package/src/editor/hooks/useMarqueeSelection.ts +2 -1
- package/src/editor/hooks/usePageSettingsManager.ts +24 -23
- package/src/editor/hooks/useRichPaste.ts +11 -10
- package/src/editor/parts.ts +7 -25
- package/src/editor/utils/component-renderer.ts +8 -7
- package/src/editor/utils/component-sync.ts +16 -15
- package/src/editor/utils/debug.ts +52 -0
- package/src/editor/utils/dom-utils.ts +11 -10
- package/src/editor/utils/drop-target.ts +135 -0
- package/src/editor/utils/eyedropper.ts +3 -1
- package/src/editor/utils/figma-export.ts +6 -5
- package/src/editor/utils/figma-kiwi-decoder.ts +28 -27
- package/src/editor/utils/figma-kiwi-encoder.ts +9 -8
- package/src/editor/utils/figma-paste.ts +57 -56
- package/src/editor/utils/flex-utils.ts +12 -10
- package/src/editor/utils/override-apply.ts +3 -2
- package/src/editor/utils/override-detection.ts +11 -10
- package/src/editor/utils/tailwind-utils.ts +4 -3
- package/src/io.ts +22 -1
- package/src/lib/firebase/css-variables.ts +4 -3
- package/src/lib/firebase/storage.ts +3 -2
- package/src/styles/skin.css +9 -4
- package/src/types/editor.ts +6 -2
- package/src/version.ts +1 -1
|
@@ -38,6 +38,14 @@ export interface ContentListItem {
|
|
|
38
38
|
parentId?: string | null;
|
|
39
39
|
/** 編集しない表示(ページそのもの・ビューア)の URL。渡すとフレーム名と一覧に「別タブで開く」が付く */
|
|
40
40
|
href?: string;
|
|
41
|
+
/**
|
|
42
|
+
* ページ全体を写した画像(PNG / JPEG)の URL。幅は 480px 以上、縦横比はページと同じ。
|
|
43
|
+
* マルチフレームのキャンバスが大きく縮小されている間(倍率 0.5 未満)は、見るだけの紙面を
|
|
44
|
+
* srcdoc の iframe ではなくこの画像で描く(26 枚の iframe をラスタライズし直さずに済む)。
|
|
45
|
+
* 内容が変わったら URL も変える(`&v=…`)。変わると紙面が読み直す。
|
|
46
|
+
* 渡さないページ・画像が読めなかったページは、今までどおり iframe で描く
|
|
47
|
+
*/
|
|
48
|
+
thumbnail?: string;
|
|
41
49
|
/**
|
|
42
50
|
* 本文の版。利用側でファイルが外から変わったとき(部品の一括反映・CLI・他の人の編集)に
|
|
43
51
|
* 数を進めると、キャンバスの見るだけの紙面がそのページを読み直す。編集中のページには効かない
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
import { io } from '../../io';
|
|
47
47
|
import type { EditorPartDef, EditorPartsLibrary } from '../../io';
|
|
48
48
|
import { useMultiPageCanvasOptional } from './MultiPageCanvasContext';
|
|
49
|
+
import { debugLog, isDebugEnabled } from '../utils/debug';
|
|
49
50
|
import {
|
|
50
51
|
materializePart,
|
|
51
52
|
partDefFromElement,
|
|
@@ -211,7 +212,7 @@ export function htmlElementToComponentElement(element: HTMLElement, isRoot: bool
|
|
|
211
212
|
if (key && value) {
|
|
212
213
|
// Skip position-related styles for root element
|
|
213
214
|
if (isRoot && POSITION_STYLES.has(key)) {
|
|
214
|
-
|
|
215
|
+
debugLog(`[htmlElementToComponentElement] Skipping position style for root: ${key}`);
|
|
215
216
|
continue;
|
|
216
217
|
}
|
|
217
218
|
// Convert kebab-case to camelCase
|
|
@@ -238,7 +239,7 @@ export function htmlElementToComponentElement(element: HTMLElement, isRoot: bool
|
|
|
238
239
|
if (hasMixedContent) {
|
|
239
240
|
// Mixed content: use innerHTML to preserve all content
|
|
240
241
|
innerHTML = element.innerHTML;
|
|
241
|
-
|
|
242
|
+
debugLog('[htmlElementToComponentElement] Mixed content detected, using innerHTML');
|
|
242
243
|
} else if (hasElementChildren) {
|
|
243
244
|
// Only element children: recursively process (not root)
|
|
244
245
|
for (const child of Array.from(element.children)) {
|
|
@@ -261,17 +262,20 @@ export function htmlElementToComponentElement(element: HTMLElement, isRoot: bool
|
|
|
261
262
|
overridable: { ...defaultOverridable },
|
|
262
263
|
};
|
|
263
264
|
|
|
264
|
-
//
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
265
|
+
// 要素 1 つにつき 1 行出る。部品 89 個 + 26 ページで 2,000 件を超えるので、
|
|
266
|
+
// 出さないときは引数のオブジェクトを組み立てること自体をやめる
|
|
267
|
+
if (isDebugEnabled()) {
|
|
268
|
+
debugLog('[htmlElementToComponentElement] Converted:', {
|
|
269
|
+
tagName: result.tagName,
|
|
270
|
+
className: result.className,
|
|
271
|
+
hasTextContent: !!result.textContent,
|
|
272
|
+
hasInnerHTML: !!result.innerHTML,
|
|
273
|
+
textContentPreview: result.textContent?.substring(0, 50),
|
|
274
|
+
innerHTMLPreview: result.innerHTML?.substring(0, 50),
|
|
275
|
+
childrenCount: result.children.length,
|
|
276
|
+
stylesCount: Object.keys(result.styles).length,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
275
279
|
|
|
276
280
|
return result;
|
|
277
281
|
}
|
|
@@ -586,7 +590,7 @@ export function EditorComponentsProvider({
|
|
|
586
590
|
setIsLoadingComponents(true);
|
|
587
591
|
setError(null);
|
|
588
592
|
try {
|
|
589
|
-
|
|
593
|
+
debugLog(
|
|
590
594
|
`[EditorComponentsContext] Loading components for website: ${targetWebsiteId}`
|
|
591
595
|
);
|
|
592
596
|
|
|
@@ -610,13 +614,13 @@ export function EditorComponentsProvider({
|
|
|
610
614
|
setMasterComponents(componentsMap);
|
|
611
615
|
setComponentLibrary(categoriesFromParts(lib, componentsMap));
|
|
612
616
|
setComponentInstances(new Map());
|
|
613
|
-
|
|
617
|
+
debugLog(`[EditorComponentsContext] Loaded ${defs.size} parts`);
|
|
614
618
|
return;
|
|
615
619
|
}
|
|
616
620
|
|
|
617
621
|
// Load master components from Firestore
|
|
618
622
|
const components = await getAllMasterComponents(targetWebsiteId);
|
|
619
|
-
|
|
623
|
+
debugLog(`[EditorComponentsContext] Loaded ${components.length} components`);
|
|
620
624
|
|
|
621
625
|
// Create Map from components
|
|
622
626
|
const componentsMap = new Map<string, MasterComponent>();
|
|
@@ -689,9 +693,9 @@ export function EditorComponentsProvider({
|
|
|
689
693
|
|
|
690
694
|
const loadInstances = async () => {
|
|
691
695
|
try {
|
|
692
|
-
|
|
696
|
+
debugLog(`[EditorComponentsContext] Loading instances for page: ${pageId}`);
|
|
693
697
|
const instances = await getPageComponentInstances(websiteId, pageId);
|
|
694
|
-
|
|
698
|
+
debugLog(`[EditorComponentsContext] Loaded ${instances.length} instances`);
|
|
695
699
|
|
|
696
700
|
// Create Map from instances (keyed by domElementId)
|
|
697
701
|
const instancesMap = new Map<string, ComponentInstance>();
|
|
@@ -766,7 +770,7 @@ export function EditorComponentsProvider({
|
|
|
766
770
|
});
|
|
767
771
|
}
|
|
768
772
|
|
|
769
|
-
|
|
773
|
+
debugLog(
|
|
770
774
|
`[EditorComponentsContext] Created master component: ${name} (${id})`
|
|
771
775
|
);
|
|
772
776
|
return masterComponent;
|
|
@@ -996,7 +1000,7 @@ export function EditorComponentsProvider({
|
|
|
996
1000
|
});
|
|
997
1001
|
}
|
|
998
1002
|
|
|
999
|
-
|
|
1003
|
+
debugLog(`[EditorComponentsContext] Deleted master component: ${id}`);
|
|
1000
1004
|
}, [websiteId, partsMode]);
|
|
1001
1005
|
|
|
1002
1006
|
const getMasterComponent = useCallback(
|
|
@@ -1069,7 +1073,7 @@ export function EditorComponentsProvider({
|
|
|
1069
1073
|
});
|
|
1070
1074
|
}
|
|
1071
1075
|
|
|
1072
|
-
|
|
1076
|
+
debugLog(
|
|
1073
1077
|
`[EditorComponentsContext] Created instance: ${id} of master ${masterComponentId}`
|
|
1074
1078
|
);
|
|
1075
1079
|
return instance;
|
|
@@ -1157,7 +1161,7 @@ export function EditorComponentsProvider({
|
|
|
1157
1161
|
return next;
|
|
1158
1162
|
});
|
|
1159
1163
|
|
|
1160
|
-
|
|
1164
|
+
debugLog(`[EditorComponentsContext] Deleted instance: ${instanceId}`);
|
|
1161
1165
|
}, [websiteId, pageId]);
|
|
1162
1166
|
|
|
1163
1167
|
const getInstanceByDomId = useCallback(
|
|
@@ -1219,7 +1223,7 @@ export function EditorComponentsProvider({
|
|
|
1219
1223
|
return next;
|
|
1220
1224
|
});
|
|
1221
1225
|
|
|
1222
|
-
|
|
1226
|
+
debugLog(
|
|
1223
1227
|
`[EditorComponentsContext] Added override to instance: ${instanceId}`
|
|
1224
1228
|
);
|
|
1225
1229
|
},
|
|
@@ -1269,7 +1273,7 @@ export function EditorComponentsProvider({
|
|
|
1269
1273
|
return next;
|
|
1270
1274
|
});
|
|
1271
1275
|
|
|
1272
|
-
|
|
1276
|
+
debugLog(
|
|
1273
1277
|
`[EditorComponentsContext] Removed override ${overrideId} from instance: ${instanceId}`
|
|
1274
1278
|
);
|
|
1275
1279
|
},
|
|
@@ -1321,7 +1325,7 @@ export function EditorComponentsProvider({
|
|
|
1321
1325
|
return next;
|
|
1322
1326
|
});
|
|
1323
1327
|
|
|
1324
|
-
|
|
1328
|
+
debugLog(
|
|
1325
1329
|
`[EditorComponentsContext] Reset all overrides for instance: ${instanceId}`
|
|
1326
1330
|
);
|
|
1327
1331
|
}, [websiteId, pageId]);
|
|
@@ -1394,7 +1398,7 @@ export function EditorComponentsProvider({
|
|
|
1394
1398
|
return next;
|
|
1395
1399
|
});
|
|
1396
1400
|
|
|
1397
|
-
|
|
1401
|
+
debugLog(
|
|
1398
1402
|
`[EditorComponentsContext] Changed variant for instance ${instanceId} to ${variantId}`
|
|
1399
1403
|
);
|
|
1400
1404
|
},
|
|
@@ -1458,7 +1462,7 @@ export function EditorComponentsProvider({
|
|
|
1458
1462
|
});
|
|
1459
1463
|
}
|
|
1460
1464
|
|
|
1461
|
-
|
|
1465
|
+
debugLog(
|
|
1462
1466
|
`[EditorComponentsContext] Detached instance: ${instanceId}`
|
|
1463
1467
|
);
|
|
1464
1468
|
return htmlElement;
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import React, { createContext, useContext, useState, useCallback } from 'react';
|
|
19
19
|
import type { DOMTreeNode, PanelSections, MarqueeState } from '../types';
|
|
20
20
|
import { DEFAULT_PANEL_SECTIONS } from '../constants';
|
|
21
|
+
import { debugLog } from '../utils/debug';
|
|
21
22
|
|
|
22
23
|
export interface EditorUIStateContextValue {
|
|
23
24
|
// DOMツリー
|
|
@@ -81,7 +82,7 @@ export function EditorUIStateProvider({
|
|
|
81
82
|
const restoreFocus = useCallback(() => {
|
|
82
83
|
const iframeDoc = getIframeDoc();
|
|
83
84
|
if (!iframeDoc) {
|
|
84
|
-
|
|
85
|
+
debugLog('[EditorUIStateContext] restoreFocus: iframe doc not available');
|
|
85
86
|
return;
|
|
86
87
|
}
|
|
87
88
|
|
|
@@ -89,14 +90,14 @@ export function EditorUIStateProvider({
|
|
|
89
90
|
const editingElement = iframeDoc.querySelector('[contenteditable="true"]') as HTMLElement;
|
|
90
91
|
if (editingElement) {
|
|
91
92
|
editingElement.focus();
|
|
92
|
-
|
|
93
|
+
debugLog('[EditorUIStateContext] restoreFocus: focused editing element');
|
|
93
94
|
return;
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
// iframeのbodyにフォーカスを設定
|
|
97
98
|
if (iframeDoc.body) {
|
|
98
99
|
iframeDoc.body.focus();
|
|
99
|
-
|
|
100
|
+
debugLog('[EditorUIStateContext] restoreFocus: focused iframe body');
|
|
100
101
|
}
|
|
101
102
|
}, [getIframeDoc]);
|
|
102
103
|
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import React, { createContext, useContext, useState, useCallback, useMemo, useRef } from 'react';
|
|
25
|
+
import { debugLog } from '../utils/debug';
|
|
25
26
|
import type {
|
|
26
27
|
CSSVariableDefinition,
|
|
27
28
|
CSSVariableCategory,
|
|
@@ -264,7 +265,7 @@ export function EditorVariablesProvider({
|
|
|
264
265
|
await onSave(variables);
|
|
265
266
|
savedVariablesRef.current = [...variables];
|
|
266
267
|
setHasChanges(false);
|
|
267
|
-
|
|
268
|
+
debugLog('[EditorVariablesContext] Variables saved successfully');
|
|
268
269
|
} catch (error) {
|
|
269
270
|
console.error('[EditorVariablesContext] Failed to save variables:', error);
|
|
270
271
|
throw error;
|
|
@@ -286,7 +287,7 @@ export function EditorVariablesProvider({
|
|
|
286
287
|
setVariablesState(loaded);
|
|
287
288
|
savedVariablesRef.current = [...loaded];
|
|
288
289
|
setHasChanges(false);
|
|
289
|
-
|
|
290
|
+
debugLog('[EditorVariablesContext] Variables loaded:', loaded.length);
|
|
290
291
|
} catch (error) {
|
|
291
292
|
console.error('[EditorVariablesContext] Failed to load variables:', error);
|
|
292
293
|
throw error;
|
|
@@ -299,7 +300,7 @@ export function EditorVariablesProvider({
|
|
|
299
300
|
const syncFromTheme = useCallback((themeVariables: CSSVariableDefinition[]) => {
|
|
300
301
|
setVariablesState(themeVariables);
|
|
301
302
|
markAsChanged();
|
|
302
|
-
|
|
303
|
+
debugLog('[EditorVariablesContext] Synced from theme:', themeVariables.length, 'variables');
|
|
303
304
|
}, [markAsChanged]);
|
|
304
305
|
|
|
305
306
|
// バルク設定
|
|
@@ -327,7 +328,7 @@ export function EditorVariablesProvider({
|
|
|
327
328
|
}
|
|
328
329
|
|
|
329
330
|
styleEl.textContent = cssString;
|
|
330
|
-
|
|
331
|
+
debugLog('[EditorVariablesContext] Injected CSS variables to iframe');
|
|
331
332
|
}, [cssString]);
|
|
332
333
|
|
|
333
334
|
// Context値
|
|
@@ -62,6 +62,15 @@ export const RULER_SIZE = 20;
|
|
|
62
62
|
const VIEW_ANIMATION_MS = 240;
|
|
63
63
|
/** 見るだけの紙面を同時に読む枚数 */
|
|
64
64
|
const PREVIEW_PARALLEL = 4;
|
|
65
|
+
/**
|
|
66
|
+
* 見るだけの紙面を画像で描く倍率のしきい値。これ未満に縮小されている間は
|
|
67
|
+
* srcdoc の iframe ではなく contentList[].thumbnail の画像を出す。
|
|
68
|
+
* 判定は操作が終わってからしか動かさない(縮小の途中で 26 枚を差し替えない)。
|
|
69
|
+
* 行き来でちらつかないように戻りは別のしきい値にする(ヒステリシス)
|
|
70
|
+
*/
|
|
71
|
+
export const PREVIEW_IMAGE_ZOOM = 0.5;
|
|
72
|
+
/** 画像 → iframe に戻す倍率(PREVIEW_IMAGE_ZOOM 以上)。iframe → 画像は PREVIEW_IMAGE_ZOOM_OUT 未満 */
|
|
73
|
+
export const PREVIEW_IMAGE_ZOOM_OUT = 0.4;
|
|
65
74
|
|
|
66
75
|
/** フレームどうしの間隔(紙面の座標系、等倍のとき)。フレーム名を出すかの判定にも使う */
|
|
67
76
|
export const FRAME_GAP: Record<EditorMode, { x: number; y: number }> = {
|
|
@@ -99,6 +108,8 @@ export interface PageFrame {
|
|
|
99
108
|
depth: number;
|
|
100
109
|
/** 編集しない表示の URL(contentList[].href) */
|
|
101
110
|
href?: string;
|
|
111
|
+
/** ページ全体を写した画像の URL(contentList[].thumbnail)。大きく縮小した間だけ紙面の代わりに出す */
|
|
112
|
+
thumbnail?: string;
|
|
102
113
|
/** 利用側が進める本文の版(contentList[].revision)。変わったら読み直す */
|
|
103
114
|
revision: number;
|
|
104
115
|
/**
|
|
@@ -244,6 +255,17 @@ export function useCanvasViewState(): CanvasViewState {
|
|
|
244
255
|
return useSyncExternalStore(viewStore.subscribe, viewStore.get, viewStore.get);
|
|
245
256
|
}
|
|
246
257
|
|
|
258
|
+
/**
|
|
259
|
+
* 編集中のページだけを購読する。
|
|
260
|
+
* useCanvasViewState() だと倍率・位置が変わるたびに描き直る(ホイール 1 段ごとに
|
|
261
|
+
* キャンバス全体が React を通る)。編集中のページしか要らない側はこちらを使う
|
|
262
|
+
*/
|
|
263
|
+
export function useCanvasActivePageId(): string | null {
|
|
264
|
+
const { viewStore } = useMultiPageCanvas();
|
|
265
|
+
const getSnapshot = useCallback(() => viewStore.get().activePageId, [viewStore]);
|
|
266
|
+
return useSyncExternalStore(viewStore.subscribe, getSnapshot, getSnapshot);
|
|
267
|
+
}
|
|
268
|
+
|
|
247
269
|
const NULL_VIEW_STORE: CanvasViewStore = {
|
|
248
270
|
get: () => NULL_VIEW,
|
|
249
271
|
set: () => undefined,
|
|
@@ -487,6 +509,7 @@ export function MultiPageCanvasProvider({ children, enabled, storageKey }: Multi
|
|
|
487
509
|
const depth = depths.get(content.id) ?? 0;
|
|
488
510
|
const revision = content.revision ?? 0;
|
|
489
511
|
const href = content.href;
|
|
512
|
+
const thumbnail = content.thumbnail;
|
|
490
513
|
if (existing) {
|
|
491
514
|
const title = content.title || existing.title;
|
|
492
515
|
const width = frameWidth;
|
|
@@ -499,9 +522,9 @@ export function MultiPageCanvasProvider({ children, enabled, storageKey }: Multi
|
|
|
499
522
|
if (
|
|
500
523
|
title !== existing.title || html !== existing.html || width !== existing.size.width ||
|
|
501
524
|
parentId !== existing.parentId || depth !== existing.depth || href !== existing.href ||
|
|
502
|
-
revision !== existing.revision || stale !== existing.stale
|
|
525
|
+
revision !== existing.revision || stale !== existing.stale || thumbnail !== existing.thumbnail
|
|
503
526
|
) changed = true;
|
|
504
|
-
next.set(content.id, { ...existing, title, html, stale, parentId, depth, href, revision, size: { width, height: existing.size.height } });
|
|
527
|
+
next.set(content.id, { ...existing, title, html, stale, parentId, depth, href, thumbnail, revision, size: { width, height: existing.size.height } });
|
|
505
528
|
} else {
|
|
506
529
|
changed = true;
|
|
507
530
|
next.set(content.id, {
|
|
@@ -516,6 +539,7 @@ export function MultiPageCanvasProvider({ children, enabled, storageKey }: Multi
|
|
|
516
539
|
parentId,
|
|
517
540
|
depth,
|
|
518
541
|
href,
|
|
542
|
+
thumbnail,
|
|
519
543
|
revision,
|
|
520
544
|
stale: false,
|
|
521
545
|
});
|
|
@@ -13,6 +13,7 @@ import { createAuthApi } from '../../lib/api/auth-fetch';
|
|
|
13
13
|
import { convertSingleElementToAbsolute, generateElementId } from '../utils/dom-utils';
|
|
14
14
|
import type { SlideAgentRequest, SlideAgentResponse, AttachedFile as SlideAttachedFile } from '../../lib/agent/slide-agent/types';
|
|
15
15
|
import type { WebsiteAgentRequest, WebsiteAgentResponse, AttachedFile as WebsiteAttachedFile } from '../../lib/agent/website-agent/types';
|
|
16
|
+
import { debugLog } from '../utils/debug';
|
|
16
17
|
|
|
17
18
|
// AttachedFile型を共通化(両方同じ構造)
|
|
18
19
|
export type AttachedFile = SlideAttachedFile;
|
|
@@ -176,7 +177,7 @@ export function useAiReplace({ presentationId, websiteId }: UseAiReplaceProps =
|
|
|
176
177
|
const convertChildrenToAbsolute = async () => {
|
|
177
178
|
// オートレイアウトモードの場合は変換をスキップ
|
|
178
179
|
if (layoutMode === 'auto') {
|
|
179
|
-
|
|
180
|
+
debugLog('[useAiReplace] Auto layout mode - skipping absolute positioning conversion for children');
|
|
180
181
|
return;
|
|
181
182
|
}
|
|
182
183
|
|
|
@@ -196,7 +197,7 @@ export function useAiReplace({ presentationId, websiteId }: UseAiReplaceProps =
|
|
|
196
197
|
convertSingleElementToAbsolute(iframeDoc, htmlChild);
|
|
197
198
|
});
|
|
198
199
|
|
|
199
|
-
|
|
200
|
+
debugLog('[useAiReplace] Converted', editableChildren.length, 'child elements to absolute positioning');
|
|
200
201
|
|
|
201
202
|
// 変更を再度通知
|
|
202
203
|
notifyIframeChange();
|
|
@@ -263,7 +264,7 @@ export function useAiReplace({ presentationId, websiteId }: UseAiReplaceProps =
|
|
|
263
264
|
// editorModeに基づいてAPI呼び出しを分岐
|
|
264
265
|
const isWebpageMode = editorMode === 'webpage';
|
|
265
266
|
|
|
266
|
-
|
|
267
|
+
debugLog('[useAiReplace] API呼び出し:', {
|
|
267
268
|
editorMode,
|
|
268
269
|
apiEndpoint: isWebpageMode ? '/api/website-agent' : '/api/slide-agent',
|
|
269
270
|
promptLength: prompt.length,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
+
import { debugLog } from '../utils/debug';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* ブラウザのネイティブズーム(ピンチ、Ctrl+ホイール、キーボードショートカット等)を防止するフック
|
|
@@ -67,7 +68,7 @@ export function useBrowserZoomPrevention(): void {
|
|
|
67
68
|
// e.key ではなく e.code を使用して物理キーを判定する
|
|
68
69
|
// preventDefault のみでブラウザのデフォルト動作を止め、自前のハンドラーは動くようにする
|
|
69
70
|
if (isCmdOrCtrl && e.altKey && (e.code === 'KeyC' || e.code === 'KeyV')) {
|
|
70
|
-
|
|
71
|
+
debugLog('[preventBrowserShortcuts] Preventing browser default for Cmd/Ctrl+Alt+C/V', {
|
|
71
72
|
key: e.key,
|
|
72
73
|
code: e.code,
|
|
73
74
|
});
|
|
@@ -7,6 +7,7 @@ import { buildDomTree } from '../utils/dom-utils';
|
|
|
7
7
|
import { applyLockInside, detachPart, partInfoOf, unlockPartDescendants } from '../parts';
|
|
8
8
|
import { toast } from 'sonner';
|
|
9
9
|
import type { MasterComponent, ComponentInstance } from '../../types/editor-components';
|
|
10
|
+
import { debugLog } from '../utils/debug';
|
|
10
11
|
|
|
11
12
|
interface UseComponentEditModeProps {
|
|
12
13
|
contentId?: string;
|
|
@@ -201,7 +202,7 @@ export function useComponentEditMode({
|
|
|
201
202
|
|
|
202
203
|
try {
|
|
203
204
|
// Debug: Log the original element
|
|
204
|
-
|
|
205
|
+
debugLog('[handleConfirmCreateComponent] Original element:', {
|
|
205
206
|
tagName: element.tagName,
|
|
206
207
|
className: element.className,
|
|
207
208
|
innerHTML: element.innerHTML.substring(0, 200),
|
|
@@ -212,7 +213,7 @@ export function useComponentEditMode({
|
|
|
212
213
|
|
|
213
214
|
// Create the master component
|
|
214
215
|
const component = createMasterComponent(element, newComponentName.trim(), newComponentCategory || 'content');
|
|
215
|
-
|
|
216
|
+
debugLog('[handleConfirmCreateComponent] Created component:', {
|
|
216
217
|
id: component.id,
|
|
217
218
|
name: component.name,
|
|
218
219
|
variantsCount: component.variants.length,
|
|
@@ -248,7 +249,7 @@ export function useComponentEditMode({
|
|
|
248
249
|
{ x: positionX, y: positionY } // initialPosition
|
|
249
250
|
);
|
|
250
251
|
if (instance) {
|
|
251
|
-
|
|
252
|
+
debugLog('[handleConfirmCreateComponent] Created instance:', {
|
|
252
253
|
id: instance.id,
|
|
253
254
|
domElementId: instance.domElementId,
|
|
254
255
|
variantId: instance.variantId,
|
|
@@ -259,7 +260,7 @@ export function useComponentEditMode({
|
|
|
259
260
|
const { renderInstance } = await import('../utils/component-renderer');
|
|
260
261
|
const instanceElement = renderInstance(component, instance, iframeDoc);
|
|
261
262
|
|
|
262
|
-
|
|
263
|
+
debugLog('[handleConfirmCreateComponent] Rendered instance element:', {
|
|
263
264
|
tagName: instanceElement.tagName,
|
|
264
265
|
className: instanceElement.className,
|
|
265
266
|
innerHTML: instanceElement.innerHTML.substring(0, 200),
|
|
@@ -281,7 +282,7 @@ export function useComponentEditMode({
|
|
|
281
282
|
// Update history
|
|
282
283
|
notifyIframeChange(true);
|
|
283
284
|
|
|
284
|
-
|
|
285
|
+
debugLog('[handleConfirmCreateComponent] Replaced element with instance:', instance.id);
|
|
285
286
|
}
|
|
286
287
|
|
|
287
288
|
setCreateComponentDialogOpen(false);
|
|
@@ -349,11 +350,11 @@ export function useComponentEditMode({
|
|
|
349
350
|
originalPageHtmlRef.current = artboard.innerHTML;
|
|
350
351
|
|
|
351
352
|
// DEBUG: Log what instances are being saved
|
|
352
|
-
|
|
353
|
+
debugLog('[enterComponentEditMode] ========== SAVING PAGE HTML ==========');
|
|
353
354
|
const instancesToSave = artboard.querySelectorAll('[data-component-instance]');
|
|
354
|
-
|
|
355
|
+
debugLog('[enterComponentEditMode] Saving', instancesToSave.length, 'instances');
|
|
355
356
|
instancesToSave.forEach((inst, idx) => {
|
|
356
|
-
|
|
357
|
+
debugLog(`[enterComponentEditMode] Instance ${idx} text being saved:`, inst.textContent?.substring(0, 100));
|
|
357
358
|
});
|
|
358
359
|
}
|
|
359
360
|
|
|
@@ -458,16 +459,16 @@ export function useComponentEditMode({
|
|
|
458
459
|
const artboard = iframeDoc.getElementById('artboard');
|
|
459
460
|
|
|
460
461
|
// DEBUG: Log what we're about to restore
|
|
461
|
-
|
|
462
|
-
|
|
462
|
+
debugLog('[exitComponentEditMode] ========== HTML RESTORE DEBUG ==========');
|
|
463
|
+
debugLog('[exitComponentEditMode] originalPageHtmlRef exists:', originalPageHtmlRef.current !== null);
|
|
463
464
|
if (originalPageHtmlRef.current) {
|
|
464
465
|
// Extract instance text from saved HTML for debugging
|
|
465
466
|
const tempDiv = document.createElement('div');
|
|
466
467
|
tempDiv.innerHTML = originalPageHtmlRef.current;
|
|
467
468
|
const savedInstances = tempDiv.querySelectorAll('[data-component-instance]');
|
|
468
|
-
|
|
469
|
+
debugLog('[exitComponentEditMode] Saved HTML has', savedInstances.length, 'instances');
|
|
469
470
|
savedInstances.forEach((inst, idx) => {
|
|
470
|
-
|
|
471
|
+
debugLog(`[exitComponentEditMode] Saved instance ${idx} text:`, inst.textContent?.substring(0, 100));
|
|
471
472
|
});
|
|
472
473
|
}
|
|
473
474
|
|
|
@@ -477,9 +478,9 @@ export function useComponentEditMode({
|
|
|
477
478
|
|
|
478
479
|
// DEBUG: Log what's in the DOM after restore
|
|
479
480
|
const restoredInstances = artboard.querySelectorAll('[data-component-instance]');
|
|
480
|
-
|
|
481
|
+
debugLog('[exitComponentEditMode] After restore, DOM has', restoredInstances.length, 'instances');
|
|
481
482
|
restoredInstances.forEach((inst, idx) => {
|
|
482
|
-
|
|
483
|
+
debugLog(`[exitComponentEditMode] Restored instance ${idx} text:`, inst.textContent?.substring(0, 100));
|
|
483
484
|
});
|
|
484
485
|
}
|
|
485
486
|
|
|
@@ -489,8 +490,8 @@ export function useComponentEditMode({
|
|
|
489
490
|
const instancesArray = Array.from(componentInstances.values());
|
|
490
491
|
|
|
491
492
|
// Debug: Log the updated master and instances
|
|
492
|
-
|
|
493
|
-
|
|
493
|
+
debugLog('[exitComponentEditMode] ========== SYNC DEBUG ==========');
|
|
494
|
+
debugLog('[exitComponentEditMode] Updated master:', {
|
|
494
495
|
id: updatedMaster.id,
|
|
495
496
|
name: updatedMaster.name,
|
|
496
497
|
variantsCount: updatedMaster.variants.length,
|
|
@@ -499,7 +500,7 @@ export function useComponentEditMode({
|
|
|
499
500
|
// Log master's text content
|
|
500
501
|
const defaultVariant = updatedMaster.variants.find(v => v.id === updatedMaster.defaultVariantId);
|
|
501
502
|
if (defaultVariant) {
|
|
502
|
-
|
|
503
|
+
debugLog('[exitComponentEditMode] Master rootElement:', {
|
|
503
504
|
tagName: defaultVariant.rootElement.tagName,
|
|
504
505
|
textContent: defaultVariant.rootElement.textContent?.substring(0, 100),
|
|
505
506
|
innerHTML: defaultVariant.rootElement.innerHTML?.substring(0, 100),
|
|
@@ -507,7 +508,7 @@ export function useComponentEditMode({
|
|
|
507
508
|
});
|
|
508
509
|
}
|
|
509
510
|
|
|
510
|
-
|
|
511
|
+
debugLog('[exitComponentEditMode] Instances to sync:', instancesArray.map(i => ({
|
|
511
512
|
id: i.id,
|
|
512
513
|
masterComponentId: i.masterComponentId,
|
|
513
514
|
domElementId: i.domElementId,
|
|
@@ -519,9 +520,9 @@ export function useComponentEditMode({
|
|
|
519
520
|
const artboardForSync = iframeDoc.getElementById('artboard');
|
|
520
521
|
if (artboardForSync) {
|
|
521
522
|
const instanceElements = artboardForSync.querySelectorAll(`[data-component-master="${updatedMaster.id}"]`);
|
|
522
|
-
|
|
523
|
+
debugLog('[exitComponentEditMode] Instance elements in DOM:', instanceElements.length);
|
|
523
524
|
instanceElements.forEach((el, i) => {
|
|
524
|
-
|
|
525
|
+
debugLog(`[exitComponentEditMode] DOM instance ${i}:`, {
|
|
525
526
|
instanceId: el.getAttribute('data-component-instance'),
|
|
526
527
|
masterId: el.getAttribute('data-component-master'),
|
|
527
528
|
elementId: el.getAttribute('data-element-id'),
|
|
@@ -532,11 +533,11 @@ export function useComponentEditMode({
|
|
|
532
533
|
|
|
533
534
|
// Propagate master changes to all instances in the DOM
|
|
534
535
|
const syncResult = propagateMasterChanges(updatedMaster, instancesArray, iframeDoc);
|
|
535
|
-
|
|
536
|
+
debugLog('[exitComponentEditMode] Synced instances:', syncResult);
|
|
536
537
|
|
|
537
538
|
// Persist updated instances with their newly detected overrides
|
|
538
539
|
if (syncResult.updatedInstances.length > 0) {
|
|
539
|
-
|
|
540
|
+
debugLog('[exitComponentEditMode] Persisting updated instances with overrides:',
|
|
540
541
|
syncResult.updatedInstances.map(i => ({
|
|
541
542
|
id: i.id,
|
|
542
543
|
overridesCount: i.overrides.length,
|
|
@@ -576,7 +577,7 @@ export function useComponentEditMode({
|
|
|
576
577
|
// Go to main component - enters component edit mode to directly edit the master in canvas
|
|
577
578
|
const handleGoToMainComponent = useCallback(() => {
|
|
578
579
|
if (!selectedElementInstance) return;
|
|
579
|
-
|
|
580
|
+
debugLog('Go to main component:', selectedElementInstance.masterComponentId);
|
|
580
581
|
enterComponentEditMode(selectedElementInstance.masterComponentId);
|
|
581
582
|
}, [selectedElementInstance, enterComponentEditMode]);
|
|
582
583
|
|
|
@@ -610,7 +611,7 @@ export function useComponentEditMode({
|
|
|
610
611
|
}
|
|
611
612
|
}
|
|
612
613
|
|
|
613
|
-
|
|
614
|
+
debugLog('Detached instance:', selectedElementInstance.id);
|
|
614
615
|
closeContextMenu();
|
|
615
616
|
toast.success('インスタンスを解除しました');
|
|
616
617
|
} catch (error) {
|
|
@@ -650,7 +651,7 @@ export function useComponentEditMode({
|
|
|
650
651
|
}
|
|
651
652
|
}
|
|
652
653
|
|
|
653
|
-
|
|
654
|
+
debugLog('Reset overrides for instance:', selectedElementInstance.id);
|
|
654
655
|
closeContextMenu();
|
|
655
656
|
toast.success('オーバーライドをリセットしました');
|
|
656
657
|
} catch (error) {
|
|
@@ -662,7 +663,7 @@ export function useComponentEditMode({
|
|
|
662
663
|
// Push overrides to main (placeholder - requires more complex implementation)
|
|
663
664
|
const handlePushOverridesToMain = useCallback(() => {
|
|
664
665
|
if (!selectedElementInstance) return;
|
|
665
|
-
|
|
666
|
+
debugLog('Push overrides to main - not yet implemented');
|
|
666
667
|
closeContextMenu();
|
|
667
668
|
toast.info('この機能は現在開発中です');
|
|
668
669
|
}, [selectedElementInstance, closeContextMenu]);
|
|
@@ -9,6 +9,7 @@ import { useEditorContext } from '../EditorContext';
|
|
|
9
9
|
import { buildDomTree, updateSelectionBox } from '../utils/dom-utils';
|
|
10
10
|
import { extractElementInfo } from '../utils/style-utils';
|
|
11
11
|
import type { DOMTreeNode } from '../types';
|
|
12
|
+
import { debugLog } from '../utils/debug';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* postMessageの受信と処理を行うHook
|
|
@@ -55,7 +56,7 @@ export function useEditorMessages() {
|
|
|
55
56
|
|
|
56
57
|
// DOMツリー更新
|
|
57
58
|
if (event.data?.type === 'DOM_TREE_UPDATED') {
|
|
58
|
-
|
|
59
|
+
debugLog('[EditorMessages] DOM_TREE_UPDATED received:', event.data.tree?.length, 'nodes');
|
|
59
60
|
if (event.data.tree && Array.isArray(event.data.tree)) {
|
|
60
61
|
setDomTree(event.data.tree);
|
|
61
62
|
// 初期状態で最初のレベルを展開
|
|
@@ -71,7 +72,7 @@ export function useEditorMessages() {
|
|
|
71
72
|
const iframeDoc = getIframeDoc();
|
|
72
73
|
if (iframeDoc) {
|
|
73
74
|
const tree = buildDomTree(iframeDoc);
|
|
74
|
-
|
|
75
|
+
debugLog('[EditorMessages] Rebuilt DOM tree:', tree.length, 'nodes');
|
|
75
76
|
setDomTree(tree);
|
|
76
77
|
}
|
|
77
78
|
}
|