@singularsystems/neo-react 1.0.16 → 1.0.18

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.
@@ -66,10 +66,15 @@ var ReactModelCreator = /** @class */ (function (_super) {
66
66
  makeObservable(object, annotations, { proxy: false });
67
67
  // Setup once properties have been converted to observables.
68
68
  for (var propertyKey in observables) {
69
- var property = observables[propertyKey];
70
- this.addChangeTracking(object, propertyKey, property);
71
- if (property.convertList) {
72
- this.setupList(object, propertyKey, property.convertList);
69
+ try {
70
+ var property = observables[propertyKey];
71
+ this.addChangeTracking(object, propertyKey, property);
72
+ if (property.convertList) {
73
+ this.setupList(object, propertyKey, property.convertList);
74
+ }
75
+ }
76
+ catch (e) {
77
+ throw "Error setting up property '".concat(propertyKey, "' on type '").concat(typeInfo.typeName, "': ").concat(e);
73
78
  }
74
79
  }
75
80
  };
@@ -58,7 +58,10 @@ export interface IGridProps<T> extends Omit<React.HTMLProps<HTMLTableElement>, "
58
58
  * This is the default unless overridden in Misc.Settings.grid
59
59
  */
60
60
  isBordered?: boolean;
61
- /** When specified, every alternating row will receive a slightly darker background color. */
61
+ /**
62
+ * When specified, every alternating row will receive a slightly darker background color.
63
+ * Note, this will not work correctly if your grid has child rows. See the neo react demo pages for a solution.
64
+ */
62
65
  isStriped?: boolean;
63
66
  /** When specified, the table will have no cell borders, and the table will have no main border. */
64
67
  isBorderless?: boolean;
@@ -79,6 +82,11 @@ export interface IGridProps<T> extends Omit<React.HTMLProps<HTMLTableElement>, "
79
82
  * Note: if your app has a fixed header, you need to specify this in the global neo settings.
80
83
  */
81
84
  stickyHeader?: boolean;
85
+ /**
86
+ * When true, the index parameter passed to the render function will be set.
87
+ * This has performance implications, as each row needs to be re-rendered on sorting or insertion of items.
88
+ */
89
+ enableRowIndexes?: boolean;
82
90
  }
83
91
  export default class Grid<T> extends React.Component<IGridProps<T>> {
84
92
  static contextType: React.Context<import("../../React/DataView").DataViewContextParams<unknown>>;
@@ -45,7 +45,7 @@ var Grid = /** @class */ (function (_super) {
45
45
  };
46
46
  Grid.prototype.render = function () {
47
47
  var _this = this;
48
- var _a = this.props, items = _a.items, showAddButton = _a.showAddButton, addButton = _a.addButton, filterPredicate = _a.filterPredicate, keyProperty = _a.keyProperty, allowSort = _a.allowSort, expandAll = _a.expandAll, collapseAll = _a.collapseAll, initialSort = _a.initialSort, initialSortAscending = _a.initialSortAscending, isBordered = _a.isBordered, isStriped = _a.isStriped, isBorderless = _a.isBorderless, showHover = _a.showHover, isSmallTable = _a.isSmallTable, footerContent = _a.footerContent, footerButtons = _a.footerButtons, stickyHeader = _a.stickyHeader, domProps = __rest(_a, ["items", "showAddButton", "addButton", "filterPredicate", "keyProperty", "allowSort", "expandAll", "collapseAll", "initialSort", "initialSortAscending", "isBordered", "isStriped", "isBorderless", "showHover", "isSmallTable", "footerContent", "footerButtons", "stickyHeader"]);
48
+ var _a = this.props, items = _a.items, showAddButton = _a.showAddButton, addButton = _a.addButton, filterPredicate = _a.filterPredicate, keyProperty = _a.keyProperty, allowSort = _a.allowSort, expandAll = _a.expandAll, collapseAll = _a.collapseAll, initialSort = _a.initialSort, initialSortAscending = _a.initialSortAscending, isBordered = _a.isBordered, isStriped = _a.isStriped, isBorderless = _a.isBorderless, showHover = _a.showHover, isSmallTable = _a.isSmallTable, footerContent = _a.footerContent, footerButtons = _a.footerButtons, stickyHeader = _a.stickyHeader, enableRowIndexes = _a.enableRowIndexes, domProps = __rest(_a, ["items", "showAddButton", "addButton", "filterPredicate", "keyProperty", "allowSort", "expandAll", "collapseAll", "initialSort", "initialSortAscending", "isBordered", "isStriped", "isBorderless", "showHover", "isSmallTable", "footerContent", "footerButtons", "stickyHeader", "enableRowIndexes"]);
49
49
  if (expandAll === true) {
50
50
  this.gridContext.expandAll = true;
51
51
  }
@@ -101,12 +101,12 @@ var Grid = /** @class */ (function (_super) {
101
101
  }
102
102
  return (React.createElement("table", __assign({}, domProps, { className: className, ref: this.domRef }),
103
103
  React.createElement(GridContext.Provider, { value: this.gridContext },
104
- React.createElement(TableSection, { type: "header" }, this.headerItem && this.props.children(this.headerItem, this.headerItem.meta, true)),
105
- React.createElement(TableSection, { type: "body" }, this.gridContext.dataView.getItems().map(function (item) { return (React.createElement(ItemGroup, { item: item, key: keyProperty ? item[keyProperty] : item.entityIdentifier, template: _this.props.children })); })),
104
+ React.createElement(TableSection, { type: "header" }, this.headerItem && this.props.children(this.headerItem, this.headerItem.meta, true, -1)),
105
+ React.createElement(TableSection, { type: "body" }, this.gridContext.dataView.getItems().map(function (item, index) { return (React.createElement(ItemGroup, { index: enableRowIndexes ? index : 0, item: item, key: keyProperty ? item[keyProperty] : item.entityIdentifier, template: _this.props.children })); })),
106
106
  React.createElement(Observer, null, function () {
107
107
  return React.createElement(React.Fragment, null, (showAddButton || addButton || footerButtons || _this.gridContext.hasSummaries || footerContent !== undefined) &&
108
108
  React.createElement(TableSection, { type: "footer" },
109
- _this.gridContext.hasSummaries && _this.headerItem && _this.props.children(_this.headerItem, _this.headerItem.meta, true),
109
+ _this.gridContext.hasSummaries && _this.headerItem && _this.props.children(_this.headerItem, _this.headerItem.meta, true, -1),
110
110
  footerContent !== undefined && footerContent(_this.gridContext.dataView.getItems()),
111
111
  (showAddButton || addButton || footerButtons) &&
112
112
  React.createElement(AddButtonRow, { addButton: addButton, showAddButton: showAddButton, additionalContent: footerButtons })));
@@ -207,8 +207,7 @@ var ItemGroup = /** @class */ (function (_super) {
207
207
  }
208
208
  ItemGroup.prototype.render = function () {
209
209
  this.context.currentItem = this.props.item;
210
- //this.context.inFirstRowInGroup = true;
211
- return (this.props.template(this.props.item, this.props.item.meta, false));
210
+ return this.props.template(this.props.item, this.props.item.meta, false, this.props.index);
212
211
  };
213
212
  ItemGroup.contextType = GridContext;
214
213
  ItemGroup = __decorate([
@@ -13,6 +13,8 @@ interface IRowProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLTab
13
13
  * Handler for click events on header or footer rows. The section is passed as the first argument.
14
14
  */
15
15
  onHeaderClick?: (section: GridSection, e: React.MouseEvent<HTMLTableRowElement, MouseEvent>) => void;
16
+ /** Class name that will not be applied to headers. */
17
+ bodyClassName?: string;
16
18
  }
17
19
  interface IState {
18
20
  isExpanded: boolean;
@@ -57,12 +59,14 @@ export declare class ChildRow extends ComponentBase<INeoChildRowProps> {
57
59
  lastExpandValue: boolean | null;
58
60
  expandProperty?: Model.IPropertyInstance;
59
61
  inBody?: boolean;
62
+ margin: number;
60
63
  containerDiv: React.RefObject<HTMLDivElement>;
61
64
  private get isExpanded();
62
65
  protected onFirstRender(): void;
63
66
  protected afterRender(isInitial: boolean): void;
64
67
  private afterTransition;
65
68
  private setHeight;
69
+ private fixPadding;
66
70
  render(): false | React.JSX.Element | undefined;
67
71
  }
68
72
  interface INeoRowGroupProps {
@@ -53,7 +53,7 @@ var Row = /** @class */ (function (_super) {
53
53
  Row.prototype.render = function () {
54
54
  var _this = this;
55
55
  _super.prototype.onRender.call(this);
56
- var _a = this.props, showInHeader = _a.showInHeader, onHeaderClick = _a.onHeaderClick, domProps = __rest(_a, ["showInHeader", "onHeaderClick"]);
56
+ var _a = this.props, showInHeader = _a.showInHeader, onHeaderClick = _a.onHeaderClick, bodyClassName = _a.bodyClassName, domProps = __rest(_a, ["showInHeader", "onHeaderClick", "bodyClassName"]);
57
57
  var inBody = this.section === "body";
58
58
  if (this.stateObserver)
59
59
  this.stateObserver.observe();
@@ -61,11 +61,16 @@ var Row = /** @class */ (function (_super) {
61
61
  throw "NeoGrid.Row cannot be used outside of a NeoGrid.";
62
62
  }
63
63
  var expandButtonOptions = __assign({}, Misc.Settings.grid.expandButton);
64
- if (inBody && this.expandProperty) {
65
- expandButtonOptions.onClick = this.onExpandClick;
66
- expandButtonOptions.icon = this.expandProperty.value ? Misc.Settings.icons.expanded : Misc.Settings.icons.collapsed;
64
+ if (inBody) {
65
+ if (this.expandProperty) {
66
+ expandButtonOptions.onClick = this.onExpandClick;
67
+ expandButtonOptions.icon = this.expandProperty.value ? Misc.Settings.icons.expanded : Misc.Settings.icons.collapsed;
68
+ }
69
+ if (bodyClassName) {
70
+ domProps.className = Utils.joinWithSpaces(domProps.className, bodyClassName);
71
+ }
67
72
  }
68
- if (!inBody) {
73
+ else {
69
74
  if (onHeaderClick) {
70
75
  domProps.onClick = function (e) { return onHeaderClick(_this.section, e); };
71
76
  }
@@ -95,6 +100,7 @@ var ChildRow = /** @class */ (function (_super) {
95
100
  var _this = _super.call(this, props) || this;
96
101
  _this.wasExpanded = false;
97
102
  _this.lastExpandValue = null;
103
+ _this.margin = 0;
98
104
  _this.containerDiv = React.createRef();
99
105
  _this.afterTransition = _this.afterTransition.bind(_this);
100
106
  _this.afterRender = _this.afterRender.bind(_this);
@@ -125,8 +131,12 @@ var ChildRow = /** @class */ (function (_super) {
125
131
  };
126
132
  ChildRow.prototype.afterTransition = function () {
127
133
  if (this.containerDiv.current) {
128
- this.containerDiv.current.style.maxHeight = 'none';
129
- this.containerDiv.current.style.overflow = "visible";
134
+ if (this.isExpanded) {
135
+ var childDiv = this.containerDiv.current;
136
+ childDiv.style.maxHeight = "";
137
+ childDiv.style.overflow = "";
138
+ this.fixPadding(childDiv, true);
139
+ }
130
140
  if (this.wasExpanded && !this.isExpanded) {
131
141
  // When collapsing, the child element must be removed after animation.
132
142
  this.wasExpanded = false;
@@ -137,20 +147,40 @@ var ChildRow = /** @class */ (function (_super) {
137
147
  ChildRow.prototype.setHeight = function (expand) {
138
148
  var childDiv = this.containerDiv.current;
139
149
  if (childDiv) {
150
+ this.fixPadding(childDiv, false);
140
151
  var transitionDuration = window.getComputedStyle(childDiv).transitionDuration;
141
152
  if (transitionDuration) {
142
153
  // If expand / collapse has a transition, reset the max height after the transition ends.
143
- // Subtract 50ms on collapse to prevent wierd chrome padding animation issue.
144
154
  var delay = parseFloat(transitionDuration) * 1000;
145
- setTimeout(this.afterTransition, delay - (expand ? 0 : 50));
155
+ setTimeout(this.afterTransition, delay);
146
156
  }
147
157
  else {
148
158
  this.afterTransition();
149
159
  }
150
- childDiv.style.maxHeight = (!expand ? childDiv.scrollHeight : 0) + 'px';
160
+ var maxHeight = childDiv.scrollHeight + (this.margin * 2);
161
+ childDiv.style.maxHeight = (!expand ? maxHeight : 0) + 'px';
151
162
  childDiv.style.overflow = "hidden";
152
163
  Components.AnimationHelper.triggerReflow(childDiv);
153
- childDiv.style.maxHeight = (expand ? childDiv.scrollHeight : 0) + 'px';
164
+ childDiv.style.maxHeight = (expand ? maxHeight : 0) + 'px';
165
+ }
166
+ };
167
+ // Fix animation by moving child cell padding to inner div margin.
168
+ ChildRow.prototype.fixPadding = function (childDiv, remove) {
169
+ var cell = childDiv.parentElement;
170
+ var innerDiv = childDiv.children[0];
171
+ if (remove) {
172
+ cell.style.paddingTop = "";
173
+ cell.style.paddingBottom = "";
174
+ innerDiv.style.marginTop = "";
175
+ innerDiv.style.marginBottom = "";
176
+ }
177
+ else {
178
+ var style = window.getComputedStyle(cell);
179
+ this.margin = parseInt(style.paddingTop);
180
+ innerDiv.style.marginTop = style.paddingTop;
181
+ innerDiv.style.marginBottom = style.paddingBottom;
182
+ cell.style.paddingTop = "0";
183
+ cell.style.paddingBottom = "0";
154
184
  }
155
185
  };
156
186
  ChildRow.prototype.render = function () {
@@ -174,9 +204,10 @@ var ChildRow = /** @class */ (function (_super) {
174
204
  var colSpan = this.context.columnCount + (showExpandButtonColumn ? 0 : 1);
175
205
  return (this.inBody && (isExpanded || this.wasExpanded) &&
176
206
  React.createElement("tr", __assign({}, domProps),
177
- showExpandButtonColumn && React.createElement("td", null),
207
+ showExpandButtonColumn && React.createElement("td", { className: "p-0" }),
178
208
  React.createElement("td", __assign({}, childCellProps, { colSpan: colSpan }),
179
- React.createElement("div", { ref: this.containerDiv, className: "neo-child-row-container" }, this.props.children))));
209
+ React.createElement("div", { ref: this.containerDiv, className: "neo-child-row-container" },
210
+ React.createElement("div", { className: "neo-child-row-container-inner" }, this.props.children)))));
180
211
  };
181
212
  ChildRow.contextType = GridContext;
182
213
  ChildRow = __decorate([
@@ -11,6 +11,8 @@ export declare class StickyTableHeader {
11
11
  * @param fixedElement A fixed element at the top of the screen to use as an anchor, rather than the top of the screen itself.
12
12
  */
13
13
  constructor(table: HTMLTableElement, fixedElement?: HTMLElement | undefined);
14
+ private domObserver;
15
+ private originalWidths;
14
16
  /** Parent element that may scroll, requiring a position update. */
15
17
  private scrollElement?;
16
18
  /** Fixed height parent element that the grid scrolls within. */
@@ -21,7 +23,9 @@ export declare class StickyTableHeader {
21
23
  private handleScroll;
22
24
  private removeCopy;
23
25
  private onPossibleContentChange;
24
- private setColumnWidths;
26
+ private syncColumnWidths;
27
+ private storeColumnWidths;
28
+ private restoreColumnWidths;
25
29
  dispose(): void;
26
30
  /**
27
31
  * Returns the first parent element that has a scrollbar.
@@ -9,8 +9,13 @@ var StickyTableHeader = /** @class */ (function () {
9
9
  * @param fixedElement A fixed element at the top of the screen to use as an anchor, rather than the top of the screen itself.
10
10
  */
11
11
  function StickyTableHeader(table, fixedElement) {
12
+ var _this = this;
12
13
  this.table = table;
13
14
  this.fixedElement = fixedElement;
15
+ this.domObserver = new MutationObserver(function (mutations) {
16
+ _this.syncColumnWidths();
17
+ });
18
+ this.originalWidths = [];
14
19
  this.headerHeight = 0;
15
20
  if (!table.tHead) {
16
21
  throw Error("Table must have a header section.");
@@ -46,28 +51,32 @@ var StickyTableHeader = /** @class */ (function () {
46
51
  if (!this.headerCopy) {
47
52
  // Clone the header, and re-insert it into the table. The table will then have 2 headers.
48
53
  // The original headers position is set to "fixed" which makes it float.
49
- // The column widths of the floating header then need to be synchronised with the header that is still inside the table layout.
54
+ // The original header is floated instead of the clone because the react events are attached to these cells, and they are the cells that are visible. Without this, sorting wouldn't work.
55
+ // The column widths of the floating header then need to be synchronized with the header that is still inside the table layout.
50
56
  this.headerHeight = this.header.getBoundingClientRect().height;
51
57
  this.headerCopy = this.header.cloneNode(true);
52
58
  this.table.insertBefore(this.headerCopy, this.header);
53
59
  this.header.classList.add("neo-grid-fixed-header");
54
- this.setColumnWidths();
60
+ this.storeColumnWidths();
61
+ this.syncColumnWidths();
62
+ this.domObserver.observe(this.header, { childList: true, subtree: true, attributes: false });
55
63
  }
56
64
  this.header.style.left = tableBounds.left + "px";
57
65
  this.header.style.top = topBoundary + "px";
58
66
  if (this.scrollElement) {
59
67
  var left = this.scrollElement.scrollLeft;
60
- var width = this.scrollElement.clientWidth + left;
68
+ var width = this.scrollElement.clientWidth + left - 1;
61
69
  this.header.style.clipPath = "rect(0px ".concat(width, "px 100% ").concat(left, "px)");
62
70
  }
63
71
  }
64
72
  else {
65
- this.setColumnWidths(true);
66
73
  this.removeCopy();
67
74
  }
68
75
  };
69
76
  StickyTableHeader.prototype.removeCopy = function () {
70
77
  if (this.headerCopy) {
78
+ this.domObserver.disconnect();
79
+ this.restoreColumnWidths();
71
80
  this.header.classList.remove("neo-grid-fixed-header");
72
81
  this.header.style.clipPath = "";
73
82
  this.table.removeChild(this.headerCopy);
@@ -76,20 +85,40 @@ var StickyTableHeader = /** @class */ (function () {
76
85
  };
77
86
  StickyTableHeader.prototype.onPossibleContentChange = function () {
78
87
  var _this = this;
79
- setTimeout(function () { return _this.setColumnWidths(); }, 0);
88
+ setTimeout(function () { return _this.syncColumnWidths(); }, 0);
80
89
  };
81
- StickyTableHeader.prototype.setColumnWidths = function (isRemoving) {
82
- if (isRemoving === void 0) { isRemoving = false; }
90
+ StickyTableHeader.prototype.syncColumnWidths = function () {
83
91
  if (this.headerCopy) {
84
92
  for (var i = 0; i < this.header.rows.length; i++) {
85
93
  var originalRow = this.header.rows[i], copyRow = this.headerCopy.rows[i];
94
+ if (originalRow.cells.length !== copyRow.cells.length) {
95
+ this.removeCopy();
96
+ this.handleScroll();
97
+ return;
98
+ }
86
99
  for (var j = 0; j < originalRow.cells.length; j++) {
87
100
  var originalCell = originalRow.cells[j], copyCell = copyRow.cells[j];
88
- originalCell.style.width = isRemoving ? copyCell.style.width : window.getComputedStyle(copyCell).width;
101
+ originalCell.style.width = window.getComputedStyle(copyCell).width;
89
102
  }
90
103
  }
91
104
  }
92
105
  };
106
+ StickyTableHeader.prototype.storeColumnWidths = function () {
107
+ this.originalWidths = [];
108
+ for (var i = 0; i < this.header.rows.length; i++) {
109
+ var row = this.header.rows[i];
110
+ for (var j = 0; j < row.cells.length; j++) {
111
+ var cell = row.cells[j];
112
+ this.originalWidths.push({ cell: cell, width: cell.style.width });
113
+ }
114
+ }
115
+ };
116
+ StickyTableHeader.prototype.restoreColumnWidths = function () {
117
+ for (var _i = 0, _a = this.originalWidths; _i < _a.length; _i++) {
118
+ var cellRef = _a[_i];
119
+ cellRef.cell.style.width = cellRef.width;
120
+ }
121
+ };
93
122
  StickyTableHeader.prototype.dispose = function () {
94
123
  document.removeEventListener("scroll", this.handleScroll);
95
124
  if (this.scrollElement) {
@@ -11,7 +11,7 @@ import PropertyInfo from '@singularsystems/neo-core/dist/Model/PropertyInfo';
11
11
  import { IComponentBase } from './ComponentBase';
12
12
  import FileInput, { IFileEditorProps } from './FileManager/FileInput';
13
13
  import { FormContextParams } from './FormContext';
14
- export type ItemCallback<T> = (item: T, meta: TransformMetaType<T>, isHeader: boolean) => React.ReactNode;
14
+ export type ItemCallback<T> = (item: T, meta: TransformMetaType<T>, isHeader: boolean, index: number) => React.ReactNode;
15
15
  export declare enum ControlType {
16
16
  Date = 0,
17
17
  Number = 1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@singularsystems/neo-react",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "React application logic and components for the Neo client library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -31,10 +31,10 @@
31
31
  "typescript": "5.4.2"
32
32
  },
33
33
  "dependencies": {
34
- "@singularsystems/neo-core": "1.0.13",
34
+ "@singularsystems/neo-core": "1.0.14",
35
35
  "@types/rc-slider": "^8.6.5",
36
36
  "@types/react-color": "^3.0.1",
37
- "axios": "1.6.7",
37
+ "axios": "1.7.4",
38
38
  "history": "4.10.1",
39
39
  "inversify": "^6.0.2",
40
40
  "memoize-one": "6.0.0",
@@ -49,7 +49,7 @@
49
49
  "tslib": "2.5.0"
50
50
  },
51
51
  "peerDependencies": {
52
- "@singularsystems/neo-core": ">=1.0.13",
52
+ "@singularsystems/neo-core": ">=1.0.14",
53
53
  "axios": ">=1.6.2",
54
54
  "inversify": ">=5.0.1",
55
55
  "mobx": ">=6.9.0",