Skip to content

Commit 2c238de

Browse files
authored
feat: add empty-view package (#362)
Adds empty view package that contains four kind of empty view components. In order to have a consisitent user experience across all our applications, we need to use these common components when there is no data to present. Also adds useMediaQuery hook which is used in `MainEmptyView`. And it will be used when we implement the responsive design.
1 parent 61a78bd commit 2c238de

File tree

24 files changed

+790
-1
lines changed

24 files changed

+790
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The React packages are based on the `@fluentui/react-*` **v9** packages.
1313
- [`@axiscommunications/fluent-stepper`](components/stepper/docs/README.md) - a stepper component for building e.g. wizards
1414
- [`@axiscommunications/fluent-slider`](components/slider/docs/README.md) - various slider components
1515
- [`@axiscommunications/fluent-topbar`](components/topbar/docs/README.md) - top level bar that hosts app and organization selection and menus
16+
- [`@axiscommunications/fluent-empty-view`](components/empty-view/docs/README.md) - Empty view component that displays when there is no data
1617
- [`@axiscommunications/fluent-password-input`](components/password-input/docs/README.md) - a password input that lets you reveal the password
1718
- [`@axiscommunications/fluent-illustrations`](illustrations/docs/README.md) - axis branded illustrations
1819

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": ["../../.eslintrc.json"],
3+
"root": true,
4+
"ignorePatterns": ["lib", "**/*.js"],
5+
"parserOptions": {
6+
"project": ["./tsconfig.src.json"]
7+
}
8+
}

components/empty-view/depcheck.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
ignores:
2+
[
3+
"react-dom",
4+
"typescript",
5+
"@testing-library/jest-dom",
6+
"@griffel/react",
7+
"@vitest/coverage-c8",
8+
]
9+
skip-missing: true
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Empty view - @axiscommunications/fluent-empty-view
2+
3+
Empty view is a component that displays when there is no data.
4+
5+
## How to install
6+
7+
```sh
8+
yarn add @axiscommunications/fluent-empty-view
9+
```
10+
11+
```sh
12+
npm install @axiscommunications/fluent-empty-view
13+
```
14+
15+
## Usage
16+
17+
```ts
18+
import { MainEmptyView, PanelEmptyView, SubmenuEmptyView, DialogEmptyView } from "@axiscommunications/fluent-empty-view";
19+
20+
export const MainEmptyViewExample = () => {
21+
return (
22+
<MainEmptyView
23+
illustration="no-connection"
24+
title="There's no connection"
25+
after={
26+
<Button icon={<ArrowSyncRegular />} onClick={reload}>
27+
"Try again"
28+
</Button>
29+
}
30+
>
31+
"You don't seem to have any connection to the internet. Check your network settings and try again."
32+
</MainEmptyView>
33+
);
34+
};
35+
36+
export const PanelEmptyViewExample = () => {
37+
return (
38+
<PanelEmptyView illustration="add-user-profile" title="No roles have been assigned to the user">
39+
"Assign roles and grant access to users to provide them with the necessary permissions to access resources within the organization."
40+
</PanelEmptyView>
41+
);
42+
};
43+
44+
export const SubmenuEmptyViewExample = () => {
45+
return (
46+
<SubmenuEmptyView illustration="no-match" title="No matching results">
47+
"We couldn't find any folders matching your search."
48+
</SubmenuEmptyView>
49+
);
50+
};
51+
52+
export const DialogEmptyViewExample = () => {
53+
return (
54+
<DialogContent>
55+
<div style={{ height: '240px' }}>
56+
<DialogEmptyView title="No roles">"You haven’t created any roles yet."</DialogEmptyView>
57+
</div>
58+
</DialogContent>
59+
);
60+
};
61+
```
62+

