Skip to content

Commit 02d04c0

Browse files
author
FalkWolsky
committed
Image Conponent Enhancements v1
1 parent 749a722 commit 02d04c0

File tree

3 files changed

+134
-20
lines changed

3 files changed

+134
-20
lines changed

client/packages/lowcoder/src/comps/comps/imageComp.tsx

+111-16
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,58 @@ import { DEFAULT_IMG_URL } from "util/stringUtils";
3434
import { useContext } from "react";
3535
import { EditorContext } from "comps/editorState";
3636
import { StringControl } from "../controls/codeControl";
37+
import { PositionControl } from "comps/controls/dropdownControl";
3738

38-
const Container = styled.div<{ $style: ImageStyleType | undefined,$animationStyle:AnimationStyleType }>`
39+
const Container = styled.div<{
40+
$style: ImageStyleType | undefined,
41+
$animationStyle: AnimationStyleType,
42+
$clipPath: string,
43+
$enableOverflow: boolean,
44+
$overflow: string,
45+
$positionX: string,
46+
$positionY: string,
47+
$aspectRatio: string | undefined,
48+
$placement: string // New property to control image placement
49+
}>`
3950
height: 100%;
4051
width: 100%;
4152
display: flex;
42-
align-items: center;
43-
justify-content: center;
44-
.ant-image,
45-
img {
46-
width: 100%;
47-
height: 100%;
48-
}
53+
align-items: ${(props) =>
54+
props.$placement.includes("bottom")
55+
? "flex-end"
56+
: props.$placement.includes("top")
57+
? "flex-start"
58+
: "center"};
59+
justify-content: ${(props) =>
60+
props.$placement.includes("right")
61+
? "flex-end"
62+
: props.$placement.includes("left")
63+
? "flex-start"
64+
: "center"};
65+
overflow: ${(props) => (props.$enableOverflow ? props.$overflow : "hidden")};
4966
67+
.ant-image,
5068
img {
51-
object-fit: contain;
52-
pointer-events: auto;
53-
${props=>props.$animationStyle}
69+
${(props) =>
70+
props.$enableOverflow
71+
? `
72+
aspect-ratio: ${props.$aspectRatio};
73+
width: 100%;
74+
height: 100%;
75+
object-fit: cover;
76+
`
77+
: `
78+
width: auto;
79+
height: auto;
80+
max-width: 100%;
81+
max-height: 100%;
82+
object-fit: contain;
83+
`}
84+
85+
object-position: ${(props) => `${props.$positionX} ${props.$positionY}`};
86+
${props => props.$clipPath && `clip-path: ${props.$clipPath};`};
87+
${props => props.$style?.opacity !== undefined && `opacity: ${props.$style?.opacity};`};
88+
${props => props.$animationStyle};
5489
}
5590
5691
${(props) => props.$style && getStyle(props.$style)}
@@ -60,6 +95,7 @@ const getStyle = (style: ImageStyleType) => {
6095
return css`
6196
img {
6297
border: ${(props) => (style.borderWidth ? style.borderWidth : "1px")} solid ${style.border};
98+
box-shadow: ${props=>`${style?.boxShadow} ${style?.boxShadowColor}`};
6399
border-radius: ${style.radius};
64100
margin: ${style.margin};
65101
padding: ${style.padding};
@@ -107,8 +143,6 @@ const ContainerImg = (props: RecordConstructorToView<typeof childrenMap>) => {
107143

108144
// on safari
109145
const setStyle = (height: string, width: string) => {
110-
// console.log(width, height);
111-
112146
const img = imgRef.current;
113147
const imgDiv = img?.getElementsByTagName("div")[0];
114148
const imgCurrent = img?.getElementsByTagName("img")[0];
@@ -123,7 +157,7 @@ const ContainerImg = (props: RecordConstructorToView<typeof childrenMap>) => {
123157
const onResize = () => {
124158
const img = imgRef.current;
125159
const container = conRef.current;
126-
if (!img?.clientWidth || !img?.clientHeight || props.autoHeight || !width) {
160+
if (!props.enableOverflow && (!img?.clientWidth || !img?.clientHeight || props.autoHeight || !width)) {
127161
return;
128162
}
129163
// fixme border style bug on safari
@@ -136,11 +170,23 @@ const ContainerImg = (props: RecordConstructorToView<typeof childrenMap>) => {
136170
setStyle("auto", "100%");
137171
}
138172
};
173+
139174
return (
140175
<ReactResizeDetector
141176
onResize={onResize}
142177
render={() => (
143-
<Container ref={conRef} $style={props.style} $animationStyle={props.animationStyle}>
178+
<Container
179+
ref={conRef}
180+
$style={props.style}
181+
$animationStyle={props.animationStyle}
182+
$clipPath={props.clipPath}
183+
$overflow={props.enableOverflow ? props.overflow : "hidden"}
184+
$positionX={props.positionX}
185+
$positionY={props.positionY}
186+
$enableOverflow={props.enableOverflow}
187+
$aspectRatio={props.aspectRatio || "16 / 9"}
188+
$placement={props.placement}
189+
>
144190
<div
145191
ref={imgRef}
146192
style={
@@ -168,10 +214,17 @@ const childrenMap = {
168214
onEvent: eventHandlerControl(EventOptions),
169215
style: styleControl(ImageStyle , 'style'),
170216
animationStyle: styleControl(AnimationStyle , 'animationStyle'),
217+
clipPath: withDefault(StringControl, "none"),
171218
autoHeight: withDefault(AutoHeightControl, "fixed"),
172219
supportPreview: BoolControl,
173220
previewSrc: StringControl,
174-
restrictPaddingOnRotation:withDefault(StringControl, 'image')
221+
restrictPaddingOnRotation:withDefault(StringControl, 'image'),
222+
enableOverflow: withDefault(BoolControl, false),
223+
aspectRatio: withDefault(StringControl, "16 / 9"),
224+
placement: withDefault(PositionControl, "top"),
225+
overflow: withDefault(StringControl, "hidden"),
226+
positionX: withDefault(StringControl, "center"),
227+
positionY: withDefault(StringControl, "center"),
175228
};
176229

177230
let ImageBasicComp = new UICompBuilder(childrenMap, (props) => {
@@ -204,10 +257,52 @@ let ImageBasicComp = new UICompBuilder(childrenMap, (props) => {
204257
{["layout", "both"].includes(useContext(EditorContext).editorModeStatus) && (
205258
<>
206259
<Section name={sectionNames.layout}>
260+
207261
{children.autoHeight.getPropertyView()}
262+
263+
{children.autoHeight.getView() == false && (
264+
children.placement.propertyView({
265+
label: trans("image.placement"),
266+
radioButton: true
267+
}))}
268+
269+
{children.autoHeight.getView() == false && (
270+
children.enableOverflow.propertyView({
271+
label: trans("image.enableOverflow"),
272+
tooltip: trans("image.enableOverflowTip")
273+
}))}
274+
275+
{children.autoHeight.getView() == false && children.enableOverflow.getView() == true && (
276+
children.overflow.propertyView({
277+
label: trans("image.overflow"),
278+
tooltip: trans("image.overflowTip")
279+
}))}
280+
281+
{children.autoHeight.getView() == false && children.enableOverflow.getView() == true && (
282+
children.positionX.propertyView({
283+
label: trans("image.positionX"),
284+
tooltip: trans("image.positionXTip")
285+
}))}
286+
287+
{children.autoHeight.getView() == false && children.enableOverflow.getView() == true && (
288+
children.positionY.propertyView({
289+
label: trans("image.positionY"),
290+
tooltip: trans("image.positionYTip")
291+
}))}
292+
293+
{children.autoHeight.getView() == false && children.enableOverflow.getView() == true && (
294+
children.aspectRatio.propertyView({
295+
label: trans("image.aspectRatio"),
296+
tooltip: trans("image.aspectRatioTip")
297+
}))}
208298
</Section>
299+
209300
<Section name={sectionNames.style}>
210301
{children.style.getPropertyView()}
302+
{children.clipPath.propertyView({
303+
label: trans("image.clipPath"),
304+
tooltip: trans("image.clipPathTip")
305+
})}
211306
</Section>
212307
<Section name={sectionNames.animationStyle} hasTooltip={true}>
213308
{children.animationStyle.getPropertyView()}

client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -1887,11 +1887,16 @@ export const NavigationStyle = [
18871887
] as const;
18881888

18891889
export const ImageStyle = [
1890-
getStaticBorder("#00000000"),
1891-
RADIUS,
1892-
BORDER_WIDTH,
1890+
// getStaticBorder("#00000000"),
18931891
MARGIN,
18941892
PADDING,
1893+
BORDER,
1894+
BORDER_STYLE,
1895+
RADIUS,
1896+
BORDER_WIDTH,
1897+
OPACITY,
1898+
BOXSHADOW,
1899+
BOXSHADOWCOLOR,
18951900
ROTATION
18961901
] as const;
18971902

client/packages/lowcoder/src/i18n/locales/en.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -2059,7 +2059,21 @@ export const en = {
20592059
"srcDesc": "The Image Source. Can be an URL, Path or Base64 String. for Example: data:image/png;base64, AAA... CCC",
20602060
"supportPreview": "Support Zoom Preview (on Click)",
20612061
"supportPreviewTip": "Effective When the Image Source is Valid",
2062-
"previewSrc": "HighRes Image Source"
2062+
"previewSrc": "HighRes Image Source",
2063+
"clipPath" : "Image Clipping Path",
2064+
"clipPathTip" : "Use clip-path to define a custom shape for your element based on CSS definition, referencing an SVG mask (via source URL) or using predefined shapes like circle(), ellipse(), polygon(), or inset() for clipping.",
2065+
"enableOverflow": "Enable Overflow",
2066+
"enableOverflowTip": "Allows the image to overflow its container, enabling cropping beyond the container's bounds. Useful for maintaining focus on specific parts of the image.",
2067+
"overflow": "Overflow Behavior (CSS)",
2068+
"overflowTip": "Defines how the content should behave when overflowing the container. Options like 'hidden', 'scroll', or 'visible' determine visibility of cropped content.",
2069+
"positionX": "Horizontal Position",
2070+
"positionXTip": "Specifies the horizontal alignment of the image within its container. Examples: 'left', 'center', 'right', or percentage values.",
2071+
"positionY": "Vertical Position",
2072+
"positionYTip": "Specifies the vertical alignment of the image within its container. Examples: 'top', 'center', 'bottom', or percentage values.",
2073+
"aspectRatio": "Aspect Ratio (CSS)",
2074+
"aspectRatioTip": "Maintains a consistent width-to-height ratio for the image, such as '16/9' for widescreen or '1/1' for square. Leave blank for natural image dimensions.",
2075+
"placement": "Image Placement",
2076+
"placementTip": "Determines where and how the image is displayed within the layout or container. Options include specific alignment or placement logic."
20632077
},
20642078
"progress": {
20652079
"value": "Value",

0 commit comments

Comments
 (0)