ui/tags: refactor generic children and icon
This commit is contained in:
@@ -164,17 +164,26 @@ export const MachineTags = (props: MachineTagsProps) => {
|
||||
<For each={state.selectedOptions()}>
|
||||
{(option) => (
|
||||
<Tag
|
||||
label={option.value}
|
||||
inverted={props.inverted}
|
||||
action={
|
||||
option.disabled || props.disabled || props.readOnly
|
||||
? undefined
|
||||
: {
|
||||
icon: "Close",
|
||||
onClick: () => state.remove(option),
|
||||
}
|
||||
interactive={
|
||||
!(option.disabled || props.disabled || props.readOnly)
|
||||
}
|
||||
/>
|
||||
icon={({ inverted }) =>
|
||||
option.disabled ||
|
||||
props.disabled ||
|
||||
props.readOnly ? undefined : (
|
||||
<Icon
|
||||
role="button"
|
||||
icon={"Close"}
|
||||
size="0.5rem"
|
||||
inverted={inverted}
|
||||
onClick={() => state.remove(option)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
>
|
||||
{option.value}
|
||||
</Tag>
|
||||
)}
|
||||
</For>
|
||||
<Show when={!props.readOnly}>
|
||||
|
||||
@@ -19,7 +19,9 @@ span.tag {
|
||||
|
||||
&.has-action {
|
||||
@apply pr-1.5;
|
||||
}
|
||||
|
||||
&.is-interactive {
|
||||
&:hover {
|
||||
@apply bg-def-acc-3;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Tag, TagProps } from "@/src/components/Tag/Tag";
|
||||
import { Meta, type StoryContext, StoryObj } from "@kachurun/storybook-solid";
|
||||
import { expect, fn } from "storybook/test";
|
||||
import { fn } from "storybook/test";
|
||||
import Icon from "../Icon/Icon";
|
||||
|
||||
const meta: Meta<TagProps> = {
|
||||
title: "Components/Tag",
|
||||
@@ -13,27 +14,44 @@ type Story = StoryObj<TagProps>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
label: "Label",
|
||||
children: "Label",
|
||||
},
|
||||
};
|
||||
|
||||
const IconAction = ({
|
||||
inverted,
|
||||
handleActionClick,
|
||||
}: {
|
||||
inverted: boolean;
|
||||
handleActionClick: () => void;
|
||||
}) => (
|
||||
<Icon
|
||||
role="button"
|
||||
icon={"Close"}
|
||||
size="0.5rem"
|
||||
onClick={() => {
|
||||
console.log("icon clicked");
|
||||
handleActionClick();
|
||||
fn();
|
||||
}}
|
||||
inverted={inverted}
|
||||
/>
|
||||
);
|
||||
export const WithAction: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
action: {
|
||||
icon: "Close",
|
||||
onClick: fn(),
|
||||
},
|
||||
icon: IconAction,
|
||||
interactive: true,
|
||||
},
|
||||
play: async ({ canvas, step, userEvent, args }: StoryContext) => {
|
||||
await userEvent.click(canvas.getByRole("button"));
|
||||
await expect(args.action.onClick).toHaveBeenCalled();
|
||||
// await expect(args.icon.onClick).toHaveBeenCalled();
|
||||
},
|
||||
};
|
||||
|
||||
export const Inverted: Story = {
|
||||
args: {
|
||||
label: "Label",
|
||||
children: "Label",
|
||||
inverted: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2,18 +2,19 @@ import "./Tag.css";
|
||||
|
||||
import cx from "classnames";
|
||||
import { Typography } from "@/src/components/Typography/Typography";
|
||||
import { createSignal, Show } from "solid-js";
|
||||
import Icon, { IconVariant } from "../Icon/Icon";
|
||||
import { createSignal, JSX } from "solid-js";
|
||||
|
||||
export interface TagAction {
|
||||
icon: IconVariant;
|
||||
onClick: () => void;
|
||||
interface IconActionProps {
|
||||
inverted: boolean;
|
||||
handleActionClick: () => void;
|
||||
}
|
||||
|
||||
export interface TagProps {
|
||||
label: string;
|
||||
action?: TagAction;
|
||||
export interface TagProps extends JSX.HTMLAttributes<HTMLSpanElement> {
|
||||
children?: JSX.Element;
|
||||
icon?: (state: IconActionProps) => JSX.Element;
|
||||
inverted?: boolean;
|
||||
interactive?: boolean;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
export const Tag = (props: TagProps) => {
|
||||
@@ -23,7 +24,6 @@ export const Tag = (props: TagProps) => {
|
||||
|
||||
const handleActionClick = () => {
|
||||
setIsActive(true);
|
||||
props.action?.onClick();
|
||||
setTimeout(() => setIsActive(false), 150);
|
||||
};
|
||||
|
||||
@@ -32,23 +32,18 @@ export const Tag = (props: TagProps) => {
|
||||
class={cx("tag", {
|
||||
inverted: inverted(),
|
||||
active: isActive(),
|
||||
"has-action": props.action,
|
||||
"has-icon": props.icon,
|
||||
"is-interactive": props.interactive,
|
||||
class: props.class,
|
||||
})}
|
||||
aria-label={props.label}
|
||||
aria-readonly={!props.action}
|
||||
>
|
||||
<Typography hierarchy="label" size="xs" inverted={inverted()}>
|
||||
{props.label}
|
||||
{props.children}
|
||||
</Typography>
|
||||
<Show when={props.action}>
|
||||
<Icon
|
||||
role="button"
|
||||
icon={props.action!.icon}
|
||||
size="0.5rem"
|
||||
inverted={inverted()}
|
||||
onClick={handleActionClick}
|
||||
/>
|
||||
</Show>
|
||||
{props.icon?.({
|
||||
inverted: inverted(),
|
||||
handleActionClick,
|
||||
})}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ export const TagGroup = (props: TagGroupProps) => {
|
||||
return (
|
||||
<div class={cx("tag-group", props.class, { inverted: inverted() })}>
|
||||
<For each={props.labels}>
|
||||
{(label) => <Tag label={label} inverted={inverted()} />}
|
||||
{(label) => <Tag inverted={inverted()}>{label}</Tag>}
|
||||
</For>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user