-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added ResponsiveTable and DataList controls
- Loading branch information
Showing
23 changed files
with
270 additions
and
749 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | ||
# yarn lockfile v1 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { observer } from "mobx-react-lite"; | ||
import React from "react"; | ||
import { PropsWithColumns, ResponsiveColumnDefinition } from "../dataTypes"; | ||
|
||
export interface DataListRowProps<TItem, TContext> extends PropsWithColumns<TItem, TContext> { | ||
item: TItem; | ||
columns: ResponsiveColumnDefinition<TItem, TContext>[]; | ||
} | ||
|
||
interface HeaderProps<TItem, TContext> { | ||
column: ResponsiveColumnDefinition<TItem, TContext>; | ||
context: TContext; | ||
} | ||
|
||
function Header<TItem, TContext>({ column, context }: HeaderProps<TItem, TContext>) { | ||
if (column.headerFormatter) { | ||
return <>{column.headerFormatter({ key: "list-header", column, context })}</>; | ||
} else { | ||
return ( | ||
<th scope="row" className={column.headerClassName}> | ||
{column.responsiveTitleFactory?.(context) ?? column.responsiveTitle ?? column.titleFactory?.(context) ?? column.title} | ||
</th> | ||
); | ||
} | ||
} | ||
|
||
function DataListRowImpl<TItem, TContext>({ item, columns, context }: DataListRowProps<TItem, TContext>) { | ||
return ( | ||
<tbody> | ||
{columns | ||
.filter(x => x.responsiveVisible !== false) | ||
.map((column, i) => { | ||
const key = column.property ?? i; | ||
const value = column.property ? item[column.property] : undefined; | ||
const hasHeader = column.responsiveTitle !== false; | ||
|
||
return ( | ||
<tr key={key}> | ||
{hasHeader && <Header column={column} context={context} />} | ||
<td colSpan={hasHeader ? 1 : 2}> | ||
{column.cellFormatter | ||
? column.cellFormatter({ key, value, item, column, context }) | ||
: column.valueFormatter | ||
? column.valueFormatter({ value, item, column, context }) | ||
: value} | ||
</td> | ||
</tr> | ||
); | ||
})} | ||
</tbody> | ||
); | ||
} | ||
|
||
const DataListRow = observer(DataListRowImpl) as typeof DataListRowImpl; | ||
|
||
export default DataListRow; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { observer } from "mobx-react-lite"; | ||
import React from "react"; | ||
import { DataTableProps } from "../dataTable"; | ||
import { ResponsiveColumnDefinition } from "../dataTypes"; | ||
import DataListRow from "./dataListRow"; | ||
|
||
export interface DataListProps<TItem, TContext> extends DataTableProps<TItem, TContext> { | ||
columns: ResponsiveColumnDefinition<TItem, TContext>[]; | ||
} | ||
|
||
const defaultProps: Omit<Partial<DataListProps<any, any>>, "id" | "columns" | "context"> = {}; | ||
|
||
function DataListImpl<TItem, TContext>(props: DataListProps<TItem, TContext>) { | ||
return ( | ||
<table id={props.id} className={props.className}> | ||
{props.items?.map(item => ( | ||
<DataListRow key={String(item[props.itemKey])} item={item} columns={props.columns} context={props.context} /> | ||
))} | ||
</table> | ||
); | ||
} | ||
|
||
DataListImpl.defaultProps = defaultProps; | ||
const DataList = observer(DataListImpl) as typeof DataListImpl; | ||
|
||
export default DataList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
export { DataListProps, default as DataList } from "./dataList"; | ||
export { DataRepeaterProps, default as DataRepeater } from "./dataRepeater"; | ||
export { DataTableProps, default as DataTable } from "./dataTable"; | ||
export * from "./dataTypes"; | ||
export { default as DataRepeater, DataRepeaterProps } from "./dataRepeater"; | ||
export { default as DataTable, DataTableProps } from "./dataTable"; | ||
export { default as ResponsiveTable, ResponsiveTableProps } from "./responsiveTable"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { observer } from "mobx-react-lite"; | ||
import React, { useEffect, useState } from "react"; | ||
import DataList from "./dataList"; | ||
import DataTable, { DataTableProps } from "./dataTable"; | ||
import { ResponsiveColumnDefinition } from "./dataTypes"; | ||
import { combineClassNames } from "@frui.ts/helpers"; | ||
|
||
function getWidth() { | ||
return document.body.clientWidth || document.documentElement.clientWidth || window.innerWidth; | ||
} | ||
|
||
export type ViewMode = "table" | "list"; | ||
|
||
export interface ResponsiveTableProps<TItem, TContext> extends DataTableProps<TItem, TContext> { | ||
columns: ResponsiveColumnDefinition<TItem, TContext>[]; | ||
widthBreakpoint: number; | ||
listModeClassName?: string; | ||
onModeChanged?: (mode: ViewMode) => void; | ||
} | ||
|
||
const defaultProps: Omit<Partial<ResponsiveTableProps<any, any>>, "id" | "columns" | "context"> = { | ||
widthBreakpoint: 576, | ||
listModeClassName: "table-list-view", | ||
}; | ||
|
||
function ResponsiveTableImpl<TItem, TContext>({ | ||
widthBreakpoint, | ||
listModeClassName, | ||
onModeChanged, | ||
...restProps | ||
}: ResponsiveTableProps<TItem, TContext>) { | ||
const [mode, setMode] = useState<ViewMode>("table"); | ||
|
||
useEffect(() => { | ||
const resizeHandler = () => { | ||
const newMode: ViewMode = getWidth() < widthBreakpoint ? "list" : "table"; | ||
if (newMode !== mode) { | ||
onModeChanged?.(newMode); | ||
setMode(newMode); | ||
} | ||
}; | ||
|
||
resizeHandler(); | ||
window.addEventListener("resize", resizeHandler); | ||
|
||
return () => { | ||
window.removeEventListener("resize", resizeHandler); | ||
}; | ||
}); | ||
|
||
if (mode === "list") { | ||
return <DataList {...restProps} className={combineClassNames(restProps.className, listModeClassName)} />; | ||
} else { | ||
return <DataTable {...restProps} />; | ||
} | ||
} | ||
|
||
ResponsiveTableImpl.defaultProps = defaultProps; | ||
const ResponsiveTable = observer(ResponsiveTableImpl) as typeof ResponsiveTableImpl; | ||
|
||
export default ResponsiveTable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { observer } from "mobx-react-lite"; | ||
import React from "react"; | ||
import { ResponsiveColumnDefinition } from "."; | ||
import "./responsiveTableHeaders.scss"; | ||
|
||
/* | ||
Responsive table headers HOWTO: | ||
0. Customize the breakpoint for collpased view in both ./responsiveTableHeaders.scss and ResponsiveTableHeaders.defaultProps. | ||
1. Wrap the <DataTable> inside <ResponsiveTableHeaders id="someID" columns={columns} context={tableContext}> | ||
2. Use `responsiveTitle` or `responsiveTitleFactory` to customize label used in the collapsed view | ||
3. Use `cellClassName: "responsive-hidden"` on a column you want to hide in the collapsed view | ||
4. Use `cellClassName: "responsive-no-label"` on a column you want to be displayed without a label (and with full width) | ||
5. Use `className="btn-responsive-block"` on a button to be displayed as block only within the collapsed view | ||
*/ | ||
|
||
export interface ResponsiveTableHeadersProps<TItem, TContext> { | ||
id: string; | ||
columns: ResponsiveColumnDefinition<TItem, TContext>[]; | ||
context: TContext; | ||
|
||
className?: string; | ||
mediaQuery?: string; | ||
} | ||
|
||
const defaultProps: Omit<Partial<ResponsiveTableHeadersProps<any, any>>, "id" | "columns" | "context"> = { | ||
mediaQuery: "@media only screen and (max-width: 576px) ", | ||
}; | ||
|
||
function getStyleWithHeaders(id: string, headers: string[], mediaQuery?: string) { | ||
const headerStyles = headers | ||
.map((label, index) => `#${id} td:nth-of-type(${index + 1})::before { content: "${headers[index]}"; }`) | ||
.join(" "); | ||
|
||
return mediaQuery ? `${mediaQuery} { ${headerStyles} }` : headerStyles; | ||
} | ||
|
||
function responsiveTableHeaders<TItem, TContext>(props: React.PropsWithChildren<ResponsiveTableHeadersProps<TItem, TContext>>) { | ||
const columnHeaders: string[] = props.columns.map(column => | ||
column.responsiveTitle === false | ||
? "" | ||
: column.responsiveTitleFactory?.(props.context) ?? | ||
column.responsiveTitle ?? | ||
column.titleFactory?.(props.context)?.toString() ?? | ||
column.title?.toString() ?? | ||
"" | ||
); | ||
|
||
return ( | ||
<> | ||
<style | ||
scoped | ||
dangerouslySetInnerHTML={{ | ||
__html: getStyleWithHeaders(props.id, columnHeaders), | ||
}} | ||
/> | ||
{props.children && ( | ||
<div className={props.className} id={props.id}> | ||
{props.children} | ||
</div> | ||
)} | ||
</> | ||
); | ||
} | ||
|
||
responsiveTableHeaders.defaultProps = defaultProps; | ||
const ResponsiveTableHeaders = observer(responsiveTableHeaders) as typeof responsiveTableHeaders; | ||
|
||
export default ResponsiveTableHeaders; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.