Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2664082
clone original Table Comp
iamfaran Aug 5, 2025
9ff640d
register table lite comp
iamfaran Aug 5, 2025
491782f
remove expansion data layer
iamfaran Aug 5, 2025
b43d31e
remove expansion functionality from table
iamfaran Aug 6, 2025
13cdeff
fix imports for table lite comp
iamfaran Aug 6, 2025
966c4df
remove edit functionality
iamfaran Aug 6, 2025
4d75755
remove filter modal / table toolbar unnecessary code
iamfaran Aug 8, 2025
d03a02d
remove search filter and fix css issue
iamfaran Aug 11, 2025
5d6301e
remove edit / insert functions
iamfaran Aug 11, 2025
714e6cc
remove row context
iamfaran Aug 11, 2025
d4afdb4
split down tableComp.tsx
iamfaran Aug 12, 2025
8b492c2
refactor tableCompView
iamfaran Aug 13, 2025
a909c64
refactor / add virtualization
iamfaran Aug 15, 2025
18a93cf
remove edit functionality from columns
iamfaran Aug 18, 2025
6b34a8d
remove remaining edit functionality from the columns
iamfaran Aug 18, 2025
38c8653
remove change value props
iamfaran Aug 18, 2025
c82279e
refactor columnToAntd function
iamfaran Aug 18, 2025
29f29b3
remove more edit related code from columns
iamfaran Aug 18, 2025
c406bb5
add basic filters in headers
iamfaran Aug 19, 2025
f09e36f
add dynamic virtualization
iamfaran Aug 20, 2025
07abda7
remove unnecssory code for virtualization
iamfaran Aug 20, 2025
5a6ac32
fix x scrolling
iamfaran Aug 20, 2025
3af069a
scroll fixes
iamfaran Aug 20, 2025
1e1b61e
fix virtualization toolbar bottom
iamfaran Aug 20, 2025
e98b05c
hide horizontal scroll virtualization
iamfaran Aug 20, 2025
fed09b1
fix y scroll
iamfaran Aug 20, 2025
58f13b2
delete rc-virtual-list
iamfaran Aug 20, 2025
b8c7586
fix infinite re renders / unnecessary logic
iamfaran Aug 21, 2025
c84c902
add styling structure / refactor styles
iamfaran Aug 22, 2025
67f9952
add custom Hook to calculate table height / body
iamfaran Aug 25, 2025
26f6b10
Add Base Table component
iamfaran Aug 25, 2025
4fd3e12
Add auto / fixed tables
iamfaran Aug 25, 2025
37d494a
basic refactor complete
iamfaran Aug 25, 2025
d73a5ff
add styles
iamfaran Aug 26, 2025
3edaee4
fix header styles
iamfaran Aug 26, 2025
4590bfe
add remaining styles
iamfaran Aug 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ const ColumnDropdown = styled(Dropdown)`
const ColumnBatchOptionWrapper = styled.div`
display: flex;
align-items: center;
color: ${GreyTextColor}
color: ${GreyTextColor};
line-height: 16px;
font-size: 13px;
`;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { DateTimeComp } from "comps/comps/tableComp/column/columnTypeComps/columnDateTimeComp";
import { TimeComp } from "./columnTypeComps/columnTimeComp";
import { ButtonComp } from "./simpleColumnTypeComps";
import { withType } from "comps/generators";
import { trans } from "i18n";
import { Dropdown } from "lowcoder-design/src/components/Dropdown";
import { BooleanComp } from "./columnTypeComps/columnBooleanComp";
import { SwitchComp } from "./columnTypeComps/columnSwitchComp";
import { DateComp } from "./columnTypeComps/columnDateComp";
import { ImageComp } from "./columnTypeComps/columnImgComp";
import { LinkComp } from "./columnTypeComps/columnLinkComp";
import { ColumnLinksComp } from "./columnTypeComps/columnLinksComp";
import { ColumnMarkdownComp } from "./columnTypeComps/columnMarkdownComp";
import { ProgressComp } from "./columnTypeComps/columnProgressComp";
import { RatingComp } from "./columnTypeComps/columnRatingComp";
import { BadgeStatusComp } from "./columnTypeComps/columnStatusComp";
import { ColumnTagsComp } from "./columnTypeComps/columnTagsComp";
import { ColumnSelectComp } from "./columnTypeComps/columnSelectComp";
import { SimpleTextComp } from "./columnTypeComps/simpleTextComp";
import { ColumnNumberComp } from "./columnTypeComps/ColumnNumberComp";

import { ColumnAvatarsComp } from "./columnTypeComps/columnAvatarsComp";
import { ColumnDropdownComp } from "./columnTypeComps/columnDropdownComp";

export type CellProps = {
tableSize?: string;
candidateTags?: string[];
candidateStatus?: { text: string; status: any }[];
textOverflow?: boolean;
cellTooltip?: string;
onTableEvent?: (eventName: any) => void;
cellIndex?: string;
};

const actionOptions = [
{
label: trans("table.avatars"),
value: "avatars",
},
{
label: trans("table.text"),
value: "text",
},
{
label: trans("table.number"),
value: "number",
},
{
label: trans("table.link"),
value: "link",
},
{
label: trans("table.links"),
value: "links",
},
{
label: trans("table.tag"),
value: "tag",
},
{
label: trans("table.select"),
value: "select",
},
{
label: trans("table.dropdown"),
value: "dropdown",
},
{
label: trans("table.badgeStatus"),
value: "badgeStatus",
},
{
label: trans("table.button"),
value: "button",
},
{
label: trans("table.image"),
value: "image",
},
{
label: trans("table.time"),
value: "time",
},

{
label: trans("table.date"),
value: "date",
},
{
label: trans("table.dateTime"),
value: "dateTime",
},
{
label: "Markdown",
value: "markdown",
},
{
label: trans("table.boolean"),
value: "boolean",
},
{
label: trans("table.switch"),
value: "switch",
},
{
label: trans("table.rating"),
value: "rating",
},
{
label: trans("table.progress"),
value: "progress",
},
] as const;

export const ColumnTypeCompMap = {
avatars: ColumnAvatarsComp,
text: SimpleTextComp,
number: ColumnNumberComp,
button: ButtonComp,
badgeStatus: BadgeStatusComp,
link: LinkComp,
tag: ColumnTagsComp,
select: ColumnSelectComp,
dropdown: ColumnDropdownComp,
links: ColumnLinksComp,
image: ImageComp,
markdown: ColumnMarkdownComp,
dateTime: DateTimeComp,
boolean: BooleanComp,
switch: SwitchComp,
rating: RatingComp,
progress: ProgressComp,
date: DateComp,
time: TimeComp,
};

type ColumnTypeMapType = typeof ColumnTypeCompMap;
export type ColumnTypeKeys = keyof ColumnTypeMapType;

const TypedColumnTypeComp = withType(ColumnTypeCompMap, "text");

export class ColumnTypeComp extends TypedColumnTypeComp {
override getView() {
const childView = this.children.comp.getView();
return {
view: (cellProps: CellProps) => {
return childView(cellProps);
},
value: this.children.comp.getDisplayValue(),
};
}

private handleTypeChange: (value: ColumnTypeKeys) => void = (value) => {
// Keep the previous text value, some components do not have text, the default value is currentCell
let textRawData = "{{currentCell}}";
if (this.children.comp.children.hasOwnProperty("text")) {
textRawData = (this.children.comp.children as any).text.toJsonValue();
}
this.dispatchChangeValueAction({
compType: value,
comp: { text: textRawData },
} as any);
}

override getPropertyView() {
return (
<>
<Dropdown
showSearch={true}
value={this.children.compType.getView()}
options={actionOptions}
label={trans("table.columnType")}
onChange={this.handleTypeChange}
/>
{this.children.comp.getPropertyView()}
</>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import { CellViewReturn } from "components/table/EditableCell";
import { stateComp } from "comps/generators";
import {
MultiCompBuilder,
PropertyViewFnTypeForComp,
ToConstructor,
ViewFnTypeForComp,
} from "comps/generators/multi";
import _ from "lodash";
import {
CompConstructor,
ConstructorToNodeType,
fromRecord,
NodeToValue,
RecordConstructorToComp,
withFunction,
} from "lowcoder-core";
import { ReactNode } from "react";
import { JSONValue } from "util/jsonTypes";

export const __COLUMN_DISPLAY_VALUE_FN = "__COLUMN_DISPLAY_VALUE_FN";

type RecordConstructorToNodeValue<T> = {
[K in keyof T]: NodeToValue<ConstructorToNodeType<T[K]>>;
};

type ViewValueFnType<ChildrenCtorMap extends Record<string, CompConstructor<unknown>>> = (
nodeValue: RecordConstructorToNodeValue<ChildrenCtorMap>
) => JSONValue;

export type ColumnTypeViewFn<ChildrenCtroMap, T extends JSONValue, ViewReturn> = ViewFnTypeForComp<
ViewReturn,
RecordConstructorToComp<ChildrenCtroMap>
>;

export class ColumnTypeCompBuilder<
ChildrenCtorMap extends Record<string, CompConstructor<unknown>>,
T extends JSONValue = JSONValue
> {
private childrenMap: ChildrenCtorMap;
private propertyViewFn?: PropertyViewFnTypeForComp<
RecordConstructorToComp<ChildrenCtorMap>
>;
private stylePropertyViewFn?: PropertyViewFnTypeForComp<
RecordConstructorToComp<ChildrenCtorMap>
>;
private cleanupFunctions: (() => void)[] = [];

constructor(
childrenMap: ChildrenCtorMap,
private viewFn: ColumnTypeViewFn<ChildrenCtorMap, T, ReactNode>,
private displayValueFn: ViewValueFnType<ChildrenCtorMap>,
private baseValueFn?: ColumnTypeViewFn<ChildrenCtorMap, T, T>
) {
this.childrenMap = { ...childrenMap } as ChildrenCtorMap;
}

setEditViewFn(_: any) {
// Edit views are disabled in Table Lite; keep chainability without storing
return this;
}

setPropertyViewFn(
propertyViewFn: PropertyViewFnTypeForComp<
RecordConstructorToComp<ChildrenCtorMap>
>
) {
this.propertyViewFn = propertyViewFn;
return this;
}

setStylePropertyViewFn(
stylePropertyViewFn: PropertyViewFnTypeForComp<
RecordConstructorToComp<ChildrenCtorMap>
>
) {
this.stylePropertyViewFn = stylePropertyViewFn;
return this;
}

build() {
if (!this.propertyViewFn) {
throw new Error("need property view fn");
}

// Memoize the props processing
const memoizedViewFn = _.memoize(
(props: any, dispatch: any) => {
const baseValue = this.baseValueFn?.(props, dispatch);
const normalView = this.viewFn(props, dispatch);
return normalView;
},
(props) => {
let safeOptions = [];
let safeAvatars = [];
if(props.options) {
safeOptions = props.options.map((option: Record<string, any>) => {
const {prefixIcon, suffixIcon, ...safeOption} = option;
return safeOption;
})
}
if(props.avatars) {
safeAvatars = props.avatars.map((avatar: Record<string, any>) => {
const {AvatarIcon, ...safeAvatar} = avatar;
return safeAvatar;
})
}
const {
prefixIcon,
suffixIcon,
iconFalse,
iconTrue,
iconNull,
tagColors,
options,
avatars,
...safeProps
} = props;
return safeProps;
}
);

const viewFn: ColumnTypeViewFn<ChildrenCtorMap, T, CellViewReturn> =
(props, dispatch): CellViewReturn =>
(cellProps) => memoizedViewFn({ ...props, ...cellProps } as any, dispatch);

const ColumnTypeCompTmp = new MultiCompBuilder(
(this.childrenMap as unknown) as ToConstructor<
RecordConstructorToComp<ChildrenCtorMap>
>,
viewFn
)
.setPropertyViewFn(this.propertyViewFn)
.build();

const displayValueFn = this.displayValueFn;

return class extends ColumnTypeCompTmp {
// table cell data
private _displayValue: JSONValue = null;
private cleanupFunctions: (() => void)[] = [];
constructor(props: any) {
super(props);
this.cleanupFunctions.push(() => {
this._displayValue = null;
memoizedViewFn.cache.clear?.();
});
}

override extraNode() {
return {
node: {
[__COLUMN_DISPLAY_VALUE_FN]: withFunction(
fromRecord(this.childrenNode()),
() => displayValueFn
),
},
updateNodeFields: (value: any) => {
const displayValueFunc = value[__COLUMN_DISPLAY_VALUE_FN];
this._displayValue = displayValueFunc(value);
return { displayValue: this._displayValue };
},
};
}

/**
* Get the data actually displayed by the table cell
*/
getDisplayValue() {
return this._displayValue;
}

componentWillUnmount() {
// Cleanup all registered cleanup functions
this.cleanupFunctions.forEach(cleanup => cleanup());
this.cleanupFunctions = [];
}
};
}

// Cleanup method to be called when the builder is no longer needed
cleanup() {
this.cleanupFunctions.forEach(cleanup => cleanup());
this.cleanupFunctions = [];
}
}
Loading
Loading