Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

## [Unreleased]

### Added

- `<ApplicationViewability />`
- component for hiding elements in specific media

### Changed

- automatically hide user interaction elements in print view
- all application header components except `<WorkspaceHeader />`
- `<CardActions />` and `<CardOptions />`
- `actionOptions` of `<ContentGroup />`
- `actions` of `<Notification />`
- `<OverviewItemActions />`
- automatically serialize display of layout elements in print view
- `<FlexibleLayoutItem />`
- `<GridColumn />`
- `<PropertyName />` and `<PropertyValue />`

## [25.0.0] - 2025-12-01

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.
Expand Down
61 changes: 61 additions & 0 deletions src/components/Application/ApplicationViewability.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from "react";
import classNames from "classnames";

import { CLASSPREFIX as eccgui } from "../../configuration/constants";

type media = "print" | "screen";

interface ApplicationViewabilityShow {
/**
* Show on media type.
* If used, `hide` cannot be set.
*/
show: media;
hide?: never;
}

interface ApplicationViewabilityHide {
/**
* Hide on media type.
* If used, `show` cannot be set.
*/
hide: media;
show?: never;
}

interface ApplicationViewabilityUndecided {
/**
* Only one child allowed.
* Need to process the `className` property.
*/
children: React.ReactElement<{ className?: string }>;
}

export type ApplicationViewabilityProps = ApplicationViewabilityUndecided &
(ApplicationViewabilityShow | ApplicationViewabilityHide);

/**
* Sets the viewability of the the contained element regarding media.
* Can be used to hide elements, e.g. when the page is printed.
*/
export const ApplicationViewability = ({ children, show, hide }: ApplicationViewabilityProps) => {
if (!show && !hide) {
return children;
}
if (show === hide) {
// eslint-disable-next-line no-console
console.warn("`<ApplicationViewability/>` used with same media type for `hide` and `show`.");
return children;
}

const enhancedClone = React.cloneElement(children, {
className: classNames(children.props.className, {
[`${eccgui}-application__hide--${hide}`]: hide,
[`${eccgui}-application__show--${show}`]: show,
}),
});

return enhancedClone;
};

export default ApplicationViewability;
7 changes: 7 additions & 0 deletions src/components/Application/_content.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,10 @@ $ui-02: $eccgui-color-workspace-background !default;
.#{$eccgui}-application__content--railsidebar {
margin-left: mini-units(8);
}

@media print {
.#{$eccgui}-application__content {
padding: $eccgui-size-block-whitespace 0 0 0 !important;
margin: 0;
}
}
15 changes: 12 additions & 3 deletions src/components/Application/_header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ span.#{$prefix}--header__name {
.#{$eccgui}-application__title--content {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
font-size: $eccgui-size-typo-caption;
font-weight: $eccgui-font-weight-bold;
line-height: $eccgui-size-typo-caption-lineheight;
text-overflow: ellipsis;
letter-spacing: $eccgui-font-spacing-wide;
white-space: nowrap;
}
Expand All @@ -122,7 +122,7 @@ span.#{$prefix}--header__name {
height: auto;
max-height: mini-units(5);
padding: 0;
margin: mini-units(1.4) 0 mini-units(1.6) 0;
margin: mini-units(1.4) 0 mini-units(1.6);
vertical-align: middle;
}
}
Expand Down Expand Up @@ -195,9 +195,9 @@ a.#{$prefix}--header__menu-item:active {
.#{$prefix}--header__action.#{$prefix}--btn--primary:focus,
a.#{$prefix}--header__name:focus,
a.#{$prefix}--header__menu-item:focus {
border: none;
outline: 1px dotted $shell-header-focus;
outline-offset: -1px;
border: none;
box-shadow: none;
}
.#{$prefix}--header__menu-title[aria-expanded="true"] {
Expand Down Expand Up @@ -267,3 +267,12 @@ a.#{$prefix}--header__menu-item:focus > svg {
margin: 0;
}
}

