Skip to content

Commit

Permalink
Merge pull request #122 from sudhanshutech/toolbar-customSearch
Browse files Browse the repository at this point in the history
[components]: Toolbar custom components
  • Loading branch information
leecalcote authored Oct 29, 2023
2 parents 0a2a5af + 0c02847 commit 55bfc25
Show file tree
Hide file tree
Showing 12 changed files with 448 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/components/src/base/Popper/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Popper } from './popper';
5 changes: 5 additions & 0 deletions packages/components/src/base/Popper/popper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Popper as MuiPopper, type PopperProps } from '@mui/material';

export const Popper = (props: PopperProps) => {
return <MuiPopper {...props} />;
};
119 changes: 119 additions & 0 deletions packages/components/src/custom/Toolbar/custom-column.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import {
Checkbox,
ClickAwayListener,
FormControlLabel,
IconButton,
Paper,
Popper,
Tooltip
} from '@layer5/sistent-components';

import React, { useState } from 'react';
import ColumnIcon from '../../../../svg/src/icons/Column/columnIcon';

interface CustomColumnVisibilityControlProps {
columns: Column[];
customToolsProps: {
columnVisibility: Record<string, boolean>;
setColumnVisibility: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
};
style?: React.CSSProperties;
}

interface Column {
name: string;
label: string;
}

const CustomColumnVisibilityControl: React.FC<CustomColumnVisibilityControlProps> = ({
columns,
customToolsProps,
style
}) => {
const [open, setOpen] = useState(false);
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);

const handleOpen = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
setOpen(true);
};

const handleClose = () => {
setAnchorEl(null);
setOpen(false);
};

const handleColumnVisibilityChange = (columnName: string, isVisible: boolean) => {
customToolsProps.setColumnVisibility((prevState) => ({
...prevState,
[columnName]: isVisible
}));
};

return (
<div>
<Tooltip title="View Columns" arrow>
<IconButton
onClick={handleOpen}
sx={{
'&:hover': {
'& svg': {
fill: '#00d3a9'
},
borderRadius: '4px'
},
...style
}}
disableRipple
>
<ColumnIcon fill="#3c494f" />
</IconButton>
</Tooltip>

<Popper
open={Boolean(anchorEl)}
anchorEl={anchorEl}
placement="bottom-end"
modifiers={{
flip: {
enabled: false
},
preventOverflow: {
enabled: true,
boundariesElement: 'scrollParent'
}
}}
transition
>
<ClickAwayListener onClickAway={handleClose}>
<Paper
sx={{
padding: '1rem',
boxShadow: open ? '0px 4px 8px rgba(0, 0, 0, 0.2)' : 'none',
background: '#f4f5f7'
}}
>
<div style={{ display: 'flex', flexDirection: 'column' }}>
{columns.map((col) => (
<FormControlLabel
key={col.name}
control={
<Checkbox
checked={customToolsProps.columnVisibility[col.name]}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
handleColumnVisibilityChange(col.name, e.target.checked)
}
/>
}
label={col.label}
/>
))}
</div>
</Paper>
</ClickAwayListener>
</Popper>
</div>
);
};

export default CustomColumnVisibilityControl;
155 changes: 155 additions & 0 deletions packages/components/src/custom/Toolbar/custom-filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import {
Button,
ClickAwayListener,
IconButton,
MenuItem,
Paper,
Popper,
Select,
Tooltip
} from '@layer5/sistent-components';
import InputLabel from '@mui/material/InputLabel';
import React, { useState } from 'react';
import FilterIcon from '../../../../svg/src/icons/Filter/FilterIcon';

interface FilterColumn {
name: string;
options: { label: string; value: string }[];
}

interface UniversalFilterProps {
filters: Record<string, FilterColumn>;
selectedFilters: Record<string, string>;
setSelectedFilters: React.Dispatch<React.SetStateAction<Record<string, string>>>;
handleApplyFilter: () => void;
showAllOption?: boolean;
}

const UniversalFilter: React.FC<UniversalFilterProps> = ({
filters,
selectedFilters,
setSelectedFilters,
handleApplyFilter,
showAllOption = true
}) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [open, setOpen] = useState(false);

const handleFilterChange = (event: React.ChangeEvent<{ value: string }>, columnName: string) => {
const value = event.target.value;

setSelectedFilters((prevFilters) => ({
...prevFilters,
[columnName]: value
}));
};

const handleApplyOnClick = () => {
handleClose();
handleApplyFilter();
};

const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
setOpen((previousOpen) => !previousOpen);
};

const canBeOpen = open && Boolean(anchorEl);
const id = canBeOpen ? 'transition-popper' : undefined;