components/empty-view/package.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"name": "@axiscommunications/fluent-empty-view",
3+
"version": "10.3.0",
4+
"description": "Empty view for Fluent UI v9",
5+
"homepage": "https://github.com/AxisCommunications/fluent-components#readme",
6+
"repository": {
7+
"type": "git",
8+
"url": "https://github.com/AxisCommunications/fluent-components.git",
9+
"directory": "components/empty-view"
10+
},
11+
"license": "MIT",
12+
"author": "Axis Communications AB",
13+
"main": "lib/index.js",
14+
"types": "lib/index.d.ts",
15+
"files": [
16+
"lib"
17+
],
18+
"scripts": {
19+
"prebuild": "pnpm run -C ../../illustrations build",
20+
"build": "pnpm prebuild && pnpm build:cjs && pnpm build:esm",
21+
"build:cjs": "tsc --module commonjs --outDir lib/cjs",
22+
"build:esm": "tsc",
23+
"check:unused-deps": "depcheck . --config=depcheck.yml",
24+
"lint": "tsc --noEmit && eslint . --cache"
25+
},
26+
"devDependencies": {
27+
"@types/react": "^18.3.12",
28+
"@types/react-dom": "^18.3.1",
29+
"eslint": "^8.57.1",
30+
"jsdom": "^22.1.0",
31+
"react": "^18.2.0",
32+
"react-dom": "^18.2.0",
33+
"typescript": "^4.5.5"
34+
},
35+
"peerDependencies": {
36+
"@fluentui/react-components": "^9.55.1",
37+
"react": ">=16.8.0 <19.0.0",
38+
"react-dom": ">=16.8.0 <19.0.0"
39+
},
40+
"dependencies": {
41+
"@axiscommunications/fluent-hooks": "workspace: *",
42+
"@axiscommunications/fluent-illustrations": "workspace:*"
43+
},
44+
"publishConfig": {
45+
"registry": "https://npm.pkg.github.com/"
46+
}
47+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import {
2+
AddUserProfileDark,
3+
AddUserProfileLight,
4+
bundleIllustrationSmart,
5+
DataDark,
6+
DataLight,
7+
DevicesDark,
8+
DevicesLight,
9+
EmptyFolderDark,
10+
EmptyFolderLight,
11+
EmptyGeneralDark,
12+
EmptyGeneralLight,
13+
EmptySpaceDark,
14+
EmptySpaceLight,
15+
FileMissingDark,
16+
FileMissingLight,
17+
NoAccessDark,
18+
NoAccessLight,
19+
NoConnectionDark,
20+
NoConnectionLight,
21+
NoContentDark,
22+
NoContentLight,
23+
NoMatchDark,
24+
NoMatchLight,
25+
NoSitesDark,
26+
NoSitesLight,
27+
NotFoundDark,
28+
NotFoundLight,
29+
SettingsDark,
30+
SettingsLight,
31+
SuccessDark,
32+
SuccessLight,
33+
TeamDark,
34+
TeamLight,
35+
UnderConstructionDark,
36+
UnderConstructionLight,
37+
} from "@axiscommunications/fluent-illustrations";
38+
39+
export const Illustration: Record<
40+
string,
41+
ReturnType<typeof bundleIllustrationSmart>
42+
> = {
43+
"add-user-profile": bundleIllustrationSmart(
44+
AddUserProfileDark,
45+
AddUserProfileLight
46+
),
47+
data: bundleIllustrationSmart(DataDark, DataLight),
48+
devices: bundleIllustrationSmart(DevicesDark, DevicesLight),
49+
"empty-folder": bundleIllustrationSmart(EmptyFolderDark, EmptyFolderLight),
50+
"empty-space": bundleIllustrationSmart(EmptySpaceDark, EmptySpaceLight),
51+
"file-missing": bundleIllustrationSmart(FileMissingDark, FileMissingLight),
52+
general: bundleIllustrationSmart(EmptyGeneralDark, EmptyGeneralLight),
53+
"no-access": bundleIllustrationSmart(NoAccessDark, NoAccessLight),
54+
"no-connection": bundleIllustrationSmart(NoConnectionDark, NoConnectionLight),
55+
"no-content": bundleIllustrationSmart(NoContentDark, NoContentLight),
56+
"no-match": bundleIllustrationSmart(NoMatchDark, NoMatchLight),
57+
"no-sites": bundleIllustrationSmart(NoSitesDark, NoSitesLight),
58+
"not-found": bundleIllustrationSmart(NotFoundDark, NotFoundLight),
59+
settings: bundleIllustrationSmart(SettingsDark, SettingsLight),
60+
success: bundleIllustrationSmart(SuccessDark, SuccessLight),
61+
team: bundleIllustrationSmart(TeamDark, TeamLight),
62+
"under-construction": bundleIllustrationSmart(
63+
UnderConstructionDark,
64+
UnderConstructionLight
65+
),
66+
} as const;

components/empty-view/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export {
2+
DialogEmptyView,
3+
MainEmptyView,
4+
PanelEmptyView,
5+
SubmenuEmptyView,
6+
} from "./view";
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { makeStyles, shorthands, tokens } from "@fluentui/react-components";
2+
3+
export const useStyles = makeStyles({
4+
container: {
5+
display: "flex",
6+
flexDirection: "column",
7+
alignItems: "center",
8+
textAlign: "center",
9+
...shorthands.margin("auto"),
10+
height: "100%",
11+
maxWidth: "500px",
12+
},
13+
fixedSpacer: {
14+
height: "60px",
15+
},
16+
spacer: {
17+
flexGrow: 1,
18+
},
19+
illustrationLarge: {
20+
flex: "none",
21+
height: "160px",
22+
width: "230px",
23+
marginBottom: tokens.spacingVerticalS,
24+
},
25+
illustrationMedium: {
26+
flex: "none",
27+
height: "140px",
28+
width: "200px",
29+
marginBottom: tokens.spacingVerticalXS,
30+
},
31+
illustrationSmall: {
32+
flex: "none",
33+
height: "80px",
34+
width: "115px",
35+
marginBottom: tokens.spacingVerticalXS,
36+
},
37+
title: {
38+
color: tokens.colorNeutralForeground2,
39+
textAlign: "center",
40+
marginBottom: tokens.spacingVerticalS,
41+
},
42+
text: {
43+
color: tokens.colorNeutralForeground2,
44+
textAlign: "center",
45+
marginBottom: tokens.spacingVerticalL,
46+
},
47+
after: {
48+
verticalAlign: "middle",
49+
},
50+
});

components/empty-view/src/types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { PropsWithChildren, ReactNode } from "react";
2+
3+
import { Illustration } from "./constants";
4+
5+
export type IllustrationKind = keyof typeof Illustration;
6+
7+
export interface ContentProps {
8+
readonly body: ReactNode;
9+
readonly illustration: IllustrationKind;
10+
readonly title: string;
11+
}
12+
13+
export type EmptyViewProps = PropsWithChildren<{
14+
readonly after?: ReactNode;
15+
readonly illustration: IllustrationKind;
16+
readonly title: string;
17+
}>;

0 commit comments

Comments
 (0)