diff --git a/playwright/visual.test.ts-snapshots/VisualList-VisualList-Default-1-chromium-linux.png b/playwright/visual.test.ts-snapshots/VisualList-VisualList-Default-1-chromium-linux.png new file mode 100644 index 00000000..8d0d0877 Binary files /dev/null and b/playwright/visual.test.ts-snapshots/VisualList-VisualList-Default-1-chromium-linux.png differ diff --git a/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Default-1-chromium-linux.png b/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Default-1-chromium-linux.png new file mode 100644 index 00000000..e9590432 Binary files /dev/null and b/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Default-1-chromium-linux.png differ diff --git a/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Destructive-1-chromium-linux.png b/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Destructive-1-chromium-linux.png new file mode 100644 index 00000000..f5ae0157 Binary files /dev/null and b/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Destructive-1-chromium-linux.png differ diff --git a/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Multiline-1-chromium-linux.png b/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Multiline-1-chromium-linux.png new file mode 100644 index 00000000..c966df3c Binary files /dev/null and b/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Multiline-1-chromium-linux.png differ diff --git a/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Success-1-chromium-linux.png b/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Success-1-chromium-linux.png new file mode 100644 index 00000000..19b96ffb Binary files /dev/null and b/playwright/visual.test.ts-snapshots/VisualList-VisualListItem-Success-1-chromium-linux.png differ diff --git a/src/components/VisualList/VisualList.module.css b/src/components/VisualList/VisualList.module.css new file mode 100644 index 00000000..046eab81 --- /dev/null +++ b/src/components/VisualList/VisualList.module.css @@ -0,0 +1,26 @@ +/* +Copyright 2024 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.visual-list { + display: flex; + flex-direction: column; + gap: var(--cpd-space-1x); + margin: 0; + padding: 0; + list-style-type: none; + border-radius: var(--cpd-space-3x); + overflow: hidden; +} diff --git a/src/components/VisualList/VisualList.stories.tsx b/src/components/VisualList/VisualList.stories.tsx new file mode 100644 index 00000000..46e80296 --- /dev/null +++ b/src/components/VisualList/VisualList.stories.tsx @@ -0,0 +1,46 @@ +/* + * Copyright 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VisualList as VisualListComponent } from "./VisualList"; +import { Meta, StoryFn } from "@storybook/react"; +import React, { ComponentProps } from "react"; +import InfoIcon from "@vector-im/compound-design-tokens/assets/web/icons/info"; +import { VisualListItem } from "./VisualListItem.tsx"; + +export default { + title: "VisualList/VisualList", + component: VisualListComponent, + tags: ["autodocs"], + argTypes: {}, + args: { + children: ( + <> + First item + Second item + Third item + + ), + }, +} as Meta; + +const Template: StoryFn = ( + args: ComponentProps, +) => { + return ; +}; + +export const Default = Template.bind({}); +Default.args = {}; diff --git a/src/components/VisualList/VisualList.test.tsx b/src/components/VisualList/VisualList.test.tsx new file mode 100644 index 00000000..81689692 --- /dev/null +++ b/src/components/VisualList/VisualList.test.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { composeStories } from "@storybook/react"; +import * as stories from "./VisualList.stories"; +import { describe, expect, it } from "vitest"; +import { render } from "@testing-library/react"; +import React from "react"; + +const { Default } = composeStories(stories); + +describe("VisualList", () => { + it("renders a Default VisualList", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/components/VisualList/VisualList.tsx b/src/components/VisualList/VisualList.tsx new file mode 100644 index 00000000..10638470 --- /dev/null +++ b/src/components/VisualList/VisualList.tsx @@ -0,0 +1,41 @@ +/* +Copyright 2024 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { JSX, PropsWithChildren } from "react"; +import styles from "./VisualList.module.css"; +import classNames from "classnames"; + +interface VisualListProps extends React.HTMLProps { + /** + * The CSS class name. + */ + className?: string; +} + +/** + * A list component. + */ +export function VisualList({ + className, + children, + ...props +}: PropsWithChildren): JSX.Element { + return ( +
    + {children} +
+ ); +} diff --git a/src/components/VisualList/VisualListItem.module.css b/src/components/VisualList/VisualListItem.module.css new file mode 100644 index 00000000..b083dbe6 --- /dev/null +++ b/src/components/VisualList/VisualListItem.module.css @@ -0,0 +1,36 @@ +/* + * Copyright 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.visual-list-item { + display: flex; + gap: var(--cpd-space-3x); + padding: var(--cpd-space-3x) var(--cpd-space-4x); + background-color: var(--cpd-color-bg-subtle-secondary); + font: var(--cpd-font-body-md-medium); +} + +.visual-list-item-icon { + flex-shrink: 0; + color: var(--cpd-color-icon-secondary); +} + +.visual-list-item-icon-success { + color: var(--cpd-color-icon-success-primary); +} + +.visual-list-item-icon-destructive { + color: var(--cpd-color-icon-critical-primary); +} diff --git a/src/components/VisualList/VisualListItem.stories.tsx b/src/components/VisualList/VisualListItem.stories.tsx new file mode 100644 index 00000000..2d2cbe62 --- /dev/null +++ b/src/components/VisualList/VisualListItem.stories.tsx @@ -0,0 +1,56 @@ +/* + * Copyright 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VisualListItem as VisualListItemComponent } from "./VisualListItem"; +import { Meta, StoryFn } from "@storybook/react"; +import React, { ComponentProps } from "react"; +import InfoIcon from "@vector-im/compound-design-tokens/assets/web/icons/info"; + +export default { + title: "VisualList/VisualListItem", + component: VisualListItemComponent, + tags: ["autodocs"], + argTypes: {}, + args: { + Icon: InfoIcon, + children: "List item description", + }, +} as Meta; + +const Template: StoryFn = ( + args: ComponentProps, +) => { + return ; +}; + +export const Default = Template.bind({}); +Default.args = {}; + +export const Success = Template.bind({}); +Success.args = { + success: true, +}; + +export const Destructive = Template.bind({}); +Destructive.args = { + destructive: true, +}; + +export const Multiline = Template.bind({}); +Multiline.args = { + children: + "List item with a looooooooooong very looooooooooong loooooooooooooong description", +}; diff --git a/src/components/VisualList/VisualListItem.test.tsx b/src/components/VisualList/VisualListItem.test.tsx new file mode 100644 index 00000000..ed9a97ad --- /dev/null +++ b/src/components/VisualList/VisualListItem.test.tsx @@ -0,0 +1,42 @@ +/* + * Copyright 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { composeStories } from "@storybook/react"; +import * as stories from "./VisualListItem.stories"; +import { describe, expect, it } from "vitest"; +import { render } from "@testing-library/react"; +import React from "react"; + +const { Default, Success, Destructive, Multiline } = composeStories(stories); + +describe("VisualListItem", () => { + it("renders a Default VisualListItem", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + it("renders a Success VisualListItem", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + it("renders a Destructive VisualListItem", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + it("renders a Multiline VisualListItem", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/components/VisualList/VisualListItem.tsx b/src/components/VisualList/VisualListItem.tsx new file mode 100644 index 00000000..4cfcfcdf --- /dev/null +++ b/src/components/VisualList/VisualListItem.tsx @@ -0,0 +1,63 @@ +/* +Copyright 2024 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { ComponentType, JSX, PropsWithChildren } from "react"; +import styles from "./VisualListItem.module.css"; +import classNames from "classnames"; + +interface VisualListItemProps extends React.HTMLProps { + /** + * The CSS class name. + */ + className?: string; + /** + * The icon component. + */ + Icon: ComponentType>; + + success?: boolean; + destructive?: boolean; +} + +/** + * A list component. + */ +export function VisualListItem({ + className, + children, + Icon, + success = false, + destructive = false, + ...props +}: PropsWithChildren): JSX.Element { + return ( +
  • + + {children} +
  • + ); +} diff --git a/src/components/VisualList/__snapshots__/VisualList.test.tsx.snap b/src/components/VisualList/__snapshots__/VisualList.test.tsx.snap new file mode 100644 index 00000000..83da01c9 --- /dev/null +++ b/src/components/VisualList/__snapshots__/VisualList.test.tsx.snap @@ -0,0 +1,79 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`VisualList > renders a Default VisualList 1`] = ` +
    +
      +
    • + + First item +
    • +
    • + + Second item +
    • +
    • + + Third item +
    • +
    +
    +`; diff --git a/src/components/VisualList/__snapshots__/VisualListItem.test.tsx.snap b/src/components/VisualList/__snapshots__/VisualListItem.test.tsx.snap new file mode 100644 index 00000000..07031320 --- /dev/null +++ b/src/components/VisualList/__snapshots__/VisualListItem.test.tsx.snap @@ -0,0 +1,113 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`VisualListItem > renders a Default VisualListItem 1`] = ` +
    +
  • + + List item description +
  • +
    +`; + +exports[`VisualListItem > renders a Destructive VisualListItem 1`] = ` +
    +
  • + + List item description +
  • +
    +`; + +exports[`VisualListItem > renders a Multiline VisualListItem 1`] = ` +
    +
  • + + List item with a looooooooooong very looooooooooong loooooooooooooong description +
  • +
    +`; + +exports[`VisualListItem > renders a Success VisualListItem 1`] = ` +
    +
  • + + List item description +
  • +
    +`; diff --git a/src/components/VisualList/index.tsx b/src/components/VisualList/index.tsx new file mode 100644 index 00000000..1a69f4f3 --- /dev/null +++ b/src/components/VisualList/index.tsx @@ -0,0 +1,18 @@ +/* +Copyright 2024 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export { VisualList } from "./VisualList"; +export { VisualListItem } from "./VisualListItem"; diff --git a/src/index.ts b/src/index.ts index 557e658a..0b662cb0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -53,6 +53,7 @@ export { Toast } from "./components/Toast/Toast"; export { Dropdown } from "./components/Dropdown"; export { InlineSpinner } from "./components/InlineSpinner"; export { Breadcrumb } from "./components/Breadcrumb"; +export { VisualList, VisualListItem } from "./components/VisualList"; export { TextControl,