@media print {
.#{$eccgui}-application__header {
position: relative;
& > :not(.#{$eccgui}-workspace__header) {
display: none;
}
}
}
13 changes: 13 additions & 0 deletions src/components/Application/_viewability.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@media print {
.#{eccgui}-application__hide--print,
.#{eccgui}-application__show--screen {
display: none !important;
}
}

@media screen {
.#{eccgui}-application__hide--screen,
.#{eccgui}-application__show--print {
display: none !important;
}
}
1 change: 1 addition & 0 deletions src/components/Application/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
// @import '~@carbon/react/scss/components/ui-shell/navigation-menu';
@import "content";
@import "dropzone";
@import "viewability";
1 change: 1 addition & 0 deletions src/components/Application/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export * from "./ApplicationToolbar";
export * from "./ApplicationToolbarSection";
export * from "./ApplicationToolbarAction";
export * from "./ApplicationToolbarPanel";
export * from "./ApplicationViewability";
export * from "./helper";
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react";
import { LoremIpsum } from "react-lorem-ipsum";
import { Meta, StoryFn } from "@storybook/react";

import { ApplicationViewability } from "../../../index";
export default {
title: "Components/Application/Viewability",
component: ApplicationViewability,
argTypes: {
children: {
control: false,
},
hide: {
control: {
type: "radio",
},
options: ["print", "screen"],
},
show: {
control: {
type: "radio",
},
options: ["print", "screen"],
},
},
} as Meta<typeof ApplicationViewability>;

const TemplateBasicExample: StoryFn<typeof ApplicationViewability> = (args) => <ApplicationViewability {...args} />;

export const Default = TemplateBasicExample.bind({});
Default.args = {
children: (
<div>
<LoremIpsum random={false} />
</div>
),
};
43 changes: 43 additions & 0 deletions src/components/Application/tests/ApplicationViewability.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import { expect } from "@storybook/test";
import { render } from "@testing-library/react";

import "@testing-library/jest-dom";

import { ApplicationViewability, ApplicationViewabilityProps, CLASSPREFIX as eccgui } from "../../../index";

import { Default as ApplicationViewabilityStory } from "./../stories/ApplicationViewability.stories";

const applyViewabilityAndCheckClass = (props: Omit<ApplicationViewabilityProps, "children">) => {
const { container } = render(<ApplicationViewability {...ApplicationViewabilityStory.args} {...props} />);
const element = container.getElementsByClassName(
props.hide ? `${eccgui}-application__hide--${props.hide}` : `${eccgui}-application__show--${props.show}`
);
expect(element.length).toBe(1);
return element;
};

describe("ApplicationViewability", () => {
it("should be visible on `show=screen`", () => {
applyViewabilityAndCheckClass({ show: "screen" });
/**
* Currently we cannot really test visibility via jest if it is defined by S/CSS rules because those styles are not known.
* Looks like it is not too easy to include and test them.
* So we only test for the correct CSS class.
*/
// console.log(window.getComputedStyle(element.item(0)??new Element).getPropertyValue("display"));
// waitFor(() => expect(element).toBeVisible());
});
it("should not be visible on `hide=screen`", () => {
applyViewabilityAndCheckClass({ hide: "screen" });
// waitFor(() => expect(element).not.toBeVisible());
});
it("should be visible on `hide=print`", () => {
applyViewabilityAndCheckClass({ hide: "print" });
// waitFor(() => expect(element).toBeVisible());
});
it("should not be visible on `show=print`", () => {
applyViewabilityAndCheckClass({ show: "print" });
// waitFor(() => expect(element).not.toBeVisible());
});
});
6 changes: 6 additions & 0 deletions src/components/Card/card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,9 @@ $eccgui-size-card-spacing: $eccgui-size-typo-base !default;
}
}
}

