-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Section): add Section component
- Loading branch information
Showing
7 changed files
with
424 additions
and
1 deletion.
There are no files selected for viewing
228 changes: 228 additions & 0 deletions
228
packages/core/src/components/Section/Section.stories.tsx
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,228 @@ | ||
import { Meta, StoryObj } from "@storybook/react"; | ||
import { | ||
HvSwitch, | ||
HvTypography, | ||
theme, | ||
} from "@hitachivantara/uikit-react-core"; | ||
import { HvDonutChart } from "@hitachivantara/uikit-react-viz"; | ||
import { Duplicate, Ticket } from "@hitachivantara/uikit-react-icons"; | ||
import { css } from "@emotion/css"; | ||
import { useMemo, useState } from "react"; | ||
import { HvActionsGeneric } from "@core/components/ActionsGeneric"; | ||
import { HvButton } from "@core/components/Button"; | ||
import { HvSection, HvSectionProps } from "./Section"; | ||
|
||
const meta: Meta<typeof HvSection> = { | ||
title: "Widgets/Section", | ||
component: HvSection, | ||
}; | ||
export default meta; | ||
|
||
export const Main: StoryObj<HvSectionProps> = { | ||
args: { | ||
title: "Section Title", | ||
expandable: false, | ||
defaultExpanded: true, | ||
}, | ||
argTypes: { | ||
classes: { control: { disable: true } }, | ||
}, | ||
render: ({ title, ...others }) => { | ||
const wrappedTitle = <HvTypography variant="title4">{title}</HvTypography>; | ||
return ( | ||
<HvSection title={wrappedTitle} {...others}> | ||
<HvTypography> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed tempor | ||
blandit ipsum quis sollicitudin. Aliquam erat volutpat. Praesent nisi | ||
nisl, sodales vitae blandit tincidunt, malesuada id sapien. Nulla | ||
dapibus accumsan est, a pharetra velit consequat et. Nullam iaculis | ||
justo sed urna condimentum ultricies. Integer nec interdum tortor. | ||
Nulla molestie nibh in elit congue malesuada. Donec fringilla volutpat | ||
sapien id maximus. Vestibulum faucibus pellentesque ex, non gravida | ||
dui pharetra quis. Nulla facilisi. Suspendisse erat nisl, mollis ut | ||
est nec, malesuada feugiat orci. Vivamus dignissim nibh id lacinia | ||
vehicula. Nullam lobortis scelerisque dui, non suscipit sapien | ||
tincidunt at. Vivamus ut orci imperdiet, volutpat mauris in, sagittis | ||
mi. Donec pulvinar nibh sit amet neque tristique, vitae gravida ipsum | ||
dapibus. Donec a eros commodo, tincidunt nunc dictum, ullamcorper | ||
quam. | ||
</HvTypography> | ||
</HvSection> | ||
); | ||
}, | ||
}; | ||
|
||
export const WithActions: StoryObj<HvSectionProps> = { | ||
parameters: { | ||
docs: { | ||
description: { | ||
story: | ||
"You can use whatever you want as actions. This example showcases the use of the `HvActionsGeneric` component.", | ||
}, | ||
}, | ||
}, | ||
render: () => { | ||
const classes = { | ||
container: css({ | ||
display: "grid", | ||
gridTemplateColumns: "repeat(2, 1fr)", | ||
gap: theme.space.sm, | ||
}), | ||
root: css({ position: "relative" }), | ||
content: css({ | ||
display: "flex", | ||
flexDirection: "column", | ||
justifyContent: "center", | ||
alignItems: "center", | ||
position: "absolute", | ||
top: "50%", | ||
left: "50%", | ||
transform: "translate(-50%, -50%)", | ||
}), | ||
}; | ||
|
||
const data = { | ||
Country: ["Portugal", "Spain", "France", "Germany"], | ||
"Tickets Sold": [61829, 123948, 253792, 524638], | ||
}; | ||
|
||
const actions = useMemo( | ||
() => ( | ||
<HvActionsGeneric | ||
actions={[ | ||
{ id: "action1", label: "Action 1" }, | ||
{ | ||
id: "action2", | ||
label: "Action 2", | ||
}, | ||
{ | ||
id: "action3", | ||
label: "Action 3", | ||
}, | ||
]} | ||
actionsCallback={(_, __, action) => { | ||
console.log(action.label); | ||
}} | ||
maxVisibleActions={1} | ||
/> | ||
), | ||
[] | ||
); | ||
|
||
return ( | ||
<HvSection | ||
title={ | ||
<HvTypography variant="title4">Section with actions</HvTypography> | ||
} | ||
actions={actions} | ||
> | ||
<div className={classes.container}> | ||
<HvTypography> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed tempor | ||
blandit ipsum quis sollicitudin. Aliquam erat volutpat. Praesent | ||
nisi nisl, sodales vitae blandit tincidunt, malesuada id sapien. | ||
Nulla dapibus accumsan est, a pharetra velit consequat et. Nullam | ||
iaculis justo sed urna condimentum ultricies. Integer nec interdum | ||
tortor. Nulla molestie nibh in elit congue malesuada. Donec | ||
fringilla volutpat sapien id maximus. Vestibulum faucibus | ||
pellentesque ex, non gravida dui pharetra quis. Nulla facilisi. | ||
Suspendisse erat nisl, mollis ut est nec, malesuada feugiat orci. | ||
Vivamus dignissim nibh id lacinia vehicula. | ||
</HvTypography> | ||
|
||
<div className={classes.root}> | ||
<HvDonutChart | ||
data={data} | ||
groupBy="Country" | ||
measure="Tickets Sold" | ||
/> | ||
<div className={classes.content}> | ||
<Ticket iconSize="M" /> | ||
<HvTypography variant="title3"> | ||
{data["Tickets Sold"].reduce((acc, value) => acc + value, 0)} | ||
</HvTypography> | ||
</div> | ||
</div> | ||
</div> | ||
</HvSection> | ||
); | ||
}, | ||
}; | ||
|
||
export const Multiple: StoryObj<HvSectionProps> = { | ||
parameters: { | ||
docs: { | ||
description: { | ||
story: | ||
"This sample showcases as example where multiple sections are used together.", | ||
}, | ||
}, | ||
}, | ||
render: () => { | ||
const [openIds, setOpenIds] = useState<string[]>([]); | ||
const [multiple, setMultiple] = useState(false); | ||
const sections = useMemo( | ||
() => [ | ||
{ id: "1", title: "Section 1", content: "Section 1 content." }, | ||
{ id: "2", title: "Section 2", content: "Section 2 content." }, | ||
{ id: "3", title: "Section 3", content: "Section 3 content." }, | ||
{ id: "4", title: "Section 4", content: "Section 4 content." }, | ||
{ id: "5", title: "Section 5", content: "Section 5 content." }, | ||
{ id: "6", title: "Section 6", content: "Section 6 content." }, | ||
], | ||
[] | ||
); | ||
|
||
const classes = { | ||
section: css({ | ||
marginBottom: theme.space.sm, | ||
}), | ||
}; | ||
|
||
return ( | ||
<> | ||
<HvSwitch | ||
label="Allow multiple sections open" | ||
checked={multiple} | ||
defaultChecked={false} | ||
onChange={(_evt, newChecked) => setMultiple(newChecked)} | ||
/> | ||
{sections.map((s) => ( | ||
<div key={s.id} className={classes.section}> | ||
<HvSection | ||
id={s.id} | ||
title={<HvTypography variant="title4">{s.title}</HvTypography>} | ||
expandable | ||
expanded={openIds.includes(s.id)} | ||
actions={ | ||
<HvButton | ||
variant="primaryGhost" | ||
startIcon={<Duplicate />} | ||
onClick={() => console.log(`Link to ${s.title} copied`)} | ||
> | ||
Copy Link | ||
</HvButton> | ||
} | ||
onToggle={(event, open) => | ||
setOpenIds((ids) => { | ||
if (!multiple) { | ||
if (open) { | ||
return [s.id]; | ||
} | ||
return []; | ||
} | ||
if (open) { | ||
return [...ids, s.id]; | ||
} | ||
return [...ids.filter((i) => i !== s.id)]; | ||
}) | ||
} | ||
> | ||
<HvTypography>{s.content}</HvTypography> | ||
</HvSection> | ||
</div> | ||
))} | ||
</> | ||
); | ||
}, | ||
}; |
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,31 @@ | ||
import { theme } from "@hitachivantara/uikit-styles"; | ||
|
||
import { createClasses } from "@core/utils/classes"; | ||
|
||
export const { staticClasses, useClasses } = createClasses("HvSection", { | ||
root: { | ||
width: "100%", | ||
display: "flex", | ||
flexDirection: "column", | ||
padding: theme.space.sm, | ||
backgroundColor: theme.colors.atmo1, | ||
borderRadius: theme.radii.round, | ||
border: `1px solid ${theme.colors.atmo4}`, | ||
}, | ||
hidden: { height: 0, display: "none" }, | ||
header: { | ||
display: "flex", | ||
alignItems: "center", | ||
position: "relative", | ||
minHeight: theme.sizes.sm, | ||
}, | ||
content: { | ||
marginTop: theme.space.sm, | ||
}, | ||
actions: { | ||
display: "flex", | ||
gap: theme.space.xs, | ||
position: "absolute", | ||
right: 0, | ||
}, | ||
}); |
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,64 @@ | ||
import { fireEvent, render, screen } from "@testing-library/react"; | ||
import { describe, expect, it } from "vitest"; | ||
import { HvButton } from "@core/components"; | ||
import { HvSection } from "./Section"; | ||
|
||
describe("Section", () => { | ||
it("should contain all the steps", () => { | ||
render(<HvSection title="Section Title" />); | ||
expect(screen.getByText("Section Title")).toBeInTheDocument(); | ||
}); | ||
|
||
it("should render the content when it's not expandable", () => { | ||
render( | ||
<HvSection title="Section Title" expanded> | ||
<div>Child Content</div> | ||
</HvSection> | ||
); | ||
expect(screen.getByText("Child Content")).toBeInTheDocument(); | ||
}); | ||
|
||
it("should render the content when it's expandable and is expanded by default", () => { | ||
render( | ||
<HvSection title="Section Title" expandable defaultExpanded> | ||
<div>Child Content</div> | ||
</HvSection> | ||
); | ||
expect(screen.queryByText("Child Content")).toBeInTheDocument(); | ||
}); | ||
|
||
it("should not render the content when it's expandable and is not expanded by default", () => { | ||
render( | ||
<HvSection title="Section Title" expandable defaultExpanded={false}> | ||
<div>Child Content</div> | ||
</HvSection> | ||
); | ||
expect(screen.queryByText("Child Content")).not.toBeVisible(); | ||
}); | ||
|
||
it("should toggle the expanded state when the expand button is clicked", async () => { | ||
render( | ||
<HvSection title="Section Title" expandable defaultExpanded={false}> | ||
<div>Child Content</div> | ||
</HvSection> | ||
); | ||
|
||
expect(screen.queryByText("Child Content")).not.toBeVisible(); | ||
|
||
const expandButton = screen.getByRole("button"); | ||
fireEvent.click(expandButton); | ||
|
||
expect(screen.queryByText("Child Content")).toBeVisible(); | ||
|
||
fireEvent.click(expandButton); | ||
|
||
expect(screen.queryByText("Child Content")).not.toBeVisible(); | ||
}); | ||
|
||
it("should render the actions prop", () => { | ||
const actions = <HvButton>Action 1</HvButton>; | ||
render(<HvSection title="Section Title" actions={actions} />); | ||
|
||
expect(screen.getByText("Action 1")).toBeInTheDocument(); | ||
}); | ||
}); |
Oops, something went wrong.