diff --git a/.changeset/flat-mirrors-fail.md b/.changeset/flat-mirrors-fail.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/flat-mirrors-fail.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/components/src/Card/Card.module.scss b/packages/components/src/Card/Card.module.scss new file mode 100644 index 00000000000..c639e05c474 --- /dev/null +++ b/packages/components/src/Card/Card.module.scss @@ -0,0 +1,38 @@ +@import "~@kaizen/design-tokens/sass/shadow"; +@import "~@kaizen/design-tokens/sass/border"; +@import "~@kaizen/design-tokens/sass/color"; + +.wrapper { + color: $color-purple-800; + background-color: $color-white; + border-radius: $border-borderless-border-radius; + box-shadow: $shadow-small-box-shadow; +} + +.informative { + background-color: $color-blue-100; +} + +.positive { + background-color: $color-green-100; +} + +.cautionary { + background-color: $color-yellow-100; +} + +.destructive { + background-color: $color-red-100; +} + +.assertive { + background-color: $color-orange-100; +} + +.highlight { + background-color: $color-purple-100; +} + +.elevated { + box-shadow: $shadow-large-box-shadow; +} diff --git a/packages/components/src/Card/Card.tsx b/packages/components/src/Card/Card.tsx new file mode 100644 index 00000000000..3c58f461f49 --- /dev/null +++ b/packages/components/src/Card/Card.tsx @@ -0,0 +1,59 @@ +import React, { HTMLAttributes } from "react" +import classnames from "classnames" +import { OverrideClassName } from "~types/OverrideClassName" +import styles from "./Card.module.scss" + +export type CardVariants = + | "default" + | "informative" + | "positive" + | "cautionary" + | "destructive" + | "assertive" + | "highlight" + +export type CardProps = OverrideClassName> & { + children?: React.ReactNode + /** + * HTML elements that are allowed on Card. + */ + tag?: "div" | "article" | "header" | "main" | "section" | "li" + /** + * determines the card background colour on the card. It should match to the type of content being conveyed. + */ + variant?: CardVariants + /** + * Adds a larger box shadow to to the card container. + */ + isElevated?: boolean +} + +/** + * {@link https://cultureamp.atlassian.net/wiki/spaces/DesignSystem/pages/3082094938/Card Guidance} | + * {@link https://cultureamp.design/?path=/story/components-card--docs Storybook} + */ +export const Card = ({ + children, + tag = "div", + variant = "default", + isElevated = false, + classNameOverride, + ...props +}: CardProps): JSX.Element => { + const Tag = tag + return ( + + {children} + + ) +} + +Card.displayName = "Card" diff --git a/packages/components/src/Card/_docs/Card.mdx b/packages/components/src/Card/_docs/Card.mdx new file mode 100644 index 00000000000..df7daa5fd8c --- /dev/null +++ b/packages/components/src/Card/_docs/Card.mdx @@ -0,0 +1,32 @@ +import { Canvas, Controls, DocsStory, Meta } from "@storybook/blocks" +import { ResourceLinks, KaioNotification, Installation } from "~storybook/components" +import * as CardStories from "./Card.stories" + + + +# Card + + + + + + + +## Overview + +The `Card` component is a flexible container used to wrap primary content. It has several variants (moods) to assist in displaying information to a user. In the UI toolkit you will find the `Card` component is referred to as `Container`. + + + + +## API + + + + diff --git a/packages/components/src/Card/_docs/Card.stickersheet.stories.tsx b/packages/components/src/Card/_docs/Card.stickersheet.stories.tsx new file mode 100644 index 00000000000..b84dcba2a24 --- /dev/null +++ b/packages/components/src/Card/_docs/Card.stickersheet.stories.tsx @@ -0,0 +1,77 @@ +import React from "react" +import { Meta } from "@storybook/react" +import { + StickerSheet, + StickerSheetStory, +} from "~storybook/components/StickerSheet" +import { Card, CardProps } from "../index" + +export default { + title: "KAIO-staging/Card", + parameters: { + chromatic: { disable: false }, + controls: { disable: true }, + }, +} satisfies Meta + +const CardWrapper = (args: CardProps): JSX.Element => ( + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +) + +const StickerSheetTemplate: StickerSheetStory = { + render: ({ isReversed }) => ( + + + + + + + + + + + + + + + + + + + + + + + + ), +} + +export const StickerSheetDefault: StickerSheetStory = { + ...StickerSheetTemplate, + name: "Sticker Sheet (Default)", +} + +export const StickerSheetReversed: StickerSheetStory = { + ...StickerSheetTemplate, + name: "Sticker Sheet (Reversed)", + parameters: { backgrounds: { default: "Purple 700" } }, + args: { isReversed: true }, +} + +export const StickerSheetRTL: StickerSheetStory = { + ...StickerSheetTemplate, + name: "Sticker Sheet (RTL)", + parameters: { textDirection: "rtl" }, +} diff --git a/packages/components/src/Card/_docs/Card.stories.tsx b/packages/components/src/Card/_docs/Card.stories.tsx new file mode 100644 index 00000000000..e10061a54c7 --- /dev/null +++ b/packages/components/src/Card/_docs/Card.stories.tsx @@ -0,0 +1,66 @@ +import React from "react" +import { Meta, StoryObj } from "@storybook/react" +import { Card } from "../index" + +const meta = { + title: "KAIO-staging/Card", + component: Card, + args: { + children: "This is a default container", + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Playground: Story = { + parameters: { + docs: { + canvas: { + sourceState: "shown", + }, + }, + }, +} + +export const Variants: Story = { + render: () => ( +
    +
  • + Default +
  • +
  • + Informative +
  • +
  • + Positive +
  • +
  • + Cautionary +
  • +
  • + Destructive +
  • +
  • + Assertive +
  • +
  • + Highlight +
  • +
