@amboss/design-system 4.5.1 → 4.6.0

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 (109) hide show
  1. package/build/cjs/components/BulkActionsToolbar/BulkActionsToolbar.js +1 -1
  2. package/build/cjs/components/DataTable/DataTable.d.ts +18 -8
  3. package/build/cjs/components/DataTable/DataTable.js +1 -1
  4. package/build/cjs/components/DataTable/DataTableToolbar/DataTableToolbar.d.ts +97 -0
  5. package/build/cjs/components/DataTable/DataTableToolbar/DataTableToolbar.js +1 -0
  6. package/build/cjs/components/DataTable/TableCell.js +1 -1
  7. package/build/cjs/components/DataTable/TableColumnGroups.d.ts +15 -0
  8. package/build/cjs/components/DataTable/TableColumnGroups.js +1 -0
  9. package/build/cjs/components/DataTable/header/DataTableHeaderLabel.d.ts +28 -0
  10. package/build/cjs/components/DataTable/header/DataTableHeaderLabel.js +1 -0
  11. package/build/cjs/components/DataTable/header/TableHeader.js +1 -1
  12. package/build/cjs/components/DataTable/index.d.ts +1 -1
  13. package/build/cjs/components/DataTable/internal/buildColumnSegments.d.ts +18 -0
  14. package/build/cjs/components/DataTable/internal/buildColumnSegments.js +1 -0
  15. package/build/cjs/components/DataTable/internal/buildInternalColumns.d.ts +2 -2
  16. package/build/cjs/components/DataTable/internal/buildInternalColumns.js +1 -1
  17. package/build/cjs/components/DataTable/internal/getColumnSticky.js +1 -1
  18. package/build/cjs/components/DataTable/internal/types.d.ts +7 -2
  19. package/build/cjs/components/DataTable/isDataTableColumnGroup.d.ts +2 -0
  20. package/build/cjs/components/DataTable/isDataTableColumnGroup.js +1 -0
  21. package/build/cjs/components/DataTable/types.d.ts +52 -8
  22. package/build/cjs/components/DataTable/useDataTableSort.d.ts +4 -4
  23. package/build/cjs/components/DataTable/useDataTableSort.js +1 -1
  24. package/build/cjs/components/FilterToolbar/FilterToolbar.d.ts +103 -0
  25. package/build/cjs/components/FilterToolbar/FilterToolbar.js +1 -0
  26. package/build/cjs/components/Internal/Panel/Panel.d.ts +22 -1
  27. package/build/cjs/components/Internal/Panel/Panel.js +1 -1
  28. package/build/cjs/components/Internal/ToolbarItemCount/ToolbarItemCount.d.ts +16 -0
  29. package/build/cjs/components/Internal/ToolbarItemCount/ToolbarItemCount.js +1 -0
  30. package/build/cjs/components/Kbd/Kbd.d.ts +118 -0
  31. package/build/cjs/components/Kbd/Kbd.js +1 -0
  32. package/build/cjs/components/KbdGroup/KbdGroup.d.ts +7 -0
  33. package/build/cjs/components/KbdGroup/KbdGroup.js +1 -0
  34. package/build/cjs/components/Layout/-types.d.ts +6 -1
  35. package/build/cjs/components/Layout/Layout.js +1 -1
  36. package/build/cjs/components/Layout/LeftPanel/LeftPanelDocked.js +1 -1
  37. package/build/cjs/components/Layout/RightPanel/RightPanel.js +1 -1
  38. package/build/cjs/components/Layout/registry.d.ts +4 -0
  39. package/build/cjs/components/Layout/registry.js +1 -1
  40. package/build/cjs/components/Layout/usePanelDockedSlide.d.ts +4 -1
  41. package/build/cjs/components/Layout/usePanelDockedSlide.js +1 -1
  42. package/build/cjs/components/Tooltip/BaseTooltip.js +1 -1
  43. package/build/cjs/components/Tooltip/Tooltip.d.ts +3 -1
  44. package/build/cjs/components/Tooltip/Tooltip.js +1 -1
  45. package/build/cjs/index.d.ts +1 -0
  46. package/build/cjs/index.js +1 -1
  47. package/build/cjs/shared/useIsMacOs.d.ts +1 -0
  48. package/build/cjs/shared/useIsMacOs.js +1 -0
  49. package/build/cjs/web-tokens/_colors.json +26 -0
  50. package/build/cjs/web-tokens/_sizes.json +10 -0
  51. package/build/cjs/web-tokens/visualConfig.d.ts +25 -0
  52. package/build/cjs/web-tokens/visualConfig.js +1 -1
  53. package/build/esm/components/BulkActionsToolbar/BulkActionsToolbar.js +1 -1
  54. package/build/esm/components/DataTable/DataTable.d.ts +18 -8
  55. package/build/esm/components/DataTable/DataTable.js +1 -1
  56. package/build/esm/components/DataTable/DataTableToolbar/DataTableToolbar.d.ts +97 -0
  57. package/build/esm/components/DataTable/DataTableToolbar/DataTableToolbar.js +1 -0
  58. package/build/esm/components/DataTable/TableCell.js +1 -1
  59. package/build/esm/components/DataTable/TableColumnGroups.d.ts +15 -0
  60. package/build/esm/components/DataTable/TableColumnGroups.js +1 -0
  61. package/build/esm/components/DataTable/header/DataTableHeaderLabel.d.ts +28 -0
  62. package/build/esm/components/DataTable/header/DataTableHeaderLabel.js +1 -0
  63. package/build/esm/components/DataTable/header/TableHeader.js +1 -1
  64. package/build/esm/components/DataTable/index.d.ts +1 -1
  65. package/build/esm/components/DataTable/internal/buildColumnSegments.d.ts +18 -0
  66. package/build/esm/components/DataTable/internal/buildColumnSegments.js +1 -0
  67. package/build/esm/components/DataTable/internal/buildInternalColumns.d.ts +2 -2
  68. package/build/esm/components/DataTable/internal/buildInternalColumns.js +1 -1
  69. package/build/esm/components/DataTable/internal/getColumnSticky.js +1 -1
  70. package/build/esm/components/DataTable/internal/types.d.ts +7 -2
  71. package/build/esm/components/DataTable/isDataTableColumnGroup.d.ts +2 -0
  72. package/build/esm/components/DataTable/isDataTableColumnGroup.js +1 -0
  73. package/build/esm/components/DataTable/types.d.ts +52 -8
  74. package/build/esm/components/DataTable/useDataTableSort.d.ts +4 -4
  75. package/build/esm/components/DataTable/useDataTableSort.js +1 -1
  76. package/build/esm/components/FilterToolbar/FilterToolbar.d.ts +103 -0
  77. package/build/esm/components/FilterToolbar/FilterToolbar.js +1 -0
  78. package/build/esm/components/Internal/Panel/Panel.d.ts +22 -1
  79. package/build/esm/components/Internal/Panel/Panel.js +1 -1
  80. package/build/esm/components/Internal/ToolbarItemCount/ToolbarItemCount.d.ts +16 -0
  81. package/build/esm/components/Internal/ToolbarItemCount/ToolbarItemCount.js +1 -0
  82. package/build/esm/components/Kbd/Kbd.d.ts +118 -0
  83. package/build/esm/components/Kbd/Kbd.js +1 -0
  84. package/build/esm/components/KbdGroup/KbdGroup.d.ts +7 -0
  85. package/build/esm/components/KbdGroup/KbdGroup.js +1 -0
  86. package/build/esm/components/Layout/-types.d.ts +6 -1
  87. package/build/esm/components/Layout/Layout.js +1 -1
  88. package/build/esm/components/Layout/LeftPanel/LeftPanelDocked.js +1 -1
  89. package/build/esm/components/Layout/RightPanel/RightPanel.js +1 -1
  90. package/build/esm/components/Layout/registry.d.ts +4 -0
  91. package/build/esm/components/Layout/registry.js +1 -1
  92. package/build/esm/components/Layout/usePanelDockedSlide.d.ts +4 -1
  93. package/build/esm/components/Layout/usePanelDockedSlide.js +1 -1
  94. package/build/esm/components/Tooltip/BaseTooltip.js +1 -1
  95. package/build/esm/components/Tooltip/Tooltip.d.ts +3 -1
  96. package/build/esm/components/Tooltip/Tooltip.js +1 -1
  97. package/build/esm/index.d.ts +1 -0
  98. package/build/esm/index.js +1 -1
  99. package/build/esm/shared/useIsMacOs.d.ts +1 -0
  100. package/build/esm/shared/useIsMacOs.js +1 -0
  101. package/build/esm/web-tokens/_colors.json +26 -0
  102. package/build/esm/web-tokens/_sizes.json +10 -0
  103. package/build/esm/web-tokens/visualConfig.d.ts +25 -0
  104. package/build/esm/web-tokens/visualConfig.js +1 -1
  105. package/build/scss/_dark.scss +3 -0
  106. package/build/scss/_light.scss +3 -0
  107. package/build/scss/_variables.scss +4 -0
  108. package/build/scss/subthemes/_inverted.scss +6 -0
  109. package/package.json +1 -1
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ import type { ColumnSegment } from "./internal/buildColumnSegments";
3
+ type TableColumnGroupsProps = {
4
+ segments: ColumnSegment[];
5
+ };
6
+ /**
7
+ * The `<colgroup>` elements that back the header, one per segment.
8
+ *
9
+ * A group header carries `scope="colgroup"`, which names a real column group and
10
+ * nothing else — `colspan` alone does not create one. The `<col>` widths also give
11
+ * a grouped column a width under `layout="fixed"`, where a fixed layout reads the
12
+ * first header row and the grouped column sits in the second.
13
+ */
14
+ declare function TableColumnGroups({ segments, }: TableColumnGroupsProps): React.ReactElement;
15
+ export default TableColumnGroups;
@@ -0,0 +1 @@
1
+ import React from"react";import styled from"@emotion/styled";import{useResponsiveValue}from"../../shared/mediaQueries";let StyledCol=styled("col",{target:"e12f45xj0",label:"StyledCol"})(({columnWidth})=>({...useResponsiveValue({width:columnWidth})}));export default function({segments}){return React.createElement(React.Fragment,null,segments.map(segment=>React.createElement("colgroup",{key:segment.columns[0].column.name},segment.columns.map(({column})=>React.createElement(StyledCol,{key:column.name,columnWidth:column.width})))))}
@@ -0,0 +1,28 @@
1
+ import type { ReactElement } from "react";
2
+ import React from "react";
3
+ import type { SlotProps } from "../../../shared/slotProps";
4
+ import type { DataTableColumn, DataTableColumnDefinition, DataTableColumnGroup } from "../types";
5
+ /**
6
+ * `aria-label` is required inside the slot because the toggletip trigger is an
7
+ * icon-only button, which needs an accessible name (WCAG 2.1 SC 4.1.2).
8
+ */
9
+ type DataTableHeaderLabelSlotProps = SlotProps<{
10
+ toggletip: {
11
+ content: ReactElement;
12
+ "aria-label": string;
13
+ };
14
+ }>;
15
+ /**
16
+ * Builds the slot in one place, so both header call sites pair `content` with
17
+ * its `aria-label` the same way. The project runs without `strictNullChecks`,
18
+ * so nothing here would flag an `aria-label` that arrives undefined.
19
+ */
20
+ export declare const toToggletipSlotProps: (source: DataTableColumnDefinition | DataTableColumnGroup) => DataTableHeaderLabelSlotProps | undefined;
21
+ type DataTableHeaderLabelProps = {
22
+ label: string;
23
+ align: DataTableColumn["align"];
24
+ /** Props forwarded to internal sub-components */
25
+ slotProps?: DataTableHeaderLabelSlotProps;
26
+ };
27
+ export declare function DataTableHeaderLabel({ label, align, slotProps, }: Readonly<DataTableHeaderLabelProps>): React.ReactElement;
28
+ export {};
@@ -0,0 +1 @@
1
+ import React from"react";import{Inline}from"../../Inline/Inline";import{StyledLabel}from"./SortableCellContent";import{DataTableHeaderToggletip}from"./DataTableHeaderToggletip";export const toToggletipSlotProps=source=>source.toggletipContent?{toggletip:{content:source.toggletipContent,"aria-label":source.toggletipAriaLabel}}:void 0;export function DataTableHeaderLabel({label,align,slotProps}){return React.createElement(Inline,{space:"xs",noWrap:!0,vAlignItems:"center",alignItems:align},React.createElement(StyledLabel,{as:"span",size:"s",alignColumn:align,color:"tertiary",normalizeHeight:!0},label),slotProps?.toggletip&&React.createElement(DataTableHeaderToggletip,{content:slotProps.toggletip.content,"aria-label":slotProps.toggletip["aria-label"]}))}
@@ -1 +1 @@
1
- import React from"react";import styled from"@emotion/styled";import TableCell from"../TableCell";import{getColumnSticky}from"../internal/getColumnSticky";import{isControlColumn}from"../internal/types";import{SortableCellContent,StyledLabel}from"./SortableCellContent";import{Inline}from"../../Inline/Inline";import{DataTableHeaderToggletip}from"./DataTableHeaderToggletip";let SORT_DIRECTION_TEXT={asc:"ascending",desc:"descending"},StyledThead=styled("thead",{target:"eqohg680",label:"StyledThead"})(({maxHeight})=>({...maxHeight&&{position:"sticky",top:0,zIndex:2}})),StyledTh=styled(TableCell,{target:"eqohg681",label:"StyledTh"})(({theme})=>({padding:`${theme.variables.size.spacing.s} ${theme.variables.size.spacing.m}`,whiteSpace:"nowrap",backgroundColor:theme.values.color.background.primary.default}));export default React.memo(function({className,columns,isFirstColumnSticky,isLastColumnSticky,currentlySortedByColumn,isTableScrolledToLeft,isTableScrolledToRight,maxHeight,allRowsSelected,selectedRowIds,selectAllRowsCheckboxAriaLabel,onAllRowsSelectionChange,onSort}){let headerContext={onSort,currentlySortedByColumn,allRowsSelected,selectedRowIds,selectAllRowsCheckboxAriaLabel,onAllRowsSelectionChange},columnElements=columns.map((column,columnIndex)=>{let headerElm,sticky=getColumnSticky({column,columnIndex,columns,isFirstColumnSticky,isLastColumnSticky});if(isControlColumn(column))return React.createElement(StyledTh,{as:"th",alignColumn:"left",columnWidth:column.width,key:column.name,sticky:sticky,isTableScrolledToLeft:isTableScrolledToLeft,isTableScrolledToRight:isTableScrolledToRight,scope:"col"},column.renderHeader(headerContext));let{isSortable,label,align="left",width,name,sortDirection,toggletipContent,toggletipAriaLabel}=column;headerElm=isSortable?React.createElement(SortableCellContent,{onSort:onSort,name:name,label:label,sortDirection:sortDirection,align:align,currentlySortedByColumn:currentlySortedByColumn,toggletipContent:toggletipContent,toggletipAriaLabel:toggletipAriaLabel}):React.createElement(Inline,{space:"xs",noWrap:!0,vAlignItems:"center",alignItems:align},React.createElement(StyledLabel,{as:"span",size:"s",alignColumn:align,color:"tertiary",normalizeHeight:!0},label),toggletipContent&&React.createElement(DataTableHeaderToggletip,{content:toggletipContent,"aria-label":toggletipAriaLabel}));let ariaSortAttr=currentlySortedByColumn===name&&{"aria-sort":SORT_DIRECTION_TEXT[sortDirection]};return React.createElement(StyledTh,{as:"th",alignColumn:align,columnWidth:width,key:name,sticky:sticky,isTableScrolledToLeft:isTableScrolledToLeft,isTableScrolledToRight:isTableScrolledToRight,scope:"col",...ariaSortAttr},headerElm)});return React.createElement(StyledThead,{className:className,maxHeight:maxHeight},React.createElement("tr",null,columnElements))});
1
+ import React from"react";import styled from"@emotion/styled";import TableCell from"../TableCell";import{getColumnSticky}from"../internal/getColumnSticky";import{isControlColumn}from"../internal/types";import{buildColumnSegments}from"../internal/buildColumnSegments";import{SortableCellContent}from"./SortableCellContent";import{DataTableHeaderLabel,toToggletipSlotProps}from"./DataTableHeaderLabel";let SORT_DIRECTION_TEXT={asc:"ascending",desc:"descending"},StyledThead=styled("thead",{target:"elv391v0",label:"StyledThead"})(({maxHeight})=>({...maxHeight&&{position:"sticky",top:0,zIndex:2}})),StyledTh=styled(TableCell,{target:"elv391v1",label:"StyledTh"})(({theme,hasDivider})=>({padding:`${theme.variables.size.spacing.s} ${theme.variables.size.spacing.m}`,whiteSpace:"nowrap",backgroundColor:theme.values.color.background.primary.default,...hasDivider&&{borderRight:`1px solid ${theme.values.color.divider.primary}`}}));export default React.memo(function({className,columns,isFirstColumnSticky,isLastColumnSticky,currentlySortedByColumn,isTableScrolledToLeft,isTableScrolledToRight,maxHeight,allRowsSelected,selectedRowIds,selectAllRowsCheckboxAriaLabel,onAllRowsSelectionChange,onSort}){let headerContext={onSort,currentlySortedByColumn,allRowsSelected,selectedRowIds,selectAllRowsCheckboxAriaLabel,onAllRowsSelectionChange},renderColumnCell=({column,columnIndex},rowSpan)=>{let headerElm,isLastColumn=columnIndex===columns.length-1,sticky=getColumnSticky({column,columnIndex,columns,isFirstColumnSticky,isLastColumnSticky});if(isControlColumn(column))return React.createElement(StyledTh,{as:"th",alignColumn:"left",columnWidth:column.width,key:column.name,rowSpan:rowSpan,sticky:sticky,isTableScrolledToLeft:isTableScrolledToLeft,isTableScrolledToRight:isTableScrolledToRight,hasDivider:!1,scope:"col"},column.renderHeader(headerContext));let{isSortable,label,align="left",width,name,sortDirection,toggletipContent,toggletipAriaLabel}=column;headerElm=isSortable?React.createElement(SortableCellContent,{onSort:onSort,name:name,label:label,sortDirection:sortDirection,align:align,currentlySortedByColumn:currentlySortedByColumn,toggletipContent:toggletipContent,toggletipAriaLabel:toggletipAriaLabel}):React.createElement(DataTableHeaderLabel,{label:label,align:align,slotProps:toToggletipSlotProps(column)});let ariaSortAttr=currentlySortedByColumn===name&&{"aria-sort":SORT_DIRECTION_TEXT[sortDirection]};return React.createElement(StyledTh,{as:"th",alignColumn:align,columnWidth:width,key:name,rowSpan:rowSpan,sticky:sticky,isTableScrolledToLeft:isTableScrolledToLeft,isTableScrolledToRight:isTableScrolledToRight,hasDivider:!isLastColumn,scope:"col",...ariaSortAttr},headerElm)},renderGroupCell=(group,groupColumns)=>{let{name,label,align="center"}=group,isLastColumn=groupColumns[groupColumns.length-1].columnIndex===columns.length-1;return React.createElement(StyledTh,{as:"th",alignColumn:align,key:name,colSpan:groupColumns.length,sticky:!1,isTableScrolledToLeft:isTableScrolledToLeft,isTableScrolledToRight:isTableScrolledToRight,hasDivider:!isLastColumn,scope:"colgroup"},React.createElement(DataTableHeaderLabel,{label:label,align:align,slotProps:toToggletipSlotProps(group)}))},segments=buildColumnSegments(columns),hasColumnGroups=segments.some(({group})=>group),ungroupedRowSpan=hasColumnGroups?2:void 0;return React.createElement(StyledThead,{className:className,maxHeight:maxHeight},React.createElement("tr",null,segments.map(segment=>segment.group?renderGroupCell(segment.group,segment.columns):renderColumnCell(segment.columns[0],ungroupedRowSpan))),hasColumnGroups&&React.createElement("tr",null,segments.flatMap(segment=>segment.group?segment.columns.map(indexed=>renderColumnCell(indexed)):[])))});
@@ -1,4 +1,4 @@
1
- export type { DataTableColumn, DataTableRow, DataTableSlotProps, } from "./types";
1
+ export type { DataTableColumn, DataTableColumnGroup, DataTableColumnOrGroup, DataTableRow, DataTableSlotProps, } from "./types";
2
2
  export { DataTable, BaseDataTable } from "./DataTable";
