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

Feature/#28 #32

Merged
merged 6 commits into from
Feb 19, 2024
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
10 changes: 8 additions & 2 deletions .storybook/modes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ export const allModes = {
"light mobile": {
backgrounds: "light",
theme: "light",
viewport: "small",
viewport: {
width: 320,
height: 568,
},
},
"dark desktop": {
backgrounds: "dark",
Expand All @@ -17,6 +20,9 @@ export const allModes = {
"dark mobile": {
backgrounds: "dark",
theme: "dark",
viewport: "small",
viewport: {
width: 320,
height: 568,
},
},
};
7 changes: 0 additions & 7 deletions src/components/data/attributelist/attributelist.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,6 @@ export const AttributeListComponent: Story = {
},
};

export const AttributeListOnMobile: Story = {
...AttributeListComponent,
parameters: {
viewport: { defaultViewport: "mobile1" },
},
};

export const SelectedFieldOnly: Story = {
...AttributeListComponent,
args: {
Expand Down
73 changes: 29 additions & 44 deletions src/components/data/datagrid/datagrid.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import type { Meta, StoryObj } from "@storybook/react";
import React, { useEffect, useState } from "react";

import { sortAttributeDataArray } from "../../../lib/data/attributedata";
import { AttributeData } from "../../../lib/data/attributedata";
import { Page } from "../../page";
import { PaginatorProps } from "../paginator";
import { DataGrid } from "./datagrid";

const meta = {
Expand Down Expand Up @@ -143,19 +142,8 @@ export const SortedDataGrid: Story = {

export const JSONPlaceholderExample: Story = {
args: {
paginatorProps: {
count: 100,
page: 1,
pageSize: 10,
pageSizeOptions: [
{ label: 10 },
{ label: 20 },
{ label: 30 },
{ label: 40 },
{ label: 50 },
],
},
results: [],
showPaginator: true,
sort: true,
title: "Posts",
},
Expand All @@ -165,40 +153,28 @@ export const JSONPlaceholderExample: Story = {
const [pageSize, setPageSize] = useState<number>(
args.paginatorProps?.pageSize || 10,
);
const [results, setResults] = useState(args.results);
const [results, setResults] = useState<AttributeData[]>([]);
const [sort, setSort] = useState<string>("");
const paginatorProps = args.paginatorProps as PaginatorProps;

paginatorProps.pageSize = pageSize;

/**
* Fetches data from jsonplaceholder.typicode.com.
*/
useEffect(() => {
setLoading(true);
const index = page - 1;
const abortController = new AbortController();
const sortKey = sort.replace(/^-/, "");
const sortDirection = sort.startsWith("-") ? "desc" : "asc";

// Process sorting and pagination locally in place for demonstration purposes.
fetch("https://jsonplaceholder.typicode.com/posts", {
signal: abortController.signal,
})
fetch(
`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${pageSize}&_sort=${sortKey}&_order=${sortDirection}`,
{
signal: abortController.signal,
},
)
.then((response) => response.json())
.then((data) => {
// Sort.
const direction = String(sort).startsWith("-") ? "DESC" : "ASC";
const sorted = sort
? sortAttributeDataArray(
data,
String(sort).replace(/^-/, ""),
direction,
)
: data;

// Paginate.
const posts = sorted.slice(
index * pageSize,
index * pageSize + pageSize,
);

setResults(posts);
.then((data: AttributeData[]) => {
setResults(data);
setLoading(false);
});

Expand All @@ -208,15 +184,24 @@ export const JSONPlaceholderExample: Story = {
};
}, [page, pageSize, sort]);

paginatorProps.loading = loading;
paginatorProps.onPageChange = (page) => setPage(page);
paginatorProps.onPageSizeChange = async (pageSize) => setPageSize(pageSize);

return (
<DataGrid
{...args}
count={100}
results={results}
onSort={(field) => setSort(field)}
loading={loading}
page={page}
pageSize={pageSize}
pageSizeOptions={[
{ label: 10 },
{ label: 20 },
{ label: 30 },
{ label: 40 },
{ label: 50 },
]}
onPageChange={setPage}
onPageSizeChange={setPageSize}
/>
);
},
Expand Down
68 changes: 65 additions & 3 deletions src/components/data/datagrid/datagrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,36 @@ export type DataGridProps = {
/** Props for Bool. */
boolProps?: Omit<BoolProps, "value">;

/** If set, the paginator is enabled. */
/**
* If set, the paginator is enabled.
* @see {PaginatorPropsAliases}
*/
paginatorProps?: PaginatorProps;

/** Defaults to whether paginatorProps is set. */
showPaginator?: boolean;

/** Props for P. */
pProps?: PProps;

/** A title for the datagrid. */
title?: string;

onSort?: (sort: string) => Promise<unknown> | void;
} & PaginatorPropsAliases;

/**
* A subset of `PaginatorProps` that act as aliases.
* @see {PaginatorProps}
*/
type PaginatorPropsAliases = {
count?: PaginatorProps["count"];
loading?: PaginatorProps["loading"];
page?: PaginatorProps["page"];
pageSize?: PaginatorProps["pageSize"];
pageSizeOptions?: PaginatorProps["pageSizeOptions"];
onPageChange?: PaginatorProps["onPageChange"];
onPageSizeChange?: PaginatorProps["onPageSizeChange"];
};

/**
Expand All @@ -78,10 +98,18 @@ export type DataGridProps = {
* @param paginatorProps
* @param results
* @param fields
* @param showPaginator
* @param pProps
* @param sort
* @param title
* @param urlFields
* @param count
* @param loading
* @param page
* @param pageSize
* @param pageSizeOptions
* @param onPageChange
* @param onPageSizeChange
* @param props
* @constructor
*/
Expand All @@ -92,11 +120,20 @@ export const DataGrid: React.FC<DataGridProps> = ({
results,
fields = results?.length ? Object.keys(results[0]) : [],
paginatorProps,
showPaginator = Boolean(paginatorProps),
pProps,
sort,
title = "",
urlFields = DEFAULT_URL_FIELDS,
onSort,
// Aliases
count,
loading,
page,
pageSize,
pageSizeOptions,
onPageChange,
onPageSizeChange,
...props
}) => {
const id = useId();
Expand Down Expand Up @@ -141,6 +178,22 @@ export const DataGrid: React.FC<DataGridProps> = ({
const page = paginatorProps?.page;
const key = `sort-${sortField}${sortDirection}-page-${page}-row-$${rowIndex}-column-${fieldIndex}`;

// Run assertions for aliased fields.
if (showPaginator) {
console.assert(
count || paginatorProps?.count,
"Either `count` or `paginatorProps.count` should be set when `showPaginator` is `true`.",
);
console.assert(
page || paginatorProps?.page,
"Either `page` or `paginatorProps.page` should be set when `showPaginator` is `true`.",
);
console.assert(
pageSize || paginatorProps?.pageSize,
"Either `pageSize` or `paginatorProps.pageSize` should be set when `showPaginator` is `true`.",
);
}

return (
<DataGridCell
key={key}
Expand Down Expand Up @@ -236,15 +289,24 @@ export const DataGrid: React.FC<DataGridProps> = ({
</tbody>

{/* Paginator */}
{paginatorProps && (
{showPaginator && (
<tfoot className="mykn-datagrid__foot">
<tr className="mykn-datagrid__row">
<th
className="mykn-datagrid__cell"
colSpan={renderableFields.length}
>
<Toolbar align="end" padH={true}>
<Paginator {...paginatorProps} />
<Paginator
count={count as number}
loading={loading}
page={page as number}
pageSize={pageSize as number}
pageSizeOptions={pageSizeOptions}
onPageChange={onPageChange}
onPageSizeChange={onPageSizeChange}
{...paginatorProps}
/>
</Toolbar>
</th>
</tr>
Expand Down
4 changes: 4 additions & 0 deletions src/components/data/paginator/paginator.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
margin-block-end: 0;
}

&__section--form .mykn-icon:first-child {
color: var(--typography-color-body);
}

@media screen and (max-width: constants.$breakpoint-desktop - 1px) {
&__section--form {
display: none;
Expand Down
21 changes: 14 additions & 7 deletions src/components/data/paginator/paginator.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import { expect, userEvent, waitFor, within } from "@storybook/test";
import React from "react";

import { allModes } from "../../../../.storybook/modes";
import { Page } from "../../page";
import { Paginator } from "./paginator";

Expand Down Expand Up @@ -39,20 +40,26 @@ export const PaginatorComponent: Story = {
},
};

export const PaginatorOnMobile = {
...PaginatorComponent,
parameters: {
viewport: { defaultViewport: "mobile1" },
},
};

export const PaginatorComponentWithSpinner: Story = {
...PaginatorComponent,
args: {
...PaginatorComponent.args,
onPageChange: () => new Promise((resolve) => setTimeout(resolve, 1000)),
},
parameters: {
chromatic: {
modes: {
"light desktop": allModes["light desktop"],
"dark desktop": allModes["dark desktop"],
},
},
},
play: async ({ canvasElement }) => {
// Spinner not supported on mobile.
if (window?.matchMedia("(max-width: 767px)").matches) {
return;
}

const canvas = within(canvasElement);
const pageInput = canvas.getByRole("spinbutton");
const previousButton = canvas.getByLabelText("Previous");
Expand Down
7 changes: 0 additions & 7 deletions src/components/dropdown/dropdown.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,6 @@ export const DropdownComponent: Story = {
},
};

export const DropdownOnMobile: Story = {
...DropdownComponent,
parameters: {
viewport: { defaultViewport: "mobile1" },
},
};

export const ActivateOnHover: Story = {
args: {
activateOnHover: true,
Expand Down
Loading