@fgv/ts-sudoku-ui 5.0.1-2

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 (190) hide show
  1. package/.rush/temp/chunked-rush-logs/ts-sudoku-ui.build.chunks.jsonl +12 -0
  2. package/.rush/temp/operation/build/log-chunks.jsonl +12 -0
  3. package/.rush/temp/operation/build/state.json +3 -0
  4. package/.rush/temp/shrinkwrap-deps.json +1087 -0
  5. package/.test-failures-catalog.md +470 -0
  6. package/CSS_MODULES_MIGRATION_SUMMARY.md +189 -0
  7. package/dist/ts-sudoku-ui.d.ts +668 -0
  8. package/etc/ts-sudoku-ui.api.md +481 -0
  9. package/lib/components/CageOverlay.d.ts +8 -0
  10. package/lib/components/CageOverlay.d.ts.map +1 -0
  11. package/lib/components/CageOverlay.js +133 -0
  12. package/lib/components/CageOverlay.js.map +1 -0
  13. package/lib/components/CageSumIndicator.d.ts +8 -0
  14. package/lib/components/CageSumIndicator.d.ts.map +1 -0
  15. package/lib/components/CageSumIndicator.js +66 -0
  16. package/lib/components/CageSumIndicator.js.map +1 -0
  17. package/lib/components/CombinationCard.d.ts +8 -0
  18. package/lib/components/CombinationCard.d.ts.map +1 -0
  19. package/lib/components/CombinationCard.js +64 -0
  20. package/lib/components/CombinationCard.js.map +1 -0
  21. package/lib/components/CombinationGrid.d.ts +8 -0
  22. package/lib/components/CombinationGrid.d.ts.map +1 -0
  23. package/lib/components/CombinationGrid.js +51 -0
  24. package/lib/components/CombinationGrid.js.map +1 -0
  25. package/lib/components/CompactControlRibbon.d.ts +45 -0
  26. package/lib/components/CompactControlRibbon.d.ts.map +1 -0
  27. package/lib/components/CompactControlRibbon.js +141 -0
  28. package/lib/components/CompactControlRibbon.js.map +1 -0
  29. package/lib/components/DualKeypad.d.ts +39 -0
  30. package/lib/components/DualKeypad.d.ts.map +1 -0
  31. package/lib/components/DualKeypad.js +137 -0
  32. package/lib/components/DualKeypad.js.map +1 -0
  33. package/lib/components/KillerCombinationsExplorer.d.ts +9 -0
  34. package/lib/components/KillerCombinationsExplorer.d.ts.map +1 -0
  35. package/lib/components/KillerCombinationsExplorer.js +69 -0
  36. package/lib/components/KillerCombinationsExplorer.js.map +1 -0
  37. package/lib/components/KillerCombinationsModal.d.ts +20 -0
  38. package/lib/components/KillerCombinationsModal.d.ts.map +1 -0
  39. package/lib/components/KillerCombinationsModal.js +135 -0
  40. package/lib/components/KillerCombinationsModal.js.map +1 -0
  41. package/lib/components/KillerCombinationsPanel.d.ts +20 -0
  42. package/lib/components/KillerCombinationsPanel.d.ts.map +1 -0
  43. package/lib/components/KillerCombinationsPanel.js +79 -0
  44. package/lib/components/KillerCombinationsPanel.js.map +1 -0
  45. package/lib/components/NumberKeypad.d.ts +30 -0
  46. package/lib/components/NumberKeypad.d.ts.map +1 -0
  47. package/lib/components/NumberKeypad.js +181 -0
  48. package/lib/components/NumberKeypad.js.map +1 -0
  49. package/lib/components/SudokuCell.d.ts +8 -0
  50. package/lib/components/SudokuCell.d.ts.map +1 -0
  51. package/lib/components/SudokuCell.js +240 -0
  52. package/lib/components/SudokuCell.js.map +1 -0
  53. package/lib/components/SudokuControls.d.ts +8 -0
  54. package/lib/components/SudokuControls.d.ts.map +1 -0
  55. package/lib/components/SudokuControls.js +140 -0
  56. package/lib/components/SudokuControls.js.map +1 -0
  57. package/lib/components/SudokuGrid.d.ts +8 -0
  58. package/lib/components/SudokuGrid.d.ts.map +1 -0
  59. package/lib/components/SudokuGrid.js +177 -0
  60. package/lib/components/SudokuGrid.js.map +1 -0
  61. package/lib/components/SudokuGridEntry.d.ts +8 -0
  62. package/lib/components/SudokuGridEntry.d.ts.map +1 -0
  63. package/lib/components/SudokuGridEntry.js +373 -0
  64. package/lib/components/SudokuGridEntry.js.map +1 -0
  65. package/lib/components/ValidationDisplay.d.ts +8 -0
  66. package/lib/components/ValidationDisplay.d.ts.map +1 -0
  67. package/lib/components/ValidationDisplay.js +95 -0
  68. package/lib/components/ValidationDisplay.js.map +1 -0
  69. package/lib/contexts/DiagnosticLoggerContext.d.ts +81 -0
  70. package/lib/contexts/DiagnosticLoggerContext.d.ts.map +1 -0
  71. package/lib/contexts/DiagnosticLoggerContext.js +98 -0
  72. package/lib/contexts/DiagnosticLoggerContext.js.map +1 -0
  73. package/lib/contexts/index.d.ts +3 -0
  74. package/lib/contexts/index.d.ts.map +1 -0
  75. package/lib/contexts/index.js +25 -0
  76. package/lib/contexts/index.js.map +1 -0
  77. package/lib/hooks/useCombinationElimination.d.ts +10 -0
  78. package/lib/hooks/useCombinationElimination.d.ts.map +1 -0
  79. package/lib/hooks/useCombinationElimination.js +123 -0
  80. package/lib/hooks/useCombinationElimination.js.map +1 -0
  81. package/lib/hooks/useKeyboardShortcut.d.ts +19 -0
  82. package/lib/hooks/useKeyboardShortcut.d.ts.map +1 -0
  83. package/lib/hooks/useKeyboardShortcut.js +55 -0
  84. package/lib/hooks/useKeyboardShortcut.js.map +1 -0
  85. package/lib/hooks/useKillerCombinations.d.ts +11 -0
  86. package/lib/hooks/useKillerCombinations.d.ts.map +1 -0
  87. package/lib/hooks/useKillerCombinations.js +65 -0
  88. package/lib/hooks/useKillerCombinations.js.map +1 -0
  89. package/lib/hooks/useLongPress.d.ts +31 -0
  90. package/lib/hooks/useLongPress.d.ts.map +1 -0
  91. package/lib/hooks/useLongPress.js +69 -0
  92. package/lib/hooks/useLongPress.js.map +1 -0
  93. package/lib/hooks/usePuzzleSession.d.ts +32 -0
  94. package/lib/hooks/usePuzzleSession.d.ts.map +1 -0
  95. package/lib/hooks/usePuzzleSession.js +398 -0
  96. package/lib/hooks/usePuzzleSession.js.map +1 -0
  97. package/lib/hooks/useResponsiveLayout.d.ts +44 -0
  98. package/lib/hooks/useResponsiveLayout.d.ts.map +1 -0
  99. package/lib/hooks/useResponsiveLayout.js +139 -0
  100. package/lib/hooks/useResponsiveLayout.js.map +1 -0
  101. package/lib/index.d.ts +28 -0
  102. package/lib/index.d.ts.map +1 -0
  103. package/lib/index.js +49 -0
  104. package/lib/index.js.map +1 -0
  105. package/lib/test/fixtures/killerSudokuPuzzles.d.ts +36 -0
  106. package/lib/test/fixtures/killerSudokuPuzzles.d.ts.map +1 -0
  107. package/lib/test/fixtures/killerSudokuPuzzles.js +57 -0
  108. package/lib/test/fixtures/killerSudokuPuzzles.js.map +1 -0
  109. package/lib/test/unit/components/SudokuGridEntry.testHelpers.d.ts +22 -0
  110. package/lib/test/unit/components/SudokuGridEntry.testHelpers.d.ts.map +1 -0
  111. package/lib/test/unit/components/SudokuGridEntry.testHelpers.js +116 -0
  112. package/lib/test/unit/components/SudokuGridEntry.testHelpers.js.map +1 -0
  113. package/lib/tsdoc-metadata.json +11 -0
  114. package/lib/types/index.d.ts +234 -0
  115. package/lib/types/index.d.ts.map +1 -0
  116. package/lib/types/index.js +25 -0
  117. package/lib/types/index.js.map +1 -0
  118. package/lib/utils/CageLookupManager.d.ts +74 -0
  119. package/lib/utils/CageLookupManager.d.ts.map +1 -0
  120. package/lib/utils/CageLookupManager.js +283 -0
  121. package/lib/utils/CageLookupManager.js.map +1 -0
  122. package/lib/utils/CagePatternManager.d.ts +82 -0
  123. package/lib/utils/CagePatternManager.d.ts.map +1 -0
  124. package/lib/utils/CagePatternManager.js +139 -0
  125. package/lib/utils/CagePatternManager.js.map +1 -0
  126. package/lib/utils/puzzleDefinitionHelper.d.ts +25 -0
  127. package/lib/utils/puzzleDefinitionHelper.d.ts.map +1 -0
  128. package/lib/utils/puzzleDefinitionHelper.js +99 -0
  129. package/lib/utils/puzzleDefinitionHelper.js.map +1 -0
  130. package/lib-commonjs/components/CageOverlay.js +138 -0
  131. package/lib-commonjs/components/CageOverlay.js.map +1 -0
  132. package/lib-commonjs/components/CageSumIndicator.js +71 -0
  133. package/lib-commonjs/components/CageSumIndicator.js.map +1 -0
  134. package/lib-commonjs/components/CombinationCard.js +68 -0
  135. package/lib-commonjs/components/CombinationCard.js.map +1 -0
  136. package/lib-commonjs/components/CombinationGrid.js +56 -0
  137. package/lib-commonjs/components/CombinationGrid.js.map +1 -0
  138. package/lib-commonjs/components/CompactControlRibbon.js +146 -0
  139. package/lib-commonjs/components/CompactControlRibbon.js.map +1 -0
  140. package/lib-commonjs/components/DualKeypad.js +142 -0
  141. package/lib-commonjs/components/DualKeypad.js.map +1 -0
  142. package/lib-commonjs/components/KillerCombinationsExplorer.js +74 -0
  143. package/lib-commonjs/components/KillerCombinationsExplorer.js.map +1 -0
  144. package/lib-commonjs/components/KillerCombinationsModal.js +140 -0
  145. package/lib-commonjs/components/KillerCombinationsModal.js.map +1 -0
  146. package/lib-commonjs/components/KillerCombinationsPanel.js +84 -0
  147. package/lib-commonjs/components/KillerCombinationsPanel.js.map +1 -0
  148. package/lib-commonjs/components/NumberKeypad.js +186 -0
  149. package/lib-commonjs/components/NumberKeypad.js.map +1 -0
  150. package/lib-commonjs/components/SudokuCell.js +245 -0
  151. package/lib-commonjs/components/SudokuCell.js.map +1 -0
  152. package/lib-commonjs/components/SudokuControls.js +145 -0
  153. package/lib-commonjs/components/SudokuControls.js.map +1 -0
  154. package/lib-commonjs/components/SudokuGrid.js +182 -0
  155. package/lib-commonjs/components/SudokuGrid.js.map +1 -0
  156. package/lib-commonjs/components/SudokuGridEntry.js +378 -0
  157. package/lib-commonjs/components/SudokuGridEntry.js.map +1 -0
  158. package/lib-commonjs/components/ValidationDisplay.js +100 -0
  159. package/lib-commonjs/components/ValidationDisplay.js.map +1 -0
  160. package/lib-commonjs/contexts/DiagnosticLoggerContext.js +104 -0
  161. package/lib-commonjs/contexts/DiagnosticLoggerContext.js.map +1 -0
  162. package/lib-commonjs/contexts/index.js +32 -0
  163. package/lib-commonjs/contexts/index.js.map +1 -0
  164. package/lib-commonjs/hooks/useCombinationElimination.js +126 -0
  165. package/lib-commonjs/hooks/useCombinationElimination.js.map +1 -0
  166. package/lib-commonjs/hooks/useKeyboardShortcut.js +58 -0
  167. package/lib-commonjs/hooks/useKeyboardShortcut.js.map +1 -0
  168. package/lib-commonjs/hooks/useKillerCombinations.js +68 -0
  169. package/lib-commonjs/hooks/useKillerCombinations.js.map +1 -0
  170. package/lib-commonjs/hooks/useLongPress.js +72 -0
  171. package/lib-commonjs/hooks/useLongPress.js.map +1 -0
  172. package/lib-commonjs/hooks/usePuzzleSession.js +401 -0
  173. package/lib-commonjs/hooks/usePuzzleSession.js.map +1 -0
  174. package/lib-commonjs/hooks/useResponsiveLayout.js +142 -0
  175. package/lib-commonjs/hooks/useResponsiveLayout.js.map +1 -0
  176. package/lib-commonjs/index.js +73 -0
  177. package/lib-commonjs/index.js.map +1 -0
  178. package/lib-commonjs/test/fixtures/killerSudokuPuzzles.js +60 -0
  179. package/lib-commonjs/test/fixtures/killerSudokuPuzzles.js.map +1 -0
  180. package/lib-commonjs/test/unit/components/SudokuGridEntry.testHelpers.js +125 -0
  181. package/lib-commonjs/test/unit/components/SudokuGridEntry.testHelpers.js.map +1 -0
  182. package/lib-commonjs/types/index.js +26 -0
  183. package/lib-commonjs/types/index.js.map +1 -0
  184. package/lib-commonjs/utils/CageLookupManager.js +287 -0
  185. package/lib-commonjs/utils/CageLookupManager.js.map +1 -0
  186. package/lib-commonjs/utils/CagePatternManager.js +143 -0
  187. package/lib-commonjs/utils/CagePatternManager.js.map +1 -0
  188. package/lib-commonjs/utils/puzzleDefinitionHelper.js +103 -0
  189. package/lib-commonjs/utils/puzzleDefinitionHelper.js.map +1 -0
  190. package/package.json +77 -0
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ /*
3
+ * MIT License
4
+ *
5
+ * Copyright (c) 2023 Erik Fortune
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in all
15
+ * copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ * SOFTWARE.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.CombinationCard = exports.CombinationGrid = exports.KillerCombinationsModal = exports.KillerCombinationsPanel = exports.KillerCombinationsExplorer = exports.useKeyboardShortcut = exports.useCombinationElimination = exports.useKillerCombinations = exports.useResponsiveLayout = exports.usePuzzleSession = exports.CageSumIndicator = exports.CageOverlay = exports.NumberKeypad = exports.DualKeypad = exports.CompactControlRibbon = exports.ValidationDisplay = exports.SudokuControls = exports.SudokuCell = exports.SudokuGrid = exports.SudokuGridEntry = void 0;
27
+ const tslib_1 = require("tslib");
28
+ // Main components
29
+ var SudokuGridEntry_1 = require("./components/SudokuGridEntry");
30
+ Object.defineProperty(exports, "SudokuGridEntry", { enumerable: true, get: function () { return SudokuGridEntry_1.SudokuGridEntry; } });
31
+ var SudokuGrid_1 = require("./components/SudokuGrid");
32
+ Object.defineProperty(exports, "SudokuGrid", { enumerable: true, get: function () { return SudokuGrid_1.SudokuGrid; } });
33
+ var SudokuCell_1 = require("./components/SudokuCell");
34
+ Object.defineProperty(exports, "SudokuCell", { enumerable: true, get: function () { return SudokuCell_1.SudokuCell; } });
35
+ var SudokuControls_1 = require("./components/SudokuControls");
36
+ Object.defineProperty(exports, "SudokuControls", { enumerable: true, get: function () { return SudokuControls_1.SudokuControls; } });
37
+ var ValidationDisplay_1 = require("./components/ValidationDisplay");
38
+ Object.defineProperty(exports, "ValidationDisplay", { enumerable: true, get: function () { return ValidationDisplay_1.ValidationDisplay; } });
39
+ var CompactControlRibbon_1 = require("./components/CompactControlRibbon");
40
+ Object.defineProperty(exports, "CompactControlRibbon", { enumerable: true, get: function () { return CompactControlRibbon_1.CompactControlRibbon; } });
41
+ var DualKeypad_1 = require("./components/DualKeypad");
42
+ Object.defineProperty(exports, "DualKeypad", { enumerable: true, get: function () { return DualKeypad_1.DualKeypad; } });
43
+ var NumberKeypad_1 = require("./components/NumberKeypad");
44
+ Object.defineProperty(exports, "NumberKeypad", { enumerable: true, get: function () { return NumberKeypad_1.NumberKeypad; } });
45
+ var CageOverlay_1 = require("./components/CageOverlay");
46
+ Object.defineProperty(exports, "CageOverlay", { enumerable: true, get: function () { return CageOverlay_1.CageOverlay; } });
47
+ var CageSumIndicator_1 = require("./components/CageSumIndicator");
48
+ Object.defineProperty(exports, "CageSumIndicator", { enumerable: true, get: function () { return CageSumIndicator_1.CageSumIndicator; } });
49
+ // Contexts
50
+ tslib_1.__exportStar(require("./contexts/DiagnosticLoggerContext"), exports);
51
+ // Hooks
52
+ var usePuzzleSession_1 = require("./hooks/usePuzzleSession");
53
+ Object.defineProperty(exports, "usePuzzleSession", { enumerable: true, get: function () { return usePuzzleSession_1.usePuzzleSession; } });
54
+ var useResponsiveLayout_1 = require("./hooks/useResponsiveLayout");
55
+ Object.defineProperty(exports, "useResponsiveLayout", { enumerable: true, get: function () { return useResponsiveLayout_1.useResponsiveLayout; } });
56
+ var useKillerCombinations_1 = require("./hooks/useKillerCombinations");
57
+ Object.defineProperty(exports, "useKillerCombinations", { enumerable: true, get: function () { return useKillerCombinations_1.useKillerCombinations; } });
58
+ var useCombinationElimination_1 = require("./hooks/useCombinationElimination");
59
+ Object.defineProperty(exports, "useCombinationElimination", { enumerable: true, get: function () { return useCombinationElimination_1.useCombinationElimination; } });
60
+ var useKeyboardShortcut_1 = require("./hooks/useKeyboardShortcut");
61
+ Object.defineProperty(exports, "useKeyboardShortcut", { enumerable: true, get: function () { return useKeyboardShortcut_1.useKeyboardShortcut; } });
62
+ // Killer Combinations Components
63
+ var KillerCombinationsExplorer_1 = require("./components/KillerCombinationsExplorer");
64
+ Object.defineProperty(exports, "KillerCombinationsExplorer", { enumerable: true, get: function () { return KillerCombinationsExplorer_1.KillerCombinationsExplorer; } });
65
+ var KillerCombinationsPanel_1 = require("./components/KillerCombinationsPanel");
66
+ Object.defineProperty(exports, "KillerCombinationsPanel", { enumerable: true, get: function () { return KillerCombinationsPanel_1.KillerCombinationsPanel; } });
67
+ var KillerCombinationsModal_1 = require("./components/KillerCombinationsModal");
68
+ Object.defineProperty(exports, "KillerCombinationsModal", { enumerable: true, get: function () { return KillerCombinationsModal_1.KillerCombinationsModal; } });
69
+ var CombinationGrid_1 = require("./components/CombinationGrid");
70
+ Object.defineProperty(exports, "CombinationGrid", { enumerable: true, get: function () { return CombinationGrid_1.CombinationGrid; } });
71
+ var CombinationCard_1 = require("./components/CombinationCard");
72
+ Object.defineProperty(exports, "CombinationCard", { enumerable: true, get: function () { return CombinationCard_1.CombinationCard; } });
73
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;;AAEH,kBAAkB;AAClB,gEAA+D;AAAtD,kHAAA,eAAe,OAAA;AACxB,sDAAqD;AAA5C,wGAAA,UAAU,OAAA;AACnB,sDAAqD;AAA5C,wGAAA,UAAU,OAAA;AACnB,8DAA6D;AAApD,gHAAA,cAAc,OAAA;AACvB,oEAAmE;AAA1D,sHAAA,iBAAiB,OAAA;AAC1B,0EAAyE;AAAhE,4HAAA,oBAAoB,OAAA;AAC7B,sDAAqD;AAA5C,wGAAA,UAAU,OAAA;AACnB,0DAAyD;AAAhD,4GAAA,YAAY,OAAA;AACrB,wDAAuD;AAA9C,0GAAA,WAAW,OAAA;AACpB,kEAAiE;AAAxD,oHAAA,gBAAgB,OAAA;AAEzB,WAAW;AACX,6EAAmD;AAEnD,QAAQ;AACR,6DAA4D;AAAnD,oHAAA,gBAAgB,OAAA;AACzB,mEAAkE;AAAzD,0HAAA,mBAAmB,OAAA;AAC5B,uEAAsE;AAA7D,8HAAA,qBAAqB,OAAA;AAC9B,+EAA8E;AAArE,sIAAA,yBAAyB,OAAA;AAClC,mEAAkE;AAAzD,0HAAA,mBAAmB,OAAA;AAE5B,iCAAiC;AACjC,sFAAqF;AAA5E,wIAAA,0BAA0B,OAAA;AACnC,gFAA+E;AAAtE,kIAAA,uBAAuB,OAAA;AAChC,gFAA+E;AAAtE,kIAAA,uBAAuB,OAAA;AAChC,gEAA+D;AAAtD,kHAAA,eAAe,OAAA;AACxB,gEAA+D;AAAtD,kHAAA,eAAe,OAAA","sourcesContent":["/*\n * MIT License\n *\n * Copyright (c) 2023 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n// Main components\nexport { SudokuGridEntry } from './components/SudokuGridEntry';\nexport { SudokuGrid } from './components/SudokuGrid';\nexport { SudokuCell } from './components/SudokuCell';\nexport { SudokuControls } from './components/SudokuControls';\nexport { ValidationDisplay } from './components/ValidationDisplay';\nexport { CompactControlRibbon } from './components/CompactControlRibbon';\nexport { DualKeypad } from './components/DualKeypad';\nexport { NumberKeypad } from './components/NumberKeypad';\nexport { CageOverlay } from './components/CageOverlay';\nexport { CageSumIndicator } from './components/CageSumIndicator';\n\n// Contexts\nexport * from './contexts/DiagnosticLoggerContext';\n\n// Hooks\nexport { usePuzzleSession } from './hooks/usePuzzleSession';\nexport { useResponsiveLayout } from './hooks/useResponsiveLayout';\nexport { useKillerCombinations } from './hooks/useKillerCombinations';\nexport { useCombinationElimination } from './hooks/useCombinationElimination';\nexport { useKeyboardShortcut } from './hooks/useKeyboardShortcut';\n\n// Killer Combinations Components\nexport { KillerCombinationsExplorer } from './components/KillerCombinationsExplorer';\nexport { KillerCombinationsPanel } from './components/KillerCombinationsPanel';\nexport { KillerCombinationsModal } from './components/KillerCombinationsModal';\nexport { CombinationGrid } from './components/CombinationGrid';\nexport { CombinationCard } from './components/CombinationCard';\n\n// Types\nexport type {\n IValidationError,\n ISudokuGridEntryProps,\n ISudokuGridProps,\n ICellDisplayInfo,\n ISudokuCellProps,\n ISudokuControlsProps,\n IValidationDisplayProps,\n ICageDisplayInfo,\n ICageOverlayProps,\n ICageSumIndicatorProps,\n IKillerCombinationsMode,\n ICombinationDisplayInfo,\n IEliminationState,\n IKillerCombinationsExplorerProps,\n ICombinationCardProps,\n ICombinationGridProps\n} from './types';\n\n// Compact control ribbon types\nexport type { ICompactControlRibbonProps } from './components/CompactControlRibbon';\n\n// Dual keypad types\nexport type { INumberKeypadProps } from './components/NumberKeypad';\nexport type { IDualKeypadProps } from './components/DualKeypad';\n\n// Responsive layout types\nexport type {\n DeviceType,\n ScreenOrientation,\n KeypadLayoutMode,\n IResponsiveLayoutInfo\n} from './hooks/useResponsiveLayout';\n\n// Keyboard shortcut types\nexport type { IKeyboardShortcutOptions } from './hooks/useKeyboardShortcut';\n"]}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ /*
3
+ * MIT License
4
+ *
5
+ * Copyright (c) 2023 Erik Fortune
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in all
15
+ * copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ * SOFTWARE.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.KILLER_SUDOKU_FIXTURES = exports.VALID_KILLER_SUDOKU = void 0;
27
+ /**
28
+ * Stable killer sudoku puzzle definitions for testing.
29
+ * These puzzles have been validated and are used across multiple test files
30
+ * to ensure consistency in testing killer sudoku functionality.
31
+ *
32
+ * @remarks
33
+ * Killer sudoku cells format: "GRID_MAPPING|CAGE_DEFINITIONS"
34
+ * - GRID_MAPPING: 81 characters mapping each cell to a cage ID (A-Z, a-z)
35
+ * - CAGE_DEFINITIONS: Comma-separated list of cageId+total (e.g., "A11,B09,C20")
36
+ *
37
+ * Example: "AABBCC....|A11,B09,C20,..."
38
+ * - Cells 0-1 are in cage A with total 11
39
+ * - Cells 2-3 are in cage B with total 09
40
+ * - Cells 4-5 are in cage C with total 20
41
+ *
42
+ * @public
43
+ */
44
+ /**
45
+ * Valid killer sudoku puzzle with complete cage definitions.
46
+ * This is a standard 9x9 killer sudoku with 27 cages.
47
+ */
48
+ exports.VALID_KILLER_SUDOKU = 'ABCCCDDDEABFFGGGDEHIJKGGLLLHIJKMGLNNHOPPMQQNROOSTMUVWRSSSTTUVWRXYTTTZZabXYYYcccab|A11,B09,C09,D20,E16,F17,G30,H17,I13,J09,K11,L16,M16,N11,O16,P07,Q11,R10,S14,T39,U08,V17,W16,X06,Y26,Z06,a09,b09,c11';
49
+ /**
50
+ * Collection of validated killer sudoku puzzles for testing.
51
+ */
52
+ exports.KILLER_SUDOKU_FIXTURES = [
53
+ {
54
+ id: 'valid-killer-1',
55
+ description: 'Valid Killer Sudoku Puzzle',
56
+ level: 1,
57
+ cells: exports.VALID_KILLER_SUDOKU
58
+ }
59
+ ];
60
+ //# sourceMappingURL=killerSudokuPuzzles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"killerSudokuPuzzles.js","sourceRoot":"","sources":["../../../src/test/fixtures/killerSudokuPuzzles.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;AAEH;;;;;;;;;;;;;;;;GAgBG;AAEH;;;GAGG;AACU,QAAA,mBAAmB,GAC9B,uMAAuM,CAAC;AAY1M;;GAEG;AACU,QAAA,sBAAsB,GAA2B;IAC5D;QACE,EAAE,EAAE,gBAAgB;QACpB,WAAW,EAAE,4BAA4B;QACzC,KAAK,EAAE,CAAC;QACR,KAAK,EAAE,2BAAmB;KAC3B;CACF,CAAC","sourcesContent":["/*\n * MIT License\n *\n * Copyright (c) 2023 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Stable killer sudoku puzzle definitions for testing.\n * These puzzles have been validated and are used across multiple test files\n * to ensure consistency in testing killer sudoku functionality.\n *\n * @remarks\n * Killer sudoku cells format: \"GRID_MAPPING|CAGE_DEFINITIONS\"\n * - GRID_MAPPING: 81 characters mapping each cell to a cage ID (A-Z, a-z)\n * - CAGE_DEFINITIONS: Comma-separated list of cageId+total (e.g., \"A11,B09,C20\")\n *\n * Example: \"AABBCC....|A11,B09,C20,...\"\n * - Cells 0-1 are in cage A with total 11\n * - Cells 2-3 are in cage B with total 09\n * - Cells 4-5 are in cage C with total 20\n *\n * @public\n */\n\n/**\n * Valid killer sudoku puzzle with complete cage definitions.\n * This is a standard 9x9 killer sudoku with 27 cages.\n */\nexport const VALID_KILLER_SUDOKU: string =\n 'ABCCCDDDEABFFGGGDEHIJKGGLLLHIJKMGLNNHOPPMQQNROOSTMUVWRSSSTTUVWRXYTTTZZabXYYYcccab|A11,B09,C09,D20,E16,F17,G30,H17,I13,J09,K11,L16,M16,N11,O16,P07,Q11,R10,S14,T39,U08,V17,W16,X06,Y26,Z06,a09,b09,c11';\n\n/**\n * Killer sudoku puzzle metadata.\n */\nexport interface IKillerSudokuFixture {\n id: string;\n description: string;\n level: number;\n cells: string;\n}\n\n/**\n * Collection of validated killer sudoku puzzles for testing.\n */\nexport const KILLER_SUDOKU_FIXTURES: IKillerSudokuFixture[] = [\n {\n id: 'valid-killer-1',\n description: 'Valid Killer Sudoku Puzzle',\n level: 1,\n cells: VALID_KILLER_SUDOKU\n }\n];\n"]}
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /*
3
+ * MIT License
4
+ *
5
+ * Copyright (c) 2023 Erik Fortune
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in all
15
+ * copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ * SOFTWARE.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.defaultProps = exports.invalidPuzzleDescription = exports.sudokuXPuzzleDescription = exports.simplePuzzleDescription = exports.validPuzzleDescription = exports.mockMatchMedia = exports.createPuzzleDefinition = void 0;
27
+ exports.customRender = customRender;
28
+ exports.advanceByLongPress = advanceByLongPress;
29
+ exports.setWindowDimensions = setWindowDimensions;
30
+ exports.renderWithMobilePortrait = renderWithMobilePortrait;
31
+ exports.renderWithDesktop = renderWithDesktop;
32
+ const react_1 = require("@testing-library/react");
33
+ const puzzleDefinitionHelper_1 = require("../../../utils/puzzleDefinitionHelper");
34
+ Object.defineProperty(exports, "createPuzzleDefinition", { enumerable: true, get: function () { return puzzleDefinitionHelper_1.createPuzzleDefinition; } });
35
+ // Custom render function - just use standard render
36
+ function customRender(ui, options) {
37
+ return (0, react_1.render)(ui, options);
38
+ }
39
+ // Helper function to simulate long press delay using fake timers
40
+ function advanceByLongPress(ms = 600) {
41
+ (0, react_1.act)(() => {
42
+ jest.advanceTimersByTime(ms);
43
+ });
44
+ }
45
+ // Helper to set window dimensions for different device types
46
+ function setWindowDimensions(width, height) {
47
+ Object.defineProperty(window, 'innerWidth', {
48
+ writable: true,
49
+ configurable: true,
50
+ value: width
51
+ });
52
+ Object.defineProperty(window, 'innerHeight', {
53
+ writable: true,
54
+ configurable: true,
55
+ value: height
56
+ });
57
+ }
58
+ // Helper to render with mobile portrait layout (side-by-side keypads)
59
+ function renderWithMobilePortrait(component, options) {
60
+ setWindowDimensions(375, 667);
61
+ return customRender(component, options);
62
+ }
63
+ // Helper to render with desktop layout (hidden/overlay keypads)
64
+ function renderWithDesktop(component, options) {
65
+ setWindowDimensions(1024, 768);
66
+ return customRender(component, options);
67
+ }
68
+ // Mock window.matchMedia for responsive layout tests
69
+ const mockMatchMedia = (query) => {
70
+ return {
71
+ matches: false,
72
+ media: query,
73
+ onchange: null,
74
+ addListener: jest.fn(),
75
+ removeListener: jest.fn(),
76
+ addEventListener: jest.fn(),
77
+ removeEventListener: jest.fn(),
78
+ dispatchEvent: jest.fn()
79
+ };
80
+ };
81
+ exports.mockMatchMedia = mockMatchMedia;
82
+ // Test puzzle definitions
83
+ exports.validPuzzleDescription = (0, puzzleDefinitionHelper_1.createPuzzleDefinition)({
84
+ id: 'test-puzzle',
85
+ description: 'Test Puzzle',
86
+ type: 'sudoku',
87
+ level: 1,
88
+ totalRows: 9,
89
+ totalColumns: 9,
90
+ cells: '123456789456789123789123456234567891567891234891234567345678912678912345912345678'
91
+ });
92
+ exports.simplePuzzleDescription = (0, puzzleDefinitionHelper_1.createPuzzleDefinition)({
93
+ id: 'simple-puzzle',
94
+ description: 'Simple Test Puzzle',
95
+ type: 'sudoku',
96
+ level: 1,
97
+ totalRows: 9,
98
+ totalColumns: 9,
99
+ cells: '1' + '.'.repeat(80) // 81 total characters
100
+ });
101
+ exports.sudokuXPuzzleDescription = (0, puzzleDefinitionHelper_1.createPuzzleDefinition)({
102
+ id: 'sudoku-x-puzzle',
103
+ description: 'Sudoku-X Test Puzzle',
104
+ type: 'sudoku-x',
105
+ level: 1,
106
+ totalRows: 9,
107
+ totalColumns: 9,
108
+ cells: '.'.repeat(81)
109
+ });
110
+ exports.invalidPuzzleDescription = (0, puzzleDefinitionHelper_1.createPuzzleDefinition)({
111
+ id: 'invalid-puzzle',
112
+ description: 'Invalid Puzzle',
113
+ type: 'sudoku',
114
+ level: 1,
115
+ totalRows: 9,
116
+ totalColumns: 9,
117
+ cells: 'invalid' // Too short
118
+ });
119
+ exports.defaultProps = {
120
+ initialPuzzleDescription: undefined,
121
+ onStateChange: undefined,
122
+ onValidationErrors: undefined,
123
+ className: undefined
124
+ };
125
+ //# sourceMappingURL=SudokuGridEntry.testHelpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SudokuGridEntry.testHelpers.js","sourceRoot":"","sources":["../../../../src/test/unit/components/SudokuGridEntry.testHelpers.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;AAWH,oCAEC;AAGD,gDAIC;AAGD,kDAWC;AAGD,4DAMC;AAGD,8CAGC;AA/CD,kDAAkF;AAElF,kFAA+E;AAItE,uGAJA,+CAAsB,OAIA;AAE/B,oDAAoD;AACpD,SAAgB,YAAY,CAAC,EAAsB,EAAE,OAAuB;IAC1E,OAAO,IAAA,cAAM,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,iEAAiE;AACjE,SAAgB,kBAAkB,CAAC,KAAa,GAAG;IACjD,IAAA,WAAG,EAAC,GAAG,EAAE;QACP,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,6DAA6D;AAC7D,SAAgB,mBAAmB,CAAC,KAAa,EAAE,MAAc;IAC/D,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,YAAY,EAAE;QAC1C,QAAQ,EAAE,IAAI;QACd,YAAY,EAAE,IAAI;QAClB,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE;QAC3C,QAAQ,EAAE,IAAI;QACd,YAAY,EAAE,IAAI;QAClB,KAAK,EAAE,MAAM;KACd,CAAC,CAAC;AACL,CAAC;AAED,sEAAsE;AACtE,SAAgB,wBAAwB,CACtC,SAA6B,EAC7B,OAAuB;IAEvB,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9B,OAAO,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED,gEAAgE;AAChE,SAAgB,iBAAiB,CAAC,SAA6B,EAAE,OAAuB;IACtF,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/B,OAAO,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED,qDAAqD;AAC9C,MAAM,cAAc,GAAG,CAAC,KAAa,EAAkB,EAAE;IAC9D,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE;QACtB,cAAc,EAAE,IAAI,CAAC,EAAE,EAAE;QACzB,gBAAgB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC3B,mBAAmB,EAAE,IAAI,CAAC,EAAE,EAAE;QAC9B,aAAa,EAAE,IAAI,CAAC,EAAE,EAAE;KACI,CAAC;AACjC,CAAC,CAAC;AAXW,QAAA,cAAc,kBAWzB;AAEF,0BAA0B;AACb,QAAA,sBAAsB,GAAsB,IAAA,+CAAsB,EAAC;IAC9E,EAAE,EAAE,aAAa;IACjB,WAAW,EAAE,aAAa;IAC1B,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,CAAC;IACR,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,CAAC;IACf,KAAK,EAAE,mFAAmF;CAC3F,CAAC,CAAC;AAEU,QAAA,uBAAuB,GAAsB,IAAA,+CAAsB,EAAC;IAC/E,EAAE,EAAE,eAAe;IACnB,WAAW,EAAE,oBAAoB;IACjC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,CAAC;IACR,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,CAAC;IACf,KAAK,EAAE,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,sBAAsB;CACnD,CAAC,CAAC;AAEU,QAAA,wBAAwB,GAAsB,IAAA,+CAAsB,EAAC;IAChF,EAAE,EAAE,iBAAiB;IACrB,WAAW,EAAE,sBAAsB;IACnC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,CAAC;IACR,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,CAAC;IACf,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;CACtB,CAAC,CAAC;AAEU,QAAA,wBAAwB,GAAsB,IAAA,+CAAsB,EAAC;IAChF,EAAE,EAAE,gBAAgB;IACpB,WAAW,EAAE,gBAAgB;IAC7B,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,CAAC;IACR,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,CAAC;IACf,KAAK,EAAE,SAAS,CAAC,YAAY;CAC9B,CAAC,CAAC;AAEU,QAAA,YAAY,GAKrB;IACF,wBAAwB,EAAE,SAAS;IACnC,aAAa,EAAE,SAAS;IACxB,kBAAkB,EAAE,SAAS;IAC7B,SAAS,EAAE,SAAS;CACrB,CAAC","sourcesContent":["/*\n * MIT License\n *\n * Copyright (c) 2023 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport { render, RenderResult, RenderOptions, act } from '@testing-library/react';\nimport { IPuzzleDefinition } from '@fgv/ts-sudoku-lib';\nimport { createPuzzleDefinition } from '../../../utils/puzzleDefinitionHelper';\n\n// Re-export for use in test files\nexport type { IPuzzleDefinition };\nexport { createPuzzleDefinition };\n\n// Custom render function - just use standard render\nexport function customRender(ui: React.ReactElement, options?: RenderOptions): RenderResult {\n return render(ui, options);\n}\n\n// Helper function to simulate long press delay using fake timers\nexport function advanceByLongPress(ms: number = 600): void {\n act(() => {\n jest.advanceTimersByTime(ms);\n });\n}\n\n// Helper to set window dimensions for different device types\nexport function setWindowDimensions(width: number, height: number): void {\n Object.defineProperty(window, 'innerWidth', {\n writable: true,\n configurable: true,\n value: width\n });\n Object.defineProperty(window, 'innerHeight', {\n writable: true,\n configurable: true,\n value: height\n });\n}\n\n// Helper to render with mobile portrait layout (side-by-side keypads)\nexport function renderWithMobilePortrait(\n component: React.ReactElement,\n options?: RenderOptions\n): RenderResult {\n setWindowDimensions(375, 667);\n return customRender(component, options);\n}\n\n// Helper to render with desktop layout (hidden/overlay keypads)\nexport function renderWithDesktop(component: React.ReactElement, options?: RenderOptions): RenderResult {\n setWindowDimensions(1024, 768);\n return customRender(component, options);\n}\n\n// Mock window.matchMedia for responsive layout tests\nexport const mockMatchMedia = (query: string): MediaQueryList => {\n return {\n matches: false,\n media: query,\n onchange: null,\n addListener: jest.fn(),\n removeListener: jest.fn(),\n addEventListener: jest.fn(),\n removeEventListener: jest.fn(),\n dispatchEvent: jest.fn()\n } as unknown as MediaQueryList;\n};\n\n// Test puzzle definitions\nexport const validPuzzleDescription: IPuzzleDefinition = createPuzzleDefinition({\n id: 'test-puzzle',\n description: 'Test Puzzle',\n type: 'sudoku',\n level: 1,\n totalRows: 9,\n totalColumns: 9,\n cells: '123456789456789123789123456234567891567891234891234567345678912678912345912345678'\n});\n\nexport const simplePuzzleDescription: IPuzzleDefinition = createPuzzleDefinition({\n id: 'simple-puzzle',\n description: 'Simple Test Puzzle',\n type: 'sudoku',\n level: 1,\n totalRows: 9,\n totalColumns: 9,\n cells: '1' + '.'.repeat(80) // 81 total characters\n});\n\nexport const sudokuXPuzzleDescription: IPuzzleDefinition = createPuzzleDefinition({\n id: 'sudoku-x-puzzle',\n description: 'Sudoku-X Test Puzzle',\n type: 'sudoku-x',\n level: 1,\n totalRows: 9,\n totalColumns: 9,\n cells: '.'.repeat(81)\n});\n\nexport const invalidPuzzleDescription: IPuzzleDefinition = createPuzzleDefinition({\n id: 'invalid-puzzle',\n description: 'Invalid Puzzle',\n type: 'sudoku',\n level: 1,\n totalRows: 9,\n totalColumns: 9,\n cells: 'invalid' // Too short\n});\n\nexport const defaultProps: {\n initialPuzzleDescription: undefined;\n onStateChange: undefined;\n onValidationErrors: undefined;\n className: undefined;\n} = {\n initialPuzzleDescription: undefined,\n onStateChange: undefined,\n onValidationErrors: undefined,\n className: undefined\n};\n"]}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ /*
3
+ * MIT License
4
+ *
5
+ * Copyright (c) 2023 Erik Fortune
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in all
15
+ * copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ * SOFTWARE.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG","sourcesContent":["/*\n * MIT License\n *\n * Copyright (c) 2023 Erik Fortune\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport { CellId, ICellContents, NavigationDirection, IPuzzleDefinition, ICage } from '@fgv/ts-sudoku-lib';\nimport { KeypadLayoutMode } from '../hooks/useResponsiveLayout';\n\n/**\n * Validation error for display in the UI\n * @public\n */\nexport interface IValidationError {\n readonly cellId: CellId;\n readonly type:\n | 'duplicate-row'\n | 'duplicate-column'\n | 'duplicate-section'\n | 'duplicate-diagonal'\n | 'invalid-value';\n readonly conflictingCells: CellId[];\n readonly message: string;\n}\n\n/**\n * Props for the main SudokuGridEntry component\n * @public\n */\nexport interface ISudokuGridEntryProps {\n /**\n * Optional initial puzzle session to load. If not provided, an empty puzzle is created.\n */\n readonly initialPuzzleDescription?: IPuzzleDefinition;\n\n /**\n * Callback fired when the puzzle state changes\n */\n readonly onStateChange?: (isValid: boolean, isSolved: boolean) => void;\n\n /**\n * Callback fired when validation errors occur\n */\n readonly onValidationErrors?: (errors: IValidationError[]) => void;\n\n /**\n * Optional CSS class name for styling\n */\n readonly className?: string;\n\n /**\n * Optional forced layout mode for testing (overrides responsive detection)\n */\n readonly forceLayoutMode?: KeypadLayoutMode;\n}\n\n/**\n * Props for the SudokuGrid component\n * @public\n */\nexport interface ISudokuGridProps {\n readonly numRows: number;\n readonly numColumns: number;\n readonly cells: ICellDisplayInfo[];\n readonly cages?: ICageDisplayInfo[];\n readonly selectedCell: CellId | null;\n readonly selectedCells: CellId[];\n readonly inputMode: InputMode;\n readonly puzzleType?: string;\n readonly puzzleDimensions?: {\n readonly cageHeightInCells: number;\n readonly cageWidthInCells: number;\n readonly boardWidthInCages: number;\n readonly boardHeightInCages: number;\n readonly totalRows: number;\n readonly totalColumns: number;\n readonly maxValue: number;\n readonly totalCages: number;\n readonly basicCageTotal: number;\n };\n readonly onCellSelect: (cellId: CellId, event?: React.MouseEvent) => void;\n readonly onLongPressToggle?: (cellId: CellId, event: React.TouchEvent | React.MouseEvent) => void;\n readonly onCellValueChange: (cellId: CellId, value: number | undefined) => void;\n readonly onNoteToggle: (cellId: CellId, note: number) => void;\n readonly onClearAllNotes: (cellId: CellId) => void;\n readonly onNavigate: (direction: NavigationDirection) => void;\n readonly onDragOver?: (cellId: CellId) => void;\n readonly onDragEnd?: () => void;\n readonly isDragging?: boolean;\n readonly className?: string;\n}\n\n/**\n * Display information for a single cell\n * @public\n */\nexport interface ICellDisplayInfo {\n readonly id: CellId;\n readonly row: number;\n readonly column: number;\n readonly contents: ICellContents;\n readonly isImmutable: boolean;\n readonly hasValidationError: boolean;\n}\n\n/**\n * Input mode for cell interactions\n * @public\n */\nexport type InputMode = 'value' | 'notes';\n\n/**\n * Props for the SudokuCell component\n * @public\n */\nexport interface ISudokuCellProps {\n readonly cellInfo: ICellDisplayInfo;\n readonly isSelected: boolean;\n readonly inputMode: InputMode;\n readonly puzzleDimensions?: {\n readonly numRows: number;\n readonly numColumns: number;\n readonly cageHeight: number;\n readonly cageWidth: number;\n };\n readonly onSelect: (event?: React.MouseEvent) => void;\n readonly onLongPressToggle?: (event: React.TouchEvent | React.MouseEvent) => void;\n readonly onValueChange: (value: number | undefined) => void;\n readonly onNoteToggle: (note: number) => void;\n readonly onClearAllNotes: () => void;\n readonly onDragOver?: () => void;\n readonly className?: string;\n}\n\n/**\n * Props for the SudokuControls component\n * @public\n */\nexport interface ISudokuControlsProps {\n readonly canUndo: boolean;\n readonly canRedo: boolean;\n readonly canReset: boolean;\n readonly isValid: boolean;\n readonly isSolved: boolean;\n readonly onUndo: () => void;\n readonly onRedo: () => void;\n readonly onReset: () => void;\n readonly onExport: () => void;\n readonly className?: string;\n}\n\n/**\n * Props for the ValidationDisplay component\n * @public\n */\nexport interface IValidationDisplayProps {\n readonly errors: IValidationError[];\n readonly isValid: boolean;\n readonly isSolved: boolean;\n readonly className?: string;\n}\n\n/**\n * Display information for a cage in Killer Sudoku\n * @public\n */\nexport interface ICageDisplayInfo {\n readonly cage: ICage;\n readonly isHighlighted: boolean;\n readonly currentSum?: number;\n readonly isComplete: boolean;\n readonly isValid: boolean;\n}\n\n/**\n * Props for the CageOverlay component\n * @public\n */\nexport interface ICageOverlayProps {\n readonly cages: ICageDisplayInfo[];\n readonly gridSize: { width: number; height: number };\n readonly cellSize: number;\n readonly numRows?: number;\n readonly numColumns?: number;\n readonly className?: string;\n}\n\n/**\n * Props for the CageSumIndicator component\n * @public\n */\nexport interface ICageSumIndicatorProps {\n readonly cage: ICage;\n readonly currentSum?: number;\n readonly isComplete: boolean;\n readonly isValid: boolean;\n readonly position: { top: number; left: number };\n readonly className?: string;\n}\n\n/**\n * Display mode for killer combinations explorer\n * @public\n */\nexport type IKillerCombinationsMode = 'panel' | 'modal';\n\n/**\n * Display information for a single combination\n * @public\n */\nexport interface ICombinationDisplayInfo {\n readonly combination: number[];\n readonly signature: string;\n readonly isEliminated: boolean;\n}\n\n/**\n * State management for combination elimination\n * @public\n */\nexport interface IEliminationState {\n readonly eliminatedSignatures: Set<string>;\n readonly toggleElimination: (signature: string) => void;\n readonly clearAll: () => void;\n}\n\n/**\n * Props for the KillerCombinationsExplorer component\n * @public\n */\nexport interface IKillerCombinationsExplorerProps {\n readonly selectedCage: ICage | null;\n readonly puzzleId?: string;\n readonly isOpen: boolean;\n readonly onClose: () => void;\n readonly mobileBreakpoint?: number;\n readonly className?: string;\n}\n\n/**\n * Props for the CombinationCard component\n * @public\n */\nexport interface ICombinationCardProps {\n readonly combination: ICombinationDisplayInfo;\n readonly onToggle: (signature: string) => void;\n readonly className?: string;\n}\n\n/**\n * Props for the CombinationGrid component\n * @public\n */\nexport interface ICombinationGridProps {\n readonly combinations: ICombinationDisplayInfo[];\n readonly onToggle: (signature: string) => void;\n readonly mode: IKillerCombinationsMode;\n readonly className?: string;\n}\n"]}
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+ /*
3
+ * MIT License
4
+ *
5
+ * Copyright (c) 2023 Erik Fortune
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in all
15
+ * copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ * SOFTWARE.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.CageLookupManager = exports.SegmentBit = void 0;
27
+ /**
28
+ * Segment bit positions for the 12-bit mask
29
+ */
30
+ var SegmentBit;
31
+ (function (SegmentBit) {
32
+ // Edges (bits 0-3)
33
+ SegmentBit[SegmentBit["EDGE_TOP"] = 1] = "EDGE_TOP";
34
+ SegmentBit[SegmentBit["EDGE_RIGHT"] = 2] = "EDGE_RIGHT";
35
+ SegmentBit[SegmentBit["EDGE_BOTTOM"] = 4] = "EDGE_BOTTOM";
36
+ SegmentBit[SegmentBit["EDGE_LEFT"] = 8] = "EDGE_LEFT";
37
+ // Corner connectors (bits 4-7)
38
+ SegmentBit[SegmentBit["CORNER_TOP_RIGHT"] = 16] = "CORNER_TOP_RIGHT";
39
+ SegmentBit[SegmentBit["CORNER_BOTTOM_RIGHT"] = 32] = "CORNER_BOTTOM_RIGHT";
40
+ SegmentBit[SegmentBit["CORNER_BOTTOM_LEFT"] = 64] = "CORNER_BOTTOM_LEFT";
41
+ SegmentBit[SegmentBit["CORNER_TOP_LEFT"] = 128] = "CORNER_TOP_LEFT";
42
+ // Internal segments (bits 8-11)
43
+ SegmentBit[SegmentBit["INTERNAL_TOP"] = 256] = "INTERNAL_TOP";
44
+ SegmentBit[SegmentBit["INTERNAL_RIGHT"] = 512] = "INTERNAL_RIGHT";
45
+ SegmentBit[SegmentBit["INTERNAL_BOTTOM"] = 1024] = "INTERNAL_BOTTOM";
46
+ SegmentBit[SegmentBit["INTERNAL_LEFT"] = 2048] = "INTERNAL_LEFT";
47
+ })(SegmentBit || (exports.SegmentBit = SegmentBit = {}));
48
+ /**
49
+ * Two-stage lookup manager for cage border rendering
50
+ * Stage 1: 8-neighbor pattern → segment pattern ID (256 → 47)
51
+ * Stage 2: segment pattern ID → SVG path data (47 unique patterns)
52
+ */
53
+ class CageLookupManager {
54
+ constructor() {
55
+ // Stage 1: Neighbor pattern (8-bit) to segment pattern ID mapping
56
+ this._neighborToSegmentLookup = new Array(256);
57
+ // Stage 2: Segment pattern ID to SVG path data mapping
58
+ this._segmentPatterns = [];
59
+ // Reverse lookup for debugging: segment mask to pattern ID
60
+ this._segmentMaskToId = new Map();
61
+ this._generateLookupTables();
62
+ }
63
+ /**
64
+ * Get singleton instance
65
+ */
66
+ static getInstance() {
67
+ if (!CageLookupManager._instance) {
68
+ CageLookupManager._instance = new CageLookupManager();
69
+ }
70
+ return CageLookupManager._instance;
71
+ }
72
+ /**
73
+ * Convert neighbor analysis to 8-bit pattern
74
+ */
75
+ neighborsToPattern(neighbors) {
76
+ // should be bitwise or but that makes eslint cranky
77
+ return ((neighbors.north ? 1 : 0) +
78
+ (neighbors.northEast ? 2 : 0) +
79
+ (neighbors.east ? 4 : 0) +
80
+ (neighbors.southEast ? 8 : 0) +
81
+ (neighbors.south ? 16 : 0) +
82
+ (neighbors.southWest ? 32 : 0) +
83
+ (neighbors.west ? 64 : 0) +
84
+ (neighbors.northWest ? 128 : 0));
85
+ }
86
+ /**
87
+ * Get SVG path data for a given neighbor pattern
88
+ */
89
+ getPatternSVG(neighborPattern) {
90
+ if (neighborPattern < 0 || neighborPattern >= 256) {
91
+ throw new Error(`Invalid neighbor pattern: ${neighborPattern}`);
92
+ }
93
+ const segmentPatternId = this._neighborToSegmentLookup[neighborPattern];
94
+ return this._segmentPatterns[segmentPatternId];
95
+ }
96
+ /**
97
+ * Get segment pattern ID for debugging
98
+ */
99
+ getSegmentPatternId(neighborPattern) {
100
+ return this._neighborToSegmentLookup[neighborPattern];
101
+ }
102
+ /**
103
+ * Get total number of unique segment patterns
104
+ */
105
+ get uniquePatternCount() {
106
+ return this._segmentPatterns.length;
107
+ }
108
+ /**
109
+ * Generate both lookup tables
110
+ */
111
+ _generateLookupTables() {
112
+ // First pass: generate all unique segment masks and assign IDs
113
+ const uniqueSegmentMasks = new Set();
114
+ for (let neighborPattern = 0; neighborPattern < 256; neighborPattern++) {
115
+ const segmentMask = this._calculateSegmentMask(neighborPattern);
116
+ uniqueSegmentMasks.add(segmentMask);
117
+ }
118
+ // Convert to sorted array for consistent ordering
119
+ const sortedSegmentMasks = Array.from(uniqueSegmentMasks).sort((a, b) => a - b);
120
+ // Generate SVG patterns for each unique segment mask
121
+ for (let i = 0; i < sortedSegmentMasks.length; i++) {
122
+ const segmentMask = sortedSegmentMasks[i];
123
+ this._segmentMaskToId.set(segmentMask, i);
124
+ this._segmentPatterns[i] = this._generateSVGPattern(segmentMask);
125
+ }
126
+ // Second pass: populate neighbor-to-segment lookup
127
+ for (let neighborPattern = 0; neighborPattern < 256; neighborPattern++) {
128
+ const segmentMask = this._calculateSegmentMask(neighborPattern);
129
+ const segmentPatternId = this._segmentMaskToId.get(segmentMask);
130
+ this._neighborToSegmentLookup[neighborPattern] = segmentPatternId;
131
+ }
132
+ }
133
+ /**
134
+ * Calculate segment mask from 8-bit neighbor pattern
135
+ */
136
+ _calculateSegmentMask(neighborPattern) {
137
+ // Extract individual neighbor bits
138
+ // eslint-disable-next-line no-bitwise
139
+ const n = Boolean(neighborPattern & 1); // North
140
+ // eslint-disable-next-line no-bitwise
141
+ const ne = Boolean(neighborPattern & 2); // NorthEast
142
+ // eslint-disable-next-line no-bitwise
143
+ const e = Boolean(neighborPattern & 4); // East
144
+ // eslint-disable-next-line no-bitwise
145
+ const se = Boolean(neighborPattern & 8); // SouthEast
146
+ // eslint-disable-next-line no-bitwise
147
+ const s = Boolean(neighborPattern & 16); // South
148
+ // eslint-disable-next-line no-bitwise
149
+ const sw = Boolean(neighborPattern & 32); // SouthWest
150
+ // eslint-disable-next-line no-bitwise
151
+ const w = Boolean(neighborPattern & 64); // West
152
+ // eslint-disable-next-line no-bitwise
153
+ const nw = Boolean(neighborPattern & 128); // NorthWest
154
+ let segmentMask = 0;
155
+ // Edges: Draw when corresponding cardinal neighbor is NOT present
156
+ // eslint-disable-next-line no-bitwise
157
+ if (!n)
158
+ segmentMask |= SegmentBit.EDGE_TOP;
159
+ // eslint-disable-next-line no-bitwise
160
+ if (!e)
161
+ segmentMask |= SegmentBit.EDGE_RIGHT;
162
+ // eslint-disable-next-line no-bitwise
163
+ if (!s)
164
+ segmentMask |= SegmentBit.EDGE_BOTTOM;
165
+ // eslint-disable-next-line no-bitwise
166
+ if (!w)
167
+ segmentMask |= SegmentBit.EDGE_LEFT;
168
+ // Internal segments: Draw when corresponding cardinal neighbor IS present
169
+ // eslint-disable-next-line no-bitwise
170
+ if (n)
171
+ segmentMask |= SegmentBit.INTERNAL_TOP;
172
+ // eslint-disable-next-line no-bitwise
173
+ if (e)
174
+ segmentMask |= SegmentBit.INTERNAL_RIGHT;
175
+ // eslint-disable-next-line no-bitwise
176
+ if (s)
177
+ segmentMask |= SegmentBit.INTERNAL_BOTTOM;
178
+ // eslint-disable-next-line no-bitwise
179
+ if (w)
180
+ segmentMask |= SegmentBit.INTERNAL_LEFT;
181
+ // Corner connectors: Draw when diagonal is missing but both adjacent cardinals are present
182
+ // eslint-disable-next-line no-bitwise
183
+ if (!ne && n && e)
184
+ segmentMask |= SegmentBit.CORNER_TOP_RIGHT;
185
+ // eslint-disable-next-line no-bitwise
186
+ if (!se && s && e)
187
+ segmentMask |= SegmentBit.CORNER_BOTTOM_RIGHT;
188
+ // eslint-disable-next-line no-bitwise
189
+ if (!sw && s && w)
190
+ segmentMask |= SegmentBit.CORNER_BOTTOM_LEFT;
191
+ // eslint-disable-next-line no-bitwise
192
+ if (!nw && n && w)
193
+ segmentMask |= SegmentBit.CORNER_TOP_LEFT;
194
+ return segmentMask;
195
+ }
196
+ /**
197
+ * Generate SVG path data for a segment mask
198
+ */
199
+ _generateSVGPattern(segmentMask) {
200
+ const paths = [];
201
+ const inset = 0.1; // Standard inset for cage boundaries
202
+ const edgeExtension = 0.0; // Extend to cell edge for connections
203
+ // Determine which segments have internal connections (need to extend to edge)
204
+ // eslint-disable-next-line no-bitwise
205
+ const hasInternalTop = Boolean(segmentMask & SegmentBit.INTERNAL_TOP);
206
+ // eslint-disable-next-line no-bitwise
207
+ const hasInternalRight = Boolean(segmentMask & SegmentBit.INTERNAL_RIGHT);
208
+ // eslint-disable-next-line no-bitwise
209
+ const hasInternalBottom = Boolean(segmentMask & SegmentBit.INTERNAL_BOTTOM);
210
+ // eslint-disable-next-line no-bitwise
211
+ const hasInternalLeft = Boolean(segmentMask & SegmentBit.INTERNAL_LEFT);
212
+ // Edge segments - draw main segment with standard inset, then extensions to edge where needed
213
+ // eslint-disable-next-line no-bitwise
214
+ if (segmentMask & SegmentBit.EDGE_TOP) {
215
+ // Main horizontal segment
216
+ paths.push(`M${inset},${inset} L${1 - inset},${inset}`);
217
+ // Extensions to cell edges where there are internal connections
218
+ if (hasInternalLeft) {
219
+ paths.push(`M${edgeExtension},${inset} L${inset},${inset}`);
220
+ }
221
+ if (hasInternalRight) {
222
+ paths.push(`M${1 - inset},${inset} L${1 - edgeExtension},${inset}`);
223
+ }
224
+ }
225
+ // eslint-disable-next-line no-bitwise
226
+ if (segmentMask & SegmentBit.EDGE_RIGHT) {
227
+ // Main vertical segment
228
+ paths.push(`M${1 - inset},${inset} L${1 - inset},${1 - inset}`);
229
+ // Extensions to cell edges where there are internal connections
230
+ if (hasInternalTop) {
231
+ paths.push(`M${1 - inset},${edgeExtension} L${1 - inset},${inset}`);
232
+ }
233
+ if (hasInternalBottom) {
234
+ paths.push(`M${1 - inset},${1 - inset} L${1 - inset},${1 - edgeExtension}`);
235
+ }
236
+ }
237
+ // eslint-disable-next-line no-bitwise
238
+ if (segmentMask & SegmentBit.EDGE_BOTTOM) {
239
+ // Main horizontal segment
240
+ paths.push(`M${1 - inset},${1 - inset} L${inset},${1 - inset}`);
241
+ // Extensions to cell edges where there are internal connections
242
+ if (hasInternalRight) {
243
+ paths.push(`M${1 - edgeExtension},${1 - inset} L${1 - inset},${1 - inset}`);
244
+ }
245
+ if (hasInternalLeft) {
246
+ paths.push(`M${inset},${1 - inset} L${edgeExtension},${1 - inset}`);
247
+ }
248
+ }
249
+ // eslint-disable-next-line no-bitwise
250
+ if (segmentMask & SegmentBit.EDGE_LEFT) {
251
+ // Main vertical segment
252
+ paths.push(`M${inset},${1 - inset} L${inset},${inset}`);
253
+ // Extensions to cell edges where there are internal connections
254
+ if (hasInternalBottom) {
255
+ paths.push(`M${inset},${1 - edgeExtension} L${inset},${1 - inset}`);
256
+ }
257
+ if (hasInternalTop) {
258
+ paths.push(`M${inset},${inset} L${inset},${edgeExtension}`);
259
+ }
260
+ }
261
+ // Corner connectors - extend outward from cage corners
262
+ const cornerRadius = 0.08;
263
+ // eslint-disable-next-line no-bitwise
264
+ if (segmentMask & SegmentBit.CORNER_TOP_RIGHT) {
265
+ // Extend outward from top-right corner
266
+ paths.push(`M${1 - inset},${inset} L${1 - inset + cornerRadius},${inset} M${1 - inset},${inset} L${1 - inset},${inset - cornerRadius}`);
267
+ }
268
+ // eslint-disable-next-line no-bitwise
269
+ if (segmentMask & SegmentBit.CORNER_BOTTOM_RIGHT) {
270
+ // Extend outward from bottom-right corner
271
+ paths.push(`M${1 - inset},${1 - inset} L${1 - inset + cornerRadius},${1 - inset} M${1 - inset},${1 - inset} L${1 - inset},${1 - inset + cornerRadius}`);
272
+ }
273
+ // eslint-disable-next-line no-bitwise
274
+ if (segmentMask & SegmentBit.CORNER_BOTTOM_LEFT) {
275
+ // Extend outward from bottom-left corner
276
+ paths.push(`M${inset},${1 - inset} L${inset - cornerRadius},${1 - inset} M${inset},${1 - inset} L${inset},${1 - inset + cornerRadius}`);
277
+ }
278
+ // eslint-disable-next-line no-bitwise
279
+ if (segmentMask & SegmentBit.CORNER_TOP_LEFT) {
280
+ // Extend outward from top-left corner
281
+ paths.push(`M${inset},${inset} L${inset - cornerRadius},${inset} M${inset},${inset} L${inset},${inset - cornerRadius}`);
282
+ }
283
+ return paths.join(' ');
284
+ }
285
+ }
286
+ exports.CageLookupManager = CageLookupManager;
287
+ //# sourceMappingURL=CageLookupManager.js.map