@orfium/ictinus 5.43.2 → 5.43.3

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.
@@ -1,16 +1,16 @@
1
1
 
2
- > @orfium/ictinus@5.43.2 build /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
2
+ > @orfium/ictinus@5.43.3 build /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
3
3
  > pnpm build:main && pnpm build:codemods && pnpm build:vanilla
4
4
 
5
5
 
6
- > @orfium/ictinus@5.43.2 build:main /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
6
+ > @orfium/ictinus@5.43.3 build:main /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
7
7
  > vite build --mode production
8
8
 
9
9
  production /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
10
10
  vite v7.3.1 building client environment for production...
11
11
  production /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
12
12
  transforming...
13
- ✓ 804 modules transformed.
13
+ ✓ 806 modules transformed.
14
14
  rendering chunks...
15
15
 
16
16
  [vite:dts] Start generate declaration files...
@@ -52,10 +52,10 @@ computing gzip size...
52
52
  dist/components/Table/components/TBody/TBody.style.js  0.29 kB │ gzip: 0.21 kB
53
53
  dist/hooks/useEscape.js  0.29 kB │ gzip: 0.19 kB
54
54
  dist/hooks/useCombinedRefs.js  0.29 kB │ gzip: 0.20 kB
55
- dist/components/Controls/ControlLabel/ControlHelpText.js  0.30 kB │ gzip: 0.24 kB
56
55
  dist/components/Icon/assets/usersAndStatus/statusIndicator.svg.js  0.30 kB │ gzip: 0.23 kB
57
- dist/components/Breadcrumb/Breadcrumb.style.js  0.30 kB │ gzip: 0.23 kB
56
+ dist/components/Controls/ControlLabel/ControlHelpText.js  0.30 kB │ gzip: 0.24 kB
58
57
  dist/components/Chart/Wrapper.js  0.30 kB │ gzip: 0.21 kB
58
+ dist/components/Breadcrumb/Breadcrumb.style.js  0.30 kB │ gzip: 0.23 kB
59
59
  dist/components/TableV4/components/RenderRowOrNestedRow/components/ContentCell/ContentCell.style.js  0.30 kB │ gzip: 0.24 kB
60
60
  dist/components/Tabs/components/TabsContainer/TabsContainer.style.js  0.31 kB │ gzip: 0.22 kB
61
61
  dist/components/TableV4/components/TableCell/utils.js  0.31 kB │ gzip: 0.23 kB
@@ -207,8 +207,8 @@ computing gzip size...
207
207
  dist/components/Search/StatefulSearch.js  0.89 kB │ gzip: 0.48 kB
208
208
  dist/components/Slider/components/SliderMark/SliderMark.js  0.89 kB │ gzip: 0.50 kB
209
209
  dist/components/Icon/assets/musicBusiness/recording.svg.js  0.90 kB │ gzip: 0.53 kB
210
- dist/components/TopAppBar/TopAppBar.style.js  0.91 kB │ gzip: 0.46 kB
211
210
  dist/components/Icon/assets/generic/search filled.svg.js  0.91 kB │ gzip: 0.48 kB
211
+ dist/components/TopAppBar/TopAppBar.style.js  0.91 kB │ gzip: 0.46 kB
212
212
  dist/icons/LicenseIcon.js  0.91 kB │ gzip: 0.54 kB
213
213
  dist/components/Icon/assets/audioControls/rewind.svg.js  0.91 kB │ gzip: 0.48 kB
214
214
  dist/components/Icon/Icon.style.js  0.91 kB │ gzip: 0.48 kB
@@ -394,8 +394,8 @@ computing gzip size...
394
394
  dist/components/Icon/assets/musicBusiness/artist.svg.js  1.54 kB │ gzip: 0.81 kB
395
395
  dist/components/Drawer/Drawer.js  1.55 kB │ gzip: 0.70 kB
396
396
  dist/icons/DigitalIcon.js  1.55 kB │ gzip: 0.78 kB
397
- dist/components/Table/components/OptimizedTableRow.js  1.55 kB │ gzip: 0.73 kB
398
397
  dist/components/Controls/Switch/Switch.style.js  1.55 kB │ gzip: 0.72 kB
398
+ dist/components/Table/components/OptimizedTableRow.js  1.55 kB │ gzip: 0.73 kB
399
399
  dist/icons/ConflictIcon.js  1.55 kB │ gzip: 0.86 kB
400
400
  dist/icons/AssetIcon.js  1.58 kB │ gzip: 0.85 kB
401
401
  dist/icons/LockIcon.js  1.59 kB │ gzip: 0.81 kB
@@ -605,11 +605,11 @@ computing gzip size...
605
605
  dist/icon/Icon.js  11.30 kB │ gzip: 2.63 kB
606
606
  dist/index.js  13.17 kB │ gzip: 3.18 kB
607
607
  dist/sprinkles/properties.css.js 115.20 kB │ gzip: 14.54 kB
608
- [vite:dts] Declaration files built in 10187ms.
608
+ [vite:dts] Declaration files built in 10065ms.
609
609
 
610
- ✓ built in 14.64s
610
+ ✓ built in 14.38s
611
611
 
612
- > @orfium/ictinus@5.43.2 build:codemods /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
612
+ > @orfium/ictinus@5.43.3 build:codemods /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
613
613
  > vite build --config vite.codemods.config.ts
614
614
 
615
615
  vite v7.3.1 building client environment for production...
@@ -642,11 +642,11 @@ computing gzip size...
642
642
  dist/codemods/drawerCodemod.cjs 1.07 kB │ gzip: 0.42 kB
643
643
  dist/codemods/unchangedIconsCodemod.cjs 1.12 kB │ gzip: 0.56 kB
644
644
  dist/codemods/globalsCodemod.cjs 6.99 kB │ gzip: 1.11 kB
645
- [vite:dts] Declaration files built in 815ms.
645
+ [vite:dts] Declaration files built in 778ms.
646
646
 
647
- ✓ built in 995ms
647
+ ✓ built in 953ms
648
648
 
649
- > @orfium/ictinus@5.43.2 build:vanilla /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
649
+ > @orfium/ictinus@5.43.3 build:vanilla /home/runner/work/orfium-ictinus/orfium-ictinus/packages/ictinus
650
650
  > rm -rf dist/vanilla && NODE_ENV=production rollup -c
651
651
 
652
652
  
@@ -657,4 +657,4 @@ computing gzip size...
657
657
  (!) Unresolved dependencies
658
658
  https://rollupjs.org/troubleshooting/#warning-treating-module-as-external-dependency
659
659
  csstype (imported by "node_modules/@vanilla-extract/css/dist/vanilla-extract-css.cjs.d.ts")
660
- created dist/vanilla in 3.3s
660
+ created dist/vanilla in 3.4s
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @orfium/ictinus
2
2
 
3
+ ## 5.43.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 9e38725: table counter + bulk actions
8
+
3
9
  ## 5.43.2
4
10
 
