generated from cloudoperators/repository-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(ui): export deprecated Panel and undo some chnages
- Loading branch information
1 parent
d70aa22
commit 6e33c99
Showing
12 changed files
with
414 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
packages/ui-components/src/deprecated_js/Panel/Panel.component.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import React, { useState, useEffect } from "react" | ||
import { createPortal } from "react-dom" | ||
import PropTypes from "prop-types" | ||
import { Icon } from "../../deprecated_js/Icon/Icon.component" | ||
import { usePortalRef } from "../../deprecated_js/PortalProvider/PortalProvider.component" | ||
|
||
const panelClasses = (isOpen, isTransitioning, size) => { | ||
return ` | ||
jn-fixed | ||
jn-right-0 | ||
jn-transition-transform | ||
jn-ease-out | ||
jn-duration-300 | ||
jn-inset-y-0 | ||
jn-z-[9989] | ||
jn-grid | ||
jn-grid-rows-[auto_1fr] | ||
jn-bg-theme-panel | ||
jn-backdrop-blur | ||
jn-backdrop-saturate-150 | ||
jn-shadow-md | ||
${ | ||
size === "large" | ||
? ` | ||
jn-w-[90%] | ||
xl:jn-w-[80%] | ||
2xl:jn-w-[1228px]` | ||
: ` | ||
jn-w-[75%] | ||
xl:jn-w-[55%] | ||
2xl:jn-w-[844px]` | ||
} | ||
${!isOpen ? `jn-translate-x-[100%]` : ""} | ||
${!isOpen && !isTransitioning ? `jn-invisible` : ""} | ||
` | ||
.replace(/\n/g, " ") | ||
.replace(/\s+/g, " ") | ||
} | ||
|
||
const contentWrapperClasses = ` | ||
jn-overflow-auto | ||
` | ||
|
||
const panelHeaderClasses = ` | ||
jn-flex | ||
jn-items-center | ||
jn-py-4 | ||
jn-px-8 | ||
` | ||
|
||
const panelTitleClasses = ` | ||
jn-text-theme-high | ||
jn-text-lg | ||
jn-font-bold | ||
` | ||
|
||
/** A slide-in panel for the Content Area. */ | ||
export const Panel = ({ | ||
heading = "", | ||
size, | ||
className = "", | ||
opened = false, | ||
closeable = true, | ||
onClose, | ||
children, | ||
...props | ||
}) => { | ||
const [isOpen, setIsOpen] = useState(opened) | ||
const [isCloseable, setIsCloseable] = useState(closeable) | ||
const [isTransitioning, setIsTransitioning] = useState(false) | ||
|
||
// ensure we notice if the opened parameter is changed from the outside | ||
useEffect(() => { | ||
setIsOpen(opened) | ||
}, [opened]) | ||
|
||
// ensure we notice if the cloeseable parameter is changed from the outside | ||
useEffect(() => { | ||
setIsCloseable(closeable) | ||
}, [closeable]) | ||
|
||
// ----- Timeout stuff ------- | ||
// necessary because we want to set the panel to invisible only after the closing transition has finished | ||
// the invisible panel is to ensure that the panel can't be tab targeted when closed | ||
const timeoutRef = React.useRef(null) | ||
|
||
React.useEffect(() => { | ||
return () => clearTimeout(timeoutRef.current) // clear when component is unmounted | ||
}, []) | ||
|
||
// if isOpen state changes to false set the transitioning state to true for 500ms | ||
useEffect(() => { | ||
if (!isOpen) { | ||
setIsTransitioning(true) | ||
clearTimeout(timeoutRef.current) | ||
timeoutRef.current = setTimeout(() => setIsTransitioning(false), 500) | ||
} | ||
}, [isOpen]) | ||
|
||
const handleClose = (event) => { | ||
setIsOpen(false) | ||
onClose && onClose(event) | ||
} | ||
|
||
const portalContainer = usePortalRef() | ||
|
||
return createPortal( | ||
<div | ||
className={`juno-panel ${panelClasses(isOpen, isTransitioning, size)} ${className}`} | ||
role="dialog" | ||
aria-labelledby="juno-panel-title" | ||
{...props} | ||
> | ||
<div className={`juno-panel-header ${panelHeaderClasses}`}> | ||
<div className={`juno-panel-title ${panelTitleClasses}`} id="juno-panel-title"> | ||
{heading} | ||
</div> | ||
{isCloseable && <Icon icon="close" onClick={handleClose} className="juno-panel-close jn-ml-auto" />} | ||
</div> | ||
<div className={`juno-panel-content-wrapper ${contentWrapperClasses}`}>{children}</div> | ||
</div>, | ||
portalContainer ? portalContainer : document.body | ||
) | ||
} | ||
|
||
Panel.propTypes = { | ||
/** Pass a Panel heading/title. */ | ||
heading: PropTypes.node, | ||
/** Size of the opened panel. If unspecified, default size is used. */ | ||
size: PropTypes.oneOf(["default", "large"]), | ||
/** Pass open state */ | ||
opened: PropTypes.bool, | ||
/** Pass whether panel should be closeable via a close button or not. If false, the close button will not be rendered. The panel can still be closed by setting "opened" to false. */ | ||
closeable: PropTypes.bool, | ||
/** Pass a handler that will be called when the close button is clicked */ | ||
onClose: PropTypes.func, | ||
/** Pass an optional className */ | ||
className: PropTypes.string, | ||
/** Pass child nodes to be rendered in the main body of the Panel */ | ||
children: PropTypes.node, | ||
} |
80 changes: 80 additions & 0 deletions
80
packages/ui-components/src/deprecated_js/Panel/Panel.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
* 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, waitFor } from "@testing-library/react" | ||
import userEvent from "@testing-library/user-event" | ||
import { Panel } from "./index" | ||
|
||
const closedClass = "jn-translate-x-[100%]" | ||
|
||
describe("Panel", () => { | ||
test("renders a panel", async () => { | ||
await waitFor(() => render(<Panel />)) | ||
expect(screen.getByRole("dialog")).toBeInTheDocument() | ||
expect(screen.getByRole("dialog")).toHaveClass("juno-panel") | ||
}) | ||
|
||
test("renders a closed panel by default", async () => { | ||
await waitFor(() => render(<Panel />)) | ||
expect(screen.getByRole("dialog")).toBeInTheDocument() | ||
expect(screen.getByRole("dialog")).toHaveClass(closedClass) | ||
}) | ||
|
||
test("renders an opened panel", async () => { | ||
await waitFor(() => render(<Panel opened />)) | ||
expect(screen.getByRole("dialog")).toBeInTheDocument() | ||
expect(screen.getByRole("dialog")).not.toHaveClass(closedClass) | ||
}) | ||
|
||
test("renders a panel with heading", async () => { | ||
await waitFor(() => render(<Panel heading="My heading" opened />)) | ||
expect(screen.getByRole("dialog")).toBeInTheDocument() | ||
expect(screen.getByRole("dialog")).toHaveTextContent("My heading") | ||
}) | ||
|
||
test("renders a panel with close button by default", async () => { | ||
await waitFor(() => render(<Panel />)) | ||
expect(screen.getByRole("dialog")).toBeInTheDocument() | ||
expect(screen.getByRole("button")).toBeInTheDocument() | ||
expect(screen.getByLabelText("close")).toBeInTheDocument() | ||
expect(screen.getByRole("button")).toHaveAttribute("aria-label", "close") | ||
expect(screen.getByRole("img")).toHaveAttribute("alt", "close") | ||
}) | ||
|
||
test("renders a panel without a close button", async () => { | ||
await waitFor(() => render(<Panel closeable={false} />)) | ||
expect(screen.getByRole("dialog")).toBeInTheDocument() | ||
expect(screen.queryByRole("button")).not.toBeInTheDocument() | ||
expect(screen.queryByLabelText("close")).not.toBeInTheDocument() | ||
}) | ||
|
||
test("renders a custom classname", async () => { | ||
await waitFor(() => render(<Panel className="my-custom-classname" />)) | ||
expect(screen.getByRole("dialog")).toBeInTheDocument() | ||
expect(screen.getByRole("dialog")).toHaveClass("my-custom-classname") | ||
}) | ||
|
||
test("renders all props as passed", async () => { | ||
await waitFor(() => render(<Panel data-xyz={true} />)) | ||
expect(screen.getByRole("dialog")).toBeInTheDocument() | ||
expect(screen.getByRole("dialog")).toHaveAttribute("data-xyz") | ||
}) | ||
|
||
// EVENTS | ||
|
||
test("on click on close button closes panel", async () => { | ||
await waitFor(() => render(<Panel />)) | ||
await waitFor(() => userEvent.click(screen.getByRole("button"))) | ||
expect(screen.getByRole("dialog")).toHaveClass(closedClass) | ||
}) | ||
|
||
test("on click on close button fires onClose handler as passed", async () => { | ||
const handleClose = jest.fn() | ||
await waitFor(() => render(<Panel onClose={handleClose} />)) | ||
await waitFor(() => userEvent.click(screen.getByRole("button"))) | ||
expect(handleClose).toHaveBeenCalledTimes(1) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
export { Panel } from "./Panel.component" |
37 changes: 37 additions & 0 deletions
37
packages/ui-components/src/deprecated_js/PanelBody/PanelBody.component.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* 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" | ||
|
||
const panelBodyClasses = ` | ||
` | ||
|
||
const bodyContentClasses = ` | ||
jn-px-8 | ||
jn-py-4 | ||
` | ||
|
||
/** | ||
* The panel body component. The main (form) content for the panel goes here. | ||
*/ | ||
export const PanelBody = ({ className = "", footer, children, ...props }) => { | ||
return ( | ||
<div className={`juno-panel-body ${panelBodyClasses} ${className}`} {...props}> | ||
<div className={`juno-panel-body-content ${bodyContentClasses}`}>{children}</div> | ||
|
||
{footer} | ||
</div> | ||
) | ||
} | ||
|
||
PanelBody.propTypes = { | ||
/** Add custom class name */ | ||
className: PropTypes.string, | ||
children: PropTypes.any, | ||
/** optional footer component */ | ||
footer: PropTypes.element, | ||
} |
45 changes: 45 additions & 0 deletions
45
packages/ui-components/src/deprecated_js/PanelBody/PanelBody.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* 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 { PanelBody } from "./index" | ||
import { PanelFooter } from "../PanelFooter/index" | ||
|
||
describe("PanelBody", () => { | ||
test("renders a panel body", async () => { | ||
render(<PanelBody data-testid="panel-body" />) | ||
expect(screen.getByTestId("panel-body")).toBeInTheDocument() | ||
expect(screen.getByTestId("panel-body")).toHaveClass("juno-panel-body") | ||
}) | ||
|
||
test("renders children as passed", async () => { | ||
render( | ||
<PanelBody data-testid="panel-body"> | ||
<button></button> | ||
</PanelBody> | ||
) | ||
expect(screen.getByTestId("panel-body")).toBeInTheDocument() | ||
expect(screen.getByRole("button")).toBeInTheDocument() | ||
}) | ||
|
||
test("renders footer as passed", async () => { | ||
render(<PanelBody data-testid="panel-body" footer={<PanelFooter>This is the footer</PanelFooter>}></PanelBody>) | ||
expect(screen.getByTestId("panel-body")).toBeInTheDocument() | ||
expect(screen.getByTestId("panel-body")).toHaveTextContent("This is the footer") | ||
}) | ||
|
||
test("renders a custom className", async () => { | ||
render(<PanelBody data-testid="panel-body" className="my-custom-classname" />) | ||
expect(screen.getByTestId("panel-body")).toBeInTheDocument() | ||
expect(screen.getByTestId("panel-body")).toHaveClass("my-custom-classname") | ||
}) | ||
|
||
test("renders all props", async () => { | ||
render(<PanelBody data-testid="panel-body" data-lolol="some-prop" />) | ||
expect(screen.getByTestId("panel-body")).toBeInTheDocument() | ||
expect(screen.getByTestId("panel-body")).toHaveAttribute("data-lolol", "some-prop") | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
export { PanelBody } from "./PanelBody.component" |
36 changes: 36 additions & 0 deletions
36
packages/ui-components/src/deprecated_js/PanelFooter/PanelFooter.component.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* 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" | ||
|
||
const panelFooterClasses = ` | ||
jn-border-t | ||
jn-border-t-theme-background-lvl-2 | ||
jn-px-8 | ||
jn-py-4 | ||
jn-flex | ||
jn-items-center | ||
jn-justify-end | ||
jn-gap-3 | ||
jn-w-full | ||
` | ||
|
||
/** | ||
* The panel footer component. You can drop buttons in here and they will automatically be aligned correctly to the right. | ||
*/ | ||
export const PanelFooter = ({ className = "", children, ...props }) => { | ||
return ( | ||
<div className={`juno-panel-footer ${panelFooterClasses} ${className}`} {...props}> | ||
{children} | ||
</div> | ||
) | ||
} | ||
|
||
PanelFooter.propTypes = { | ||
/** Add custom class name */ | ||
className: PropTypes.string, | ||
children: PropTypes.any, | ||
} |
Oops, something went wrong.