@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.
- package/LICENSE +21 -0
- package/NOTICE +52 -0
- package/README.md +143 -0
- package/dist/editor.css +2 -0
- package/package.json +94 -0
- package/src/components/DeckSlideRender.tsx +21 -0
- package/src/components/SaveNote.tsx +21 -0
- package/src/components/auth/AuthProvider.tsx +44 -0
- package/src/components/ui/accordion.tsx +57 -0
- package/src/components/ui/alert-dialog.tsx +141 -0
- package/src/components/ui/badge.tsx +36 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.tsx +76 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/collapsible.tsx +11 -0
- package/src/components/ui/context-menu.tsx +200 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/dropdown-menu.tsx +201 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/popover.tsx +33 -0
- package/src/components/ui/scroll-area.tsx +48 -0
- package/src/components/ui/scrubbable-label.tsx +95 -0
- package/src/components/ui/select.tsx +159 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/slider.tsx +28 -0
- package/src/components/ui/switch.tsx +29 -0
- package/src/components/ui/tabs.tsx +55 -0
- package/src/components/ui/textarea.tsx +22 -0
- package/src/components/ui/tooltip.tsx +32 -0
- package/src/components/viewer/useDeck.ts +58 -0
- package/src/editor/EditorContext.tsx +632 -0
- package/src/editor/EditorToolbar.tsx +446 -0
- package/src/editor/FrontendVisualEditor.tsx +2595 -0
- package/src/editor/autosave.ts +34 -0
- package/src/editor/components/AiPromptPopover.tsx +378 -0
- package/src/editor/components/BreakpointGuides.tsx +323 -0
- package/src/editor/components/BreakpointSelector.tsx +180 -0
- package/src/editor/components/ComponentPropertyEditor.tsx +426 -0
- package/src/editor/components/CssEditorDialog.tsx +168 -0
- package/src/editor/components/EditorCanvas.tsx +987 -0
- package/src/editor/components/EditorContextMenu.tsx +515 -0
- package/src/editor/components/EditorFooter.tsx +81 -0
- package/src/editor/components/EditorHeader.tsx +524 -0
- package/src/editor/components/EditorLayerPanel.tsx +1197 -0
- package/src/editor/components/EditorPropertyPanel.tsx +2996 -0
- package/src/editor/components/EditorSidebar.tsx +226 -0
- package/src/editor/components/FigmaColorPicker.tsx +1577 -0
- package/src/editor/components/HtmlEditorDialog.tsx +71 -0
- package/src/editor/components/HtmlImportDialog.tsx +346 -0
- package/src/editor/components/JsEditorDialog.tsx +175 -0
- package/src/editor/components/LayerTreeItem.tsx +494 -0
- package/src/editor/components/MasterComponentEditor.tsx +846 -0
- package/src/editor/components/MediaLibraryDialog.tsx +447 -0
- package/src/editor/components/PageSettingsDialog.tsx +776 -0
- package/src/editor/components/VariablePicker.tsx +355 -0
- package/src/editor/components/VariablesDialog.tsx +564 -0
- package/src/editor/components/VariantEditor.tsx +687 -0
- package/src/editor/components/VariantMatrix.tsx +507 -0
- package/src/editor/components/component-panel/CategoryAccordion.tsx +139 -0
- package/src/editor/components/component-panel/ComponentGrid.tsx +51 -0
- package/src/editor/components/component-panel/ComponentItem.tsx +368 -0
- package/src/editor/components/component-panel/ComponentPanel.tsx +275 -0
- package/src/editor/components/component-panel/ComponentSearch.tsx +82 -0
- package/src/editor/components/component-panel/VariantList.tsx +260 -0
- package/src/editor/components/component-panel/index.ts +12 -0
- package/src/editor/components/index.ts +48 -0
- package/src/editor/components/multi-page/CanvasZoomControls.tsx +71 -0
- package/src/editor/components/multi-page/InfiniteCanvas.tsx +95 -0
- package/src/editor/components/multi-page/MultiPageCanvasView.tsx +1404 -0
- package/src/editor/components/multi-page/PageFrameOverlay.tsx +76 -0
- package/src/editor/components/multi-page/PageLabel.tsx +34 -0
- package/src/editor/components/multi-page/PageLivePreview.tsx +242 -0
- package/src/editor/components/multi-page/PageThumbnail.tsx +59 -0
- package/src/editor/components/multi-page/index.ts +7 -0
- package/src/editor/components/ppt/PptChrome.tsx +2508 -0
- package/src/editor/components/ppt/PptComments.tsx +589 -0
- package/src/editor/components/ppt/PptDesignProposals.tsx +275 -0
- package/src/editor/components/ppt/PptFormatPane.tsx +320 -0
- package/src/editor/components/ppt/PptNotes.tsx +246 -0
- package/src/editor/components/property-panel/AlignmentPanel.tsx +110 -0
- package/src/editor/components/property-panel/AutoLayoutPanel.tsx +615 -0
- package/src/editor/components/property-panel/BorderSection.tsx +104 -0
- package/src/editor/components/property-panel/CompactNumberInput.tsx +237 -0
- package/src/editor/components/property-panel/CompactSizeInput.tsx +148 -0
- package/src/editor/components/property-panel/EffectSection.tsx +157 -0
- package/src/editor/components/property-panel/FillSection.tsx +69 -0
- package/src/editor/components/property-panel/GoogleFontPicker.tsx +192 -0
- package/src/editor/components/property-panel/ImageSection.tsx +206 -0
- package/src/editor/components/property-panel/ImgSrcSection.tsx +125 -0
- package/src/editor/components/property-panel/InstanceOverrideSection.tsx +413 -0
- package/src/editor/components/property-panel/LayoutSection.tsx +105 -0
- package/src/editor/components/property-panel/LinkSection.tsx +103 -0
- package/src/editor/components/property-panel/PropertyVariablePicker.tsx +311 -0
- package/src/editor/components/property-panel/ScalePanel.tsx +212 -0
- package/src/editor/components/property-panel/TypographySection.tsx +230 -0
- package/src/editor/components/property-panel/UnitAwareNumberInput.tsx +238 -0
- package/src/editor/components/property-panel/VariableAwareColorInput.tsx +477 -0
- package/src/editor/components/property-panel/VariableAwareInput.tsx +606 -0
- package/src/editor/components/property-panel/VariableAwareSizeInput.tsx +588 -0
- package/src/editor/components/property-panel/VariableAwareUnitInput.tsx +546 -0
- package/src/editor/components/property-panel/index.ts +24 -0
- package/src/editor/components/property-panel/unit-utils.ts +261 -0
- package/src/editor/components/shell/EditorTopBar.tsx +392 -0
- package/src/editor/components/shell/LeftPanel.tsx +47 -0
- package/src/editor/components/shell/PagesPanel.tsx +118 -0
- package/src/editor/components/variables-panel/ColorValueCell.tsx +165 -0
- package/src/editor/components/variables-panel/TextValueCell.tsx +116 -0
- package/src/editor/components/variables-panel/VariablesPanel.tsx +518 -0
- package/src/editor/components/variables-panel/index.ts +7 -0
- package/src/editor/constants.ts +468 -0
- package/src/editor/contexts/EditorArtboardContext.tsx +229 -0
- package/src/editor/contexts/EditorComponentsContext.tsx +1320 -0
- package/src/editor/contexts/EditorDocumentContext.tsx +113 -0
- package/src/editor/contexts/EditorHistoryContext.tsx +516 -0
- package/src/editor/contexts/EditorRefsContext.tsx +204 -0
- package/src/editor/contexts/EditorSelectionContext.tsx +54 -0
- package/src/editor/contexts/EditorToolContext.tsx +58 -0
- package/src/editor/contexts/EditorUIStateContext.tsx +122 -0
- package/src/editor/contexts/EditorVariablesContext.tsx +397 -0
- package/src/editor/contexts/EditorViewContext.tsx +101 -0
- package/src/editor/contexts/MultiPageCanvasContext.tsx +498 -0
- package/src/editor/contexts/index.ts +17 -0
- package/src/editor/editor-skin.css +122 -0
- package/src/editor/hooks/index.ts +38 -0
- package/src/editor/hooks/useAiReplace.ts +397 -0
- package/src/editor/hooks/useAltMeasure.ts +67 -0
- package/src/editor/hooks/useBrowserZoomPrevention.ts +121 -0
- package/src/editor/hooks/useCanvasControls.ts +1222 -0
- package/src/editor/hooks/useComponentEditMode.ts +658 -0
- package/src/editor/hooks/useComponentInstances.ts +515 -0
- package/src/editor/hooks/useContextMenuHandler.ts +157 -0
- package/src/editor/hooks/useCoordinateTransform.ts +207 -0
- package/src/editor/hooks/useDragResize.ts +1317 -0
- package/src/editor/hooks/useDrawingMode.ts +472 -0
- package/src/editor/hooks/useEditorColors.ts +144 -0
- package/src/editor/hooks/useEditorMessages.ts +108 -0
- package/src/editor/hooks/useElementActions.ts +1754 -0
- package/src/editor/hooks/useElementSelection.ts +1573 -0
- package/src/editor/hooks/useFocusManagement.ts +249 -0
- package/src/editor/hooks/useGoogleFonts.ts +305 -0
- package/src/editor/hooks/useIframeInitializer.ts +584 -0
- package/src/editor/hooks/useIframeSetup.ts +360 -0
- package/src/editor/hooks/useImageUpload.ts +270 -0
- package/src/editor/hooks/useInfiniteCanvas.ts +301 -0
- package/src/editor/hooks/useKeyboardShortcuts.ts +205 -0
- package/src/editor/hooks/useMarqueeSelection.ts +388 -0
- package/src/editor/hooks/useMediaLibrary.ts +129 -0
- package/src/editor/hooks/usePageSettingsManager.ts +739 -0
- package/src/editor/hooks/useResizablePanel.ts +163 -0
- package/src/editor/hooks/useRichPaste.ts +255 -0
- package/src/editor/hooks/useTouchGestures.ts +197 -0
- package/src/editor/index.ts +27 -0
- package/src/editor/types/page-settings.ts +513 -0
- package/src/editor/types.ts +382 -0
- package/src/editor/utils/align-elements.ts +169 -0
- package/src/editor/utils/api-json.ts +21 -0
- package/src/editor/utils/aspect-lock.ts +50 -0
- package/src/editor/utils/component-renderer.ts +702 -0
- package/src/editor/utils/component-sync.ts +845 -0
- package/src/editor/utils/crop-mode.ts +265 -0
- package/src/editor/utils/dom-utils.ts +2238 -0
- package/src/editor/utils/element-effects.ts +218 -0
- package/src/editor/utils/eyedropper.ts +35 -0
- package/src/editor/utils/figma-export.ts +560 -0
- package/src/editor/utils/figma-kiwi-decoder.ts +722 -0
- package/src/editor/utils/figma-kiwi-encoder.ts +583 -0
- package/src/editor/utils/figma-paste.ts +2262 -0
- package/src/editor/utils/flex-reorder.ts +231 -0
- package/src/editor/utils/flex-utils.ts +1230 -0
- package/src/editor/utils/geometry.ts +232 -0
- package/src/editor/utils/grid-layout.ts +210 -0
- package/src/editor/utils/html-utils.ts +470 -0
- package/src/editor/utils/index.ts +11 -0
- package/src/editor/utils/ink-style.ts +57 -0
- package/src/editor/utils/inline-format.ts +236 -0
- package/src/editor/utils/measure-distance.ts +120 -0
- package/src/editor/utils/override-apply.ts +526 -0
- package/src/editor/utils/override-detection.ts +613 -0
- package/src/editor/utils/paste-processors.ts +609 -0
- package/src/editor/utils/paste-sanitizer.ts +244 -0
- package/src/editor/utils/restore-flow.ts +188 -0
- package/src/editor/utils/shape-library.ts +171 -0
- package/src/editor/utils/slide-root.ts +29 -0
- package/src/editor/utils/smart-guides.ts +218 -0
- package/src/editor/utils/style-utils.ts +685 -0
- package/src/editor/utils/table-edit.ts +151 -0
- package/src/editor/utils/tailwind-mappings.ts +778 -0
- package/src/editor/utils/tailwind-utils.ts +804 -0
- package/src/editor/utils/text-highlight.ts +216 -0
- package/src/editor/utils/theme-to-variables.ts +341 -0
- package/src/editor/utils/variant-resolver.ts +456 -0
- package/src/editor/utils/viewport-utils.ts +295 -0
- package/src/hooks/useEditorHistory.ts +195 -0
- package/src/hooks/useEditorShortcuts.ts +260 -0
- package/src/index.ts +40 -0
- package/src/io.ts +134 -0
- package/src/lib/agent/slide-agent/types.ts +547 -0
- package/src/lib/agent/website-agent/types.ts +805 -0
- package/src/lib/api/auth-fetch.ts +58 -0
- package/src/lib/deck.ts +69 -0
- package/src/lib/export.ts +47 -0
- package/src/lib/firebase/config.ts +29 -0
- package/src/lib/firebase/css-variables.ts +378 -0
- package/src/lib/firebase/editor-components.ts +677 -0
- package/src/lib/firebase/storage.ts +469 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/editor.css +52 -0
- package/src/styles/skin.css +122 -0
- package/src/types/css-variables.ts +645 -0
- package/src/types/editor-components.ts +944 -0
- package/src/types/editor.ts +420 -0
- package/src/types/page-master.ts +197 -0
- package/src/types/page.ts +419 -0
- package/src/types/slide.ts +402 -0
- package/src/types/website-theme.ts +788 -0
- package/src/types/website.ts +374 -0
- package/src/vendor/firebase-firestore.ts +13 -0
- package/src/vendor/firebase-functions.ts +17 -0
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { useEditorContext, useEditorComponents } from '../EditorContext';
|
|
3
|
+
import { htmlElementToComponentElement } from '../contexts/EditorComponentsContext';
|
|
4
|
+
import { renderComponentElement } from '../utils/component-renderer';
|
|
5
|
+
import { propagateMasterChanges } from '../utils/component-sync';
|
|
6
|
+
import { buildDomTree } from '../utils/dom-utils';
|
|
7
|
+
import { toast } from 'sonner';
|
|
8
|
+
import type { MasterComponent, ComponentInstance } from '../../types/editor-components';
|
|
9
|
+
|
|
10
|
+
interface UseComponentEditModeProps {
|
|
11
|
+
contentId?: string;
|
|
12
|
+
closeContextMenu: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface UseComponentEditModeReturn {
|
|
16
|
+
// Panel state
|
|
17
|
+
isComponentPanelOpen: boolean;
|
|
18
|
+
setIsComponentPanelOpen: (open: boolean) => void;
|
|
19
|
+
selectedMasterComponentId: string | null;
|
|
20
|
+
setSelectedMasterComponentId: (id: string | null) => void;
|
|
21
|
+
// Master editor
|
|
22
|
+
editingMasterComponent: MasterComponent | null;
|
|
23
|
+
isMasterEditorOpen: boolean;
|
|
24
|
+
setIsMasterEditorOpen: (open: boolean) => void;
|
|
25
|
+
setEditingMasterComponent: (c: MasterComponent | null) => void;
|
|
26
|
+
// Component edit mode
|
|
27
|
+
isComponentEditMode: boolean;
|
|
28
|
+
editingComponentId: string | null;
|
|
29
|
+
// Create component dialog
|
|
30
|
+
createComponentDialogOpen: boolean;
|
|
31
|
+
setCreateComponentDialogOpen: (open: boolean) => void;
|
|
32
|
+
newComponentName: string;
|
|
33
|
+
setNewComponentName: (name: string) => void;
|
|
34
|
+
newComponentCategory: string;
|
|
35
|
+
setNewComponentCategory: (category: string) => void;
|
|
36
|
+
// Computed
|
|
37
|
+
selectedElementInstance: ComponentInstance | null;
|
|
38
|
+
isComponentInstance: boolean;
|
|
39
|
+
hasOverrides: boolean;
|
|
40
|
+
// Handlers
|
|
41
|
+
handleCreateComponent: () => void;
|
|
42
|
+
handleConfirmCreateComponent: () => Promise<void>;
|
|
43
|
+
handleEditMasterComponent: (masterId: string) => void;
|
|
44
|
+
handleSaveMasterComponent: (updatedMaster: MasterComponent) => Promise<void>;
|
|
45
|
+
handleDeleteMasterComponent: (masterId: string) => Promise<void>;
|
|
46
|
+
enterComponentEditMode: (masterId: string) => void;
|
|
47
|
+
exitComponentEditMode: (save: boolean) => Promise<void>;
|
|
48
|
+
handleGoToMainComponent: () => void;
|
|
49
|
+
handleDetachInstance: () => void;
|
|
50
|
+
handleResetOverrides: () => Promise<void>;
|
|
51
|
+
handlePushOverridesToMain: () => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* コンポーネント編集モード管理フック
|
|
56
|
+
* マスターコンポーネントの作成・編集・削除、インスタンス操作、
|
|
57
|
+
* コンポーネントパネル・エディタ状態を管理
|
|
58
|
+
*/
|
|
59
|
+
export function useComponentEditMode({
|
|
60
|
+
contentId,
|
|
61
|
+
closeContextMenu,
|
|
62
|
+
}: UseComponentEditModeProps): UseComponentEditModeReturn {
|
|
63
|
+
const {
|
|
64
|
+
iframeRef,
|
|
65
|
+
selectedElement,
|
|
66
|
+
setSelectedElement,
|
|
67
|
+
setSelectedElementIds,
|
|
68
|
+
setDomTree,
|
|
69
|
+
setExpandedNodes,
|
|
70
|
+
getIframeDoc,
|
|
71
|
+
notifyIframeChange,
|
|
72
|
+
} = useEditorContext();
|
|
73
|
+
|
|
74
|
+
const {
|
|
75
|
+
masterComponents,
|
|
76
|
+
componentInstances,
|
|
77
|
+
componentLibrary,
|
|
78
|
+
createMasterComponent,
|
|
79
|
+
createInstance,
|
|
80
|
+
updateInstance,
|
|
81
|
+
getInstanceByDomId,
|
|
82
|
+
getMasterComponent,
|
|
83
|
+
detachInstance,
|
|
84
|
+
resetAllOverrides,
|
|
85
|
+
updateMasterComponent,
|
|
86
|
+
deleteMasterComponent,
|
|
87
|
+
pendingNavigationTarget,
|
|
88
|
+
clearNavigationRequest,
|
|
89
|
+
} = useEditorComponents();
|
|
90
|
+
|
|
91
|
+
// コンポーネントパネル状態
|
|
92
|
+
const [isComponentPanelOpen, setIsComponentPanelOpen] = useState(false);
|
|
93
|
+
// 選択中のマスターコンポーネントID(「メインコンポーネントに移動」機能用)
|
|
94
|
+
const [selectedMasterComponentId, setSelectedMasterComponentId] = useState<string | null>(null);
|
|
95
|
+
// マスターコンポーネントエディタ(メタデータ編集用ダイアログ)状態
|
|
96
|
+
const [editingMasterComponent, setEditingMasterComponent] = useState<MasterComponent | null>(null);
|
|
97
|
+
const [isMasterEditorOpen, setIsMasterEditorOpen] = useState(false);
|
|
98
|
+
|
|
99
|
+
// コンポーネント編集モード(キャンバス内でマスターを直接編集)
|
|
100
|
+
const [isComponentEditMode, setIsComponentEditMode] = useState(false);
|
|
101
|
+
const [editingComponentId, setEditingComponentId] = useState<string | null>(null);
|
|
102
|
+
const originalPageHtmlRef = useRef<string | null>(null);
|
|
103
|
+
|
|
104
|
+
// コンポーネント作成ダイアログ状態
|
|
105
|
+
const [createComponentDialogOpen, setCreateComponentDialogOpen] = useState(false);
|
|
106
|
+
const [newComponentName, setNewComponentName] = useState('');
|
|
107
|
+
const [newComponentCategory, setNewComponentCategory] = useState('');
|
|
108
|
+
|
|
109
|
+
// Handle navigation request from property panel ("Go to Main Component")
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (pendingNavigationTarget) {
|
|
112
|
+
setIsComponentPanelOpen(true);
|
|
113
|
+
setSelectedMasterComponentId(pendingNavigationTarget);
|
|
114
|
+
clearNavigationRequest();
|
|
115
|
+
}
|
|
116
|
+
}, [pendingNavigationTarget, clearNavigationRequest]);
|
|
117
|
+
|
|
118
|
+
// Check if selected element is a component instance
|
|
119
|
+
const selectedElementInstance = useMemo(() => {
|
|
120
|
+
if (!selectedElement?.id) return null;
|
|
121
|
+
return getInstanceByDomId(selectedElement.id);
|
|
122
|
+
}, [selectedElement?.id, getInstanceByDomId]);
|
|
123
|
+
|
|
124
|
+
const isComponentInstance = !!selectedElementInstance;
|
|
125
|
+
|
|
126
|
+
const hasOverrides = useMemo(() => {
|
|
127
|
+
if (!selectedElementInstance) return false;
|
|
128
|
+
return selectedElementInstance.overrides.length > 0;
|
|
129
|
+
}, [selectedElementInstance]);
|
|
130
|
+
|
|
131
|
+
// Create component from selected element
|
|
132
|
+
const handleCreateComponent = useCallback(() => {
|
|
133
|
+
if (!selectedElement?.id || !iframeRef.current) return;
|
|
134
|
+
const iframeDoc = iframeRef.current.contentDocument;
|
|
135
|
+
if (!iframeDoc) return;
|
|
136
|
+
|
|
137
|
+
const element = iframeDoc.querySelector(`[data-element-id="${selectedElement.id}"]`) as HTMLElement;
|
|
138
|
+
if (!element) return;
|
|
139
|
+
|
|
140
|
+
// Open dialog to get component name and category
|
|
141
|
+
setCreateComponentDialogOpen(true);
|
|
142
|
+
}, [selectedElement?.id, iframeRef]);
|
|
143
|
+
|
|
144
|
+
const handleConfirmCreateComponent = useCallback(async () => {
|
|
145
|
+
if (!selectedElement?.id || !iframeRef.current || !newComponentName.trim() || !contentId) return;
|
|
146
|
+
const iframeDoc = iframeRef.current.contentDocument;
|
|
147
|
+
if (!iframeDoc) return;
|
|
148
|
+
|
|
149
|
+
const element = iframeDoc.querySelector(`[data-element-id="${selectedElement.id}"]`) as HTMLElement;
|
|
150
|
+
if (!element) return;
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
// Debug: Log the original element
|
|
154
|
+
console.log('[handleConfirmCreateComponent] Original element:', {
|
|
155
|
+
tagName: element.tagName,
|
|
156
|
+
className: element.className,
|
|
157
|
+
innerHTML: element.innerHTML.substring(0, 200),
|
|
158
|
+
outerHTML: element.outerHTML.substring(0, 300),
|
|
159
|
+
childrenCount: element.children.length,
|
|
160
|
+
textContent: element.textContent?.substring(0, 100),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Create the master component
|
|
164
|
+
const component = createMasterComponent(element, newComponentName.trim(), newComponentCategory || 'content');
|
|
165
|
+
console.log('[handleConfirmCreateComponent] Created component:', {
|
|
166
|
+
id: component.id,
|
|
167
|
+
name: component.name,
|
|
168
|
+
variantsCount: component.variants.length,
|
|
169
|
+
defaultVariantId: component.defaultVariantId,
|
|
170
|
+
rootElement: component.variants[0]?.rootElement ? {
|
|
171
|
+
tagName: component.variants[0].rootElement.tagName,
|
|
172
|
+
className: component.variants[0].rootElement.className,
|
|
173
|
+
childrenCount: component.variants[0].rootElement.children.length,
|
|
174
|
+
textContent: component.variants[0].rootElement.textContent?.substring(0, 100),
|
|
175
|
+
} : 'NO ROOT ELEMENT',
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Calculate position from original element BEFORE creating instance
|
|
179
|
+
// Note: Can't use `parseFloat(style) || fallback` because 0 is falsy
|
|
180
|
+
const rect = element.getBoundingClientRect();
|
|
181
|
+
const iframeRect = iframeRef.current!.getBoundingClientRect();
|
|
182
|
+
const styleLeft = element.style.left ? parseFloat(element.style.left) : NaN;
|
|
183
|
+
const styleTop = element.style.top ? parseFloat(element.style.top) : NaN;
|
|
184
|
+
const positionX = !isNaN(styleLeft) ? styleLeft : (rect.left - iframeRect.left);
|
|
185
|
+
const positionY = !isNaN(styleTop) ? styleTop : (rect.top - iframeRect.top);
|
|
186
|
+
|
|
187
|
+
// Create an instance of the component to replace the original element
|
|
188
|
+
// Pass the component directly since state update is async
|
|
189
|
+
// Pass position directly to createInstance to avoid React state batching race condition
|
|
190
|
+
const instance = createInstance(
|
|
191
|
+
component.id,
|
|
192
|
+
undefined,
|
|
193
|
+
contentId,
|
|
194
|
+
component,
|
|
195
|
+
undefined, // customDomElementId
|
|
196
|
+
undefined, // initialOverrides
|
|
197
|
+
undefined, // initialPropertyValues
|
|
198
|
+
{ x: positionX, y: positionY } // initialPosition
|
|
199
|
+
);
|
|
200
|
+
if (instance) {
|
|
201
|
+
console.log('[handleConfirmCreateComponent] Created instance:', {
|
|
202
|
+
id: instance.id,
|
|
203
|
+
domElementId: instance.domElementId,
|
|
204
|
+
variantId: instance.variantId,
|
|
205
|
+
position: instance.position,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Render the instance to DOM (position will be applied from instance.position)
|
|
209
|
+
const { renderInstance } = await import('../utils/component-renderer');
|
|
210
|
+
const instanceElement = renderInstance(component, instance, iframeDoc);
|
|
211
|
+
|
|
212
|
+
console.log('[handleConfirmCreateComponent] Rendered instance element:', {
|
|
213
|
+
tagName: instanceElement.tagName,
|
|
214
|
+
className: instanceElement.className,
|
|
215
|
+
innerHTML: instanceElement.innerHTML.substring(0, 200),
|
|
216
|
+
outerHTML: instanceElement.outerHTML.substring(0, 300),
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Replace the original element with the instance
|
|
220
|
+
element.parentNode?.replaceChild(instanceElement, element);
|
|
221
|
+
|
|
222
|
+
// Update selection to the new instance using proper element info extraction
|
|
223
|
+
const { extractElementInfo } = await import('../utils/style-utils');
|
|
224
|
+
const elementInfo = extractElementInfo(instanceElement, iframeDoc);
|
|
225
|
+
if (elementInfo) {
|
|
226
|
+
setSelectedElement(elementInfo);
|
|
227
|
+
setSelectedElementIds([instance.domElementId]);
|
|
228
|
+
instanceElement.classList.add('selected');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Update history
|
|
232
|
+
notifyIframeChange(true);
|
|
233
|
+
|
|
234
|
+
console.log('[handleConfirmCreateComponent] Replaced element with instance:', instance.id);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
setCreateComponentDialogOpen(false);
|
|
238
|
+
setNewComponentName('');
|
|
239
|
+
setNewComponentCategory('');
|
|
240
|
+
closeContextMenu();
|
|
241
|
+
toast.success(`コンポーネント "${newComponentName}" を作成しました`);
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.error('Failed to create component:', error);
|
|
244
|
+
toast.error('コンポーネントの作成に失敗しました');
|
|
245
|
+
}
|
|
246
|
+
}, [selectedElement?.id, iframeRef, newComponentName, newComponentCategory, createMasterComponent, createInstance, contentId, notifyIframeChange, closeContextMenu, setSelectedElement, setSelectedElementIds]);
|
|
247
|
+
|
|
248
|
+
// Open master component editor
|
|
249
|
+
const handleEditMasterComponent = useCallback((masterId: string) => {
|
|
250
|
+
const master = getMasterComponent(masterId);
|
|
251
|
+
if (master) {
|
|
252
|
+
setEditingMasterComponent(master);
|
|
253
|
+
setIsMasterEditorOpen(true);
|
|
254
|
+
}
|
|
255
|
+
}, [getMasterComponent]);
|
|
256
|
+
|
|
257
|
+
// Save master component changes
|
|
258
|
+
const handleSaveMasterComponent = useCallback(async (updatedMaster: MasterComponent) => {
|
|
259
|
+
try {
|
|
260
|
+
updateMasterComponent(updatedMaster.id, updatedMaster);
|
|
261
|
+
setIsMasterEditorOpen(false);
|
|
262
|
+
setEditingMasterComponent(null);
|
|
263
|
+
toast.success('コンポーネントを保存しました');
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.error('Failed to save master component:', error);
|
|
266
|
+
toast.error('コンポーネントの保存に失敗しました');
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
269
|
+
}, [updateMasterComponent]);
|
|
270
|
+
|
|
271
|
+
// Delete master component
|
|
272
|
+
const handleDeleteMasterComponent = useCallback(async (masterId: string) => {
|
|
273
|
+
try {
|
|
274
|
+
deleteMasterComponent(masterId);
|
|
275
|
+
setIsMasterEditorOpen(false);
|
|
276
|
+
setEditingMasterComponent(null);
|
|
277
|
+
toast.success('コンポーネントを削除しました');
|
|
278
|
+
} catch (error) {
|
|
279
|
+
console.error('Failed to delete master component:', error);
|
|
280
|
+
toast.error('コンポーネントの削除に失敗しました');
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
283
|
+
}, [deleteMasterComponent]);
|
|
284
|
+
|
|
285
|
+
// Enter component edit mode - directly edit the master component in the canvas
|
|
286
|
+
const enterComponentEditMode = useCallback((masterId: string) => {
|
|
287
|
+
const master = getMasterComponent(masterId);
|
|
288
|
+
if (!master) {
|
|
289
|
+
toast.error('コンポーネントが見つかりません');
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const iframeDoc = getIframeDoc();
|
|
294
|
+
if (!iframeDoc) return;
|
|
295
|
+
|
|
296
|
+
// Save current page HTML
|
|
297
|
+
const artboard = iframeDoc.getElementById('artboard');
|
|
298
|
+
if (artboard) {
|
|
299
|
+
originalPageHtmlRef.current = artboard.innerHTML;
|
|
300
|
+
|
|
301
|
+
// DEBUG: Log what instances are being saved
|
|
302
|
+
console.log('[enterComponentEditMode] ========== SAVING PAGE HTML ==========');
|
|
303
|
+
const instancesToSave = artboard.querySelectorAll('[data-component-instance]');
|
|
304
|
+
console.log('[enterComponentEditMode] Saving', instancesToSave.length, 'instances');
|
|
305
|
+
instancesToSave.forEach((inst, idx) => {
|
|
306
|
+
console.log(`[enterComponentEditMode] Instance ${idx} text being saved:`, inst.textContent?.substring(0, 100));
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Get the default variant's root element
|
|
311
|
+
const defaultVariant = master.variants.find(v => v.id === master.defaultVariantId);
|
|
312
|
+
if (!defaultVariant?.rootElement) {
|
|
313
|
+
toast.error('コンポーネントの構造が見つかりません');
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Render the component element to HTML
|
|
318
|
+
const componentElement = renderComponentElement(defaultVariant.rootElement, iframeDoc);
|
|
319
|
+
|
|
320
|
+
// Clear the artboard and add the component
|
|
321
|
+
if (artboard) {
|
|
322
|
+
artboard.innerHTML = '';
|
|
323
|
+
// Add padding/centering wrapper
|
|
324
|
+
const wrapper = iframeDoc.createElement('div');
|
|
325
|
+
wrapper.style.cssText = 'padding: 40px; display: flex; align-items: flex-start; justify-content: center; min-height: 100%;';
|
|
326
|
+
wrapper.appendChild(componentElement);
|
|
327
|
+
artboard.appendChild(wrapper);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Add class to body to indicate component edit mode (used by selection hooks)
|
|
331
|
+
iframeDoc.body.classList.add('component-edit-mode');
|
|
332
|
+
|
|
333
|
+
// Set edit mode state
|
|
334
|
+
setIsComponentEditMode(true);
|
|
335
|
+
setEditingComponentId(masterId);
|
|
336
|
+
|
|
337
|
+
// Clear selection
|
|
338
|
+
setSelectedElement(null);
|
|
339
|
+
setSelectedElementIds([]);
|
|
340
|
+
|
|
341
|
+
// Rebuild DOM tree
|
|
342
|
+
const tree = buildDomTree(iframeDoc);
|
|
343
|
+
setDomTree(tree);
|
|
344
|
+
setExpandedNodes(new Set(tree.map((n: { id: string }) => n.id)));
|
|
345
|
+
|
|
346
|
+
toast.success(`コンポーネント「${master.name}」を編集中`);
|
|
347
|
+
closeContextMenu();
|
|
348
|
+
}, [getMasterComponent, getIframeDoc, setSelectedElement, setSelectedElementIds, setDomTree, setExpandedNodes, closeContextMenu]);
|
|
349
|
+
|
|
350
|
+
// Exit component edit mode
|
|
351
|
+
const exitComponentEditMode = useCallback(async (save: boolean) => {
|
|
352
|
+
if (!editingComponentId) return;
|
|
353
|
+
|
|
354
|
+
const iframeDoc = getIframeDoc();
|
|
355
|
+
if (!iframeDoc) return;
|
|
356
|
+
|
|
357
|
+
// Store the updated master component for syncing after page restore
|
|
358
|
+
let updatedMaster: MasterComponent | null = null;
|
|
359
|
+
|
|
360
|
+
if (save) {
|
|
361
|
+
// Get the master component
|
|
362
|
+
const master = getMasterComponent(editingComponentId);
|
|
363
|
+
if (!master) {
|
|
364
|
+
toast.error('コンポーネントが見つかりません');
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Get the edited element from the artboard
|
|
369
|
+
const artboard = iframeDoc.getElementById('artboard');
|
|
370
|
+
const wrapper = artboard?.firstElementChild as HTMLElement;
|
|
371
|
+
const editedElement = wrapper?.firstElementChild as HTMLElement;
|
|
372
|
+
|
|
373
|
+
if (editedElement) {
|
|
374
|
+
// Convert back to ComponentElement
|
|
375
|
+
const newRootElement = htmlElementToComponentElement(editedElement);
|
|
376
|
+
|
|
377
|
+
// Find and update the default variant
|
|
378
|
+
const updatedVariants = master.variants.map(v => {
|
|
379
|
+
if (v.id === master.defaultVariantId) {
|
|
380
|
+
return { ...v, rootElement: newRootElement };
|
|
381
|
+
}
|
|
382
|
+
return v;
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// Update the master component
|
|
386
|
+
try {
|
|
387
|
+
updateMasterComponent(master.id, {
|
|
388
|
+
variants: updatedVariants,
|
|
389
|
+
updatedAt: new Date().toISOString(),
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Store for syncing after page restore
|
|
393
|
+
updatedMaster = {
|
|
394
|
+
...master,
|
|
395
|
+
variants: updatedVariants,
|
|
396
|
+
updatedAt: new Date().toISOString(),
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
toast.success('コンポーネントを保存しました');
|
|
400
|
+
} catch (error) {
|
|
401
|
+
console.error('Failed to save component:', error);
|
|
402
|
+
toast.error('コンポーネントの保存に失敗しました');
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Restore original page HTML
|
|
408
|
+
const artboard = iframeDoc.getElementById('artboard');
|
|
409
|
+
|
|
410
|
+
// DEBUG: Log what we're about to restore
|
|
411
|
+
console.log('[exitComponentEditMode] ========== HTML RESTORE DEBUG ==========');
|
|
412
|
+
console.log('[exitComponentEditMode] originalPageHtmlRef exists:', originalPageHtmlRef.current !== null);
|
|
413
|
+
if (originalPageHtmlRef.current) {
|
|
414
|
+
// Extract instance text from saved HTML for debugging
|
|
415
|
+
const tempDiv = document.createElement('div');
|
|
416
|
+
tempDiv.innerHTML = originalPageHtmlRef.current;
|
|
417
|
+
const savedInstances = tempDiv.querySelectorAll('[data-component-instance]');
|
|
418
|
+
console.log('[exitComponentEditMode] Saved HTML has', savedInstances.length, 'instances');
|
|
419
|
+
savedInstances.forEach((inst, idx) => {
|
|
420
|
+
console.log(`[exitComponentEditMode] Saved instance ${idx} text:`, inst.textContent?.substring(0, 100));
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (artboard && originalPageHtmlRef.current !== null) {
|
|
425
|
+
artboard.innerHTML = originalPageHtmlRef.current;
|
|
426
|
+
originalPageHtmlRef.current = null;
|
|
427
|
+
|
|
428
|
+
// DEBUG: Log what's in the DOM after restore
|
|
429
|
+
const restoredInstances = artboard.querySelectorAll('[data-component-instance]');
|
|
430
|
+
console.log('[exitComponentEditMode] After restore, DOM has', restoredInstances.length, 'instances');
|
|
431
|
+
restoredInstances.forEach((inst, idx) => {
|
|
432
|
+
console.log(`[exitComponentEditMode] Restored instance ${idx} text:`, inst.textContent?.substring(0, 100));
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Sync all instances with the updated master component
|
|
437
|
+
if (updatedMaster && save) {
|
|
438
|
+
// Get all instances as an array
|
|
439
|
+
const instancesArray = Array.from(componentInstances.values());
|
|
440
|
+
|
|
441
|
+
// Debug: Log the updated master and instances
|
|
442
|
+
console.log('[exitComponentEditMode] ========== SYNC DEBUG ==========');
|
|
443
|
+
console.log('[exitComponentEditMode] Updated master:', {
|
|
444
|
+
id: updatedMaster.id,
|
|
445
|
+
name: updatedMaster.name,
|
|
446
|
+
variantsCount: updatedMaster.variants.length,
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// Log master's text content
|
|
450
|
+
const defaultVariant = updatedMaster.variants.find(v => v.id === updatedMaster.defaultVariantId);
|
|
451
|
+
if (defaultVariant) {
|
|
452
|
+
console.log('[exitComponentEditMode] Master rootElement:', {
|
|
453
|
+
tagName: defaultVariant.rootElement.tagName,
|
|
454
|
+
textContent: defaultVariant.rootElement.textContent?.substring(0, 100),
|
|
455
|
+
innerHTML: defaultVariant.rootElement.innerHTML?.substring(0, 100),
|
|
456
|
+
childrenCount: defaultVariant.rootElement.children.length,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
console.log('[exitComponentEditMode] Instances to sync:', instancesArray.map(i => ({
|
|
461
|
+
id: i.id,
|
|
462
|
+
masterComponentId: i.masterComponentId,
|
|
463
|
+
domElementId: i.domElementId,
|
|
464
|
+
isDetached: i.isDetached,
|
|
465
|
+
existingOverrides: i.overrides.length,
|
|
466
|
+
})));
|
|
467
|
+
|
|
468
|
+
// Debug: Check if instances exist in restored DOM
|
|
469
|
+
const artboardForSync = iframeDoc.getElementById('artboard');
|
|
470
|
+
if (artboardForSync) {
|
|
471
|
+
const instanceElements = artboardForSync.querySelectorAll(`[data-component-master="${updatedMaster.id}"]`);
|
|
472
|
+
console.log('[exitComponentEditMode] Instance elements in DOM:', instanceElements.length);
|
|
473
|
+
instanceElements.forEach((el, i) => {
|
|
474
|
+
console.log(`[exitComponentEditMode] DOM instance ${i}:`, {
|
|
475
|
+
instanceId: el.getAttribute('data-component-instance'),
|
|
476
|
+
masterId: el.getAttribute('data-component-master'),
|
|
477
|
+
elementId: el.getAttribute('data-element-id'),
|
|
478
|
+
textContent: el.textContent?.substring(0, 100),
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Propagate master changes to all instances in the DOM
|
|
484
|
+
const syncResult = propagateMasterChanges(updatedMaster, instancesArray, iframeDoc);
|
|
485
|
+
console.log('[exitComponentEditMode] Synced instances:', syncResult);
|
|
486
|
+
|
|
487
|
+
// Persist updated instances with their newly detected overrides
|
|
488
|
+
if (syncResult.updatedInstances.length > 0) {
|
|
489
|
+
console.log('[exitComponentEditMode] Persisting updated instances with overrides:',
|
|
490
|
+
syncResult.updatedInstances.map(i => ({
|
|
491
|
+
id: i.id,
|
|
492
|
+
overridesCount: i.overrides.length,
|
|
493
|
+
}))
|
|
494
|
+
);
|
|
495
|
+
for (const updatedInst of syncResult.updatedInstances) {
|
|
496
|
+
updateInstance(updatedInst.id, {
|
|
497
|
+
overrides: updatedInst.overrides,
|
|
498
|
+
variantId: updatedInst.variantId,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (syncResult.updatedCount > 0) {
|
|
504
|
+
toast.success(`${syncResult.updatedCount}個のインスタンスを更新しました`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Remove component edit mode class from body
|
|
509
|
+
iframeDoc.body.classList.remove('component-edit-mode');
|
|
510
|
+
|
|
511
|
+
// Clear edit mode state
|
|
512
|
+
setIsComponentEditMode(false);
|
|
513
|
+
setEditingComponentId(null);
|
|
514
|
+
setSelectedElement(null);
|
|
515
|
+
setSelectedElementIds([]);
|
|
516
|
+
|
|
517
|
+
// Rebuild DOM tree
|
|
518
|
+
const tree = buildDomTree(iframeDoc);
|
|
519
|
+
setDomTree(tree);
|
|
520
|
+
setExpandedNodes(new Set(tree.map((n: { id: string }) => n.id)));
|
|
521
|
+
|
|
522
|
+
// Notify change
|
|
523
|
+
notifyIframeChange(true);
|
|
524
|
+
}, [editingComponentId, getMasterComponent, getIframeDoc, updateMasterComponent, updateInstance, componentInstances, setSelectedElement, setSelectedElementIds, setDomTree, setExpandedNodes, notifyIframeChange]);
|
|
525
|
+
|
|
526
|
+
// Go to main component - enters component edit mode to directly edit the master in canvas
|
|
527
|
+
const handleGoToMainComponent = useCallback(() => {
|
|
528
|
+
if (!selectedElementInstance) return;
|
|
529
|
+
console.log('Go to main component:', selectedElementInstance.masterComponentId);
|
|
530
|
+
enterComponentEditMode(selectedElementInstance.masterComponentId);
|
|
531
|
+
}, [selectedElementInstance, enterComponentEditMode]);
|
|
532
|
+
|
|
533
|
+
// Detach instance
|
|
534
|
+
const handleDetachInstance = useCallback(() => {
|
|
535
|
+
if (!selectedElementInstance) return;
|
|
536
|
+
try {
|
|
537
|
+
// Get the rendered HTML element from the detach operation
|
|
538
|
+
const detachedElement = detachInstance(selectedElementInstance.id);
|
|
539
|
+
|
|
540
|
+
// Find and replace the instance element in the DOM
|
|
541
|
+
const iframeDoc = getIframeDoc();
|
|
542
|
+
if (iframeDoc && detachedElement) {
|
|
543
|
+
const existingElement = iframeDoc.querySelector(`[data-element-id="${selectedElementInstance.domElementId}"]`);
|
|
544
|
+
if (existingElement) {
|
|
545
|
+
// Remove component-related attributes from the detached element
|
|
546
|
+
detachedElement.removeAttribute('data-component-instance');
|
|
547
|
+
detachedElement.removeAttribute('data-component-master');
|
|
548
|
+
|
|
549
|
+
// Preserve position from existing element
|
|
550
|
+
const existingStyle = existingElement.getAttribute('style');
|
|
551
|
+
if (existingStyle) {
|
|
552
|
+
detachedElement.setAttribute('style', existingStyle);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Replace with detached element
|
|
556
|
+
existingElement.replaceWith(detachedElement);
|
|
557
|
+
|
|
558
|
+
// Notify change
|
|
559
|
+
notifyIframeChange(true);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
console.log('Detached instance:', selectedElementInstance.id);
|
|
564
|
+
closeContextMenu();
|
|
565
|
+
toast.success('インスタンスを解除しました');
|
|
566
|
+
} catch (error) {
|
|
567
|
+
console.error('Failed to detach instance:', error);
|
|
568
|
+
toast.error('インスタンスの解除に失敗しました');
|
|
569
|
+
}
|
|
570
|
+
}, [selectedElementInstance, detachInstance, getIframeDoc, notifyIframeChange, closeContextMenu]);
|
|
571
|
+
|
|
572
|
+
// Reset all overrides
|
|
573
|
+
const handleResetOverrides = useCallback(async () => {
|
|
574
|
+
if (!selectedElementInstance) return;
|
|
575
|
+
try {
|
|
576
|
+
resetAllOverrides(selectedElementInstance.id);
|
|
577
|
+
|
|
578
|
+
// Re-render the instance in the DOM
|
|
579
|
+
const master = getMasterComponent(selectedElementInstance.masterComponentId);
|
|
580
|
+
const iframeDoc = getIframeDoc();
|
|
581
|
+
if (master && iframeDoc) {
|
|
582
|
+
const existingElement = iframeDoc.querySelector(`[data-element-id="${selectedElementInstance.domElementId}"]`);
|
|
583
|
+
if (existingElement) {
|
|
584
|
+
// Get the reset instance (with no overrides)
|
|
585
|
+
const resetInstance = { ...selectedElementInstance, overrides: [], propertyValues: {} };
|
|
586
|
+
const { renderInstance } = await import('../utils/component-renderer');
|
|
587
|
+
const newElement = renderInstance(master, resetInstance, iframeDoc);
|
|
588
|
+
|
|
589
|
+
// Preserve position from existing element
|
|
590
|
+
const existingStyle = existingElement.getAttribute('style');
|
|
591
|
+
if (existingStyle) {
|
|
592
|
+
newElement.setAttribute('style', existingStyle);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Replace the old element
|
|
596
|
+
existingElement.replaceWith(newElement);
|
|
597
|
+
|
|
598
|
+
// Notify change
|
|
599
|
+
notifyIframeChange(true);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
console.log('Reset overrides for instance:', selectedElementInstance.id);
|
|
604
|
+
closeContextMenu();
|
|
605
|
+
toast.success('オーバーライドをリセットしました');
|
|
606
|
+
} catch (error) {
|
|
607
|
+
console.error('Failed to reset overrides:', error);
|
|
608
|
+
toast.error('オーバーライドのリセットに失敗しました');
|
|
609
|
+
}
|
|
610
|
+
}, [selectedElementInstance, resetAllOverrides, getMasterComponent, getIframeDoc, notifyIframeChange, closeContextMenu]);
|
|
611
|
+
|
|
612
|
+
// Push overrides to main (placeholder - requires more complex implementation)
|
|
613
|
+
const handlePushOverridesToMain = useCallback(() => {
|
|
614
|
+
if (!selectedElementInstance) return;
|
|
615
|
+
console.log('Push overrides to main - not yet implemented');
|
|
616
|
+
closeContextMenu();
|
|
617
|
+
toast.info('この機能は現在開発中です');
|
|
618
|
+
}, [selectedElementInstance, closeContextMenu]);
|
|
619
|
+
|
|
620
|
+
return {
|
|
621
|
+
// Panel state
|
|
622
|
+
isComponentPanelOpen,
|
|
623
|
+
setIsComponentPanelOpen,
|
|
624
|
+
selectedMasterComponentId,
|
|
625
|
+
setSelectedMasterComponentId,
|
|
626
|
+
// Master editor
|
|
627
|
+
editingMasterComponent,
|
|
628
|
+
isMasterEditorOpen,
|
|
629
|
+
setIsMasterEditorOpen,
|
|
630
|
+
setEditingMasterComponent,
|
|
631
|
+
// Component edit mode
|
|
632
|
+
isComponentEditMode,
|
|
633
|
+
editingComponentId,
|
|
634
|
+
// Create component dialog
|
|
635
|
+
createComponentDialogOpen,
|
|
636
|
+
setCreateComponentDialogOpen,
|
|
637
|
+
newComponentName,
|
|
638
|
+
setNewComponentName,
|
|
639
|
+
newComponentCategory,
|
|
640
|
+
setNewComponentCategory,
|
|
641
|
+
// Computed
|
|
642
|
+
selectedElementInstance,
|
|
643
|
+
isComponentInstance,
|
|
644
|
+
hasOverrides,
|
|
645
|
+
// Handlers
|
|
646
|
+
handleCreateComponent,
|
|
647
|
+
handleConfirmCreateComponent,
|
|
648
|
+
handleEditMasterComponent,
|
|
649
|
+
handleSaveMasterComponent,
|
|
650
|
+
handleDeleteMasterComponent,
|
|
651
|
+
enterComponentEditMode,
|
|
652
|
+
exitComponentEditMode,
|
|
653
|
+
handleGoToMainComponent,
|
|
654
|
+
handleDetachInstance,
|
|
655
|
+
handleResetOverrides,
|
|
656
|
+
handlePushOverridesToMain,
|
|
657
|
+
};
|
|
658
|
+
}
|