3
3
  export type { DataTableProps } from "./DataTable";
4
4
  export { useDataTableSort } from "./useDataTableSort";
@@ -0,0 +1,18 @@
1
+ import type { DataTableColumnGroup } from "../types";
2
+ import type { InternalColumn } from "./types";
3
+ export type IndexedColumn = {
4
+ column: InternalColumn;
5
+ columnIndex: number;
6
+ };
7
+ export type ColumnSegment = {
8
+ /** Set when the segment's columns share one `DataTableColumnGroup`. */
9
+ group?: DataTableColumnGroup;
10
+ columns: IndexedColumn[];
11
+ };
12
+ /**
13
+ * Splits the flat column list into segments: one segment per group, and a
14
+ * segment of one for every column that has no group. A segment is both a
15
+ * cell of the first header row and a `<colgroup>`, so the two always agree
16
+ * on where a group starts and ends.
17
+ */
18
+ export declare function buildColumnSegments(columns: InternalColumn[]): ColumnSegment[];
@@ -0,0 +1 @@
1
+ import{isDataColumn}from"./types";export function buildColumnSegments(columns){let segments=[];return columns.forEach((column,columnIndex)=>{let group=isDataColumn(column)?column.group:void 0,currentSegment=segments[segments.length-1];if(group&&currentSegment?.group===group)return void currentSegment.columns.push({column,columnIndex});segments.push({group,columns:[{column,columnIndex}]})}),segments}
@@ -1,10 +1,10 @@
1
- import type { DataTableColumn } from "../types";
1
+ import type { DataTableColumnOrGroup } from "../types";
2
2
  import type { InternalColumn } from "./types";
