Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: responsive screen size hook and css var #548

Merged
merged 21 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ function DarkPanel(props) {
export const decorators = [
(Story, Context) => {
if (Context.story.includes("Interactions")) {
return <Story theme="light" />;
return (
<GlobalStyles>
<Story theme="light" />;
</GlobalStyles>
);
}

return (
Expand Down
38 changes: 38 additions & 0 deletions build.washingtonpost.com/docs/foundations/breakpoints.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,41 @@ export default function Example() {
);
}
```

### Using the Responsive Screen Size React Hook

The `useResponsiveScreenSize` hook can be used to get the current screen size and use it in your components.

<Alert variant="info">
<p>
The hook is only available in the browser and will return{" "}
<code>unknown</code> on the server.
</p>
</Alert>

#### An example using the hook

Our Spectrum render engine uses the hook to render a drawer on small screens and a dialog on larger screens. This is a simplified version of the code used in the Spectrum render engine.

```jsx
import {
useResponsiveScreenSize,
screenSizesEnums,
Dialog,
Drawer,
} from "@washingtonpost/wpds-ui-kit";

export default function Example() {
const screenSize = useResponsiveScreenSize();

return (
<div>
{screenSize === screenSizesEnums.small ? (
<Drawer>{/* Drawer content */}</Drawer>
) : (
<Dialog>{/* Dialog content */}</Dialog>
)}
</div>
);
}
```
1 change: 0 additions & 1 deletion build.washingtonpost.com/pages/_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { useRouter } from "next/router";
import { darkModeStyles } from "~/components/DarkModeStyles";
import { PageLayout } from "~/components/Layout";
import SEO from "../next-seo.config";
import "@washingtonpost/wpds-tokens/dist/styles.css";
import "../public/global.css";

const globalTextStyles = globalCss({
Expand Down
4 changes: 2 additions & 2 deletions build.washingtonpost.com/services/getContributors.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ export const getContributors = async () => {
.concat({
name: "baconjulie",
avatar: "https://avatars.githubusercontent.com/u/5865863?v=4",
url: "https://github.com/baconjulie"
url: "https://github.com/baconjulie",
})
.concat({
name: "erikreyna",
avatar: "https://avatars.githubusercontent.com/u/2431045?v=4",
url: "https://github.com/erikreyna"
url: "https://github.com/erikreyna",
})
// sort alphabetically
.sort((a, b) => (a.name > b.name ? 1 : -1))
Expand Down
1 change: 1 addition & 0 deletions ui/theme/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./stitches.config";
export * from "./useResponsiveScreenSize";
19 changes: 19 additions & 0 deletions ui/theme/src/stitches.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,25 @@ export const globalStyles = globalCss({
":root": {
"--base": `${tokens.base}`,
lineHeight: "$meta",
$$screenSize: "unknown",
"@sm": {
$$screenSize: "small",
},
"@md": {
$$screenSize: "medium",
},
"@lg": {
$$screenSize: "large",
},
"@xl": {
$$screenSize: "xlarge",
},
"@xxl": {
$$screenSize: "xxlarge",
},
"@minXxl": {
$$screenSize: "infinity", // temporary name cause we don't have a name for this
},
},
"*": {
boxSizing: "border-box",
Expand Down
214 changes: 214 additions & 0 deletions ui/theme/src/useResponsiveScreenSize.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import React from "react";

Check failure on line 1 in ui/theme/src/useResponsiveScreenSize.stories.tsx

View workflow job for this annotation

GitHub Actions / Validate

Default React import not allowed
import { Meta, Story } from "@storybook/react";
import { within } from "@storybook/testing-library";
import { expect } from "@storybook/jest";
import { Box } from "@washingtonpost/wpds-box";
import { useResponsiveScreenSize } from "./useResponsiveScreenSize";

const allModes = {
sm: {
viewport: "small",
},
md: {
viewport: "medium",
},
lg: {
viewport: "large",
},
xl: {
viewport: "xlarge",
},
xxl: {
viewport: "xxlarge",
},
};

export default {
title: "useResponsiveScreenSize",
parameters: {
viewport: {
viewports: {
small: {
name: "Small",
styles: {
height: "590px",
width: "767px",
},
type: "mobile",
},
medium: {
name: "Medium",
styles: {
height: "590px",
width: "900px",
},
type: "tablet",
},
large: {
name: "Large",
styles: {
height: "590px",
width: "1024px",
},
type: "tablet",
},
xlarge: {
name: "Extra Large",
styles: {
height: "590px",
width: "1280px",
},
type: "desktop",
},
xxlarge: {
name: "Extra Extra Large",
styles: {
height: "590px",
width: "1440px",
},
type: "desktop",
},
},
defaultViewport: "responsive",
},
},
} as Meta;

const Template: Story<typeof Box> = () => {
const screenSize = useResponsiveScreenSize();

return (
<div>
<h1>Responsive Screen Size</h1>
<p>Current screen size: {screenSize}</p>
</div>
);
};

// Function to emulate pausing between interactions
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

export const InteractionsSmall = Template.bind({});

InteractionsSmall.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
await sleep(500);

const screenSize = canvas.getByText("Current screen size: small");
expect(screenSize).toBeTruthy();

Check failure on line 100 in ui/theme/src/useResponsiveScreenSize.stories.tsx

View workflow job for this annotation

GitHub Actions / Validate

Prefer .toBeInTheDocument() for asserting DOM node existence
};

InteractionsSmall.parameters = {
viewport: {
defaultViewport: "small",
},
chromatic: {
modes: {
mobile: allModes["sm"],
},
},
};

export const InteractionsMedium = Template.bind({});
InteractionsMedium.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
await sleep(500);

const screenSize = canvas.getByText("Current screen size: medium");
expect(screenSize).toBeTruthy();

Check failure on line 120 in ui/theme/src/useResponsiveScreenSize.stories.tsx

View workflow job for this annotation

GitHub Actions / Validate

Prefer .toBeInTheDocument() for asserting DOM node existence
};

InteractionsMedium.parameters = {
viewport: {
defaultViewport: "medium",
},
chromatic: {
modes: {
tablet: allModes["md"],
},
},
};

export const InteractionsLarge = Template.bind({});
InteractionsLarge.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
await sleep(500);

const screenSize = canvas.getByText("Current screen size: large");
expect(screenSize).toBeTruthy();

Check failure on line 140 in ui/theme/src/useResponsiveScreenSize.stories.tsx

View workflow job for this annotation

GitHub Actions / Validate

Prefer .toBeInTheDocument() for asserting DOM node existence
};

InteractionsLarge.parameters = {
viewport: {
defaultViewport: "large",
},
chromatic: {
modes: {
tablet: allModes["lg"],
},
},
};

export const InteractionsXLarge = Template.bind({});
InteractionsXLarge.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
await sleep(500);

const screenSize = canvas.getByText("Current screen size: xlarge");
expect(screenSize).toBeTruthy();

Check failure on line 160 in ui/theme/src/useResponsiveScreenSize.stories.tsx

View workflow job for this annotation

GitHub Actions / Validate

Prefer .toBeInTheDocument() for asserting DOM node existence
};

InteractionsXLarge.parameters = {
viewport: {
defaultViewport: "xlarge",
},
chromatic: {
modes: {
desktop: allModes["xl"],
},
},
};

export const InteractionsXXLarge = Template.bind({});

InteractionsXXLarge.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
await sleep(500);

const screenSize = canvas.getByText("Current screen size: xxlarge");
expect(screenSize).toBeTruthy();

Check failure on line 181 in ui/theme/src/useResponsiveScreenSize.stories.tsx

View workflow job for this annotation

GitHub Actions / Validate

Prefer .toBeInTheDocument() for asserting DOM node existence
};

InteractionsXXLarge.parameters = {
viewport: {
defaultViewport: "xxlarge",
},
chromatic: {
modes: {
desktop: allModes["xxl"],
},
},
};

export const InteractionsInfinity = Template.bind({});

InteractionsInfinity.play = async ({ canvasElement }) => {
const canvas = within(canvasElement);
await sleep(500);

const screenSize = canvas.getByText("Current screen size: infinity");
expect(screenSize).toBeTruthy();

Check failure on line 202 in ui/theme/src/useResponsiveScreenSize.stories.tsx

View workflow job for this annotation

GitHub Actions / Validate

Prefer .toBeInTheDocument() for asserting DOM node existence
artmsilva marked this conversation as resolved.
Show resolved Hide resolved
};

InteractionsInfinity.parameters = {
viewport: {
defaultViewport: "responsive",
},
chromatic: {
modes: {
mobile: allModes["sm"],
artmsilva marked this conversation as resolved.
Show resolved Hide resolved
},
},
};