From d70f6e8a904309cfea7fa7bfeff01b8d449bc56d Mon Sep 17 00:00:00 2001 From: Nathaniel Waldschmidt Date: Wed, 13 Mar 2024 13:58:47 -0500 Subject: [PATCH] refactor: badge component --- CHANGELOG.md | 10 + package-lock.json | 18 +- package.json | 4 +- src/components/Badge/Badge.mdx | 30 +-- src/components/Badge/Badge.stories.js | 76 ++++++-- src/components/Badge/Badge.vue | 171 ++++++++++-------- .../{Badge.spec.js => Badge.spec.ts} | 7 +- src/components/Badge/constants.ts | 24 +++ src/components/Badge/index.ts | 2 + src/components/Icon/svgs/Globe.svg | 3 + src/components/Icon/svgs/Rocket.svg | 3 + src/components/Icon/svgs/Shop.svg | 3 + src/components/Icon/svgs/UserChatBubble.svg | 3 + src/components/Icon/types.ts | 4 + src/components/TabMenu/TabMenu.mdx | 10 + src/components/TabMenu/TabMenu.stories.js | 31 ++++ src/components/TabMenu/TabMenu.vue | 73 ++++++++ .../TabMenu/__tests__/TabMenu.spec.ts | 17 ++ src/components/TabMenu/index.ts | 1 + src/components/index.js | 1 - src/main.ts | 2 + src/types/Variant.ts | 1 + 22 files changed, 361 insertions(+), 133 deletions(-) rename src/components/Badge/__tests__/{Badge.spec.js => Badge.spec.ts} (68%) create mode 100644 src/components/Badge/constants.ts create mode 100644 src/components/Badge/index.ts create mode 100644 src/components/Icon/svgs/Globe.svg create mode 100644 src/components/Icon/svgs/Rocket.svg create mode 100644 src/components/Icon/svgs/Shop.svg create mode 100644 src/components/Icon/svgs/UserChatBubble.svg create mode 100644 src/components/TabMenu/TabMenu.mdx create mode 100644 src/components/TabMenu/TabMenu.stories.js create mode 100644 src/components/TabMenu/TabMenu.vue create mode 100644 src/components/TabMenu/__tests__/TabMenu.spec.ts create mode 100644 src/components/TabMenu/index.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f90f2db3d..822c11ed4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # CHANGELOG +## v2.0.21 + +- Refactor the `Badge` component's interface and implementation +- Add the new `TabMenu` component + +### Breaking Changes + +- The `Badge` interface has changed and does not contain as many variants in favor of utilizing `variant` and `color` +- The `Badge` component is no longer available globally, it must be imported directly + ## v2.0.20 - Begin adding type definitions diff --git a/package-lock.json b/package-lock.json index 99ddd8aa9..711011099 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@lob/ui-components", - "version": "2.0.20", + "version": "2.0.21", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@lob/ui-components", - "version": "2.0.20", + "version": "2.0.21", "dependencies": { "date-fns": "^2.29.3", "date-fns-holiday-us": "^0.3.1", @@ -53,7 +53,7 @@ "storybook": "^7.6.12", "stylelint": "^13.13.1", "stylelint-config-standard": "^22.0.0", - "tailwind-plugin-lob": "^1.0.5", + "tailwind-plugin-lob": "^1.0.8", "tailwindcss": "^3.0.24", "typescript": "^5.1.6", "vite": "^3.1.4", @@ -21109,9 +21109,9 @@ "dev": true }, "node_modules/tailwind-plugin-lob": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tailwind-plugin-lob/-/tailwind-plugin-lob-1.0.5.tgz", - "integrity": "sha512-Sdr+fhvMHL2XFsjXAP0PVzlKEZ9Soy0AtGhJPLL83bAUEsolEUBwr+1O6HPBOJhNbG6qwIC0dGxRdyxTApuTjw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/tailwind-plugin-lob/-/tailwind-plugin-lob-1.0.8.tgz", + "integrity": "sha512-UesRKr3p976bkdcg6jandrfVQLoUw/mdpT2FWOAb9OuiA/xjJvP1ojQzgkUoErTg3/+W++TgPQMp823INwlaVw==", "dev": true, "engines": { "node": ">=14.18.2" @@ -38906,9 +38906,9 @@ } }, "tailwind-plugin-lob": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tailwind-plugin-lob/-/tailwind-plugin-lob-1.0.5.tgz", - "integrity": "sha512-Sdr+fhvMHL2XFsjXAP0PVzlKEZ9Soy0AtGhJPLL83bAUEsolEUBwr+1O6HPBOJhNbG6qwIC0dGxRdyxTApuTjw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/tailwind-plugin-lob/-/tailwind-plugin-lob-1.0.8.tgz", + "integrity": "sha512-UesRKr3p976bkdcg6jandrfVQLoUw/mdpT2FWOAb9OuiA/xjJvP1ojQzgkUoErTg3/+W++TgPQMp823INwlaVw==", "dev": true }, "tailwindcss": { diff --git a/package.json b/package.json index 2043550f8..0e7a6b1cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@lob/ui-components", - "version": "2.0.20", + "version": "2.0.21", "engines": { "node": ">=20.2.0", "npm": ">=10.2.0" @@ -81,7 +81,7 @@ "storybook": "^7.6.12", "stylelint": "^13.13.1", "stylelint-config-standard": "^22.0.0", - "tailwind-plugin-lob": "^1.0.5", + "tailwind-plugin-lob": "^1.0.8", "tailwindcss": "^3.0.24", "typescript": "^5.1.6", "vite": "^3.1.4", diff --git a/src/components/Badge/Badge.mdx b/src/components/Badge/Badge.mdx index 43093e65f..23c21ffd0 100644 --- a/src/components/Badge/Badge.mdx +++ b/src/components/Badge/Badge.mdx @@ -1,34 +1,14 @@ import { Canvas, ArgTypes, PRIMARY_STORY } from '@storybook/addon-docs'; -import { Primary } from './Badge.stories'; +import { AllBadges } from './Badge.stories'; +import { BadgeVariant } from './constants'; # Badge -Badges are a flexible component used to display small nuggets of text prominently. - - - -## How to Use - -There are 6 variants of badges: `default`, `secondary`, `info`, `success`, `warning`, and `error`. - -You can change the variant of the badge by adding the `variant` prop to the component. + -There are 2 sizes of badges: `default` and `small`. +## Usage -To change the size of the badge add the `size` prop to the component. - -Please note: though you can only insert text in the Storybook demo, the badge component will accept any valid HTML or Vue component. - -Example of using this component as a default badge in a template - -```html - -

