From 1197a3453d00efb5afb483f769f16973412936d5 Mon Sep 17 00:00:00 2001 From: Germain Date: Wed, 23 Aug 2023 14:44:44 +0100 Subject: [PATCH 01/47] Create tooltip component (#62) --- package.json | 2 + src/components/Tooltip/Tooltip.module.css | 28 ++++++ src/components/Tooltip/Tooltip.stories.tsx | 95 ++++++++++++++++++ src/components/Tooltip/Tooltip.test.tsx | 48 ++++++++++ src/components/Tooltip/Tooltip.tsx | 96 +++++++++++++++++++ .../__snapshots__/Tooltip.test.tsx.snap | 26 +++++ src/index.ts | 1 + vite.config.ts | 1 + yarn.lock | 33 +++++++ 9 files changed, 330 insertions(+) create mode 100644 src/components/Tooltip/Tooltip.module.css create mode 100644 src/components/Tooltip/Tooltip.stories.tsx create mode 100644 src/components/Tooltip/Tooltip.test.tsx create mode 100644 src/components/Tooltip/Tooltip.tsx create mode 100644 src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap diff --git a/package.json b/package.json index e52d045e..1b8d4bb2 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "prettier": "3.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "resize-observer-polyfill": "^1.5.1", "storybook": "^7.0.27", "stylelint": "^15.10.2", "stylelint-config-standard": "^34.0.0", @@ -96,6 +97,7 @@ }, "dependencies": { "@radix-ui/react-form": "^0.0.3", + "@radix-ui/react-tooltip": "^1.0.6", "classnames": "^2.3.2", "graphemer": "^1.4.0", "rimraf": "^3.0.1" diff --git a/src/components/Tooltip/Tooltip.module.css b/src/components/Tooltip/Tooltip.module.css new file mode 100644 index 00000000..aa4c20bf --- /dev/null +++ b/src/components/Tooltip/Tooltip.module.css @@ -0,0 +1,28 @@ +/* +Copyright 2023 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. +*/ + +.tooltip { + font: var(--cpd-font-body-xs-medium); + padding: var(--cpd-space-1-5x) var(--cpd-space-3x); + background: var(--cpd-color-alpha-gray-1400); + color: var(--cpd-color-text-on-solid-primary); + border-radius: 4px; +} + +.arrow { + /* same color as the tooltip background */ + fill: var(--cpd-color-alpha-gray-1400); +} diff --git a/src/components/Tooltip/Tooltip.stories.tsx b/src/components/Tooltip/Tooltip.stories.tsx new file mode 100644 index 00000000..43a8c9ca --- /dev/null +++ b/src/components/Tooltip/Tooltip.stories.tsx @@ -0,0 +1,95 @@ +/* +Copyright 2023 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 from "react"; +import { Meta, StoryFn } from "@storybook/react"; + +import { Tooltip as TooltipComponent } from "./Tooltip"; +import { IconButton } from "../IconButton/IconButton"; + +import UserIcon from "@vector-im/compound-design-tokens/icons/user.svg"; + +export default { + title: "Tooltip", + component: TooltipComponent, + argTypes: {}, + args: {}, +} as Meta; + +const TemplateSide: StoryFn = () => ( +
+ + + + + + + + + + + + + + + + + + + + +
+); + +export const Side = TemplateSide.bind({}); +Side.args = {}; + +const TemplateAlign: StoryFn = () => ( +
+ + + + + + + + + + + + + + + +
+); + +export const Align = TemplateAlign.bind({}); +Align.args = {}; diff --git a/src/components/Tooltip/Tooltip.test.tsx b/src/components/Tooltip/Tooltip.test.tsx new file mode 100644 index 00000000..ba7ebf9a --- /dev/null +++ b/src/components/Tooltip/Tooltip.test.tsx @@ -0,0 +1,48 @@ +/* +Copyright 2023 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 { describe, it, expect } from "vitest"; +import { render } from "@testing-library/react"; +import React from "react"; + +import { Tooltip } from "./Tooltip"; +import { IconButton } from "../IconButton/IconButton"; + +describe("Tooltip", () => { + beforeAll(() => { + global.ResizeObserver = require("resize-observer-polyfill"); + }); + it("renders open by default", () => { + const { asFragment } = render( + + + + + , + ); + expect(asFragment()).toMatchSnapshot(); + }); + it("renders", () => { + const { asFragment } = render( + + + + + , + ); + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx new file mode 100644 index 00000000..dc8b8eaa --- /dev/null +++ b/src/components/Tooltip/Tooltip.tsx @@ -0,0 +1,96 @@ +/* +Copyright 2023 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, { PropsWithChildren } from "react"; +import { + Root, + Trigger, + Portal, + Content, + Arrow, + Provider, +} from "@radix-ui/react-tooltip"; + +import styles from "./Tooltip.module.css"; + +type TooltipProps = { + /** + * The tooltip text + */ + text: string; + /** + * The side where the tooltip is rendered + * @default bottom + */ + side?: React.ComponentProps["side"]; + /** + * The preferred alignment against the trigger. + * May change when collisions occur. + * @default center + */ + align?: React.ComponentProps["align"]; + /** + * Event handler called when the escape key is down. + */ + onEscapeKeyDown?: React.ComponentProps["onEscapeKeyDown"]; + /** + * Event handler called when a pointer event occurs outside + * the bounds of the component. + */ + onPointerDownOutside?: React.ComponentProps< + typeof Content + >["onPointerDownOutside"]; + /** + * The controlled open state of the tooltip. + * You will mostly want to omit this property. Will be used the vast majority + * of the time during development. + * @default undefined + */ + open?: boolean; +}; + +/** + * A tooltip component + */ +export const Tooltip = ({ + children, + text, + side = "bottom", + align = "center", + onEscapeKeyDown, + onPointerDownOutside, + open, +}: PropsWithChildren) => { + return ( + + + {children} + + + {text} + + + + + + ); +}; diff --git a/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap b/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap new file mode 100644 index 00000000..2369ce34 --- /dev/null +++ b/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap @@ -0,0 +1,26 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Tooltip > renders 1`] = ` + + + +`; + +exports[`Tooltip > renders open by default 1`] = ` + + + +`; diff --git a/src/index.ts b/src/index.ts index f3b772f0..8254f8d3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -44,6 +44,7 @@ export { Radio } from "./components/Radio/Radio"; export { Root } from "./components/Form/Root"; export { Submit } from "./components/Form/Submit"; export { Toggle } from "./components/Toggle/Toggle"; +export { Tooltip } from "./components/Tooltip/Tooltip"; export { ValidityState } from "./components/Form/ValidityState"; /** diff --git a/vite.config.ts b/vite.config.ts index f970b8c4..41500a59 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -34,6 +34,7 @@ export default defineConfig({ "classnames", "graphemer", "@radix-ui/react-form", + "@radix-ui/react-tooltip", ], // Without this, none of the exports are preserved in the bundle diff --git a/yarn.lock b/yarn.lock index 3ea6962f..6e9eea32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2012,6 +2012,15 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-primitive" "1.0.3" +"@radix-ui/react-presence@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba" + integrity sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-primitive@1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0" @@ -2056,6 +2065,25 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-compose-refs" "1.0.1" +"@radix-ui/react-tooltip@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.0.6.tgz#87a7786cd9f2b4de957ac645afae1575339c58b0" + integrity sha512-DmNFOiwEc2UDigsYj6clJENma58OelxD24O4IODoZ+3sQc3Zb+L8w1EP+y9laTuKCLAysPw4fD6/v0j4KNV8rg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-popper" "1.1.2" + "@radix-ui/react-portal" "1.0.3" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + "@radix-ui/react-visually-hidden" "1.0.3" + "@radix-ui/react-use-callback-ref@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a" @@ -8707,6 +8735,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== +resize-observer-polyfill@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" From 6ca502e58995e5fde61807324c7c1016ac1d5f4f Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Wed, 23 Aug 2023 13:45:56 +0000 Subject: [PATCH 02/47] patch version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b8d4bb2..aaf64dde 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.2.10", + "version": "0.2.11", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From 96c8b6d7cfa241aa382a086dfc853bc75778488e Mon Sep 17 00:00:00 2001 From: Germain Date: Wed, 23 Aug 2023 14:12:19 +0100 Subject: [PATCH 03/47] Add shortcut ability for tooltips --- src/components/Tooltip/Tooltip.module.css | 9 ++++++++ src/components/Tooltip/Tooltip.stories.tsx | 24 +++++++++++++++------- src/components/Tooltip/Tooltip.test.tsx | 4 ++-- src/components/Tooltip/Tooltip.tsx | 23 +++++++++++++++++---- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/components/Tooltip/Tooltip.module.css b/src/components/Tooltip/Tooltip.module.css index aa4c20bf..99bfd53b 100644 --- a/src/components/Tooltip/Tooltip.module.css +++ b/src/components/Tooltip/Tooltip.module.css @@ -20,6 +20,15 @@ limitations under the License. background: var(--cpd-color-alpha-gray-1400); color: var(--cpd-color-text-on-solid-primary); border-radius: 4px; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} + +.shortcut { + font-weight: (--cpd-font-weight-normal); + color: var(--cpd-color-text-secondary); } .arrow { diff --git a/src/components/Tooltip/Tooltip.stories.tsx b/src/components/Tooltip/Tooltip.stories.tsx index 43a8c9ca..d4fabf43 100644 --- a/src/components/Tooltip/Tooltip.stories.tsx +++ b/src/components/Tooltip/Tooltip.stories.tsx @@ -38,22 +38,22 @@ const TemplateSide: StoryFn = () => ( alignItems: "center", }} > - + - + - + - + @@ -73,17 +73,27 @@ const TemplateAlign: StoryFn = () => ( alignItems: "center", }} > - + - + - + diff --git a/src/components/Tooltip/Tooltip.test.tsx b/src/components/Tooltip/Tooltip.test.tsx index ba7ebf9a..a541757d 100644 --- a/src/components/Tooltip/Tooltip.test.tsx +++ b/src/components/Tooltip/Tooltip.test.tsx @@ -27,7 +27,7 @@ describe("Tooltip", () => { }); it("renders open by default", () => { const { asFragment } = render( - + @@ -37,7 +37,7 @@ describe("Tooltip", () => { }); it("renders", () => { const { asFragment } = render( - + diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx index dc8b8eaa..5c88eda0 100644 --- a/src/components/Tooltip/Tooltip.tsx +++ b/src/components/Tooltip/Tooltip.tsx @@ -25,12 +25,17 @@ import { } from "@radix-ui/react-tooltip"; import styles from "./Tooltip.module.css"; +import classNames from "classnames"; type TooltipProps = { /** - * The tooltip text + * The tooltip label */ - text: string; + label: string; + /** + * The associated keyboard shortcut + */ + shortcut?: string; /** * The side where the tooltip is rendered * @default bottom @@ -67,7 +72,8 @@ type TooltipProps = { */ export const Tooltip = ({ children, - text, + label, + shortcut, side = "bottom", align = "center", onEscapeKeyDown, @@ -86,7 +92,16 @@ export const Tooltip = ({ onPointerDownOutside={onPointerDownOutside} className={styles.tooltip} > - {text} + {label} + {/* Forcing dark theme, so that we have the correct contrast when + using the text color secondary on a solid dark background. + This is temporary and should only remain until we figure out + the approach to on-solid tokens */} + {shortcut && ( + + {shortcut} + + )} From b6004b0335e0de254e6129b76feb4cf4a6998f9b Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Wed, 23 Aug 2023 14:00:50 +0000 Subject: [PATCH 04/47] patch version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aaf64dde..7a4e1ce2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.2.11", + "version": "0.2.12", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From 1361a4a114b1d1d78096b6abe0f653e7673da340 Mon Sep 17 00:00:00 2001 From: Germain Date: Thu, 24 Aug 2023 14:55:03 +0100 Subject: [PATCH 05/47] Use CSS class over :has() for Firefox compatibility (#64) --- src/components/Avatar/Avatar.module.css | 2 +- src/components/Avatar/Avatar.tsx | 4 +++- src/components/Avatar/__snapshots__/Avatar.test.tsx.snap | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Avatar/Avatar.module.css b/src/components/Avatar/Avatar.module.css index 11a41880..0c09f097 100644 --- a/src/components/Avatar/Avatar.module.css +++ b/src/components/Avatar/Avatar.module.css @@ -53,7 +53,7 @@ button.avatar:disabled { overflow: hidden; } -.avatar:not(:has(.image)) { +.avatar-imageless { /* In the future we'd prefer to pass the HEX code as the data attr and use `attr(data-color)` to avoid the style declaration from below but this is currently not supported in all browsers */ diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index dc8f2fad..a8668269 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -105,7 +105,9 @@ export const Avatar = forwardRef< ...props, "data-type": type, "data-color": useIdColorHash(id), - className: classnames(styles.avatar, className), + className: classnames(styles.avatar, className, { + [styles["avatar-imageless"]]: !src, + }), style: { ...style, "--cpd-avatar-size": size, diff --git a/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap b/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap index b2c0a6b5..b5c4d3e9 100644 --- a/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap +++ b/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap @@ -4,7 +4,7 @@ exports[`Avatar > renders the image-less avatar 1`] = ` Date: Thu, 24 Aug 2023 14:07:20 +0000 Subject: [PATCH 06/47] patch version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7a4e1ce2..b04cdbdd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.2.12", + "version": "0.2.13", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From e28b6ab73565bdf5fe7bfd68be407d006c029a3c Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Thu, 24 Aug 2023 15:41:46 +0000 Subject: [PATCH 07/47] patch version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b04cdbdd..9a1db5a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.2.13", + "version": "0.2.14", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From 9adc23b806f0bcd2e9467fa20808b46b8cc792e0 Mon Sep 17 00:00:00 2001 From: Germain Date: Thu, 24 Aug 2023 16:47:15 +0100 Subject: [PATCH 08/47] Update Tooltip return type for compat with @types/react@^17 --- src/components/Tooltip/Tooltip.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx index 5c88eda0..db24f041 100644 --- a/src/components/Tooltip/Tooltip.tsx +++ b/src/components/Tooltip/Tooltip.tsx @@ -79,7 +79,7 @@ export const Tooltip = ({ onEscapeKeyDown, onPointerDownOutside, open, -}: PropsWithChildren) => { +}: PropsWithChildren): JSX.Element => { return ( From 5dda11aa9733462fb8422968181275bc3e9b35e3 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Thu, 24 Aug 2023 15:48:21 +0000 Subject: [PATCH 09/47] patch version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9a1db5a4..c1de8657 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.2.14", + "version": "0.2.15", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From 0682d6afd9a9d5e1855a96807fcda5b0a15befa8 Mon Sep 17 00:00:00 2001 From: Germain Date: Fri, 1 Sep 2023 07:19:31 +0100 Subject: [PATCH 10/47] Bugfixes for Avatar and IconButton components (#66) --- src/components/Avatar/Avatar.tsx | 3 ++- src/components/IconButton/IconButton.module.css | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index a8668269..f67155af 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -91,6 +91,7 @@ export const Avatar = forwardRef< size, style = {}, onError, + title, ...props }, ref, @@ -128,7 +129,7 @@ export const Avatar = forwardRef< style={style} width={size} height={size} - title={id} + title={title} onError={onError} /> )} diff --git a/src/components/IconButton/IconButton.module.css b/src/components/IconButton/IconButton.module.css index 1c6c0eec..296f6a90 100644 --- a/src/components/IconButton/IconButton.module.css +++ b/src/components/IconButton/IconButton.module.css @@ -57,7 +57,7 @@ limitations under the License. width: calc(var(--cpd-icon-button-size) * 0.25); height: calc(var(--cpd-icon-button-size) * 0.25); border-radius: 50%; - background: currentColor; + background: currentcolor; } .icon-button[data-indicator="highlight"]::before { @@ -68,7 +68,7 @@ limitations under the License. * Hover state */ -.icon-button:hover { +.icon-button:not(:disabled):hover { color: var(--cpd-color-icon-primary); background: var(--cpd-color-bg-subtle-primary); } From bc9270b12e2641823fa48295f2d480617399edf3 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Fri, 1 Sep 2023 06:20:32 +0000 Subject: [PATCH 11/47] patch version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c1de8657..6e50387d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.2.15", + "version": "0.2.16", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From bf6d5d6c779e22ad0d9e99d4c9de5df5fbc5668a Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 1 Sep 2023 15:16:21 +0200 Subject: [PATCH 12/47] Button: use semantic tokens (#67) --- src/components/Button/Button.module.css | 74 ++++++++++--------------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/src/components/Button/Button.module.css b/src/components/Button/Button.module.css index 5705b0df..0c733983 100644 --- a/src/components/Button/Button.module.css +++ b/src/components/Button/Button.module.css @@ -15,9 +15,7 @@ limitations under the License. */ .button { - /* use a very large value to ensure the pill happens if the content - go over multiple line */ - border-radius: 666em; + border-radius: var(--cpd-radius-pill-effect); cursor: pointer; -webkit-appeareance: none; } @@ -46,71 +44,59 @@ limitations under the License. */ .button[data-kind="primary"] { - color: #fff; /* TODO: Replace with a token */ - - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-gray-1400); + color: var(--cpd-color-text-on-solid-primary); + background: var(--cpd-color-bg-action-primary-rest); border-width: 0; } .button[data-kind="primary"]:hover { - color: #fff; /* TODO: Replace with a token */ - - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-gray-1300); + background: var(--cpd-color-bg-action-primary-hovered); } .button[data-kind="primary"]:active { - color: #fff; /* TODO: Replace with a token */ - - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-gray-1200); + background: var(--cpd-color-bg-action-primary-pressed); } .button[data-kind="primary"][disabled] { - background: var(--cpd-color-gray-800); + color: var(--cpd-color-text-disabled); + background: var(--cpd-color-bg-subtle-primary); } .button[data-kind="secondary"] { - border: 1px solid var(--cpd-color-gray-1400); /* TODO: Replace with a token */ + border: 1px solid var(--cpd-color-border-interactive-primary); color: var(--cpd-color-text-primary); - - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-theme-bg); + background: var(--cpd-color-bg-canvas-default); } .button[data-kind="secondary"]:hover { - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-gray-300); - border-color: var(--cpd-color-gray-1300); + border-color: var(--cpd-color-border-interactive-hovered); + background: var(--cpd-color-bg-subtle-secondary); } .button[data-kind="secondary"]:active { - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-gray-100); + border-color: var(--cpd-color-border-interactive-hovered); + background: var(--cpd-color-bg-subtle-primary); } .button[data-kind="secondary"][disabled] { - color: var(--cpd-color-gray-800); - border-color: var(--cpd-color-gray-800); - background: var(--cpd-color-theme-bg); + border-color: var(--cpd-color-border-interactive-secondary); + color: var(--cpd-color-text-disabled); + background: var(--cpd-color-bg-subtle-secondary); } .button[data-kind="tertiary"] { - border: none; /* TODO: Replace with a token */ + border: none; color: var(--cpd-color-text-primary); text-decoration: underline; background: transparent; } .button[data-kind="tertiary"]:hover { - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-gray-200); + background: var(--cpd-color-bg-subtle-secondary); } .button[data-kind="tertiary"]:active { - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-gray-300); + background: var(--cpd-color-bg-subtle-primary); } .button[data-kind="tertiary"][disabled] { @@ -118,25 +104,23 @@ limitations under the License. } .button[data-kind="destructive"] { - border: 1px solid var(--cpd-color-text-action-critical); - color: var(--cpd-color-text-action-critical); - - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-theme-bg); + border: 1px solid var(--cpd-color-border-critical-primary); + color: var(--cpd-color-text-critical-primary); + background: var(--cpd-color-bg-canvas-default); } .button[data-kind="destructive"]:hover { - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-red-300); + border-color: var(--cpd-color-border-critical-hovered); + background: var(--cpd-color-bg-critical-subtle); } .button[data-kind="destructive"]:active { - /* TODO: Replace with a semantic token */ - background: var(--cpd-color-red-200); + border-color: var(--cpd-color-border-critical-hovered); + background: var(--cpd-color-bg-critical-subtle-hovered); } .button[data-kind="destructive"][disabled] { - color: var(--cpd-color-gray-800); - border-color: var(--cpd-color-gray-800); - background: var(--cpd-color-theme-bg); + border-color: var(--cpd-color-border-interactive-secondary); + color: var(--cpd-color-text-disabled); + background: var(--cpd-color-bg-subtle-secondary); } From 72c06205b3a6acaeb2b0bb1fe0aa50682a7cae28 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Fri, 1 Sep 2023 13:18:04 +0000 Subject: [PATCH 13/47] patch version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6e50387d..1a270a9b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.2.16", + "version": "0.2.17", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From 13c4f1f3cc46d3288f5d252b82e40bf79b04ca46 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 4 Sep 2023 18:53:25 +0100 Subject: [PATCH 14/47] Update Avatar.tsx --- src/components/Avatar/Avatar.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/Avatar/Avatar.tsx b/src/components/Avatar/Avatar.tsx index f67155af..4db51ecd 100644 --- a/src/components/Avatar/Avatar.tsx +++ b/src/components/Avatar/Avatar.tsx @@ -91,7 +91,6 @@ export const Avatar = forwardRef< size, style = {}, onError, - title, ...props }, ref, @@ -101,8 +100,8 @@ export const Avatar = forwardRef< { ref, role: "img", - title: id, - "aria-label": "", + // Default the aria-label to id + "aria-label": id, ...props, "data-type": type, "data-color": useIdColorHash(id), @@ -129,7 +128,6 @@ export const Avatar = forwardRef< style={style} width={size} height={size} - title={title} onError={onError} /> )} From 9bfaf79434735689857c0d7ed001389124b675a0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 4 Sep 2023 18:57:49 +0100 Subject: [PATCH 15/47] Update Avatar.test.tsx.snap --- src/components/Avatar/__snapshots__/Avatar.test.tsx.snap | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap b/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap index b5c4d3e9..83f5bdc8 100644 --- a/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap +++ b/src/components/Avatar/__snapshots__/Avatar.test.tsx.snap @@ -3,12 +3,11 @@ exports[`Avatar > renders the image-less avatar 1`] = ` B From 5a7ffd731f590bf144b1704af664f88c4b022009 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Mon, 4 Sep 2023 18:35:10 +0000 Subject: [PATCH 16/47] patch version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a270a9b..0a88ba36 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.2.17", + "version": "0.2.18", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From 3311b5444efe45a8d2d578c8256a91b5d39a97aa Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 6 Sep 2023 20:43:32 -0400 Subject: [PATCH 17/47] Document a gotcha where linking this package leads to conflicting @types/react copies I spent a good couple hours today struggling to yarn link this package in a way that wouldn't create type errors in my Element Call checkout, and feel compelled to write down my workaround somewhere that others can find it. --- .storybook/main.ts | 2 +- README.md | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.storybook/main.ts b/.storybook/main.ts index c6b13622..c5cc3451 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -29,7 +29,7 @@ const config: StorybookConfig = { publicDir: "res", }; - } + }, }; export default config; diff --git a/README.md b/README.md index e7fd11c8..9081c656 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,20 @@ React implementation of Compound – Element's design system – See full docume ## Commands -| Command | Runs | -| ------- | ---- | -| `yarn dev` | Runs a local development environment | -| `yarn test` | Tests all components | -| `yarn lint` | Lints all components | -| `yarn gen:component $name` | Bootstraps a new component | +| Command | Runs | +| -------------------------- | ------------------------------------ | +| `yarn dev` | Runs a local development environment | +| `yarn test` | Tests all components | +| `yarn lint` | Lints all components | +| `yarn gen:component $name` | Bootstraps a new component | +## Development + +If you want to work on Compound Web as a linked package within a larger React application, TypeScript might complain about there being multiple copies of @types/react in the tree. You can work around this by linking Compound Web's copy of @types/react to your application's copy: + +```bash +$ cd my-application/node_modules/@types/react +$ yarn link +$ cd ../../../../compound-web +$ yarn link @types/react +``` From af4c5041f7a82f0059e5b412fae4679f78522a95 Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 7 Sep 2023 00:32:07 -0400 Subject: [PATCH 18/47] Include global.css in the build output Surely you shouldn't have to manually import it from src/ in downstream projects? --- src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.ts b/src/index.ts index 8254f8d3..5f07d673 100644 --- a/src/index.ts +++ b/src/index.ts @@ -53,3 +53,5 @@ export { ValidityState } from "./components/Form/ValidityState"; export { useIdColorHash } from "./components/Avatar/useIdColorHash"; export { getInitialLetter } from "./utils/string"; + +import "./styles/global.css"; From a3ede84fecde1633412821c23fcb5ca1e6cc68b9 Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 7 Sep 2023 00:35:02 -0400 Subject: [PATCH 19/47] Support icons on buttons Buttons in Compound have an optional slot for an icon to go in - this adds that capability to the Button component. --- src/components/Button/Button.module.css | 15 +++++++++- src/components/Button/Button.stories.tsx | 8 +++++- src/components/Button/Button.test.tsx | 10 +++++++ src/components/Button/Button.tsx | 22 +++++++++++++-- .../Button/__snapshots__/Button.test.tsx.snap | 28 +++++++++++++++++++ 5 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/components/Button/Button.module.css b/src/components/Button/Button.module.css index 0c733983..e535fdd3 100644 --- a/src/components/Button/Button.module.css +++ b/src/components/Button/Button.module.css @@ -18,6 +18,9 @@ limitations under the License. border-radius: var(--cpd-radius-pill-effect); cursor: pointer; -webkit-appeareance: none; + display: flex; + align-items: center; + gap: var(--cpd-space-2x); } .button[disabled] { @@ -31,12 +34,22 @@ limitations under the License. .button[data-size="lg"] { font: var(--cpd-font-body-lg-semibold); - padding: var(--cpd-space-3x) var(--cpd-space-10x); + padding: var(--cpd-space-2x) var(--cpd-space-10x); + min-height: var(--cpd-space-12x); +} + +.button[data-size="lg"].hasIcon { + padding-inline-start: var(--cpd-space-9x); } .button[data-size="sm"] { font: var(--cpd-font-body-md-semibold); padding: var(--cpd-space-1x) var(--cpd-space-6x); + min-height: var(--cpd-space-9x); +} + +.button[data-size="sm"].hasIcon { + padding-inline-start: var(--cpd-space-5x); } /** diff --git a/src/components/Button/Button.stories.tsx b/src/components/Button/Button.stories.tsx index 1746f8bd..f59e9a99 100644 --- a/src/components/Button/Button.stories.tsx +++ b/src/components/Button/Button.stories.tsx @@ -18,6 +18,7 @@ import React from "react"; import { Meta, StoryFn } from "@storybook/react"; import { Button as ButtonComponent } from "./Button"; +import VisibilityVisibleIcon from "@vector-im/compound-design-tokens/icons/visibility-visible.svg"; export default { title: "Button", @@ -32,7 +33,12 @@ export default { } as Meta; const Template: StoryFn = (args) => ( - Click me! +
+ Click me! + + Click me! + +
); export const Primary = Template.bind({}); diff --git a/src/components/Button/Button.test.tsx b/src/components/Button/Button.test.tsx index 9841ed42..57237acd 100644 --- a/src/components/Button/Button.test.tsx +++ b/src/components/Button/Button.test.tsx @@ -18,6 +18,7 @@ import { vi, describe, it } from "vitest"; import React from "react"; import { getByRole, render } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; +import ChatIcon from "@vector-im/compound-design-tokens/icons/chat.svg"; import { Button } from "./Button"; @@ -27,6 +28,15 @@ describe("Button", () => { expect(asFragment()).toMatchSnapshot(); }); + it("accepts an icon", () => { + const { asFragment } = render( + , + ); + expect(asFragment()).toMatchSnapshot(); + }); + it("can be clicked", async () => { const spy = vi.fn(); const { container } = render(); diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index 4be25552..a268aa22 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import classNames from "classnames"; -import React, { PropsWithChildren } from "react"; +import React, { ComponentType, PropsWithChildren } from "react"; import styles from "./Button.module.css"; type ButtonProps = { @@ -29,13 +29,17 @@ type ButtonProps = { */ kind?: "primary" | "secondary" | "tertiary" | "destructive"; // TODO: Refine the naming /** - * The t-shirt size of the button + * The t-shirt size of the button. */ size?: "sm" | "lg"; /** * The CSS class name. */ className?: string; + /** + * An icon to display within the button. + */ + Icon?: ComponentType>; } & React.ComponentPropsWithoutRef; /** @@ -48,10 +52,14 @@ export const Button = ({ size = "lg", children, className, + Icon, ...props }: PropsWithChildren>): React.ReactElement => { const Component = as || "button"; - const classes = classNames(styles.button, className); + const classes = classNames(styles.button, className, { + [styles.hasIcon]: Icon, + }); + const iconSize = size === "lg" ? 24 : 20; return ( ({ role={as === "a" ? "link" : "button"} tabIndex={0} > + {Icon && ( + + )} {children} ); diff --git a/src/components/Button/__snapshots__/Button.test.tsx.snap b/src/components/Button/__snapshots__/Button.test.tsx.snap index 16515c36..2a35d142 100644 --- a/src/components/Button/__snapshots__/Button.test.tsx.snap +++ b/src/components/Button/__snapshots__/Button.test.tsx.snap @@ -1,5 +1,33 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`Button > accepts an icon 1`] = ` + + + +`; + exports[`Button > renders 1`] = ` diff --git a/src/components/Radio/Radio.module.css b/src/components/Radio/Radio.module.css index 1b5d3c6d..8fc5a66c 100644 --- a/src/components/Radio/Radio.module.css +++ b/src/components/Radio/Radio.module.css @@ -102,8 +102,8 @@ limitations under the License. .radio[data-kind] [type="radio"][disabled] + .radio-ui { border-color: var(--cpd-color-border-disabled); - background: var(--cpd-border-disabled); - color: var(--color-text-disabled); + background: var(--cpd-color-bg-canvas-disabled); + color: var(--cpd-color-text-disabled); } .radio[data-kind] [type="radio"][disabled]:checked + .radio-ui { diff --git a/src/components/Tooltip/Tooltip.module.css b/src/components/Tooltip/Tooltip.module.css index 99bfd53b..68a25454 100644 --- a/src/components/Tooltip/Tooltip.module.css +++ b/src/components/Tooltip/Tooltip.module.css @@ -27,7 +27,7 @@ limitations under the License. } .shortcut { - font-weight: (--cpd-font-weight-normal); + font-weight: var(--cpd-font-weight-regular); color: var(--cpd-color-text-secondary); } diff --git a/src/components/Tooltip/Tooltip.stories.tsx b/src/components/Tooltip/Tooltip.stories.tsx index d4fabf43..82300e52 100644 --- a/src/components/Tooltip/Tooltip.stories.tsx +++ b/src/components/Tooltip/Tooltip.stories.tsx @@ -20,7 +20,7 @@ import { Meta, StoryFn } from "@storybook/react"; import { Tooltip as TooltipComponent } from "./Tooltip"; import { IconButton } from "../IconButton/IconButton"; -import UserIcon from "@vector-im/compound-design-tokens/icons/user.svg"; +import UserIcon from "@vector-im/compound-design-tokens/icons/user-profile.svg"; export default { title: "Tooltip", diff --git a/src/components/Typography/Typography.module.css b/src/components/Typography/Typography.module.css index 46609f1d..25422529 100644 --- a/src/components/Typography/Typography.module.css +++ b/src/components/Typography/Typography.module.css @@ -18,19 +18,18 @@ limitations under the License. * Font – Body – Extra Small */ -[class^="font-body-xs"] { - letter-spacing: var(--cpd-font-letter-spacing-body-xs); -} - .font-body-xs-regular { + letter-spacing: var(--cpd-font-letter-spacing-body-xs); font: var(--cpd-font-body-xs-regular); } .font-body-xs-semibold { + letter-spacing: var(--cpd-font-letter-spacing-body-xs); font: var(--cpd-font-body-xs-semibold); } .font-body-xs-medium { + letter-spacing: var(--cpd-font-letter-spacing-body-xs); font: var(--cpd-font-body-xs-medium); } @@ -38,19 +37,18 @@ limitations under the License. * Font – Body – Small */ -[class^="font-body-sm"] { - letter-spacing: var(--cpd-font-letter-spacing-body-sm); -} - .font-body-sm-regular { + letter-spacing: var(--cpd-font-letter-spacing-body-sm); font: var(--cpd-font-body-sm-regular); } .font-body-sm-semibold { + letter-spacing: var(--cpd-font-letter-spacing-body-sm); font: var(--cpd-font-body-sm-semibold); } .font-body-sm-medium { + letter-spacing: var(--cpd-font-letter-spacing-body-sm); font: var(--cpd-font-body-sm-medium); } @@ -58,19 +56,18 @@ limitations under the License. * Font – Body – Medium */ -[class^="font-body-md"] { - letter-spacing: var(--cpd-font-letter-spacing-body-md); -} - .font-body-md-regular { + letter-spacing: var(--cpd-font-letter-spacing-body-md); font: var(--cpd-font-body-md-regular); } .font-body-md-semibold { + letter-spacing: var(--cpd-font-letter-spacing-body-md); font: var(--cpd-font-body-md-semibold); } .font-body-md-medium { + letter-spacing: var(--cpd-font-letter-spacing-body-md); font: var(--cpd-font-body-md-medium); } @@ -78,19 +75,18 @@ limitations under the License. * Font – Body – Large */ -[class^="font-body-lg"] { - letter-spacing: var(--cpd-font-letter-spacing-body-lg); -} - .font-body-lg-regular { + letter-spacing: var(--cpd-font-letter-spacing-body-lg); font: var(--cpd-font-body-lg-regular); } .font-body-lg-semibold { + letter-spacing: var(--cpd-font-letter-spacing-body-lg); font: var(--cpd-font-body-lg-semibold); } .font-body-lg-medium { + letter-spacing: var(--cpd-font-letter-spacing-body-lg); font: var(--cpd-font-body-lg-medium); } @@ -98,19 +94,18 @@ limitations under the License. * Font – Heading – Small */ -[class^="font-heading-sm"] { - letter-spacing: var(--cpd-font-letter-spacing-heading-sm); -} - .font-heading-sm-regular { + letter-spacing: var(--cpd-font-letter-spacing-heading-sm); font: var(--cpd-font-heading-sm-regular); } .font-heading-sm-semibold { + letter-spacing: var(--cpd-font-letter-spacing-heading-sm); font: var(--cpd-font-heading-sm-semibold); } .font-heading-sm-medium { + letter-spacing: var(--cpd-font-letter-spacing-heading-sm); font: var(--cpd-font-heading-sm-medium); } @@ -118,58 +113,40 @@ limitations under the License. * Font – Heading – Medium */ -[class^="font-heading-md"] { - letter-spacing: var(--cpd-font-letter-spacing-heading-md); -} - .font-heading-md-regular { + letter-spacing: var(--cpd-font-letter-spacing-heading-md); font: var(--cpd-font-heading-md-regular); } .font-heading-md-semibold { + letter-spacing: var(--cpd-font-letter-spacing-heading-md); font: var(--cpd-font-heading-md-semibold); } -.font-heading-md-medium { - font: var(--cpd-font-heading-md-medium); -} - /** * Font – Heading – Large */ -[class^="font-heading-lg"] { - letter-spacing: var(--cpd-font-letter-spacing-heading-lg); -} - .font-heading-lg-regular { + letter-spacing: var(--cpd-font-letter-spacing-heading-lg); font: var(--cpd-font-heading-lg-regular); } .font-heading-lg-semibold { + letter-spacing: var(--cpd-font-letter-spacing-heading-lg); font: var(--cpd-font-heading-lg-semibold); } -.font-heading-lg-medium { - font: var(--cpd-font-heading-lg-medium); -} - /** * Font – Heading – Extra Large */ -[class^="font-heading-xl"] { - letter-spacing: var(--cpd-font-letter-spacing-heading-xl); -} - .font-heading-xl-regular { + letter-spacing: var(--cpd-font-letter-spacing-heading-xl); font: var(--cpd-font-heading-xl-regular); } .font-heading-xl-semibold { + letter-spacing: var(--cpd-font-letter-spacing-heading-xl); font: var(--cpd-font-heading-xl-semibold); } - -.font-heading-xl-medium { - font: var(--cpd-font-heading-xl-medium); -} diff --git a/src/styles/global.css b/src/styles/global.css index 91f1b199..dc84e8b9 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -17,6 +17,10 @@ limitations under the License. :root { --cpd-radius-pill-effect: 9999px; + + /* Default icon and avatar size */ + --cpd-icon-button-size: var(--cpd-space-8x); + --cpd-avatar-size: var(--cpd-space-16x); } html, @@ -29,10 +33,7 @@ input { html, body { height: 100%; - - /* TODO: This should be a token defining the based font size for `rem` usage - * This is already set on Tokens Studio side, but not exposed in the tokens */ - font-size: 16px; + font-size: var(--cpd-font-size-root); } body { diff --git a/yarn.lock b/yarn.lock index 6e9eea32..02775436 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3775,10 +3775,10 @@ "@typescript-eslint/types" "6.2.1" eslint-visitor-keys "^3.4.1" -"@vector-im/compound-design-tokens@0.0.3": - version "0.0.3" - resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-0.0.3.tgz#89214c69108a14f5d3e4a73ddc44852862531f2b" - integrity sha512-XxmySUvfjD6EuAM7f6lsGIhuv94TFfoEpKxYh+HKn1hPBFcMEKKImu/jK5tnpOv2xuZOSrK0Pm6qMLnxLwOXOw== +"@vector-im/compound-design-tokens@0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-0.0.5.tgz#33ef2c9dae9c52bbf2a6a62ddc143dbb4efa1a00" + integrity sha512-JSe2IXe374jVk7It6HnSGnri1+g47sTv/aP+hsxtex85OpK84Gd/WxBViNQHGBCT3dhPYKjIwodyB52EsXDWZQ== dependencies: svg2vectordrawable "^2.9.1" @@ -6630,6 +6630,13 @@ is-core-module@^2.1.0, is-core-module@^2.11.0, is-core-module@^2.5.0, is-core-mo dependencies: has "^1.0.3" +is-core-module@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== + dependencies: + has "^1.0.3" + is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -8770,6 +8777,15 @@ resolve@^1.10.0, resolve@^1.14.2, resolve@^1.17.0, resolve@~1.22.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.0: + version "1.22.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" + integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^2.0.0-next.4: version "2.0.0-next.4" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" @@ -9298,6 +9314,14 @@ stylelint-config-standard@^34.0.0: dependencies: stylelint-config-recommended "^13.0.0" +stylelint-value-no-unknown-custom-properties@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/stylelint-value-no-unknown-custom-properties/-/stylelint-value-no-unknown-custom-properties-4.0.0.tgz#9255e3b09e4da3d88244d4cf03042feb5bb1f4a3" + integrity sha512-FTi/EHipLplFl9O2zNCH5PMerBxxuPPYFHiVRX8wcMg+Y/hebsGa/hzjMN6Xq7MsvtFl7RoiQV+kykC5ous5Rg== + dependencies: + postcss-value-parser "^4.2.0" + resolve "^1.22.0" + stylelint@^15.10.2: version "15.10.2" resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-15.10.2.tgz#0ee5a8371d3a2e1ff27fefd48309d3ddef7c3405" From 0b30007bccf3f641cbdeb3546d081b3d57824f15 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Fri, 8 Sep 2023 07:30:39 +0000 Subject: [PATCH 22/47] minor version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 488d4144..95503e64 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.2.18", + "version": "0.3.0", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From 50c65d8baeb5351fb9476c12f9110b95ddc5d084 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 8 Sep 2023 10:02:03 +0200 Subject: [PATCH 23/47] Fix a regression in the button alignment --- src/components/Button/Button.module.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Button/Button.module.css b/src/components/Button/Button.module.css index 1097c35e..18f74761 100644 --- a/src/components/Button/Button.module.css +++ b/src/components/Button/Button.module.css @@ -20,6 +20,7 @@ limitations under the License. appearance: none; display: flex; align-items: center; + justify-content: center; gap: var(--cpd-space-2x); } From be7d172e69cbafebdcc4ebd83cb84c6eaec520f8 Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Fri, 8 Sep 2023 08:16:09 +0000 Subject: [PATCH 24/47] patch version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 95503e64..985ec08d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.3.0", + "version": "0.3.1", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From db5a50cf0ee2e3d461b1a103bd5ca356a68159e8 Mon Sep 17 00:00:00 2001 From: Robin Date: Fri, 8 Sep 2023 20:18:58 -0400 Subject: [PATCH 25/47] Export the Text component This appears to have been forgotten. --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index 30b621ae..16637933 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,6 +25,7 @@ export { AvatarStack } from "./components/Avatar/AvatarStack"; export { Badge } from "./components/Badge/Badge"; export { Button } from "./components/Button/Button"; export { Body } from "./components/Typography/Body"; +export { Text } from "./components/Typography/Text"; export { Checkbox } from "./components/Checkbox/Checkbox"; export { Control } from "./components/Form/Control"; export { Field } from "./components/Form/Field"; From 1b0bf41cf7782db098eb67b9e4de683a2fb32eac Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Mon, 11 Sep 2023 14:49:17 +0000 Subject: [PATCH 26/47] minor version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 985ec08d..be92d3cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vector-im/compound-web", - "version": "0.3.1", + "version": "0.4.0", "description": "Compound components for the Web", "type": "module", "main": "./dist/compound-web.js", From 4fbb7f5d48fa9f1f73dde42f034ef1c6572abeb2 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 18 Sep 2023 08:21:12 +0200 Subject: [PATCH 27/47] Fix the AvatarStack component tests (#77) --- src/components/Avatar/Avatar.stories.tsx | 1 - src/components/Avatar/AvatarStack.test.tsx | 38 +++++++++++++++++-- .../__snapshots__/AvatarStack.test.tsx.snap | 23 ++++++++++- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/components/Avatar/Avatar.stories.tsx b/src/components/Avatar/Avatar.stories.tsx index ea28832e..a8a8e34d 100644 --- a/src/components/Avatar/Avatar.stories.tsx +++ b/src/components/Avatar/Avatar.stories.tsx @@ -49,7 +49,6 @@ Square.args = { export const Button = Template.bind({}); Button.args = { type: "round", - as: "button", onClick: () => console.log("clicked!"), }; diff --git a/src/components/Avatar/AvatarStack.test.tsx b/src/components/Avatar/AvatarStack.test.tsx index 1432f7f1..5e9bbc40 100644 --- a/src/components/Avatar/AvatarStack.test.tsx +++ b/src/components/Avatar/AvatarStack.test.tsx @@ -19,6 +19,7 @@ import { render } from "@testing-library/react"; import React from "react"; import { AvatarStack } from "./AvatarStack"; +import { Avatar } from "./Avatar"; const originalImage = global.Image; @@ -45,18 +46,49 @@ describe("AvatarStack", () => { it("renders", () => { const { asFragment } = render( - , + + {avatars.map((avatar) => ( + + ))} + , ); expect(asFragment()).toMatchSnapshot(); }); it("adds the mask to the body", () => { - render(); + render( + + {avatars.map((avatar) => ( + + ))} + , + ); // We can't run better assertions as `SVG` loading is mocked out in jest expect(document.querySelectorAll("svg")).toHaveLength(1); - render(); + render( + + {avatars.map((avatar) => ( + + ))} + , + ); // We only one instance of the mask, ever! expect(document.querySelectorAll("svg")).toHaveLength(1); diff --git a/src/components/Avatar/__snapshots__/AvatarStack.test.tsx.snap b/src/components/Avatar/__snapshots__/AvatarStack.test.tsx.snap index f670c889..5c98ec08 100644 --- a/src/components/Avatar/__snapshots__/AvatarStack.test.tsx.snap +++ b/src/components/Avatar/__snapshots__/AvatarStack.test.tsx.snap @@ -4,6 +4,27 @@ exports[`AvatarStack > renders 1`] = `
+ > + + A + + + B + +
`; From e7f673d885282555e47380943f7162746058dc07 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 18 Sep 2023 08:31:36 +0200 Subject: [PATCH 28/47] Forward the ref in the Button component (#76) --- src/components/Button/Button.stories.tsx | 20 ++++++-- src/components/Button/Button.tsx | 63 +++++++++++++++--------- 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/components/Button/Button.stories.tsx b/src/components/Button/Button.stories.tsx index 641f408c..848e825d 100644 --- a/src/components/Button/Button.stories.tsx +++ b/src/components/Button/Button.stories.tsx @@ -20,6 +20,11 @@ import { Meta, StoryFn } from "@storybook/react"; import { Button as ButtonComponent } from "./Button"; import VisibilityOnIcon from "@vector-im/compound-design-tokens/icons/visibility-on.svg"; +type Props = { + kind?: "primary" | "secondary" | "tertiary" | "destructive"; + size?: "sm" | "lg"; +}; + export default { title: "Button", component: ButtonComponent, @@ -29,13 +34,20 @@ export default { control: { type: "inline-radio" }, }, }, - args: {}, + args: { + size: "sm", + }, } as Meta; -const Template: StoryFn = (args) => ( +const Template: StoryFn = ({ kind, size }: Props) => (
- Click me! - + + Click me! + + + Click me! + + Click me!
diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index 0cf84cd4..06359673 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -15,15 +15,25 @@ limitations under the License. */ import classNames from "classnames"; -import React, { ComponentType, PropsWithChildren } from "react"; +import React, { + ComponentType, + PropsWithChildren, + forwardRef, + ForwardedRef, + Ref, +} from "react"; import styles from "./Button.module.css"; -type ButtonProps = { - /** - * The underlying HTML element to use. Can be a button or a link. - * @default "button" - */ - as?: C; +interface ButtonComponent { + // With the explicit `as` prop + ( + props: { as: C } & ButtonPropsFor, + ): React.ReactElement; + // Without the explicit `as` prop, defaulting to a