Skip to content

Commit 1c6f8bd

Browse files
committed
Tags Component Completed
1 parent c682cc0 commit 1c6f8bd

File tree

9 files changed

+270
-80
lines changed

9 files changed

+270
-80
lines changed

client/packages/lowcoder-design/src/icons/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ export { ReactComponent as VideoCameraStreamCompIconSmall } from "./v2/camera-st
355355
export { ReactComponent as VideoScreenshareCompIconSmall } from "./v2/screen-share-stream-s.svg"; // new
356356
export { ReactComponent as SignatureCompIconSmall } from "./v2/signature-s.svg";
357357
export { ReactComponent as StepCompIconSmall } from "./v2/steps-s.svg";
358+
export { ReactComponent as TagsCompIconSmall } from "./v2/tags-s.svg"
358359

359360

360361
export { ReactComponent as CandlestickChartCompIconSmall } from "./v2/candlestick-chart-s.svg"; // new
@@ -468,6 +469,7 @@ export { ReactComponent as SignatureCompIcon } from "./v2/signature-m.svg";
468469
export { ReactComponent as GanttCompIcon } from "./v2/gantt-chart-m.svg";
469470
export { ReactComponent as KanbanCompIconSmall } from "./v2/kanban-s.svg";
470471
export { ReactComponent as KanbanCompIcon } from "./v2/kanban-m.svg";
472+
export { ReactComponent as TagsCompIcon } from "./v2/tags-l.svg";
471473

472474
export { ReactComponent as CandlestickChartCompIcon } from "./v2/candlestick-chart-m.svg";
473475
export { ReactComponent as FunnelChartCompIcon } from "./v2/funnel-chart-m.svg";
Lines changed: 10 additions & 0 deletions
Loading
Lines changed: 10 additions & 0 deletions
Loading

