@linzjs/step-ag-grid 28.4.0 → 28.4.2

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@linzjs/step-ag-grid",
3
3
  "repository": "github:linz/step-ag-grid.git",
4
4
  "license": "MIT",
5
- "version": "28.4.0",
5
+ "version": "28.4.2",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -24,7 +24,7 @@
24
24
  "access": "public"
25
25
  },
26
26
  "engines": {
27
- "node": ">=20"
27
+ "node": ">=22"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@linzjs/lui": ">=21",
@@ -47,7 +47,7 @@
47
47
  "clean": "rimraf dist && mkdirp ./dist",
48
48
  "bundle": "rollup -c",
49
49
  "css": "sass ./src/styles/index.scss:dist/index.css --no-source-map",
50
- "test": "vitest run",
50
+ "test": "cross-env NODE_OPTIONS='--no-experimental-global-navigator' vitest run",
51
51
  "test:watch": "vitest --watch",
52
52
  "lint": "eslint ./src --ext .js,.ts,.tsx --cache --ignore-path .gitignore",
53
53
  "lint:fix": "eslint ./src --ext .js,.ts,.tsx --fix --cache --ignore-path .gitignore",
@@ -81,7 +81,7 @@
81
81
  },
82
82
  "devDependencies": {
83
83
  "@chromatic-com/storybook": "^4.0.1",
84
- "@linzjs/lui": "^23.7.2",
84
+ "@linzjs/lui": "^23.11.1",
85
85
  "@linzjs/style": "^5.4.0",
86
86
  "@rollup/plugin-commonjs": "^28.0.6",
87
87
  "@rollup/plugin-json": "^6.1.0",
@@ -95,6 +95,7 @@
95
95
  "@testing-library/react": "^16.3.0",
96
96
  "@testing-library/user-event": "^14.6.1",
97
97
  "@types/debounce-promise": "^3.1.9",
98
+ "@types/jsdom": "^21.1.7",
98
99
  "@types/lodash-es": "^4.17.12",
99
100
  "@types/node": "^22.17.0",
100
101
  "@types/react": "^18.3.23",
@@ -105,7 +106,9 @@
105
106
  "ag-grid-community": "^34.1.0",
106
107
  "ag-grid-react": "^34.1.0",
107
108
  "babel-preset-react-app": "^10.1.0",
109
+ "canvas": "^3.2.0",
108
110
  "chromatic": "^13.1.3",
111
+ "cross-env": "^10.0.0",
109
112
  "css-loader": "^7.1.2",
110
113
  "eslint-plugin-react": "^7.37.5",
111
114
  "eslint-plugin-storybook": "^9.1.0",
@@ -135,8 +138,7 @@
135
138
  "vite": "^6.3.5",
136
139
  "vite-plugin-html": "^3.2.2",
137
140
  "vite-tsconfig-paths": "^5.1.4",
138
- "vitest": "^3.2.4",
139
- "vitest-canvas-mock": "^0.3.3"
141
+ "vitest": "^3.2.4"
140
142
  },
