@linzjs/step-ag-grid 6.1.1 → 7.0.1

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.
Files changed (46) hide show
  1. package/dist/index.css +12 -2
  2. package/dist/index.js +378 -203
  3. package/dist/index.js.map +1 -1
  4. package/dist/src/components/GridPopoverHook.d.ts +1 -1
  5. package/dist/src/components/gridForm/GridFormMultiSelect.d.ts +17 -12
  6. package/dist/src/components/gridPopoverEdit/GridPopoutEditMultiSelect.d.ts +1 -1
  7. package/dist/src/contexts/GridSubComponentContext.d.ts +1 -0
  8. package/dist/src/lui/ActionButton.d.ts +4 -2
  9. package/dist/src/lui/FormError.d.ts +2 -1
  10. package/dist/src/lui/TextAreaInput.d.ts +1 -1
  11. package/dist/src/lui/TextInputFormatted.d.ts +1 -1
  12. package/dist/src/react-menu3/utils/utils.d.ts +1 -0
  13. package/dist/src/utils/textMatcher.d.ts +13 -0
  14. package/dist/src/utils/textValidator.d.ts +3 -2
  15. package/dist/src/utils/util.d.ts +2 -1
  16. package/dist/step-ag-grid.esm.js +379 -205
  17. package/dist/step-ag-grid.esm.js.map +1 -1
  18. package/package.json +9 -8
  19. package/src/components/GridPopoverHook.tsx +7 -1
  20. package/src/components/gridForm/GridFormDropDown.tsx +1 -0
  21. package/src/components/gridForm/GridFormMultiSelect.tsx +290 -188
  22. package/src/components/gridForm/GridFormPopoverMenu.tsx +1 -0
  23. package/src/components/gridForm/GridFormSubComponentTextArea.tsx +2 -2
  24. package/src/components/gridForm/GridFormSubComponentTextInput.tsx +3 -5
  25. package/src/components/gridForm/GridFormTextArea.tsx +13 -13
  26. package/src/components/gridForm/GridFormTextInput.tsx +3 -8
  27. package/src/components/gridPopoverEdit/GridPopoutEditMultiSelect.ts +3 -3
  28. package/src/contexts/GridSubComponentContext.ts +2 -0
  29. package/src/lui/ActionButton.scss +10 -0
  30. package/src/lui/ActionButton.tsx +36 -10
  31. package/src/lui/FormError.scss +7 -0
  32. package/src/lui/FormError.tsx +4 -13
  33. package/src/lui/TextAreaInput.tsx +1 -1
  34. package/src/lui/TextInputFormatted.tsx +1 -1
  35. package/src/react-menu3/components/ControlledMenu.tsx +3 -2
  36. package/src/react-menu3/components/MenuList.tsx +2 -12
  37. package/src/react-menu3/hooks/useItems.ts +5 -2
  38. package/src/react-menu3/utils/utils.ts +15 -0
  39. package/src/stories/components/ActionButton.stories.tsx +11 -0
  40. package/src/stories/grid/FormTest.tsx +1 -1
  41. package/src/stories/grid/GridPopoutEditMultiSelect.stories.tsx +93 -17
  42. package/src/styles/Grid.scss +12 -0
  43. package/src/styles/lui-overrides.scss +0 -2
  44. package/src/utils/textMatcher.ts +31 -0
  45. package/src/utils/textValidator.ts +6 -3
  46. package/src/utils/util.ts +6 -7
package/dist/index.js CHANGED
@@ -180,7 +180,22 @@ function commonProps(isDisabled, isHovering) {
180
180
  tabIndex: isHovering ? 0 : -1
181
181
  };
182
182
  }
183
- var indexOfNode = function (nodeList, node) { return lodashEs.findIndex(nodeList, node); };
183
+ var indexOfNode = function (nodeList, node) { return lodashEs.findIndex(nodeList, node); };
184
+ var focusFirstInput = function (container) {
185
+ if (!(container instanceof Element))
186
+ return false;
187
+ var inputs = container.querySelectorAll("input[type='text'],textarea");
188
+ var input = inputs[0];
189
+ if (input instanceof HTMLElement) {
190
+ input.focus();
191
+ // Text areas should start at end
192
+ if (input instanceof HTMLTextAreaElement) {
193
+ input.selectionStart = input.value.length;
194
+ }
195
+ return true;
196
+ }
197
+ return false;
198
+ };
184
199
 
185
200
  /******************************************************************************
186
201
  Copyright (c) Microsoft Corporation.
@@ -355,8 +370,9 @@ var useItems = function (menuRef, focusRef) {
355
370
  if (index >= items.length)
356
371
  index = 0;
357
372
  newItem = items[index];
373
+ focusFirstInput(newItem);
358
374
  break;
359
- case HoverActionTypes.DECREASE:
375
+ case HoverActionTypes.DECREASE: {
360
376
  sortItems();
361
377
  index = hoverIndex;
362
378
  if (index < 0)
@@ -365,7 +381,9 @@ var useItems = function (menuRef, focusRef) {
365
381
  if (index < 0)
366
382
  index = items.length - 1;
367
383
  newItem = items[index];
384
+ focusFirstInput(newItem);
368
385
  break;
386
+ }
369
387
  default:
370
388
  if (process.env.NODE_ENV !== "production")
371
389
  throw new Error("[React-Menu] Unknown hover action type: ".concat(actionType));
@@ -1201,26 +1219,13 @@ var MenuList = function (_a) {
1201
1219
  else if (captureFocus) {
1202
1220
  // Use a timeout here because if set focus immediately, page might scroll unexpectedly.
1203
1221
  var id_1 = setTimeout(function () {
1204
- var _a, _b, _c;
1222
+ var _a, _b;
1205
1223
  // If focus has already been set to a children element, don't set focus on menu or item
1206
1224
  if (!menuRef.current.contains(document.activeElement)) {
1207
1225
  // Handle popover portal focus
1208
1226
  var popupElement = (_a = focusRef.current) === null || _a === void 0 ? void 0 : _a.nextSibling;
1209
- if (popupElement instanceof Element) {
1210
- var input = popupElement.querySelectorAll("input,textarea")[0];
1211
- if (input) {
1212
- input.focus();
1213
- // Text areas should start at end
1214
- if (input instanceof HTMLTextAreaElement) {
1215
- input.selectionStart = input.value.length;
1216
- }
1217
- }
1218
- else {
1219
- (_b = focusRef.current) === null || _b === void 0 ? void 0 : _b.focus();
1220
- }
1221
- }
1222
- else {
1223
- (_c = focusRef.current) === null || _c === void 0 ? void 0 : _c.focus();
1227
+ if (!focusFirstInput(popupElement)) {
1228
+ (_b = focusRef.current) === null || _b === void 0 ? void 0 : _b.focus();
1224
1229
  }
1225
1230
  setItemFocus();
1226
1231
  }
@@ -1278,10 +1283,7 @@ var MenuList = function (_a) {
1278
1283
  return (jsxRuntime.jsxs("ul", __assign({ role: "menu", "aria-label": ariaLabel }, mergeProps({ onKeyDown: onKeyDown, onAnimationEnd: onAnimationEnd }, restProps), commonProps(isDisabled), { ref: useCombinedRef(externalRef, menuRef), className: useBEM({ block: menuClass, modifiers: modifiers, className: menuClassName }), style: __assign(__assign(__assign(__assign({}, menuStyle), overflowStyle), dontShrinkOps), { margin: 0, display: state === "closed" ? "none" : undefined, position: "absolute", left: menuPosition.x, top: menuPosition.y }) }, { children: [jsxRuntime.jsx("div", { ref: focusRef, tabIndex: -1, style: { position: "absolute", left: 0, top: 0 } }), arrow && (jsxRuntime.jsx("div", { className: _arrowClass, style: __assign(__assign({}, arrowStyle), { position: "absolute", left: arrowPosition.x, top: arrowPosition.y }), ref: arrowRef })), jsxRuntime.jsx(MenuListContext.Provider, __assign({ value: listContext }, { children: jsxRuntime.jsx(MenuListItemContext.Provider, __assign({ value: itemContext }, { children: jsxRuntime.jsx(HoverItemContext.Provider, __assign({ value: hoverItem }, { children: children })) })) }))] })));
1279
1284
  };
1280
1285
 
1281
- // Typed version of lodash !isEmpty
1282
- var isNotEmpty = function (obj) {
1283
- return !lodashEs.isEmpty(obj);
1284
- };
1286
+ var isNotEmpty = lodashEs.negate(lodashEs.isEmpty);
1285
1287
  var wait = function (timeoutMs) {
1286
1288
  return new Promise(function (resolve) {
1287
1289
  setTimeout(resolve, timeoutMs);
@@ -1292,15 +1294,16 @@ var isFloat = function (value) {
1292
1294
  return regexp.test(value);
1293
1295
  };
1294
1296
  var hasParentClass = function (className, child) {
1295
- var node = child;
1296
- while (node) {
1297
+ for (var node = child; node; node = node.parentNode) {
1297
1298
  // When nodes are in portals they aren't type node anymore hence treating it as any here
1298
1299
  if (node.classList && node.classList.contains(className)) {
1299
1300
  return true;
1300
1301
  }
1301
- node = node.parentNode;
1302
1302
  }
1303
1303
  return false;
1304
+ };
1305
+ var stringByteLengthIsInvalid = function (str, maxBytes) {
1306
+ return new TextEncoder().encode(str).length > maxBytes;
1304
1307
  };
1305
1308
 
1306
1309
  var EventHandlersContext = react.createContext({
@@ -1396,7 +1399,8 @@ var ControlledMenuFr = function (_a, externalRef) {
1396
1399
  if (activeElement !== firstInputEl && activeElement !== lastInputEl)
1397
1400
  return;
1398
1401
  var isTextArea = activeElement.nodeName === "TEXTAREA";
1399
- var suppressEnterAutoSave = activeElement.getAttribute("data-disableEnterAutoSave") || isTextArea;
1402
+ var suppressEnterAutoSave = activeElement.getAttribute("data-disableenterautosave") || isTextArea;
1403
+ var allowTabToSave = activeElement.getAttribute("data-allowtabtoSave");
1400
1404
  var invokeSave = function (reason) {
1401
1405
  var _a, _b;
1402
1406
  if (!(saveButtonRef === null || saveButtonRef === void 0 ? void 0 : saveButtonRef.current))
@@ -1407,7 +1411,7 @@ var ControlledMenuFr = function (_a, externalRef) {
1407
1411
  switch (activeElement.nodeName) {
1408
1412
  case "TEXTAREA":
1409
1413
  case "INPUT": {
1410
- if (activeElement === lastInputEl && activeElement === firstInputEl) {
1414
+ if ((activeElement === lastInputEl && activeElement === firstInputEl) || allowTabToSave) {
1411
1415
  if (ev.key === "Tab") {
1412
1416
  // Can't forward/backwards tab out of popup
1413
1417
  ev.preventDefault();
@@ -2426,7 +2430,8 @@ var GridSubComponentContext = react.createContext({
2426
2430
  console.error("GridSubComponentContext triggerSave no context");
2427
2431
  return [2 /*return*/];
