onekijs-ui 0.19.20 → 0.19.21

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.
@@ -36,4 +36,4 @@ export declare const borderTopWidth: import("./typings").CssProperty<string | nu
36
36
  export declare const borderBottomWidth: import("./typings").CssProperty<string | number>;
37
37
  export declare const borderLeftWidth: import("./typings").CssProperty<string | number>;
38
38
  export declare const borderRightWidth: import("./typings").CssProperty<string | number>;
39
- export declare const boxShadow: import("./typings").CssProperty<"default" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "inner" | "outline" | Property.BoxShadow>;
39
+ export declare const boxShadow: import("./typings").CssProperty<"xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "default" | "inner" | "outline" | Property.BoxShadow>;
@@ -6,4 +6,4 @@ export declare const flexDirection: import("./typings").CssProperty<Property.Fle
6
6
  export declare const flexGrow: import("./typings").CssProperty<number>;
7
7
  export declare const flexShrink: import("./typings").CssProperty<number>;
8
8
  export declare const flexWrap: import("./typings").CssProperty<Property.FlexWrap>;
9
- export declare const order: import("./typings").CssProperty<number | Globals | "none" | "first" | "last">;
9
+ export declare const order: import("./typings").CssProperty<number | "none" | Globals | "first" | "last">;
@@ -1,10 +1,10 @@
1
1
  import { Property } from 'csstype';
2
- export declare const width: import("./typings").CssProperty<string | 0 | (string & {}) | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
3
- export declare const minWidth: import("./typings").CssProperty<string | 0 | (string & {}) | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
4
- export declare const maxWidth: import("./typings").CssProperty<string | 0 | (string & {}) | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
5
- export declare const height: import("./typings").CssProperty<string | 0 | (string & {}) | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
6
- export declare const minHeight: import("./typings").CssProperty<string | 0 | (string & {}) | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
7
- export declare const maxHeight: import("./typings").CssProperty<string | 0 | (string & {}) | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
2
+ export declare const width: import("./typings").CssProperty<string | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | (string & {}) | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
3
+ export declare const minWidth: import("./typings").CssProperty<string | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | (string & {}) | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
4
+ export declare const maxWidth: import("./typings").CssProperty<string | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | (string & {}) | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
5
+ export declare const height: import("./typings").CssProperty<string | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | (string & {}) | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
6
+ export declare const minHeight: import("./typings").CssProperty<string | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | (string & {}) | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
7
+ export declare const maxHeight: import("./typings").CssProperty<string | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | 12 | (string & {}) | 16 | 20 | 24 | 32 | 40 | 48 | 56 | 64>;
8
8
  export declare const overscrollBehavior: import("./typings").CssProperty<Property.OverscrollBehavior>;
9
9
  export declare const overscrollBehaviorBlock: import("./typings").CssProperty<Property.OverscrollBehaviorBlock>;
10
10
  export declare const overscrollBehaviorInline: import("./typings").CssProperty<Property.OverscrollBehaviorInline>;
@@ -20,10 +20,10 @@ export declare const fontVariantLigatures: import("./typings").CssProperty<Prope
20
20
  export declare const fontVariantNumeric: import("./typings").CssProperty<Property.FontVariantNumeric>;
21
21
  export declare const fontVariantPosition: import("./typings").CssProperty<Property.FontVariantPosition>;
22
22
  export declare const fontVariationSettings: import("./typings").CssProperty<Property.FontVariationSettings>;
23
- export declare const fontWeight: import("./typings").CssProperty<number | "bold" | (string & {}) | "-moz-initial" | "inherit" | "initial" | "revert" | "revert-layer" | "unset" | "lighter" | "light" | "black" | "medium" | "thin" | "hairline" | "normal" | "semibold" | "extrabold" | (number & {}) | "bolder">;
23
+ export declare const fontWeight: import("./typings").CssProperty<number | "lighter" | "light" | "black" | (string & {}) | "-moz-initial" | "inherit" | "initial" | "revert" | "revert-layer" | "unset" | "medium" | "thin" | "hairline" | "normal" | "semibold" | "bold" | "extrabold" | (number & {}) | "bolder">;
24
24
  export declare const hyphens: import("./typings").CssProperty<Property.Hyphens>;
25
25
  export declare const letterSpacing: import("./typings").CssProperty<Property.LetterSpacing<TLength>>;
26
- export declare const lineHeight: import("./typings").CssProperty<string | 0 | (string & {}) | 4 | (number & {}) | 5 | 6 | 8 | 10 | 7 | 9>;
26
+ export declare const lineHeight: import("./typings").CssProperty<string | 0 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | (string & {}) | (number & {})>;
27
27
  export declare const lineHeightStep: import("./typings").CssProperty<Property.LineHeightStep<TLength>>;
