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

Decoupling data table manager components #2807

Merged
merged 37 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
1d32361
feat(data-table-manager): managing state using window state - poc
Apr 30, 2024
6f04b6f
feat(data-table-manager): update data row
Apr 30, 2024
6f0dac2
feat(data-table-manager): fix state update async behaviour
May 1, 2024
6606cb5
feat(data-table-manager): rertore story to original order
May 2, 2024
1636ea3
feat(data-table-manager): add changeset
May 2, 2024
f5df920
feat(data-table-manager): use provider method
May 2, 2024
c3bd460
feat(data-table-manager): use proper import
May 2, 2024
4d40cf0
feat(data-table-manager): remove unnecesary prop
May 3, 2024
53851ad
feat(data table manager): rename data table manager provider
May 3, 2024
ff35e1b
feat(data table manager): add datatable manager as data table dependency
May 5, 2024
16c5ca9
feat(data table manager): add tests for when data table is used in de…
May 6, 2024
3eb990f
feat(data table manager): proper function initial values
May 7, 2024
b6ff69c
feat(data table manager): move data table context to separate file
May 8, 2024
03e5b4e
feat(data table manager): update usage example
May 8, 2024
6def73e
feat(data table manager): update data table import
May 9, 2024
5dd0915
feat(data table manager): resolve conflict
May 9, 2024
e4e11d5
feat(data table manager): update tests
May 9, 2024
aa8c241
feat(data table manager): reuse exported types
May 10, 2024
6c902f5
feat(data table manager): reuse exported types
May 10, 2024
28a3f4b
feat(data table manager): introduce story for when data table is deco…
May 10, 2024
0dcd7af
feat(data table manager): add documentation when datatable is decoupled
May 13, 2024
b5c1a37
feat(data table manager): remove children prop from decoupled data ta…
May 13, 2024
8d03194
feat(data table manager): remove children prop from decoupled data ta…
May 13, 2024
4d191d7
feat(data table manager): update package
May 13, 2024
d63f3e8
feat(data table manager): update package import path
May 13, 2024
1f8c6ba
feat(data table manager): refactor data table provider
May 14, 2024
112491d
feat(data table manager): refactor data table manager to move all log…
May 15, 2024
6ceb935
refactor(data table manager): refactor data table types location
May 15, 2024
be8def9
Merge branch 'main' into SHIELD-1187-decoupling-data-table-manager-co…
ddouglasz May 15, 2024
557b6f8
feat(data table manager): throw error to notify users of provider alt…
May 15, 2024
dad4ee5
feat(data table manager): remove unused file
May 15, 2024
d1c1679
refactor(data table manager): refactor manager provider
May 15, 2024
e04a522
feat(data table manager): update readme
May 16, 2024
e4aacf4
feat(selectable search input): update test
May 16, 2024
be1afaf
feat(data table manager): update readme
May 16, 2024
37d6c7c
feat(data table manager): update types import
May 17, 2024
1af83b5
feat(data table manager): update usage example
May 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/shy-goats-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@commercetools-uikit/data-table-manager': minor
'@commercetools-uikit/data-table': minor
---

decouple the datatable manager from the data table to enable users position the data table manager settings dropdown anywhere in the DOM structure.
63 changes: 57 additions & 6 deletions packages/components/data-table-manager/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ This component enhances the `<DataTable>` component and additionally provides a

- The `disableDisplaySettings` enables / disables the layout settings panel, allowing the user to select wrapping text and density display options.
- The `disableColumnManager` enables / disables the column manager panel, allowing the user to select which columns are visible.
- To Detach the `DatatableManager` settings dropdown from the Datatable and position it anywhere else, you would need to import a `DataTableManagerProvider` and wrap both components with the provider.

Both panels delegate the handling of the settings change on the parent through function properties, allowing the settings to be persisted or just used as state props.
28 changes: 25 additions & 3 deletions packages/components/data-table-manager/_docs/usage-example.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import DataTableManager from '@commercetools-uikit/data-table-manager';
import DataTableManager, {
DataTableManagerProvider,
} from '@commercetools-uikit/data-table-manager';
import DataTable from '@commercetools-uikit/data-table';
import SearchTextInput from '@commercetools-uikit/search-text-input';