2428
2432
  });
2429
- }); }
2433
+ }); },
2434
+ context: null
2430
2435
  });
2431
2436
 
2432
2437
  function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);else for(t in e)e[t]&&(n&&(n+=" "),n+=t);return n}function clsx(){for(var e,t,f=0,n="";f<arguments.length;)(e=arguments[f++])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
@@ -2824,11 +2829,11 @@ function styleInject(css, ref) {
2824
2829
  }
2825
2830
  }
2826
2831
 
2827
- var css_248z$7 = ".AgGridGenericCellRenderer-icon{margin-right:4px}.AgGridGenericCellRenderer-ic_infoIcon{fill:#3a7cdf;margin-right:4px}.AgGridGenericCellRenderer-ic_warningIcon{fill:#ea6a2e;margin-right:4px}";
2828
- styleInject(css_248z$7);
2832
+ var css_248z$8 = ".AgGridGenericCellRenderer-icon{margin-right:4px}.AgGridGenericCellRenderer-ic_infoIcon{fill:#3a7cdf;margin-right:4px}.AgGridGenericCellRenderer-ic_warningIcon{fill:#ea6a2e;margin-right:4px}";
2833
+ styleInject(css_248z$8);
2829
2834
 
2830
- var css_248z$6 = ".GridLoadableCell-container{align-items:center;display:flex}";
2831
- styleInject(css_248z$6);
2835
+ var css_248z$7 = ".GridLoadableCell-container{align-items:center;display:flex}";
2836
+ styleInject(css_248z$7);
2832
2837
 
2833
2838
  var GridLoadableCell = function (props) {
2834
2839
  if (props.isLoading) {
@@ -3002,11 +3007,11 @@ var GridRenderPopoutMenuCell = function (props) {
3002
3007
  return (jsxRuntime.jsx(GridLoadableCell, __assign({ isLoading: isLoading, className: disabled ? "GridPopoutMenu-burgerDisabled" : "GridPopoutMenu-burger" }, { children: jsxRuntime.jsx(lui.LuiIcon, { name: "ic_more_vert", alt: "More actions", size: "md" }) })));
3003
3008
  };
3004
3009
 
3005
- var css_248z$5 = ".GridMultiSelect-containerSmall .GridFormMultiSelect-options{max-height:130px;overflow-y:auto}.GridMultiSelect-containerMedium .GridFormMultiSelect-options{max-height:190px;overflow-y:auto}.GridMultiSelect-containerLarge .GridFormMultiSelect-options{max-height:320px;overflow-y:auto}.GridMultiSelect-containerUnlimited .GridFormMultiSelect-options{overflow-y:auto}";
3006
- styleInject(css_248z$5);
3010
+ var css_248z$6 = ".GridMultiSelect-containerSmall .GridFormMultiSelect-options{max-height:130px;overflow-y:auto}.GridMultiSelect-containerMedium .GridFormMultiSelect-options{max-height:190px;overflow-y:auto}.GridMultiSelect-containerLarge .GridFormMultiSelect-options{max-height:320px;overflow-y:auto}.GridMultiSelect-containerUnlimited .GridFormMultiSelect-options{overflow-y:auto}";
3011
+ styleInject(css_248z$6);
3007
3012
 
3008
- var css_248z$4 = ".GridPopoverEditDropDown-containerSmall .GridFormDropDown-options{max-height:120px;overflow-y:auto}.GridPopoverEditDropDown-containerMedium .GridFormDropDown-options{max-height:220px;overflow-y:auto}.GridPopoverEditDropDown-containerLarge .GridFormDropDown-options{max-height:400px;overflow-y:auto}.GridPopoverEditDropDown-containerUnlimited .GridFormDropDown-options{overflow-y:auto}";
3009
- styleInject(css_248z$4);
3013
+ var css_248z$5 = ".GridPopoverEditDropDown-containerSmall .GridFormDropDown-options{max-height:120px;overflow-y:auto}.GridPopoverEditDropDown-containerMedium .GridFormDropDown-options{max-height:220px;overflow-y:auto}.GridPopoverEditDropDown-containerLarge .GridFormDropDown-options{max-height:400px;overflow-y:auto}.GridPopoverEditDropDown-containerUnlimited .GridFormDropDown-options{overflow-y:auto}";
3014
+ styleInject(css_248z$5);
3010
3015
 
3011
3016
  /* global setTimeout, clearTimeout */
3012
3017
 
@@ -3295,6 +3300,7 @@ var GridFormDropDown = function (props) {
3295
3300
  : CloseReason.CLICK).then();
3296
3301
  }
3297
3302
  } }, { children: [(_a = item.label) !== null && _a !== void 0 ? _a : (item.value == null ? "<".concat(item.value, ">") : "".concat(item.value)), item.subComponent ? "..." : ""] }), "".concat(fieldToString(field), "-").concat(index)), item.subComponent && selectedSubComponent === item && (jsxRuntime.jsx(FocusableItem, __assign({ className: "LuiDeprecatedForms" }, { children: function (ref) { return (jsxRuntime.jsx(GridSubComponentContext.Provider, __assign({ value: {
3303
+ context: { options: options },
3298
3304
  data: data,
3299
3305
  value: subSelectedValue,
3300
3306
  setValue: function (value) {
@@ -3317,154 +3323,326 @@ var GridFormDropDown = function (props) {
3317
3323
  })] }) }))] }));
