@semcore/data-table 1.5.4 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/DataTable.jsx DELETED
@@ -1,283 +0,0 @@
1
- import React from 'react';
2
- import createComponent, { Component, sstyled, Root } from '@semcore/core';
3
- import { Box } from '@semcore/flex-box';
4
- import syncScroll from '@semcore/utils/lib/syncScroll';
5
- import { callAllEventHandlers } from '@semcore/utils/lib/assignProps';
6
- import fire from '@semcore/utils/lib/fire';
7
- import { flattenColumns } from './utils';
8
- import Head from './Head';
9
- import Body from './Body';
10
-
11
- import style from './style/data-table.shadow.css';
12
-
13
- const MAP_SORT_DIRECTION = {
14
- desc: 'asc',
15
- asc: 'desc',
16
- };
17
- const DEFAULT_SORT_DIRECTION = 'desc';
18
-
19
- const ROW_GROUP = Symbol('ROW_GROUP');
20
-
21
- const cssVarReg = /[:;]/g;
22
-
23
- function createCssVarForWidth(name) {
24
- return `--${name.replace(cssVarReg, '_')}_width`;
25
- }
26
-
27
- class RootDefinitionTable extends Component {
28
- static displayName = 'DefinitionTable';
29
-
30
- static style = style;
31
-
32
- static defaultProps = {
33
- use: 'primary',
34
- sort: [],
35
- data: [],
36
- };
37
-
38
- columns = [];
39
-
40
- tableRef = React.createRef();
41
-
42
- constructor(props) {
43
- super(props);
44
-
45
- const createRef = syncScroll();
46
- // first create body ref for master scroll
47
- this.scrollBodyRef = createRef('body');
48
- this.scrollHeadRef = createRef('head');
49
- }
50
-
51
- handlerSortClick = (name, e) => {
52
- const column = this.columns.find((c) => c.name === name);
53
- return fire(
54
- this,
55
- 'onSortChange',
56
- [
57
- column.name,
58
- column.active ? MAP_SORT_DIRECTION[column.sortDirection] : column.sortDirection,
59
- ],
60
- e,
61
- );
62
- };
63
-
64
- handlerResize = () => {
65
- this.forceUpdate();
66
- };
67
-
68
- scrollToUp = () => {
69
- this.tableRef?.current?.scrollIntoView({
70
- block: 'nearest',
71
- inline: 'nearest',
72
- behavior: 'smooth',
73
- });
74
- };
75
-
76
- setVarStyle(columns) {
77
- columns.forEach((column) => {
78
- this.tableRef.current?.style.setProperty(column.cssVar, `${column.width}px`);
79
- }, {});
80
- }
81
-
82
- childrenToColumns(children, options = { fixed: undefined }) {
83
- const { sort } = this.asProps;
84
- const columnsChildren = [];
85
- React.Children.forEach(children, (child) => {
86
- if (!React.isValidElement(child)) return;
87
- if (child.type !== DefinitionTable.Column) return;
88
-
89
- let { children, name, fixed = options.fixed, resizable, sortable, ...props } = child.props;
90
- const isGroup = !name;
91
- let columns = null;
92
-
93
- if (isGroup) {
94
- columns = this.childrenToColumns(children, {
95
- fixed,
96
- });
97
- name = flattenColumns(columns)
98
- .map((c) => c.name)
99
- .join('/');
100
- if (!columns.length) return;
101
- children = React.Children.toArray(children).filter(
102
- (child) => !(React.isValidElement(child) && child.type === DefinitionTable.Column),
103
- );
104
- }
105
-
106
- const column = this.columns.find((c) => c.name === name);
107
-
108
- columnsChildren.push({
109
- get width() {
110
- return this.props.ref.current?.getBoundingClientRect().width || 0;
111
- },
112
- name,
113
- cssVar: createCssVarForWidth(name),
114
- fixed,
115
- resizable,
116
- active: sort[0] === name,
117
- sortable,
118
- sortDirection:
119
- sort[0] === name
120
- ? sort[1]
121
- : column?.sortDirection ||
122
- (typeof sortable == 'string' ? sortable : DEFAULT_SORT_DIRECTION),
123
- columns,
124
- props: {
125
- ref: column?.props?.ref || React.createRef(),
126
- children,
127
- ...props,
128
- },
129
- });
130
- });
131
- return columnsChildren;
132
- }
133
-
134
- getHeadProps(props) {
135
- const { use } = this.asProps;
136
- const columnsChildren = this.childrenToColumns(props.children);
137
- this.columns = flattenColumns(columnsChildren);
138
- return {
139
- $onSortClick: callAllEventHandlers(this.handlerSortClick, this.scrollToUp),
140
- columnsChildren,
141
- use,
142
- onResize: this.handlerResize,
143
- $scrollRef: this.scrollHeadRef,
144
- };
145
- }
146
-
147
- getBodyProps(props) {
148
- const { data, use } = this.asProps;
149
- const propsCells = {};
150
- const $propsRow = [];
151
- React.Children.forEach(props.children, (child) => {
152
- if (React.isValidElement(child)) {
153
- const { name, children, ...other } = child.props;
154
- if (child.type === DefinitionTable.Cell && name) {
155
- name.split('/').forEach((name) => {
156
- propsCells[name] = propsCells[name] || [];
157
- propsCells[name].push({
158
- ...other,
159
- getCellProps: children,
160
- });
161
- });
162
- }
163
- if (child.type === DefinitionTable.Row) {
164
- $propsRow.push({
165
- ...other,
166
- getRowProps: children,
167
- });
168
- }
169
- }
170
- });
171
-
172
- return {
173
- columns: this.columns,
174
- rows: this.dataToRows(data, propsCells),
175
- use,
176
- $propsRow,
177
- $scrollRef: this.scrollBodyRef,
178
- };
179
- }
180
-
181
- dataToRows(data, propsCells) {
182
- const columns = this.columns;
183
-
184
- function parseData(data, options = { exclude: [] }) {
185
- return data.map((row) => {
186
- const columnsGroups = Object.keys(row).reduce((acc, name) => {
187
- const names = name.split('/');
188
- if (names.length >= 2) {
189
- acc.push([names, row[name]]);
190
- }
191
- return acc;
192
- }, []);
193
- const nameColumnsGroup = columnsGroups
194
- .reduce((acc, [names]) => acc.concat(names), [])
195
- .filter((name, i, arr) => arr.indexOf(name) === i);
196
- const rowsGroup = row[ROW_GROUP] || [];
197
- const nameRowsGroup = rowsGroup
198
- .reduce((acc, row) => acc.concat(Object.keys(row)), [])
199
- .filter((name, i, arr) => arr.indexOf(name) === i);
200
- let isGroupRow = false;
201
-
202
- const cells = [];
203
- cells._row = row;
204
- return columns.reduce((acc, column) => {
205
- const columnGroup = columnsGroups.find((group) => group[0]?.includes(column.name));
206
- if (columnGroup) {
207
- const [names, data] = columnGroup;
208
- if (names[0] === column.name) {
209
- acc.push({
210
- name: names.join('/'),
211
- cssVar: names.map(createCssVarForWidth),
212
- fixed: column.fixed,
213
- data,
214
- rendersCell: propsCells[column.name] || [],
215
- });
216
- }
217
- } else if (column.name in row) {
218
- acc.push({
219
- name: column.name,
220
- cssVar: column.cssVar,
221
- fixed: column.fixed,
222
- data: row[column.name],
223
- rendersCell: propsCells[column.name] || [],
224
- });
225
- } else if (!isGroupRow && nameRowsGroup.includes(column.name)) {
226
- // TODO: сделать универсально
227
- isGroupRow = true;
228
- acc.push(
229
- parseData(rowsGroup, {
230
- exclude: [...Object.keys(row), ...nameColumnsGroup],
231
- }),
232
- );
233
- } else if (![...options.exclude, ...nameRowsGroup].includes(column.name)) {
234
- acc.push({
235
- name: column.name,
236
- cssVar: column.cssVar,
237
- fixed: column.fixed,
238
- data: null,
239
- rendersCell: propsCells[column.name] || [],
240
- });
241
- }
242
- return acc;
243
- }, cells);
244
- });
245
- }
246
-
247
- return parseData(data);
248
- }
249
-
250
- componentDidUpdate() {
251
- this.setVarStyle(this.columns);
252
- }
253
-
254
- render() {
255
- const SDataTable = Root;
256
- const { Children, styles } = this.asProps;
257
-
258
- return sstyled(styles)(
259
- <SDataTable render={Box} __excludeProps={['data']} ref={this.tableRef}>
260
- <Children />
261
- </SDataTable>,
262
- );
263
- }
264
- }
265
-
266
- function ComponentDefinition() {
267
- return null;
268
- }
269
-
270
- const DefinitionTable = createComponent(
271
- RootDefinitionTable,
272
- {
273
- Head,
274
- Body,
275
- Column: ComponentDefinition,
276
- Cell: ComponentDefinition,
277
- Row: ComponentDefinition,
278
- },
279
- {},
280
- );
281
-
282
- export { ROW_GROUP };
283
- export default DefinitionTable;
package/src/index.d.ts DELETED
@@ -1,99 +0,0 @@
1
- import React from 'react';
2
- import { PropGetterFn } from '@semcore/core';
3
- import { IBoxProps, IFlexProps } from '@semcore/flex-box';
4
-
5
- /* utils type */
6
- type CProps<Props, Ctx = {}, UCProps = {}> = Props & {
7
- children?: ((props: Props & Ctx, handlers: UCProps) => React.ReactNode) | React.ReactNode;
8
- };
9
- type ReturnEl = React.ReactElement | null;
10
- /* utils type */
11
-
12
- type ChildRenderFn<Props> = Props & {
13
- children?: (props: Props, column: DataTableData, index: number) => { [key: string]: unknown };
14
- };
15
-
16
- export type DataTableData = { [key: string]: unknown };
17
- export type DataTableSort = [string, 'desc' | 'asc'];
18
- export type DataTableTheme = 'muted' | 'info' | 'success' | 'warning' | 'danger';
19
- export type DataTableUse = 'primary' | 'secondary';
20
- export type DataTableRow = DataTableCell[];
21
- export type DataTableCell = {
22
- /** Name of column */
23
- name: string;
24
- /** Data of column */
25
- data: React.ReactNode;
26
- [key: string]: unknown;
27
- };
28
-
29
- export interface IDataTableProps extends IBoxProps {
30
- /** Theme for table
31
- * @default primary
32
- * */
33
- use?: DataTableUse;
34
- /** Data for table */
35
- data?: DataTableData[];
36
- /** Active sort object */
37
- sort?: DataTableSort;
38
- /** Handler call when will request change sort */
39
- onSortChange?: (sort: DataTableSort, e?: React.SyntheticEvent) => void;
40
- }
41
-
42
- export interface IDataTableHeadProps extends IBoxProps {
43
- /** Sticky header table
44
- * @deprecated
45
- * */
46
- sticky?: boolean;
47
-
48
- /** Hidden header */
49
- hidden?: boolean;
50
- }
51
-
52
- export interface IDataTableColumnProps extends IFlexProps {
53
- /** Unique name column */
54
- name?: string;
55
- /** Enable sort for column also if you pass string you can set default sort */
56
- sortable?: boolean | 'desc' | 'asc';
57
- /** Enable resize for column
58
- * @ignore */
59
- resizable?: boolean;
60
- /** Fixed column on the left/right */
61
- fixed?: 'left' | 'right';
62
- }
63
-
64
- export interface IDataTableBodyProps extends IBoxProps {
65
- /** Rows table */
66
- rows?: DataTableRow[];
67
- }
68
-
69
- export interface IDataTableRowProps extends IBoxProps {
70
- /** Theme for row */
71
- theme?: DataTableTheme;
72
- /** Displays row as active/hover */
73
- active?: boolean;
74
- }
75
-
76
- export interface IDataTableCellProps extends IFlexProps {
77
- /** Unique name column or columns separated by / */
78
- name: string;
79
- /** Theme for cell */
80
- theme?: DataTableTheme;
81
- }
82
-
83
- interface IDataTableCtx {
84
- getHeadProps: PropGetterFn;
85
- getBodyProps: PropGetterFn;
86
- }
87
-
88
- declare const ROW_GROUP: unique symbol;
89
-
90
- declare const DataTable: (<T>(props: CProps<IDataTableProps & T, IDataTableCtx>) => ReturnEl) & {
91
- Head: <T>(props: IDataTableHeadProps & T) => ReturnEl;
92
- Body: <T>(props: IDataTableBodyProps & T) => ReturnEl;
93
- Column: <T>(props: IDataTableColumnProps & T) => ReturnEl;
94
- Cell: <T>(props: ChildRenderFn<IDataTableCellProps & T>) => ReturnEl;
95
- Row: <T>(props: ChildRenderFn<IDataTableRowProps & T>) => ReturnEl;
96
- };
97
-
98
- export { ROW_GROUP };
99
- export default DataTable;
package/src/utils.js DELETED
@@ -1,54 +0,0 @@
1
- export function getScrollOffsetValue(columns) {
2
- return columns.reduce(
3
- (acc, c) => {
4
- if (c.fixed === 'left') {
5
- acc[0] += c.width;
6
- }
7
- if (c.fixed === 'right') {
8
- acc[1] += c.width;
9
- }
10
- return acc;
11
- },
12
- [0, 0],
13
- );
14
- }
15
-
16
- export function flattenColumns(columns) {
17
- return columns.reduce((acc, c) => {
18
- let columns = [c];
19
- if (c.columns) {
20
- columns = flattenColumns(c.columns);
21
- }
22
- acc = acc.concat(columns);
23
- return acc;
24
- }, []);
25
- }
26
-
27
- export function getFixedStyle(column, columns) {
28
- const side = column.fixed;
29
- if (!side) return [undefined, undefined];
30
- const names = column.name.split('/');
31
- const nameSideMap = {
32
- left: names[0],
33
- right: names[names.length - 1],
34
- };
35
- const name = nameSideMap[side];
36
- const index = columns.findIndex((c) => c.name === name);
37
-
38
- if (index === -1) return [undefined, undefined];
39
-
40
- const startIndexSideMap = {
41
- left: 0,
42
- right: index,
43
- };
44
- const endIndexSideMap = {
45
- left: index,
46
- right: columns.length - 1,
47
- };
48
- const columnsFixed = columns.slice(startIndexSideMap[side], endIndexSideMap[side]);
49
-
50
- if (columnsFixed.length < 1) return [side, 0];
51
-
52
- const vars = columnsFixed.map((c) => `var(--${c.name}_width)`);
53
- return [side, vars.length === 1 ? vars[0] : `calc(${vars.join(' + ')})`];
54
- }