@growgroup/visual-editor 0.1.6 → 0.2.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.
- package/README.md +59 -2
- package/dist/editor.css +1 -1
- package/package.json +7 -3
- package/src/components/ui/alert-dialog.tsx +18 -4
- package/src/components/ui/context-menu.tsx +18 -4
- package/src/components/ui/dialog.tsx +19 -5
- package/src/components/ui/dropdown-menu.tsx +18 -4
- package/src/components/ui/popover.tsx +10 -2
- package/src/components/ui/select.tsx +10 -2
- package/src/components/ui/tooltip.tsx +10 -2
- package/src/editor/EditorToolbar.tsx +10 -20
- package/src/editor/FrontendVisualEditor.tsx +157 -43
- package/src/editor/components/EditorCanvas.tsx +1 -1
- package/src/editor/components/EditorContextMenu.tsx +53 -71
- package/src/editor/components/EditorFooter.tsx +36 -70
- package/src/editor/components/EditorHeader.tsx +37 -20
- package/src/editor/components/EditorLayerPanel.tsx +7 -9
- package/src/editor/components/EditorPropertyPanel.tsx +84 -8
- package/src/editor/components/LayerTreeItem.tsx +28 -5
- package/src/editor/components/component-panel/ComponentPanel.tsx +4 -3
- package/src/editor/components/ppt/PptChrome.tsx +156 -344
- package/src/editor/components/ppt/PptComments.tsx +135 -87
- package/src/editor/components/ppt/PptDesignProposals.tsx +21 -26
- package/src/editor/components/ppt/PptNotes.tsx +15 -15
- package/src/editor/components/shell/CanvasAppearance.tsx +19 -0
- package/src/editor/components/shell/ConfirmDialog.tsx +15 -0
- package/src/editor/components/shell/EditorTopBar.tsx +29 -68
- package/src/editor/components/shell/LeftPanel.tsx +20 -94
- package/src/editor/components/shell/PagesPanel.tsx +4 -2
- package/src/editor/contexts/EditorAppearanceContext.tsx +44 -0
- package/src/editor/contexts/EditorComponentsContext.tsx +278 -16
- package/src/editor/editor-skin.css +2 -122
- package/src/editor/hooks/useComponentEditMode.ts +93 -1
- package/src/editor/hooks/useIframeSetup.ts +10 -0
- package/src/editor/hooks/useMediaLibrary.ts +4 -5
- package/src/editor/hooks/useResizablePanel.ts +40 -11
- package/src/editor/parts.ts +321 -0
- package/src/editor/utils/dom-utils.ts +5 -4
- package/src/index.ts +25 -0
- package/src/io.ts +54 -0
- package/src/styles/skin.css +159 -0
- package/src/types/editor-components.ts +23 -1
|
@@ -4,6 +4,8 @@ import * as React from "react"
|
|
|
4
4
|
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
|
5
5
|
import { X } from "lucide-react"
|
|
6
6
|
|
|
7
|
+
import { useEditorAppearance } from "../../editor/contexts/EditorAppearanceContext"
|
|
8
|
+
|
|
7
9
|
import { cn } from "../../lib/utils"
|
|
8
10
|
|
|
9
11
|
const Dialog = DialogPrimitive.Root
|
|
@@ -17,27 +19,38 @@ const DialogClose = DialogPrimitive.Close
|
|
|
17
19
|
const DialogOverlay = React.forwardRef<
|
|
18
20
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
|
19
21
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
|
20
|
-
>(({ className, ...props }, ref) =>
|
|
22
|
+
>(({ className, ...props }, ref) => {
|
|
23
|
+
const appearance = useEditorAppearance();
|
|
24
|
+
return (
|
|
21
25
|
<DialogPrimitive.Overlay
|
|
26
|
+
data-editor-theme={appearance["data-editor-theme"]}
|
|
27
|
+
data-editor-surface="overlay"
|
|
22
28
|
ref={ref}
|
|
23
29
|
className={cn(
|
|
30
|
+
appearance.className,
|
|
24
31
|
"fixed inset-0 z-[100] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
25
32
|
className
|
|
26
33
|
)}
|
|
27
34
|
{...props}
|
|
28
35
|
/>
|
|
29
|
-
)
|
|
36
|
+
);
|
|
37
|
+
})
|
|
30
38
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
|
31
39
|
|
|
32
40
|
const DialogContent = React.forwardRef<
|
|
33
41
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
34
42
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
|
35
|
-
>(({ className, children, ...props }, ref) =>
|
|
43
|
+
>(({ className, children, ...props }, ref) => {
|
|
44
|
+
const appearance = useEditorAppearance();
|
|
45
|
+
return (
|
|
36
46
|
<DialogPortal>
|
|
37
47
|
<DialogOverlay />
|
|
38
48
|
<DialogPrimitive.Content
|
|
49
|
+
data-editor-theme={appearance["data-editor-theme"]}
|
|
50
|
+
data-editor-surface="dialog"
|
|
39
51
|
ref={ref}
|
|
40
52
|
className={cn(
|
|
53
|
+
appearance.className,
|
|
41
54
|
"fixed left-[50%] top-[50%] z-[100] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
|
42
55
|
className
|
|
43
56
|
)}
|
|
@@ -46,11 +59,12 @@ const DialogContent = React.forwardRef<
|
|
|
46
59
|
{children}
|
|
47
60
|
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
|
48
61
|
<X className="h-4 w-4" />
|
|
49
|
-
<span className="sr-only"
|
|
62
|
+
<span className="sr-only">閉じる</span>
|
|
50
63
|
</DialogPrimitive.Close>
|
|
51
64
|
</DialogPrimitive.Content>
|
|
52
65
|
</DialogPortal>
|
|
53
|
-
)
|
|
66
|
+
);
|
|
67
|
+
})
|
|
54
68
|
DialogContent.displayName = DialogPrimitive.Content.displayName
|
|
55
69
|
|
|
56
70
|
const DialogHeader = ({
|
|
@@ -4,6 +4,8 @@ import * as React from "react"
|
|
|
4
4
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
|
5
5
|
import { Check, ChevronRight, Circle } from "lucide-react"
|
|
6
6
|
|
|
7
|
+
import { useEditorAppearance } from "../../editor/contexts/EditorAppearanceContext"
|
|
8
|
+
|
|
7
9
|
import { cn } from "../../lib/utils"
|
|
8
10
|
|
|
9
11
|
const DropdownMenu = DropdownMenuPrimitive.Root
|
|
@@ -43,28 +45,39 @@ DropdownMenuSubTrigger.displayName =
|
|
|
43
45
|
const DropdownMenuSubContent = React.forwardRef<
|
|
44
46
|
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
|
45
47
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
|
46
|
-
>(({ className, ...props }, ref) =>
|
|
48
|
+
>(({ className, ...props }, ref) => {
|
|
49
|
+
const appearance = useEditorAppearance();
|
|
50
|
+
return (
|
|
47
51
|
<DropdownMenuPrimitive.SubContent
|
|
52
|
+
data-editor-theme={appearance["data-editor-theme"]}
|
|
53
|
+
data-editor-surface="popup"
|
|
48
54
|
ref={ref}
|
|
49
55
|
className={cn(
|
|
56
|
+
appearance.className,
|
|
50
57
|
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
51
58
|
className
|
|
52
59
|
)}
|
|
53
60
|
{...props}
|
|
54
61
|
/>
|
|
55
|
-
)
|
|
62
|
+
);
|
|
63
|
+
})
|
|
56
64
|
DropdownMenuSubContent.displayName =
|
|
57
65
|
DropdownMenuPrimitive.SubContent.displayName
|
|
58
66
|
|
|
59
67
|
const DropdownMenuContent = React.forwardRef<
|
|
60
68
|
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
|
61
69
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
|
62
|
-
>(({ className, sideOffset = 4, ...props }, ref) =>
|
|
70
|
+
>(({ className, sideOffset = 4, ...props }, ref) => {
|
|
71
|
+
const appearance = useEditorAppearance();
|
|
72
|
+
return (
|
|
63
73
|
<DropdownMenuPrimitive.Portal>
|
|
64
74
|
<DropdownMenuPrimitive.Content
|
|
75
|
+
data-editor-theme={appearance["data-editor-theme"]}
|
|
76
|
+
data-editor-surface="popup"
|
|
65
77
|
ref={ref}
|
|
66
78
|
sideOffset={sideOffset}
|
|
67
79
|
className={cn(
|
|
80
|
+
appearance.className,
|
|
68
81
|
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
|
|
69
82
|
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
70
83
|
className
|
|
@@ -72,7 +85,8 @@ const DropdownMenuContent = React.forwardRef<
|
|
|
72
85
|
{...props}
|
|
73
86
|
/>
|
|
74
87
|
</DropdownMenuPrimitive.Portal>
|
|
75
|
-
)
|
|
88
|
+
);
|
|
89
|
+
})
|
|
76
90
|
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
|
77
91
|
|
|
78
92
|
const DropdownMenuItem = React.forwardRef<
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import * as React from "react"
|
|
4
4
|
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
|
5
5
|
|
|
6
|
+
import { useEditorAppearance } from "../../editor/contexts/EditorAppearanceContext"
|
|
7
|
+
|
|
6
8
|
import { cn } from "../../lib/utils"
|
|
7
9
|
|
|
8
10
|
const Popover = PopoverPrimitive.Root
|
|
@@ -14,20 +16,26 @@ const PopoverAnchor = PopoverPrimitive.Anchor
|
|
|
14
16
|
const PopoverContent = React.forwardRef<
|
|
15
17
|
React.ElementRef<typeof PopoverPrimitive.Content>,
|
|
16
18
|
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
|
17
|
-
>(({ className, align = "center", sideOffset = 4, ...props }, ref) =>
|
|
19
|
+
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => {
|
|
20
|
+
const appearance = useEditorAppearance();
|
|
21
|
+
return (
|
|
18
22
|
<PopoverPrimitive.Portal>
|
|
19
23
|
<PopoverPrimitive.Content
|
|
24
|
+
data-editor-theme={appearance["data-editor-theme"]}
|
|
25
|
+
data-editor-surface="popup"
|
|
20
26
|
ref={ref}
|
|
21
27
|
align={align}
|
|
22
28
|
sideOffset={sideOffset}
|
|
23
29
|
className={cn(
|
|
30
|
+
appearance.className,
|
|
24
31
|
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",
|
|
25
32
|
className
|
|
26
33
|
)}
|
|
27
34
|
{...props}
|
|
28
35
|
/>
|
|
29
36
|
</PopoverPrimitive.Portal>
|
|
30
|
-
)
|
|
37
|
+
);
|
|
38
|
+
})
|
|
31
39
|
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
|
32
40
|
|
|
33
41
|
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
|
@@ -4,6 +4,8 @@ import * as React from "react"
|
|
|
4
4
|
import * as SelectPrimitive from "@radix-ui/react-select"
|
|
5
5
|
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
|
6
6
|
|
|
7
|
+
import { useEditorAppearance } from "../../editor/contexts/EditorAppearanceContext"
|
|
8
|
+
|
|
7
9
|
import { cn } from "../../lib/utils"
|
|
8
10
|
|
|
9
11
|
const Select = SelectPrimitive.Root
|
|
@@ -70,11 +72,16 @@ SelectScrollDownButton.displayName =
|
|
|
70
72
|
const SelectContent = React.forwardRef<
|
|
71
73
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
|
72
74
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
|
73
|
-
>(({ className, children, position = "popper", ...props }, ref) =>
|
|
75
|
+
>(({ className, children, position = "popper", ...props }, ref) => {
|
|
76
|
+
const appearance = useEditorAppearance();
|
|
77
|
+
return (
|
|
74
78
|
<SelectPrimitive.Portal>
|
|
75
79
|
<SelectPrimitive.Content
|
|
80
|
+
data-editor-theme={appearance["data-editor-theme"]}
|
|
81
|
+
data-editor-surface="popup"
|
|
76
82
|
ref={ref}
|
|
77
83
|
className={cn(
|
|
84
|
+
appearance.className,
|
|
78
85
|
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
|
|
79
86
|
position === "popper" &&
|
|
80
87
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
@@ -96,7 +103,8 @@ const SelectContent = React.forwardRef<
|
|
|
96
103
|
<SelectScrollDownButton />
|
|
97
104
|
</SelectPrimitive.Content>
|
|
98
105
|
</SelectPrimitive.Portal>
|
|
99
|
-
)
|
|
106
|
+
);
|
|
107
|
+
})
|
|
100
108
|
SelectContent.displayName = SelectPrimitive.Content.displayName
|
|
101
109
|
|
|
102
110
|
const SelectLabel = React.forwardRef<
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import * as React from "react"
|
|
4
4
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
|
|
5
5
|
|
|
6
|
+
import { useEditorAppearance } from "../../editor/contexts/EditorAppearanceContext"
|
|
7
|
+
|
|
6
8
|
import { cn } from "../../lib/utils"
|
|
7
9
|
|
|
8
10
|
const TooltipProvider = TooltipPrimitive.Provider
|
|
@@ -14,19 +16,25 @@ const TooltipTrigger = TooltipPrimitive.Trigger
|
|
|
14
16
|
const TooltipContent = React.forwardRef<
|
|
15
17
|
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
16
18
|
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
|
17
|
-
>(({ className, sideOffset = 4, ...props }, ref) =>
|
|
19
|
+
>(({ className, sideOffset = 4, ...props }, ref) => {
|
|
20
|
+
const appearance = useEditorAppearance();
|
|
21
|
+
return (
|
|
18
22
|
<TooltipPrimitive.Portal>
|
|
19
23
|
<TooltipPrimitive.Content
|
|
24
|
+
data-editor-theme={appearance["data-editor-theme"]}
|
|
25
|
+
data-editor-surface="tooltip"
|
|
20
26
|
ref={ref}
|
|
21
27
|
sideOffset={sideOffset}
|
|
22
28
|
className={cn(
|
|
29
|
+
appearance.className,
|
|
23
30
|
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
|
|
24
31
|
className
|
|
25
32
|
)}
|
|
26
33
|
{...props}
|
|
27
34
|
/>
|
|
28
35
|
</TooltipPrimitive.Portal>
|
|
29
|
-
)
|
|
36
|
+
);
|
|
37
|
+
})
|
|
30
38
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
|
31
39
|
|
|
32
40
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
|
@@ -232,7 +232,7 @@ export const EditorToolbar = memo(function EditorToolbar({
|
|
|
232
232
|
選択中の副次操作(重ね順・グループ)は…メニューへ畳む。配色もビューアに合わせる。
|
|
233
233
|
*/}
|
|
234
234
|
<div className="absolute bottom-5 left-1/2 z-50 max-w-[calc(100%-5rem)] -translate-x-1/2 px-0">
|
|
235
|
-
<div className="no-scrollbar flex items-center gap-
|
|
235
|
+
<div className="ed-toolbar no-scrollbar flex items-center gap-1 overflow-x-auto"
|
|
236
236
|
style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}>
|
|
237
237
|
{/* 取り消し/やり直し */}
|
|
238
238
|
<ActionButton icon={Undo2} onClick={onUndo} disabled={!canUndo} tooltip="元に戻す" shortcut={`${cmdKey}Z`} />
|
|
@@ -359,26 +359,16 @@ export const EditorToolbar = memo(function EditorToolbar({
|
|
|
359
359
|
</>
|
|
360
360
|
)}
|
|
361
361
|
|
|
362
|
-
{
|
|
363
|
-
{(onOpenVariables || onOpenComponents) && (
|
|
362
|
+
{(onOpenVariables || onOpenComponents) && <>
|
|
364
363
|
<Separator orientation="vertical" className="mx-1 h-6 bg-white/15" />
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
)}
|
|
374
|
-
{onOpenComponents && (
|
|
375
|
-
<ActionButton
|
|
376
|
-
icon={Component}
|
|
377
|
-
onClick={onOpenComponents}
|
|
378
|
-
tooltip="コンポーネント"
|
|
379
|
-
className={hasComponents ? 'text-sky-400' : undefined}
|
|
380
|
-
/>
|
|
381
|
-
)}
|
|
364
|
+
<DropdownMenu>
|
|
365
|
+
<DropdownMenuTrigger asChild><Button variant="ghost" size="sm" className="h-9 gap-2 px-2 text-xs"><Component className="h-4 w-4" />パネル<ChevronDown className="h-3 w-3" /></Button></DropdownMenuTrigger>
|
|
366
|
+
<DropdownMenuContent side="top" align="end" className="w-52">
|
|
367
|
+
{onOpenComponents && <DropdownMenuItem onSelect={onOpenComponents} className="gap-2"><Component className="h-4 w-4" />コンポーネント</DropdownMenuItem>}
|
|
368
|
+
{onOpenVariables && <DropdownMenuItem onSelect={onOpenVariables} className="gap-2"><Paintbrush className="h-4 w-4" />CSS変数</DropdownMenuItem>}
|
|
369
|
+
</DropdownMenuContent>
|
|
370
|
+
</DropdownMenu>
|
|
371
|
+
</>}
|
|
382
372
|
|
|
383
373
|
{/* 選択中のみ: よく使う3つを出し、残りは…メニュー */}
|
|
384
374
|
{selectedCount > 0 && (
|