Skip to content
Open
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: 6 additions & 4 deletions src/ColumnIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as Actions from "./actions";
import useDispatch from "./use-dispatch";
import useSelector from "./use-selector";

const ColumnIndicator: Types.ColumnIndicatorComponent = ({
const ColumnIndicator: Types.ColumnIndicatorComponent<string> = ({
column,
label,
selected,
Expand All @@ -32,9 +32,11 @@ const ColumnIndicator: Types.ColumnIndicatorComponent = ({

export default ColumnIndicator;

export const enhance = (
ColumnIndicatorComponent: Types.ColumnIndicatorComponent
): React.FC<Omit<Types.ColumnIndicatorProps, "selected" | "onSelect">> => {
export const enhance = <Label,>(
ColumnIndicatorComponent: Types.ColumnIndicatorComponent<Label>
): React.FC<
Omit<Types.ColumnIndicatorProps<Label>, "selected" | "onSelect">
> => {
return function ColumnIndicatorWrapper(props) {
const dispatch = useDispatch();
const selectEntireColumn = React.useCallback(
Expand Down
8 changes: 4 additions & 4 deletions src/RowIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as Types from "./types";
import useDispatch from "./use-dispatch";
import useSelector from "./use-selector";

const RowIndicator: Types.RowIndicatorComponent = ({
const RowIndicator: Types.RowIndicatorComponent<string> = ({
row,
label,
selected,
Expand Down Expand Up @@ -33,9 +33,9 @@ const RowIndicator: Types.RowIndicatorComponent = ({

export default RowIndicator;

export const enhance = (
RowIndicatorComponent: Types.RowIndicatorComponent
): React.FC<Omit<Types.RowIndicatorProps, "selected" | "onSelect">> => {
export const enhance = <Label,>(
RowIndicatorComponent: Types.RowIndicatorComponent<Label>
): React.FC<Omit<Types.RowIndicatorProps<Label>, "selected" | "onSelect">> => {
return function RowIndicatorWrapper(props) {
const dispatch = useDispatch();
const selected = useSelector((state) =>
Expand Down
36 changes: 27 additions & 9 deletions src/Spreadsheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ import Copied from "./Copied";
import "./Spreadsheet.css";

/** The Spreadsheet component props */
export type Props<CellType extends Types.CellBase> = {
export type Props<
CellType extends Types.CellBase,
RowIndicatorLabel = string,
ColumnIndicatorLabel = string
> = Types.IndicatorLabelValidator<RowIndicatorLabel, ColumnIndicatorLabel> & {
/** The spreadsheet's data */
data: Matrix.Matrix<CellType>;
/** Class name to be added to the spreadsheet's root element */
Expand All @@ -64,12 +68,12 @@ export type Props<CellType extends Types.CellBase> = {
* Labels to use in column indicators.
* @defaultValue alphabetical labels.
*/
columnLabels?: string[];
columnLabels?: ColumnIndicatorLabel[];
/**
* Labels to use in row indicators.
* @defaultValue row index labels.
*/
rowLabels?: string[];
rowLabels?: RowIndicatorLabel[];
/**
* If set to true, hides the row indicators of the spreadsheet.
* @defaultValue `false`.
Expand All @@ -84,11 +88,11 @@ export type Props<CellType extends Types.CellBase> = {
selected?: Selection;
// Custom Components
/** Component rendered above each column. */
ColumnIndicator?: Types.ColumnIndicatorComponent;
ColumnIndicator?: unknown;
/** Component rendered in the corner of row and column indicators. */
CornerIndicator?: Types.CornerIndicatorComponent;
/** Component rendered next to each row. */
RowIndicator?: Types.RowIndicatorComponent;
RowIndicator?: unknown;
/** The Spreadsheet's table component. */
Table?: Types.TableComponent;
/** The Spreadsheet's row component. */
Expand Down Expand Up @@ -124,8 +128,12 @@ export type Props<CellType extends Types.CellBase> = {
/**
* The Spreadsheet component
*/
const Spreadsheet = <CellType extends Types.CellBase>(
props: Props<CellType>
const Spreadsheet = <
CellType extends Types.CellBase,
RowIndicatorLabel = React.ReactNode,
ColumnIndicatorLabel = React.ReactNode
>(
props: Props<CellType, RowIndicatorLabel, ColumnIndicatorLabel>
): React.ReactElement => {
const {
className,
Expand Down Expand Up @@ -426,13 +434,23 @@ const Spreadsheet = <CellType extends Types.CellBase>(
);

const RowIndicator = React.useMemo(
() => enhanceRowIndicator(props.RowIndicator || DefaultRowIndicator),
() =>
enhanceRowIndicator<RowIndicatorLabel>(
props.RowIndicator ||
(DefaultRowIndicator as Types.RowIndicatorComponent<RowIndicatorLabel>)
),
[props.RowIndicator]
);

const ColumnIndicator = React.useMemo(
() =>
enhanceColumnIndicator(props.ColumnIndicator || DefaultColumnIndicator),
enhanceColumnIndicator<ColumnIndicatorLabel>(
props.ColumnIndicator ||
// We typecheck that a ColumnIndicator is required when the Label type is not a string,
// so if it is not defined we can safely assume that the Label type is a string, so we cast
// the default component to the correct type.
(DefaultColumnIndicator as Types.ColumnIndicatorComponent<ColumnIndicatorLabel>)
),
[props.ColumnIndicator]
);

Expand Down
30 changes: 23 additions & 7 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,35 +161,38 @@ export type HeaderRowProps = React.PropsWithChildren<{}>;
export type HeaderRowComponent = React.ComponentType<HeaderRowProps>;

/** Type of the Spreadsheet RowIndicator component props */
export type RowIndicatorProps = {
export type RowIndicatorProps<Label = string> = {
/** The row the indicator indicates */
row: number;
/** A custom label for the indicator as provided in rowLabels */
label?: React.ReactNode | null;
label?: Label | null;
/** Whether the entire row is selected */
selected: boolean;
/** Callback to be called when the row is selected */
onSelect: (row: number, extend: boolean) => void;
};

/** Type of the RowIndicator component */
export type RowIndicatorComponent = React.ComponentType<RowIndicatorProps>;
export type RowIndicatorComponent<Label = string> = React.ComponentType<
RowIndicatorProps<Label>
>;

/** Type of the Spreadsheet ColumnIndicator component props */
export type ColumnIndicatorProps = {
export type ColumnIndicatorProps<Label = string> = {
/** The column the indicator indicates */
column: number;
/** A custom label for the indicator as provided in columnLabels */
label?: React.ReactNode | null;
label?: Label | null;
/** Whether the entire column in selected */
selected: boolean;
/** Callback to be called when the column is selected */
onSelect: (column: number, extend: boolean) => void;
};

/** Type of the ColumnIndicator component */
export type ColumnIndicatorComponent =
React.ComponentType<ColumnIndicatorProps>;
export type ColumnIndicatorComponent<Label = string> = React.ComponentType<
ColumnIndicatorProps<Label>
>;

/** Type of the Spreadsheet CornerIndicator component props */
export type CornerIndicatorProps = {
Expand All @@ -199,6 +202,19 @@ export type CornerIndicatorProps = {
onSelect: () => void;
};

export type IndicatorLabelValidator<RowIndicatorLabel, ColumnIndicatorLabel> =
RowLabelValidator<RowIndicatorLabel> &
ColumnLabelValidator<ColumnIndicatorLabel>;

type RowLabelValidator<RowIndicatorLabel> = RowIndicatorLabel extends string
? { RowIndicator?: RowIndicatorComponent<RowIndicatorLabel> }
: { RowIndicator: RowIndicatorComponent<RowIndicatorLabel> };

type ColumnLabelValidator<ColumnIndicatorLabel> =
ColumnIndicatorLabel extends string
? { ColumnIndicator?: ColumnIndicatorComponent<ColumnIndicatorLabel> }
: { ColumnIndicator: ColumnIndicatorComponent<ColumnIndicatorLabel> };

/** Type of the CornerIndicator component */
export type CornerIndicatorComponent =
React.ComponentType<CornerIndicatorProps>;
Expand Down
9 changes: 6 additions & 3 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,13 @@ export function getCSV(data: Matrix.Matrix<Types.CellBase>): string {
* @param columnLabels - the spreadsheet's column labels (if defined)
* @returns the rows and columns counts of a spreadsheet
*/
export function calculateSpreadsheetSize(
export function calculateSpreadsheetSize<
RowIndicatorLabel = React.ReactNode,
ColumnIndicatorLabel = React.ReactNode
>(
data: Matrix.Matrix<unknown>,
rowLabels?: string[],
columnLabels?: string[]
rowLabels?: RowIndicatorLabel[],
columnLabels?: ColumnIndicatorLabel[]
): Matrix.Size {
const { columns, rows } = Matrix.getSize(data);
return {
Expand Down