3318
3324
  };
3319
3325
 
3326
+ var css_248z$4 = ".helpText{color:#6b6966;font-size:.75rem;font-weight:400}";
3327
+ styleInject(css_248z$4);
3328
+
3329
+ var FormError = function (props) {
3330
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.error && (jsxRuntime.jsx("span", __assign({ className: "LuiTextInput-error", style: { paddingLeft: 0 } }, { children: props.error }))), props.helpText && !props.error && jsxRuntime.jsx("span", __assign({ className: "helpText" }, { children: props.helpText }))] }));
3331
+ };
3332
+
3333
+ function escapeStringRegexp(string) {
3334
+ if (typeof string !== 'string') {
3335
+ throw new TypeError('Expected a string');
3336
+ }
3337
+
3338
+ // Escape characters with special meaning either inside or outside character sets.
3339
+ // Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
3340
+ return string
3341
+ .replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
3342
+ .replace(/-/g, '\\x2d');
3343
+ }
3344
+
3345
+ const regexpCache = new Map();
3346
+
3347
+ const sanitizeArray = (input, inputName) => {
3348
+ if (!Array.isArray(input)) {
3349
+ switch (typeof input) {
3350
+ case 'string':
3351
+ input = [input];
3352
+ break;
3353
+ case 'undefined':
3354
+ input = [];
3355
+ break;
3356
+ default:
3357
+ throw new TypeError(`Expected '${inputName}' to be a string or an array, but got a type of '${typeof input}'`);
3358
+ }
3359
+ }
3360
+
3361
+ return input.filter(string => {
3362
+ if (typeof string !== 'string') {
3363
+ if (typeof string === 'undefined') {
3364
+ return false;
3365
+ }
3366
+
3367
+ throw new TypeError(`Expected '${inputName}' to be an array of strings, but found a type of '${typeof string}' in the array`);
3368
+ }
3369
+
3370
+ return true;
3371
+ });
3372
+ };
3373
+
3374
+ const makeRegexp = (pattern, options) => {
3375
+ options = {
3376
+ caseSensitive: false,
3377
+ ...options,
3378
+ };
3379
+
3380
+ const cacheKey = pattern + JSON.stringify(options);
3381
+
3382
+ if (regexpCache.has(cacheKey)) {
3383
+ return regexpCache.get(cacheKey);
3384
+ }
3385
+
3386
+ const negated = pattern[0] === '!';
3387
+
3388
+ if (negated) {
3389
+ pattern = pattern.slice(1);
3390
+ }
3391
+
3392
+ pattern = escapeStringRegexp(pattern).replace(/\\\*/g, '[\\s\\S]*');
3393
+
3394
+ const regexp = new RegExp(`^${pattern}$`, options.caseSensitive ? '' : 'i');
3395
+ regexp.negated = negated;
3396
+ regexpCache.set(cacheKey, regexp);
3397
+
3398
+ return regexp;
3399
+ };
3400
+
3401
+ const baseMatcher = (inputs, patterns, options, firstMatchOnly) => {
3402
+ inputs = sanitizeArray(inputs, 'inputs');
3403
+ patterns = sanitizeArray(patterns, 'patterns');
3404
+
3405
+ if (patterns.length === 0) {
3406
+ return [];
3407
+ }
3408
+
3409
+ patterns = patterns.map(pattern => makeRegexp(pattern, options));
3410
+
3411
+ const {allPatterns} = options || {};
3412
+ const result = [];
3413
+
3414
+ for (const input of inputs) {
3415
+ // String is included only if it matches at least one non-negated pattern supplied.
3416
+ // Note: the `allPatterns` option requires every non-negated pattern to be matched once.
3417
+ // Matching a negated pattern excludes the string.
3418
+ let matches;
3419
+ const didFit = [...patterns].fill(false);
3420
+
3421
+ for (const [index, pattern] of patterns.entries()) {
3422
+ if (pattern.test(input)) {
3423
+ didFit[index] = true;
3424
+ matches = !pattern.negated;
3425
+
3426
+ if (!matches) {
3427
+ break;
3428
+ }
3429
+ }
3430
+ }
3431
+
3432
+ if (
3433
+ !(
3434
+ matches === false
3435
+ || (matches === undefined && patterns.some(pattern => !pattern.negated))
3436
+ || (allPatterns && didFit.some((yes, index) => !yes && !patterns[index].negated))
3437
+ )
3438
+ ) {
3439
+ result.push(input);
3440
+
3441
+ if (firstMatchOnly) {
3442
+ break;
3443
+ }
3444
+ }
3445
+ }
3446
+
3447
+ return result;
3448
+ };
3449
+
3450
+ function isMatch(inputs, patterns, options) {
3451
+ return baseMatcher(inputs, patterns, options, true).length > 0;
3452
+ }
3453
+
3454
+ /**
3455
+ * Text matching with wildcards and multiple matchers.
3456
+ *
3457
+ * "L" => L*
3458
+ * "L*" => L*
3459
+ * "*L*" => *L*
3460
+ * "*L" => *L
3461
+ * "A B" => A* and B*
3462
+ * "A B, C" => (A* and B*) or C*
3463
+ *
3464
+ * Returns ture if there's a text match.
3465
+ */
3466
+ var textMatch = function (text, filter) {
3467
+ if (text == null)
3468
+ return true;
3469
+ var superFilters = filter
3470
+ .split(",")
3471
+ .map(function (sf) { return sf.trim(); })
3472
+ .filter(function (sf) { return sf; });
3473
+ var values = text.replaceAll(",", " ").trim().split(/\s+/);
3474
+ return (lodashEs.isEmpty(superFilters) || // Not filtered
3475
+ superFilters.some(function (superFilter) {
3476
+ var subFilters = superFilter.split(/\s+/).map(function (s) { return s.replaceAll(/([!?])/g, "\\$1"); });
3477
+ return subFilters.every(function (subFilter) { return values.some(function (value) { return isMatch(value, subFilter); }); });
3478
+ }));
3479
+ };
3480
+
3320
3481
  var GridFormMultiSelect = function (props) {
3321
3482
  var _a = useGridPopoverContext(), selectedRows = _a.selectedRows, data = _a.data;
3322
- var initialiseValues = react.useMemo(function () {
3323
- var r = props.initialSelectedValues && props.initialSelectedValues(selectedRows);
3324
- // convert array of strings to object<value,null>
3325
- return Array.isArray(r) ? lodashEs.fromPairs(r.map(function (v) { return [v, null]; })) : r;
3326
- }, [props, selectedRows]);
3327
- var subComponentIsValid = react.useRef({});
3328
- var _b = react.useState(function () { return initialiseValues !== null && initialiseValues !== void 0 ? initialiseValues : {}; }), selectedValues = _b[0], setSelectedValues = _b[1];
3329
- var _c = react.useState(""), filter = _c[0], setFilter = _c[1];
3330
- var _d = react.useState([]), filteredValues = _d[0], setFilteredValues = _d[1];
3483
+ var subComponentIsValidRef = react.useRef({});
3331
3484
  var optionsInitialising = react.useRef(false);
3332
- var _e = react.useState(), options = _e[0], setOptions = _e[1];
3485
+ var _b = react.useState(""), filter = _b[0], setFilter = _b[1];
3486
+ var _c = react.useState(""), initialValues = _c[0], setInitialValues = _c[1];
3487
+ var _d = react.useState(), options = _d[0], setOptions = _d[1];
3333
3488
  var invalid = react.useCallback(function () {
3334
- var validations = lodashEs.pick(subComponentIsValid.current, Object.keys(selectedValues));
3335
- return Object.values(validations).some(function (v) { return !v; });
3336
- }, [selectedValues]);
3489
+ if (!options)
3490
+ return true;
3491
+ var selectedValues = options.filter(function (o) { return o.checked; }).map(function (o) { return o.value; });
3492
+ var subValidations = lodashEs.pick(subComponentIsValidRef.current, selectedValues);
3493
+ if (Object.values(subValidations).some(function (v) { return !v; }))
3494
+ return true;
3495
+ return (props.invalid &&
3496
+ props.invalid(selectedRows, options.filter(function (o) { return o.checked; })));
3497
+ }, [options, props, selectedRows]);
3337
3498
  var save = react.useCallback(function (selectedRows) { return __awaiter(void 0, void 0, void 0, function () {
3338
- var validations, notValid, menuOptionSubValueResult;
3339
3499
  return __generator(this, function (_a) {
3340
- switch (_a.label) {
3341
- case 0:
3342
- if (!props.onSave) return [3 /*break*/, 2];
3343
- if (!options) {
3344
- console.error("options not initialised");
3345
- return [2 /*return*/, false];
3346
- }
3347
- validations = lodashEs.pick(subComponentIsValid.current, Object.keys(selectedValues));
3348
- notValid = Object.values(validations).some(function (v) { return !v; });
3349
- if (notValid)
3350
- return [2 /*return*/, false];
3351
- menuOptionSubValueResult = lodashEs.toPairs(selectedValues).map(function (_a) {
3352
- var value = _a[0], subValue = _a[1];
3353
- var o = __assign({}, options.find(function (o) { return o.value == value; }));
3354
- o.subValue = subValue;
3355
- return o;
3356
- });
3357
- if (lodashEs.isEqual(initialiseValues, selectedValues)) {
3358
- // No changes to save
3359
- return [2 /*return*/, true];
3360
- }
3361
- return [4 /*yield*/, props.onSave(selectedRows, menuOptionSubValueResult)];
3362
- case 1: return [2 /*return*/, _a.sent()];
3363
- case 2: return [2 /*return*/, true];
3364
- }
3500
+ if (!options || !props.onSave)
3501
+ return [2 /*return*/, true];
3502
+ // Any changes to save?
3503
+ if (initialValues === JSON.stringify(options))
3504
+ return [2 /*return*/, true];
3505
+ return [2 /*return*/, props.onSave(selectedRows, options.filter(function (o) { return o.checked; }))];
3365
3506
  });
3366
- }); }, [initialiseValues, options, props, selectedValues]);
3507
+ }); }, [initialValues, options, props]);
3367
3508
  // Load up options list if it's async function
