@astryxdesign/core 0.1.1 → 0.1.2-canary.3893cd5

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 (169) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +119 -1
  3. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  4. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  5. package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
  6. package/dist/Banner/Banner.d.ts +7 -0
  7. package/dist/Banner/Banner.d.ts.map +1 -1
  8. package/dist/Banner/Banner.js +9 -2
  9. package/dist/Button/Button.d.ts +12 -2
  10. package/dist/Button/Button.d.ts.map +1 -1
  11. package/dist/Button/Button.js +51 -13
  12. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  13. package/dist/EmptyState/EmptyState.js +7 -1
  14. package/dist/HoverCard/HoverCard.d.ts +2 -2
  15. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  16. package/dist/HoverCard/HoverCard.js +18 -6
  17. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  18. package/dist/HoverCard/useHoverCard.js +7 -3
  19. package/dist/Kbd/Kbd.d.ts.map +1 -1
  20. package/dist/Kbd/Kbd.js +1 -1
  21. package/dist/Layer/anchorName.d.ts +20 -0
  22. package/dist/Layer/anchorName.d.ts.map +1 -0
  23. package/dist/Layer/anchorName.js +36 -0
  24. package/dist/Layer/useLayer.d.ts +19 -0
  25. package/dist/Layer/useLayer.d.ts.map +1 -1
  26. package/dist/Layer/useLayer.js +15 -6
  27. package/dist/Link/Link.d.ts +1 -1
  28. package/dist/Link/Link.js +2 -2
  29. package/dist/Link/LinkProvider.d.ts +1 -0
  30. package/dist/Link/LinkProvider.d.ts.map +1 -1
  31. package/dist/Link/LinkProvider.js +1 -0
  32. package/dist/Markdown/Markdown.d.ts.map +1 -1
  33. package/dist/Markdown/Markdown.js +13 -3
  34. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  35. package/dist/MobileNav/MobileNav.js +13 -0
  36. package/dist/Pagination/Pagination.d.ts.map +1 -1
  37. package/dist/Pagination/Pagination.js +31 -27
  38. package/dist/Slider/Slider.js +2 -2
  39. package/dist/Table/BaseTable.d.ts.map +1 -1
  40. package/dist/Table/BaseTable.js +27 -8
  41. package/dist/Table/Table.d.ts.map +1 -1
  42. package/dist/Table/Table.js +30 -7
  43. package/dist/Table/TableRow.d.ts +6 -1
  44. package/dist/Table/TableRow.d.ts.map +1 -1
  45. package/dist/Table/TableRow.js +15 -7
  46. package/dist/Table/index.d.ts +3 -1
  47. package/dist/Table/index.d.ts.map +1 -1
  48. package/dist/Table/index.js +1 -0
  49. package/dist/Table/plugins/stickyColumns/index.d.ts +3 -0
  50. package/dist/Table/plugins/stickyColumns/index.d.ts.map +1 -0
  51. package/dist/Table/plugins/stickyColumns/index.js +3 -0
  52. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts +25 -0
  53. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -0
  54. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +369 -0
  55. package/dist/Table/types.d.ts +95 -5
  56. package/dist/Table/types.d.ts.map +1 -1
  57. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  58. package/dist/Table/useBaseTablePlugins.js +1 -1
  59. package/dist/Text/text.stylex.d.ts +2 -2
  60. package/dist/Text/text.stylex.js +2 -2
  61. package/dist/Timestamp/Timestamp.d.ts +1 -1
  62. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  63. package/dist/Timestamp/Timestamp.js +28 -3
  64. package/dist/ToggleButton/ToggleButton.d.ts +7 -9
  65. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  66. package/dist/ToggleButton/ToggleButton.js +34 -57
  67. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  68. package/dist/Tokenizer/Tokenizer.js +1 -1
  69. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  70. package/dist/Tooltip/useTooltip.js +1 -0
  71. package/dist/astryx.css +30 -1
  72. package/dist/astryx.umd.js +147 -0
  73. package/dist/astryx.umd.js.map +7 -0
  74. package/dist/theme/generateThemeRules.js +1 -1
  75. package/dist/theme/syntax/SyntaxTheme.d.ts +1 -1
  76. package/dist/theme/syntax/SyntaxTheme.js +1 -1
  77. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  78. package/dist/theme/syntax/defineSyntaxTheme.js +2 -2
  79. package/dist/theme/syntax/presets.d.ts +1 -1
  80. package/dist/theme/syntax/presets.d.ts.map +1 -1
  81. package/dist/theme/syntax/presets.js +1 -1
  82. package/dist/theme/syntax/tokens.d.ts +1 -1
  83. package/dist/theme/syntax/tokens.js +1 -1
  84. package/dist/theme/types.d.ts +1 -1
  85. package/package.json +6 -2
  86. package/src/AvatarGroup/AvatarGroupOverflow.tsx +3 -0
  87. package/src/Banner/Banner.doc.mjs +8 -0
  88. package/src/Banner/Banner.test.tsx +16 -7
  89. package/src/Banner/Banner.tsx +9 -2
  90. package/src/Button/Button.doc.mjs +6 -0
  91. package/src/Button/Button.test.tsx +105 -11
  92. package/src/Button/Button.tsx +73 -5
  93. package/src/Chat/ChatComposer.doc.mjs +3 -0
  94. package/src/Chat/ChatComposerDrawer.doc.mjs +12 -0
  95. package/src/CheckboxInput/CheckboxInput.doc.mjs +8 -0
  96. package/src/ClickableCard/ClickableCard.doc.mjs +15 -0
  97. package/src/Dialog/Dialog.doc.mjs +2 -2
  98. package/src/EmptyState/EmptyState.test.tsx +4 -2
  99. package/src/EmptyState/EmptyState.tsx +6 -2
  100. package/src/HoverCard/HoverCard.doc.mjs +3 -0
  101. package/src/HoverCard/HoverCard.test.tsx +189 -2
  102. package/src/HoverCard/HoverCard.tsx +20 -16
  103. package/src/HoverCard/useHoverCard.tsx +13 -10
  104. package/src/Icon/Icon.doc.mjs +8 -0
  105. package/src/Kbd/Kbd.tsx +2 -9
  106. package/src/Layer/anchorName.test.ts +146 -0
  107. package/src/Layer/anchorName.ts +46 -0
  108. package/src/Layer/useLayer.doc.mjs +7 -2
  109. package/src/Layer/useLayer.tsx +33 -9
  110. package/src/Layout/Layout.doc.mjs +1 -1
  111. package/src/Lightbox/Lightbox.doc.mjs +0 -2
  112. package/src/Link/Link.test.tsx +2 -2
  113. package/src/Link/Link.tsx +3 -3
  114. package/src/Link/LinkProvider.tsx +1 -0
  115. package/src/List/List.doc.mjs +7 -0
  116. package/src/Markdown/Markdown.doc.mjs +2 -0
  117. package/src/Markdown/Markdown.test.tsx +17 -26
  118. package/src/Markdown/Markdown.tsx +16 -6
  119. package/src/MobileNav/MobileNav.doc.mjs +8 -8
  120. package/src/MobileNav/MobileNav.tsx +13 -0
  121. package/src/MobileNav/MobileNavReopen.test.tsx +118 -0
  122. package/src/OverflowList/OverflowList.doc.mjs +17 -0
  123. package/src/Pagination/Pagination.test.tsx +137 -13
  124. package/src/Pagination/Pagination.tsx +33 -28
  125. package/src/ProgressBar/ProgressBar.test.tsx +13 -3
  126. package/src/Resizable/Resizable.doc.mjs +1 -1
  127. package/src/Section/Section.doc.mjs +11 -0
  128. package/src/SelectableCard/SelectableCard.doc.mjs +15 -0
  129. package/src/Selector/Selector.doc.mjs +4 -0
  130. package/src/Skeleton/Skeleton.doc.mjs +11 -1
  131. package/src/Slider/Slider.doc.mjs +4 -0
  132. package/src/Slider/Slider.test.tsx +3 -16
  133. package/src/Slider/Slider.tsx +1 -1
  134. package/src/TabList/TabList.doc.mjs +6 -0
  135. package/src/Table/BaseTable.tsx +51 -24
  136. package/src/Table/Table.doc.mjs +12 -0
  137. package/src/Table/Table.test.tsx +29 -30
  138. package/src/Table/Table.tsx +22 -1
  139. package/src/Table/TableRow.tsx +37 -7
  140. package/src/Table/index.ts +3 -0
  141. package/src/Table/plugins/stickyColumns/index.ts +4 -0
  142. package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +163 -0
  143. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +407 -0
  144. package/src/Table/types.ts +101 -4
  145. package/src/Table/useBaseTablePlugins.ts +1 -0
  146. package/src/Table/useTableColumnResize.doc.mjs +96 -0
  147. package/src/Table/useTableStickyColumns.doc.mjs +59 -0
  148. package/src/Text/Heading.doc.mjs +15 -2
  149. package/src/Text/Text.doc.mjs +7 -1
  150. package/src/Text/text.stylex.ts +2 -2
  151. package/src/Timestamp/Timestamp.doc.mjs +9 -0
  152. package/src/Timestamp/Timestamp.test.tsx +44 -18
  153. package/src/Timestamp/Timestamp.tsx +30 -10
  154. package/src/ToggleButton/ToggleButton.doc.mjs +9 -3
  155. package/src/ToggleButton/ToggleButton.test.tsx +39 -18
  156. package/src/ToggleButton/ToggleButton.tsx +46 -83
  157. package/src/Tokenizer/Tokenizer.tsx +4 -1
  158. package/src/Toolbar/Toolbar.doc.mjs +65 -5
  159. package/src/Tooltip/Tooltip.test.tsx +13 -0
  160. package/src/Tooltip/useTooltip.tsx +2 -3
  161. package/src/hooks/useImageMode.test.ts +133 -0
  162. package/src/theme/derivedVarRegistry.test.ts +4 -0
  163. package/src/theme/generateThemeRules.test.ts +7 -8
  164. package/src/theme/generateThemeRules.ts +1 -1
  165. package/src/theme/syntax/SyntaxTheme.tsx +1 -1
  166. package/src/theme/syntax/defineSyntaxTheme.ts +20 -11
  167. package/src/theme/syntax/presets.ts +5 -2
  168. package/src/theme/syntax/tokens.ts +1 -1
  169. package/src/theme/types.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"TableRow.d.ts","sourceRoot":"","sources":["../../src/Table/TableRow.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,EAAM,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAMjD,+CAA+C;AAC/C,MAAM,WAAW,aAAc,SAAQ,SAAS,CAAC,mBAAmB,CAAC;IACnE,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;CACzB;AAwCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,MAAM,EACN,GAAG,EACH,GAAG,KAAK,EACT,EAAE,aAAa,+BAgDf;yBArDe,QAAQ"}
