@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,481 @@
1
+ ## API Report File for "@fgv/ts-sudoku-ui"
2
+
3
+ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
4
+
5
+ ```ts
6
+
7
+ import { CellId } from '@fgv/ts-sudoku-lib';
8
+ import { ICage } from '@fgv/ts-sudoku-lib';
9
+ import { ICellContents } from '@fgv/ts-sudoku-lib';
10
+ import { IPuzzleDefinition } from '@fgv/ts-sudoku-lib';
11
+ import { Logging } from '@fgv/ts-utils';
12
+ import { NavigationDirection } from '@fgv/ts-sudoku-lib';
13
+ import { NavigationWrap } from '@fgv/ts-sudoku-lib';
14
+ import { PuzzleSession } from '@fgv/ts-sudoku-lib';
15
+ import { default as React_2 } from 'react';
16
+ import { ReactNode } from 'react';
17
+ import { Result } from '@fgv/ts-utils';
18
+
19
+ // @public
20
+ export const CageOverlay: React_2.FC<ICageOverlayProps>;
21
+
22
+ // @public
23
+ export const CageSumIndicator: React_2.FC<ICageSumIndicatorProps>;
24
+
25
+ // @public
26
+ export const CombinationCard: React_2.NamedExoticComponent<ICombinationCardProps>;
27
+
28
+ // @public
29
+ export const CombinationGrid: React_2.FC<ICombinationGridProps>;
30
+
31
+ // @public
32
+ export const CompactControlRibbon: React_2.FC<ICompactControlRibbonProps>;
33
+
34
+ // @public
35
+ export const DefaultDiagnosticLogger: Logging.LogReporter<unknown>;
36
+
37
+ // @public
38
+ export type DeviceType = 'mobile' | 'tablet' | 'desktop';
39
+
40
+ // @public
41
+ export const DiagnosticLoggerContext: React_2.Context<Logging.LogReporter<unknown>>;
42
+
43
+ // @public
44
+ export const DiagnosticLoggerProvider: React_2.FC<IDiagnosticLoggerProviderProps>;
45
+
46
+ // @public
47
+ export const DualKeypad: React_2.FC<IDualKeypadProps>;
48
+
49
+ // @public
50
+ export interface ICageDisplayInfo {
51
+ // (undocumented)
52
+ readonly cage: ICage;
53
+ // (undocumented)
54
+ readonly currentSum?: number;
55
+ // (undocumented)
56
+ readonly isComplete: boolean;
57
+ // (undocumented)
58
+ readonly isHighlighted: boolean;
59
+ // (undocumented)
60
+ readonly isValid: boolean;
61
+ }
62
+
63
+ // @public
64
+ export interface ICageOverlayProps {
65
+ // (undocumented)
66
+ readonly cages: ICageDisplayInfo[];
67
+ // (undocumented)
68
+ readonly cellSize: number;
69
+ // (undocumented)
70
+ readonly className?: string;
71
+ // (undocumented)
72
+ readonly gridSize: {
73
+ width: number;
74
+ height: number;
75
+ };
76
+ // (undocumented)
77
+ readonly numColumns?: number;
78
+ // (undocumented)
79
+ readonly numRows?: number;
80
+ }
81
+
82
+ // @public
83
+ export interface ICageSumIndicatorProps {
84
+ // (undocumented)
85
+ readonly cage: ICage;
86
+ // (undocumented)
87
+ readonly className?: string;
88
+ // (undocumented)
89
+ readonly currentSum?: number;
90
+ // (undocumented)
91
+ readonly isComplete: boolean;
92
+ // (undocumented)
93
+ readonly isValid: boolean;
94
+ // (undocumented)
95
+ readonly position: {
96
+ top: number;
97
+ left: number;
98
+ };
99
+ }
100
+
101
+ // @public
102
+ export interface ICellDisplayInfo {
103
+ // (undocumented)
104
+ readonly column: number;
105
+ // (undocumented)
106
+ readonly contents: ICellContents;
107
+ // (undocumented)
108
+ readonly hasValidationError: boolean;
109
+ // (undocumented)
110
+ readonly id: CellId;
111
+ // (undocumented)
112
+ readonly isImmutable: boolean;
113
+ // (undocumented)
114
+ readonly row: number;
115
+ }
116
+
117
+ // @public
118
+ export interface ICombinationCardProps {
119
+ // (undocumented)
120
+ readonly className?: string;
121
+ // (undocumented)
122
+ readonly combination: ICombinationDisplayInfo;
123
+ // (undocumented)
124
+ readonly onToggle: (signature: string) => void;
125
+ }
126
+
127
+ // @public
128
+ export interface ICombinationDisplayInfo {
129
+ // (undocumented)
130
+ readonly combination: number[];
131
+ // (undocumented)
132
+ readonly isEliminated: boolean;
133
+ // (undocumented)
134
+ readonly signature: string;
135
+ }
136
+
137
+ // @public
138
+ export interface ICombinationGridProps {
139
+ // (undocumented)
140
+ readonly className?: string;
141
+ // (undocumented)
142
+ readonly combinations: ICombinationDisplayInfo[];
143
+ // (undocumented)
144
+ readonly mode: IKillerCombinationsMode;
145
+ // (undocumented)
146
+ readonly onToggle: (signature: string) => void;
147
+ }
148
+
149
+ // @public
150
+ export interface ICompactControlRibbonProps {
151
+ readonly canRedo: boolean;
152
+ readonly canReset: boolean;
153
+ readonly canShowCombinations?: boolean;
154
+ readonly canUndo: boolean;
155
+ readonly className?: string;
156
+ readonly isSolved: boolean;
157
+ readonly isValid: boolean;
158
+ readonly onCombinations?: () => void;
159
+ readonly onExport: () => void;
160
+ readonly onRedo: () => void;
161
+ readonly onReset: () => void;
162
+ readonly onUndo: () => void;
163
+ readonly showCombinations?: boolean;
164
+ readonly validationErrors: ReadonlyArray<{
165
+ readonly type: string;
166
+ readonly cellId: string;
167
+ readonly message: string;
168
+ }>;
169
+ }
170
+
171
+ // @public
172
+ export interface IDiagnosticLoggerProviderProps {
173
+ children: ReactNode;
174
+ logger?: Logging.LogReporter<unknown>;
175
+ }
176
+
177
+ // @public
178
+ export interface IDualKeypadProps {
179
+ readonly className?: string;
180
+ readonly disabled?: boolean;
181
+ readonly forceLayoutMode?: KeypadLayoutMode;
182
+ readonly hasCellSelection: boolean;
183
+ // Warning: (ae-forgotten-export) The symbol "InputMode" needs to be exported by the entry point index.d.ts
184
+ readonly inputMode: InputMode;
185
+ readonly onClearNotes: () => void;
186
+ readonly onClearValues: () => void;
187
+ readonly onInputModeChange: (mode: InputMode) => void;
188
+ readonly onNotePress: (number: number) => void;
189
+ readonly onValuePress: (number: number) => void;
190
+ readonly selectedCellCount: number;
191
+ readonly showOverlayToggle?: boolean;
192
+ }
193
+
194
+ // @public
195
+ export interface IEliminationState {
196
+ // (undocumented)
197
+ readonly clearAll: () => void;
198
+ // (undocumented)
199
+ readonly eliminatedSignatures: Set<string>;
200
+ // (undocumented)
201
+ readonly toggleElimination: (signature: string) => void;
202
+ }
203
+
204
+ // @public
205
+ export interface IKeyboardShortcutOptions {
206
+ // (undocumented)
207
+ readonly ctrl?: boolean;
208
+ // (undocumented)
209
+ readonly meta?: boolean;
210
+ // (undocumented)
211
+ readonly preventDefault?: boolean;
212
+ // (undocumented)
213
+ readonly shift?: boolean;
214
+ }
215
+
216
+ // @public
217
+ export interface IKillerCombinationsExplorerProps {
218
+ // (undocumented)
219
+ readonly className?: string;
220
+ // (undocumented)
221
+ readonly isOpen: boolean;
222
+ // (undocumented)
223
+ readonly mobileBreakpoint?: number;
224
+ // (undocumented)
225
+ readonly onClose: () => void;
226
+ // (undocumented)
227
+ readonly puzzleId?: string;
228
+ // (undocumented)
229
+ readonly selectedCage: ICage | null;
230
+ }
231
+
232
+ // @public
233
+ export type IKillerCombinationsMode = 'panel' | 'modal';
234
+
235
+ // @public
236
+ export interface INumberKeypadProps {
237
+ readonly className?: string;
238
+ readonly compact?: boolean;
239
+ readonly disabled?: boolean;
240
+ readonly inputMode: InputMode;
241
+ readonly isActive: boolean;
242
+ readonly keypadType: 'notes' | 'values';
243
+ readonly onClear: () => void;
244
+ readonly onNumberPress: (number: number) => void;
245
+ }
246
+
247
+ // @public
248
+ export interface IResponsiveLayoutInfo {
249
+ readonly deviceType: DeviceType;
250
+ readonly hasSpaceForDualKeypads: boolean;
251
+ readonly isSmallScreen: boolean;
252
+ readonly isTouchDevice: boolean;
253
+ readonly keypadLayoutMode: KeypadLayoutMode;
254
+ readonly orientation: ScreenOrientation_2;
255
+ readonly screenHeight: number;
256
+ readonly screenWidth: number;
257
+ }
258
+
259
+ // @public
260
+ export interface ISudokuCellProps {
261
+ // (undocumented)
262
+ readonly cellInfo: ICellDisplayInfo;
263
+ // (undocumented)
264
+ readonly className?: string;
265
+ // (undocumented)
266
+ readonly inputMode: InputMode;
267
+ // (undocumented)
268
+ readonly isSelected: boolean;
269
+ // (undocumented)
270
+ readonly onClearAllNotes: () => void;
271
+ // (undocumented)
272
+ readonly onDragOver?: () => void;
273
+ // (undocumented)
274
+ readonly onLongPressToggle?: (event: React.TouchEvent | React.MouseEvent) => void;
275
+ // (undocumented)
276
+ readonly onNoteToggle: (note: number) => void;
277
+ // (undocumented)
278
+ readonly onSelect: (event?: React.MouseEvent) => void;
279
+ // (undocumented)
280
+ readonly onValueChange: (value: number | undefined) => void;
281
+ // (undocumented)
282
+ readonly puzzleDimensions?: {
283
+ readonly numRows: number;
284
+ readonly numColumns: number;
285
+ readonly cageHeight: number;
286
+ readonly cageWidth: number;
287
+ };
288
+ }
289
+
290
+ // @public
291
+ export interface ISudokuControlsProps {
292
+ // (undocumented)
293
+ readonly canRedo: boolean;
294
+ // (undocumented)
295
+ readonly canReset: boolean;
296
+ // (undocumented)
297
+ readonly canUndo: boolean;
298
+ // (undocumented)
299
+ readonly className?: string;
300
+ // (undocumented)
301
+ readonly isSolved: boolean;
302
+ // (undocumented)
303
+ readonly isValid: boolean;
304
+ // (undocumented)
305
+ readonly onExport: () => void;
306
+ // (undocumented)
307
+ readonly onRedo: () => void;
308
+ // (undocumented)
309
+ readonly onReset: () => void;
310
+ // (undocumented)
311
+ readonly onUndo: () => void;
312
+ }
313
+
314
+ // @public
315
+ export interface ISudokuGridEntryProps {
316
+ readonly className?: string;
317
+ readonly forceLayoutMode?: KeypadLayoutMode;
318
+ readonly initialPuzzleDescription?: IPuzzleDefinition;
319
+ readonly onStateChange?: (isValid: boolean, isSolved: boolean) => void;
320
+ readonly onValidationErrors?: (errors: IValidationError[]) => void;
321
+ }
322
+
323
+ // @public
324
+ export interface ISudokuGridProps {
325
+ // (undocumented)
326
+ readonly cages?: ICageDisplayInfo[];
327
+ // (undocumented)
328
+ readonly cells: ICellDisplayInfo[];
329
+ // (undocumented)
330
+ readonly className?: string;
331
+ // (undocumented)
332
+ readonly inputMode: InputMode;
333
+ // (undocumented)
334
+ readonly isDragging?: boolean;
335
+ // (undocumented)
336
+ readonly numColumns: number;
337
+ // (undocumented)
338
+ readonly numRows: number;
339
+ // (undocumented)
340
+ readonly onCellSelect: (cellId: CellId, event?: React.MouseEvent) => void;
341
+ // (undocumented)
342
+ readonly onCellValueChange: (cellId: CellId, value: number | undefined) => void;
343
+ // (undocumented)
344
+ readonly onClearAllNotes: (cellId: CellId) => void;
345
+ // (undocumented)
346
+ readonly onDragEnd?: () => void;
347
+ // (undocumented)
348
+ readonly onDragOver?: (cellId: CellId) => void;
349
+ // (undocumented)
350
+ readonly onLongPressToggle?: (cellId: CellId, event: React.TouchEvent | React.MouseEvent) => void;
351
+ // (undocumented)
352
+ readonly onNavigate: (direction: NavigationDirection) => void;
353
+ // (undocumented)
354
+ readonly onNoteToggle: (cellId: CellId, note: number) => void;
355
+ // (undocumented)
356
+ readonly puzzleDimensions?: {
357
+ readonly cageHeightInCells: number;
358
+ readonly cageWidthInCells: number;
359
+ readonly boardWidthInCages: number;
360
+ readonly boardHeightInCages: number;
361
+ readonly totalRows: number;
362
+ readonly totalColumns: number;
363
+ readonly maxValue: number;
364
+ readonly totalCages: number;
365
+ readonly basicCageTotal: number;
366
+ };
367
+ // (undocumented)
368
+ readonly puzzleType?: string;
369
+ // (undocumented)
370
+ readonly selectedCell: CellId | null;
371
+ // (undocumented)
372
+ readonly selectedCells: CellId[];
373
+ }
374
+
375
+ // @public
376
+ export interface IValidationDisplayProps {
377
+ // (undocumented)
378
+ readonly className?: string;
379
+ // (undocumented)
380
+ readonly errors: IValidationError[];
381
+ // (undocumented)
382
+ readonly isSolved: boolean;
383
+ // (undocumented)
384
+ readonly isValid: boolean;
385
+ }
386
+
387
+ // @public
388
+ export interface IValidationError {
389
+ // (undocumented)
390
+ readonly cellId: CellId;
391
+ // (undocumented)
392
+ readonly conflictingCells: CellId[];
393
+ // (undocumented)
394
+ readonly message: string;
395
+ // (undocumented)
396
+ readonly type: 'duplicate-row' | 'duplicate-column' | 'duplicate-section' | 'duplicate-diagonal' | 'invalid-value';
397
+ }
398
+
399
+ // @public
400
+ export type KeypadLayoutMode = 'side-by-side' | 'stacked' | 'overlay' | 'hidden';
401
+
402
+ // @public
403
+ export const KillerCombinationsExplorer: React_2.FC<IKillerCombinationsExplorerProps>;
404
+
405
+ // Warning: (ae-forgotten-export) The symbol "IKillerCombinationsModalProps" needs to be exported by the entry point index.d.ts
406
+ //
407
+ // @public
408
+ export const KillerCombinationsModal: React_2.FC<IKillerCombinationsModalProps>;
409
+
410
+ // Warning: (ae-forgotten-export) The symbol "IKillerCombinationsPanelProps" needs to be exported by the entry point index.d.ts
411
+ //
412
+ // @public
413
+ export const KillerCombinationsPanel: React_2.FC<IKillerCombinationsPanelProps>;
414
+
415
+ // @public
416
+ export const NumberKeypad: React_2.FC<INumberKeypadProps>;
417
+
418
+ // @public
419
+ type ScreenOrientation_2 = 'portrait' | 'landscape';
420
+ export { ScreenOrientation_2 as ScreenOrientation }
421
+
422
+ // @public
423
+ export const SudokuCell: React_2.FC<ISudokuCellProps>;
424
+
425
+ // @public
426
+ export const SudokuControls: React_2.FC<ISudokuControlsProps>;
427
+
428
+ // @public
429
+ export const SudokuGrid: React_2.FC<ISudokuGridProps>;
430
+
431
+ // @public
432
+ export const SudokuGridEntry: React_2.FC<ISudokuGridEntryProps>;
433
+
434
+ // @public
435
+ export function useCombinationElimination(puzzleId: string | undefined, cageId: string | undefined): IEliminationState;
436
+
437
+ // @public
438
+ export const useDiagnosticLogger: () => Logging.LogReporter<unknown>;
439
+
440
+ // @public
441
+ export function useKeyboardShortcut(key: string, callback: () => void, options?: IKeyboardShortcutOptions): void;
442
+
443
+ // @public
444
+ export function useKillerCombinations(cage: ICage | null): Result<ICombinationDisplayInfo[]>;
445
+
446
+ // @public
447
+ export function usePuzzleSession(initialPuzzleDescription?: IPuzzleDefinition): {
448
+ session: PuzzleSession | null;
449
+ selectedCell: CellId | null;
450
+ selectedCells: CellId[];
451
+ inputMode: InputMode;
452
+ setSelectedCell: (cell: CellId | null) => void;
453
+ setSelectedCells: (cells: CellId[]) => void;
454
+ setInputMode: (mode: InputMode) => void;
455
+ cellDisplayInfo: ICellDisplayInfo[];
456
+ cageDisplayInfo: ICageDisplayInfo[];
457
+ validationErrors: IValidationError[];
458
+ isValid: boolean;
459
+ isSolved: boolean;
460
+ canUndo: boolean;
461
+ canRedo: boolean;
462
+ error: string | null;
463
+ updateCellValue: (cellId: CellId, value: number | undefined) => void;
464
+ toggleCellNote: (cellId: CellId, note: number) => void;
465
+ clearCellNotes: (cellId: CellId) => void;
466
+ navigateToCell: (direction: NavigationDirection, wrap?: NavigationWrap) => void;
467
+ undo: () => void;
468
+ redo: () => void;
469
+ reset: () => void;
470
+ exportPuzzle: () => IPuzzleDefinition | null;
471
+ };
472
+
473
+ // @public
474
+ export function useResponsiveLayout(forceLayoutMode?: KeypadLayoutMode): IResponsiveLayoutInfo;
475
+
476
+ // @public
477
+ export const ValidationDisplay: React_2.FC<IValidationDisplayProps>;
478
+
479
+ // (No @packageDocumentation comment for this package)
480
+
481
+ ```
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { ICageOverlayProps } from '../types';
3
+ /**
4
+ * Component for rendering cage boundaries and sum indicators in Killer Sudoku
5
+ * @public
6
+ */
7
+ export declare const CageOverlay: React.FC<ICageOverlayProps>;
8
+ //# sourceMappingURL=CageOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CageOverlay.d.ts","sourceRoot":"","sources":["../../src/components/CageOverlay.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAA6B,MAAM,OAAO,CAAC;AAElD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAiD7C;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAmInD,CAAC"}
@@ -0,0 +1,133 @@
1
+ /*
2
+ * MIT License
3
+ *
4
+ * Copyright (c) 2023 Erik Fortune
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ import React, { useMemo, useEffect } from 'react';
25
+ import { parseCellId } from '@fgv/ts-sudoku-lib';
26
+ import { CageSumIndicator } from './CageSumIndicator';
27
+ import { CagePatternManager } from '../utils/CagePatternManager';
28
+ import { CageLookupManager } from '../utils/CageLookupManager';
29
+ import { useDiagnosticLogger } from '../contexts/DiagnosticLoggerContext';
30
+ /**
31
+ * Helper to get cell position from CellId
32
+ */
33
+ function getTopLeftPosition(cellIds, log, numRows, numColumns) {
34
+ if (cellIds.length === 0)
35
+ return { top: 0, left: 0 };
36
+ const positions = cellIds.map((cellId) => {
37
+ const parsed = parseCellId(cellId);
38
+ if (parsed && parsed.row >= 0 && parsed.row < numRows && parsed.col >= 0 && parsed.col < numColumns) {
39
+ return parsed;
40
+ }
41
+ // Fallback - should not happen with valid CellIds
42
+ log.warn(`Invalid CellId format: ${cellId}`);
43
+ return { row: 0, col: 0 };
44
+ });
45
+ // Find the top-left most cell
46
+ let minRow = positions[0].row;
47
+ let minCol = positions[0].col;
48
+ positions.forEach(({ row, col }) => {
49
+ if (row < minRow || (row === minRow && col < minCol)) {
50
+ minRow = row;
51
+ minCol = col;
52
+ }
53
+ });
54
+ // Convert grid coordinates to percentage-based positioning
55
+ const cellWidthPercent = 100 / numColumns;
56
+ const cellHeightPercent = 100 / numRows;
57
+ return {
58
+ top: minRow * cellHeightPercent + 0.5, // Small offset from corner
59
+ left: minCol * cellWidthPercent + 0.5 // Small offset from corner
60
+ };
61
+ }
62
+ /**
63
+ * Component for rendering cage boundaries and sum indicators in Killer Sudoku
64
+ * @public
65
+ */
66
+ export const CageOverlay = ({ cages, gridSize, cellSize, numRows = 9, numColumns = 9, className }) => {
67
+ const log = useDiagnosticLogger();
68
+ // Initialize managers once
69
+ const patternManager = useMemo(() => new CagePatternManager(), []);
70
+ const lookupManager = useMemo(() => CageLookupManager.getInstance(), []);
71
+ // Debug logging
72
+ useEffect(() => {
73
+ log.info('CageOverlay rendered', {
74
+ cageCount: cages.length,
75
+ gridSize,
76
+ cellSize,
77
+ cages: cages.map((c) => ({ id: c.cage.id, cellIds: c.cage.cellIds }))
78
+ });
79
+ }, [cages, gridSize, cellSize, log]);
80
+ // Calculate SVG viewBox and class names
81
+ const viewBox = `0 0 ${gridSize.width} ${gridSize.height}`;
82
+ const overlayClasses = useMemo(() => {
83
+ const classes = ['cage-overlay'];
84
+ if (className)
85
+ classes.push(className);
86
+ return classes.join(' ');
87
+ }, [className]);
88
+ return (React.createElement("div", { className: `
89
+ ${overlayClasses}
90
+ absolute inset-0 w-full h-full pointer-events-none
91
+ `, style: { zIndex: 1000 }, "data-testid": "cage-overlay" },
92
+ React.createElement("svg", { width: "100%", height: "100%", viewBox: viewBox, className: "absolute inset-0", preserveAspectRatio: "none" }, cages.map((cageInfo, index) => {
93
+ const { cage, isHighlighted, isValid } = cageInfo;
94
+ // Build occupied cells set for this cage
95
+ const occupiedCells = patternManager.buildOccupiedCellsSet(cage.cellIds);
96
+ // Render each cell with connected borders
97
+ return cage.cellIds.map((cellId, cellIndex) => {
98
+ // Parse cell position using centralized function
99
+ const parsed = parseCellId(cellId);
100
+ let row = 0, col = 0;
101
+ if (parsed &&
102
+ parsed.row >= 0 &&
103
+ parsed.row < numRows &&
104
+ parsed.col >= 0 &&
105
+ parsed.col < numColumns) {
106
+ row = parsed.row;
107
+ col = parsed.col;
108
+ }
109
+ else {
110
+ log.warn(`Invalid CellId format: ${cellId}`);
111
+ }
112
+ const x = col * cellSize;
113
+ const y = row * cellSize;
114
+ // Analyze neighbors and get pattern
115
+ const neighbors = patternManager.analyzeNeighbors(cellId, occupiedCells);
116
+ const neighborPattern = lookupManager.neighborsToPattern(neighbors);
117
+ const pathData = lookupManager.getPatternSVG(neighborPattern);
118
+ // Skip if no path data
119
+ if (!pathData) {
120
+ return null;
121
+ }
122
+ // Render connected border pattern
123
+ return (React.createElement("g", { key: /* c8 ignore next 1 - defense in depth */ `${cage.id ?? index}-${cellIndex}`, transform: `translate(${x}, ${y}) scale(${cellSize})` },
124
+ React.createElement("path", { d: pathData, stroke: isHighlighted ? '#1e40af' : isValid ? '#2563eb' : '#dc2626', strokeWidth: 0.8 / cellSize, strokeDasharray: "6 4", strokeLinecap: "round", strokeLinejoin: "round", fill: "none", opacity: "1.0", vectorEffect: "non-scaling-stroke" })));
125
+ });
126
+ })),
127
+ cages.map((cageInfo, index) => {
128
+ const { cage, currentSum, isComplete, isValid } = cageInfo;
129
+ const position = getTopLeftPosition(cage.cellIds, log, numRows, numColumns);
130
+ return (React.createElement(CageSumIndicator, { key: /* c8 ignore next 1 - defense in depth */ cage.id ?? index, cage: cage, currentSum: currentSum, isComplete: isComplete, isValid: isValid, position: position }));
131
+ })));
132
+ };
133
+ //# sourceMappingURL=CageOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CageOverlay.js","sourceRoot":"","sources":["../../src/components/CageOverlay.tsx"],"names":[],"mappings":"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","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 React, { useMemo, useEffect } from 'react';\nimport { CellId, parseCellId } from '@fgv/ts-sudoku-lib';\nimport { ICageOverlayProps } from '../types';\nimport { CageSumIndicator } from './CageSumIndicator';\nimport { CagePatternManager } from '../utils/CagePatternManager';\nimport { CageLookupManager } from '../utils/CageLookupManager';\nimport { useDiagnosticLogger } from '../contexts/DiagnosticLoggerContext';\nimport { Logging } from '@fgv/ts-utils';\n\n/**\n * Helper to get cell position from CellId\n */\nfunction getTopLeftPosition(\n cellIds: CellId[],\n log: Logging.LogReporter<unknown, unknown>,\n numRows: number,\n numColumns: number\n): { top: number; left: number } {\n if (cellIds.length === 0) return { top: 0, left: 0 };\n\n const positions = cellIds.map((cellId) => {\n const parsed = parseCellId(cellId);\n if (parsed && parsed.row >= 0 && parsed.row < numRows && parsed.col >= 0 && parsed.col < numColumns) {\n return parsed;\n }\n // Fallback - should not happen with valid CellIds\n log.warn(`Invalid CellId format: ${cellId}`);\n return { row: 0, col: 0 };\n });\n\n // Find the top-left most cell\n let minRow = positions[0].row;\n let minCol = positions[0].col;\n\n positions.forEach(({ row, col }) => {\n if (row < minRow || (row === minRow && col < minCol)) {\n minRow = row;\n minCol = col;\n }\n });\n\n // Convert grid coordinates to percentage-based positioning\n const cellWidthPercent = 100 / numColumns;\n const cellHeightPercent = 100 / numRows;\n\n return {\n top: minRow * cellHeightPercent + 0.5, // Small offset from corner\n left: minCol * cellWidthPercent + 0.5 // Small offset from corner\n };\n}\n\n/**\n * Component for rendering cage boundaries and sum indicators in Killer Sudoku\n * @public\n */\nexport const CageOverlay: React.FC<ICageOverlayProps> = ({\n cages,\n gridSize,\n cellSize,\n numRows = 9,\n numColumns = 9,\n className\n}) => {\n const log = useDiagnosticLogger();\n\n // Initialize managers once\n const patternManager = useMemo(() => new CagePatternManager(), []);\n const lookupManager = useMemo(() => CageLookupManager.getInstance(), []);\n\n // Debug logging\n useEffect(() => {\n log.info('CageOverlay rendered', {\n cageCount: cages.length,\n gridSize,\n cellSize,\n cages: cages.map((c) => ({ id: c.cage.id, cellIds: c.cage.cellIds }))\n });\n }, [cages, gridSize, cellSize, log]);\n\n // Calculate SVG viewBox and class names\n const viewBox = `0 0 ${gridSize.width} ${gridSize.height}`;\n\n const overlayClasses = useMemo(() => {\n const classes = ['cage-overlay'];\n if (className) classes.push(className);\n return classes.join(' ');\n }, [className]);\n\n return (\n <div\n className={`\n ${overlayClasses}\n absolute inset-0 w-full h-full pointer-events-none\n `}\n style={{ zIndex: 1000 }}\n data-testid=\"cage-overlay\"\n >\n {/* SVG for cage boundaries using connected border system */}\n <svg\n width=\"100%\"\n height=\"100%\"\n viewBox={viewBox}\n className=\"absolute inset-0\"\n preserveAspectRatio=\"none\"\n >\n {/* Render connected cage borders using two-stage lookup */}\n {cages.map((cageInfo, index) => {\n const { cage, isHighlighted, isValid } = cageInfo;\n\n // Build occupied cells set for this cage\n const occupiedCells = patternManager.buildOccupiedCellsSet(cage.cellIds);\n\n // Render each cell with connected borders\n return cage.cellIds.map((cellId, cellIndex) => {\n // Parse cell position using centralized function\n const parsed = parseCellId(cellId);\n let row = 0,\n col = 0;\n\n if (\n parsed &&\n parsed.row >= 0 &&\n parsed.row < numRows &&\n parsed.col >= 0 &&\n parsed.col < numColumns\n ) {\n row = parsed.row;\n col = parsed.col;\n } else {\n log.warn(`Invalid CellId format: ${cellId}`);\n }\n\n const x = col * cellSize;\n const y = row * cellSize;\n\n // Analyze neighbors and get pattern\n const neighbors = patternManager.analyzeNeighbors(cellId, occupiedCells);\n const neighborPattern = lookupManager.neighborsToPattern(neighbors);\n const pathData = lookupManager.getPatternSVG(neighborPattern);\n\n // Skip if no path data\n if (!pathData) {\n return null;\n }\n\n // Render connected border pattern\n return (\n <g\n key={/* c8 ignore next 1 - defense in depth */ `${cage.id ?? index}-${cellIndex}`}\n transform={`translate(${x}, ${y}) scale(${cellSize})`}\n >\n <path\n d={pathData}\n stroke={isHighlighted ? '#1e40af' : isValid ? '#2563eb' : '#dc2626'}\n strokeWidth={0.8 / cellSize}\n strokeDasharray=\"6 4\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n fill=\"none\"\n opacity=\"1.0\"\n vectorEffect=\"non-scaling-stroke\"\n />\n </g>\n );\n });\n })}\n </svg>\n\n {/* Sum indicators */}\n {cages.map((cageInfo, index) => {\n const { cage, currentSum, isComplete, isValid } = cageInfo;\n const position = getTopLeftPosition(cage.cellIds, log, numRows, numColumns);\n\n return (\n <CageSumIndicator\n key={/* c8 ignore next 1 - defense in depth */ cage.id ?? index}\n cage={cage}\n currentSum={currentSum}\n isComplete={isComplete}\n isValid={isValid}\n position={position}\n />\n );\n })}\n </div>\n );\n};\n"]}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { ICageSumIndicatorProps } from '../types';
3
+ /**
4
+ * Component for displaying the target sum of a cage in Killer Sudoku
5
+ * @public
6
+ */
7
+ export declare const CageSumIndicator: React.FC<ICageSumIndicatorProps>;
8
+ //# sourceMappingURL=CageSumIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CageSumIndicator.d.ts","sourceRoot":"","sources":["../../src/components/CageSumIndicator.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA0D7D,CAAC"}