@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,140 @@
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, { useCallback, useMemo, useState } from 'react';
25
+ import { useResponsiveLayout } from '../hooks/useResponsiveLayout';
26
+ /**
27
+ * Control panel for grid-wide operations
28
+ * @public
29
+ */
30
+ export const SudokuControls = ({ canUndo, canRedo, canReset, isValid, isSolved, onUndo, onRedo, onReset, onExport, className }) => {
31
+ const [showResetConfirm, setShowResetConfirm] = useState(false);
32
+ const responsiveLayout = useResponsiveLayout();
33
+ // Handle reset with confirmation
34
+ const handleResetClick = useCallback(() => {
35
+ if (showResetConfirm) {
36
+ onReset();
37
+ setShowResetConfirm(false);
38
+ }
39
+ else {
40
+ setShowResetConfirm(true);
41
+ // Auto-hide confirmation after 3 seconds
42
+ setTimeout(() => setShowResetConfirm(false), 3000);
43
+ }
44
+ }, [showResetConfirm, onReset]);
45
+ // Cancel reset confirmation
46
+ const handleCancelReset = useCallback(() => {
47
+ setShowResetConfirm(false);
48
+ }, []);
49
+ // Calculate control classes
50
+ const controlClasses = useMemo(() => {
51
+ const classes = ['sudoku-controls'];
52
+ if (className)
53
+ classes.push(className);
54
+ return classes.join(' ');
55
+ }, [className]);
56
+ // Button base styles
57
+ const buttonStyle = {
58
+ padding: '8px 16px',
59
+ margin: '4px',
60
+ border: '1px solid #ddd',
61
+ borderRadius: '4px',
62
+ backgroundColor: '#fff',
63
+ cursor: 'pointer',
64
+ fontSize: '14px',
65
+ fontWeight: 'bold'
66
+ };
67
+ const disabledButtonStyle = {
68
+ ...buttonStyle,
69
+ backgroundColor: '#f5f5f5',
70
+ color: '#999',
71
+ cursor: 'not-allowed'
72
+ };
73
+ // Removed unused primaryButtonStyle variable
74
+ const dangerButtonStyle = {
75
+ ...buttonStyle,
76
+ backgroundColor: '#f44336',
77
+ color: '#fff',
78
+ border: '1px solid #d32f2f'
79
+ };
80
+ const successButtonStyle = {
81
+ ...buttonStyle,
82
+ backgroundColor: '#4caf50',
83
+ color: '#fff',
84
+ border: '1px solid #388e3c'
85
+ };
86
+ // Calculate if we should use compact layout
87
+ const isCompactMode = responsiveLayout.deviceType === 'mobile' &&
88
+ (responsiveLayout.keypadLayoutMode === 'side-by-side' || responsiveLayout.keypadLayoutMode === 'stacked');
89
+ return (React.createElement("div", { className: controlClasses, "data-testid": "sudoku-controls" },
90
+ React.createElement("div", { style: {
91
+ display: 'flex',
92
+ flexDirection: isCompactMode ? 'row' : 'column',
93
+ alignItems: 'center',
94
+ justifyContent: 'center',
95
+ gap: isCompactMode ? '8px' : '16px',
96
+ padding: isCompactMode ? '8px' : '16px',
97
+ border: '1px solid #ddd',
98
+ borderRadius: '8px',
99
+ backgroundColor: '#fafafa',
100
+ flexWrap: isCompactMode ? 'wrap' : 'nowrap'
101
+ } },
102
+ React.createElement("div", { style: { display: 'flex', gap: '8px' } },
103
+ React.createElement("button", { type: "button", onClick: onUndo, disabled: !canUndo, style: canUndo ? buttonStyle : disabledButtonStyle, "data-testid": "undo-button", title: "Undo last move" }, "\u21B6 Undo"),
104
+ React.createElement("button", { type: "button", onClick: onRedo, disabled: !canRedo, style: canRedo ? buttonStyle : disabledButtonStyle, "data-testid": "redo-button", title: "Redo last undone move" }, "\u21B7 Redo")),
105
+ !showResetConfirm ? (React.createElement("button", { type: "button", onClick: handleResetClick, disabled: !canReset, style: canReset ? dangerButtonStyle : disabledButtonStyle, "data-testid": "reset-button", title: "Clear all entries" }, "\uD83D\uDDD1\uFE0F Reset Puzzle")) : (React.createElement("div", { style: {
106
+ display: 'flex',
107
+ flexDirection: isCompactMode ? 'row' : 'column',
108
+ alignItems: 'center',
109
+ gap: '8px'
110
+ } },
111
+ !isCompactMode && (React.createElement("div", { style: { fontSize: '12px', color: '#666', textAlign: 'center' } }, "Are you sure? This will clear all entries.")),
112
+ React.createElement("div", { style: { display: 'flex', gap: '8px' } },
113
+ React.createElement("button", { type: "button", onClick: handleResetClick, style: dangerButtonStyle, "data-testid": "confirm-reset-button", title: isCompactMode ? 'Are you sure? This will clear all entries.' : undefined }, "Yes, Reset"),
114
+ React.createElement("button", { type: "button", onClick: handleCancelReset, style: buttonStyle, "data-testid": "cancel-reset-button" }, "Cancel")))),
115
+ React.createElement("button", { type: "button", onClick: onExport, style: successButtonStyle, "data-testid": "export-button", title: "Export puzzle in compatible format" }, "\uD83D\uDCE4 Export Puzzle"),
116
+ !(responsiveLayout.deviceType === 'mobile' &&
117
+ (responsiveLayout.keypadLayoutMode === 'side-by-side' ||
118
+ responsiveLayout.keypadLayoutMode === 'stacked')) && (React.createElement("div", { style: {
119
+ fontSize: '12px',
120
+ color: '#666',
121
+ textAlign: 'center',
122
+ maxWidth: '300px',
123
+ lineHeight: '1.4'
124
+ } },
125
+ React.createElement("div", { style: { fontWeight: 'bold', marginBottom: '4px' } }, "Instructions:"),
126
+ React.createElement("div", null, "\u2022 Click a cell to select it"),
127
+ React.createElement("div", null, "\u2022 Type 1-9 to enter numbers"),
128
+ React.createElement("div", null, "\u2022 Press Delete/Backspace to clear"),
129
+ React.createElement("div", null, "\u2022 Use arrow keys to navigate"))),
130
+ React.createElement("div", { style: {
131
+ padding: '8px 12px',
132
+ borderRadius: '4px',
133
+ fontSize: '12px',
134
+ fontWeight: 'bold',
135
+ backgroundColor: isSolved ? '#e8f5e8' : isValid ? '#e3f2fd' : '#ffebee',
136
+ color: isSolved ? '#2e7d32' : isValid ? '#1565c0' : '#c62828',
137
+ border: `1px solid ${isSolved ? '#4caf50' : isValid ? '#2196f3' : '#f44336'}`
138
+ } }, isSolved ? '✅ Solved!' : isValid ? '✓ Valid' : '⚠ Has Errors'))));
139
+ };
140
+ //# sourceMappingURL=SudokuControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SudokuControls.js","sourceRoot":"","sources":["../../src/components/SudokuControls.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, { useCallback, useMemo, useState } from 'react';\nimport { ISudokuControlsProps } from '../types';\nimport { useResponsiveLayout } from '../hooks/useResponsiveLayout';\n\n/**\n * Control panel for grid-wide operations\n * @public\n */\nexport const SudokuControls: React.FC<ISudokuControlsProps> = ({\n canUndo,\n canRedo,\n canReset,\n isValid,\n isSolved,\n onUndo,\n onRedo,\n onReset,\n onExport,\n className\n}) => {\n const [showResetConfirm, setShowResetConfirm] = useState(false);\n const responsiveLayout = useResponsiveLayout();\n\n // Handle reset with confirmation\n const handleResetClick = useCallback(() => {\n if (showResetConfirm) {\n onReset();\n setShowResetConfirm(false);\n } else {\n setShowResetConfirm(true);\n // Auto-hide confirmation after 3 seconds\n setTimeout(() => setShowResetConfirm(false), 3000);\n }\n }, [showResetConfirm, onReset]);\n\n // Cancel reset confirmation\n const handleCancelReset = useCallback(() => {\n setShowResetConfirm(false);\n }, []);\n\n // Calculate control classes\n const controlClasses = useMemo(() => {\n const classes = ['sudoku-controls'];\n if (className) classes.push(className);\n return classes.join(' ');\n }, [className]);\n\n // Button base styles\n const buttonStyle = {\n padding: '8px 16px',\n margin: '4px',\n border: '1px solid #ddd',\n borderRadius: '4px',\n backgroundColor: '#fff',\n cursor: 'pointer',\n fontSize: '14px',\n fontWeight: 'bold'\n };\n\n const disabledButtonStyle = {\n ...buttonStyle,\n backgroundColor: '#f5f5f5',\n color: '#999',\n cursor: 'not-allowed'\n };\n\n // Removed unused primaryButtonStyle variable\n\n const dangerButtonStyle = {\n ...buttonStyle,\n backgroundColor: '#f44336',\n color: '#fff',\n border: '1px solid #d32f2f'\n };\n\n const successButtonStyle = {\n ...buttonStyle,\n backgroundColor: '#4caf50',\n color: '#fff',\n border: '1px solid #388e3c'\n };\n\n // Calculate if we should use compact layout\n const isCompactMode =\n responsiveLayout.deviceType === 'mobile' &&\n (responsiveLayout.keypadLayoutMode === 'side-by-side' || responsiveLayout.keypadLayoutMode === 'stacked');\n\n return (\n <div className={controlClasses} data-testid=\"sudoku-controls\">\n <div\n style={{\n display: 'flex',\n flexDirection: isCompactMode ? 'row' : 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: isCompactMode ? '8px' : '16px',\n padding: isCompactMode ? '8px' : '16px',\n border: '1px solid #ddd',\n borderRadius: '8px',\n backgroundColor: '#fafafa',\n flexWrap: isCompactMode ? 'wrap' : 'nowrap'\n }}\n >\n {/* Undo/Redo controls */}\n <div style={{ display: 'flex', gap: '8px' }}>\n <button\n type=\"button\"\n onClick={onUndo}\n disabled={!canUndo}\n style={canUndo ? buttonStyle : disabledButtonStyle}\n data-testid=\"undo-button\"\n title=\"Undo last move\"\n >\n ↶ Undo\n </button>\n <button\n type=\"button\"\n onClick={onRedo}\n disabled={!canRedo}\n style={canRedo ? buttonStyle : disabledButtonStyle}\n data-testid=\"redo-button\"\n title=\"Redo last undone move\"\n >\n ↷ Redo\n </button>\n </div>\n\n {/* Reset control with confirmation */}\n {!showResetConfirm ? (\n <button\n type=\"button\"\n onClick={handleResetClick}\n disabled={!canReset}\n style={canReset ? dangerButtonStyle : disabledButtonStyle}\n data-testid=\"reset-button\"\n title=\"Clear all entries\"\n >\n 🗑️ Reset Puzzle\n </button>\n ) : (\n <div\n style={{\n display: 'flex',\n flexDirection: isCompactMode ? 'row' : 'column',\n alignItems: 'center',\n gap: '8px'\n }}\n >\n {!isCompactMode && (\n <div style={{ fontSize: '12px', color: '#666', textAlign: 'center' }}>\n Are you sure? This will clear all entries.\n </div>\n )}\n <div style={{ display: 'flex', gap: '8px' }}>\n <button\n type=\"button\"\n onClick={handleResetClick}\n style={dangerButtonStyle}\n data-testid=\"confirm-reset-button\"\n title={isCompactMode ? 'Are you sure? This will clear all entries.' : undefined}\n >\n Yes, Reset\n </button>\n <button\n type=\"button\"\n onClick={handleCancelReset}\n style={buttonStyle}\n data-testid=\"cancel-reset-button\"\n >\n Cancel\n </button>\n </div>\n </div>\n )}\n\n {/* Export control */}\n <button\n type=\"button\"\n onClick={onExport}\n style={successButtonStyle}\n data-testid=\"export-button\"\n title=\"Export puzzle in compatible format\"\n >\n 📤 Export Puzzle\n </button>\n\n {/* Instructions - hide on mobile with visible keypads */}\n {!(\n responsiveLayout.deviceType === 'mobile' &&\n (responsiveLayout.keypadLayoutMode === 'side-by-side' ||\n responsiveLayout.keypadLayoutMode === 'stacked')\n ) && (\n <div\n style={{\n fontSize: '12px',\n color: '#666',\n textAlign: 'center',\n maxWidth: '300px',\n lineHeight: '1.4'\n }}\n >\n <div style={{ fontWeight: 'bold', marginBottom: '4px' }}>Instructions:</div>\n <div>• Click a cell to select it</div>\n <div>• Type 1-9 to enter numbers</div>\n <div>• Press Delete/Backspace to clear</div>\n <div>• Use arrow keys to navigate</div>\n </div>\n )}\n\n {/* Status indicator */}\n <div\n style={{\n padding: '8px 12px',\n borderRadius: '4px',\n fontSize: '12px',\n fontWeight: 'bold',\n backgroundColor: isSolved ? '#e8f5e8' : isValid ? '#e3f2fd' : '#ffebee',\n color: isSolved ? '#2e7d32' : isValid ? '#1565c0' : '#c62828',\n border: `1px solid ${isSolved ? '#4caf50' : isValid ? '#2196f3' : '#f44336'}`\n }}\n >\n {isSolved ? '✅ Solved!' : isValid ? '✓ Valid' : '⚠ Has Errors'}\n </div>\n </div>\n </div>\n );\n};\n"]}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { ISudokuGridProps } from '../types';
3
+ /**
4
+ * Grid component that renders the 9x9 Sudoku grid with proper visual structure
5
+ * @public
6
+ */
7
+ export declare const SudokuGrid: React.FC<ISudokuGridProps>;
8
+ //# sourceMappingURL=SudokuGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SudokuGrid.d.ts","sourceRoot":"","sources":["../../src/components/SudokuGrid.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAEpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAI5C;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAsPjD,CAAC"}
@@ -0,0 +1,177 @@
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, { useCallback, useMemo } from 'react';
25
+ import { SudokuCell } from './SudokuCell';
26
+ import { CageOverlay } from './CageOverlay';
27
+ /**
28
+ * Grid component that renders the 9x9 Sudoku grid with proper visual structure
29
+ * @public
30
+ */
31
+ export const SudokuGrid = ({ numRows, numColumns, cells, cages, selectedCell, selectedCells, inputMode, puzzleType, puzzleDimensions, onCellSelect, onLongPressToggle, onCellValueChange, onNoteToggle, onClearAllNotes, onNavigate, onDragOver, onDragEnd, isDragging, className }) => {
32
+ // Handle keyboard navigation
33
+ const handleKeyDown = useCallback((event) => {
34
+ if (!selectedCell)
35
+ return;
36
+ const { key } = event;
37
+ let direction = null;
38
+ switch (key) {
39
+ case 'ArrowUp':
40
+ direction = 'up';
41
+ break;
42
+ case 'ArrowDown':
43
+ direction = 'down';
44
+ break;
45
+ case 'ArrowLeft':
46
+ direction = 'left';
47
+ break;
48
+ case 'ArrowRight':
49
+ direction = 'right';
50
+ break;
51
+ default:
52
+ return; // Let the cell handle number/delete keys
53
+ }
54
+ if (direction) {
55
+ onNavigate(direction);
56
+ event.preventDefault();
57
+ }
58
+ }, [selectedCell, onNavigate]);
59
+ // Create cell select handler
60
+ const createCellSelectHandler = useCallback((cellId) => {
61
+ return (event) => onCellSelect(cellId, event);
62
+ }, [onCellSelect]);
63
+ // Create cell value change handler
64
+ const createCellValueChangeHandler = useCallback((cellId) => {
65
+ return (value) => onCellValueChange(cellId, value);
66
+ }, [onCellValueChange]);
67
+ // Create note toggle handler
68
+ const createNoteToggleHandler = useCallback((cellId) => {
69
+ return (note) => onNoteToggle(cellId, note);
70
+ }, [onNoteToggle]);
71
+ // Create clear all notes handler
72
+ const createClearAllNotesHandler = useCallback((cellId) => {
73
+ return () => onClearAllNotes(cellId);
74
+ }, [onClearAllNotes]);
75
+ // Create long press toggle handler
76
+ const createLongPressToggleHandler = useCallback((cellId) => {
77
+ return onLongPressToggle
78
+ ? (event) => onLongPressToggle(cellId, event)
79
+ : undefined;
80
+ }, [onLongPressToggle]);
81
+ // Create drag over handler
82
+ const createDragOverHandler = useCallback((cellId) => {
83
+ return onDragOver ? () => onDragOver(cellId) : undefined;
84
+ }, [onDragOver]);
85
+ // Calculate grid classes
86
+ const gridClasses = useMemo(() => {
87
+ const classes = ['sudoku-grid'];
88
+ if (className)
89
+ classes.push(className);
90
+ return classes.join(' ');
91
+ }, [className]);
92
+ // Calculate grid template styles for dynamic grid sizes
93
+ const gridStyles = useMemo(() => {
94
+ // Base cell size in pixels (for 9x9 grid, this would be 50px, 60px, 70px at different breakpoints)
95
+ const baseCellSizePx = 50; // Base size for small screens
96
+ // Calculate width based on number of columns
97
+ // We use the max of rows/columns to ensure square cells
98
+ const maxDimension = Math.max(numRows, numColumns);
99
+ const width = maxDimension * baseCellSizePx;
100
+ return {
101
+ gridTemplateColumns: `repeat(${numColumns}, 1fr)`,
102
+ gridTemplateRows: `repeat(${numRows}, 1fr)`,
103
+ width: `min(${width}px, 100%)`,
104
+ maxWidth: `${width}px`
105
+ };
106
+ }, [numRows, numColumns]);
107
+ // Calculate border classes based on puzzle type
108
+ const borderClasses = useMemo(() => {
109
+ //if (puzzleType === 'killer') {
110
+ // Minimal borders for Killer Sudoku to let cage borders stand out
111
+ //return 'gap-px border border-2 border-gray-300 bg-gray-300';
112
+ //}
113
+ // Standard thick borders for other puzzle types
114
+ return 'border-2 border-black bg-black';
115
+ }, [puzzleType]);
116
+ // Sort cells by row and column for proper display order
117
+ const sortedCells = useMemo(() => {
118
+ return [...cells].sort((a, b) => {
119
+ if (a.row !== b.row)
120
+ return a.row - b.row;
121
+ return a.column - b.column;
122
+ });
123
+ }, [cells]);
124
+ // Calculate grid dimensions for overlays
125
+ const gridDimensions = useMemo(() => {
126
+ // Base cell size in grid units - we'll scale this with CSS
127
+ const baseCellSize = 1;
128
+ return {
129
+ cellSize: baseCellSize,
130
+ gridSize: {
131
+ width: numColumns * baseCellSize,
132
+ height: numRows * baseCellSize
133
+ }
134
+ };
135
+ }, [numRows, numColumns]);
136
+ // Render diagonal lines for Sudoku X puzzles
137
+ const renderDiagonalLines = () => {
138
+ if (puzzleType !== 'sudoku-x')
139
+ return null;
140
+ return (React.createElement("div", { className: "absolute inset-0 w-full h-full pointer-events-none", style: {
141
+ background: `
142
+ linear-gradient(45deg, transparent 49%, rgba(156, 163, 175, 0.15) 49.5%, rgba(156, 163, 175, 0.15) 50.5%, transparent 51%),
143
+ linear-gradient(-45deg, transparent 49%, rgba(156, 163, 175, 0.15) 49.5%, rgba(156, 163, 175, 0.15) 50.5%, transparent 51%)
144
+ `,
145
+ zIndex: 1
146
+ } }));
147
+ };
148
+ // Render cage overlay for Killer Sudoku
149
+ const renderCageOverlay = () => {
150
+ if (puzzleType !== 'killer-sudoku' || !cages || cages.length === 0)
151
+ return null;
152
+ return (React.createElement(CageOverlay, { cages: cages, gridSize: gridDimensions.gridSize, cellSize: gridDimensions.cellSize, numRows: numRows, numColumns: numColumns }));
153
+ };
154
+ return (React.createElement("div", { className: `
155
+ ${gridClasses}
156
+ relative
157
+ grid ${puzzleType === 'killer-sudoku' ? 'gap-0' : 'gap-0'}
158
+ ${borderClasses}
159
+ mx-auto outline-none
160
+ aspect-square
161
+ `, style: gridStyles, onKeyDown: handleKeyDown, onMouseUp: onDragEnd, onTouchEnd: onDragEnd, role: "grid", "aria-label": "Sudoku puzzle entry grid", tabIndex: 0, "data-testid": "sudoku-grid" },
162
+ renderDiagonalLines(),
163
+ renderCageOverlay(),
164
+ sortedCells.map((cellInfo) => {
165
+ const isPrimarySelected = selectedCell === cellInfo.id;
166
+ const isInMultiSelection = selectedCells.includes(cellInfo.id);
167
+ return (React.createElement(SudokuCell, { key: cellInfo.id, cellInfo: cellInfo, isSelected: isPrimarySelected || isInMultiSelection, inputMode: inputMode, puzzleDimensions: puzzleDimensions
168
+ ? {
169
+ numRows,
170
+ numColumns,
171
+ cageHeight: puzzleDimensions.cageHeightInCells,
172
+ cageWidth: puzzleDimensions.cageWidthInCells
173
+ }
174
+ : undefined, onSelect: createCellSelectHandler(cellInfo.id), onLongPressToggle: createLongPressToggleHandler(cellInfo.id), onValueChange: createCellValueChangeHandler(cellInfo.id), onNoteToggle: createNoteToggleHandler(cellInfo.id), onClearAllNotes: createClearAllNotesHandler(cellInfo.id), onDragOver: createDragOverHandler(cellInfo.id), className: isInMultiSelection && !isPrimarySelected ? 'sudoku-cell--multi-selected' : undefined }));
175
+ })));
176
+ };
177
+ //# sourceMappingURL=SudokuGrid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SudokuGrid.js","sourceRoot":"","sources":["../../src/components/SudokuGrid.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, { useCallback, useMemo } from 'react';\nimport { CellId, NavigationDirection } from '@fgv/ts-sudoku-lib';\nimport { ISudokuGridProps } from '../types';\nimport { SudokuCell } from './SudokuCell';\nimport { CageOverlay } from './CageOverlay';\n\n/**\n * Grid component that renders the 9x9 Sudoku grid with proper visual structure\n * @public\n */\nexport const SudokuGrid: React.FC<ISudokuGridProps> = ({\n numRows,\n numColumns,\n cells,\n cages,\n selectedCell,\n selectedCells,\n inputMode,\n puzzleType,\n puzzleDimensions,\n onCellSelect,\n onLongPressToggle,\n onCellValueChange,\n onNoteToggle,\n onClearAllNotes,\n onNavigate,\n onDragOver,\n onDragEnd,\n isDragging,\n className\n}) => {\n // Handle keyboard navigation\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (!selectedCell) return;\n\n const { key } = event;\n let direction: NavigationDirection | null = null;\n\n switch (key) {\n case 'ArrowUp':\n direction = 'up';\n break;\n case 'ArrowDown':\n direction = 'down';\n break;\n case 'ArrowLeft':\n direction = 'left';\n break;\n case 'ArrowRight':\n direction = 'right';\n break;\n default:\n return; // Let the cell handle number/delete keys\n }\n\n if (direction) {\n onNavigate(direction);\n event.preventDefault();\n }\n },\n [selectedCell, onNavigate]\n );\n\n // Create cell select handler\n const createCellSelectHandler = useCallback(\n (cellId: CellId) => {\n return (event?: React.MouseEvent) => onCellSelect(cellId, event);\n },\n [onCellSelect]\n );\n\n // Create cell value change handler\n const createCellValueChangeHandler = useCallback(\n (cellId: CellId) => {\n return (value: number | undefined) => onCellValueChange(cellId, value);\n },\n [onCellValueChange]\n );\n\n // Create note toggle handler\n const createNoteToggleHandler = useCallback(\n (cellId: CellId) => {\n return (note: number) => onNoteToggle(cellId, note);\n },\n [onNoteToggle]\n );\n\n // Create clear all notes handler\n const createClearAllNotesHandler = useCallback(\n (cellId: CellId) => {\n return () => onClearAllNotes(cellId);\n },\n [onClearAllNotes]\n );\n\n // Create long press toggle handler\n const createLongPressToggleHandler = useCallback(\n (cellId: CellId) => {\n return onLongPressToggle\n ? (event: React.TouchEvent | React.MouseEvent) => onLongPressToggle(cellId, event)\n : undefined;\n },\n [onLongPressToggle]\n );\n\n // Create drag over handler\n const createDragOverHandler = useCallback(\n (cellId: CellId) => {\n return onDragOver ? () => onDragOver(cellId) : undefined;\n },\n [onDragOver]\n );\n\n // Calculate grid classes\n const gridClasses = useMemo(() => {\n const classes = ['sudoku-grid'];\n if (className) classes.push(className);\n return classes.join(' ');\n }, [className]);\n\n // Calculate grid template styles for dynamic grid sizes\n const gridStyles = useMemo(() => {\n // Base cell size in pixels (for 9x9 grid, this would be 50px, 60px, 70px at different breakpoints)\n const baseCellSizePx = 50; // Base size for small screens\n\n // Calculate width based on number of columns\n // We use the max of rows/columns to ensure square cells\n const maxDimension = Math.max(numRows, numColumns);\n const width = maxDimension * baseCellSizePx;\n\n return {\n gridTemplateColumns: `repeat(${numColumns}, 1fr)`,\n gridTemplateRows: `repeat(${numRows}, 1fr)`,\n width: `min(${width}px, 100%)`,\n maxWidth: `${width}px`\n };\n }, [numRows, numColumns]);\n\n // Calculate border classes based on puzzle type\n const borderClasses = useMemo(() => {\n //if (puzzleType === 'killer') {\n // Minimal borders for Killer Sudoku to let cage borders stand out\n //return 'gap-px border border-2 border-gray-300 bg-gray-300';\n //}\n // Standard thick borders for other puzzle types\n return 'border-2 border-black bg-black';\n }, [puzzleType]);\n\n // Sort cells by row and column for proper display order\n const sortedCells = useMemo(() => {\n return [...cells].sort((a, b) => {\n if (a.row !== b.row) return a.row - b.row;\n return a.column - b.column;\n });\n }, [cells]);\n\n // Calculate grid dimensions for overlays\n const gridDimensions = useMemo(() => {\n // Base cell size in grid units - we'll scale this with CSS\n const baseCellSize = 1;\n return {\n cellSize: baseCellSize,\n gridSize: {\n width: numColumns * baseCellSize,\n height: numRows * baseCellSize\n }\n };\n }, [numRows, numColumns]);\n\n // Render diagonal lines for Sudoku X puzzles\n const renderDiagonalLines = (): React.ReactNode => {\n if (puzzleType !== 'sudoku-x') return null;\n\n return (\n <div\n className=\"absolute inset-0 w-full h-full pointer-events-none\"\n style={{\n background: `\n linear-gradient(45deg, transparent 49%, rgba(156, 163, 175, 0.15) 49.5%, rgba(156, 163, 175, 0.15) 50.5%, transparent 51%),\n linear-gradient(-45deg, transparent 49%, rgba(156, 163, 175, 0.15) 49.5%, rgba(156, 163, 175, 0.15) 50.5%, transparent 51%)\n `,\n zIndex: 1\n }}\n />\n );\n };\n\n // Render cage overlay for Killer Sudoku\n const renderCageOverlay = (): React.ReactNode => {\n if (puzzleType !== 'killer-sudoku' || !cages || cages.length === 0) return null;\n\n return (\n <CageOverlay\n cages={cages}\n gridSize={gridDimensions.gridSize}\n cellSize={gridDimensions.cellSize}\n numRows={numRows}\n numColumns={numColumns}\n />\n );\n };\n\n return (\n <div\n className={`\n ${gridClasses}\n relative\n grid ${puzzleType === 'killer-sudoku' ? 'gap-0' : 'gap-0'}\n ${borderClasses}\n mx-auto outline-none\n aspect-square\n `}\n style={gridStyles}\n onKeyDown={handleKeyDown}\n onMouseUp={onDragEnd}\n onTouchEnd={onDragEnd}\n role=\"grid\"\n aria-label=\"Sudoku puzzle entry grid\"\n tabIndex={0}\n data-testid=\"sudoku-grid\"\n >\n {renderDiagonalLines()}\n {renderCageOverlay()}\n {sortedCells.map((cellInfo) => {\n const isPrimarySelected = selectedCell === cellInfo.id;\n const isInMultiSelection = selectedCells.includes(cellInfo.id);\n\n return (\n <SudokuCell\n key={cellInfo.id}\n cellInfo={cellInfo}\n isSelected={isPrimarySelected || isInMultiSelection}\n inputMode={inputMode}\n puzzleDimensions={\n puzzleDimensions\n ? {\n numRows,\n numColumns,\n cageHeight: puzzleDimensions.cageHeightInCells,\n cageWidth: puzzleDimensions.cageWidthInCells\n }\n : undefined\n }\n onSelect={createCellSelectHandler(cellInfo.id)}\n onLongPressToggle={createLongPressToggleHandler(cellInfo.id)}\n onValueChange={createCellValueChangeHandler(cellInfo.id)}\n onNoteToggle={createNoteToggleHandler(cellInfo.id)}\n onClearAllNotes={createClearAllNotesHandler(cellInfo.id)}\n onDragOver={createDragOverHandler(cellInfo.id)}\n className={isInMultiSelection && !isPrimarySelected ? 'sudoku-cell--multi-selected' : undefined}\n />\n );\n })}\n </div>\n );\n};\n"]}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { ISudokuGridEntryProps } from '../types';
3
+ /**
4
+ * Main container component that orchestrates puzzle entry
5
+ * @public
6
+ */
7
+ export declare const SudokuGridEntry: React.FC<ISudokuGridEntryProps>;
8
+ //# sourceMappingURL=SudokuGridEntry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SudokuGridEntry.d.ts","sourceRoot":"","sources":["../../src/components/SudokuGridEntry.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAEjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AASjD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAkkB3D,CAAC"}