1
+ {"version":3,"file":"TableRow.d.ts","sourceRoot":"","sources":["../../src/Table/TableRow.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,EAAM,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAMjD,+CAA+C;AAC/C,MAAM,WAAW,aAAc,SAAQ,SAAS,CAAC,mBAAmB,CAAC;IACnE,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACrC,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AA4DD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,MAAM,EACN,GAAG,EACH,WAAmB,EACnB,GAAG,KAAK,EACT,EAAE,aAAa,+BAoDf;yBA1De,QAAQ"}
@@ -27,12 +27,14 @@ import { jsx as _jsx } from "react/jsx-runtime";
27
27
  const stripedRowStyles = {
28
28
  row: {
29
29
  kWkggS: "x1dnou9g",
30
+ "--table-row-overlay": "x1rht92",
30
31
  $$css: true
31
32
  }
32
33
  };
33
34
  const hoverRowStyles = {
34
35
  row: {
35
36
  kWkggS: "xe9uy6x",
37
+ "--table-row-overlay": "x1pkcbo2",
36
38
  k1ekBW: "x15406qy",
37
39
  kIyJzY: "xuedmi6",
38
40
  kAMwcw: "xlr8y92",
@@ -42,6 +44,7 @@ const hoverRowStyles = {
42
44
  const stripedHoverRowStyles = {
43
45
  row: {
44
46
  kWkggS: "x1dnou9g xe9uy6x",
47
+ "--table-row-overlay": "x1rht92 x1pkcbo2",
45
48
  k1ekBW: "x15406qy",
46
49
  kIyJzY: "xuedmi6",
47
50
  kAMwcw: "xlr8y92",
@@ -69,6 +72,7 @@ export function TableRow({
69
72
  children,
70
73
  xstyle,
71
74
  ref,
75
+ isHeaderRow = false,
72
76
  ...props
73
77
  }) {
74
78
  const ctx = use(TableContext);
@@ -82,13 +86,17 @@ export function TableRow({
82
86
  }
83
87
  const rowStyles = [];
84
88
 
85
- // Handle striped + hover combination to avoid backgroundColor conflicts
86
- if (ctx.isStriped && ctx.hasHover) {
87
- rowStyles.push(stripedHoverRowStyles.row);
88
- } else if (ctx.isStriped) {
89
- rowStyles.push(stripedRowStyles.row);
90
- } else if (ctx.hasHover) {
91
- rowStyles.push(hoverRowStyles.row);
89
+ // Striped + hover styling is for body rows only — the header row must not
90
+ // pick up the hover highlight (or striping) even when hasHover/isStriped.
91
+ if (!isHeaderRow) {
92
+ // Handle striped + hover combination to avoid backgroundColor conflicts
93
+ if (ctx.isStriped && ctx.hasHover) {
94
+ rowStyles.push(stripedHoverRowStyles.row);
95
+ } else if (ctx.isStriped) {
96
+ rowStyles.push(stripedRowStyles.row);
97
+ } else if (ctx.hasHover) {
98
+ rowStyles.push(hoverRowStyles.row);
99
+ }
92
100
  }
93
101
  if (ctx.dividers === 'rows' || ctx.dividers === 'grid') {
94
102
  // Note: last-body-row border removal is handled by TableCell
@@ -22,10 +22,11 @@ export { useTablePagination, paginateData } from './plugins/pagination';
22
22
  export { useTableColumnSettings } from './plugins/columnSettings';
23
23
  export { useTableColumnSettingsState } from './plugins/columnSettings';
24
24
  export { useTableColumnResize } from './plugins/columnResize';
25
+ export { useTableStickyColumns } from './plugins/stickyColumns';
25
26
  export { useTableFiltering, useTableFilterState, toSearchFilters, } from './plugins/filtering';
26
27
  export { useBaseTablePlugins } from './useBaseTablePlugins';
27
28
  export { proportional, pixel, generateColumns, resolveColumnWidths, DEFAULT_MIN_COLUMN_WIDTH, } from './columnUtils';
28
- export type { TableColumn, TableColumnAlign, TableVerticalAlign, ColumnWidth, ProportionalWidth, PixelWidth, TablePlugin, TableRenderProps, HeaderRowRenderProps, HeaderCellRenderProps, BodyRowRenderProps, BodyCellRenderProps, BaseTableProps, } from './types';
29
+ export type { TableColumn, TableColumnAlign, TableVerticalAlign, ColumnWidth, ProportionalWidth, PixelWidth, TablePlugin, TableRenderProps, HeaderRowRenderProps, HeaderCellRenderProps, BodyRowRenderProps, BodyCellRenderProps, ScrollWrapperRenderProps, BaseTableProps, } from './types';
29
30
  export type { TableProps, TableDensity, TableDividers, TableTextOverflow, } from './Table';
30
31
  export type { TableRowProps } from './TableRow';
31
32
  export type { TableCellProps } from './TableCell';
@@ -42,5 +43,6 @@ export type { UseTablePaginationConfig } from './plugins/pagination';
42
43
  export type { UseTableColumnSettingsConfig, ColumnSettingsOption, } from './plugins/columnSettings';
43
44
  export type { UseTableColumnSettingsStateConfig, UseTableColumnSettingsStateReturn, } from './plugins/columnSettings';
44
45
  export type { UseTableColumnResizeConfig } from './plugins/columnResize';
46
+ export type { UseTableStickyColumnsConfig } from './plugins/stickyColumns';
45
47
  export type { UseTableFilteringConfig, TableFilterState, TableFilterVariant, TableFilterValue, TableFilterFieldRef, } from './plugins/filtering';
46
48
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,7 @@ export { useTablePagination, paginateData } from "./plugins/pagination/index.js"
26
26
  export { useTableColumnSettings } from "./plugins/columnSettings/index.js";
27
27
  export { useTableColumnSettingsState } from "./plugins/columnSettings/index.js";
28
28
  export { useTableColumnResize } from "./plugins/columnResize/index.js";
29
+ export { useTableStickyColumns } from "./plugins/stickyColumns/index.js";
29
30
  export { useTableFiltering, useTableFilterState, toSearchFilters } from "./plugins/filtering/index.js";
30
31
  export { useBaseTablePlugins } from "./useBaseTablePlugins.js";
31
32
  export { proportional, pixel, generateColumns, resolveColumnWidths, DEFAULT_MIN_COLUMN_WIDTH } from "./columnUtils.js";
@@ -0,0 +1,3 @@
1
+ export { useTableStickyColumns } from './useTableStickyColumns';
2
+ export type { UseTableStickyColumnsConfig } from './useTableStickyColumns';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/Table/plugins/stickyColumns/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,qBAAqB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,YAAY,EAAC,2BAA2B,EAAC,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,3 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ export { useTableStickyColumns } from "./useTableStickyColumns.js";
@@ -0,0 +1,25 @@
1
+ import type { TablePlugin } from '../../types';
2
+ /**
3
+ * Config for {@link useTableStickyColumns}. Provide at least one of
4
+ * `startKeys` / `endKeys` to pin columns.
5
+ *
6
+ * @remarks Every field is optional by design, so `useTableStickyColumns({})`
7
+ * compiles and is an intentional no-op that pins nothing — the hook returns a
8
+ * plugin that passes every cell through untouched. This lets callers compute
9
+ * the config conditionally (e.g. `endKeys: enabled ? ['notes'] : undefined`)
10
+ * without branching on whether to install the plugin at all.
11
+ */
12
+ export interface UseTableStickyColumnsConfig {
13
+ /**
14
+ * Column keys pinned to the START (inline-start / left in LTR) edge — the
15
+ * contiguous run from the first column through the last listed key.
16
+ */
17
+ startKeys?: string[];
18
+ /**
19
+ * Column keys pinned to the END (inline-end / right in LTR) edge — the
20
+ * contiguous run from the first listed key through the last column.
21
+ */
22
+ endKeys?: string[];
23
+ }
24
+ export declare function useTableStickyColumns<T extends Record<string, unknown>>(config: UseTableStickyColumnsConfig): TablePlugin<T>;
25
+ //# sourceMappingURL=useTableStickyColumns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTableStickyColumns.d.ts","sourceRoot":"","sources":["../../../../src/Table/plugins/stickyColumns/useTableStickyColumns.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAEV,WAAW,EAIZ,MAAM,aAAa,CAAC;AAOrB;;;;;;;;;GASG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AA6MD,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrE,MAAM,EAAE,2BAA2B,GAClC,WAAW,CAAC,CAAC,CAAC,CAmJhB"}
@@ -0,0 +1,369 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useTableStickyColumns.tsx
7
+ * @input React, StyleX, theme tokens, Table types
8
+ * @output Exports useTableStickyColumns hook and UseTableStickyColumnsConfig type
9
+ * @position Sticky-columns plugin; consumed by Table via plugins prop
10
+ *
11
+ * SYNC: When modified, update these files to stay in sync:
12
+ * - /packages/core/src/Table/Table.doc.mjs (sticky-columns documentation)
13
+ * - /packages/core/src/Table/index.ts (exports)
14
+ */
15
+ import { useCallback, useMemo, useRef } from 'react';
16
+ import * as stylex from '@stylexjs/stylex';
17
+ import "../../../theme/tokens.stylex.js";
18
+ import { colorVars, durationVars, easeVars } from "../../../theme/tokens.stylex.js";
19
+ import { DEFAULT_MIN_COLUMN_WIDTH } from "../../columnUtils.js";
20
+
21
+ // =============================================================================
22
+ // Config
23
+ // =============================================================================
24
+
25
+ /**
26
+ * Config for {@link useTableStickyColumns}. Provide at least one of
27
+ * `startKeys` / `endKeys` to pin columns.
28
+ *
29
+ * @remarks Every field is optional by design, so `useTableStickyColumns({})`
30
+ * compiles and is an intentional no-op that pins nothing — the hook returns a
31
+ * plugin that passes every cell through untouched. This lets callers compute
32
+ * the config conditionally (e.g. `endKeys: enabled ? ['notes'] : undefined`)
33
+ * without branching on whether to install the plugin at all.
34
+ */
35
+
36
+ // =============================================================================
37
+ // Width helpers
38
+ // =============================================================================
39
+
40
+ /**
41
+ * Resolve a column's pixel width for cumulative offset math. Mirrors the
42
+ * resize plugin's fallback so offsets line up with rendered widths:
43
+ * pixel columns use their value; proportional columns use their declared
44
+ * minWidth (or the default); unknown widths use the default.
45
+ */
46
+ function getColumnWidth(col) {
47
+ const w = col.width;
48
+ if (!w) {
49
+ return DEFAULT_MIN_COLUMN_WIDTH;
50
+ }
51
+ if (w.type === 'pixel') {
52
+ return w.value;
53
+ }
54
+ // proportional
55
+ return w.minWidth ?? DEFAULT_MIN_COLUMN_WIDTH;
56
+ }
57
+
58
+ /**
59
+ * Columns pinned to the START edge → cumulative inline offset (px). The pinned
60
+ * block is the contiguous run from column 0 through the last key in `startKeys`
61
+ * (inclusive of any synthetic columns before it). `null` if none / no context.
62
+ */
63
+ function computeStartOffsets(columns, startKeys) {
64
+ if (!columns || columns.length === 0 || startKeys.length === 0) {
65
+ return null;
66
+ }
67
+ let lastStickyIndex = -1;
68
+ for (let i = 0; i < columns.length; i++) {
69
+ if (startKeys.includes(columns[i].key)) {
70
+ lastStickyIndex = i;
71
+ }
72
+ }
73
+ if (lastStickyIndex === -1) {
74
+ return null;
75
+ }
76
+ const offsets = new Map();
77
+ let cumulative = 0;
78
+ for (let i = 0; i <= lastStickyIndex; i++) {
79
+ offsets.set(columns[i].key, cumulative);
80
+ cumulative += getColumnWidth(columns[i]);
81
+ }
82
+ return offsets;
83
+ }
84
+
85
+ /**
86
+ * Mirror of {@link computeStartOffsets} for the END edge — contiguous run from
87
+ * the first key in `endKeys` through the last column, offsets accumulating from
88
+ * the end (last column = 0). `null` if none.
89
+ */
90
+ function computeEndOffsets(columns, endKeys) {
91
+ if (!columns || columns.length === 0 || endKeys.length === 0) {
92
+ return null;
93
+ }
94
+ let firstStickyIndex = -1;
95
+ for (let i = 0; i < columns.length; i++) {
96
+ if (endKeys.includes(columns[i].key)) {
97
+ firstStickyIndex = i;
98
+ break;
99
+ }
100
+ }
101
+ if (firstStickyIndex === -1) {
102
+ return null;
103
+ }
104
+ const offsets = new Map();
105
+ let cumulative = 0;
106
+ for (let i = columns.length - 1; i >= firstStickyIndex; i--) {
107
+ offsets.set(columns[i].key, cumulative);
108
+ cumulative += getColumnWidth(columns[i]);
109
+ }
110
+ return offsets;
111
+ }
112
+ /**
113
+ * Resolve how a single column should be pinned given the start/end configs and
114
+ * the full column list. A key (mis)configured on both edges resolves to start.
115
+ * Returns `null` for columns that should not be pinned.
116
+ */
117
+ function resolveStickySide(columns, columnKey, startKeys, endKeys) {
118
+ const startOffsets = computeStartOffsets(columns, startKeys);
119
+ if (startOffsets?.has(columnKey)) {
120
+ return {
121
+ edge: 'start',
122
+ offset: startOffsets.get(columnKey) ?? 0
123
+ };
124
+ }
125
+ const endOffsets = computeEndOffsets(columns, endKeys);
126
+ if (endOffsets?.has(columnKey)) {
127
+ return {
128
+ edge: 'end',
129
+ offset: endOffsets.get(columnKey) ?? 0
130
+ };
131
+ }
132
+ return null;
133
+ }
134
+
135
+ // =============================================================================
136
+ // Styles
137
+ // =============================================================================
138
+
139
+ // Scroll-state CSS variables set on the scroll container by the layout ref;
140
+ // the cell ::after shadows read them so each edge's shadow only shows when
141
+ // content is hidden behind it. (A variable, not stylex.when.ancestor, because
142
+ // StyleX ancestor selectors are pseudo-class only — not scroll state.)
143
+ const SHADOW_VAR_START = '--table-sticky-shadow-start';
144
+ const SHADOW_VAR_END = '--table-sticky-shadow-end';
145
+ const stickyStyles = {
146
+ cell: {
147
+ kVAEAm: "x7wzq59",
148
+ kWkggS: "x1fd97le",
149
+ kgeoSG: "x1cpjm7i",
150
+ kEoFBp: "x1hmns74",
151
+ kFcpXp: "xxx281p",
152
+ kxmVGU: "xy5mcqj",
153
+ km8f2m: "xkk1bqk",
154
+ kLkRvE: "x1uvfo0n",
155
+ k7KCAZ: "xxcwgru",
156
+ kKXxxB: "x1y1nw7a",
157
+ kqUdNP: "xa5v58t",
158
+ kHypHr: "xx83zyx",
159
+ kVQacm: "x1rea2x4",
160
+ $$css: true
161
+ },
162
+ headerCell: {
163
+ kY2c9j: "xzkaem6",
164
+ $$css: true
165
+ },
166
+ bodyCell: {
167
+ kY2c9j: "x1vjfegm",
168
+ $$css: true
169
+ }
170
+ };
171
+
172
+ // Soft drop shadow over the scrolling region (matches the EPS sticky treatment).
173
+ // border-collapse tables don't paint box-shadow on cells in Chromium, so it's a
174
+ // ::after gradient strip just past the pinned edge (visible thanks to the cell's
175
+ // overflow: visible). Opacity is gated by the scroll-state variable above.
176
+ const SHADOW_WIDTH = '6px';
177
+ // --color-shadow is only ~10% alpha (too faint here); use a slightly stronger soft tint.
178
+ const SHADOW_TINT = 'light-dark(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.32))';
179
+ const shadowStyles = {
180
+ start: {
181
+ k5JduY: "x1s928wv",
182
+ kwXMNM: "x1j6awrg",
183
+ k3foIR: "x1m1drc7",
184
+ k8Iv0R: "x1xrz1ek",
185
+ kH8aOt: "x1unh1gc",
186
+ kkgrvl: "xzkji8o",
187
+ kLigFv: "x1qyefdi",
188
+ kloYau: "x2q1x1w",
189
+ kFJxch: "x17s1k9h",
190
+ kypkao: "x1sggmfs",
191
+ kNctxI: "x156sm4c",
192
+ $$css: true
193
+ },
194
+ end: {
195
+ k5JduY: "x1s928wv",
196
+ kwXMNM: "x1j6awrg",
197
+ k3foIR: "x1m1drc7",
198
+ k8Iv0R: "x1xrz1ek",
199
+ kc1e00: "x1iygr5g",
200
+ kkgrvl: "xzkji8o",
201
+ kLigFv: "xvs0bi2",
202
+ kloYau: "x2q1x1w",
203
+ kFJxch: "x17s1k9h",
204
+ kypkao: "x1c2idit",
205
+ kNctxI: "x14ofgck",
206
+ $$css: true
207
+ }
208
+ };
209
+
210
+ // Stable empty default so an unset start/end doesn't allocate a fresh array
211
+ // (and bust the memo) on every render.
212
+ const EMPTY = [];
213
+
214
+ // =============================================================================
215
+ // Hook
216
+ // =============================================================================
217
+
218
+ export function useTableStickyColumns(config) {
219
+ const {
220
+ startKeys,
221
+ endKeys
222
+ } = config;
223
+ const start = startKeys ?? EMPTY;
224
+ const end = endKeys ?? EMPTY;
225
+ const hasStart = start.length > 0;
226
+ const hasEnd = end.length > 0;
227
+
228
+ // Live snapshot of the resolved config, read inside the (memoized) transforms
229
+ // and the scroll-shadow callback. Keeping these in a ref lets the plugin memo
230
+ // be computed once (deps: only the stable scroll-shadow callback) while never
231
+ // reading stale config — consumers typically pass fresh array literals each
232
+ // render, so we never want array identity in the deps.
233
+ const stateRef = useRef({
234
+ start,
235
+ end,
236
+ hasStart,
237
+ hasEnd
238
+ });
239
+ stateRef.current = {
240
+ start,
241
+ end,
242
+ hasStart,
243
+ hasEnd
244
+ };
245
+
246
+ // Scroll-aware shadows: toggle CSS variables on the scroll container so each
247
+ // edge's shadow only paints when there is hidden, horizontally-scrolled
248
+ // content behind that edge. Implemented with a callback ref + scroll/resize
249
+ // listeners (synchronizing with the DOM) rather than React state, so
250
+ // scrolling never triggers re-renders.
251
+ const detachRef = useRef(null);
252
+ const attachScrollShadow = useCallback(el => {
253
+ detachRef.current?.();
254
+ detachRef.current = null;
255
+ if (!el) {
256
+ return;
257
+ }
258
+ const update = () => {
259
+ const {
260
+ hasStart: hs,
261
+ hasEnd: he
262
+ } = stateRef.current;
263
+ const maxScroll = el.scrollWidth - el.clientWidth;
264
+ const hasOverflow = maxScroll > 1;
265
+ if (hs) {
266
+ el.style.setProperty(SHADOW_VAR_START, hasOverflow && el.scrollLeft > 1 ? '1' : '0');
267
+ }
268
+ if (he) {
269
+ el.style.setProperty(SHADOW_VAR_END, hasOverflow && el.scrollLeft < maxScroll - 1 ? '1' : '0');
270
+ }
271
+ };
272
+ el.addEventListener('scroll', update, {
273
+ passive: true
274
+ });
275
+ const resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(update) : null;
276
+ resizeObserver?.observe(el);
277
+ update();
278
+ detachRef.current = () => {
279
+ el.removeEventListener('scroll', update);
280
+ resizeObserver?.disconnect();
281
+ };
282
+ }, []);
283
+ return useMemo(() => ({
284
+ transformHeaderCell(props, column) {
285
+ const {
286
+ start: s,
287
+ end: e
288
+ } = stateRef.current;
289
+ const side = resolveStickySide(props.columns, column.key, s, e);
290
+ if (!side) {
291
+ return props;
292
+ }
293
+ // position/inline-offset are runtime values → set via inline style so
294
+ // they are authoritative regardless of plugin composition order (the
295
+ // resize plugin also writes inline style on header cells).
296
+ const offsetStyle = side.edge === 'start' ? {
297
+ insetInlineStart: `${side.offset}px`
298
+ } : {
299
+ insetInlineEnd: `${side.offset}px`
300
+ };
301
+ return {
302
+ ...props,
303
+ htmlProps: {
304
+ ...props.htmlProps,
305
+ style: {
306
+ ...props.htmlProps.style,
307
+ ...offsetStyle
308
+ }
309
+ },
310
+ styles: [...props.styles, stickyStyles.cell, stickyStyles.headerCell, side.edge === 'start' ? shadowStyles.start : shadowStyles.end]
311
+ };
312
+ },
313
+ transformBodyCell(props, column) {
314
+ const {
315
+ start: s,
316
+ end: e
317
+ } = stateRef.current;
318
+ const side = resolveStickySide(props.columns, column.key, s, e);
319
+ if (!side) {
320
+ return props;
321
+ }
322
+ const offsetStyle = side.edge === 'start' ? {
323
+ insetInlineStart: `${side.offset}px`
324
+ } : {
325
+ insetInlineEnd: `${side.offset}px`
326
+ };
327
+ return {
328
+ ...props,
329
+ htmlProps: {
330
+ ...props.htmlProps,
331
+ style: {
332
+ ...props.htmlProps.style,
333
+ ...offsetStyle
334
+ }
335
+ },
336
+ styles: [...props.styles, stickyStyles.cell, stickyStyles.bodyCell, side.edge === 'start' ? shadowStyles.start : shadowStyles.end]
337
+ };
338
+ },
339
+ transformScrollWrapper(props) {
340
+ // No pinned edges → nothing to gate; leave the wrapper untouched.
341
+ if (!stateRef.current.hasStart && !stateRef.current.hasEnd) {
342
+ return props;
343
+ }
344
+ // Compose with any ref a prior plugin (e.g. virtualization) set on the
345
+ // scroll container.
346
+ const existingRef = props.htmlProps.ref;
347
+ const mergedRef = node => {
348
+ attachScrollShadow(node);
349
+ if (typeof existingRef === 'function') {
350
+ existingRef(node);
351
+ } else if (existingRef != null) {
352
+ // RefObject — assign through its writable `.current`.
353
+ existingRef.current = node;
354
+ }
355
+ };
356
+ return {
357
+ ...props,
358
+ htmlProps: {
359
+ ...props.htmlProps,
360
+ ref: mergedRef
361
+ }
362
+ };
363
+ }
364
+ }),
365
+ // The returned plugin's transforms read live config from `stateRef` and
366
+ // `attachScrollShadow` is stable (empty deps), so the plugin object can be
367
+ // computed once and reused across renders.
368
+ [attachScrollShadow]);
369
+ }
@@ -217,6 +217,20 @@ export interface HeaderCellRenderProps {
217
217
  overlay?: ReactNode;
218
218
  /** Content rendered below the header label row (e.g. inline filter controls). */
219
219
  below?: ReactNode;
220
+ /**
221
+ * Index of this column within the final, ordered list of rendered columns
222
+ * (after column injection/reordering by other plugins). Populated by
223
+ * BaseTable. Optional for backward compatibility with hand-constructed
224
+ * renders in tests.
225
+ */
226
+ columnIndex?: number;
227
+ /**
228
+ * The full, final ordered list of columns being rendered (after column
229
+ * injection/reordering by other plugins). Populated by BaseTable so plugins
230
+ * can reason about column position — e.g. cumulative sticky offsets. Optional
231
+ * for backward compatibility.
232
+ */
233
+ columns?: ReadonlyArray<TableColumn<Record<string, unknown>>>;
220
234
  }
221
235
  /** Props passed through the plugin pipeline for each body `<tr>` */
222
236
  export interface BodyRowRenderProps {
@@ -230,6 +244,48 @@ export interface BodyRowRenderProps {
230
244
  export interface BodyCellRenderProps {
231
245
  htmlProps: TdHTMLAttributes<HTMLTableCellElement>;
232
246
  styles: StyleXStyles[];
247
+ /**
248
+ * Index of this cell's column within the final ordered column list.
249
+ * Mirrors the `columnIndex` passed to `transformHeaderCell`. Populated by
250
+ * BaseTable. Optional for backward compatibility with hand-constructed
251
+ * renders in tests.
252
+ */
253
+ columnIndex?: number;
254
+ /**
255
+ * The full, final ordered list of columns being rendered. Populated by
256
+ * BaseTable so plugins can reason about column position — e.g. cumulative
257
+ * sticky offsets. Optional for backward compatibility.
258
+ */
259
+ columns?: ReadonlyArray<TableColumn<Record<string, unknown>>>;
260
+ }
261
+ /**
262
+ * Props passed through the plugin pipeline for the scroll-wrapper region — the
263
+ * `<div>` wrapping the `<table>` element (the horizontal scroll container, see
264
+ * the `scrollWrapper` prop on `BaseTableProps`). Lets plugins attach a `ref` to
265
+ * the scrollable element (e.g. for scroll-aware sticky-column shadows or
266
+ * virtualization) and inject chrome before/after the table.
267
+ *
268
+ * Named after `scrollWrapper` (not "layout") to avoid ambiguity: it transforms
269
+ * the wrapper element, not the internal header/body/footer layout of `<table>`.
270
+ *
271
+ * Runs after `transformTable`/cell transforms but inside `transformTableContext`,
272
+ * so plugin chrome added here stays within any context providers but wraps the
273
+ * scroll area.
274
+ */
275
+ export interface ScrollWrapperRenderProps {
276
+ /**
277
+ * HTML attributes applied to the scroll container `<div>`, including an
278
+ * optional `ref`. Plugins compose refs by reading the existing `ref` and
279
+ * merging their own (see `useTableStickyColumns`).
280
+ */
281
+ htmlProps: HTMLAttributes<HTMLDivElement> & {
282
+ ref?: Ref<HTMLDivElement>;
283
+ };
284
+ styles: StyleXStyles[];
285
+ /** Content rendered before the `<table>`, inside the scroll container. */
286
+ beforeTable?: ReactNode;
287
+ /** Content rendered after the `<table>`, inside the scroll container. */
288
+ afterTable?: ReactNode;
233
289
  }
234
290
  /**
235
291
  * Table plugin — transforms render props at each structural level.
@@ -243,7 +299,8 @@ export interface BodyCellRenderProps {
243
299
  * 4. `transformHeaderCell` — transform each `<th>` props
244
300
  * 5. `transformBodyRow` — transform each body `<tr>` props
245
301
  * 6. `transformBodyCell` — transform each body `<td>` props
246
- * 7. `transformTableContext` — wrap the table output in context providers
302
+ * 7. `transformScrollWrapper` — transform the scroll-container wrapper around the table
303
+ * 8. `transformTableContext` — wrap the table output in context providers
247
304
  */
248
305
  export interface TablePlugin<T extends Record<string, unknown> = Record<string, unknown>> {
249
306
  /**
@@ -256,12 +313,29 @@ export interface TablePlugin<T extends Record<string, unknown> = Record<string,
256
313
  transformTable?: (props: TableRenderProps) => TableRenderProps;
257
314
  /** Transform the header `<tr>` props */
258
315
  transformHeaderRow?: (props: HeaderRowRenderProps) => HeaderRowRenderProps;
259
- /** Transform each `<th>` props */
260
- transformHeaderCell?: (props: HeaderCellRenderProps, column: TableColumn<T>) => HeaderCellRenderProps;
316
+ /**
317
+ * Transform each `<th>` props.
318
+ *
319
+ * `columnIndex` and the full `columns` list are provided for plugins that
320
+ * need to reason about column position (e.g. cumulative sticky offsets).
321
+ */
322
+ transformHeaderCell?: (props: HeaderCellRenderProps, column: TableColumn<T>, columnIndex: number, columns: ReadonlyArray<TableColumn<T>>) => HeaderCellRenderProps;
261
323
  /** Transform each body `<tr>` props */
262
324
  transformBodyRow?: (props: BodyRowRenderProps, item: T, index: number) => BodyRowRenderProps;
263
- /** Transform each body `<td>` props */
264
- transformBodyCell?: (props: BodyCellRenderProps, column: TableColumn<T>, item: T) => BodyCellRenderProps;
325
+ /**
326
+ * Transform each body `<td>` props.
327
+ *
328
+ * `columnIndex` and the full `columns` list are provided for plugins that
329
+ * need to reason about column position (e.g. cumulative sticky offsets).
330
+ */
331
+ transformBodyCell?: (props: BodyCellRenderProps, column: TableColumn<T>, item: T, columnIndex: number, columns: ReadonlyArray<TableColumn<T>>) => BodyCellRenderProps;
332
+ /**
333
+ * Transform the scroll-wrapper region — the `<div>` wrapping the `<table>`
334
+ * (see the `scrollWrapper` prop). Use to attach a `ref` to the scrollable
335
+ * element (scroll-aware shadows, virtualization) or to inject chrome
336
+ * before/after the table.
337
+ */
338
+ transformScrollWrapper?: (props: ScrollWrapperRenderProps) => ScrollWrapperRenderProps;
265
339
  /** Wrap the table output in context providers */
266
340
  transformTableContext?: (children: ReactNode) => ReactNode;
267
341
  }
@@ -271,6 +345,11 @@ export interface TableRowComponentProps extends HTMLAttributes<HTMLTableRowEleme
271
345
  ref?: Ref<HTMLTableRowElement>;
272
346
  children: ReactNode;
273
347
  xstyle?: StyleXStyles[];
348
+ /**
349
+ * Whether this row is the header row. Header rows skip the striped/hover
350
+ * row styling, which is only meant for body rows.
351
+ */
352
+ isHeaderRow?: boolean;
274
353
  }
275
354
  /** Props for cell components used in the components prop */
276
355
  export interface TableCellComponentProps extends TdHTMLAttributes<HTMLTableCellElement> {
@@ -311,9 +390,20 @@ export interface BaseTableProps<T extends Record<string, unknown>> extends BaseP
311
390
  * plugin `transformTableContext` layer. Used by `Table` to add a
312
391
  * horizontal scroll container so plugin chrome (pagination, toolbars)
313
392
  * stays outside the scrollable area.
393
+ *
394
+ * Receives `htmlProps` (including an optional `ref`) and `styles` produced
395
+ * by the plugin `transformScrollWrapper` pipeline, plus `beforeTable`/`afterTable`
396
+ * chrome. The wrapper must spread `htmlProps` (and apply `styles`) onto its
397
+ * scroll-container element so plugins can attach refs / scroll listeners.
314
398
  */
315
399
  scrollWrapper?: ComponentType<{
316
400
  children: ReactNode;
401
+ htmlProps?: HTMLAttributes<HTMLDivElement> & {
402
+ ref?: Ref<HTMLDivElement>;
403
+ };
404
+ styles?: StyleXStyles[];
405
+ beforeTable?: ReactNode;
406
+ afterTable?: ReactNode;
317
407
  }>;
318
408
  /**
319
409
  * How default-rendered body cell text behaves when it exceeds column width.