+ ), +} + +export const Elevation: Story = { + render: () => ( +
    +
  • + Default +
  • +
  • + isElevated +
  • +
+ ), +} diff --git a/packages/components/src/Card/index.ts b/packages/components/src/Card/index.ts new file mode 100644 index 00000000000..1ae2698c5fc --- /dev/null +++ b/packages/components/src/Card/index.ts @@ -0,0 +1 @@ +export * from "./Card" diff --git a/packages/components/src/Divider/Divider.module.scss b/packages/components/src/Divider/Divider.module.scss new file mode 100644 index 00000000000..bc2d1326df6 --- /dev/null +++ b/packages/components/src/Divider/Divider.module.scss @@ -0,0 +1,37 @@ +@import "~@kaizen/design-tokens/sass/border"; +@import "~@kaizen/design-tokens/sass/color"; + +// Use different tokens with different opacities across the Zen and Heart themes, by assuming that when Zen is applied there won't be any CSS variables declared. + +$dt-content-border-color: rgba($color-gray-600-rgb, 0.1); + +.wrapper { + width: 100%; + border: 0; + margin: 0; + border-radius: $border-solid-border-radius; + // This is here to protect against a global style in a consumer. + // https://github.com/cultureamp/murmur/blob/master/app/assets/stylesheets/legacy/modules/_body.scss + visibility: visible; +} + +.content { + border-top: 1px solid; + border-color: $dt-content-border-color; +} + +.canvas { + border-top: 1px solid; + border-bottom: 1px solid; + border-color: rgba($color-gray-600-rgb, 0.1); +} + +.reversed { + border-color: rgba($color-white-rgb, 0.1); +} + +.menuSeparator { + @extend .content; /* stylelint-disable-line scss/at-extend-no-missing-placeholder */ + + margin: 5px 0; +} diff --git a/packages/components/src/Divider/Divider.tsx b/packages/components/src/Divider/Divider.tsx new file mode 100644 index 00000000000..41880637719 --- /dev/null +++ b/packages/components/src/Divider/Divider.tsx @@ -0,0 +1,33 @@ +import React, { HTMLAttributes } from "react" +import classnames from "classnames" +import { OverrideClassName } from "~types/OverrideClassName" +import styles from "./Divider.module.scss" + +export type DividerProps = { + variant: "content" | "canvas" | "menuSeparator" + isReversed?: boolean +} & OverrideClassName> + +/** + * {@link https://cultureamp.atlassian.net/wiki/spaces/DesignSystem/pages/3082061035/Divider Guidance} | + * {@link https://cultureamp.design/?path=/docs/components-divider--docs Storybook} + */ +export const Divider = ({ + variant, + isReversed = false, + classNameOverride, + ...props +}: DividerProps): JSX.Element => ( + +) + +Divider.displayName = "Divider" diff --git a/packages/components/src/Divider/_docs/Divider.mdx b/packages/components/src/Divider/_docs/Divider.mdx new file mode 100644 index 00000000000..cbeb6be6511 --- /dev/null +++ b/packages/components/src/Divider/_docs/Divider.mdx @@ -0,0 +1,32 @@ +import { Canvas, Controls, DocsStory, Meta } from "@storybook/blocks" +import { ResourceLinks, KaioNotification, Installation } from "~storybook/components" +import * as DividerStories from "./Divider.stories" + + + +# Divider + + + + + + + +## Overview + +Dividers are thin lines that group content in lists and layouts, or separate blocks of content. + + + + +## Examples + + diff --git a/packages/components/src/Divider/_docs/Divider.stickersheet.stories.tsx b/packages/components/src/Divider/_docs/Divider.stickersheet.stories.tsx new file mode 100644 index 00000000000..188edf6ba15 --- /dev/null +++ b/packages/components/src/Divider/_docs/Divider.stickersheet.stories.tsx @@ -0,0 +1,46 @@ +import React from "react" +import { Meta } from "@storybook/react" +import { + StickerSheet, + StickerSheetStory, +} from "~storybook/components/StickerSheet" +import { Divider } from "../index" + +export default { + title: "KAIO-staging/Divider", + parameters: { + chromatic: { disable: false }, + controls: { disable: true }, + }, +} satisfies Meta + +const StickerSheetTemplate: StickerSheetStory = { + render: ({ isReversed }) => ( + + + + + + + + + + + + + + + ), +} + +export const StickerSheetDefault: StickerSheetStory = { + ...StickerSheetTemplate, + name: "Sticker Sheet (Default)", +} + +export const StickerSheetReversed: StickerSheetStory = { + ...StickerSheetTemplate, + name: "Sticker Sheet (Reversed)", + parameters: { backgrounds: { default: "Purple 700" } }, + args: { isReversed: true }, +} diff --git a/packages/components/src/Divider/_docs/Divider.stories.tsx b/packages/components/src/Divider/_docs/Divider.stories.tsx new file mode 100644 index 00000000000..71c737ac762 --- /dev/null +++ b/packages/components/src/Divider/_docs/Divider.stories.tsx @@ -0,0 +1,60 @@ +import React from "react" +import { Meta, StoryObj } from "@storybook/react" +import { Heading, Paragraph } from "@kaizen/typography" +import { Card } from "~components/Card" +import { Divider } from "../index" + +const meta = { + title: "KAIO-staging/Divider", + component: Divider, + args: { + variant: "content", + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Playground: Story = { + parameters: { + docs: { + canvas: { + sourceState: "shown", + }, + }, + }, +} + +export const ContentGroup: Story = { + render: () => ( + +
+ + Understands people's agenda and perspectives + + + Interpersonal + +
+ +
+ + Anticipates customers needs + + + Self management + +
+ +
+ + Initiates and develops relationships + + + Interpersonal + +
+
+ ), +} diff --git a/packages/components/src/Divider/index.ts b/packages/components/src/Divider/index.ts new file mode 100644 index 00000000000..a40b3411a56 --- /dev/null +++ b/packages/components/src/Divider/index.ts @@ -0,0 +1 @@ +export * from "./Divider" diff --git a/packages/components/src/EmptyState/EmptyState.module.scss b/packages/components/src/EmptyState/EmptyState.module.scss new file mode 100644 index 00000000000..c4cc5329bfe --- /dev/null +++ b/packages/components/src/EmptyState/EmptyState.module.scss @@ -0,0 +1,157 @@ +@import "~@kaizen/design-tokens/sass/spacing"; +@import "~@kaizen/design-tokens/sass/color"; +@import "~@kaizen/design-tokens/sass/border"; +@import "./mixins"; + +.container { + display: flex; + justify-content: space-around; + width: 100%; + padding: 2% $spacing-md; + color: $color-purple-800; + border: $border-solid-border-width $border-solid-border-style + $border-borderless-border-color-id; + border-radius: $border-solid-border-radius; + + @include small { + flex-direction: column; + align-items: center; + padding-top: $spacing-md; + padding-bottom: $spacing-md; + } + + &.straightCorners { + border-radius: 0; + } + + // These class names must match the possible values of the component's layoutContext prop + &.sidebarAndContent { + @include large-sidebar-and-content { + padding-top: $spacing-md; + padding-bottom: $spacing-md; + } + } + + &.contentOnly { + @include large-content-only { + padding-top: $spacing-md; + padding-bottom: $spacing-md; + } + } + + &.positive { + background-color: $color-green-100; + } + + &.negative { + background-color: $color-red-100; + } + + &.action { + background-color: $color-orange-100; + } + + &.neutral { + background-color: $color-purple-100; + } + + &.informative { + background-color: $color-blue-100; + } +} + +.illustrationSide, +.textSide { + display: inline-block; +} + +.illustrationSide { + min-width: 224px; + flex-grow: 0; + flex-shrink: 1; + margin-bottom: $spacing-md; + + @include small { + width: 224px; + } + + @include medium { + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-end; + margin-bottom: 0; + min-width: 40%; + max-width: 50%; + flex-grow: 1; + box-sizing: border-box; + padding-inline-end: $spacing-md; + } + + .sidebarAndContent & { + @include large-sidebar-and-content { + flex-shrink: 1; + flex-basis: auto; + } + } + + .contentOnly & { + @include large-content-only { + flex-shrink: 1; + flex-basis: auto; + } + } +} + +.illustration, +.illustrationSide video { + max-width: 100%; + max-height: 366px; + width: auto; + + // Fixes for IE11 Flexbox issues + min-height: 196px; + + @include small { + max-height: 196px; + } +} + +.textSide { + display: flex; + flex-grow: 1; + flex-shrink: 1; + align-items: center; + -webkit-font-smoothing: antialiased; + + @include medium { + flex-basis: 50%; + flex-grow: 0; + } +} + +.textSideInner { + flex-grow: 0; + height: auto; + margin: 0 $spacing-sm; + + @include small { + margin-bottom: 0; + } + + @include medium { + max-width: 426px; + } +} + +.heading { + margin-bottom: $spacing-md; + + @media (max-width: (375px)) { + @include typography-heading-3-sm; + } +} + +.description { + margin-bottom: $spacing-md; +} diff --git a/packages/components/src/EmptyState/EmptyState.spec.tsx b/packages/components/src/EmptyState/EmptyState.spec.tsx new file mode 100644 index 00000000000..465ba7e5aca --- /dev/null +++ b/packages/components/src/EmptyState/EmptyState.spec.tsx @@ -0,0 +1,48 @@ +import React from "react" +import { cleanup, render } from "@testing-library/react" +import { EmptyState, EmptyStateProps } from "./EmptyState" + +jest.mock("@kaizen/draft-illustration", () => ({ + EmptyStatesPositive: (): JSX.Element => ( +
EmptyStatesPositive_Component
+ ), + EmptyStatesNeutral: (): JSX.Element => ( +
EmptyStatesNeutral_Component
+ ), + EmptyStatesNegative: (): JSX.Element => ( +
EmptyStatesNegative_Component
+ ), + EmptyStatesInformative: (): JSX.Element => ( +
EmptyStatesInformative_Component
+ ), + EmptyStatesAction: (): JSX.Element =>
EmptyStatesAction_Component
, +})) + +describe("", () => { + afterEach(cleanup) + + const defaultProps: EmptyStateProps = { + id: "someId", + headingProps: { + children: "Some heading", + variant: "heading-1", + }, + bodyText: "Lorem ipsum dolor...", + } + + it("renders an `id` attribute", () => { + const { container } = render() + + expect(container.querySelector("#someId")).toBeTruthy() + }) + + it("renders given children", () => { + const { getByText } = render( + +

Child Heading

+
+ ) + + expect(getByText("Child Heading")).toBeTruthy() + }) +}) diff --git a/packages/components/src/EmptyState/EmptyState.tsx b/packages/components/src/EmptyState/EmptyState.tsx new file mode 100644 index 00000000000..f632d333d1e --- /dev/null +++ b/packages/components/src/EmptyState/EmptyState.tsx @@ -0,0 +1,107 @@ +import React, { HTMLAttributes } from "react" +import classnames from "classnames" +import { + AnimatedSceneProps, + EmptyStatesAction, + EmptyStatesInformative, + EmptyStatesNegative, + EmptyStatesNeutral, + EmptyStatesPositive, +} from "@kaizen/draft-illustration" +import { HeadingProps, Heading, Paragraph } from "@kaizen/typography" +import { OverrideClassName } from "~types/OverrideClassName" +import styles from "./EmptyState.module.scss" + +const ILLUSTRATIONS: Record< + string, + (props: AnimatedSceneProps) => JSX.Element +> = { + positive: EmptyStatesPositive, + neutral: EmptyStatesNeutral, + negative: EmptyStatesNegative, + informative: EmptyStatesInformative, + action: EmptyStatesAction, +} + +type IllustrationType = + | "positive" + | "neutral" + | "negative" + | "informative" + | "action" + +type LayoutContextType = "sidebarAndContent" | "contentOnly" + +export type EmptyStateProps = { + children?: React.ReactNode + id?: string + illustrationType?: IllustrationType + layoutContext?: LayoutContextType + bodyText: string | React.ReactNode + straightCorners?: boolean + headingProps?: HeadingProps +} & OverrideClassName> & + Pick + +/** + * {@link https://cultureamp.atlassian.net/wiki/spaces/DesignSystem/pages/3082094098/Empty+State Guidance} | + * {@link https://cultureamp.design/?path=/docs/components-empty-state--docs Storybook} + */ +export const EmptyState = ({ + children, + id, + illustrationType = "informative", + layoutContext = "sidebarAndContent", + headingProps, + bodyText, + straightCorners, + isAnimated = true, + loop = false, + classNameOverride, + ...props +}: EmptyStateProps): JSX.Element => { + const IllustrationComponent = ILLUSTRATIONS[illustrationType] + + return ( +
+
+ {isAnimated ? ( + + ) : ( + + )} +
+
+
+ {headingProps && ( + + )} + + {bodyText} + + {children} +
+
+
+ ) +} + +EmptyState.displayName = "EmptyState" diff --git a/packages/components/src/EmptyState/_docs/EmptyState.mdx b/packages/components/src/EmptyState/_docs/EmptyState.mdx new file mode 100644 index 00000000000..4e0e6c24e30 --- /dev/null +++ b/packages/components/src/EmptyState/_docs/EmptyState.mdx @@ -0,0 +1,28 @@ +import { Canvas, Controls, Meta } from "@storybook/blocks" +import { ResourceLinks, KaioNotification, Installation } from "~storybook/components" +import * as EmptyStateStories from "./EmptyState.stories" + + + +# EmptyState + + + + + + + +## Overview + +Empty states tell users that there's no content to display—and what they can do next. + + + diff --git a/packages/components/src/EmptyState/_docs/EmptyState.stickersheet.stories.tsx b/packages/components/src/EmptyState/_docs/EmptyState.stickersheet.stories.tsx new file mode 100644 index 00000000000..0a8bed82412 --- /dev/null +++ b/packages/components/src/EmptyState/_docs/EmptyState.stickersheet.stories.tsx @@ -0,0 +1,162 @@ +import React from "react" +import { Meta, StoryFn } from "@storybook/react" +import isChromatic from "chromatic" +import { Button } from "~components/Button" +import { ChevronRightIcon } from "~components/Icons" +import { + StickerSheet, + StickerSheetStory, +} from "~storybook/components/StickerSheet" +import { EmptyState, EmptyStateProps } from "../index" +import styles from "./EmptyState.stories.module.scss" + +export default { + title: "KAIO-staging/EmptyState", + parameters: { + chromatic: { disable: false }, + controls: { disable: true }, + }, +} satisfies Meta + +const IS_CHROMATIC = isChromatic() + +const EmptyStateWrapper: StoryFn = ({ + isAnimated, + ...args +}) => + +const ButtonWrapper = ( +
+
+) + +const POSTIVE_PROPS: EmptyStateProps = { + children: ButtonWrapper, + headingProps: { + variant: "heading-3", + children: "Positive empty state", + }, + bodyText: + "If providing further actions, include a link to an action or use a Default or Primary action.", + illustrationType: "positive", +} + +const INFORMATIVE_PROPS: EmptyStateProps = { + headingProps: { + variant: "heading-3", + children: "Informative empty state", + }, + bodyText: + "If providing further actions, include a link to an action or use a Default or Primary action.", + illustrationType: "informative", +} + +const ACTION_PROPS: EmptyStateProps = { + children: ButtonWrapper, + headingProps: { + variant: "heading-3", + children: "Action empty state", + }, + bodyText: + "If providing further actions, include a link to an action or use a Default or Primary action.", + illustrationType: "action", +} + +const NEUTRAL_PROPS: EmptyStateProps = { + headingProps: { + variant: "heading-3", + children: "Neutral empty state", + }, + bodyText: + "If providing further actions, include a link to an action or use a Default or Primary action.", + illustrationType: "neutral", +} + +const NEGATIVE_PROPS: EmptyStateProps = { + children: ButtonWrapper, + headingProps: { + variant: "heading-3", + children: "Negative empty state", + }, + bodyText: + "If providing further actions, include a link to an action or use a Default or Primary action.", + illustrationType: "negative", +} + +const STRAIGHT_CORNERS_PROPS: EmptyStateProps = { + children: ButtonWrapper, + headingProps: { + variant: "heading-3", + children: "Straight corners empty state", + }, + bodyText: + "If providing further actions, include a link to an action or use a Default or Primary action.", + illustrationType: "action", + straightCorners: true, +} + +const CUSTOM_HEADING_PROPS: EmptyStateProps = { + children: ButtonWrapper, + bodyText: + "Customise heading level so that the correct semantic heading level can be used for your page.", + illustrationType: "neutral", + headingProps: { + variant: "heading-3", + children: "Custom heading empty state", + tag: "h2", + color: "dark-reduced-opacity", + }, +} + +const StickerSheetTemplate: StickerSheetStory = { + render: ({ isReversed }) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + ), +} + +export const StickerSheetDefault: StickerSheetStory = { + ...StickerSheetTemplate, + name: "Sticker Sheet (Default)", +} + +export const StickerSheetReversed: StickerSheetStory = { + ...StickerSheetTemplate, + name: "Sticker Sheet (Reversed)", + parameters: { backgrounds: { default: "Purple 700" } }, + args: { isReversed: true }, +} + +export const StickerSheetRTL: StickerSheetStory = { + ...StickerSheetTemplate, + name: "Sticker Sheet (RTL)", + parameters: { textDirection: "rtl" }, +} diff --git a/packages/components/src/EmptyState/_docs/EmptyState.stories.module.scss b/packages/components/src/EmptyState/_docs/EmptyState.stories.module.scss new file mode 100644 index 00000000000..b213ba6ab2a --- /dev/null +++ b/packages/components/src/EmptyState/_docs/EmptyState.stories.module.scss @@ -0,0 +1,15 @@ +@import "../mixins"; + +.buttonContainer { + // This size mixin comes from EmptyState's _mixins.scss - useful for + // applying your own styles at the component's own breakpoints. + // Unfortunately if you want full-width buttons at the "sm" size and + // regular buttons otherwise, you'll have to specify a fixed width for + // "md" size and above (fullWidth prop on the Button controls full width; + // can't use CSS breakpoints unless we make the Button component aware + // of which page layout and component it's a part of). + // If in doubt, ask Design Systems Team! + @include medium { + width: 118px; + } +} diff --git a/packages/components/src/EmptyState/_docs/EmptyState.stories.tsx b/packages/components/src/EmptyState/_docs/EmptyState.stories.tsx new file mode 100644 index 00000000000..75ce105096c --- /dev/null +++ b/packages/components/src/EmptyState/_docs/EmptyState.stories.tsx @@ -0,0 +1,52 @@ +import React from "react" +import { Meta, StoryObj } from "@storybook/react" +import { Button } from "~components/Button" +import { ChevronRightIcon } from "~components/Icons" +import { EmptyState } from "../index" +import styles from "./EmptyState.stories.module.scss" + +const meta = { + title: "KAIO-staging/EmptyState", + component: EmptyState, + argTypes: { + children: { + table: { type: { summary: "React.ReactNode" } }, + control: { type: "radio" }, + options: ["Default (no children)", "Button (chevron right)"], + mapping: { + "Default (no children)": undefined, + "Button (chevron right)": ( +
+
+ ), + }, + }, + }, + args: { + headingProps: { + variant: "heading-3", + children: "Empty state title", + }, + bodyText: + "If providing further actions, include a link to an action or use a Default or Primary action.", + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Playground: Story = { + parameters: { + docs: { + canvas: { + sourceState: "shown", + }, + }, + }, +} diff --git a/packages/components/src/EmptyState/_mixins.scss b/packages/components/src/EmptyState/_mixins.scss new file mode 100644 index 00000000000..b7f55ea3ec9 --- /dev/null +++ b/packages/components/src/EmptyState/_mixins.scss @@ -0,0 +1,44 @@ +@import "~@kaizen/design-tokens/sass/layout"; + +$small: 300px; +$medium: $layout-breakpoints-medium; +$large: $layout-breakpoints-large; + +// comes from ca-layout-padding x2 which is no longer used +$side-padding: 48px; +$sidebarWidth: 240px; +$sidebarWithPadding: $sidebarWidth + $side-padding; + +$typography-heading-3-font-size-small: 1.25rem; +$typography-heading-3-font-weight-small: 700; +$typography-heading-3-line-height-small: 1.5rem; + +@mixin large-sidebar-and-content { + @media (min-width: ($large + $sidebarWithPadding + $side-padding)) { + @content; + } +} + +@mixin large-content-only { + @media (min-width: ($large + $side-padding)) { + @content; + } +} + +@mixin medium { + @media (min-width: ($medium + $side-padding)) { + @content; + } +} + +@mixin small { + @media (max-width: ($medium + $side-padding - 1px)) { + @content; + } +} + +@mixin typography-heading-3-sm { + font-size: $typography-heading-3-font-size-small; + line-height: $typography-heading-3-line-height-small; + font-weight: $typography-heading-3-font-weight-small; +} diff --git a/packages/components/src/EmptyState/illustrations/action.png b/packages/components/src/EmptyState/illustrations/action.png new file mode 100755 index 00000000000..7949649ee4f Binary files /dev/null and b/packages/components/src/EmptyState/illustrations/action.png differ diff --git a/packages/components/src/EmptyState/illustrations/informative.png b/packages/components/src/EmptyState/illustrations/informative.png new file mode 100755 index 00000000000..a7f24f90556 Binary files /dev/null and b/packages/components/src/EmptyState/illustrations/informative.png differ diff --git a/packages/components/src/EmptyState/illustrations/negative.png b/packages/components/src/EmptyState/illustrations/negative.png new file mode 100755 index 00000000000..70499bcceb6 Binary files /dev/null and b/packages/components/src/EmptyState/illustrations/negative.png differ diff --git a/packages/components/src/EmptyState/illustrations/neutral.png b/packages/components/src/EmptyState/illustrations/neutral.png new file mode 100755 index 00000000000..01d858fad16 Binary files /dev/null and b/packages/components/src/EmptyState/illustrations/neutral.png differ diff --git a/packages/components/src/EmptyState/illustrations/positive.png b/packages/components/src/EmptyState/illustrations/positive.png new file mode 100755 index 00000000000..f37b29127f9 Binary files /dev/null and b/packages/components/src/EmptyState/illustrations/positive.png differ diff --git a/packages/components/src/EmptyState/index.ts b/packages/components/src/EmptyState/index.ts new file mode 100644 index 00000000000..dfdb52e2057 --- /dev/null +++ b/packages/components/src/EmptyState/index.ts @@ -0,0 +1 @@ +export * from "./EmptyState"