@growgroup/visual-editor 0.1.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 (219) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +52 -0
  3. package/README.md +143 -0
  4. package/dist/editor.css +2 -0
  5. package/package.json +94 -0
  6. package/src/components/DeckSlideRender.tsx +21 -0
  7. package/src/components/SaveNote.tsx +21 -0
  8. package/src/components/auth/AuthProvider.tsx +44 -0
  9. package/src/components/ui/accordion.tsx +57 -0
  10. package/src/components/ui/alert-dialog.tsx +141 -0
  11. package/src/components/ui/badge.tsx +36 -0
  12. package/src/components/ui/button.tsx +56 -0
  13. package/src/components/ui/card.tsx +76 -0
  14. package/src/components/ui/checkbox.tsx +30 -0
  15. package/src/components/ui/collapsible.tsx +11 -0
  16. package/src/components/ui/context-menu.tsx +200 -0
  17. package/src/components/ui/dialog.tsx +122 -0
  18. package/src/components/ui/dropdown-menu.tsx +201 -0
  19. package/src/components/ui/input.tsx +22 -0
  20. package/src/components/ui/label.tsx +26 -0
  21. package/src/components/ui/popover.tsx +33 -0
  22. package/src/components/ui/scroll-area.tsx +48 -0
  23. package/src/components/ui/scrubbable-label.tsx +95 -0
  24. package/src/components/ui/select.tsx +159 -0
  25. package/src/components/ui/separator.tsx +31 -0
  26. package/src/components/ui/slider.tsx +28 -0
  27. package/src/components/ui/switch.tsx +29 -0
  28. package/src/components/ui/tabs.tsx +55 -0
  29. package/src/components/ui/textarea.tsx +22 -0
  30. package/src/components/ui/tooltip.tsx +32 -0
  31. package/src/components/viewer/useDeck.ts +58 -0
  32. package/src/editor/EditorContext.tsx +632 -0
  33. package/src/editor/EditorToolbar.tsx +446 -0
  34. package/src/editor/FrontendVisualEditor.tsx +2595 -0
  35. package/src/editor/autosave.ts +34 -0
  36. package/src/editor/components/AiPromptPopover.tsx +378 -0
  37. package/src/editor/components/BreakpointGuides.tsx +323 -0
  38. package/src/editor/components/BreakpointSelector.tsx +180 -0
  39. package/src/editor/components/ComponentPropertyEditor.tsx +426 -0
  40. package/src/editor/components/CssEditorDialog.tsx +168 -0
  41. package/src/editor/components/EditorCanvas.tsx +987 -0
  42. package/src/editor/components/EditorContextMenu.tsx +515 -0
  43. package/src/editor/components/EditorFooter.tsx +81 -0
  44. package/src/editor/components/EditorHeader.tsx +524 -0
  45. package/src/editor/components/EditorLayerPanel.tsx +1197 -0
  46. package/src/editor/components/EditorPropertyPanel.tsx +2996 -0
  47. package/src/editor/components/EditorSidebar.tsx +226 -0
  48. package/src/editor/components/FigmaColorPicker.tsx +1577 -0
  49. package/src/editor/components/HtmlEditorDialog.tsx +71 -0
  50. package/src/editor/components/HtmlImportDialog.tsx +346 -0
  51. package/src/editor/components/JsEditorDialog.tsx +175 -0
  52. package/src/editor/components/LayerTreeItem.tsx +494 -0
  53. package/src/editor/components/MasterComponentEditor.tsx +846 -0
  54. package/src/editor/components/MediaLibraryDialog.tsx +447 -0
  55. package/src/editor/components/PageSettingsDialog.tsx +776 -0
  56. package/src/editor/components/VariablePicker.tsx +355 -0
  57. package/src/editor/components/VariablesDialog.tsx +564 -0
  58. package/src/editor/components/VariantEditor.tsx +687 -0
  59. package/src/editor/components/VariantMatrix.tsx +507 -0
  60. package/src/editor/components/component-panel/CategoryAccordion.tsx +139 -0
  61. package/src/editor/components/component-panel/ComponentGrid.tsx +51 -0
  62. package/src/editor/components/component-panel/ComponentItem.tsx +368 -0
  63. package/src/editor/components/component-panel/ComponentPanel.tsx +275 -0
  64. package/src/editor/components/component-panel/ComponentSearch.tsx +82 -0
  65. package/src/editor/components/component-panel/VariantList.tsx +260 -0
  66. package/src/editor/components/component-panel/index.ts +12 -0
  67. package/src/editor/components/index.ts +48 -0
  68. package/src/editor/components/multi-page/CanvasZoomControls.tsx +71 -0
  69. package/src/editor/components/multi-page/InfiniteCanvas.tsx +95 -0
  70. package/src/editor/components/multi-page/MultiPageCanvasView.tsx +1404 -0
  71. package/src/editor/components/multi-page/PageFrameOverlay.tsx +76 -0
  72. package/src/editor/components/multi-page/PageLabel.tsx +34 -0
  73. package/src/editor/components/multi-page/PageLivePreview.tsx +242 -0
  74. package/src/editor/components/multi-page/PageThumbnail.tsx +59 -0
  75. package/src/editor/components/multi-page/index.ts +7 -0
  76. package/src/editor/components/ppt/PptChrome.tsx +2508 -0
  77. package/src/editor/components/ppt/PptComments.tsx +589 -0
  78. package/src/editor/components/ppt/PptDesignProposals.tsx +275 -0
  79. package/src/editor/components/ppt/PptFormatPane.tsx +320 -0
  80. package/src/editor/components/ppt/PptNotes.tsx +246 -0
  81. package/src/editor/components/property-panel/AlignmentPanel.tsx +110 -0
  82. package/src/editor/components/property-panel/AutoLayoutPanel.tsx +615 -0
  83. package/src/editor/components/property-panel/BorderSection.tsx +104 -0
  84. package/src/editor/components/property-panel/CompactNumberInput.tsx +237 -0
  85. package/src/editor/components/property-panel/CompactSizeInput.tsx +148 -0
  86. package/src/editor/components/property-panel/EffectSection.tsx +157 -0
  87. package/src/editor/components/property-panel/FillSection.tsx +69 -0
  88. package/src/editor/components/property-panel/GoogleFontPicker.tsx +192 -0
  89. package/src/editor/components/property-panel/ImageSection.tsx +206 -0
  90. package/src/editor/components/property-panel/ImgSrcSection.tsx +125 -0
  91. package/src/editor/components/property-panel/InstanceOverrideSection.tsx +413 -0
  92. package/src/editor/components/property-panel/LayoutSection.tsx +105 -0
  93. package/src/editor/components/property-panel/LinkSection.tsx +103 -0
  94. package/src/editor/components/property-panel/PropertyVariablePicker.tsx +311 -0
  95. package/src/editor/components/property-panel/ScalePanel.tsx +212 -0
  96. package/src/editor/components/property-panel/TypographySection.tsx +230 -0
  97. package/src/editor/components/property-panel/UnitAwareNumberInput.tsx +238 -0
  98. package/src/editor/components/property-panel/VariableAwareColorInput.tsx +477 -0
  99. package/src/editor/components/property-panel/VariableAwareInput.tsx +606 -0
  100. package/src/editor/components/property-panel/VariableAwareSizeInput.tsx +588 -0
  101. package/src/editor/components/property-panel/VariableAwareUnitInput.tsx +546 -0
  102. package/src/editor/components/property-panel/index.ts +24 -0
  103. package/src/editor/components/property-panel/unit-utils.ts +261 -0
  104. package/src/editor/components/shell/EditorTopBar.tsx +392 -0
  105. package/src/editor/components/shell/LeftPanel.tsx +47 -0
  106. package/src/editor/components/shell/PagesPanel.tsx +118 -0
  107. package/src/editor/components/variables-panel/ColorValueCell.tsx +165 -0
  108. package/src/editor/components/variables-panel/TextValueCell.tsx +116 -0
  109. package/src/editor/components/variables-panel/VariablesPanel.tsx +518 -0
  110. package/src/editor/components/variables-panel/index.ts +7 -0
  111. package/src/editor/constants.ts +468 -0
  112. package/src/editor/contexts/EditorArtboardContext.tsx +229 -0
  113. package/src/editor/contexts/EditorComponentsContext.tsx +1320 -0
  114. package/src/editor/contexts/EditorDocumentContext.tsx +113 -0
  115. package/src/editor/contexts/EditorHistoryContext.tsx +516 -0
  116. package/src/editor/contexts/EditorRefsContext.tsx +204 -0
  117. package/src/editor/contexts/EditorSelectionContext.tsx +54 -0
  118. package/src/editor/contexts/EditorToolContext.tsx +58 -0
  119. package/src/editor/contexts/EditorUIStateContext.tsx +122 -0
  120. package/src/editor/contexts/EditorVariablesContext.tsx +397 -0
  121. package/src/editor/contexts/EditorViewContext.tsx +101 -0
  122. package/src/editor/contexts/MultiPageCanvasContext.tsx +498 -0
  123. package/src/editor/contexts/index.ts +17 -0
  124. package/src/editor/editor-skin.css +122 -0
  125. package/src/editor/hooks/index.ts +38 -0
  126. package/src/editor/hooks/useAiReplace.ts +397 -0
  127. package/src/editor/hooks/useAltMeasure.ts +67 -0
  128. package/src/editor/hooks/useBrowserZoomPrevention.ts +121 -0
  129. package/src/editor/hooks/useCanvasControls.ts +1222 -0
  130. package/src/editor/hooks/useComponentEditMode.ts +658 -0
  131. package/src/editor/hooks/useComponentInstances.ts +515 -0
  132. package/src/editor/hooks/useContextMenuHandler.ts +157 -0
  133. package/src/editor/hooks/useCoordinateTransform.ts +207 -0
  134. package/src/editor/hooks/useDragResize.ts +1317 -0
  135. package/src/editor/hooks/useDrawingMode.ts +472 -0
  136. package/src/editor/hooks/useEditorColors.ts +144 -0
  137. package/src/editor/hooks/useEditorMessages.ts +108 -0
  138. package/src/editor/hooks/useElementActions.ts +1754 -0
  139. package/src/editor/hooks/useElementSelection.ts +1573 -0
  140. package/src/editor/hooks/useFocusManagement.ts +249 -0
  141. package/src/editor/hooks/useGoogleFonts.ts +305 -0
  142. package/src/editor/hooks/useIframeInitializer.ts +584 -0
  143. package/src/editor/hooks/useIframeSetup.ts +360 -0
  144. package/src/editor/hooks/useImageUpload.ts +270 -0
  145. package/src/editor/hooks/useInfiniteCanvas.ts +301 -0
  146. package/src/editor/hooks/useKeyboardShortcuts.ts +205 -0
  147. package/src/editor/hooks/useMarqueeSelection.ts +388 -0
  148. package/src/editor/hooks/useMediaLibrary.ts +129 -0
  149. package/src/editor/hooks/usePageSettingsManager.ts +739 -0
  150. package/src/editor/hooks/useResizablePanel.ts +163 -0
  151. package/src/editor/hooks/useRichPaste.ts +255 -0
  152. package/src/editor/hooks/useTouchGestures.ts +197 -0
  153. package/src/editor/index.ts +27 -0
  154. package/src/editor/types/page-settings.ts +513 -0
  155. package/src/editor/types.ts +382 -0
  156. package/src/editor/utils/align-elements.ts +169 -0
  157. package/src/editor/utils/api-json.ts +21 -0
  158. package/src/editor/utils/aspect-lock.ts +50 -0
  159. package/src/editor/utils/component-renderer.ts +702 -0
  160. package/src/editor/utils/component-sync.ts +845 -0
  161. package/src/editor/utils/crop-mode.ts +265 -0
  162. package/src/editor/utils/dom-utils.ts +2238 -0
  163. package/src/editor/utils/element-effects.ts +218 -0
  164. package/src/editor/utils/eyedropper.ts +35 -0
  165. package/src/editor/utils/figma-export.ts +560 -0
  166. package/src/editor/utils/figma-kiwi-decoder.ts +722 -0
  167. package/src/editor/utils/figma-kiwi-encoder.ts +583 -0
  168. package/src/editor/utils/figma-paste.ts +2262 -0
  169. package/src/editor/utils/flex-reorder.ts +231 -0
  170. package/src/editor/utils/flex-utils.ts +1230 -0
  171. package/src/editor/utils/geometry.ts +232 -0
  172. package/src/editor/utils/grid-layout.ts +210 -0
  173. package/src/editor/utils/html-utils.ts +470 -0
  174. package/src/editor/utils/index.ts +11 -0
  175. package/src/editor/utils/ink-style.ts +57 -0
  176. package/src/editor/utils/inline-format.ts +236 -0
  177. package/src/editor/utils/measure-distance.ts +120 -0
  178. package/src/editor/utils/override-apply.ts +526 -0
  179. package/src/editor/utils/override-detection.ts +613 -0
  180. package/src/editor/utils/paste-processors.ts +609 -0
  181. package/src/editor/utils/paste-sanitizer.ts +244 -0
  182. package/src/editor/utils/restore-flow.ts +188 -0
  183. package/src/editor/utils/shape-library.ts +171 -0
  184. package/src/editor/utils/slide-root.ts +29 -0
  185. package/src/editor/utils/smart-guides.ts +218 -0
  186. package/src/editor/utils/style-utils.ts +685 -0
  187. package/src/editor/utils/table-edit.ts +151 -0
  188. package/src/editor/utils/tailwind-mappings.ts +778 -0
  189. package/src/editor/utils/tailwind-utils.ts +804 -0
  190. package/src/editor/utils/text-highlight.ts +216 -0
  191. package/src/editor/utils/theme-to-variables.ts +341 -0
  192. package/src/editor/utils/variant-resolver.ts +456 -0
  193. package/src/editor/utils/viewport-utils.ts +295 -0
  194. package/src/hooks/useEditorHistory.ts +195 -0
  195. package/src/hooks/useEditorShortcuts.ts +260 -0
  196. package/src/index.ts +40 -0
  197. package/src/io.ts +134 -0
  198. package/src/lib/agent/slide-agent/types.ts +547 -0
  199. package/src/lib/agent/website-agent/types.ts +805 -0
  200. package/src/lib/api/auth-fetch.ts +58 -0
  201. package/src/lib/deck.ts +69 -0
  202. package/src/lib/export.ts +47 -0
  203. package/src/lib/firebase/config.ts +29 -0
  204. package/src/lib/firebase/css-variables.ts +378 -0
  205. package/src/lib/firebase/editor-components.ts +677 -0
  206. package/src/lib/firebase/storage.ts +469 -0
  207. package/src/lib/utils.ts +6 -0
  208. package/src/styles/editor.css +52 -0
  209. package/src/styles/skin.css +122 -0
  210. package/src/types/css-variables.ts +645 -0
  211. package/src/types/editor-components.ts +944 -0
  212. package/src/types/editor.ts +420 -0
  213. package/src/types/page-master.ts +197 -0
  214. package/src/types/page.ts +419 -0
  215. package/src/types/slide.ts +402 -0
  216. package/src/types/website-theme.ts +788 -0
  217. package/src/types/website.ts +374 -0
  218. package/src/vendor/firebase-firestore.ts +13 -0
  219. package/src/vendor/firebase-functions.ts +17 -0
