From 45967062d1188af371356f9f3f21acc1a669e214 Mon Sep 17 00:00:00 2001 From: "gjaskiewicz@objectivity.co.uk" Date: Wed, 28 Aug 2024 10:44:10 +0200 Subject: [PATCH 1/7] refactor(ui): Migrate pill component to Typescript --- .changeset/six-walls-prove.md | 5 + .../src/components/Pill/Pill.component.js | 112 ---------------- .../src/components/Pill/Pill.component.tsx | 120 ++++++++++++++++++ .../Pill/{Pill.stories.js => Pill.stories.ts} | 2 +- .../Pill/{Pill.test.js => Pill.test.tsx} | 27 ++-- .../components/Pill/{index.js => index.ts} | 0 6 files changed, 140 insertions(+), 126 deletions(-) create mode 100644 .changeset/six-walls-prove.md delete mode 100644 packages/ui-components/src/components/Pill/Pill.component.js create mode 100644 packages/ui-components/src/components/Pill/Pill.component.tsx rename packages/ui-components/src/components/Pill/{Pill.stories.js => Pill.stories.ts} (95%) rename packages/ui-components/src/components/Pill/{Pill.test.js => Pill.test.tsx} (85%) rename packages/ui-components/src/components/Pill/{index.js => index.ts} (100%) diff --git a/.changeset/six-walls-prove.md b/.changeset/six-walls-prove.md new file mode 100644 index 000000000..9ac0d4cee --- /dev/null +++ b/.changeset/six-walls-prove.md @@ -0,0 +1,5 @@ +--- +"@cloudoperators/juno-oauth": minor +--- + +Migration to Typescript diff --git a/packages/ui-components/src/components/Pill/Pill.component.js b/packages/ui-components/src/components/Pill/Pill.component.js deleted file mode 100644 index 1d034f3b9..000000000 --- a/packages/ui-components/src/components/Pill/Pill.component.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import React from "react" -import PropTypes from "prop-types" -import { Icon } from "../Icon/Icon.component.js" - -const pillStyles = (onClick) => { - return ` - jn-inline-flex - jn-basis-auto - jn-shrink - jn-items-center - jn-flex-nowrap - jn-text-xs - jn-p-px - jn-border - jn-rounded - jn-border-theme-background-lvl-4 - jn-group - ${onClick ? "jn-cursor-pointer" : ""} - ` -} - -const pillKeyStyles = (onClick) => { - return ` - jn-bg-theme-background-lvl-4 - jn-text-theme-high - ${onClick ? "group-hover:jn-text-theme-highest" : ""} - jn-px-1 - jn-py-0.5 - jn-rounded-sm - jn-inline-block - ` -} - -const pillValueStyles = (onClick) => { - return ` - jn-px-1 - jn-py-0.5 - jn-text-theme-high - ${onClick ? "group-hover:jn-text-theme-highest" : ""} - jn-inline-block - ` -} - -/** -A Pill to represent a value, or key and value. Can e.g. be used to represent selected filter values in a filter component. Can optionally be closed. On close the uid, if provided, or the pillKey is returned in the callback. - */ -export const Pill = ({ - uid = "", - pillKey = "", - pillKeyLabel = "", - pillValue = "", - pillValueLabel = "", - closeable = false, - onClick = undefined, - onClose = undefined, - className = "", - ...props -}) => { - const handleCloseClick = (event) => { - onClose && onClose(event, uid || pillKey || pillValue) - } - - const handleClick = (event) => { - onClick && onClick(event, uid || pillKey || pillValue) - } - - return ( -
- {!pillValue && !pillValueLabel ? ( - set pillValue or pillValueLabel - ) : ( - <> - {(pillKeyLabel || pillKey) && ( - handleClick(e)}> - {pillKeyLabel || pillKey} - - )} - handleClick(e)}> - {pillValueLabel || pillValue} - - - )} - {closeable && handleCloseClick(e)} />} -
- ) -} - -Pill.propTypes = { - /** The unique identifier of the pill. Returned by the onClose callback */ - uid: PropTypes.string, - /** The key of the filter the pill represents. Returned by the onClose callback if uid undefined. Optional. */ - pillKey: PropTypes.string, - /** The visible label to describe the pill key. If not set pillKey is used. Optional. */ - pillKeyLabel: PropTypes.string, - /** The value of filter the pill represents. Returned by the onClose callback if uid and pillKey undefined */ - pillValue: PropTypes.string.isRequired, - /** The visible label to describe the pill value. If not set pillValue is used. Optional. */ - pillValueLabel: PropTypes.string, - /** add custom classNames */ - className: PropTypes.string, - /** Whether the pill should be closeable */ - closeable: PropTypes.bool, - /** Pass a handler to be executed when closing the Pill. Also returns the event and the uid (fallback: pillKey -> fallback: pillValue) */ - onClose: PropTypes.func, - /** Pass a handler to be executed when clicking on the Pill (but not on the close button). Also returns the event and the uid (fallback: pillKey -> fallback: pillValue) */ - onClick: PropTypes.func, -} diff --git a/packages/ui-components/src/components/Pill/Pill.component.tsx b/packages/ui-components/src/components/Pill/Pill.component.tsx new file mode 100644 index 000000000..d9c96ff8d --- /dev/null +++ b/packages/ui-components/src/components/Pill/Pill.component.tsx @@ -0,0 +1,120 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { FC } from "react" +import Close from "@material-design-icons/svg/filled/close.svg" + +type EventHandler = (_event :React.MouseEvent, _id :string) => void; + +const pillStyles = (onClick :boolean) => { + return ` + jn-inline-flex + jn-basis-auto + jn-shrink + jn-items-center + jn-flex-nowrap + jn-text-xs + jn-p-px + jn-border + jn-rounded + jn-border-theme-background-lvl-4 + jn-group + ${onClick ? "jn-cursor-pointer" : ""} + ` +} + +const pillKeyStyles = (onClick :boolean) => { + return ` + jn-bg-theme-background-lvl-4 + jn-text-theme-high + ${onClick ? "group-hover:jn-text-theme-highest" : ""} + jn-px-1 + jn-py-0.5 + jn-rounded-sm + jn-inline-block + ` +} + +const pillValueStyles = (onClick :boolean) => { + return ` + jn-px-1 + jn-py-0.5 + jn-text-theme-high + ${onClick ? "group-hover:jn-text-theme-highest" : ""} + jn-inline-block + ` +} + +/** +A Pill to represent a value, or key and value. Can e.g. be used to represent selected filter values in a filter component. Can optionally be closed. On close the uid, if provided, or the pillKey is returned in the callback. + */ +export const Pill : FC = ({ + uid = "", + pillKey = "", + pillKeyLabel = "", + pillValue = "", + pillValueLabel = "", + closeable = false, + onClick = undefined, + onClose = undefined, + className = "", + ...props +}) => { + const handleCloseClick = (event :React.MouseEvent) => { + onClose && onClose(event, uid || pillKey || pillValue) + } + + const handleClick = (event :React.MouseEvent) => { + onClick && onClick(event, uid || pillKey || pillValue) + } + + return ( +
+ {!pillValue && !pillValueLabel ? ( + set pillValue or pillValueLabel + ) : ( + <> + {(pillKeyLabel || pillKey) && ( + handleClick(e)}> + {pillKeyLabel || pillKey} + + )} + handleClick(e)}> + {pillValueLabel || pillValue} + + + )} + {closeable && ) => handleCloseClick(e)} + />} +
+ ) +} + +export interface PillProps { + /** The unique identifier of the pill. Returned by the onClose callback */ + uid? :string + /** The key of the filter the pill represents. Returned by the onClose callback if uid undefined. Optional. */ + pillKey? :string + /** The visible label to describe the pill key. If not set pillKey is used. Optional. */ + pillKeyLabel? :string + /** The value of filter the pill represents. Returned by the onClose callback if uid and pillKey undefined */ + pillValue :string //.isRequired, + /** The visible label to describe the pill value. If not set pillValue is used. Optional. */ + pillValueLabel? :string + /** add custom classNames */ + className? :string + /** Whether the pill should be closeable */ + closeable? :boolean + /** Pass a handler to be executed when closing the Pill. Also returns the event and the uid (fallback: pillKey -> fallback: pillValue) */ + onClose? :EventHandler + /** Pass a handler to be executed when clicking on the Pill (but not on the close button). Also returns the event and the uid (fallback: pillKey -> fallback: pillValue) */ + onClick? :EventHandler +} diff --git a/packages/ui-components/src/components/Pill/Pill.stories.js b/packages/ui-components/src/components/Pill/Pill.stories.ts similarity index 95% rename from packages/ui-components/src/components/Pill/Pill.stories.js rename to packages/ui-components/src/components/Pill/Pill.stories.ts index 463a7015d..8ba407429 100644 --- a/packages/ui-components/src/components/Pill/Pill.stories.js +++ b/packages/ui-components/src/components/Pill/Pill.stories.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Pill } from "./index.js" +import { Pill } from "./index.ts" export default { title: "Components/Pill", diff --git a/packages/ui-components/src/components/Pill/Pill.test.js b/packages/ui-components/src/components/Pill/Pill.test.tsx similarity index 85% rename from packages/ui-components/src/components/Pill/Pill.test.js rename to packages/ui-components/src/components/Pill/Pill.test.tsx index d532a7479..dfab6a170 100644 --- a/packages/ui-components/src/components/Pill/Pill.test.js +++ b/packages/ui-components/src/components/Pill/Pill.test.tsx @@ -4,44 +4,45 @@ */ import * as React from "react" +import { describe, expect, test, vi } from "vitest" import { render, screen } from "@testing-library/react" import { Pill } from "./index" describe("Pill", () => { - test("renders a Pill", async () => { + test("renders a Pill", () => { render() expect(screen.getByTestId("my-Pill")).toBeInTheDocument() expect(screen.getByTestId("my-Pill")).toHaveClass("juno-pill") }) - test("renders a pill key label as passed", async () => { + test("renders a pill key label as passed", () => { render() expect(screen.getByText("My Pill Key")).toBeInTheDocument() }) - test("renders a pill key if pill key label missing", async () => { + test("renders a pill key if pill key label missing", () => { render() expect(screen.getByText("my_Pill_key")).toBeInTheDocument() }) - test("renders only value if pill key label not set", async () => { + test("renders only value if pill key label not set", () => { // the attribute pillKey and pillValue are required keep them empty to test render nothing render() expect(screen.getByTestId("23")).toBeInTheDocument() expect(screen.getByTestId("23")).toHaveTextContent("TheRequiredValue") }) - test("renders a pill value label as passed", async () => { + test("renders a pill value label as passed", () => { render() expect(screen.getByText("My Pill Value")).toBeInTheDocument() }) - test("renders a pill value if value label missing", async () => { + test("renders a pill value if value label missing", () => { render() expect(screen.getByText("my_Pill_value")).toBeInTheDocument() }) - test("renders information about missing value if pill value or value label not given", async () => { + test("renders information about missing value if pill value or value label not given", () => { // the attribute pillKey and pillValue are required keep them empty to test render nothing render() expect(screen.getByTestId("23")).toBeInTheDocument() @@ -49,7 +50,7 @@ describe("Pill", () => { }) test("an onClose handler is called as passed and returns the uid", () => { - const handleClose = jest.fn() + const handleClose = vi.fn() render( ) @@ -59,7 +60,7 @@ describe("Pill", () => { }) test("an onClose handler is called as passed and returns the pillKey if uid missing", () => { - const handleClose = jest.fn() + const handleClose = vi.fn() render() screen.getByRole("button").click() expect(handleClose).toHaveBeenCalledTimes(1) @@ -67,7 +68,7 @@ describe("Pill", () => { }) test("an onClick handler is called as passed and returns the uid", () => { - const handleClick = jest.fn() + const handleClick = vi.fn() render() screen.getByText("TheRequiredKey").click() expect(handleClick).toHaveBeenCalledTimes(1) @@ -75,14 +76,14 @@ describe("Pill", () => { }) test("an onClick handler is called as passed and returns the pillKey if uid missing", () => { - const handleClick = jest.fn() + const handleClick = vi.fn() render() screen.getByText("abc").click() expect(handleClick).toHaveBeenCalledTimes(1) expect(handleClick).toHaveBeenCalledWith(expect.anything(), "abc") }) - test("renders a custom className", async () => { + test("renders a custom className", () => { render( ) @@ -90,7 +91,7 @@ describe("Pill", () => { expect(screen.getByTestId("my-Pill")).toHaveClass("my-custom-class") }) - test("renders all props as passed", async () => { + test("renders all props as passed", () => { render() expect(screen.getByTestId("23")).toBeInTheDocument() expect(screen.getByTestId("23")).toHaveAttribute("data-lolol") diff --git a/packages/ui-components/src/components/Pill/index.js b/packages/ui-components/src/components/Pill/index.ts similarity index 100% rename from packages/ui-components/src/components/Pill/index.js rename to packages/ui-components/src/components/Pill/index.ts From 95b131ae194f0a849825005749068751046311c1 Mon Sep 17 00:00:00 2001 From: "gjaskiewicz@objectivity.co.uk" Date: Wed, 28 Aug 2024 11:18:33 +0200 Subject: [PATCH 2/7] fix(ui): fix icon interaction --- .../src/components/Pill/Pill.component.tsx | 72 ++++++++++--------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/packages/ui-components/src/components/Pill/Pill.component.tsx b/packages/ui-components/src/components/Pill/Pill.component.tsx index d9c96ff8d..17199e946 100644 --- a/packages/ui-components/src/components/Pill/Pill.component.tsx +++ b/packages/ui-components/src/components/Pill/Pill.component.tsx @@ -6,9 +6,9 @@ import React, { FC } from "react" import Close from "@material-design-icons/svg/filled/close.svg" -type EventHandler = (_event :React.MouseEvent, _id :string) => void; +type EventHandler = (_event: React.MouseEvent, _id: string) => void -const pillStyles = (onClick :boolean) => { +const pillStyles = (onClick: boolean) => { return ` jn-inline-flex jn-basis-auto @@ -25,7 +25,7 @@ const pillStyles = (onClick :boolean) => { ` } -const pillKeyStyles = (onClick :boolean) => { +const pillKeyStyles = (onClick: boolean) => { return ` jn-bg-theme-background-lvl-4 jn-text-theme-high @@ -37,7 +37,7 @@ const pillKeyStyles = (onClick :boolean) => { ` } -const pillValueStyles = (onClick :boolean) => { +const pillValueStyles = (onClick: boolean) => { return ` jn-px-1 jn-py-0.5 @@ -50,7 +50,7 @@ const pillValueStyles = (onClick :boolean) => { /** A Pill to represent a value, or key and value. Can e.g. be used to represent selected filter values in a filter component. Can optionally be closed. On close the uid, if provided, or the pillKey is returned in the callback. */ -export const Pill : FC = ({ +export const Pill: FC = ({ uid = "", pillKey = "", pillKeyLabel = "", @@ -62,11 +62,11 @@ export const Pill : FC = ({ className = "", ...props }) => { - const handleCloseClick = (event :React.MouseEvent) => { + const handleCloseClick = (event: React.MouseEvent) => { onClose && onClose(event, uid || pillKey || pillValue) } - const handleClick = (event :React.MouseEvent) => { + const handleClick = (event: React.MouseEvent) => { onClick && onClick(event, uid || pillKey || pillValue) } @@ -86,35 +86,41 @@ export const Pill : FC = ({ )} - {closeable && ) => handleCloseClick(e)} - />} + {closeable && ( + + )} ) } export interface PillProps { - /** The unique identifier of the pill. Returned by the onClose callback */ - uid? :string - /** The key of the filter the pill represents. Returned by the onClose callback if uid undefined. Optional. */ - pillKey? :string - /** The visible label to describe the pill key. If not set pillKey is used. Optional. */ - pillKeyLabel? :string - /** The value of filter the pill represents. Returned by the onClose callback if uid and pillKey undefined */ - pillValue :string //.isRequired, - /** The visible label to describe the pill value. If not set pillValue is used. Optional. */ - pillValueLabel? :string - /** add custom classNames */ - className? :string - /** Whether the pill should be closeable */ - closeable? :boolean - /** Pass a handler to be executed when closing the Pill. Also returns the event and the uid (fallback: pillKey -> fallback: pillValue) */ - onClose? :EventHandler - /** Pass a handler to be executed when clicking on the Pill (but not on the close button). Also returns the event and the uid (fallback: pillKey -> fallback: pillValue) */ - onClick? :EventHandler + /** The unique identifier of the pill. Returned by the onClose callback */ + uid?: string + /** The key of the filter the pill represents. Returned by the onClose callback if uid undefined. Optional. */ + pillKey?: string + /** The visible label to describe the pill key. If not set pillKey is used. Optional. */ + pillKeyLabel?: string + /** The value of filter the pill represents. Returned by the onClose callback if uid and pillKey undefined */ + pillValue: string //.isRequired, + /** The visible label to describe the pill value. If not set pillValue is used. Optional. */ + pillValueLabel?: string + /** add custom classNames */ + className?: string + /** Whether the pill should be closeable */ + closeable?: boolean + /** Pass a handler to be executed when closing the Pill. Also returns the event and the uid (fallback: pillKey -> fallback: pillValue) */ + onClose?: EventHandler + /** Pass a handler to be executed when clicking on the Pill (but not on the close button). Also returns the event and the uid (fallback: pillKey -> fallback: pillValue) */ + onClick?: EventHandler } From 9b4a060e85e663b793ac672808e258a9d9d035c0 Mon Sep 17 00:00:00 2001 From: "gjaskiewicz@objectivity.co.uk" Date: Wed, 28 Aug 2024 13:15:03 +0200 Subject: [PATCH 3/7] fix(ui): fix DatePickr test for non-US locale --- .../components/DateTimePicker/DateTimePicker.test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ui-components/src/components/DateTimePicker/DateTimePicker.test.js b/packages/ui-components/src/components/DateTimePicker/DateTimePicker.test.js index ec8d48f76..0c5f91e98 100644 --- a/packages/ui-components/src/components/DateTimePicker/DateTimePicker.test.js +++ b/packages/ui-components/src/components/DateTimePicker/DateTimePicker.test.js @@ -739,7 +739,7 @@ describe("DateTimePicker", () => { const today = new Date() const yesterday = new Date() yesterday.setDate(yesterday.getDate() - 1) - const fullMonth = yesterday.toLocaleString("default", { month: "long" }) + const fullMonth = yesterday.toLocaleString("en-US", { month: "long" }) const day = yesterday.getDate() const fullYear = yesterday.getFullYear() const yesterdayLabel = `${fullMonth} ${day}, ${fullYear}` @@ -761,7 +761,7 @@ describe("DateTimePicker", () => { const today = new Date() const tomorrow = new Date() tomorrow.setDate(tomorrow.getDate() + 1) - const fullMonth = tomorrow.toLocaleString("default", { month: "long" }) + const fullMonth = tomorrow.toLocaleString("en-US", { month: "long" }) const day = tomorrow.getDate() const fullYear = tomorrow.getFullYear() const tomorrowLabel = `${fullMonth} ${day}, ${fullYear}` @@ -783,7 +783,7 @@ describe("DateTimePicker", () => { const today = new Date() const tomorrow = new Date() tomorrow.setDate(tomorrow.getDate() + 1) - const tomorrowFullMonth = tomorrow.toLocaleString("default", { + const tomorrowFullMonth = tomorrow.toLocaleString("en-US", { month: "long", }) const tomorrowDay = tomorrow.getDate() @@ -807,7 +807,7 @@ describe("DateTimePicker", () => { const today = new Date() const tomorrow = new Date() tomorrow.setDate(tomorrow.getDate() + 1) - const todayFullMonth = today.toLocaleString("default", { month: "long" }) + const todayFullMonth = today.toLocaleString("en-US", { month: "long" }) const todayDay = today.getDate() const todayFullYear = today.getFullYear() const todayLabel = `${todayFullMonth} ${todayDay}, ${todayFullYear}` @@ -889,7 +889,7 @@ describe("DateTimePicker", () => { const today = new Date() const tomorrow = new Date() tomorrow.setDate(tomorrow.getDate() + 1) - const tomorrowFullMonth = tomorrow.toLocaleString("default", { + const tomorrowFullMonth = tomorrow.toLocaleString("en-US", { month: "long", }) const tomorrowDay = tomorrow.getDate() From a42d08a97fc304b0fb6b3fd15fcc114feafc02f6 Mon Sep 17 00:00:00 2001 From: "gjaskiewicz@objectivity.co.uk" Date: Wed, 28 Aug 2024 13:30:55 +0200 Subject: [PATCH 4/7] fix(ui): remove changeset from different PR --- .changeset/six-walls-prove.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/six-walls-prove.md diff --git a/.changeset/six-walls-prove.md b/.changeset/six-walls-prove.md deleted file mode 100644 index 9ac0d4cee..000000000 --- a/.changeset/six-walls-prove.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@cloudoperators/juno-oauth": minor ---- - -Migration to Typescript From ff6345e2ddcbf2cf2420c51b2c33963f580c5650 Mon Sep 17 00:00:00 2001 From: "gjaskiewicz@objectivity.co.uk" Date: Thu, 29 Aug 2024 13:46:30 +0200 Subject: [PATCH 5/7] refactor(ui): migrate Icon component to Typescript as temporarily new file --- .../src/components/IconTs/Icon.component.tsx | 849 ++++++++++++++++++ .../src/components/IconTs/Icon.stories.ts | 416 +++++++++ .../src/components/IconTs/Icon.test.tsx | 364 ++++++++ .../src/components/IconTs/index.ts | 6 + .../src/components/Pill/Pill.component.tsx | 19 +- 5 files changed, 1641 insertions(+), 13 deletions(-) create mode 100644 packages/ui-components/src/components/IconTs/Icon.component.tsx create mode 100644 packages/ui-components/src/components/IconTs/Icon.stories.ts create mode 100644 packages/ui-components/src/components/IconTs/Icon.test.tsx create mode 100644 packages/ui-components/src/components/IconTs/index.ts diff --git a/packages/ui-components/src/components/IconTs/Icon.component.tsx b/packages/ui-components/src/components/IconTs/Icon.component.tsx new file mode 100644 index 000000000..7b1cc62e0 --- /dev/null +++ b/packages/ui-components/src/components/IconTs/Icon.component.tsx @@ -0,0 +1,849 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React, { forwardRef, LegacyRef } from "react" + +/* Import Icons here. The icon svgs in the icons folder correspond to the respective "xyz_24px.svg" from material-ui icons. + */ +import AccessTime from "@material-design-icons/svg/filled/access_time.svg" +import AccountCircle from "@material-design-icons/svg/filled/account_circle.svg" +import AddCircle from "@material-design-icons/svg/filled/add_circle.svg" +import AutoAwesomeMosaic from "@material-design-icons/svg/filled/auto_awesome_mosaic.svg" +import AutoAwesomeMotion from "@material-design-icons/svg/filled/auto_awesome_motion.svg" +import Bolt from "@material-design-icons/svg/filled/bolt.svg" +import CalendarToday from "@material-design-icons/svg/filled/calendar_today.svg" +import Cancel from "@material-design-icons/svg/filled/cancel.svg" +import Check from "@material-design-icons/svg/filled/check.svg" +import CheckCircle from "@material-design-icons/svg/filled/check_circle.svg" +import ChevronLeft from "@material-design-icons/svg/outlined/chevron_left.svg" +import ChevronRight from "@material-design-icons/svg/outlined/chevron_right.svg" +import Close from "@material-design-icons/svg/filled/close.svg" +import ContentCopy from "@material-design-icons/svg/outlined/content_copy.svg" +import Danger from "./../Icon/icons/juno-danger.svg" +import Dangerous from "@material-design-icons/svg/filled/dangerous.svg" +import Download from "@material-design-icons/svg/filled/download.svg" +import DeleteForever from "@material-design-icons/svg/filled/delete_forever.svg" +import Description from "@material-design-icons/svg/filled/description.svg" +import DNS from "@material-design-icons/svg/filled/dns.svg" +import Edit from "@material-design-icons/svg/filled/edit.svg" +import Error from "@material-design-icons/svg/filled/dangerous.svg" +import ErrorOutline from "@material-design-icons/svg/outlined/error_outline.svg" +import ExitToApp from "@material-design-icons/svg/outlined/exit_to_app.svg" +import ExpandLess from "@material-design-icons/svg/outlined/expand_less.svg" +import ExpandMore from "@material-design-icons/svg/outlined/expand_more.svg" +import FilterAlt from "@material-design-icons/svg/filled/filter_alt.svg" +import Forum from "@material-design-icons/svg/filled/forum.svg" +import Help from "@material-design-icons/svg/filled/help.svg" +import Home from "./../Icon/icons/home_sharp.svg" +import Info from "@material-design-icons/svg/filled/info.svg" +import Comment from "@material-design-icons/svg/filled/comment.svg" +import ManageAccounts from "@material-design-icons/svg/filled/manage_accounts.svg" +import MonitorHeart from "@material-design-icons/svg/outlined/monitor_heart.svg" +import MoreVert from "@material-design-icons/svg/outlined/more_vert.svg" +import NightsStay from "@material-design-icons/svg/outlined/nights_stay.svg" +import NotificationsOff from "@material-design-icons/svg/outlined/notifications_off.svg" +import OpenInBrowser from "@material-design-icons/svg/outlined/open_in_browser.svg" +import OpenInNew from "@material-design-icons/svg/outlined/open_in_new.svg" +import Place from "./../Icon/icons/place.svg" +import Success from "@material-design-icons/svg/filled/check_box.svg" +import Search from "@material-design-icons/svg/outlined/search.svg" +import SeverityLow from "./../Icon/icons/juno_severity_low.svg" +import SeverityMedium from "./../Icon/icons/juno_severity_medium.svg" +import SeverityHigh from "./../Icon/icons/juno_severity_high.svg" +import SeverityCritical from "./../Icon/icons/juno_severity_critical.svg" +import Warning from "@material-design-icons/svg/filled/warning.svg" +import WBSunny from "@material-design-icons/svg/outlined/wb_sunny.svg" +import Widgets from "@material-design-icons/svg/filled/widgets.svg" + +/** +Generic Icon component. +*/ +// hover style needs to be revisited. only works if no icon color was passed +const anchorIconStyles = ` + jn-text-current + hover:jn-text-theme-high + focus:jn-outline-none + focus-visible:jn-ring-2 + focus-visible:jn-ring-theme-focus + focus-visible:jn-ring-offset-1 + focus-visible:jn-ring-offset-theme-focus + disabled:jn-opacity-50 + disabled:jn-cursor-not-allowed +` + +// hover style needs to be revisited. only works if no icon color was passed +const buttonIconStyles = ` + hover:jn-text-theme-high + focus:jn-outline-none + focus-visible:jn-ring-2 + focus-visible:jn-ring-theme-focus + focus-visible:jn-ring-offset-1 + focus-visible:jn-ring-offset-theme-focus + disabled:jn-opacity-50 + disabled:jn-cursor-not-allowed +` + +// const wrapperStyles = ` +// jn-leading-none +// ` +// export all known icons as an array of their names to be used with PropTypes here and from other components: +export type KnownIcons = + "accessTime" | + "accountCircle" | + "addCircle" | + "autoAwesomeMosaic" | + "autoAwesomeMotion" | + "bolt" | + "calendarToday" | + "cancel" | + "check" | + "checkCircle" | + "chevronLeft" | + "chevronRight" | + "close" | + "comment" | + "contentCopy" | + "danger" | + "dangerous" | + "default" | + "deleteForever" | + "description" | + "dns" | + "download" | + "edit" | + "error" | + "errorOutline" | + "exitToApp" | + "expandLess" | + "expandMore" | + "filterAlt" | + "forum" | + "help" | + "home" | + "info" | + "manageAccounts" | + "monitorHeart" | + "moreVert" | + "nightsStay" | + "notificationsOff" | + "openInBrowser" | + "openInNew" | + "place" | + "search" | + "severityLow" | + "severityMedium" | + "severityHigh" | + "severityCritical" | + "success" | + "warning" | + "wbSunny" | + "widgets"; + +interface IconColorProps { + icon? :KnownIcons + color :string, + title :string + size :number + iconClassName :string +} + +const getColoredSizedIcon = ({ icon, color, size, title, iconClassName, ...iconProps } :IconColorProps) => { + const iconClass = `juno-icon juno-icon-${icon} jn-fill-current ${color} ${iconClassName}` + + switch (icon) { + case "accessTime": + return ( + + ) + case "accountCircle": + return ( + + ) + case "addCircle": + return ( + + ) + case "autoAwesomeMosaic": + return ( + + ) + case "autoAwesomeMotion": + return ( + + ) + case "bolt": + return ( + + ) + case "calendarToday": + return ( + + ) + case "cancel": + return ( + + ) + case "check": + return ( + + ) + case "checkCircle": + return ( + + ) + case "chevronLeft": + return ( + + ) + case "chevronRight": + return ( + + ) + case "close": + return ( + + ) + case "comment": + return ( + + ) + case "contentCopy": + return ( + + ) + case "danger": + return ( + + ) + case "dangerous": + return ( + + ) + case "deleteForever": + return ( + + ) + case "description": + return ( + + ) + case "dns": + return ( + + ) + case "download": + return ( + + ) + case "edit": + return ( + + ) + case "error": + return ( + + ) + case "errorOutline": + return ( + + ) + case "exitToApp": + return ( + + ) + case "expandLess": + return ( + + ) + case "expandMore": + return ( + + ) + case "filterAlt": + return ( + + ) + case "forum": + return ( + + ) + case "help": + return ( + + ) + case "home": + return ( + + ) + case "info": + return ( + + ) + case "manageAccounts": + return ( + + ) + case "monitorHeart": + return ( + + ) + case "moreVert": + return ( + + ) + case "nightsStay": + return ( + + ) + case "notificationsOff": + return ( + + ) + case "openInBrowser": + return ( + + ) + case "openInNew": + return ( + + ) + case "place": + return ( + + ) + case "search": + return ( + + ) + case "severityLow": + return ( + + ) + case "severityMedium": + return ( + + ) + case "severityHigh": + return ( + + ) + case "severityCritical": + return ( + + ) + case "success": + return ( + + ) + case "widgets": + return ( + + ) + case "warning": + return ( + + ) + case "wbSunny": + return ( + + ) + case "default": // keep explicit default case to allow consuming components to use 'default' w/o throwing warnings + return ( + + ) + default: + return ( + + ) + } +} + +export const Icon = forwardRef<(HTMLAnchorElement | HTMLButtonElement), IconProps>( + ( + { + icon = null, + color = "", + size = 24, + title = "", + className = "", + href = "", + disabled = false, + onClick, + ...props + }, + ref + ) => { + // if href or onClick was passed, then we want to add the passed classes and passed arbitrary props to the button or anchor + // otherwise add the passed classes/props to the icon itself + const iconClassName = href || onClick ? "" : className + const iconProps = href || onClick ? {} : props + + const icn = getColoredSizedIcon({ + icon: (icon || undefined), + color, + size, + title, + iconClassName, + ...iconProps, + }) + + const handleClick = (event: React.MouseEvent) => { + onClick && onClick(event) + } + + const button = ( + + ) + + const anchor = ( + )} + aria-label={title || icon || undefined} + href={href} + className={`juno-icon-link ${anchorIconStyles} ${className}`} + ref={ref as LegacyRef} + > + {icn} + + ) + + /* render an if href was passed, otherwise render button if onClick was passes, otherwise render plain icon: */ + /* if plain icon, add ref to the icon. In the other cases the ref goes on the anchor or button */ + return href ? anchor : onClick ? button : {icn} + } +) + +Icon.displayName = "IconTs" + +type EventHandler = (_event: React.MouseEvent) => void + +export type IconProps = { + icon? :KnownIcons + color? :string + size? :number + title? :string + className? :string + href? :string + disabled? :boolean + onClick? :EventHandler +} & (React.HTMLProps | React.HTMLProps) diff --git a/packages/ui-components/src/components/IconTs/Icon.stories.ts b/packages/ui-components/src/components/IconTs/Icon.stories.ts new file mode 100644 index 000000000..681550122 --- /dev/null +++ b/packages/ui-components/src/components/IconTs/Icon.stories.ts @@ -0,0 +1,416 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Icon } from "./index.ts" + +export default { + title: "Components/IconTs", + component: Icon, + argTypes: {}, + parameters: { + docs: { + description: { + component: + "A generic icon component. Accepts text color classes for color. Please note that the 'jn-' prefix for tailwind classes is only necessary within the juno ui design system itself. When using icons in your own applications use the normal tailwing-generated text color classes starting with 'text-'", + }, + }, + }, +} + +export const Default = { + args: { + icon: "help", + color: "jn-global-text", + }, +} + +export const Info_Colored = { + args: { + icon: "info", + color: "jn-text-theme-info", + }, +} + +export const Danger_Colored = { + args: { + icon: "danger", + color: "jn-text-theme-danger", + }, +} + +export const Success_Colored = { + args: { + icon: "success", + color: "jn-text-theme-success", + }, +} + +export const Warning_Colored = { + args: { + icon: "warning", + color: "jn-text-theme-warning", + }, +} + +export const ThemeColor = { + args: { + icon: "help", + color: "jn-global-text", + }, +} + +export const Smaller = { + args: { + ...Default.args, + icon: "help", + size: "18", + }, +} + +export const Larger = { + args: { + ...Default.args, + icon: "help", + size: "64", + }, +} + +export const IconAsLink = { + args: { + ...Default.args, + href: "#", + title: "The Icon is a link", + }, +} + +export const IconAsButton = { + args: { + ...Default.args, + title: "The Icon is a button", + onClick: () => { + console.log("click") + }, + }, +} + +export const Account_Circle = { + args: { + ...Default.args, + icon: "accountCircle", + }, +} + +export const Add_Circle = { + args: { + ...Default.args, + icon: "addCircle", + }, +} + +export const Auto_Awesome_Mosaic = { + args: { + ...Default.args, + icon: "autoAwesomeMosaic", + }, +} + +export const Auto_Awesome_Motion = { + args: { + ...Default.args, + icon: "autoAwesomeMotion", + }, +} + +export const Bolt = { + args: { + ...Default.args, + icon: "bolt", + }, +} + +export const Cancel = { + args: { + ...Default.args, + icon: "cancel", + }, +} + +export const Check = { + args: { + icon: "check", + }, +} + +export const CheckCircle = { + args: { + icon: "checkCircle", + }, +} + +export const ChevronLeft = { + args: { + icon: "chevronLeft", + }, +} + +export const ChevronRight = { + args: { + icon: "chevronRight", + }, +} + +export const Close = { + args: { + icon: "close", + }, +} + +export const Comment = { + args: { + ...Default.args, + icon: "comment", + }, +} + +export const ContentCopy = { + args: { + icon: "contentCopy", + }, +} + +export const Danger = { + args: { + ...Default.args, + icon: "danger", + }, +} + +export const Dangerous = { + args: { + icon: "dangerous", + }, +} + +export const DeleteForever = { + args: { + icon: "deleteForever", + }, +} + +export const Description = { + args: { + ...Default.args, + icon: "description", + }, +} + +export const DNS = { + args: { + ...Default.args, + icon: "dns", + }, +} + +export const Download = { + args: { + icon: "download", + }, +} + +export const Edit = { + args: { + ...Default.args, + icon: "edit", + }, +} + +export const Error = { + args: { + ...Default.args, + icon: "dangerous", + }, +} + +export const Error_Outline = { + args: { + ...Default.args, + icon: "errorOutline", + }, +} + +export const Exit_To_App = { + args: { + ...Default.args, + icon: "exitToApp", + }, +} + +export const Expand_Less = { + args: { + ...Default.args, + icon: "expandLess", + }, +} + +export const Expand_More = { + args: { + ...Default.args, + icon: "expandMore", + }, +} + +export const Filter_Alt = { + args: { + ...Default.args, + icon: "filterAlt", + }, +} + +export const Forum = { + args: { + ...Default.args, + icon: "forum", + }, +} + +export const Help = { + args: { + ...Default.args, + icon: "help", + }, +} + +export const Home = { + args: { + ...Default.args, + icon: "home", + }, +} + +export const Info = { + args: { + ...Default.args, + icon: "info", + }, +} + +export const Manage_Accounts = { + args: { + ...Default.args, + icon: "manageAccounts", + }, +} + +export const Monitor_Heart = { + args: { + ...Default.args, + icon: "monitorHeart", + }, +} + +export const More_Vert = { + args: { + ...Default.args, + icon: "moreVert", + }, +} + +export const Nights_Stay = { + args: { + ...Default.args, + icon: "nightsStay", + }, +} + +export const Notifications_Off = { + args: { + ...Default.args, + icon: "notificationsOff", + }, +} + +export const Open_In_Browser = { + args: { + ...Default.args, + icon: "openInBrowser", + }, +} + +export const Open_In_New = { + args: { + ...Default.args, + icon: "openInNew", + }, +} + +export const Place = { + args: { + ...Default.args, + icon: "place", + }, +} + +export const Search = { + args: { + ...Default.args, + icon: "search", + }, +} + +export const SeverityLow = { + args: { + ...Default.args, + icon: "severityLow", + }, +} + +export const SeverityMedium = { + args: { + ...Default.args, + icon: "severityMedium", + }, +} + +export const SeverityHigh = { + args: { + ...Default.args, + icon: "severityHigh", + }, +} + +export const SeverityCritical = { + args: { + ...Default.args, + icon: "severityCritical", + }, +} + +export const Success = { + args: { + ...Default.args, + icon: "success", + }, +} + +export const Warning = { + args: { + ...Default.args, + icon: "warning", + }, +} + +export const WBSunny = { + args: { + ...Default.args, + icon: "wbSunny", + }, +} + +export const Widgets = { + args: { + ...Default.args, + icon: "widgets", + }, +} diff --git a/packages/ui-components/src/components/IconTs/Icon.test.tsx b/packages/ui-components/src/components/IconTs/Icon.test.tsx new file mode 100644 index 000000000..f8165a76b --- /dev/null +++ b/packages/ui-components/src/components/IconTs/Icon.test.tsx @@ -0,0 +1,364 @@ +/* + * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as React from "react" +import { render, screen } from "@testing-library/react" +import { Icon } from "./index" +import { describe, expect, test, vi } from "vitest" + +describe("Icon (typescript)", () => { + test("renders an Icon as passed", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "warning") + }) + + test("renders a custom className as passed", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveClass("my-custom-class") + }) + + test("renders a default icon when none was passed", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + // note: currently the default icon is the help icon + expect(screen.getByRole("img")).toHaveAttribute("alt", "help") + }) + + test("renders an Icon with no text class by default so that text color is inherited from context", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + // check that there is no class that contains 'text-' + expect(screen.getByRole("img")).not.toHaveAttribute("class", expect.stringContaining("text-")) + }) + + test("renders an Icon with color as passed", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveClass("text-juno-blue") + }) + + test("renders an Icon with default size", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("width", "24") + expect(screen.getByRole("img")).toHaveAttribute("height", "24") + }) + + test("renders an Icon with size as passed", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("width", "48") + expect(screen.getByRole("img")).toHaveAttribute("height", "48") + }) + + test("renders a custom alt text instead of default when passed", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "my super custom icon alt text") + }) + + // Test individual icons: + + test("renders an accessTime icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "time") + }) + + test("renders an accountCircle icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "account") + }) + + test("renders an addCircle icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "add") + }) + + test("renders a autoAwesomeMosaic icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "mosaic") + }) + + test("renders a autoAwesomeMotion icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "items stacked behind each other") + }) + + test("renders a bolt icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "bolt") + }) + + test("renders a cancel icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "cancel") + }) + + test("renders a check icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "check") + }) + + test("renders a checkCircle icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "checkCircle") + }) + + test("renders a chevronLeft icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "chevronLeft") + }) + + test("renders a chevronRight icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "chevronRight") + }) + + test("renders a close icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "close") + }) + + test("renders a copy icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "copy") + }) + + test("renders a danger icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "danger") + }) + + test("renders a dangerous icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "dangerous") + }) + + test("renders a deleteForever icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "delete forever") + }) + + test("renders a description icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "description") + }) + + test("renders a dns icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "service") + }) + + test("renders an edit icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "edit") + }) + + test("renders an error icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "error") + }) + + test("renders an outlined error icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "error outline") + }) + + test("renders an exitToApp icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "exit to other app") + }) + + test("renders an expandLess icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "expand less") + }) + + test("renders an expandMore icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "expand more") + }) + + test("renders an filterAlt icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "filter") + }) + + test("renders an forum icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "forum") + }) + + test("renders a forum help icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "help") + }) + + test("renders a Home icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "home") + }) + + test("renders an info icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "info") + }) + + test("renders a comment icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "comment") + }) + + test("renders a manageAccounts icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "user account configuration") + }) + + test("renders an openInBrowser icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "open in browser") + }) + + test("renders a place icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "location") + }) + + test("renders a search icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "search") + }) + + test("renders a success icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "success") + }) + + test("renders a warning icon", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toHaveAttribute("alt", "warning") + }) + + test("renders a custom title", () => { + render() + expect(screen.getByRole("img")).toBeInTheDocument() + expect(screen.getByRole("img")).toContainHTML("My custom title") + }) + + test("renders an element if href is passed as prop", () => { + render() + expect(screen.getByRole("link")).toBeInTheDocument() + expect(screen.getByRole("link")).toHaveAttribute("href", "#") + }) + + test("renders an element with correct aria-label-attribute as passed", () => { + render() + expect(screen.getByRole("link")).toBeInTheDocument() + expect(screen.getByRole("link")).toHaveAttribute("aria-label", "my link title") + }) + + test("renders an element with correct aria-label-attribute fallback if not passed", () => { + render() + expect(screen.getByRole("link")).toBeInTheDocument() + expect(screen.getByRole("link")).toHaveAttribute("aria-label", "warning") + }) + + test("renders a + ) => handleCloseClick(e)} + /> )} ) From cbb6f1b652bfa5cb41f54eed9485032d4573d1f9 Mon Sep 17 00:00:00 2001 From: "gjaskiewicz@objectivity.co.uk" Date: Thu, 29 Aug 2024 14:49:48 +0200 Subject: [PATCH 6/7] fix(ui): fix format --- .../src/components/IconTs/Icon.component.tsx | 144 ++++++++---------- .../src/components/Pill/Pill.component.tsx | 8 +- 2 files changed, 68 insertions(+), 84 deletions(-) diff --git a/packages/ui-components/src/components/IconTs/Icon.component.tsx b/packages/ui-components/src/components/IconTs/Icon.component.tsx index 7b1cc62e0..5fbf9b5e6 100644 --- a/packages/ui-components/src/components/IconTs/Icon.component.tsx +++ b/packages/ui-components/src/components/IconTs/Icon.component.tsx @@ -90,66 +90,66 @@ const buttonIconStyles = ` // ` // export all known icons as an array of their names to be used with PropTypes here and from other components: export type KnownIcons = - "accessTime" | - "accountCircle" | - "addCircle" | - "autoAwesomeMosaic" | - "autoAwesomeMotion" | - "bolt" | - "calendarToday" | - "cancel" | - "check" | - "checkCircle" | - "chevronLeft" | - "chevronRight" | - "close" | - "comment" | - "contentCopy" | - "danger" | - "dangerous" | - "default" | - "deleteForever" | - "description" | - "dns" | - "download" | - "edit" | - "error" | - "errorOutline" | - "exitToApp" | - "expandLess" | - "expandMore" | - "filterAlt" | - "forum" | - "help" | - "home" | - "info" | - "manageAccounts" | - "monitorHeart" | - "moreVert" | - "nightsStay" | - "notificationsOff" | - "openInBrowser" | - "openInNew" | - "place" | - "search" | - "severityLow" | - "severityMedium" | - "severityHigh" | - "severityCritical" | - "success" | - "warning" | - "wbSunny" | - "widgets"; + | "accessTime" + | "accountCircle" + | "addCircle" + | "autoAwesomeMosaic" + | "autoAwesomeMotion" + | "bolt" + | "calendarToday" + | "cancel" + | "check" + | "checkCircle" + | "chevronLeft" + | "chevronRight" + | "close" + | "comment" + | "contentCopy" + | "danger" + | "dangerous" + | "default" + | "deleteForever" + | "description" + | "dns" + | "download" + | "edit" + | "error" + | "errorOutline" + | "exitToApp" + | "expandLess" + | "expandMore" + | "filterAlt" + | "forum" + | "help" + | "home" + | "info" + | "manageAccounts" + | "monitorHeart" + | "moreVert" + | "nightsStay" + | "notificationsOff" + | "openInBrowser" + | "openInNew" + | "place" + | "search" + | "severityLow" + | "severityMedium" + | "severityHigh" + | "severityCritical" + | "success" + | "warning" + | "wbSunny" + | "widgets" interface IconColorProps { - icon? :KnownIcons - color :string, - title :string - size :number - iconClassName :string + icon?: KnownIcons + color: string + title: string + size: number + iconClassName: string } -const getColoredSizedIcon = ({ icon, color, size, title, iconClassName, ...iconProps } :IconColorProps) => { +const getColoredSizedIcon = ({ icon, color, size, title, iconClassName, ...iconProps }: IconColorProps) => { const iconClass = `juno-icon juno-icon-${icon} jn-fill-current ${color} ${iconClassName}` switch (icon) { @@ -768,19 +768,9 @@ const getColoredSizedIcon = ({ icon, color, size, title, iconClassName, ...iconP } } -export const Icon = forwardRef<(HTMLAnchorElement | HTMLButtonElement), IconProps>( +export const Icon = forwardRef( ( - { - icon = null, - color = "", - size = 24, - title = "", - className = "", - href = "", - disabled = false, - onClick, - ...props - }, + { icon = null, color = "", size = 24, title = "", className = "", href = "", disabled = false, onClick, ...props }, ref ) => { // if href or onClick was passed, then we want to add the passed classes and passed arbitrary props to the button or anchor @@ -789,7 +779,7 @@ export const Icon = forwardRef<(HTMLAnchorElement | HTMLButtonElement), IconProp const iconProps = href || onClick ? {} : props const icn = getColoredSizedIcon({ - icon: (icon || undefined), + icon: icon || undefined, color, size, title, @@ -838,12 +828,12 @@ Icon.displayName = "IconTs" type EventHandler = (_event: React.MouseEvent) => void export type IconProps = { - icon? :KnownIcons - color? :string - size? :number - title? :string - className? :string - href? :string - disabled? :boolean - onClick? :EventHandler + icon?: KnownIcons + color?: string + size?: number + title?: string + className?: string + href?: string + disabled?: boolean + onClick?: EventHandler } & (React.HTMLProps | React.HTMLProps) diff --git a/packages/ui-components/src/components/Pill/Pill.component.tsx b/packages/ui-components/src/components/Pill/Pill.component.tsx index e6052b79d..3585cf8b3 100644 --- a/packages/ui-components/src/components/Pill/Pill.component.tsx +++ b/packages/ui-components/src/components/Pill/Pill.component.tsx @@ -86,13 +86,7 @@ export const Pill: FC = ({ )} - {closeable && ( - ) => handleCloseClick(e)} - /> - )} + {closeable && ) => handleCloseClick(e)} />} ) } From 3b06cc5b8c254b80307a5feef94a2bcc47463c14 Mon Sep 17 00:00:00 2001 From: Wowa Barsukov Date: Fri, 30 Aug 2024 11:32:42 +0200 Subject: [PATCH 7/7] chore(ui): add changeset --- .changeset/eighty-geese-thank.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/eighty-geese-thank.md diff --git a/.changeset/eighty-geese-thank.md b/.changeset/eighty-geese-thank.md new file mode 100644 index 000000000..ae04ecbe6 --- /dev/null +++ b/.changeset/eighty-geese-thank.md @@ -0,0 +1,5 @@ +--- +"@cloudoperators/juno-ui-components": patch +--- + +chore(ui): migrate Pill component to typescript