@mezzanine-ui/react 1.0.0-beta.1 → 1.0.0-beta.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.
Files changed (172) hide show
  1. package/Anchor/Anchor.d.ts +51 -18
  2. package/Anchor/Anchor.js +15 -15
  3. package/Anchor/AnchorGroup.d.ts +34 -0
  4. package/Anchor/AnchorGroup.js +37 -0
  5. package/Anchor/AnchorItem.d.ts +30 -0
  6. package/Anchor/AnchorItem.js +65 -0
  7. package/Anchor/index.d.ts +2 -0
  8. package/Anchor/index.js +1 -0
  9. package/Anchor/utils.d.ts +13 -0
  10. package/Anchor/utils.js +95 -0
  11. package/AutoComplete/AutoComplete.d.ts +194 -0
  12. package/AutoComplete/AutoComplete.js +419 -0
  13. package/AutoComplete/index.d.ts +2 -0
  14. package/AutoComplete/index.js +1 -0
  15. package/AutoComplete/useAutoCompleteCreation.d.ts +33 -0
  16. package/AutoComplete/useAutoCompleteCreation.js +201 -0
  17. package/AutoComplete/useAutoCompleteKeyboard.d.ts +31 -0
  18. package/AutoComplete/useAutoCompleteKeyboard.js +149 -0
  19. package/AutoComplete/useAutoCompleteSearch.d.ts +16 -0
  20. package/AutoComplete/useAutoCompleteSearch.js +69 -0
  21. package/AutoComplete/useCreationTracker.d.ts +17 -0
  22. package/AutoComplete/useCreationTracker.js +47 -0
  23. package/Badge/Badge.js +2 -2
  24. package/Breadcrumb/BreadcrumbItem.d.ts +1 -1
  25. package/Button/Button.js +13 -11
  26. package/Button/index.d.ts +1 -1
  27. package/Button/typings.d.ts +27 -4
  28. package/Description/Description.d.ts +30 -0
  29. package/Description/Description.js +13 -0
  30. package/Description/DescriptionContent.d.ts +41 -0
  31. package/Description/DescriptionContent.js +14 -0
  32. package/Description/DescriptionGroup.d.ts +13 -0
  33. package/Description/DescriptionGroup.js +12 -0
  34. package/Description/DescriptionTitle.d.ts +45 -0
  35. package/Description/DescriptionTitle.js +17 -0
  36. package/Description/index.d.ts +8 -0
  37. package/Description/index.js +4 -0
  38. package/Dropdown/Dropdown.d.ts +43 -3
  39. package/Dropdown/Dropdown.js +154 -35
  40. package/Dropdown/DropdownAction.d.ts +1 -1
  41. package/Dropdown/DropdownAction.js +1 -4
  42. package/Dropdown/DropdownItem.d.ts +21 -4
  43. package/Dropdown/DropdownItem.js +23 -10
  44. package/Dropdown/DropdownItemCard.d.ts +5 -5
  45. package/Dropdown/DropdownItemCard.js +11 -10
  46. package/Dropdown/DropdownStatus.d.ts +2 -2
  47. package/Dropdown/DropdownStatus.js +29 -0
  48. package/Dropdown/dropdownKeydownHandler.d.ts +2 -1
  49. package/Dropdown/dropdownKeydownHandler.js +73 -0
  50. package/Dropdown/highlightText.js +5 -1
  51. package/Dropdown/shortcutTextHandler.d.ts +24 -0
  52. package/Dropdown/shortcutTextHandler.js +171 -0
  53. package/Form/FormControlContext.d.ts +2 -2
  54. package/Form/FormField.d.ts +56 -4
  55. package/Form/FormField.js +10 -6
  56. package/Form/FormHintText.d.ts +24 -1
  57. package/Form/FormHintText.js +4 -4
  58. package/Form/FormLabel.d.ts +6 -3
  59. package/Form/FormLabel.js +5 -3
  60. package/Input/Input.d.ts +29 -3
  61. package/Input/Input.js +22 -6
  62. package/Input/PasswordStrengthIndicator/PasswordStrengthIndicator.js +1 -1
  63. package/Modal/Modal.d.ts +103 -11
  64. package/Modal/Modal.js +14 -9
  65. package/Modal/ModalBodyForVerification.d.ts +59 -0
  66. package/Modal/ModalBodyForVerification.js +99 -0
  67. package/Modal/ModalControl.d.ts +2 -2
  68. package/Modal/ModalControl.js +1 -1
  69. package/Modal/ModalFooter.d.ts +119 -1
  70. package/Modal/ModalFooter.js +15 -3
  71. package/Modal/ModalHeader.d.ts +26 -7
  72. package/Modal/ModalHeader.js +33 -7
  73. package/Modal/index.d.ts +4 -5
  74. package/Modal/index.js +1 -2
  75. package/Modal/useModalContainer.d.ts +12 -3
  76. package/Modal/useModalContainer.js +28 -6
  77. package/Navigation/CollapsedMenu.d.ts +6 -0
  78. package/Navigation/CollapsedMenu.js +16 -0
  79. package/Navigation/Navigation.d.ts +17 -3
  80. package/Navigation/Navigation.js +48 -33
  81. package/Navigation/NavigationFooter.js +4 -2
  82. package/Navigation/NavigationHeader.d.ts +11 -1
  83. package/Navigation/NavigationHeader.js +6 -3
  84. package/Navigation/NavigationOption.d.ts +3 -2
  85. package/Navigation/NavigationOption.js +45 -26
  86. package/Navigation/NavigationOptionCategory.js +20 -2
  87. package/Navigation/context.d.ts +2 -0
  88. package/Navigation/useVisibleItems.d.ts +5 -0
  89. package/Navigation/useVisibleItems.js +54 -0
  90. package/NotificationCenter/NotificationCenter.d.ts +124 -0
  91. package/NotificationCenter/NotificationCenter.js +259 -0
  92. package/NotificationCenter/NotificationCenterDrawer.d.ts +89 -0
  93. package/NotificationCenter/index.d.ts +3 -0
  94. package/NotificationCenter/index.js +1 -0
  95. package/PageFooter/PageFooter.d.ts +19 -9
  96. package/PageFooter/PageFooter.js +10 -10
  97. package/PageHeader/PageHeader.js +4 -12
  98. package/PageToolbar/PageToolbar.d.ts +2 -6
  99. package/PageToolbar/utils.js +4 -12
  100. package/Select/index.d.ts +0 -2
  101. package/Select/index.js +0 -1
  102. package/Slider/useSlider.js +1 -1
  103. package/Table/Table.d.ts +53 -15
  104. package/Table/Table.js +178 -82
  105. package/Table/TableContext.d.ts +18 -42
  106. package/Table/components/TableActionsCell.d.ts +26 -0
  107. package/Table/components/TableActionsCell.js +78 -0
  108. package/Table/components/TableBody.d.ts +2 -5
  109. package/Table/components/TableBody.js +16 -19
  110. package/Table/components/TableBulkActions.d.ts +15 -0
  111. package/Table/components/TableBulkActions.js +26 -0
  112. package/Table/components/TableCell.d.ts +2 -0
  113. package/Table/components/TableCell.js +42 -10
  114. package/Table/components/TableColGroup.js +10 -112
  115. package/Table/components/TableColumnTitleMenu.d.ts +6 -0
  116. package/Table/components/TableColumnTitleMenu.js +20 -0
  117. package/Table/components/TableDragHandleCell.d.ts +2 -0
  118. package/Table/components/TableDragHandleCell.js +8 -1
  119. package/Table/components/TableExpandCell.d.ts +2 -0
  120. package/Table/components/TableExpandCell.js +8 -1
  121. package/Table/components/TableExpandedRow.js +3 -2
  122. package/Table/components/TableHeader.d.ts +2 -4
  123. package/Table/components/TableHeader.js +11 -14
  124. package/Table/components/TableResizeHandle.js +3 -7
  125. package/Table/components/TableRow.js +54 -20
  126. package/Table/components/TableSelectionCell.d.ts +5 -0
  127. package/Table/components/TableSelectionCell.js +12 -1
  128. package/Table/components/index.d.ts +1 -0
  129. package/Table/components/index.js +1 -0
  130. package/Table/hooks/index.d.ts +1 -1
  131. package/Table/hooks/index.js +1 -1
  132. package/Table/hooks/useTableDataSource.d.ts +2 -2
  133. package/Table/hooks/useTableExpansion.js +0 -6
  134. package/Table/hooks/useTableFixedOffsets.d.ts +1 -1
  135. package/Table/hooks/useTableFixedOffsets.js +24 -26
  136. package/Table/hooks/useTableResizedColumns.d.ts +2 -0
  137. package/Table/hooks/useTableResizedColumns.js +22 -0
  138. package/Table/hooks/useTableScroll.d.ts +3 -1
  139. package/Table/hooks/useTableScroll.js +25 -19
  140. package/Table/hooks/useTableSelection.js +32 -8
  141. package/Table/hooks/useTableVirtualization.d.ts +1 -1
  142. package/Table/index.d.ts +4 -4
  143. package/Table/index.js +5 -3
  144. package/Table/utils/calculateColumnWidths.d.ts +28 -0
  145. package/Table/utils/calculateColumnWidths.js +80 -0
  146. package/Table/utils/index.d.ts +2 -0
  147. package/Table/utils/index.js +1 -0
  148. package/Table/utils/useTableRowSelection.d.ts +5 -5
  149. package/Table/utils/useTableRowSelection.js +14 -6
  150. package/Tag/TagGroup.d.ts +3 -0
  151. package/Tag/index.d.ts +2 -0
  152. package/Tag/index.js +1 -0
  153. package/Upload/UploadPictureCard.js +1 -1
  154. package/index.d.ts +36 -20
  155. package/index.js +26 -7
  156. package/package.json +4 -4
  157. package/utils/format-number-with-commas.d.ts +4 -0
  158. package/utils/format-number-with-commas.js +27 -0
  159. package/utils/parse-number-with-commas.d.ts +4 -0
  160. package/utils/parse-number-with-commas.js +22 -0
  161. package/Modal/ModalActions.d.ts +0 -9
  162. package/Modal/ModalActions.js +0 -20
  163. package/Modal/ModalBody.d.ts +0 -7
  164. package/Modal/ModalBody.js +0 -14
  165. package/Notification/Notification.d.ts +0 -54
  166. package/Notification/Notification.js +0 -76
  167. package/Notification/index.d.ts +0 -3
  168. package/Notification/index.js +0 -1
  169. package/Select/AutoComplete.d.ts +0 -107
  170. package/Select/AutoComplete.js +0 -114
  171. package/Table/hooks/useTableColumns.d.ts +0 -8
  172. package/Table/hooks/useTableColumns.js +0 -91
