Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added color prop to the Tag component #2338

Closed
wants to merge 9 commits into from
29 changes: 18 additions & 11 deletions src/components/Tag.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Fragment, forwardRef } from "react";

import classnames from "classnames";
import { isPresent } from "neetocist";
import { Close } from "neetoicons";
import PropTypes from "prop-types";

Expand Down Expand Up @@ -29,6 +30,7 @@ const Tag = forwardRef(
disabled = false,
size = SIZES.small,
type = TYPES.outline,
color,
children,
...otherProps
},
Expand All @@ -40,6 +42,19 @@ const Tag = forwardRef(
: icon || Fragment;
const renderLabel = label || children;

const internalColor = color?.replace("#", "");
const colorStyles = `
.neeto-ui-tag--type-outline.neeto-ui-tag--color-${internalColor},
.neeto-ui-tag--type-solid.neeto-ui-tag--color-${internalColor} {
--neeto-ui-tag-bg-color: rgb(from ${color} r g b / 0.1);
--neeto-ui-tag-border-color: rgb(from ${color} r g b / 0.1);
}
.neeto-ui-tag--type-outline.neeto-ui-tag--color-${internalColor} {
--neeto-ui-tag-color: ${color};
--neeto-ui-tag-border-color: ${color};
}
`;

return (
<div
{...{ ref }}
Expand All @@ -58,11 +73,13 @@ const Tag = forwardRef(
"neeto-ui-tag--style-info": style === STYLES.info,
"neeto-ui-tag--style-warning": style === STYLES.warning,
"neeto-ui-tag--style-danger": style === STYLES.danger,
[`neeto-ui-tag--color-${internalColor}`]: isPresent(color),
},
className
)}
{...otherProps}
>
{isPresent(color) && <style>{colorStyles}</style>}
{indicatorStyle && (
<span
data-testid="tag-indicator"
Expand Down Expand Up @@ -137,19 +154,9 @@ Tag.propTypes = {
*/
className: PropTypes.string,
/**
* <div class="neeto-ui-tag neeto-ui-tag--size-small neeto-ui-tag--style-outline neeto-ui-tag--style-danger mb-2">
* Removed
* </div>
* _Use `status` prop instead._
* Accepts a color in hexadecimal format (#000000). It overrides the colors added by the `style` prop.
*/
color: PropTypes.string,
/**
* <div class="neeto-ui-tag neeto-ui-tag--size-small neeto-ui-tag--style-outline neeto-ui-tag--style-danger mb-2">
* Removed
* </div>
* _Use `indicatorStatus` prop instead._
*/
indicatorColor: PropTypes.string,
/**
* To specify the children to be rendered inside the Tag.
*/
Expand Down
126 changes: 125 additions & 1 deletion stories/Components/Tag.stories.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from "react";
import React, { useState } from "react";

import { Favorite } from "neetoicons";

import ColorPicker from "components/ColorPicker";
import Tag from "components/Tag";

import { icons } from "../constants";
Expand Down Expand Up @@ -81,6 +82,127 @@ const Types = args => (
</div>
);

const Colors = args => (
<div className="space-y-4">
<div>
<h5 className="mb-4 capitalize">Outline</h5>
<div className="space-x-3">
<Tag {...args} color="green" label="green" type="outline" />
<Tag {...args} color="#08397B" label="#08397B" type="outline" />
<Tag {...args} color="#5319E7" label="#5319E7" type="outline" />
<Tag {...args} color="#0E8A16" label="#0E8A16" type="outline" />
<Tag {...args} color="#FBCA04" label="#FBCA04" type="outline" />
<Tag {...args} color="red" label="red" type="outline" />
</div>
</div>
<div>
<h5 className="mb-4 capitalize">Solid</h5>
<div className="space-x-3">
<Tag {...args} color="green" label="green" type="solid" />
<Tag {...args} color="#08397B" label="#08397B" type="solid" />
<Tag {...args} color="#5319E7" label="#5319E7" type="solid" />
<Tag {...args} color="#0E8A16" label="#0E8A16" type="solid" />
<Tag {...args} color="#FBCA04" label="#FBCA04" type="solid" />
<Tag {...args} color="red" label="red" type="solid" />
</div>
</div>
</div>
);

const TemporaryComponent = args => {
const COLORS = [
"#b60205",
"#d93f0b",
"#fbca04",
"#0e8a16",
"#006b75",
"#1d76db",
"#0052cc",
"#5319e7",
"#e99695",
"#f9d0c4",
"#fef2c0",
"#c2e0c6",
"#bfdadc",
"#c5def5",
"#bfd4f2",
"#d4c5f9",
];

const [color, setColor] = useState(COLORS[0].replace("#", ""));

return (
<div className="space-y-4">
<style>
{COLORS.map(color => {
const c = color.replace("#", "");

return `.from-${c}, .to-${c} { background-color: ${color}; }`;
})}
</style>
<h5 className="mb-4">
This is a temporary component inserted for easy PR review
</h5>
<div className="flex items-center gap-3">
<span className="inline-block">
<ColorPicker
color={`#${color}`}
dropdownProps={{ appendTo: document.body, zIndex: 99999 }}
size="medium"
colorPaletteProps={{
color: { from: color, to: color },
colorList: COLORS.map(color => ({
from: color.replace("#", ""),
to: color.replace("#", ""),
})),
onChange: setColor,
}}
onChange={({ hex }) => setColor(hex.replace("#", ""))}
/>
</span>
<Tag
{...{ ...args }}
color={`#${color}`}
label={`#${color} - outline`}
type="outline"
/>
<Tag
{...{ ...args }}
color={`#${color}`}
label={`#${color} - solid`}
type="solid"
/>
</div>
<div>
<h5 className="mb-4 capitalize">Outline</h5>
<div className="flex flex-wrap gap-3">
{COLORS.map(color => (
<Tag
key={color}
{...{ ...args, color }}
label={color}
type="outline"
/>
))}
</div>
</div>
<div>
<h5 className="mb-4 capitalize">Solid</h5>
<div className="flex flex-wrap gap-3">
{COLORS.map(color => (
<Tag
key={color}
{...{ ...args, color }}
label={color}
type="solid"
/>
))}
</div>
</div>
</div>
);
};

const WithIndicator = args => (
<div className="flex flex-row items-start justify-start space-x-4">
<Tag {...args} indicatorStyle="primary" label="Primary" style="secondary" />
Expand Down Expand Up @@ -132,6 +254,8 @@ export {
Sizes,
Styles,
Types,
Colors,
TemporaryComponent,
WithIndicator,
WithIcon,
WithOnClose,
Expand Down
33 changes: 28 additions & 5 deletions tests/Tag.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,32 @@ describe("Tag", () => {
expect(getByTestId("class-icon")).toBeInTheDocument();
});

it("should show indicator when indicatorStatus is provided", () => {
const { getByTestId } = render(<Tag indicatorStyle="success" />);
expect(getByTestId("tag-indicator")).toBeInTheDocument();
it("should render a with style 'success'", () => {
const { container } = render(<Tag label="Tag" style="success" />);
expect(
container.querySelector(".neeto-ui-tag--style-success")
).toBeInTheDocument();
});

it("should render with a 'large' size", () => {
const { container } = render(<Tag label="Tag" size="large" />);
expect(
container.querySelector(".neeto-ui-tag--size-large")
).toBeInTheDocument();
});

it("should render a 'outline' type", () => {
const { container } = render(<Tag label="Tag" type="outline" />);
expect(
container.querySelector(".neeto-ui-tag--type-outline")
).toBeInTheDocument();
});

it("should render with a different color", () => {
const { container } = render(<Tag color="#ff0000" label="Tag" />);
expect(
container.querySelector(".neeto-ui-tag--color-ff0000")
).toBeInTheDocument();
});

it("should show close button if onClose function is provided", () => {
Expand All @@ -28,14 +51,14 @@ describe("Tag", () => {

it("should call onClose on button click", async () => {
const onClose = jest.fn();
const { getByTestId } = render(<Tag onClose={onClose} />);
const { getByTestId } = render(<Tag {...{ onClose }} />);
await userEvent.click(getByTestId("tag-close-button"));
expect(onClose).toHaveBeenCalledTimes(1);
});

it("should not call onClose function if tag is disabled", async () => {
const onClose = jest.fn();
const { getByTestId } = render(<Tag disabled onClose={onClose} />);
const { getByTestId } = render(<Tag {...{ onClose }} disabled />);
await userEvent.click(getByTestId("tag-close-button"));
expect(onClose).toHaveBeenCalledTimes(0);
});
Expand Down
3 changes: 0 additions & 3 deletions types/Tag.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ export interface TagProps {
| "primary"
| "secondary"
| "info";
/** @deprecated Prop deprecated. Use `style` prop instead*/
color?: string;
/** @deprecated Prop deprecated. Use `indicatorStyle` prop instead*/
indicatorColor?: string;
children?: string;
}

Expand Down