Skip to content

Commit

Permalink
Merge pull request #2119 from chanzuckerberg/release-v15.9.0
Browse files Browse the repository at this point in the history
## [15.9.0](v15.8.0...v15.9.0) (2024-12-20)

[Storybook](https://61313967cde49b003ae2a860-djnybfeowx.chromatic.com/)

### Features

* **VisualPageIndicator:** introduce 1.0 component ([#2118](#2118)) ([3df98a3](3df98a3))
  • Loading branch information
booc0mtaco authored Dec 23, 2024
2 parents 5d175c5 + 51895b2 commit bdff74d
Show file tree
Hide file tree
Showing 17 changed files with 1,109 additions and 771 deletions.
2 changes: 2 additions & 0 deletions .storybook/data/tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@
"eds-theme-color-background-table-row-stripe-1": "#F5FAFF",
"eds-theme-color-background-table-row-stripe-2": "rgb(var(--eds-color-white) / 1)",
"eds-theme-color-background-table-row-selected": "#CEE6FF",
"eds-theme-color-background-visual-page-indicator": "#CFC9C7",
"eds-theme-color-background-visual-page-indicator-current": "#DB458D",
"eds-theme-color-background-utility-base-1": "rgb(var(--eds-color-white) / 1)",
"eds-theme-color-background-utility-base-2": "#FDF9F8",
"eds-theme-color-background-utility-container": "rgb(var(--eds-color-white) / 1)",
Expand Down
614 changes: 307 additions & 307 deletions .yarn/releases/yarn-4.5.1.cjs → .yarn/releases/yarn-4.5.3.cjs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ enableGlobalCache: false

nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-4.5.1.cjs
yarnPath: .yarn/releases/yarn-4.5.3.cjs
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [15.9.0](https://github.com/chanzuckerberg/edu-design-system/compare/v15.8.0...v15.9.0) (2024-12-20)


### Features

* **VisualPageIndicator:** introduce 1.0 component ([#2118](https://github.com/chanzuckerberg/edu-design-system/issues/2118)) ([3df98a3](https://github.com/chanzuckerberg/edu-design-system/commit/3df98a3d21f246c7e56b2a6f8d280baba2b2e5c3))

## [15.8.0](https://github.com/chanzuckerberg/edu-design-system/compare/v15.7.0...v15.8.0) (2024-12-11)


Expand Down
54 changes: 27 additions & 27 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@chanzuckerberg/eds",
"version": "15.8.0",
"version": "15.9.0",
"description": "The React-powered design system library for Chan Zuckerberg Initiative education web applications",
"author": "CZI <[email protected]>",
"homepage": "https://github.com/chanzuckerberg/edu-design-system",
Expand Down Expand Up @@ -97,7 +97,7 @@
"enquirer": "^2.4.1",
"graphemer": "^1.4.0",
"jsonfile": "^6.1.0",
"lilconfig": "^3.1.2",
"lilconfig": "^3.1.3",
"lodash": "^4.17.21",
"ora": "^8.1.1",
"react-beautiful-dnd": "^13.1.1",
Expand All @@ -114,7 +114,7 @@
},
"devDependencies": {
"@babel/preset-env": "^7.26.0",
"@babel/preset-react": "^7.25.9",
"@babel/preset-react": "^7.26.3",
"@babel/preset-typescript": "^7.26.0",
"@chanzuckerberg/axe-storybook-testing": "^8.2.1",
"@chanzuckerberg/eslint-config-edu-js": "^1.1.0",
Expand All @@ -130,67 +130,67 @@
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-typescript": "^12.1.1",
"@size-limit/file": "^8.2.6",
"@storybook/addon-a11y": "^8.4.2",
"@storybook/addon-essentials": "^8.4.2",
"@storybook/addon-interactions": "^8.4.2",
"@storybook/addon-links": "^8.4.2",
"@storybook/addon-mdx-gfm": "^8.4.2",
"@storybook/addon-a11y": "^8.4.7",
"@storybook/addon-essentials": "^8.4.7",
"@storybook/addon-interactions": "^8.4.7",
"@storybook/addon-links": "^8.4.7",
"@storybook/addon-mdx-gfm": "^8.4.7",
"@storybook/addon-styling": "^1.3.7",
"@storybook/addon-webpack5-compiler-babel": "^3.0.3",
"@storybook/manager-api": "^8.4.2",
"@storybook/react": "^8.4.2",
"@storybook/react-webpack5": "^8.4.2",
"@storybook/test": "^8.4.2",
"@storybook/manager-api": "^8.4.7",
"@storybook/react": "^8.4.7",
"@storybook/react-webpack5": "^8.4.7",
"@storybook/test": "^8.4.7",
"@storybook/testing-library": "^0.2.2",
"@storybook/theming": "^8.4.2",
"@storybook/theming": "^8.4.7",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.0.1",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.14",
"@types/jsonfile": "^6",
"@types/lodash": "^4.17.13",
"@types/node": "^20.17.6",
"@types/react": "^18.3.12",
"@types/node": "^20.17.10",
"@types/react": "^18.3.16",
"@types/react-beautiful-dnd": "^13.1.8",
"@types/react-dom": "^18.3.1",
"@types/react-dom": "^18.3.5",
"@types/react-portal": "^4.0.7",
"@types/yargs": "^17.0.33",
"axe-core": "4.10.2",
"chromatic": "^11.18.0",
"chromatic": "^11.20.2",
"codecov": "^3.8.3",
"copyfiles": "^2.4.1",
"eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest": "^28.9.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-storybook": "^0.11.0",
"eslint-plugin-testing-library": "^7.0.0",
"eslint-plugin-testing-library": "^7.1.1",
"husky": "^9.1.7",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-preset-stylelint": "^7.1.0",
"lint-staged": "^15.2.10",
"lint-staged": "^15.2.11",
"plop": "^4.0.1",
"postcss": "^8.4.47",
"postcss": "^8.4.49",
"postcss-cli": "^11.0.0",
"postcss-import": "^16.1.0",
"postcss-mixins": "^11.0.3",
"postcss-nested": "^7.0.2",
"postcss-simple-vars": "^7.0.1",
"prettier": "^3.4.1",
"prettier": "^3.4.2",
"prettier-plugin-tailwindcss": "^0.6.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"rollup": "^4.24.4",
"rollup": "^4.28.1",
"rollup-plugin-postcss": "^4.0.2",
"size-limit": "^8.2.6",
"standard-version": "^9.5.0",
"storybook": "^8.4.2",
"storybook": "^8.4.7",
"style-dictionary": "^3.9.2",
"stylelint": "^16.10.0",
"stylelint": "^16.11.0",
"stylelint-config-recommended": "^14.0.1",
"tailwindcss": "^3.4.14",
"tailwindcss": "^3.4.16",
"ts-jest": "^29.2.5",
"typescript": "^5.7.2"
},
Expand All @@ -203,5 +203,5 @@
"stylelint --fix --allow-empty-input"
]
},
"packageManager": "[email protected].1"
"packageManager": "[email protected].3"
}
34 changes: 34 additions & 0 deletions src/components/VisualPageIndicator/VisualPageIndicator.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*------------------------------------*\
# VISUAL PAGE INDICATOR
\*------------------------------------*/

/**
* VisualPageIndicator
*/
.visual-page-indicator {
display: flex;
justify-content: center;
gap: calc(var(--eds-size-1-and-half) / 16 * 1rem);
}

.visual-page-indicator__item {
--visual-page-indicator-bg: var(--eds-theme-color-background-visual-page-indicator);

height: calc(var(--eds-size-1-and-half) / 16 * 1rem);
width: calc(var(--eds-size-1-and-half) / 16 * 1rem);
border-radius: calc(var(--eds-border-radius-full) * 1px);

transition: background-color ease calc(var(--eds-anim-move-medium) * 1s);

background-color: var(--visual-page-indicator-bg);
}

.visual-page-indicator--active {
--visual-page-indicator-bg: var(--eds-theme-color-background-visual-page-indicator-current);
}

@media screen and (prefers-reduced-motion: reduce) {
.visual-page-indicator__item {
transition: none;
}
}
37 changes: 37 additions & 0 deletions src/components/VisualPageIndicator/VisualPageIndicator.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { StoryObj, Meta } from '@storybook/react';
import type React from 'react';

import { VisualPageIndicator } from './VisualPageIndicator';

export default {
title: 'Components/VisualPageIndicator',
component: VisualPageIndicator,
parameters: {
badges: ['api-1.0', 'theme-2.0'],
},
} as Meta<Args>;

type Args = React.ComponentProps<typeof VisualPageIndicator>;

export const Default: StoryObj<Args> = {
args: {
activePage: 0,
totalPageCount: 6,
},
};

export const MinimumPages: StoryObj<Args> = {
args: {
activePage: 1,
totalPageCount: 2,
},
};

export const FivePages: StoryObj<Args> = {
args: {
activePage: 2,
totalPageCount: 5,
},
};

// TODO: add implementation example showing usage of state with a label for a11y handling
55 changes: 55 additions & 0 deletions src/components/VisualPageIndicator/VisualPageIndicator.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { generateSnapshots } from '@chanzuckerberg/story-utils';
import { render } from '@testing-library/react';

import React from 'react';
import { VisualPageIndicator } from './VisualPageIndicator';

import * as stories from './VisualPageIndicator.stories';
import type { StoryFile } from '../../util/utility-types';

describe('<VisualPageIndicator />', () => {
beforeEach(() => {
// Add in mocks for the calls that can occur in implementation to suppress logging in tests
const consoleMock = jest.spyOn(console, 'error');
const consoleWarnMock = jest.spyOn(console, 'warn');
consoleMock.mockImplementation();
consoleWarnMock.mockImplementation();
});

afterEach(() => {
jest.resetAllMocks();
});

generateSnapshots(stories as StoryFile);

describe('emits messages when misused', () => {
let consoleErrorMock: jest.SpyInstance, consoleWarnMock: jest.SpyInstance;
beforeEach(() => {
consoleWarnMock = jest.spyOn(console, 'warn');
consoleErrorMock = jest.spyOn(console, 'error');
consoleWarnMock.mockImplementation();
consoleErrorMock.mockImplementation();
});

it('errors when active page is above range', () => {
render(<VisualPageIndicator activePage={3} totalPageCount={2} />);

expect(consoleWarnMock).toHaveBeenCalledTimes(0);
expect(consoleErrorMock).toHaveBeenCalledTimes(1);
});

it('errors when active page is below range', () => {
render(<VisualPageIndicator activePage={-1} totalPageCount={2} />);

expect(consoleWarnMock).toHaveBeenCalledTimes(0);
expect(consoleErrorMock).toHaveBeenCalledTimes(1);
});

it('warns when total page count is too small', () => {
render(<VisualPageIndicator activePage={0} totalPageCount={1} />);

expect(consoleWarnMock).toHaveBeenCalledTimes(1);
expect(consoleErrorMock).toHaveBeenCalledTimes(0);
});
});
});
68 changes: 68 additions & 0 deletions src/components/VisualPageIndicator/VisualPageIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import clsx from 'clsx';
import React from 'react';
import { assertEdsUsage } from '../../util/logging';

import styles from './VisualPageIndicator.module.css';

export type VisualPageIndicatorProps = {
// Component API
/**
* CSS class names that can be appended to the component.
*/
className?: string;
// Design API
/**
* Index of the active page in the indicator (0-based).
*/
activePage: number;
/**
* Total number of pages available in this experience
*/
totalPageCount: number;
};

/**
* `import {VisualPageIndicator} from "@chanzuckerberg/eds";`
*
* Static visual cue to help users understand their current position within a series of content or pages.
*/
export const VisualPageIndicator = ({
className,
activePage,
totalPageCount,
...other
}: VisualPageIndicatorProps) => {
const componentClassName = clsx(styles['visual-page-indicator'], className);

assertEdsUsage(
[totalPageCount < 2],
'The minimum allowed count of indicators is 2',
);

assertEdsUsage(
[activePage < 0, activePage > totalPageCount - 1],
`The position in the indicator is out of range: [0, ${totalPageCount - 1}]`,
'error',
);

return (
<ul className={componentClassName} {...other}>
{Array(totalPageCount)
.fill(0)
.map((_, index) => {
return `Page ${index}`;
})
.map((name, index) => {
return (
<li
className={clsx(
styles['visual-page-indicator__item'],
index === activePage && styles['visual-page-indicator--active'],
)}
key={name}
></li>
);
})}
</ul>
);
};
Loading

0 comments on commit bdff74d

Please sign in to comment.