@infinite-table/infinite-react 0.4.12 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/API.md +0 -0
  3. package/build/buildPackageJson.js +43 -0
  4. package/build/scripts/test.js +37 -0
  5. package/bundler.config.js +25 -0
  6. package/globals.d.ts +7 -0
  7. package/package.json +95 -3
  8. package/rollup.config.js +15 -0
  9. package/run-build-deepmap.js +47 -0
  10. package/run-build.js +45 -0
  11. package/run-dts-concat.js +21 -0
  12. package/src/components/CSSVariableWatch.tsx +82 -0
  13. package/src/components/DataSource/BooleanCollectionState.ts +214 -0
  14. package/src/components/DataSource/BooleanDeepCollectionState.ts +208 -0
  15. package/src/components/DataSource/DataSourceContext.ts +20 -0
  16. package/src/components/DataSource/GroupRowsState.ts +74 -0
  17. package/src/components/DataSource/Indexer.ts +27 -0
  18. package/src/components/DataSource/RowSelectionState.ts +763 -0
  19. package/src/components/DataSource/defaultFilterTypes.ts +64 -0
  20. package/src/components/DataSource/index.tsx +108 -0
  21. package/src/components/DataSource/privateHooks/getChangeDetect.ts +7 -0
  22. package/src/components/DataSource/privateHooks/useLoadData.ts +783 -0
  23. package/src/components/DataSource/publicHooks/useDataSource.ts +19 -0
  24. package/src/components/DataSource/publicHooks/useDataSourceActions.ts +14 -0
  25. package/src/components/DataSource/state/getInitialState.ts +494 -0
  26. package/src/components/DataSource/state/normalizeSortInfo.ts +35 -0
  27. package/src/components/DataSource/state/reducer.ts +466 -0
  28. package/src/components/DataSource/state/rowInfoStatus.ts +27 -0
  29. package/src/components/DataSource/types.ts +548 -0
  30. package/src/components/HeadlessTable/HeadlessTableWithPinnedContainers.tsx +142 -0
  31. package/src/components/HeadlessTable/MappedCells.ts +251 -0
  32. package/src/components/HeadlessTable/RawTable.tsx +98 -0
  33. package/src/components/HeadlessTable/ReactHeadlessTableRenderer.tsx +1516 -0
  34. package/src/components/HeadlessTable/index.tsx +234 -0
  35. package/src/components/InfiniteTable/InfiniteCls.css.ts +164 -0
  36. package/src/components/InfiniteTable/InfiniteTableContext.ts +16 -0
  37. package/src/components/InfiniteTable/api/getImperativeApi.ts +391 -0
  38. package/src/components/InfiniteTable/api/getSelectionApi.ts +364 -0
  39. package/src/components/InfiniteTable/api/type.ts +11 -0
  40. package/src/components/InfiniteTable/components/ActiveCellIndicator.css.ts +51 -0
  41. package/src/components/InfiniteTable/components/ActiveCellIndicator.tsx +116 -0
  42. package/src/components/InfiniteTable/components/ActiveRowIndicator.css.ts +56 -0
  43. package/src/components/InfiniteTable/components/ActiveRowIndicator.tsx +94 -0
  44. package/src/components/InfiniteTable/components/CheckBox.css.ts +13 -0
  45. package/src/components/InfiniteTable/components/CheckBox.tsx +96 -0
  46. package/src/components/InfiniteTable/components/FilterEditors.tsx +52 -0
  47. package/src/components/InfiniteTable/components/InfiniteTableBody/InfiniteTableBody.tsx +27 -0
  48. package/src/components/InfiniteTable/components/InfiniteTableBody/index.tsx +1 -0
  49. package/src/components/InfiniteTable/components/InfiniteTableFooter/InfiniteTableFooter.tsx +31 -0
  50. package/src/components/InfiniteTable/components/InfiniteTableFooter/index.tsx +1 -0
  51. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableColumnHeaderFilter.tsx +102 -0
  52. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeader.tsx +163 -0
  53. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderCell.tsx +574 -0
  54. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderGroup.tsx +79 -0
  55. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderTypes.tsx +25 -0
  56. package/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeaderWrapper.tsx +185 -0
  57. package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/GroupResizeHandle.tsx +159 -0
  58. package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/ResizeHandle.css.ts +124 -0
  59. package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/columnResizer.ts +166 -0
  60. package/src/components/InfiniteTable/components/InfiniteTableHeader/ResizeHandle/index.tsx +146 -0
  61. package/src/components/InfiniteTable/components/InfiniteTableHeader/buildColumnAndGroupTree.ts +240 -0
  62. package/src/components/InfiniteTable/components/InfiniteTableHeader/header.css.ts +358 -0
  63. package/src/components/InfiniteTable/components/InfiniteTableHeader/index.tsx +1 -0
  64. package/src/components/InfiniteTable/components/InfiniteTableHeader/useColumnGroupResizeHandle.tsx +114 -0
  65. package/src/components/InfiniteTable/components/InfiniteTableHeader/useColumnResizeHandle.tsx +146 -0
  66. package/src/components/InfiniteTable/components/InfiniteTableLicenseFooter/footer.css.ts +7 -0
  67. package/src/components/InfiniteTable/components/InfiniteTableLicenseFooter/index.tsx +110 -0
  68. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableCell.tsx +120 -0
  69. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableCellTypes.ts +74 -0
  70. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableColumnCell.tsx +457 -0
  71. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRow.tsx +107 -0
  72. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRowClassName.ts +6 -0
  73. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRowTypes.ts +32 -0
  74. package/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableRowUnvirtualized.tsx +75 -0
  75. package/src/components/InfiniteTable/components/InfiniteTableRow/columnRendering.tsx +263 -0
  76. package/src/components/InfiniteTable/components/InfiniteTableRow/index.tsx +1 -0
  77. package/src/components/InfiniteTable/components/InfiniteTableRow/row.css.ts +74 -0
  78. package/src/components/InfiniteTable/components/InfiniteTableRow/useRowDOMProps.ts +199 -0
  79. package/src/components/InfiniteTable/components/LoadMask.css.ts +34 -0
  80. package/src/components/InfiniteTable/components/LoadMask.tsx +27 -0
  81. package/src/components/InfiniteTable/components/ScrollbarPlaceholder.tsx +56 -0
  82. package/src/components/InfiniteTable/components/cell.css.ts +192 -0
  83. package/src/components/InfiniteTable/components/icons/ArrowDown.tsx +14 -0
  84. package/src/components/InfiniteTable/components/icons/ArrowUp.tsx +14 -0
  85. package/src/components/InfiniteTable/components/icons/ExpanderIcon.css.ts +31 -0
  86. package/src/components/InfiniteTable/components/icons/ExpanderIcon.tsx +63 -0
  87. package/src/components/InfiniteTable/components/icons/Icon.tsx +18 -0
  88. package/src/components/InfiniteTable/components/icons/InfiniteTableIconClassName.ts +1 -0
  89. package/src/components/InfiniteTable/components/icons/LoadingIcon.css.ts +8 -0
  90. package/src/components/InfiniteTable/components/icons/LoadingIcon.tsx +45 -0
  91. package/src/components/InfiniteTable/components/icons/MenuIcon.tsx +50 -0
  92. package/src/components/InfiniteTable/components/icons/SortIcon.tsx +113 -0
  93. package/src/components/InfiniteTable/eventHandlers/eventHandlerTypes.ts +57 -0
  94. package/src/components/InfiniteTable/eventHandlers/index.ts +95 -0
  95. package/src/components/InfiniteTable/eventHandlers/keyboardNavigation.ts +232 -0
  96. package/src/components/InfiniteTable/eventHandlers/keyboardSelection.ts +110 -0
  97. package/src/components/InfiniteTable/eventHandlers/onCellClick.ts +94 -0
  98. package/src/components/InfiniteTable/eventHandlers/onKeyDown.ts +25 -0
  99. package/src/components/InfiniteTable/hooks/adjustColumnOrderForAllColumns.ts +70 -0
  100. package/src/components/InfiniteTable/hooks/reorderColumnsOnDrag.ts +476 -0
  101. package/src/components/InfiniteTable/hooks/useAutoSizeColumns.ts +206 -0
  102. package/src/components/InfiniteTable/hooks/useCellClassName.ts +80 -0
  103. package/src/components/InfiniteTable/hooks/useCellRendering.tsx +217 -0
  104. package/src/components/InfiniteTable/hooks/useColumnGroups.ts +71 -0
  105. package/src/components/InfiniteTable/hooks/useColumnMenu.ts +72 -0
  106. package/src/components/InfiniteTable/hooks/useColumnPointerEvents.ts +258 -0
  107. package/src/components/InfiniteTable/hooks/useColumnRowspan.ts +43 -0
  108. package/src/components/InfiniteTable/hooks/useColumnSizeFn.ts +24 -0
  109. package/src/components/InfiniteTable/hooks/useColumnsWhen.ts +582 -0
  110. package/src/components/InfiniteTable/hooks/useComputed.ts +186 -0
  111. package/src/components/InfiniteTable/hooks/useComputedVisibleColumns.ts +219 -0
  112. package/src/components/InfiniteTable/hooks/useDOMProps.ts +306 -0
  113. package/src/components/InfiniteTable/hooks/useEffectWithRaf.ts +47 -0
  114. package/src/components/InfiniteTable/hooks/useInfiniteTable.ts +10 -0
  115. package/src/components/InfiniteTable/hooks/useInfiniteTableState.ts +11 -0
  116. package/src/components/InfiniteTable/hooks/useInternalProps.ts +8 -0
  117. package/src/components/InfiniteTable/hooks/useLicense/LicenseDetails.ts +13 -0
  118. package/src/components/InfiniteTable/hooks/useLicense/crc32.ts +56 -0
  119. package/src/components/InfiniteTable/hooks/useLicense/decode.ts +147 -0
  120. package/src/components/InfiniteTable/hooks/useLicense/useLicense.ts +39 -0
  121. package/src/components/InfiniteTable/hooks/useRerenderOnKeyChange.ts +21 -0
  122. package/src/components/InfiniteTable/hooks/useRowHover.ts +18 -0
  123. package/src/components/InfiniteTable/hooks/useScrollToActiveCell.ts +48 -0
  124. package/src/components/InfiniteTable/hooks/useScrollToActiveRow.ts +44 -0
  125. package/src/components/InfiniteTable/hooks/useScrollbars.ts +51 -0
  126. package/src/components/InfiniteTable/hooks/useToggleGroupRow.ts +56 -0
  127. package/src/components/InfiniteTable/hooks/useUnpinnedRendering.tsx +165 -0
  128. package/src/components/InfiniteTable/hooks/useYourBrain.ts +55 -0
  129. package/src/components/InfiniteTable/index.tsx +352 -0
  130. package/src/components/InfiniteTable/internalProps.ts +4 -0
  131. package/src/components/InfiniteTable/state/computeColumnGroupsDepths.ts +29 -0
  132. package/src/components/InfiniteTable/state/getColumnVisibilityForHideEmptyGroupColumns.ts +127 -0
  133. package/src/components/InfiniteTable/state/getInitialState.ts +375 -0
  134. package/src/components/InfiniteTable/theme.css.ts +556 -0
  135. package/src/components/InfiniteTable/types/InfiniteTableAction.ts +6 -0
  136. package/src/components/InfiniteTable/types/InfiniteTableActionType.ts +12 -0
  137. package/src/components/InfiniteTable/types/InfiniteTableColumn.ts +478 -0
  138. package/src/components/InfiniteTable/types/InfiniteTableComputedValues.ts +43 -0
  139. package/src/components/InfiniteTable/types/InfiniteTableContextValue.ts +12 -0
  140. package/src/components/InfiniteTable/types/InfiniteTableInternalProps.ts +3 -0
  141. package/src/components/InfiniteTable/types/InfiniteTableProps.ts +511 -0
  142. package/src/components/InfiniteTable/types/InfiniteTableState.ts +195 -0
  143. package/src/components/InfiniteTable/types/Utility.ts +35 -0
  144. package/src/components/InfiniteTable/types/index.ts +96 -0
  145. package/src/components/InfiniteTable/utilities.css.ts +179 -0
  146. package/src/components/InfiniteTable/utils/MultiRowSelector.ts +111 -0
  147. package/src/components/InfiniteTable/utils/RenderHookComponentForInfinite.tsx +52 -0
  148. package/src/components/InfiniteTable/utils/adjustColumnOrderForPinning.ts +33 -0
  149. package/src/components/InfiniteTable/utils/assignFiltered.ts +29 -0
  150. package/src/components/InfiniteTable/utils/defaultGetColumContextMenuItems.tsx +108 -0
  151. package/src/components/InfiniteTable/utils/getColumnComputedType.ts +33 -0
  152. package/src/components/InfiniteTable/utils/getColumnForGroupBy.tsx +313 -0
  153. package/src/components/InfiniteTable/utils/getComputedVisibleColumns.ts +773 -0
  154. package/src/components/InfiniteTable/utils/getContextMenuForColumn.tsx +72 -0
  155. package/src/components/InfiniteTable/utils/infiniteDOMUtils.ts +189 -0
  156. package/src/components/InfiniteTable/utils/mapToObject.ts +20 -0
  157. package/src/components/InfiniteTable/utils/moveXatY.ts +25 -0
  158. package/src/components/InfiniteTable/utils/objectValuesExcept.ts +9 -0
  159. package/src/components/InfiniteTable/utils/progressiveSpeedScroller.ts +158 -0
  160. package/src/components/InfiniteTable/utils/rafFn.ts +13 -0
  161. package/src/components/InfiniteTable/utils/toCSSVarName.ts +1 -0
  162. package/src/components/InfiniteTable/utils/toMap.ts +24 -0
  163. package/src/components/Menu/Menu.tsx +750 -0
  164. package/src/components/Menu/MenuCls.css.ts +139 -0
  165. package/src/components/Menu/MenuContext.ts +10 -0
  166. package/src/components/Menu/MenuContextValue.ts +15 -0
  167. package/src/components/Menu/MenuProps.ts +98 -0
  168. package/src/components/Menu/MenuState.ts +56 -0
  169. package/src/components/Menu/MenuTriangleContext.ts +352 -0
  170. package/src/components/Menu/childrenToRuntimeItems.tsx +103 -0
  171. package/src/components/Menu/getMenuState.tsx +119 -0
  172. package/src/components/Menu/index.tsx +88 -0
  173. package/src/components/Menu/propToIdentifyMenu.ts +1 -0
  174. package/src/components/RawList/AvoidReactDiff.tsx +48 -0
  175. package/src/components/RawList/MappedItems.ts +143 -0
  176. package/src/components/RawList/ReactVirtualRenderer.tsx +307 -0
  177. package/src/components/RawList/index.tsx +42 -0
  178. package/src/components/RawList/types.ts +23 -0
  179. package/src/components/RawList/useVirtualRenderer.ts +36 -0
  180. package/src/components/RenderHookComponent.tsx +10 -0
  181. package/src/components/ResizeObserver/index.tsx +170 -0
  182. package/src/components/VirtualBrain/MatrixBrain.ts +1621 -0
  183. package/src/components/VirtualBrain/ScrollListener.ts +39 -0
  184. package/src/components/VirtualBrain/index.ts +664 -0
  185. package/src/components/VirtualList/ColumnListWithExternalScrolling.tsx +78 -0
  186. package/src/components/VirtualList/InfiniteListRootClassName.ts +1 -0
  187. package/src/components/VirtualList/RowListWithExternalScrolling.tsx +120 -0
  188. package/src/components/VirtualList/SpacePlaceholder.tsx +32 -0
  189. package/src/components/VirtualList/VirtualList.css.ts +29 -0
  190. package/src/components/VirtualList/VirtualList.tsx +141 -0
  191. package/src/components/VirtualList/VirtualRowList.tsx +34 -0
  192. package/src/components/VirtualList/types.ts +56 -0
  193. package/src/components/VirtualList/useCorrectHeightForRowElements.ts +14 -0
  194. package/src/components/VirtualScrollContainer/VirtualScrollContainer.css.ts +51 -0
  195. package/src/components/VirtualScrollContainer/getScrollableClassName.ts +30 -0
  196. package/src/components/VirtualScrollContainer/index.tsx +63 -0
  197. package/src/components/flexbox/index.ts +562 -0
  198. package/src/components/hooks/useComponentState/index.tsx +562 -0
  199. package/src/components/hooks/useComponentState/types.ts +32 -0
  200. package/src/components/hooks/useEffectOnceWithProperUnmount.ts +33 -0
  201. package/src/components/hooks/useEffectWithChanges.ts +56 -0
  202. package/src/components/hooks/useImmutableRef.ts +7 -0
  203. package/src/components/hooks/useInterceptedMap.ts +71 -0
  204. package/src/components/hooks/useLatest.tsx +8 -0
  205. package/src/components/hooks/useLazyLatest.ts +23 -0
  206. package/src/components/hooks/useMemoShallowObjectMerge.ts +16 -0
  207. package/src/components/hooks/useMounted.ts +18 -0
  208. package/src/components/hooks/useOnMount.ts +21 -0
  209. package/src/components/hooks/useOnScroll.ts +34 -0
  210. package/src/components/hooks/useOnce.ts +10 -0
  211. package/src/components/hooks/useOverlay/index.tsx +418 -0
  212. package/src/components/hooks/usePrevious.ts +8 -0
  213. package/src/components/hooks/usePropertyOld.ts +168 -0
  214. package/src/components/hooks/useRerender.ts +12 -0
  215. package/src/components/hooks/xuseProperty.ts +165 -0
  216. package/src/components/types/CellPosition.ts +4 -0
  217. package/src/components/types/NonUndefined.ts +1 -0
  218. package/src/components/types/RemoveObject.ts +22 -0
  219. package/src/components/types/Renderable.ts +3 -0
  220. package/src/components/types/ScrollPosition.ts +7 -0
  221. package/src/components/types/Setter.ts +2 -0
  222. package/src/components/types/Size.ts +6 -0
  223. package/src/components/types/SubscriptionCallback.ts +10 -0
  224. package/src/components/types/VoidFn.ts +1 -0
  225. package/src/components/utils/buildSubscriptionCallback.tsx +60 -0
  226. package/src/components/utils/clamp.ts +3 -0
  227. package/src/components/utils/debounce.ts +16 -0
  228. package/src/components/utils/decamelize.ts +11 -0
  229. package/src/components/utils/discardCallsWithEqualArg.ts +42 -0
  230. package/src/components/utils/getRenderIndexes.ts +33 -0
  231. package/src/components/utils/getScrollbarWidth.ts +31 -0
  232. package/src/components/utils/getVirtualRenderCount.ts +21 -0
  233. package/src/components/utils/isControlled.ts +12 -0
  234. package/src/components/utils/isControlledValue.ts +5 -0
  235. package/src/index.tsx +34 -0
  236. package/src/test.tsx +18 -0
  237. package/src/utils/DeepMap/index.ts +588 -0
  238. package/src/utils/DeepMap/once.ts +16 -0
  239. package/src/utils/DeepMap/sortAscending.ts +1 -0
  240. package/src/utils/DeepMap/tsconfig.deepmap.json +17 -0
  241. package/src/utils/DeepMap/xpackage.json +26 -0
  242. package/src/utils/debug.ts +40 -0
  243. package/src/utils/deepClone.ts +38 -0
  244. package/src/utils/getGlobal.ts +3 -0
  245. package/src/utils/groupAndPivot/defaultToKey.ts +3 -0
  246. package/src/utils/groupAndPivot/getGroupKeysForDataItem.ts +19 -0
  247. package/src/utils/groupAndPivot/getPivotColumnsAndColumnGroups.ts +361 -0
  248. package/src/utils/groupAndPivot/index.ts +1229 -0
  249. package/src/utils/groupAndPivot/types.ts +10 -0
  250. package/src/utils/join.ts +4 -0
  251. package/src/utils/mathIntersection.ts +21 -0
  252. package/src/utils/minified.d.ts +2 -0
  253. package/src/utils/minified.js +6 -0
  254. package/src/utils/multisort/index.ts +151 -0
  255. package/src/utils/multisort/sortTypes.ts +25 -0
  256. package/src/utils/notes-status.md +92 -0
  257. package/src/utils/pageGeometry/ConvexPoly.ts +34 -0
  258. package/src/utils/pageGeometry/Point.ts +51 -0
  259. package/src/utils/pageGeometry/PolyWithPoints.ts +52 -0
  260. package/src/utils/pageGeometry/Rectangle.ts +98 -0
  261. package/src/utils/pageGeometry/Triangle.ts +16 -0
  262. package/src/utils/pageGeometry/alignment/index.ts +221 -0
  263. package/src/utils/pageGeometry/polyContainsPoint.ts +182 -0
  264. package/src/utils/pageGeometry/types.ts +3 -0
  265. package/src/utils/proxyFnCall.ts +46 -0
  266. package/src/utils/raf.ts +13 -0
  267. package/src/utils/selectParent.ts +18 -0
  268. package/src/utils/shallowEqualObjects.ts +49 -0
  269. package/src/utils/stripVar.ts +3 -0
  270. package/src/utils/toUpperFirst.ts +5 -0
  271. package/todo.md +2 -0
  272. package/tsconfig.build.json +8 -0
  273. package/tsconfig.dev.json +7 -0
  274. package/tsconfig.json +30 -0
  275. package/tsconfig.typebundler.json +13 -0
  276. package/typedoc.json +4 -0
  277. package/README.md +0 -104
  278. package/index.css +0 -857
  279. package/index.d.ts +0 -2111
  280. package/index.esm.css +0 -857
  281. package/index.esm.js +0 -13689
  282. package/index.js +0 -13560