28
28
  export declare const overflowWrap: import("./typings").CssProperty<Property.OverflowWrap>;
29
29
  export declare const textAlign: import("./typings").CssProperty<Property.TextAlign>;
@@ -4,4 +4,5 @@ export declare const booleanFormatter: Formatter<boolean>;
4
4
  export declare const themeFormatter: (category: string) => Formatter<string | number>;
5
5
  export declare const colorFormatter: (key: string, opacityKey?: string) => Formatter<string>;
6
6
  export declare const enumFormatter: <T>(values: AnonymousObject) => Formatter<T>;
7
+ export declare const escapeCsvValue: (value: any, separator?: string) => string;
7
8
  export declare const pxFormatter: Formatter<string | number>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "onekijs-ui",
3
3
  "private": false,
4
- "version": "0.19.20",
4
+ "version": "0.19.21",
5
5
  "description": "Advanced React Web Components",
6
6
  "source": "src/index.ts",
7
7
  "main": "dist/index.js",
@@ -53,5 +53,5 @@
53
53
  "react-dom": ">=18"
54
54
  },
55
55
  "sideEffects": false,
56
- "gitHead": "6e90682d010150138b408047280686f6c0065d14"
56
+ "gitHead": "1cda04828413aa2f83c4a6c16d2a6e409185df40"
57
57
  }
@@ -1,6 +1,15 @@
1
- import { AnonymousObject, CollectionService, reducer, service } from 'onekijs-framework';
1
+ import { AnonymousObject, CollectionService, get, reducer, service } from 'onekijs-framework';
2
2
  import React from 'react';
3
- import { TableColumn, TableColumnWidth, TableConfig, TableController, TableItem, TableState } from './typings';
3
+ import {
4
+ TableColumn,
5
+ TableColumnWidth,
6
+ TableConfig,
7
+ TableController,
8
+ TableItem,
9
+ TableSerializerFormat,
10
+ TableState,
11
+ } from './typings';
12
+ import { escapeCsvValue } from '../../utils/formatter';
4
13
 
5
14
  export const parseColumnWidth = (width: string | number = 'auto'): TableColumnWidth => {
6
15
  const regex = /^\s*(auto|(?:(?:([0-9]+)|(?:([0-9]+)\s*(px|%)))\s*(grow|force)?)|(grow))\s*$/;
@@ -98,6 +107,39 @@ class TableService<T = any, I extends TableItem<T> = TableItem<T>, S extends Tab
98
107
  });
99
108
  }
100
109
 
110
+ serialize(data: T[], format: TableSerializerFormat): string {
111
+ const serializer = this.config?.serializer;
112
+ if (serializer) {
113
+ return serializer(data, format);
114
+ }
115
+
116
+ const serializableColumns = (this.state.columns || []).filter((c) => c.serializer !== undefined);
117
+
118
+ switch(format) {
119
+ case 'csv':
120
+ let result = 'sep=,'
121
+ const header = serializableColumns.map((c) => escapeCsvValue(get(c, 'title', get(c, 'id')))).join(',')
122
+ result = `${result}\n${header}`
123
+ const csvRows = data.map((row) => {
124
+ const columns = serializableColumns
125
+ .map((c) => c.serializer!(row, c, format))
126
+ .map((s) => {
127
+ return escapeCsvValue(s, ',');
128
+ });
129
+ return columns.join(',');
130
+ });
131
+ return `${result}\n${csvRows.join('\n')}`;
132
+ case 'json':
133
+ const rows = data.map((row) => {
134
+ return serializableColumns.reduce((accumulator, c) => {
135
+ accumulator[c.title ?? c.id] = c.serializer!(row, c, format);
136
+ return accumulator;
137
+ }, {} as AnonymousObject);
138
+ });
139
+ return JSON.stringify(rows);
140
+ }
141
+ }
142
+
101
143
  @reducer
