@rowsncolumns/spreadsheet 10.2.72 → 10.2.74

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 (132) hide show
  1. package/dist/cjs/api/evaluate-formula.d.ts +17 -0
  2. package/dist/cjs/api/evaluate-formula.d.ts.map +1 -0
  3. package/dist/cjs/api/evaluate-formula.js +141 -0
  4. package/dist/cjs/api/go-to.d.ts +19 -0
  5. package/dist/cjs/api/go-to.d.ts.map +1 -0
  6. package/dist/cjs/api/go-to.js +49 -0
  7. package/dist/cjs/atoms/evaluate-formula-dialog.atom.d.ts +36 -0
  8. package/dist/cjs/atoms/evaluate-formula-dialog.atom.d.ts.map +1 -0
  9. package/dist/cjs/atoms/evaluate-formula-dialog.atom.js +36 -0
  10. package/dist/cjs/atoms/go-to-dialog.atom.d.ts +36 -0
  11. package/dist/cjs/atoms/go-to-dialog.atom.d.ts.map +1 -0
  12. package/dist/cjs/atoms/go-to-dialog.atom.js +34 -0
  13. package/dist/cjs/atoms/index.d.ts +4 -0
  14. package/dist/cjs/atoms/index.d.ts.map +1 -1
  15. package/dist/cjs/atoms/index.js +4 -0
  16. package/dist/cjs/atoms/paste-special-dialog.atom.d.ts +29 -0
  17. package/dist/cjs/atoms/paste-special-dialog.atom.d.ts.map +1 -0
  18. package/dist/cjs/atoms/paste-special-dialog.atom.js +34 -0
  19. package/dist/cjs/atoms/remove-duplicates-dialog.atom.d.ts +45 -0
  20. package/dist/cjs/atoms/remove-duplicates-dialog.atom.d.ts.map +1 -0
  21. package/dist/cjs/atoms/remove-duplicates-dialog.atom.js +37 -0
  22. package/dist/cjs/components/canvas-grid/index.d.ts.map +1 -1
  23. package/dist/cjs/components/canvas-grid/index.js +109 -3
  24. package/dist/cjs/components/canvas-grid/typings.d.ts +54 -8
  25. package/dist/cjs/components/canvas-grid/typings.d.ts.map +1 -1
  26. package/dist/cjs/components/context-menu/index.d.ts +16 -3
  27. package/dist/cjs/components/context-menu/index.d.ts.map +1 -1
  28. package/dist/cjs/components/context-menu/index.js +112 -5
  29. package/dist/cjs/components/context-menu/total-row-functions.d.ts +32 -0
  30. package/dist/cjs/components/context-menu/total-row-functions.d.ts.map +1 -0
  31. package/dist/cjs/components/context-menu/total-row-functions.js +62 -0
  32. package/dist/cjs/components/evaluate-formula-dialog/index.d.ts +34 -0
  33. package/dist/cjs/components/evaluate-formula-dialog/index.d.ts.map +1 -0
  34. package/dist/cjs/components/evaluate-formula-dialog/index.js +106 -0
  35. package/dist/cjs/components/go-to-dialog/index.d.ts +35 -0
  36. package/dist/cjs/components/go-to-dialog/index.d.ts.map +1 -0
  37. package/dist/cjs/components/go-to-dialog/index.js +93 -0
  38. package/dist/cjs/components/paste-special-dialog/index.d.ts +29 -0
  39. package/dist/cjs/components/paste-special-dialog/index.d.ts.map +1 -0
  40. package/dist/cjs/components/paste-special-dialog/index.js +99 -0
  41. package/dist/cjs/components/remove-duplicates-dialog/index.d.ts +37 -0
  42. package/dist/cjs/components/remove-duplicates-dialog/index.d.ts.map +1 -0
  43. package/dist/cjs/components/remove-duplicates-dialog/index.js +91 -0
  44. package/dist/cjs/components/toolbar/index.d.ts +1 -0
  45. package/dist/cjs/components/toolbar/index.d.ts.map +1 -1
  46. package/dist/cjs/components/toolbar/index.js +1 -0
  47. package/dist/cjs/components/toolbar/text-rotation-selector.d.ts +29 -0
  48. package/dist/cjs/components/toolbar/text-rotation-selector.d.ts.map +1 -0
  49. package/dist/cjs/components/toolbar/text-rotation-selector.js +78 -0
  50. package/dist/cjs/components/toolbar/text-wrap-selector.d.ts +7 -1
  51. package/dist/cjs/components/toolbar/text-wrap-selector.d.ts.map +1 -1
  52. package/dist/cjs/components/toolbar/text-wrap-selector.js +10 -3
  53. package/dist/cjs/hooks/use-copy-paste-cut.d.ts +20 -1
  54. package/dist/cjs/hooks/use-copy-paste-cut.d.ts.map +1 -1
  55. package/dist/cjs/hooks/use-copy-paste-cut.js +27 -21
  56. package/dist/cjs/hooks/use-keyboard-handler.d.ts +17 -2
  57. package/dist/cjs/hooks/use-keyboard-handler.d.ts.map +1 -1
  58. package/dist/cjs/hooks/use-keyboard-handler.js +186 -21
  59. package/dist/cjs/index.d.ts +6 -1
  60. package/dist/cjs/index.d.ts.map +1 -1
  61. package/dist/cjs/index.js +7 -1
  62. package/dist/cjs/release-date.js +1 -1
  63. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  64. package/dist/cjs/types.d.ts +173 -1
  65. package/dist/cjs/types.d.ts.map +1 -1
  66. package/dist/esm/api/evaluate-formula.d.ts +17 -0
  67. package/dist/esm/api/evaluate-formula.d.ts.map +1 -0
  68. package/dist/esm/api/evaluate-formula.js +109 -0
  69. package/dist/esm/api/go-to.d.ts +19 -0
  70. package/dist/esm/api/go-to.d.ts.map +1 -0
  71. package/dist/esm/api/go-to.js +41 -0
  72. package/dist/esm/atoms/evaluate-formula-dialog.atom.d.ts +36 -0
  73. package/dist/esm/atoms/evaluate-formula-dialog.atom.d.ts.map +1 -0
  74. package/dist/esm/atoms/evaluate-formula-dialog.atom.js +25 -0
  75. package/dist/esm/atoms/go-to-dialog.atom.d.ts +36 -0
  76. package/dist/esm/atoms/go-to-dialog.atom.d.ts.map +1 -0
  77. package/dist/esm/atoms/go-to-dialog.atom.js +25 -0
  78. package/dist/esm/atoms/index.d.ts +4 -0
  79. package/dist/esm/atoms/index.d.ts.map +1 -1
  80. package/dist/esm/atoms/index.js +4 -0
  81. package/dist/esm/atoms/paste-special-dialog.atom.d.ts +29 -0
  82. package/dist/esm/atoms/paste-special-dialog.atom.d.ts.map +1 -0
  83. package/dist/esm/atoms/paste-special-dialog.atom.js +25 -0
  84. package/dist/esm/atoms/remove-duplicates-dialog.atom.d.ts +45 -0
  85. package/dist/esm/atoms/remove-duplicates-dialog.atom.d.ts.map +1 -0
  86. package/dist/esm/atoms/remove-duplicates-dialog.atom.js +26 -0
  87. package/dist/esm/components/canvas-grid/index.d.ts.map +1 -1
  88. package/dist/esm/components/canvas-grid/index.js +107 -3
  89. package/dist/esm/components/canvas-grid/typings.d.ts +54 -8
  90. package/dist/esm/components/canvas-grid/typings.d.ts.map +1 -1
  91. package/dist/esm/components/context-menu/index.d.ts +16 -3
  92. package/dist/esm/components/context-menu/index.d.ts.map +1 -1
  93. package/dist/esm/components/context-menu/index.js +114 -7
  94. package/dist/esm/components/context-menu/total-row-functions.d.ts +32 -0
  95. package/dist/esm/components/context-menu/total-row-functions.d.ts.map +1 -0
  96. package/dist/esm/components/context-menu/total-row-functions.js +50 -0
  97. package/dist/esm/components/evaluate-formula-dialog/index.d.ts +34 -0
  98. package/dist/esm/components/evaluate-formula-dialog/index.d.ts.map +1 -0
  99. package/dist/esm/components/evaluate-formula-dialog/index.js +86 -0
  100. package/dist/esm/components/go-to-dialog/index.d.ts +35 -0
  101. package/dist/esm/components/go-to-dialog/index.d.ts.map +1 -0
  102. package/dist/esm/components/go-to-dialog/index.js +84 -0
  103. package/dist/esm/components/paste-special-dialog/index.d.ts +29 -0
  104. package/dist/esm/components/paste-special-dialog/index.d.ts.map +1 -0
  105. package/dist/esm/components/paste-special-dialog/index.js +90 -0
  106. package/dist/esm/components/remove-duplicates-dialog/index.d.ts +37 -0
  107. package/dist/esm/components/remove-duplicates-dialog/index.d.ts.map +1 -0
  108. package/dist/esm/components/remove-duplicates-dialog/index.js +82 -0
  109. package/dist/esm/components/toolbar/index.d.ts +1 -0
  110. package/dist/esm/components/toolbar/index.d.ts.map +1 -1
  111. package/dist/esm/components/toolbar/index.js +1 -0
  112. package/dist/esm/components/toolbar/text-rotation-selector.d.ts +29 -0
  113. package/dist/esm/components/toolbar/text-rotation-selector.d.ts.map +1 -0
  114. package/dist/esm/components/toolbar/text-rotation-selector.js +71 -0
  115. package/dist/esm/components/toolbar/text-wrap-selector.d.ts +7 -1
  116. package/dist/esm/components/toolbar/text-wrap-selector.d.ts.map +1 -1
  117. package/dist/esm/components/toolbar/text-wrap-selector.js +10 -3
  118. package/dist/esm/hooks/use-copy-paste-cut.d.ts +20 -1
  119. package/dist/esm/hooks/use-copy-paste-cut.d.ts.map +1 -1
  120. package/dist/esm/hooks/use-copy-paste-cut.js +10 -4
  121. package/dist/esm/hooks/use-keyboard-handler.d.ts +17 -2
  122. package/dist/esm/hooks/use-keyboard-handler.d.ts.map +1 -1
  123. package/dist/esm/hooks/use-keyboard-handler.js +173 -21
  124. package/dist/esm/index.d.ts +6 -1
  125. package/dist/esm/index.d.ts.map +1 -1
  126. package/dist/esm/index.js +5 -0
  127. package/dist/esm/release-date.js +1 -1
  128. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  129. package/dist/esm/types.d.ts +173 -1
  130. package/dist/esm/types.d.ts.map +1 -1
  131. package/dist/spreadsheet.min.css +1 -1
  132. package/package.json +6 -6
