@growgroup/visual-editor 0.3.1 → 0.4.1

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 (60) hide show
  1. package/README.md +6 -1
  2. package/dist/editor.css +1 -1
  3. package/package.json +1 -1
  4. package/src/editor/EditorContext.tsx +3 -2
  5. package/src/editor/EditorToolbar.tsx +8 -2
  6. package/src/editor/FrontendVisualEditor.tsx +123 -44
  7. package/src/editor/components/EditorCanvas.tsx +73 -15
  8. package/src/editor/components/EditorFooter.tsx +2 -0
  9. package/src/editor/components/EditorHeader.tsx +3 -2
  10. package/src/editor/components/FigmaColorPicker.tsx +2 -1
  11. package/src/editor/components/JsEditorDialog.tsx +1 -0
  12. package/src/editor/components/PageSettingsDialog.tsx +1 -0
  13. package/src/editor/components/comments/CommentBoard.tsx +9 -6
  14. package/src/editor/components/multi-page/CanvasFrameDecor.tsx +172 -0
  15. package/src/editor/components/multi-page/MultiPageCanvasView.tsx +179 -77
  16. package/src/editor/components/multi-page/PageFramePreview.tsx +99 -21
  17. package/src/editor/components/multi-page/index.ts +1 -0
  18. package/src/editor/components/ppt/PptChrome.tsx +6 -2
  19. package/src/editor/components/ppt/PptComments.tsx +411 -71
  20. package/src/editor/constants.ts +16 -1
  21. package/src/editor/contexts/EditorArtboardContext.tsx +8 -0
  22. package/src/editor/contexts/EditorComponentsContext.tsx +31 -27
  23. package/src/editor/contexts/EditorUIStateContext.tsx +4 -3
  24. package/src/editor/contexts/EditorVariablesContext.tsx +5 -4
  25. package/src/editor/contexts/MultiPageCanvasContext.tsx +194 -26
  26. package/src/editor/hooks/useAiReplace.ts +4 -3
  27. package/src/editor/hooks/useBrowserZoomPrevention.ts +2 -1
  28. package/src/editor/hooks/useComponentEditMode.ts +27 -26
  29. package/src/editor/hooks/useEditorMessages.ts +3 -2
  30. package/src/editor/hooks/useElementActions.ts +27 -26
  31. package/src/editor/hooks/useElementSelection.ts +19 -16
  32. package/src/editor/hooks/useFocusManagement.ts +7 -6
  33. package/src/editor/hooks/useGoogleFonts.ts +3 -2
  34. package/src/editor/hooks/useIframeInitializer.ts +6 -3
  35. package/src/editor/hooks/useIframeSetup.ts +4 -3
  36. package/src/editor/hooks/useImageUpload.ts +4 -3
  37. package/src/editor/hooks/useMarqueeSelection.ts +2 -1
  38. package/src/editor/hooks/usePageSettingsManager.ts +24 -23
  39. package/src/editor/hooks/useRichPaste.ts +11 -10
  40. package/src/editor/parts.ts +7 -25
  41. package/src/editor/utils/component-renderer.ts +8 -7
  42. package/src/editor/utils/component-sync.ts +16 -15
  43. package/src/editor/utils/debug.ts +52 -0
  44. package/src/editor/utils/dom-utils.ts +43 -11
  45. package/src/editor/utils/drop-target.ts +135 -0
  46. package/src/editor/utils/eyedropper.ts +3 -1
  47. package/src/editor/utils/figma-export.ts +6 -5
  48. package/src/editor/utils/figma-kiwi-decoder.ts +28 -27
  49. package/src/editor/utils/figma-kiwi-encoder.ts +9 -8
  50. package/src/editor/utils/figma-paste.ts +57 -56
  51. package/src/editor/utils/flex-utils.ts +12 -10
  52. package/src/editor/utils/override-apply.ts +3 -2
  53. package/src/editor/utils/override-detection.ts +11 -10
  54. package/src/editor/utils/tailwind-utils.ts +4 -3
  55. package/src/io.ts +22 -1
  56. package/src/lib/firebase/css-variables.ts +4 -3
  57. package/src/lib/firebase/storage.ts +3 -2
  58. package/src/styles/skin.css +9 -4
  59. package/src/types/editor.ts +6 -2
  60. package/src/version.ts +1 -1
