@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,420 @@
1
+ /**
2
+ * Editor Types - Figma-like visual editor type definitions
3
+ */
4
+
5
+ // Tool types available in the editor
6
+ export type EditorTool =
7
+ | 'select' // V - Selection tool
8
+ | 'move' // H - Hand/pan tool
9
+ | 'frame' // F - Frame tool
10
+ | 'rectangle' // R - Rectangle shape
11
+ | 'ellipse' // O - Ellipse/circle shape
12
+ | 'line' // L - Line
13
+ | 'arrow' // Shift+L - Arrow line
14
+ | 'pen' // P - Pen tool (bezier curves)
15
+ | 'pencil' // Shift+P - Freehand drawing
16
+ | 'text' // T - Text tool
17
+ | 'scale' // K - Scale tool
18
+ | 'eraser' // E - Eraser (ペン/鉛筆ストロークを消す)
19
+ | 'shape'; // 図形ギャラリーで選んだ図形(ドラッグでサイズ指定)
20
+
21
+ // Shape types that can be drawn
22
+ export type ShapeType = 'rectangle' | 'ellipse' | 'line' | 'arrow' | 'text' | 'pen' | 'pencil' | 'frame';
23
+
24
+ // History state for undo/redo
25
+ export interface HistoryState {
26
+ html: string;
27
+ selectedElementId: string | null;
28
+ timestamp: number;
29
+ }
30
+
31
+ // Editor history structure
32
+ export interface EditorHistory {
33
+ past: HistoryState[];
34
+ present: HistoryState;
35
+ future: HistoryState[];
36
+ }
37
+
38
+ // Point for drawing operations
39
+ export interface PathPoint {
40
+ x: number;
41
+ y: number;
42
+ pressure?: number; // For pressure-sensitive drawing
43
+ }
44
+
45
+ // Serialized element for clipboard operations
46
+ export interface SerializedElement {
47
+ tagName: string;
48
+ id: string;
49
+ className: string;
50
+ style: string;
51
+ innerHTML: string;
52
+ attributes: Record<string, string>;
53
+ }
54
+
55
+ // Clipboard data structure
56
+ export interface ClipboardData {
57
+ elements: SerializedElement[];
58
+ offset: { x: number; y: number };
59
+ /**
60
+ * OSクリップボードへの書き込みが成功したか。
61
+ * 成功していれば paste イベント側がOSクリップボード(スライド跨ぎ可)を正とし、
62
+ * 失敗環境でのみ内部クリップボードへフォールバックする。
63
+ * これが無いと「昔の内部コピー」と「新しいOSコピー」の区別が付かない
64
+ */
65
+ osWritten?: boolean;
66
+ }
67
+
68
+ // Bounding box for grouping
69
+ export interface BoundingBox {
70
+ left: number;
71
+ top: number;
72
+ width: number;
73
+ height: number;
74
+ right: number;
75
+ bottom: number;
76
+ }
77
+
78
+ // Drawing state during shape creation
79
+ export interface DrawingState {
80
+ isDrawing: boolean;
81
+ startX: number;
82
+ startY: number;
83
+ currentX: number;
84
+ currentY: number;
85
+ previewElement: HTMLElement | null;
86
+ points: PathPoint[]; // For pen/pencil tools
87
+ }
88
+
89
+ // Shortcut action types
90
+ export type ShortcutAction =
91
+ // Tool switching
92
+ | 'select'
93
+ | 'move'
94
+ | 'rectangle'
95
+ | 'ellipse'
96
+ | 'line'
97
+ | 'arrow'
98
+ | 'eraser'
99
+ | 'pen'
100
+ | 'pencil'
101
+ | 'text'
102
+ | 'frame'
103
+ | 'scale'
104
+ // Edit operations
105
+ | 'undo'
106
+ | 'redo'
107
+ | 'copy'
108
+ | 'cut'
109
+ | 'paste'
110
+ | 'duplicate'
111
+ | 'delete'
112
+ // Style operations
113
+ | 'copyStyle'
114
+ | 'pasteStyle'
115
+ // Grouping
116
+ | 'group'
117
+ | 'ungroup'
118
+ // Selection
119
+ | 'selectAll'
120
+ | 'deselect'
121
+ // 兄弟要素の巡回選択(Tab / Shift+Tab)
122
+ | 'selectNextSibling'
123
+ | 'selectPrevSibling'
124
+ // Clipboard (external)
125
+ | 'copyToFigma'
126
+ // Zoom(実処理はエディタ側のズームAPIに委譲する)
127
+ | 'zoomFit'
128
+ | 'zoomActual'
129
+ | 'zoomSelection'
130
+ // Movement
131
+ | 'moveUp'
132
+ | 'moveDown'
133
+ | 'moveLeft'
134
+ | 'moveRight'
135
+ | 'moveUpLarge'
136
+ | 'moveDownLarge'
137
+ | 'moveLeftLarge'
138
+ | 'moveRightLarge'
139
+ // Resize (Figmaと同じ: Cmd+矢印=1px / Cmd+Shift+矢印=10px。→↓で広がり←↑で縮む)
140
+ | 'resizeGrowX'
141
+ | 'resizeShrinkX'
142
+ | 'resizeGrowY'
143
+ | 'resizeShrinkY'
144
+ | 'resizeGrowXLarge'
145
+ | 'resizeShrinkXLarge'
146
+ | 'resizeGrowYLarge'
147
+ | 'resizeShrinkYLarge'
148
+ // Layer ordering
149
+ | 'bringForward'
150
+ | 'sendBackward'
151
+ | 'bringToFront'
152
+ | 'sendToBack';
153
+
154
+ // Shortcut callbacks interface
155
+ export type ShortcutCallbacks = Partial<Record<ShortcutAction, () => void>>;
156
+
157
+ // Editor toolbar props
158
+ export interface EditorToolbarProps {
159
+ activeTool: EditorTool;
160
+ onToolChange: (tool: EditorTool) => void;
161
+ onUndo: () => void;
162
+ onRedo: () => void;
163
+ canUndo: boolean;
164
+ canRedo: boolean;
165
+ selectedCount: number;
166
+ onGroup?: () => void;
167
+ onUngroup?: () => void;
168
+ onDelete?: () => void;
169
+ onDuplicate?: () => void;
170
+ onBringForward?: () => void;
171
+ onSendBackward?: () => void;
172
+ onBringToFront?: () => void;
173
+ onSendToBack?: () => void;
174
+ onImageUpload?: () => void;
175
+ onAiRegenerate?: () => void;
176
+ /** CSS変数管理ダイアログを開くコールバック */
177
+ onOpenVariables?: () => void;
178
+ /** CSS変数が定義されているかどうか */
179
+ hasVariables?: boolean;
180
+ /** コンポーネントパネルを開くコールバック */
181
+ onOpenComponents?: () => void;
182
+ /** コンポーネントが定義されているかどうか */
183
+ hasComponents?: boolean;
184
+ }
185
+
186
+ // Tool configuration
187
+ export interface ToolConfig {
188
+ id: EditorTool;
189
+ label: string;
190
+ shortcut: string;
191
+ icon: string; // Lucide icon name
192
+ group: 'selection' | 'shapes' | 'drawing' | 'text' | 'frame';
193
+ }
194
+
195
+ // Default tool configurations
196
+ export const TOOL_CONFIGS: ToolConfig[] = [
197
+ { id: 'select', label: '選択・移動', shortcut: 'V', icon: 'MousePointer2', group: 'selection' },
198
+ { id: 'scale', label: '拡大縮小', shortcut: 'K', icon: 'Scaling', group: 'selection' },
199
+ { id: 'move', label: 'ハンド(パン)', shortcut: 'H', icon: 'Hand', group: 'selection' },
200
+ { id: 'frame', label: 'フレーム', shortcut: 'F', icon: 'Frame', group: 'frame' },
201
+ { id: 'rectangle', label: '長方形', shortcut: 'R', icon: 'Square', group: 'shapes' },
202
+ { id: 'ellipse', label: '楕円', shortcut: 'O', icon: 'Circle', group: 'shapes' },
203
+ { id: 'line', label: '直線', shortcut: 'L', icon: 'Minus', group: 'shapes' },
204
+ { id: 'arrow', label: '矢印', shortcut: '⇧L', icon: 'ArrowRight', group: 'shapes' },
205
+ { id: 'pen', label: 'ペン', shortcut: 'P', icon: 'Pen', group: 'drawing' },
206
+ { id: 'pencil', label: 'フリーハンド', shortcut: '⇧P', icon: 'Pencil', group: 'drawing' },
207
+ { id: 'text', label: 'テキスト', shortcut: 'T', icon: 'Type', group: 'text' },
208
+ ];
209
+
210
+ /**
211
+ * キーボードショートカットの唯一のキーマップ。
212
+ *
213
+ * [移植時の修正] 以前はここ以外に
214
+ * - FrontendVisualEditor の window capture ハンドラ
215
+ * - useKeyboardShortcuts(iframeDoc) の独自 if 羅列
216
+ * という2系統の判定が併存していて、同じキーが二重発火したり
217
+ * (Cmd+D で複製が2個できる)、フォーカス位置で効くキーが入れ替わったりしていた。
218
+ * ツールキー・Cmd+A・Cmd+G・ズームまで全部この表に載せ、
219
+ * ディスパッチャ(useEditorShortcuts)1本だけがこの表を読む構成にしている。
220
+ */
221
+ export const KEYBOARD_SHORTCUTS: Record<string, ShortcutAction> = {
222
+ // Tool switching (single keys)
223
+ 'v': 'select',
224
+ 'k': 'scale', // 追加
225
+ 'h': 'move',
226
+ 'r': 'rectangle',
227
+ 'o': 'ellipse',
228
+ 'l': 'line',
229
+ 'shift+l': 'arrow',
230
+ 'p': 'pen',
231
+ 'e': 'eraser',
232
+ 'shift+p': 'pencil',
233
+ 't': 'text',
234
+ 'f': 'frame',
235
+
236
+ // Edit operations (Cmd/Ctrl + key)
237
+ 'meta+z': 'undo',
238
+ 'ctrl+z': 'undo',
239
+ 'meta+shift+z': 'redo',
240
+ 'ctrl+shift+z': 'redo',
241
+ 'meta+y': 'redo',
242
+ 'ctrl+y': 'redo',
243
+ 'meta+c': 'copy',
244
+ 'ctrl+c': 'copy',
245
+ 'meta+x': 'cut',
246
+ 'ctrl+x': 'cut',
247
+ 'meta+v': 'paste',
248
+ 'ctrl+v': 'paste',
249
+ 'meta+d': 'duplicate',
250
+ 'ctrl+d': 'duplicate',
251
+ 'delete': 'delete',
252
+ 'backspace': 'delete',
253
+
254
+ // Style operations
255
+ 'meta+alt+c': 'copyStyle',
256
+ 'ctrl+alt+c': 'copyStyle',
257
+ 'meta+alt+v': 'pasteStyle',
258
+ 'ctrl+alt+v': 'pasteStyle',
259
+
260
+ // Grouping
261
+ 'meta+g': 'group',
262
+ 'ctrl+g': 'group',
263
+ 'meta+shift+g': 'ungroup',
264
+ 'ctrl+shift+g': 'ungroup',
265
+
266
+ // Selection
267
+ 'meta+a': 'selectAll',
268
+ 'ctrl+a': 'selectAll',
269
+ 'escape': 'deselect',
270
+ // Tab で兄弟要素を順に選ぶ(Figma準拠)。ブラウザ既定のフォーカス移動より
271
+ // キャンバス上の選択移動のほうが期待される操作なので、こちらへ割り当てる
272
+ 'tab': 'selectNextSibling',
273
+ 'shift+tab': 'selectPrevSibling',
274
+
275
+ // Movement (arrow keys)
276
+ // リサイズ(Cmd/Ctrl+矢印)。→↓で広がり、←↑で縮む
277
+ 'meta+arrowright': 'resizeGrowX',
278
+ 'ctrl+arrowright': 'resizeGrowX',
279
+ 'meta+arrowleft': 'resizeShrinkX',
280
+ 'ctrl+arrowleft': 'resizeShrinkX',
281
+ 'meta+arrowdown': 'resizeGrowY',
282
+ 'ctrl+arrowdown': 'resizeGrowY',
283
+ 'meta+arrowup': 'resizeShrinkY',
284
+ 'ctrl+arrowup': 'resizeShrinkY',
285
+ 'meta+shift+arrowright': 'resizeGrowXLarge',
286
+ 'ctrl+shift+arrowright': 'resizeGrowXLarge',
287
+ 'meta+shift+arrowleft': 'resizeShrinkXLarge',
288
+ 'ctrl+shift+arrowleft': 'resizeShrinkXLarge',
289
+ 'meta+shift+arrowdown': 'resizeGrowYLarge',
290
+ 'ctrl+shift+arrowdown': 'resizeGrowYLarge',
291
+ 'meta+shift+arrowup': 'resizeShrinkYLarge',
292
+ 'ctrl+shift+arrowup': 'resizeShrinkYLarge',
293
+ 'arrowup': 'moveUp',
294
+ 'arrowdown': 'moveDown',
295
+ 'arrowleft': 'moveLeft',
296
+ 'arrowright': 'moveRight',
297
+ 'shift+arrowup': 'moveUpLarge',
298
+ 'shift+arrowdown': 'moveDownLarge',
299
+ 'shift+arrowleft': 'moveLeftLarge',
300
+ 'shift+arrowright': 'moveRightLarge',
301
+
302
+ // Figma形式でコピー
303
+ 'meta+shift+c': 'copyToFigma',
304
+ 'ctrl+shift+c': 'copyToFigma',
305
+
306
+ // Zoom(Figma準拠: 0=全体表示 / 1=100% / 2=選択範囲にズーム)
307
+ 'meta+0': 'zoomFit',
308
+ 'ctrl+0': 'zoomFit',
309
+ 'meta+1': 'zoomActual',
310
+ 'ctrl+1': 'zoomActual',
311
+ 'meta+2': 'zoomSelection',
312
+ 'ctrl+2': 'zoomSelection',
313
+
314
+ // Layer ordering
315
+ 'meta+]': 'bringForward',
316
+ 'ctrl+]': 'bringForward',
317
+ 'meta+[': 'sendBackward',
318
+ 'ctrl+[': 'sendBackward',
319
+ 'meta+shift+]': 'bringToFront',
320
+ 'ctrl+shift+]': 'bringToFront',
321
+ 'meta+shift+[': 'sendToBack',
322
+ 'ctrl+shift+[': 'sendToBack',
323
+ };
324
+
325
+ // Movement amounts in pixels
326
+ export const MOVEMENT_AMOUNTS = {
327
+ normal: 1,
328
+ large: 10,
329
+ };
330
+
331
+ // Maximum history stack size
332
+ export const MAX_HISTORY_SIZE = 50;
333
+
334
+ // Debounce delay for history saves (ms)
335
+ export const HISTORY_DEBOUNCE_MS = 300;
336
+
337
+ // Image fill modes (Figma-like)
338
+ export type ImageFillMode =
339
+ | 'fill' // 塗り - 要素全体を埋める(アスペクト比無視)
340
+ | 'fit' // 自動 - アスペクト比維持で収める(contain)
341
+ | 'crop' // トリミング - アスペクト比維持で埋める(cover)
342
+ | 'tile'; // タイル - 繰り返し
343
+
344
+ // Image fill settings
345
+ export interface ImageFillSettings {
346
+ url: string;
347
+ mode: ImageFillMode;
348
+ opacity: number; // 0-100
349
+ position: {
350
+ x: number; // -100 to 100 (percentage offset)
351
+ y: number; // -100 to 100 (percentage offset)
352
+ };
353
+ scale: number; // 1-500 (percentage)
354
+ rotation: number; // 0-360 degrees
355
+ }
356
+
357
+ // Element fill type
358
+ export type FillType = 'solid' | 'image' | 'gradient' | 'none';
359
+
360
+ // Element fill settings
361
+ export interface ElementFill {
362
+ type: FillType;
363
+ color?: string; // for solid
364
+ image?: ImageFillSettings; // for image
365
+ gradient?: {
366
+ type: 'linear' | 'radial';
367
+ angle: number;
368
+ stops: Array<{ color: string; position: number }>;
369
+ }; // for gradient
370
+ }
371
+
372
+ // Default image fill settings
373
+ export const DEFAULT_IMAGE_FILL: ImageFillSettings = {
374
+ url: '',
375
+ mode: 'crop',
376
+ opacity: 100,
377
+ position: { x: 0, y: 0 },
378
+ scale: 100,
379
+ rotation: 0,
380
+ };
381
+
382
+ // Default shape styles
383
+ export const DEFAULT_SHAPE_STYLES = {
384
+ rectangle: {
385
+ backgroundColor: '#3B82F6',
386
+ borderRadius: '4px',
387
+ },
388
+ ellipse: {
389
+ backgroundColor: '#3B82F6',
390
+ borderRadius: '50%',
391
+ },
392
+ line: {
393
+ stroke: '#1F2937',
394
+ strokeWidth: 2,
395
+ },
396
+ arrow: {
397
+ stroke: '#1F2937',
398
+ strokeWidth: 2,
399
+ },
400
+ text: {
401
+ fontSize: '16px',
402
+ color: '#1F2937',
403
+ fontFamily: 'inherit',
404
+ },
405
+ frame: {
406
+ backgroundColor: 'transparent',
407
+ border: '1px dashed #9CA3AF',
408
+ },
409
+ pen: {
410
+ stroke: '#1F2937',
411
+ strokeWidth: 2,
412
+ fill: 'none',
413
+ },
414
+ pencil: {
415
+ stroke: '#1F2937',
416
+ strokeWidth: 2,
417
+ fill: 'none',
418
+ },
419
+ scale: {},
420
+ };
@@ -0,0 +1,197 @@
1
+ import { Timestamp } from '../vendor/firebase-firestore';
2
+ import { PageCategory, SectionCategory, PageGenerationResult } from './website';
3
+
4
+ // =====================================================
5
+ // PageMaster(ページマスター/テンプレート)
6
+ // =====================================================
7
+
8
+ export interface PageMaster {
9
+ id: string;
10
+ name: string;
11
+ description: string;
12
+ category: SectionCategory; // セクション/コンポーネントの種類
13
+ userId: string;
14
+ isPublic?: boolean;
15
+ layout?: {
16
+ width: number;
17
+ minHeight: number;
18
+ sections: Array<{
19
+ type: 'header' | 'content' | 'footer' | 'sidebar' | 'hero' | 'cta';
20
+ position: { x: number; y: number; width: number; height: number };
21
+ styles?: Record<string, string>;
22
+ }>;
23
+ };
24
+ template: {
25
+ htmlTemplate: string;
26
+ cssClasses: string[];
27
+ variables?: Record<string, string>; // テンプレート変数
28
+ };
29
+ metadata: {
30
+ usageCount: number;
31
+ tags: string[];
32
+ author?: string;
33
+ version?: string;
34
+ rating?: number;
35
+ reviews?: unknown[];
36
+ };
37
+ // AI生成されたサンプルページ
38
+ generatedPage?: PageGenerationResult;
39
+ // 生成時のプロンプト情報(再生成用)
40
+ generationInfo?: {
41
+ prompt: string;
42
+ attachedFiles?: Array<{
43
+ name: string;
44
+ type: string;
45
+ size: number;
46
+ data: string;
47
+ }>;
48
+ modelName?: string;
49
+ };
50
+ createdAt: Timestamp;
51
+ updatedAt: Timestamp;
52
+ }
53
+
54
+ // =====================================================
55
+ // WebsiteMaster(Webサイトマスター/テンプレート)
56
+ // =====================================================
57
+
58
+ // Webサイトマスターのカテゴリ
59
+ export type WebsiteMasterCategory =
60
+ | 'landing' // ランディングページ
61
+ | 'corporate' // コーポレートサイト
62
+ | 'portfolio' // ポートフォリオ
63
+ | 'blog' // ブログ
64
+ | 'ecommerce' // ECサイト
65
+ | 'saas' // SaaSプロダクト
66
+ | 'agency' // エージェンシー
67
+ | 'other'; // その他
68
+
69
+ // Webサイトマスター内のページ定義
70
+ export interface WebsiteMasterPage {
71
+ id: string;
72
+ pageMasterId: string; // 参照するページマスターID
73
+ pageOrder: number; // ページ順序(1始まり)
74
+ title?: string; // カスタムタイトル(上書き用)
75
+ slug?: string; // カスタムスラッグ
76
+ notes?: string; // 生成時の指示メモ
77
+ overrides?: { // ページマスターからの上書き設定
78
+ category?: PageCategory;
79
+ variables?: Record<string, string>;
80
+ };
81
+ }
82
+
83
+ // Webサイトマスター
84
+ export interface WebsiteMaster {
85
+ id: string;
86
+ name: string; // 例: "SaaS LPテンプレート"
87
+ description: string;
88
+ category: WebsiteMasterCategory;
89
+ userId: string;
90
+ isPublic?: boolean;
91
+
92
+ // ページ構成(順序付きリスト)
93
+ pages: WebsiteMasterPage[];
94
+
95
+ settings: {
96
+ theme: 'light' | 'dark' | 'corporate' | 'modern';
97
+ primaryColor: string;
98
+ fontFamily: string;
99
+ };
100
+
101
+ metadata: {
102
+ usageCount: number;
103
+ tags: string[];
104
+ author?: string;
105
+ version?: string;
106
+ estimatedBuildTime?: number; // 推定構築時間(分)
107
+ };
108
+
109
+ // プレビュー用
110
+ preview?: {
111
+ thumbnailUrl?: string;
112
+ demoUrl?: string;
113
+ };
114
+
115
+ createdAt: Timestamp;
116
+ updatedAt: Timestamp;
117
+ }
118
+
119
+ // =====================================================
120
+ // 作成・更新用データ型
121
+ // =====================================================
122
+
123
+ export interface CreatePageMasterData {
124
+ name: string;
125
+ description: string;
126
+ category: SectionCategory;
127
+ layout?: PageMaster['layout'];
128
+ template: PageMaster['template'];
129
+ metadata?: Partial<PageMaster['metadata']>;
130
+ }
131
+
132
+ export interface UpdatePageMasterData {
133
+ name?: string;
134
+ description?: string;
135
+ category?: SectionCategory;
136
+ layout?: PageMaster['layout'];
137
+ template?: PageMaster['template'];
138
+ metadata?: Partial<PageMaster['metadata']>;
139
+ isPublic?: boolean;
140
+ }
141
+
142
+ export interface CreateWebsiteMasterData {
143
+ name: string;
144
+ description: string;
145
+ category: WebsiteMasterCategory;
146
+ pages: Omit<WebsiteMasterPage, 'id'>[];
147
+ settings?: Partial<WebsiteMaster['settings']>;
148
+ metadata?: Partial<WebsiteMaster['metadata']>;
149
+ }
150
+
151
+ export interface UpdateWebsiteMasterData {
152
+ name?: string;
153
+ description?: string;
154
+ category?: WebsiteMasterCategory;
155
+ pages?: WebsiteMasterPage[];
156
+ settings?: Partial<WebsiteMaster['settings']>;
157
+ metadata?: Partial<WebsiteMaster['metadata']>;
158
+ isPublic?: boolean;
159
+ }
160
+
161
+ // =====================================================
162
+ // フィルター用型
163
+ // =====================================================
164
+
165
+ export interface PageMasterFilter {
166
+ category?: SectionCategory;
167
+ userId?: string;
168
+ tags?: string[];
169
+ search?: string;
170
+ isPublic?: boolean;
171
+ }
172
+
173
+ export interface WebsiteMasterFilter {
174
+ category?: WebsiteMasterCategory;
175
+ userId?: string;
176
+ tags?: string[];
177
+ search?: string;
178
+ isPublic?: boolean;
179
+ }
180
+
181
+ // =====================================================
182
+ // ページマスター生成用型
183
+ // =====================================================
184
+
185
+ export interface PageMasterGenerationRequest {
186
+ name: string;
187
+ description: string;
188
+ category: SectionCategory;
189
+ samplePrompt: string; // サンプルページ生成用プロンプト
190
+ pageCount?: number; // 自動生成するサンプルページ数(デフォルト1枚)
191
+ attachedFiles?: Array<{
192
+ name: string;
193
+ type: string;
194
+ size: number;
195
+ data: string;
196
+ }>;
197
+ }