@growgroup/visual-editor 0.3.0 → 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.
Files changed (65) hide show
  1. package/README.md +10 -1
  2. package/dist/editor.css +1 -1
  3. package/package.json +3 -2
  4. package/src/editor/EditorContext.tsx +11 -2
  5. package/src/editor/EditorToolbar.tsx +8 -2
  6. package/src/editor/FrontendVisualEditor.tsx +128 -45
  7. package/src/editor/components/EditorCanvas.tsx +87 -15
  8. package/src/editor/components/EditorContextMenu.tsx +12 -3
  9. package/src/editor/components/EditorFooter.tsx +2 -0
  10. package/src/editor/components/EditorHeader.tsx +3 -2
  11. package/src/editor/components/EditorLayerPanel.tsx +28 -2
  12. package/src/editor/components/EditorPropertyPanel.tsx +54 -25
  13. package/src/editor/components/FigmaColorPicker.tsx +2 -1
  14. package/src/editor/components/JsEditorDialog.tsx +1 -0
  15. package/src/editor/components/PageSettingsDialog.tsx +1 -0
  16. package/src/editor/components/comments/CommentBoard.tsx +9 -6
  17. package/src/editor/components/multi-page/CanvasFrameDecor.tsx +172 -0
  18. package/src/editor/components/multi-page/MultiPageCanvasView.tsx +204 -58
  19. package/src/editor/components/multi-page/PageFramePreview.tsx +131 -22
  20. package/src/editor/components/multi-page/index.ts +1 -0
  21. package/src/editor/components/ppt/PptChrome.tsx +6 -2
  22. package/src/editor/components/ppt/PptComments.tsx +411 -71
  23. package/src/editor/constants.ts +44 -1
  24. package/src/editor/contexts/EditorArtboardContext.tsx +60 -1
  25. package/src/editor/contexts/EditorComponentsContext.tsx +48 -31
  26. package/src/editor/contexts/EditorUIStateContext.tsx +4 -3
  27. package/src/editor/contexts/EditorVariablesContext.tsx +5 -4
  28. package/src/editor/contexts/MultiPageCanvasContext.tsx +211 -34
  29. package/src/editor/hooks/useAiReplace.ts +4 -3
  30. package/src/editor/hooks/useBrowserZoomPrevention.ts +2 -1
  31. package/src/editor/hooks/useComponentEditMode.ts +27 -26
  32. package/src/editor/hooks/useEditorMessages.ts +3 -2
  33. package/src/editor/hooks/useElementActions.ts +27 -26
  34. package/src/editor/hooks/useElementSelection.ts +19 -16
  35. package/src/editor/hooks/useFocusManagement.ts +7 -6
  36. package/src/editor/hooks/useGoogleFonts.ts +3 -2
  37. package/src/editor/hooks/useIframeInitializer.ts +6 -3
  38. package/src/editor/hooks/useIframeSetup.ts +4 -3
  39. package/src/editor/hooks/useImageUpload.ts +4 -3
  40. package/src/editor/hooks/useMarqueeSelection.ts +2 -1
  41. package/src/editor/hooks/usePageSettingsManager.ts +24 -23
  42. package/src/editor/hooks/useRichPaste.ts +11 -10
  43. package/src/editor/parts.ts +7 -25
  44. package/src/editor/utils/component-renderer.ts +8 -7
  45. package/src/editor/utils/component-sync.ts +16 -15
  46. package/src/editor/utils/debug.ts +52 -0
  47. package/src/editor/utils/dom-utils.ts +27 -10
  48. package/src/editor/utils/drop-target.ts +135 -0
  49. package/src/editor/utils/eyedropper.ts +3 -1
  50. package/src/editor/utils/figma-export.ts +6 -5
  51. package/src/editor/utils/figma-kiwi-decoder.ts +28 -27
  52. package/src/editor/utils/figma-kiwi-encoder.ts +9 -8
  53. package/src/editor/utils/figma-paste.ts +57 -56
  54. package/src/editor/utils/flex-utils.ts +12 -10
  55. package/src/editor/utils/html-utils.ts +19 -6
  56. package/src/editor/utils/override-apply.ts +3 -2
  57. package/src/editor/utils/override-detection.ts +11 -10
  58. package/src/editor/utils/tailwind-utils.ts +4 -3
  59. package/src/index.ts +5 -0
  60. package/src/io.ts +22 -1
  61. package/src/lib/firebase/css-variables.ts +4 -3
  62. package/src/lib/firebase/storage.ts +3 -2
  63. package/src/styles/skin.css +63 -4
  64. package/src/types/editor.ts +6 -2
  65. package/src/version.ts +9 -0