@@ -62,9 +62,7 @@ export type PageToolbarProps = Omit<NativeElementPropsWithoutKeyAndRef<'div'>, '
62
62
  * They usually appear as smaller buttons with only an icon and no text.
63
63
  */
64
64
  utilities?: (ButtonProps & {
65
- icon: {
66
- src: IconDefinition;
67
- };
65
+ icon: IconDefinition;
68
66
  })[];
69
67
  };
70
68
  /**
@@ -106,9 +104,7 @@ declare const PageToolbar: import("react").ForwardRefExoticComponent<Omit<Native
106
104
  * They usually appear as smaller buttons with only an icon and no text.
107
105
  */
108
106
  utilities?: (ButtonProps & {
109
- icon: {
110
- src: IconDefinition;
111
- };
107
+ icon: IconDefinition;
112
108
  })[];
113
109
  } & import("react").RefAttributes<HTMLDivElement>>;
114
110
  export default PageToolbar;
@@ -45,12 +45,8 @@ const renderFilterProp = (prop, size) => {
45
45
  const renderIconButtonWithProps = (child, size) => {
46
46
  const { icon } = child.props;
47
47
  return cloneElement(child, {
48
- icon: icon
49
- ? {
50
- ...icon,
51
- position: 'icon-only',
52
- }
53
- : undefined,
48
+ icon: icon,
49
+ iconType: icon ? 'icon-only' : undefined,
54
50
  size,
55
51
  variant: 'base-secondary',
56
52
  });
@@ -58,10 +54,7 @@ const renderIconButtonWithProps = (child, size) => {
58
54
  const renderIconButtonsProp = (utilities, size) => {
59
55
  const result = [];
60
56
  utilities === null || utilities === void 0 ? void 0 : utilities.forEach((buttonProps) => {
61
- result.push(jsx(Button, { ...buttonProps, size: size, icon: {
62
- ...buttonProps.icon,
63
- position: 'icon-only',
64
- }, variant: "base-secondary" }));
57
+ result.push(jsx(Button, { ...buttonProps, size: size, icon: buttonProps.icon, iconType: buttonProps.icon ? 'icon-only' : undefined, variant: "base-secondary" }));
65
58
  });
66
59
  return result;
67
60
  };
@@ -94,7 +87,6 @@ const resolvePageToolbarChild = (children, size) => {
94
87
  if (children) {
95
88
  const flatChildren = flattenChildren(children);
96
89
  Children.forEach(flatChildren, (child) => {
97
- var _a;
98
90
  if (!isValidElement(child)) {
99
91
  return;
100
92
  }
@@ -112,7 +104,7 @@ const resolvePageToolbarChild = (children, size) => {
112
104
  }
113
105
  // is utilities (icon button)
114
106
  else if (type === Button &&
115
- ((_a = props.icon) === null || _a === void 0 ? void 0 : _a.position) === 'icon-only') {
107
+ props.iconType === 'icon-only') {
116
108
  utilities.push(renderIconButtonWithProps(child, size));
117
109
  }
118
110
  // is actions (normal button)
package/Select/index.d.ts CHANGED
@@ -12,5 +12,3 @@ export { default as OptionGroup } from '../Menu/MenuItemGroup';
12
12
  export type { MenuItemGroupProps as OptionGroupProps } from '../Menu/MenuItemGroup';
13
13
  export type { TreeSelectProps } from './TreeSelect';
14
14
  export { default as TreeSelect } from './TreeSelect';
15
- export type { AutoCompleteProps } from './AutoComplete';
16
- export { default as AutoComplete } from './AutoComplete';
package/Select/index.js CHANGED
@@ -5,4 +5,3 @@ export { default } from './Select.js';
5
5
  export { default as Option } from './Option.js';
6
6
  export { default as OptionGroup } from '../Menu/MenuItemGroup.js';
7
7
  export { default as TreeSelect } from './TreeSelect.js';
8
- export { default as AutoComplete } from './AutoComplete.js';
@@ -1,4 +1,4 @@
1
- import { isRangeSlider, fixRangeSliderValue, fixSingleSliderValue, toSliderCssVars, getPercentage, sortSliderValue, findClosetValueIndex, getSliderRect, getValueFromClientX, roundToStep } from '@mezzanine-ui/core/slider';
1
+ import { isRangeSlider, fixRangeSliderValue, fixSingleSliderValue, toSliderCssVars, getPercentage, findClosetValueIndex, sortSliderValue, getSliderRect, getValueFromClientX, roundToStep } from '@mezzanine-ui/core/slider';
2
2
  import { useRef, useState } from 'react';
3
3
  import { useDocumentEvents } from '../hooks/useDocumentEvents.js';
4
4
 
package/Table/Table.d.ts CHANGED
@@ -1,17 +1,25 @@
1
- import { TableSize, type HighlightMode, type TableColumn, type TableDataSource, type TableDraggable, type TableExpandable, type TableRowSelection, type TableScroll } from '@mezzanine-ui/core/table';
1
+ import { TableSize, type HighlightMode, type TableActions, type TableActionsWithMinWidth, type TableColumn, type TableColumnWithMinWidth, type TableDataSource, type TableDraggable, type TableExpandable, type TableRowSelection, type TableScroll } from '@mezzanine-ui/core/table';
2
2
  import type { NativeElementPropsWithoutKeyAndRef } from '../utils/jsx-types';
3
- import { type TableTransitionState } from './TableContext';
3
+ import type { TableTransitionState } from './hooks/useTableDataSource';
4
4
  import { TablePaginationProps } from './components/TablePagination';
5
5
  import type { EmptyProps } from '../Empty';
6
6
  export interface TableBaseProps<T extends TableDataSource = TableDataSource> extends Omit<NativeElementPropsWithoutKeyAndRef<'table'>, 'children' | 'draggable' | 'summary' | 'onChange'> {
7
- /** Column configuration */
8
- columns: TableColumn<T>[];
9
7
  /** Data source */
10
8
  dataSource: T[];
11
9
  /** Props for Empty component when no data */
12
- emptyProps?: EmptyProps;
10
+ emptyProps?: EmptyProps & {
11
+ height?: number | string;
12
+ };
13
13
  /** Expandable row configuration */
14
14
  expandable?: TableExpandable<T>;
15
+ /**
16
+ * Whether the table should stretch to fill its container width.
17
+ * When true, the table will always be 100% width of its container.
18
+ * Note: If the sum of all column widths is less than the table width,
19
+ * columns will be proportionally stretched to fill the remaining space.
20
+ * @default false
21
+ */
22
+ fullWidth?: boolean;
15
23
  /** Highlight mode for hover effects
16
24
  * @default 'row'
17
25
  */
@@ -20,23 +28,22 @@ export interface TableBaseProps<T extends TableDataSource = TableDataSource> ext
20
28
  loading?: boolean;
21
29
  /** Number of rows to display when loading */
22
30
  loadingRowsCount?: number;
31
+ /** Minimum height of the table */
32
+ minHeight?: number | string;
23
33
  /**
24
34
  * Whether the table is nested inside an expanded row content area
25
35
  */
26
36
  nested?: boolean;
27
37
  /** Pagination configuration */
28
38
  pagination?: TablePaginationProps;
29
- /**
30
- * Whether columns are resizable by user interaction
31
- * @default false
32
- */
33
- resizable?: boolean;
34
39
  /**
35
40
  * Row height preset token.
36
41
  */
37
42
  rowHeightPreset?: 'base' | 'condensed' | 'detailed' | 'roomy';
38
43
  /** Row selection configuration */
39
44
  rowSelection?: TableRowSelection<T>;
45
+ /** Row indexes where a separator border should be displayed */
46
+ separatorAtRowIndexes?: number[];
40
47
  /** Show header row */
41
48
  showHeader?: boolean;
42
49
  /** Custom size variant
@@ -49,12 +56,42 @@ export interface TableBaseProps<T extends TableDataSource = TableDataSource> ext
49
56
  sticky?: boolean;
50
57
  /** Transition state for row add/remove animations (from useTableDataSource hook) */
51
58
  transitionState?: TableTransitionState;
59
+ /** Enable zebra striping for alternating row backgrounds */
60
+ zebraStriping?: boolean;
61
+ }
62
+ /**
63
+ * Props when resizable is enabled.
64
+ * Requires minWidth on all columns.
65
+ */
66
+ export interface TableResizableProps<T extends TableDataSource = TableDataSource> extends TableBaseProps<T> {
67
+ /** Actions column configuration - minWidth required when resizable */
68
+ actions?: TableActionsWithMinWidth<T>;
69
+ /** Column configuration - minWidth required for each column when resizable */
70
+ columns: TableColumnWithMinWidth<T>[];
71
+ /**
72
+ * Whether columns are resizable by user interaction
73
+ */
74
+ resizable: true;
75
+ }
76
+ /**
77
+ * Props when resizable is disabled or not specified.
78
+ */
79
+ export interface TableNonResizableProps<T extends TableDataSource = TableDataSource> extends TableBaseProps<T> {
80
+ /** Actions column configuration */
81
+ actions?: TableActions<T>;
82
+ /** Column configuration */
83
+ columns: TableColumn<T>[];
84
+ /**
85
+ * Whether columns are resizable by user interaction
86
+ * @default false
87
+ */
88
+ resizable?: false;
52
89
  }
53
90
  /**
54
91
  * Props when virtualized scrolling is enabled.
55
92
  * Draggable is not allowed in this mode.
56
93
  */
57
- export interface TableVirtualizedProps<T extends TableDataSource = TableDataSource> extends TableBaseProps<T> {
94
+ export type TableVirtualizedProps<T extends TableDataSource = TableDataSource> = (TableResizableProps<T> | TableNonResizableProps<T>) & {
58
95
  /** Draggable row configuration - not available when virtualized is enabled */
59
96
  draggable?: never;
60
97
  /** Scroll configuration with virtualized enabled */
@@ -62,22 +99,23 @@ export interface TableVirtualizedProps<T extends TableDataSource = TableDataSour
62
99
  virtualized: true;
63
100
  y: number | string;
64
101
  };
65
- }
102
+ };
66
103
  /**
67
104
  * Props when virtualized scrolling is disabled or not specified.
68
105
  * Draggable is allowed in this mode.
69
106
  */
70
- export interface TableNonVirtualizedProps<T extends TableDataSource = TableDataSource> extends TableBaseProps<T> {
107
+ export type TableNonVirtualizedProps<T extends TableDataSource = TableDataSource> = (TableResizableProps<T> | TableNonResizableProps<T>) & {
71
108
  /** Draggable row configuration */
72
109
  draggable?: TableDraggable<T>;
73
110
  /** Scroll configuration for scrolling (virtualized defaults to false) */
74
111
  scroll?: TableScroll & {
75
112
  virtualized?: false;
76
113
  };
77
- }
114
+ };
78
115
  /**
79
116
  * TableProps - discriminated union to ensure draggable and virtualized
80
- * scrolling are mutually exclusive at the type level.
117
+ * scrolling are mutually exclusive at the type level, and resizable
118
+ * requires minWidth on all columns.
81
119
  */
82
120
  export type TableProps<T extends TableDataSource = TableDataSource> = TableVirtualizedProps<T> | TableNonVirtualizedProps<T>;
83
121
  /**
package/Table/Table.js CHANGED
@@ -1,36 +1,37 @@
1
1
  'use client';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
- import { forwardRef, useRef, useMemo, useState, useCallback } from 'react';
4
- import { tableClasses } from '@mezzanine-ui/core/table';
3
+ import { forwardRef, useRef, useMemo, useState, useCallback, useEffect } from 'react';
4
+ import throttle from 'lodash/throttle';
5
+ import { TABLE_ACTIONS_KEY, tableClasses } from '@mezzanine-ui/core/table';
5
6
  import { DragDropContext, Droppable } from '@hello-pangea/dnd';
6
- import { TableContext, TableDataContext, TableSuperContext } from './TableContext.js';
7
+ import { TableSuperContext, TableContext, TableDataContext } from './TableContext.js';
7
8
  import { TableBody } from './components/TableBody.js';
8
9
  import { TableColGroup } from './components/TableColGroup.js';
9
10
  import { TableHeader } from './components/TableHeader.js';
10
11
  import { TablePagination } from './components/TablePagination.js';
11
- import { useTableColumns } from './hooks/useTableColumns.js';
12
+ import { useTableResizedColumns } from './hooks/useTableResizedColumns.js';
12
13
  import { useTableExpansion } from './hooks/useTableExpansion.js';
13
14
  import { useTableFixedOffsets } from './hooks/useTableFixedOffsets.js';
14
15
  import { useTableScroll } from './hooks/useTableScroll.js';
15
16
  import { useTableSelection } from './hooks/useTableSelection.js';
16
17
  import { useTableSorting } from './hooks/useTableSorting.js';
17
- import { composeRefs } from '../utils/composeRefs.js';
18
18
  import { getNumericCSSVariablePixelValue } from '../utils/get-css-variable-value.js';
19
19
  import { spacingPrefix } from '@mezzanine-ui/system/spacing';
20
+ import TableBulkActions from './components/TableBulkActions.js';
21
+ import { useComposeRefs } from '../hooks/useComposeRefs.js';
20
22
  import cx from 'clsx';
21
23
 
22
24
  function TableInner(props, ref) {
23
- const { className, columns, dataSource, draggable, emptyProps, expandable, highlight = 'row', loading = false, loadingRowsCount = 10, nested = false, pagination, resizable = false, rowHeightPreset = 'base', rowSelection, scroll, showHeader = true, size = 'main', sticky = true, style, transitionState, ...restProps } = props;
25
+ const { actions, className, columns, dataSource, draggable, emptyProps, expandable, fullWidth = false, highlight = 'row', loading = false, loadingRowsCount = 10, minHeight, nested = false, pagination, resizable = false, rowHeightPreset = 'base', rowSelection, scroll, showHeader = true, size = 'main', sticky = true, style, transitionState, zebraStriping, separatorAtRowIndexes, ...restProps } = props;
24
26
  const hostRef = useRef(null);
25
- const scrollContainerRef = useRef(null);
26
- const tableRef = useRef(null);
27
- // mock loading dataSource
27
+ const composedHostRef = useComposeRefs([ref, hostRef]);
28
+ /** Feature: Loading */
28
29
  const dataSourceForRender = loading
29
30
  ? Array.from({ length: Math.max(loadingRowsCount, 1) }).map((_, idx) => ({
30
- key: idx,
31
+ key: `${idx}`,
31
32
  }))
32
33
  : dataSource;
33
- // get row height from preset
34
+ /** Feature: Row Height Preset */
34
35
  const rowHeight = useMemo(() => {
35
36
  switch (rowHeightPreset) {
36
37
  case 'condensed':
@@ -52,25 +53,55 @@ function TableInner(props, ref) {
52
53
  : getNumericCSSVariablePixelValue(`--${spacingPrefix}-size-container-minimal`);
53
54
  }
54
55
  }, [rowHeightPreset, size]);
55
- // Highlight state for hover effects
56
+ /** Feature: Highlight */
56
57
  const [hoveredRowIndex, setHoveredRowIndex] = useState(null);
57
58
  const [hoveredColumnIndex, setHoveredColumnIndex] = useState(null);
58
59
  const setHoveredCell = useCallback((rowIndex, columnIndex) => {
59
60
  setHoveredRowIndex(rowIndex);
60
61
  setHoveredColumnIndex(columnIndex);
61
62
  }, []);
62
- // Hooks
63
+ const highlightValue = useMemo(() => ({
64
+ columnIndex: hoveredColumnIndex,
65
+ mode: highlight,
66
+ rowIndex: hoveredRowIndex,
67
+ setHoveredCell,
68
+ }), [highlight, hoveredColumnIndex, hoveredRowIndex, setHoveredCell]);
69
+ /** Feature: sorting */
63
70
  const sortingState = useTableSorting({
64
71
  columns,
65
72
  });
73
+ /** Feature: Actions column */
74
+ const columnsWithActions = useMemo(() => {
75
+ var _a;
76
+ if (!actions)
77
+ return columns;
78
+ const actionsColumn = {
79
+ ...actions,
80
+ align: (_a = actions.align) !== null && _a !== void 0 ? _a : 'end',
81
+ ellipsis: false,
82
+ key: TABLE_ACTIONS_KEY,
83
+ render: () => null, // Placeholder, actual rendering is handled in TableRow
84
+ };
85
+ return [...columns, actionsColumn];
86
+ }, [actions, columns]);
87
+ /** Feature: Row selection */
66
88
  const selectionState = useTableSelection({
67
89
  dataSource,
68
90
  rowSelection,
69
91
  });
92
+ /** Feature: Expansion */
70
93
  const expansionState = useTableExpansion({
71
94
  expandable,
72
95
  hasDragHandle: !!(draggable === null || draggable === void 0 ? void 0 : draggable.enabled),
73
96
  });
97
+ /** Feature: Column resized */
98
+ const columnState = useTableResizedColumns();
99
+ /** Feature: Scroll and dimensions calculation */
100
+ const { containerWidth, handleScroll, isScrollingHorizontally, scrollLeft, containerRef: scrollContainerRef, setContainerRef, } = useTableScroll({
101
+ enabled: !nested,
102
+ });
103
+ const virtualScrollEnabled = useMemo(() => !!((scroll === null || scroll === void 0 ? void 0 : scroll.virtualized) && (scroll === null || scroll === void 0 ? void 0 : scroll.y)), [scroll === null || scroll === void 0 ? void 0 : scroll.virtualized, scroll === null || scroll === void 0 ? void 0 : scroll.y]);
104
+ /** Feature: Column fixed */
74
105
  const actionConfig = useMemo(() => ({
75
106
  hasDragHandle: !!(draggable === null || draggable === void 0 ? void 0 : draggable.enabled),
76
107
  dragHandleFixed: !!(draggable === null || draggable === void 0 ? void 0 : draggable.fixed),
@@ -79,50 +110,48 @@ function TableInner(props, ref) {
79
110
  hasSelection: !!rowSelection,
80
111
  selectionFixed: !!(rowSelection === null || rowSelection === void 0 ? void 0 : rowSelection.fixed),
81
112
  }), [draggable === null || draggable === void 0 ? void 0 : draggable.enabled, draggable === null || draggable === void 0 ? void 0 : draggable.fixed, expandable, rowSelection]);
82
- const columnState = useTableColumns({
83
- actionConfig,
84
- columns,
85
- });
86
- const scrollState = useTableScroll({
87
- enabled: !nested,
88
- });
89
- // Fixed column offset calculations
90
113
  const fixedOffsetsState = useTableFixedOffsets({
91
114
  actionConfig,
92
- columns: columns,
115
+ columns: columnsWithActions,
93
116
  getResizedColumnWidth: columnState.getResizedColumnWidth,
94
117
  });
95
- // Stabilize draggable object
96
- const draggableValue = useMemo(() => draggable
118
+ /** Feature: Drag n Drop */
119
+ const handleDragEnd = useCallback((result) => {
120
+ var _a;
121
+ if (!result.destination || !draggable)
122
+ return;
123
+ const sourceIndex = result.source.index;
124
+ const destIndex = result.destination.index;
125
+ if (sourceIndex === destIndex)
126
+ return;
127
+ const newData = [...dataSource];
128
+ const [removed] = newData.splice(sourceIndex, 1);
129
+ newData.splice(destIndex, 0, removed);
130
+ (_a = draggable.onDragEnd) === null || _a === void 0 ? void 0 : _a.call(draggable, newData, {
131
+ draggingId: result.draggableId,
132
+ fromIndex: sourceIndex,
133
+ toIndex: destIndex,
134
+ });
135
+ }, [dataSource, draggable]);
136
+ const draggableState = useMemo(() => draggable
97
137
  ? {
98
- draggingId: null,
99
- enabled: true,
138
+ enabled: draggable.enabled,
100
139
  fixed: draggable.fixed,
101
140
  }
102
141
  : undefined, [draggable]);
103
- // Stabilize highlight object
104
- const highlightValue = useMemo(() => ({
105
- columnIndex: hoveredColumnIndex,
106
- mode: highlight,
107
- rowIndex: hoveredRowIndex,
108
- setHoveredCell,
109
- }), [highlight, hoveredColumnIndex, hoveredRowIndex, setHoveredCell]);
110
- // Determine if virtual scrolling should be enabled
111
- // Requires scroll.virtualized to be true AND scroll.y to be set
112
- const virtualScrollEnabled = !!((scroll === null || scroll === void 0 ? void 0 : scroll.virtualized) && (scroll === null || scroll === void 0 ? void 0 : scroll.y));
113
- // Context value - cast to any to avoid complex generic issues
142
+ /** Context values */
114
143
  const contextValue = useMemo(() => ({
144
+ actions: actions,
115
145
  columnState,
116
- columns: columns,
117
146
  dataSource: dataSourceForRender,
118
- draggable: draggableValue,
147
+ draggable: draggableState,
119
148
  emptyProps,
120
149
  expansion: expansionState,
121
150
  fixedOffsets: fixedOffsetsState,
122
151
  resizable,
123
152
  rowHeight,
124
153
  highlight: highlightValue,
125
- isScrollingHorizontally: scrollState.isScrollingHorizontally,
154
+ isScrollingHorizontally: isScrollingHorizontally,
126
155
  isInsideExpandedContentArea: nested,
127
156
  loading,
128
157
  pagination: pagination || undefined,
@@ -130,14 +159,16 @@ function TableInner(props, ref) {
130
159
  scrollContainerRef,
131
160
  selection: selectionState,
132
161
  size,
162
+ separatorAtRowIndexes,
133
163
  sorting: sortingState,
134
164
  transitionState,
135
165
  virtualScrollEnabled,
166
+ zebraStriping,
136
167
  }), [
168
+ actions,
137
169
  columnState,
138
- columns,
139
170
  dataSourceForRender,
140
- draggableValue,
171
+ draggableState,
141
172
  emptyProps,
142
173
  expansionState,
143
174
  fixedOffsetsState,
@@ -148,84 +179,149 @@ function TableInner(props, ref) {
148
179
  pagination,
149
180
  scroll,
150
181
  scrollContainerRef,
151
- scrollState.isScrollingHorizontally,
182
+ isScrollingHorizontally,
152
183
  selectionState,
153
184
  size,
154
185
  sortingState,
155
186
  transitionState,
156
187
  virtualScrollEnabled,
188
+ zebraStriping,
189
+ separatorAtRowIndexes,
157
190
  nested,
158
191
  ]);
159
192
  const dataContextValue = useMemo(() => ({
160
- columns: columns,
193
+ columns: columnsWithActions,
161
194
  dataSource,
162
- }), [columns, dataSource]);
195
+ }), [columnsWithActions, dataSource]);
163
196
  const superContextValue = useMemo(() => {
164
197
  var _a;
165
198
  return ({
166
- containerWidth: scrollState.containerWidth,
199
+ containerWidth: containerWidth,
167
200
  getResizedColumnWidth: columnState.getResizedColumnWidth,
168
- scrollLeft: scrollState.scrollLeft,
201
+ scrollLeft: scrollLeft,
169
202
  expansionLeftPadding: (_a = expansionState === null || expansionState === void 0 ? void 0 : expansionState.expansionLeftPadding) !== null && _a !== void 0 ? _a : 0,
203
+ hasDragHandleFixed: !!(draggable === null || draggable === void 0 ? void 0 : draggable.enabled) && draggable.fixed,
170
204
  });
171
205
  }, [
172
- scrollState.scrollLeft,
206
+ scrollLeft,
173
207
  expansionState === null || expansionState === void 0 ? void 0 : expansionState.expansionLeftPadding,
174
- scrollState.containerWidth,
208
+ containerWidth,
175
209
  columnState.getResizedColumnWidth,
210
+ draggable === null || draggable === void 0 ? void 0 : draggable.enabled,
211
+ draggable === null || draggable === void 0 ? void 0 : draggable.fixed,
176
212
  ]);
177
- // Drag and drop handler
178
- const handleDragEnd = useCallback((result) => {
179
- var _a;
180
- if (!result.destination || !draggable)
181
- return;
182
- const sourceIndex = result.source.index;
183
- const destIndex = result.destination.index;
184
- if (sourceIndex === destIndex)
185
- return;
186
- const newData = [...dataSource];
187
- const [removed] = newData.splice(sourceIndex, 1);
188
- newData.splice(destIndex, 0, removed);
189
- (_a = draggable.onDragEnd) === null || _a === void 0 ? void 0 : _a.call(draggable, newData);
190
- }, [dataSource, draggable]);
191
- const sizeClass = size === 'sub' ? tableClasses.sub : tableClasses.main;
192
- // Scroll container style
213
+ /** Computed styles */
193
214
  const scrollContainerStyle = useMemo(() => {
194
215
  const containerStyle = {};
195
216
  if (scroll === null || scroll === void 0 ? void 0 : scroll.y) {
196
217
  containerStyle.maxHeight = scroll.y;
197
- containerStyle.overflowY = 'auto';
198
- }
199
- if (scroll === null || scroll === void 0 ? void 0 : scroll.x) {
200
- containerStyle.overflowX = 'auto';
201
218
  }
202
219
  if (nested) {
203
220
  containerStyle.position = 'unset';
204
221
  containerStyle.overflow = 'unset';
205
222
  }
223
+ if (minHeight) {
224
+ containerStyle.minHeight = minHeight;
225
+ }
206
226
  return containerStyle;
207
- }, [scroll === null || scroll === void 0 ? void 0 : scroll.x, scroll === null || scroll === void 0 ? void 0 : scroll.y, nested]);
208
- // Table style with min-width for horizontal scroll
227
+ }, [scroll === null || scroll === void 0 ? void 0 : scroll.y, nested, minHeight]);
209
228
  const tableStyle = useMemo(() => {
210
229
  const baseStyle = {};
211
- if (scroll === null || scroll === void 0 ? void 0 : scroll.x) {
212
- baseStyle.minWidth = scroll.x;
230
+ if (fullWidth) {
213
231
  baseStyle.width = '100%';
214
232
  }
215
233
  return baseStyle;
216
- }, [scroll === null || scroll === void 0 ? void 0 : scroll.x]);
217
- const { setContainerRef } = scrollState;
218
- const handleScrollContainerRef = useCallback((element) => {
219
- scrollContainerRef.current = element;
234
+ }, [fullWidth]);
235
+ /** Scroll Container Ref */
236
+ const droppableInnerRefSetter = useRef(null);
237
+ const composedScrollContainerRef = useCallback((element) => {
220
238
  setContainerRef(element);
239
+ if (droppableInnerRefSetter.current) {
240
+ droppableInnerRefSetter.current(element);
241
+ }
221
242
  }, [setContainerRef]);
222
- const mainTable = (jsx(TableContext.Provider, { value: contextValue, children: jsx(TableDataContext.Provider, { value: dataContextValue, children: jsxs("div", { className: cx(tableClasses.host, className), ref: ref, style: style, ...restProps, children: [jsx("div", { className: cx(tableClasses.scrollContainer, {
223
- [tableClasses.sticky]: !!sticky,
224
- }), onScroll: scrollState.handleScroll, ref: handleScrollContainerRef, style: scrollContainerStyle, children: jsxs("table", { className: cx(tableClasses.root, sizeClass), ref: tableRef, style: tableStyle, children: [jsx(TableColGroup, {}), showHeader && jsx(TableHeader, {}), jsx(TableBody, {})] }) }), pagination && jsx(TablePagination, { ...pagination })] }) }) }));
243
+ /** Feature: bulk actions */
244
+ const bulkActionsConfig = useMemo(() => {
245
+ if (!selectionState || selectionState.mode !== 'checkbox') {
246
+ return null;
247
+ }
248
+ const checkboxConfig = selectionState.config;
249
+ return {
250
+ enabled: !!checkboxConfig.bulkActions && selectionState.selectedRowKeys.length,
251
+ bulkActions: checkboxConfig.bulkActions,
252
+ onClearSelection: () => checkboxConfig.onChange([], null, []),
253
+ selectedRowKeys: selectionState.selectedRowKeys,
254
+ };
255
+ }, [selectionState]);
256
+ const [isBulkActionsFixed, setIsBulkActionsFixed] = useState(false);
257
+ useEffect(() => {
258
+ if (!(bulkActionsConfig === null || bulkActionsConfig === void 0 ? void 0 : bulkActionsConfig.enabled)) {
259
+ return;
260
+ }
261
+ const calculateFixedState = () => {
262
+ const { current: hostEl } = hostRef;
263
+ if (!hostEl)
264
+ return;
265
+ const hostRect = hostEl.getBoundingClientRect();
266
+ const paginationHeightWithPx = hostEl.style.getPropertyValue('--mzn-table-pagination-height');
267
+ const paginationHeight = paginationHeightWithPx
268
+ ? Number(paginationHeightWithPx.replace('px', ''))
269
+ : 0;
270
+ const viewportHeight = window.innerHeight;
271
+ const bottomSpacing = getNumericCSSVariablePixelValue(`--${spacingPrefix}-padding-vertical-relaxed`);
272
+ const bulkActionsFixedBottom = viewportHeight - bottomSpacing;
273
+ const shouldBeFixed = hostRect.bottom > viewportHeight + paginationHeight &&
274
+ hostRect.top < bulkActionsFixedBottom;
275
+ setIsBulkActionsFixed(shouldBeFixed);
276
+ if (shouldBeFixed) {
277
+ /** Table 不一定在 viewport 中間 */
278
+ const centerLeft = hostRect.left + hostRect.width / 2;
279
+ hostEl.style.setProperty('--mzn-bulk-actions-fixed-left', `${centerLeft}px`);
280
+ }
281
+ };
282
+ /** @NOTE 如果覺得位置更新的不夠即時,再把 throttle 拔掉 (目前先以減少觸發次數做效能優化) */
283
+ const throttledCalculateFixedState = throttle(calculateFixedState, 50);
284
+ calculateFixedState();
285
+ window.addEventListener('scroll', throttledCalculateFixedState, false);
286
+ window.addEventListener('resize', throttledCalculateFixedState, false);
287
+ return () => {
288
+ throttledCalculateFixedState.cancel();
289
+ window.removeEventListener('scroll', throttledCalculateFixedState, false);
290
+ window.removeEventListener('resize', throttledCalculateFixedState, false);
291
+ };
292
+ }, [bulkActionsConfig === null || bulkActionsConfig === void 0 ? void 0 : bulkActionsConfig.enabled]);
293
+ /** Get Dynamic Pagination Height */
294
+ const paginationRef = useRef(null);
295
+ useEffect(() => {
296
+ const { current: paginationEl } = paginationRef;
297
+ if (paginationEl) {
298
+ const resizeObserver = new ResizeObserver(() => {
299
+ var _a;
300
+ (_a = hostRef.current) === null || _a === void 0 ? void 0 : _a.style.setProperty('--mzn-table-pagination-height', `${paginationEl.offsetHeight}px`);
301
+ });
302
+ resizeObserver.observe(paginationEl);
303
+ return () => {
304
+ resizeObserver.disconnect();
305
+ };
306
+ }
307
+ return;
308
+ }, []);
309
+ /** Main render */
310
+ const renderMainTable = (droppableProvided) => {
311
+ if (droppableProvided) {
312
+ droppableInnerRefSetter.current = droppableProvided.innerRef;
313
+ }
314
+ else {
315
+ droppableInnerRefSetter.current = null;
316
+ }
317
+ return (jsx(TableContext.Provider, { value: contextValue, children: jsx(TableDataContext.Provider, { value: dataContextValue, children: jsxs("div", { className: cx(tableClasses.host, className), ref: composedHostRef, style: style, ...restProps, children: [jsx("div", { ...droppableProvided === null || droppableProvided === void 0 ? void 0 : droppableProvided.droppableProps, className: cx(tableClasses.scrollContainer, {
318
+ [tableClasses.sticky]: !!sticky,
319
+ }), onScroll: handleScroll, ref: droppableProvided ? composedScrollContainerRef : setContainerRef, style: scrollContainerStyle, children: jsxs("table", { className: cx(tableClasses.root, size === 'sub' ? tableClasses.sub : tableClasses.main), style: tableStyle, children: [jsx(TableColGroup, {}), showHeader && jsx(TableHeader, {}), jsx(TableBody, {}), (droppableProvided === null || droppableProvided === void 0 ? void 0 : droppableProvided.placeholder) ? (jsx("tbody", { children: droppableProvided.placeholder })) : null] }) }), pagination && (jsx(TablePagination, { ...pagination, ref: paginationRef })), (bulkActionsConfig === null || bulkActionsConfig === void 0 ? void 0 : bulkActionsConfig.enabled) ? (jsx(TableBulkActions, { bulkActions: bulkActionsConfig.bulkActions, isFixed: isBulkActionsFixed, onClearSelection: bulkActionsConfig.onClearSelection, selectedRowKeys: bulkActionsConfig.selectedRowKeys })) : null] }) }) }));
320
+ };
225
321
  if (nested) {
226
- return mainTable;
322
+ return renderMainTable();
227
323
  }
228
- return (jsx(DragDropContext, { onDragEnd: handleDragEnd, children: jsx(Droppable, { droppableId: "mzn-table-v2-dnd", children: (provided) => (jsxs("div", { ...provided.droppableProps, ref: composeRefs([hostRef, provided.innerRef]), children: [jsx(TableSuperContext.Provider, { value: superContextValue, children: mainTable }), provided.placeholder] })) }) }));
324
+ return (jsx(DragDropContext, { onDragEnd: handleDragEnd, children: jsx(Droppable, { droppableId: "mzn-table-dnd", children: (provided) => (jsx(TableSuperContext.Provider, { value: superContextValue, children: renderMainTable(provided) })) }) }));
229
325
  }
230
326
  /**
231
327
  * Table is a high-performance data table component with support for