@media print {
.#{$eccgui}-card__actions {
display: none;
}
}
16 changes: 14 additions & 2 deletions src/components/Checkbox/checkbox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ $control-indicator-spacing: $eccgui-size-inline-whitespace !default;
// $switch-background-color-active: rgba($gray1, 0.5) !default;
// $switch-background-color-disabled: $button-background-color-disabled !default;
$switch-checked-background-color: $eccgui-color-accent !default;
$switch-checked-background-color-hover: eccgui-color-rgba($switch-checked-background-color, $eccgui-opacity-narrow) !default;
$switch-checked-background-color-hover: eccgui-color-rgba(
$switch-checked-background-color,
$eccgui-opacity-narrow
) !default;
$switch-checked-background-color-active: $switch-checked-background-color-hover !default;
$switch-checked-background-color-disabled: eccgui-color-rgba($switch-checked-background-color, $eccgui-opacity-disabled) !default;
$switch-checked-background-color-disabled: eccgui-color-rgba(
$switch-checked-background-color,
$eccgui-opacity-disabled
) !default;

@import "~@blueprintjs/core/src/components/forms/controls"; // Checkbox, Radio, Switch

Expand Down Expand Up @@ -73,3 +79,9 @@ $switch-checked-background-color-disabled: eccgui-color-rgba($switch-checked-bac
display: inline-block;
vertical-align: text-top;
}

@media print {
.#{$ns}-control {
print-color-adjust: exact;
}
}
9 changes: 9 additions & 0 deletions src/components/ContentGroup/_contentgroup.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,12 @@ $eccgui-color-scontentgroup-border-sub: eccgui-color-rgba(
flex-shrink: 1;
width: 100%;
}

@media print {
.#{$eccgui}-contentgroup__header__options {
display: none;
}
.#{$eccgui}-contentgroup--border-sub::after {
print-color-adjust: exact;
}
}
6 changes: 6 additions & 0 deletions src/components/Depiction/depiction.scss
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,9 @@ $eccgui-size-depiction-border-radius: $pt-border-radius !default;
position: fixed;
left: -5000rem;
}

@media print {
.#{$eccgui}-depiction {
print-color-adjust: exact;
}
}
16 changes: 16 additions & 0 deletions src/components/FlexibleLayout/flexiblelayout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,19 @@
flex-basis: auto;
}
}

@media print {
.#{$eccgui}-flexible__container,
.#{$eccgui}-flexible__item {
position: relative;
display: block;
width: auto;
height: auto;
padding: 0;
margin: 0;

&:is(.#{$eccgui}-flexible__item) {
margin-bottom: $eccgui-size-block-whitespace;
}
}
}
17 changes: 17 additions & 0 deletions src/components/Grid/grid.scss
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,20 @@ $grid-gutter: rem($eccgui-size-grid-gutter);
flex-wrap: nowrap;
}
}

@media print {
.#{$eccgui}-grid,
.#{$eccgui}-grid__row,
.#{$eccgui}-grid__column {
position: relative;
display: block;
width: auto;
height: auto;
padding: 0;
margin: 0;

&:is(.#{$eccgui}-grid__column) {
margin-bottom: $eccgui-size-block-whitespace;
}
}
}
17 changes: 10 additions & 7 deletions src/components/Grid/stories/Grid.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ export default {
subcomponents: { GridRow, GridColumn },
argTypes: {
children: {
control: "none",
control: false,
},
},
decorators: [
(Story) => (
<div style={{ minHeight: "30vh", position: "relative" }}>
<Story />
</div>
),
],
} as Meta<typeof Grid>;

const Template: StoryFn<typeof Grid> = (args) => (
<div style={{ minHeight: "30vh", position: "relative" }}>
<Grid {...args} />
</div>
);
const Template: StoryFn<typeof Grid> = (args) => <Grid {...args} />;

export const Default = Template.bind({});
Default.args = {
children: <GridRow {...RowExample.args} verticalStretched />,
children: [<GridRow {...RowExample.args} verticalStretched />, <GridRow {...RowExample.args} verticalStretched />],
verticalStretchable: true,
};
Loading