Skip to content

Commit 337ed16

Browse files
Merge pull request #512 from contentstack/stage_v4
2nd Oct Release
2 parents a96bdd4 + 4e4153a commit 337ed16

File tree

13 files changed

+170
-24
lines changed

13 files changed

+170
-24
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Alternatively, if you want to include the package directly in your website HTML
1616

1717
```html
1818
<script type='module' crossorigin="anonymous">
19-
import ContentstackLivePreview from 'https://esm.sh/@contentstack/live-preview-utils@4.0.2';
19+
import ContentstackLivePreview from 'https://esm.sh/@contentstack/live-preview-utils@4.1.0';
2020
2121
ContentstackLivePreview.init({
2222
stackDetails: {

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@contentstack/live-preview-utils",
3-
"version": "4.0.2",
3+
"version": "4.1.0",
44
"description": "Contentstack provides the Live Preview SDK to establish a communication channel between the various Contentstack SDKs and your website, transmitting live changes to the preview pane.",
55
"type": "module",
66
"types": "dist/legacy/index.d.ts",
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from "preact/compat";
2+
import { VariantIcon } from "./icons/variant";
3+
import { visualBuilderStyles } from "../visualBuilder.style";
4+
5+
export function VariantIndicator(): JSX.Element {
6+
return (
7+
<div className={visualBuilderStyles()["visual-builder__variant-indicator"]}>
8+
<VariantIcon size="18px" />
9+
</div>
10+
);
11+
12+
}

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

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,13 @@ vi.mock("../generators/generateCustomCursor", () => ({
118118
}));
119119

120120
vi.mock("../visualBuilder.style", () => ({
121-
visualBuilderStyles: vi.fn().mockReturnValue({}),
121+
visualBuilderStyles: vi.fn().mockReturnValue({
122+
"visual-builder__focused-toolbar--variant": "visual-builder__focused-toolbar--variant"
123+
}),
124+
}));
125+
126+
vi.mock("../VariantIndicator", () => ({
127+
VariantIndicator: () => <div data-testid="variant-indicator">Variant</div>
122128
}));
123129

124130
vi.mock("../../utils/errorHandling", () => ({
@@ -387,4 +393,78 @@ describe("FieldLabelWrapperComponent", () => {
387393
const contentTypeIcon = container.querySelector(".visual-builder__content-type-icon");
388394
expect(contentTypeIcon).not.toBeInTheDocument();
389395
});
396+
397+
test("renders VariantIndicator when field has variant", async () => {
398+
const variantFieldMetadata = {
399+
...mockFieldMetadata,
400+
variant: "variant-uid-123"
401+
};
402+
403+
const { findByTestId } = await asyncRender(
404+
<FieldLabelWrapperComponent
405+
fieldMetadata={variantFieldMetadata}
406+
eventDetails={mockEventDetails}
407+
parentPaths={[]}
408+
getParentEditableElement={mockGetParentEditable}
409+
/>
410+
);
411+
412+
const variantIndicator = await findByTestId("variant-indicator");
413+
expect(variantIndicator).toBeInTheDocument();
414+
});
415+
416+
test("does not render VariantIndicator when field has no variant", async () => {
417+
const { container } = await asyncRender(
418+
<FieldLabelWrapperComponent
419+
fieldMetadata={mockFieldMetadata}
420+
eventDetails={mockEventDetails}
421+
parentPaths={[]}
422+
getParentEditableElement={mockGetParentEditable}
423+
/>
424+
);
425+
426+
await waitFor(() => {
427+
const variantIndicator = container.querySelector("[data-testid='variant-indicator']");
428+
expect(variantIndicator).not.toBeInTheDocument();
429+
});
430+
});
431+
432+
test("applies variant CSS classes when field has variant", async () => {
433+
const variantFieldMetadata = {
434+
...mockFieldMetadata,
435+
variant: "variant-uid-123"
436+
};
437+
438+
const { findByTestId } = await asyncRender(
439+
<FieldLabelWrapperComponent
440+
fieldMetadata={variantFieldMetadata}
441+
eventDetails={mockEventDetails}
442+
parentPaths={[]}
443+
getParentEditableElement={mockGetParentEditable}
444+
/>
445+
);
446+
447+
const fieldLabelWrapper = await findByTestId("visual-builder__focused-toolbar__field-label-wrapper");
448+
449+
await waitFor(() => {
450+
expect(fieldLabelWrapper).toHaveClass("visual-builder__focused-toolbar--variant");
451+
});
452+
});
453+
454+
test("does not apply variant CSS classes when field has no variant", async () => {
455+
const { findByTestId } = await asyncRender(
456+
<FieldLabelWrapperComponent
457+
fieldMetadata={mockFieldMetadata}
458+
eventDetails={mockEventDetails}
459+
parentPaths={[]}
460+
getParentEditableElement={mockGetParentEditable}
461+
/>
462+
);
463+
464+
const fieldLabelWrapper = await findByTestId("visual-builder__focused-toolbar__field-label-wrapper");
465+
466+
await waitFor(() => {
467+
expect(fieldLabelWrapper).not.toHaveClass("visual-builder__focused-toolbar--variant");
468+
});
469+
});
390470
});

src/visualBuilder/components/fieldLabelWrapper.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { VisualBuilderPostMessageEvents } from "../utils/types/postMessage.types
1717
import { ContentTypeIcon } from "./icons";
1818
import { ToolbarTooltip } from "./Tooltip";
1919
import { fetchEntryPermissionsAndStageDetails } from "../utils/fetchEntryPermissionsAndStageDetails";
20+
import { VariantIndicator } from "./VariantIndicator";
2021

2122
interface ReferenceParentMap {
2223
[entryUid: string]: {
@@ -246,6 +247,7 @@ function FieldLabelWrapperComponent(
246247
]
247248
)}
248249
>
250+
{currentField.isVariant ? <VariantIndicator /> : null}
249251
<ToolbarTooltip data={{contentTypeName: currentField.parentContentTypeName, referenceFieldName: currentField.referenceFieldName}} disabled={!currentField.isReference || isDropdownOpen}>
250252
<div
251253
className={classNames(
@@ -266,6 +268,15 @@ function FieldLabelWrapperComponent(
266268
"field-label-dropdown-open": isDropdownOpen,
267269
[visualBuilderStyles()["field-label-dropdown-open"]]:
268270
isDropdownOpen,
271+
},
272+
{
273+
"visual-builder__focused-toolbar--variant":
274+
currentField.isVariant,
275+
},
276+
{
277+
[visualBuilderStyles()[
278+
"visual-builder__focused-toolbar--variant"
279+
]]: currentField.isVariant,
269280
}
270281
)}
271282
onClick={() => setIsDropdownOpen((prev) => !prev)}
Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
import React from "preact/compat";
22

3-
export function VariantIcon(): JSX.Element {
4-
return (
3+
export function VariantIcon(props: {
4+
size?: string;
5+
}): JSX.Element {
6+
return (
57
<svg
68
width="12"
79
height="12"
810
viewBox="0 0 12 12"
911
fill="none"
1012
xmlns="http://www.w3.org/2000/svg"
13+
style={{
14+
width: props.size,
15+
height: props.size,
16+
}}
1117
>
1218
<path
1319
fill-rule="evenodd"
1420
clip-rule="evenodd"
1521
d="M4.41131 0.157165C4.34585 0.0589769 4.23565 0 4.11765 0C3.99964 0 3.88944 0.0589769 3.82398 0.157165L0.0592764 5.80422C-0.0197588 5.92278 -0.0197588 6.07722 0.0592764 6.19578L3.82398 11.8428C3.88944 11.941 3.99964 12 4.11765 12C4.23565 12 4.34585 11.941 4.41131 11.8428L6 9.4598L7.58869 11.8428C7.65415 11.941 7.76435 12 7.88235 12C8.00036 12 8.11056 11.941 8.17602 11.8428L11.9407 6.19578C12.0198 6.07722 12.0198 5.92278 11.9407 5.80422L8.17602 0.157165C8.11056 0.0589769 8.00036 0 7.88235 0C7.76435 0 7.65415 0.0589769 7.58869 0.157165L6 2.5402L4.41131 0.157165ZM5.57582 3.17647L4.11765 0.989215L0.777124 6L4.11765 11.0108L5.57582 8.82353L3.82398 6.19578C3.74495 6.07722 3.74495 5.92278 3.82398 5.80422L5.57582 3.17647ZM6 8.18726L4.54183 6L6 3.81274L7.45817 6L6 8.18726ZM6.42418 8.82353L8.17602 6.19578C8.25505 6.07722 8.25505 5.92278 8.17602 5.80422L6.42418 3.17647L7.88235 0.989215L11.2229 6L7.88235 11.0108L6.42418 8.82353Z"
1622
fill="currentColor"
1723
/>
18-
</svg>
24+
</svg>
1925
);
2026
}

src/visualBuilder/generators/__test__/generateToolbar.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ describe("appendFieldPathDropdown", () => {
161161
fireEvent.click(focusedToolbar);
162162

163163
expect(fieldLabelWrapper?.classList.toString()).toBe(
164-
"visual-builder__focused-toolbar__field-label-wrapper go3399023040"
164+
"visual-builder__focused-toolbar__field-label-wrapper go3061601331"
165165
);
166166
});
167167
});

src/visualBuilder/generators/generateHoverOutline.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { visualBuilderStyles } from "../visualBuilder.style";
88
*/
99
export function addHoverOutline(
1010
targetElement: Element,
11-
disabled?: boolean
11+
disabled?: boolean,
12+
isVariant?: boolean
1213
): void {
1314
const targetElementDimension = targetElement.getBoundingClientRect();
1415

@@ -29,6 +30,15 @@ export function addHoverOutline(
2930
hoverOutline.classList.remove(
3031
visualBuilderStyles()["visual-builder__hover-outline--disabled"]
3132
);
33+
if (isVariant) {
34+
hoverOutline.classList.add(
35+
visualBuilderStyles()["visual-builder__hover-outline--variant"]
36+
);
37+
} else {
38+
hoverOutline.classList.remove(
39+
visualBuilderStyles()["visual-builder__hover-outline--variant"]
40+
);
41+
}
3242
}
3343

3444
hoverOutline.style.top = `${

src/visualBuilder/listeners/mouseHover.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ async function addOutline(params?: AddOutlineParams): Promise<void> {
8181
fieldDisabled,
8282
} = params;
8383
if (!editableElement) return;
84-
addHoverOutline(editableElement as HTMLElement, fieldDisabled);
84+
const isVariant = !!fieldMetadata.variant;
85+
addHoverOutline(editableElement as HTMLElement, fieldDisabled, isVariant);
8586
const fieldSchema = await FieldSchemaMap.getFieldSchema(
8687
content_type_uid,
8788
fieldPath
@@ -100,7 +101,7 @@ async function addOutline(params?: AddOutlineParams): Promise<void> {
100101
entryAcl,
101102
entryWorkflowStageDetails
102103
);
103-
addHoverOutline(editableElement, fieldDisabled || isDisabled);
104+
addHoverOutline(editableElement, fieldDisabled || isDisabled, isVariant);
104105
}
105106

106107
const debouncedAddOutline = debounce(addOutline, 50, { trailing: true });
@@ -333,15 +334,16 @@ const throttledMouseHover = throttle(async (params: HandleMouseHoverParams) => {
333334
const isFocussed= VisualBuilder.VisualBuilderGlobalState.value.isFocussed;
334335
if(!isFocussed) {
335336
showHoverToolbar({
336-
event: params.event,
337-
overlayWrapper: params.overlayWrapper,
338-
visualBuilderContainer: params.visualBuilderContainer,
339-
previousSelectedEditableDOM:
340-
VisualBuilder.VisualBuilderGlobalState.value
341-
.previousSelectedEditableDOM,
342-
focusedToolbar: params.focusedToolbar,
343-
resizeObserver: params.resizeObserver,
344-
});
337+
event: params.event,
338+
overlayWrapper: params.overlayWrapper,
339+
visualBuilderContainer: params.visualBuilderContainer,
340+
previousSelectedEditableDOM:
341+
VisualBuilder.VisualBuilderGlobalState.value
342+
.previousSelectedEditableDOM,
343+
focusedToolbar: params.focusedToolbar,
344+
resizeObserver: params.resizeObserver,
345+
}
346+
);
345347
}
346348
}
347349

0 commit comments

Comments
 (0)