Files
react-test/docs/data/material/components/transfer-list/TransferList.tsx
how2ice 005cf56baf
Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
init project
2025-12-12 14:26:25 +09:00

147 lines
4.1 KiB
TypeScript

import * as React from 'react';
import Grid from '@mui/material/Grid';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Checkbox from '@mui/material/Checkbox';
import Button from '@mui/material/Button';
import Paper from '@mui/material/Paper';
function not(a: readonly number[], b: readonly number[]) {
return a.filter((value) => !b.includes(value));
}
function intersection(a: readonly number[], b: readonly number[]) {
return a.filter((value) => b.includes(value));
}
export default function TransferList() {
const [checked, setChecked] = React.useState<readonly number[]>([]);
const [left, setLeft] = React.useState<readonly number[]>([0, 1, 2, 3]);
const [right, setRight] = React.useState<readonly number[]>([4, 5, 6, 7]);
const leftChecked = intersection(checked, left);
const rightChecked = intersection(checked, right);
const handleToggle = (value: number) => () => {
const currentIndex = checked.indexOf(value);
const newChecked = [...checked];
if (currentIndex === -1) {
newChecked.push(value);
} else {
newChecked.splice(currentIndex, 1);
}
setChecked(newChecked);
};
const handleAllRight = () => {
setRight(right.concat(left));
setLeft([]);
};
const handleCheckedRight = () => {
setRight(right.concat(leftChecked));
setLeft(not(left, leftChecked));
setChecked(not(checked, leftChecked));
};
const handleCheckedLeft = () => {
setLeft(left.concat(rightChecked));
setRight(not(right, rightChecked));
setChecked(not(checked, rightChecked));
};
const handleAllLeft = () => {
setLeft(left.concat(right));
setRight([]);
};
const customList = (items: readonly number[]) => (
<Paper sx={{ width: 200, height: 230, overflow: 'auto' }}>
<List dense component="div" role="list">
{items.map((value: number) => {
const labelId = `transfer-list-item-${value}-label`;
return (
<ListItemButton
key={value}
role="listitem"
onClick={handleToggle(value)}
>
<ListItemIcon>
<Checkbox
checked={checked.includes(value)}
tabIndex={-1}
disableRipple
inputProps={{
'aria-labelledby': labelId,
}}
/>
</ListItemIcon>
<ListItemText id={labelId} primary={`List item ${value + 1}`} />
</ListItemButton>
);
})}
</List>
</Paper>
);
return (
<Grid
container
spacing={2}
sx={{ justifyContent: 'center', alignItems: 'center' }}
>
<Grid>{customList(left)}</Grid>
<Grid>
<Grid container direction="column" sx={{ alignItems: 'center' }}>
<Button
sx={{ my: 0.5 }}
variant="outlined"
size="small"
onClick={handleAllRight}
disabled={left.length === 0}
aria-label="move all right"
>
</Button>
<Button
sx={{ my: 0.5 }}
variant="outlined"
size="small"
onClick={handleCheckedRight}
disabled={leftChecked.length === 0}
aria-label="move selected right"
>
&gt;
</Button>
<Button
sx={{ my: 0.5 }}
variant="outlined"
size="small"
onClick={handleCheckedLeft}
disabled={rightChecked.length === 0}
aria-label="move selected left"
>
&lt;
</Button>
<Button
sx={{ my: 0.5 }}
variant="outlined"
size="small"
onClick={handleAllLeft}
disabled={right.length === 0}
aria-label="move all left"
>
</Button>
</Grid>
</Grid>
<Grid>{customList(right)}</Grid>
</Grid>
);
}