3
3
  export type DataTableFeatures = {
4
4
  selectable?: boolean;
5
5
  expandable?: boolean;
6
6
  };
7
7
  export declare function buildInternalColumns({ columns, features: { selectable, expandable }, }: {
8
- columns: DataTableColumn[];
8
+ columns: DataTableColumnOrGroup[];
9
9
  features: DataTableFeatures;
10
10
  }): InternalColumn[];
@@ -1 +1 @@
1
- import{createCheckboxColumn}from"./controlColumns/checkboxColumn";import{createExpandColumn}from"./controlColumns/expandColumn";export function buildInternalColumns({columns,features:{selectable,expandable}}){let dataColumns=columns.map(column=>({...column,kind:"data"})),controlColumns=[];return expandable&&controlColumns.push(createExpandColumn()),selectable&&controlColumns.push(createCheckboxColumn()),[...controlColumns,...dataColumns]}
1
+ import{isDataTableColumnGroup}from"../isDataTableColumnGroup";import{createCheckboxColumn}from"./controlColumns/checkboxColumn";import{createExpandColumn}from"./controlColumns/expandColumn";let toDataColumns=column=>isDataTableColumnGroup(column)?column.children.map(child=>({...child,kind:"data",group:column})):[{...column,kind:"data"}];export function buildInternalColumns({columns,features:{selectable,expandable}}){let dataColumns=columns.flatMap(toDataColumns),controlColumns=[];return expandable&&controlColumns.push(createExpandColumn()),selectable&&controlColumns.push(createCheckboxColumn()),[...controlColumns,...dataColumns]}
@@ -1 +1 @@
1
- import{isControlColumn,isDataColumn}from"./types";export function getColumnSticky({column,columnIndex,columns,isFirstColumnSticky,isLastColumnSticky}){if(isControlColumn(column))return!1;let dataColumnIndices=columns.reduce((indices,col,index)=>(isDataColumn(col)&&indices.push(index),indices),[]),firstDataIndex=dataColumnIndices[0],lastDataIndex=dataColumnIndices[dataColumnIndices.length-1];return isFirstColumnSticky&&columnIndex===firstDataIndex?"left":!!isLastColumnSticky&&columnIndex===lastDataIndex&&"right"}
1
+ import{isControlColumn,isDataColumn}from"./types";export function getColumnSticky({column,columnIndex,columns,isFirstColumnSticky,isLastColumnSticky}){if(isControlColumn(column)||column.group)return!1;let dataColumnIndices=columns.reduce((indices,col,index)=>(isDataColumn(col)&&indices.push(index),indices),[]),firstDataIndex=dataColumnIndices[0],lastDataIndex=dataColumnIndices[dataColumnIndices.length-1];return isFirstColumnSticky&&columnIndex===firstDataIndex?"left":!!isLastColumnSticky&&columnIndex===lastDataIndex&&"right"}
@@ -1,6 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { DataTableProps } from "../DataTable";
3
- import type { DataTableColumn, DataTableRow, DataTableRowProps } from "../types";
3
+ import type { DataTableColumnDefinition, DataTableColumnGroup, DataTableRow, DataTableRowProps } from "../types";
4
4
  export type ControlColumnKind = "checkbox" | "expand";
