Skip to content

Commit

Permalink
feat(Tag): add new bq-tag component (#695)
Browse files Browse the repository at this point in the history
Co-authored-by: Dabiel González Ramos <[email protected]>
  • Loading branch information
Cata1989 and dgonzalezr authored Dec 21, 2023
1 parent 3b298b9 commit bc67079
Show file tree
Hide file tree
Showing 12 changed files with 1,058 additions and 0 deletions.
134 changes: 134 additions & 0 deletions packages/beeq/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { TStepsSize, TStepsType } from "./components/steps/bq-steps.types";
import { TStepItemStatus } from "./components/step-item/bq-step-item.types";
import { TSwitchInnerLabel, TSwitchJustifyContent } from "./components/switch/bq-switch.types";
import { TTabSize } from "./components/tab/bq-tab.types";
import { TTagBorderRadius, TTagColor, TTagSize, TTagVariant } from "./components/tag/bq-tag.types";
import { TTextareaAutoCapitalize, TTextareaWrap } from "./components/textarea/bq-textarea.types";
import { TToastPlacement, TToastType } from "./components/toast/bq-toast.types";
export { TAccordionAppearance, TAccordionSize } from "./components/accordion/bq-accordion.types";
Expand All @@ -49,6 +50,7 @@ export { TStepsSize, TStepsType } from "./components/steps/bq-steps.types";
export { TStepItemStatus } from "./components/step-item/bq-step-item.types";
export { TSwitchInnerLabel, TSwitchJustifyContent } from "./components/switch/bq-switch.types";
export { TTabSize } from "./components/tab/bq-tab.types";
export { TTagBorderRadius, TTagColor, TTagSize, TTagVariant } from "./components/tag/bq-tag.types";
export { TTextareaAutoCapitalize, TTextareaWrap } from "./components/textarea/bq-textarea.types";
export { TToastPlacement, TToastType } from "./components/toast/bq-toast.types";
export namespace Components {
Expand Down Expand Up @@ -1001,6 +1003,52 @@ export namespace Components {
*/
"value": string;
}
interface BqTag {
/**
* The corner radius of the Tag (will override size's predefined border)
*/
"border": TTagBorderRadius;
/**
* If true, the Tag can be clickable
*/
"clickable": boolean;
/**
* The color style of the Tag
*/
"color": TTagColor;
/**
* If true, the Tag will be disabled (only if clickable = `true`, no interaction allowed)
*/
"disabled"?: boolean;
/**
* If true, the Tag component will hidden (only if removable = `true`)
*/
"hidden": boolean;
/**
* Method to be called to remove the tag component
*/
"hide": () => Promise<void>;
/**
* If true, the Tag component can be removed
*/
"removable": boolean;
/**
* If true, the Tag is selected (only if clickable = `true`)
*/
"selected": boolean;
/**
* Method to be called to show the tag component
*/
"show": () => Promise<void>;
/**
* The size of the Tag component
*/
"size": TTagSize;
/**
* The variant of Tag to apply on top of the variant
*/
"variant": TTagVariant;
}
interface BqTextarea {
/**
* If `true`, the textarea will automatically grow and shrink to fit its contents. If `false`, the textarea will have a fixed height specified by the `rows` property.
Expand Down Expand Up @@ -1238,6 +1286,10 @@ export interface BqTabGroupCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLBqTabGroupElement;
}
export interface BqTagCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLBqTagElement;
}
export interface BqTextareaCustomEvent<T> extends CustomEvent<T> {
detail: T;
target: HTMLBqTextareaElement;
Expand Down Expand Up @@ -1750,6 +1802,27 @@ declare global {
prototype: HTMLBqTabGroupElement;
new (): HTMLBqTabGroupElement;
};
interface HTMLBqTagElementEventMap {
"bqClose": any;
"bqOpen": any;
"bqBlur": HTMLBqTagElement;
"bqClick": HTMLBqTagElement;
"bqFocus": HTMLBqTagElement;
}
interface HTMLBqTagElement extends Components.BqTag, HTMLStencilElement {
addEventListener<K extends keyof HTMLBqTagElementEventMap>(type: K, listener: (this: HTMLBqTagElement, ev: BqTagCustomEvent<HTMLBqTagElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof HTMLBqTagElementEventMap>(type: K, listener: (this: HTMLBqTagElement, ev: BqTagCustomEvent<HTMLBqTagElementEventMap[K]>) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof DocumentEventMap>(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
var HTMLBqTagElement: {
prototype: HTMLBqTagElement;
new (): HTMLBqTagElement;
};
interface HTMLBqTextareaElementEventMap {
"bqBlur": HTMLBqTextareaElement;
"bqChange": { value: string; el: HTMLBqTextareaElement };
Expand Down Expand Up @@ -1829,6 +1902,7 @@ declare global {
"bq-switch": HTMLBqSwitchElement;
"bq-tab": HTMLBqTabElement;
"bq-tab-group": HTMLBqTabGroupElement;
"bq-tag": HTMLBqTagElement;
"bq-textarea": HTMLBqTextareaElement;
"bq-toast": HTMLBqToastElement;
"bq-tooltip": HTMLBqTooltipElement;
Expand Down Expand Up @@ -2941,6 +3015,64 @@ declare namespace LocalJSX {
*/
"value"?: string;
}
interface BqTag {
/**
* The corner radius of the Tag (will override size's predefined border)
*/
"border"?: TTagBorderRadius;
/**
* If true, the Tag can be clickable
*/
"clickable"?: boolean;
/**
* The color style of the Tag
*/
"color"?: TTagColor;
/**
* If true, the Tag will be disabled (only if clickable = `true`, no interaction allowed)
*/
"disabled"?: boolean;
/**
* If true, the Tag component will hidden (only if removable = `true`)
*/
"hidden"?: boolean;
/**
* Handler to be called when tag loses focus
*/
"onBqBlur"?: (event: BqTagCustomEvent<HTMLBqTagElement>) => void;
/**
* Handler to be called when tag is clicked
*/
"onBqClick"?: (event: BqTagCustomEvent<HTMLBqTagElement>) => void;
/**
* Callback handler to be called when the tag is close/hidden
*/
"onBqClose"?: (event: BqTagCustomEvent<any>) => void;
/**
* Handler to be called when tag is focused
*/
"onBqFocus"?: (event: BqTagCustomEvent<HTMLBqTagElement>) => void;
/**
* Callback handler to be called when the tag is not open/shown
*/
"onBqOpen"?: (event: BqTagCustomEvent<any>) => void;
/**
* If true, the Tag component can be removed
*/
"removable"?: boolean;
/**
* If true, the Tag is selected (only if clickable = `true`)
*/
"selected"?: boolean;
/**
* The size of the Tag component
*/
"size"?: TTagSize;
/**
* The variant of Tag to apply on top of the variant
*/
"variant"?: TTagVariant;
}
interface BqTextarea {
/**
* If `true`, the textarea will automatically grow and shrink to fit its contents. If `false`, the textarea will have a fixed height specified by the `rows` property.
Expand Down Expand Up @@ -3127,6 +3259,7 @@ declare namespace LocalJSX {
"bq-switch": BqSwitch;
"bq-tab": BqTab;
"bq-tab-group": BqTabGroup;
"bq-tag": BqTag;
"bq-textarea": BqTextarea;
"bq-toast": BqToast;
"bq-tooltip": BqTooltip;
Expand Down Expand Up @@ -3182,6 +3315,7 @@ declare module "@stencil/core" {
"bq-switch": LocalJSX.BqSwitch & JSXBase.HTMLAttributes<HTMLBqSwitchElement>;
"bq-tab": LocalJSX.BqTab & JSXBase.HTMLAttributes<HTMLBqTabElement>;
"bq-tab-group": LocalJSX.BqTabGroup & JSXBase.HTMLAttributes<HTMLBqTabGroupElement>;
"bq-tag": LocalJSX.BqTag & JSXBase.HTMLAttributes<HTMLBqTagElement>;
"bq-textarea": LocalJSX.BqTextarea & JSXBase.HTMLAttributes<HTMLBqTextareaElement>;
"bq-toast": LocalJSX.BqToast & JSXBase.HTMLAttributes<HTMLBqToastElement>;
"bq-tooltip": LocalJSX.BqTooltip & JSXBase.HTMLAttributes<HTMLBqTooltipElement>;
Expand Down
2 changes: 2 additions & 0 deletions packages/beeq/src/components/button/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Buttons are designed for users to take action on a page or a screen.
- [bq-input](../input)
- [bq-notification](../notification)
- [bq-select](../select)
- [bq-tag](../tag)

### Depends on

Expand All @@ -69,6 +70,7 @@ graph TD;
bq-input --> bq-button
bq-notification --> bq-button
bq-select --> bq-button
bq-tag --> bq-button
style bq-button fill:#f9f,stroke:#333,stroke-width:4px
```

Expand Down
2 changes: 2 additions & 0 deletions packages/beeq/src/components/icon/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Icons are simplified images that graphically explain the meaning of an object on
- [bq-notification](../notification)
- [bq-select](../select)
- [bq-switch](../switch)
- [bq-tag](../tag)
- [bq-toast](../toast)

### Graph
Expand All @@ -59,6 +60,7 @@ graph TD;
bq-notification --> bq-icon
bq-select --> bq-icon
bq-switch --> bq-icon
bq-tag --> bq-icon
bq-toast --> bq-icon
style bq-icon fill:#f9f,stroke:#333,stroke-width:4px
```
Expand Down
116 changes: 116 additions & 0 deletions packages/beeq/src/components/tag/__tests__/bq-tag.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { newE2EPage } from '@stencil/core/testing';

import { computedStyle } from '../../../shared/test-utils';

describe('bq-tag', () => {
it('should render', async () => {
const page = await newE2EPage({
html: '<bq-tag></bq-tag>',
});
const element = await page.find('bq-tag');

expect(element).toHaveClass('hydrated');
});

it('should have shadow root', async () => {
const page = await newE2EPage({
html: '<bq-tag></bq-tag>',
});
const element = await page.find('bq-tag');

expect(element.shadowRoot).not.toBeNull();
});

it('should render as hidden', async () => {
const page = await newE2EPage({
html: `<bq-tag removable hidden></bq-tag>`,
});

const element = await page.find('bq-tag');
expect(element).toEqualAttribute('aria-hidden', 'true');
});

it('should render as hidden with `hidden="true"`', async () => {
const page = await newE2EPage({
html: `<bq-tag removable hidden="true"></bq-tag>`,
});

const element = await page.find('bq-tag');
expect(element).toEqualAttribute('aria-hidden', 'true');
});

it('should render as open', async () => {
const page = await newE2EPage({
html: `<bq-tag></bq-tag>`,
});

const element = await page.find('bq-tag');
expect(element).toEqualAttribute('aria-hidden', 'false');
expect(element).not.toHaveClass('is-hidden');
});

it('should render as open with `hidden="false"`', async () => {
const page = await newE2EPage({
html: `<bq-tag hidden="false"></bq-tag>`,
});

const element = await page.find('bq-tag');
expect(element).toEqualAttribute('aria-hidden', 'false');
expect(element).not.toHaveClass('is-hidden');
});

it('should render a removable tag component', async () => {
const page = await newE2EPage({
html: `<bq-tag removable>Tag</bq-tag>`,
});

const element = await page.find('bq-tag >>> bq-icon[name="x-circle"]');
expect(element).not.toBeNull();
});

it('should render a basic tag without icon', async () => {
const page = await newE2EPage({
html: `<bq-tag>Tag</bq-tag>`,
});

const element = await page.find('bq-tag >>> slot');

expect(element).not.toBeNull();
});

it('should render a tag with a prefix (icon)', async () => {
const page = await newE2EPage({
html: `
<bq-tag>
<span slot="prefix">
<bq-icon name="star"></bq-icon>
</span>
Tag
</bq-tag>
`,
});

const prefixSlot = await page.find('bq-tag >>> slot[name="prefix"]');
expect(prefixSlot).not.toBeNull();
});

it('should respect design style', async () => {
const page = await newE2EPage({
html: `
<bq-tag size="xsmall">Tag</tag>
<bq-tag size="small">Tag</tag>
<bq-tag size="medium">Tag</tag>
`,
});

const styleProps = ['padding'] as const;

const extra_smallStyle = await computedStyle(page, 'bq-tag[size="xsmall"] >>> [part="wrapper"]', styleProps);
const smallStyle = await computedStyle(page, 'bq-tag[size="small"] >>> [part="wrapper"]', styleProps);
const mediumStyle = await computedStyle(page, 'bq-tag[size="medium"] >>> [part="wrapper"]', styleProps);

expect(extra_smallStyle).toEqual({ padding: '2px 8px' });
expect(smallStyle).toEqual({ padding: '2px 8px' });
expect(mediumStyle).toEqual({ padding: '4px 12px' });
});
});
27 changes: 27 additions & 0 deletions packages/beeq/src/components/tag/_storybook/bq-tag.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ArgTypes, Title, Subtitle } from '@storybook/addon-docs';

<div className="bq-doc__wrapper" data-theme="light">
<div className="bq-doc__container">
<Title>Tag</Title>

The Tag Component is a UI element used to label and categorize content within an application.
Tags are commonly used to label items with keywords or categories, making it easier to find and organize content.

<Subtitle>Usage</Subtitle>

- Use tags for labeling and categorizing items or content, such as tagging articles with keywords or categorizing items in a shopping cart.
- Use tags for representing metadata about an item or content, such as the author, date, or source of an article.
- Use tags for filtering and organizing content based on tags, such as allowing users to filter articles based on keywords or categories.
- Use clear and concise labels for tags, avoiding complex sentences and technical jargon.

<Subtitle>👍 When to use</Subtitle>

- When using tags, ensure that you position them in a location that is easily visible and accessible, without obstructing important content or interactions.
- When using tags, ensure the use of visually distinct styles and colors to differentiate between different types of tags, allowing users to easily recognize the meaning of each tag.
- Ensure that tags are easy to interact with, allowing users to click on a tag to view related content or to remove a tag if desired.

<Title>Properties</Title>

<ArgTypes of="bq-tag" />
</div>
</div>
Loading

0 comments on commit bc67079

Please sign in to comment.