const handleClose = () => {
setAnchorEl(null);
setOpen(false);
};

return (
<div>
<Tooltip title="Filter" arrow>
<IconButton
onClick={handleClick}
sx={{
'&:hover': {
'& svg': {
fill: '#00d3a9'
}
}
}}
disableRipple
>
<FilterIcon fill="#3c494f" />
</IconButton>
</Tooltip>
<Popper
id={id}
open={open}
anchorEl={anchorEl}
placement="bottom-end"
modifiers={{
flip: {
enabled: false
},
preventOverflow: {
enabled: true,
boundariesElement: 'scrollParent'
}
}}
transition
>
<ClickAwayListener
onClickAway={handleClose}
mouseEvent="onMouseDown"
touchEvent="onTouchStart"
>
<Paper
sx={{
padding: '1rem',
paddingTop: '1.8rem',
boxShadow: '0px 4px 8px rgba(0, 0, 0, 0.1)',
backgroundColor: '#f4f5f7'
}}
>
{Object.keys(filters).map((filterColumn) => {
const options = filters[filterColumn].options;
return (
<div key={filterColumn} role="presentation">
<InputLabel id={filters[filterColumn].name}>
{filters[filterColumn].name}
</InputLabel>
<Select
defaultValue="All"
key={filterColumn}
value={selectedFilters[filterColumn]}
onChange={(e: React.ChangeEvent<{ value: string }>) =>
handleFilterChange(e, filterColumn)
}
style={{
width: '15rem',
marginBottom: '1rem'
}}
inputProps={{ 'aria-label': 'Without label' }}
displayEmpty
>
{showAllOption && <MenuItem value="All">All</MenuItem>}
{options.map((option) => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</Select>
</div>
);
})}

<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button variant="contained" onClick={handleApplyOnClick}>
Apply
</Button>
</div>
</Paper>
</ClickAwayListener>
</Popper>
</div>
);
};

export default UniversalFilter;
106 changes: 106 additions & 0 deletions packages/components/src/custom/Toolbar/custom-search.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { IconButton, TextField, Tooltip } from '@layer5/sistent-components';
import React, { useRef, useState } from 'react';
import CloseIcon from '../../../../svg/src/icons/Close/closeIcon';
import SearchIcon from '../../../../svg/src/icons/Search/searchIcon';

interface SearchBarProps {
onSearch: (searchText: string) => void;
style?: React.CSSProperties;
placeholder?: string;
onClear?: () => void;
expanded: boolean;
setExpanded: (expanded: boolean) => void;
}

const SearchBar: React.FC<SearchBarProps> = ({ placeholder, onClear, expanded, setExpanded }) => {
const [searchText, setSearchText] = useState('');
const searchRef = useRef<HTMLInputElement | null>(null);

const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
setSearchText(event.target.value);
};

const handleClearIconClick = (): void => {
setSearchText('');
setExpanded(false);
if (onClear) {
onClear();
}
};

const handleSearchIconClick = (): void => {
if (expanded) {
setSearchText('');
setExpanded(false);
} else {
setExpanded(true);
setTimeout(() => {
if (searchRef.current) {
searchRef.current.focus();
}
}, 300);
}
};

//Todo: Need a width utility function
// const width = window.innerWidth;
// let searchWidth = "200px";
// if (width <= 360) {
// searchWidth = "100px";
// }

return (
<div>
<TextField
variant="standard"
value={searchText}
onChange={handleSearchChange}
inputRef={searchRef}
placeholder={placeholder}
style={{
width: '150px',
opacity: expanded ? 1 : 0,
transition: 'width 0.3s ease, opacity 0.3s ease'
}}
/>

{expanded ? (
<Tooltip title="Close">
<IconButton
onClick={handleClearIconClick}
sx={{
'&:hover': {
'& svg': {
fill: '#00D3A9'
},
borderRadius: '4px'
}
}}
disableRipple
>
<CloseIcon fill="#00D3A9" />
</IconButton>
</Tooltip>
) : (
<Tooltip title="Search" arrow>
<IconButton
onClick={handleSearchIconClick}
sx={{
'&:hover': {
'& svg': {
fill: '#00D3A9'
},
borderRadius: '4px'
}
}}
disableRipple
>
<SearchIcon fill="#00D3A9" />
</IconButton>
</Tooltip>
)}
</div>
);
};

export default SearchBar;
3 changes: 3 additions & 0 deletions packages/components/src/custom/Toolbar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './custom-column';
export * from './custom-filter';
export * from './custom-search';
Loading

0 comments on commit 55bfc25

Please sign in to comment.