const rows = [
{ id: 'parasite', title: 'Parasite', country: 'South Korea' },
Expand All @@ -12,10 +15,29 @@ const columns = [
{ key: 'country', label: 'Country' },
];

const Example = () => (
export const Example = () => (
<DataTableManager columns={columns}>
<DataTable rows={rows} />
</DataTableManager>
);

export default Example;

// Introduce this component to test that DataTable and DataTableManager should not necessarily be direct descendants
const SomeOtherComponent = () => {
return <div>Some other component</div>;
};

// With the data table settings decoupled.
// It can also be exported as default.
export const ExampleWithDecoupledDataTableManager = () => (
<DataTableManagerProvider columns={columns}>
<header>
<DataTableManager />
<SearchTextInput />
</header>
<main>
<SomeOtherComponent />
<DataTable rows={rows} />
</main>
</DataTableManagerProvider>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"main": "dist/commercetools-uikit-data-table-manager-data-table-manager-provider.cjs.js",
"module": "dist/commercetools-uikit-data-table-manager-data-table-manager-provider.esm.js"
}
5 changes: 4 additions & 1 deletion packages/components/data-table-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
"sideEffects": false,
"main": "dist/commercetools-uikit-data-table-manager.cjs.js",
"module": "dist/commercetools-uikit-data-table-manager.esm.js",
"files": ["dist"],
"preconstruct": {
"entrypoints": ["./index.ts", "data-table-manager-provider/index.ts"]
},
"files": ["dist", "data-table-manager-provider"],
"dependencies": {
"@babel/runtime": "^7.20.13",
"@babel/runtime-corejs3": "^7.20.13",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { createContext, useContext, useMemo } from 'react';
import type { TDataTableSettingsProps, TColumnManagerProps } from '../types';
import type { TDataTableManagerColumnProps, TRow } from './types';

export type TDataTableManagerContext<Row extends TRow = TRow> =
TDataTableSettingsProps & {
columns: TDataTableManagerColumnProps<Row>[];
isCondensed?: boolean;
};

const DataTableManagerContext = createContext<TDataTableManagerContext>({
columns: [],
displaySettings: undefined,
isCondensed: true,
});

export const useDataTableManagerContext = () => {
const dataTableManagerContext = useContext(DataTableManagerContext);

if (!dataTableManagerContext) {
throw new Error(
'ui-kit/DataTableManager: `useDataTableManagerContext` must be used within the DataTableManagerProvider.'
);
}

return dataTableManagerContext;
};

export const DataTableManagerProvider = ({
children,
columns,
displaySettings,
topBar,
onSettingsChange,
columnManager,
}: {
children: React.ReactNode;
columns: TDataTableManagerColumnProps[];
displaySettings: TDataTableSettingsProps['displaySettings'];
topBar: string;
onSettingsChange: () => void;
columnManager: TColumnManagerProps;
}) => {
const decoupledDataTableManagerContext = useMemo(() => {
const areDisplaySettingsEnabled = Boolean(
displaySettings && !displaySettings.disableDisplaySettings
);

const isWrappingText =
areDisplaySettingsEnabled && displaySettings!.isWrappingText;

return {
columns: columns.map((column) => ({
...column,
isTruncated: areDisplaySettingsEnabled
? isWrappingText
: column.isTruncated,
})),
displaySettings,
topBar,
onSettingsChange,
columnManager,
isCondensed: areDisplaySettingsEnabled && displaySettings!.isCondensed,
};
}, [columns, displaySettings, topBar, onSettingsChange, columnManager]);

return (
<DataTableManagerContext.Provider value={decoupledDataTableManagerContext}>
{children}
</DataTableManagerContext.Provider>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export {
DataTableManagerProvider,
useDataTableManagerContext,
} from './data-table-manager-provider';

export type { TDataTableManagerContext } from './data-table-manager-provider';
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { type ReactNode, type MouseEventHandler } from 'react';

export interface TRow {
id: string;
}

export type TDataTableManagerColumnProps<Row extends TRow = TRow> = {
/**
* The unique key of the column that is used to identify your data type.
* You can use this value to determine which value from a row item should be rendered.
* <br>
* For example, if the data is a list of users, where each user has a `firstName` property,
* the column key should be `firstName`, which renders the correct value by default.
* The key can also be some custom or computed value, in which case you need to provide
* an explicit mapping of the value by implementing either the `itemRendered` function or
* the column-specific `renderItem` function.
*/
key: string;

/**
* The label of the column that will be shown on the column header.
*/
label: ReactNode;

/**
* Sets a width for this column. Accepts the same values as the ones specified for
* individual [grid-template-columns](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns).
* <br>
* For example, using `minmax` pairs (e.g. `minmax(200px, 400px)`), a combinations of
* fraction values (`1fr`/`2fr`/etc), or fixed values such as `200px`.
* By default, the column grows according to the content and respecting the total table available width.
*/
width?: string;

/**
* Use this to override the table's own `horizontalCellAlignment` prop for this specific column.
*/
align?: 'left' | 'center' | 'right';

/**
* A callback function, called when the header cell is clicked.
*/
onClick?: (event: MouseEventHandler) => void;

/**
* A callback function to render the content of cells under this column, overriding
* the default `itemRenderer` prop of the table.
*/
renderItem?: (row: Row, isRowCollapsed: boolean) => ReactNode;

/**
* Use this prop to place an `Icon` or `IconButton` on the left of the column label.
* It is advised to place these types of components through this prop instead of `label`,
* in order to properly position and align the elements.
* This is particularly useful for medium-sized icons which require more vertical space than the typography.
*/
headerIcon?: ReactNode;

/**
* Set this to `true` to allow text content of this cell to be truncated with an ellipsis,
* instead of breaking into multiple lines.
* <br>
* NOTE: when using this option, it is recommended to specify a `width` for the column, because
* if the table doesn't have enough space for all columns, it will start clipping the columns
* with _truncated_ content, and if no `width` is set (or the value is set `auto` -- the default)
* it can shrink until the column disappears completely.
* By enforcing a minimum width for these columns, the table will respect them and grow horizontally,
* adding scrollbars if needed.
*/
isTruncated?: boolean;

/**
* Set this to `true` to show a sorting button, which calls `onSortChange` upon being clicked.
* You should enable this flag for every column you want to be able to sort.
* When at least one column is sortable, the table props `sortBy`, `sortDirection` and `onSortChange` should be provided.
*/
isSortable?: boolean;

/**
* Set this to `true` to prevent this column from being manually resized by dragging
* the edge of the header with a mouse.
*/
disableResizing?: boolean;

/**
* Set this to `true` to prevent click event propagation for this cell.
* You might want this if you need the column to have its own call-to-action or input while
* the row also has a defined `onRowClick`.
*/
shouldIgnoreRowClick?: boolean;
};