@@ -183,7 +183,22 @@ export const EDITOR_IFRAME_STYLES = `
183
183
  body.text-mode [data-editable="true"] {
184
184
  pointer-events: none;
185
185
  }
186
- body:not(.draw-mode):not(.text-mode):not(.move-mode) [data-editable="true"] {
186
+ /* コメントの範囲指定中: 要素は反応せず、紙面のドラッグが範囲になる */
187
+ body.comment-mode {
188
+ cursor: crosshair !important;
189
+ }
190
+ body.comment-mode [data-editable="true"] {
191
+ pointer-events: none;
192
+ }
193
+ body.comment-mode .selection-box,
194
+ body.comment-mode .hover-preview {
195
+ display: none !important;
196
+ }
197
+ /* 範囲の枠の上からも新しい範囲を描けるように(ピンはクリックでスレッドを開く) */
198
+ body.comment-mode .gg-comment-layer [data-comment-rect] {
199
+ pointer-events: none !important;
200
+ }
201
+ body:not(.draw-mode):not(.text-mode):not(.move-mode):not(.comment-mode) [data-editable="true"] {
187
202
  pointer-events: auto !important;
188
203
  cursor: pointer;
189
204
  }
@@ -375,6 +390,34 @@ export const EDITOR_IFRAME_STYLES = `
375
390
  .selection-box.selection-member .selection-outline {
376
391
  box-shadow: 0 0 0 calc(1px * var(--ov)) rgba(13, 153, 255, 0.75);
377
392
  }