package/src/io.ts CHANGED
@@ -36,15 +36,36 @@ export type EditorContent = {
36
36
  comments?: EditorComment[];
37
37
  };
38
38
 
39
+ /**
40
+ * 範囲アンカー。紙面(`#artboard`)の左上を原点にした px。
41
+ * `ref` は投稿したときの紙面の大きさ。紙面の幅が変わったら(ノート欄の有無など)
42
+ * 横方向だけ幅の比で補正する。縦は内容が増減すると動くので補正しない。
43
+ * width / height が 0 のときは「点」(クリックで置いたピン)。
44
+ */
45
+ export type CommentRect = {
46
+ x: number;
47
+ y: number;
48
+ width: number;
49
+ height: number;
50
+ ref?: { width: number; height: number };
51
+ };
52
+
39
53
  export type EditorComment = {
40
54
  id: string;
41
55
  author: string;
42
56
  text: string;
43
57
  createdAt: string;
44
58
  resolved?: boolean;
59
+ /**
60
+ * ページ内の通し番号(投稿順)。削除しても振り直さないので、返信で「#3 の件」と
61
+ * 書いても指す先が変わらない。ホストが採番する(無いホストでは付かない)
62
+ */
63
+ seq?: number;
45
64
  /** 要素アンカー。無ければ全体へのコメント */
46
65
  anchorSrc?: string;
47
66
  anchorLabel?: string;
67
+ /** 範囲アンカー(紙面の px)。要素アンカーより優先して表示する */
68
+ anchorRect?: CommentRect;
48
69
  replies?: { id: string; author: string; text: string; createdAt: string }[];
49
70
  };
50
71
 
@@ -55,7 +76,7 @@ export type EditorDeck = {
55
76
  };
56
77
 
57
78
  export type CommentAction =
58
- | { action: "add"; author: string; text: string; anchorSrc?: string; anchorLabel?: string }
79
+ | { action: "add"; author: string; text: string; anchorSrc?: string; anchorLabel?: string; anchorRect?: CommentRect }
59
80
  | { action: "reply"; commentId: string; author: string; text: string }
60
81
  | { action: "resolve"; commentId: string; resolved: boolean }
61
82
  | { action: "delete"; commentId: string };
@@ -17,6 +17,7 @@ import type {
17
17
  CSSVariableDefinition,
18
18
  CSSVariableCollection,
19
19
  } from '../../types/css-variables';
20
+ import { debugLog } from '../../editor/utils/debug';
20
21
 
21
22
  // ============================================
22
23
  // スコープタイプ定義
@@ -184,7 +185,7 @@ export async function getCSSVariables(
184
185
  const data = readDoc(key);
185
186
 
186
187
  if (!data) {
187
- console.log(`[CSSVariables] No variables found for ${scope}:`, resourceId);
188
+ debugLog(`[CSSVariables] No variables found for ${scope}:`, resourceId);
188
189
  return null;
189
190
  }
190
191
 
@@ -240,7 +241,7 @@ export async function saveCSSVariables(
240
241
  };
241
242
 
242
243
  writeDoc(key, data);
243
- console.log(`[CSSVariables] Saved variables for ${scope}:`, resourceId, 'count:', variables.length);
244
+ debugLog(`[CSSVariables] Saved variables for ${scope}:`, resourceId, 'count:', variables.length);
244
245
  } catch (error) {
245
246
  console.error('[CSSVariables] Error saving variables:', error);
246
247
  throw error;
@@ -298,7 +299,7 @@ export async function deleteCSSVariablesCollection(websiteId: string): Promise<v
298
299
  const key = getCSSVariablesKey(websiteId);
299
300
  const store = getStore();
300
301
  if (store) store.removeItem(key);
301
- console.log('[CSSVariables] Deleted variables for website:', websiteId);
302
+ debugLog('[CSSVariables] Deleted variables for website:', websiteId);
302
303
  } catch (error) {
303
304
  console.error('[CSSVariables] Error deleting variables:', error);
304
305
  throw error;
@@ -42,6 +42,7 @@ async function persistDataUrl(dataUrl: string, fileName: string): Promise<string
42
42
  }
43
43
 
44
44
  import type { PageResourceUpload } from '../../types/page';
45
+ import { debugLog } from '../../editor/utils/debug';
45
46
 
46
47
  // ============================================
47
48
  // 内部ヘルパー