@@ -0,0 +1,36 @@
1
+ import type { CellInterface } from "@rowsncolumns/grid";
2
+ import type { NamedRange, SheetRange } from "../types";
3
+ /**
4
+ * Open-state + payload for the Go To dialog (Excel `Ctrl+G` / `F5`). The grid
5
+ * opens it with everything needed to resolve a reference against the
6
+ * workbook; the host-mounted dialog hands the resolved range to `onNavigate`.
7
+ */
8
+ export type GoToDialogRequest = {
9
+ sheetId: number;
10
+ activeCell: CellInterface;
11
+ namedRanges?: NamedRange[] | null;
12
+ getSheetId?: (sheetName: string) => number | undefined;
13
+ getSheetName?: (sheetId: number) => string | undefined;
14
+ rowCount?: number;
15
+ columnCount?: number;
16
+ onNavigate: (range: SheetRange) => void;
17
+ };
18
+ export declare const goToDialogAtom: import("jotai").PrimitiveAtom<GoToDialogRequest | null> & {
19
+ init: GoToDialogRequest | null;
20
+ };
21
+ export declare const useGoToDialogState: () => [GoToDialogRequest | null, (args_0: GoToDialogRequest | ((prev: GoToDialogRequest | null) => GoToDialogRequest | null) | null) => void];
22
+ /**
23
+ * Number of mounted `GoToDialogHost`s. The grid only claims the trigger
24
+ * (shortcut / context-menu item) while a host is mounted, so a host that has
25
+ * not adopted the dialog keeps the browser default instead of a dead action.
26
+ */
27
+ export declare const goToDialogHostCountAtom: import("jotai").PrimitiveAtom<number> & {
28
+ init: number;
29
+ };
30
+ /** True when at least one `GoToDialogHost` is mounted. */
31
+ export declare const useIsGoToDialogMounted: () => boolean;
32
+ /** Registers the calling component as a dialog host for its lifetime. */
33
+ export declare const useRegisterGoToDialogHost: () => void;
34
+ /** Returns a function that opens the host-mounted Go To dialog. */
35
+ export declare const useOpenGoToDialog: () => (request: GoToDialogRequest) => void;
36
+ //# sourceMappingURL=go-to-dialog.atom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"go-to-dialog.atom.d.ts","sourceRoot":"","sources":["../../../atoms/go-to-dialog.atom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEvD;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,aAAa,CAAC;IAC1B,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACvD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACzC,CAAC;AAEF,eAAO,MAAM,cAAc;;CAAuC,CAAC;AAEnE,eAAO,MAAM,kBAAkB,+IAAgC,CAAC;AAEhE;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;CAAU,CAAC;AAE/C,0DAA0D;AAC1D,eAAO,MAAM,sBAAsB,eACQ,CAAC;AAE5C,yEAAyE;AACzE,eAAO,MAAM,yBAAyB,YAMrC,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,kBAGhB,iBAAiB,SAG9B,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
2
+ import { useCallback, useEffect } from "react";
3
+ export const goToDialogAtom = atom(null);
4
+ export const useGoToDialogState = () => useAtom(goToDialogAtom);
5
+ /**
6
+ * Number of mounted `GoToDialogHost`s. The grid only claims the trigger
7
+ * (shortcut / context-menu item) while a host is mounted, so a host that has
8
+ * not adopted the dialog keeps the browser default instead of a dead action.
9
+ */
10
+ export const goToDialogHostCountAtom = atom(0);
11
+ /** True when at least one `GoToDialogHost` is mounted. */
12
+ export const useIsGoToDialogMounted = () => useAtomValue(goToDialogHostCountAtom) > 0;
13
+ /** Registers the calling component as a dialog host for its lifetime. */
14
+ export const useRegisterGoToDialogHost = () => {
15
+ const setCount = useSetAtom(goToDialogHostCountAtom);
16
+ useEffect(() => {
17
+ setCount((count) => count + 1);
18
+ return () => setCount((count) => count - 1);
19
+ }, [setCount]);
20
+ };
21
+ /** Returns a function that opens the host-mounted Go To dialog. */
22
+ export const useOpenGoToDialog = () => {
23
+ const setRequest = useSetAtom(goToDialogAtom);
24
+ return useCallback((request) => setRequest(request), [setRequest]);
25
+ };
@@ -15,4 +15,8 @@ export * from "./paste-menu.atom";
15
15
  export * from "./magic-fill-state.atom";
16
16
  export * from "./validation-alert.atom";
17
17
  export * from "./sort-dialog.atom";
18
+ export * from "./paste-special-dialog.atom";
19
+ export * from "./go-to-dialog.atom";
20
+ export * from "./evaluate-formula-dialog.atom";
21
+ export * from "./remove-duplicates-dialog.atom";
18
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../atoms/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../atoms/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC;AAChD,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC"}
@@ -15,3 +15,7 @@ export * from "./paste-menu.atom";
15
15
  export * from "./magic-fill-state.atom";
16
16
  export * from "./validation-alert.atom";
17
17
  export * from "./sort-dialog.atom";