393
+ /*
394
+ * 部品(data-part)のインスタンスは紫(Figma のコンポーネントと同じ色)。
395
+ * ルートを選んだら枠・ハンドル・サイズラベルが紫、中のスロットを選んだら枠は青のまま
396
+ * 「部品の中」の札だけ出す。札はパンくず(上 -22px)の左上に重ならないよう、その上に置く
397
+ */
398
+ .selection-box.selection-part .selection-outline { box-shadow: 0 0 0 var(--outline-w) #7b61ff; }
399
+ .selection-box.selection-part .resize-handle::after { border-color: #7b61ff; }
400
+ .selection-box.selection-part .size-label { background: #7b61ff; }
401
+ .selection-box.selection-member.selection-part .selection-outline { box-shadow: 0 0 0 calc(1px * var(--ov)) rgba(123, 97, 255, 0.8); }
402
+ .selection-box .part-badge {
403
+ position: absolute;
404
+ top: calc(-44px * var(--ov));
405
+ left: 0;
406
+ padding: calc(2px * var(--ov)) calc(6px * var(--ov));
407
+ border-radius: calc(3px * var(--ov));
408
+ background: #7b61ff;
409
+ color: #fff;
410
+ font-size: calc(10px * var(--ov));
411
+ line-height: 1.4;
412
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Hiragino Sans', 'Noto Sans JP', sans-serif;
413
+ white-space: nowrap;
414
+ pointer-events: none;
415
+ z-index: 40;
416
+ }
417
+ .selection-box.selection-in-part .part-badge { background: rgba(123, 97, 255, 0.85); }
418
+ /* 選んでいる部品のスロット(編集できる範囲)は点線。中を選んでいるときは部品の外周を薄い点線で示す */
419
+ [data-part].selected [data-slot] { outline: calc(1px * var(--overlay-scale, 1)) dashed rgba(123, 97, 255, 0.75); outline-offset: calc(-1px * var(--overlay-scale, 1)); }
420
+ [data-part]:not(.selected):has(.selected) { outline: calc(1px * var(--overlay-scale, 1)) dashed rgba(123, 97, 255, 0.55); outline-offset: calc(2px * var(--overlay-scale, 1)); }
378
421
  .size-label {
379
422
  position: absolute;
380
423
  bottom: calc(-22px * var(--ov));
@@ -14,7 +14,7 @@
14
14
  * - contentList: コンテンツリスト(スライド、ページ等)
15
15
  */
16
16
 
17
- import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
17
+ import React, { createContext, useContext, useState, useCallback, useEffect, useMemo } from 'react';
18
18
  import type { DOMTreeNode } from '../types';
19
19
 
20
20
  /**
@@ -30,6 +30,56 @@ export interface ContentListItem {
30
30
  /** 表示順序(スライド番号、ページ番号等) */
31
31
  order: number;
32
32
  thumbnailHtml?: string;
33
+ /**
34
+ * 親ページの id(サイトマップの階層)。渡すと、マルチフレームのキャンバスが
35
+ * フレームを階層のツリー(親の下に子を並べる)で配置し、左パネルの一覧も段を付ける。
36
+ * 無ければ(全ページ null / undefined)従来どおり行で折り返す
37
+ */
38
+ parentId?: string | null;
39
+ /** 編集しない表示(ページそのもの・ビューア)の URL。渡すとフレーム名と一覧に「別タブで開く」が付く */
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;
49
+ /**
50
+ * 本文の版。利用側でファイルが外から変わったとき(部品の一括反映・CLI・他の人の編集)に
51
+ * 数を進めると、キャンバスの見るだけの紙面がそのページを読み直す。編集中のページには効かない
52
+ * (編集中の本文は上書きしない)
53
+ */
54
+ revision?: number;
55
+ }
56
+
57
+ /**
58
+ * 文書に付ける属性(`<html>` の属性)。生きているエディタと見るだけの紙面の両方の文書に、
59
+ * 読み直さずに反映する。利用側の CSS が `html[data-…]` で切り替える表示(構成ラフの
60
+ * 注釈カラムの表示・非表示など)に使う。値が null / undefined の属性は外す
61
+ */
62
+ export type DocumentAttributes = Record<string, string | null | undefined>;
63
+
64
+ /** contentList の parentId から各ページの深さ(ルート = 0)を求める。親が一覧に無い・循環しているものはルート扱い */
65
+ export function computeContentDepths(list: readonly ContentListItem[]): Map<string, number> {
66
+ const byId = new Map(list.map((c) => [c.id, c] as const));
67
+ const depths = new Map<string, number>();
68
+ const depthOf = (id: string, seen: Set<string>): number => {
69
+ const cached = depths.get(id);
70
+ if (cached != null) return cached;
71
+ const item = byId.get(id);
72
+ const parent = item?.parentId;
73
+ let d = 0;
74
+ if (parent && parent !== id && byId.has(parent) && !seen.has(parent)) {
75
+ seen.add(id);
76
+ d = depthOf(parent, seen) + 1;
77
+ }
78
+ depths.set(id, d);
79
+ return d;
80
+ };
81
+ list.forEach((c) => depthOf(c.id, new Set()));
82
+ return depths;
33
83
  }
34
84
 
35
85
  // アートボード(スライド/ページ)ごとの状態
@@ -55,6 +105,8 @@ export interface EditorArtboardContextValue {
55
105
  contentList: ContentListItem[];
56
106
  currentContentId: string | null;
57
107
  onContentChange: ContentChangeHandler | null;
108
+ /** 文書(`<html>`)に付ける属性。エディタと見るだけの紙面の両方に、読み直さずに反映する */
109
+ documentAttributes: DocumentAttributes;
58
110
 
59
111
  // Deprecated aliases
60
112
  /** @deprecated Use contentList instead */
@@ -79,6 +131,7 @@ interface EditorArtboardProviderProps {
79
131
  contentList?: ContentListItem[];
80
132
  currentContentId?: string;
81
133
  onContentChange?: ContentChangeHandler;
134
+ documentAttributes?: DocumentAttributes;
82
135
  // 状態同期用のコールバック(ファサードで設定)
83
136
  onArtboardSwitch?: (
84
137
  newId: string,
@@ -110,6 +163,7 @@ export function EditorArtboardProvider({
110
163
  contentList: contentListProp,
111
164
  currentContentId: currentContentIdProp,
112
165
  onContentChange: onContentChangeProp,
166
+ documentAttributes: documentAttributesProp,
113
167
  slides: slidesProp,
114
168
  currentSlideId: currentSlideIdProp,
115
169
  onSlideChange: onSlideChangeProp,
@@ -119,6 +173,10 @@ export function EditorArtboardProvider({
119
173
  const contentList = contentListProp ?? slidesProp ?? [];
120
174
  const currentContentId = currentContentIdProp ?? currentSlideIdProp ?? null;
121
175
  const onContentChange = onContentChangeProp ?? onSlideChangeProp ?? null;
176
+ // 属性は中身で比べる(利用側が毎描画で新しいオブジェクトを渡しても、購読側を描き直さない)
177
+ const documentAttributesKey = JSON.stringify(documentAttributesProp ?? {});
178
+ // eslint-disable-next-line react-hooks/exhaustive-deps
179
+ const documentAttributes = useMemo<DocumentAttributes>(() => ({ ...(documentAttributesProp ?? {}) }), [documentAttributesKey]);
122
180
 
123
181
  // Deprecated aliases
124
182
  const slides = contentList;
@@ -221,6 +279,7 @@ export function EditorArtboardProvider({
221
279
  contentList,
222
280
  currentContentId,
223
281
  onContentChange,
282
+ documentAttributes,
224
283
  // Deprecated
225
284
  slides,
226
285
  currentSlideId,
@@ -45,6 +45,8 @@ import {
45
45
  } from '../../lib/firebase/editor-components';
46
46
  import { io } from '../../io';
47
47
  import type { EditorPartDef, EditorPartsLibrary } from '../../io';
48
+ import { useMultiPageCanvasOptional } from './MultiPageCanvasContext';
49
+ import { debugLog, isDebugEnabled } from '../utils/debug';
48
50
  import {
49
51
  materializePart,
50
52
  partDefFromElement,
@@ -210,7 +212,7 @@ export function htmlElementToComponentElement(element: HTMLElement, isRoot: bool
210
212
  if (key && value) {
211
213
  // Skip position-related styles for root element
212
214
  if (isRoot && POSITION_STYLES.has(key)) {
213
- console.log(`[htmlElementToComponentElement] Skipping position style for root: ${key}`);
215
+ debugLog(`[htmlElementToComponentElement] Skipping position style for root: ${key}`);
214
216
  continue;
215
217
  }
216
218
  // Convert kebab-case to camelCase
@@ -237,7 +239,7 @@ export function htmlElementToComponentElement(element: HTMLElement, isRoot: bool
237
239
  if (hasMixedContent) {
238
240
  // Mixed content: use innerHTML to preserve all content
239
241
  innerHTML = element.innerHTML;
240
- console.log('[htmlElementToComponentElement] Mixed content detected, using innerHTML');
242
+ debugLog('[htmlElementToComponentElement] Mixed content detected, using innerHTML');
241
243
  } else if (hasElementChildren) {
242
244
  // Only element children: recursively process (not root)
243
245
  for (const child of Array.from(element.children)) {
@@ -260,17 +262,20 @@ export function htmlElementToComponentElement(element: HTMLElement, isRoot: bool
260
262
  overridable: { ...defaultOverridable },
261
263
  };
262
264
 
263
- // Debug logging
264
- console.log('[htmlElementToComponentElement] Converted:', {
265
- tagName: result.tagName,
266
- className: result.className,
267
- hasTextContent: !!result.textContent,
268
- hasInnerHTML: !!result.innerHTML,
269
- textContentPreview: result.textContent?.substring(0, 50),
270
- innerHTMLPreview: result.innerHTML?.substring(0, 50),
271
- childrenCount: result.children.length,
272
- stylesCount: Object.keys(result.styles).length,
273
- });
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
+ }
274
279
 
275
280
  return result;
276
281
  }
@@ -474,6 +479,13 @@ export function EditorComponentsProvider({
474
479
  websiteId,
475
480
  pageId,
476
481
  }: EditorComponentsProviderProps) {
482
+ // マルチフレームのキャンバス(あれば)。部品の定義を更新したあと、他ページの紙面を読み直させる。
483
+ // ref で持つ: キャンバスの値は高さの実測のたびに変わるので、コールバックの依存に入れない
484
+ const canvas = useMultiPageCanvasOptional();
485
+ const canvasRef = useRef(canvas);
486
+ canvasRef.current = canvas;
487
+ const pageIdRef = useRef(pageId);
488
+ pageIdRef.current = pageId;
477
489
  // State
478
490
  const [masterComponents, setMasterComponents] = useState<
479
491
  Map<string, MasterComponent>
@@ -578,7 +590,7 @@ export function EditorComponentsProvider({
578
590
  setIsLoadingComponents(true);
579
591
  setError(null);
580
592
  try {
581
- console.log(
593
+ debugLog(
582
594
  `[EditorComponentsContext] Loading components for website: ${targetWebsiteId}`
583
595
  );
584
596
 
@@ -602,13 +614,13 @@ export function EditorComponentsProvider({
602
614
  setMasterComponents(componentsMap);
603
615
  setComponentLibrary(categoriesFromParts(lib, componentsMap));
604
616
  setComponentInstances(new Map());
605
- console.log(`[EditorComponentsContext] Loaded ${defs.size} parts`);
617
+ debugLog(`[EditorComponentsContext] Loaded ${defs.size} parts`);
606
618
  return;
607
619
  }
608
620
 
609
621
  // Load master components from Firestore
610
622
  const components = await getAllMasterComponents(targetWebsiteId);
611
- console.log(`[EditorComponentsContext] Loaded ${components.length} components`);
623
+ debugLog(`[EditorComponentsContext] Loaded ${components.length} components`);
612
624
 
613
625
  // Create Map from components
614
626
  const componentsMap = new Map<string, MasterComponent>();
@@ -681,9 +693,9 @@ export function EditorComponentsProvider({
681
693
 
682
694
  const loadInstances = async () => {
683
695
  try {
684
- console.log(`[EditorComponentsContext] Loading instances for page: ${pageId}`);
696
+ debugLog(`[EditorComponentsContext] Loading instances for page: ${pageId}`);
685
697
  const instances = await getPageComponentInstances(websiteId, pageId);
686
- console.log(`[EditorComponentsContext] Loaded ${instances.length} instances`);
698
+ debugLog(`[EditorComponentsContext] Loaded ${instances.length} instances`);
687
699
 
688
700
  // Create Map from instances (keyed by domElementId)
689
701
  const instancesMap = new Map<string, ComponentInstance>();
@@ -758,7 +770,7 @@ export function EditorComponentsProvider({
758
770
  });
759
771
  }
760
772
 
761
- console.log(
773
+ debugLog(
762
774
  `[EditorComponentsContext] Created master component: ${name} (${id})`
763
775
  );
764
776
  return masterComponent;
@@ -870,6 +882,9 @@ export function EditorComponentsProvider({
870
882
  const saved = (save ? await save(next) : undefined) ?? next;
871
883
  upsertPartDef(saved);
872
884
  el.setAttribute('data-part-v', String(saved.version));
885
+ // 他ページのインスタンスは利用側(savePart)が書き換えている。キャンバスの見るだけの紙面にもその場で反映する
886
+ // (以前は読み直すまで前の姿のままだった)。編集中のページは今の DOM が正なので触らない
887
+ canvasRef.current?.invalidatePages({ except: [pageIdRef.current] });
873
888
  return saved;
874
889
  },
875
890
  [partDefs, upsertPartDef]
@@ -930,10 +945,12 @@ export function EditorComponentsProvider({
930
945
  m.set(id, next);
931
946
  return m;
932
947
  });
933
- io().savePart?.(next).catch((err) => {
934
- console.error('[EditorComponentsContext] 部品の保存に失敗:', err);
935
- setError('部品の保存に失敗しました');
936
- });
948
+ io().savePart?.(next)
949
+ .then(() => canvasRef.current?.invalidatePages({ except: [pageIdRef.current] }))
950
+ .catch((err) => {
951
+ console.error('[EditorComponentsContext] 部品の保存に失敗:', err);
952
+ setError('部品の保存に失敗しました');
953
+ });
937
954
  }
938
955
  }
939
956
  },
@@ -983,7 +1000,7 @@ export function EditorComponentsProvider({
983
1000
  });
984
1001
  }
985
1002
 
986
- console.log(`[EditorComponentsContext] Deleted master component: ${id}`);
1003
+ debugLog(`[EditorComponentsContext] Deleted master component: ${id}`);
987
1004
  }, [websiteId, partsMode]);
988
1005
 
989
1006
  const getMasterComponent = useCallback(
@@ -1056,7 +1073,7 @@ export function EditorComponentsProvider({
1056
1073
  });
1057
1074
  }
1058
1075
 
1059
- console.log(
1076
+ debugLog(
1060
1077
  `[EditorComponentsContext] Created instance: ${id} of master ${masterComponentId}`
1061
1078
  );
1062
1079
  return instance;
@@ -1144,7 +1161,7 @@ export function EditorComponentsProvider({
1144
1161
  return next;
1145
1162
  });
1146
1163
 
1147
- console.log(`[EditorComponentsContext] Deleted instance: ${instanceId}`);
1164
+ debugLog(`[EditorComponentsContext] Deleted instance: ${instanceId}`);
1148
1165
  }, [websiteId, pageId]);
1149
1166
 
1150
1167
  const getInstanceByDomId = useCallback(
@@ -1206,7 +1223,7 @@ export function EditorComponentsProvider({
1206
1223
  return next;
1207
1224
  });
1208
1225
 
1209
- console.log(
1226
+ debugLog(
1210
1227
  `[EditorComponentsContext] Added override to instance: ${instanceId}`
1211
1228
  );
1212
1229
  },
@@ -1256,7 +1273,7 @@ export function EditorComponentsProvider({
1256
1273
  return next;
1257
1274
  });
1258
1275
 
1259
- console.log(
1276
+ debugLog(
1260
1277
  `[EditorComponentsContext] Removed override ${overrideId} from instance: ${instanceId}`
1261
1278
  );
1262
1279
  },
@@ -1308,7 +1325,7 @@ export function EditorComponentsProvider({
1308
1325
  return next;
1309
1326
  });
1310
1327
 
1311
- console.log(
1328
+ debugLog(
1312
1329
  `[EditorComponentsContext] Reset all overrides for instance: ${instanceId}`
1313
1330
  );
1314
1331
  }, [websiteId, pageId]);
@@ -1381,7 +1398,7 @@ export function EditorComponentsProvider({
1381
1398
  return next;
1382
1399
  });
1383
1400
 
1384
- console.log(
1401
+ debugLog(
1385
1402
  `[EditorComponentsContext] Changed variant for instance ${instanceId} to ${variantId}`
1386
1403
  );
1387
1404
  },
@@ -1445,7 +1462,7 @@ export function EditorComponentsProvider({
1445
1462
  });
1446
1463
  }
1447
1464
 
1448
- console.log(
1465
+ debugLog(
1449
1466
  `[EditorComponentsContext] Detached instance: ${instanceId}`
1450
1467
  );
1451
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
- console.log('[EditorUIStateContext] restoreFocus: iframe doc not available');
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
- console.log('[EditorUIStateContext] restoreFocus: focused editing element');
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
- console.log('[EditorUIStateContext] restoreFocus: focused iframe body');
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
- console.log('[EditorVariablesContext] Variables saved successfully');
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
- console.log('[EditorVariablesContext] Variables loaded:', loaded.length);
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
- console.log('[EditorVariablesContext] Synced from theme:', themeVariables.length, 'variables');
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
- console.log('[EditorVariablesContext] Injected CSS variables to iframe');
331
+ debugLog('[EditorVariablesContext] Injected CSS variables to iframe');
331
332
  }, [cssString]);
332
333
 
333
334
  // Context値