Skip to content

Commit

Permalink
feat: reset table state button
Browse files Browse the repository at this point in the history
  • Loading branch information
schummar committed Aug 29, 2022
1 parent cec5c8a commit 536b86d
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 19 deletions.
11 changes: 9 additions & 2 deletions src/components/columnSelection.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import React, { useState } from 'react';
import React, { useContext, useState } from 'react';
import { useTheme } from '..';
import { useCssVariables } from '../theme/useCssVariables';
import { InternalColumn } from '../types';
import { FormControlLabel } from './formControlLabel';
import { useTableContext } from './table';
import { TableResetContext, useTableContext } from './table';

export function ColumnSelection<T>(): JSX.Element {
const IconButton = useTheme((t) => t.components.IconButton);
const Popover = useTheme((t) => t.components.Popover);
const Checkbox = useTheme((t) => t.components.Checkbox);
const Button = useTheme((t) => t.components.Button);
const Settings = useTheme((t) => t.icons.Settings);
const selectColumns = useTheme((t) => t.text.selectColumns);
const resetAll = useTheme((t) => t.text.resetAll);
const cssVariables = useCssVariables();

const table = useTableContext<T>();
const reset = useContext(TableResetContext);
const columns = table.useState('props.columns');
const hiddenColumns = table.useState('hiddenColumns');

Expand Down Expand Up @@ -54,6 +57,10 @@ export function ColumnSelection<T>(): JSX.Element {
label={column.header}
></FormControlLabel>
))}

<Button variant="outlined" onClick={reset}>
{resetAll}
</Button>
</div>
</Popover>
</>
Expand Down
20 changes: 14 additions & 6 deletions src/components/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { SelectComponent } from './selectComponent';
import { Virtualized } from './virtualized';

export const TableContext = createContext<Store<InternalTableState<any>> | null>(null);
export const TableResetContext = createContext<() => void>(() => undefined);
export const ColumnContext = createContext<Id | null>(null);
export function useTableContext<T>(): Store<InternalTableState<T>> {
const value = useContext(TableContext);
Expand All @@ -31,22 +32,29 @@ export function useColumnContext(): Id {
}

export function Table<T>(props: TableProps<T>): JSX.Element {
const table = useTableState(props);
const [table, resetState] = useTableState(props);
const [isHydrated, clearStorage] = useTableStateStorage(table);

async function reset() {
await clearStorage();
resetState();
}

useLayoutEffect(() => table.getState().props.debugRender?.('render table'));

return (
<TableContext.Provider value={table}>
<TableMemoContextProvider>
<TableLoadingState />
</TableMemoContextProvider>
<TableResetContext.Provider value={reset}>
<TableMemoContextProvider>
<TableLoadingState isHydrated={isHydrated} />
</TableMemoContextProvider>
</TableResetContext.Provider>
</TableContext.Provider>
);
}

function TableLoadingState() {
function TableLoadingState({ isHydrated }: { isHydrated: boolean }) {
const loadingText = useTheme((t) => t.text.loading);
const isHydrated = useTableStateStorage();
const [showLoading, setShowLoading] = useState(false);

useEffect(() => {
Expand Down
39 changes: 32 additions & 7 deletions src/internalState/tableStateStorage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { useTableContext } from '..';
import { Store } from 'schummar-state/react';
import { Queue } from '../misc/queue';
import { SerializableValue } from '../types';
import { InternalTableState, SerializableValue } from '../types';

const KEYS = ['sort', 'selection', 'expanded', 'hiddenColumns', 'filterValues', 'columnWidths', 'columnOrder'] as const;

Expand Down Expand Up @@ -67,9 +67,9 @@ function parse(value: string) {
});
}

export function useTableStateStorage() {
const table = useTableContext();
export function useTableStateStorage(table: Store<InternalTableState<any>>) {
const [isHydrated, setIsHydrated] = useState(false);
const [q] = useState(() => new Queue());

// On mount: load
useEffect(() => {
Expand Down Expand Up @@ -130,8 +130,6 @@ export function useTableStateStorage() {
useEffect(() => {
if (!isHydrated) return;

const q = new Queue();

return table.subscribe(
(state) => {
if (!state.props.persist) return;
Expand Down Expand Up @@ -173,5 +171,32 @@ export function useTableStateStorage() {
);
}, [isHydrated]);

return isHydrated;
async function clear() {
await q.run(async () => {
const persist = table.getState().props.persist;
if (!persist) {
return;
}

const { storage } = persist;
const keys =
'keys' in storage
? await storage.keys()
: await Promise.all(
Array(storage.length)
.fill(0)
.map((_x, i) => storage.key(i)),
);

for (const key of keys) {
if (key !== null) {
await storage.removeItem(key);
}
}

q.clear();
});
}

return [isHydrated, clear] as const;
}
13 changes: 9 additions & 4 deletions src/internalState/useTableState.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { castDraft } from 'immer';
import { useEffect, useMemo } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { Store } from 'schummar-state/react';
import { InternalTableState, TableProps } from '../types';
import { calcItems } from './calcItems';
Expand All @@ -9,9 +9,14 @@ import { filterColumns } from './filterColumns';
import { normalizeExpanded } from './normalizeExpanded';
import { syncSelections } from './syncSelections';

export function useTableState<T>(_props: TableProps<T>): Store<InternalTableState<T>> {
export function useTableState<T>(_props: TableProps<T>): [Store<InternalTableState<T>>, () => void] {
const [key, setKey] = useState({});
const props = calcProps(_props);

function reset() {
setKey({});
}

const state = useMemo(
() =>
new Store<InternalTableState<T>>({
Expand All @@ -35,7 +40,7 @@ export function useTableState<T>(_props: TableProps<T>): Store<InternalTableStat
activeItemsById: new Map(),
lastSelectedId: undefined,
}),
[],
[key],
);

filterColumns(state);
Expand All @@ -60,5 +65,5 @@ export function useTableState<T>(_props: TableProps<T>): Store<InternalTableStat
});
}, [state, props]);

return state;
return [state, reset];
}
4 changes: 4 additions & 0 deletions src/misc/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export class Queue {
});
}

clear() {
this.q = [];
}

private async start() {
this.isRunning = true;

Expand Down
1 change: 1 addition & 0 deletions src/theme/defaultTheme/defaultTexts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export const defaultTexts: TableTheme['text'] = {
reset: 'Reset',
loading: 'Loading',
deselectAll: 'Deselect all',
resetAll: 'Reset table state',
};
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface TableTheme<T = unknown> {
loading: ReactNode;
clearFilters: ReactNode;
deselectAll: ReactNode;
resetAll: ReactNode;
};
/** Define styles. */
classes?: {
Expand Down

0 comments on commit 536b86d

Please sign in to comment.