@linzjs/step-ag-grid 29.13.0 → 29.14.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 (44) hide show
  1. package/dist/index.css +26 -2
  2. package/dist/src/components/Grid.d.ts +36 -61
  3. package/dist/src/components/GridRangeSelectContextMenu.d.ts +10 -0
  4. package/dist/src/components/gridForm/GridFormDropDown.d.ts +1 -1
  5. package/dist/src/components/gridForm/GridFormPopoverMenu.d.ts +2 -1
  6. package/dist/src/components/gridHook/useGridContextMenu.d.ts +12 -7
  7. package/dist/src/components/gridHook/useGridCopy.d.ts +15 -0
  8. package/dist/src/components/gridHook/useGridCopySettings.d.ts +11 -0
  9. package/dist/src/components/gridHook/useGridRangeSelection.d.ts +25 -0
  10. package/dist/src/components/gridPopoverEdit/GridPopoverEditBearing.d.ts +2 -0
  11. package/dist/src/components/types.d.ts +1 -0
  12. package/dist/src/contexts/GridContext.d.ts +1 -0
  13. package/dist/src/lui/timeoutHook.d.ts +0 -6
  14. package/dist/src/lui/tsUtils.d.ts +5 -0
  15. package/dist/src/utils/__tests__/random.ts +19 -0
  16. package/dist/src/utils/util.d.ts +1 -0
  17. package/dist/step-ag-grid.cjs +560 -79
  18. package/dist/step-ag-grid.cjs.map +1 -1
  19. package/dist/step-ag-grid.esm.js +561 -82
  20. package/dist/step-ag-grid.esm.js.map +1 -1
  21. package/package.json +1 -1
  22. package/src/components/Grid.tsx +249 -179
  23. package/src/components/GridRangeSelectContextMenu.tsx +73 -0
  24. package/src/components/gridForm/GridFormDropDown.tsx +1 -3
  25. package/src/components/gridForm/GridFormPopoverMenu.tsx +2 -1
  26. package/src/components/gridHook/useGridContextMenu.tsx +22 -9
  27. package/src/components/gridHook/useGridCopy.ts +279 -0
  28. package/src/components/gridHook/useGridCopySettings.ts +28 -0
  29. package/src/components/gridHook/useGridRangeSelection.ts +235 -0
  30. package/src/components/gridPopoverEdit/GridPopoverEditBearing.ts +3 -0
  31. package/src/components/types.ts +2 -0
  32. package/src/contexts/GridContext.tsx +2 -0
  33. package/src/contexts/GridContextProvider.tsx +5 -2
  34. package/src/lui/timeoutHook.tsx +0 -19
  35. package/src/lui/tsUtils.ts +8 -0
  36. package/src/stories/grid/GridCopy.stories.tsx +175 -0
  37. package/src/stories/grid/GridPopoverEditBearing.stories.tsx +4 -4
  38. package/src/stories/grid/GridReadOnly.stories.tsx +1 -0
  39. package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +2 -2
  40. package/src/styles/ContextMenu.scss +61 -0
  41. package/src/styles/Grid.scss +26 -2
  42. package/src/utils/__tests__/random.ts +19 -0
  43. package/src/utils/bearing.ts +2 -2
  44. package/src/utils/util.ts +2 -0
@@ -1,8 +1,8 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { LuiMiniSpinner, LuiStatusSpinner, LuiIcon, LuiButtonGroup, LuiButton, LuiCheckboxInput } from '@linzjs/lui';
2
+ import { LuiMiniSpinner, LuiIcon, useShowLUIMessage, LuiStatusSpinner, LuiButtonGroup, LuiButton, LuiCheckboxInput } from '@linzjs/lui';
3
3
  import { ModuleRegistry, AllCommunityModule } from 'ag-grid-community';
4
4
  import { AgGridReact } from 'ag-grid-react';
5
- import { negate, isEmpty, findIndex, defer, debounce as debounce$1, xorBy, last, difference, delay, omit, sortBy, partition, compact, pick, groupBy, fromPairs, toPairs, isEqual, pull, filter, sumBy, remove, flatten, castArray } from 'lodash-es';
5
+ import { negate, isEmpty, findIndex, defer, debounce as debounce$1, compact, xorBy, last, difference, delay, omit, sortBy, partition, pick, groupBy, fromPairs, toPairs, isEqual, pull, filter, sumBy, remove, flatten, castArray } from 'lodash-es';
6
6
  import React, { useRef, useLayoutEffect, useEffect, createContext, useContext, useState, useMemo, memo, forwardRef, useCallback, useReducer, cloneElement, useImperativeHandle, Fragment as Fragment$1, useId } from 'react';
7
7
  import { unstable_batchedUpdates, flushSync, createPortal } from 'react-dom';
8
8
  import { createRoot } from 'react-dom/client';
@@ -417,6 +417,9 @@ function useInterval(callback, delay) {
417
417
  savedCallback.current = callback;
418
418
  }, [callback]);
419
419
  useEffect(() => {
420
+ if (delay === null) {
421
+ return;
422
+ }
420
423
  const id = setInterval(() => {
421
424
  savedCallback.current();
422
425
  }, delay);
@@ -433,6 +436,7 @@ const NoContext = () => {
433
436
  const GridContext = createContext({
434
437
  gridReady: false,
435
438
  gridRenderState: () => null,
439
+ getCellValue: NoContext,
436
440
  getColDef: NoContext,
437
441
  getColumns: NoContext,
438
442
  getColumnIds: NoContext,
@@ -754,6 +758,36 @@ const GridHeaderSelect = ({ api }) => {
754
758
  } }) }));
755
759
  };
756
760
 
761
+ function styleInject(css, ref) {
762
+ if ( ref === void 0 ) ref = {};
763
+ var insertAt = ref.insertAt;
764
+
765
+ if (!css || typeof document === 'undefined') { return; }
766
+
767
+ var head = document.head || document.getElementsByTagName('head')[0];
768
+ var style = document.createElement('style');
769
+ style.type = 'text/css';
770
+
771
+ if (insertAt === 'top') {
772
+ if (head.firstChild) {
773
+ head.insertBefore(style, head.firstChild);
774
+ } else {
775
+ head.appendChild(style);
776
+ }
777
+ } else {
778
+ head.appendChild(style);
779
+ }
780
+
781
+ if (style.styleSheet) {
782
+ style.styleSheet.cssText = css;
783
+ } else {
784
+ style.appendChild(document.createTextNode(css));
785
+ }
786
+ }
787
+
788
+ var css_248z$4 = ".GridContextMenu li.szh-menu__header{color:#6b6966;font-size:14px;font-weight:600;padding-left:16px;padding-right:16px;text-transform:none}.GridContextMenu li.szh-menu__item{padding-left:16px;padding-right:16px}.GridContextMenu li.szh-menu__item .copyMenuMenuItem{align-items:center;display:flex;gap:8px}.GridContextMenu li.szh-menu__item .copyMenuMenuItem__text{color:#2a292c;font-size:16px;font-weight:400;width:80px}.GridContextMenu li.szh-menu__item .copyMenuMenuItem__buttonDefault{background:none;border:2px solid #0000;display:flex;padding:6px}.GridContextMenu li.szh-menu__item .copyMenuMenuItem__buttonDefault.copyMenuMenuItem__buttonDefault--hidden:hover{border:2px solid #2a292c}.GridContextMenu li.szh-menu__item .copyMenuMenuItem__buttonDefault--hidden .LuiIcon{fill:#0000}.GridContextMenu li.szh-menu__item .LuiIcon,.GridContextMenu li.szh-menu__item .copyMenuMenuItem__buttonDefault--hidden:hover .LuiIcon{fill:#6b6966}.GridContextMenu li.szh-menu__item .LuiIcon[data-icon=ic_tick]{padding-left:4px;padding-right:4px}.GridContextMenu li.szh-menu__item--hover{background-color:#e2f3f7}";
789
+ styleInject(css_248z$4);
790
+
757
791
  const EventHandlersContext = createContext({
758
792
  handleClick: () => { },
759
793
  });
