From 4bcc9f711ed19da82e0f300ef76af6842c2dece0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aliz=C3=A9=20Debray?= <33580481+alizedebray@users.noreply.github.com> Date: Fri, 5 Apr 2024 10:25:44 +0200 Subject: [PATCH] feat(styles, docs): update badges (#2860) --- .changeset/dry-wasps-film.md | 6 + .../background-colors.module.scss} | 0 .../src/shared/decorators/dark-background.ts | 10 + .../stories/components/badge/badge.docs.mdx | 37 ++- .../badge/badge.snapshot.stories.ts | 12 +- .../stories/components/badge/badge.stories.ts | 241 ++++++------------ .../card-control/card-control.stories.ts | 11 +- .../cards/card-button/card-button.stories.ts | 4 +- packages/styles/src/components/badge.scss | 100 ++------ packages/styles/src/placeholders/_badge.scss | 2 +- .../src/variables/components/_badge.scss | 37 ++- 11 files changed, 157 insertions(+), 303 deletions(-) create mode 100644 .changeset/dry-wasps-film.md rename packages/documentation/src/{stories/components/cards/card-button/card-button.module.scss => shared/background-colors.module.scss} (100%) create mode 100644 packages/documentation/src/shared/decorators/dark-background.ts diff --git a/.changeset/dry-wasps-film.md b/.changeset/dry-wasps-film.md new file mode 100644 index 0000000000..335ab35008 --- /dev/null +++ b/.changeset/dry-wasps-film.md @@ -0,0 +1,6 @@ +--- +'@swisspost/design-system-styles': major +'@swisspost/design-system-documentation': patch +--- + +Restricted the badge to showing counts only and updated the styles accordingly. diff --git a/packages/documentation/src/stories/components/cards/card-button/card-button.module.scss b/packages/documentation/src/shared/background-colors.module.scss similarity index 100% rename from packages/documentation/src/stories/components/cards/card-button/card-button.module.scss rename to packages/documentation/src/shared/background-colors.module.scss diff --git a/packages/documentation/src/shared/decorators/dark-background.ts b/packages/documentation/src/shared/decorators/dark-background.ts new file mode 100644 index 0000000000..73b82b8680 --- /dev/null +++ b/packages/documentation/src/shared/decorators/dark-background.ts @@ -0,0 +1,10 @@ +import { StoryContext, StoryFn } from '@storybook/web-components'; +import { html } from 'lit'; + +export function coloredBackground(story: StoryFn, context: StoryContext, color: string) { + return html` +
+ ${story(context.args, context)} +
+ `; +} diff --git a/packages/documentation/src/stories/components/badge/badge.docs.mdx b/packages/documentation/src/stories/components/badge/badge.docs.mdx index b46b72edd1..d1ba0c3485 100644 --- a/packages/documentation/src/stories/components/badge/badge.docs.mdx +++ b/packages/documentation/src/stories/components/badge/badge.docs.mdx @@ -8,20 +8,9 @@ import StylesPackageImport from '../../../shared/styles-package-import.mdx'; # Badge
- Documentation and examples for badges, our small count and labeling component. + Highlight a numerical characteristic or mark an item with a status.
- -

Badge is deprecated

-

- The current `badge` component is deprecated and will be replaced with the `chip` component which will behave similarly to the current `badge` component. - There will also be a new `badge` component, but with a different behavior. Check out the new components in figma: - [Chip](https://www.figma.com/file/xZ0IW0MJO0vnFicmrHiKaY/Components-Post?type=design&node-id=11194-50777&mode=design&t=SeiMf2Vt3dmUnpMT-0) - / - [Badge](https://www.figma.com/file/xZ0IW0MJO0vnFicmrHiKaY/Components-Post?type=design&node-id=11038-51303&mode=design&t=SeiMf2Vt3dmUnpMT-0) -

-
-
@@ -31,17 +20,23 @@ import StylesPackageImport from '../../../shared/styles-package-import.mdx'; ## Examples -### Checkable +### Colors + +You can change the badge color simply by applying a `.bg-*` class to it. +See all available classes in the [background utilities documentation](/?path=/docs/60852fac-a861-4415-8276-bd38d68653bb--docs). + + + +### Large number -Checkable badges are nothing more than personalized checkboxes. -Therefore, you can handle then like standard checkboxes. +A large number will extend the badge with. +To prevent the badge from being too large you can simply use the `+` notation as shown hereafter. - + -### Dismissible +### Position -Dismissible badges include a close button, allowing users to easily clear them from the page. -Because the close button does not have a visible text, -it should always include a visually hidden label to ensure accessibility for assistive technology users. +As inline elements, the badges can be placed inside other element such as tags. +They can also be place absolutely to appear above other elements such as icons for example. - + diff --git a/packages/documentation/src/stories/components/badge/badge.snapshot.stories.ts b/packages/documentation/src/stories/components/badge/badge.snapshot.stories.ts index 3a90dca504..2181c8b0c6 100644 --- a/packages/documentation/src/stories/components/badge/badge.snapshot.stories.ts +++ b/packages/documentation/src/stories/components/badge/badge.snapshot.stories.ts @@ -20,17 +20,11 @@ export const Badge: Story = { bg => html`
${bombArgs({ - text: [ - 'Malakceptebla Insigno', - 'Contentus momentus vero siteos et accusam iretea et justo.', - ], + showNumber: [true, false], size: context.argTypes.size.options, - interactionType: context.argTypes.interactionType.options, - nestedBadge: [false, true], - checked: [false, true], - dismissed: [false], + background: context.argTypes.background.options, }) - .filter(args => !(args.interactionType !== 'checkable' && args.checked === true)) + .filter(args => !(!args.showNumber && args.size === 'small')) .map((args: Args) => meta.render?.({ ...context.args, ...args }, context))}
`, diff --git a/packages/documentation/src/stories/components/badge/badge.stories.ts b/packages/documentation/src/stories/components/badge/badge.stories.ts index 2be92512ef..1173ce76e2 100644 --- a/packages/documentation/src/stories/components/badge/badge.stories.ts +++ b/packages/documentation/src/stories/components/badge/badge.stories.ts @@ -1,32 +1,41 @@ -import { useArgs } from '@storybook/preview-api'; -import type { Args, StoryContext, StoryObj } from '@storybook/web-components'; +import { Args, StoryContext, StoryFn, StoryObj } from '@storybook/web-components'; import { html, nothing } from 'lit'; -import { mapClasses } from '../../../utils'; import { MetaComponent } from '../../../../types'; +import backgroundColors from '../../../shared/background-colors.module.scss'; +import { coloredBackground } from '../../../shared/decorators/dark-background'; const meta: MetaComponent = { id: 'bec68e8b-445e-4760-8bd7-1b9970206d8d', title: 'Components/Badge', tags: ['package:HTML'], render: renderBadge, - decorators: [externalControl], - parameters: { - badges: [], - }, + decorators: [adaptiveBackground], args: { - text: 'Insigno', - size: 'default', - nestedBadge: false, - interactionType: 'none', - checked: false, - dismissed: false, + showNumber: true, + number: 1, + size: 'large', }, argTypes: { - text: { - name: 'Text', - description: 'The text contained in the badge.', + showNumber: { + name: 'Show Number', + description: 'If `true`, the badge contains a number otherwise it is empty.', + control: { + type: 'boolean', + }, + table: { + category: 'Content', + }, + }, + number: { + name: 'Number', + description: 'The number contained in the badge.', + if: { + arg: 'showNumber', + truthy: true, + }, control: { - type: 'text', + type: 'number', + min: 0, }, table: { category: 'Content', @@ -35,161 +44,51 @@ const meta: MetaComponent = { size: { name: 'Size', description: 'The size of the badge.', + if: { + arg: 'showNumber', + truthy: true, + }, control: { type: 'radio', labels: { - 'default': 'Default', + 'large': 'Large', 'badge-sm': 'Small', }, }, - options: ['default', 'badge-sm'], + options: ['large', 'badge-sm'], table: { category: 'General', }, }, - nestedBadge: { - name: 'Nested Badge', - description: 'If `true`, a nested badge is displayed inside the main badge.', + background: { + name: 'Backround', + description: 'You can use the Background classes to color the cards', control: { - type: 'boolean', + type: 'select', }, + options: Object.keys(backgroundColors), table: { category: 'General', }, }, - interactionType: { - name: 'Interaction Type', - description: 'Defines how the badge can be interacted with.', - control: { - type: 'inline-radio', - labels: { - none: 'None', - checkable: 'Checkable', - dismissible: 'Dismissible', - }, - }, - options: ['none', 'checkable', 'dismissible'], - table: { - category: 'Interactions', - }, - }, - checked: { - name: 'Checked', - description: 'If `true`, the badge is checked otherwise it is unchecked.', - if: { - arg: 'interactionType', - eq: 'checkable', - }, - control: { - type: 'boolean', - }, - table: { - category: 'Interactions', - }, - }, - dismissed: { - name: 'Dismissed', - description: 'If `true`, the badge is removed from the page otherwise it is displayed.', - if: { - arg: 'interactionType', - eq: 'dismissible', - }, - control: { - type: 'boolean', - }, - table: { - category: 'Interactions', - }, - }, }, }; export default meta; // DECORATORS -function externalControl(story: any, { args }: StoryContext) { - const [_, updateArgs] = useArgs(); - - const button = html` - - Show badge - - `; - - return html` ${args.dismissed ? button : nothing} ${story()} `; +function adaptiveBackground(story: StoryFn, context: StoryContext) { + const { args } = context; + const isLight = ['bg-white', 'bg-light', 'bg-gray'].includes(args.background as string); + return isLight ? coloredBackground(story, context, 'dark') : story(args, context); } // RENDERER -function getDefaultContent(args: Args) { - return html` - ${args.text} - ${args.nestedBadge ? html` 10 ` : nothing} - `; -} - -function getCheckableContent(args: Args, updateArgs: (args: Args) => void, context: StoryContext) { - const checkboxId = `badge-example--${context.name.replace(/ /g, '-').toLowerCase()}`; - const labelClasses = mapClasses({ - 'badge-check-label': true, - [args.size]: args.size !== 'default', - }); - - const handleChange = (e: Event) => { - updateArgs({ checked: !args.checked }); - - if (document.activeElement === e.target) { - setTimeout(() => { - const element: HTMLInputElement | null = document.querySelector(`#${checkboxId}`); - if (element) element.focus(); - }, 25); - } - }; - - return html` - - - `; -} - -function getDismissButton(updateArgs: (args: Args) => void) { - return html` - - `; -} - -function renderBadge(args: Args, context: StoryContext) { - const [_, updateArgs] = useArgs(); - - if (args.dismissed) return html` ${nothing} `; - - const isCheckable = args.interactionType === 'checkable'; - const isDismissible = args.interactionType === 'dismissible'; - - const badgeClasses = mapClasses({ - 'badge': !isCheckable, - 'badge-check': isCheckable, - [args.size]: args.size !== 'default' && !isCheckable, - }); - +function renderBadge(args: Args) { + const sizingClass = args.showNumber && args.size !== 'large' ? ` ${args.size}` : ''; + const bgClass = args.background && args.background !== 'bg-danger' ? ` ${args.background}` : ''; return html` -
- ${isCheckable ? getCheckableContent(args, updateArgs, context) : getDefaultContent(args)} - ${isDismissible ? getDismissButton(updateArgs) : nothing} -
+
${args.showNumber ? args.number : nothing}
`; } @@ -198,26 +97,36 @@ type Story = StoryObj; export const Default: Story = {}; -export const Checkable: Story = { - parameters: { - controls: { - exclude: ['Interaction Type'], - }, - }, - args: { - text: 'Kontrolebla Insigno', - interactionType: 'checkable', - }, +export const Colors: Story = { + render: args => html` + ${renderBadge({ ...args, background: 'bg-info' })} + ${renderBadge({ ...args, background: 'bg-success' })} + ${renderBadge({ ...args, background: 'bg-warning' })} + ${renderBadge({ ...args, background: 'bg-yellow' })} + `, }; -export const Dismissible: Story = { - parameters: { - controls: { - exclude: ['Interaction Type'], - }, - }, - args: { - text: 'Malakceptebla Insigno', - interactionType: 'dismissible', - }, +export const LargeNumber: Story = { + render: args => html` + ${renderBadge({ ...args, number: 256 })} ${renderBadge({ ...args, number: '+99' })} + `, +}; + +export const Position: Story = { + render: args => html` +
+ Filter +
1
+
+ +
+ +
3
+
+ `, + decorators: [ + (story: StoryFn, { args, context }: StoryContext) => html` +
${story(args, context)}
+ `, + ], }; diff --git a/packages/documentation/src/stories/components/card-control/card-control.stories.ts b/packages/documentation/src/stories/components/card-control/card-control.stories.ts index 7a68ba4ad9..7e78953284 100644 --- a/packages/documentation/src/stories/components/card-control/card-control.stories.ts +++ b/packages/documentation/src/stories/components/card-control/card-control.stories.ts @@ -6,6 +6,7 @@ import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { parse } from '../../../utils/sass-export'; import './card-control.styles.scss'; import scss from './card-control.module.scss'; +import { coloredBackground } from '../../../shared/decorators/dark-background'; const SCSS_VARIABLES: any = parse(scss); @@ -116,15 +117,7 @@ export const DarkBackground: Story = { }, }, }, - decorators: [ - (story, context) => - html`
- ${story()} -
`, - ], + decorators: [(story, context) => coloredBackground(story, context, context.args.background)], args: { background: 'dark', icon: '1001', diff --git a/packages/documentation/src/stories/components/cards/card-button/card-button.stories.ts b/packages/documentation/src/stories/components/cards/card-button/card-button.stories.ts index 9b9757a4e9..8ea937dff0 100644 --- a/packages/documentation/src/stories/components/cards/card-button/card-button.stories.ts +++ b/packages/documentation/src/stories/components/cards/card-button/card-button.stories.ts @@ -1,8 +1,8 @@ import { Args, StoryObj } from '@storybook/web-components'; import { html } from 'lit'; import { useArgs } from '@storybook/preview-api'; -import scss from './card-button.module.scss'; import { MetaComponent } from '../../../../../types'; +import backgroundColors from '../../../../shared/background-colors.module.scss'; const meta: MetaComponent = { id: '6f8f76ec-a2b5-4eb0-87f7-4021e1a5b8d0', @@ -64,7 +64,7 @@ const meta: MetaComponent = { control: { type: 'select', }, - options: Object.keys(scss), + options: Object.keys(backgroundColors), table: { category: 'General', }, diff --git a/packages/styles/src/components/badge.scss b/packages/styles/src/components/badge.scss index cc7ed9dbd9..b4c9fcff7e 100644 --- a/packages/styles/src/components/badge.scss +++ b/packages/styles/src/components/badge.scss @@ -1,85 +1,33 @@ @forward './../variables/options'; -@use './../lic/bootstrap-license'; -@use './../themes/bootstrap/core' as *; -@use './../themes/bootstrap/badge' as bb; - +@use './../mixins/color' as color-mx; @use './../variables/components/badge'; -@use './../variables/components/forms'; -@use './../variables/components/form-check'; -@use './../variables/color'; -@use './../mixins/utilities'; -@use './../mixins/forms' as forms-mx; -@use './../mixins/badge' as badge-mx; -@use './../placeholders/badge' as badge-ph; -@use './../functions/icons' as icons-fn; .badge { - @extend %badge; -} - -a, -button { - &.badge { - @include forms-mx.focus-outline; - background-color: transparent; - text-decoration: none; - transition: badge.$badge-transition; - - @include utilities.not-disabled-focus-hover { - @include badge-mx.badge-hover-state; - } - - &:active, - &.active { - @include badge-mx.badge-active-state; - } - } -} - -.badge-check { - &-label { - @extend %badge; - @include forms-mx.focus-outline; - transition: badge.$badge-transition; - cursor: pointer; - } - - &-input { - @include utilities.visuallyhidden; - } - - &-input:focus-visible + &-label { - outline-offset: forms.$input-focus-outline-thickness; - outline: forms.$input-focus-outline-thickness solid var(--post-contrast-color); - } - - &-input:not(:checked) + &-label:hover { - @include badge-mx.badge-hover-state; - } - - &-input:checked + &-label { - @include badge-mx.badge-active-state; + --post-badge-height: #{badge.$badge-height}; + --post-badge-padding-x: #{badge.$badge-padding-x}; + + display: inline-flex; + align-items: center; + justify-content: center; + box-sizing: content-box; + height: var(--post-badge-height); + min-width: calc(var(--post-badge-height) - 2 * var(--post-badge-padding-x)); + padding-inline: var(--post-badge-padding-x); + border: badge.$badge-border; + border-radius: badge.$badge-border-radius; + font-size: badge.$badge-font-size; + background-color: badge.$badge-bg; + color: badge.$badge-color; + + &:empty { + --post-badge-height: #{badge.$badge-height-empty}; + --post-badge-padding-x: #{badge.$badge-padding-x-empty}; } } -@include utilities.high-contrast-mode() { - .badge-check { - &-input:focus-visible + &-label { - border-color: Highlight; - outline-color: Highlight; - } - - &-input:checked + &-label { - &:hover { - @include badge-mx.badge-hover-state; - } - } - } - - button.badge, - a.badge, - .badge-check-label { - transition: none; - } +.badge-sm { + --post-badge-height: #{badge.$badge-height-sm}; + --post-badge-padding-x: #{badge.$badge-padding-x-sm}; + font-size: badge.$badge-font-size-sm; } diff --git a/packages/styles/src/placeholders/_badge.scss b/packages/styles/src/placeholders/_badge.scss index 8c187aeb71..a98cfd3afa 100644 --- a/packages/styles/src/placeholders/_badge.scss +++ b/packages/styles/src/placeholders/_badge.scss @@ -9,7 +9,7 @@ align-items: center; gap: badge.$badge-gap; padding: $badge-padding-y $badge-padding-x; - border: badge.$badge-border-width solid badge.$badge-border-color; + border: badge.$badge-border; height: badge.$badge-height; font-size: badge.$badge-font-size; font-weight: $badge-font-weight; diff --git a/packages/styles/src/variables/components/_badge.scss b/packages/styles/src/variables/components/_badge.scss index d47f01e4fe..49ea1bfbad 100644 --- a/packages/styles/src/variables/components/_badge.scss +++ b/packages/styles/src/variables/components/_badge.scss @@ -1,19 +1,29 @@ -@use 'sass:math'; - -@use './button'; -@use './../animation'; @use './../color'; @use './../commons'; @use './../spacing'; @use './../type'; +@use './button'; @use './../../functions/sizing'; -// Design System custom variables -$badge-height: button.$btn-height-rg; +$badge-border-radius: 50rem; +$badge-color: color.$white; +$badge-bg: color.$error; +$badge-border: color.$white solid commons.$border-thick; + +$badge-height: spacing.$size-large; +$badge-height-sm: spacing.$size-regular; +$badge-height-empty: spacing.$size-mini; + +$badge-padding-x: spacing.$size-mini; +$badge-padding-x-sm: spacing.$size-micro; +$badge-padding-x-empty: 0%; // needs a unit for the calculated min-width + +$badge-font-size: type.$font-size-12; +$badge-font-size-sm: 10px; + +// DEPRECATED $badge-gap: spacing.$size-mini; -$badge-border-color: var(--post-gray-60); -$badge-border-width: commons.$border-thick; $badge-transition: color 250ms, background-color 250ms, @@ -22,11 +32,7 @@ $badge-hover-color: color.$black; $badge-hover-bg-color: color.$gray-10; $badge-active-color: color.$black; $badge-active-bg-color: color.$yellow; - -$badge-height-sm: button.$btn-height-sm; $badge-gap-sm: sizing.px-to-rem(6px); -$badge-font-size-sm: type.$font-size-tiny; - $badge-nested-height: sizing.px-to-rem(22px); $badge-nested-color: color.$gray-60; $badge-nested-bg-color: color.$gray-10; @@ -35,14 +41,7 @@ $badge-nested-font-size: sizing.px-to-rem(10px); $badge-nested-translate-x: ($badge-height - $badge-nested-height) * 0.5; $badge-nested-active-bg-color: color.$white; $badge-nested-translate-x-sm: ($badge-height-sm - $badge-nested-height) * 0.5; - $badge-check-input-height: spacing.$size-small-large; $badge-check-input-bg-color: color.$white; - -// Bootstrap variables -$badge-font-size: type.$font-size-small; $badge-font-weight: type.$font-weight-normal; -$badge-color: var(--post-gray-80); $badge-padding-y: 0; -$badge-padding-x: spacing.$size-regular - sizing.px-to-rem($badge-border-width); -$badge-border-radius: 50rem;