@astryxdesign/core 0.1.1 → 0.1.2-canary.03536f1

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 (207) 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/Calendar/Calendar.d.ts +5 -4
  13. package/dist/Calendar/Calendar.d.ts.map +1 -1
  14. package/dist/Calendar/Calendar.js +6 -1
  15. package/dist/Calendar/index.d.ts +1 -1
  16. package/dist/Calendar/index.d.ts.map +1 -1
  17. package/dist/DateTimeInput/DateTimeInput.d.ts +7 -2
  18. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  19. package/dist/DateTimeInput/DateTimeInput.js +5 -4
  20. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  21. package/dist/EmptyState/EmptyState.js +7 -1
  22. package/dist/HoverCard/HoverCard.d.ts +2 -2
  23. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  24. package/dist/HoverCard/HoverCard.js +18 -6
  25. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  26. package/dist/HoverCard/useHoverCard.js +7 -3
  27. package/dist/Kbd/Kbd.d.ts.map +1 -1
  28. package/dist/Kbd/Kbd.js +1 -1
  29. package/dist/Layer/anchorName.d.ts +20 -0
  30. package/dist/Layer/anchorName.d.ts.map +1 -0
  31. package/dist/Layer/anchorName.js +36 -0
  32. package/dist/Layer/useLayer.d.ts +19 -0
  33. package/dist/Layer/useLayer.d.ts.map +1 -1
  34. package/dist/Layer/useLayer.js +15 -6
  35. package/dist/Link/Link.d.ts +10 -1
  36. package/dist/Link/Link.d.ts.map +1 -1
  37. package/dist/Link/Link.js +7 -2
  38. package/dist/Link/LinkProvider.d.ts +1 -0
  39. package/dist/Link/LinkProvider.d.ts.map +1 -1
  40. package/dist/Link/LinkProvider.js +1 -0
  41. package/dist/Markdown/Markdown.d.ts.map +1 -1
  42. package/dist/Markdown/Markdown.js +13 -3
  43. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  44. package/dist/MobileNav/MobileNav.js +13 -0
  45. package/dist/Pagination/Pagination.d.ts.map +1 -1
  46. package/dist/Pagination/Pagination.js +31 -27
  47. package/dist/Slider/Slider.js +2 -2
  48. package/dist/Table/BaseTable.d.ts.map +1 -1
  49. package/dist/Table/BaseTable.js +38 -16
  50. package/dist/Table/Table.d.ts.map +1 -1
  51. package/dist/Table/Table.js +30 -7
  52. package/dist/Table/TableCell.d.ts +8 -1
  53. package/dist/Table/TableCell.d.ts.map +1 -1
  54. package/dist/Table/TableCell.js +10 -10
  55. package/dist/Table/TableHeaderCell.d.ts +8 -1
  56. package/dist/Table/TableHeaderCell.d.ts.map +1 -1
  57. package/dist/Table/TableHeaderCell.js +16 -16
  58. package/dist/Table/TableRow.d.ts +6 -1
  59. package/dist/Table/TableRow.d.ts.map +1 -1
  60. package/dist/Table/TableRow.js +15 -7
  61. package/dist/Table/index.d.ts +4 -1
  62. package/dist/Table/index.d.ts.map +1 -1
  63. package/dist/Table/index.js +2 -0
  64. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  65. package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
  66. package/dist/Table/plugins/stickyColumns/index.d.ts +3 -0
  67. package/dist/Table/plugins/stickyColumns/index.d.ts.map +1 -0
  68. package/dist/Table/plugins/stickyColumns/index.js +3 -0
  69. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts +25 -0
  70. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -0
  71. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +369 -0
  72. package/dist/Table/tableContextMenu.d.ts +33 -0
  73. package/dist/Table/tableContextMenu.d.ts.map +1 -0
  74. package/dist/Table/tableContextMenu.js +136 -0
  75. package/dist/Table/types.d.ts +161 -5
  76. package/dist/Table/types.d.ts.map +1 -1
  77. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  78. package/dist/Table/useBaseTablePlugins.js +1 -1
  79. package/dist/Text/text.stylex.d.ts +2 -2
  80. package/dist/Text/text.stylex.js +2 -2
  81. package/dist/Timestamp/Timestamp.d.ts +1 -1
  82. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  83. package/dist/Timestamp/Timestamp.js +28 -3
  84. package/dist/ToggleButton/ToggleButton.d.ts +7 -9
  85. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  86. package/dist/ToggleButton/ToggleButton.js +34 -57
  87. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  88. package/dist/Tokenizer/Tokenizer.js +1 -1
  89. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  90. package/dist/Tooltip/useTooltip.js +1 -0
  91. package/dist/astryx.css +30 -1
  92. package/dist/astryx.umd.js +147 -0
  93. package/dist/astryx.umd.js.map +7 -0
  94. package/dist/theme/generateThemeRules.js +1 -1
  95. package/dist/theme/syntax/SyntaxTheme.d.ts +1 -1
  96. package/dist/theme/syntax/SyntaxTheme.js +1 -1
  97. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  98. package/dist/theme/syntax/defineSyntaxTheme.js +2 -2
  99. package/dist/theme/syntax/presets.d.ts +1 -1
  100. package/dist/theme/syntax/presets.d.ts.map +1 -1
  101. package/dist/theme/syntax/presets.js +1 -1
  102. package/dist/theme/syntax/tokens.d.ts +1 -1
  103. package/dist/theme/syntax/tokens.js +1 -1
  104. package/dist/theme/types.d.ts +1 -1
  105. package/dist/utils/dateTypes.d.ts +12 -0
  106. package/dist/utils/dateTypes.d.ts.map +1 -1
  107. package/dist/utils/dateTypes.js +41 -1
  108. package/package.json +6 -2
  109. package/src/AvatarGroup/AvatarGroupOverflow.tsx +3 -0
  110. package/src/Banner/Banner.doc.mjs +8 -0
  111. package/src/Banner/Banner.test.tsx +16 -7
  112. package/src/Banner/Banner.tsx +9 -2
  113. package/src/Button/Button.doc.mjs +6 -0
  114. package/src/Button/Button.test.tsx +105 -11
  115. package/src/Button/Button.tsx +73 -5
  116. package/src/Calendar/Calendar.doc.mjs +4 -4
  117. package/src/Calendar/Calendar.test.tsx +21 -26
  118. package/src/Calendar/Calendar.tsx +21 -5
  119. package/src/Calendar/index.ts +1 -0
  120. package/src/Chat/ChatComposer.doc.mjs +3 -0
  121. package/src/Chat/ChatComposerDrawer.doc.mjs +12 -0
  122. package/src/CheckboxInput/CheckboxInput.doc.mjs +8 -0
  123. package/src/ClickableCard/ClickableCard.doc.mjs +15 -0
  124. package/src/DateTimeInput/DateTimeInput.doc.mjs +11 -3
  125. package/src/DateTimeInput/DateTimeInput.test.tsx +23 -3
  126. package/src/DateTimeInput/DateTimeInput.tsx +13 -10
  127. package/src/Dialog/Dialog.doc.mjs +2 -2
  128. package/src/EmptyState/EmptyState.test.tsx +4 -2
  129. package/src/EmptyState/EmptyState.tsx +6 -2
  130. package/src/HoverCard/HoverCard.doc.mjs +3 -0
  131. package/src/HoverCard/HoverCard.test.tsx +189 -2
  132. package/src/HoverCard/HoverCard.tsx +20 -16
  133. package/src/HoverCard/useHoverCard.tsx +13 -10
  134. package/src/Icon/Icon.doc.mjs +8 -0
  135. package/src/Kbd/Kbd.tsx +2 -9
  136. package/src/Layer/anchorName.test.ts +146 -0
  137. package/src/Layer/anchorName.ts +46 -0
  138. package/src/Layer/useLayer.doc.mjs +7 -2
  139. package/src/Layer/useLayer.tsx +33 -9
  140. package/src/Layout/Layout.doc.mjs +1 -1
  141. package/src/Lightbox/Lightbox.doc.mjs +0 -2
  142. package/src/Link/Link.test.tsx +20 -2
  143. package/src/Link/Link.tsx +12 -3
  144. package/src/Link/LinkProvider.tsx +1 -0
  145. package/src/List/List.doc.mjs +7 -0
  146. package/src/Markdown/Markdown.doc.mjs +2 -0
  147. package/src/Markdown/Markdown.test.tsx +17 -26
  148. package/src/Markdown/Markdown.tsx +16 -6
  149. package/src/MobileNav/MobileNav.doc.mjs +8 -8
  150. package/src/MobileNav/MobileNav.tsx +13 -0
  151. package/src/MobileNav/MobileNavReopen.test.tsx +118 -0
  152. package/src/OverflowList/OverflowList.doc.mjs +17 -0
  153. package/src/Pagination/Pagination.test.tsx +137 -13
  154. package/src/Pagination/Pagination.tsx +33 -28
  155. package/src/ProgressBar/ProgressBar.test.tsx +13 -3
  156. package/src/Resizable/Resizable.doc.mjs +1 -1
  157. package/src/Section/Section.doc.mjs +11 -0
  158. package/src/SelectableCard/SelectableCard.doc.mjs +15 -0
  159. package/src/Selector/Selector.doc.mjs +4 -0
  160. package/src/Skeleton/Skeleton.doc.mjs +11 -1
  161. package/src/Slider/Slider.doc.mjs +4 -0
  162. package/src/Slider/Slider.test.tsx +3 -16
  163. package/src/Slider/Slider.tsx +1 -1
  164. package/src/TabList/TabList.doc.mjs +6 -0
  165. package/src/Table/BaseTable.tsx +72 -41
  166. package/src/Table/Table.doc.mjs +12 -0
  167. package/src/Table/Table.test.tsx +29 -30
  168. package/src/Table/Table.tsx +22 -1
  169. package/src/Table/TableCell.tsx +25 -23
  170. package/src/Table/TableHeaderCell.tsx +28 -29
  171. package/src/Table/TableRow.tsx +37 -7
  172. package/src/Table/index.ts +6 -0
  173. package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
  174. package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
  175. package/src/Table/plugins/stickyColumns/index.ts +4 -0
  176. package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +163 -0
  177. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +407 -0
  178. package/src/Table/tableContextMenu.test.tsx +157 -0
  179. package/src/Table/tableContextMenu.tsx +146 -0
  180. package/src/Table/types.ts +175 -4
  181. package/src/Table/useBaseTablePlugins.ts +1 -0
  182. package/src/Table/useTableColumnResize.doc.mjs +96 -0
  183. package/src/Table/useTableStickyColumns.doc.mjs +59 -0
  184. package/src/Text/Heading.doc.mjs +15 -2
  185. package/src/Text/Text.doc.mjs +7 -1
  186. package/src/Text/text.stylex.ts +2 -2
  187. package/src/Timestamp/Timestamp.doc.mjs +9 -0
  188. package/src/Timestamp/Timestamp.test.tsx +44 -18
  189. package/src/Timestamp/Timestamp.tsx +30 -10
  190. package/src/ToggleButton/ToggleButton.doc.mjs +9 -3
  191. package/src/ToggleButton/ToggleButton.test.tsx +39 -18
  192. package/src/ToggleButton/ToggleButton.tsx +46 -83
  193. package/src/Tokenizer/Tokenizer.tsx +4 -1
  194. package/src/Toolbar/Toolbar.doc.mjs +65 -5
  195. package/src/Tooltip/Tooltip.test.tsx +13 -0
  196. package/src/Tooltip/useTooltip.tsx +2 -3
  197. package/src/hooks/useImageMode.test.ts +133 -0
  198. package/src/theme/derivedVarRegistry.test.ts +4 -0
  199. package/src/theme/generateThemeRules.test.ts +7 -8
  200. package/src/theme/generateThemeRules.ts +1 -1
  201. package/src/theme/syntax/SyntaxTheme.tsx +1 -1
  202. package/src/theme/syntax/defineSyntaxTheme.ts +20 -11
  203. package/src/theme/syntax/presets.ts +5 -2
  204. package/src/theme/syntax/tokens.ts +1 -1
  205. package/src/theme/types.ts +1 -1
  206. package/src/utils/dateTypes.test.ts +40 -0
  207. package/src/utils/dateTypes.ts +40 -0