@@ -161,7 +162,7 @@ export async function uploadPageResource(
161
162
 
162
163
  // ファイル削除(ローカルではリモート実体が無いため no-op)
163
164
  export async function deletePageResource(storagePath: string): Promise<void> {
164
- console.log('[storage] deletePageResource is a no-op in local mode:', storagePath);
165
+ debugLog('[storage] deletePageResource is a no-op in local mode:', storagePath);
165
166
  }
166
167
 
167
168
  // ファイル情報取得(ローカルではメタデータを保持しないためスタブを返す)
@@ -264,7 +265,7 @@ export async function uploadFigmaImage(
264
265
  // コンポーネントの画像ファイルを削除(ローカルでは no-op)
265
266
  export async function deleteFigmaComponentImages(componentId: string): Promise<void> {
266
267
  const basePath = `components/${componentId}/figma-images/`;
267
- console.log(`[storage] deleteFigmaComponentImages is a no-op in local mode: ${basePath}`);
268
+ debugLog(`[storage] deleteFigmaComponentImages is a no-op in local mode: ${basePath}`);
268
269
  }
269
270
 
270
271
  // 画像ファイルサイズの推定(Base64から)
@@ -325,8 +325,12 @@
325
325
  .gg-editor-ui :is(input:not([type="color"]), textarea, select):not([data-editor-preview] *) { border-color: var(--ed-line-strong) !important; }
326
326
 
327
327
  /* ── マルチフレームのキャンバス(Figma 風) ──────────────
328
- フレーム名とリングは画面座標に置く(倍率に関係なく同じ太さ・同じ文字サイズ)。
328
+ フレーム名とリングはオーバーレイの中で scale(1/倍率) を掛けて画面上の大きさに戻す
329
+ (倍率に関係なく同じ太さ・同じ文字サイズ)。
329
330
  見るだけの紙面の骨組み(スケルトン)だけは転写層の中にあるので、フレームの寸法に対する % で描く */
331
+ /* フレームの白地だけ。枠線と階層の線は画面の座標の canvas(CanvasFrameDecor)が描く。
332
+ 転写層の中に枠線を持たせると、倍率が変わるたびに転写層まるごとが塗り直される(実測) */
333
+ .gg-editor-ui .ed-frame-shell { background: #fff; }
330
334
  .gg-editor-ui .ed-frame-label-row { position: absolute; left: 0; height: 20px; display: inline-flex; align-items: center; gap: 2px; max-width: 100%; }
331
335
  .gg-editor-ui .ed-frame-label {
332
336
  height: 20px; min-width: 0; display: inline-flex; align-items: center; gap: 6px;
@@ -341,9 +345,6 @@
341
345
  .gg-editor-ui .ed-frame-label-link svg { width: 12px; height: 12px; }
342
346
  .gg-editor-ui .ed-frame-label-row:hover .ed-frame-label-link, .gg-editor-ui .ed-frame-label-active + .ed-frame-label-link, .gg-editor-ui .ed-frame-label-link:focus-visible { opacity: 1; }
343
347
  .gg-editor-ui .ed-frame-label-link:hover { color: var(--ed-text); background: var(--ed-panel); box-shadow: 0 0 0 1px var(--ed-line); }
344
- /* 階層の線(ツリー配置)。転写層の中にあるが、線の太さは non-scaling-stroke で画面上 1.5px */
345
- .gg-editor-ui .ed-frame-connectors { position: absolute; left: 0; top: 0; pointer-events: none; overflow: visible; }
346
- .gg-editor-ui .ed-frame-connectors path { stroke: var(--ed-line-strong); stroke-width: 1.5px; stroke-linejoin: round; }
347
348
  /* 部品(data-part)のカード。紙面の紫の選択枠と同じ色 */
348
349
  .gg-editor-ui .ed-part-card { border: 1px solid color-mix(in srgb, #7b61ff 45%, var(--ed-line)); background: color-mix(in srgb, #7b61ff 8%, var(--ed-panel)); color: var(--ed-text); }
349
350
  .gg-editor-ui .ed-part-accent { color: #7b61ff; }
@@ -360,6 +361,10 @@
360
361
  .gg-editor-ui .ed-canvas-marquee { position: absolute; z-index: 20; pointer-events: none; border: 1px solid var(--ed-accent); background: color-mix(in srgb, var(--ed-accent) 12%, transparent); }
361
362
  .gg-editor-ui .ed-frame-ring-active { box-shadow: 0 0 0 1.5px var(--ed-accent-strong); }
362
363
  .gg-editor-ui .ed-frame-ring-hover { box-shadow: 0 0 0 1px var(--ed-accent-strong); opacity: 0.55; }
364
+ /* 縮小の途中(倍率 0.4 未満)は、画像が読めている紙面の iframe を止めて、下に敷いた画像を見せる。
365
+ iframe を外して(メモリを返して)しまうのは操作が止まってから ── その間もラスタは止まっている。
366
+ 属性 1 つ(キャンバスの容器の data-canvas-preview-image)の書き換えで 26 枚がいっぺんに切り替わる */
367
+ .gg-editor-ui [data-canvas-preview-image="1"] [data-page-preview][data-image-ready="1"] iframe { visibility: hidden; }
363
368
  .gg-editor-ui .ed-frame-skeleton { position: absolute; inset: 0; padding: 6% 8%; display: flex; flex-direction: column; gap: 3%; background: #fff; }
364
369
  .gg-editor-ui .ed-frame-skeleton-bar { display: block; height: 2.5%; min-height: 8px; border-radius: 999px; background: #eceff3; }
365
370
  .gg-editor-ui .ed-frame-skeleton-note { font-size: 40px; color: #9aa3b2; }
@@ -16,7 +16,8 @@ export type EditorTool =
16
16
  | 'text' // T - Text tool
17
17
  | 'scale' // K - Scale tool
18
18
  | 'eraser' // E - Eraser (ペン/鉛筆ストロークを消す)
19
- | 'shape'; // 図形ギャラリーで選んだ図形(ドラッグでサイズ指定)
19
+ | 'shape' // 図形ギャラリーで選んだ図形(ドラッグでサイズ指定)
20
+ | 'comment'; // C - コメント(紙面をドラッグして範囲を指定。クリックで点)
20
21
 
21
22
  // Shape types that can be drawn
22
23
  export type ShapeType = 'rectangle' | 'ellipse' | 'line' | 'arrow' | 'text' | 'pen' | 'pencil' | 'frame';
@@ -101,6 +102,7 @@ export type ShortcutAction =
101
102
  | 'text'
102
103
  | 'frame'
103
104
  | 'scale'
105
+ | 'comment'
104
106
  // Edit operations
105
107
  | 'undo'
106
108
  | 'redo'
@@ -189,7 +191,7 @@ export interface ToolConfig {
189
191
  label: string;
190
192
  shortcut: string;
191
193
  icon: string; // Lucide icon name
192
- group: 'selection' | 'shapes' | 'drawing' | 'text' | 'frame';
194
+ group: 'selection' | 'shapes' | 'drawing' | 'text' | 'frame' | 'comment';
193
195
  }
194
196
 
195
197
  // Default tool configurations
@@ -205,6 +207,7 @@ export const TOOL_CONFIGS: ToolConfig[] = [
205
207
  { id: 'pen', label: 'ペン', shortcut: 'P', icon: 'Pen', group: 'drawing' },
206
208
  { id: 'pencil', label: 'フリーハンド', shortcut: '⇧P', icon: 'Pencil', group: 'drawing' },
207
209
  { id: 'text', label: 'テキスト', shortcut: 'T', icon: 'Type', group: 'text' },
210
+ { id: 'comment', label: 'コメント(範囲を指定)', shortcut: 'C', icon: 'MessageSquare', group: 'comment' },
208
211
  ];
209
212
 
210
213
  /**
@@ -232,6 +235,7 @@ export const KEYBOARD_SHORTCUTS: Record<string, ShortcutAction> = {
232
235
  'shift+p': 'pencil',
233
236
  't': 'text',
234
237
  'f': 'frame',
238
+ 'c': 'comment',
235
239
 
236
240
  // Edit operations (Cmd/Ctrl + key)
237
241
  'meta+z': 'undo',
package/src/version.ts CHANGED
@@ -6,4 +6,4 @@
6
6
  * 利用側はこの値と node_modules の package.json を見比べて、食い違っていれば
7
7
  * 「再起動してください」と出せる(構成ラフのテンプレートが行っている)
8
8
  */
9
- export const EDITOR_VERSION = '0.3.1';
9
+ export const EDITOR_VERSION = '0.4.1';