141
143
  "babel": {
142
144
  "presets": [
@@ -1,35 +1,37 @@
1
- import { ValueGetterParams } from 'ag-grid-community';
2
1
  import { describe, expect, test } from 'vitest';
3
2
 
4
- import { GridBaseRow } from './Grid';
5
- import { generateFilterGetter } from './GridCell';
3
+ import { defaultValueFormatter, generateFilterGetter } from './GridCell';
6
4
 
7
5
  describe('GridCell', () => {
8
- test('generateFilterGetter returns passed filterValueGetter', () => {
9
- const filterValueGetter = () => 'a';
10
- expect(generateFilterGetter(undefined, filterValueGetter, () => 'b')).toBe(filterValueGetter);
11
- expect(generateFilterGetter('xxx', filterValueGetter, undefined)).toBe(filterValueGetter);
12
- expect(generateFilterGetter(undefined, filterValueGetter, undefined)).toBe(filterValueGetter);
6
+ test('defaultValueFormatter', () => {
7
+ expect(defaultValueFormatter({ value: null } as any)).toBe('');
8
+ expect(defaultValueFormatter({ value: undefined } as any)).toBe('–');
9
+ expect(defaultValueFormatter({ value: 'a' } as any)).toBe('a');
10
+ expect(defaultValueFormatter({ value: 1 } as any)).toBe('1');
11
+ expect(defaultValueFormatter({ value: false } as any)).toBe('false');
12
+ expect(defaultValueFormatter({ value: { x: 1 } } as any)).toBe('{"x":1}');
13
13
  });
14
14
 
15
15
  test('generateFilterGetter', () => {
16
- expect(generateFilterGetter('xxx', undefined, undefined)).toBeUndefined();
17
-
18
- const tests = [
19
- { formatted: 'f1', value: 'v1', expected: 'f1 v1' },
20
- { formatted: 'f2', value: {}, expected: 'f2' },
21
- { formatted: '', value: 'v3', expected: 'v3' },
22
- ];
23
-
24
- tests.forEach((test) => {
25
- const field = 'xxx';
26
- const valueFormatter = test.formatted == null ? undefined : () => test.formatted;
27
- const filterGetter = generateFilterGetter(field, undefined, valueFormatter);
28
- expect(typeof filterGetter).toBe('function');
29
- if (typeof filterGetter !== 'function') return;
30
- expect(filterGetter({ getValue: () => test.value } as unknown as ValueGetterParams<GridBaseRow>)).toBe(
31
- test.expected,
32
- );
16
+ expect(generateFilterGetter(undefined)).toBeUndefined();
17
+ expect(generateFilterGetter('x')).toBeUndefined();
18
+ const fn = generateFilterGetter((props) => {
19
+ return String(props.value);
33
20
  });
21
+ expect(fn).toBeTypeOf('function');
22
+ if (typeof fn !== 'function') {
23
+ return;
24
+ }
25
+ expect(
26
+ fn({
27
+ value: 'x',
28
+ colDef: { colId: 'col1' },
29
+ node: undefined!,
30
+ data: undefined!,
31
+ column: undefined!,
32
+ api: undefined!,
33
+ context: undefined,
34
+ }),
35
+ ).toBe('x');
34
36
  });
35
37
  });
@@ -1,10 +1,15 @@
1
- import { ColDef, EditableCallback, ICellEditorParams, ICellRendererParams } from 'ag-grid-community';
1
+ import {
2
+ ColDef,
3
+ EditableCallback,
4
+ GetQuickFilterTextParams,
5
+ ICellEditorParams,
6
+ ICellRendererParams,
7
+ } from 'ag-grid-community';
2
8
  import {
3
9
  SuppressKeyboardEventParams,
4
10
  ValueFormatterFunc,
5
11
  ValueFormatterParams,
6
12
  ValueGetterFunc,
7
- ValueGetterParams,
8
13
  } from 'ag-grid-community';
9
14
  import { forwardRef, ReactElement, useContext } from 'react';
10
15
 
@@ -32,8 +37,12 @@ export const GridCellRenderer = (props: ICellRendererParams) => {
32
37
  let warningText = props.data !== undefined && warningFn ? warningFn(props) : undefined;
33
38
  const infoFn = rendererParams?.info;
34
39
  let infoText = props.data !== undefined && infoFn ? infoFn(props) : undefined;
35
- if (Array.isArray(warningText)) warningText = warningText.join('\n');
36
- if (Array.isArray(infoText)) infoText = infoText.join('\n');
40
+ if (Array.isArray(warningText)) {
41
+ warningText = warningText.join('\n');
42
+ }
43
+ if (Array.isArray(infoText)) {
44
+ infoText = infoText.join('\n');
45
+ }
37
46
 
38
47
  return checkUpdating(colDef.field ?? colDef.colId ?? '', props.data.id) ? (
39
48
  <GridLoadableCell />
@@ -47,7 +56,7 @@ export const GridCellRenderer = (props: ICellRendererParams) => {
47
56
  {colDef.cellRendererParams?.originalCellRenderer ? (
48
57
  <colDef.cellRendererParams.originalCellRenderer {...props} />
49
58
  ) : (
50
- <span title={props.valueFormatted ?? undefined}>{props.valueFormatted}</span>
59
+ <span title={props.valueFormatted ?? undefined}>{props.valueFormatted || '–'}</span>
51
60
  )}
52
61
  </div>
53
62
  {fnOrVar(colDef.editable, props) && rendererParams?.rightHoverElement && (
@@ -91,25 +100,24 @@ export const suppressCellKeyboardEvents = (e: SuppressKeyboardEventParams) => {
91
100
  };
92
101
 
93
102
  export const generateFilterGetter = <TData extends GridBaseRow, ValueType>(
94
- field: string | undefined,
95
- filterValueGetter: string | ValueGetterFunc<TData, ValueType> | undefined,
96
103
  valueFormatter: string | ValueFormatterFunc<TData, ValueType> | undefined,
97
- ): string | ValueGetterFunc<TData, ValueType> | undefined => {
98
- if (filterValueGetter) return filterValueGetter;
104
+ ): string | ((params: GetQuickFilterTextParams<TData, ValueType>) => string) | undefined => {
99
105
  // aggrid will default to valueGetter
100
- if (typeof valueFormatter !== 'function' || !field) return undefined;
106
+ if (typeof valueFormatter !== 'function') {
107
+ return undefined;
108
+ }
101
109
 
102
- return (params: ValueGetterParams<TData, ValueType>): any => {
103
- const value = params.getValue(field);
104
- let formattedValue = valueFormatter({ ...params, value });
105
- // Search for null values using standard dash
106
- if (formattedValue === '–') formattedValue += ' -';
107
- // Search by raw value as well as formatted
108
- const gotValue = ['string', 'number'].includes(typeof value) ? value : undefined;
109
- return (formattedValue + (gotValue != null && formattedValue != gotValue ? ' ' + gotValue : '')) //
110
- .replace(/\s+/g, ' ')
111
- .trim();
112
- };
110
+ return (params: GetQuickFilterTextParams<TData, ValueType>) => valueFormatter(params);
111
+ };
112
+
113
+ const stringableValueFormatterTypes = ['number', 'boolean', 'string'];
114
+ export const defaultValueFormatter = ({ value }: ValueFormatterParams) => {
115
+ if (value == null) {
116
+ return '';
117
+ }
118
+ return stringableValueFormatterTypes.includes(typeof value) //
119
+ ? String(value)
120
+ : JSON.stringify(value);
113
121
  };
114
122
 
115
123
  /*
@@ -128,17 +136,18 @@ export const GridCell = <TData extends GridBaseRow, TValue = any, Props extends
128
136
  // Generate a default filter value getter which uses the formatted value plus
129
137
  // the editable value if it's a string and different from the formatted value.
130
138
  // This is so that e.g. bearings can be searched for by DMS or raw number.
131
- const valueFormatter = props.valueFormatter;
139
+ const valueFormatter = props.valueFormatter ?? defaultValueFormatter;
132
140
  // FIXME
133
- const filterValueGetter = generateFilterGetter(props.field, props.filterValueGetter as any, valueFormatter as any);
141
+ const filterValueGetter = props.filterValueGetter ?? generateFilterGetter(valueFormatter as any);
134
142
  const exportable = props.exportable;
135
143
  // Can't leave this here ag-grid will complain
136
144
  delete props.exportable;
137
145
 
138
146
  return {
139
- colId: props.field ?? props.field,
147
+ // Will be overridden if specified later
148
+ colId: props.field,
140
149
  headerTooltip: props.headerName,
141
- sortable: !!(props?.field || props?.valueGetter),
150
+ sortable: true,
142
151
  resizable: true,
143
152
  editable: props.editable ?? false,
144
153
  ...(custom?.editor && {
@@ -155,15 +164,9 @@ export const GridCell = <TData extends GridBaseRow, TValue = any, Props extends
155
164
  },
156
165
  }),
157
166
  // If there's a valueFormatter and no filterValueGetter then create a filterValueGetter
158
- // FIXME
159
- filterValueGetter: filterValueGetter as any,
167
+ getQuickFilterText: filterValueGetter as any,
160
168
  // Default value formatter, otherwise react freaks out on objects
161
- valueFormatter: (params: ValueFormatterParams) => {
162
- if (params.value == null) return '–';
163
- const types = ['number', 'boolean', 'string'];
164
- if (types.includes(typeof params.value)) return `${params.value}`;
165
- else return JSON.stringify(params.value);
166
- },
169
+ valueFormatter,
167
170
  ...props,
168
171
  cellRenderer: typeof props.cellRenderer === 'string' ? props.cellRenderer : GridCellRenderer,
169
172
  cellRendererParams: {
@@ -16,6 +16,7 @@ export const GridIcon = (props: {
16
16
  alt={props.title}
17
17
  size={props.size ?? 'md'}
18
18
  className={clsx(
19
+ `step-ag-grid__alert-icon`,
19
20
  `AgGridGenericCellRenderer-${props.icon}Icon`,
20
21
  props.className,
21
22
  props.disabled && 'GridIcon-disabled',
@@ -139,3 +139,8 @@
139
139
  div.ag-ltr div.ag-header-cell-resize {
140
140
  right: -4px;
141
141
  }
142
+
143
+ .step-ag-grid__alert-icon {
144
+ max-width: 34px;
145
+ width: 34px;
146
+ }