@@ -1 +1 @@
1
- {"version":3,"file":"useTableSortable.d.ts","sourceRoot":"","sources":["../../../../src/Table/plugins/sortable/useTableSortable.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACV,WAAW,EAGZ,MAAM,aAAa,CAAC;AAMrB;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,YAAY,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM;IAC9D,2EAA2E;IAC3E,OAAO,EAAE,QAAQ,CAAC;IAClB,0BAA0B;IAC1B,SAAS,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,IACzD,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;AAM7B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,sBAAsB,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM;IACtE,iEAAiE;IACjE,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IAE/B;;;OAGG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAEvD;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAmND;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAChC,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAuC1D"}
1
+ {"version":3,"file":"useTableSortable.d.ts","sourceRoot":"","sources":["../../../../src/Table/plugins/sortable/useTableSortable.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,WAAW,EAIZ,MAAM,aAAa,CAAC;AAMrB;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,YAAY,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM;IAC9D,2EAA2E;IAC3E,OAAO,EAAE,QAAQ,CAAC;IAClB,0BAA0B;IAC1B,SAAS,EAAE,kBAAkB,CAAC;CAC/B;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,IACzD,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;AAM7B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,sBAAsB,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM;IACtE,iEAAiE;IACjE,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;IAE/B;;;OAGG;IACH,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAEvD;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAmND;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAChC,MAAM,EAAE,sBAAsB,CAAC,QAAQ,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAyF1D"}
@@ -17,6 +17,7 @@ import * as stylex from '@stylexjs/stylex';
17
17
  import "../../../theme/tokens.stylex.js";
18
18
  import { colorVars, spacingVars, radiusVars } from "../../../theme/tokens.stylex.js";
19
19
  import { Icon } from "../../../Icon/index.js";
20
+ import { resolveContextActions } from "../../tableContextMenu.js";
20
21
 
21
22
  // =============================================================================
22
23
  // Sort Types
@@ -243,10 +244,64 @@ export function useTableSortable(config) {
243
244
  if (sortKey == null) {
244
245
  return props;
245
246
  }
246
-
247
- // Find sort entry for this column
248
247
  const cfg = configRef.current;
249
248
  const entry = cfg.sort.find(e => e.sortKey === sortKey);
249
+
250
+ // Context-menu actions are built lazily (only when the menu opens) via
251
+ // a getter, reading the current sort state at call time — so we don't
252
+ // build an action array for every header on every render, and the
253
+ // checked/clear state always reflects the latest sort.
254
+ const getSortActions = () => {
255
+ const c = configRef.current;
256
+ const dir = c.sort.find(e => e.sortKey === sortKey)?.direction ?? null;
257
+ const actions = [{
258
+ id: 'sort-asc',
259
+ group: 'sort',
260
+ label: 'Sort ascending',
261
+ icon: /*#__PURE__*/_jsx(Icon, {
262
+ icon: "arrowUp",
263
+ size: "xsm",
264
+ "aria-hidden": true
265
+ }),
266
+ checked: dir === 'ascending',
267
+ onSelect: () => c.onSortChange([{
268
+ sortKey: sortKey,
269
+ direction: 'ascending'
270
+ }])
271
+ }, {
272
+ id: 'sort-desc',
273
+ group: 'sort',
274
+ label: 'Sort descending',
275
+ icon: /*#__PURE__*/_jsx(Icon, {
276
+ icon: "arrowDown",
277
+ size: "xsm",
278
+ "aria-hidden": true
279
+ }),
280
+ checked: dir === 'descending',
281
+ onSelect: () => c.onSortChange([{
282
+ sortKey: sortKey,
283
+ direction: 'descending'
284
+ }])
285
+ }];
286
+ if (dir != null) {
287
+ actions.push({
288
+ id: 'sort-clear',
289
+ group: 'sort-clear',
290
+ label: 'Clear sort',
291
+ icon: /*#__PURE__*/_jsx(Icon, {
292
+ icon: "close",
293
+ size: "xsm",
294
+ "aria-hidden": true
295
+ }),
296
+ onSelect: () => c.onSortChange(c.sort.filter(e => e.sortKey !== sortKey))
297
+ });
298
+ }
299
+ return actions;
300
+ };
301
+
302
+ // Merge with any actions a prior plugin contributed (array or getter),
303
+ // resolving both lazily at open time.
304
+ const priorActions = props.contextMenuActions;
250
305
  return {
251
306
  ...props,
252
307
  htmlProps: {
@@ -259,7 +314,8 @@ export function useTableSortable(config) {
259
314
  column: column,
260
315
  configRef: configRef,
261
316
  children: props.content
262
- })
317
+ }),
318
+ contextMenuActions: () => [...resolveContextActions(priorActions), ...getSortActions()]
263
319
  };
264
320
  }