102
144
  toggle(item: I): void {
103
145
  this.setMeta('item', item, 'expanded', !item.expanded);
@@ -1,5 +1,6 @@
1
1
  import CheckboxCellComponent from '../components/cells/CheckboxCellComponent';
2
2
  import DefaultCellDisplayer from '../displayers/DefaultCellDisplayer';
3
+ import defaultCellSerializer from '../seralizers/defaultCellSerializer';
3
4
  import { CheckboxColumn, CheckboxColumnOptions, TableItem } from '../typings';
4
5
 
5
6
  const checkboxColumn = <T = any, I extends TableItem<T> = TableItem<T>>(
@@ -13,6 +14,7 @@ const checkboxColumn = <T = any, I extends TableItem<T> = TableItem<T>>(
13
14
  sortable: false,
14
15
  className: 'o-checkbox-cell',
15
16
  Displayer: DefaultCellDisplayer,
17
+ serializer: defaultCellSerializer,
16
18
  },
17
19
  options,
18
20
  {
@@ -1,13 +1,31 @@
1
1
  import React from 'react';
2
2
  import DefaultCellComponent from '../components/cells/DefaultCellComponent';
3
3
  import TableSelectFilterComponent from '../components/filters/TableSelectFilterComponent';
4
- import { EnumColumnOptions, TableColumn, TableHeaderCellProps, TableItem } from '../typings';
4
+ import { EnumColumnOptions, TableCellSerializer, TableColumn, TableHeaderCellProps, TableItem } from '../typings';
5
5
  import DefaultCellDisplayer from '../displayers/DefaultCellDisplayer';
6
+ import { get } from 'onekijs-framework';
7
+ import defaultCellSerializer from '../seralizers/defaultCellSerializer';
8
+
6
9
 
7
10
  const enumColumn = <T extends any = any, I extends TableItem<T> = TableItem<T>>(
8
11
  id: string,
9
12
  options: EnumColumnOptions<T, I>,
10
13
  ): TableColumn<T, I> => {
14
+ const serializer: TableCellSerializer<T, I> = (data: any, column, format) => {
15
+ const value = get(data, column.id, null);
16
+ const entry = (options.filterDataSource as any[]).find((item: any) => {
17
+ if (Array.isArray(item)) {
18
+ if (item[0] === value) {
19
+ return true;
20
+ }
21
+ }
22
+ return false;
23
+ })
24
+ if (entry) {
25
+ return entry[1];
26
+ }
27
+ return defaultCellSerializer(data, column, format);
28
+ }
11
29
  return Object.assign(
12
30
  {
13
31
  CellComponent: DefaultCellComponent,
@@ -17,6 +35,7 @@ const enumColumn = <T extends any = any, I extends TableItem<T> = TableItem<T>>(
17
35
  ),
18
36
  sortable: true,
19
37
  Displayer: DefaultCellDisplayer,
38
+ serializer,
20
39
  },
21
40
  options,
22
41
  {
@@ -1,5 +1,6 @@
1
1
  import InputCellComponent from '../components/cells/InputCellComponent';
2
2
  import DefaultCellDisplayer from '../displayers/DefaultCellDisplayer';
3
+ import defaultCellSerializer from '../seralizers/defaultCellSerializer';
3
4
  import { InputColumn, InputColumnOptions, TableItem } from '../typings';
4
5
 
5
6
  const inputColumn = <T extends any = any, I extends TableItem<T> = TableItem<T>>(
@@ -12,6 +13,7 @@ const inputColumn = <T extends any = any, I extends TableItem<T> = TableItem<T>>
12
13
  filterable: false,
13
14
  sortable: false,
14
15
  Displayer: DefaultCellDisplayer,
16
+ serializer: defaultCellSerializer,
15
17
  },
16
18
  options,
17
19
  {
@@ -1,6 +1,7 @@
1
1
  import DefaultCellComponent from '../components/cells/DefaultCellComponent';
2
2
  import TableNumberFilterComponent from '../components/filters/TableNumberFilterComponent';
3
3
  import DefaultCellDisplayer from '../displayers/DefaultCellDisplayer';
4
+ import defaultCellSerializer from '../seralizers/defaultCellSerializer';
4
5
  import { TableColumn, TableColumnOptions, TableItem } from '../typings';
5
6
 
6
7
  const numberColumn = <T = any, I extends TableItem<T> = TableItem<T>>(
@@ -14,6 +15,7 @@ const numberColumn = <T = any, I extends TableItem<T> = TableItem<T>>(
14
15
  FilterComponent: TableNumberFilterComponent,
15
16
  sortable: true,
16
17
  Displayer: DefaultCellDisplayer,
18
+ serializer: defaultCellSerializer,
17
19
  },
18
20
  options,
19
21
  {
@@ -1,8 +1,10 @@
1
+ import { get } from 'onekijs-framework';
1
2
  import DefaultSelectBroker from '../../select/SelectBroker';
2
3
  import { SelectItem, SelectItemAdapter } from '../../select/typings';
3
4
  import SelectCellComponent from '../components/cells/SelectCellComponent';
4
5
  import DefaultCellDisplayer from '../displayers/DefaultCellDisplayer';
5
- import { SelectCell, SelectColumn, SelectColumnOptions, TableItem } from '../typings';
6
+ import { SelectCell, SelectColumn, SelectColumnOptions, TableCellSerializer, TableItem } from '../typings';
7
+ import defaultCellSerializer from '../seralizers/defaultCellSerializer';
6
8
 
7
9
  const selectColumn = <
8
10
  T = any,
@@ -27,6 +29,25 @@ const selectColumn = <
27
29
  opts.adapter = adapter;
28
30
  }
29
31
 
32
+ const serializer: TableCellSerializer<T, TI> = (data: any, column, format) => {
33
+ const value = get(data, column.id, null);
34
+ if (Array.isArray(opts.dataSource)) {
35
+ const entry = (opts.dataSource as [S, string][]).find((item) => {
36
+ if (Array.isArray(item)) {
37
+ if (item[0] === value) {
38
+ return true;
39
+ }
40
+ }
41
+ return false;
42
+ })
43
+ if (entry && Array.isArray(entry)) {
44
+ return entry[1];
45
+ }
46
+ }
47
+
48
+ return defaultCellSerializer(data, column, format);
49
+ }
50
+
30
51
  const broker = new DefaultSelectBroker(dataSource, opts);
31
52
 
32
53
  const Component: SelectCell<T, S, TI, SI> = opts.CellComponent || (SelectCellComponent as any);
@@ -36,6 +57,7 @@ const selectColumn = <
36
57
  filterable: false,
37
58
  sortable: false,
38
59
  Displayer: DefaultCellDisplayer,
60
+ serializer,
39
61
  },
40
62
  opts,
41
63
  {
@@ -1,6 +1,7 @@
1
1
  import DefaultCellComponent from '../components/cells/DefaultCellComponent';
2
2
  import TableTextFilterComponent from '../components/filters/TableTextFilterComponent';
3
3
  import DefaultCellDisplayer from '../displayers/DefaultCellDisplayer';
4
+ import defaultCellSerializer from '../seralizers/defaultCellSerializer';
4
5
  import { TableColumn, TableColumnOptions, TableItem } from '../typings';
5
6
 
6
7
  const textColumn = <T = any, I extends TableItem<T> = TableItem<T>>(
@@ -14,6 +15,7 @@ const textColumn = <T = any, I extends TableItem<T> = TableItem<T>>(
14
15
  FilterComponent: TableTextFilterComponent,
15
16
  sortable: true,
16
17
  Displayer: DefaultCellDisplayer,
18
+ serializer: defaultCellSerializer,
17
19
  },
18
20
  options,
19
21
  {
@@ -1,5 +1,6 @@
1
1
  import TextareaCellComponent from '../components/cells/TextareaCellComponent';
2
2
  import DefaultCellDisplayer from '../displayers/DefaultCellDisplayer';
3
+ import defaultCellSerializer from '../seralizers/defaultCellSerializer';
3
4
  import { TableItem, TextareaColumn, TextareaColumnOptions } from '../typings';
4
5
 
5
6
  const textareaColumn = <T = any, I extends TableItem<T> = TableItem<T>>(
@@ -13,6 +14,7 @@ const textareaColumn = <T = any, I extends TableItem<T> = TableItem<T>>(
13
14
  filterable: false,
14
15
  sortable: false,
15
16
  Displayer: DefaultCellDisplayer,
17
+ serializer: defaultCellSerializer,
16
18
  },
17
19
  options,
18
20
  {
@@ -0,0 +1,8 @@
1
+ import { get } from 'onekijs-framework';
2
+ import { TableCellSerializer } from '../typings';
3
+
4
+ const defaultCellSerializer: TableCellSerializer<any, any> = (data, column) => {
5
+ return get(data, column.id, null);
6
+ }
7
+
8
+ export default defaultCellSerializer;
@@ -133,6 +133,8 @@ export type TableBodyRowProps<T = any, I extends TableItem<T> = TableItem<T>> =
133
133
  onCollapsed?: (item: I | undefined, index: number) => void;
134
134
  };
135
135
 
136
+ export type TableSerializerFormat = 'csv' | 'json'
137
+
136
138
  export type TableConfig<T = any, I extends TableItem<T> = TableItem<T>> = {
137
139
  autoRefresh?: number;
138
140
  bodyClassName?: string;
@@ -168,6 +170,7 @@ export type TableConfig<T = any, I extends TableItem<T> = TableItem<T>> = {
168
170
  preload?: number;
169
171
  rowClassName?: string | ((item: I | undefined, rowIndex: number, columns: TableColumn<T, I>[]) => string);
170
172
  RowComponent?: React.FC<TableBodyRowProps<T, I>>;
173
+ serializer?: (data: T[], format: TableSerializerFormat) => string;
171
174
  sortable?: boolean;
172
175
  stripRows?: boolean;
173
176
  tail?: boolean;
@@ -200,6 +203,7 @@ export type TableController<
200
203
  by: B,
201
204
  target: CollectionBy<T, I>[B] | CollectionBy<T, I>[B][],
202
205
  ): I[];
206
+ serialize: (data: T[], format: TableSerializerFormat) => string;
203
207
  setSelected<B extends keyof CollectionBy<T, I>>(by: B, target: CollectionBy<T, I>[B] | CollectionBy<T, I>[B][]): I[];
204
208
  startAutoRefresh: (interval: number) => void;
205
209
  stopAutoRefresh: () => void;
@@ -223,6 +227,8 @@ export type TableCellDisplayerProps<T, I extends TableItem<T> = TableItem<T>> =
223
227
  format: FormDisplayerProps['format'];
224
228
  };
225
229
 
230
+ export type TableCellSerializer<T, I extends TableItem<T> = TableItem<T>> = (data: T, column: TableColumn<T, I>, format: TableSerializerFormat) => any;
231
+
226
232
  export type TableColumnSpec<T, I extends TableItem<T> = TableItem<T>> = {
227
233
  className?: string | ((item: I, column: TableColumn<T, I>, rowIndex: number) => string);
228
234
  CellComponent?: Cell<T, I>;
@@ -233,15 +239,16 @@ export type TableColumnSpec<T, I extends TableItem<T> = TableItem<T>> = {
233
239
  filterable?: boolean;
234
240
  FilterComponent?: React.FC<TableHeaderCellProps<T, I>>;
235
241
  headerClassName?: string | ((column: TableColumn<T, I>) => string);
242
+ help?: ReactNode;
236
243
  id: string;
237
244
  maxWidth?: string;
238
245
  minWidth?: string;
246
+ serializer?: TableCellSerializer<T, I>;
239
247
  sortable?: boolean;
240
248
  title?: string;
241
249
  TitleComponent?: React.FC<TableHeaderCellProps<T, I>>;
242
250
  weight?: number;
243
251
  width?: string;
244
- help?: ReactNode;
245
252
  };
246
253
 
247
254
  export type TableColumnWidth = {
package/src/index.ts CHANGED
@@ -304,6 +304,8 @@ export {
304
304
  TextareaColumnOptions,
305
305
  UseTableController,
306
306
  UseTableOptions,
307
+ TableCellSerializer,
308
+ TableSerializerFormat
307
309
  } from './components/table/typings';
308
310
  export { default as Tag } from './components/tag';
309
311
  export { default as TagComponent } from './components/tag/components/TagComponent';
@@ -326,6 +328,7 @@ export { default as ArrayTreeComponent } from './components/tree/components/Arra
326
328
  export { default as ControllerTreeComponent } from './components/tree/components/ControllerTreeComponent';
327
329
  export { default as TreeBodyComponent } from './components/tree/components/TreeBodyComponent';
328
330
  export { default as TreeComponent } from './components/tree/components/TreeComponent';
331
+ export { default as defaultCellSerializer } from './components/table/seralizers/defaultCellSerializer';
329
332
  export {
330
333
  default as TreeItemComponent,
331
334
  TreeItemContent,
@@ -39,6 +39,26 @@ export const enumFormatter = <T>(values: AnonymousObject): Formatter<T> => {
39
39
  };
40
40
  };
41
41
 
42
+
43
+
44
+ export const escapeCsvValue = (value: any, separator = ','): string => {
45
+ const escape = (value: any): string => {
46
+ if (Array.isArray(value)) {
47
+ return value.map((v) => escape(v)).join(',');
48
+ }
49
+ if (value === null || value === undefined) return '';
50
+ return `${value}`;
51
+ }
52
+
53
+ const result = escape(value);
54
+ if (result.startsWith('"') && result.endsWith('"')) return result; // the string is already escaped
55
+ // escape only if the string contains the separator
56
+ if (result.includes(separator)) {
57
+ return `"${result.replace(/"/g, '""')}"`
58
+ }
59
+ return result;
60
+ }
61
+
42
62
  export const pxFormatter: Formatter<string | number> = (value) => {
43
63
  if (typeof value === 'string') {
44
64
  return value;