diff --git a/e2e/components/IconIndicator/IconIndicator-test.avt.e2e.js b/e2e/components/IconIndicator/IconIndicator-test.avt.e2e.js new file mode 100644 index 000000000000..f8a2af15707b --- /dev/null +++ b/e2e/components/IconIndicator/IconIndicator-test.avt.e2e.js @@ -0,0 +1,23 @@ +/** + * Copyright IBM Corp. 2016, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; +import { expect, test } from '@playwright/test'; +import { visitStory } from '../../test-utils/storybook'; + +test.describe('@avt IconIndicator', () => { + test('@avt-default-state', async ({ page }) => { + await visitStory(page, { + component: 'IconIndicator', + id: 'experimental-statusindicators-unstable-iconindicator--default', + globals: { + theme: 'white', + }, + }); + await expect(page).toHaveNoACViolations('IconIndicator'); + }); +}); diff --git a/e2e/components/IconIndicator/IconIndicator-test.e2e.js b/e2e/components/IconIndicator/IconIndicator-test.e2e.js new file mode 100644 index 000000000000..e390bf8f781a --- /dev/null +++ b/e2e/components/IconIndicator/IconIndicator-test.e2e.js @@ -0,0 +1,25 @@ +/** + * Copyright IBM Corp. 2016, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; +const { test } = require('@playwright/test'); +const { themes } = require('../../test-utils/env'); +const { snapshotStory } = require('../../test-utils/storybook'); + +test.describe('IconIndicator', () => { + themes.forEach((theme) => { + test.describe(theme, () => { + test('icon indicator @vrt', async ({ page }) => { + await snapshotStory(page, { + component: 'IconIndicator', + id: 'experimental-statusindicators-unstable-iconindicator--default', + theme, + }); + }); + }); + }); +}); diff --git a/packages/carbon-components-react/scss/components/icon-indicator/_icon-indicator.scss b/packages/carbon-components-react/scss/components/icon-indicator/_icon-indicator.scss new file mode 100644 index 000000000000..da5dd0bc1454 --- /dev/null +++ b/packages/carbon-components-react/scss/components/icon-indicator/_icon-indicator.scss @@ -0,0 +1,9 @@ +// Code generated by carbon-components-react. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/icon-indicator/icon-indicator'; diff --git a/packages/carbon-components-react/scss/components/icon-indicator/_index.scss b/packages/carbon-components-react/scss/components/icon-indicator/_index.scss new file mode 100644 index 000000000000..25c1fa65bc50 --- /dev/null +++ b/packages/carbon-components-react/scss/components/icon-indicator/_index.scss @@ -0,0 +1,9 @@ +// Code generated by carbon-components-react. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/icon-indicator'; diff --git a/packages/carbon-components/scss/components/icon-indicator/_icon-indicator.scss b/packages/carbon-components/scss/components/icon-indicator/_icon-indicator.scss new file mode 100644 index 000000000000..f615b318b076 --- /dev/null +++ b/packages/carbon-components/scss/components/icon-indicator/_icon-indicator.scss @@ -0,0 +1,9 @@ +// Code generated by carbon-components. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/icon-indicator/icon-indicator'; diff --git a/packages/carbon-components/scss/components/icon-indicator/_index.scss b/packages/carbon-components/scss/components/icon-indicator/_index.scss new file mode 100644 index 000000000000..64849481615a --- /dev/null +++ b/packages/carbon-components/scss/components/icon-indicator/_index.scss @@ -0,0 +1,9 @@ +// Code generated by carbon-components. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/icon-indicator'; diff --git a/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap index deeae8dc8bda..2f04a6c6c3b0 100644 --- a/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/elements/src/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -324,6 +324,7 @@ Array [ "spacing11", "spacing12", "spacing13", + "statusTokens", "styles", "supportCautionMajor", "supportCautionMinor", diff --git a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap index fb2430d115ee..897b767d57de 100644 --- a/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap +++ b/packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap @@ -10986,6 +10986,48 @@ Map { }, }, }, + "unstable__IconIndicator" => Object { + "$$typeof": Symbol(react.forward_ref), + "propTypes": Object { + "className": Object { + "type": "string", + }, + "kind": Object { + "args": Array [ + Array [ + "failed", + "caution-major", + "caution-minor", + "undefined", + "succeeded", + "normal", + "in-progress", + "incomplete", + "not-started", + "pending", + "unknown", + "informative", + ], + ], + "isRequired": true, + "type": "oneOf", + }, + "label": Object { + "isRequired": true, + "type": "string", + }, + "size": Object { + "args": Array [ + Array [ + 16, + 20, + ], + ], + "type": "oneOf", + }, + }, + "render": [Function], + }, "unstable__Slug" => Object { "$$typeof": Symbol(react.forward_ref), "propTypes": Object { diff --git a/packages/react/scss/components/icon-indicator/_icon-indicator.scss b/packages/react/scss/components/icon-indicator/_icon-indicator.scss new file mode 100644 index 000000000000..8fe9070c9ee5 --- /dev/null +++ b/packages/react/scss/components/icon-indicator/_icon-indicator.scss @@ -0,0 +1,9 @@ +// Code generated by @carbon/react. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/icon-indicator/icon-indicator'; diff --git a/packages/react/scss/components/icon-indicator/_index.scss b/packages/react/scss/components/icon-indicator/_index.scss new file mode 100644 index 000000000000..aebc92cede58 --- /dev/null +++ b/packages/react/scss/components/icon-indicator/_index.scss @@ -0,0 +1,9 @@ +// Code generated by @carbon/react. DO NOT EDIT. +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward '@carbon/styles/scss/components/icon-indicator'; diff --git a/packages/react/src/__tests__/index-test.js b/packages/react/src/__tests__/index-test.js index 17cd9a659b01..fe6ddc2e7fdb 100644 --- a/packages/react/src/__tests__/index-test.js +++ b/packages/react/src/__tests__/index-test.js @@ -284,6 +284,7 @@ describe('Carbon Components React', () => { "unstable__FluidTimePicker", "unstable__FluidTimePickerSelect", "unstable__FluidTimePickerSkeleton", + "unstable__IconIndicator", "unstable__Slug", "unstable__SlugActions", "unstable__SlugContent", diff --git a/packages/react/src/components/DataTable/stories/dynamic-content/DataTable-dynamic-content.stories.js b/packages/react/src/components/DataTable/stories/dynamic-content/DataTable-dynamic-content.stories.js index a8ec5fdb9400..b30c49104d36 100644 --- a/packages/react/src/components/DataTable/stories/dynamic-content/DataTable-dynamic-content.stories.js +++ b/packages/react/src/components/DataTable/stories/dynamic-content/DataTable-dynamic-content.stories.js @@ -31,7 +31,65 @@ import DataTable, { TableToolbarSearch, TableToolbarMenu, } from '../..'; -import { batchActionClick, rows, headers } from '../shared'; +import { batchActionClick, headers } from '../shared'; +import IconIndicator from '../../../IconIndicator'; + +const rows = [ + { + id: 'a', + name: 'Load Balancer 3', + protocol: 'HTTP', + port: 3000, + rule: 'Round robin', + attached_groups: 'Kevin’s VM Groups', + status: , + }, + { + id: 'b', + name: 'Load Balancer 1', + protocol: 'HTTP', + port: 443, + rule: 'Round robin', + attached_groups: 'Maureen’s VM Groups', + status: , + }, + { + id: 'c', + name: 'Load Balancer 2', + protocol: 'HTTP', + port: 80, + rule: 'DNS delegation', + attached_groups: 'Andrew’s VM Groups', + status: , + }, + { + id: 'd', + name: 'Load Balancer 6', + protocol: 'HTTP', + port: 3000, + rule: 'Round robin', + attached_groups: 'Marc’s VM Groups', + status: , + }, + { + id: 'e', + name: 'Load Balancer 4', + protocol: 'HTTP', + port: 443, + rule: 'Round robin', + attached_groups: 'Mel’s VM Groups', + status: , + }, + { + id: 'f', + name: 'Load Balancer 5', + protocol: 'HTTP', + port: 80, + rule: 'DNS delegation', + attached_groups: 'Ronja’s VM Groups', + status: , + }, +]; export default { title: 'Components/DataTable/Dynamic', diff --git a/packages/react/src/components/IconIndicator/IconIndicator.mdx b/packages/react/src/components/IconIndicator/IconIndicator.mdx new file mode 100644 index 000000000000..0236b269827c --- /dev/null +++ b/packages/react/src/components/IconIndicator/IconIndicator.mdx @@ -0,0 +1,58 @@ +import { ArgTypes, Meta } from '@storybook/blocks'; + + + +# IconIndicator + +[Source code](https://github.com/carbon-design-system/carbon/tree/main/packages/react/src/components/IconIndicator) +  + +{/* */} + +## Table of Contents + +- [Overview](#overview) +- [Component API](#component-api) +- [Feedback](#feedback) + +{/* */} + +## Overview + +The `IconIndicator` component is useful for communicating severity level +information to users. The shapes and colors, communicate severity that enables +users to quickly assess and identify status and respond accordingly. + +```jsx +import { IconIndicator as unstable__IconIndicator } from '@carbon/react'; + +function ExampleComponent() { + return ( + + ); +} +``` + +## Kind + +Icon indicators can take the form of failed, caution major, caution minor, +undefined, succeeded, normal, in-progressm incomplete, not started, pending, +unknown, and informative. + +## Size + +Icon indicators have two size options 16 and 20. The default is 16. + +## Customizing the label + +You can set a string to customize the label of the Icon indicator. + +## Component API + + + +## Feedback + +Help us improve this component by providing feedback, asking questions on Slack, +or updating this file on +[GitHub](https://github.com/carbon-design-system/carbon/edit/main/packages/react/src/components/IconIndicator/IconIndicator.mdx). diff --git a/packages/react/src/components/IconIndicator/IconIndicator.stories.js b/packages/react/src/components/IconIndicator/IconIndicator.stories.js new file mode 100644 index 000000000000..5136ccb2def7 --- /dev/null +++ b/packages/react/src/components/IconIndicator/IconIndicator.stories.js @@ -0,0 +1,73 @@ +/** + * Copyright IBM Corp. 2016, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import React from 'react'; +import IconIndicator from '.'; +import { IconIndicatorKinds } from './index'; +import mdx from './IconIndicator.mdx'; + +export default { + title: 'Experimental/StatusIndicators/unstable__IconIndicator', + component: IconIndicator, + parameters: { + docs: { + page: mdx, + }, + }, +}; + +export const Default = () => { + return ( +
+ {IconIndicatorKinds.map((type) => ( + <> + + + + ))} +
+ ); +}; + +const PlaygroundStory = (props) => { + return ; +}; + +export const Playground = PlaygroundStory.bind({}); + +Playground.args = { + label: 'Custom label', + kind: 'failed', + size: 16, +}; + +Playground.argTypes = { + label: { + control: { + type: 'text', + }, + }, + kind: { + control: { + type: 'select', + }, + options: IconIndicatorKinds, + }, + size: { + control: { + type: 'select', + }, + options: [16, 20], + }, +}; diff --git a/packages/react/src/components/IconIndicator/__tests__/IconIndicator-test.js b/packages/react/src/components/IconIndicator/__tests__/IconIndicator-test.js new file mode 100644 index 000000000000..6d122583ec1a --- /dev/null +++ b/packages/react/src/components/IconIndicator/__tests__/IconIndicator-test.js @@ -0,0 +1,44 @@ +/** + * Copyright IBM Corp. 2016, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import IconIndicator from '../index'; + +describe('IconIndicator', () => { + it('should use a custom label', () => { + render(); + expect(screen.getByText('label')).toBeInTheDocument(); + }); + + it('should update with size prop', () => { + render(); + expect(screen.getByText('label')).toHaveClass('cds--icon-indicator--20'); + }); + + it('should update with kind prop', () => { + render(); + expect(document.querySelector('svg')).toHaveClass( + 'cds--icon-indicator--pending' + ); + }); + + it('should support a custom class name on the outermost element', () => { + const { container } = render( + + ); + expect(container.firstChild).toHaveClass('custom-class'); + }); + + it('should support a ref on the outermost element', () => { + const ref = jest.fn(); + const { container } = render( + + ); + expect(ref).toHaveBeenCalledWith(container.firstChild); + }); +}); diff --git a/packages/react/src/components/IconIndicator/docs/overview.mdx b/packages/react/src/components/IconIndicator/docs/overview.mdx new file mode 100644 index 000000000000..747a86cea343 --- /dev/null +++ b/packages/react/src/components/IconIndicator/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/react/src/components/IconIndicator/index.tsx b/packages/react/src/components/IconIndicator/index.tsx new file mode 100644 index 000000000000..91f190734ef0 --- /dev/null +++ b/packages/react/src/components/IconIndicator/index.tsx @@ -0,0 +1,133 @@ +/** + * Copyright IBM Corp. 2016, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import PropTypes from 'prop-types'; +import React from 'react'; +import cx from 'classnames'; +import { usePrefix } from '../../internal/usePrefix'; +import { + ErrorFilled, + CheckmarkFilled, + WarningAltFilled, + WarningAltInvertedFilled, + UndefinedFilled, + InProgress, + Incomplete, + CircleDash, + UnknownFilled, + WarningSquareFilled, + CheckmarkOutline, + PendingFilled, +} from '@carbon/icons-react'; + +export const IconIndicatorKinds = [ + 'failed', + 'caution-major', + 'caution-minor', + 'undefined', + 'succeeded', + 'normal', + 'in-progress', + 'incomplete', + 'not-started', + 'pending', + 'unknown', + 'informative', +]; + +const iconTypes = { + failed: ErrorFilled, + ['caution-major']: WarningAltInvertedFilled, + ['caution-minor']: WarningAltFilled, + undefined: UndefinedFilled, + succeeded: CheckmarkFilled, + normal: CheckmarkOutline, + ['in-progress']: InProgress, + incomplete: Incomplete, + ['not-started']: CircleDash, + pending: PendingFilled, + unknown: UnknownFilled, + informative: WarningSquareFilled, +}; + +export type IconIndicatorKind = (typeof IconIndicatorKinds)[number]; + +interface IconIndicatorProps { + /** + * Specify an optional className to add. + */ + className?: string; + + /** + * Specify the kind of icon to be used + */ + kind: IconIndicatorKind; + + /** + * Label next to the icon + */ + label: string; + + /** + * Specify the size of the Icon Indicator. Defaults to 16. + */ + size?: 16 | 20; +} + +export const IconIndicator = React.forwardRef(function IconIndicatorContent( + { + className: customClassName, + kind, + label, + size = 16, + ...rest + }: IconIndicatorProps, + ref: React.Ref +) { + const prefix = usePrefix(); + const classNames = cx(`${prefix}--icon-indicator`, customClassName, { + [`${prefix}--icon-indicator--20`]: size == 20, + }); + + const IconForKind = iconTypes[kind]; + if (!IconForKind) { + return null; + } + return ( +
+ + {label} +
+ ); +}); + +IconIndicator.propTypes = { + /** + * Specify an optional className to add. + */ + className: PropTypes.string, + + /** + * Specify the kind of the Icon Indicator + */ + kind: PropTypes.oneOf(IconIndicatorKinds).isRequired, + + /** + * Label next to the icon. + */ + label: PropTypes.string.isRequired, + + /** + * Specify the size of the Icon Indicator. Defaults to 16. + */ + size: PropTypes.oneOf([16, 20]), +}; + +export default IconIndicator; diff --git a/packages/react/src/index.js b/packages/react/src/index.js index 8700ebd8142e..1319bc6b99df 100644 --- a/packages/react/src/index.js +++ b/packages/react/src/index.js @@ -335,3 +335,5 @@ export { ChatButton as unstable__ChatButton, ChatButtonSkeleton as unstable__ChatButtonSkeleton, } from './components/ChatButton'; + +export { IconIndicator as unstable__IconIndicator } from './components/IconIndicator'; diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 7adc10746533..b60be8450aad 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -189,3 +189,4 @@ export * from './components/Tooltip/DefinitionTooltip'; export * from './components/Theme'; export * from './internal/usePrefix'; export { useIdPrefix } from './internal/useIdPrefix'; +export { IconIndicator as unstable__IconIndicator } from './components/IconIndicator'; diff --git a/packages/styles/__tests__/__snapshots__/styles-test.js.snap b/packages/styles/__tests__/__snapshots__/styles-test.js.snap index ef00ac6812af..dcba62e42ef3 100644 --- a/packages/styles/__tests__/__snapshots__/styles-test.js.snap +++ b/packages/styles/__tests__/__snapshots__/styles-test.js.snap @@ -407,6 +407,16 @@ Array [ "importPath": "@carbon/styles/scss/components/fluid-time-picker", "relativePath": "scss/components/fluid-time-picker", }, + Object { + "filepath": "scss/components/icon-indicator/_icon-indicator.scss", + "importPath": "@carbon/styles/scss/components/icon-indicator/icon-indicator", + "relativePath": "scss/components/icon-indicator/icon-indicator", + }, + Object { + "filepath": "scss/components/icon-indicator/_index.scss", + "importPath": "@carbon/styles/scss/components/icon-indicator", + "relativePath": "scss/components/icon-indicator", + }, Object { "filepath": "scss/components/inline-loading/_index.scss", "importPath": "@carbon/styles/scss/components/inline-loading", diff --git a/packages/styles/files.js b/packages/styles/files.js index b31759d83e32..d1cd1c82e866 100644 --- a/packages/styles/files.js +++ b/packages/styles/files.js @@ -100,6 +100,8 @@ const files = [ 'scss/components/fluid-text-input/_index.scss', 'scss/components/fluid-time-picker/_fluid-time-picker.scss', 'scss/components/fluid-time-picker/_index.scss', + 'scss/components/icon-indicator/_icon-indicator.scss', + 'scss/components/icon-indicator/_index.scss', 'scss/components/inline-loading/_index.scss', 'scss/components/inline-loading/_inline-loading.scss', 'scss/components/link/_index.scss', diff --git a/packages/styles/scss/_zone.scss b/packages/styles/scss/_zone.scss index bf79c8074a56..8f78b112fdc6 100644 --- a/packages/styles/scss/_zone.scss +++ b/packages/styles/scss/_zone.scss @@ -17,6 +17,7 @@ @use './components/button/tokens' as button; @use './components/notification/tokens' as notification; @use './components/tag/tokens' as tag; +@use './components/icon-indicator/tokens' as icon-indicator; /// Specify a Map of zones where the key will be used as part of the selector /// and the value will be a map used to emit CSS Custom Properties for all color @@ -31,7 +32,8 @@ $zones: ( $-components: ( button.$button-tokens, notification.$notification-tokens, - tag.$tag-tokens + tag.$tag-tokens, + icon-indicator.$status-tokens ); @each $name, $theme in $zones { diff --git a/packages/styles/scss/components/_index.scss b/packages/styles/scss/components/_index.scss index 0877a1b896ec..a8f4126a8f09 100644 --- a/packages/styles/scss/components/_index.scss +++ b/packages/styles/scss/components/_index.scss @@ -38,6 +38,7 @@ @use 'fluid-text-input'; @use 'fluid-time-picker'; @use 'form'; +@use 'icon-indicator'; @use 'inline-loading'; @use 'link'; @use 'list'; diff --git a/packages/styles/scss/components/icon-indicator/_icon-indicator.scss b/packages/styles/scss/components/icon-indicator/_icon-indicator.scss new file mode 100644 index 000000000000..2b91deb6a8a3 --- /dev/null +++ b/packages/styles/scss/components/icon-indicator/_icon-indicator.scss @@ -0,0 +1,90 @@ +// +// Copyright IBM Corp. 2016, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use '../../theme' as *; +@use '../../type' as *; +@use '../../config' as *; +@use '../../spacing' as *; +@use '../../colors' as *; +@use './tokens' as *; + +/// icon-indicator styles +/// @access public +/// @group tag +@mixin icon-indicator { + .#{$prefix}--icon-indicator { + @include type-style('body-compact-01'); + + display: flex; + color: $text-secondary; + } + + .#{$prefix}--icon-indicator svg { + align-self: center; + margin-inline-end: $spacing-03; + } + + .#{$prefix}--icon-indicator--20 { + @include type-style('body-compact-02'); + } + + .#{$prefix}--icon-indicator--failed { + fill: $status-red; + } + + .#{$prefix}--icon-indicator--caution-major { + fill: $status-orange; + + path:first-of-type { + fill: $black; + } + } + + .#{$prefix}--icon-indicator--caution-minor { + fill: $status-yellow; + + path:first-of-type { + fill: $black; + } + } + + .#{$prefix}--icon-indicator--undefined { + fill: $status-purple; + } + + .#{$prefix}--icon-indicator--succeeded { + fill: $status-green; + } + + .#{$prefix}--icon-indicator--normal { + fill: $status-blue; + } + + .#{$prefix}--icon-indicator--in-progress { + fill: $status-blue; + } + + .#{$prefix}--icon-indicator--incomplete { + fill: $status-blue; + } + + .#{$prefix}--icon-indicator--not-started { + fill: $status-gray; + } + + .#{$prefix}--icon-indicator--pending { + fill: $status-gray; + } + + .#{$prefix}--icon-indicator--unknown { + fill: $status-gray; + } + + .#{$prefix}--icon-indicator--informative { + fill: $status-blue; + } +} diff --git a/packages/styles/scss/components/icon-indicator/_index.scss b/packages/styles/scss/components/icon-indicator/_index.scss new file mode 100644 index 000000000000..9c2a757521d6 --- /dev/null +++ b/packages/styles/scss/components/icon-indicator/_index.scss @@ -0,0 +1,16 @@ +// +// Copyright IBM Corp. 2018, 2023 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@forward 'icon-indicator'; +@forward 'tokens'; + +@use '../../theme'; +@use 'icon-indicator'; +@use 'tokens'; + +@include theme.add-component-tokens(tokens.$status-tokens); +@include icon-indicator.icon-indicator; diff --git a/packages/styles/scss/components/icon-indicator/_tokens.scss b/packages/styles/scss/components/icon-indicator/_tokens.scss new file mode 100644 index 000000000000..253b532172dd --- /dev/null +++ b/packages/styles/scss/components/icon-indicator/_tokens.scss @@ -0,0 +1,196 @@ +// +// Copyright IBM Corp. 2020 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +@use 'sass:color'; +@use 'sass:map'; +@use '../../config'; +@use '../../colors'; +@use '../../themes'; +@use '../../theme' as *; +@use '../../utilities/component-tokens'; +@use '@carbon/themes/scss/component-tokens' as status; + +// status-red +$status-red: ( + fallback: map.get(status.$status-red, white-theme), + values: ( + ( + theme: themes.$white, + value: map.get(status.$status-red, white-theme), + ), + ( + theme: themes.$g10, + value: map.get(status.$status-red, g-10), + ), + ( + theme: themes.$g90, + value: map.get(status.$status-red, g-90), + ), + ( + theme: themes.$g100, + value: map.get(status.$status-red, g-100), + ), + ), +) !default; + +// status-orange +$status-orange: ( + fallback: map.get(status.$status-orange, white-theme), + values: ( + ( + theme: themes.$white, + value: map.get(status.$status-orange, white-theme), + ), + ( + theme: themes.$g10, + value: map.get(status.$status-orange, g-10), + ), + ( + theme: themes.$g90, + value: map.get(status.$status-orange, g-90), + ), + ( + theme: themes.$g100, + value: map.get(status.$status-orange, g-100), + ), + ), +) !default; + +// status-yellow +$status-yellow: ( + fallback: map.get(status.$status-yellow, white-theme), + values: ( + ( + theme: themes.$white, + value: map.get(status.$status-yellow, white-theme), + ), + ( + theme: themes.$g10, + value: map.get(status.$status-yellow, g-10), + ), + ( + theme: themes.$g90, + value: map.get(status.$status-yellow, g-90), + ), + ( + theme: themes.$g100, + value: map.get(status.$status-yellow, g-100), + ), + ), +) !default; + +// status-green +$status-green: ( + fallback: map.get(status.$status-green, white-theme), + values: ( + ( + theme: themes.$white, + value: map.get(status.$status-green, white-theme), + ), + ( + theme: themes.$g10, + value: map.get(status.$status-green, g-10), + ), + ( + theme: themes.$g90, + value: map.get(status.$status-green, g-90), + ), + ( + theme: themes.$g100, + value: map.get(status.$status-green, g-100), + ), + ), +) !default; + +// status-blue +$status-blue: ( + fallback: map.get(status.$status-blue, white-theme), + values: ( + ( + theme: themes.$white, + value: map.get(status.$status-blue, white-theme), + ), + ( + theme: themes.$g10, + value: map.get(status.$status-blue, g-10), + ), + ( + theme: themes.$g90, + value: map.get(status.$status-blue, g-90), + ), + ( + theme: themes.$g100, + value: map.get(status.$status-blue, g-100), + ), + ), +) !default; + +// status-purple +$status-purple: ( + fallback: map.get(status.$status-purple, white-theme), + values: ( + ( + theme: themes.$white, + value: map.get(status.$status-purple, white-theme), + ), + ( + theme: themes.$g10, + value: map.get(status.$status-purple, g-10), + ), + ( + theme: themes.$g90, + value: map.get(status.$status-purple, g-90), + ), + ( + theme: themes.$g100, + value: map.get(status.$status-purple, g-100), + ), + ), +) !default; + +// status-gray +$status-gray: ( + fallback: map.get(status.$status-gray, white-theme), + values: ( + ( + theme: themes.$white, + value: map.get(status.$status-gray, white-theme), + ), + ( + theme: themes.$g10, + value: map.get(status.$status-gray, g-10), + ), + ( + theme: themes.$g90, + value: map.get(status.$status-gray, g-90), + ), + ( + theme: themes.$g100, + value: map.get(status.$status-gray, g-100), + ), + ), +) !default; + +// Add to $status-tokens map +$status-tokens: ( + status-red: $status-red, + status-orange: $status-orange, + status-yellow: $status-yellow, + status-green: $status-green, + status-blue: $status-blue, + status-purple: $status-purple, + status-gray: $status-gray, +); + +// Generate CSS custom properties for each token +$status-red: component-tokens.get-var($status-red, 'status-red'); +$status-orange: component-tokens.get-var($status-orange, 'status-orange'); +$status-yellow: component-tokens.get-var($status-yellow, 'status-yellow'); +$status-green: component-tokens.get-var($status-green, 'status-green'); +$status-blue: component-tokens.get-var($status-blue, 'status-blue'); +$status-purple: component-tokens.get-var($status-purple, 'status-purple'); +$status-gray: component-tokens.get-var($status-gray, 'status-gray'); diff --git a/packages/themes/scss/_component-tokens.scss b/packages/themes/scss/_component-tokens.scss index 0769ba109d05..060ba363e555 100644 --- a/packages/themes/scss/_component-tokens.scss +++ b/packages/themes/scss/_component-tokens.scss @@ -8,3 +8,4 @@ @forward 'generated/button-tokens'; @forward 'generated/tag-tokens'; @forward 'generated/notification-tokens'; +@forward 'generated/status-tokens'; diff --git a/packages/themes/src/component-tokens/status/index.js b/packages/themes/src/component-tokens/status/index.js new file mode 100644 index 000000000000..ed8dbbdedc16 --- /dev/null +++ b/packages/themes/src/component-tokens/status/index.js @@ -0,0 +1 @@ +export * as statusTokens from './tokens'; diff --git a/packages/themes/src/component-tokens/status/tokens.js b/packages/themes/src/component-tokens/status/tokens.js new file mode 100644 index 000000000000..b61b50bc5353 --- /dev/null +++ b/packages/themes/src/component-tokens/status/tokens.js @@ -0,0 +1,71 @@ +import { + red50, + red60, + orange40, + yellow30, + purple50, + purple60, + green40, + green50, + blue50, + blue70, + gray50, + gray60, + white, + gray100, +} from '@carbon/colors'; + +export const statusRed = { + whiteTheme: red60, + g10: red60, + g90: red50, + g100: red50, +}; + +export const statusOrange = { + whiteTheme: orange40, + g10: orange40, + g90: orange40, + g100: orange40, +}; + +export const statusYellow = { + whiteTheme: yellow30, + g10: yellow30, + g90: yellow30, + g100: yellow30, +}; + +export const statusPurple = { + whiteTheme: purple60, + g10: purple60, + g90: purple50, + g100: purple50, +}; + +export const statusGreen = { + whiteTheme: green50, + g10: green50, + g90: green40, + g100: green40, +}; + +export const statusBlue = { + whiteTheme: blue70, + g10: blue70, + g90: blue50, + g100: blue50, +}; + +export const statusGray = { + whiteTheme: gray60, + g10: gray60, + g90: gray50, + g100: gray50, +}; +export const statusAccessibilityBackground = { + whiteTheme: white, + g10: white, + g90: gray100, + g100: gray100, +}; diff --git a/packages/themes/src/index.js b/packages/themes/src/index.js index 42843674e8bc..2c84f5e9dbea 100644 --- a/packages/themes/src/index.js +++ b/packages/themes/src/index.js @@ -13,6 +13,7 @@ import * as v10 from './v10'; import * as buttonTokens from './component-tokens/button'; import * as tagTokens from './component-tokens/tag'; import * as notificationTokens from './component-tokens/notification'; +import * as statusTokens from './component-tokens/status'; import { formatTokenName } from './tools'; import { unstable_metadata } from './tokens'; @@ -34,6 +35,7 @@ export { buttonTokens, tagTokens, notificationTokens, + statusTokens, unstable_metadata, formatTokenName, }; diff --git a/packages/themes/src/tokens/__tests__/metadata-test.js b/packages/themes/src/tokens/__tests__/metadata-test.js index ce25421ff6a9..8a8e8a92ac97 100644 --- a/packages/themes/src/tokens/__tests__/metadata-test.js +++ b/packages/themes/src/tokens/__tests__/metadata-test.js @@ -1273,6 +1273,34 @@ test('metadata', () => { "name": "notification-action-tertiary-inverse-text-on-color-disabled", "type": "color", }, + Object { + "name": "status-red", + "type": "color", + }, + Object { + "name": "status-orange", + "type": "color", + }, + Object { + "name": "status-yellow", + "type": "color", + }, + Object { + "name": "status-purple", + "type": "color", + }, + Object { + "name": "status-green", + "type": "color", + }, + Object { + "name": "status-blue", + "type": "color", + }, + Object { + "name": "status-gray", + "type": "color", + }, Object { "name": "tag-background-red", "type": "color", diff --git a/packages/themes/src/tokens/components.js b/packages/themes/src/tokens/components.js index 8c98807421fd..6cb1549ef52b 100644 --- a/packages/themes/src/tokens/components.js +++ b/packages/themes/src/tokens/components.js @@ -92,3 +92,17 @@ export const tag = TokenGroup.create({ 'tag-hover-warm-gray', ], }); + +export const status = TokenGroup.create({ + name: 'Status', + properties: [], + tokens: [ + 'status-red', + 'status-orange', + 'status-yellow', + 'status-purple', + 'status-green', + 'status-blue', + 'status-gray', + ], +}); diff --git a/packages/themes/tasks/build.js b/packages/themes/tasks/build.js index 9a1e2013b3ba..b4a6559157a6 100644 --- a/packages/themes/tasks/build.js +++ b/packages/themes/tasks/build.js @@ -20,6 +20,7 @@ const buildModulesTokensFile = require('./builders/modules-tokens'); const buildModulesButtonTokens = require('./builders/modules-button-tokens'); const buildModulesTagTokens = require('./builders/modules-tag-tokens'); const buildModulesNotificationTokens = require('./builders/modules-notification-tokens'); +const buildModulesStatusTokens = require('./builders/modules-status-tokens'); async function build() { reporter.info('Building scss files for themes...'); @@ -69,6 +70,12 @@ async function build() { return buildModulesNotificationTokens(); }, }, + { + filepath: path.join(GENERATED_SCSS_DIR, '_status-tokens.scss'), + builder() { + return buildModulesStatusTokens(); + }, + }, ]; for (const { filepath, builder } of files) { diff --git a/packages/themes/tasks/builders/modules-status-tokens.js b/packages/themes/tasks/builders/modules-status-tokens.js new file mode 100644 index 000000000000..84c3b292c902 --- /dev/null +++ b/packages/themes/tasks/builders/modules-status-tokens.js @@ -0,0 +1,43 @@ +/** + * Copyright IBM Corp. 2015, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const { types: t } = require('@carbon/scss-generator'); +const { TokenFormat } = require('../../src/tokens'); +const { statusTokens } = require('../../src/component-tokens/status'); +const { FILE_BANNER, primitive } = require('./shared'); +const { paramCase } = require('change-case'); + +function buildThemesFile() { + const imports = [t.SassModule('sass:map')]; + + const variables = Object.entries(statusTokens).flatMap( + ([key, statusToken]) => { + return [ + t.Newline(), + t.Assignment({ + id: t.Identifier(paramCase(key)), + init: t.SassMap({ + properties: Object.entries(statusToken).map(([token, value]) => { + const id = TokenFormat.convert({ + name: token, + format: TokenFormat.formats.scss, + }); + return t.SassMapProperty(t.Identifier(id), primitive(value)); + }), + }), + default: true, + }), + ]; + } + ); + + return t.StyleSheet([FILE_BANNER, t.Newline(), ...imports, ...variables]); +} + +module.exports = buildThemesFile; diff --git a/packages/web-components/.storybook/_container.scss b/packages/web-components/.storybook/_container.scss index 8397ebacc793..19c03457552d 100644 --- a/packages/web-components/.storybook/_container.scss +++ b/packages/web-components/.storybook/_container.scss @@ -15,9 +15,11 @@ @use '@carbon/styles/scss/components/button/tokens' as button-tokens; @use '@carbon/styles/scss/components/notification/tokens' as notification-tokens; @use '@carbon/styles/scss/components/tag/tokens' as tag-tokens; +@use '@carbon/styles/scss/components/icon-indicator/tokens' as status-tokens; @include theme.add-component-tokens(button-tokens.$button-tokens); @include theme.add-component-tokens(notification-tokens.$notification-tokens); @include theme.add-component-tokens(tag-tokens.$tag-tokens); +@include theme.add-component-tokens(status-tokens.$status-tokens); // Emit the flex-grid styles @include grid.flex-grid(); diff --git a/packages/web-components/examples/components/icon-indicator/.gitignore b/packages/web-components/examples/components/icon-indicator/.gitignore new file mode 100644 index 000000000000..d94d6e13e948 --- /dev/null +++ b/packages/web-components/examples/components/icon-indicator/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.cache +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/packages/web-components/examples/components/icon-indicator/.sassrc b/packages/web-components/examples/components/icon-indicator/.sassrc new file mode 100644 index 000000000000..956b9e0a3d8a --- /dev/null +++ b/packages/web-components/examples/components/icon-indicator/.sassrc @@ -0,0 +1,6 @@ +{ + "includePaths": [ + "node_modules", + "../../node_modules" + ] +} \ No newline at end of file diff --git a/packages/web-components/examples/components/icon-indicator/cdn.html b/packages/web-components/examples/components/icon-indicator/cdn.html new file mode 100644 index 000000000000..b3f88a71d4b4 --- /dev/null +++ b/packages/web-components/examples/components/icon-indicator/cdn.html @@ -0,0 +1,30 @@ + + + + + @carbon/ibmdotcom-web-components example + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/icon-indicator/index.html b/packages/web-components/examples/components/icon-indicator/index.html new file mode 100644 index 000000000000..4adcb253ff0e --- /dev/null +++ b/packages/web-components/examples/components/icon-indicator/index.html @@ -0,0 +1,30 @@ + + + + + carbon-web-components example + + + + + + + + + + + + diff --git a/packages/web-components/examples/components/icon-indicator/package.json b/packages/web-components/examples/components/icon-indicator/package.json new file mode 100644 index 000000000000..c94bb213b9a4 --- /dev/null +++ b/packages/web-components/examples/components/icon-indicator/package.json @@ -0,0 +1,22 @@ +{ + "name": "carbon-web-components-icon-indicator-example", + "version": "0.1.0", + "private": true, + "description": "Sample project for getting started with the Web Components from Carbon.", + "license": "Apache-2", + "main": "index.html", + "scripts": { + "build": "vite build", + "clean": "rimraf node_modules dist .cache", + "dev": "vite" + }, + "dependencies": { + "@carbon/styles": "^1.34.0", + "@carbon/web-components": "latest", + "sass": "^1.64.1" + }, + "devDependencies": { + "vite": "5.2.13", + "rimraf": "^3.0.2" + } +} diff --git a/packages/web-components/examples/components/icon-indicator/sandbox.config.json b/packages/web-components/examples/components/icon-indicator/sandbox.config.json new file mode 100644 index 000000000000..a4df8557d7bf --- /dev/null +++ b/packages/web-components/examples/components/icon-indicator/sandbox.config.json @@ -0,0 +1,3 @@ +{ + "template": "node" +} diff --git a/packages/web-components/examples/components/icon-indicator/src/index.js b/packages/web-components/examples/components/icon-indicator/src/index.js new file mode 100644 index 000000000000..4143768e5159 --- /dev/null +++ b/packages/web-components/examples/components/icon-indicator/src/index.js @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2022 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import '@carbon/web-components/es/components/icon-indicator/index.js'; diff --git a/packages/web-components/examples/components/icon-indicator/src/styles.scss b/packages/web-components/examples/components/icon-indicator/src/styles.scss new file mode 100644 index 000000000000..dcbf34e26210 --- /dev/null +++ b/packages/web-components/examples/components/icon-indicator/src/styles.scss @@ -0,0 +1,12 @@ +@use '@carbon/styles/scss/reset'; +@use '@carbon/styles/scss/theme'; +@use '@carbon/styles/scss/themes'; + +@use '@carbon/styles/scss/components/icon-indicator/tokens' as status-tokens; +@include theme.add-component-tokens(status-tokens.$status-tokens); + +:root { + @include theme.theme(themes.$white); + background-color: var(--cds-background); + color: var(--cds-text-primary); +} diff --git a/packages/web-components/examples/components/icon-indicator/vite.config.js b/packages/web-components/examples/components/icon-indicator/vite.config.js new file mode 100644 index 000000000000..1e91b76eb5da --- /dev/null +++ b/packages/web-components/examples/components/icon-indicator/vite.config.js @@ -0,0 +1,12 @@ +import { resolve } from "path"; +import { defineConfig } from "vite"; + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, "index.html"), + }, + }, + }, +}); diff --git a/packages/web-components/src/components/data-table/stories/data-table-dynamic.stories.ts b/packages/web-components/src/components/data-table/stories/data-table-dynamic.stories.ts index 487cf2a93d2a..196dbf9cb6ef 100644 --- a/packages/web-components/src/components/data-table/stories/data-table-dynamic.stories.ts +++ b/packages/web-components/src/components/data-table/stories/data-table-dynamic.stories.ts @@ -18,6 +18,7 @@ import Download16 from '@carbon/icons/lib/download/16.js'; // @ts-ignore import Settings16 from '@carbon/icons/lib/settings/16.js'; import '../index'; +import '../../icon-indicator/index'; import storyDocs from './data-table.mdx'; const sizes = { @@ -186,9 +187,11 @@ export const Default = { 3000 Round robin Kevin's VM Groups - Disabled + + + Load Balancer 1 @@ -196,7 +199,11 @@ export const Default = { 443 Round robin Maureen's VM Groups - Starting + Load Balancer 2 @@ -204,7 +211,11 @@ export const Default = { 80 DNS delegation Andrew's VM Groups - Active + Load Balancer 6 @@ -213,8 +224,10 @@ export const Default = { Round robin Marc's VM Groups Disabled + > Load Balancer 4 @@ -222,7 +235,11 @@ export const Default = { 443 Round robin Mel's VM Groups - Starting + Load Balancer 5 @@ -230,7 +247,11 @@ export const Default = { 80 DNS delegation Ronja's VM Groups - Active + @@ -308,8 +329,10 @@ export const Playground = { Round robin Kevin's VM Groups Disabled + >
Expandable row content
@@ -321,7 +344,11 @@ export const Playground = { 443 Round robin Maureen's VM Groups - Starting +
Expandable row content
@@ -333,7 +360,11 @@ export const Playground = { 80 DNS delegation Andrew's VM Groups - Active +
Expandable row content
@@ -346,8 +377,10 @@ export const Playground = { Round robin Marc's VM Groups Disabled + >
Expandable row content
@@ -359,7 +392,11 @@ export const Playground = { 443 Round robin Mel's VM Groups - Starting +
Expandable row content
@@ -371,7 +408,11 @@ export const Playground = { 80 DNS delegation Ronja's VM Groups - Active +
Expandable row content
diff --git a/packages/web-components/src/components/icon-indicator/defs.ts b/packages/web-components/src/components/icon-indicator/defs.ts new file mode 100644 index 000000000000..96497c6d6d34 --- /dev/null +++ b/packages/web-components/src/components/icon-indicator/defs.ts @@ -0,0 +1,70 @@ +/** + * @license + * + * Copyright IBM Corp. 2020, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +export enum ICON_INDICATOR_KIND { + /** + * Failed + */ + FAILED = 'failed', + + /** + * Caution major. + */ + 'CAUTION-MAJOR' = 'caution-major', + + /** + * Caution minor. + */ + 'CAUTION-MINOR' = 'caution-minor', + + /** + * Undefined. + */ + UNDEFINED = 'undefined', + + /** + * Succeeded. + */ + SUCCEEDED = 'succeeded', + + /** + * Normal. + */ + NORMAL = 'normal', + + /** + * In-progress. + */ + 'IN-PROGRESS' = 'in-progress', + + /** + * Incomplete. + */ + INCOMPLETE = 'incomplete', + + /** + * Not started. + */ + 'NOT-STARTED' = 'not-started', + + /** + * Pending. + */ + PENDING = 'pending', + + /** + * Unknown. + */ + UNKNOWN = 'unknown', + + /** + * Informative. + */ + INFORMATIVE = 'informative', +} diff --git a/packages/web-components/src/components/icon-indicator/docs/overview.mdx b/packages/web-components/src/components/icon-indicator/docs/overview.mdx new file mode 100644 index 000000000000..4314c34fed03 --- /dev/null +++ b/packages/web-components/src/components/icon-indicator/docs/overview.mdx @@ -0,0 +1,12 @@ +## Live demo + + diff --git a/packages/web-components/src/components/icon-indicator/icon-indicator.mdx b/packages/web-components/src/components/icon-indicator/icon-indicator.mdx new file mode 100644 index 000000000000..ae1ebae9ca49 --- /dev/null +++ b/packages/web-components/src/components/icon-indicator/icon-indicator.mdx @@ -0,0 +1,40 @@ +import { ArgTypes, Markdown, Meta } from '@storybook/blocks'; +import { cdnJs, cdnCss } from '../../globals/internal/storybook-cdn'; +import * as IconIndicatorStories from './icon-indicator.stories'; + + + +# Icon indicator + +The icon-indicator component is useful for communicating severity level +information to users. The shapes and colors, communicate severity that enables +users to quickly assess and identify status and respond accordingly. + +> 💡 Check our +> [Stackblitz](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/icon-indicator) +> example implementation. + +[![Edit carbon-web-components](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/carbon-design-system/carbon/tree/main/packages/web-components/examples/components/icon-indicator) + +## Getting started + +Here's a quick example to get you started. + +### JS (via import) + +```javascript +import '@carbon/web-components/es/components/icon-indicator/index.js'; +``` + +{`${cdnJs({ components: ['icon-indicator'] })}`} +{`${cdnCss()}`} + +### HTML + +```html + +``` + +## `` attributes and properties + + diff --git a/packages/web-components/src/components/icon-indicator/icon-indicator.scss b/packages/web-components/src/components/icon-indicator/icon-indicator.scss new file mode 100644 index 000000000000..7834788b926d --- /dev/null +++ b/packages/web-components/src/components/icon-indicator/icon-indicator.scss @@ -0,0 +1,67 @@ +// +// Copyright IBM Corp. 2019, 2024 +// +// This source code is licensed under the Apache-2.0 license found in the +// LICENSE file in the root directory of this source tree. +// + +$css--plex: true !default; + +@use '@carbon/styles/scss/config' as *; +@use '@carbon/styles/scss/components/icon-indicator/index' as *; + +:host(#{$prefix}-icon-indicator) { + @extend .#{$prefix}--icon-indicator; +} + +:host(#{$prefix}-icon-indicator[size='20']) { + @extend .#{$prefix}--icon-indicator--20; +} + +:host(#{$prefix}-icon-indicator[kind='failed']) svg { + @extend .#{$prefix}--icon-indicator--failed; +} + +:host(#{$prefix}-icon-indicator[kind='caution-major']) svg { + @extend .#{$prefix}--icon-indicator--caution-major; +} + +:host(#{$prefix}-icon-indicator[kind='caution-minor']) svg { + @extend .#{$prefix}--icon-indicator--caution-minor; +} + +:host(#{$prefix}-icon-indicator[kind='undefined']) svg { + @extend .#{$prefix}--icon-indicator--undefined; +} + +:host(#{$prefix}-icon-indicator[kind='succeeded']) svg { + @extend .#{$prefix}--icon-indicator--succeeded; +} + +:host(#{$prefix}-icon-indicator[kind='normal']) svg { + @extend .#{$prefix}--icon-indicator--normal; +} + +:host(#{$prefix}-icon-indicator[kind='in-progress']) svg { + @extend .#{$prefix}--icon-indicator--in-progress; +} + +:host(#{$prefix}-icon-indicator[kind='incomplete']) svg { + @extend .#{$prefix}--icon-indicator--incomplete; +} + +:host(#{$prefix}-icon-indicator[kind='not-started']) svg { + @extend .#{$prefix}--icon-indicator--not-started; +} + +:host(#{$prefix}-icon-indicator[kind='pending']) svg { + @extend .#{$prefix}--icon-indicator--pending; +} + +:host(#{$prefix}-icon-indicator[kind='unknown']) svg { + @extend .#{$prefix}--icon-indicator--unknown; +} + +:host(#{$prefix}-icon-indicator[kind='informative']) svg { + @extend .#{$prefix}--icon-indicator--informative; +} diff --git a/packages/web-components/src/components/icon-indicator/icon-indicator.stories.ts b/packages/web-components/src/components/icon-indicator/icon-indicator.stories.ts new file mode 100644 index 000000000000..7a3f1273018d --- /dev/null +++ b/packages/web-components/src/components/icon-indicator/icon-indicator.stories.ts @@ -0,0 +1,86 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { html } from 'lit'; +import './index'; +import { ICON_INDICATOR_KIND } from './defs'; + +const kinds = [ + 'failed', + 'caution-major', + 'caution-minor', + 'undefined', + 'succeeded', + 'normal', + 'in-progress', + 'incomplete', + 'not-started', + 'pending', + 'unknown', + 'informative', +]; + +export const Default = { + render: () => html` +
+ ${kinds.map( + (kind) => html` + + + ` + )} +
+ `, +}; + +const defaultArgs = { + label: 'Custom label', + kind: ICON_INDICATOR_KIND.FAILED, + size: 16, +}; + +const controls = { + size: { + control: 'select', + description: + 'Specify the size of the Icon Indicator. Currently supports either 16 (default) or 20 sizes.', + options: [16, 20], + }, + label: { + control: 'text', + description: 'Label next to the icon.', + }, + kind: { + control: 'select', + description: 'Specify the kind of the Icon Indicator.', + options: kinds, + }, +}; + +export const Playground = { + argTypes: controls, + args: defaultArgs, + render: ({ label, size, kind }) => + html` `, +}; + +const meta = { + title: 'Experimental/Status Indicators/Icon Indicator', +}; + +export default meta; diff --git a/packages/web-components/src/components/icon-indicator/icon-indicator.ts b/packages/web-components/src/components/icon-indicator/icon-indicator.ts new file mode 100644 index 000000000000..b1320285add4 --- /dev/null +++ b/packages/web-components/src/components/icon-indicator/icon-indicator.ts @@ -0,0 +1,127 @@ +/** + * @license + * + * Copyright IBM Corp. 2019, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { prefix } from '../../globals/settings'; +import { ICON_INDICATOR_KIND } from './defs'; +import ErrorFilled16 from '@carbon/icons/lib/error--filled/16.js'; +import ErrorFilled20 from '@carbon/icons/lib/error--filled/20.js'; +import WarningAltInvertedFilled16 from '@carbon/icons/lib/warning--alt-inverted--filled/16.js'; +import WarningAltInvertedFilled20 from '@carbon/icons/lib/warning--alt-inverted--filled/20.js'; +import WarningAltFilled16 from '@carbon/icons/lib/warning--alt--filled/16.js'; +import WarningAltFilled20 from '@carbon/icons/lib/warning--alt--filled/20.js'; +import UndefinedFilled16 from '@carbon/icons/lib/undefined--filled/16.js'; +import UndefinedFilled20 from '@carbon/icons/lib/undefined--filled/20.js'; +import CheckmarkFilled16 from '@carbon/icons/lib/checkmark--filled/16.js'; +import CheckmarkFilled20 from '@carbon/icons/lib/checkmark--filled/20.js'; +import CheckmarkOutline16 from '@carbon/icons/lib/checkmark--outline/16.js'; +import CheckmarkOutline20 from '@carbon/icons/lib/checkmark--outline/20.js'; +import InProgress16 from '@carbon/icons/lib/in-progress/16.js'; +import InProgress20 from '@carbon/icons/lib/in-progress/20.js'; +import Incomplete16 from '@carbon/icons/lib/incomplete/16.js'; +import Incomplete20 from '@carbon/icons/lib/incomplete/20.js'; +import CircleDash16 from '@carbon/icons/lib/circle-dash/16.js'; +import CircleDash20 from '@carbon/icons/lib/circle-dash/20.js'; +import Pending16 from '@carbon/icons/lib/pending--filled/16.js'; +import Pending20 from '@carbon/icons/lib/pending--filled/20.js'; +import UnknownFilled16 from '@carbon/icons/lib/unknown--filled/16.js'; +import UnknownFilled20 from '@carbon/icons/lib/unknown--filled/20.js'; +import WarningSquareFilled16 from '@carbon/icons/lib/warning-square--filled/16.js'; +import WarningSquareFilled20 from '@carbon/icons/lib/warning-square--filled/20.js'; +export { ICON_INDICATOR_KIND }; + +import styles from './icon-indicator.scss?lit'; +import { carbonElement as customElement } from '../../globals/decorators/carbon-element'; + +const iconMap = { + [ICON_INDICATOR_KIND.FAILED]: { + 16: ErrorFilled16, + 20: ErrorFilled20, + }, + [ICON_INDICATOR_KIND['CAUTION-MAJOR']]: { + 16: WarningAltInvertedFilled16, + 20: WarningAltInvertedFilled20, + }, + [ICON_INDICATOR_KIND['CAUTION-MINOR']]: { + 16: WarningAltFilled16, + 20: WarningAltFilled20, + }, + [ICON_INDICATOR_KIND.UNDEFINED]: { + 16: UndefinedFilled16, + 20: UndefinedFilled20, + }, + [ICON_INDICATOR_KIND.SUCCEEDED]: { + 16: CheckmarkFilled16, + 20: CheckmarkFilled20, + }, + [ICON_INDICATOR_KIND.NORMAL]: { + 16: CheckmarkOutline16, + 20: CheckmarkOutline20, + }, + [ICON_INDICATOR_KIND['IN-PROGRESS']]: { + 16: InProgress16, + 20: InProgress20, + }, + [ICON_INDICATOR_KIND.INCOMPLETE]: { + 16: Incomplete16, + 20: Incomplete20, + }, + [ICON_INDICATOR_KIND['NOT-STARTED']]: { + 16: CircleDash16, + 20: CircleDash20, + }, + [ICON_INDICATOR_KIND.PENDING]: { + 16: Pending16, + 20: Pending20, + }, + [ICON_INDICATOR_KIND.UNKNOWN]: { + 16: UnknownFilled16, + 20: UnknownFilled20, + }, + [ICON_INDICATOR_KIND.INFORMATIVE]: { + 16: WarningSquareFilled16, + 20: WarningSquareFilled20, + }, +}; + +/** + * Icon Indicator. + * + * @element cds-icon-indicator + */ +@customElement(`${prefix}-icon-indicator`) +class CDSIconIndicator extends LitElement { + /** + * Icon indicator should be size 16 or 20 + */ + @property() + size = 16; + + /** + * Label next to the icon. + */ + @property() + label!: string; + + /** + * Icon Indicator kind + */ + @property() + kind!: ICON_INDICATOR_KIND; + + render() { + const icon = iconMap[this.kind]?.[this.size]; + return html`${icon()}${this.label}`; + } + + static styles = styles; // `styles` here is a `CSSResult` generated by custom Vite loader +} + +export default CDSIconIndicator; diff --git a/packages/web-components/src/components/icon-indicator/index.ts b/packages/web-components/src/components/icon-indicator/index.ts new file mode 100644 index 000000000000..4f59fbfc8300 --- /dev/null +++ b/packages/web-components/src/components/icon-indicator/index.ts @@ -0,0 +1,10 @@ +/** + * @license + * + * Copyright IBM Corp. 2021, 2023 + * + * This source code is licensed under the Apache-2.0 license found in the + * LICENSE file in the root directory of this source tree. + */ + +import './icon-indicator'; diff --git a/packages/web-components/src/index.ts b/packages/web-components/src/index.ts index b655fce5cbbb..64996334ee96 100644 --- a/packages/web-components/src/index.ts +++ b/packages/web-components/src/index.ts @@ -67,6 +67,7 @@ export { default as CDSDropdownSkeleton } from './components/dropdown/dropdown-s export { default as CDSFormItem } from './components/form/form-item'; export { default as CDSFormGroup } from './components/form-group/form-group'; export { default as CDSIconButton } from './components/icon-button/icon-button'; +export { default as CDSIconIndicator } from './components/icon-indicator/icon-indicator'; export { default as CDSTextInput } from './components/text-input/text-input'; export { default as CDSTextInputSkeleton } from './components/text-input/text-input-skeleton'; export { default as CDSInlineLoading } from './components/inline-loading/inline-loading';