@@ -0,0 +1,632 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * エディタのコンテキスト(ファサード)
5
+ *
6
+ * Phase 1: Context分割によるパフォーマンス最適化
7
+ * - 51個のstateを8つの専門Contextに分割
8
+ * - ファサードパターンで後方互換性を100%維持
9
+ * - 既存のuseEditorContext()は変更なしで動作
10
+ *
11
+ * パフォーマンス最適化:
12
+ * - 個別のContext hookを使用することで、必要な状態のみを購読可能
13
+ * - 例: useEditorSelection() - 選択状態のみを購読
14
+ */
15
+
16
+ import React, { createContext, useContext, useCallback, useEffect, MutableRefObject } from 'react';
17
+ import { buildDomTree } from './utils/dom-utils';
18
+ import type {
19
+ EditorTool,
20
+ DOMTreeNode,
21
+ SelectedElementInfo,
22
+ PanelSections,
23
+ ClipboardData,
24
+ DrawingState,
25
+ MarqueeState,
26
+ StyleClipboard,
27
+ } from './types';
28
+
29
+ // 個別Context
30
+ import {
31
+ EditorRefsProvider,
32
+ useEditorRefs,
33
+ globalStyleClipboardRef,
34
+ globalLastUsedStylesRef,
35
+ } from './contexts/EditorRefsContext';
36
+ import {
37
+ EditorSelectionProvider,
38
+ useEditorSelection,
39
+ } from './contexts/EditorSelectionContext';
40
+ import {
41
+ EditorToolProvider,
42
+ useEditorTool,
43
+ type EditorMode,
44
+ } from './contexts/EditorToolContext';
45
+ import {
46
+ EditorViewProvider,
47
+ useEditorView,
48
+ type ViewMode,
49
+ } from './contexts/EditorViewContext';
50
+ import {
51
+ EditorHistoryProvider,
52
+ useEditorHistory,
53
+ } from './contexts/EditorHistoryContext';
54
+ import {
55
+ EditorDocumentProvider,
56
+ useEditorDocument,
57
+ } from './contexts/EditorDocumentContext';
58
+ import {
59
+ EditorArtboardProvider,
60
+ useEditorArtboard,
61
+ type ContentListItem,
62
+ type ArtboardState,
63
+ } from './contexts/EditorArtboardContext';
64
+ import {
65
+ EditorUIStateProvider,
66
+ useEditorUIState,
67
+ } from './contexts/EditorUIStateContext';
68
+ import {
69
+ EditorVariablesProvider,
70
+ useEditorVariables,
71
+ } from './contexts/EditorVariablesContext';
72
+ import {
73
+ EditorComponentsProvider,
74
+ useEditorComponents,
75
+ } from './contexts/EditorComponentsContext';
76
+ import {
77
+ ConditionalMultiPageProvider,
78
+ useMultiPageCanvasOptional,
79
+ } from './contexts/MultiPageCanvasContext';
80
+ import type { CSSVariableDefinition } from '../types/css-variables';
81
+
82
+ // 型の再エクスポート
83
+ export type { ContentListItem, ArtboardState, EditorMode, ViewMode };
84
+ export { globalStyleClipboardRef };
85
+
86
+ /** @deprecated Use ContentListItem instead */
87
+ export type SlideListItem = ContentListItem;
88
+
89
+ // ============================================================
90
+ // EditorContextValue インターフェース(後方互換性維持)
91
+ // ============================================================
92
+
93
+ interface EditorContextValue {
94
+ // エディタモード
95
+ editorMode: EditorMode;
96
+
97
+ // ビューモード(シングルまたはグリッド表示)
98
+ viewMode: ViewMode;
99
+ setViewMode: (mode: ViewMode) => void;
100
+
101
+ // Refs
102
+ iframeRef: MutableRefObject<HTMLIFrameElement | null>;
103
+ containerRef: MutableRefObject<HTMLDivElement | null>;
104
+ clipboardRef: MutableRefObject<ClipboardData | null>;
105
+ styleClipboardRef: typeof globalStyleClipboardRef;
106
+ lastUsedStylesRef: typeof globalLastUsedStylesRef;
107
+ iframeHtmlRef: MutableRefObject<string>;
108
+ isUndoRedoRef: MutableRefObject<boolean>;
109
+ drawingStateRef: MutableRefObject<DrawingState>;
110
+
111
+ // アートボード状態管理(マルチアートボード対応)
112
+ artboardStates: Map<string, ArtboardState>;
113
+ activeArtboardId: string | null;
114
+ setActiveArtboard: (id: string) => void;
115
+ getArtboardState: (id: string) => ArtboardState | undefined;
116
+ updateArtboardState: (id: string, updates: Partial<ArtboardState>) => void;
117
+
118
+ // グローバルキャンバス状態(グリッド表示用)
119
+ globalZoom: number;
120
+ setGlobalZoom: (zoom: number) => void;
121
+ globalScrollPosition: { x: number; y: number };
122
+ setGlobalScrollPosition: (pos: { x: number; y: number }) => void;
123
+
124
+ // 基本状態
125
+ originalHtml: string;
126
+ html: string;
127
+ setHtml: (html: string) => void;
128
+ hasChanges: boolean;
129
+ setOriginalHtml: (html: string) => void;
130
+ sourceHtml: string;
131
+ saving: boolean;
132
+ setSaving: (saving: boolean) => void;
133
+
134
+ // コンテンツリスト(他コンテンツへのナビゲーション用)
135
+ contentList: ContentListItem[];
136
+ currentContentId: string | null;
137
+ onContentChange: ((contentId: string) => void) | null;
138
+
139
+ /** @deprecated Use contentList instead */
140
+ slides: ContentListItem[];
141
+ /** @deprecated Use currentContentId instead */
142
+ currentSlideId: string | null;
143
+ /** @deprecated Use onContentChange instead */
144
+ onSlideChange: ((slideId: string) => void) | null;
145
+
146
+ // ツール・選択
147
+ activeTool: EditorTool;
148
+ setActiveTool: (tool: EditorTool) => void;
149
+ selectedElement: SelectedElementInfo | null;
150
+ setSelectedElement: (element: SelectedElementInfo | null) => void;
151
+ selectedElementIds: string[];
152
+ setSelectedElementIds: (ids: string[]) => void;
153
+
154
+ // レイアウトモード
155
+ layoutMode: 'absolute' | 'auto';
156
+ setLayoutMode: (mode: 'absolute' | 'auto') => void;
157
+ showLayoutHint: boolean;
158
+ setShowLayoutHint: (show: boolean) => void;
159
+ autoLayoutHtml: string | null;
160
+ setAutoLayoutHtml: (html: string | null) => void;
161
+
162
+ // ズーム
163
+ zoom: number;
164
+ setZoom: (zoom: number) => void;
165
+ fitZoom: number;
166
+ setFitZoom: (zoom: number) => void;
167
+
168
+ // ビューポート幅(webpageモードのレスポンシブプレビュー用)
169
+ viewportWidth: number;
170
+ setViewportWidth: (width: number) => void;
171
+
172
+ // DOMツリー
173
+ domTree: DOMTreeNode[];
174
+ setDomTree: (tree: DOMTreeNode[]) => void;
175
+ searchQuery: string;
176
+ setSearchQuery: (query: string) => void;
177
+ expandedNodes: Set<string>;
178
+ setExpandedNodes: React.Dispatch<React.SetStateAction<Set<string>>>;
179
+
180
+ // パネル状態
181
+ openSections: PanelSections;
182
+ setOpenSections: React.Dispatch<React.SetStateAction<PanelSections>>;
183
+
184
+ // 履歴
185
+ pushHistory: (html: string, selectedId?: string) => void;
186
+ undo: () => void;
187
+ redo: () => void;
188
+ canUndo: boolean;
189
+ canRedo: boolean;
190
+ clearHistory: () => void;
191
+
192
+ // マーキー選択(範囲選択)
193
+ marqueeState: MarqueeState;
194
+ setMarqueeState: React.Dispatch<React.SetStateAction<MarqueeState>>;
195
+
196
+ // iframe操作ヘルパー
197
+ getIframeDoc: () => Document | null;
198
+ notifyIframeChange: (saveToHistory?: boolean) => void;
199
+
200
+ // iframe読み込み状態
201
+ iframeReady: boolean;
202
+ setIframeReady: (ready: boolean) => void;
203
+
204
+ // フォーカス管理
205
+ restoreFocus: () => void;
206
+ }
207
+
208
+ // ============================================================
209
+ // ファサードContext
210
+ // ============================================================
211
+
212
+ const EditorContext = createContext<EditorContextValue | null>(null);
213
+
214
+ /**
215
+ * エディタコンテキストを取得(後方互換性維持)
216
+ *
217
+ * パフォーマンス最適化が必要な場合は、個別のContextフックを使用:
218
+ * - useEditorRefs() - Refs関連のみ
219
+ * - useEditorSelection() - 選択状態のみ
220
+ * - useEditorTool() - ツール状態のみ
221
+ * - useEditorView() - 表示/ズーム状態のみ
222
+ * - useEditorHistory() - 履歴管理のみ
223
+ * - useEditorDocument() - ドキュメント状態のみ
224
+ * - useEditorArtboard() - アートボード管理のみ
225
+ * - useEditorUIState() - UI状態のみ
226
+ */
227
+ export function useEditorContext(): EditorContextValue {
228
+ const context = useContext(EditorContext);
229
+ if (!context) {
230
+ throw new Error('useEditorContext must be used within EditorProvider');
231
+ }
232
+ return context;
233
+ }
234
+
235
+ // 個別Context hookの再エクスポート(パフォーマンス最適化用)
236
+ export {
237
+ useEditorRefs,
238
+ useEditorSelection,
239
+ useEditorTool,
240
+ useEditorView,
241
+ useEditorHistory,
242
+ useEditorDocument,
243
+ useEditorArtboard,
244
+ useEditorUIState,
245
+ useEditorVariables,
246
+ useEditorComponents,
247
+ useMultiPageCanvasOptional,
248
+ };
249
+
250
+ // ============================================================
251
+ // EditorProvider Props
252
+ // ============================================================
253
+
254
+ interface EditorProviderProps {
255
+ initialHtml: string;
256
+ children: React.ReactNode;
257
+ editorMode?: EditorMode;
258
+ /**
259
+ * アートボードの幅(webpageモードの初期表示幅)。
260
+ * 省略時はブレイクポイントプリセットの先頭。
261
+ * 「この幅で見る」と決まっている用途(構成ラフ等)で指定する。
262
+ */
263
+ artboardWidth?: number;
264
+ contentList?: ContentListItem[];
265
+ currentContentId?: string;
266
+ onContentChange?: (contentId: string) => void;
267
+ initialLayoutMode?: 'absolute' | 'auto';
268
+ /** CSS変数の初期値 */
269
+ initialVariables?: CSSVariableDefinition[];
270
+ /** CSS変数保存コールバック */
271
+ onSaveVariables?: (variables: CSSVariableDefinition[]) => Promise<void>;
272
+ /** CSS変数読み込みコールバック */
273
+ onLoadVariables?: (websiteId: string) => Promise<CSSVariableDefinition[]>;
274
+ /** Website ID for component management */
275
+ websiteId?: string;
276
+ /** マルチページ無限キャンバスモードを有効にする (default: false) */
277
+ enableMultiPageCanvas?: boolean;
278
+ /** @deprecated Use contentList instead */
279
+ slides?: ContentListItem[];
280
+ /** @deprecated Use currentContentId instead */
281
+ currentSlideId?: string;
282
+ /** @deprecated Use onContentChange instead */
283
+ onSlideChange?: (slideId: string) => void;
284
+ }
285
+
286
+ // ============================================================
287
+ // 内部コンポーネント: Context値の集約
288
+ // ============================================================
289
+
290
+ interface EditorContextAggregatorProps {
291
+ children: React.ReactNode;
292
+ }
293
+
294
+ function EditorContextAggregator({ children }: EditorContextAggregatorProps) {
295
+ // 全ての個別Contextから値を取得
296
+ const refs = useEditorRefs();
297
+ const selection = useEditorSelection();
298
+ const tool = useEditorTool();
299
+ const view = useEditorView();
300
+ const history = useEditorHistory();
301
+ const document = useEditorDocument();
302
+ const artboard = useEditorArtboard();
303
+ const uiState = useEditorUIState();
304
+
305
+ // notifyIframeChange: 複数Contextに跨る操作
306
+ const notifyIframeChange = useCallback((saveToHistory = true) => {
307
+ const iframeDoc = refs.getIframeDoc();
308
+ if (iframeDoc) {
309
+ const artboardEl = iframeDoc.getElementById('artboard');
310
+ const newHtml = artboardEl ? artboardEl.innerHTML : iframeDoc.body.innerHTML;
311
+ if (saveToHistory) {
312
+ history.pushHistory(newHtml, selection.selectedElement?.id);
313
+ } else {
314
+ history.setHtml(newHtml);
315
+ }
316
+ const newTree = buildDomTree(iframeDoc);
317
+ uiState.setDomTree(newTree);
318
+ window.postMessage({ type: 'DOM_TREE_UPDATED', tree: newTree }, '*');
319
+ }
320
+ }, [refs, history, selection.selectedElement?.id, uiState]);
321
+
322
+ // setActiveArtboard: 状態保存・復元付きのアートボード切り替え
323
+ const setActiveArtboard = useCallback((id: string) => {
324
+ // 現在のアートボードの状態を保存
325
+ if (artboard.activeArtboardId) {
326
+ artboard.updateArtboardState(artboard.activeArtboardId, {
327
+ zoom: view.zoom,
328
+ selectedElementIds: selection.selectedElementIds,
329
+ domTree: uiState.domTree,
330
+ expandedNodes: uiState.expandedNodes,
331
+ html: history.html,
332
+ });
333
+ }
334
+
335
+ // 元のsetActiveArtboardを呼び出し(内部でactiveArtboardIdを更新)
336
+ artboard.setActiveArtboard(id);
337
+
338
+ // 新しいアートボードの状態を復元
339
+ const newState = artboard.artboardStates.get(id);
340
+ if (newState) {
341
+ view.setZoom(newState.zoom);
342
+ selection.setSelectedElementIds(newState.selectedElementIds);
343
+ uiState.setDomTree(newState.domTree);
344
+ uiState.setExpandedNodes(newState.expandedNodes);
345
+ if (newState.html) {
346
+ history.setHtml(newState.html);
347
+ }
348
+ }
349
+ }, [artboard, view, selection, uiState, history]);
350
+
351
+ // Undo/Redo時にiframeを同期
352
+ useEffect(() => {
353
+ if (history.isUndoRedoRef.current) {
354
+ history.isUndoRedoRef.current = false;
355
+ const iframe = refs.iframeRef.current;
356
+ const iframeDoc = iframe?.contentDocument || iframe?.contentWindow?.document;
357
+ if (iframeDoc && history.html !== refs.iframeHtmlRef.current) {
358
+ console.log('[EditorContext] Syncing iframe after undo/redo');
359
+ const artboardEl = iframeDoc.getElementById('artboard');
360
+ if (artboardEl) {
361
+ artboardEl.innerHTML = history.html;
362
+ } else {
363
+ console.warn('[EditorContext] #artboard not found, falling back to body.innerHTML');
364
+ iframeDoc.body.innerHTML = history.html;
365
+ }
366
+ refs.iframeHtmlRef.current = history.html;
367
+ selection.setSelectedElement(null);
368
+ selection.setSelectedElementIds([]);
369
+ setTimeout(() => {
370
+ window.postMessage({ type: 'REQUEST_DOM_TREE_UPDATE' }, '*');
371
+ }, 50);
372
+
373
+ // フォーカス復元
374
+ const restoreFocusToIframe = () => {
375
+ const currentIframe = refs.iframeRef.current;
376
+ const currentIframeDoc = currentIframe?.contentDocument || currentIframe?.contentWindow?.document;
377
+ if (currentIframe && currentIframeDoc?.body) {
378
+ currentIframe.focus();
379
+ currentIframeDoc.body.focus();
380
+ console.log('[EditorContext] Focus restored to iframe and body after undo/redo');
381
+ }
382
+ };
383
+ restoreFocusToIframe();
384
+ requestAnimationFrame(restoreFocusToIframe);
385
+ setTimeout(restoreFocusToIframe, 100);
386
+ }
387
+ }
388
+ }, [history.html, history.isUndoRedoRef, refs, selection]);
389
+
390
+ // ファサード値の構築
391
+ const value: EditorContextValue = {
392
+ // エディタモード
393
+ editorMode: tool.editorMode,
394
+
395
+ // ビューモード
396
+ viewMode: view.viewMode,
397
+ setViewMode: view.setViewMode,
398
+
399
+ // Refs
400
+ iframeRef: refs.iframeRef,
401
+ containerRef: refs.containerRef,
402
+ clipboardRef: refs.clipboardRef,
403
+ styleClipboardRef: refs.styleClipboardRef,
404
+ lastUsedStylesRef: refs.lastUsedStylesRef,
405
+ iframeHtmlRef: refs.iframeHtmlRef,
406
+ isUndoRedoRef: history.isUndoRedoRef,
407
+ drawingStateRef: refs.drawingStateRef,
408
+
409
+ // アートボード状態管理
410
+ artboardStates: artboard.artboardStates,
411
+ activeArtboardId: artboard.activeArtboardId,
412
+ setActiveArtboard,
413
+ getArtboardState: artboard.getArtboardState,
414
+ updateArtboardState: artboard.updateArtboardState,
415
+
416
+ // グローバルキャンバス状態
417
+ globalZoom: view.globalZoom,
418
+ setGlobalZoom: view.setGlobalZoom,
419
+ globalScrollPosition: view.globalScrollPosition,
420
+ setGlobalScrollPosition: view.setGlobalScrollPosition,
421
+
422
+ // 基本状態
423
+ originalHtml: document.originalHtml,
424
+ html: history.html,
425
+ setHtml: history.setHtml,
426
+ hasChanges: document.hasChanges,
427
+ setOriginalHtml: document.setOriginalHtml,
428
+ sourceHtml: document.sourceHtml,
429
+ saving: document.saving,
430
+ setSaving: document.setSaving,
431
+
432
+ // コンテンツリスト
433
+ contentList: artboard.contentList,
434
+ currentContentId: artboard.currentContentId,
435
+ onContentChange: artboard.onContentChange,
436
+
437
+ // Deprecated aliases
438
+ slides: artboard.slides,
439
+ currentSlideId: artboard.currentSlideId,
440
+ onSlideChange: artboard.onSlideChange,
441
+
442
+ // ツール・選択
443
+ activeTool: tool.activeTool,
444
+ setActiveTool: tool.setActiveTool,
445
+ selectedElement: selection.selectedElement,
446
+ setSelectedElement: selection.setSelectedElement,
447
+ selectedElementIds: selection.selectedElementIds,
448
+ setSelectedElementIds: selection.setSelectedElementIds,
449
+
450
+ // レイアウトモード
451
+ layoutMode: document.layoutMode,
452
+ setLayoutMode: document.setLayoutMode,
453
+ showLayoutHint: document.showLayoutHint,
454
+ setShowLayoutHint: document.setShowLayoutHint,
455
+ autoLayoutHtml: document.autoLayoutHtml,
456
+ setAutoLayoutHtml: document.setAutoLayoutHtml,
457
+
458
+ // ズーム
459
+ zoom: view.zoom,
460
+ setZoom: view.setZoom,
461
+ fitZoom: view.fitZoom,
462
+ setFitZoom: view.setFitZoom,
463
+
464
+ // ビューポート幅
465
+ viewportWidth: view.viewportWidth,
466
+ setViewportWidth: view.setViewportWidth,
467
+
468
+ // DOMツリー
469
+ domTree: uiState.domTree,
470
+ setDomTree: uiState.setDomTree,
471
+ searchQuery: uiState.searchQuery,
472
+ setSearchQuery: uiState.setSearchQuery,
473
+ expandedNodes: uiState.expandedNodes,
474
+ setExpandedNodes: uiState.setExpandedNodes,
475
+
476
+ // パネル状態
477
+ openSections: uiState.openSections,
478
+ setOpenSections: uiState.setOpenSections,
479
+
480
+ // マーキー選択
481
+ marqueeState: uiState.marqueeState,
482
+ setMarqueeState: uiState.setMarqueeState,
483
+
484
+ // 履歴
485
+ pushHistory: history.pushHistory,
486
+ undo: history.undo,
487
+ redo: history.redo,
488
+ canUndo: history.canUndo,
489
+ canRedo: history.canRedo,
490
+ clearHistory: history.clearHistory,
491
+
492
+ // ヘルパー
493
+ getIframeDoc: refs.getIframeDoc,
494
+ notifyIframeChange,
495
+
496
+ // iframe読み込み状態
497
+ iframeReady: refs.iframeReady,
498
+ setIframeReady: refs.setIframeReady,
499
+
500
+ // フォーカス管理
501
+ restoreFocus: uiState.restoreFocus,
502
+ };
503
+
504
+ return (
505
+ <EditorContext.Provider value={value}>
506
+ {children}
507
+ </EditorContext.Provider>
508
+ );
509
+ }
510
+
511
+ // ============================================================
512
+ // EditorProvider(公開API - 後方互換性維持)
513
+ // ============================================================
514
+
515
+ export function EditorProvider({
516
+ initialHtml,
517
+ children,
518
+ editorMode = 'slide',
519
+ artboardWidth,
520
+ contentList,
521
+ currentContentId,
522
+ onContentChange,
523
+ initialLayoutMode = 'auto',
524
+ // CSS変数関連
525
+ initialVariables,
526
+ onSaveVariables,
527
+ onLoadVariables,
528
+ // Component system
529
+ websiteId,
530
+ // Multi-page canvas
531
+ enableMultiPageCanvas = false,
532
+ // deprecated props
533
+ slides,
534
+ currentSlideId,
535
+ onSlideChange,
536
+ }: EditorProviderProps) {
537
+ return (
538
+ <EditorRefsProvider initialHtml={initialHtml}>
539
+ <EditorHistoryProvider initialHtml={initialHtml}>
540
+ <EditorHistoryConsumer initialHtml={initialHtml} initialLayoutMode={initialLayoutMode}>
541
+ {(html) => (
542
+ <EditorDocumentProvider
543
+ initialHtml={initialHtml}
544
+ currentHtml={html}
545
+ initialLayoutMode={initialLayoutMode}
546
+ >
547
+ <EditorSelectionProvider>
548
+ <EditorToolProvider editorMode={editorMode}>
549
+ <EditorViewProvider initialViewportWidth={artboardWidth}>
550
+ <EditorArtboardProvider
551
+ contentList={contentList}
552
+ currentContentId={currentContentId}
553
+ onContentChange={onContentChange}
554
+ slides={slides}
555
+ currentSlideId={currentSlideId}
556
+ onSlideChange={onSlideChange}
557
+ >
558
+ <ConditionalMultiPageProvider enabled={enableMultiPageCanvas}>
559
+ <EditorUIStateProviderWrapper>
560
+ <EditorVariablesProviderWrapper
561
+ initialVariables={initialVariables}
562
+ onSaveVariables={onSaveVariables}
563
+ onLoadVariables={onLoadVariables}
564
+ >
565
+ <EditorComponentsProvider websiteId={websiteId} pageId={currentContentId || currentSlideId}>
566
+ <EditorContextAggregator>
567
+ {children}
568
+ </EditorContextAggregator>
569
+ </EditorComponentsProvider>
570
+ </EditorVariablesProviderWrapper>
571
+ </EditorUIStateProviderWrapper>
572
+ </ConditionalMultiPageProvider>
573
+ </EditorArtboardProvider>
574
+ </EditorViewProvider>
575
+ </EditorToolProvider>
576
+ </EditorSelectionProvider>
577
+ </EditorDocumentProvider>
578
+ )}
579
+ </EditorHistoryConsumer>
580
+ </EditorHistoryProvider>
581
+ </EditorRefsProvider>
582
+ );
583
+ }
584
+
585
+ // EditorHistoryのhtmlを子に渡すためのコンシューマ
586
+ interface EditorHistoryConsumerProps {
587
+ initialHtml: string;
588
+ initialLayoutMode: 'absolute' | 'auto';
589
+ children: (html: string) => React.ReactNode;
590
+ }
591
+
592
+ function EditorHistoryConsumer({ children }: EditorHistoryConsumerProps) {
593
+ const history = useEditorHistory();
594
+ return <>{children(history.html)}</>;
595
+ }
596
+
597
+ // EditorUIStateProviderのラッパー(getIframeDocを渡すため)
598
+ function EditorUIStateProviderWrapper({ children }: { children: React.ReactNode }) {
599
+ const refs = useEditorRefs();
600
+ return (
601
+ <EditorUIStateProvider getIframeDoc={refs.getIframeDoc}>
602
+ {children}
603
+ </EditorUIStateProvider>
604
+ );
605
+ }
606
+
607
+ // EditorVariablesProviderのラッパー(保存・読み込みコールバックを渡すため)
608
+ interface EditorVariablesProviderWrapperProps {
609
+ children: React.ReactNode;
610
+ onSaveVariables?: (variables: CSSVariableDefinition[]) => Promise<void>;
611
+ onLoadVariables?: (websiteId: string) => Promise<CSSVariableDefinition[]>;
612
+ initialVariables?: CSSVariableDefinition[];
613
+ }
614
+
615
+ function EditorVariablesProviderWrapper({
616
+ children,
617
+ onSaveVariables,
618
+ onLoadVariables,
619
+ initialVariables,
620
+ }: EditorVariablesProviderWrapperProps) {
621
+ return (
622
+ <EditorVariablesProvider
623
+ initialVariables={initialVariables}
624
+ onSave={onSaveVariables}
625
+ onLoad={onLoadVariables}
626
+ >
627
+ {children}
628
+ </EditorVariablesProvider>
629
+ );
630
+ }
631
+
632
+ export default EditorContext;