Skip to content

Commit 05e9e5b

Browse files
Merge pull request #275 from contentstack/VE-3781-focus-toolbar-update
Field focus wrapper and toolbar design update
2 parents 3f0664a + 9d30360 commit 05e9e5b

8 files changed

Lines changed: 109 additions & 78 deletions

File tree

src/visualBuilder/__test__/__snapshots__/index.test.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ exports[`Visual builder > on click, the sdk > should do nothing if data-cslp not
113113
data-testid="visual-builder__hover-outline"
114114
/>
115115
<div
116-
class="visual-builder__focused-toolbar go635291819"
116+
class="visual-builder__focused-toolbar go1658980850"
117117
data-testid="visual-builder__focused-toolbar"
118118
/>
119119
</div>
@@ -178,7 +178,7 @@ exports[`Visual builder > should append a visual builder container to the DOM 1`
178178
data-testid="visual-builder__hover-outline"
179179
/>
180180
<div
181-
class="visual-builder__focused-toolbar go635291819"
181+
class="visual-builder__focused-toolbar go1658980850"
182182
data-testid="visual-builder__focused-toolbar"
183183
/>
184184
</div>

src/visualBuilder/components/FieldToolbar.tsx

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@ import { FieldSchemaMap } from "../utils/fieldSchemaMap";
2929
import { isFieldDisabled } from "../utils/isFieldDisabled";
3030
import { IReferenceContentTypeSchema } from "../../cms/types/contentTypeSchema.types";
3131
import { VisualBuilderCslpEventDetails } from "../types/visualBuilder.types";
32+
import { FormIcon } from "./icons";
33+
import { getDOMEditStack } from "../utils/getCsDataOfElement";
3234

3335
export type FieldDetails = Pick<VisualBuilderCslpEventDetails, "editableElement" | "fieldMetadata">;
34-
interface MultipleFieldToolbarProps extends FieldDetails {};
36+
interface MultipleFieldToolbarProps {
37+
eventDetails: VisualBuilderCslpEventDetails;
38+
};
3539

3640
function handleReplaceAsset(fieldMetadata: CslpData) {
3741
// TODO avoid sending whole fieldMetadata
@@ -72,13 +76,26 @@ function handleEdit(fieldMetadata: CslpData) {
7276
);
7377
}
7478

79+
function handleFormFieldFocus(eventDetails: VisualBuilderCslpEventDetails) {
80+
const { editableElement, fieldMetadata, cslpData } = eventDetails;
81+
visualBuilderPostMessage?.send(
82+
VisualBuilderPostMessageEvents.OPEN_QUICK_FORM,
83+
{
84+
fieldMetadata,
85+
cslpData,
86+
}
87+
).then(() => {
88+
visualBuilderPostMessage?.send(VisualBuilderPostMessageEvents.FOCUS_FIELD, {
89+
DOMEditStack: getDOMEditStack(editableElement),
90+
});
91+
});
92+
}
93+
7594
function FieldToolbarComponent(
7695
props: MultipleFieldToolbarProps
7796
): JSX.Element | null {
78-
const {
79-
fieldMetadata,
80-
editableElement: targetElement,
81-
} = props;
97+
const { eventDetails } = props;
98+
const { fieldMetadata, editableElement: targetElement} = eventDetails;
8299
const direction = useSignal("");
83100
const parentPath =
84101
fieldMetadata?.multipleFieldMetadata?.parentDetails?.parentCslpValue ||
@@ -151,7 +168,7 @@ function FieldToolbarComponent(
151168
// propagation to be stopped, should ideally only attach onClick to fieldpath dropdown
152169
e.preventDefault();
153170
e.stopPropagation();
154-
handleEdit(props.fieldMetadata);
171+
handleEdit(fieldMetadata);
155172
}}
156173
>
157174
<Icon />
@@ -172,10 +189,10 @@ function FieldToolbarComponent(
172189
e.stopPropagation();
173190
e.preventDefault();
174191
if (fieldType === FieldDataType.REFERENCE) {
175-
handleReplaceReference(props.fieldMetadata);
192+
handleReplaceReference(fieldMetadata);
176193
return;
177194
} else if (fieldType === FieldDataType.FILE) {
178-
handleReplaceAsset(props.fieldMetadata);
195+
handleReplaceAsset(fieldMetadata);
179196
return;
180197
}
181198
}}
@@ -184,6 +201,20 @@ function FieldToolbarComponent(
184201
</button>
185202
) : null;
186203

204+
const formButton = <button
205+
className={classNames(
206+
"visual-builder__replace-button visual-builder__button visual-builder__button--secondary",
207+
visualBuilderStyles()["visual-builder__button"],
208+
visualBuilderStyles()["visual-builder__button--secondary"],
209+
visualBuilderStyles()["visual-builder__tooltip"]
210+
)}
211+
data-tooltip={"Form"}
212+
data-testid={`visual-builder-form`}
213+
onClick={(e) => {handleFormFieldFocus(eventDetails)}}
214+
>
215+
<FormIcon />
216+
</button>
217+
187218
const totalElementCount = targetElement?.parentNode?.childElementCount ?? 1;
188219
const indexOfElement = fieldMetadata?.multipleFieldMetadata?.index;
189220

@@ -292,6 +323,7 @@ function FieldToolbarComponent(
292323
</button>
293324

294325
{isModalEditable ? editButton : null}
326+
{formButton}
295327
{isReplaceAllowed ? replaceButton : null}
296328

297329
<button
@@ -320,8 +352,8 @@ function FieldToolbarComponent(
320352
<>
321353
{isModalEditable ? editButton : null}
322354
{isReplaceAllowed ? replaceButton : null}
323-
{fieldSchema ? <CommentIcon fieldMetadata={fieldMetadata} fieldSchema={fieldSchema}/> : null}
324-
355+
{formButton}
356+
{fieldSchema ? <CommentIcon fieldMetadata={fieldMetadata} fieldSchema={fieldSchema}/> : null}
325357
</>
326358
)}
327359
</>

src/visualBuilder/components/__test__/fieldToolbar.test.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { ISchemaFieldMap } from "../../utils/types/index.types";
99
import FieldToolbarComponent from "../FieldToolbar";
1010
import { mockMultipleLinkFieldSchema } from "../../../__test__/data/fields";
1111
import { asyncRender } from "../../../__test__/utils";
12+
import { VisualBuilderCslpEventDetails } from "../../types/visualBuilder.types";
1213

1314
vi.mock("../../utils/instanceHandlers", () => ({
1415
handleMoveInstance: vi.fn(),
@@ -56,11 +57,17 @@ const mockMultipleFieldMetadata: CslpData = {
5657

5758
describe("MultipleFieldToolbarComponent", () => {
5859
let targetElement: HTMLDivElement;
60+
const mockEventDetails: VisualBuilderCslpEventDetails = {
61+
fieldMetadata: mockMultipleFieldMetadata,
62+
editableElement: {} as Element,
63+
cslpData: ""
64+
}
5965

6066
beforeEach(() => {
6167
document.body.innerHTML = "";
6268
targetElement = document.createElement("div");
6369
targetElement.setAttribute("data-testid", "mock-target-element");
70+
mockEventDetails['editableElement'] = targetElement;
6471
document.body.appendChild(targetElement);
6572

6673
vi.spyOn(FieldSchemaMap, "getFieldSchema").mockResolvedValue(
@@ -77,8 +84,7 @@ describe("MultipleFieldToolbarComponent", () => {
7784
test("renders toolbar buttons correctly", async () => {
7885
const { findByTestId } = await asyncRender(
7986
<FieldToolbarComponent
80-
fieldMetadata={mockMultipleFieldMetadata}
81-
editableElement={targetElement}
87+
eventDetails={mockEventDetails}
8288
/>
8389
);
8490

@@ -100,8 +106,7 @@ describe("MultipleFieldToolbarComponent", () => {
100106
test("calls handleMoveInstance with 'previous' when move left button is clicked", async () => {
101107
const { findByTestId } = await asyncRender(
102108
<FieldToolbarComponent
103-
fieldMetadata={mockMultipleFieldMetadata}
104-
editableElement={targetElement}
109+
eventDetails={mockEventDetails}
105110
/>
106111
);
107112

@@ -121,8 +126,7 @@ describe("MultipleFieldToolbarComponent", () => {
121126
test("calls handleMoveInstance with 'next' when move right button is clicked", async () => {
122127
const { findByTestId } = await asyncRender(
123128
<FieldToolbarComponent
124-
fieldMetadata={mockMultipleFieldMetadata}
125-
editableElement={targetElement}
129+
eventDetails={mockEventDetails}
126130
/>
127131
);
128132

@@ -142,8 +146,7 @@ describe("MultipleFieldToolbarComponent", () => {
142146
test("calls handleDeleteInstance when delete button is clicked", async () => {
143147
const { findByTestId } = await asyncRender(
144148
<FieldToolbarComponent
145-
fieldMetadata={mockMultipleFieldMetadata}
146-
editableElement={targetElement}
149+
eventDetails={mockEventDetails}
147150
/>
148151
);
149152

src/visualBuilder/components/__test__/icons.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe("IconComponents", () => {
3939
expect(svgElement).toBeInTheDocument();
4040
expect(svgElement).toHaveAttribute("width", "16");
4141
expect(svgElement).toHaveAttribute("height", "16");
42-
expect(svgElement).toHaveAttribute("fill", "none");
42+
expect(svgElement).toHaveAttribute("fill", "currentColor");
4343
expect(svgElement).toHaveAttribute(
4444
"data-testid",
4545
"visual-builder__delete-icon"
@@ -56,7 +56,7 @@ describe("IconComponents", () => {
5656
expect(svgElement).toBeInTheDocument();
5757
expect(svgElement).toHaveAttribute("width", "16");
5858
expect(svgElement).toHaveAttribute("height", "16");
59-
expect(svgElement).toHaveAttribute("fill", "none");
59+
expect(svgElement).toHaveAttribute("fill", "currentColor");
6060
expect(svgElement).toHaveAttribute(
6161
"data-testid",
6262
"visual-builder__move-left-icon"
@@ -73,7 +73,7 @@ describe("IconComponents", () => {
7373
expect(svgElement).toBeInTheDocument();
7474
expect(svgElement).toHaveAttribute("width", "16");
7575
expect(svgElement).toHaveAttribute("height", "16");
76-
expect(svgElement).toHaveAttribute("fill", "none");
76+
expect(svgElement).toHaveAttribute("fill", "currentColor");
7777
expect(svgElement).toHaveAttribute(
7878
"data-testid",
7979
"visual-builder__move-right-icon"
@@ -107,7 +107,7 @@ describe("IconComponents", () => {
107107
expect(svgElement).toBeInTheDocument();
108108
expect(svgElement).toHaveAttribute("width", "24");
109109
expect(svgElement).toHaveAttribute("height", "24");
110-
expect(svgElement).toHaveAttribute("fill", "none");
110+
expect(svgElement).toHaveAttribute("fill", "currentColor");
111111
expect(svgElement).toHaveAttribute(
112112
"data-testid",
113113
"visual-builder__edit-icon"

0 commit comments

Comments
 (0)