5
5
  export type HeaderRenderContext = Pick<DataTableProps, "onSort" | "currentlySortedByColumn" | "allRowsSelected" | "selectedRowIds" | "selectAllRowsCheckboxAriaLabel" | "onAllRowsSelectionChange">;
6
6
  export type RowCellRenderContext = {
@@ -14,8 +14,13 @@ export type RowCellRenderContext = {
14
14
  onRowExpansionChange: (expandedRowIds: DataTableRow["id"][]) => void;
15
15
  emptyCellContent: string;
16
16
  };
17
- export type DataColumn = DataTableColumn & {
17
+ export type DataColumn = DataTableColumnDefinition & {
18
18
  kind: "data";
19
+ /**
20
+ * Set when the column came from a `DataTableColumnGroup`. The header collapses
21
+ * neighbours that share this reference into one spanning cell.
22
+ */
23
+ group?: DataTableColumnGroup;
19
24
  };
20
25
  export type ControlColumn = {
21
26
  kind: ControlColumnKind;
@@ -0,0 +1,2 @@
1
+ import type { DataTableColumnGroup, DataTableColumnOrGroup } from "./types";
2
+ export declare function isDataTableColumnGroup(column: DataTableColumnOrGroup): column is DataTableColumnGroup;
@@ -0,0 +1 @@
1
+ export function isDataTableColumnGroup(column){return"group"===column.kind}
@@ -7,6 +7,16 @@ export type DataTableRow = {
7
7
  id: string;
8
8
  [key: string]: any;
9
9
  };
10
+ /** A toggletip needs both fields or neither. A column and a group share the pair. */
11
+ type WithToggletip = {
12
+ toggletipContent: ReactElement;
13
+ /** Accessible name for the toggletip trigger button. Required when `toggletipContent` is set. */
14
+ toggletipAriaLabel: string;
15
+ };
16
+ type WithoutToggletip = {
17
+ toggletipContent?: never;
18
+ toggletipAriaLabel?: never;
19
+ };
10
20
  type DataTableColumnBase = {
11
21
  name: string;
12
22
  label: string;
@@ -16,16 +26,50 @@ type DataTableColumnBase = {
16
26
  sortDirection?: "asc" | "desc";
17
27
  renderCell?: (row: DataTableRow) => React.ReactElement;
18
28
  };
19
- type DataTableColumnWithToggletip = DataTableColumnBase & {
20
- toggletipContent: ReactElement;
21
- /** Accessible name for the toggletip trigger button. Required when `toggletipContent` is set. */
22
- toggletipAriaLabel: string;
29
+ /**
30
+ * A column before a discriminant marks it public or internal. The public
31
+ * `DataTableColumn` adds `kind?: "column"`; the internal `DataColumn` adds
32
+ * `kind: "data"`. Each adds its own, so neither has to strip the other's.
33
+ */
34
+ export type DataTableColumnDefinition = (DataTableColumnBase & WithToggletip) | (DataTableColumnBase & WithoutToggletip);
35
+ export type DataTableColumn = DataTableColumnDefinition & {
36
+ /** Leave it out on a column. Only a group sets it, to `"group"`. */
37
+ kind?: "column";
38
+ /** Not on a column — `children` makes a group, and a group is one level deep. */
39
+ children?: never;
23
40
  };
24
- type DataTableColumnWithoutToggletip = DataTableColumnBase & {
25
- toggletipContent?: never;
26
- toggletipAriaLabel?: never;
41
+ type DataTableColumnGroupBase = {
42
+ /**
43
+ * Marks the entry as a group. Required: it also makes TypeScript match the
44
+ * literal against the group alone, so a rejected field is reported where you
45
+ * wrote it instead of blaming `children`.
46
+ */
47
+ kind: "group";
48
+ name: string;
49
+ label: string;
50
+ /** Defaults to `"center"`. It aligns the group label only, not the children. */
51
+ align?: TextAlignment | MQ<TextAlignment>;
52
+ /** The columns under the shared label. One level only — a column cannot itself be a group. */
53
+ children: DataTableColumn[];
54
+ /** Not on a group — a group spans its children and has no width of its own. */
55
+ width?: never;
56
+ /** Not on a group — a group label has no sort control. Sort a child instead. */
57
+ isSortable?: never;
58
+ /** Not on a group — sorting belongs to a child column. */
59
+ sortDirection?: never;
60
+ /** Not on a group — a group renders a label, not a cell of data. */
61
+ renderCell?: never;
27
62
  };
28
- export type DataTableColumn = DataTableColumnWithToggletip | DataTableColumnWithoutToggletip;
63
+ /**
64
+ * A shared label above its `children`, rendered in the first header row.
65
+ *
66
+ * A group labels columns and owns no data, so it rejects `width`,
67
+ * `isSortable`, `sortDirection` and `renderCell`. Passing one is a type error
68
+ * rather than a silent no-op. They stay readable on `DataTableColumnOrGroup`,
69
+ * so reading a column field off the union still needs no narrowing step.
70
+ */
71
+ export type DataTableColumnGroup = (DataTableColumnGroupBase & WithToggletip) | (DataTableColumnGroupBase & WithoutToggletip);
72
+ export type DataTableColumnOrGroup = DataTableColumn | DataTableColumnGroup;
29
73
  export type DataTableRowProps = {
30
74
  verticalAlign?: Property.VerticalAlign;
31
75
  isActive?: boolean;
@@ -1,15 +1,15 @@
1
1
  import type { Dispatch, SetStateAction } from "react";
2
- import type { DataTableColumn, DataTableRow } from "./types";
2
+ import type { DataTableColumn, DataTableColumnOrGroup, DataTableRow } from "./types";
3
3
  import type { DataTableProps } from "./DataTable";
4
4
  type SortCompareFn = (a: DataTableRow, b: DataTableRow, columnName: DataTableColumn["name"], desiredSortDirection: DataTableColumn["sortDirection"]) => number;
5
5
  export declare const defaultSortCompareFn: (a: DataTableRow, b: DataTableRow, columnName: DataTableColumn["name"], desiredSortDirection: DataTableColumn["sortDirection"]) => number;
6
- export declare function useDataTableSort(initialColumns: DataTableColumn[], initialRows: DataTableRow[], initialSortedByColumn?: DataTableColumn["name"], sortCompareFn?: SortCompareFn): {
7
- columns: DataTableColumn[];
6
+ export declare function useDataTableSort(initialColumns: DataTableColumnOrGroup[], initialRows: DataTableRow[], initialSortedByColumn?: DataTableColumn["name"], sortCompareFn?: SortCompareFn): {
7
+ columns: DataTableColumnOrGroup[];
8
8
  rows: DataTableRow[];
9
9
  currentlySortedByColumn: DataTableColumn["name"];
10
10
  handleSort: DataTableProps["onSort"];
11
11
  resetColumns: VoidFunction;
12
- setColumns: Dispatch<SetStateAction<DataTableColumn[]>>;
12
+ setColumns: Dispatch<SetStateAction<DataTableColumnOrGroup[]>>;
13
13
  setRows: Dispatch<SetStateAction<DataTableRow[]>>;
14
14
  setCurrentlySortedByColumn: Dispatch<SetStateAction<DataTableColumn["name"]>>;
15
15
  };
@@ -1 +1 @@
1
- import{useState}from"react";export const defaultSortCompareFn=(a,b,columnName,desiredSortDirection)=>a[columnName]<b[columnName]?"asc"===desiredSortDirection?-1:1:a[columnName]>b[columnName]?"asc"===desiredSortDirection?1:-1:0;export function useDataTableSort(initialColumns,initialRows,initialSortedByColumn,sortCompareFn=defaultSortCompareFn){let[columns,setColumns]=useState(initialColumns),[currentlySortedByColumn,setCurrentlySortedByColumn]=useState(initialSortedByColumn),[rows,setRows]=useState(initialRows);return{columns,rows,currentlySortedByColumn,handleSort:(columnName,desiredSortDirection)=>{let newColumns=[...columns],newRows=[...rows],column=newColumns.find(item=>item.name===columnName);column&&(column.sortDirection=desiredSortDirection),newRows.sort((a,b)=>sortCompareFn(a,b,columnName,desiredSortDirection)),setRows(newRows),setColumns(newColumns),setCurrentlySortedByColumn(columnName)},setColumns,resetColumns:()=>{setColumns(initialColumns),setCurrentlySortedByColumn(initialSortedByColumn)},setRows,setCurrentlySortedByColumn}}
1
+ import{useState}from"react";import{isDataTableColumnGroup}from"./isDataTableColumnGroup";export const defaultSortCompareFn=(a,b,columnName,desiredSortDirection)=>a[columnName]<b[columnName]?"asc"===desiredSortDirection?-1:1:a[columnName]>b[columnName]?"asc"===desiredSortDirection?1:-1:0;let withUpdatedSortDirection=({columns,columnName,desiredSortDirection})=>{let updateColumn=column=>column.name===columnName?{...column,sortDirection:desiredSortDirection}:column;return columns.map(column=>isDataTableColumnGroup(column)?{...column,children:column.children.map(updateColumn)}:updateColumn(column))};export function useDataTableSort(initialColumns,initialRows,initialSortedByColumn,sortCompareFn=defaultSortCompareFn){let[columns,setColumns]=useState(initialColumns),[currentlySortedByColumn,setCurrentlySortedByColumn]=useState(initialSortedByColumn),[rows,setRows]=useState(initialRows);return{columns,rows,currentlySortedByColumn,handleSort:(columnName,desiredSortDirection)=>{let newColumns=withUpdatedSortDirection({columns,columnName,desiredSortDirection}),newRows=[...rows];newRows.sort((a,b)=>sortCompareFn(a,b,columnName,desiredSortDirection)),setRows(newRows),setColumns(newColumns),setCurrentlySortedByColumn(columnName)},setColumns,resetColumns:()=>{setColumns(initialColumns),setCurrentlySortedByColumn(initialSortedByColumn)},setRows,setCurrentlySortedByColumn}}
@@ -0,0 +1,103 @@
1
+ import type { ReactElement } from "react";
2
+ import React from "react";
3
+ import type { ConditionalAccessibleName } from "../../types/a11y";
4
+ import type { SegmentedControlProps } from "../Form/SegmentedControl/SegmentedControl";
5
+ import type { SearchInputProps } from "../Form/SearchInput/SearchInput";
6
+ import type { IconName } from "../Icon/Icon";
7
+ import type { PopupRole } from "../Sheet/Sheet";
8
+ export type FilterToolbarFilter = {
9
+ /** Visible label and accessible name of the trigger button. */
10
+ label: string;
11
+ /** Count shown in the trigger's badge. Pass `null` to hide the badge. */
12
+ count: number | null;
13
+ /** Icon shown on the trigger button, e.g. `"filter"`, `"columns3"`. */
14
+ leftIcon?: IconName;
15
+ /** Whether this filter's popup (e.g. a `FilterDialog` or `Popover`) is open. Wired into the trigger's `aria-expanded`. */
16
+ isOpen: boolean;
17
+ /**
18
+ * Id of the popup this trigger controls, wired into `aria-controls` while
19
+ * `isOpen`. Leave it out for `FilterDialog`/`Popover`, since neither
20
+ * exposes an `id`.
21
+ */
22
+ popupId?: string;
23
+ /**
24
+ * Popup type opened by the trigger. Wired into `aria-haspopup`. Leave it out
25
+ * when the trigger opens no popup, so the button claims none.
26
+ */
27
+ role?: Extract<PopupRole, "dialog" | "menu" | "listbox">;
28
+ /**
29
+ * Ref to this trigger's button. A `Popover` needs it as its own
30
+ * `externalTriggerRef`, to anchor to the trigger and to manage its click and
31
+ * focus-return behavior. It also writes `aria-expanded`, `aria-haspopup`, and
32
+ * `aria-controls` on the button itself, so keep `isOpen` in sync with the
33
+ * popover and leave `role` and `popupId` out. `FilterDialog` needs no ref: it
34
+ * opens as a modal or sheet, not anchored to the trigger.
35
+ */
36
+ triggerRef?: React.RefObject<HTMLButtonElement>;
37
+ /**
38
+ * Called when the trigger is clicked, for a popup the consumer opens itself,
39
+ * e.g. a `FilterDialog`. Leave it out with `triggerRef`: a `Popover` adds its
40
+ * own click listener to that button, so a second handler here toggles the
41
+ * open state twice on one click.
42
+ */
43
+ onClick?: () => void;
44
+ };
45
+ /** The visible content of a filter toolbar, without its accessible name or test id. */
46
+ export type FilterToolbarContentProps = {
47
+ /**
48
+ * Visible item count shown at the start of the row, e.g. `"50 items"`. It is
49
+ * a live region, so a count change is announced without a move of focus.
50
+ * Use it when no other row shows the count.
51
+ */
52
+ totalItems?: string;
53
+ /**
54
+ * A segmented control rendered at the start of the row, e.g. a year toggle.
55
+ * `label` is required because `FormFieldGroup` always renders a `<legend>`,
56
+ * even when the label is visually hidden. `size` is set by the toolbar, so
57
+ * the row keeps one height.
58
+ */
59
+ segmentedControlProps?: Omit<SegmentedControlProps, "size"> & {
60
+ label: string;
61
+ };
62
+ /**
63
+ * Filter and column trigger buttons, e.g. "Filter 4", "Columns 9". Each one
64
+ * renders as a `CountButton` whose `aria-expanded`, `aria-haspopup`, and
65
+ * `aria-controls` come from the entry's state. The toolbar does not render or
66
+ * manage the popup (`FilterDialog`, `Popover`) itself.
67
+ *
68
+ * Always wrap in `useMemo` to avoid unnecessary re-renders.
69
+ */
70
+ filters?: FilterToolbarFilter[];
71
+ /**
72
+ * Search field rendered at the end of the row. Always wrap in `useMemo` to
73
+ * avoid unnecessary re-renders. `slotProps.clearButton.ariaLabel` is
74
+ * required so the icon-only clear button has an accessible name.
75
+ */
76
+ searchInputProps?: Omit<SearchInputProps, "slotProps"> & {
77
+ slotProps: {
78
+ clearButton: {
79
+ ariaLabel: string;
80
+ };
81
+ };
82
+ };
83
+ };
84
+ export type FilterToolbarProps = FilterToolbarContentProps & {
85
+ "data-e2e-test-id"?: string;
86
+ } & ConditionalAccessibleName;
87
+ /**
88
+ * A row of filter controls: an optional item count, an optional segmented
89
+ * control, any number of count-badged filter triggers, and an optional search
90
+ * field pinned to the end. Use it above a table, a list, a grid, or any other
91
+ * filterable collection. It renders the triggers only — the popups behind
92
+ * them (`FilterDialog`, `Popover`) stay with the consumer; see `filters`.
93
+ *
94
+ * The root is `role="group"`, not `role="toolbar"`: the APG toolbar pattern
95
+ * assumes one arrow-key widget, placed last, but this row has two (the native
96
+ * radio group inside `SegmentedControl`, and the search textbox), and a
97
+ * roving tabindex would break both (WCAG SC 2.1.1). `role="group"` gives the
98
+ * same programmatic grouping with no custom keyboard code, so every control
99
+ * keeps its native behavior.
100
+ */
101
+ declare function FilterToolbarUI({ totalItems, segmentedControlProps, filters, searchInputProps, "data-e2e-test-id": dataE2eTestId, ...ariaAttributes }: FilterToolbarProps): ReactElement;
102
+ export declare const FilterToolbar: React.MemoExoticComponent<typeof FilterToolbarUI>;
103
+ export {};
@@ -0,0 +1 @@
1
+ import React from"react";import styled from"@emotion/styled";import breakpoints from"../../web-tokens/_breakpoints.json";import{Inline}from"../Inline/Inline";import{ToolbarItemCount}from"../Internal/ToolbarItemCount/ToolbarItemCount";import{SegmentedControl}from"../Form/SegmentedControl/SegmentedControl";import{SearchInput}from"../Form/SearchInput/SearchInput";import{CountButton}from"../CountButton/CountButton";let containerMediumSize=breakpoints.m.value,toolbarContainerName="filterToolbar",containerBelowMedium=`@container ${toolbarContainerName} (min-width: 0px) and (max-width:${containerMediumSize}px)`,StyledFilterToolbar=styled("div",{target:"e1pn7li40",label:"StyledFilterToolbar"})(({theme})=>({containerType:"inline-size",containerName:toolbarContainerName,backgroundColor:theme.values.color.background.primary.default,borderTopLeftRadius:"inherit",borderTopRightRadius:"inherit"})),StyledFilterRow=styled("div",{target:"e1pn7li41",label:"StyledFilterRow"})(({theme})=>({padding:theme.variables.size.spacing.xs,display:"flex",flexWrap:"wrap",alignItems:"center",gap:theme.variables.size.spacing.s,[containerBelowMedium]:{flexDirection:"column",alignItems:"stretch"}})),CustomInline=styled(Inline,{target:"e1pn7li42",label:"CustomInline"})({[containerBelowMedium]:{order:2}}),StyledSearchSlot=styled("div",{target:"e1pn7li43",label:"StyledSearchSlot"})({display:"flex",flexGrow:1,justifyContent:"flex-end",[containerBelowMedium]:{order:1,flexGrow:0,display:"block"}}),CustomToolbarItemCount=styled(ToolbarItemCount,{target:"e1pn7li44",label:"CustomToolbarItemCount"})(({theme})=>({paddingInline:theme.variables.size.spacing.xxs}));export const FilterToolbar=React.memo(function({totalItems,segmentedControlProps,filters,searchInputProps,"data-e2e-test-id":dataE2eTestId,...ariaAttributes}){let hasLeadingContent=!!totalItems||!!segmentedControlProps||!!filters?.length;return React.createElement(StyledFilterToolbar,{role:"group","data-ds-id":"FilterToolbar","data-e2e-test-id":dataE2eTestId,...ariaAttributes},React.createElement(StyledFilterRow,null,hasLeadingContent&&React.createElement(CustomInline,{vAlignItems:"center",space:"xs"},totalItems&&React.createElement(CustomToolbarItemCount,null,totalItems),segmentedControlProps&&React.createElement(SegmentedControl,{...segmentedControlProps,size:"s"}),filters?.map(({label,count,leftIcon,isOpen,popupId,role,onClick,triggerRef})=>React.createElement(CountButton,{key:`filter-${label}`,ref:triggerRef,size:"s",leftIcon:leftIcon,count:count,onClick:onClick,"aria-haspopup":role,"aria-expanded":isOpen,"aria-controls":isOpen?popupId:void 0},label))),searchInputProps&&React.createElement(StyledSearchSlot,null,React.createElement(SearchInput,searchInputProps))))});
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import type { LayoutStorage, PanelImperativeHandle } from "react-resizable-panels";
2
+ import type { LayoutStorage, PanelImperativeHandle, PanelProps as ResizablePanelProps } from "react-resizable-panels";
3
3
  /** A size: plain number = pixels; unitless string = percentage ("10%"). */
4
4
  type Size = number | string;
5
5
  export type PanelItem = {
@@ -19,6 +19,16 @@ export type PanelItem = {
19
19
  * neighbour. Separators beside it stay usable as long as a resizable panel
20
20
  * remains on each of their sides - the drag just passes this panel by. */
21
21
  resizable?: boolean;
22
+ /** Hold this panel's width when the window (or the containing group) is
23
+ * resized, rather than its share of the group - so the change lands on the
24
+ * panels without it. Orthogonal to `resizable`, which governs drags only,
25
+ * and to the unit of `defaultSize`: a panel sized in `%` starts at that
26
+ * share and then holds the width it resolved to.
27
+ *
28
+ * Ignored on a panel with no `defaultSize` (nothing was asked for, so there
29
+ * is no width worth holding) and on every panel of a row where no panel is
30
+ * left to absorb the change. */
31
+ lockWidthOnWindowResize?: boolean;
22
32
  };
23
33
  export type PanelProps = {
24
34
  /** Visible panels, left-to-right. Conditionally rendering items toggles a
@@ -45,6 +55,17 @@ export type PanelProps = {
45
55
  * it lifts (~300ms). */
46
56
  shouldSuppressLayoutCallback?: () => boolean;
47
57
  };
58
+ type GroupResizeBehavior = ResizablePanelProps["groupResizeBehavior"];
59
+ /**
60
+ * A panel's `groupResizeBehavior` - what a resize of the GROUP
61
+ * (window/container) holds constant; a separator drag is unaffected either way.
62
+ * `"preserve-relative-size"`, the library's default, keeps a panel's share of
63
+ * the group, so its pixel width scales with the window. A panel that locks its
64
+ * width takes `"preserve-pixel-size"` and the rest absorb the change, which
65
+ * takes at least one panel without the lock - so a row of nothing else stays
66
+ * relative throughout rather than leaving the change nowhere to go.
67
+ */
68
+ export declare const groupResizeBehaviorFor: (item: PanelItem, panels: PanelItem[]) => GroupResizeBehavior;
48
69
  /**
49
70
  * Internal resizable panel row — the only wrapper around react-resizable-panels.
50
71
  * Renders one Panel per item with that item's `child` in a full-bleed host,
@@ -1 +1 @@
1
- import React from"react";import styled from"@emotion/styled";import{Group,Panel as ResizablePanel,Separator,useDefaultLayout}from"react-resizable-panels";let CustomGroup=styled(Group,{target:"e1vzb9ge0",label:"CustomGroup"})({height:"100%",width:"100%"}),StyledPanelChild=styled("div",{target:"e1vzb9ge1",label:"StyledPanelChild"})({position:"relative",height:"100%",width:"100%"}),NOOP_STORAGE={getItem:()=>null,setItem:()=>{}},isResizable=item=>!1!==item.resizable,canSeparatorResize=({panels,index})=>panels.slice(0,index).some(isResizable)&&panels.slice(index).some(isResizable);export function Panel({panels,persistenceKey,storage,onResize,onCollapse,panelHandleFor,panelElementFor,shouldSuppressLayoutCallback}){let{defaultLayout,onLayoutChanged:persistSizes}=useDefaultLayout({id:persistenceKey??"ds-layout",panelIds:panels.map(p=>p.id),storage:persistenceKey&&storage?storage:NOOP_STORAGE});return React.createElement(CustomGroup,{orientation:"horizontal",defaultLayout:defaultLayout,onLayoutChanged:layout=>{shouldSuppressLayoutCallback?.()||(persistSizes(layout),panels.forEach(({id,collapsible})=>{let pct=layout[id];if("number"==typeof pct){if(collapsible&&pct<.5)return void onCollapse(id);pct>=.5&&onResize(id,`${pct}%`)}}))}},panels.map((item,index)=>{let isSeparatorDisabled=!canSeparatorResize({panels,index});return React.createElement(React.Fragment,{key:item.id},index>0&&React.createElement(Separator,{disabled:isSeparatorDisabled}),React.createElement(ResizablePanel,{id:item.id,defaultSize:item.defaultSize,collapsible:item.collapsible,disabled:!1===item.resizable,minSize:item.minSize,maxSize:item.maxSize,panelRef:panelHandleFor?.(item.id),elementRef:panelElementFor?.(item.id)},React.createElement(StyledPanelChild,null,item.child)))}))}
1
+ import React from"react";import styled from"@emotion/styled";import{Group,Panel as ResizablePanel,Separator,useDefaultLayout}from"react-resizable-panels";let CustomGroup=styled(Group,{target:"e1q4b9dw0",label:"CustomGroup"})({height:"100%",width:"100%"}),StyledPanelChild=styled("div",{target:"e1q4b9dw1",label:"StyledPanelChild"})({position:"relative",height:"100%",width:"100%"}),NOOP_STORAGE={getItem:()=>null,setItem:()=>{}},isResizable=item=>!1!==item.resizable,locksWidth=item=>!0===item.lockWidthOnWindowResize&&void 0!==item.defaultSize;export const groupResizeBehaviorFor=(item,panels)=>locksWidth(item)&&panels.some(panel=>!locksWidth(panel))?"preserve-pixel-size":"preserve-relative-size";let canSeparatorResize=({panels,index})=>panels.slice(0,index).some(isResizable)&&panels.slice(index).some(isResizable);export function Panel({panels,persistenceKey,storage,onResize,onCollapse,panelHandleFor,panelElementFor,shouldSuppressLayoutCallback}){let{defaultLayout,onLayoutChanged:persistSizes}=useDefaultLayout({id:persistenceKey??"ds-layout",panelIds:panels.map(p=>p.id),storage:persistenceKey&&storage?storage:NOOP_STORAGE});return React.createElement(CustomGroup,{orientation:"horizontal",defaultLayout:defaultLayout,onLayoutChanged:layout=>{shouldSuppressLayoutCallback?.()||(persistSizes(layout),panels.forEach(({id,collapsible})=>{let pct=layout[id];if("number"==typeof pct){if(collapsible&&pct<.5)return void onCollapse(id);pct>=.5&&onResize(id,`${pct}%`)}}))}},panels.map((item,index)=>{let isSeparatorDisabled=!canSeparatorResize({panels,index});return React.createElement(React.Fragment,{key:item.id},index>0&&React.createElement(Separator,{disabled:isSeparatorDisabled}),React.createElement(ResizablePanel,{id:item.id,defaultSize:item.defaultSize,collapsible:item.collapsible,disabled:!1===item.resizable,groupResizeBehavior:groupResizeBehaviorFor(item,panels),minSize:item.minSize,maxSize:item.maxSize,panelRef:panelHandleFor?.(item.id),elementRef:panelElementFor?.(item.id)},React.createElement(StyledPanelChild,null,item.child)))}))}
@@ -0,0 +1,16 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ type ToolbarItemCountProps = {
3
+ /** The count itself, e.g. `"50 items"`. */
4
+ children: ReactNode;
5
+ /** Published on the text, so a toolbar's `aria-labelledby`/`aria-describedby` can point at it. */
6
+ id?: string;
7
+ "data-e2e-test-id"?: string;
8
+ };
9
+ /**
10
+ * The live region shown by `BulkActionsToolbar` and `FilterToolbar`, so a
11
+ * count change announces without moving focus. `DataTableToolbar` moves it
12
+ * between the two rows as `isSelectable` changes, so one definition covers
13
+ * both instead of two copies drifting apart.
14
+ */
15
+ export declare function ToolbarItemCount({ children, id, "data-e2e-test-id": dataE2eTestId, ...rest }: ToolbarItemCountProps): ReactElement;
16
+ export {};
@@ -0,0 +1 @@
1
+ import React from"react";import{Text}from"../../Typography/Text/Text";export function ToolbarItemCount({children,id,"data-e2e-test-id":dataE2eTestId,...rest}){return React.createElement("div",{...rest,role:"status","aria-atomic":"true","data-e2e-test-id":dataE2eTestId},React.createElement(Text,{size:"s",color:"secondary",weight:"bold",id:id},children))}
@@ -0,0 +1,118 @@
1
+ import React from "react";
2
+ /** Every name both key maps must define, so neither can drift from the other. */
3
+ export type KeyName = "cmd" | "meta" | "ctrl" | "alt" | "shift" | "enter" | "esc" | "backspace" | "tab" | "up" | "down" | "left" | "right" | "updown";
4
+ export declare const MAC_OS_KEYS: {
5
+ cmd: {
6
+ label: string;
7
+ spokenLabel: string;
8
+ };
9
+ meta: {
10
+ label: string;
11
+ spokenLabel: string;
12
+ };
13
+ ctrl: {
14
+ label: string;
15
+ spokenLabel: string;
16
+ };
17
+ alt: {
18
+ label: string;
19
+ spokenLabel: string;
20
+ };
21
+ shift: {
22
+ label: string;
23
+ spokenLabel: string;
24
+ };
25
+ enter: {
26
+ label: string;
27
+ spokenLabel: string;
28
+ };
29
+ esc: {
30
+ label: string;
31
+ };
32
+ backspace: {
33
+ label: string;
34
+ spokenLabel: string;
35
+ };
36
+ tab: {
37
+ label: string;
38
+ spokenLabel: string;
39
+ };
40
+ up: {
41
+ label: string;
42
+ spokenLabel: string;
43
+ };
44
+ down: {
45
+ label: string;
46
+ spokenLabel: string;
47
+ };
48
+ left: {
49
+ label: string;
50
+ spokenLabel: string;
51
+ };
52
+ right: {
53
+ label: string;
54
+ spokenLabel: string;
55
+ };
56
+ updown: {
57
+ label: string;
58
+ spokenLabel: string;
59
+ };
60
+ };
61
+ export declare const WINDOWS_KEYS: {
62
+ cmd: {
63
+ label: string;
64
+ };
65
+ meta: {
66
+ label: string;
67
+ };
68
+ ctrl: {
69
+ label: string;
70
+ };
71
+ alt: {
72
+ label: string;
73
+ };
74
+ shift: {
75
+ label: string;
76
+ };
77
+ enter: {
78
+ label: string;
79
+ };
80
+ esc: {
81
+ label: string;
82
+ };
83
+ backspace: {
84
+ label: string;
85
+ };
86
+ tab: {
87
+ label: string;
88
+ };
89
+ up: {
90
+ label: string;
91
+ spokenLabel: string;
92
+ };
93
+ down: {
94
+ label: string;
95
+ spokenLabel: string;
96
+ };
97
+ left: {
98
+ label: string;
99
+ spokenLabel: string;
100
+ };
101
+ right: {
102
+ label: string;
103
+ spokenLabel: string;
104
+ };
105
+ updown: {
106
+ label: string;
107
+ spokenLabel: string;
108
+ };
109
+ };
110
+ export type KbdPlatform = "macOs" | "windows";
111
+ export type KbdProps = {
112
+ /** Semantic key name(s) to display, e.g. `"A"` or `["shift", "cmd"]`. Recognised names (`cmd`, `ctrl`, `alt`, `shift`, `enter`, `esc`, `backspace`, `tab`, `up`, `down`, `left`, `right`, `updown`) render the symbol for the detected platform; any other value is rendered as written, with a single character uppercased. */
113
+ keys: string | string[];
114
+ /** Pins the rendered symbols to one platform instead of detecting the user's. Use for tests, stories, and shortcuts that only exist on one platform. */
115
+ platform?: KbdPlatform;
116
+ "data-e2e-test-id"?: string;
117
+ };
118
+ export declare function Kbd({ keys, platform, "data-e2e-test-id": dataE2eTestId, }: KbdProps): React.ReactElement;
@@ -0,0 +1 @@
1
+ import React from"react";import styled from"@emotion/styled";import{useIsMacOs}from"../../shared/useIsMacOs";import{ScreenReaderText}from"../Utilities/ScreenReaderText/ScreenReaderText";export const MAC_OS_KEYS={cmd:{label:"⌘",spokenLabel:"Command"},meta:{label:"⌘",spokenLabel:"Command"},ctrl:{label:"⌃",spokenLabel:"Control"},alt:{label:"⌥",spokenLabel:"Option"},shift:{label:"⇧",spokenLabel:"Shift"},enter:{label:"↩",spokenLabel:"Enter"},esc:{label:"Esc"},backspace:{label:"⌫",spokenLabel:"Backspace"},tab:{label:"⇥",spokenLabel:"Tab"},up:{label:"↑",spokenLabel:"Up arrow"},down:{label:"↓",spokenLabel:"Down arrow"},left:{label:"←",spokenLabel:"Left arrow"},right:{label:"→",spokenLabel:"Right arrow"},updown:{label:"⇅",spokenLabel:"Up and down arrows"}};export const WINDOWS_KEYS={cmd:{label:"Ctrl"},meta:{label:"Ctrl"},ctrl:{label:"Ctrl"},alt:{label:"Alt"},shift:{label:"Shift"},enter:{label:"Enter"},esc:{label:"Esc"},backspace:{label:"Backspace"},tab:{label:"Tab"},up:{label:"↑",spokenLabel:"Up arrow"},down:{label:"↓",spokenLabel:"Down arrow"},left:{label:"←",spokenLabel:"Left arrow"},right:{label:"→",spokenLabel:"Right arrow"},updown:{label:"⇅",spokenLabel:"Up and down arrows"}};let StyledKbd=styled("kbd",{target:"e1v9oi190",label:"StyledKbd"})(({theme})=>({display:"inline-flex",alignItems:"center",justifyContent:"center",boxSizing:"border-box",minWidth:theme.variables.size.dimension.kbd.minWidth,padding:theme.variables.size.spacing.xxxs,border:`1px solid ${theme.values.color.kbd.border.default}`,borderRadius:theme.variables.size.borderRadius.xs,backgroundColor:theme.values.color.kbd.background.default,color:theme.values.color.kbd.foreground.default,fontFamily:theme.variables.fontFamily.lato,fontSize:theme.variables.size.font.xxs,fontWeight:theme.variables.weight.normal,lineHeight:1,whiteSpace:"nowrap",cursor:"default",userSelect:"none"})),StyledKbdKeys=styled("span",{target:"e1v9oi191",label:"StyledKbdKeys"})(({theme,hasSeparators})=>({display:"inline-flex",gap:hasSeparators?theme.variables.size.spacing.xxs:theme.variables.size.spacing.zero})),toDisplayLabel=key=>1===key.length?key.toUpperCase():key,toKeyDisplay=(key,isMacOs)=>{let trimmedKey=key.trim();return(isMacOs?MAC_OS_KEYS:WINDOWS_KEYS)[trimmedKey.toLowerCase()]??{label:toDisplayLabel(trimmedKey)}};export function Kbd({keys,platform,"data-e2e-test-id":dataE2eTestId}){let detectedIsMacOs=useIsMacOs(),isMacOs=platform?"macOs"===platform:detectedIsMacOs,keyDisplays=(Array.isArray(keys)?keys:[keys]).map(key=>toKeyDisplay(key,isMacOs)),spokenKeys=keyDisplays.map(({label,spokenLabel})=>spokenLabel??label).join(" ");return React.createElement(StyledKbd,{"data-e2e-test-id":dataE2eTestId,"data-ds-id":"Kbd"},React.createElement(StyledKbdKeys,{"aria-hidden":"true",hasSeparators:!isMacOs&&keyDisplays.length>1},keyDisplays.map(({label},index)=>React.createElement(React.Fragment,{key:`${label}-${index}`},index>0&&!isMacOs&&React.createElement("span",null,"+"),React.createElement("span",null,label)))),React.createElement(ScreenReaderText,{as:"span"},spokenKeys))}
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ export type KbdGroupProps = {
3
+ /** The `Kbd` elements making up the sequence, in the order they are pressed. */
4
+ children: React.ReactNode;
5
+ "data-e2e-test-id"?: string;
6
+ };
7
+ export declare function KbdGroup({ children, "data-e2e-test-id": dataE2eTestId, }: KbdGroupProps): React.ReactElement;
@@ -0,0 +1 @@
1
+ import React from"react";import styled from"@emotion/styled";let StyledKbdGroup=styled("span",{target:"e1mlf86z0",label:"StyledKbdGroup"})(({theme})=>({display:"inline-flex",alignItems:"flex-start",gap:theme.variables.size.spacing.xxs}));export function KbdGroup({children,"data-e2e-test-id":dataE2eTestId}){return React.createElement(StyledKbdGroup,{"data-e2e-test-id":dataE2eTestId,"data-ds-id":"KbdGroup"},children)}
@@ -289,7 +289,12 @@ export type SidePanelProps = ForwardedScrollProps & {
289
289
  /** Accessible name; when set, the panel renders as a `region` landmark. */
290
290
  "aria-label"?: string;
291
291
  collapsible?: boolean;
292
- /** Number = pixels, unitless string = percent (e.g. `"30%"`). */
292
+ /** Number = pixels, unitless string = percent (e.g. `"30%"`).
293
+ *
294
+ * Either unit sets the column's starting width only: a docked side panel
295
+ * then keeps that width when the window resizes, and `Layout.Content` grows
296
+ * and shrinks around it. Drag-resizing is a separate story - see
297
+ * `resizable`. */
293
298
  defaultSize?: Size;
294
299
  minSize?: Size;
295
300
  maxSize?: Size;