- You are in LIVE mode, all verifications will be - charged according to your chosen plan. -

-
-``` +Badges are a flexible component used to display small nuggets of text prominently. ## Props diff --git a/src/components/Badge/Badge.stories.js b/src/components/Badge/Badge.stories.js index 488e169dd..d1059310f 100644 --- a/src/components/Badge/Badge.stories.js +++ b/src/components/Badge/Badge.stories.js @@ -1,5 +1,7 @@ +import { IconName } from '../Icon/types'; import Badge from './Badge.vue'; import mdx from './Badge.mdx'; +import { BadgeColor, BadgeSize, BadgeVariant } from './constants'; export default { title: 'Components/Badge', @@ -10,37 +12,59 @@ export default { } }, argTypes: { + color: { + options: Object.values(BadgeColor), + control: { + type: 'select' + }, + table: { + type: { + summary: Object.values(BadgeColor).join(' | ') + } + } + }, content: { control: { type: 'text' }, - description: 'Content to display inside of the card', + description: 'Slot content', table: { - defaultValue: 'I am a card.', type: { - summary: 'html or component' + summary: 'string | Vue.Component' + } + } + }, + icon: { + options: Object.values(IconName), + control: { + type: 'select' + }, + table: { + type: { + summary: Object.values(IconName).join(' | ') } } }, variant: { - options: [ - 'default', - 'secondary', - 'info', - 'success', - 'warning', - 'error', - 'gradient-primary', - 'gradient-secondary' - ], + options: Object.values(BadgeVariant), control: { type: 'select' + }, + table: { + type: { + summary: Object.values(BadgeVariant).join(' | ') + } } }, size: { - options: ['default', 'small'], + options: Object.values(BadgeSize), control: { type: 'select' + }, + table: { + type: { + summary: Object.values(BadgeSize).join(' | ') + } } } } @@ -50,10 +74,32 @@ const Template = (args, { argTypes }) => ({ props: Object.keys(argTypes), components: { Badge }, setup: () => ({ args }), - template: '{{ args.content }}' + template: '{{ args.content }}' }); export const Primary = Template.bind({}); Primary.args = { + content: 'Badge' +}; + +const AllBadgesTemplate = (args) => ({ + components: { Badge }, + setup: () => ({ args }), + template: `
+ ${Object.values(BadgeVariant).map((variant) => ( + `
+ ${Object.values(BadgeColor).map((color) => ( + `
+ ${Object.values(BadgeSize).map((size) => ( + `Badge` + )).join('')} +
` + )).join('')} +
` + )).join('')} +
` +}); +export const AllBadges = AllBadgesTemplate.bind({}); +AllBadges.args = { content: 'Badge text.' }; diff --git a/src/components/Badge/Badge.vue b/src/components/Badge/Badge.vue index 06f2ebc03..9d7af593e 100644 --- a/src/components/Badge/Badge.vue +++ b/src/components/Badge/Badge.vue @@ -1,85 +1,100 @@ - + + diff --git a/src/components/Badge/__tests__/Badge.spec.js b/src/components/Badge/__tests__/Badge.spec.ts similarity index 68% rename from src/components/Badge/__tests__/Badge.spec.js rename to src/components/Badge/__tests__/Badge.spec.ts index 98931f019..75363cf6a 100644 --- a/src/components/Badge/__tests__/Badge.spec.js +++ b/src/components/Badge/__tests__/Badge.spec.ts @@ -1,13 +1,14 @@ import '@testing-library/jest-dom'; -import { render } from '@testing-library/vue'; +import { RenderOptions, render } from '@testing-library/vue'; + import Badge from '../Badge.vue'; let slots; -const renderComponent = (options) => render(Badge, { ...options }); +const renderComponent = (options: RenderOptions) => render(Badge, { ...options }); describe('Badge', () => { - it('renders correctly', () => { + it('renders', () => { const slotContent = 'Hello, this is a badge.'; slots = { default: slotContent }; const { queryByText } = renderComponent({ slots }); diff --git a/src/components/Badge/constants.ts b/src/components/Badge/constants.ts new file mode 100644 index 000000000..6e0788cf5 --- /dev/null +++ b/src/components/Badge/constants.ts @@ -0,0 +1,24 @@ +import { Color, Size, Variant } from "@/types"; + +export const BadgeColor = { + ERROR: Color.ERROR, + INFO: Color.INFO, + PRIMARY: Color.PRIMARY, + SUCCESS: Color.SUCCESS, + UPGRADE: Color.UPGRADE, + WARNING: Color.WARNING +} as const; +export type BadgeColor = (typeof BadgeColor)[keyof typeof BadgeColor]; + +export const BadgeSize = { + SM: Size.SM, + MD: Size.MD, + LG: Size.LG +} as const; +export type BadgeSize = (typeof BadgeSize)[keyof typeof BadgeSize]; + +export const BadgeVariant = { + OUTLINED: Variant.OUTLINED, + PRIMARY: Variant.PRIMARY +} as const; +export type BadgeVariant = (typeof BadgeVariant)[keyof typeof BadgeVariant]; diff --git a/src/components/Badge/index.ts b/src/components/Badge/index.ts new file mode 100644 index 000000000..59323888d --- /dev/null +++ b/src/components/Badge/index.ts @@ -0,0 +1,2 @@ +export { default as Badge } from './Badge.vue'; +export * from './constants'; diff --git a/src/components/Icon/svgs/Globe.svg b/src/components/Icon/svgs/Globe.svg new file mode 100644 index 000000000..2710f4783 --- /dev/null +++ b/src/components/Icon/svgs/Globe.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Icon/svgs/Rocket.svg b/src/components/Icon/svgs/Rocket.svg new file mode 100644 index 000000000..63e0f27e4 --- /dev/null +++ b/src/components/Icon/svgs/Rocket.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Icon/svgs/Shop.svg b/src/components/Icon/svgs/Shop.svg new file mode 100644 index 000000000..721265b0d --- /dev/null +++ b/src/components/Icon/svgs/Shop.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Icon/svgs/UserChatBubble.svg b/src/components/Icon/svgs/UserChatBubble.svg new file mode 100644 index 000000000..5eba60742 --- /dev/null +++ b/src/components/Icon/svgs/UserChatBubble.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Icon/types.ts b/src/components/Icon/types.ts index 143990e3f..7b4a860fc 100644 --- a/src/components/Icon/types.ts +++ b/src/components/Icon/types.ts @@ -36,6 +36,7 @@ export const IconName = { FIRE: 'Fire', GEAR: 'Gear', GIFT: 'Gift', + GLOBE: 'Globe', LAYER_GROUP: 'LayerGroup', LIGHTNING: 'Lightning', LOCATION_PIN: 'LocationPin', @@ -43,8 +44,11 @@ export const IconName = { OPEN_BOOK: 'OpenBook', PIE_CHART_SLICE: 'PieChartSlice', PLUS: 'Plus', + ROCKET: 'Rocket', + SHOP: 'Shop', SIGNAL: 'Signal', TRIANGLE_EXCLAMATION: 'TriangleExclamation', + USER_CHAT_BUBBLE: 'UserChatBubble', USER: 'User', USERS: 'Users', WEBHOOKS: 'Webhooks' diff --git a/src/components/TabMenu/TabMenu.mdx b/src/components/TabMenu/TabMenu.mdx new file mode 100644 index 000000000..ee5af0870 --- /dev/null +++ b/src/components/TabMenu/TabMenu.mdx @@ -0,0 +1,10 @@ +import { Canvas, ArgTypes, PRIMARY_STORY } from '@storybook/addon-docs'; +import { Primary } from './TabMenu.stories'; + +# TabMenu + + + +## Props + + diff --git a/src/components/TabMenu/TabMenu.stories.js b/src/components/TabMenu/TabMenu.stories.js new file mode 100644 index 000000000..1aad769b4 --- /dev/null +++ b/src/components/TabMenu/TabMenu.stories.js @@ -0,0 +1,31 @@ +import TabMenu from './TabMenu.vue'; +import mdx from './TabMenu.mdx'; + +export default { + title: 'Components/TabMenu', + component: TabMenu, + parameters: { + docs: { + page: mdx + } + }, + argTypes: { + items: { + table: { + type: { + summary: '{ label: string; active?: boolean; id: string; }[]' + } + } + } + } +}; + +const PrimaryTemplate = (args, { argTypes }) => ({ + props: Object.keys(argTypes), + components: { TabMenu }, + setup: () => ({ args }), + template: `` +}); + +export const Primary = PrimaryTemplate.bind({}); +Primary.args = {}; diff --git a/src/components/TabMenu/TabMenu.vue b/src/components/TabMenu/TabMenu.vue new file mode 100644 index 000000000..9e29502cd --- /dev/null +++ b/src/components/TabMenu/TabMenu.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/components/TabMenu/__tests__/TabMenu.spec.ts b/src/components/TabMenu/__tests__/TabMenu.spec.ts new file mode 100644 index 000000000..de74162ee --- /dev/null +++ b/src/components/TabMenu/__tests__/TabMenu.spec.ts @@ -0,0 +1,17 @@ +import '@testing-library/jest-dom'; +import { RenderResult, render } from '@testing-library/vue'; + +import TabMenu from '../TabMenu.vue'; + +describe('Badge', () => { + let renderResult: RenderResult; + + beforeEach(() => { + renderResult = render(TabMenu, { props: { items: []}}); + }); + + it('renders', () => { + const { getByTestId } = renderResult; + expect(getByTestId('uic-tab-menu')).toBeVisible(); + }); +}); diff --git a/src/components/TabMenu/index.ts b/src/components/TabMenu/index.ts new file mode 100644 index 000000000..de485de7c --- /dev/null +++ b/src/components/TabMenu/index.ts @@ -0,0 +1 @@ +export { default as TabMenu } from './TabMenu.vue'; diff --git a/src/components/index.js b/src/components/index.js index c3670bca5..d612dd88e 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,6 +1,5 @@ export { default as Accordion } from './Accordion/Accordion'; export { default as Alert } from './Alert/Alert'; -export { default as Badge } from './Badge/Badge'; export { default as Breadcrumb } from './Breadcrumb/Breadcrumb'; export { default as LobButton } from './Button/Button'; export { default as Card } from './Card/Card'; diff --git a/src/main.ts b/src/main.ts index 687f7db04..32a2f5f9e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -25,8 +25,10 @@ const ComponentLibrary = { }; // TODO Utilize the components export but first we will have to remove global usage. +export * from './components/Badge'; export * from './components/Icon'; export * from './components/Modal'; +export * from './components/TabMenu'; export default ComponentLibrary; diff --git a/src/types/Variant.ts b/src/types/Variant.ts index 087a5a21c..5e6e1fe7d 100644 --- a/src/types/Variant.ts +++ b/src/types/Variant.ts @@ -1,4 +1,5 @@ export const Variant = { + OUTLINED: 'outlined', PRIMARY: 'primary' } as const; export type Variant = (typeof Variant)[keyof typeof Variant];