Skip to content

Commit

Permalink
GUI Components: add List component (#3780)
Browse files Browse the repository at this point in the history
  • Loading branch information
AleksandrGorodetskii committed Nov 26, 2024
1 parent a550313 commit e813d2a
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 4 deletions.
71 changes: 71 additions & 0 deletions portals-ui/packages/components/lib/components/list/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type { Key, ReactNode } from 'react';
import React, { useState } from 'react';
import type { VirtualListState } from '@epam/uui-core';
import type { CommonProps } from '../..';
import { VirtualList } from '@epam/uui';
import classNames from 'classnames';

const MIN_VISIBLE_COUNT = 20;

export type ListProps<Item> = CommonProps & {
data: Item[];
renderItem: (item: Item, index: number) => ReactNode | string;
header?: ReactNode;
footer?: ReactNode;
virtualized?: boolean;
fieldKey?: string;
};

export default function List<Item>(props: ListProps<Item>): ReactNode {
const {
header,
footer,
data,
renderItem,
fieldKey,
virtualized = false,
style,
className,
} = props;
const [listState, setListState] = useState<VirtualListState>({
topIndex: 0,
visibleCount: MIN_VISIBLE_COUNT,
});
const visibleData = data.slice(
listState.topIndex,
(listState.topIndex ?? 0) + (listState.visibleCount ?? MIN_VISIBLE_COUNT),
);
const rows = visibleData.map((item, index) => (
<React.Fragment key={index}>{renderItem(item, index)}</React.Fragment>
));
const listComponent = virtualized ? (
<VirtualList
cx="max-h-full"
rows={rows}
value={listState}
onValueChange={setListState}
rowsCount={data.length}
/>
) : (
<div className="overflow-y-auto">
{data.map((item, index) => {
let key: Key = `key_${index}`;
if (item && typeof item === 'object' && fieldKey) {
key = (item[fieldKey as keyof typeof item] as string | number) ?? key;
}
return (
<React.Fragment key={key}>{renderItem(item, index)}</React.Fragment>
);
})}
</div>
);
return (
<div
style={style}
className={classNames('overflow-hidden flex flex-col', className)}>
{header ?? null}
{listComponent}
{footer ?? null}
</div>
);
}
3 changes: 2 additions & 1 deletion portals-ui/packages/components/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import DummyComponent from './components/dummy-component';
import List from './components/list';
import '@epam/uui-components/styles.css';
import '@epam/uui/styles.css';
import './style.css';

export { DummyComponent };
export { DummyComponent, List };
export * from './components/common.types';
56 changes: 53 additions & 3 deletions portals-ui/sites/ngs-portal/src/pages/home/home.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,59 @@
import { DummyComponent } from '@cloud-pipeline/components';
import { useEffect } from 'react';
import { List } from '@cloud-pipeline/components';
import { useProjectsState } from '../../state/projects/hooks';
import { loadProjects } from '../../state/projects/load-projects';
import type { Project } from '@cloud-pipeline/core';
import './style.css';

export const Home = () => {
const { projects } = useProjectsState();
useEffect(() => {
loadProjects()
.then(() => {})
.catch(() => {});
}, []);
if (!projects) {
return null;
}
return (
<div>
<DummyComponent />
<div className="flex h-full gap-5 overflow-hidden flex-nowrap justify-around p-2">
<List
className="list-container"
header={<div className="p-2 list-header-container">Projects</div>}
footer={<div className="p-2">List footer</div>}
data={projects}
virtualized
renderItem={(item: Project) => (
<div className="p-2" style={{ height: 100 }}>
{item.name}
</div>
)}
style={{ flex: 1 }}
/>
<List
className="list-container"
header={<div className="p-2">List header</div>}
footer={<div className="p-2">List footer</div>}
data={projects}
virtualized
renderItem={(item: Project) => (
<div className="p-2" style={{ height: 100 }}>
{item.name}
</div>
)}
style={{ flex: 1 }}
/>
<List
className="list-container"
data={projects}
virtualized
renderItem={(item: Project) => (
<div className="p-2" style={{ height: 300 }}>
{item.name}
</div>
)}
style={{ flex: 1 }}
/>
</div>
);
};
8 changes: 8 additions & 0 deletions portals-ui/sites/ngs-portal/src/pages/home/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.list-container {
box-shadow: var(--uui-shadow-level-1);
border-radius: var(--uui-border-radius);
}

.list-header-container {
box-shadow: var(--uui-shadow-level-1);
}

0 comments on commit e813d2a

Please sign in to comment.