3368
3509
  react.useEffect(function () {
3369
- var _a;
3370
3510
  if (options || optionsInitialising.current)
3371
3511
  return;
3372
3512
  optionsInitialising.current = true;
3373
- var optionsConf = (_a = props.options) !== null && _a !== void 0 ? _a : [];
3374
3513
  (function () { return __awaiter(void 0, void 0, void 0, function () {
3375
- var optionsList;
3376
- return __generator(this, function (_a) {
3377
- switch (_a.label) {
3514
+ var optionsList, _a;
3515
+ return __generator(this, function (_b) {
3516
+ switch (_b.label) {
3378
3517
  case 0:
3379
- if (!(typeof optionsConf == "function")) return [3 /*break*/, 2];
3380
- return [4 /*yield*/, optionsConf(selectedRows)];
3518
+ if (!(typeof props.options === "function")) return [3 /*break*/, 2];
3519
+ return [4 /*yield*/, props.options(selectedRows)];
3381
3520
  case 1:
3382
- optionsConf = _a.sent();
3383
- _a.label = 2;
3521
+ _a = _b.sent();
3522
+ return [3 /*break*/, 3];
3384
3523
  case 2:
3385
- optionsList = optionsConf === null || optionsConf === void 0 ? void 0 : optionsConf.map(function (item) {
3386
- if (item == null || typeof item === "string" || typeof item === "number") {
3387
- item = { value: item, label: item };
3388
- }
3389
- return item;
3390
- });
3391
- if (props.filtered) {
3392
- // This is needed otherwise when filter input is rendered and sets autofocus
3393
- // the mouse up of the double click edit triggers the cell to cancel editing
3394
- lodashEs.delay(function () { return setOptions(optionsList); }, 100);
3395
- }
3396
- else {
3397
- setOptions(optionsList);
3398
- }
3524
+ _a = props.options;
3525
+ _b.label = 3;
3526
+ case 3:
3527
+ optionsList = _a;
3528
+ setInitialValues(JSON.stringify(optionsList));
3529
+ setOptions(optionsList);
3399
3530
  optionsInitialising.current = false;
3400
3531
  return [2 /*return*/];
3401
3532
  }
3402
3533
  });
3403
3534
  }); })();
3404
- }, [props.filtered, props.options, options, selectedRows]);
3405
- react.useEffect(function () {
3406
- if (!props.filtered || options == null)
3535
+ }, [options, props, selectedRows]);
3536
+ /**
3537
+ * Groups options into their header groups
3538
+ */
3539
+ var headerGroups = react.useMemo(function () {
3540
+ return options &&
3541
+ lodashEs.groupBy(options.filter(function (o) { return textMatch(o.label, filter) && o.value; }), "filter");
3542
+ }, [filter, options]);
3543
+ var headers = react.useMemo(function () { var _a; return (_a = props.headers) !== null && _a !== void 0 ? _a : [{ header: "" }]; }, [props.headers]);
3544
+ var _e = useGridPopoverHook({
3545
+ className: props.className,
3546
+ invalid: invalid,
3547
+ save: save
3548
+ }), popoverWrapper = _e.popoverWrapper, triggerSave = _e.triggerSave;
3549
+ return popoverWrapper(jsxRuntime.jsx(ComponentLoadingWrapper, __assign({ loading: !options, className: "GridFormMultiSelect-container" }, { children: options && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.filtered && (jsxRuntime.jsx(FilterInput, __assign({}, { headerGroups: headerGroups, options: options, setOptions: setOptions, filter: filter, setFilter: setFilter }, { filterHelpText: props.filterHelpText, onSelectFilter: props.onSelectFilter, filterPlaceholder: props.filterPlaceholder }))), headerGroups && (jsxRuntime.jsx("div", __assign({ className: "GridFormMultiSelect-options" }, { children: headers.map(function (header) {
3550
+ var subOptions = headerGroups["".concat(header.filter)];
3551
+ return (!lodashEs.isEmpty(subOptions) && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [header.header && jsxRuntime.jsx(MenuHeader, { children: header.header }), subOptions.map(function (item, index) {
3552
+ return item.value === MenuSeparatorString ? (jsxRuntime.jsx(MenuDivider, {}, "div_".concat(index))) : (jsxRuntime.jsxs(react.Fragment, { children: [jsxRuntime.jsx(MenuRadioItem, { item: item, options: options, setOptions: setOptions }), item.checked && item.subComponent && (jsxRuntime.jsx(MenuSubComponent, __assign({}, { item: item, options: options, setOptions: setOptions, data: data, triggerSave: triggerSave }, { subComponentIsValid: subComponentIsValidRef.current })))] }, "val_".concat(item.value)));
3553
+ })] })));
3554
+ }) })))] })) })));
3555
+ };
3556
+ var FilterInput = function (props) {
3557
+ var options = props.options, setOptions = props.setOptions, onSelectFilter = props.onSelectFilter, filter = props.filter, setFilter = props.setFilter, headerGroups = props.headerGroups, filterPlaceholder = props.filterPlaceholder, filterHelpText = props.filterHelpText;
3558
+ var toggleSelectAllVisible = react.useCallback(function () {
3559
+ if (!options || !headerGroups)
3407
3560
  return;
3408
- setFilteredValues(options
3409
- .map(function (option) {
3410
- if (option.label != null && typeof option.label !== "string") {
3411
- console.error("Cannot filter non-string labels", option);
3412
- return undefined;
3413
- }
3414
- var str = option.label || "";
3415
- return str.toLowerCase().indexOf(filter.trim()) === -1 ? option.value : undefined;
3416
- })
3417
- .filter(function (r) { return r !== undefined; }));
3418
- }, [props.filtered, filter, options]);
3419
- var toggleValue = react.useCallback(function (item) {
3420
- var _a;
3421
- if ("".concat(item.value) in selectedValues) {
3422
- setSelectedValues(lodashEs.omit(selectedValues, ["".concat(item.value)]));
3561
+ if (lodashEs.isEmpty(filter.trim())) {
3562
+ // Toggle off if any items are checked otherwise on
3563
+ var anyChecked_1 = options.some(function (o) { return o.checked; });
3564
+ options.forEach(function (o) { return (o.checked = !anyChecked_1); });
3423
3565
  }
3424
3566
  else {
3425
- setSelectedValues(__assign(__assign({}, selectedValues), (_a = {}, _a["".concat(item.value)] = null, _a)));
3567
+ // Toggle on if any filtered items are checked otherwise off
3568
+ var anyChecked_2 = Object.values(headerGroups).some(function (headerOptions) {
3569
+ return headerOptions.some(function (o) { return o.checked === false; });
3570
+ });
3571
+ Object.values(headerGroups).forEach(function (headerOptions) {
3572
+ headerOptions.forEach(function (o) {
3573
+ if (o.checked !== undefined)
3574
+ o.checked = anyChecked_2;
3575
+ });
3576
+ });
3426
3577
  }
3427
- }, [selectedValues]);
3428
- var _f = useGridPopoverHook({
3429
- className: props.className,
3430
- invalid: invalid,
3431
- save: save
3432
- }), popoverWrapper = _f.popoverWrapper, triggerSave = _f.triggerSave;
3433
- return popoverWrapper(jsxRuntime.jsx(ComponentLoadingWrapper, __assign({ loading: !options, className: "GridFormMultiSelect-container" }, { children: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [options && props.filtered && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(FocusableItem, __assign({ className: "filter-item" }, { children: function (_a) {
3434
- var _b;
3435
- var ref = _a.ref;
3436
- return (jsxRuntime.jsx("div", __assign({ style: { display: "flex", width: "100%" }, className: "GridFormMultiSelect-filter" }, { children: jsxRuntime.jsx("input", { autoFocus: true, className: "free-text-input", style: { border: "0px" }, ref: ref, type: "text", placeholder: (_b = props.filterPlaceholder) !== null && _b !== void 0 ? _b : "Placeholder", "data-testid": "filteredMenu-free-text-input", defaultValue: "", onChange: function (e) { return setFilter(e.target.value.toLowerCase()); } }) })));
3437
- } }), "filter"), jsxRuntime.jsx(MenuDivider, {}, "$$divider_filter")] })), jsxRuntime.jsx("div", __assign({ className: "GridFormMultiSelect-options" }, { children: options === null || options === void 0 ? void 0 : options.map(function (item, index) {
3438
- var _a;
3439
- return item.value === MenuSeparatorString ? (jsxRuntime.jsx(MenuDivider, {}, "$$divider_".concat(index))) : filteredValues.includes(item.value) ? null : (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(MenuItem, __assign({ onClick: function (e) {
3440
- // Global react-menu MenuItem handler handles tabs
3441
- if (e.key !== "Tab") {
3442
- e.keepOpen = true;
3443
- toggleValue(item);
3444
- }
3445
- } }, { children: jsxRuntime.jsx(lui.LuiCheckboxInput, { isChecked: "".concat(item.value) in selectedValues, value: "".concat(item.value), label: (_a = item.label) !== null && _a !== void 0 ? _a : (item.value == null ? "<".concat(item.value, ">") : "".concat(item.value)), inputProps: {
3446
- onClick: function (e) {
3447
- e.preventDefault();
3448
- e.stopPropagation();
3449
- return false;
3450
- }
3451
- }, onChange: function () {
3452
- /*Do nothing, change handled by menuItem*/
3453
- } }) })), "".concat(item.value) in selectedValues && item.subComponent && (jsxRuntime.jsx(FocusableItem, __assign({ className: "LuiDeprecatedForms" }, { children: function (_) {
3454
- return item.subComponent && (jsxRuntime.jsx(GridSubComponentContext.Provider, __assign({ value: {
3455
- data: data,
3456
- value: selectedValues["".concat(item.value)],
3457
- setValue: function (value) {
3458
- var _a;
3459
- setSelectedValues(__assign(__assign({}, selectedValues), (_a = {}, _a["".concat(item.value)] = value, _a)));
3460
- },
3461
- setValid: function (valid) {
3462
- subComponentIsValid.current["".concat(item.value)] = valid;
3463
- },
3464
- triggerSave: triggerSave
3465
- } }, { children: jsxRuntime.jsx(item.subComponent, {}) })));
3466
- } }), "".concat(item.value, "_subcomponent")))] }, "".concat(index)));
3467
- }) }))] }) })));
3578
+ setOptions(__spreadArray([], options, true));
3579
+ }, [filter, headerGroups, options, setOptions]);
3580
+ var addCustomFilterValue = react.useCallback(function () {
3581
+ if (!options || !onSelectFilter)
3582
+ return;
3583
+ var preFilterOptions = JSON.stringify(options);
3584
+ onSelectFilter(filter.trim(), options);
3585
+ // Detect if options list changed and update
3586
+ if (preFilterOptions === JSON.stringify(options))
3587
+ return;
3588
+ setOptions(__spreadArray([], options, true));
3589
+ setFilter("");
3590
+ }, [filter, onSelectFilter, options, setFilter, setOptions]);
3591
+ var handleKeyUp = react.useCallback(function (e) {
3592
+ if (e.key === "Enter") {
3593
+ e.stopPropagation();
3594
+ e.preventDefault();
3595
+ if (e.ctrlKey)
3596
+ toggleSelectAllVisible();
3597
+ else if (onSelectFilter)
3598
+ addCustomFilterValue();
3599
+ }
3600
+ }, [addCustomFilterValue, onSelectFilter, toggleSelectAllVisible]);
3601
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(FocusableItem, __assign({ className: "filter-item" }, { children: function (_) { return (jsxRuntime.jsxs("div", __assign({ style: { width: "100%" }, className: "GridFormMultiSelect-filter" }, { children: [jsxRuntime.jsx("input", { className: "LuiTextInput-input", type: "text", placeholder: filterPlaceholder !== null && filterPlaceholder !== void 0 ? filterPlaceholder : "Placeholder", "data-testid": "filteredMenu-free-text-input", value: filter, "data-disableenterautosave": true, "data-allowtabtoSave": true, onChange: function (e) { return setFilter(e.target.value); }, onKeyUp: handleKeyUp }), filterHelpText && (jsxRuntime.jsx(FormError, { error: null, helpText: typeof filterHelpText === "function" ? filterHelpText(filter.trim(), options) : filterHelpText }))] }))); } }), "filter"), jsxRuntime.jsx(MenuDivider, {}, "$$divider_filter"), headerGroups && !lodashEs.toPairs(headerGroups).some(function (_a) {
3602
+ _a[0]; var options = _a[1];
3603
+ return !lodashEs.isEmpty(options);
3604
+ }) && (jsxRuntime.jsx("div", __assign({ className: "szh-menu__item" }, { children: "[No items match the filter]" })))] }));
3605
+ };
3606
+ var MenuRadioItem = function (props) {
3607
+ var _a, _b;
3608
+ var item = props.item, options = props.options, setOptions = props.setOptions;
3609
+ var toggleValue = react.useCallback(function (item) {
3610
+ item.checked = !item.checked;
3611
+ setOptions(__spreadArray([], options, true));
3612
+ }, [options, setOptions]);
3613
+ return (jsxRuntime.jsx(MenuItem, __assign({ onClick: function (e) {
3614
+ // Global react-menu MenuItem handler handles tabs
3615
+ if (e.key !== "Tab") {
3616
+ e.keepOpen = true;
3617
+ toggleValue(item);
3618
+ }
3619
+ } }, { children: jsxRuntime.jsx(lui.LuiCheckboxInput, { isChecked: (_a = item.checked) !== null && _a !== void 0 ? _a : false, value: "".concat(item.value), label: (_b = item.label) !== null && _b !== void 0 ? _b : (item.value == null ? "<".concat(item.value, ">") : "".concat(item.value)), inputProps: {
3620
+ onClick: function (e) {
3621
+ // Click is handled by MenuItem onClick
3622
+ e.preventDefault();
3623
+ e.stopPropagation();
3624
+ }
3625
+ }, onChange: function () {
3626
+ /*Do nothing, change handled by menuItem*/
3627
+ } }) })));
3628
+ };
3629
+ var MenuSubComponent = function (props) {
3630
+ var data = props.data, item = props.item, options = props.options, setOptions = props.setOptions, subComponentIsValid = props.subComponentIsValid, triggerSave = props.triggerSave;
3631
+ return (jsxRuntime.jsx(FocusableItem, __assign({ className: "LuiDeprecatedForms" }, { children: function (_) {
3632
+ return item.subComponent && (jsxRuntime.jsx(GridSubComponentContext.Provider, __assign({ value: {
3633
+ context: { options: options },
3634
+ data: data,
3635
+ value: item.subValue,
3636
+ setValue: function (value) {
3637
+ item.subValue = value;
3638
+ setOptions(__spreadArray([], options, true));
3639
+ },
3640
+ setValid: function (valid) {
3641
+ subComponentIsValid["".concat(item.value)] = valid;
3642
+ },
3643
+ triggerSave: triggerSave
3644
+ } }, { children: jsxRuntime.jsx(item.subComponent, {}) })));
3645
+ } }), "".concat(item.value, "_subcomponent")));
3468
3646
  };
