From a2e4fd7d4ab5011db1295cd587534fed9f24dd87 Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 11 Nov 2024 19:11:31 +0000 Subject: [PATCH 1/7] feat(button): create scale image button --- .../OakScaleImageButton.stories.tsx | 40 ++++ .../OakScaleImageButton.test.tsx | 56 +++++ .../OakScaleImageButton.tsx | 70 ++++++ .../OakScaleImageButton.test.tsx.snap | 205 ++++++++++++++++++ .../molecules/OakScaleImageButton/index.ts | 1 + src/components/molecules/index.ts | 1 + src/image-map.ts | 2 + 7 files changed, 375 insertions(+) create mode 100644 src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx create mode 100644 src/components/molecules/OakScaleImageButton/OakScaleImageButton.test.tsx create mode 100644 src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx create mode 100644 src/components/molecules/OakScaleImageButton/__snapshots__/OakScaleImageButton.test.tsx.snap create mode 100644 src/components/molecules/OakScaleImageButton/index.ts diff --git a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx new file mode 100644 index 00000000..de2ae8e3 --- /dev/null +++ b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import { Meta, StoryObj } from "@storybook/react"; + +import { OakScaleImageButton } from "./OakScaleImageButton"; + +import { OakFlex } from "@/components/atoms"; + +const meta: Meta = { + component: OakScaleImageButton, + tags: ["autodocs"], + title: "components/molecules/OakScaleImageButton", + argTypes: { + onImageScaleCallback: { + options: ["expand", "minimise"], + }, + isExpanded: { + control: "boolean", + }, + }, + parameters: { + controls: { + include: ["onImageScaleCallback", "isExpanded"], + }, + }, +}; +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: (args) => ( + + + + ), +}; diff --git a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.test.tsx b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.test.tsx new file mode 100644 index 00000000..5215bdcc --- /dev/null +++ b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.test.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import "@testing-library/jest-dom"; +import { create } from "react-test-renderer"; +import { ThemeProvider } from "styled-components"; + +import { + OakScaleImageButton, + OakScaleImageButtonProps, +} from "./OakScaleImageButton"; + +import renderWithTheme from "@/test-helpers/renderWithTheme"; +import { oakDefaultTheme } from "@/styles"; + +const defaultArgs: OakScaleImageButtonProps = { + onImageScaleCallback: jest.fn(), + isExpanded: false, +}; + +describe("OakScaleImageButton", () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.runOnlyPendingTimers(); + jest.useRealTimers(); + }); + + it("renders", () => { + const { getByTestId } = renderWithTheme( + , + ); + expect(getByTestId("expand-image-button")).toBeInTheDocument(); + }); + + it("matches snapshot", () => { + const tree = create( + + Click Me + , + ).toJSON(); + expect(tree).toMatchSnapshot(); + }); + + it("calls onImageScaleCallback method", () => { + const onImageScaleCallback = jest.fn(); + const { getByTestId } = renderWithTheme( + , + ); + getByTestId("expand-image-button").click(); + expect(onImageScaleCallback).toHaveBeenCalled(); + }); +}); diff --git a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx new file mode 100644 index 00000000..32a3d603 --- /dev/null +++ b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx @@ -0,0 +1,70 @@ +import React, { ElementType } from "react"; + +import { + InternalShadowRectButton, + InternalShadowRectButtonProps, +} from "@/components/molecules/InternalShadowRectButton"; +import { PolymorphicPropsWithoutRef } from "@/components/polymorphic"; + +export type OakScaleImageButtonProps = Omit< + InternalShadowRectButtonProps, + | "defaultTextColor" + | "hoverTextColor" + | "disabledTextColor" + | "defaultBackground" + | "defaultBorderColor" + | "hoverBackground" + | "hoverBorderColor" + | "disabledBackground" + | "disabledBorderColor" + | "iconGap" + | "pv" + | "ph" + | "$bblr" + | "$btlr" + | "width" +> & { + onImageScaleCallback: (event: React.MouseEvent) => void; + isExpanded: boolean; +}; + +/** + * + * A specific implementation of InternalRectButton + * + * The following callback is available for tracking focus events: + * + * ### onImageScaleCallback + * `onImageScaleCallback: (event: React.MouseEvent) => void;` + * + */ + +export const OakScaleImageButton = ({ + onImageScaleCallback, + isExpanded, +}: OakScaleImageButtonProps & PolymorphicPropsWithoutRef) => { + return ( + + ); +}; diff --git a/src/components/molecules/OakScaleImageButton/__snapshots__/OakScaleImageButton.test.tsx.snap b/src/components/molecules/OakScaleImageButton/__snapshots__/OakScaleImageButton.test.tsx.snap new file mode 100644 index 00000000..6794fa4c --- /dev/null +++ b/src/components/molecules/OakScaleImageButton/__snapshots__/OakScaleImageButton.test.tsx.snap @@ -0,0 +1,205 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`OakScaleImageButton matches snapshot 1`] = ` +.c0 { + position: relative; + width: 100%; + font-family: --var(google-font),Lexend,sans-serif; +} + +.c2 { + position: absolute; + top: 0rem; + width: 100%; + height: 100%; + border-radius: 0.25rem; + font-family: --var(google-font),Lexend,sans-serif; +} + +.c5 { + font-family: --var(google-font),Lexend,sans-serif; +} + +.c7 { + position: relative; + width: 1.5rem; + min-width: 1.5rem; + height: 1.5rem; + min-height: 1.5rem; + font-family: --var(google-font),Lexend,sans-serif; +} + +.c8 { + -webkit-filter: invert(10%) sepia(1%) saturate(236%) hue-rotate(314deg) brightness(95%) contrast(91%); + filter: invert(10%) sepia(1%) saturate(236%) hue-rotate(314deg) brightness(95%) contrast(91%); + object-fit: contain; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + gap: 0rem; +} + +.c9 { + font-family: --var(google-font),Lexend,sans-serif; + font-weight: 600; + font-size: 1rem; + line-height: 1.25rem; + -webkit-letter-spacing: 0.0115rem; + -moz-letter-spacing: 0.0115rem; + -ms-letter-spacing: 0.0115rem; + letter-spacing: 0.0115rem; + text-align: left; +} + +.c3 { + background: none; + color: inherit; + border: none; + padding: 0; + font: inherit; + cursor: pointer; + text-align: left; + font-family: unset; + outline: none; + font-family: --var(google-font),Lexend,sans-serif; + color: #222222; + background: #f2f2f2; + padding-left: 0rem; + padding-right: 0rem; + padding-top: 0rem; + padding-bottom: 0rem; + border: 0.125rem solid; + border-color: #f2f2f2; + border-radius: 0.25rem; + border-top-left-radius: 0rem; + border-bottom-left-radius: 0rem; +} + +.c3:disabled { + pointer-events: none; + cursor: default; +} + +.c4 { + position: relative; + width: 100%; + height: 100%; + display: inline-block; +} + +.c4:hover { + -webkit-text-decoration: underline; + text-decoration: underline; + color: #222222; + background: #e4e4e4; + border-color: #e4e4e4; +} + +.c4:active { + background: #f2f2f2; + border-color: #f2f2f2; + color: #222222; +} + +.c4:disabled { + background: #808080; + border-color: #808080; + color: #222222; +} + +.c1 .grey-shadow:has(+ * + .internal-button:focus-visible) { + box-shadow: 0 0 0 0.3rem rgba(87,87,87,100%); +} + +.c1 .yellow-shadow:has(+ .internal-button:focus-visible) { + box-shadow: 0 0 0 0.125rem rgba(255,229,85,100%); +} + +.c1 .yellow-shadow:has(+ .internal-button:hover), +.c1 .yellow-shadow:has(+ .internal-button:hover:not(:focus-visible,:active)) { + box-shadow: 0.125rem 0.125rem 0 rgba(255,229,85,100%); +} + +.c1 .grey-shadow:has(+ * + .internal-button:hover) { + box-shadow: none; +} + +.c1 .grey-shadow:has(+ * + .internal-button:active) { + box-shadow: 0.25rem 0.25rem 0 rgba(87,87,87,100%); +} + +.c1 .yellow-shadow:has(+ .internal-button:active) { + box-shadow: 0.125rem 0.125rem 0 rgba(255,229,85,100%); +} + +
+
+
+ +
+`; diff --git a/src/components/molecules/OakScaleImageButton/index.ts b/src/components/molecules/OakScaleImageButton/index.ts new file mode 100644 index 00000000..26d6447b --- /dev/null +++ b/src/components/molecules/OakScaleImageButton/index.ts @@ -0,0 +1 @@ +export * from "./OakScaleImageButton"; diff --git a/src/components/molecules/index.ts b/src/components/molecules/index.ts index 45c5d831..f70e4536 100644 --- a/src/components/molecules/index.ts +++ b/src/components/molecules/index.ts @@ -38,3 +38,4 @@ export * from "./OakSmallSecondaryButton"; export * from "./OakTertiaryButton"; export * from "./OakTextInput"; export * from "./OakTooltip"; +export * from "./OakScaleImageButton"; diff --git a/src/image-map.ts b/src/image-map.ts index 3b0296f9..61381720 100644 --- a/src/image-map.ts +++ b/src/image-map.ts @@ -4,6 +4,8 @@ export const icons = { send: "v1699893673/icons/rmvytilpjgvh3pgwc8ph.svg", rocket: "v1699894015/icons/u26xm5hteot875ozfnk9.svg", edit: "v1699894149/icons/qxlunbg5tfrdherzsvlt.svg", + expand: "v1730982187/Icon_Expand_arrktl.svg", + minimise: "v1730982213/Icon_Minimise_btcdbz.svg", hamburger: "v1699895123/icons/jaqdnomtbhqvjcap962u.svg", cross: "v1699895179/icons/xigimrbivcaxt4omxamp.svg", copy: "v1727861316/icons/Icon_Copy_qxgynv.svg", From 77b8a01b73f6b82fcfa5e2b235c2b3c45d89cf3a Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 11 Nov 2024 19:34:03 +0000 Subject: [PATCH 2/7] feat(button): create scale image button --- .../OakScaleImageButton.stories.tsx | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx index de2ae8e3..bd4f19cd 100644 --- a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx +++ b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx @@ -1,9 +1,9 @@ -import React from "react"; +import React, { useState } from "react"; import { Meta, StoryObj } from "@storybook/react"; import { OakScaleImageButton } from "./OakScaleImageButton"; -import { OakFlex } from "@/components/atoms"; +import { OakCloudinaryImage, OakFlex } from "@/components/atoms"; const meta: Meta = { component: OakScaleImageButton, @@ -38,3 +38,32 @@ export const Default: Story = { ), }; + +export const withImageScaleCallback: Story = { + render: (args) => { + const [scaled, setScale] = useState(false); + + return ( + + + { + setScale(!scaled); + }} + isExpanded={scaled} + /> + + ); + }, +}; From 94295c45d45d508f56d9212a76fd82bfed46f3cd Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 11 Nov 2024 19:47:50 +0000 Subject: [PATCH 3/7] feat(button): create scale image button --- .../OakScaleImageButton/OakScaleImageButton.stories.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx index bd4f19cd..5b7364a3 100644 --- a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx +++ b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx @@ -41,8 +41,7 @@ export const Default: Story = { export const withImageScaleCallback: Story = { render: (args) => { - const [scaled, setScale] = useState(false); - + const [scaled, setScale] = useState(false); return ( ); }, + args: {}, + parameters: { + controls: { + include: [], + }, + }, }; From 0d674da6fe6c49f57b1e7ec85b776408ec9b116b Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 11 Nov 2024 19:59:37 +0000 Subject: [PATCH 4/7] feat(button): create scale image button --- .../OakScaleImageButton.stories.tsx | 38 +------------------ 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx index 5b7364a3..de2ae8e3 100644 --- a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx +++ b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx @@ -1,9 +1,9 @@ -import React, { useState } from "react"; +import React from "react"; import { Meta, StoryObj } from "@storybook/react"; import { OakScaleImageButton } from "./OakScaleImageButton"; -import { OakCloudinaryImage, OakFlex } from "@/components/atoms"; +import { OakFlex } from "@/components/atoms"; const meta: Meta = { component: OakScaleImageButton, @@ -38,37 +38,3 @@ export const Default: Story = { ), }; - -export const withImageScaleCallback: Story = { - render: (args) => { - const [scaled, setScale] = useState(false); - return ( - - - { - setScale(!scaled); - }} - isExpanded={scaled} - /> - - ); - }, - args: {}, - parameters: { - controls: { - include: [], - }, - }, -}; From 563a8370c4346e7ca5e4e5e2b89b9faa04def686 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 12 Nov 2024 09:01:07 +0000 Subject: [PATCH 5/7] feat(button): create scale image button --- .../OakScaleImageButton.stories.tsx | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx index de2ae8e3..90353e3e 100644 --- a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx +++ b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.stories.tsx @@ -3,7 +3,7 @@ import { Meta, StoryObj } from "@storybook/react"; import { OakScaleImageButton } from "./OakScaleImageButton"; -import { OakFlex } from "@/components/atoms"; +import { OakCloudinaryImage, OakFlex } from "@/components/atoms"; const meta: Meta = { component: OakScaleImageButton, @@ -38,3 +38,24 @@ export const Default: Story = { ), }; + +export const withImage: Story = { + render: (args) => { + return ( + + + + + ); + }, +}; From 4ed8ed05242eabbc44c3a34aa10eca5c1867879d Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 12 Nov 2024 09:04:00 +0000 Subject: [PATCH 6/7] feat(button): create scale image button --- .../molecules/OakScaleImageButton/OakScaleImageButton.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx index 32a3d603..cba57762 100644 --- a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx +++ b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx @@ -23,6 +23,7 @@ export type OakScaleImageButtonProps = Omit< | "$bblr" | "$btlr" | "width" + | "onClick" > & { onImageScaleCallback: (event: React.MouseEvent) => void; isExpanded: boolean; From 4de79a5809b3db29844df895b454820d4ad99515 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 12 Nov 2024 11:30:23 +0000 Subject: [PATCH 7/7] feat(button): create scale image button --- .../molecules/OakScaleImageButton/OakScaleImageButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx index cba57762..6a6c80b5 100644 --- a/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx +++ b/src/components/molecules/OakScaleImageButton/OakScaleImageButton.tsx @@ -64,7 +64,7 @@ export const OakScaleImageButton = ({ $bblr={"border-radius-square"} $btlr={"border-radius-square"} width={"100%"} - aria-label={!isExpanded ? "Expand Image" : "Minimise imagew"} + aria-label={!isExpanded ? "Expand Image" : "Minimise image"} data-testid="expand-image-button" /> );