for grouping.
+ */
+export const UserProfileDetails: Story = {
+ render: (args) => (
+
+
+
- Full Name
+ - John Doe
+
+
+
- Email
+ - johndoe@example.com
+
+
+
- Membership
+ - Platinum Member
+ - Joined: January 2020
+
+
+
- Preferences
+ - Language: English
+ - Theme: Dark
+
+
+ ),
+}
diff --git a/packages/ui-components/src/components/DescriptionList/DescriptionList.test.tsx b/packages/ui-components/src/components/DescriptionList/DescriptionList.test.tsx
new file mode 100644
index 0000000000..c4226e85d3
--- /dev/null
+++ b/packages/ui-components/src/components/DescriptionList/DescriptionList.test.tsx
@@ -0,0 +1,70 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from "react"
+import { render, screen } from "@testing-library/react"
+import { describe, it, expect } from "vitest"
+import { DescriptionList } from "./DescriptionList.component"
+import { DescriptionTerm } from "../DescriptionTerm"
+import { DescriptionDefinition } from "../DescriptionDefinition"
+
+describe("DescriptionList", () => {
+ it("renders child DescriptionTerm and DescriptionDefinition components correctly", () => {
+ render(
+
+ Term 1
+ Definition 1
+
+ )
+ expect(screen.getByText("Term 1")).toBeInTheDocument()
+ expect(screen.getByText("Definition 1")).toBeInTheDocument()
+ })
+
+ it("applies custom className to the
element", () => {
+ const customClass = "custom-class"
+ render(
+
+ Term 2
+ Definition 2
+
+ )
+
+ const dlElement = screen.getByTestId("description-list")
+ expect(dlElement).toHaveClass(customClass)
+ })
+
+ it("aligns terms to the right by default", () => {
+ render(
+
+ Term 3
+ Definition 3
+
+ )
+ })
+
+ it("aligns terms to the left when specified", () => {
+ render(
+
+ Left Term
+ Definition for Left Term
+
+ )
+ })
+
+ it("renders multiple terms and definitions in a single list", () => {
+ render(
+
+ Term 4
+ Definition 4
+ Term 5
+ Definition 5
+
+ )
+ expect(screen.getByText("Term 4")).toBeInTheDocument()
+ expect(screen.getByText("Definition 4")).toBeInTheDocument()
+ expect(screen.getByText("Term 5")).toBeInTheDocument()
+ expect(screen.getByText("Definition 5")).toBeInTheDocument()
+ })
+})
diff --git a/packages/ui-components/src/components/DescriptionList/description-list.css b/packages/ui-components/src/components/DescriptionList/description-list.css
new file mode 100644
index 0000000000..75ed0a8728
--- /dev/null
+++ b/packages/ui-components/src/components/DescriptionList/description-list.css
@@ -0,0 +1,10 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.dl {
+ display: flex;
+ flex-direction: row;
+ gap: 0.25rem;
+}
diff --git a/packages/ui-components/src/components/DescriptionList/index.ts b/packages/ui-components/src/components/DescriptionList/index.ts
new file mode 100644
index 0000000000..d8d66b9ab9
--- /dev/null
+++ b/packages/ui-components/src/components/DescriptionList/index.ts
@@ -0,0 +1,6 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { DescriptionList, type DescriptionListProps } from "./DescriptionList.component"
diff --git a/packages/ui-components/src/components/DescriptionTerm/DescriptionTerm.component.tsx b/packages/ui-components/src/components/DescriptionTerm/DescriptionTerm.component.tsx
new file mode 100644
index 0000000000..8c267b001d
--- /dev/null
+++ b/packages/ui-components/src/components/DescriptionTerm/DescriptionTerm.component.tsx
@@ -0,0 +1,30 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { ReactNode } from "react"
+import "./description-term.css"
+
+export interface DescriptionTermProps {
+ /**
+ * Content to be displayed as the term, which could be simple text or any ReactNode, providing semantic meaning to the associated description.
+ */
+ children: ReactNode
+ /**
+ * Custom class names to apply additional styling to the - element, useful for overrides or custom styles.
+ */
+ className?: string
+}
+
+/**
+ * Represents a term in a description list, rendering an HTML
- element.
+ * Used to denote terms, headers, or keys in a semantic way, allowing for flexible styling.
+ */
+export const DescriptionTerm: React.FC = ({ children, className = "" }) => (
+
+
- {children}
+
+)
+
+export const DT = DescriptionTerm
diff --git a/packages/ui-components/src/components/DescriptionTerm/DescriptionTerm.test.tsx b/packages/ui-components/src/components/DescriptionTerm/DescriptionTerm.test.tsx
new file mode 100644
index 0000000000..a20e775f8f
--- /dev/null
+++ b/packages/ui-components/src/components/DescriptionTerm/DescriptionTerm.test.tsx
@@ -0,0 +1,39 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from "react"
+import { render, screen } from "@testing-library/react"
+import { describe, it, expect } from "vitest"
+import { DescriptionTerm } from "./DescriptionTerm.component"
+
+describe("DescriptionTerm", () => {
+ it("renders the children properly", () => {
+ render(Test Term)
+ expect(screen.getByText("Test Term")).toBeInTheDocument()
+ })
+
+ it("applies custom className to the - element", () => {
+ const customClass = "custom-class"
+ render(Styled Term)
+ const dtElement = screen.getByText("Styled Term")
+ expect(dtElement).toHaveClass(customClass)
+ })
+
+ it("renders within a
- element", () => {
+ render(Term Element)
+ const dtElement = screen.getByText("Term Element")
+ expect(dtElement.tagName.toLowerCase()).toBe("dt")
+ })
+
+ it("can render complex children", () => {
+ render(
+
+ Complex Term Content
+
+ )
+ expect(screen.getByText("Complex Term")).toBeInTheDocument()
+ expect(screen.getByText("Content")).toBeInTheDocument()
+ })
+})
diff --git a/packages/ui-components/src/components/DescriptionTerm/description-term.css b/packages/ui-components/src/components/DescriptionTerm/description-term.css
new file mode 100644
index 0000000000..0cbd322783
--- /dev/null
+++ b/packages/ui-components/src/components/DescriptionTerm/description-term.css
@@ -0,0 +1,17 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+.dt {
+ background-color: var(--color-dt-background);
+ border-bottom: 1px solid var(--color-dd-dt-border);
+ font-weight: bold;
+ color: var(--color-dt-text);
+ display: flex;
+ align-items: center;
+ height: 2rem;
+ padding: 0.5rem;
+ white-space: nowrap;
+ gap: 0.25rem;
+}
diff --git a/packages/ui-components/src/components/DescriptionTerm/index.ts b/packages/ui-components/src/components/DescriptionTerm/index.ts
new file mode 100644
index 0000000000..99c3cb2656
--- /dev/null
+++ b/packages/ui-components/src/components/DescriptionTerm/index.ts
@@ -0,0 +1,6 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { DescriptionTerm, type DescriptionTermProps } from "./DescriptionTerm.component"
diff --git a/packages/ui-components/src/components/Modal/Modal.stories.tsx b/packages/ui-components/src/components/Modal/Modal.stories.tsx
index 5e78781455..a3d97f1fb5 100644
--- a/packages/ui-components/src/components/Modal/Modal.stories.tsx
+++ b/packages/ui-components/src/components/Modal/Modal.stories.tsx
@@ -115,6 +115,35 @@ export const SimpleConfirmDialogWithDisabledButtons: Story = {
},
}
+export const DisabledCloseButton: Story = {
+ render: Template,
+ args: {
+ title: "Disabled Close Button Modal",
+ children:
This Modal has a disabled top-right close button.
,
+ disableCloseButton: true,
+ cancelButtonLabel: "Cancel",
+ },
+}
+
+export const NonCloseable: Story = {
+ render: Template,
+ args: {
+ title: "Non-Closeable Modal",
+ children:
+ "Use only if all else fails. If you need to inform users about something, in 99.9% of cases is the better choice.",
+ closeable: false,
+ },
+}
+
+export const CloseOnBackdropClick: Story = {
+ render: Template,
+ args: {
+ title: "Close on Backdrop Click",
+ children: This Modal closes when clicking the backdrop.
,
+ closeOnBackdropClick: true,
+ },
+}
+
export const AutoFocusDialog: Story = {
render: Template,
args: {
@@ -209,35 +238,6 @@ export const XXLWithForm: Story = {
},
}
-export const NonCloseable: Story = {
- render: Template,
- args: {
- title: "Non-Closeable Modal",
- children:
- "Use only if all else fails. If you need to inform users about something, in 99.9% of cases is the better choice.",
- closeable: false,
- },
-}
-
-export const CloseOnBackdropClick: Story = {
- render: Template,
- args: {
- title: "Close on Backdrop Click",
- children: This Modal closes when clicking the backdrop.
,
- closeOnBackdropClick: true,
- },
-}
-
-export const DisabledCloseButton: Story = {
- render: Template,
- args: {
- title: "Disabled Close Button Modal",
- children: This Modal has a disabled top-right close button.
,
- disableCloseButton: true,
- cancelButtonLabel: "Cancel",
- },
-}
-
export const Login: Story = {
render: Template,
args: {
diff --git a/packages/ui-components/src/global.css b/packages/ui-components/src/global.css
index a23bdd9675..ba80e6ef58 100644
--- a/packages/ui-components/src/global.css
+++ b/packages/ui-components/src/global.css
@@ -14,6 +14,9 @@
@import "./components/ThemeToggle/themeToggle.css" layer(utilities);
@import "./components/DataGridRow/data-grid-row.css" layer(utilities);
@import "./components/SideNavigationItem/sidenavigationitem.css" layer(utilities);
+@import "./components/DescriptionList/description-list.css" layer(utilities);
+@import "./components/DescriptionTerm/description-term.css" layer(utilities);
+@import "./components/DescriptionDefinition/description-definition.css" layer(utilities);
:root,
:host {
@@ -406,7 +409,7 @@
--text-color-theme-sidenavigation-item-active: var(--color-sidenavigation-item-active);
/* Component Border Colors: */
- --border-color-theme-default: var(--color-default-border);
+ --border-color-theme-default: var(--color-dd-dt-border);
--border-color-theme-box-default: var(--color-box-border);
@@ -722,6 +725,13 @@
/* LT Box Shadow */
--box-shadow-default: 0 1px 2px 0 rgba(34, 54, 73, 0.3);
--box-shadow-hover: 0 0 0 1px var(--color-color-shadow, rgba(79, 79, 79, 0.3)), 0 2px 8px 0 rgba(0, 0, 0, 0.3);
+ /* LT Description - DescriptionList, DescriptionTerm, DescriptionDefinition */
+ --color-dt-background: var(--color-background-lvl-1);
+ --color-dt-text: var(--color-text-high);
+ --color-dd-background: var(--color-transparent);
+ --color-dd-text: var(--color-text-high);
+ --color-dd-dt-border: var(--color-border-default);
+ --color-border-default: var(--color-juno-grey-blue-3);
}
/* JUNO THEME: DARK MODE */
@@ -960,6 +970,13 @@
/* DT Box Shadow */
--box-shadow-default: 0 1px 2px 0 rgba(34, 54, 73, 0.3);
--box-shadow-hover: 0 1px 2px 0 rgba(34, 54, 73, 0.3);
+ /* DT Description - DescriptionList, DescriptionTerm, DescriptionDefinition */
+ --color-dt-background: var(--color-background-lvl-0);
+ --color-dt-text: var(--color-text-high);
+ --color-dd-background: var(--color-transparent);
+ --color-dd-text: var(--color-text-high);
+ --color-dd-dt-border: var(--color-border-default);
+ --color-border-default: var(--color-juno-grey-light-7);
}
/*
diff --git a/packages/ui-components/src/theme.css b/packages/ui-components/src/theme.css
index d9049faf95..98e1a9c0ce 100644
--- a/packages/ui-components/src/theme.css
+++ b/packages/ui-components/src/theme.css
@@ -398,7 +398,7 @@
--text-color-theme-sidenavigation-item-active: var(--color-sidenavigation-item-active);
/* Component Border Colors: */
- --border-color-theme-default: var(--color-default-border);
+ --border-color-theme-default: var(--color-dd-dt-border);
--border-color-theme-box-default: var(--color-box-border);
@@ -715,6 +715,13 @@
/* LT Box Shadow */
--box-shadow-default: 0 1px 2px 0 rgba(34, 54, 73, 0.3);
--box-shadow-hover: 0 0 0 1px var(--color-color-shadow, rgba(79, 79, 79, 0.3)), 0 2px 8px 0 rgba(0, 0, 0, 0.3);
+ /* LT Description - DescriptionList, DescriptionTerm, DescriptionDefinition */
+ --color-dt-background: var(--color-background-lvl-1);
+ --color-dt-text: var(--color-text-high);
+ --color-dd-background: var(--color-transparent);
+ --color-dd-text: var(--color-text-high);
+ --color-dd-dt-border: var(--color-border-default);
+ --color-border-default: var(--color-juno-grey-blue-3);
}
/* JUNO THEME: DARK MODE */
@@ -953,6 +960,13 @@
/* DT Box Shadow */
--box-shadow-default: 0 1px 2px 0 rgba(34, 54, 73, 0.3);
--box-shadow-hover: 0 1px 2px 0 rgba(34, 54, 73, 0.3);
+ /* DT Description - DescriptionList, DescriptionTerm, DescriptionDefinition */
+ --color-dt-background: var(--color-background-lvl-1);
+ --color-dt-text: var(--color-text-high);
+ --color-dd-background: var(--color-transparent);
+ --color-dd-text: var(--color-text-high);
+ --color-dd-dt-border: var(--color-border-default);
+ --color-border-default: var(--color-juno-grey-light-7);
}
/*