Skip to content

Commit 72c5943

Browse files
authored
fix(scrim): Responsively set the scale of the loading spinner (#7182)
**Related Issue:** #7147 ## Summary - Updates the scrim to set the scale of the internal loading spinner based on the scrim size. - Scrim is now responsive with a resize observer. - Breakpoints added based on design. These could maybe go into some kind of component token in the future. - Breakpoint is based on the minimum value of width or height. - Adds test
1 parent 6191788 commit 72c5943

File tree

3 files changed

+110
-8
lines changed

3 files changed

+110
-8
lines changed

packages/calcite-components/src/components/scrim/resources.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,9 @@ export const CSS = {
22
scrim: "scrim",
33
content: "content"
44
};
5+
6+
export const BREAKPOINTS = {
7+
s: 72, // Less than 72px.
8+
// medium is assumed default.
9+
l: 480 // Greater than or equal to 480px.
10+
};

packages/calcite-components/src/components/scrim/scrim.e2e.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { newE2EPage } from "@stencil/core/testing";
22
import { accessible, defaults, hidden, renders, t9n } from "../../tests/commonTests";
3-
import { CSS } from "./resources";
3+
import { BREAKPOINTS, CSS } from "./resources";
4+
import { html } from "../../../support/formatting";
5+
import { Scale } from "../interfaces";
46

57
describe("calcite-scrim", () => {
68
describe("renders", () => {
@@ -107,6 +109,65 @@ describe("calcite-scrim", () => {
107109
expect(contentNode).not.toBeNull();
108110
});
109111

112+
describe("Responsive loading spinner", () => {
113+
const testValues: { width: number; height: number; scale: Scale }[] = [
114+
{
115+
width: BREAKPOINTS.s - 1,
116+
height: 800,
117+
scale: "s"
118+
},
119+
{
120+
width: 800,
121+
height: BREAKPOINTS.s - 1,
122+
scale: "s"
123+
},
124+
{
125+
width: BREAKPOINTS.l - 1,
126+
height: 800,
127+
scale: "m"
128+
},
129+
{
130+
width: 800,
131+
height: BREAKPOINTS.l - 1,
132+
scale: "m"
133+
},
134+
{
135+
width: BREAKPOINTS.l,
136+
height: 800,
137+
scale: "l"
138+
},
139+
{
140+
width: 800,
141+
height: BREAKPOINTS.l,
142+
scale: "l"
143+
}
144+
];
145+
146+
testValues.forEach((scaleSize) => {
147+
it(`should have a scale="${scaleSize.scale}" loading spinner`, async () => {
148+
const page = await newE2EPage();
149+
await page.setContent(html`<style>
150+
.scrim-container {
151+
position: relative;
152+
overflow: auto;
153+
width: ${scaleSize.width}px;
154+
height: ${scaleSize.height}px;
155+
}
156+
</style>
157+
<div class="scrim-container">
158+
<calcite-scrim loading><p>I'm a panel that is loading.</p></calcite-scrim>
159+
</div>`);
160+
await page.waitForChanges();
161+
162+
const loader = await page.find("calcite-scrim >>> calcite-loader");
163+
164+
expect(loader).toBeDefined();
165+
expect(await loader.isVisible()).toBe(true);
166+
expect(await loader.getProperty("scale")).toBe(scaleSize.scale);
167+
});
168+
});
169+
});
170+
110171
describe("CSS properties for light/dark modes", () => {
111172
const scrimSnippet = `
112173
<div style="position: relative; width: 200px; height: 200px; overflow: auto;">

packages/calcite-components/src/components/scrim/scrim.tsx

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import {
88
updateMessages
99
} from "../../utils/t9n";
1010
import { ScrimMessages } from "./assets/scrim/t9n";
11-
import { CSS } from "./resources";
11+
import { CSS, BREAKPOINTS } from "./resources";
12+
import { createObserver } from "../../utils/observers";
13+
import { Scale } from "../interfaces";
1214

1315
/**
1416
* @slot - A slot for adding custom content, primarily loading information.
@@ -58,11 +60,11 @@ export class Scrim implements LocalizedComponent, T9nComponent {
5860

5961
@Element() el: HTMLCalciteScrimElement;
6062

61-
// --------------------------------------------------------------------------
62-
//
63-
// Private State / Properties
64-
//
65-
// --------------------------------------------------------------------------
63+
resizeObserver = createObserver("resize", () => this.handleResize());
64+
65+
loaderEl: HTMLCalciteLoaderElement;
66+
67+
@State() loaderScale: Scale;
6668

6769
@State() defaultMessages: ScrimMessages;
6870

@@ -102,7 +104,9 @@ export class Scrim implements LocalizedComponent, T9nComponent {
102104
render(): VNode {
103105
const { el, loading, messages } = this;
104106
const hasContent = el.innerHTML.trim().length > 0;
105-
const loaderNode = loading ? <calcite-loader label={messages.loading} /> : null;
107+
const loaderNode = loading ? (
108+
<calcite-loader label={messages.loading} ref={this.storeLoaderEl} scale={this.loaderScale} />
109+
) : null;
106110
const contentNode = hasContent ? (
107111
<div class={CSS.content}>
108112
<slot />
@@ -116,4 +120,35 @@ export class Scrim implements LocalizedComponent, T9nComponent {
116120
</div>
117121
);
118122
}
123+
124+
// --------------------------------------------------------------------------
125+
//
126+
// Private Methods
127+
//
128+
// --------------------------------------------------------------------------
129+
130+
private storeLoaderEl = (el: HTMLCalciteLoaderElement): void => {
131+
this.loaderEl = el;
132+
this.handleResize();
133+
};
134+
135+
private getScale(size: number): Scale {
136+
if (size < BREAKPOINTS.s) {
137+
return "s";
138+
} else if (size >= BREAKPOINTS.l) {
139+
return "l";
140+
} else {
141+
return "m";
142+
}
143+
}
144+
145+
private handleResize(): void {
146+
const { loaderEl, el } = this;
147+
148+
if (!loaderEl) {
149+
return;
150+
}
151+
152+
this.loaderScale = this.getScale(Math.min(el.clientHeight, el.clientWidth) ?? 0);
153+
}
119154
}

0 commit comments

Comments
 (0)