onekijs-ui 0.19.19 → 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.
@@ -15,6 +15,7 @@ export type DropdownProps = {
15
15
  onCollapsing?: (node: HTMLElement) => void;
16
16
  animationTimeout?: number;
17
17
  placement?: Placement;
18
+ fallbackPlacements?: Placement[];
18
19
  widthModifier?: DropdownWidthModifier;
19
20
  width?: string;
20
21
  zIndex?: number;
@@ -1,6 +1,6 @@
1
1
  import { AnonymousObject, CollectionService } from 'onekijs-framework';
2
2
  import React from 'react';
3
- import { TableColumn, TableColumnWidth, TableConfig, TableController, TableItem, TableState } from './typings';
3
+ import { TableColumn, TableColumnWidth, TableConfig, TableController, TableItem, TableSerializerFormat, TableState } from './typings';
4
4
  export declare const parseColumnWidth: (width?: string | number) => TableColumnWidth;
5
5
  declare class TableService<T = any, I extends TableItem<T> = TableItem<T>, S extends TableState<T, I> = TableState<T, I>> extends CollectionService<T, I, S> implements TableController<T, I> {
6
6
  protected cells: AnonymousObject<AnonymousObject<React.RefObject<HTMLDivElement>>>;
@@ -13,6 +13,7 @@ declare class TableService<T = any, I extends TableItem<T> = TableItem<T>, S ext
13
13
  initCell(rowNumber: number | 'header-title' | 'header-filter' | 'footer', colId: string, ref: React.RefObject<HTMLDivElement>): void;
14
14
  removeColumn(id: string): void;
15
15
  resetWidth(): void;
16
+ serialize(data: T[], format: TableSerializerFormat): string;
16
17
  toggle(item: I): void;
17
18
  protected _setCellWidth(fit: boolean): void;
18
19
  }
@@ -0,0 +1,3 @@
1
+ import { TableCellSerializer } from '../typings';
2
+ declare const defaultCellSerializer: TableCellSerializer<any, any>;
3
+ export default defaultCellSerializer;
@@ -92,6 +92,7 @@ export type TableBodyRowProps<T = any, I extends TableItem<T> = TableItem<T>> =
92
92
  onCollapsing?: (item: I | undefined, index: number) => void;
93
93
  onCollapsed?: (item: I | undefined, index: number) => void;
94
94
  };
