Skip to content

Commit 17f8931

Browse files
authored
feat(image-web): support icon collections (#441)
2 parents d733204 + deb805f commit 17f8931

File tree

9 files changed

+91
-33
lines changed

9 files changed

+91
-33
lines changed

packages/pluggableWidgets/image-web/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66

77
## [Unreleased]
88

9+
### Changed
10+
11+
- We added custom icon collections support.
12+
913
## [1.2.1] - 2022-04-01
1014

1115
### Fixed

packages/pluggableWidgets/image-web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"mpkName": "com.mendix.widget.web.Image.mpk"
1717
},
1818
"marketplace": {
19-
"minimumMXVersion": "9.6.0",
19+
"minimumMXVersion": "9.24.0",
2020
"appNumber": 118579,
2121
"appName": "Image"
2222
},

packages/pluggableWidgets/image-web/src/Image.editorPreview.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@ export function preview(props: ImagePreviewProps): ReactElement | null {
2121
case "icon":
2222
// TODO: Remove these when preview typing for `icon` property is aligned properly by PageEditor
2323
const imageIcon: WebIcon | null = props.imageIcon as any;
24-
if (imageIcon?.type === "glyph") {
25-
image = imageIcon.iconClass;
26-
}
27-
if (imageIcon?.type === "image") {
28-
image = imageIcon.iconUrl;
24+
switch (imageIcon?.type) {
25+
case "glyph":
26+
case "icon":
27+
image = imageIcon.iconClass;
28+
break;
29+
case "image":
30+
image = imageIcon.iconUrl;
31+
break;
2932
}
3033
break;
3134
case "imageUrl":
@@ -48,7 +51,7 @@ export function preview(props: ImagePreviewProps): ReactElement | null {
4851
responsive={props.responsive}
4952
onClickType={props.onClickType}
5053
onClick={undefined}
51-
type={props.datasource === "icon" && props.imageIcon?.type === "glyph" ? "icon" : "image"}
54+
type={props.datasource === "icon" && props.imageIcon ? props.imageIcon.type : "image"}
5255
image={image}
5356
displayAs={props.displayAs}
5457
renderAsBackground={props.datasource !== "icon" && props.isBackgroundImage}

packages/pluggableWidgets/image-web/src/Image.tsx

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,12 @@ function getImageProps({
4141
image: imageUrl?.status === ValueStatus.Available ? imageUrl.value : undefined
4242
};
4343
case "icon": {
44-
if (imageIcon?.status === ValueStatus.Available) {
45-
if (imageIcon.value?.type === "glyph") {
46-
return {
47-
type: "icon",
48-
image: imageIcon.value.iconClass
49-
};
50-
}
51-
if (imageIcon.value?.type === "image") {
52-
return {
53-
type: "image",
54-
image: imageIcon.value.iconUrl
55-
};
56-
}
44+
if (imageIcon?.status === ValueStatus.Available && imageIcon.value) {
45+
const icon = imageIcon.value;
46+
return {
47+
type: icon.type,
48+
image: icon.type === "image" ? icon.iconUrl : icon.iconClass
49+
};
5750
}
5851
return fallback;
5952
}

packages/pluggableWidgets/image-web/src/components/Image/Image.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import "../../ui/Image.scss";
88
import classNames from "classnames";
99

1010
export type ImageType = {
11-
type: "image" | "icon";
11+
type: "image" | "icon" | "glyph";
1212
image: string | undefined;
1313
};
1414

@@ -99,7 +99,7 @@ export const Image: FunctionComponent<ImageProps> = ({
9999
{...sharedContentProps}
100100
/>
101101
) : (
102-
<ImageUi.ContentGlyphicon icon={image} size={iconSize} {...sharedContentProps} />
102+
<ImageUi.ContentIcon icon={image} isGlyph={type === "glyph"} size={iconSize} {...sharedContentProps} />
103103
);
104104

105105
if (renderAsBackground) {

packages/pluggableWidgets/image-web/src/components/Image/ui.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export interface ImageWrapperProps {
2020
responsive: boolean;
2121
hasImage: boolean;
2222
children:
23-
| ReactElement<ImageContentGlyphicon | ImageContentImage>
24-
| [ReactElement<ImageContentGlyphicon | ImageContentImage>, ReactElement<LightboxProps> | false];
23+
| ReactElement<ImageContentIcon | ImageContentImage>
24+
| [ReactElement<ImageContentIcon | ImageContentImage>, ReactElement<LightboxProps> | false];
2525
}
2626

2727
export interface ImageContentProps {
@@ -45,12 +45,13 @@ function Wrapper(props: ImageWrapperProps): ReactElement {
4545
);
4646
}
4747

48-
export interface ImageContentGlyphicon extends ImageContentProps {
48+
export interface ImageContentIcon extends ImageContentProps {
4949
icon: string | undefined;
5050
size: number;
51+
isGlyph?: boolean;
5152
}
5253

53-
function ContentGlyphicon(props: ImageContentGlyphicon): ReactElement {
54+
function ContentIcon(props: ImageContentIcon): ReactElement {
5455
const accessibilityProps = props.altText
5556
? {
5657
"aria-label": props.altText,
@@ -62,7 +63,7 @@ function ContentGlyphicon(props: ImageContentGlyphicon): ReactElement {
6263

6364
return (
6465
<span
65-
className={classNames("glyphicon", props.icon)}
66+
className={classNames(props.icon, { glyphicon: props.isGlyph })}
6667
style={{ ...props.style, fontSize: `${props.size}px` }}
6768
{...accessibilityProps}
6869
{...onClickProps}
@@ -136,6 +137,6 @@ function BackgroundImage(props: BackgroundImageProps): ReactElement {
136137
export const ImageUi = {
137138
Wrapper,
138139
BackgroundImage,
139-
ContentGlyphicon,
140+
ContentIcon,
140141
ContentImage
141142
};

packages/pluggableWidgets/image-web/src/components/__tests__/Image.spec.tsx

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const imageProps: ImageProps = {
3838

3939
const glyphiconProps: ImageProps = {
4040
class: "",
41-
type: "icon",
41+
type: "glyph",
4242
image: "glyphicon-asterisk",
4343
iconSize: 20,
4444
height: 0,
@@ -52,6 +52,22 @@ const glyphiconProps: ImageProps = {
5252
backgroundImageContent: null
5353
};
5454

55+
const iconProps: ImageProps = {
56+
class: "",
57+
type: "icon",
58+
image: "mx-icon mx-icon-asterisk",
59+
iconSize: 20,
60+
height: 0,
61+
heightUnit: "pixels",
62+
width: 0,
63+
widthUnit: "pixels",
64+
responsive: true,
65+
onClickType: "action",
66+
displayAs: "fullImage",
67+
renderAsBackground: false,
68+
backgroundImageContent: null
69+
};
70+
5571
describe("Image", () => {
5672
it("renders the structure with an image", () => {
5773
expect(render(<Image {...imageProps} />)).toMatchSnapshot();
@@ -63,10 +79,14 @@ describe("Image", () => {
6379
).toMatchSnapshot();
6480
});
6581

66-
it("renders the structure with an icon", () => {
82+
it("renders the structure with a glyph icon", () => {
6783
expect(render(<Image {...glyphiconProps} />)).toMatchSnapshot();
6884
});
6985

86+
it("renders the structure with an icon", () => {
87+
expect(render(<Image {...iconProps} />)).toMatchSnapshot();
88+
});
89+
7090
it("renders the structure as a background image", () => {
7191
expect(
7292
render(<Image {...imageProps} renderAsBackground backgroundImageContent={<div>Image content</div>} />)
@@ -85,7 +105,7 @@ describe("Image", () => {
85105
expect(onClickMock).toHaveBeenCalled();
86106
});
87107

88-
it("calls the onClick when clicking on an icon", () => {
108+
it("calls the onClick when clicking on a glyph icon", () => {
89109
const onClickMock = jest.fn();
90110
const imageRender = mount(<Image {...glyphiconProps} onClick={onClickMock} onClickType="action" />);
91111

@@ -95,6 +115,17 @@ describe("Image", () => {
95115
glyphicon.simulate("click");
96116
expect(onClickMock).toHaveBeenCalled();
97117
});
118+
119+
it("calls the onClick when clicking on an icon", () => {
120+
const onClickMock = jest.fn();
121+
const imageRender = mount(<Image {...iconProps} onClick={onClickMock} onClickType="action" />);
122+
123+
const glyphicon = imageRender.find("span");
124+
expect(glyphicon).toHaveLength(1);
125+
126+
glyphicon.simulate("click");
127+
expect(onClickMock).toHaveBeenCalled();
128+
});
98129
});
99130

100131
describe("when the onClickType is enlarge", () => {
@@ -151,7 +182,14 @@ describe("Image", () => {
151182
});
152183

153184
it("is set properly on a glyphicon", () => {
154-
const imageRender = mount(<Image {...glyphiconProps} altText="this is an awesome icon" />);
185+
const imageRender = mount(<Image {...glyphiconProps} altText="this is an awesome glyphicon" />);
186+
const image = imageRender.find("span");
187+
expect(image.prop("aria-label")).toBe("this is an awesome glyphicon");
188+
expect(image.prop("role")).toBe("img");
189+
});
190+
191+
it("is set properly on an icon", () => {
192+
const imageRender = mount(<Image {...iconProps} altText="this is an awesome icon" />);
155193
const image = imageRender.find("span");
156194
expect(image.prop("aria-label")).toBe("this is an awesome icon");
157195
expect(image.prop("role")).toBe("img");
@@ -171,6 +209,13 @@ describe("Image", () => {
171209
expect(image).not.toHaveProperty("aria-label");
172210
expect(image).not.toHaveProperty("role");
173211
});
212+
213+
it("nothing is set on an icon", () => {
214+
const imageRender = mount(<Image {...iconProps} />);
215+
const image = imageRender.find("span");
216+
expect(image).not.toHaveProperty("aria-label");
217+
expect(image).not.toHaveProperty("role");
218+
});
174219
});
175220

176221
describe("when showing an image as a thumbnail", () => {

packages/pluggableWidgets/image-web/src/components/__tests__/__snapshots__/Image.spec.tsx.snap

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,23 @@ exports[`Image renders the structure as a background image 1`] = `
1111
</div>
1212
`;
1313

14+
exports[`Image renders the structure with a glyph icon 1`] = `
15+
<div
16+
class="mx-image-viewer mx-image-viewer-responsive"
17+
>
18+
<span
19+
class="glyphicon-asterisk glyphicon"
20+
style="font-size:20px"
21+
/>
22+
</div>
23+
`;
24+
1425
exports[`Image renders the structure with an icon 1`] = `
1526
<div
1627
class="mx-image-viewer mx-image-viewer-responsive"
1728
>
1829
<span
19-
class="glyphicon glyphicon-asterisk"
30+
class="mx-icon mx-icon-asterisk"
2031
style="font-size:20px"
2132
/>
2233
</div>

packages/shared/pluggable-widgets-commons/src/structure-preview-api/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ interface TextStylingProps extends BaseStylingProps {
2020
export interface ImageProps extends BaseStylingProps {
2121
type: "Image";
2222
document?: string; // svg image
23+
property?: object; // property containing the image property
2324
data?: string; // base64 image. Will only be read if no svg image is passed
2425
width?: number; // sets a fixed maximum width
2526
height?: number; // sets a fixed maximum height

0 commit comments

Comments
 (0)