multiselect component

This commit is contained in:
Red Adaya 2024-12-18 13:32:51 +08:00
parent 69bb1d4274
commit 11c8723b37
5 changed files with 145 additions and 0 deletions

View File

@ -0,0 +1,44 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
.multi-select {
border-radius: 7px;
background: rgb(from var(--block-bg-color) r g b / 70%);
color: var(--main-text-color);
padding: 4px;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 3px;
align-self: stretch;
border: 1px solid rgb(from var(--main-text-color) r g b / 15%);
width: 100%;
.option {
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
padding: 9px 12px;
border-radius: 4px;
align-self: stretch;
border: 1px solid transparent;
&:hover {
background-color: rgb(from var(--main-bg-color) r g b / 60%);
}
&.selected {
border: 1px solid var(--success-color);
background: rgb(from var(--success-color) r g b / 15%);
i {
color: var(--success-color);
}
}
}
i {
font-size: 1rem;
}
}

View File

@ -0,0 +1,55 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import type { Meta, StoryObj } from "@storybook/react";
import { MultiSelect } from "./multiselect";
const meta: Meta<typeof MultiSelect> = {
title: "Components/MultiSelect",
component: MultiSelect,
args: {
options: [
{ label: "macOS", value: "macos" },
{ label: "Windows", value: "windows" },
{ label: "Linux", value: "linux" },
],
},
argTypes: {
options: {
description: "List of selectable options.",
},
selectedValues: {
description: "Array of selected option values.",
},
onChange: {
description: "Callback triggered when selected options change.",
action: "changed",
},
},
};
export default meta;
type Story = StoryObj<typeof MultiSelect>;
export const WithPreselectedValues: Story = {
render: (args) => (
<div style={{ width: "500px", padding: "20px", border: "2px solid #ccc", background: "#111" }}>
<MultiSelect {...args} />
</div>
),
args: {
selectedValues: ["macos", "windows"],
},
};
export const WithNoSelection: Story = {
render: (args) => (
<div style={{ width: "500px", padding: "20px", border: "2px solid #ccc", background: "#111" }}>
<MultiSelect {...args} />
</div>
),
args: {
selectedValues: [],
},
};

View File

@ -0,0 +1,46 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import React, { useState } from "react";
import "./MultiSelect.scss";
type Option = {
label: string;
value: string;
};
type MultiSelectProps = {
options: Option[];
selectedValues?: string[]; // Pre-selected options
onChange: (values: string[]) => void;
};
const MultiSelect: React.FC<MultiSelectProps> = ({ options, selectedValues = [], onChange }) => {
const [selected, setSelected] = useState<string[]>(selectedValues);
const handleToggle = (value: string) => {
const newSelected = selected.includes(value)
? selected.filter((v) => v !== value) // Remove if already selected
: [...selected, value]; // Add if not selected
setSelected(newSelected);
onChange(newSelected);
};
return (
<div className="multi-select">
{options.map((option) => (
<div
key={option.value}
className={`option ${selected.includes(option.value) ? "selected" : ""}`}
onClick={() => handleToggle(option.value)}
>
{option.label}
{selected.includes(option.value) && <i className="fa fa-solid fa-check" />}
</div>
))}
</div>
);
};
export { MultiSelect };