Skip to content

Commit b2c3a26

Browse files
authored
Merge pull request #360 from eccenca/feature/improvePrintstyles-CMEM-6985
Improve basic print styles (CMEM-6985)
2 parents 4c21036 + 43d8a1b commit b2c3a26

23 files changed

Lines changed: 356 additions & 20 deletions

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,24 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- `<ApplicationViewability />`
12+
- component for hiding elements in specific media
13+
14+
### Changed
15+
16+
- automatically hide user interaction elements in print view
17+
- all application header components except `<WorkspaceHeader />`
18+
- `<CardActions />` and `<CardOptions />`
19+
- `actionOptions` of `<ContentGroup />`
20+
- `actions` of `<Notification />`
21+
- `<OverviewItemActions />`
22+
- automatically serialize display of layout elements in print view
23+
- `<FlexibleLayoutItem />`
24+
- `<GridColumn />`
25+
- `<PropertyName />` and `<PropertyValue />`
26+
927
## [25.0.0] - 2025-12-01
1028

1129
This is a major release, and it might be not compatible with your current usage of our library. Please read about the necessary changes in the section about how to migrate.
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;

src/components/Application/_content.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,10 @@ $ui-02: $eccgui-color-workspace-background !default;
2525
.#{$eccgui}-application__content--railsidebar {
2626
margin-left: mini-units(8);
2727
}
28+
29+
@media print {
30+
.#{$eccgui}-application__content {
31+
padding: $eccgui-size-block-whitespace 0 0 0 !important;
32+
margin: 0;
33+
}
34+
}

src/components/Application/_header.scss

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,10 @@ span.#{$prefix}--header__name {
9898
.#{$eccgui}-application__title--content {
9999
display: inline-block;
100100
overflow: hidden;
101+
text-overflow: ellipsis;
101102
font-size: $eccgui-size-typo-caption;
102103
font-weight: $eccgui-font-weight-bold;
103104
line-height: $eccgui-size-typo-caption-lineheight;
104-
text-overflow: ellipsis;
105105
letter-spacing: $eccgui-font-spacing-wide;
106106
white-space: nowrap;
107107
}
@@ -122,7 +122,7 @@ span.#{$prefix}--header__name {
122122
height: auto;
123123
max-height: mini-units(5);
124124
padding: 0;
125-
margin: mini-units(1.4) 0 mini-units(1.6) 0;
125+
margin: mini-units(1.4) 0 mini-units(1.6);
126126
vertical-align: middle;
127127
}
128128
}
@@ -195,9 +195,9 @@ a.#{$prefix}--header__menu-item:active {
195195
.#{$prefix}--header__action.#{$prefix}--btn--primary:focus,
196196
a.#{$prefix}--header__name:focus,
197197
a.#{$prefix}--header__menu-item:focus {
198-
border: none;
199198
outline: 1px dotted $shell-header-focus;
200199
outline-offset: -1px;
200+
border: none;
201201
box-shadow: none;
202202
}
203203
.#{$prefix}--header__menu-title[aria-expanded="true"] {
@@ -267,3 +267,12 @@ a.#{$prefix}--header__menu-item:focus > svg {
267267
margin: 0;
268268
}
269269
}
270+
271+
@media print {
272+
.#{$eccgui}-application__header {
273+
position: relative;
274+
& > :not(.#{$eccgui}-workspace__header) {
275+
display: none;
276+
}
277+
}
278+
}
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 !important;
5+
}
6+
}
7+
8+
@media screen {
9+
.#{eccgui}-application__hide--screen,
10+
.#{eccgui}-application__show--print {
11+
display: none !important;
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+
});

src/components/Card/card.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,3 +288,9 @@ $eccgui-size-card-spacing: $eccgui-size-typo-base !default;
288288
}
289289
}
290290
}
291+
292+
@media print {
293+
.#{$eccgui}-card__actions {
294+
display: none;
295+
}
296+
}

0 commit comments

Comments
 (0)