@@ -2588,7 +2622,7 @@ const SubMenuFr = ({ 'aria-label': ariaLabel, className, disabled, direction, la
2588
2622
  };
2589
2623
  const SubMenu = withHovering('SubMenu', SubMenuFr);
2590
2624
 
2591
- const useGridContextMenu = ({ contextMenuSelectRow, contextMenu: ContextMenu, }) => {
2625
+ const useGridContextMenu = ({ contextMenuSelectRow, contextMenu: ContextMenu, context, }) => {
2592
2626
  const { redrawRows, prePopupOps, resetFocusedCellAfterCellEditing, getSelectedRows } = useContext(GridContext);
2593
2627
  const [isOpen, setOpen] = useState(false);
2594
2628
  const [anchorPoint, setAnchorPoint] = useState({ x: 0, y: 0 });
@@ -2596,6 +2630,7 @@ const useGridContextMenu = ({ contextMenuSelectRow, contextMenu: ContextMenu, })
2596
2630
  const clickedColDefRef = useRef(null);
2597
2631
  const selectedRowsRef = useRef([]);
2598
2632
  const clickedRowRef = useRef(null);
2633
+ const eventRef = useRef(undefined);
2599
2634
  const openMenu = useCallback((e) => {
2600
2635
  if (!e)
2601
2636
  return;
@@ -2615,15 +2650,423 @@ const useGridContextMenu = ({ contextMenuSelectRow, contextMenu: ContextMenu, })
2615
2650
  clickedColDefRef.current = event.colDef;
2616
2651
  selectedRowsRef.current = getSelectedRows();
2617
2652
  clickedRowRef.current = event.data;
2653
+ eventRef.current = event;
2618
2654
  // This is actually a pointer event
2619
2655
  openMenu(event.event);
2620
2656
  }, [contextMenuSelectRow, getSelectedRows, openMenu]);
2621
2657
  return {
2622
2658
  openMenu,
2623
2659
  cellContextMenu,
2624
- component: ContextMenu ? (jsx(Fragment, { children: jsx(ControlledMenu, { anchorPoint: anchorPoint, state: isOpen ? 'open' : 'closed', direction: "right", onClose: closeMenu, children: isOpen && (jsx(ContextMenu, { selectedRows: selectedRowsRef.current, clickedRow: clickedRowRef.current, colDef: clickedColDefRef.current, close: closeMenu })) }) })) : null,
2660
+ contextMenuComponent: ContextMenu ? (jsx(Fragment, { children: jsx(ControlledMenu, { className: 'GridContextMenu', anchorPoint: anchorPoint, state: isOpen ? 'open' : 'closed', direction: "right", onClose: closeMenu, children: isOpen && (jsx(ContextMenu, { selectedRows: selectedRowsRef.current, clickedRow: clickedRowRef.current, colDef: clickedColDefRef.current, event: eventRef.current, close: closeMenu, context: context })) }) })) : null,
2661
+ };
2662
+ };
2663
+
2664
+ const typedEntries = (obj) => Object.entries(obj);
2665
+
2666
+ const gridCopyOptions = {
2667
+ html: { text: 'Text\xa0/\xa0HTML', icon: 'ic_product_list' },
2668
+ csv: { text: 'CSV', icon: 'ic_csv_file' },
2669
+ json: { text: 'Json', icon: 'ic_file_attached_outline', developer: true },
2670
+ };
2671
+ const CopyOptionsStorageKey = 'stepAgGrid_defaultCopy';
2672
+ const useGridCopySettings = () => {
2673
+ const [copyType, _setCopyType] = useState(() => {
2674
+ const defaultCopy = window.localStorage.getItem(CopyOptionsStorageKey) ?? '';
2675
+ return Object.keys(gridCopyOptions).includes(defaultCopy) ? defaultCopy : 'html';
2676
+ });
2677
+ const setCopyType = useCallback((key) => {
2678
+ window.localStorage.setItem(CopyOptionsStorageKey, key);
2679
+ _setCopyType(key);
2680
+ }, []);
2681
+ return {
2682
+ copyType,
2683
+ setCopyType,
2684
+ };
2685
+ };
2686
+
2687
+ const GridRangeSelectContextMenu = ({ event, context, }) => {
2688
+ const developerContextMenu = !!event?.event?.ctrlKey && !!event?.event?.shiftKey;
2689
+ const onCopy = useMemo(() => context?.onCopy, [context?.onCopy]);
2690
+ const onClick = useCallback((type) => {
2691
+ onCopy?.(type);
2692
+ }, [onCopy]);
2693
+ return (jsxs(Fragment, { children: [jsx(MenuHeader, { children: "Copy as" }), typedEntries(gridCopyOptions).map(([key, { icon, text, developer }]) => {
2694
+ return ((!developer || developerContextMenu) && (jsx(MenuItem, { onClick: () => void onClick(key), children: jsxs("div", { className: 'copyMenuMenuItem', children: [jsx(LuiIcon, { name: icon, alt: text, size: 'md' }), jsx("div", { className: 'copyMenuMenuItem__text', children: text })] }) }, key)));
2695
+ }), jsx(MenuDivider, {}), jsx(MenuHeader, { children: "Set copy default" }), typedEntries(gridCopyOptions).map(([key, { text, developer }]) => {
2696
+ return (!developer && (jsx(MenuItem, { onClick: (e) => {
2697
+ context?.setCopyType(key);
2698
+ e.keepOpen = true;
2699
+ }, children: jsxs("div", { className: clsx('copyMenuMenuItem', context?.copyType === key ? '' : 'copyMenuMenuItem__buttonDefault--hidden'), children: [jsx(LuiIcon, { name: 'ic_tick', alt: 'CSV', size: 'sm' }), jsx("div", { className: 'copyMenuMenuItem__text', children: text })] }) }, 'default_' + key)));
2700
+ })] }));
2701
+ };
2702
+
2703
+ const agGridSelectRowColId = 'ag-Grid-SelectionColumn';
2704
+
2705
+ const useGridCopy = ({ ranges, rangeStartRef, rangeEndRef, hasSelectedMoreThanOneCellRef, cellContextMenu, }) => {
2706
+ const showToast = useShowLUIMessage();
2707
+ const { getSelectedRowIds } = useGridContext();
2708
+ const { getColDef, getCellValue } = useGridContext();
2709
+ const { copyType, setCopyType } = useGridCopySettings();
2710
+ const onCopy = useCallback((type = copyType) => {
2711
+ const rangeStart = rangeStartRef.current;
2712
+ const rangeEnd = rangeEndRef.current;
2713
+ if (rangeStart === null || rangeEnd === null || !hasSelectedMoreThanOneCellRef.current) {
2714
+ return;
2715
+ }
2716
+ if (rangeStart.rowId === rangeEnd.rowId && rangeStart.colId === rangeEnd.colId) {
2717
+ type = 'html';
2718
+ }
2719
+ const json = type === 'json';
2720
+ const { selectedColIds, selectedNodes } = ranges();
2721
+ const filteredSelectedColIds = selectedColIds.filter((colId) => colId === agGridSelectRowColId ||
2722
+ (colId !== 'gridCellFiller' && getColDef(colId)?.headerComponentParams?.exportable !== false));
2723
+ const selectedRowIds = getSelectedRowIds();
2724
+ const formatters = compact(filteredSelectedColIds.map((colKey) => {
2725
+ return (rowNode) => {
2726
+ if (colKey === agGridSelectRowColId) {
2727
+ return selectedRowIds.includes(rowNode.data.id);
2728
+ }
2729
+ else {
2730
+ const v = getCellValue({ rowNode, colKey });
2731
+ if (json && v !== undefined) {
2732
+ return v;
2733
+ }
2734
+ const f = getCellValue({ rowNode, colKey, useFormatter: true });
2735
+ // If it's a number, and it matches value return the original type
2736
+ return v == f ? v : f;
2737
+ }
2738
+ };
2739
+ }));
2740
+ // Get and apply headers
2741
+ const headers = filteredSelectedColIds.map((colId) => {
2742
+ if (colId === agGridSelectRowColId)
2743
+ return type === 'json' ? 'selected' : 'Selected';
2744
+ if (json) {
2745
+ return colId;
2746
+ }
2747
+ return getColDef(colId)?.headerName ?? '?';
2748
+ });
2749
+ const maxCellLength = {};
2750
+ headers.forEach((headerName, i) => {
2751
+ const colId = filteredSelectedColIds[i];
2752
+ maxCellLength[colId] = headerName.length;
2753
+ });
2754
+ const rows = [];
2755
+ if (type === 'csv' || type === 'html') {
2756
+ rows.push(headers);
2757
+ }
2758
+ selectedNodes.forEach((node) => {
2759
+ const row = [];
2760
+ rows.push(row);
2761
+ formatters.forEach((formatter, i) => {
2762
+ const colId = filteredSelectedColIds[i];
2763
+ let value = formatter(node);
2764
+ if (typeof value === 'string') {
2765
+ value = value.replaceAll('\xa0', ' ');
2766
+ }
2767
+ if (!json) {
2768
+ if (value === '-' || value === '–' || value == null) {
2769
+ value = '';
2770
+ }
2771
+ value = String(value);
2772
+ if (value === '-' || value === '–') {
2773
+ value = '';
2774
+ }
2775
+ maxCellLength[colId] = Math.max(maxCellLength[colId], value.length);
2776
+ }
2777
+ switch (type) {
2778
+ case 'json':
2779
+ value =
2780
+ value === 'undefined' || (value !== null && typeof value === 'object') || typeof value === 'string'
2781
+ ? JSON.stringify(value)
2782
+ : value;
2783
+ break;
2784
+ case 'markdown':
2785
+ value = encodeMarkdownValue(value);
2786
+ break;
2787
+ case 'csv':
2788
+ value = encodeCSVValue(value);
2789
+ break;
2790
+ }
2791
+ row.push(String(value));
2792
+ });
2793
+ });
2794
+ let result = '';
2795
+ let html = `<table style="
2796
+ font-family: 'Open Sans', system-ui, sans-serif;
2797
+ font-size: 10px;
2798
+ line-height: 10px;
2799
+ border: 1px solid #d1d9e0;
2800
+ border-collapse: collapse;
2801
+ ">`;
2802
+ if (json) {
2803
+ result += '[\n';
2804
+ }
2805
+ rows.forEach((row, rowIndex) => {
2806
+ if (json) {
2807
+ result += ' { ';
2808
+ }
2809
+ if (rowIndex == 1) {
2810
+ html += '<tbody style="font-weight: 400;">';
2811
+ }
2812
+ if (rowIndex == 0) {
2813
+ html += '<thead style="font-weight: 600;">';
2814
+ }
2815
+ if (rowIndex === 0 || (rowIndex & 1) === 1) {
2816
+ html += '<tr>';
2817
+ }
2818
+ else {
2819
+ html += '<tr style="background-color: #f6f8fa;">';
2820
+ }
2821
+ if (rowIndex === 1 && type === 'html') {
2822
+ Object.values(maxCellLength).forEach((maxLength) => {
2823
+ result += '|' + '-'.repeat(maxLength + 2);
2824
+ });
2825
+ result += '|\n';
2826
+ }
2827
+ row.forEach((cell, i) => {
2828
+ switch (type) {
2829
+ case 'csv':
2830
+ if (i !== 0) {
2831
+ result += ', ';
2832
+ }
2833
+ result += cell;
2834
+ break;
2835
+ case 'html':
2836
+ if (i === 0) {
2837
+ result += '|';
2838
+ }
2839
+ const colId = filteredSelectedColIds[i];
2840
+ result += ' ' + cell.padEnd(maxCellLength[colId], ' ') + ' ';
2841
+ result += '|';
2842
+ html +=
2843
+ rowIndex === 0
2844
+ ? '<th style="border: 1px solid #d1d9e0; padding:6px 13px; text-align: left;">'
2845
+ : '<td style="border: 1px solid #d1d9e0; padding:6px 13px;">';
2846
+ html += cell;
2847
+ html += rowIndex === 0 ? '</th>' : '</td>';
2848
+ break;
2849
+ case 'json':
2850
+ if (i !== 0) {
2851
+ result += ', ';
2852
+ }
2853
+ result += JSON.stringify(headers[i]) + ': ' + cell;
2854
+ break;
2855
+ }
2856
+ });
2857
+ html += '</tr>';
2858
+ if (rowIndex == 0) {
2859
+ html += '</thead>';
2860
+ }
2861
+ if (rowIndex == rows.length - 1) {
2862
+ html += '</tbody>';
2863
+ }
2864
+ if (json) {
2865
+ result += ' }';
2866
+ }
2867
+ result += '\n';
2868
+ });
2869
+ if (json) {
2870
+ result += ']\n';
2871
+ }
2872
+ html += '</table>';
2873
+ showToast({
2874
+ message: `${gridCopyOptions[type].text} copied`,
2875
+ messageType: 'toast',
2876
+ messageLevel: 'info',
2877
+ });
2878
+ if (type === 'html') {
2879
+ const clipboardItem = new ClipboardItem({
2880
+ 'text/html': new Blob([html], { type: 'text/html' }),
2881
+ 'text/plain': new Blob([result], { type: 'text/plain' }), // fallback
2882
+ });
2883
+ void navigator.clipboard.write([clipboardItem]).catch((err) => console.error('Failed to copy: ', err));
2884
+ }
2885
+ else {
2886
+ void navigator.clipboard.writeText(result).catch((err) => console.error('Failed to copy: ', err));
2887
+ }
2888
+ }, [getCellValue, ranges, copyType]);
2889
+ const onCopyEvent = useCallback((e) => {
2890
+ const rangeStart = rangeStartRef.current;
2891
+ const rangeEnd = rangeEndRef.current;
2892
+ if (rangeStart === null ||
2893
+ rangeEnd === null ||
2894
+ (rangeStart.colId === rangeEnd.colId &&
2895
+ rangeStart.rowId === rangeEnd.rowId &&
2896
+ !hasSelectedMoreThanOneCellRef.current)) {
2897
+ return;
2898
+ }
2899
+ e.preventDefault();
2900
+ onCopy();
2901
+ }, [onCopy]);
2902
+ const { cellContextMenu: rangeSelectContextMenu, contextMenuComponent: rangeSelectContextMenuComponent } = useGridContextMenu({
2903
+ contextMenu: (GridRangeSelectContextMenu),
2904
+ context: { onCopy, copyType, setCopyType },
2905
+ });
2906
+ const rangeSelectInterceptContextMenu = useCallback((event) => rangeStartRef.current == null ? cellContextMenu(event) : rangeSelectContextMenu(event), [cellContextMenu, rangeSelectContextMenu]);
2907
+ return {
2908
+ onCopyEvent,
2909
+ rangeSelectInterceptContextMenu,
2910
+ rangeSelectContextMenuComponent,
2625
2911
  };
2626
2912
  };
2913
+ const encodeMarkdownValue = (value) => {
2914
+ return value.replaceAll('|', '\\|');
2915
+ };
2916
+ const encodeCSVValue = (value) => {
2917
+ let str = String(value);
2918
+ // Check if it needs quoting
2919
+ if (/[",\n]/.test(str)) {
2920
+ // Escape double quotes by doubling them
2921
+ str = '"' + str.replace(/"/g, '""') + '"';
2922
+ }
2923
+ return str;
2924
+ };
2925
+
2926
+ const useGridRangeSelection = ({ enableRangeSelection, gridDivRef, rangeStartRef, rangeEndRef, hasSelectedMoreThanOneCellRef, rangeSortedNodesRef, }) => {
2927
+ const [refreshIntervalEnabled, setRefreshIntervalEnabled] = useState(false);
2928
+ const ranges = useCallback(() => {
2929
+ const gridElement = gridDivRef.current;
2930
+ const rangeStart = rangeStartRef.current;
2931
+ const rangeEnd = rangeEndRef.current;
2932
+ const rangeSortedNodes = rangeSortedNodesRef.current;
2933
+ if (!gridElement || !rangeStart || !rangeEnd || !rangeSortedNodes) {
2934
+ return {
2935
+ selectedColIds: [],
2936
+ selectedNodes: [],
2937
+ };
2938
+ }
2939
+ const elStyleLeftComparator = (el1, el2) => elStyleLeft(el1) - elStyleLeft(el2);
2940
+ const elStyleLeft = (el) => parseFloat(el.style.left) ?? 0;
2941
+ const getSortedColIds = () => {
2942
+ //
2943
+ const leftHeaders = [...gridElement.querySelectorAll('.ag-pinned-left-header .ag-header-cell')].sort(elStyleLeftComparator);
2944
+ const centerHeaders = [...gridElement.querySelectorAll('.ag-header-viewport .ag-header-cell')].sort(elStyleLeftComparator);
2945
+ const rightHeaders = [...gridElement.querySelectorAll('.ag-pinned-right-header .ag-header-cell')].sort(elStyleLeftComparator);
2946
+ return [...leftHeaders, ...centerHeaders, ...rightHeaders].map((el, i) => el.getAttribute('col-id') ?? String(i));
2947
+ };
2948
+ const sortedColIds = getSortedColIds();
2949
+ const startColIndex = sortedColIds.indexOf(rangeStart.colId);
2950
+ const endColIndex = sortedColIds.indexOf(rangeEnd.colId);
2951
+ const selectedColIds = sortedColIds.slice(Math.min(startColIndex, endColIndex), Math.max(startColIndex, endColIndex) + 1);
2952
+ const startRowIndex = rangeSortedNodes.findIndex((node) => node.data.id === rangeStart.rowId);
2953
+ const endRowIndex = rangeSortedNodes.findIndex((node) => node.data.id === rangeEnd.rowId);
2954
+ const selectedNodes = rangeSortedNodes.slice(Math.min(startRowIndex, endRowIndex), Math.max(startRowIndex, endRowIndex) + 1);
2955
+ return { selectedColIds, selectedNodes };
2956
+ }, []);
2957
+ const redrawSelectedRanges = useCallback(() => {
2958
+ const gridElement = gridDivRef.current;
2959
+ const { selectedColIds, selectedNodes } = ranges();
2960
+ selectedColIds.forEach((colId, colIndex) => {
2961
+ selectedNodes.forEach((node, rowIndex) => {
2962
+ const rowId = node.data.id;
2963
+ const cell = gridElement.querySelector(`.ag-row[row-id=${JSON.stringify(String(rowId))}] .ag-cell[col-id=${JSON.stringify(colId)}`);
2964
+ cell?.classList.add('rangeSelect');
2965
+ if (colIndex === 0) {
2966
+ cell?.classList.add('rangeSelectLeft');
2967
+ }
2968
+ if (colIndex === selectedColIds.length - 1) {
2969
+ cell?.classList.add('rangeSelectRight');
2970
+ }
2971
+ if (rowIndex === 0) {
2972
+ cell?.classList.add('rangeSelectTop');
2973
+ }
2974
+ if (rowIndex === selectedNodes.length - 1) {
2975
+ cell?.classList.add('rangeSelectBottom');
2976
+ }
2977
+ });
2978
+ });
2979
+ }, []);
2980
+ const updateRangeSelectionCellClasses = useCallback((justRefresh) => {
2981
+ //
2982
+ // Get all grid cols, sort by pinned, then style: left
2983
+ const gridElement = gridDivRef.current;
2984
+ if (!gridElement) {
2985
+ return;
2986
+ }
2987
+ // Clear all selections
2988
+ if (!justRefresh) {
2989
+ gridElement
2990
+ .querySelectorAll('.rangeSelect,.rangeSelectLeft,.rangeSelectTop,.rangeSelectRight,.rangeSelectBottom')
2991
+ .forEach((el) => {
2992
+ el.classList.remove('rangeSelect', 'rangeSelectLeft', 'rangeSelectTop', 'rangeSelectRight', 'rangeSelectBottom');
2993
+ });
2994
+ }
2995
+ // if range selection multiple add .Grid-container.rangeSelectingMultiple
2996
+ const rangeStart = rangeStartRef.current;
2997
+ const rangeEnd = rangeEndRef.current;
2998
+ if (rangeStart !== null &&
2999
+ rangeEnd !== null &&
3000
+ (hasSelectedMoreThanOneCellRef.current ||
3001
+ rangeStart.colId !== rangeEnd.colId ||
3002
+ rangeStart.rowId !== rangeEnd.rowId)) {
3003
+ gridElement.classList.add('rangeSelectingMultiple');
3004
+ gridElement.querySelectorAll('.ag-cell-focus').forEach((el) => {
3005
+ el.classList.remove('ag-cell-focus');
3006
+ });
3007
+ }
3008
+ else {
3009
+ gridElement.classList.remove('rangeSelectingMultiple');
3010
+ return;
3011
+ }
3012
+ const rangeSortedNodes = rangeSortedNodesRef.current;
3013
+ if (!rangeSortedNodes) {
3014
+ return;
3015
+ }
3016
+ redrawSelectedRanges();
3017
+ }, [ranges, redrawSelectedRanges]);
3018
+ // Handle updates after scroll / grid refresh
3019
+ useInterval(() => {
3020
+ updateRangeSelectionCellClasses(true);
3021
+ }, refreshIntervalEnabled ? 150 : null);
3022
+ const clearRangeSelection = useCallback(() => {
3023
+ hasSelectedMoreThanOneCellRef.current = false;
3024
+ setRefreshIntervalEnabled(false);
3025
+ hasSelectedMoreThanOneCellRef.current = false;
3026
+ rangeStartRef.current = null;
3027
+ rangeEndRef.current = null;
3028
+ updateRangeSelectionCellClasses();
3029
+ }, [updateRangeSelectionCellClasses]);
3030
+ const onCellMouseOver = useCallback((e, mouseDown) => {
3031
+ if (!enableRangeSelection) {
3032
+ return;
3033
+ }
3034
+ const button = e.event.buttons;
3035
+ if (button !== 1) {
3036
+ // TODO fix this?
3037
+ //rangeSortedNodesRef.current = null;
3038
+ return;
3039
+ }
3040
+ rangeEndRef.current = {
3041
+ rowId: e.node.data.id,
3042
+ colId: e.column.getColId(),
3043
+ timestamp: Date.now(),
3044
+ };
3045
+ if (mouseDown) {
3046
+ const sortedNodes = [];
3047
+ e.api.forEachNodeAfterFilterAndSort((node) => sortedNodes.push(node));
3048
+ rangeSortedNodesRef.current = sortedNodes;
3049
+ setRefreshIntervalEnabled(true);
3050
+ rangeStartRef.current = { ...rangeEndRef.current };
3051
+ }
3052
+ if (rangeStartRef.current &&
3053
+ rangeEndRef.current &&
3054
+ (rangeStartRef.current.rowId !== rangeEndRef.current.rowId ||
3055
+ rangeStartRef.current.colId !== rangeEndRef.current.colId)) {
3056
+ hasSelectedMoreThanOneCellRef.current = true;
3057
+ window.getSelection()?.removeAllRanges();
3058
+ }
3059
+ updateRangeSelectionCellClasses();
3060
+ }, [enableRangeSelection, updateRangeSelectionCellClasses]);
3061
+ const onCellMouseDown = useCallback((e) => {
3062
+ const button = e.event.buttons;
3063
+ if (button === 1) {
3064
+ clearRangeSelection();
3065
+ }
3066
+ onCellMouseOver(e, true);
3067
+ }, [onCellMouseOver]);
3068
+ return { clearRangeSelection, ranges, onCellMouseDown, onCellMouseOver };
3069
+ };
2627
3070
 
2628
3071
  const GridLoadingOverlayComponentFr = (props, externalRef) => (jsx("div", { ref: externalRef, style: {
2629
3072
  left: 0,
@@ -2806,8 +3249,26 @@ ModuleRegistry.registerModules([AllCommunityModule]);
2806
3249
  /**
2807
3250
  * Wrapper for AgGrid to add commonly used functionality.
2808
3251
  */
2809
- const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection = 'multiple', suppressColumnVirtualization = true, theme = 'ag-theme-step-default', sizeColumns = 'auto', selectColumnPinned = 'left', contextMenuSelectRow = false, singleClickEdit = false, rowData, rowHeight = theme === 'ag-theme-step-default' ? 40 : theme === 'ag-theme-step-compact' ? 36 : 40, selectable, autoSelectFirstRow, onCellFocused: paramsOnCellFocused, maxInitialWidth, suppressReadOnlyStyle = false, externalSelectedItems, setExternalSelectedItems, externalSelectedIds, setExternalSelectedIds, ...params }) => {
2810
- const { gridReady, gridRenderState, setApis, ensureRowVisible, getFirstRowId, selectRowsById, focusByRowById, ensureSelectedRowIsVisible, autoSizeColumns, sizeColumnsToFit, externallySelectedItemsAreInSync, setExternallySelectedItemsAreInSync, isExternalFilterPresent, doesExternalFilterPass, setOnBulkEditingComplete, getColDef, showNoRowsOverlay, prePopupOps, startCellEditing: propStartCellEditing, } = useGridContext();
3252
+ const Grid = ({ theme = 'ag-theme-step-default', 'data-testid': dataTestId,
3253
+ // ─── Grid State ───────────────────────────────
3254
+ suppressReadOnlyStyle = false,
3255
+ // ─── Data & Columns ───────────────────────────
3256
+ defaultPostSort = true, rowData, rowHeight = theme === 'ag-theme-step-default' ? 40 : theme === 'ag-theme-step-compact' ? 36 : 40, rowSelection = 'multiple', sizeColumns = 'auto',
3257
+ // ─── Selection ────────────────────────────────
3258
+ autoSelectFirstRow, enableRangeSelection = false, externalSelectedIds, externalSelectedItems, selectColumnPinned = 'left', selectable, setExternalSelectedIds, setExternalSelectedItems,
3259
+ // ─── Editing ──────────────────────────────────
3260
+ singleClickEdit = false,
3261
+ // ─── Context Menu ─────────────────────────────
3262
+ contextMenuSelectRow = false, contextMenu,
3263
+ // ─── Callbacks / Events ───────────────────────
3264
+ onCellFocused: paramsOnCellFocused, onColumnMoved,
3265
+ // ─── Row Behavior ─────────────────────────────
3266
+ suppressColumnVirtualization = true,
3267
+ // ─── Miscellaneous ────────────────────────────
3268
+ maxInitialWidth,
3269
+ // ─── Spread Remaining Params ──────────────────
3270
+ ...params }) => {
3271
+ const { setApis, setExternallySelectedItemsAreInSync, setOnBulkEditingComplete, gridReady, gridRenderState, externallySelectedItemsAreInSync, showNoRowsOverlay, autoSizeColumns, sizeColumnsToFit, doesExternalFilterPass, ensureRowVisible, ensureSelectedRowIsVisible, focusByRowById, getColDef, getFirstRowId, isExternalFilterPresent, prePopupOps, selectRowsById, startCellEditing: propStartCellEditing, } = useGridContext();
2811
3272
  // CellEditingStop event happens too much for one edit
2812
3273
  const startedEditRef = useRef(false);
2813
3274
  const startCellEditing = useCallback((props) => {
@@ -2946,7 +3407,7 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
2946
3407
  return;
2947
3408
  }
2948
3409
  hasSelectedFirstItem.current = true;
2949
- if (isNotEmpty(rowData) && isEmpty(externalSelectedItems)) {
3410
+ if (isNotEmpty(rowData) && isEmpty(externalSelectedItems) && isEmpty(externalSelectedIds)) {
2950
3411
  const firstRowId = getFirstRowId();
2951
3412
  if (autoSelectFirstRow && selectable) {
2952
3413
  selectRowsById([firstRowId]);
@@ -2965,6 +3426,7 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
2965
3426
  selectRowsById,
2966
3427
  getFirstRowId,
2967
3428
  selectable,
3429
+ externalSelectedIds,
2968
3430
  ]);
2969
3431
  /**
2970
3432
  * Ensure external selected items list is in sync with panel.
@@ -3128,15 +3590,6 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3128
3590
  void startCellEditing({ rowId: event.data.id, colId: event.column.getColId() });
3129
3591
  }
3130
3592
  }, [startCellEditing]);
3131
- /**
3132
- * Handle single click edits
3133
- */
3134
- const onCellClicked = useCallback((event) => {
3135
- const editable = fnOrVar(event.colDef?.editable, event);
3136
- if ((editable && event.colDef.singleClickEdit) ?? singleClickEdit) {
3137
- void startCellEditing({ rowId: event.data.id, colId: event.column.getColId() });
3138
- }
3139
- }, [singleClickEdit, startCellEditing]);
3140
3593
  const onCellEditingStopped = useCallback((event) => {
3141
3594
  if (!startedEditRef.current) {
3142
3595
  return;
@@ -3185,6 +3638,78 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3185
3638
  prePopupOps();
3186
3639
  }
3187
3640
  }, [prePopupOps, startCellEditing]);
3641
+ const { cellContextMenu, contextMenuComponent } = useGridContextMenu({
3642
+ contextMenu,
3643
+ contextMenuSelectRow,
3644
+ });
3645
+ const hasSelectedMoreThanOneCellRef = useRef(false);
3646
+ const rangeStartRef = useRef(null);
3647
+ const rangeEndRef = useRef(null);
3648
+ const rangeSortedNodesRef = useRef(null);
3649
+ const { clearRangeSelection, ranges, onCellMouseDown, onCellMouseOver } = useGridRangeSelection({
3650
+ enableRangeSelection,
3651
+ gridDivRef,
3652
+ rangeStartRef,
3653
+ rangeEndRef,
3654
+ hasSelectedMoreThanOneCellRef,
3655
+ rangeSortedNodesRef,
3656
+ });
3657
+ const { onCopyEvent, rangeSelectInterceptContextMenu, rangeSelectContextMenuComponent } = useGridCopy({
3658
+ ranges,
3659
+ rangeStartRef,
3660
+ rangeEndRef,
3661
+ hasSelectedMoreThanOneCellRef,
3662
+ cellContextMenu,
3663
+ });
3664
+ const onSortChanged = useCallback(() => {
3665
+ clearRangeSelection();
3666
+ ensureSelectedRowIsVisible();
3667
+ }, [clearRangeSelection, ensureSelectedRowIsVisible]);
3668
+ /**
3669
+ * Handle single click edits
3670
+ */
3671
+ const onCellClicked = useCallback((event) => {
3672
+ if (rangeStartRef.current && rangeEndRef.current) {
3673
+ // This is to detect difference between a single click and a click drag return to cell.
3674
+ if (rangeEndRef.current.timestamp - rangeStartRef.current.timestamp < 100) {
3675
+ clearRangeSelection();
3676
+ }
3677
+ return;
3678
+ }
3679
+ const editable = fnOrVar(event.colDef?.editable, event);
3680
+ if ((editable && event.colDef.singleClickEdit) ?? singleClickEdit) {
3681
+ void startCellEditing({ rowId: event.data.id, colId: event.column.getColId() });
3682
+ }
3683
+ }, [clearRangeSelection, singleClickEdit, startCellEditing]);
3684
+ /**
3685
+ * Set of column I'd's that are prevented from auto-sizing as they are user set
3686
+ */
3687
+ const userSizedColIds = useRef(new Map());
3688
+ /**
3689
+ * Lock/unlock column width on user edit/reset.
3690
+ */
3691
+ const onColumnResized = useCallback((e) => {
3692
+ const colId = e.column?.getColId();
3693
+ if (colId == null) {
3694
+ return;
3695
+ }
3696
+ const width = e.column?.getActualWidth();
3697
+ if (width == null) {
3698
+ return;
3699
+ }
3700
+ switch (e.source) {
3701
+ case 'uiColumnResized':
3702
+ userSizedColIds.current.set(colId, width);
3703
+ break;
3704
+ case 'autosizeColumns':
3705
+ userSizedColIds.current.delete(colId);
3706
+ break;
3707
+ }
3708
+ }, []);
3709
+ const columnMoved = useCallback((e) => {
3710
+ clearRangeSelection();
3711
+ onColumnMoved?.(e);
3712
+ }, [clearRangeSelection, onColumnMoved]);
3188
3713
  /**
3189
3714
  * Once the grid has auto-sized we want to run fit to fit the grid in its container,
3190
3715
  * but we don't want the non-flex auto-sized columns to "fit" size, so suppressSizeToFit is set to true.
@@ -3292,37 +3817,6 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3292
3817
  }
3293
3818
  prevLoading.current = newLoading;
3294
3819
  }, [params.loading, rowData, showNoRowsOverlay]);
3295
- /**
3296
- * Set of column I'd's that are prevented from auto-sizing as they are user set
3297
- */
3298
- const userSizedColIds = useRef(new Map());
3299
- /**
3300
- * Lock/unlock column width on user edit/reset.
3301
- */
3302
- const onColumnResized = useCallback((e) => {
3303
- const colId = e.column?.getColId();
3304
- if (colId == null) {
3305
- return;
3306
- }
3307
- const width = e.column?.getActualWidth();
3308
- if (width == null) {
3309
- return;
3310
- }
3311
- switch (e.source) {
3312
- case 'uiColumnResized':
3313
- userSizedColIds.current.set(colId, width);
3314
- /*const colDef = e.column?.getColDef();
3315
- if (!colDef?.flex) {
3316
- onGridResize(e);
3317
- }*/
3318
- break;
3319
- case 'autosizeColumns':
3320
- userSizedColIds.current.delete(colId);
3321
- //onGridResize(e);
3322
- break;
3323
- }
3324
- }, []);
3325
- const gridContextMenu = useGridContextMenu({ contextMenu: params.contextMenu, contextMenuSelectRow });
3326
3820
  const startDragYRef = useRef(null);
3327
3821
  const clearHighlightRowClasses = useCallback(() => {
3328
3822
  document.querySelectorAll(`.ag-row-highlight-above`)?.forEach((el) => {
@@ -3450,15 +3944,24 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3450
3944
  }
3451
3945
  return false;
3452
3946
  },
3453
- onCellClicked: clickInputWhenContainingCellClicked,
3947
+ // enableClickSelection = true means ag-grid auto selects row if you click outside the checkbox
3948
+ // if it's false we have to do it.
3949
+ onCellClicked: params.enableClickSelection ? undefined : clickInputWhenContainingCellClicked,
3454
3950
  };
3455
- }, [params.hideSelectColumn, params.onRowDragEnd, rowSelection, selectColumnPinned, selectable]);
3951
+ }, [
3952
+ params.hideSelectColumn,
3953
+ params.onRowDragEnd,
3954
+ rowSelection,
3955
+ selectColumnPinned,
3956
+ selectable,
3957
+ params.enableClickSelection,
3958
+ ]);
3456
3959
  const onGridSizeChanged = useCallback((event) => {
3457
3960
  if (sizeColumns === 'fit' || (['auto', 'auto-skip-headers'].includes(sizeColumns) && hasSetContentSize.current)) {
3458
3961
  event.api.sizeColumnsToFit();
3459
3962
  }
3460
3963
  }, [sizeColumns]);
3461
- return (jsxs("div", { "data-testid": dataTestId, className: clsx('Grid-container', theme, 'theme-specific', staleGrid && 'Grid-sortIsStale', gridReady && rowData && autoSized && 'Grid-ready'), children: [gridContextMenu.component, jsx("div", { style: { flex: 1 }, ref: gridDivRef, children: jsx(AgGridReact, { theme: 'legacy', rowSelection: selectable
3964
+ return (jsxs("div", { "data-testid": dataTestId, className: clsx('Grid-container', theme, 'theme-specific', staleGrid && 'Grid-sortIsStale', gridReady && rowData && autoSized && 'Grid-ready'), children: [contextMenuComponent, rangeSelectContextMenuComponent, jsx("div", { style: { flex: 1 }, ref: gridDivRef, onCopy: onCopyEvent, children: jsx(AgGridReact, { theme: 'legacy', domLayout: params.domLayout, defaultColDef: defaultColDef, columnDefs: columnDefsAdjusted, getRowId: getRowId, rowData: rowData, alwaysShowVerticalScroll: params.alwaysShowVerticalScroll, animateRows: params.animateRows ?? false, doesExternalFilterPass: doesExternalFilterPass, isExternalFilterPresent: isExternalFilterPresent, maintainColumnOrder: true, noRowsOverlayComponent: noRowsOverlayComponent, onCellClicked: onCellClicked, onCellContextMenu: rangeSelectInterceptContextMenu, onCellDoubleClicked: onCellDoubleClick, onCellEditingStopped: onCellEditingStopped, onCellFocused: onCellFocused, onCellKeyDown: onCellKeyPress, onCellMouseDown: onCellMouseDown, onCellMouseOver: onCellMouseOver, onColumnMoved: columnMoved, onColumnResized: onColumnResized, onColumnVisible: () => void setInitialContentSize(), onGridReady: onGridReady, onGridSizeChanged: onGridSizeChanged, onModelUpdated: onModelUpdated, onRowClicked: params.onRowClicked, onRowDataUpdated: onRowDataUpdated, onRowDoubleClicked: params.onRowDoubleClicked, onRowDragCancel: clearHighlightRowClasses, onRowDragEnd: onRowDragEnd, onRowDragMove: onRowDragMove, onSelectionChanged: synchroniseExternalStateToGridSelection, onSortChanged: onSortChanged, pinnedBottomRowData: params.pinnedBottomRowData, pinnedTopRowData: params.pinnedTopRowData, postSortRows: params.onRowDragEnd || !defaultPostSort ? undefined : postSortRows, preventDefaultOnContextMenu: true, quickFilterParser: quickFilterParser, rowClassRules: params.rowClassRules, rowDragText: params.rowDragText, rowHeight: rowHeight, rowSelection: selectable
3462
3965
  ? {
3463
3966
  enableSelectionWithoutKeys: params.enableSelectionWithoutKeys ?? false,
3464
3967
  enableClickSelection: params.enableClickSelection ?? false,
@@ -3468,7 +3971,7 @@ const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection
3468
3971
  headerCheckbox: false,
3469
3972
  }),
3470
3973
  }
3471
- : undefined, selectionColumnDef: selectionColumnDef, rowHeight: rowHeight, animateRows: params.animateRows ?? false, rowClassRules: params.rowClassRules, getRowId: getRowId, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onGridSizeChanged: onGridSizeChanged, onColumnVisible: () => void setInitialContentSize(), onRowDataUpdated: onRowDataUpdated, onCellFocused: onCellFocused, onCellKeyDown: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStopped: onCellEditingStopped, domLayout: params.domLayout, onColumnResized: onColumnResized, defaultColDef: defaultColDef, columnDefs: columnDefsAdjusted, rowData: rowData, postSortRows: params.onRowDragEnd || !defaultPostSort ? undefined : postSortRows, onModelUpdated: onModelUpdated, onGridReady: onGridReady, onSortChanged: ensureSelectedRowIsVisible, quickFilterParser: quickFilterParser, onSelectionChanged: synchroniseExternalStateToGridSelection, onColumnMoved: params.onColumnMoved, noRowsOverlayComponent: noRowsOverlayComponent, alwaysShowVerticalScroll: params.alwaysShowVerticalScroll, isExternalFilterPresent: isExternalFilterPresent, doesExternalFilterPass: doesExternalFilterPass, maintainColumnOrder: true, preventDefaultOnContextMenu: true, onCellContextMenu: gridContextMenu.cellContextMenu, rowDragText: params.rowDragText, onRowDragCancel: clearHighlightRowClasses, onRowDragMove: onRowDragMove, onRowDragEnd: onRowDragEnd, suppressCellFocus: params.suppressCellFocus, pinnedTopRowData: params.pinnedTopRowData, pinnedBottomRowData: params.pinnedBottomRowData, onRowClicked: params.onRowClicked, onRowDoubleClicked: params.onRowDoubleClicked, suppressStartEditOnTab: true }) })] }));
3974
+ : undefined, selectionColumnDef: selectionColumnDef, suppressCellFocus: params.suppressCellFocus, suppressClickEdit: true, suppressColumnVirtualisation: suppressColumnVirtualization, suppressStartEditOnTab: true }) })] }));
3472
3975
  };
3473
3976
  const quickFilterParser = (filterStr) => {
3474
3977
  // filter is exact matches exactly groups separated by commas
@@ -3709,33 +4212,6 @@ const GridFilterButtons = ({ className, luiButtonProps, options, }) => {
3709
4212
  return (jsx("div", { className: clsx(className, 'flex-col-center'), children: jsx(LuiButtonGroup, { children: options.map((option, index) => (jsx(LuiButton, { ...luiButtonProps, className: clsx(`lui-button lui-button-secondary`, selectedOption?.label === option.label && `lui-button-active`, luiButtonProps?.className), onClick: () => setSelectedOption(option), children: option.label }, `${index}`))) }) }));
3710
4213
  };
3711
4214
 
3712
- function styleInject(css, ref) {
3713
- if ( ref === void 0 ) ref = {};
3714
- var insertAt = ref.insertAt;
3715
-
3716
- if (!css || typeof document === 'undefined') { return; }
3717
-
3718
- var head = document.head || document.getElementsByTagName('head')[0];
3719
- var style = document.createElement('style');
3720
- style.type = 'text/css';
3721
-
3722
- if (insertAt === 'top') {
3723
- if (head.firstChild) {
3724
- head.insertBefore(style, head.firstChild);
3725
- } else {
3726
- head.appendChild(style);
3727
- }
3728
- } else {
3729
- head.appendChild(style);
3730
- }
3731
-
3732
- if (style.styleSheet) {
3733
- style.styleSheet.cssText = css;
3734
- } else {
3735
- style.appendChild(document.createTextNode(css));
3736
- }
3737
- }
3738
-
3739
4215
  var css_248z$3 = ".GridFilterColsMultiSelect{background:#fff;font-family:Open Sans,system-ui,sans-serif;font-style:normal;font-weight:600;padding:8px}.GridFilterColsMultiSelect .LuiSelect-label-text{color:#6b6966;display:inline-block}.GridFilterColsMultiSelect .LuiCheckboxInput-item,.GridFilterColsMultiSelect .LuiCheckboxInput-selectAll{color:#2a292c;font-size:16px;font-weight:600;letter-spacing:0;line-height:20px;line-height:24px;margin-bottom:0}";
3740
4216
  styleInject(css_248z$3);
3741
4217
 
@@ -4543,14 +5019,14 @@ const TextInputFormatted = (props) => {
4543
5019
 
4544
5020
  const bearingValueFormatter = (value) => {
4545
5021
  const safeValue = typeof value === 'string' ? parseFloat(value) : value;
4546
- if (safeValue == null) {
5022
+ if (safeValue == null || Number.isNaN(safeValue)) {
4547
5023
  return '–';
4548
5024
  }
4549
5025
  return convertDDToDMS(safeValue, false);
4550
5026
  };
4551
5027
  const bearingCorrectionValueFormatter = (value) => {
4552
5028
  const safeValue = value;
4553
- if (safeValue == null) {
5029
+ if (safeValue == null || Number.isNaN(safeValue)) {
4554
5030
  return '–';
4555
5031
  }
4556
5032
  if (typeof safeValue === 'string') {
@@ -5346,6 +5822,7 @@ const GridPopoutEditMultiSelectGrid = (colDef, props) => GridCell(colDef, {
5346
5822
  },
5347
5823
  });
5348
5824
 
5825
+ const GridCellBearingValueFormatter = (params) => bearingValueFormatter(params.value) ?? '';
5349
5826
  const GridPopoverEditBearingLike = (colDef, props) => GridCell({
5350
5827
  valueFormatter: (params) => props.editorParams?.formatValue(params.value) ?? '',
5351
5828
  ...colDef,
@@ -5498,6 +5975,7 @@ const GridContextProvider = (props) => {
5498
5975
  }
5499
5976
  return gridApi && !gridApi.isDestroyed() ? hasApiFn(gridApi) : noApiFn();
5500
5977
  }, [gridApi]);
5978
+ const getCellValue = useCallback((...props) => gridApi?.getCellValue(...props), [gridApi]);
5501
5979
  /**
5502
5980
  * Scroll row into view by Id.
5503
5981
  *
@@ -5657,7 +6135,7 @@ const GridContextProvider = (props) => {
5657
6135
  // It may be that the first cell is the selection cell, this doesn't exist as a colDef
5658
6136
  // so instead, I just try and select it. If it doesn't exist selection will stay on the
5659
6137
  // previously focused cell
5660
- gridApi.setFocusedCell(rowIndex, 'ag-Grid-SelectionColumn');
6138
+ gridApi.setFocusedCell(rowIndex, agGridSelectRowColId);
5661
6139
  }
5662
6140
  }, 100);
5663
6141
  }
@@ -6096,6 +6574,7 @@ const GridContextProvider = (props) => {
6096
6574
  getSelectedRowIds,
6097
6575
  getFilteredSelectedRowIds,
6098
6576
  getFirstRowId,
6577
+ getCellValue,
6099
6578
  editingCells,
6100
6579
  ensureRowVisible,
6101
6580
  ensureSelectedRowIsVisible,
@@ -6275,5 +6754,5 @@ const useDeferredPromise = () => {
6275
6754
  };
6276
6755
  };
6277
6756
 
6278
- export { ActionButton, CancelPromise, ComponentLoadingWrapper, ControlledMenu, Editor, FocusableItem, FormError, GenericCellEditorComponentWrapper, Grid, GridButton, GridCell, GridCellFiller, GridCellFillerColId, GridCellMultiEditor, GridCellMultiSelectClassRules, GridCellRenderer, GridContext, GridContextProvider, GridEditBoolean, GridFilterButtons, GridFilterColumnsMultiSelect, GridFilterColumnsToggle, GridFilterDownloadCsvButton, GridFilterHeaderIconButton, GridFilterQuick, GridFilters, GridFormDropDown, GridFormEditBearing, GridFormMessage, GridFormMultiSelect, GridFormMultiSelectGrid, GridFormPopoverMenu, GridFormSubComponentTextArea, GridFormSubComponentTextInput, GridFormTextArea, GridFormTextInput, GridIcon, GridLoadableCell, GridNoRowsOverlay, GridNoRowsOverlayFr, GridPopoutEditMultiSelect, GridPopoutEditMultiSelectGrid, GridPopoverContext, GridPopoverContextProvider, GridPopoverEditBearing, GridPopoverEditBearingCorrection, GridPopoverEditBearingCorrectionEditorParams, GridPopoverEditBearingEditorParams, GridPopoverEditDropDown, GridPopoverMenu, GridPopoverMessage, GridPopoverTextArea, GridPopoverTextInput, GridRenderPopoutMenuCell, GridSubComponentContext, GridUpdatingContext, GridUpdatingContextProvider, GridWrapper, Menu, MenuButton, MenuDivider, MenuGroup, MenuHeader, MenuHeaderItem, MenuHeaderString, MenuItem, MenuRadioGroup, MenuSeparator, MenuSeparatorString, PopoutMenuSeparator, SubMenu, TextAreaInput, TextInputFormatted, TextInputValidator, bearingCorrectionRangeValidator, bearingCorrectionValueFormatter, bearingNumberParser, bearingRangeValidator, bearingStringValidator, bearingValueFormatter, colStateFlexed, colStateId, colStateNotFlexed, compareNaturalInsensitive, convertDDToDMS, createCheckboxMultiFilterParams, defaultValueFormatter, downloadCsvUseValueFormattersProcessCellCallback, findParentWithClass, fnOrVar, generateFilterGetter, hasParentClass, isFloat, isGridCellFiller, isNotEmpty, primitiveToSelectOption, sanitiseFileName, stringByteLengthIsInvalid, suppressCellKeyboardEvents, textMatch, useDeferredPromise, useGridContext, useGridContextMenu, useGridFilter, useGridPopoverContext, useGridPopoverHook, useMenuState, usePostSortRowsHook, wait, waitForCondition };
6757
+ export { ActionButton, CancelPromise, ComponentLoadingWrapper, ControlledMenu, Editor, FocusableItem, FormError, GenericCellEditorComponentWrapper, Grid, GridButton, GridCell, GridCellBearingValueFormatter, GridCellFiller, GridCellFillerColId, GridCellMultiEditor, GridCellMultiSelectClassRules, GridCellRenderer, GridContext, GridContextProvider, GridEditBoolean, GridFilterButtons, GridFilterColumnsMultiSelect, GridFilterColumnsToggle, GridFilterDownloadCsvButton, GridFilterHeaderIconButton, GridFilterQuick, GridFilters, GridFormDropDown, GridFormEditBearing, GridFormMessage, GridFormMultiSelect, GridFormMultiSelectGrid, GridFormPopoverMenu, GridFormSubComponentTextArea, GridFormSubComponentTextInput, GridFormTextArea, GridFormTextInput, GridIcon, GridLoadableCell, GridNoRowsOverlay, GridNoRowsOverlayFr, GridPopoutEditMultiSelect, GridPopoutEditMultiSelectGrid, GridPopoverContext, GridPopoverContextProvider, GridPopoverEditBearing, GridPopoverEditBearingCorrection, GridPopoverEditBearingCorrectionEditorParams, GridPopoverEditBearingEditorParams, GridPopoverEditDropDown, GridPopoverMenu, GridPopoverMessage, GridPopoverTextArea, GridPopoverTextInput, GridRenderPopoutMenuCell, GridSubComponentContext, GridUpdatingContext, GridUpdatingContextProvider, GridWrapper, Menu, MenuButton, MenuDivider, MenuGroup, MenuHeader, MenuHeaderItem, MenuHeaderString, MenuItem, MenuRadioGroup, MenuSeparator, MenuSeparatorString, PopoutMenuSeparator, SubMenu, TextAreaInput, TextInputFormatted, TextInputValidator, agGridSelectRowColId, bearingCorrectionRangeValidator, bearingCorrectionValueFormatter, bearingNumberParser, bearingRangeValidator, bearingStringValidator, bearingValueFormatter, colStateFlexed, colStateId, colStateNotFlexed, compareNaturalInsensitive, convertDDToDMS, createCheckboxMultiFilterParams, defaultValueFormatter, downloadCsvUseValueFormattersProcessCellCallback, findParentWithClass, fnOrVar, generateFilterGetter, hasParentClass, isFloat, isGridCellFiller, isNotEmpty, primitiveToSelectOption, sanitiseFileName, stringByteLengthIsInvalid, suppressCellKeyboardEvents, textMatch, useDeferredPromise, useGridContext, useGridContextMenu, useGridFilter, useGridPopoverContext, useGridPopoverHook, useMenuState, usePostSortRowsHook, wait, waitForCondition };
6279
6758
  //# sourceMappingURL=step-ag-grid.esm.js.map