Skip to content

Commit

Permalink
feat(selects, react): generics
Browse files Browse the repository at this point in the history
  • Loading branch information
RyushiAok committed Sep 15, 2024
1 parent a562aa3 commit fa8a94f
Show file tree
Hide file tree
Showing 17 changed files with 126 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ARIA_LABELS, ComponentName } from "@wizleap-inc/wiz-ui-constants";
import * as styles from "@wizleap-inc/wiz-ui-styles/bases/search-input.css";
import { inputBorderStyle } from "@wizleap-inc/wiz-ui-styles/commons";
import clsx from "clsx";
import { FC, KeyboardEventHandler, useMemo, useRef, useState } from "react";
import { KeyboardEventHandler, useMemo, useRef, useState } from "react";

import {
TIcon,
Expand All @@ -15,11 +15,11 @@ import {
import { BaseProps } from "@/types";

import { SearchPopupPanel } from "./search-popup-panel";
import { SearchInputOption } from "./types";
import { CheckboxOption, SearchInputOption } from "./types";

type Props = BaseProps & {
options: SearchInputOption[];
values: number[];
type Props<T extends CheckboxOption> = BaseProps & {
options: SearchInputOption<T>[];
values: T[];
name?: string;
placeholder?: string;
disabled?: boolean;
Expand All @@ -32,13 +32,13 @@ type Props = BaseProps & {
icon?: TIcon;
showSelectedItem?: boolean;
showParentLabel?: boolean;
onChangeValues: (values: number[]) => void;
onChangeValues: (values: T[]) => void;
};

function filterOptions(
options: SearchInputOption[],
function filterOptions<T extends CheckboxOption>(
options: SearchInputOption<T>[],
text: string
): SearchInputOption[] {
): SearchInputOption<T>[] {
return options.flatMap((option) => {
const isMatched = option.label.includes(text);
if (!option.children || option.children.length === 0) {
Expand All @@ -56,7 +56,7 @@ function filterOptions(
});
}

const SearchInput: FC<Props> = ({
const SearchInput = <T extends CheckboxOption>({
className,
style,
options,
Expand All @@ -74,21 +74,23 @@ const SearchInput: FC<Props> = ({
onChangeValues,
showParentLabel,
icon = WizISearch,
}) => {
}: Props<T>) => {
const [filteringText, setFilteringText] = useState("");
const [isFocused, setIsFocused] = useState(false);
const [isPopupOpen, setIsPopupOpen] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);

const filteredOptions = useMemo(
() => filterOptions(options, filteringText),
() => filterOptions<T>(options, filteringText),
[filteringText, options]
);

const valueToOptions = useMemo(() => {
const map = new Map<number, SearchInputOption>();
const map = new Map<T, SearchInputOption<T>>();

const flatten = (options: SearchInputOption[]): SearchInputOption[] => {
const flatten = (
options: SearchInputOption<T>[]
): SearchInputOption<T>[] => {
return options.flatMap((option) => {
if (!option.children) return [option];

Expand All @@ -113,12 +115,12 @@ const SearchInput: FC<Props> = ({

const IconComponent = icon;

const onClear = (value: number) => {
const onClear = (value: T) => {
const newValues = values.filter((v) => v !== value);
onChangeValues(newValues);
};

const handleKeyDown = (value: number): KeyboardEventHandler => {
const handleKeyDown = (value: T): KeyboardEventHandler => {
return (e) => {
if (e.key === "Backspace") {
onClear(value);
Expand All @@ -128,7 +130,7 @@ const SearchInput: FC<Props> = ({

const displayingSelectedItems = showSelectedItem && values.length > 0;

const handleClickPanelItem = (value: number[]) => {
const handleClickPanelItem = (value: T[]) => {
onChangeValues(value);
setFilteringText("");
};
Expand Down Expand Up @@ -162,7 +164,7 @@ const SearchInput: FC<Props> = ({
{showSelectedItem &&
values.map((value) => (
<span
key={value}
key={value.toString()}
className={styles.searchInputInnerBoxSelectedItemStyle}
>
<span
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as styles from "@wizleap-inc/wiz-ui-styles/bases/search-input.css";
import clsx from "clsx";
import { FC, useCallback, useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";

import {
WizCheckBoxNew,
Expand All @@ -12,19 +12,19 @@ import {
} from "@/components";
import { BaseProps } from "@/types";

import { SearchInputOption } from "./types";
import { CheckboxOption, SearchInputOption } from "./types";

type Props = BaseProps & {
options: SearchInputOption[];
values: number[];
type Props<T extends CheckboxOption> = BaseProps & {
options: SearchInputOption<T>[];
values: T[];
width?: string;
emptyMessage: string;
singleSelect?: boolean;
onChangeValues: (values: number[]) => void;
onChangeValues: (values: T[]) => void;
closePopup: () => void;
};

export const SearchPopupPanel: FC<Props> = ({
export const SearchPopupPanel = <T extends CheckboxOption>({
className,
style,
options,
Expand All @@ -34,8 +34,8 @@ export const SearchPopupPanel: FC<Props> = ({
singleSelect,
onChangeValues,
closePopup,
}) => {
const [activeValue, setActiveValue] = useState<number | null>(null);
}: Props<T>) => {
const [activeValue, setActiveValue] = useState<T | null>(null);
const activeOption = useMemo(
() => options.find((option) => activeValue === option.value),
[activeValue, options]
Expand All @@ -45,7 +45,7 @@ export const SearchPopupPanel: FC<Props> = ({
const isOpen = activeOptionChildren !== undefined;

const handleChangeValues = useCallback(
(selectedOptionValue: number, isChecked: boolean) => {
(selectedOptionValue: T, isChecked: boolean) => {
const newValues = (() => {
if (isChecked) {
return [...values, selectedOptionValue];
Expand All @@ -58,7 +58,7 @@ export const SearchPopupPanel: FC<Props> = ({
[onChangeValues, values]
);

const handleClickButton = (value: number) => {
const handleClickButton = (value: T) => {
onChangeValues([value]);
closePopup();
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export type Tag = {
label: string;
};

export type SearchInputOption = {
export type CheckboxOption = string | number | string[]; // WizCheckBoxNew
export type SearchInputOption<T> = {
label: string;
value: number;
children?: SearchInputOption[];
value: T;
children?: SearchInputOption<T>[];
tag?: Tag;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const tag = {
label: "タグ",
};

export const normalOptions: SearchInputOption[] = [
export const normalOptions: SearchInputOption<number>[] = [
{
label: "テスト会社1",
value: 1,
Expand Down Expand Up @@ -208,7 +208,7 @@ export const normalOptions: SearchInputOption[] = [
},
];

export const longLabelOptions: SearchInputOption[] = [
export const longLabelOptions: SearchInputOption<number>[] = [
{
label: "テスト会社1",
value: 1,
Expand All @@ -233,7 +233,7 @@ export const longLabelOptions: SearchInputOption[] = [
},
];

export const taggedOptions: SearchInputOption[] = [
export const taggedOptions: SearchInputOption<number>[] = [
{
label: "テスト会社1",
value: 1,
Expand Down Expand Up @@ -328,8 +328,8 @@ const getNextValue = (): number => {
const generateGrandchildren = (
startValue: number,
count: number
): SearchInputOption[] => {
const grandchildren: SearchInputOption[] = [];
): SearchInputOption<number>[] => {
const grandchildren: SearchInputOption<number>[] = [];
for (let i = 0; i < count; i++) {
const grandchildValue = getNextValue();
grandchildren.push({
Expand All @@ -344,8 +344,8 @@ const generateGrandchildren = (
const generateChildren = (
startValue: number,
count: number
): SearchInputOption[] => {
const children: SearchInputOption[] = [];
): SearchInputOption<number>[] => {
const children: SearchInputOption<number>[] = [];
for (let i = 0; i < count; i++) {
const childValue = getNextValue();
children.push({
Expand All @@ -365,8 +365,8 @@ const generateChildren = (
const generateParentElements = (
startValue: number,
count: number
): SearchInputOption[] => {
const parentElements: SearchInputOption[] = [];
): SearchInputOption<number>[] => {
const parentElements: SearchInputOption<number>[] = [];
for (let i = 0; i < count; i++) {
const parentValue = getNextValue();
parentElements.push({
Expand All @@ -378,7 +378,7 @@ const generateParentElements = (
return parentElements;
};

export const debugOptions: SearchInputOption[] = [
export const debugOptions: SearchInputOption<number>[] = [
{
label: "親要素1",
value: getNextValue(),
Expand All @@ -397,7 +397,7 @@ export const debugOptions: SearchInputOption[] = [
...generateParentElements(getNextValue(), 13),
];

export const emptyMessageOptions: SearchInputOption[] = [
export const emptyMessageOptions: SearchInputOption<number>[] = [
{
label: "テスト会社1",
value: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const meta: Meta<typeof WizSearchInput> = {
};

export default meta;
type Story = StoryObj<typeof WizSearchInput>;
type Story = StoryObj<typeof WizSearchInput<number>>;

const Template: Story = {
render: (args) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@ import {
popupButtonGroupInnerContainerStyle,
} from "@wizleap-inc/wiz-ui-styles/bases/search-selector.css";
import clsx from "clsx";
import { FC, KeyboardEvent, useMemo, useState } from "react";
import { KeyboardEvent, useMemo, useState } from "react";

import { WizIcon } from "@/components";
import { BaseProps } from "@/types";

import { ButtonItem as ButtonItemType } from "../types";

type Props = BaseProps & {
item: ButtonItemType;
type Props<T> = BaseProps & {
item: ButtonItemType<T>;
disabled: boolean;
depth: number;
};

export const ButtonItem: FC<Props> = ({
export const ButtonItem = <T,>({
className,
style,
item,
disabled,
depth,
}) => {
}: Props<T>) => {
const [isClicking, setIsClicking] = useState(false);
const [isHover, setIsHover] = useState(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,26 @@ import {
popupButtonGroupTitleVariantStyle,
} from "@wizleap-inc/wiz-ui-styles/bases/search-selector.css";
import clsx from "clsx";
import { FC } from "react";

import { BaseProps } from "@/types";

import { GroupItem as GroupItemType } from "../types";

import { PopupButtonGroup } from "./popup-button-group";

type Props = BaseProps & {
item: GroupItemType;
type Props<T> = BaseProps & {
item: GroupItemType<T>;
disabled: boolean;
depth: number;
};

export const GroupItem: FC<Props> = ({
export const GroupItem = <T,>({
className,
style,
item,
disabled,
depth,
}) => {
}: Props<T>) => {
return (
<div className={className} style={style}>
<span
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
popupButtonGroupStyle,
} from "@wizleap-inc/wiz-ui-styles/bases/search-selector.css";
import clsx from "clsx";
import { FC, useMemo } from "react";
import { useMemo } from "react";

import { WizVStack } from "@/components";
import { BaseProps } from "@/types";
Expand All @@ -16,8 +16,8 @@ import { ButtonItem } from "./button-item";
import { DividerItem } from "./divider-item";
import { GroupItem } from "./group-item";

type Props = BaseProps & {
options: ButtonGroupItem[];
type Props<T> = BaseProps & {
options: ButtonGroupItem<T>[];
width?: string;
p?: SpacingKeys;
borderRadius?: SpacingKeys;
Expand All @@ -28,7 +28,7 @@ type Props = BaseProps & {
depth?: number;
};

export const PopupButtonGroup: FC<Props> = ({
export const PopupButtonGroup = <T,>({
className,
style,
options,
Expand All @@ -40,15 +40,15 @@ export const PopupButtonGroup: FC<Props> = ({
groupDivider = false,
buttonDivider = false,
depth = 0,
}) => {
}: Props<T>) => {
const items = useMemo(() => {
const divider: ItemElement = { kind: "divider" };
const divider: ItemElement<T> = { kind: "divider" };
const items = options
.map((opt, i) => {
if (opt.kind === "divider") {
return [divider];
}
const optionItem: ItemElement = {
const optionItem: ItemElement<T> = {
kind: "item",
item: opt,
};
Expand Down
Loading

0 comments on commit fa8a94f

Please sign in to comment.