5
11
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  declare const _default: {
2
2
  "name": "@orfium/ictinus",
3
- "version": "5.43.2",
3
+ "version": "5.43.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.umd.cjs",
6
6
  "module": "./dist/index.js",
@@ -1,4 +1,4 @@
1
- const o = "5.43.2";
1
+ const o = "5.43.3";
2
2
  export {
3
3
  o as version
4
4
  };
@@ -1,5 +1,10 @@
1
1
  import { default as React } from 'react';
2
2
  import { StyledBoxProps } from './Box.types';
3
3
  export type BoxProps = StyledBoxProps & React.HTMLAttributes<HTMLDivElement>;
4
+ /**
5
+ *
6
+ * @deprecated {@link Box} has been deprecated; use vanilla Box instead.
7
+ *
8
+ */
4
9
  declare const Box: React.ForwardRefExoticComponent<StyledBoxProps & React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
5
10
  export default Box;
@@ -1,5 +1,10 @@
1
1
  import { NoUndefined } from '.';
2
2
  import { TableProps } from './types';
3
+ /**
4
+ *
5
+ * @deprecated {@link Table} has been deprecated; use DataTable instead.
6
+ *
7
+ */
3
8
  declare const Table: <TData extends NoUndefined<TData>>({ type, rowsConfig, data, columns, rowSize, columnsConfig, sorting, hasStickyHeader, pagination, sx, dataTestPrefixId, }: TableProps<TData>) => import("@emotion/react/jsx-runtime").JSX.Element;
4
9
  declare const _default: typeof Table;
5
10
  export default _default;
@@ -24,5 +24,10 @@ export type TypographyProps = {
24
24
  id?: string;
25
25
  };
26
26
  export declare const detectComponentBasedOnType: (variant: TypographyVariant) => TypographyComponent;
27
+ /**
28
+ *
29
+ * @deprecated {@link Typography} has been deprecated; use vanilla Text instead.
30
+ *
31
+ */
27
32
  declare const Typography: React.ForwardRefExoticComponent<TypographyProps & React.RefAttributes<HTMLHeadingElement>>;
28
33
  export default Typography;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { BoxProps } from '../vanilla/Box';
2
+ export type DataTableBulkActionsProps = BoxProps<'div'>;
3
+ export declare function DataTableBulkActions({ children, ...props }: DataTableBulkActionsProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { BoxProps } from '../vanilla/Box';
2
+ export type DataTableCounterProps = BoxProps<'div', {
3
+ count?: number;
4
+ singular?: string;
5
+ plural?: string;
6
+ }>;
7
+ export declare function DataTableCounter({ count: countProp, singular, plural, ...props }: DataTableCounterProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,5 +1,7 @@
1
1
  export * from './DataTable';
2
2
  export * from './DataTableBody';
3
+ export * from './DataTableBulkActions';
3
4
  export * from './DataTableCheckbox';
5
+ export * from './DataTableCounter';
4
6
  export * from './DataTableEditColumns';
5
7
  export * from './DataTableHeader';
@@ -1706,6 +1706,9 @@ declare const DataTableBody: react.ForwardRefExoticComponent<{
1706
1706
  className?: string;
1707
1707
  }>, "size"> & Omit<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "color" | "className"> & react.RefAttributes<HTMLDivElement>>;
1708
1708
 
1709
+ type DataTableBulkActionsProps = BoxProps<'div'>;
1710
+ declare function DataTableBulkActions({ children, ...props }: DataTableBulkActionsProps): _emotion_react_jsx_runtime.JSX.Element;
1711
+
1709
1712
  declare const CheckBox: react__default.ForwardRefExoticComponent<any>;
1710
1713
 
1711
1714
  type DataTableCheckboxProps = ComponentPropsWithoutRef<typeof CheckBox>;
@@ -1714,6 +1717,13 @@ type DataTableCheckboxProps = ComponentPropsWithoutRef<typeof CheckBox>;
1714
1717
  */
1715
1718
  declare const DataTableCheckbox: react.ForwardRefExoticComponent<any>;
1716
1719
 
1720
+ type DataTableCounterProps = BoxProps<'div', {
1721
+ count?: number;
1722
+ singular?: string;
1723
+ plural?: string;
1724
+ }>;
1725
+ declare function DataTableCounter({ count: countProp, singular, plural, ...props }: DataTableCounterProps): _emotion_react_jsx_runtime.JSX.Element;
1726
+
1717
1727
  declare function DataTableEditColumns(): _emotion_react_jsx_runtime.JSX.Element;
1718
1728
 
1719
1729
  type DataTableHeaderProps = BoxProps;
@@ -6164,5 +6174,5 @@ declare namespace TooltipTrigger {
6164
6174
  var displayName: string;
6165
6175
  }
6166
6176
 
6167
- export { AccountIcon, AlbumIcon, AnalyticsIcon, AppsIcon, ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, ArtistIcon, AssetIcon, AudioIcon, AudioOffIcon, BookmarkIcon, BookmarkOffIcon, Box, BroadcastIcon, CalendarIcon, CatalogIcon, ChannelIcon, ChatIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, CinemaIcon, ClaimIcon, CloseIcon, ColumnChooserIcon, CompositionIcon, ConcertIcon, ConflictIcon, ConvertIcon, CopyIcon, CueSheetIcon, DashboardIcon, DataTable, DataTableBody, DataTableCheckbox, DataTableEditColumns, DataTableHeader, DatasetIcon, DeleteIcon, DeliveryIcon, DetailsIcon, Dialog, DialogBody, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DigitalIcon, DistributionIcon, DownloadIcon, EarningsIcon, EditIcon, EntitiesIcon, ErrorIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FavoriteIcon, FavoriteOffIcon, FileIcon, FilterIcon, FlagIcon, FlagOffIcon, ForwardIcon, FreezeIcon, HelpIcon, ICONS, Icon, ImageIcon, ImageOffIcon, IncomeIcon, InformationalIcon, InsightIcon, InvoiceIcon, IssueIcon, KeywordIcon, LanguageIcon, LegalIcon, LicenseIcon, LinkIcon, LocationIcon, LockIcon, LoginIcon, LogoutIcon, MailIcon, ManualIcon, MediaFileIcon, Menu, MenuContent, MenuDescription, MenuHeader, MenuIcon, MenuItem, MenuLabel, MenuSection, MenuSeparator, MenuSubmenu, MenuTrigger, MinusIcon, MoreOptionsIcon, NextIcon, NotificationIcon, OrganizationIcon, PageFirstIcon, PageLastIcon, PairIcon, PauseIcon, PendingIcon, PlayIcon, PlaycountIcon, PlusIcon, PolicyIcon, Popover, PopoverBody, PopoverContent, PopoverDescription, PopoverFooter, PopoverHeader, PopoverTitle, PopoverTrigger, PreviousIcon, PublicPerformanceIcon, PublisherIcon, RadioIcon, RecordLabelIcon, RecordingIcon, RedoIcon, RefreshIcon, ReportIcon, RestoreIcon, ResumeIcon, ReviewIcon, RewindIcon, RoleIcon, SearchFilledIcon, SearchIcon, SettingsIcon, ShareIcon, SortAscendingIcon, SortDescendingIcon, SortIcon, StatusIndicatorIcon, StopIcon, SuccessIcon, Table, TableBody, TableCell, TableFooter, TableHeader, TableHeaderCell, TableRow, TagIcon, TelevisionIcon, Text, ThemeProvider, ThumbsDownIcon, ThumbsUpIcon, Tooltip, TooltipContent, TooltipTrigger, TrendingDownIcon, TrendingUpIcon, TriangleDownIcon, TriangleLeftIcon, TriangleRightIcon, TriangleUpIcon, UndoIcon, UnfreezeIcon, UnlinkIcon, UnlockIcon, UnpairIcon, UnverifiedIcon, UpdateIcon, UploadIcon, UsageIcon, UserIcon, UsersIcon, VerifiedIcon, VideoIcon, VideoOffIcon, WarningIcon, WorkIcon, WriterIcon, YouTubeIcon, extractBoxProps, useTheme };
6168
- export type { BoxProps, DataTableBodyProps, DataTableCheckboxProps, DataTableHeaderProps, DataTableProps, DialogBodyProps, DialogDescriptionProps, DialogFooterProps, DialogHeaderProps, DialogTitleProps, IconProps, MenuContentProps, MenuHeaderProps, MenuItemProps, MenuSectionProps, MenuTriggerProps, PopoverContentProps, PopoverProps, TableBodyProps, TableCellProps, TableFooterProps, TableHeaderCellProps, TableHeaderProps, TableProps, TableRowProps, TextProps, TooltipContentProps, TooltipProps };
6177
+ export { AccountIcon, AlbumIcon, AnalyticsIcon, AppsIcon, ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, ArtistIcon, AssetIcon, AudioIcon, AudioOffIcon, BookmarkIcon, BookmarkOffIcon, Box, BroadcastIcon, CalendarIcon, CatalogIcon, ChannelIcon, ChatIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, CinemaIcon, ClaimIcon, CloseIcon, ColumnChooserIcon, CompositionIcon, ConcertIcon, ConflictIcon, ConvertIcon, CopyIcon, CueSheetIcon, DashboardIcon, DataTable, DataTableBody, DataTableBulkActions, DataTableCheckbox, DataTableCounter, DataTableEditColumns, DataTableHeader, DatasetIcon, DeleteIcon, DeliveryIcon, DetailsIcon, Dialog, DialogBody, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DigitalIcon, DistributionIcon, DownloadIcon, EarningsIcon, EditIcon, EntitiesIcon, ErrorIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FavoriteIcon, FavoriteOffIcon, FileIcon, FilterIcon, FlagIcon, FlagOffIcon, ForwardIcon, FreezeIcon, HelpIcon, ICONS, Icon, ImageIcon, ImageOffIcon, IncomeIcon, InformationalIcon, InsightIcon, InvoiceIcon, IssueIcon, KeywordIcon, LanguageIcon, LegalIcon, LicenseIcon, LinkIcon, LocationIcon, LockIcon, LoginIcon, LogoutIcon, MailIcon, ManualIcon, MediaFileIcon, Menu, MenuContent, MenuDescription, MenuHeader, MenuIcon, MenuItem, MenuLabel, MenuSection, MenuSeparator, MenuSubmenu, MenuTrigger, MinusIcon, MoreOptionsIcon, NextIcon, NotificationIcon, OrganizationIcon, PageFirstIcon, PageLastIcon, PairIcon, PauseIcon, PendingIcon, PlayIcon, PlaycountIcon, PlusIcon, PolicyIcon, Popover, PopoverBody, PopoverContent, PopoverDescription, PopoverFooter, PopoverHeader, PopoverTitle, PopoverTrigger, PreviousIcon, PublicPerformanceIcon, PublisherIcon, RadioIcon, RecordLabelIcon, RecordingIcon, RedoIcon, RefreshIcon, ReportIcon, RestoreIcon, ResumeIcon, ReviewIcon, RewindIcon, RoleIcon, SearchFilledIcon, SearchIcon, SettingsIcon, ShareIcon, SortAscendingIcon, SortDescendingIcon, SortIcon, StatusIndicatorIcon, StopIcon, SuccessIcon, Table, TableBody, TableCell, TableFooter, TableHeader, TableHeaderCell, TableRow, TagIcon, TelevisionIcon, Text, ThemeProvider, ThumbsDownIcon, ThumbsUpIcon, Tooltip, TooltipContent, TooltipTrigger, TrendingDownIcon, TrendingUpIcon, TriangleDownIcon, TriangleLeftIcon, TriangleRightIcon, TriangleUpIcon, UndoIcon, UnfreezeIcon, UnlinkIcon, UnlockIcon, UnpairIcon, UnverifiedIcon, UpdateIcon, UploadIcon, UsageIcon, UserIcon, UsersIcon, VerifiedIcon, VideoIcon, VideoOffIcon, WarningIcon, WorkIcon, WriterIcon, YouTubeIcon, extractBoxProps, useTheme };
6178
+ export type { BoxProps, DataTableBodyProps, DataTableBulkActionsProps, DataTableCheckboxProps, DataTableCounterProps, DataTableHeaderProps, DataTableProps, DialogBodyProps, DialogDescriptionProps, DialogFooterProps, DialogHeaderProps, DialogTitleProps, IconProps, MenuContentProps, MenuHeaderProps, MenuItemProps, MenuSectionProps, MenuTriggerProps, PopoverContentProps, PopoverProps, TableBodyProps, TableCellProps, TableFooterProps, TableHeaderCellProps, TableHeaderProps, TableProps, TableRowProps, TextProps, TooltipContentProps, TooltipProps };
@@ -1,6 +1,8 @@
1
1
  export { DataTable } from './src/data-table/DataTable.js';
2
2
  export { DataTableBody } from './src/data-table/DataTableBody.js';
3
+ export { DataTableBulkActions } from './src/data-table/DataTableBulkActions.js';
3
4
  export { DataTableCheckbox } from './src/data-table/DataTableCheckbox.js';
5
+ export { DataTableCounter } from './src/data-table/DataTableCounter.js';
4
6
  export { DataTableEditColumns } from './src/data-table/DataTableEditColumns.js';
5
7
  export { DataTableHeader } from './src/data-table/DataTableHeader.js';
6
8
  export { ICONS, Icon } from './src/icon/Icon.js';
@@ -1,3 +1,3 @@
1
- var version = "5.43.2";
1
+ var version = "5.43.3";
2
2
 
3
3
  export { version };
@@ -0,0 +1,13 @@
1
+ import { jsx } from '@emotion/react/jsx-runtime';
2
+ import { Box } from '../../Box/Box.js';
3
+ import '../sprinkles/sprinkles.js';
4
+ import { useDataTableContext } from './DataTableContext.js';
5
+
6
+ function DataTableBulkActions({ children, ...props }) {
7
+ const { table } = useDataTableContext();
8
+ const hasSelection = table.getSelectedRowModel().rows.length > 0;
9
+ if (!hasSelection) return null;
10
+ return /* @__PURE__ */ jsx(Box, { display: "flex", alignItems: "center", gap: "sm", ...props, children });
11
+ }
12
+
13
+ export { DataTableBulkActions };
@@ -0,0 +1,25 @@
1
+ import { jsxs, jsx } from '@emotion/react/jsx-runtime';
2
+ import { Box } from '../../Box/Box.js';
3
+ import '../sprinkles/sprinkles.js';
4
+ import { Text } from '../../Text/Text.js';
5
+ import { useDataTableContext } from './DataTableContext.js';
6
+
7
+ function DataTableCounter({
8
+ count: countProp,
9
+ singular = "item",
10
+ plural = "items",
11
+ ...props
12
+ }) {
13
+ const { table } = useDataTableContext();
14
+ const selectedCount = table.getSelectedRowModel().rows.length;
15
+ const totalCount = countProp ?? table.getRowCount();
16
+ const hasSelection = selectedCount > 0;
17
+ const count = hasSelection ? selectedCount : totalCount;
18
+ const label = count === 1 ? singular : plural;
19
+ return /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "sm", ...props, children: [
20
+ /* @__PURE__ */ jsx(Text, { typography: "label02", color: "active", children: count.toLocaleString() }),
21
+ /* @__PURE__ */ jsx(Text, { typography: "label02", children: hasSelection ? `${label} selected` : label })
22
+ ] });
23
+ }
24
+
25
+ export { DataTableCounter };
@@ -49,7 +49,7 @@ function DataTableEditColumns() {
49
49
  children: allColumns.map((column) => {
50
50
  const canHide = column.getCanHide();
51
51
  const isSelected = canHide ? selectedColumns.has(column.id) : true;
52
- const label = column.columnDef.meta?.label;
52
+ const label = column.columnDef.meta?.label ?? (typeof column.columnDef.header === "string" ? column.columnDef.header : void 0);
53
53
  if (!label) {
54
54
  return null;
55
55
  }
@@ -36,7 +36,7 @@ const DataTableHeaderCell = forwardRef(
36
36
  ref,
37
37
  "data-test": true,
38
38
  ...props,
39
- children: typeof children !== "string" || !header.column.getCanSort() ? children : /* @__PURE__ */ jsxs(
39
+ children: typeof children === "string" ? /* @__PURE__ */ jsxs(
40
40
  Box,
41
41
  {
42
42
  display: "flex",
@@ -84,7 +84,7 @@ const DataTableHeaderCell = forwardRef(
84
84
  /* @__PURE__ */ jsx(TooltipTrigger, { children: /* @__PURE__ */ jsx(Box, { display: "flex", alignItems: "center", justifyContent: "center", size: "3", children: /* @__PURE__ */ jsx(Icon, { name: "informational", size: "xs", color: "secondary" }) }) }),
85
85
  /* @__PURE__ */ jsx(TooltipContent, { maxW: "22", children: header.column.columnDef.meta.tooltip })
86
86
  ] }),
87
- /* @__PURE__ */ jsxs(
87
+ header.column.getCanSort() && /* @__PURE__ */ jsxs(
88
88
  ActionsContent,
89
89
  {
90
90
  display: "grid",
@@ -117,19 +117,21 @@ const DataTableHeaderCell = forwardRef(
117
117
  }
118
118
  )
119
119
  ] }),
120
- /* @__PURE__ */ jsx(ActionsContent, { visible: sortDir ? "always" : "if-needed", children: /* @__PURE__ */ jsxs(Menu, { children: [
120
+ (header.column.getCanSort() || header.column.getCanPin()) && /* @__PURE__ */ jsx(ActionsContent, { visible: sortDir ? "always" : "if-needed", children: /* @__PURE__ */ jsxs(Menu, { children: [
121
121
  /* @__PURE__ */ jsx(MenuTrigger, { children: /* @__PURE__ */ jsx(IconButton, { type: "tertiary", size: "compact", iconName: "moreOptions" }) }),
122
122
  /* @__PURE__ */ jsxs(MenuContent, { style: { minWidth: "220px" }, children: [
123
- /* @__PURE__ */ jsx(MenuItem, { onAction: () => header.column.toggleSorting(true), children: /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "sm", children: [
124
- /* @__PURE__ */ jsx(Icon, { name: "sortDescending" }),
125
- /* @__PURE__ */ jsx(Text, { typography: "body03", children: "Sort descending (z-a)" })
126
- ] }) }),
127
- /* @__PURE__ */ jsx(MenuItem, { onAction: () => header.column.toggleSorting(false), children: /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "sm", children: [
128
- /* @__PURE__ */ jsx(Icon, { name: "sortAscending" }),
129
- /* @__PURE__ */ jsx(Text, { typography: "body03", children: "Sort ascending (a-z)" })
130
- ] }) }),
123
+ header.column.getCanSort() && /* @__PURE__ */ jsxs(Fragment, { children: [
124
+ /* @__PURE__ */ jsx(MenuItem, { onAction: () => header.column.toggleSorting(true), children: /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "sm", children: [
125
+ /* @__PURE__ */ jsx(Icon, { name: "sortDescending" }),
126
+ /* @__PURE__ */ jsx(Text, { typography: "body03", children: "Sort descending (z-a)" })
127
+ ] }) }),
128
+ /* @__PURE__ */ jsx(MenuItem, { onAction: () => header.column.toggleSorting(false), children: /* @__PURE__ */ jsxs(Box, { display: "flex", alignItems: "center", gap: "sm", children: [
129
+ /* @__PURE__ */ jsx(Icon, { name: "sortAscending" }),
130
+ /* @__PURE__ */ jsx(Text, { typography: "body03", children: "Sort ascending (a-z)" })
131
+ ] }) })
132
+ ] }),
131
133
  header.column.getCanPin() && /* @__PURE__ */ jsxs(Fragment, { children: [
132
- /* @__PURE__ */ jsx(MenuSeparator, {}),
134
+ header.column.getCanSort() && /* @__PURE__ */ jsx(MenuSeparator, {}),
133
135
  /* @__PURE__ */ jsx(
134
136
  MenuItem,
135
137
  {
@@ -177,7 +179,7 @@ const DataTableHeaderCell = forwardRef(
177
179
  ] }) })
178
180
  ]
179
181
  }
180
- )
182
+ ) : children
181
183
  }
182
184
  ) });
183
185
  }
package/eslint.config.mjs CHANGED
@@ -111,7 +111,7 @@ export default defineConfig([
111
111
  ],
112
112
 
113
113
  'react/prop-types': 'off',
114
- 'react/button-has-type': 'warn',
114
+ 'react/button-has-type': 'off',
115
115
  '@typescript-eslint/no-explicit-any': 'off',
116
116
  'react/no-array-index-key': 'warn',
117
117
  'react/no-render-return-value': 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orfium/ictinus",
3
- "version": "5.43.2",
3
+ "version": "5.43.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.umd.cjs",
6
6
  "module": "./dist/index.js",
@@ -10,6 +10,11 @@ import { cssResolver, omitedCSSprops, pickCSSProperties, pickNonCSSProps } from
10
10
 
11
11
  export type BoxProps = StyledBoxProps & React.HTMLAttributes<HTMLDivElement>;
12
12
 
13
+ /**
14
+ *
15
+ * @deprecated {@link Box} has been deprecated; use vanilla Box instead.
16
+ *
17
+ */
13
18
  const Box = forwardRef<HTMLDivElement, BoxProps>(({ children, ...rest }, ref) => {
14
19
  const theme = useTheme();
15
20
  const cssPropsOnly = pickCSSProperties(rest);
@@ -13,6 +13,11 @@ import useTable from './hooks/useTable';
13
13
  import { tableContainer, tableStyles } from './Table.style';
14
14
  import type { TableProps } from './types';
15
15
 
16
+ /**
17
+ *
18
+ * @deprecated {@link Table} has been deprecated; use DataTable instead.
19
+ *
20
+ */
16
21
  const Table = <TData extends NoUndefined<TData>>({
17
22
  type = 'read-only',
18
23
  rowsConfig,
@@ -59,6 +59,11 @@ export const detectComponentBasedOnType = (variant: TypographyVariant): Typograp
59
59
  return 'p';
60
60
  };
61
61
 
62
+ /**
63
+ *
64
+ * @deprecated {@link Typography} has been deprecated; use vanilla Text instead.
65
+ *
66
+ */
62
67
  // display name breaks storybook props
63
68
  // https://github.com/storybookjs/storybook/issues/13304
64
69
  // eslint-disable-next-line react/display-name
@@ -0,0 +1,425 @@
1
+ import {
2
+ type ColumnDef,
3
+ createColumnHelper,
4
+ getCoreRowModel,
5
+ getSortedRowModel,
6
+ type RowSelectionState,
7
+ useReactTable,
8
+ type VisibilityState,
9
+ } from '@tanstack/react-table';
10
+ import userEvent from '@testing-library/user-event';
11
+ import { type ReactNode, useState } from 'react';
12
+ import { render, screen } from '../test';
13
+ import { DataTable } from './DataTable';
14
+ import { DataTableBody } from './DataTableBody';
15
+ import { DataTableBulkActions } from './DataTableBulkActions';
16
+ import { DataTableCounter } from './DataTableCounter';
17
+ import { DataTableEditColumns } from './DataTableEditColumns';
18
+ import { DataTableHeader } from './DataTableHeader';
19
+
20
+ type Person = {
21
+ firstName: string;
22
+ lastName: string;
23
+ age: number;
24
+ };
25
+
26
+ const testData: Person[] = [
27
+ { firstName: 'Alice', lastName: 'Smith', age: 25 },
28
+ { firstName: 'Bob', lastName: 'Jones', age: 30 },
29
+ { firstName: 'Charlie', lastName: 'Brown', age: 35 },
30
+ ];
31
+
32
+ const columnHelper = createColumnHelper<Person>();
33
+
34
+ const simpleColumns: ColumnDef<Person, any>[] = [
35
+ columnHelper.accessor('firstName', {
36
+ header: 'First Name',
37
+ meta: { label: 'First Name' },
38
+ enableHiding: false,
39
+ }),
40
+ columnHelper.accessor('lastName', {
41
+ header: 'Last Name',
42
+ meta: { label: 'Last Name' },
43
+ }),
44
+ columnHelper.accessor('age', {
45
+ header: 'Age',
46
+ meta: { label: 'Age' },
47
+ }),
48
+ ];
49
+
50
+ /**
51
+ * A wrapper component that creates a `useReactTable` instance and renders
52
+ * DataTable with the provided children. Props allow controlling initial state.
53
+ */
54
+ function DataTableFixture({
55
+ children,
56
+ data = testData,
57
+ columns = simpleColumns,
58
+ enableRowSelection = true,
59
+ enableSorting = true,
60
+ initialRowSelection = {},
61
+ initialVisibility = {},
62
+ }: {
63
+ children: ReactNode;
64
+ data?: Person[];
65
+ columns?: ColumnDef<Person, any>[];
66
+ enableRowSelection?: boolean;
67
+ enableSorting?: boolean;
68
+ initialRowSelection?: RowSelectionState;
69
+ initialVisibility?: VisibilityState;
70
+ }) {
71
+ const [rowSelection, setRowSelection] = useState<RowSelectionState>(initialRowSelection);
72
+ const [columnVisibility, setColumnVisibility] = useState<VisibilityState>(initialVisibility);
73
+
74
+ const table = useReactTable({
75
+ columns,
76
+ data,
77
+ getCoreRowModel: getCoreRowModel(),
78
+ getSortedRowModel: getSortedRowModel(),
79
+ enableRowSelection,
80
+ enableSorting,
81
+ state: {
82
+ rowSelection,
83
+ columnVisibility,
84
+ },
85
+ onRowSelectionChange: setRowSelection,
86
+ onColumnVisibilityChange: setColumnVisibility,
87
+ });
88
+
89
+ return <DataTable table={table}>{children}</DataTable>;
90
+ }
91
+
92
+ describe('DataTable', () => {
93
+ it('renders children inside a flex container', () => {
94
+ render(
95
+ <DataTableFixture>
96
+ <div data-testid="child">Hello</div>
97
+ </DataTableFixture>
98
+ );
99
+
100
+ expect(screen.getByTestId('child')).toBeInTheDocument();
101
+ expect(screen.getByTestId('child').textContent).toBe('Hello');
102
+ });
103
+
104
+ it('renders with the DataTable displayName', () => {
105
+ expect(DataTable.displayName).toBe('DataTable');
106
+ });
107
+ });
108
+
109
+ describe('DataTableCounter', () => {
110
+ it('shows total row count with default plural label', () => {
111
+ render(
112
+ <DataTableFixture>
113
+ <DataTableCounter />
114
+ </DataTableFixture>
115
+ );
116
+
117
+ expect(screen.getByText('3')).toBeInTheDocument();
118
+ expect(screen.getByText('items')).toBeInTheDocument();
119
+ });
120
+
121
+ it('shows singular label when there is exactly 1 row', () => {
122
+ render(
123
+ <DataTableFixture data={[testData[0]]}>
124
+ <DataTableCounter />
125
+ </DataTableFixture>
126
+ );
127
+
128
+ expect(screen.getByText('1')).toBeInTheDocument();
129
+ expect(screen.getByText('item')).toBeInTheDocument();
130
+ });
131
+
132
+ it('uses custom singular/plural labels', () => {
133
+ render(
134
+ <DataTableFixture>
135
+ <DataTableCounter singular="Friend" plural="Friends" />
136
+ </DataTableFixture>
137
+ );
138
+
139
+ expect(screen.getByText('3')).toBeInTheDocument();
140
+ expect(screen.getByText('Friends')).toBeInTheDocument();
141
+ });
142
+
143
+ it('shows selected count with "selected" suffix when rows are selected', () => {
144
+ render(
145
+ <DataTableFixture initialRowSelection={{ '0': true, '1': true }}>
146
+ <DataTableCounter singular="Friend" plural="Friends" />
147
+ </DataTableFixture>
148
+ );
149
+
150
+ expect(screen.getByText('2')).toBeInTheDocument();
151
+ expect(screen.getByText('Friends selected')).toBeInTheDocument();
152
+ });
153
+
154
+ it('uses singular label when exactly 1 row is selected', () => {
155
+ render(
156
+ <DataTableFixture initialRowSelection={{ '0': true }}>
157
+ <DataTableCounter singular="Friend" plural="Friends" />
158
+ </DataTableFixture>
159
+ );
160
+
161
+ expect(screen.getByText('1')).toBeInTheDocument();
162
+ expect(screen.getByText('Friend selected')).toBeInTheDocument();
163
+ });
164
+
165
+ it('accepts a custom count prop that overrides the table row count', () => {
166
+ render(
167
+ <DataTableFixture>
168
+ <DataTableCounter count={999} />
169
+ </DataTableFixture>
170
+ );
171
+
172
+ expect(screen.getByText('999')).toBeInTheDocument();
173
+ expect(screen.getByText('items')).toBeInTheDocument();
174
+ });
175
+ });
176
+
177
+ describe('DataTableBulkActions', () => {
178
+ it('does not render children when no rows are selected', () => {
179
+ render(
180
+ <DataTableFixture>
181
+ <DataTableBulkActions>
182
+ <button>Bulk Action</button>
183
+ </DataTableBulkActions>
184
+ </DataTableFixture>
185
+ );
186
+
187
+ expect(screen.queryByText('Bulk Action')).not.toBeInTheDocument();
188
+ });
189
+
190
+ it('renders children when rows are selected', () => {
191
+ render(
192
+ <DataTableFixture initialRowSelection={{ '0': true }}>
193
+ <DataTableBulkActions>
194
+ <button>Bulk Action</button>
195
+ </DataTableBulkActions>
196
+ </DataTableFixture>
197
+ );
198
+
199
+ expect(screen.getByText('Bulk Action')).toBeInTheDocument();
200
+ });
201
+ });
202
+
203
+ describe('DataTableBody', () => {
204
+ it('renders column headers', () => {
205
+ render(
206
+ <DataTableFixture>
207
+ <DataTableBody />
208
+ </DataTableFixture>
209
+ );
210
+
211
+ expect(screen.getByText('First Name')).toBeInTheDocument();
212
+ expect(screen.getByText('Last Name')).toBeInTheDocument();
213
+ expect(screen.getByText('Age')).toBeInTheDocument();
214
+ });
215
+
216
+ it('renders all data rows', () => {
217
+ render(
218
+ <DataTableFixture>
219
+ <DataTableBody />
220
+ </DataTableFixture>
221
+ );
222
+
223
+ expect(screen.getByText('Alice')).toBeInTheDocument();
224
+ expect(screen.getByText('Bob')).toBeInTheDocument();
225
+ expect(screen.getByText('Charlie')).toBeInTheDocument();
226
+ });
227
+
228
+ it('renders cell values for each row', () => {
229
+ render(
230
+ <DataTableFixture>
231
+ <DataTableBody />
232
+ </DataTableFixture>
233
+ );
234
+
235
+ expect(screen.getByText('Smith')).toBeInTheDocument();
236
+ expect(screen.getByText('Jones')).toBeInTheDocument();
237
+ expect(screen.getByText('Brown')).toBeInTheDocument();
238
+
239
+ expect(screen.getByText('25')).toBeInTheDocument();
240
+ expect(screen.getByText('30')).toBeInTheDocument();
241
+ expect(screen.getByText('35')).toBeInTheDocument();
242
+ });
243
+
244
+ it('respects initial column visibility', () => {
245
+ render(
246
+ <DataTableFixture initialVisibility={{ age: false }}>
247
+ <DataTableBody />
248
+ </DataTableFixture>
249
+ );
250
+
251
+ // Age column should be hidden
252
+ expect(screen.queryByText('Age')).not.toBeInTheDocument();
253
+ expect(screen.queryByText('25')).not.toBeInTheDocument();
254
+
255
+ // Other columns should still be visible
256
+ expect(screen.getByText('First Name')).toBeInTheDocument();
257
+ expect(screen.getByText('Alice')).toBeInTheDocument();
258
+ });
259
+
260
+ it('renders an empty body when data is empty', () => {
261
+ render(
262
+ <DataTableFixture data={[]}>
263
+ <DataTableBody />
264
+ </DataTableFixture>
265
+ );
266
+
267
+ // Headers should still render
268
+ expect(screen.getByText('First Name')).toBeInTheDocument();
269
+
270
+ // No data rows
271
+ expect(screen.queryByText('Alice')).not.toBeInTheDocument();
272
+ });
273
+ });
274
+
275
+ describe('DataTableEditColumns', () => {
276
+ it('renders the "Edit columns" button', () => {
277
+ render(
278
+ <DataTableFixture>
279
+ <DataTableEditColumns />
280
+ </DataTableFixture>
281
+ );
282
+
283
+ expect(screen.getByText('Edit columns')).toBeInTheDocument();
284
+ });
285
+
286
+ it('shows hidable columns in the menu when clicked', async () => {
287
+ const user = userEvent.setup();
288
+
289
+ render(
290
+ <DataTableFixture>
291
+ <DataTableEditColumns />
292
+ </DataTableFixture>
293
+ );
294
+
295
+ await user.click(screen.getByText('Edit columns'));
296
+
297
+ expect(screen.getByText('First Name')).toBeInTheDocument();
298
+ expect(screen.getByText('Last Name')).toBeInTheDocument();
299
+ expect(screen.getByText('Age')).toBeInTheDocument();
300
+ });
301
+
302
+ it('toggles column visibility when a hidable column is clicked', async () => {
303
+ const user = userEvent.setup();
304
+
305
+ render(
306
+ <DataTableFixture>
307
+ <DataTableEditColumns />
308
+ <DataTableBody />
309
+ </DataTableFixture>
310
+ );
311
+
312
+ expect(screen.getByText('35')).toBeInTheDocument();
313
+
314
+ await user.click(screen.getByText('Edit columns'));
315
+
316
+ const ageOption = screen.getAllByText('Age');
317
+ // There may be multiple "Age" texts (header cell + menu item)
318
+ // The menu item is the last one
319
+ await user.click(ageOption[ageOption.length - 1]);
320
+
321
+ expect(screen.queryByText('35')).not.toBeInTheDocument();
322
+ });
323
+ });
324
+
325
+ describe('DataTableHeader', () => {
326
+ it('renders children', () => {
327
+ render(
328
+ <DataTableFixture>
329
+ <DataTableHeader>
330
+ <span data-testid="header-child">Header Content</span>
331
+ </DataTableHeader>
332
+ </DataTableFixture>
333
+ );
334
+
335
+ expect(screen.getByTestId('header-child')).toBeInTheDocument();
336
+ expect(screen.getByText('Header Content')).toBeInTheDocument();
337
+ });
338
+ });
339
+
340
+ describe('DataTable integration', () => {
341
+ it('counter updates when row selection changes via bulk actions', () => {
342
+ render(
343
+ <DataTableFixture initialRowSelection={{ '0': true }}>
344
+ <DataTableHeader>
345
+ <DataTableCounter singular="Friend" plural="Friends" />
346
+ <DataTableBulkActions>
347
+ <button>Delete</button>
348
+ </DataTableBulkActions>
349
+ </DataTableHeader>
350
+ <DataTableBody />
351
+ </DataTableFixture>
352
+ );
353
+
354
+ expect(screen.getByText('1')).toBeInTheDocument();
355
+ expect(screen.getByText('Friend selected')).toBeInTheDocument();
356
+ expect(screen.getByText('Delete')).toBeInTheDocument();
357
+ });
358
+
359
+ it('bulk actions disappear and counter shows total when no rows are selected', () => {
360
+ render(
361
+ <DataTableFixture>
362
+ <DataTableHeader>
363
+ <DataTableCounter singular="Friend" plural="Friends" />
364
+ <DataTableBulkActions>
365
+ <button>Delete</button>
366
+ </DataTableBulkActions>
367
+ </DataTableHeader>
368
+ <DataTableBody />
369
+ </DataTableFixture>
370
+ );
371
+
372
+ expect(screen.getByText('3')).toBeInTheDocument();
373
+ expect(screen.getByText('Friends')).toBeInTheDocument();
374
+
375
+ expect(screen.queryByText('Delete')).not.toBeInTheDocument();
376
+ });
377
+
378
+ it('renders the full composition (header + body) with data', () => {
379
+ render(
380
+ <DataTableFixture>
381
+ <DataTableHeader>
382
+ <DataTableCounter />
383
+ <DataTableEditColumns />
384
+ </DataTableHeader>
385
+ <DataTableBody />
386
+ </DataTableFixture>
387
+ );
388
+
389
+ // Header
390
+ expect(screen.getByText('3')).toBeInTheDocument();
391
+ expect(screen.getByText('items')).toBeInTheDocument();
392
+ expect(screen.getByText('Edit columns')).toBeInTheDocument();
393
+
394
+ // Body
395
+ expect(screen.getByText('Alice')).toBeInTheDocument();
396
+ expect(screen.getByText('Bob')).toBeInTheDocument();
397
+ expect(screen.getByText('Charlie')).toBeInTheDocument();
398
+ });
399
+
400
+ it('hides column via EditColumns and verifies body updates', async () => {
401
+ const user = userEvent.setup();
402
+
403
+ render(
404
+ <DataTableFixture>
405
+ <DataTableHeader>
406
+ <DataTableEditColumns />
407
+ </DataTableHeader>
408
+ <DataTableBody />
409
+ </DataTableFixture>
410
+ );
411
+
412
+ expect(screen.getByText('Smith')).toBeInTheDocument();
413
+
414
+ await user.click(screen.getByText('Edit columns'));
415
+
416
+ const lastNameOptions = screen.getAllByText('Last Name');
417
+ await user.click(lastNameOptions[lastNameOptions.length - 1]);
418
+
419
+ expect(screen.queryByText('Smith')).not.toBeInTheDocument();
420
+ expect(screen.queryByText('Jones')).not.toBeInTheDocument();
421
+ expect(screen.queryByText('Brown')).not.toBeInTheDocument();
422
+
423
+ expect(screen.getByText('Alice')).toBeInTheDocument();
424
+ });
425
+ });
@@ -0,0 +1,17 @@
1
+ import { Box, type BoxProps } from '../vanilla/Box';
2
+ import { useDataTableContext } from './DataTableContext';
3
+
4
+ export type DataTableBulkActionsProps = BoxProps<'div'>;
5
+
6
+ export function DataTableBulkActions({ children, ...props }: DataTableBulkActionsProps) {
7
+ const { table } = useDataTableContext();
8
+ const hasSelection = table.getSelectedRowModel().rows.length > 0;
9
+
10
+ if (!hasSelection) return null;
11
+
12
+ return (
13
+ <Box display="flex" alignItems="center" gap="sm" {...props}>
14
+ {children}
15
+ </Box>
16
+ );
17
+ }
@@ -0,0 +1,37 @@
1
+ import { Box, type BoxProps } from '../vanilla/Box';
2
+ import { Text } from '../vanilla/Text';
3
+ import { useDataTableContext } from './DataTableContext';
4
+
5
+ export type DataTableCounterProps = BoxProps<
6
+ 'div',
7
+ {
8
+ count?: number;
9
+ singular?: string;
10
+ plural?: string;
11
+ }
12
+ >;
13
+
14
+ export function DataTableCounter({
15
+ count: countProp,
16
+ singular = 'item',
17
+ plural = 'items',
18
+ ...props
19
+ }: DataTableCounterProps) {
20
+ const { table } = useDataTableContext();
21
+
22
+ const selectedCount = table.getSelectedRowModel().rows.length;
23
+ const totalCount = countProp ?? table.getRowCount();
24
+ const hasSelection = selectedCount > 0;
25
+
26
+ const count = hasSelection ? selectedCount : totalCount;
27
+ const label = count === 1 ? singular : plural;
28
+
29
+ return (
30
+ <Box display="flex" alignItems="center" gap="sm" {...props}>
31
+ <Text typography="label02" color="active">
32
+ {count.toLocaleString()}
33
+ </Text>
34
+ <Text typography="label02">{hasSelection ? `${label} selected` : label}</Text>
35
+ </Box>
36
+ );
37
+ }
@@ -55,7 +55,9 @@ export function DataTableEditColumns() {
55
55
  {allColumns.map((column) => {
56
56
  const canHide = column.getCanHide();
57
57
  const isSelected = canHide ? selectedColumns.has(column.id) : true;
58
- const label = (column.columnDef.meta as { label?: string })?.label;
58
+ const label =
59
+ (column.columnDef.meta as { label?: string })?.label ??
60
+ (typeof column.columnDef.header === 'string' ? column.columnDef.header : undefined);
59
61
 
60
62
  if (!label) {
61
63
  return null;
@@ -40,9 +40,7 @@ export const DataTableHeaderCell = forwardRef<HTMLTableCellElement, DataTableHea
40
40
  data-test
41
41
  {...props}
42
42
  >
43
- {typeof children !== 'string' || !header.column.getCanSort() ? (
44
- children
45
- ) : (
43
+ {typeof children === 'string' ? (
46
44
  <Box
47
45
  display="flex"
48
46
  alignItems="center"
@@ -87,7 +85,6 @@ export const DataTableHeaderCell = forwardRef<HTMLTableCellElement, DataTableHea
87
85
  </TooltipTrigger>
88
86
  <TooltipContent>{children}</TooltipContent>
89
87
  </Tooltip>
90
-
91
88
  {header.column.columnDef.meta?.tooltip && (
92
89
  <Tooltip>
93
90
  <TooltipTrigger>
@@ -101,95 +98,104 @@ export const DataTableHeaderCell = forwardRef<HTMLTableCellElement, DataTableHea
101
98
  </TooltipContent>
102
99
  </Tooltip>
103
100
  )}
104
-
105
- <ActionsContent
106
- display="grid"
107
- placeItems="center"
108
- position="relative"
109
- visible={sortDir ? 'always' : 'if-needed'}
110
- flexDirection={flexDir}
111
- >
112
- <IconButton
113
- onClick={() =>
114
- header.column.toggleSorting(undefined, header.column.getCanMultiSort())
115
- }
116
- type="tertiary"
117
- size="compact"
118
- iconName={getSortIcon(sortDir)}
119
- />
120
- {header.column.getCanMultiSort() && header.column.getSortIndex() > -1 && (
121
- <Text
122
- typography="label04"
123
- color="primary"
124
- position="absolute"
125
- pointerEvents="none"
126
- style={{ top: 0, right: 0 }}
127
- >
128
- {header.column.getSortIndex() + 1}
129
- </Text>
130
- )}
131
- </ActionsContent>
101
+ {header.column.getCanSort() && (
102
+ <ActionsContent
103
+ display="grid"
104
+ placeItems="center"
105
+ position="relative"
106
+ visible={sortDir ? 'always' : 'if-needed'}
107
+ flexDirection={flexDir}
108
+ >
109
+ <IconButton
110
+ onClick={() =>
111
+ header.column.toggleSorting(undefined, header.column.getCanMultiSort())
112
+ }
113
+ type="tertiary"
114
+ size="compact"
115
+ iconName={getSortIcon(sortDir)}
116
+ />
117
+ {header.column.getCanMultiSort() && header.column.getSortIndex() > -1 && (
118
+ <Text
119
+ typography="label04"
120
+ color="primary"
121
+ position="absolute"
122
+ pointerEvents="none"
123
+ style={{ top: 0, right: 0 }}
124
+ >
125
+ {header.column.getSortIndex() + 1}
126
+ </Text>
127
+ )}
128
+ </ActionsContent>
129
+ )}
132
130
  </Box>
133
131
 
134
- <ActionsContent visible={sortDir ? 'always' : 'if-needed'}>
135
- <Menu>
136
- <MenuTrigger>
137
- <IconButton type="tertiary" size="compact" iconName="moreOptions" />
138
- </MenuTrigger>
139
- <MenuContent style={{ minWidth: '220px' }}>
140
- <MenuItem onAction={() => header.column.toggleSorting(true)}>
141
- <Box display="flex" alignItems="center" gap="sm">
142
- <Icon name="sortDescending" />
143
- <Text typography="body03">Sort descending (z-a)</Text>
144
- </Box>
145
- </MenuItem>
146
- <MenuItem onAction={() => header.column.toggleSorting(false)}>
147
- <Box display="flex" alignItems="center" gap="sm">
148
- <Icon name="sortAscending" />
149
- <Text typography="body03">Sort ascending (a-z)</Text>
150
- </Box>
151
- </MenuItem>
152
- {header.column.getCanPin() && (
153
- <>
154
- <MenuSeparator />
155
- <MenuItem
156
- onAction={() => {
157
- const isPinnedLeft = header.column.getIsPinned() === 'left';
158
- header.column.pin(isPinnedLeft ? false : 'left');
159
- }}
160
- >
161
- <Box display="flex" alignItems="center" gap="sm" w="full">
162
- <Icon name="freeze" />
163
- <Text typography="body03">Freeze column (left)</Text>
164
- <Box flex="1" />
165
- <Switch
166
- isSelected={header.column.getIsPinned() === 'left'}
167
- isReadOnly
168
- />
169
- </Box>
170
- </MenuItem>
171
- <MenuItem
172
- onAction={() => {
173
- const isPinnedRight = header.column.getIsPinned() === 'right';
174
- header.column.pin(isPinnedRight ? false : 'right');
175
- }}
176
- >
177
- <Box display="flex" alignItems="center" gap="sm" w="full">
178
- <Icon name="freeze" />
179
- <Text typography="body03">Freeze column (right)</Text>
180
- <Box flex="1" />
181
- <Switch
182
- isSelected={header.column.getIsPinned() === 'right'}
183
- isReadOnly
184
- />
185
- </Box>
186
- </MenuItem>
187
- </>
188
- )}
189
- </MenuContent>
190
- </Menu>
191
- </ActionsContent>
132
+ {(header.column.getCanSort() || header.column.getCanPin()) && (
133
+ <ActionsContent visible={sortDir ? 'always' : 'if-needed'}>
134
+ <Menu>
135
+ <MenuTrigger>
136
+ <IconButton type="tertiary" size="compact" iconName="moreOptions" />
137
+ </MenuTrigger>
138
+ <MenuContent style={{ minWidth: '220px' }}>
139
+ {header.column.getCanSort() && (
140
+ <>
141
+ <MenuItem onAction={() => header.column.toggleSorting(true)}>
142
+ <Box display="flex" alignItems="center" gap="sm">
143
+ <Icon name="sortDescending" />
144
+ <Text typography="body03">Sort descending (z-a)</Text>
145
+ </Box>
146
+ </MenuItem>
147
+ <MenuItem onAction={() => header.column.toggleSorting(false)}>
148
+ <Box display="flex" alignItems="center" gap="sm">
149
+ <Icon name="sortAscending" />
150
+ <Text typography="body03">Sort ascending (a-z)</Text>
151
+ </Box>
152
+ </MenuItem>
153
+ </>
154
+ )}
155
+ {header.column.getCanPin() && (
156
+ <>
157
+ {header.column.getCanSort() && <MenuSeparator />}
158
+ <MenuItem
159
+ onAction={() => {
160
+ const isPinnedLeft = header.column.getIsPinned() === 'left';
161
+ header.column.pin(isPinnedLeft ? false : 'left');
162
+ }}
163
+ >
164
+ <Box display="flex" alignItems="center" gap="sm" w="full">
165
+ <Icon name="freeze" />
166
+ <Text typography="body03">Freeze column (left)</Text>
167
+ <Box flex="1" />
168
+ <Switch
169
+ isSelected={header.column.getIsPinned() === 'left'}
170
+ isReadOnly
171
+ />
172
+ </Box>
173
+ </MenuItem>
174
+ <MenuItem
175
+ onAction={() => {
176
+ const isPinnedRight = header.column.getIsPinned() === 'right';
177
+ header.column.pin(isPinnedRight ? false : 'right');
178
+ }}
179
+ >
180
+ <Box display="flex" alignItems="center" gap="sm" w="full">
181
+ <Icon name="freeze" />
182
+ <Text typography="body03">Freeze column (right)</Text>
183
+ <Box flex="1" />
184
+ <Switch
185
+ isSelected={header.column.getIsPinned() === 'right'}
186
+ isReadOnly
187
+ />
188
+ </Box>
189
+ </MenuItem>
190
+ </>
191
+ )}
192
+ </MenuContent>
193
+ </Menu>
194
+ </ActionsContent>
195
+ )}
192
196
  </Box>
197
+ ) : (
198
+ children
193
199
  )}
194
200
  </TableHeaderCell>
195
201
  </ActionsRoot>
@@ -1,5 +1,7 @@
1
1
  export * from './DataTable';
2
2
  export * from './DataTableBody';
3
+ export * from './DataTableBulkActions';
3
4
  export * from './DataTableCheckbox';
5
+ export * from './DataTableCounter';
4
6
  export * from './DataTableEditColumns';
5
7
  export * from './DataTableHeader';