265
321
  }), []);
@@ -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
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @file tableContextMenu.tsx
3
+ * @input React, ContextMenu, Icon, types
4
+ * @output wrapInTableContextMenu helper
5
+ * @position Renders the aggregated `contextMenuActions` for a header cell / row
6
+ *
7
+ * SYNC: When modified, update these files to stay in sync:
8
+ * - /packages/core/src/Table/BaseTable.tsx (call sites)
9
+ * - /packages/core/src/Table/types.ts (TableContextAction)
10
+ */
11
+ import { type ReactNode } from 'react';
12
+ import type { TableContextAction, TableContextActions } from './types';
13
+ /**
14
+ * Resolve a `contextMenuActions` value (array or getter) to a plain array.
15
+ * Use this when composing actions from a prior plugin's render props so you
16
+ * don't have to branch on the array-vs-getter form:
17
+ *
18
+ * ```
19
+ * contextMenuActions: () => [
20
+ * ...resolveContextActions(props.contextMenuActions),
21
+ * ...myActions,
22
+ * ]
23
+ * ```
24
+ */
25
+ export declare function resolveContextActions(actions: TableContextActions | undefined): TableContextAction[];
26
+ /**
27
+ * Wrap a table element (a header cell's content or a body cell) in a right-click
28
+ * context menu rendering the aggregated `actions`. Accepts a static array or a
29
+ * getter (resolved lazily on open). When there are no actions the element is
30
+ * returned untouched so the native browser menu passes through.
31
+ */
32
+ export declare function wrapInTableContextMenu(element: ReactNode, actions: TableContextActions | undefined): ReactNode;
33
+ //# sourceMappingURL=tableContextMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tableContextMenu.d.ts","sourceRoot":"","sources":["../../src/Table/tableContextMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AAEH,OAAO,EAAW,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAG/C,OAAO,KAAK,EAAC,kBAAkB,EAAE,mBAAmB,EAAC,MAAM,SAAS,CAAC;AAErE;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,mBAAmB,GAAG,SAAS,GACvC,kBAAkB,EAAE,CAKtB;AAiFD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,mBAAmB,GAAG,SAAS,GACvC,SAAS,CAgBX"}
@@ -0,0 +1,136 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file tableContextMenu.tsx
7
+ * @input React, ContextMenu, Icon, types
8
+ * @output wrapInTableContextMenu helper
9
+ * @position Renders the aggregated `contextMenuActions` for a header cell / row
10
+ *
11
+ * SYNC: When modified, update these files to stay in sync:
12
+ * - /packages/core/src/Table/BaseTable.tsx (call sites)
13
+ * - /packages/core/src/Table/types.ts (TableContextAction)
14
+ */
15
+ import { useState } from 'react';
16
+ import { ContextMenu } from "../ContextMenu/index.js";
17
+ import { Icon } from "../Icon/index.js";
18
+ import { jsx as _jsx } from "react/jsx-runtime";
19
+ /**
20
+ * Resolve a `contextMenuActions` value (array or getter) to a plain array.
21
+ * Use this when composing actions from a prior plugin's render props so you
22
+ * don't have to branch on the array-vs-getter form:
23
+ *
24
+ * ```
25
+ * contextMenuActions: () => [
26
+ * ...resolveContextActions(props.contextMenuActions),
27
+ * ...myActions,
28
+ * ]
29
+ * ```
30
+ */
31
+ export function resolveContextActions(actions) {
32
+ if (typeof actions === 'function') {
33
+ return actions();
34
+ }
35
+ return actions ?? [];
36
+ }
37
+
38
+ /**
39
+ * Convert the flat action list into ContextMenu options, inserting a divider
40
+ * between groups (first-seen group order). Ungrouped actions form a trailing
41
+ * group. A `checked` action shows a trailing check icon.
42
+ */
43
+ function toContextMenuOptions(actions) {
44
+ const order = [];
45
+ const buckets = new Map();
46
+ for (const action of actions) {
47
+ const key = action.group ?? '__ungrouped__';
48
+ let bucket = buckets.get(key);
49
+ if (!bucket) {
50
+ bucket = [];
51
+ buckets.set(key, bucket);
52
+ order.push(key);
53
+ }
54
+ bucket.push(action);
55
+ }
56
+ const options = [];
57
+ order.forEach((key, groupIndex) => {
58
+ if (groupIndex > 0) {
59
+ options.push({
60
+ type: 'divider'
61
+ });
62
+ }
63
+ for (const action of buckets.get(key) ?? []) {
64
+ options.push({
65
+ label: typeof action.label === 'string' ? action.label : action.id,
66
+ // A checked action (e.g. the active sort direction) shows a checkmark;
67
+ // otherwise the action's own icon. ContextMenu's data form takes a
68
+ // single leading icon, so checked state replaces the icon.
69
+ icon: action.checked ? /*#__PURE__*/_jsx(Icon, {
70
+ icon: "check",
71
+ size: "xsm",
72
+ "aria-hidden": true
73
+ }) : action.icon,
74
+ isDisabled: action.disabled,
75
+ onClick: action.onSelect
76
+ });
77
+ }
78
+ });
79
+ return options;
80
+ }
81
+
82
+ /**
83
+ * Wrap a table element (a header cell's content or a row) in a right-click
84
+ * context menu rendering the aggregated `actions`. When no plugin contributes
85
+ * actions the element is returned untouched so the native browser menu passes
86
+ * through.
87
+ */
88
+ /**
89
+ * A context menu whose actions are resolved lazily — only when the user opens
90
+ * the menu (right-click). Deferring the work means plugins that pass a getter
91
+ * don't build an action array (with its closures) for every cell on every
92
+ * render; it's computed on demand and memoized until the menu closes.
93
+ */
94
+ function LazyTableContextMenu({
95
+ element,
96
+ getActions
97
+ }) {
98
+ const [options, setOptions] = useState(null);
99
+ return /*#__PURE__*/_jsx(ContextMenu, {
100
+ items: options ?? [],
101
+ hasAutoFocus: false,
102
+ onOpenChange: open => {
103
+ // Resolve actions when opening; clear on close so state derived later
104
+ // (e.g. current sort direction) is always fresh next open.
105
+ setOptions(open ? toContextMenuOptions(getActions()) : null);
106
+ },
107
+ children: element
108
+ });
109
+ }
110
+
111
+ /**
112
+ * Wrap a table element (a header cell's content or a body cell) in a right-click
113
+ * context menu rendering the aggregated `actions`. Accepts a static array or a
114
+ * getter (resolved lazily on open). When there are no actions the element is
115
+ * returned untouched so the native browser menu passes through.
116
+ */
117
+ export function wrapInTableContextMenu(element, actions) {
118
+ // Getter form → resolve lazily on open.
119
+ if (typeof actions === 'function') {
120
+ return /*#__PURE__*/_jsx(LazyTableContextMenu, {
121
+ element: element,
122
+ getActions: actions
123
+ });
124
+ }
125
+ if (!actions || actions.length === 0) {
126
+ return element;
127
+ }
128
+ // hasAutoFocus={false}: a right-click menu shouldn't pre-highlight the first
129
+ // item (it looked like "ascending" was always selected). Focus moves only
130
+ // when the user arrow-keys into the menu.
131
+ return /*#__PURE__*/_jsx(ContextMenu, {
132
+ items: toContextMenuOptions(actions),
133
+ hasAutoFocus: false,
134
+ children: element
135
+ });
136
+ }