@alpaca-editor/core 1.0.3959 → 1.0.3962
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/dist/components/FilterInput.d.ts +21 -0
- package/dist/components/FilterInput.js +33 -0
- package/dist/components/FilterInput.js.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -0
- package/dist/config/config.js +4 -2
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +1 -1
- package/dist/editor/ContextMenu.js +1 -1
- package/dist/editor/ContextMenu.js.map +1 -1
- package/dist/editor/FieldList.js +2 -3
- package/dist/editor/FieldList.js.map +1 -1
- package/dist/editor/ImageEditButton.d.ts +26 -0
- package/dist/editor/ImageEditButton.js +15 -0
- package/dist/editor/ImageEditButton.js.map +1 -0
- package/dist/editor/ImageEditor.js +25 -21
- package/dist/editor/ImageEditor.js.map +1 -1
- package/dist/editor/ItemInfo.js +1 -1
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/MainLayout.js +1 -1
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/MobileLayout.js +1 -1
- package/dist/editor/MobileLayout.js.map +1 -1
- package/dist/editor/PictureEditor.js +60 -36
- package/dist/editor/PictureEditor.js.map +1 -1
- package/dist/editor/client/EditorClient.js +7 -8
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/context-menu/InsertMenu.js +3 -5
- package/dist/editor/context-menu/InsertMenu.js.map +1 -1
- package/dist/editor/field-types/DropListEditor.js +1 -1
- package/dist/editor/field-types/DropListEditor.js.map +1 -1
- package/dist/editor/menubar/VersionSelector.js +8 -8
- package/dist/editor/menubar/VersionSelector.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +1 -1
- package/dist/editor/page-viewer/PageViewer.js +7 -2
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/sidebar/ComponentPalette.js +3 -5
- package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
- package/dist/editor/sidebar/Insert.js +1 -1
- package/dist/editor/sidebar/Insert.js.map +1 -1
- package/dist/editor/sidebar/SidebarView.js +1 -1
- package/dist/editor/sidebar/SidebarView.js.map +1 -1
- package/dist/editor/ui/Icons.d.ts +3 -0
- package/dist/editor/ui/Icons.js +4 -1
- package/dist/editor/ui/Icons.js.map +1 -1
- package/dist/editor/ui/ItemSearch.js +3 -4
- package/dist/editor/ui/ItemSearch.js.map +1 -1
- package/dist/editor/ui/SimpleTabs.js +2 -2
- package/dist/editor/ui/SimpleTabs.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +25 -18
- package/package.json +1 -1
- package/src/components/FilterInput.tsx +102 -0
- package/src/components/index.ts +2 -0
- package/src/config/config.tsx +4 -2
- package/src/config/types.ts +2 -1
- package/src/editor/ContextMenu.tsx +1 -3
- package/src/editor/FieldList.tsx +6 -15
- package/src/editor/ImageEditButton.tsx +78 -0
- package/src/editor/ImageEditor.tsx +43 -91
- package/src/editor/ItemInfo.tsx +1 -1
- package/src/editor/MainLayout.tsx +2 -2
- package/src/editor/MobileLayout.tsx +1 -1
- package/src/editor/PictureEditor.tsx +60 -134
- package/src/editor/client/EditorClient.tsx +8 -8
- package/src/editor/context-menu/InsertMenu.tsx +5 -14
- package/src/editor/field-types/DropListEditor.tsx +1 -1
- package/src/editor/menubar/VersionSelector.tsx +28 -28
- package/src/editor/page-editor-chrome/FrameMenu.tsx +3 -3
- package/src/editor/page-viewer/PageViewer.tsx +8 -4
- package/src/editor/page-viewer/PageViewerFrame.tsx +1 -1
- package/src/editor/sidebar/ComponentPalette.tsx +9 -32
- package/src/editor/sidebar/Insert.tsx +1 -1
- package/src/editor/sidebar/SidebarView.tsx +2 -2
- package/src/editor/ui/Icons.tsx +23 -0
- package/src/editor/ui/ItemSearch.tsx +10 -23
- package/src/editor/ui/SimpleTabs.tsx +3 -3
- package/src/revision.ts +2 -2
package/dist/styles.css
CHANGED
|
@@ -232,6 +232,9 @@
|
|
|
232
232
|
.right-1 {
|
|
233
233
|
right: calc(var(--spacing) * 1);
|
|
234
234
|
}
|
|
235
|
+
.right-1\.5 {
|
|
236
|
+
right: calc(var(--spacing) * 1.5);
|
|
237
|
+
}
|
|
235
238
|
.right-2 {
|
|
236
239
|
right: calc(var(--spacing) * 2);
|
|
237
240
|
}
|
|
@@ -385,6 +388,9 @@
|
|
|
385
388
|
.mt-auto {
|
|
386
389
|
margin-top: auto;
|
|
387
390
|
}
|
|
391
|
+
.-mr-2 {
|
|
392
|
+
margin-right: calc(var(--spacing) * -2);
|
|
393
|
+
}
|
|
388
394
|
.mr-1 {
|
|
389
395
|
margin-right: calc(var(--spacing) * 1);
|
|
390
396
|
}
|
|
@@ -421,9 +427,6 @@
|
|
|
421
427
|
.mb-\[-3px\] {
|
|
422
428
|
margin-bottom: -3px;
|
|
423
429
|
}
|
|
424
|
-
.-ml-1 {
|
|
425
|
-
margin-left: calc(var(--spacing) * -1);
|
|
426
|
-
}
|
|
427
430
|
.ml-0\.5 {
|
|
428
431
|
margin-left: calc(var(--spacing) * 0.5);
|
|
429
432
|
}
|
|
@@ -619,6 +622,9 @@
|
|
|
619
622
|
.max-h-96 {
|
|
620
623
|
max-height: calc(var(--spacing) * 96);
|
|
621
624
|
}
|
|
625
|
+
.max-h-\[30vh\] {
|
|
626
|
+
max-height: 30vh;
|
|
627
|
+
}
|
|
622
628
|
.max-h-\[45vh\] {
|
|
623
629
|
max-height: 45vh;
|
|
624
630
|
}
|
|
@@ -826,6 +832,9 @@
|
|
|
826
832
|
.flex-2 {
|
|
827
833
|
flex: 2;
|
|
828
834
|
}
|
|
835
|
+
.flex-shrink {
|
|
836
|
+
flex-shrink: 1;
|
|
837
|
+
}
|
|
829
838
|
.flex-shrink-0 {
|
|
830
839
|
flex-shrink: 0;
|
|
831
840
|
}
|
|
@@ -1169,9 +1178,9 @@
|
|
|
1169
1178
|
border-top-left-radius: 0.25rem;
|
|
1170
1179
|
border-top-right-radius: 0.25rem;
|
|
1171
1180
|
}
|
|
1172
|
-
.rounded-t-
|
|
1173
|
-
border-top-left-radius:
|
|
1174
|
-
border-top-right-radius:
|
|
1181
|
+
.rounded-t-xs {
|
|
1182
|
+
border-top-left-radius: var(--radius-xs);
|
|
1183
|
+
border-top-right-radius: var(--radius-xs);
|
|
1175
1184
|
}
|
|
1176
1185
|
.rounded-l-full {
|
|
1177
1186
|
border-top-left-radius: calc(infinity * 1px);
|
|
@@ -1180,12 +1189,12 @@
|
|
|
1180
1189
|
.rounded-tl-2xl {
|
|
1181
1190
|
border-top-left-radius: var(--radius-2xl);
|
|
1182
1191
|
}
|
|
1183
|
-
.rounded-tl-
|
|
1184
|
-
border-top-left-radius:
|
|
1192
|
+
.rounded-tl-xs {
|
|
1193
|
+
border-top-left-radius: var(--radius-xs);
|
|
1185
1194
|
}
|
|
1186
|
-
.rounded-b-
|
|
1187
|
-
border-bottom-right-radius:
|
|
1188
|
-
border-bottom-left-radius:
|
|
1195
|
+
.rounded-b-xs {
|
|
1196
|
+
border-bottom-right-radius: var(--radius-xs);
|
|
1197
|
+
border-bottom-left-radius: var(--radius-xs);
|
|
1189
1198
|
}
|
|
1190
1199
|
.rounded-bl {
|
|
1191
1200
|
border-bottom-left-radius: 0.25rem;
|
|
@@ -1210,10 +1219,6 @@
|
|
|
1210
1219
|
border-inline-style: var(--tw-border-style);
|
|
1211
1220
|
border-inline-width: 1px;
|
|
1212
1221
|
}
|
|
1213
|
-
.border-y {
|
|
1214
|
-
border-block-style: var(--tw-border-style);
|
|
1215
|
-
border-block-width: 1px;
|
|
1216
|
-
}
|
|
1217
1222
|
.border-t {
|
|
1218
1223
|
border-top-style: var(--tw-border-style);
|
|
1219
1224
|
border-top-width: 1px;
|
|
@@ -1704,9 +1709,6 @@
|
|
|
1704
1709
|
.pb-6 {
|
|
1705
1710
|
padding-bottom: calc(var(--spacing) * 6);
|
|
1706
1711
|
}
|
|
1707
|
-
.pl-1 {
|
|
1708
|
-
padding-left: calc(var(--spacing) * 1);
|
|
1709
|
-
}
|
|
1710
1712
|
.pl-1\.5 {
|
|
1711
1713
|
padding-left: calc(var(--spacing) * 1.5);
|
|
1712
1714
|
}
|
|
@@ -3048,6 +3050,11 @@
|
|
|
3048
3050
|
width: 4px;
|
|
3049
3051
|
}
|
|
3050
3052
|
}
|
|
3053
|
+
.md\:w-\[8px\] {
|
|
3054
|
+
@media (width >= 48rem) {
|
|
3055
|
+
width: 8px;
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3051
3058
|
.md\:w-auto {
|
|
3052
3059
|
@media (width >= 48rem) {
|
|
3053
3060
|
width: auto;
|
package/package.json
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { InputText } from "primereact/inputtext";
|
|
2
|
+
import { ProgressSpinner } from "primereact/progressspinner";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
import { cn } from "../lib/utils";
|
|
5
|
+
|
|
6
|
+
export interface FilterInputProps {
|
|
7
|
+
value: string;
|
|
8
|
+
onChange: (value: string) => void;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
showSearchIcon?: boolean;
|
|
12
|
+
showClearIcon?: boolean;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
autoFocus?: boolean;
|
|
15
|
+
loading?: boolean;
|
|
16
|
+
spinnerStyle?: React.CSSProperties;
|
|
17
|
+
onClear?: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const FilterInput = forwardRef<HTMLInputElement, FilterInputProps>(
|
|
21
|
+
(
|
|
22
|
+
{
|
|
23
|
+
value,
|
|
24
|
+
onChange,
|
|
25
|
+
placeholder = "Filter...",
|
|
26
|
+
className,
|
|
27
|
+
showSearchIcon = true,
|
|
28
|
+
showClearIcon = true,
|
|
29
|
+
disabled = false,
|
|
30
|
+
autoFocus = false,
|
|
31
|
+
loading = false,
|
|
32
|
+
spinnerStyle,
|
|
33
|
+
onClear,
|
|
34
|
+
},
|
|
35
|
+
ref,
|
|
36
|
+
) => {
|
|
37
|
+
const handleClear = () => {
|
|
38
|
+
onChange("");
|
|
39
|
+
if (onClear) {
|
|
40
|
+
onClear();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className={cn("relative flex items-center", className)}>
|
|
46
|
+
<InputText
|
|
47
|
+
ref={ref}
|
|
48
|
+
type="text"
|
|
49
|
+
value={value}
|
|
50
|
+
onChange={(e) => onChange(e.target.value)}
|
|
51
|
+
className="border-gray-3 w-full rounded border px-2 py-1 pr-6 text-xs focus:ring-1 focus:outline-none"
|
|
52
|
+
placeholder={placeholder}
|
|
53
|
+
disabled={disabled}
|
|
54
|
+
autoFocus={autoFocus}
|
|
55
|
+
/>
|
|
56
|
+
{loading && (
|
|
57
|
+
<ProgressSpinner
|
|
58
|
+
className="absolute right-1.5"
|
|
59
|
+
style={{
|
|
60
|
+
width: "18px",
|
|
61
|
+
height: "18px",
|
|
62
|
+
...spinnerStyle,
|
|
63
|
+
}}
|
|
64
|
+
/>
|
|
65
|
+
)}
|
|
66
|
+
{!loading && !value && showSearchIcon && (
|
|
67
|
+
<i className="pi pi-search absolute right-2 text-xs text-gray-400" />
|
|
68
|
+
)}
|
|
69
|
+
{!loading && value && showClearIcon && (
|
|
70
|
+
<i
|
|
71
|
+
className="pi pi-times absolute right-2 cursor-pointer text-xs text-gray-400 hover:text-gray-600"
|
|
72
|
+
onClick={handleClear}
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
FilterInput.displayName = "FilterInput";
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Utility function to highlight matching text in search results
|
|
84
|
+
* @param text - The text to highlight
|
|
85
|
+
* @param filter - The filter string to match
|
|
86
|
+
* @returns JSX elements with highlighted matches
|
|
87
|
+
*/
|
|
88
|
+
export const highlightMatch = (text: string, filter: string) => {
|
|
89
|
+
if (!filter.trim()) return text;
|
|
90
|
+
|
|
91
|
+
return text
|
|
92
|
+
.split(new RegExp(`(${filter})`, "i"))
|
|
93
|
+
.map((part: string, i: number) =>
|
|
94
|
+
part.toLowerCase() === filter.toLowerCase() && part ? (
|
|
95
|
+
<u className="font-bold" key={i}>
|
|
96
|
+
{part}
|
|
97
|
+
</u>
|
|
98
|
+
) : (
|
|
99
|
+
part && <span key={i}>{part}</span>
|
|
100
|
+
),
|
|
101
|
+
);
|
|
102
|
+
};
|
package/src/config/config.tsx
CHANGED
|
@@ -188,6 +188,7 @@ const pageEditorViewBase = {
|
|
|
188
188
|
toolbar: editToolbar,
|
|
189
189
|
rightSidebar: pageEditorRightSidebar,
|
|
190
190
|
defaultCenterPanelView: editView,
|
|
191
|
+
titlebar: <Titlebar />,
|
|
191
192
|
};
|
|
192
193
|
|
|
193
194
|
export const getConfiguration = (): EditorConfiguration => {
|
|
@@ -567,6 +568,7 @@ export const getConfiguration = (): EditorConfiguration => {
|
|
|
567
568
|
},
|
|
568
569
|
rightSidebar: pageEditorRightSidebar,
|
|
569
570
|
toolbar: editToolbar,
|
|
571
|
+
titlebar: <Titlebar />,
|
|
570
572
|
},
|
|
571
573
|
|
|
572
574
|
{
|
|
@@ -607,7 +609,8 @@ export const getConfiguration = (): EditorConfiguration => {
|
|
|
607
609
|
name: "debug",
|
|
608
610
|
title: "Debug",
|
|
609
611
|
icon: <Bug strokeWidth={1} />,
|
|
610
|
-
|
|
612
|
+
titlebar: <Titlebar />,
|
|
613
|
+
toolbar: <PageViewerControls />,
|
|
611
614
|
leftSidebar: {
|
|
612
615
|
panels: [
|
|
613
616
|
{
|
|
@@ -713,7 +716,6 @@ export const getConfiguration = (): EditorConfiguration => {
|
|
|
713
716
|
},
|
|
714
717
|
],
|
|
715
718
|
|
|
716
|
-
titlebar: <Titlebar />,
|
|
717
719
|
itemActionsMenu: {
|
|
718
720
|
itemsFactory: (editContext: EditContextType): MenuItemGroup[] => {
|
|
719
721
|
const groups: MenuItemGroup[] = [];
|
package/src/config/types.ts
CHANGED
|
@@ -84,6 +84,7 @@ export type EditorView = {
|
|
|
84
84
|
visible?: (editContext: EditContextType) => boolean;
|
|
85
85
|
beforeClose?: (editContext: EditContextType) => Promise<boolean>;
|
|
86
86
|
headerTitle?: (editContext: EditContextType) => string;
|
|
87
|
+
titlebar?: ReactNode;
|
|
87
88
|
};
|
|
88
89
|
|
|
89
90
|
export type ViewPanel = {
|
|
@@ -166,7 +167,7 @@ export type EditorConfiguration = {
|
|
|
166
167
|
};
|
|
167
168
|
mainNavigation?: (MenuItem | Command<any>)[];
|
|
168
169
|
embedded?: boolean;
|
|
169
|
-
|
|
170
|
+
|
|
170
171
|
contentTree: {
|
|
171
172
|
contextMenu: {
|
|
172
173
|
factory: (props: {
|
|
@@ -183,9 +183,7 @@ export const EditContextMenu = forwardRef<
|
|
|
183
183
|
return (
|
|
184
184
|
<ContextMenu>
|
|
185
185
|
<ContextMenuTrigger>
|
|
186
|
-
<span id="contextmenu_canvas" ref={canvasRef}>
|
|
187
|
-
CM trigger
|
|
188
|
-
</span>
|
|
186
|
+
<span id="contextmenu_canvas" ref={canvasRef}></span>
|
|
189
187
|
</ContextMenuTrigger>
|
|
190
188
|
<ContextMenuContent>
|
|
191
189
|
{menuItems.map((item, index) =>
|
package/src/editor/FieldList.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import { useEditContext } from "./client/editContext";
|
|
|
5
5
|
import { FieldListFieldWithFallbacks } from "./FieldListFieldWithFallbacks";
|
|
6
6
|
import { SingleValidatorResult } from "../types";
|
|
7
7
|
import { Field } from "./pageModel";
|
|
8
|
-
import {
|
|
8
|
+
import { FilterInput } from "../components/FilterInput";
|
|
9
9
|
import { Fragment, useState } from "react";
|
|
10
10
|
import { Checkbox } from "primereact/checkbox";
|
|
11
11
|
import uuid from "react-uuid";
|
|
@@ -46,22 +46,13 @@ export function FieldList({
|
|
|
46
46
|
|
|
47
47
|
return (
|
|
48
48
|
<div className="text-dark">
|
|
49
|
-
<div className="tour-field-list sticky top-0 z-10 ml-[1px] flex items-center gap-2 border-
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
<InputText
|
|
53
|
-
className="flex-1 text-xs"
|
|
49
|
+
<div className="tour-field-list sticky top-0 z-10 ml-[1px] flex items-center gap-2 border-b border-gray-200 bg-white p-2">
|
|
50
|
+
<FilterInput
|
|
51
|
+
className="flex-1"
|
|
54
52
|
value={searchFilter}
|
|
55
|
-
onChange={
|
|
53
|
+
onChange={setSearchFilter}
|
|
54
|
+
placeholder="Filter fields..."
|
|
56
55
|
/>
|
|
57
|
-
{searchFilter && (
|
|
58
|
-
<SimpleIconButton
|
|
59
|
-
icon="pi pi-times"
|
|
60
|
-
onClick={() => setSearchFilter("")}
|
|
61
|
-
className="text-xs"
|
|
62
|
-
label="Clear"
|
|
63
|
-
/>
|
|
64
|
-
)}
|
|
65
56
|
{showStandardFieldsEnabled && (
|
|
66
57
|
<>
|
|
67
58
|
<Checkbox
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React, { ReactNode, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
DropdownMenu,
|
|
4
|
+
DropdownMenuContent,
|
|
5
|
+
DropdownMenuItem,
|
|
6
|
+
DropdownMenuTrigger,
|
|
7
|
+
} from "../components/ui/dropdown-menu";
|
|
8
|
+
import { MagicEditImageIcon } from "./ui/Icons";
|
|
9
|
+
|
|
10
|
+
export interface MenuAction {
|
|
11
|
+
id: string;
|
|
12
|
+
label: string;
|
|
13
|
+
icon: string;
|
|
14
|
+
onClick: (e?: React.MouseEvent) => void;
|
|
15
|
+
parameters?: any[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ImageEditButtonProps {
|
|
19
|
+
/** Menu items to display in the dropdown */
|
|
20
|
+
actions: MenuAction[];
|
|
21
|
+
/** Custom trigger button content */
|
|
22
|
+
triggerButton?: ReactNode;
|
|
23
|
+
/** Whether to use the compact round button style (default: false) */
|
|
24
|
+
compact?: boolean;
|
|
25
|
+
/** Custom trigger button text (used with non-compact style) */
|
|
26
|
+
buttonText?: string;
|
|
27
|
+
/** Custom trigger button icon (used with compact style) */
|
|
28
|
+
buttonIcon?: string;
|
|
29
|
+
/** Test ID for the trigger button */
|
|
30
|
+
testId?: string;
|
|
31
|
+
/** Additional CSS classes for the trigger button */
|
|
32
|
+
buttonClassName?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function ImageEditButton({
|
|
36
|
+
actions,
|
|
37
|
+
triggerButton,
|
|
38
|
+
|
|
39
|
+
buttonText = "Edit",
|
|
40
|
+
buttonIcon = "pi pi-ellipsis-v",
|
|
41
|
+
testId = "menu-toggle-button",
|
|
42
|
+
buttonClassName,
|
|
43
|
+
}: ImageEditButtonProps) {
|
|
44
|
+
const [showMenu, setShowMenu] = useState(false);
|
|
45
|
+
|
|
46
|
+
const defaultTriggerButton = (
|
|
47
|
+
<button
|
|
48
|
+
className={`text-dark border-gray-3 hover:bg-gray-5 absolute right-2 bottom-2 flex items-center justify-center gap-2 border bg-white p-2 opacity-70 shadow-lg transition-opacity hover:opacity-85 ${buttonClassName || ""}`}
|
|
49
|
+
onClick={(e) => {
|
|
50
|
+
e.stopPropagation();
|
|
51
|
+
}}
|
|
52
|
+
data-testid={testId}
|
|
53
|
+
>
|
|
54
|
+
<MagicEditImageIcon /> {buttonText}
|
|
55
|
+
</button>
|
|
56
|
+
);
|
|
57
|
+
return (
|
|
58
|
+
<DropdownMenu open={showMenu} onOpenChange={setShowMenu}>
|
|
59
|
+
<DropdownMenuTrigger asChild>
|
|
60
|
+
{triggerButton || defaultTriggerButton}
|
|
61
|
+
</DropdownMenuTrigger>
|
|
62
|
+
<DropdownMenuContent align="end" side="top" sideOffset={8}>
|
|
63
|
+
{actions.map((action) => (
|
|
64
|
+
<DropdownMenuItem
|
|
65
|
+
key={action.id}
|
|
66
|
+
onClick={(e) => {
|
|
67
|
+
action.onClick(e);
|
|
68
|
+
setShowMenu(false);
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
<i className={action.icon} />
|
|
72
|
+
{action.label}
|
|
73
|
+
</DropdownMenuItem>
|
|
74
|
+
))}
|
|
75
|
+
</DropdownMenuContent>
|
|
76
|
+
</DropdownMenu>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback } from "react";
|
|
2
2
|
import { useEditContext } from "./client/editContext";
|
|
3
3
|
import { ImageField } from "./fieldTypes";
|
|
4
4
|
//import { useDialog } from "./client/DialogContext";
|
|
5
5
|
import { ClientFieldButton } from "../config/types";
|
|
6
|
-
import {
|
|
7
|
-
DropdownMenu,
|
|
8
|
-
DropdownMenuContent,
|
|
9
|
-
DropdownMenuItem,
|
|
10
|
-
DropdownMenuTrigger,
|
|
11
|
-
} from "../components/ui/dropdown-menu";
|
|
12
|
-
import { MagicEditIcon } from "./ui/Icons";
|
|
6
|
+
import { ImageEditButton, MenuAction } from "./ImageEditButton";
|
|
13
7
|
|
|
14
8
|
export function ImageEditor({
|
|
15
9
|
field,
|
|
@@ -18,7 +12,6 @@ export function ImageEditor({
|
|
|
18
12
|
field: ImageField;
|
|
19
13
|
style?: React.CSSProperties;
|
|
20
14
|
}) {
|
|
21
|
-
const [showMenu, setShowMenu] = useState(false);
|
|
22
15
|
const editContext = useEditContext();
|
|
23
16
|
//const dialogContext = useDialog();
|
|
24
17
|
|
|
@@ -62,90 +55,49 @@ export function ImageEditor({
|
|
|
62
55
|
return field.value.alt;
|
|
63
56
|
};
|
|
64
57
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
data-testid="menu-toggle-button"
|
|
89
|
-
>
|
|
90
|
-
<MagicEditIcon /> Edit
|
|
91
|
-
</button>
|
|
92
|
-
</DropdownMenuTrigger>
|
|
93
|
-
<DropdownMenuContent align="end" side="top" sideOffset={8}>
|
|
94
|
-
<DropdownMenuItem
|
|
95
|
-
onClick={() => {
|
|
96
|
-
selectMedia();
|
|
97
|
-
setShowMenu(false);
|
|
98
|
-
}}
|
|
99
|
-
>
|
|
100
|
-
<i className="pi pi-image" />
|
|
101
|
-
{getImageSrc() ? "Change Image" : "Select Image"}
|
|
102
|
-
</DropdownMenuItem>
|
|
103
|
-
|
|
104
|
-
{editContext?.configuration?.fieldTypes["image"]?.buttons?.map(
|
|
105
|
-
(button: ClientFieldButton) => (
|
|
106
|
-
<DropdownMenuItem
|
|
107
|
-
key={button.id}
|
|
108
|
-
onClick={() => {
|
|
109
|
-
button?.clientAction?.({
|
|
110
|
-
field,
|
|
111
|
-
editContext,
|
|
112
|
-
//dialogContext,
|
|
113
|
-
});
|
|
114
|
-
setShowMenu(false);
|
|
115
|
-
}}
|
|
116
|
-
>
|
|
117
|
-
<i className={button.icon} />
|
|
118
|
-
{button.label}
|
|
119
|
-
</DropdownMenuItem>
|
|
120
|
-
),
|
|
121
|
-
)}
|
|
122
|
-
</DropdownMenuContent>
|
|
123
|
-
</DropdownMenu>
|
|
124
|
-
</div>
|
|
125
|
-
</>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
58
|
+
// Build actions for the dropdown menu
|
|
59
|
+
const menuActions: MenuAction[] = [
|
|
60
|
+
{
|
|
61
|
+
id: "select",
|
|
62
|
+
label: getImageSrc() ? "Change Image" : "Select Image",
|
|
63
|
+
icon: "pi pi-image",
|
|
64
|
+
onClick: () => selectMedia(),
|
|
65
|
+
},
|
|
66
|
+
...(editContext?.configuration?.fieldTypes["image"]?.buttons?.map(
|
|
67
|
+
(button: ClientFieldButton) => ({
|
|
68
|
+
id: button.id,
|
|
69
|
+
label: button.label,
|
|
70
|
+
icon: button.icon || "pi pi-bolt",
|
|
71
|
+
onClick: () => {
|
|
72
|
+
button?.clientAction?.({
|
|
73
|
+
field,
|
|
74
|
+
editContext,
|
|
75
|
+
//dialogContext,
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
}),
|
|
79
|
+
) || []),
|
|
80
|
+
];
|
|
128
81
|
|
|
129
|
-
function Btn({
|
|
130
|
-
label,
|
|
131
|
-
icon,
|
|
132
|
-
onClick,
|
|
133
|
-
testId,
|
|
134
|
-
className,
|
|
135
|
-
}: {
|
|
136
|
-
label: string;
|
|
137
|
-
icon?: string;
|
|
138
|
-
onClick?: MouseEventHandler<HTMLButtonElement>;
|
|
139
|
-
testId?: string;
|
|
140
|
-
className?: string;
|
|
141
|
-
}) {
|
|
142
82
|
return (
|
|
143
|
-
<
|
|
144
|
-
className=
|
|
145
|
-
|
|
146
|
-
data-testid=
|
|
83
|
+
<div
|
|
84
|
+
className="absolute inset-0 flex items-center justify-center"
|
|
85
|
+
style={style}
|
|
86
|
+
data-testid="select-media"
|
|
147
87
|
>
|
|
148
|
-
|
|
149
|
-
|
|
88
|
+
{getImageSrc() && (
|
|
89
|
+
<img
|
|
90
|
+
src={getImageSrc()!}
|
|
91
|
+
alt={getImageAlt()}
|
|
92
|
+
className="max-h-full max-w-full object-contain"
|
|
93
|
+
/>
|
|
94
|
+
)}
|
|
95
|
+
|
|
96
|
+
<ImageEditButton
|
|
97
|
+
actions={menuActions}
|
|
98
|
+
compact={false}
|
|
99
|
+
buttonText="Edit"
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
150
102
|
);
|
|
151
103
|
}
|
package/src/editor/ItemInfo.tsx
CHANGED
|
@@ -77,12 +77,12 @@ export default function MainLayout(props: MainLayoutProps) {
|
|
|
77
77
|
<div className="flex flex-1">
|
|
78
78
|
{!props.view.hideViewSelector && <LeftToolbar />}
|
|
79
79
|
<div className="flex flex-1 flex-col">
|
|
80
|
-
{editContext?.
|
|
80
|
+
{editContext?.view?.titlebar}
|
|
81
81
|
{editContext?.view?.toolbar}
|
|
82
82
|
<div className="bg-gray-4 flex-1">
|
|
83
83
|
<Splitter
|
|
84
|
+
splitterClassName="bg-transparent -mr-2 md:w-[8px]"
|
|
84
85
|
localStorageKey="editor.panelSizes"
|
|
85
|
-
splitterClassName="bg-transparent"
|
|
86
86
|
expandLabel={
|
|
87
87
|
<div className="flex items-center justify-center">
|
|
88
88
|
<Layers size={14} />
|