@procore/data-table 14.46.2 → 14.46.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Change Log
2
2
 
3
+ ## 14.46.4
4
+
5
+ ### Patch Changes
6
+
7
+ - d5bab3a: Add `headerClass` to `ColumnDefinition` as a typed prop (string, string[], or function). Previously worked at runtime via `...rest` passthrough but was absent from the type.
8
+
9
+ ## 14.46.3
10
+
11
+ ### Patch Changes
12
+
13
+ - 05247ae: Fix inconsistent keyboard focus management across Filters, Configure, and Bulk Edit panels
14
+ - Move focus to the panel container on open and return focus to the trigger button on close
15
+ - Add `role="region"` and `aria-label` to panel containers for screen reader announcements
16
+ - Centralize focus logic in `useContextPanel` hook, removing scattered per-panel implementations
17
+ - Updated dependencies [05247ae]
18
+ - @procore/toast-alert@5.2.0
19
+
3
20
  ## 14.46.2
4
21
 
5
22
  ### Patch Changes
@@ -1402,7 +1402,7 @@ ag-grid, ag-grid-angular, ag-grid-ng2, ag-grid-polymer, ag-grid-aurelia {
1402
1402
  animation-iteration-count: infinite;
1403
1403
  animation-name: ag-shake-left-to-right;
1404
1404
  }