95
+ export type TableSerializerFormat = 'csv' | 'json';
95
96
  export type TableConfig<T = any, I extends TableItem<T> = TableItem<T>> = {
96
97
  autoRefresh?: number;
97
98
  bodyClassName?: string;
@@ -127,6 +128,7 @@ export type TableConfig<T = any, I extends TableItem<T> = TableItem<T>> = {
127
128
  preload?: number;
128
129
  rowClassName?: string | ((item: I | undefined, rowIndex: number, columns: TableColumn<T, I>[]) => string);
129
130
  RowComponent?: React.FC<TableBodyRowProps<T, I>>;
131
+ serializer?: (data: T[], format: TableSerializerFormat) => string;
130
132
  sortable?: boolean;
131
133
  stripRows?: boolean;
132
134
  tail?: boolean;
@@ -147,6 +149,7 @@ export type TableController<T = any, I extends TableItem<T> = TableItem<T>, S ex
147
149
  initCell(rowIndex: number | 'header-title' | 'header-filter' | 'footer', colId: string, ref: React.RefObject<HTMLDivElement>): void;
148
150
  removeColumn(id: string): void;
149
151
  removeSelected<B extends keyof CollectionBy<T, I>>(by: B, target: CollectionBy<T, I>[B] | CollectionBy<T, I>[B][]): I[];
152
+ serialize: (data: T[], format: TableSerializerFormat) => string;
150
153
  setSelected<B extends keyof CollectionBy<T, I>>(by: B, target: CollectionBy<T, I>[B] | CollectionBy<T, I>[B][]): I[];
151
154
  startAutoRefresh: (interval: number) => void;
152
155
  stopAutoRefresh: () => void;
@@ -167,6 +170,7 @@ export type TableCellDisplayerProps<T, I extends TableItem<T> = TableItem<T>> =
167
170
  value: T;
168
171
  format: FormDisplayerProps['format'];
169
172
  };
173
+ export type TableCellSerializer<T, I extends TableItem<T> = TableItem<T>> = (data: T, column: TableColumn<T, I>, format: TableSerializerFormat) => any;
170
174
  export type TableColumnSpec<T, I extends TableItem<T> = TableItem<T>> = {
171
175
  className?: string | ((item: I, column: TableColumn<T, I>, rowIndex: number) => string);
172
176
  CellComponent?: Cell<T, I>;
@@ -177,15 +181,16 @@ export type TableColumnSpec<T, I extends TableItem<T> = TableItem<T>> = {
177
181
  filterable?: boolean;
178
182
  FilterComponent?: React.FC<TableHeaderCellProps<T, I>>;
179
183
  headerClassName?: string | ((column: TableColumn<T, I>) => string);
184
+ help?: ReactNode;
180
185
  id: string;
181
186
  maxWidth?: string;
182
187
  minWidth?: string;
188
+ serializer?: TableCellSerializer<T, I>;
183
189
  sortable?: boolean;
184
190
  title?: string;
185
191
  TitleComponent?: React.FC<TableHeaderCellProps<T, I>>;
186
192
  weight?: number;
187
193
  width?: string;
188
- help?: ReactNode;
189
194
  };
190
195
  export type TableColumnWidth = {
191
196
  auto?: boolean;
package/dist/index.d.ts CHANGED
@@ -160,7 +160,7 @@ export { default as useTextColumn } from './components/table/hooks/useTextColumn
160
160
  export { default as useTextareaColumn } from './components/table/hooks/useTextareaColumn';
161
161
  export { default as FormCardDisplayer } from './components/card/FormCardDisplayer';
162
162
  export { filterListStyle, tableStyle } from './components/table/style';
163
- export { ArrayTableProps, Cell, CheckboxColumn, CheckboxColumnOptions, ControllerTableProps, EnumColumnOptions, FormCellDisplayerProps, FormTableContext, FormTableItemDisplayerProps, FormTableProps, TableValueDisplayerProps, InputColumn, InputColumnOptions, LinkColumnOptions, SelectCell, SelectColumn, SelectColumnOptions, TableBodyCellProps, TableBodyProps, TableBodyRowProps, TableCellDisplayerProps, TableColumn, TableColumnComputedWidth, TableColumnOptions, TableColumnSpec, TableColumnWidth, TableColumnsState, TableConfig, TableController, TableExpandedProps, TableFilterOperator, TableFilterOperatorProps, TableFooterCellProps, TableFooterProps, TableHeaderCellProps, TableHeaderProps, TableItem, TableItemAdaptee, TableItemAdapter, TableItems, TableNotFoundProps, TableProps, TableRowHandler, TableSortProps, TableState, TextareaColumn, TextareaColumnOptions, UseTableController, UseTableOptions, } from './components/table/typings';
163
+ export { ArrayTableProps, Cell, CheckboxColumn, CheckboxColumnOptions, ControllerTableProps, EnumColumnOptions, FormCellDisplayerProps, FormTableContext, FormTableItemDisplayerProps, FormTableProps, TableValueDisplayerProps, InputColumn, InputColumnOptions, LinkColumnOptions, SelectCell, SelectColumn, SelectColumnOptions, TableBodyCellProps, TableBodyProps, TableBodyRowProps, TableCellDisplayerProps, TableColumn, TableColumnComputedWidth, TableColumnOptions, TableColumnSpec, TableColumnWidth, TableColumnsState, TableConfig, TableController, TableExpandedProps, TableFilterOperator, TableFilterOperatorProps, TableFooterCellProps, TableFooterProps, TableHeaderCellProps, TableHeaderProps, TableItem, TableItemAdaptee, TableItemAdapter, TableItems, TableNotFoundProps, TableProps, TableRowHandler, TableSortProps, TableState, TextareaColumn, TextareaColumnOptions, UseTableController, UseTableOptions, TableCellSerializer, TableSerializerFormat } from './components/table/typings';
164
164
  export { default as Tag } from './components/tag';
165
165
  export { default as TagComponent } from './components/tag/components/TagComponent';
166
166
  export { tagStyle } from './components/tag/style';
@@ -182,6 +182,7 @@ export { default as ArrayTreeComponent } from './components/tree/components/Arra
182
182
  export { default as ControllerTreeComponent } from './components/tree/components/ControllerTreeComponent';
183
183
  export { default as TreeBodyComponent } from './components/tree/components/TreeBodyComponent';
184
184
  export { default as TreeComponent } from './components/tree/components/TreeComponent';
185
+ export { default as defaultCellSerializer } from './components/table/seralizers/defaultCellSerializer';
185
186
  export { default as TreeItemComponent, TreeItemContent, TreeItemToggler, } from './components/tree/components/TreeItemComponent';
186
187
  export { default as TreeListComponent } from './components/tree/components/TreeListComponent';
187
188
  export { default as VirtualTreeBodyComponent } from './components/tree/components/VirtualTreeBodyComponent';
package/dist/index.js CHANGED
@@ -405,6 +405,24 @@ const enumFormatter = (values) => {
405
405
  return String(value);
406
406
  };
407
407
  };
408
+ const escapeCsvValue = (value, separator = ',') => {
409
+ const escape = (value) => {
410
+ if (Array.isArray(value)) {
411
+ return value.map((v) => escape(v)).join(',');
412
+ }
413
+ if (value === null || value === undefined)
414
+ return '';
415
+ return `${value}`;
416
+ };
417
+ const result = escape(value);
418
+ if (result.startsWith('"') && result.endsWith('"'))
419
+ return result; // the string is already escaped
420
+ // escape only if the string contains the separator
421
+ if (result.includes(separator)) {
422
+ return `"${result.replace(/"/g, '""')}"`;
423
+ }
424
+ return result;
425
+ };
408
426
  const pxFormatter = (value) => {
409
427
  if (typeof value === 'string') {
410
428
  return value;
@@ -1094,7 +1112,7 @@ const sameWidthPopperModifier = refWidth('width');
1094
1112
  const minWidthPopperModifier = refWidth('minWidth');
1095
1113
  const maxWidthPopperModifier = refWidth('maxWidth');
1096
1114
 
1097
- const DropdownComponent = ({ animationTimeout = 0, attachToBody = false, className, refElement, open, children, skidding = 0, distance = 0, onUpdate, onDropDone, onDropStart, onCollapseDone, onCollapseStart, onDropping, onCollapsing, placement = 'auto', width, widthModifier = 'same', zIndex = 1, }) => {
1115
+ const DropdownComponent = ({ animationTimeout = 0, attachToBody = false, className, refElement, open, children, skidding = 0, distance = 0, onUpdate, onDropDone, onDropStart, onCollapseDone, onCollapseStart, onDropping, onCollapsing, placement = 'auto', fallbackPlacements, width, widthModifier = 'same', zIndex = 1, }) => {
1098
1116
  const [popperElement, setPopperElement] = React.useState(null);
1099
1117
  const popperWidthModifier = widthModifier === 'same'
1100
1118
  ? sameWidthPopperModifier
@@ -1113,7 +1131,8 @@ const DropdownComponent = ({ animationTimeout = 0, attachToBody = false, classNa
1113
1131
  },
1114
1132
  {
1115
1133
  name: 'flip',
1116
- enabled: placement === 'auto',
1134
+ enabled: placement === 'auto' || (fallbackPlacements !== undefined && fallbackPlacements.length > 0),
1135
+ options: fallbackPlacements && fallbackPlacements.length > 0 ? { fallbackPlacements } : undefined,
1117
1136
  },
1118
1137
  {
1119
1138
  name: 'eventListeners',
@@ -9181,6 +9200,36 @@ let TableService = class TableService extends onekijsFramework.CollectionService
9181
9200
  column.computedWidth = undefined;
9182
9201
  });
9183
9202
  }
9203
+ serialize(data, format) {
9204
+ const serializer = this.config?.serializer;
9205
+ if (serializer) {
9206
+ return serializer(data, format);
9207
+ }
9208
+ const serializableColumns = (this.state.columns || []).filter((c) => c.serializer !== undefined);
9209
+ switch (format) {
9210
+ case 'csv':
9211
+ let result = 'sep=,';
9212
+ const header = serializableColumns.map((c) => escapeCsvValue(onekijsFramework.get(c, 'title', onekijsFramework.get(c, 'id')))).join(',');
9213
+ result = `${result}\n${header}`;
9214
+ const csvRows = data.map((row) => {
9215
+ const columns = serializableColumns
9216
+ .map((c) => c.serializer(row, c, format))
9217
+ .map((s) => {
9218
+ return escapeCsvValue(s, ',');
9219
+ });
9220
+ return columns.join(',');
9221
+ });
9222
+ return `${result}\n${csvRows.join('\n')}`;
9223
+ case 'json':
9224
+ const rows = data.map((row) => {
9225
+ return serializableColumns.reduce((accumulator, c) => {
9226
+ accumulator[c.title ?? c.id] = c.serializer(row, c, format);
9227
+ return accumulator;
9228
+ }, {});
9229
+ });
9230
+ return JSON.stringify(rows);
9231
+ }
9232
+ }
9184
9233
  toggle(item) {
9185
9234
  this.setMeta('item', item, 'expanded', !item.expanded);
9186
9235
  }
@@ -10481,6 +10530,10 @@ const DefaultFormCellDisplayer = (props) => {
10481
10530
  return null;
10482
10531
  };
10483
10532
 
10533
+ const defaultCellSerializer = (data, column) => {
10534
+ return onekijsFramework.get(data, column.id, null);
10535
+ };
10536
+
10484
10537
  const checkboxColumn = (id, options) => {
10485
10538
  const Component = options.CellComponent || CheckboxCellComponent;
10486
10539
  return Object.assign({
@@ -10488,6 +10541,7 @@ const checkboxColumn = (id, options) => {
10488
10541
  sortable: false,
10489
10542
  className: 'o-checkbox-cell',
10490
10543
  Displayer: DefaultFormCellDisplayer,
10544
+ serializer: defaultCellSerializer,
10491
10545
  }, options, {
10492
10546
  id,
10493
10547
  CellComponent: Component(options),
@@ -10540,12 +10594,28 @@ const TableSelectFilterComponent = ({ column, dataSource, }) => {
10540
10594
  TableSelectFilterComponent.displayName = 'TableInputFilterComponent';
10541
10595
 
10542
10596
  const enumColumn = (id, options) => {
10597
+ const serializer = (data, column, format) => {
10598
+ const value = onekijsFramework.get(data, column.id, null);
10599
+ const entry = options.filterDataSource.find((item) => {
10600
+ if (Array.isArray(item)) {
10601
+ if (item[0] === value) {
10602
+ return true;
10603
+ }
10604
+ }
10605
+ return false;
10606
+ });
10607
+ if (entry) {
10608
+ return entry[1];
10609
+ }
10610
+ return defaultCellSerializer(data, column);
10611
+ };
10543
10612
  return Object.assign({
10544
10613
  CellComponent: DefaultCellComponent,
10545
10614
  filterable: true,
10546
10615
  FilterComponent: (props) => (React.createElement(TableSelectFilterComponent, { ...props, dataSource: options.filterDataSource })),
10547
10616
  sortable: true,
10548
10617
  Displayer: DefaultFormCellDisplayer,
10618
+ serializer,
10549
10619
  }, options, {
10550
10620
  id,
10551
10621
  });
@@ -10569,6 +10639,7 @@ const inputColumn = (id, options) => {
10569
10639
  filterable: false,
10570
10640
  sortable: false,
10571
10641
  Displayer: DefaultFormCellDisplayer,
10642
+ serializer: defaultCellSerializer,
10572
10643
  }, options, {
10573
10644
  id,
10574
10645
  CellComponent: Component(options),
@@ -10592,6 +10663,7 @@ const textColumn = (id, options) => {
10592
10663
  FilterComponent: TableTextFilterComponent,
10593
10664
  sortable: true,
10594
10665
  Displayer: DefaultFormCellDisplayer,
10666
+ serializer: defaultCellSerializer,
10595
10667
  }, options, {
10596
10668
  id,
10597
10669
  });
@@ -10623,6 +10695,7 @@ const numberColumn = (id, options) => {
10623
10695
  FilterComponent: TableNumberFilterComponent,
10624
10696
  sortable: true,
10625
10697
  Displayer: DefaultFormCellDisplayer,
10698
+ serializer: defaultCellSerializer,
10626
10699
  }, options, {
10627
10700
  id,
10628
10701
  });
@@ -10662,12 +10735,30 @@ const selectColumn = (id, options) => {
10662
10735
  };
10663
10736
  opts.adapter = adapter;
10664
10737
  }
10738
+ const serializer = (data, column, format) => {
10739
+ const value = onekijsFramework.get(data, column.id, null);
10740
+ if (Array.isArray(opts.dataSource)) {
10741
+ const entry = opts.dataSource.find((item) => {
10742
+ if (Array.isArray(item)) {
10743
+ if (item[0] === value) {
10744
+ return true;
10745
+ }
10746
+ }
10747
+ return false;
10748
+ });
10749
+ if (entry && Array.isArray(entry)) {
10750
+ return entry[1];
10751
+ }
10752
+ }
10753
+ return defaultCellSerializer(data, column);
10754
+ };
10665
10755
  const broker = new DefaultSelectBroker(dataSource, opts);
10666
10756
  const Component = opts.CellComponent || SelectCellComponent;
10667
10757
  return Object.assign({
10668
10758
  filterable: false,
10669
10759
  sortable: false,
10670
10760
  Displayer: DefaultFormCellDisplayer,
10761
+ serializer,
10671
10762
  }, opts, {
10672
10763
  id,
10673
10764
  CellComponent: Component(opts, broker),
@@ -10819,6 +10910,7 @@ const textareaColumn = (id, options) => {
10819
10910
  filterable: false,
10820
10911
  sortable: false,
10821
10912
  Displayer: DefaultFormCellDisplayer,
10913
+ serializer: defaultCellSerializer,
10822
10914
  }, options, {
10823
10915
  id,
10824
10916
  CellComponent: Component(options),
@@ -12610,6 +12702,7 @@ exports.cssProperty = cssProperty;
12610
12702
  exports.cursor = cursor;
12611
12703
  exports.darken = darken;
12612
12704
  exports.dashboardOverlayStyle = dashboardOverlayStyle;
12705
+ exports.defaultCellSerializer = defaultCellSerializer;
12613
12706
  exports.defaultTreeQueryEngine = defaultTreeQueryEngine;
12614
12707
  exports.deriveColor = deriveColor;
12615
12708
  exports.display = display;
@@ -12618,6 +12711,7 @@ exports.dropdownStyle = dropdownStyle;
12618
12711
  exports.emptyCells = emptyCells;
12619
12712
  exports.enumColumn = enumColumn;
12620
12713
  exports.enumFormatter = enumFormatter;
12714
+ exports.escapeCsvValue = escapeCsvValue;
12621
12715
  exports.fieldDescriptionStyle = fieldDescriptionStyle;
12622
12716
  exports.fieldDisplayerStyle = fieldDisplayerStyle;
12623
12717
  exports.fieldHelpStyle = fieldHelpStyle;