From 91b373cf0951b503eba38e8a1bd9c12b25f50135 Mon Sep 17 00:00:00 2001 From: Germain Date: Wed, 23 Aug 2023 13:51:27 +0100 Subject: [PATCH 1/7] Upgrade compound design tokens --- package.json | 2 +- .../Alert/__snapshots__/Alert.test.tsx.snap | 4 ++-- .../Checkbox/__snapshots__/Checkbox.test.tsx.snap | 4 ++-- src/components/Form/Controls/Password/Password.tsx | 8 ++++---- src/components/IconButton/IconButton.stories.tsx | 2 +- src/components/IconButton/IconButton.test.tsx | 2 +- .../__snapshots__/IconButton.test.tsx.snap | 14 ++++++++++---- yarn.lock | 8 ++++---- 8 files changed, 25 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index e52d045e..d014ab60 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@types/testing-library__jest-dom": "^5.14.9", "@typescript-eslint/eslint-plugin": "^6.2.1", "@typescript-eslint/parser": "^6.2.1", - "@vector-im/compound-design-tokens": "0.0.3", + "@vector-im/compound-design-tokens": "^0.0.4", "@vitejs/plugin-react": "^4.0.4", "@vitest/coverage-v8": "^0.33.0", "browserslist-to-esbuild": "^1.2.0", diff --git a/src/components/Alert/__snapshots__/Alert.test.tsx.snap b/src/components/Alert/__snapshots__/Alert.test.tsx.snap index 5db022b1..62968157 100644 --- a/src/components/Alert/__snapshots__/Alert.test.tsx.snap +++ b/src/components/Alert/__snapshots__/Alert.test.tsx.snap @@ -9,14 +9,14 @@ exports[`Alert > renders 1`] = ` diff --git a/src/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap b/src/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap index 83b1cc5c..9124eb1f 100644 --- a/src/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap +++ b/src/components/Checkbox/__snapshots__/Checkbox.test.tsx.snap @@ -15,14 +15,14 @@ exports[`Checkbox > renders 1`] = ` diff --git a/src/components/Form/Controls/Password/Password.tsx b/src/components/Form/Controls/Password/Password.tsx index b16361de..db9878d4 100644 --- a/src/components/Form/Controls/Password/Password.tsx +++ b/src/components/Form/Controls/Password/Password.tsx @@ -18,19 +18,19 @@ import React, { forwardRef, PropsWithChildren, useReducer } from "react"; import { ActionControl } from "../../../ActionControl/ActionControl"; import { Control } from "../../Control"; -import VisibilityVisible from "@vector-im/compound-design-tokens/icons/visibility-visible.svg"; -import VisibilityInvisible from "@vector-im/compound-design-tokens/icons/visibility-invisible.svg"; +import VisibilityOn from "@vector-im/compound-design-tokens/icons/visibility-on.svg"; +import VisibilityOff from "@vector-im/compound-design-tokens/icons/visibility-off.svg"; const showState = { isHidden: true, - icon: VisibilityVisible, + icon: VisibilityOn, label: "Show", type: "password", }; const hideState = { isHidden: false, - icon: VisibilityInvisible, + icon: VisibilityOff, label: "Hide", type: "text", }; diff --git a/src/components/IconButton/IconButton.stories.tsx b/src/components/IconButton/IconButton.stories.tsx index 0f5c392f..f5410d20 100644 --- a/src/components/IconButton/IconButton.stories.tsx +++ b/src/components/IconButton/IconButton.stories.tsx @@ -19,7 +19,7 @@ import { Meta, StoryFn } from "@storybook/react"; import { IconButton as IconButtonComponent } from "./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: "IconButton", diff --git a/src/components/IconButton/IconButton.test.tsx b/src/components/IconButton/IconButton.test.tsx index 5ebd12da..d967a396 100644 --- a/src/components/IconButton/IconButton.test.tsx +++ b/src/components/IconButton/IconButton.test.tsx @@ -20,7 +20,7 @@ import React from "react"; import { IconButton } from "./IconButton"; -import UserIcon from "@vector-im/compound-design-tokens/icons/user.svg"; +import UserIcon from "@vector-im/compound-design-tokens/icons/user-profile.svg"; describe("IconButton", () => { it("renders", () => { diff --git a/src/components/IconButton/__snapshots__/IconButton.test.tsx.snap b/src/components/IconButton/__snapshots__/IconButton.test.tsx.snap index 3f20e825..4b3d112f 100644 --- a/src/components/IconButton/__snapshots__/IconButton.test.tsx.snap +++ b/src/components/IconButton/__snapshots__/IconButton.test.tsx.snap @@ -8,17 +8,23 @@ exports[`IconButton > renders 1`] = ` > + + diff --git a/yarn.lock b/yarn.lock index 3ea6962f..faa995a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3747,10 +3747,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.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-0.0.4.tgz#bf31120f026118d9dc379917364e2c27b51cce94" + integrity sha512-ZGflwlUANnEbsX/whWqRomyRHS36F1t5AoNBez2EfBVGXMIu7IsURVQfK/UJYPLoSHcArcTFCSbi5KSSsSiymw== dependencies: svg2vectordrawable "^2.9.1" From c71f6836e071cabc09f3a45fe6496cabb3152199 Mon Sep 17 00:00:00 2001 From: Germain Date: Wed, 23 Aug 2023 13:51:43 +0100 Subject: [PATCH 2/7] Create search component --- src/components/Search/Search.module.css | 60 +++++++++++++++ src/components/Search/Search.stories.tsx | 37 ++++++++++ src/components/Search/Search.test.tsx | 33 +++++++++ src/components/Search/Search.tsx | 73 +++++++++++++++++++ .../Search/__snapshots__/Search.test.tsx.snap | 35 +++++++++ 5 files changed, 238 insertions(+) create mode 100644 src/components/Search/Search.module.css create mode 100644 src/components/Search/Search.stories.tsx create mode 100644 src/components/Search/Search.test.tsx create mode 100644 src/components/Search/Search.tsx create mode 100644 src/components/Search/__snapshots__/Search.test.tsx.snap diff --git a/src/components/Search/Search.module.css b/src/components/Search/Search.module.css new file mode 100644 index 00000000..eb060372 --- /dev/null +++ b/src/components/Search/Search.module.css @@ -0,0 +1,60 @@ +/* +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. +*/ + +.search { + border: 1px solid var(--cpd-color-border-interactive-secondary); + border-radius: 9999px; + height: 36px; + box-sizing: border-box; + color: var(--cpd-color-text-primary); + display: inline-flex; + gap: var(--cpd-space-2x); + align-items: center; + padding: var(--cpd-space-1-5x) var(--cpd-space-3x); +} + +.search:hover { + border-color: var(--cpd-color-border-interactive-hovered); +} + +.search:focus-within { + border-color: currentcolor; +} + +.icon { + color: var(--cpd-color-icon-secondary); + height: 100%; + aspect-ratio: 1 / 1; +} + +.search:hover .icon, +.search:focus-within .icon { + color: var(--cpd-color-icon-primary); +} + +.input { + border: 0; + outline: 0; +} + +.input::placeholder { + color: var(--cpd-color-text-placeholder); +} + +.input:focus::placeholder, +.search:hover .input::placeholder { + color: var(--cpd-color-text-secondary); +} diff --git a/src/components/Search/Search.stories.tsx b/src/components/Search/Search.stories.tsx new file mode 100644 index 00000000..81ec373b --- /dev/null +++ b/src/components/Search/Search.stories.tsx @@ -0,0 +1,37 @@ +/* +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 { Search as SearchComponent } from "./Search"; +import { Form } from "@radix-ui/react-form"; + +export default { + title: "Search", + component: SearchComponent, + argTypes: {}, + args: {}, +} as Meta; + +const Template: StoryFn = (args) => ( +
+ + +); + +export const Search = Template.bind({}); +Search.args = {}; diff --git a/src/components/Search/Search.test.tsx b/src/components/Search/Search.test.tsx new file mode 100644 index 00000000..0b80b03d --- /dev/null +++ b/src/components/Search/Search.test.tsx @@ -0,0 +1,33 @@ +/* +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 { Search } from "./Search"; +import { Form } from "@radix-ui/react-form"; + +describe("Search", () => { + it("renders", () => { + const { asFragment } = render( +
+ + , + ); + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/src/components/Search/Search.tsx b/src/components/Search/Search.tsx new file mode 100644 index 00000000..a0921cae --- /dev/null +++ b/src/components/Search/Search.tsx @@ -0,0 +1,73 @@ +/* +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 classnames from "classnames"; +import React from "react"; +import styles from "./Search.module.css"; +import { Field, Label } from "../Form"; + +import SearchIcon from "@vector-im/compound-design-tokens/icons/search.svg"; + +type SearchProps = { + /** + * The CSS class name + */ + className?: string; + /** + * The input placeholder. + * @default Search + */ + placeholder?: string; + /** + * The field name. + */ + name: React.ComponentProps["name"]; + /** + * Event handler called when the search changes. + */ + onChange?: (e: React.ChangeEvent) => void; + /** + * The input disabled state + */ + disabled?: boolean; +}; + +/** + * A standalone search component + */ +export const Search = ({ + className, + onChange, + // TODO: i18n needs to be setup + placeholder = "Search…", + disabled, +}: SearchProps) => { + const classes = classnames(styles.search, className); + return ( + + + + ); +}; diff --git a/src/components/Search/__snapshots__/Search.test.tsx.snap b/src/components/Search/__snapshots__/Search.test.tsx.snap new file mode 100644 index 00000000..58a949d0 --- /dev/null +++ b/src/components/Search/__snapshots__/Search.test.tsx.snap @@ -0,0 +1,35 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Search > renders 1`] = ` + +
+
+ +
+
+
+`; From 6315b8cc6a7f3ee9a164125fce8008af79488de5 Mon Sep 17 00:00:00 2001 From: Germain Date: Wed, 23 Aug 2023 13:57:34 +0100 Subject: [PATCH 3/7] Fix small screen support --- src/components/Search/Search.module.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/Search/Search.module.css b/src/components/Search/Search.module.css index eb060372..fc67ccd0 100644 --- a/src/components/Search/Search.module.css +++ b/src/components/Search/Search.module.css @@ -24,6 +24,7 @@ limitations under the License. gap: var(--cpd-space-2x); align-items: center; padding: var(--cpd-space-1-5x) var(--cpd-space-3x); + overflow: hidden; } .search:hover { @@ -38,6 +39,7 @@ limitations under the License. color: var(--cpd-color-icon-secondary); height: 100%; aspect-ratio: 1 / 1; + flex-shrink: 0; } .search:hover .icon, @@ -48,6 +50,8 @@ limitations under the License. .input { border: 0; outline: 0; + flex: 1; + min-width: 0; } .input::placeholder { From 8d5d60faee947a35cc0c124f7fa2d3309f331dd8 Mon Sep 17 00:00:00 2001 From: Germain Date: Wed, 27 Sep 2023 10:10:52 +0100 Subject: [PATCH 4/7] Align Search component with Figma specs --- src/components/Search/Search.module.css | 30 ++++++++++++++++--------- src/components/Search/Search.tsx | 12 ++++++---- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/components/Search/Search.module.css b/src/components/Search/Search.module.css index fc67ccd0..134d389a 100644 --- a/src/components/Search/Search.module.css +++ b/src/components/Search/Search.module.css @@ -20,15 +20,17 @@ limitations under the License. height: 36px; box-sizing: border-box; color: var(--cpd-color-text-primary); - display: inline-flex; + display: flex; + flex-direction: row; gap: var(--cpd-space-2x); align-items: center; padding: var(--cpd-space-1-5x) var(--cpd-space-3x); - overflow: hidden; } -.search:hover { - border-color: var(--cpd-color-border-interactive-hovered); +@media (hover) { + .search:hover { + border-color: var(--cpd-color-border-interactive-hovered); + } } .search:focus-within { @@ -37,16 +39,19 @@ limitations under the License. .icon { color: var(--cpd-color-icon-secondary); - height: 100%; - aspect-ratio: 1 / 1; flex-shrink: 0; } -.search:hover .icon, -.search:focus-within .icon { +.search:hover .icon { color: var(--cpd-color-icon-primary); } +@media (hover) { + .search:hover .icon { + color: var(--cpd-color-icon-primary); + } +} + .input { border: 0; outline: 0; @@ -58,7 +63,12 @@ limitations under the License. color: var(--cpd-color-text-placeholder); } -.input:focus::placeholder, -.search:hover .input::placeholder { +.input:focus::placeholder { color: var(--cpd-color-text-secondary); } + +@media (hover) { + .search:hover .input::placeholder { + color: var(--cpd-color-text-secondary); + } +} diff --git a/src/components/Search/Search.tsx b/src/components/Search/Search.tsx index a0921cae..2dd9820b 100644 --- a/src/components/Search/Search.tsx +++ b/src/components/Search/Search.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import classnames from "classnames"; -import React from "react"; +import React, { useId } from "react"; import styles from "./Search.module.css"; import { Field, Label } from "../Form"; @@ -54,13 +54,17 @@ export const Search = ({ // TODO: i18n needs to be setup placeholder = "Search…", disabled, + name, }: SearchProps) => { const classes = classnames(styles.search, className); + const id = useId(); return ( - -