3469
3647
 
3470
3648
  var GridPopoutEditMultiSelect = function (colDef, props) {
@@ -3599,6 +3777,7 @@ var GridFormPopoverMenu = function (props) {
3599
3777
  return popoverWrapper(jsxRuntime.jsx(ComponentLoadingWrapper, __assign({ loading: !options, className: "GridFormPopupMenu" }, { children: jsxRuntime.jsx(jsxRuntime.Fragment, { children: options === null || options === void 0 ? void 0 : options.map(function (item, index) {
3600
3778
  return item.label === PopoutMenuSeparator ? (jsxRuntime.jsx(MenuDivider, {}, "$$divider_".concat(index))) : (!item.hidden && (jsxRuntime.jsxs(react.Fragment, { children: [jsxRuntime.jsx(MenuItem, __assign({ onClick: function (e) { return onMenuItemClick(e, item); }, disabled: !!item.disabled, title: item.disabled && typeof item.disabled !== "boolean" ? item.disabled : "" }, { children: item.label }), "".concat(item.label)), item.subComponent && subComponentSelected === item && (jsxRuntime.jsx(FocusableItem, __assign({ className: "LuiDeprecatedForms" }, { children: function (_) {
3601
3779
  return item.subComponent && (jsxRuntime.jsx(GridSubComponentContext.Provider, __assign({ value: {
3780
+ context: {},
3602
3781
  data: data,
3603
3782
  value: subSelectedValue,
3604
3783
  setValue: function (value) {
@@ -3707,12 +3886,6 @@ styleInject(css_248z$2);
3707
3886
  var css_248z$1 = ".LuiTextInput{margin-bottom:0}.LuiTextInput-formatted{color:#beb9b4;line-height:48px;position:absolute;right:14px;top:0}";
3708
3887
  styleInject(css_248z$1);
3709
3888
 
3710
- var FormError = function (props) {
3711
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.error && (jsxRuntime.jsxs("span", __assign({ className: "LuiTextInput-error" }, { children: [jsxRuntime.jsx(lui.LuiIcon, { alt: "error", name: "ic_error", className: "LuiTextInput-error-icon", size: "sm", status: "error" }), props.error] }))), props.helpText && !props.error && (jsxRuntime.jsx("span", __assign({ style: {
3712
- fontSize: "0.7rem"
3713
- } }, { children: props.helpText })))] }));
3714
- };
3715
-
3716
3889
  var TextInputFormatted = function (props) {
3717
3890
  return (jsxRuntime.jsxs("div", __assign({ className: clsx("LuiTextInput Grid-popoverContainer", props.error && "hasError", props.className) }, { children: [jsxRuntime.jsxs("span", __assign({ className: "LuiTextInput-inputWrapper" }, { children: [jsxRuntime.jsx("input", __assign({ type: "text", spellCheck: true, defaultValue: props.value }, lodashEs.omit(props, ["error", "value", "helpText", "formatted", "className"]), { className: "LuiTextInput-input", onMouseEnter: function (e) {
3718
3891
  e.currentTarget.focus();
@@ -3908,12 +4081,13 @@ var TextAreaInput = function (props) {
3908
4081
  } }, { children: props.value })) }))] })), jsxRuntime.jsx(FormError, { error: props.error, helpText: props.helpText })] })));
3909
4082
  };
3910
4083
 
3911
- var TextInputValidator = function (props, value, data) {
4084
+ var TextInputValidator = function (props, value, data, context) {
3912
4085
  if (value == null)
3913
4086
  return null;
3914
4087
  // This can happen because subcomponent is invoked without type safety
3915
4088
  if (typeof value !== "string") {
3916
4089
  console.error("Value is not a string", value);
4090
+ return null;
3917
4091
  }
3918
4092
  if (props.required && value.length === 0) {
3919
4093
  return "Some text is required";
@@ -3921,11 +4095,11 @@ var TextInputValidator = function (props, value, data) {
3921
4095
  if (props.maxLength && value.length > props.maxLength) {
3922
4096
  return "Text must be no longer than ".concat(props.maxLength, " characters");
3923
4097
  }
3924
- if (props.maxBytes && new TextEncoder().encode(value).length > props.maxBytes) {
4098
+ if (props.maxBytes && stringByteLengthIsInvalid(value, props.maxBytes)) {
3925
4099
  return "Text must be no longer than ".concat(props.maxLength, " bytes");
3926
4100
  }
3927
4101
  if (props.invalid) {
3928
- return props.invalid(value, data);
4102
+ return props.invalid(value, data, context);
3929
4103
  }
3930
4104
  return null;
3931
4105
  };
@@ -3933,30 +4107,30 @@ var TextInputValidator = function (props, value, data) {
3933
4107
  var GridFormTextArea = function (props) {
3934
4108
  var _a, _b;
3935
4109
  var _c = useGridPopoverContext(), field = _c.field, initialVale = _c.value, data = _c.data;
3936
- var _d = react.useState(initialVale != null ? "".concat(initialVale) : ""), value = _d[0], setValue = _d[1];
4110
+ var initValue = react.useMemo(function () { return (initialVale == null ? "" : "".concat(initialVale)); }, [initialVale]);
4111
+ var _d = react.useState(initValue), value = _d[0], setValue = _d[1];
3937
4112
  var helpText = (_a = props.helpText) !== null && _a !== void 0 ? _a : "Press tab to save";
3938
- var invalid = react.useCallback(function () { return TextInputValidator(props, value, data); }, [props, value, data]);
4113
+ var invalid = react.useCallback(function () { return TextInputValidator(props, value, data, {}); }, [props, value, data]);
3939
4114
  var save = react.useCallback(function (selectedRows) { return __awaiter(void 0, void 0, void 0, function () {
4115
+ var trimmedValue;
3940
4116
  return __generator(this, function (_a) {
3941
4117
  switch (_a.label) {
3942
4118
  case 0:
3943
- if (initialVale === (value !== null && value !== void 0 ? value : ""))
4119
+ if (invalid())
4120
+ return [2 /*return*/, false];
4121
+ trimmedValue = value.trim();
4122
+ // No change, so don't save
4123
+ if (initValue === trimmedValue)
3944
4124
  return [2 /*return*/, true];
3945
4125
  if (!props.onSave) return [3 /*break*/, 2];
3946
- return [4 /*yield*/, props.onSave(selectedRows, value)];
4126
+ return [4 /*yield*/, props.onSave(selectedRows, trimmedValue)];
3947
4127
  case 1: return [2 /*return*/, _a.sent()];
3948
4128
  case 2:
3949
- if (field == null) {
3950
- console.error("ColDef has no field set");
3951
- return [2 /*return*/, false];
3952
- }
3953
- selectedRows.forEach(function (row) {
3954
- row[field] = value;
3955
- });
4129
+ selectedRows.forEach(function (row) { return (row[field] = trimmedValue); });
3956
4130
  return [2 /*return*/, true];
3957
4131
  }
3958
4132
  });
3959
- }); }, [initialVale, value, props, field]);
4133
+ }); }, [invalid, value, initValue, props, field]);
3960
4134
  var popoverWrapper = useGridPopoverHook({
3961
4135
  className: props.className,
3962
4136
  invalid: invalid,
@@ -3973,7 +4147,7 @@ var GridFormTextInput = function (props) {
3973
4147
  var helpText = (_a = props.helpText) !== null && _a !== void 0 ? _a : "Press enter or tab to save";
3974
4148
  var initValue = react.useMemo(function () { return (initialVale == null ? "" : "".concat(initialVale)); }, [initialVale]);
3975
4149
  var _d = react.useState(initValue), value = _d[0], setValue = _d[1];
3976
- var invalid = react.useCallback(function () { return TextInputValidator(props, value, data); }, [data, props, value]);
4150
+ var invalid = react.useCallback(function () { return TextInputValidator(props, value, data, {}); }, [data, props, value]);
3977
4151
  var save = react.useCallback(function (selectedRows) { return __awaiter(void 0, void 0, void 0, function () {
3978
4152
  var trimmedValue;
3979
4153
  return __generator(this, function (_a) {
@@ -3982,19 +4156,14 @@ var GridFormTextInput = function (props) {
3982
4156
  if (invalid())
3983
4157
  return [2 /*return*/, false];
3984
4158
  trimmedValue = value.trim();
4159
+ // No change, so don't save
3985
4160
  if (initValue === trimmedValue)
3986
4161
  return [2 /*return*/, true];
3987
4162
  if (!props.onSave) return [3 /*break*/, 2];
3988
4163
  return [4 /*yield*/, props.onSave(selectedRows, trimmedValue)];
3989
4164
  case 1: return [2 /*return*/, _a.sent()];
3990
4165
  case 2:
3991
- if (field == null) {
3992
- console.error("ColDef has no field set");
3993
- return [2 /*return*/, false];
3994
- }
3995
- selectedRows.forEach(function (row) {
3996
- row[field] = trimmedValue;
3997
- });
4166
+ selectedRows.forEach(function (row) { return (row[field] = trimmedValue); });
3998
4167
  return [2 /*return*/, true];
3999
4168
  }
4000
4169
  });
@@ -4013,39 +4182,37 @@ var GridPopoverTextInput = function (colDef, params) {
4013
4182
 
4014
4183
  var GridFormSubComponentTextInput = function (props) {
4015
4184
  var _a;
4016
- var _b = react.useContext(GridSubComponentContext), value = _b.value, setValue = _b.setValue, setValid = _b.setValid, data = _b.data;
4185
+ var _b = react.useContext(GridSubComponentContext), value = _b.value, setValue = _b.setValue, setValid = _b.setValid, data = _b.data, context = _b.context;
4017
4186
  var helpText = (_a = props.helpText) !== null && _a !== void 0 ? _a : "Press enter or tab to save";
4018
4187
  // If is not initialised yet as it's just been created then set the default value
4019
4188
  react.useEffect(function () {
4020
4189
  if (value == null)
4021
4190
  setValue(props.defaultValue);
4022
4191
  }, [props.defaultValue, setValue, value]);
4023
- var invalid = react.useCallback(function () { return TextInputValidator(props, value, data); }, [data, props, value]);
4192
+ var invalid = react.useCallback(function () { return TextInputValidator(props, value, data, context); }, [context, data, props, value]);
4024
4193
  react.useEffect(function () {
4025
4194
  setValid(value != null && invalid() == null);
4026
4195
  }, [setValid, invalid, value]);
4027
- return (jsxRuntime.jsx(TextInputFormatted, { value: value, error: invalid(), onChange: function (e) { return setValue(e.target.value); }, helpText: helpText, autoFocus: true, placeholder: props.placeholder, style: {
4028
- width: "100%"
4029
- } }));
4196
+ return (jsxRuntime.jsx(TextInputFormatted, { value: value, error: invalid(), onChange: function (e) { return setValue(e.target.value); }, helpText: helpText, autoFocus: true, placeholder: props.placeholder, style: { width: "100%" } }));
4030
4197
  };
4031
4198
 
4032
4199
  var GridFormSubComponentTextArea = function (props) {
4033
4200
  var _a;
4034
- var _b = react.useContext(GridSubComponentContext), value = _b.value, data = _b.data, setValue = _b.setValue, setValid = _b.setValid;
4201
+ var _b = react.useContext(GridSubComponentContext), value = _b.value, data = _b.data, setValue = _b.setValue, setValid = _b.setValid, context = _b.context;
4035
4202
  var helpText = (_a = props.helpText) !== null && _a !== void 0 ? _a : "Press tab to save";
4036
4203
  // If is not initialised yet as it's just been created then set the default value
4037
4204
  react.useEffect(function () {
4038
4205
  if (value == null)
4039
4206
  setValue(props.defaultValue);
4040
4207
  }, [props.defaultValue, setValue, value]);
4041
- var invalid = react.useCallback(function () { return TextInputValidator(props, value, data); }, [data, props, value]);
4208
+ var invalid = react.useCallback(function () { return TextInputValidator(props, value, data, context); }, [data, props, value, context]);
4042
4209
  react.useEffect(function () {
4043
4210
  setValid(value != null && invalid() == null);
4044
4211
  }, [setValid, invalid, value]);
4045
4212
  return (jsxRuntime.jsx("div", __assign({ className: clsx("FreeTextInput LuiDeprecatedForms", props.className) }, { children: jsxRuntime.jsx(TextAreaInput, { className: "free-text-input", value: value, onChange: function (e) { return setValue(e.target.value); }, error: invalid(), helpText: helpText, autoFocus: true, placeholder: props.placeholder }) })));
4046
4213
  };
4047
4214
 
4048
- var css_248z = ".ActionButton{align-items:center;display:flex}.ActionButton .LuiIcon{margin:0 4px!important}.ActionButton-minimalArea{position:relative}.ActionButton-minimalAreaDisplay{position:absolute}.ActionButton-minimalAreaExpand{visibility:hidden}.ActionButton-inProgress{background-color:#e2f3f7!important;color:#007198!important;cursor:progress}.ActionButton-inProgress svg *{fill:#0000!important}";
4215
+ var css_248z = ".ActionButton{align-items:center;display:flex}.ActionButton-minimal{padding-right:38px!important}.ActionButton .LuiIcon{margin:0 4px!important}.ActionButton-minimalArea{position:relative}.ActionButton-minimalAreaDisplay{position:absolute}.ActionButton-minimalAreaExpand{visibility:hidden}.ActionButton-inProgress{background-color:#e2f3f7!important;color:#007198!important;cursor:progress}.ActionButton-inProgress svg *{fill:#0000!important}.ActionButton-fill{justify-content:center;width:100%}";
4049
4216
  styleInject(css_248z);
4050
4217
 
4051
4218
  /**
@@ -4118,16 +4285,17 @@ var useStateDeferred = function (initialValue) {
4118
4285
  var minimumInProgressTimeMs = 950;
4119
4286
  var ActionButton = function (_a) {
4120
4287
  var _b, _c, _d;
4121
- var icon = _a.icon, name = _a.name, inProgressName = _a.inProgressName, dataTestId = _a.dataTestId, className = _a.className, title = _a.title, onAction = _a.onAction, externalSetInProgress = _a.externalSetInProgress, _e = _a.size, size = _e === void 0 ? "sm" : _e, _f = _a.level, level = _f === void 0 ? "tertiary" : _f, ariaLabel = _a["aria-label"];
4122
- var _g = react.useState(false), inProgress = _g[0], setInProgress = _g[1];
4288
+ var icon = _a.icon, name = _a.name, inProgressName = _a.inProgressName, dataTestId = _a.dataTestId, style = _a.style, className = _a.className, title = _a.title, onAction = _a.onAction, externalSetInProgress = _a.externalSetInProgress, _e = _a.size, size = _e === void 0 ? "sm" : _e, _f = _a.iconPosition, iconPosition = _f === void 0 ? "left" : _f, _g = _a.level, level = _g === void 0 ? "tertiary" : _g, ariaLabel = _a["aria-label"];
4289
+ var _h = react.useState(false), inProgress = _h[0], setInProgress = _h[1];
4123
4290
  var lastInProgress = usePrevious(inProgress !== null && inProgress !== void 0 ? inProgress : false);
4124
- var _h = useStateDeferred(inProgress), localInProgress = _h[0], setLocalInProgress = _h[1], setLocalInProgressDeferred = _h[2];
4291
+ var _j = useStateDeferred(inProgress), localInProgress = _j[0], setLocalInProgress = _j[1], setLocalInProgressDeferred = _j[2];
4125
4292
  react.useEffect(function () {
4126
4293
  if (inProgress == lastInProgress)
4127
4294
  return;
4128
4295
  inProgress ? setLocalInProgress(true) : setLocalInProgressDeferred(false, minimumInProgressTimeMs);
4129
4296
  }, [inProgress, lastInProgress, setLocalInProgress, setLocalInProgressDeferred]);
4130
- return (jsxRuntime.jsxs(lui.LuiButton, __assign({ "data-testid": dataTestId, type: "button", level: level, title: (_b = title !== null && title !== void 0 ? title : ariaLabel) !== null && _b !== void 0 ? _b : name, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : name, className: clsx("lui-button-icon", "ActionButton", className, localInProgress && "ActionButton-inProgress"), size: "lg", style: name == null ? { padding: "8px 5px" } : {}, onClick: function () { return __awaiter(void 0, void 0, void 0, function () {
4297
+ var buttonText = (jsxRuntime.jsxs("span", __assign({ className: "ActionButton-minimalArea" }, { children: [jsxRuntime.jsx("span", __assign({ className: "ActionButton-minimalAreaDisplay" }, { children: (_b = (localInProgress ? inProgressName : name)) !== null && _b !== void 0 ? _b : name })), jsxRuntime.jsx("span", __assign({ className: "ActionButton-minimalAreaExpand" }, { children: name }))] })));
4298
+ return (jsxRuntime.jsxs(lui.LuiButton, __assign({ "data-testid": dataTestId, type: "button", level: level, title: (_c = title !== null && title !== void 0 ? title : ariaLabel) !== null && _c !== void 0 ? _c : name, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : name, className: clsx("lui-button-icon-right", "ActionButton", className, localInProgress && "ActionButton-inProgress", name != null && !(className === null || className === void 0 ? void 0 : className.includes("ActionButton-fill")) && "ActionButton-minimal"), size: "lg", style: __assign(__assign({}, (name == null && { padding: "8px 5px" })), style), onClick: function () { return __awaiter(void 0, void 0, void 0, function () {
4131
4299
  var promise, isPromise;
4132
4300
  return __generator(this, function (_a) {
4133
4301
  switch (_a.label) {
@@ -4149,12 +4317,18 @@ var ActionButton = function (_a) {
4149
4317
  case 3: return [2 /*return*/];
4150
4318
  }
4151
4319
  });
4152
- }); }, disabled: localInProgress }, { children: [localInProgress ? (jsxRuntime.jsx(lui.LuiMiniSpinner, { size: 16, divProps: {
4320
+ }); }, disabled: localInProgress }, { children: [iconPosition === "right" && buttonText, localInProgress ? (jsxRuntime.jsx(lui.LuiMiniSpinner, { size: 16, divProps: {
4153
4321
  "data-testid": "loading-spinner",
4154
- style: { margin: 0, paddingRight: 5, paddingLeft: 3, paddingBottom: 0, paddingTop: 0 },
4322
+ style: {
4323
+ margin: 0,
4324
+ paddingRight: 5,
4325
+ paddingLeft: 3,
4326
+ paddingBottom: 0,
4327
+ paddingTop: 0
4328
+ },
4155
4329
  role: "status",
4156
4330
  "aria-label": "Loading"
4157
- } })) : (jsxRuntime.jsx(lui.LuiIcon, { name: icon, alt: (_c = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : name) !== null && _c !== void 0 ? _c : "", size: size })), jsxRuntime.jsxs("span", __assign({ className: "ActionButton-minimalArea" }, { children: [jsxRuntime.jsx("span", __assign({ className: "ActionButton-minimalAreaDisplay" }, { children: (_d = (localInProgress ? inProgressName : name)) !== null && _d !== void 0 ? _d : name })), jsxRuntime.jsx("span", __assign({ className: "ActionButton-minimalAreaExpand" }, { children: name }))] }))] })));
4331
+ } })) : (jsxRuntime.jsx(lui.LuiIcon, { name: icon, alt: (_d = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : name) !== null && _d !== void 0 ? _d : "", size: size, spanProps: { style: iconPosition === "right" ? { transform: "scaleX(-1)" } : {} } })), iconPosition === "left" && buttonText] })));
4158
4332
  };
4159
4333
 
4160
4334
  exports.ActionButton = ActionButton;
@@ -4214,6 +4388,7 @@ exports.convertDDToDMS = convertDDToDMS;
4214
4388
  exports.hasParentClass = hasParentClass;
4215
4389
  exports.isFloat = isFloat;
4216
4390
  exports.isNotEmpty = isNotEmpty;
4391
+ exports.stringByteLengthIsInvalid = stringByteLengthIsInvalid;
4217
4392
  exports.useGridPopoverContext = useGridPopoverContext;
4218
4393
  exports.useGridPopoverHook = useGridPopoverHook;
4219
4394
  exports.useMenuState = useMenuState;