1405
- @keyframes _ag-shake-left-to-right_1ern5_342 {
1405
+ @keyframes _ag-shake-left-to-right_pphrk_342 {
1406
1406
  from {
1407
1407
  padding-left: 6px;
1408
1408
  padding-right: 2px;
@@ -5403,7 +5403,7 @@ input[class^=ag-][type=button]:focus, button[class^=ag-]:focus {
5403
5403
  animation-iteration-count: infinite;
5404
5404
  animation-timing-function: linear;
5405
5405
  }
5406
- @keyframes _spin_1ern5_1 {
5406
+ @keyframes _spin_pphrk_1 {
5407
5407
  from {
5408
5408
  transform: rotate(0deg);
5409
5409
  }
@@ -7935,7 +7935,7 @@ input[class^=ag-][type=range]:disabled {
7935
7935
  padding-left: 16px;
7936
7936
  }
7937
7937
 
7938
- div._contextPanel_1ern5_7159 {
7938
+ div._contextPanel_pphrk_7159 {
7939
7939
  width: 400px;
7940
7940
  transition: all ease 500ms;
7941
7941
  flex: 0 0 auto;
@@ -7944,7 +7944,12 @@ div._contextPanel_1ern5_7159 {
7944
7944
  border: 1px solid #d6dadc;
7945
7945
  display: flex;
7946
7946
  }
7947
- div._contextPanel--hidden_1ern5_7168 {
7947
+ div._contextPanel_pphrk_7159:focus {
7948
+ border-color: #2066df;
7949
+ box-shadow: inset 0 0 1px 0 #2066df;
7950
+ outline: none;
7951
+ }
7952
+ div._contextPanel--hidden_pphrk_7173 {
7948
7953
  border: none;
7949
7954
  overflow: hidden;
7950
7955
  padding: 0px;
@@ -7952,50 +7957,50 @@ div._contextPanel--hidden_1ern5_7168 {
7952
7957
  width: 0px;
7953
7958
  }
7954
7959
 
7955
- ._contextPanelWrapper_1ern5_7176 {
7960
+ ._contextPanelWrapper_pphrk_7181 {
7956
7961
  position: relative;
7957
7962
  flex-grow: 1;
7958
7963
  }
7959
7964
 
7960
- ._contextPanelBody_1ern5_7181 {
7965
+ ._contextPanelBody_pphrk_7186 {
7961
7966
  width: clamp(380px, 400px, 100%);
7962
7967
  }
7963
7968
 
7964
- ._contextPanel-stickyHeader_1ern5_7185 {
7969
+ ._contextPanel-stickyHeader_pphrk_7190 {
7965
7970
  background-color: #ffffff;
7966
7971
  position: sticky;
7967
7972
  top: 0;
7968
7973
  z-index: 5;
7969
7974
  }
7970
7975
 
7971
- ._filters-list_1ern5_7192 {
7976
+ ._filters-list_pphrk_7197 {
7972
7977
  padding: 0;
7973
7978
  margin: 0;
7974
7979
  }
7975
- ._filters-list_1ern5_7192 ol {
7980
+ ._filters-list_pphrk_7197 ol {
7976
7981
  padding: 0;
7977
7982
  margin: 0;
7978
7983
  }
7979
7984
 
7980
- ._col-drag-column-icon_1ern5_7201 {
7985
+ ._col-drag-column-icon_pphrk_7206 {
7981
7986
  color: #6a767c;
7982
7987
  }
7983
7988
 
7984
- ._tabular-nums_1ern5_7205 {
7989
+ ._tabular-nums_pphrk_7210 {
7985
7990
  font-variant-numeric: tabular-nums;
7986
7991
  }`;
7987
7992
  document.head.appendChild(document.createElement("style")).appendChild(document.createTextNode(css));
7988
7993
  var styles_default = {
7989
- "contextPanel": "_contextPanel_1ern5_7159",
7990
- "contextPanel--hidden": "_contextPanel--hidden_1ern5_7168",
7991
- "contextPanelWrapper": "_contextPanelWrapper_1ern5_7176",
7992
- "contextPanelBody": "_contextPanelBody_1ern5_7181",
7993
- "contextPanel-stickyHeader": "_contextPanel-stickyHeader_1ern5_7185",
7994
- "filters-list": "_filters-list_1ern5_7192",
7995
- "col-drag-column-icon": "_col-drag-column-icon_1ern5_7201",
7996
- "tabular-nums": "_tabular-nums_1ern5_7205",
7997
- "ag-shake-left-to-right": "_ag-shake-left-to-right_1ern5_342",
7998
- "spin": "_spin_1ern5_1"
7994
+ "contextPanel": "_contextPanel_pphrk_7159",
7995
+ "contextPanel--hidden": "_contextPanel--hidden_pphrk_7173",
7996
+ "contextPanelWrapper": "_contextPanelWrapper_pphrk_7181",
7997
+ "contextPanelBody": "_contextPanelBody_pphrk_7186",
7998
+ "contextPanel-stickyHeader": "_contextPanel-stickyHeader_pphrk_7190",
7999
+ "filters-list": "_filters-list_pphrk_7197",
8000
+ "col-drag-column-icon": "_col-drag-column-icon_pphrk_7206",
8001
+ "tabular-nums": "_tabular-nums_pphrk_7210",
8002
+ "ag-shake-left-to-right": "_ag-shake-left-to-right_pphrk_342",
8003
+ "spin": "_spin_pphrk_1"
7999
8004
  };
8000
8005
 
8001
8006
  // src/CellRenderers/BooleanCell.tsx
@@ -54783,6 +54788,7 @@ function transformToColumnDefinition(colDef = emptyObject) {
54783
54788
  getStringFormattedValue,
54784
54789
  columnHeaderParams: colDef.headerComponentParams,
54785
54790
  headerName: colDef.headerName,
54791
+ headerClass: colDef.headerClass,
54786
54792
  hidden: colDef.hide,
54787
54793
  filterRenderer: colDef.filterRenderer,
54788
54794
  lockVisible: colDef.lockVisible,
@@ -58025,6 +58031,7 @@ var InternalTableContext = React80__default.default.createContext({
58025
58031
  hide: () => {
58026
58032
  },
58027
58033
  isVisible: false,
58034
+ panelRef: React80__default.default.createRef(),
58028
58035
  show: () => {
58029
58036
  }
58030
58037
  },
@@ -59829,14 +59836,16 @@ var useRowSelectionState = () => {
59829
59836
  var BulkEditActionButton = (props) => {
59830
59837
  const { contextPanel } = useInternalTableContext();
59831
59838
  const i18n = coreReact.useI18nContext();
59839
+ const buttonRef = React80__default.default.useRef(null);
59832
59840
  const editActionLabel = props.actionText ?? i18n.t("dataTable.bulkActions.editValues");
59833
59841
  return /* @__PURE__ */ React80__default.default.createElement(
59834
59842
  coreReact.Button,
59835
59843
  {
59844
+ ref: buttonRef,
59836
59845
  "aria-label": i18n.t("dataTable.bulkActions.bulkEdit"),
59837
59846
  "data-qa": "bulkEditIcon",
59838
59847
  icon: /* @__PURE__ */ React80__default.default.createElement(coreIcons.Pencil, null),
59839
- onClick: () => contextPanel.show("bulkEdit"),
59848
+ onClick: () => contextPanel.show("bulkEdit", buttonRef.current ?? void 0),
59840
59849
  variant: "tertiary"
59841
59850
  },
59842
59851
  props.showLabel && editActionLabel
@@ -104481,11 +104490,6 @@ var BulkEditPanel = ({}) => {
104481
104490
  const { contextPanel, suppressBulkEditToasts } = useInternalTableContext();
104482
104491
  const I18n = coreReact.useI18nContext();
104483
104492
  const bulkEditRef = React80__default.default.useRef(null);
104484
- const bodyRef = React80__default.default.useRef(null);
104485
- React80.useEffect(() => {
104486
- var _a;
104487
- (_a = bodyRef.current) == null ? void 0 : _a.focus();
104488
- }, []);
104489
104493
  return /* @__PURE__ */ React80__default.default.createElement(coreReact.Panel, null, /* @__PURE__ */ React80__default.default.createElement(
104490
104494
  coreReact.Panel.Header,
104491
104495
  {
@@ -104496,7 +104500,7 @@ var BulkEditPanel = ({}) => {
104496
104500
  }
104497
104501
  },
104498
104502
  /* @__PURE__ */ React80__default.default.createElement(coreReact.Panel.Title, null, I18n.t("dataTable.bulkActions.editValues"))
104499
- ), /* @__PURE__ */ React80__default.default.createElement(coreReact.Panel.Body, { ref: bodyRef }, /* @__PURE__ */ React80__default.default.createElement(coreReact.Panel.Section, null, /* @__PURE__ */ React80__default.default.createElement(
104503
+ ), /* @__PURE__ */ React80__default.default.createElement(coreReact.Panel.Body, null, /* @__PURE__ */ React80__default.default.createElement(coreReact.Panel.Section, null, /* @__PURE__ */ React80__default.default.createElement(
104500
104504
  BulkEdit,
104501
104505
  {
104502
104506
  ref: bulkEditRef,
@@ -104942,18 +104946,34 @@ var ConfigurationPanel = ({
104942
104946
  function useContextPanel() {
104943
104947
  const [content, setContent] = React80.useState();
104944
104948
  const visibility = coreReact.useVisibility({ afterHide: () => setContent(void 0) });
104945
- const show = React80.useCallback((panelContent) => {
104946
- setContent(panelContent);
104947
- visibility.show();
104948
- }, []);
104949
+ const triggerRef = React80.useRef(null);
104950
+ const panelRef = React80.useRef(null);
104951
+ const show = React80.useCallback(
104952
+ (panelContent, trigger) => {
104953
+ triggerRef.current = trigger ?? null;
104954
+ setContent(panelContent);
104955
+ visibility.show();
104956
+ },
104957
+ []
104958
+ );
104949
104959
  const hide = React80.useCallback(() => {
104960
+ const trigger = triggerRef.current;
104950
104961
  setContent(void 0);
104951
104962
  visibility.hide();
104963
+ trigger == null ? void 0 : trigger.focus();
104964
+ triggerRef.current = null;
104952
104965
  }, []);
104966
+ React80.useEffect(() => {
104967
+ var _a;
104968
+ if (content) {
104969
+ (_a = panelRef.current) == null ? void 0 : _a.focus();
104970
+ }
104971
+ }, [content]);
104953
104972
  return {
104954
104973
  content,
104955
104974
  hide,
104956
104975
  isVisible: visibility.isVisible,
104976
+ panelRef,
104957
104977
  show
104958
104978
  };
104959
104979
  }
@@ -111273,9 +111293,26 @@ var ContextPanel = ({
111273
111293
  ...props
111274
111294
  }) => {
111275
111295
  const { contextPanel } = useInternalTableContext();
111296
+ const I18n = coreReact.useI18nContext();
111297
+ const cardRef = React80__default.default.useRef(null);
111298
+ const panelLabelKeys = {
111299
+ configuration: "dataTable.tableSettings.tableSettings",
111300
+ bulkEdit: "dataTable.bulkActions.editValues"
111301
+ };
111302
+ const panelLabel = contextPanel.content ? panelLabelKeys[contextPanel.content] : void 0;
111303
+ const ariaLabel = panelLabel ? I18n.t(panelLabel) : void 0;
111304
+ React80__default.default.useLayoutEffect(() => {
111305
+ if (contextPanel.content && contextPanel.content !== "filters") {
111306
+ contextPanel.panelRef.current = cardRef.current;
111307
+ }
111308
+ }, [contextPanel.content, contextPanel.panelRef]);
111276
111309
  return /* @__PURE__ */ React80__default.default.createElement(
111277
111310
  coreReact.Card,
111278
111311
  {
111312
+ ref: cardRef,
111313
+ tabIndex: -1,
111314
+ role: "region",
111315
+ "aria-label": ariaLabel,
111279
111316
  className: cx19("contextPanel", className, {
111280
111317
  "contextPanel--hidden": !contextPanel.isVisible || contextPanel.content === "filters"
111281
111318
  }),
@@ -111548,19 +111585,27 @@ var BaseFiltersPanel = ({
111548
111585
  onClearAllFilters = noop5,
111549
111586
  ...props
111550
111587
  }) => {
111551
- const ref = React80__default.default.useRef(null);
111588
+ const cardRef = React80__default.default.useRef(null);
111552
111589
  const { contextPanel, filtersBodyId, filtersPanelId } = useInternalTableContext();
111553
111590
  const I18n = coreReact.useI18nContext();
111554
111591
  const hidden = !contextPanel.isVisible || contextPanel.content !== "filters";
111555
111592
  React80__default.default.useLayoutEffect(() => {
111556
- if (ref.current) {
111557
- ref.current.inert = hidden;
111593
+ if (contextPanel.content === "filters") {
111594
+ contextPanel.panelRef.current = cardRef.current;
111595
+ }
111596
+ }, [contextPanel.content, contextPanel.panelRef]);
111597
+ React80__default.default.useLayoutEffect(() => {
111598
+ if (cardRef.current) {
111599
+ cardRef.current.inert = hidden;
111558
111600
  }
111559
111601
  }, [hidden]);
111560
111602
  return /* @__PURE__ */ React80__default.default.createElement(
111561
111603
  coreReact.Card,
111562
111604
  {
111563
- ref,
111605
+ ref: cardRef,
111606
+ tabIndex: -1,
111607
+ role: "region",
111608
+ "aria-label": I18n.t("dataTable.filters.filters"),
111564
111609
  style: { maxHeight: "100vh" },
111565
111610
  className: cx20("contextPanel", className, {
111566
111611
  "contextPanel--hidden": hidden
@@ -111615,6 +111660,7 @@ var ConfigPanelButton = () => {
111615
111660
  const { contextPanel } = useInternalTableContext();
111616
111661
  const hasNoContent = useTableHasNoContent();
111617
111662
  const I18n = coreReact.useI18nContext();
111663
+ const buttonRef = React80__default.default.useRef(null);
111618
111664
  return /* @__PURE__ */ React80__default.default.createElement(
111619
111665
  EmptyResultsControlTooltip,
111620
111666
  {
@@ -111624,12 +111670,13 @@ var ConfigPanelButton = () => {
111624
111670
  /* @__PURE__ */ React80__default.default.createElement(
111625
111671
  coreReact.ToggleButton,
111626
111672
  {
111673
+ ref: buttonRef,
111627
111674
  disabled: hasNoContent,
111628
111675
  onClick: () => {
111629
111676
  if (contextPanel.content === "configuration") {
111630
111677
  contextPanel.hide();
111631
111678
  } else {
111632
- contextPanel.show("configuration");
111679
+ contextPanel.show("configuration", buttonRef.current ?? void 0);
111633
111680
  }
111634
111681
  },
111635
111682
  icon: /* @__PURE__ */ React80__default.default.createElement(
@@ -112806,27 +112853,12 @@ var SingleSelectQuickFilterRenderer = (props) => {
112806
112853
  return /* @__PURE__ */ React80__default.default.createElement(ClientSideSingleSelectQuickFilter, { ...props });
112807
112854
  };
112808
112855
  var SingleSelectQuickFilterRenderer_default = SingleSelectQuickFilterRenderer;
112809
- var FOCUSABLE_SELECTOR2 = 'button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
112810
112856
  var FiltersPanelToggleButton = ({ hasDefinedFilters }) => {
112811
112857
  const I18n = coreReact.useI18nContext();
112812
- const { contextPanel, filtersBodyId, filtersPanelId } = useInternalTableContext();
112858
+ const { contextPanel, filtersPanelId } = useInternalTableContext();
112813
112859
  const hasNoContent = useTableHasNoContent();
112814
112860
  const buttonRef = React80__default.default.useRef(null);
112815
112861
  const isFiltersOpen = contextPanel.content === "filters";
112816
- const isMounted = React80__default.default.useRef(false);
112817
- React80__default.default.useEffect(() => {
112818
- var _a, _b;
112819
- if (!isMounted.current) {
112820
- isMounted.current = true;
112821
- return;
112822
- }
112823
- if (isFiltersOpen) {
112824
- const panel = filtersBodyId ? document.getElementById(filtersBodyId) : null;
112825
- (_a = panel == null ? void 0 : panel.querySelector(FOCUSABLE_SELECTOR2)) == null ? void 0 : _a.focus();
112826
- } else {
112827
- (_b = buttonRef.current) == null ? void 0 : _b.focus();
112828
- }
112829
- }, [isFiltersOpen, filtersBodyId]);
112830
112862
  if (!hasDefinedFilters) {
112831
112863
  return null;
112832
112864
  }
@@ -112847,7 +112879,7 @@ var FiltersPanelToggleButton = ({ hasDefinedFilters }) => {
112847
112879
  "aria-controls": filtersPanelId,
112848
112880
  onClick: () => {
112849
112881
  if (!isFiltersOpen) {
112850
- contextPanel.show("filters");
112882
+ contextPanel.show("filters", buttonRef.current ?? void 0);
112851
112883
  } else {
112852
112884
  contextPanel.hide();
112853
112885
  }
@@ -502,6 +502,7 @@ interface ColumnDefinition<TValue = any, TRenderer = React.FC<ICellRendererParam
502
502
  getStringFormattedValue?: (value: TValue) => string;
503
503
  getFilterKeyCreator?: ColDef['keyCreator'];
504
504
  headerName?: string;
505
+ headerClass?: ColDef['headerClass'];
505
506
  columnHeaderParams?: {
506
507
  menuOptions?: MenuDropdownOption[];
507
508
  headerNode?: (props: {
@@ -724,7 +725,8 @@ interface ContextPanelApi {
724
725
  content?: ContextPanelContent;
725
726
  hide: () => void;
726
727
  isVisible: boolean;
727
- show: (content: ContextPanelContent) => void;
728
+ panelRef: React.RefObject<HTMLElement>;
729
+ show: (content: ContextPanelContent, trigger?: HTMLElement) => void;
728
730
  }
729
731
  interface CustomFooterConfig {
730
732
  height?: RowSize;
@@ -502,6 +502,7 @@ interface ColumnDefinition<TValue = any, TRenderer = React.FC<ICellRendererParam
502
502
  getStringFormattedValue?: (value: TValue) => string;
503
503
  getFilterKeyCreator?: ColDef['keyCreator'];
504
504
  headerName?: string;
505
+ headerClass?: ColDef['headerClass'];
505
506
  columnHeaderParams?: {
506
507
  menuOptions?: MenuDropdownOption[];
507
508
  headerNode?: (props: {
@@ -724,7 +725,8 @@ interface ContextPanelApi {
724
725
  content?: ContextPanelContent;
725
726
  hide: () => void;
726
727
  isVisible: boolean;
727
- show: (content: ContextPanelContent) => void;
728
+ panelRef: React.RefObject<HTMLElement>;
729
+ show: (content: ContextPanelContent, trigger?: HTMLElement) => void;
728
730
  }
729
731
  interface CustomFooterConfig {
730
732
  height?: RowSize;