18
+ export * from "./paste-special-dialog.atom";
19
+ export * from "./go-to-dialog.atom";
20
+ export * from "./evaluate-formula-dialog.atom";
21
+ export * from "./remove-duplicates-dialog.atom";
@@ -0,0 +1,29 @@
1
+ import type { PasteSpecialOptions } from "../hooks/use-copy-paste-cut";
2
+ /**
3
+ * Open-state + payload for the Paste Special dialog (Excel `Ctrl+Alt+V` /
4
+ * context menu → Paste special…). The grid opens it with the paste callback
5
+ * of the current sheet; the host-mounted dialog routes the chosen options
6
+ * back through `onApply`.
7
+ */
8
+ export type PasteSpecialDialogRequest = {
9
+ onApply: (options: PasteSpecialOptions) => void;
10
+ };
11
+ export declare const pasteSpecialDialogAtom: import("jotai").PrimitiveAtom<PasteSpecialDialogRequest | null> & {
12
+ init: PasteSpecialDialogRequest | null;
13
+ };
14
+ export declare const usePasteSpecialDialogState: () => [PasteSpecialDialogRequest | null, (args_0: PasteSpecialDialogRequest | ((prev: PasteSpecialDialogRequest | null) => PasteSpecialDialogRequest | null) | null) => void];
15
+ /**
16
+ * Number of mounted `PasteSpecialDialogHost`s. The grid only claims the trigger
17
+ * (shortcut / context-menu item) while a host is mounted, so a host that has
18
+ * not adopted the dialog keeps the browser default instead of a dead action.
19
+ */
20
+ export declare const pasteSpecialDialogHostCountAtom: import("jotai").PrimitiveAtom<number> & {
21
+ init: number;
22
+ };
23
+ /** True when at least one `PasteSpecialDialogHost` is mounted. */
24
+ export declare const useIsPasteSpecialDialogMounted: () => boolean;
25
+ /** Registers the calling component as a dialog host for its lifetime. */
26
+ export declare const useRegisterPasteSpecialDialogHost: () => void;
27
+ /** Returns a function that opens the host-mounted Paste Special dialog. */
28
+ export declare const useOpenPasteSpecialDialog: () => (request: PasteSpecialDialogRequest) => void;
29
+ //# sourceMappingURL=paste-special-dialog.atom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paste-special-dialog.atom.d.ts","sourceRoot":"","sources":["../../../atoms/paste-special-dialog.atom.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF,eAAO,MAAM,sBAAsB;;CAElC,CAAC;AAEF,eAAO,MAAM,0BAA0B,+KAAwC,CAAC;AAEhF;;;;GAIG;AACH,eAAO,MAAM,+BAA+B;;CAAU,CAAC;AAEvD,kEAAkE;AAClE,eAAO,MAAM,8BAA8B,eACQ,CAAC;AAEpD,yEAAyE;AACzE,eAAO,MAAM,iCAAiC,YAM7C,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,yBAAyB,kBAGxB,yBAAyB,SAGtC,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
2
+ import { useCallback, useEffect } from "react";
3
+ export const pasteSpecialDialogAtom = atom(null);
4
+ export const usePasteSpecialDialogState = () => useAtom(pasteSpecialDialogAtom);
5
+ /**
6
+ * Number of mounted `PasteSpecialDialogHost`s. The grid only claims the trigger
7
+ * (shortcut / context-menu item) while a host is mounted, so a host that has
8
+ * not adopted the dialog keeps the browser default instead of a dead action.
9
+ */
10
+ export const pasteSpecialDialogHostCountAtom = atom(0);
11
+ /** True when at least one `PasteSpecialDialogHost` is mounted. */
12
+ export const useIsPasteSpecialDialogMounted = () => useAtomValue(pasteSpecialDialogHostCountAtom) > 0;
13
+ /** Registers the calling component as a dialog host for its lifetime. */
14
+ export const useRegisterPasteSpecialDialogHost = () => {
15
+ const setCount = useSetAtom(pasteSpecialDialogHostCountAtom);
16
+ useEffect(() => {
17
+ setCount((count) => count + 1);
18
+ return () => setCount((count) => count - 1);
19
+ }, [setCount]);
20
+ };
21
+ /** Returns a function that opens the host-mounted Paste Special dialog. */
22
+ export const useOpenPasteSpecialDialog = () => {
23
+ const setRequest = useSetAtom(pasteSpecialDialogAtom);
24
+ return useCallback((request) => setRequest(request), [setRequest]);
25
+ };
@@ -0,0 +1,45 @@
1
+ import type { RemoveDuplicatesOptions } from "../types";
2
+ /**
3
+ * One column of the range being de-duplicated.
4
+ */
5
+ export type RemoveDuplicatesDialogColumn = {
6
+ /** Absolute sheet column index. */
7
+ columnIndex: number;
8
+ /** Positional label, e.g. "Column B". */
9
+ label: string;
10
+ /** Text of the first row, shown instead of `label` when "My data has headers" is on. */
11
+ header?: string;
12
+ };
13
+ /**
14
+ * Open-state + payload for the Remove Duplicates dialog. The context menu
15
+ * (which unmounts when it closes) opens the dialog by setting this atom; the
16
+ * dialog itself is host-mounted so it survives the menu closing. Mirrors the
17
+ * Sort dialog atom pattern.
18
+ */
19
+ export type RemoveDuplicatesDialogRequest = {
20
+ columns: RemoveDuplicatesDialogColumn[];
21
+ /** Initial state of "My data has headers". */
22
+ hasHeader: boolean;
23
+ /** Routed to `onRemoveDuplicates` by the opener. */
24
+ onApply: (options: RemoveDuplicatesOptions) => void;
25
+ };
26
+ export declare const removeDuplicatesDialogAtom: import("jotai").PrimitiveAtom<RemoveDuplicatesDialogRequest | null> & {
27
+ init: RemoveDuplicatesDialogRequest | null;
28
+ };
29
+ /**
30
+ * Number of mounted `RemoveDuplicatesDialogHost`s. Openers fall back to an
31
+ * immediate de-dupe when no host is mounted, so a host that has not adopted
32
+ * the dialog keeps the previous one-click behaviour instead of a dead menu
33
+ * item.
34
+ */
35
+ export declare const removeDuplicatesDialogHostCountAtom: import("jotai").PrimitiveAtom<number> & {
36
+ init: number;
37
+ };
38
+ export declare const useRemoveDuplicatesDialogState: () => [RemoveDuplicatesDialogRequest | null, (args_0: RemoveDuplicatesDialogRequest | ((prev: RemoveDuplicatesDialogRequest | null) => RemoveDuplicatesDialogRequest | null) | null) => void];
39
+ /** Returns a function that opens the host-mounted Remove Duplicates dialog. */
40
+ export declare const useOpenRemoveDuplicatesDialog: () => (request: RemoveDuplicatesDialogRequest) => void;
41
+ /** True when at least one `RemoveDuplicatesDialogHost` is mounted. */
42
+ export declare const useIsRemoveDuplicatesDialogMounted: () => boolean;
43
+ /** Registers the calling component as a dialog host for its lifetime. */
44
+ export declare const useRegisterRemoveDuplicatesDialogHost: () => void;
45
+ //# sourceMappingURL=remove-duplicates-dialog.atom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove-duplicates-dialog.atom.d.ts","sourceRoot":"","sources":["../../../atoms/remove-duplicates-dialog.atom.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,mCAAmC;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,4BAA4B,EAAE,CAAC;IACxC,8CAA8C;IAC9C,SAAS,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,OAAO,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAC;CACrD,CAAC;AAEF,eAAO,MAAM,0BAA0B;;CACW,CAAC;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,mCAAmC;;CAAU,CAAC;AAE3D,eAAO,MAAM,8BAA8B,+LACN,CAAC;AAEtC,+EAA+E;AAC/E,eAAO,MAAM,6BAA6B,kBAG5B,6BAA6B,SAG1C,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,kCAAkC,eACQ,CAAC;AAExD,yEAAyE;AACzE,eAAO,MAAM,qCAAqC,YAMjD,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { atom, useAtom, useAtomValue, useSetAtom } from "jotai";
2
+ import { useCallback, useEffect } from "react";
3
+ export const removeDuplicatesDialogAtom = atom(null);
4
+ /**
5
+ * Number of mounted `RemoveDuplicatesDialogHost`s. Openers fall back to an
6
+ * immediate de-dupe when no host is mounted, so a host that has not adopted
7
+ * the dialog keeps the previous one-click behaviour instead of a dead menu
8
+ * item.
9
+ */
10
+ export const removeDuplicatesDialogHostCountAtom = atom(0);
11
+ export const useRemoveDuplicatesDialogState = () => useAtom(removeDuplicatesDialogAtom);
12
+ /** Returns a function that opens the host-mounted Remove Duplicates dialog. */
13
+ export const useOpenRemoveDuplicatesDialog = () => {
14
+ const setRequest = useSetAtom(removeDuplicatesDialogAtom);
15
+ return useCallback((request) => setRequest(request), [setRequest]);
16
+ };
17
+ /** True when at least one `RemoveDuplicatesDialogHost` is mounted. */
18
+ export const useIsRemoveDuplicatesDialogMounted = () => useAtomValue(removeDuplicatesDialogHostCountAtom) > 0;
19
+ /** Registers the calling component as a dialog host for its lifetime. */
20
+ export const useRegisterRemoveDuplicatesDialogHost = () => {
21
+ const setCount = useSetAtom(removeDuplicatesDialogHostCountAtom);
22
+ useEffect(() => {
23
+ setCount((count) => count + 1);
24
+ return () => setCount((count) => count - 1);
25
+ }, [setCount]);
26
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/canvas-grid/index.tsx"],"names":[],"mappings":"AA2CA,OAAO,KASN,MAAM,OAAO,CAAC;AAoKf,OAAO,KAAK,EAEV,QAAQ,EAST,MAAM,aAAa,CAAC;AAarB,OAAO,KAAK,EACV,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EAEhB,MAAM,WAAW,CAAC;AAipJnB,eAAO,MAAM,UAAU,EAA4C,CACjE,CAAC,SAAS,QAAQ,CAAC,GAAG,CAAC,EAEvB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GACvB,wBAAwB,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;CAAE,KAChE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../components/canvas-grid/index.tsx"],"names":[],"mappings":"AA2CA,OAAO,KASN,MAAM,OAAO,CAAC;AA2Kf,OAAO,KAAK,EAEV,QAAQ,EAST,MAAM,aAAa,CAAC;AAarB,OAAO,KAAK,EACV,wBAAwB,EACxB,iBAAiB,EACjB,eAAe,EAEhB,MAAM,WAAW,CAAC;AA2wJnB,eAAO,MAAM,UAAU,EAA4C,CACjE,CAAC,SAAS,QAAQ,CAAC,GAAG,CAAC,EAEvB,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GACvB,wBAAwB,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;CAAE,KAChE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC"}
@@ -17,7 +17,7 @@ import { generateSelectionsFromFormula } from "../../api/selections";
17
17
  import { SpreadsheetApi } from "../../api/spreadsheet-api";
18
18
  import { findActiveTableWithinCell } from "../../api/table";
19
19
  import { checkBooleanRule, decideValidationCommit, isCellLockedUnderProtection, isProtectedCell, isProtectedSheet, showValidationDropdownArrow, } from "../../api/validation";
20
- import { useFormulaModeValue, useSetNoteEditorCell, useSetPinnedTooltip, useShowPasteMenu, useShowValidationAlert, } from "../../atoms";
20
+ import { useFormulaModeValue, useIsEvaluateFormulaDialogMounted, useIsGoToDialogMounted, useIsPasteSpecialDialogMounted, useOpenEvaluateFormulaDialog, useOpenGoToDialog, useOpenPasteSpecialDialog, useSetNoteEditorCell, useSetPinnedTooltip, useShowPasteMenu, useShowValidationAlert, } from "../../atoms";
21
21
  import { useActiveEditor } from "../../atoms/active-editor.atom";
22
22
  import { useEditingCell } from "../../atoms/editing-cell.atom";
23
23
  import { useCellEditorInstance, useSetFormulabarEditorValue, useSetFormulaBarTextFormatRuns, } from "../../atoms/formula-bar-editor-value.atom";
@@ -60,6 +60,7 @@ import { useKeyboardHandler } from "../../hooks/use-keyboard-handler";
60
60
  import { useLicenseKeyValidator } from "../../hooks/use-licensekey-validator";
61
61
  import { useMoveColumnsAndRows } from "../../hooks/use-move-columns-rows";
62
62
  import { useNavigateToSheetRange } from "../../hooks/use-navigate-sheet-range";
63
+ import { createExpressionEvaluator } from "../../api/evaluate-formula";
63
64
  import { useRaf } from "../../hooks/use-raf";
64
65
  import { useResizeObserver } from "../../hooks/use-resize-observer";
65
66
  import { useScaleListener } from "../../hooks/use-scale-listener";
@@ -99,7 +100,7 @@ import { getNestedPropertyNames } from "./helpers";
99
100
  * @returns
100
101
  */
101
102
  function CanvasGridComponent(props, forwardedRef) {
102
- const { licenseKey, sheetId, instanceId, activeCell = DEFAULT_ACTIVE_CELL, selections = DEFAULT_ARRAY, frozenColumnCount = 0, frozenRowCount = 0, rowCount = DEFAULT_ROW_COUNT, columnCount = DEFAULT_COLUMN_COUNT, autoFocus, basicFilter, tables, namedRanges, bandedRanges = DEFAULT_ARRAY, tableBorderColor = "#008000", filterIconColor = "#008000", conditionalFormats, showFilterIcon = true, showCalculatedColumnIcon = true, showHeaders = true, defaultColumnWidth = DEFAULT_COLUMN_WIDTH, defaultRowHeight = DEFAULT_ROW_HEIGHT, columnHeaderHeight = COLUMN_HEADER_HEIGHT, rowHeaderWidth = ROW_HEADER_WIDTH, gridLineColor = GRIDLINE_COLOR, cellBackgroundColor = DEFAULT_CELL_BACKGROUND_COLOR, cellColor = DEFAULT_CELL_COLOR, headerBorderColor = DEFAULT_HEADER_BORDER_COLOR, headerBackgroundColor = DEFAULT_HEADER_BG, headerColor = DEFAULT_HEADER_COLOR, headerActiveBackgroundColor = DEFAULT_HEADER_ACTIVE_BG, headerSelectedBackgroundColor = DEFAULT_HEADER_SELECTED_BG, headerSelectedColor = "white", headerTableBackgroundColor = DEFAULT_HEADER_TABLE_BG, headerTableActiveBackgroundColor = DEFAULT_HEADER_ACTIVE_TABLE_BG, headerTableSelectedBackgroundColor = DEFAULT_HEADER_SELECTED_TABLE_BG, frozenShadowColor = headerBorderColor, frozenShadowThickness = 1, selectionBackgroundColor = SELECTION_BG, selectionBorderColor = SELECTION_BORDER, selectionDragBorderColor = SELECTION_BORDER, chartSelectedColor, chipBackgroundColor = CHIP_COLOR, merges = DEFAULT_ARRAY, borderStyles, protectedRanges, isWorkbookProtected: isWorkbookProtectedProp = false, getSheetProtection, pivotTables, charts, embeds, slicers, rowMetadata = DEFAULT_ARRAY, columnMetadata = DEFAULT_ARRAY, scale = 1, zoomSpeed = 1, overscanCount = 3, enableEditOnEnterKey = true, enableTextOverflow = true, showGridLines: _showGridLines, showFormulas = false, protectFormulas = false, showFrozenSeparator = true, HeaderCell = DefaultHeaderCell, Cell = DefaultCell, SelectionTitleComponent = SelectionTitle, CellEditor = DefaultCellEditor, CellTooltip, ContextMenu = DefaultContextMenu, ContextMenuWrapper = DefaultContextMenuWrapper, FilterBox = DefaultFilterBox, HeaderMoveDragComponent = DefaultHeaderMoveDragComponent, SuggestionsDropdown, stickyEditor = true, scrollSnap = false, scrollThrottleTimeout, preventBrowserDefaultScroll, mouseMoveThrottleTimeout = 60, tooltipIntentInterval = 60, selectionPolicy, users, userId, renderCollaboratorCursor, functionDescriptions, showHeaderMenuButton = true, scrollbarSize = SCROLLBAR_SIZE, theme = defaultSpreadsheetTheme, showNotes = true, showComments = true, locale, agentSuggestions, onReviewSuggestion, onShowFormulas, getDataRowCount, getChartComponent, getEmbedComponent, getSlicerComponent, onChange, onChangeBatch, onExpandCollapse, onPivotDrillDown, onDelete, onChangeEditorValue, onFill, onRequestCalculate, onChangeActiveCell, onChangeActiveSheet, onChangeSelections, getSheetName, getSheetId, getCellData, getNote: getNoteProp, getTextFormatRuns, getDataValidation, getEffectiveFormat, getFormattedValue: getFormattedValueProp, getTooltipContent, errorResolutionComponent, getEffectiveValue: getEffectiveValueProp, getUserEnteredExtendedValue, getEffectiveExtendedValue, getSheetRowCount, getSheetColumnCount, getCellPopoverContent, onScroll, onViewPortChange, windowConditionalFormats = false, engineConditionalFormatResults = false, onResize, onAutoResize, onHideColumn, onHideRow, onShowColumn, onShowRow, onGroupRows, onUngroupRows, onCollapseRowGroup, onExpandRowGroup, onGroupColumns, onUngroupColumns, onCollapseColumnGroup, onExpandColumnGroup, onSetOutlineDepth, onDeleteRow, onDeleteColumn, onInsertRow, onInsertColumn, onInsertCellsShiftDown, onInsertCellsShiftRight, onDeleteCellsShiftLeft, onDeleteCellsShiftUp, onClearContents, onMoveColumns, onMoveRows, onSelectNextSheet, onSelectPreviousSheet, onCreateNewSheet, onKeyDown, onChangeFormatting, onRepeatFormatting, onClearFormatting, onRequestEditProtectedRange, onMoveChart, onResizeChart, onDeleteChart, onMoveEmbed, onResizeEmbed, onDeleteEmbed, onRequestEditEmbed, onMoveSlicer, onResizeSlicer, onDeleteSlicer, onRequestEditSlicer, onFillRange, disableFillRightShortcut, onMoveSelection, onInsertTime, onInsertDate, onInsertDateTime, onInsertAutoSum, onUndo, onRedo, onPaste, onCopy, onCut, onSortColumn, onSortTable, onFilterTable, onFilterPivot, onResizeTable, onRequestEditTable, onRequestEditPivotTable, onRequestDeletePivotTable, onRemoveTable, onCreateTable, onInsertTableColumn, onDeleteTableColumn, onInsertTableRow, onDeleteTableRow, onCreateBasicFilter, onRequestDefineNamedRange, onRequestFormatCells, onRequestConditionalFormat, onRequestDataValidation, onRequestInsertComment, onRequestInsertLink, onFreezeColumn, onFreezeRow, onUpdateNote, onProtectRange, onUnProtectRange, onSortRange, onRequestSearch, onRequestReplace, onRequestResize, getRowHeaderText = getDefaultRowHeader, getColumnHeaderText = getDefaultColumnHeader, getAdditionalCellSpacing, tokenizer: defaultTokenizer = defaultFormulaTokenizer, onChangeScale, onRemoveLink, onSelectLink, onSplitTextToColumns, onRemoveDuplicates, onRequestExpand, cellExpandPredicate, StructuredResult = DefaultStructuredResult, getMentions, getStructuredProperties: getStructuredPropertiesProp, getFunctionParameterSuggestions, shouldFetchFunctionParameters, MentionTagComponent, MentionDropdownItemComponent, showSelectionResizeHandles = true, enableMagicFill, enableQuickEdit = true, MagicFillComponent, MagicFillContent, QuickEdit, PasteMenu, SuggestionAction, HiddenRowMarkers, HiddenColumnMarkers, enableResizerOverflow, className, defaultFontSizePoint = DEFAULT_FONT_SIZE_PT, readonly, isComparing = false, getCellDiff, enableDataBoundaryNavigation, footerHeight, footerComponent, arrowComponents,
103
+ const { licenseKey, sheetId, instanceId, activeCell = DEFAULT_ACTIVE_CELL, selections = DEFAULT_ARRAY, frozenColumnCount = 0, frozenRowCount = 0, rowCount = DEFAULT_ROW_COUNT, columnCount = DEFAULT_COLUMN_COUNT, autoFocus, basicFilter, tables, namedRanges, bandedRanges = DEFAULT_ARRAY, tableBorderColor = "#008000", filterIconColor = "#008000", conditionalFormats, showFilterIcon = true, showCalculatedColumnIcon = true, showHeaders = true, defaultColumnWidth = DEFAULT_COLUMN_WIDTH, defaultRowHeight = DEFAULT_ROW_HEIGHT, columnHeaderHeight = COLUMN_HEADER_HEIGHT, rowHeaderWidth = ROW_HEADER_WIDTH, gridLineColor = GRIDLINE_COLOR, cellBackgroundColor = DEFAULT_CELL_BACKGROUND_COLOR, cellColor = DEFAULT_CELL_COLOR, headerBorderColor = DEFAULT_HEADER_BORDER_COLOR, headerBackgroundColor = DEFAULT_HEADER_BG, headerColor = DEFAULT_HEADER_COLOR, headerActiveBackgroundColor = DEFAULT_HEADER_ACTIVE_BG, headerSelectedBackgroundColor = DEFAULT_HEADER_SELECTED_BG, headerSelectedColor = "white", headerTableBackgroundColor = DEFAULT_HEADER_TABLE_BG, headerTableActiveBackgroundColor = DEFAULT_HEADER_ACTIVE_TABLE_BG, headerTableSelectedBackgroundColor = DEFAULT_HEADER_SELECTED_TABLE_BG, frozenShadowColor = headerBorderColor, frozenShadowThickness = 1, selectionBackgroundColor = SELECTION_BG, selectionBorderColor = SELECTION_BORDER, selectionDragBorderColor = SELECTION_BORDER, chartSelectedColor, chipBackgroundColor = CHIP_COLOR, merges = DEFAULT_ARRAY, borderStyles, protectedRanges, isWorkbookProtected: isWorkbookProtectedProp = false, getSheetProtection, pivotTables, charts, embeds, slicers, rowMetadata = DEFAULT_ARRAY, columnMetadata = DEFAULT_ARRAY, scale = 1, zoomSpeed = 1, overscanCount = 3, enableEditOnEnterKey = true, enableTextOverflow = true, showGridLines: _showGridLines, showFormulas = false, protectFormulas = false, showFrozenSeparator = true, HeaderCell = DefaultHeaderCell, Cell = DefaultCell, SelectionTitleComponent = SelectionTitle, CellEditor = DefaultCellEditor, CellTooltip, ContextMenu = DefaultContextMenu, ContextMenuWrapper = DefaultContextMenuWrapper, FilterBox = DefaultFilterBox, HeaderMoveDragComponent = DefaultHeaderMoveDragComponent, SuggestionsDropdown, stickyEditor = true, scrollSnap = false, scrollThrottleTimeout, preventBrowserDefaultScroll, mouseMoveThrottleTimeout = 60, tooltipIntentInterval = 60, selectionPolicy, users, userId, renderCollaboratorCursor, functionDescriptions, showHeaderMenuButton = true, scrollbarSize = SCROLLBAR_SIZE, theme = defaultSpreadsheetTheme, showNotes = true, showComments = true, locale, agentSuggestions, onReviewSuggestion, onShowFormulas, getDataRowCount, getChartComponent, getEmbedComponent, getSlicerComponent, onChange, onChangeBatch, onExpandCollapse, onPivotDrillDown, onDelete, onChangeEditorValue, onFill, onRequestCalculate, onChangeActiveCell, onChangeActiveSheet, onChangeSelections, getSheetName, getSheetId, getCellData, getNote: getNoteProp, getTextFormatRuns, getDataValidation, getEffectiveFormat, getFormattedValue: getFormattedValueProp, getTooltipContent, errorResolutionComponent, getEffectiveValue: getEffectiveValueProp, getUserEnteredExtendedValue, getEffectiveExtendedValue, getSheetRowCount, getSheetColumnCount, getCellPopoverContent, onScroll, onViewPortChange, windowConditionalFormats = false, engineConditionalFormatResults = false, onResize, onAutoResize, onHideColumn, onHideRow, onShowColumn, onShowRow, onGroupRows, onUngroupRows, onCollapseRowGroup, onExpandRowGroup, onGroupColumns, onUngroupColumns, onCollapseColumnGroup, onExpandColumnGroup, onSetOutlineDepth, onDeleteRow, onDeleteColumn, onInsertRow, onInsertColumn, onInsertCellsShiftDown, onInsertCellsShiftRight, onDeleteCellsShiftLeft, onDeleteCellsShiftUp, onClearContents, onMoveColumns, onMoveRows, onSelectNextSheet, onSelectPreviousSheet, onCreateNewSheet, onKeyDown, onChangeFormatting, onRepeatFormatting, onClearFormatting, onRequestEditProtectedRange, onMoveChart, onResizeChart, onDeleteChart, onMoveEmbed, onResizeEmbed, onDeleteEmbed, onRequestEditEmbed, onMoveSlicer, onResizeSlicer, onDeleteSlicer, onRequestEditSlicer, onFillRange, disableFillRightShortcut, keymap, onCalculateNow, onRequestGoTo, onMoveSelection, onInsertTime, onInsertDate, onInsertDateTime, onInsertAutoSum, onUndo, onRedo, onPaste, onCopy, onCut, onSortColumn, onSortTable, onFilterTable, onFilterPivot, onResizeTable, onRequestEditTable, onRequestEditPivotTable, onRequestDeletePivotTable, onRemoveTable, onCreateTable, onInsertTableColumn, onDeleteTableColumn, onInsertTableRow, onDeleteTableRow, onCreateBasicFilter, onRequestDefineNamedRange, onRequestFormatCells, onRequestConditionalFormat, onRequestDataValidation, onRequestInsertComment, onRequestInsertLink, onFreezeColumn, onFreezeRow, onUpdateNote, onProtectRange, onUnProtectRange, onSortRange, onRequestSearch, onRequestReplace, onRequestResize, getRowHeaderText = getDefaultRowHeader, getColumnHeaderText = getDefaultColumnHeader, getAdditionalCellSpacing, tokenizer: defaultTokenizer = defaultFormulaTokenizer, onChangeScale, onRemoveLink, onSelectLink, onSplitTextToColumns, onRemoveDuplicates, onRequestExpand, cellExpandPredicate, StructuredResult = DefaultStructuredResult, getMentions, getStructuredProperties: getStructuredPropertiesProp, getFunctionParameterSuggestions, shouldFetchFunctionParameters, MentionTagComponent, MentionDropdownItemComponent, showSelectionResizeHandles = true, enableMagicFill, enableQuickEdit = true, MagicFillComponent, MagicFillContent, QuickEdit, PasteMenu, SuggestionAction, HiddenRowMarkers, HiddenColumnMarkers, enableResizerOverflow, className, defaultFontSizePoint = DEFAULT_FONT_SIZE_PT, readonly, isComparing = false, getCellDiff, enableDataBoundaryNavigation, footerHeight, footerComponent, arrowComponents,
103
104
  // Host-driven filter props. `hostHiddenRowRanges`
104
105
  // supplies compact [start, end] hidden-row tuples; `getFilterValues` supplies a
105
106
  // column's distinct values. Both let a million-row filter render without scanning
@@ -1937,6 +1938,77 @@ function CanvasGridComponent(props, forwardedRef) {
1937
1938
  onCopy,
1938
1939
  onCut,
1939
1940
  });
1941
+ /**
1942
+ * Paste Special dialog (context menu → Paste special…, Ctrl+Alt+V). The
1943
+ * dialog is host-mounted (`PasteSpecialDialogHost`); its request routes
1944
+ * back through the same `paste()` the submenu uses. Without a mounted host
1945
+ * the trigger stays undefined so the menu item is not shown and the
1946
+ * shortcut is not claimed (a host that has not adopted the dialog keeps
1947
+ * its previous behaviour instead of a dead action).
1948
+ */
1949
+ const openPasteSpecialDialog = useOpenPasteSpecialDialog();
1950
+ const isPasteSpecialDialogMounted = useIsPasteSpecialDialogMounted();
1951
+ const requestPasteSpecial = useMemo(() => {
1952
+ if (!isPasteSpecialDialogMounted)
1953
+ return undefined;
1954
+ return () => {
1955
+ if (readonly)
1956
+ return;
1957
+ openPasteSpecialDialog({
1958
+ onApply: (options) => {
1959
+ void paste(options);
1960
+ },
1961
+ });
1962
+ };
1963
+ }, [isPasteSpecialDialogMounted, openPasteSpecialDialog, paste, readonly]);
1964
+ /**
1965
+ * Evaluate Formula dialog (context menu → Evaluate formula) for a formula
1966
+ * cell. Steps are scratch-evaluated through `onRequestCalculate`, the cell
1967
+ * editor's live-preview calculator, so nothing is written to the sheet.
1968
+ * Only offered while an `EvaluateFormulaDialogHost` is mounted.
1969
+ */
1970
+ const openEvaluateFormulaDialog = useOpenEvaluateFormulaDialog();
1971
+ const isEvaluateFormulaDialogMounted = useIsEvaluateFormulaDialogMounted();
1972
+ const requestEvaluateFormula = useMemo(() => {
1973
+ if (!isEvaluateFormulaDialogMounted || !onRequestCalculate)
1974
+ return undefined;
1975
+ return (evaluateSheetId, cell) => {
1976
+ const formula = getFormulaValue(evaluateSheetId, cell.rowIndex, cell.columnIndex);
1977
+ if (!formula)
1978
+ return;
1979
+ openEvaluateFormulaDialog({
1980
+ sheetId: evaluateSheetId,
1981
+ cell,
1982
+ sheetName: getSheetName?.(evaluateSheetId),
1983
+ formula,
1984
+ evaluate: createExpressionEvaluator(onRequestCalculate, evaluateSheetId, cell),
1985
+ });
1986
+ };
1987
+ }, [
1988
+ isEvaluateFormulaDialogMounted,
1989
+ openEvaluateFormulaDialog,
1990
+ getFormulaValue,
1991
+ getSheetName,
1992
+ onRequestCalculate,
1993
+ ]);
1994
+ /**
1995
+ * Go To (Ctrl+G / F5). A host `onRequestGoTo` wins; otherwise the built-in
1996
+ * dialog opens — but only while a `GoToDialogHost` is mounted, so a host
1997
+ * without one keeps the browser's own Ctrl+G / F5 (the keyboard handler
1998
+ * claims the keys only when this is defined). The built-in opener needs
1999
+ * `navigateToSheetRange`, which is created further down, so it is reached
2000
+ * through a ref.
2001
+ */
2002
+ const openGoToDialog = useOpenGoToDialog();
2003
+ const isGoToDialogMounted = useIsGoToDialogMounted();
2004
+ const builtInGoToRef = useRef(() => undefined);
2005
+ const requestGoTo = useMemo(() => {
2006
+ if (onRequestGoTo)
2007
+ return onRequestGoTo;
2008
+ if (!isGoToDialogMounted)
2009
+ return undefined;
2010
+ return (goToSheetId, goToActiveCell, goToSelections) => builtInGoToRef.current(goToSheetId, goToActiveCell, goToSelections);
2011
+ }, [onRequestGoTo, isGoToDialogMounted]);
1940
2012
  /**
1941
2013
  * After formula mode
1942
2014
  * Recover old selections
@@ -2093,7 +2165,7 @@ function CanvasGridComponent(props, forwardedRef) {
2093
2165
  * Get context Menu component
2094
2166
  */
2095
2167
  const getContextMenu = useCallback((cell) => {
2096
- return (React.createElement(ContextMenu, { activeCell: activeCell, selections: selections, sheetId: sheetId, frozenRows: frozenRows, frozenColumns: frozenColumns, onHideColumn: isRestricted ? undefined : onHideColumn, onShowColumn: isRestricted ? undefined : onShowColumn, onShowRow: isRestricted ? undefined : onShowRow, onHideRow: isRestricted ? undefined : onHideRow, onGroupRows: isRestricted ? undefined : onGroupRows, onUngroupRows: isRestricted ? undefined : onUngroupRows, onGroupColumns: isRestricted ? undefined : onGroupColumns, onUngroupColumns: isRestricted ? undefined : onUngroupColumns, isHiddenColumn: isHiddenColumn, isHiddenRow: isHiddenRow, onDeleteColumn: onDeleteColumn, onDeleteRow: onDeleteRow, onInsertRow: onInsertRow, onInsertColumn: onInsertColumn, onInsertCellsShiftDown: onInsertCellsShiftDown, onInsertCellsShiftRight: onInsertCellsShiftRight, onDeleteCellsShiftLeft: onDeleteCellsShiftLeft, onDeleteCellsShiftUp: onDeleteCellsShiftUp, onClearContents: onClearContents, onFreezeColumn: onFreezeColumn, onFreezeRow: onFreezeRow, focusSheet: focusSheet, onSortColumn: onSortColumn, onInsertNote: onInsertNote, onProtectRange: onProtectRange, onUnProtectRange: onUnProtectRange, onSortRange: onSortRange, onRequestDefineNamedRange: onRequestDefineNamedRange, protectedRanges: protectedRanges, isRowHeader: isRowHeader(cell.columnIndex), isColumnHeader: isColumnHeader(cell.rowIndex), selectedRowHeadersIds: selectedRowHeadersIds, selectedColumnHeadersIds: selectedColumnHeadersIds, onCopy: copy, onCut: cut, onPaste: paste, onRequestResize: onRequestResize, isSheetFocused: isSheetFocused, tables: activeTables, pivotTables: pivotTables, basicFilter: basicFilter, onRequestEditTable: onRequestEditTable, onRequestEditPivotTable: onRequestEditPivotTable, onRemoveTable: onRemoveTable, onRequestDeletePivotTable: onRequestDeletePivotTable, onPivotDrillDown: onPivotDrillDown, onRequestFormatCells: onRequestFormatCells, onRequestConditionalFormat: onRequestConditionalFormat, onRequestDataValidation: onRequestDataValidation, onClearFormatting: onClearFormatting, onCreateTable: onCreateTable, onCreateBasicFilter: onCreateBasicFilter, onInsertTableColumn: onInsertTableColumn, onDeleteTableColumn: onDeleteTableColumn, onInsertTableRow: onInsertTableRow, onDeleteTableRow: onDeleteTableRow, onFilterTable: onFilterTable, onSortTable: onSortTable, getFormattedValue: getFormattedValue, getFormattedValuesFromRange: getFormattedValuesFromRange, isTableHeader: isTableHeader, readonly: readonly, onSplitTextToColumns: onSplitTextToColumns, onRemoveDuplicates: onRemoveDuplicates, onAddQuickEdit: onAddQuickEdit, enableMagicFill: enableMagicFill }));
2168
+ return (React.createElement(ContextMenu, { activeCell: activeCell, selections: selections, sheetId: sheetId, frozenRows: frozenRows, frozenColumns: frozenColumns, onHideColumn: isRestricted ? undefined : onHideColumn, onShowColumn: isRestricted ? undefined : onShowColumn, onShowRow: isRestricted ? undefined : onShowRow, onHideRow: isRestricted ? undefined : onHideRow, onGroupRows: isRestricted ? undefined : onGroupRows, onUngroupRows: isRestricted ? undefined : onUngroupRows, onGroupColumns: isRestricted ? undefined : onGroupColumns, onUngroupColumns: isRestricted ? undefined : onUngroupColumns, isHiddenColumn: isHiddenColumn, isHiddenRow: isHiddenRow, onDeleteColumn: onDeleteColumn, onDeleteRow: onDeleteRow, onInsertRow: onInsertRow, onInsertColumn: onInsertColumn, onInsertCellsShiftDown: onInsertCellsShiftDown, onInsertCellsShiftRight: onInsertCellsShiftRight, onDeleteCellsShiftLeft: onDeleteCellsShiftLeft, onDeleteCellsShiftUp: onDeleteCellsShiftUp, onClearContents: onClearContents, onFreezeColumn: onFreezeColumn, onFreezeRow: onFreezeRow, focusSheet: focusSheet, onSortColumn: onSortColumn, onInsertNote: onInsertNote, onProtectRange: onProtectRange, onUnProtectRange: onUnProtectRange, onSortRange: onSortRange, onRequestDefineNamedRange: onRequestDefineNamedRange, protectedRanges: protectedRanges, isRowHeader: isRowHeader(cell.columnIndex), isColumnHeader: isColumnHeader(cell.rowIndex), selectedRowHeadersIds: selectedRowHeadersIds, selectedColumnHeadersIds: selectedColumnHeadersIds, onCopy: copy, onCut: cut, onPaste: paste, onRequestPasteSpecial: requestPasteSpecial, onRequestEvaluateFormula: requestEvaluateFormula, isActiveCellFormula: Boolean(getFormulaValue(sheetId, activeCell.rowIndex, activeCell.columnIndex)), onRequestResize: onRequestResize, isSheetFocused: isSheetFocused, tables: activeTables, pivotTables: pivotTables, basicFilter: basicFilter, onRequestEditTable: onRequestEditTable, onRequestEditPivotTable: onRequestEditPivotTable, onRemoveTable: onRemoveTable, onRequestDeletePivotTable: onRequestDeletePivotTable, onPivotDrillDown: onPivotDrillDown, onRequestFormatCells: onRequestFormatCells, onRequestConditionalFormat: onRequestConditionalFormat, onRequestDataValidation: onRequestDataValidation, onClearFormatting: onClearFormatting, onCreateTable: onCreateTable, onCreateBasicFilter: onCreateBasicFilter, onInsertTableColumn: onInsertTableColumn, onDeleteTableColumn: onDeleteTableColumn, onInsertTableRow: onInsertTableRow, onDeleteTableRow: onDeleteTableRow, onFilterTable: onFilterTable, onSortTable: onSortTable, getFormattedValue: getFormattedValue, getFormattedValuesFromRange: getFormattedValuesFromRange, isTableHeader: isTableHeader, readonly: readonly, onSplitTextToColumns: onSplitTextToColumns, onRemoveDuplicates: onRemoveDuplicates, onChange: onChange, getCellData: getCellData, onAddQuickEdit: onAddQuickEdit, enableMagicFill: enableMagicFill }));
2097
2169
  }, [
2098
2170
  isRestricted,
2099
2171
  activeCell,
@@ -2120,6 +2192,9 @@ function CanvasGridComponent(props, forwardedRef) {
2120
2192
  copy,
2121
2193
  paste,
2122
2194
  cut,
2195
+ requestPasteSpecial,
2196
+ requestEvaluateFormula,
2197
+ getFormulaValue,
2123
2198
  onInsertNote,
2124
2199
  onProtectRange,
2125
2200
  onUnProtectRange,
@@ -2158,6 +2233,8 @@ function CanvasGridComponent(props, forwardedRef) {
2158
2233
  enableMagicFill,
2159
2234
  onSplitTextToColumns,
2160
2235
  onRemoveDuplicates,
2236
+ onChange,
2237
+ getCellData,
2161
2238
  onRequestDeletePivotTable,
2162
2239
  isHiddenColumn,
2163
2240
  isHiddenRow,
@@ -2198,6 +2275,8 @@ function CanvasGridComponent(props, forwardedRef) {
2198
2275
  selections,
2199
2276
  selectedColumns,
2200
2277
  selectedRows,
2278
+ selectedColumnHeadersIds,
2279
+ selectedRowHeadersIds,
2201
2280
  onChangeFormatting,
2202
2281
  onRepeatFormatting,
2203
2282
  onInsertNote,
@@ -2207,6 +2286,13 @@ function CanvasGridComponent(props, forwardedRef) {
2207
2286
  onCreateNewSheet,
2208
2287
  onFillRange,
2209
2288
  disableFillRightShortcut,
2289
+ keymap,
2290
+ onCalculateNow,
2291
+ onRequestGoTo: requestGoTo,
2292
+ onRequestPasteSpecial: requestPasteSpecial,
2293
+ onChangeBatch,
2294
+ getUserEnteredValue: getUserEnteredStringValue,
2295
+ getEffectiveValue,
2210
2296
  onInsertTime,
2211
2297
  onInsertDate,
2212
2298
  onInsertDateTime,
@@ -2976,6 +3062,24 @@ function CanvasGridComponent(props, forwardedRef) {
2976
3062
  setActiveCell,
2977
3063
  flash,
2978
3064
  });
3065
+ // Built-in Go To: resolve against the workbook, then select + scroll.
3066
+ useIsomorphicLayoutEffect(() => {
3067
+ builtInGoToRef.current = (goToSheetId, goToActiveCell) => {
3068
+ openGoToDialog({
3069
+ sheetId: goToSheetId,
3070
+ activeCell: goToActiveCell,
3071
+ namedRanges,
3072
+ getSheetId,
3073
+ getSheetName,
3074
+ rowCount,
3075
+ columnCount,
3076
+ onNavigate: (range) => {
3077
+ navigateToSheetRange(range, { enableFlash: false });
3078
+ focusSheet();
3079
+ },
3080
+ });
3081
+ };
3082
+ });
2979
3083
  // Dispatch keyboard event
2980
3084
  const dispatchEvent = useCallback((event) => {
2981
3085
  gridRef.current?.container?.dispatchEvent(event);
@@ -6,14 +6,14 @@ import type { CellDiff } from "@rowsncolumns/version-comparison";
6
6
  import type { ElementType } from "react";
7
7
  import type React from "react";
8
8
  import type { ContextMenuWrapperProps } from "../../hooks/use-context-menu";
9
- import type { PasteSpecialType } from "../../hooks/use-copy-paste-cut";
9
+ import type { PasteSpecialRequest } from "../../hooks/use-copy-paste-cut";
10
10
  import type { MakeEditableOptions } from "../../hooks/use-editable";
11
11
  import type { ExportRangeOutput } from "../../hooks/use-export-range";
12
12
  import type { useFlash } from "../../hooks/use-flash";
13
13
  import type { useNavigateToSheetRange } from "../../hooks/use-navigate-sheet-range";
14
14
  import type { UseSelectionOptions } from "../../hooks/use-selection";
15
15
  import type { GetCellDimensionsOptions as SizerGetCellDimensionsOptions, useSizer } from "../../hooks/use-sizer";
16
- import type { AgentSuggestion, BandedDefinition, BandedRange, BorderStyle, CellFormat, Collaborator, Color, ColorFilterCriteria, ConditionType, ConditionValue, DataValidationRule, DataValidationRuleRecord, EmbeddedObject, IconFilterCriteria, Maybe, NamedRange, ParsedToken, PivotTable, ProtectedRange, Sheet, SheetCoordinate, SheetProtection, SheetRange, Slicer, SortOrder, SortSpecs, TableTheme, TableView } from "../../types";
16
+ import type { AgentSuggestion, BandedDefinition, BandedRange, BorderStyle, CellFormat, Collaborator, Color, ColorFilterCriteria, ConditionType, ConditionValue, DataValidationRule, DataValidationRuleRecord, EmbeddedObject, IconFilterCriteria, Maybe, NamedRange, ParsedToken, PivotTable, ProtectedRange, RemoveDuplicatesOptions, Sheet, SheetCoordinate, SheetProtection, SheetRange, Slicer, SortOrder, SortSpecs, TableTheme, TableView } from "../../types";
17
17
  import type { AXIS, CellData, ConditionalFormatRule, EmbeddedChart, FilterView } from "../../types";
18
18
  import type { CellProps } from "../cell/typings";
19
19
  import type { CellEditorProps } from "../cell-editor";
@@ -33,6 +33,11 @@ import type { SuggestionActionProps } from "../selection/suggestion-action";
33
33
  import type { SelectionTitleProps } from "../selection/title";
34
34
  import type { BorderLocation } from "../toolbar";
35
35
  export type ExtractMentionType<T> = T extends CellData<any, infer M> ? M : Mention;
36
+ /**
37
+ * Keyboard shortcut flavour for the combos Excel and Google Sheets bind
38
+ * differently. See `CanvasGridProps["keymap"]`.
39
+ */
40
+ export type SpreadsheetKeymap = "sheets" | "excel";
36
41
  /**
37
42
  * Color / icon / custom-list sort options shared by the column-, table-
38
43
  * and range-sort callbacks. Mirrors the engine's `DimensionSortSpec`
@@ -1044,6 +1049,45 @@ export type CanvasGridProps<T extends CellData = CellData<any, any>> = {
1044
1049
  * When true, key combo falls through to the browser default.
1045
1050
  */
1046
1051
  disableFillRightShortcut?: boolean;
1052
+ /**
1053
+ * Which product's shortcuts win where Excel and Google Sheets disagree.
1054
+ *
1055
+ * Both keymaps share every non-conflicting binding (Excel's `Ctrl+R`,
1056
+ * `Ctrl+T`, `Ctrl+1`, `Ctrl+5`, `F9`, `Ctrl+'`, `Ctrl+G` are always on,
1057
+ * as are Sheets' `Ctrl+Alt+T`, `Ctrl+Alt+1`, `Ctrl+Alt+9/0`, and the
1058
+ * unhide combos both products share, `Ctrl+Shift+9` / `Ctrl+Shift+0`).
1059
+ * The keymap only decides the combos the two products bind differently:
1060
+ *
1061
+ * | Shortcut | `"sheets"` (default) | `"excel"` |
1062
+ * | ---------------- | -------------------- | --------------------- |
1063
+ * | Ctrl+Shift+L | Align left | Toggle AutoFilter |
1064
+ * | Ctrl+9 / Ctrl+0 | (browser) | Hide rows / columns |
1065
+ *
1066
+ * Hide / unhide act on the rows / columns selected through their headers
1067
+ * plus the rows / columns of the selected cell ranges (what the context
1068
+ * menu's Hide item uses). With the other axis fully selected there is
1069
+ * nothing to act on and the shortcut is a no-op (Excel would hide every
1070
+ * row / column).
1071
+ */
1072
+ keymap?: SpreadsheetKeymap;
1073
+ /**
1074
+ * Excel `F9` (workbook) / `Shift+F9` (active sheet): recalculate now.
1075
+ * Hosts wire this to `calculateNow` from `useSpreadsheetState` /
1076
+ * `useSpreadsheetEngine`; the shortcut is inert when omitted.
1077
+ * @param sheetId
1078
+ * @param scope
1079
+ */
1080
+ onCalculateNow?(sheetId: number, scope: "workbook" | "sheet"): void | Promise<void>;
1081
+ /**
1082
+ * Excel `Ctrl+G` / `F5`: the user wants the Go To dialog (or the Name
1083
+ * Box focused). When omitted the grid opens its built-in Go To dialog —
1084
+ * mount `<GoToDialogHost />` in the host next to the other editor
1085
+ * dialogs. Provide this to replace it with your own UI.
1086
+ * @param sheetId
1087
+ * @param activeCell
1088
+ * @param selections
1089
+ */
1090
+ onRequestGoTo?(sheetId: number, activeCell: CellInterface, selections: SelectionArea<SelectionAttributes>[]): void;
1047
1091
  /**
1048
1092
  * User is creating a new chart
1049
1093
  * @param sheetId
@@ -1282,9 +1326,9 @@ export type CanvasGridProps<T extends CellData = CellData<any, any>> = {
1282
1326
  */
1283
1327
  onDeleteTableRow?(table: TableView, rowIndexes: number[]): void;
1284
1328
  /**
1285
- * Create a basic filter
1286
- * Ctrl+Shift+F
1287
- * Cmd+Shift+F
1329
+ * Create a basic filter, or remove the sheet's existing one when the
1330
+ * selection touches it (a toggle).
1331
+ * Ctrl+Shift+F / Cmd+Shift+F, and Ctrl+Shift+L under `keymap="excel"`
1288
1332
  * @param sheetId
1289
1333
  * @param activeCell
1290
1334
  * @param selections
@@ -1491,7 +1535,7 @@ export type CanvasGridProps<T extends CellData = CellData<any, any>> = {
1491
1535
  * @param selections
1492
1536
  * @returns
1493
1537
  */
1494
- onRemoveDuplicates?: (sheetId: number, activeCell: CellInterface, selections?: SelectionArea<SelectionAttributes>[]) => void;
1538
+ onRemoveDuplicates?: (sheetId: number, activeCell: CellInterface, selections?: SelectionArea<SelectionAttributes>[], options?: RemoveDuplicatesOptions) => void;
1495
1539
  /**
1496
1540
  * Callback to get effective value of a cell
1497
1541
  * @param sheetId
@@ -1980,10 +2024,12 @@ export type CanvasGridMethods = {
1980
2024
  */
1981
2025
  cut?: () => void;
1982
2026
  /**
1983
- * Copies current selections
2027
+ * Pastes the clipboard at the active cell. Pass a legacy single mode
2028
+ * (`"Value"`, `"Transposed"`, …) or a full `PasteSpecialOptions` request
2029
+ * (paste what / operation / skip blanks / transpose).
1984
2030
  * @returns
1985
2031
  */
1986
- paste?: (pasteSpecial?: PasteSpecialType) => void;
2032
+ paste?: (pasteSpecial?: PasteSpecialRequest) => void;
1987
2033
  };
1988
2034
  export type SelectionAttributes = RangeStyle & {
1989
2035
  sheetName?: string;