client/packages/lowcoder/src/comps/comps/selectInputComp/multiSelectComp.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ let MultiSelectBasicComp = (function () {
3030
padding: PaddingControl,
3131
};
3232
return new UICompBuilder(childrenMap, (props, dispatch) => {
33-
const valueSet = new Set<any>(props.options.map((o) => o.value)); // Filter illegal default values entered by the user
33+
const valueSet = new Set<any>((props.options as any[]).map((o: any) => o.value)); // Filter illegal default values entered by the user
3434
const [
3535
validateState,
3636
handleChange,

client/packages/lowcoder/src/comps/comps/selectInputComp/selectComp.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ let SelectBasicComp = (function () {
3939
const propsRef = useRef<RecordConstructorToView<typeof childrenMap>>(props);
4040
propsRef.current = props;
4141

42-
const valueSet = new Set<any>(props.options.map((o) => o.value)); // Filter illegal default values entered by the user
42+
const valueSet = new Set<any>((props.options as any[]).map((o: any) => o.value)); // Filter illegal default values entered by the user
4343

4444
return props.label({
4545
required: props.required,
Lines changed: 158 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,179 @@
1-
import { AnimationStyle, BoolCodeControl, ButtonEventHandlerControl, CommonNameConfig, DropdownOptionControl, IconControl, LinkStyle, NameConfig, NameConfigDisabled, RefControl, Section, SelectOptionControl, StringControl, TabsOptionControl, TagsOptionControl, UICompBuilder, blurMethod, clickMethod, focusWithOptions, migrateOldData, refMethods, sectionNames, stringExposingStateControl, styleControl, withDefault, withExposingConfigs } from "@lowcoder-ee/index.sdk";
2-
import React from "react";
1+
import {
2+
BoolCodeControl,
3+
ButtonEventHandlerControl,
4+
InputLikeStyle,
5+
NameConfig,
6+
Section,
7+
UICompBuilder,
8+
hiddenPropertyView,
9+
sectionNames,
10+
showDataLoadingIndicatorsPropertyView,
11+
styleControl,
12+
withExposingConfigs
13+
} from "@lowcoder-ee/index.sdk";
14+
import styled from "styled-components";
15+
import React, { useContext } from "react";
316
import { trans } from "i18n";
4-
import { buttonRefMethods } from "../buttonComp/buttonCompConstants";
517
import { Tag } from "antd";
6-
import { autoCompleteRefMethods } from "../autoCompleteComp/autoCompleteConstants";
18+
import { EditorContext } from "comps/editorState";
19+
import { PresetStatusColorTypes } from "antd/es/_util/colors";
20+
import { hashToNum } from "util/stringUtils";
21+
import { TagsCompOptionsControl } from "comps/controls/optionsControl";
22+
import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler";
723

24+
const colors = PresetStatusColorTypes;
825

9-
// const TagsCompView = (function () {
10-
// // const childrenMap = {
11-
// // text: withDefault(StringControl, trans("link.link")),
12-
// // onEvent: ButtonEventHandlerControl,
13-
// // disabled: BoolCodeControl,
14-
// // loading: BoolCodeControl,
15-
16-
// // // style: migrateOldData(styleControl(LinkStyle, 'style')),
17-
// // animationStyle: styleControl(AnimationStyle, 'animationStyle'),
18-
// // prefixIcon: IconControl,
19-
// // suffixIcon: IconControl,
20-
// // viewRef: RefControl<HTMLElement>,
21-
// // };
26+
// These functions are used for individual tag styling
27+
function getTagColor(tagText : any, tagOptions: any[]) {
28+
const foundOption = tagOptions.find((option: { label: any; }) => option.label === tagText);
29+
if (foundOption) {
30+
if (foundOption.colorType === "preset") {
31+
return foundOption.presetColor;
32+
} else if (foundOption.colorType === "custom") {
33+
return undefined;
34+
}
35+
return foundOption.color;
36+
}
37+
const index = Math.abs(hashToNum(tagText)) % colors.length;
38+
return colors[index];
39+
}
2240

23-
// const childrenMap = {
24-
// text: stringExposingStateControl("text", "world"),
25-
// // options: TabsOptionControl,
26-
// };
27-
// return new UICompBuilder(childrenMap, (props) => {
28-
// return (
29-
// <Tag>Tag 1</Tag>
30-
// )
31-
// })
32-
// .setPropertyViewFn((children) => {
33-
// return(
34-
// <Section name={sectionNames.basic}>
35-
// {/* {children.options.propertyView({})} */}
36-
// {children.text.propertyView({ label: trans("text") })}
37-
// </Section>
38-
// )
39-
// })
40-
// .build();
41-
// })();
41+
const getTagStyle = (tagText: any, tagOptions: any[], baseStyle: any = {}) => {
42+
const foundOption = tagOptions.find((option: { label: any; }) => option.label === tagText);
43+
if (foundOption) {
44+
const style: any = { ...baseStyle };
45+
46+
if (foundOption.colorType === "custom") {
47+
style.backgroundColor = foundOption.color;
48+
style.color = foundOption.textColor;
49+
style.border = `1px solid ${foundOption.color}`;
50+
}
51+
52+
if (foundOption.border) {
53+
style.borderColor = foundOption.border;
54+
if (!foundOption.colorType || foundOption.colorType !== "custom") {
55+
style.border = `1px solid ${foundOption.border}`;
56+
}
57+
}
58+
59+
if (foundOption.radius) {
60+
style.borderRadius = foundOption.radius;
61+
}
62+
63+
if (foundOption.margin) {
64+
style.margin = foundOption.margin;
65+
}
66+
67+
if (foundOption.padding) {
68+
style.padding = foundOption.padding;
69+
}
70+
71+
return style;
72+
}
73+
return baseStyle;
74+
};
75+
76+
function getTagIcon(tagText: any, tagOptions: any[]) {
77+
const foundOption = tagOptions.find(option => option.label === tagText);
78+
return foundOption ? foundOption.icon : undefined;
79+
}
4280

4381
const multiTags = (function () {
82+
83+
const StyledTag = styled(Tag)<{ $style: any, $bordered: boolean, $customStyle: any }>`
84+
display: flex;
85+
justify-content: center;
86+
align-items: center;
87+
width: 100%;
88+
background: ${(props) => props.$customStyle?.backgroundColor || props.$style?.background};
89+
color: ${(props) => props.$customStyle?.color || props.$style?.text};
90+
border-radius: ${(props) => props.$customStyle?.borderRadius || props.$style?.borderRadius};
91+
border: ${(props) => {
92+
if (props.$customStyle?.border) return props.$customStyle.border;
93+
return props.$bordered ? `${props.$style?.borderStyle} ${props.$style?.borderWidth} ${props.$style?.border}` : 'none';
94+
}};
95+
padding: ${(props) => props.$customStyle?.padding || props.$style?.padding};
96+
margin: ${(props) => props.$customStyle?.margin || props.$style?.margin};
97+
font-size: ${(props) => props.$style?.textSize};
98+
font-weight: ${(props) => props.$style?.fontWeight};
99+
cursor: pointer;
100+
`;
101+
102+
const StyledTagContainer = styled.div`
103+
display: flex;
104+
gap: 5px;
105+
padding: 5px;
106+
`;
107+
44108
const childrenMap = {
45-
text: stringExposingStateControl("text", "world"),
46-
options: TagsOptionControl,
109+
options: TagsCompOptionsControl,
110+
style: styleControl(InputLikeStyle, 'style'),
111+
onEvent: ButtonEventHandlerControl,
112+
borderless: BoolCodeControl,
113+
enableIndividualStyling: BoolCodeControl,
47114
};
48115

49116
return new UICompBuilder(childrenMap, (props) => {
50-
const text = props.text.value;
51-
console.log(props.options)
117+
const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent});
118+
52119
return (
53-
<>
54-
{props.options.map(tag => (
55-
<Tag>{tag.label}</Tag>
56-
))}
57-
</>
58-
);
120+
<StyledTagContainer>
121+
{props.options.map((tag, index) => {
122+
123+
// Use individual styling only if enableIndividualStyling is true
124+
const tagColor = props.enableIndividualStyling ? getTagColor(tag.label, props.options) : undefined;
125+
const tagIcon = props.enableIndividualStyling ? getTagIcon(tag.label, props.options) : tag.icon;
126+
const tagStyle = props.enableIndividualStyling ? getTagStyle(tag.label, props.options, props.style) : {};
127+
128+
return (
129+
<StyledTag
130+
key={`tag-${index}`}
131+
$style={props.style}
132+
$bordered={!props.borderless}
133+
$customStyle={tagStyle}
134+
icon={tagIcon}
135+
color={tagColor}
136+
onClick={() => handleClickEvent()}
137+
>
138+
{tag.label}
139+
</StyledTag>
140+
);
141+
})}
142+
</StyledTagContainer>
143+
);
59144
})
60145
.setPropertyViewFn((children: any) => {
61146
return (
62-
<Section name="Basic">
63-
{children.options.propertyView({})}
64-
{children.text.propertyView({ label: "Text" })}
65-
</Section>
147+
<>
148+
<Section name="Basic">
149+
{children.options.propertyView({})}
150+
</Section>
151+
152+
{["logic", "both"].includes(useContext(EditorContext).editorModeStatus) && (
153+
<Section name={sectionNames.interaction}>
154+
{children.onEvent.getPropertyView()}
155+
{hiddenPropertyView(children)}
156+
{showDataLoadingIndicatorsPropertyView(children)}
157+
</Section>
158+
)}
159+
160+
{["layout", "both"].includes(
161+
useContext(EditorContext).editorModeStatus
162+
) && (
163+
<Section name={sectionNames.style}>
164+
{children.enableIndividualStyling.propertyView({
165+
label: trans("style.individualStyling"),
166+
tooltip: trans("style.individualStylingTooltip")
167+
})}
168+
{children.borderless.propertyView({ label: trans("style.borderless") })}
169+
{children.style.getPropertyView()}
170+
</Section>
171+
)}
172+
</>
66173
)
67174
})
68175
.build();
69176
})()
70177

71-
72-
// const childrenMap = {
73-
// text: stringExposingStateControl("text", "world"),
74-
// options: TagsOptionControl,
75-
// };
76-
77-
// const TagsCompView = new UICompBuilder(childrenMap, (props: any) => {
78-
// const text = props.text.value;
79-
// return <div>Hello {text}</div>;
80-
// })
81-
// .setPropertyViewFn((children: any) => {
82-
// return (
83-
// <Section name="Basic">
84-
// {children.options.propertyView({})}
85-
// {children.text.propertyView({ label: "Text" })}
86-
// </Section>
87-
// )
88-
// })
89-
// .build();
90-
91-
export const MultiTagsComp = withExposingConfigs(multiTags, [new NameConfig("text", "")]);
178+
export const MultiTagsComp = withExposingConfigs(multiTags, [new NameConfig("options", "")]);
92179

0 commit comments

Comments
 (0)