@@ -0,0 +1,139 @@
1
+ import { fallbackVar, style } from '@vanilla-extract/css';
2
+ import { recipe } from '@vanilla-extract/recipes';
3
+ import { ThemeVars } from '../InfiniteTable/theme.css';
4
+ import {
5
+ alignItems,
6
+ boxSizingBorderBox,
7
+ cursor,
8
+ display,
9
+ flexFlow,
10
+ margin,
11
+ position,
12
+ userSelect,
13
+ } from '../InfiniteTable/utilities.css';
14
+
15
+ export const MenuCls = style([
16
+ boxSizingBorderBox,
17
+ position.relative,
18
+ display.inlineGrid,
19
+ flexFlow.column,
20
+ margin.none,
21
+ {
22
+ padding: ThemeVars.components.Menu.padding,
23
+ color: ThemeVars.components.Menu.color,
24
+ background: ThemeVars.components.Menu.background,
25
+ borderRadius: ThemeVars.components.Menu.borderRadius,
26
+ outline: 'none',
27
+ boxShadow: `0 6px 12px -2px ${ThemeVars.components.Menu.shadowColor},0 3px 7px -3px ${ThemeVars.components.Menu.background}`,
28
+ },
29
+ ]);
30
+
31
+ export const MenuRowCls = style({
32
+ display: 'contents',
33
+ });
34
+
35
+ const keyboardActiveItemBorder = fallbackVar(
36
+ ThemeVars.components.Row.activeBorder,
37
+ `${fallbackVar(
38
+ ThemeVars.components.Row.activeBorderWidth,
39
+ ThemeVars.components.Cell.activeBorderWidth,
40
+ )} ${fallbackVar(
41
+ ThemeVars.components.Row.activeBorderStyle,
42
+ ThemeVars.components.Cell.activeBorderStyle,
43
+ )} ${fallbackVar(
44
+ ThemeVars.components.Row.activeBorderColor,
45
+ `rgb(${ThemeVars.components.Cell.activeBorderColor_R} ${ThemeVars.components.Cell.activeBorderColor_G} ${ThemeVars.components.Cell.activeBorderColor_B})`,
46
+ )}`,
47
+ );
48
+ export const MenuItemCls = recipe({
49
+ base: [
50
+ {
51
+ paddingBlock: ThemeVars.components.Menu.cellPaddingVertical,
52
+ paddingInline: ThemeVars.components.Menu.cellPaddingHorizontal,
53
+ marginBlock: ThemeVars.components.Menu.cellMarginVertical,
54
+ border: keyboardActiveItemBorder,
55
+ borderColor: 'transparent',
56
+ },
57
+ display.flex,
58
+ alignItems.center,
59
+ userSelect.none,
60
+ ],
61
+ variants: {
62
+ disabled: {
63
+ true: [
64
+ {
65
+ opacity: ThemeVars.components.Menu.itemDisabledOpacity,
66
+ background: ThemeVars.components.Menu.itemDisabledBackground,
67
+ },
68
+ cursor.default,
69
+ userSelect.none,
70
+ ],
71
+ false: [cursor.pointer],
72
+ },
73
+ active: {
74
+ true: {},
75
+ false: {},
76
+ },
77
+ pressed: {
78
+ false: {},
79
+ true: {},
80
+ },
81
+ keyboardActive: {
82
+ true: {
83
+ selectors: {
84
+ [`${MenuCls}:focus-within > ${MenuRowCls} > &`]: {
85
+ border: keyboardActiveItemBorder,
86
+ },
87
+ [`${MenuCls}:focus-within > ${MenuRowCls} > &:first-child:last-child`]:
88
+ {
89
+ border: keyboardActiveItemBorder,
90
+ },
91
+ [`${MenuCls}:focus-within > ${MenuRowCls} > &:first-child`]: {
92
+ borderRightColor: 'transparent',
93
+ },
94
+ [`${MenuCls}:focus-within > ${MenuRowCls} > &:last-child`]: {
95
+ borderLeftColor: 'transparent',
96
+ },
97
+ [`${MenuCls}:focus-within > ${MenuRowCls} > &:not(:first-child):not(:last-child)`]:
98
+ {
99
+ borderLeftColor: 'transparent',
100
+ borderRightColor: 'transparent',
101
+ },
102
+ },
103
+ },
104
+ false: {},
105
+ },
106
+ },
107
+ compoundVariants: [
108
+ {
109
+ variants: {
110
+ active: true,
111
+ disabled: false,
112
+ },
113
+ style: {
114
+ background: ThemeVars.components.Menu.itemActiveBackground,
115
+ opacity: ThemeVars.components.Menu.itemActiveOpacity,
116
+ },
117
+ },
118
+ {
119
+ variants: {
120
+ pressed: true,
121
+ active: true,
122
+ disabled: false,
123
+ },
124
+ style: {
125
+ background: ThemeVars.components.Menu.itemPressedBackground,
126
+ opacity: ThemeVars.components.Menu.itemPressedOpacity,
127
+ },
128
+ },
129
+ ],
130
+ });
131
+
132
+ export const MenuSeparatorCls = style([
133
+ {
134
+ borderTop: '1px solid currentColor',
135
+ borderBottom: 0,
136
+ marginTop: `calc(${ThemeVars.components.Menu.cellPaddingVertical} / 2)`,
137
+ marginBottom: `calc(${ThemeVars.components.Menu.cellPaddingVertical} / 2)`,
138
+ },
139
+ ]);
@@ -0,0 +1,10 @@
1
+ import { createContext, useContext } from 'react';
2
+ import { MenuContextValue } from './MenuContextValue';
3
+
4
+ export const MenuContext = createContext<MenuContextValue | null>(null);
5
+
6
+ export function useMenuContext(): MenuContextValue {
7
+ const contextValue = useContext(MenuContext);
8
+
9
+ return contextValue!;
10
+ }
@@ -0,0 +1,15 @@
1
+ import {
2
+ MenuActions,
3
+ // MenuApi,
4
+ // MenuComputedValues,
5
+ MenuState,
6
+ } from './MenuState';
7
+
8
+ export interface MenuContextValue {
9
+ // imperativeApi: MenuApi;
10
+ componentState: MenuState;
11
+ componentActions: MenuActions;
12
+ // computed: MenuComputedValues;
13
+ // getComputed: () => MenuComputedValues;
14
+ getState: () => MenuState;
15
+ }
@@ -0,0 +1,98 @@
1
+ import { CSSProperties, HTMLProps } from 'react';
2
+ import { ElementContainerGetter, OverlayShowParams } from '../hooks/useOverlay';
3
+ import { NonUndefined } from '../types/NonUndefined';
4
+ import { RemoveObject } from '../types/RemoveObject';
5
+ import { Renderable } from '../types/Renderable';
6
+ import { MenuApi, MenuState } from './MenuState';
7
+
8
+ export type MenuRenderable = string | number | RemoveObject<Renderable>;
9
+
10
+ export type MenuRuntimeItemSelectable = {
11
+ type: 'item';
12
+ key: string;
13
+ parentMenuId: string;
14
+ active: boolean;
15
+ keyboardActive: boolean;
16
+ value: MenuItemObject;
17
+ style?: CSSProperties;
18
+ className?: string;
19
+ disabled: boolean;
20
+ span: number;
21
+ menu: MenuProps | (() => MenuProps) | null;
22
+ originalMenuItem: MenuItemObject;
23
+ };
24
+ export type MenuRuntimeItem =
25
+ | MenuRuntimeItemSelectable
26
+ | {
27
+ type: 'decoration';
28
+ value: MenuDecoration;
29
+ style: CSSProperties;
30
+ span: number;
31
+ };
32
+
33
+ export type MenuChildrenFnParam = {
34
+ item: MenuRuntimeItem;
35
+ column: MenuColumn;
36
+ columns: MenuColumn[];
37
+ };
38
+
39
+ export type MenuProps = {
40
+ id?: string;
41
+ portalContainer?: ElementContainerGetter | false | null;
42
+ items?: MenuItemDefinition[];
43
+ constrainTo?: OverlayShowParams['constrainTo'];
44
+ columns?: MenuColumn[];
45
+ children?: MenuRenderable;
46
+ wrapLabels?: boolean;
47
+ onShow?: (state: MenuState, api: MenuApi) => void;
48
+ onHide?: (state: MenuState) => void;
49
+ onHideIntent?: (state: MenuState) => void;
50
+ bubbleActionsFromSubmenus?: boolean;
51
+ addSubmenuColumnIfNeeded?: boolean;
52
+ onAction?: (key: string, item: MenuItemObject) => void;
53
+ parentMenuId?: string;
54
+ parentMenuItemKey?: string;
55
+ autoFocus?: boolean;
56
+ };
57
+
58
+ export type MenuSeparator = '-';
59
+ export type MenuItemDefinition =
60
+ | MenuItemObject
61
+ | MenuDecoration
62
+ | MenuSeparator;
63
+
64
+ type MenuItemSubMenu = Omit<MenuProps, 'children' | 'items'> & {
65
+ items: (MenuItemObject | MenuSeparator)[];
66
+ };
67
+
68
+ export type MenuItemObject = {
69
+ key: string;
70
+ label: NonUndefined<MenuRenderable>;
71
+ span?: number;
72
+ description?: MenuRenderable;
73
+ disabled?: boolean;
74
+ menu?: MenuItemSubMenu | (() => MenuItemSubMenu);
75
+ style?: CSSProperties;
76
+ className?: string;
77
+ onClick?: (event: React.MouseEvent) => void;
78
+ onAction?: (key: string, item: MenuItemObject) => void;
79
+ [k: string]: any;
80
+ };
81
+
82
+ export type MenuDecoration = MenuRenderable;
83
+
84
+ export type MenuColumn = {
85
+ flex?: number;
86
+ width?: string | number;
87
+ style?: CSSProperties;
88
+ name: string;
89
+ field?: string;
90
+ render?: (param: MenuColumnRenderParam) => MenuRenderable;
91
+ };
92
+
93
+ export type MenuColumnRenderParam = {
94
+ item: MenuItemObject;
95
+ column: MenuColumn;
96
+ value: MenuRenderable;
97
+ domProps: HTMLProps<HTMLDivElement>;
98
+ };
@@ -0,0 +1,56 @@
1
+ import { MutableRefObject } from 'react';
2
+ import { ComponentStateActions } from '../hooks/useComponentState/types';
3
+ import {
4
+ MenuColumn,
5
+ MenuProps,
6
+ MenuRuntimeItem,
7
+ MenuRuntimeItemSelectable,
8
+ } from './MenuProps';
9
+
10
+ export type MenuSetupState = {
11
+ domRef: MutableRefObject<HTMLDivElement | null>;
12
+ keyboardActiveItemKey: string | null;
13
+ activeItemKey: string | null;
14
+ generatedId: string;
15
+ focused: boolean;
16
+ destroyed: boolean;
17
+ };
18
+
19
+ export type MenuDerivedState = {
20
+ runtimeItems: MenuRuntimeItem[];
21
+ runtimeSelectableItems: MenuRuntimeItemSelectable[];
22
+ columns: MenuColumn[];
23
+ menuId: string;
24
+ };
25
+
26
+ export type MenuMappedState = {
27
+ parentMenuId: MenuProps['parentMenuId'];
28
+ parentMenuItemKey: MenuProps['parentMenuItemKey'];
29
+ constrainTo: MenuProps['constrainTo'];
30
+ autoFocus: MenuProps['autoFocus'];
31
+ onHideIntent: MenuProps['onHideIntent'];
32
+ onAction: MenuProps['onAction'];
33
+ onShow: MenuProps['onShow'];
34
+ onHide: MenuProps['onHide'];
35
+ wrapLabels: MenuProps['wrapLabels'];
36
+ };
37
+
38
+ export interface MenuState
39
+ extends MenuMappedState,
40
+ MenuDerivedState,
41
+ MenuSetupState {}
42
+
43
+ export type MenuActions = ComponentStateActions<MenuState>;
44
+
45
+ export type MenuApi = {
46
+ focus: VoidFunction;
47
+ getMenuId: () => string;
48
+ getParentMenuId: () => string | undefined;
49
+ };
50
+ export type MenuComputedValues = {};
51
+ export type MenuRuntimeItemContext = {
52
+ columns: MenuColumn[];
53
+ keyboardActiveItemKey: string | null;
54
+ activeItemKey: string | null;
55
+ menuId: string;
56
+ };
@@ -0,0 +1,352 @@
1
+ import { getGlobal } from '../../utils/getGlobal';
2
+ import { Point } from '../../utils/pageGeometry/Point';
3
+ import { Rectangle } from '../../utils/pageGeometry/Rectangle';
4
+ import { Triangle } from '../../utils/pageGeometry/Triangle';
5
+ import { raf } from '../../utils/raf';
6
+
7
+ const ACTIVE_OTHER_MENU_ITEM_TIMEOUT = 250;
8
+
9
+ export function waitForValueOnRaf<ReturnType>(
10
+ getter: () => ReturnType,
11
+ timeout: number = 100,
12
+ ): Promise<ReturnType | undefined> {
13
+ const start = Date.now();
14
+ return new Promise((resolve) => {
15
+ let value;
16
+
17
+ const fn = () => {
18
+ value = getter();
19
+ if (value !== undefined) {
20
+ resolve(value);
21
+ return;
22
+ }
23
+ if (Date.now() - start > timeout) {
24
+ resolve(undefined);
25
+ return;
26
+ }
27
+
28
+ raf(fn);
29
+ };
30
+
31
+ // it's important to start it on next tick
32
+ raf(() => {
33
+ fn();
34
+ });
35
+ });
36
+ }
37
+
38
+ const globalObject = getGlobal();
39
+
40
+ type MenuTriangleParams = {
41
+ timeout?: number;
42
+ /**
43
+ * NOTE: #IAC-false
44
+ * onItemActivateChange will only be called
45
+ * with `itemKey: null` when the user has an active item that has no submenu and
46
+ * leaves the menu hovering off that item directly outside the menu (not over another item).
47
+ *
48
+ * In this case, we want to mark that menu item as inactive, as it doesn't have any submenus.
49
+ *
50
+ * If the user hovers away from the menu when an item (that has submenu) is active,
51
+ * we keep that as active even when the mouse is away, so we don't call onItemActivateChange with `itemKey: null`.
52
+ */
53
+ onItemActivate: (itemKey: string | null, target: HTMLElement | null) => void;
54
+ itemHasSubMenu: (itemKey: string) => boolean;
55
+ getMenuRectFor: (itemKey: string) => Rectangle | undefined;
56
+ parentMenuId?: string;
57
+ };
58
+ /**
59
+ * Here's the logic of menu and the menu triangle solution:
60
+ *
61
+ * - use hovers a menu item
62
+ * - user then diagonally goes down and to the right to access the submenu
63
+ * and even though along the way other menu items are hovered, the submenu
64
+ * is not closed (and submenus for hovered items are not displayed along the way) - unless the move is slow (take more than say 200ms). When
65
+ * an item has the submenu visible, we call it "active".
66
+ * - if the move reverses, the submenu is closed and the last hovered item is activated
67
+ *
68
+ * Even items with no submenus can be active.
69
+ *
70
+ */
71
+
72
+ export class MenuTriangleContext {
73
+ private activeItem: string | null = null;
74
+ private currentHoveredItem: string | null = null;
75
+
76
+ // private activeItemTimestamp: number = 0;
77
+ private activeItemLeavePoint: Point | null = null;
78
+
79
+ private menuLeaveTimeoutId: any = null;
80
+
81
+ // private activeItemEventTarget: HTMLElement | null = null;
82
+ private activeItemMenuRect: Rectangle | null = null;
83
+
84
+ private lastPointerMoveTimestamp: number = 0;
85
+ private mouseMoveTimeoutId: number = 0;
86
+ private params: MenuTriangleParams;
87
+
88
+ private lastHorizontalDiff: number = 0;
89
+
90
+ constructor(params: MenuTriangleParams) {
91
+ this.params = params;
92
+ }
93
+
94
+ private getTimeout = () => {
95
+ return this.params.timeout || ACTIVE_OTHER_MENU_ITEM_TIMEOUT;
96
+ };
97
+
98
+ private getPointerMoveTarget = () => {
99
+ return document.documentElement || globalObject;
100
+ };
101
+
102
+ private removePointerMoveListener = () => {
103
+ this.getPointerMoveTarget().removeEventListener(
104
+ 'pointermove',
105
+ this.onPointerMoveWhileActiveItem,
106
+ );
107
+ };
108
+
109
+ /**
110
+ * The whole point of this method is to change the active item when the mouse moves,
111
+ * if the user is moving slowly or outside the menu triangle.
112
+ *
113
+ * This is called while having a currently active item.
114
+ */
115
+ private onPointerMoveWhileActiveItem = (pointerMoveEvent?: PointerEvent) => {
116
+ clearTimeout(this.mouseMoveTimeoutId);
117
+
118
+ if (!pointerMoveEvent) {
119
+ // we called it ourselves
120
+ // in order to update the timestamp of the last move
121
+ this.lastPointerMoveTimestamp = Date.now();
122
+ // and we exit early
123
+ return;
124
+ }
125
+
126
+ // if there is no hovered item, or the hovered item is the active one, we can return
127
+ // because we don't need tp update the active item
128
+ if (
129
+ !this.currentHoveredItem ||
130
+ this.currentHoveredItem === this.activeItem
131
+ ) {
132
+ return;
133
+ }
134
+
135
+ const now = Date.now();
136
+
137
+ if (!this.lastPointerMoveTimestamp) {
138
+ this.lastPointerMoveTimestamp = now;
139
+ }
140
+
141
+ const timeElapsed = now - this.lastPointerMoveTimestamp;
142
+ const timeoutGone = timeElapsed > this.getTimeout();
143
+
144
+ // update the value of the last move timestamp
145
+ this.lastPointerMoveTimestamp = now;
146
+
147
+ const activateHoveredItem = () => {
148
+ this.setActiveItem(null, null);
149
+ // so we trigger onItemChange for the last hovered item again
150
+ // because the move was slow or out of triangle
151
+
152
+ this.onItemChange(true, this.currentHoveredItem!, pointerMoveEvent);
153
+ };
154
+
155
+ if (timeoutGone) {
156
+ // the last mouse move was too long ago
157
+ // so we trigger onItemChange for the last hovered item
158
+ activateHoveredItem();
159
+ return;
160
+ }
161
+
162
+ let hoveredItem = this.currentHoveredItem;
163
+ this.mouseMoveTimeoutId = setTimeout(() => {
164
+ if (hoveredItem !== this.currentHoveredItem) {
165
+ // the hover item has changed, so we're out of sync
166
+ return;
167
+ }
168
+
169
+ const now = Date.now();
170
+ const elapsedTime = now - this.lastPointerMoveTimestamp;
171
+ const timeoutGone = elapsedTime > this.getTimeout();
172
+
173
+ if (timeoutGone) {
174
+ activateHoveredItem();
175
+ }
176
+ }, this.getTimeout()) as any as number;
177
+
178
+ const currentPoint = new Point({
179
+ left: pointerMoveEvent.clientX,
180
+ top: pointerMoveEvent.clientY,
181
+ });
182
+
183
+ // for checking the triangle logic, we have to have those, otherwise we can't continue
184
+ if (!this.activeItemMenuRect || !this.activeItemLeavePoint) {
185
+ return;
186
+ }
187
+
188
+ // we need to check if the user is moving the mouse back from the submenu to the menu again
189
+ // this is a reverse movement, so we should activate the last hovered item
190
+
191
+ const submenuToTheRight =
192
+ this.activeItemLeavePoint.left < this.activeItemMenuRect.left;
193
+
194
+ const horizontalDirectionSign = submenuToTheRight ? 1 : -1;
195
+ const horizontalDiff =
196
+ horizontalDirectionSign *
197
+ (currentPoint.left - this.activeItemLeavePoint.left);
198
+
199
+ if (horizontalDiff - this.lastHorizontalDiff < 0) {
200
+ this.lastHorizontalDiff = 0;
201
+ activateHoveredItem();
202
+ return;
203
+ }
204
+ this.lastHorizontalDiff = horizontalDiff;
205
+
206
+ // we need to check if the user is moving diagonally down and to the right/left (depending on the submenu position)
207
+ const triangle = submenuToTheRight
208
+ ? new Triangle([
209
+ this.activeItemLeavePoint,
210
+ this.activeItemMenuRect.getTopLeft(),
211
+ this.activeItemMenuRect.getBottomLeft(),
212
+ ])
213
+ : new Triangle([
214
+ // in this case, the menu is placed to the left, so adjust the triangle
215
+ this.activeItemLeavePoint,
216
+ this.activeItemMenuRect.getTopRight(),
217
+ this.activeItemMenuRect.getBottomRight(),
218
+ ]);
219
+
220
+ if (!triangle.containsPoint(currentPoint)) {
221
+ this.setActiveItem(null, null);
222
+ this.onItemChange(true, this.currentHoveredItem!, pointerMoveEvent);
223
+ }
224
+ };
225
+
226
+ /**
227
+ * See #IAC-false note above
228
+ */
229
+ private setupMenuLeaveTracking = () => {
230
+ this.menuLeaveTimeoutId = setTimeout(() => {
231
+ if (this.activeItem && this.params.itemHasSubMenu(this.activeItem)) {
232
+ // as per the note #IAC-false
233
+ // we don't continue clearing the active item if it has submenus
234
+ return;
235
+ }
236
+ this.setActiveItem(null, null);
237
+ }, this.getTimeout());
238
+ };
239
+
240
+ /**
241
+ * This function should call onItemActivate to notify whoever's listening
242
+ */
243
+ private setActiveItem = (
244
+ itemKey: string | null,
245
+ target: HTMLElement | null,
246
+ ) => {
247
+ if (itemKey === this.activeItem) {
248
+ return;
249
+ }
250
+
251
+ if (itemKey == null) {
252
+ this.removePointerMoveListener();
253
+ this.params.onItemActivate(null, null);
254
+
255
+ this.activeItem = null;
256
+ // this.activeItemTimestamp = 0;
257
+ // this.activeItemEventTarget = null;
258
+ this.activeItemMenuRect = null;
259
+
260
+ return;
261
+ }
262
+
263
+ this.activeItem = itemKey;
264
+ // this.activeItemTimestamp = Date.now();
265
+ // this.activeItemEventTarget = target as HTMLElement;
266
+
267
+ this.params.onItemActivate(itemKey, target);
268
+
269
+ this.activeItemMenuRect = null;
270
+ // wait for the active item to be rendered
271
+ // so we can retrieve the rect
272
+
273
+ waitForValueOnRaf(() => {
274
+ if (this.activeItem != itemKey) {
275
+ return false;
276
+ }
277
+ return this.params.getMenuRectFor(itemKey);
278
+ }).then((rect: Rectangle | false | undefined) => {
279
+ if (this.activeItem != itemKey) {
280
+ return;
281
+ }
282
+ if (rect) {
283
+ this.activeItemMenuRect = rect;
284
+ }
285
+ });
286
+ };
287
+
288
+ /**
289
+ * This function is called when an item receives mouse enter or mouse leave.
290
+ */
291
+ private onItemChange = (
292
+ hovered: boolean,
293
+ itemKey: string,
294
+ event: PointerEvent,
295
+ ) => {
296
+ clearTimeout(this.menuLeaveTimeoutId);
297
+ clearTimeout(this.mouseMoveTimeoutId);
298
+
299
+ if (!hovered) {
300
+ this.removePointerMoveListener();
301
+
302
+ if (itemKey === this.activeItem) {
303
+ // we're leaving the currently opened item
304
+ // so make sure we save the leave coords as we might need them
305
+ // later in the triangle logic
306
+ this.activeItemLeavePoint = new Point({
307
+ left: event.clientX,
308
+ top: event.clientY,
309
+ });
310
+ }
311
+
312
+ // we might be leaving the menu for good and stop moving the mouse for a while
313
+ // so we need to make sure we start the timeout
314
+ this.setupMenuLeaveTracking();
315
+ return;
316
+ }
317
+
318
+ // if by some accident this gets called twice one after the other, we can simply ignore this
319
+ // if (this.currentHoveredItem === itemKey) {
320
+ // return;
321
+ // }
322
+
323
+ this.currentHoveredItem = itemKey;
324
+ if (!this.activeItem || !this.params.itemHasSubMenu(this.activeItem)) {
325
+ // no item is currently activated or the currently activated item does not have a submenu
326
+ // so we can safely activate the hovered item immediately
327
+ this.setActiveItem(itemKey, event.target as HTMLElement);
328
+ return;
329
+ }
330
+
331
+ // there is an active item already, and the active item does have a submenu
332
+ // and the active item is different from the currently hovered item
333
+ // so we listen to mouse moves
334
+
335
+ this.onPointerMoveWhileActiveItem(); // we need to call this in order to initialize the timestamp of the last "move" (to the value of Date.now())
336
+ this.getPointerMoveTarget().addEventListener(
337
+ 'pointermove',
338
+ this.onPointerMoveWhileActiveItem,
339
+ );
340
+ };
341
+
342
+ getHandlers = () => {
343
+ return {
344
+ onItemEnter: (itemKey: string, event: PointerEvent) => {
345
+ this.onItemChange(true, itemKey, event);
346
+ },
347
+ onItemLeave: (itemKey: string, event: PointerEvent) => {
348
+ this.onItemChange(false, itemKey, event);
349
+ },
350
+ };
351
+ };
352
+ }