Skip to content

Commit a3a9032

Browse files
committed
add ApplicationViewability component to hide elements for certain media
1 parent 285e4fe commit a3a9032

6 files changed

Lines changed: 156 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React from "react";
2+
import classNames from "classnames";
3+
4+
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
5+
6+
type media = "print" | "screen";
7+
8+
interface ApplicationViewabilityShow {
9+
/**
10+
* Show on media type.
11+
* If used, `hide` cannot be set.
12+
*/
13+
show: media;
14+
hide?: never;
15+
}
16+
17+
interface ApplicationViewabilityHide {
18+
/**
19+
* Hide on media type.
20+
* If used, `show` cannot be set.
21+
*/
22+
hide: media;
23+
show?: never;
24+
}
25+
26+
interface ApplicationViewabilityUndecided {
27+
/**
28+
* Only one child allowed.
29+
* Need to process the `className` property.
30+
*/
31+
children: React.ReactElement<{ className?: string }>;
32+
}
33+
34+
export type ApplicationViewabilityProps = ApplicationViewabilityUndecided &
35+
(ApplicationViewabilityShow | ApplicationViewabilityHide);
36+
37+
/**
38+
* Sets the viewability of the the contained element regarding media.
39+
* Can be used to hide elements, e.g. when the page is printed.
40+
*/
41+
export const ApplicationViewability = ({ children, show, hide }: ApplicationViewabilityProps) => {
42+
if (!show && !hide) {
43+
return children;
44+
}
45+
if (show === hide) {
46+
// eslint-disable-next-line no-console
47+
console.warn("`<ApplicationViewability/>` used with same media type for `hide` and `show`.");
48+
return children;
49+
}
50+
51+
const enhancedClone = React.cloneElement(children, {
52+
className: classNames(children.props.className, {
53+
[`${eccgui}-application__hide--${hide}`]: hide,
54+
[`${eccgui}-application__show--${show}`]: show,
55+
}),
56+
});
57+
58+
return enhancedClone;
59+
};
60+
61+
export default ApplicationViewability;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@media print {
2+
.#{eccgui}-application__hide--print,
3+
.#{eccgui}-application__show--screen {
4+
display: none;
5+
}
6+
}
7+
8+
@media screen {
9+
.#{eccgui}-application__hide--screen,
10+
.#{eccgui}-application__show--print {
11+
display: none;
12+
}
13+
}

src/components/Application/application.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
// @import '~@carbon/react/scss/components/ui-shell/navigation-menu';
1111
@import "content";
1212
@import "dropzone";
13+
@import "viewability";

src/components/Application/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export * from "./ApplicationToolbar";
88
export * from "./ApplicationToolbarSection";
99
export * from "./ApplicationToolbarAction";
1010
export * from "./ApplicationToolbarPanel";
11+
export * from "./ApplicationViewability";
1112
export * from "./helper";
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from "react";
2+
import { LoremIpsum } from "react-lorem-ipsum";
3+
import { Meta, StoryFn } from "@storybook/react";
4+
5+
import { ApplicationViewability } from "../../../index";
6+
export default {
7+
title: "Components/Application/Viewability",
8+
component: ApplicationViewability,
9+
argTypes: {
10+
children: {
11+
control: false,
12+
},
13+
hide: {
14+
control: {
15+
type: "radio",
16+
},
17+
options: ["print", "screen"],
18+
},
19+
show: {
20+
control: {
21+
type: "radio",
22+
},
23+
options: ["print", "screen"],
24+
},
25+
},
26+
} as Meta<typeof ApplicationViewability>;
27+
28+
const TemplateBasicExample: StoryFn<typeof ApplicationViewability> = (args) => <ApplicationViewability {...args} />;
29+
30+
export const Default = TemplateBasicExample.bind({});
31+
Default.args = {
32+
children: (
33+
<div>
34+
<LoremIpsum random={false} />
35+
</div>
36+
),
37+
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from "react";
2+
import { expect } from "@storybook/test";
3+
import { render } from "@testing-library/react";
4+
5+
import "@testing-library/jest-dom";
6+
7+
import { ApplicationViewability, ApplicationViewabilityProps, CLASSPREFIX as eccgui } from "../../../index";
8+
9+
import { Default as ApplicationViewabilityStory } from "./../stories/ApplicationViewability.stories";
10+
11+
const applyViewabilityAndCheckClass = (props: Omit<ApplicationViewabilityProps, "children">) => {
12+
const { container } = render(<ApplicationViewability {...ApplicationViewabilityStory.args} {...props} />);
13+
const element = container.getElementsByClassName(
14+
props.hide ? `${eccgui}-application__hide--${props.hide}` : `${eccgui}-application__show--${props.show}`
15+
);
16+
expect(element.length).toBe(1);
17+
return element;
18+
};
19+
20+
describe("ApplicationViewability", () => {
21+
it("should be visible on `show=screen`", () => {
22+
applyViewabilityAndCheckClass({ show: "screen" });
23+
/**
24+
* Currently we cannot really test visibility via jest if it is defined by S/CSS rules because those styles are not known.
25+
* Looks like it is not too easy to include and test them.
26+
* So we only test for the correct CSS class.
27+
*/
28+
// console.log(window.getComputedStyle(element.item(0)??new Element).getPropertyValue("display"));
29+
// waitFor(() => expect(element).toBeVisible());
30+
});
31+
it("should not be visible on `hide=screen`", () => {
32+
applyViewabilityAndCheckClass({ hide: "screen" });
33+
// waitFor(() => expect(element).not.toBeVisible());
34+
});
35+
it("should be visible on `hide=print`", () => {
36+
applyViewabilityAndCheckClass({ hide: "print" });
37+
// waitFor(() => expect(element).toBeVisible());
38+
});
39+
it("should not be visible on `show=print`", () => {
40+
applyViewabilityAndCheckClass({ show: "print" });
41+
// waitFor(() => expect(element).not.toBeVisible());
42+
});
43+
});

0 commit comments

Comments
 (0)