@fgv/ts-sudoku-ui 5.1.0-2 → 5.1.0-21
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.
- package/eslint.config.js +18 -0
- package/lib/tsdoc-metadata.json +1 -1
- package/package.json +22 -21
- package/.test-failures-catalog.md +0 -470
- package/CHANGELOG.md +0 -11
- package/CSS_MODULES_MIGRATION_SUMMARY.md +0 -189
- package/dist/ts-sudoku-ui.d.ts +0 -668
- package/etc/ts-sudoku-ui.api.md +0 -481
- package/lib/test/fixtures/killerSudokuPuzzles.d.ts +0 -36
- package/lib/test/fixtures/killerSudokuPuzzles.d.ts.map +0 -1
- package/lib/test/fixtures/killerSudokuPuzzles.js +0 -57
- package/lib/test/fixtures/killerSudokuPuzzles.js.map +0 -1
- package/lib/test/unit/components/SudokuGridEntry.testHelpers.d.ts +0 -22
- package/lib/test/unit/components/SudokuGridEntry.testHelpers.d.ts.map +0 -1
- package/lib/test/unit/components/SudokuGridEntry.testHelpers.js +0 -116
- package/lib/test/unit/components/SudokuGridEntry.testHelpers.js.map +0 -1
- package/lib-commonjs/components/CageOverlay.js +0 -138
- package/lib-commonjs/components/CageOverlay.js.map +0 -1
- package/lib-commonjs/components/CageSumIndicator.js +0 -71
- package/lib-commonjs/components/CageSumIndicator.js.map +0 -1
- package/lib-commonjs/components/CombinationCard.js +0 -68
- package/lib-commonjs/components/CombinationCard.js.map +0 -1
- package/lib-commonjs/components/CombinationGrid.js +0 -56
- package/lib-commonjs/components/CombinationGrid.js.map +0 -1
- package/lib-commonjs/components/CompactControlRibbon.js +0 -146
- package/lib-commonjs/components/CompactControlRibbon.js.map +0 -1
- package/lib-commonjs/components/DualKeypad.js +0 -142
- package/lib-commonjs/components/DualKeypad.js.map +0 -1
- package/lib-commonjs/components/KillerCombinationsExplorer.js +0 -74
- package/lib-commonjs/components/KillerCombinationsExplorer.js.map +0 -1
- package/lib-commonjs/components/KillerCombinationsModal.js +0 -140
- package/lib-commonjs/components/KillerCombinationsModal.js.map +0 -1
- package/lib-commonjs/components/KillerCombinationsPanel.js +0 -84
- package/lib-commonjs/components/KillerCombinationsPanel.js.map +0 -1
- package/lib-commonjs/components/NumberKeypad.js +0 -186
- package/lib-commonjs/components/NumberKeypad.js.map +0 -1
- package/lib-commonjs/components/SudokuCell.js +0 -245
- package/lib-commonjs/components/SudokuCell.js.map +0 -1
- package/lib-commonjs/components/SudokuControls.js +0 -145
- package/lib-commonjs/components/SudokuControls.js.map +0 -1
- package/lib-commonjs/components/SudokuGrid.js +0 -182
- package/lib-commonjs/components/SudokuGrid.js.map +0 -1
- package/lib-commonjs/components/SudokuGridEntry.js +0 -378
- package/lib-commonjs/components/SudokuGridEntry.js.map +0 -1
- package/lib-commonjs/components/ValidationDisplay.js +0 -100
- package/lib-commonjs/components/ValidationDisplay.js.map +0 -1
- package/lib-commonjs/contexts/DiagnosticLoggerContext.js +0 -104
- package/lib-commonjs/contexts/DiagnosticLoggerContext.js.map +0 -1
- package/lib-commonjs/contexts/index.js +0 -32
- package/lib-commonjs/contexts/index.js.map +0 -1
- package/lib-commonjs/hooks/useCombinationElimination.js +0 -126
- package/lib-commonjs/hooks/useCombinationElimination.js.map +0 -1
- package/lib-commonjs/hooks/useKeyboardShortcut.js +0 -58
- package/lib-commonjs/hooks/useKeyboardShortcut.js.map +0 -1
- package/lib-commonjs/hooks/useKillerCombinations.js +0 -68
- package/lib-commonjs/hooks/useKillerCombinations.js.map +0 -1
- package/lib-commonjs/hooks/useLongPress.js +0 -72
- package/lib-commonjs/hooks/useLongPress.js.map +0 -1
- package/lib-commonjs/hooks/usePuzzleSession.js +0 -401
- package/lib-commonjs/hooks/usePuzzleSession.js.map +0 -1
- package/lib-commonjs/hooks/useResponsiveLayout.js +0 -142
- package/lib-commonjs/hooks/useResponsiveLayout.js.map +0 -1
- package/lib-commonjs/index.browser.js +0 -29
- package/lib-commonjs/index.browser.js.map +0 -1
- package/lib-commonjs/index.js +0 -73
- package/lib-commonjs/index.js.map +0 -1
- package/lib-commonjs/test/fixtures/killerSudokuPuzzles.js +0 -60
- package/lib-commonjs/test/fixtures/killerSudokuPuzzles.js.map +0 -1
- package/lib-commonjs/test/unit/components/SudokuGridEntry.testHelpers.js +0 -125
- package/lib-commonjs/test/unit/components/SudokuGridEntry.testHelpers.js.map +0 -1
- package/lib-commonjs/types/index.js +0 -26
- package/lib-commonjs/types/index.js.map +0 -1
- package/lib-commonjs/utils/CageLookupManager.js +0 -287
- package/lib-commonjs/utils/CageLookupManager.js.map +0 -1
- package/lib-commonjs/utils/CagePatternManager.js +0 -143
- package/lib-commonjs/utils/CagePatternManager.js.map +0 -1
- package/lib-commonjs/utils/puzzleDefinitionHelper.js +0 -103
- package/lib-commonjs/utils/puzzleDefinitionHelper.js.map +0 -1
|
@@ -1,104 +0,0 @@
|
|
|
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.useDiagnosticLogger = exports.DiagnosticLoggerProvider = exports.DiagnosticLoggerContext = exports.DefaultDiagnosticLogger = void 0;
|
|
27
|
-
const tslib_1 = require("tslib");
|
|
28
|
-
const react_1 = tslib_1.__importStar(require("react"));
|
|
29
|
-
const ts_utils_1 = require("@fgv/ts-utils");
|
|
30
|
-
/**
|
|
31
|
-
* Default diagnostic logger (no-op for production).
|
|
32
|
-
* @public
|
|
33
|
-
*/
|
|
34
|
-
exports.DefaultDiagnosticLogger = new ts_utils_1.Logging.LogReporter({
|
|
35
|
-
logger: new ts_utils_1.Logging.NoOpLogger()
|
|
36
|
-
});
|
|
37
|
-
/**
|
|
38
|
-
* React context for diagnostic logging.
|
|
39
|
-
* Provides access to diagnostic logger throughout the component tree.
|
|
40
|
-
* @public
|
|
41
|
-
*/
|
|
42
|
-
exports.DiagnosticLoggerContext = (0, react_1.createContext)(exports.DefaultDiagnosticLogger);
|
|
43
|
-
/**
|
|
44
|
-
* Provider component that makes diagnostic logger available to all child components.
|
|
45
|
-
*
|
|
46
|
-
* @example
|
|
47
|
-
* ```tsx
|
|
48
|
-
* // Basic usage with default no-op logger
|
|
49
|
-
* <DiagnosticLoggerProvider>
|
|
50
|
-
* <SudokuGrid />
|
|
51
|
-
* </DiagnosticLoggerProvider>
|
|
52
|
-
*
|
|
53
|
-
* // Console logging for development
|
|
54
|
-
* const consoleLogger = new Logging.LogReporter({
|
|
55
|
-
* logger: new Logging.ConsoleLogger('info')
|
|
56
|
-
* });
|
|
57
|
-
* <DiagnosticLoggerProvider logger={consoleLogger}>
|
|
58
|
-
* <SudokuGrid />
|
|
59
|
-
* </DiagnosticLoggerProvider>
|
|
60
|
-
*
|
|
61
|
-
* // In-memory logger for tests
|
|
62
|
-
* const testLogger = new Logging.LogReporter({
|
|
63
|
-
* logger: new Logging.InMemoryLogger('detail')
|
|
64
|
-
* });
|
|
65
|
-
* <DiagnosticLoggerProvider logger={testLogger}>
|
|
66
|
-
* <SudokuGrid />
|
|
67
|
-
* </DiagnosticLoggerProvider>
|
|
68
|
-
* ```
|
|
69
|
-
*
|
|
70
|
-
* @param props - Provider configuration
|
|
71
|
-
* @returns JSX provider element
|
|
72
|
-
* @public
|
|
73
|
-
*/
|
|
74
|
-
const DiagnosticLoggerProvider = ({ children, logger = exports.DefaultDiagnosticLogger }) => react_1.default.createElement(exports.DiagnosticLoggerContext.Provider, { value: logger }, children);
|
|
75
|
-
exports.DiagnosticLoggerProvider = DiagnosticLoggerProvider;
|
|
76
|
-
/**
|
|
77
|
-
* Hook to access the current diagnostic logger.
|
|
78
|
-
*
|
|
79
|
-
* Provides access to diagnostic logging for development and debugging.
|
|
80
|
-
*
|
|
81
|
-
* @example
|
|
82
|
-
* ```tsx
|
|
83
|
-
* function CageOverlay({ cages }: ICageOverlayProps) {
|
|
84
|
-
* const log = useDiagnosticLogger();
|
|
85
|
-
*
|
|
86
|
-
* useEffect(() => {
|
|
87
|
-
* log.info('CageOverlay rendered', {
|
|
88
|
-
* cageCount: cages.length,
|
|
89
|
-
* cages: cages.map((c) => ({ id: c.cage.id, cellIds: c.cage.cellIds }))
|
|
90
|
-
* });
|
|
91
|
-
* }, [cages, log]);
|
|
92
|
-
*
|
|
93
|
-
* return <div>...</div>;
|
|
94
|
-
* }
|
|
95
|
-
* ```
|
|
96
|
-
*
|
|
97
|
-
* @returns The current diagnostic logger
|
|
98
|
-
* @public
|
|
99
|
-
*/
|
|
100
|
-
const useDiagnosticLogger = () => {
|
|
101
|
-
return (0, react_1.useContext)(exports.DiagnosticLoggerContext);
|
|
102
|
-
};
|
|
103
|
-
exports.useDiagnosticLogger = useDiagnosticLogger;
|
|
104
|
-
//# sourceMappingURL=DiagnosticLoggerContext.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DiagnosticLoggerContext.js","sourceRoot":"","sources":["../../src/contexts/DiagnosticLoggerContext.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;;AAEH,uDAAoE;AACpE,4CAAwC;AAExC;;;GAGG;AACU,QAAA,uBAAuB,GAAiC,IAAI,kBAAO,CAAC,WAAW,CAAC;IAC3F,MAAM,EAAE,IAAI,kBAAO,CAAC,UAAU,EAAE;CACjC,CAAC,CAAC;AAEH;;;;GAIG;AACU,QAAA,uBAAuB,GAClC,IAAA,qBAAa,EAA+B,+BAAuB,CAAC,CAAC;AAavE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACI,MAAM,wBAAwB,GAA6C,CAAC,EACjF,QAAQ,EACR,MAAM,GAAG,+BAAuB,EACjC,EAAE,EAAE,CAAC,8BAAC,+BAAuB,CAAC,QAAQ,IAAC,KAAK,EAAE,MAAM,IAAG,QAAQ,CAAoC,CAAC;AAHxF,QAAA,wBAAwB,4BAGgE;AAErG;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACI,MAAM,mBAAmB,GAAG,GAAiC,EAAE;IACpE,OAAO,IAAA,kBAAU,EAAC,+BAAuB,CAAC,CAAC;AAC7C,CAAC,CAAC;AAFW,QAAA,mBAAmB,uBAE9B","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, { createContext, useContext, ReactNode } from 'react';\nimport { Logging } from '@fgv/ts-utils';\n\n/**\n * Default diagnostic logger (no-op for production).\n * @public\n */\nexport const DefaultDiagnosticLogger: Logging.LogReporter<unknown> = new Logging.LogReporter({\n logger: new Logging.NoOpLogger()\n});\n\n/**\n * React context for diagnostic logging.\n * Provides access to diagnostic logger throughout the component tree.\n * @public\n */\nexport const DiagnosticLoggerContext: React.Context<Logging.LogReporter<unknown>> =\n createContext<Logging.LogReporter<unknown>>(DefaultDiagnosticLogger);\n\n/**\n * Props for the DiagnosticLoggerProvider component.\n * @public\n */\nexport interface IDiagnosticLoggerProviderProps {\n /** Child components that will have access to the diagnostic logger */\n children: ReactNode;\n /** Optional logger to provide (defaults to no-op logger) */\n logger?: Logging.LogReporter<unknown>;\n}\n\n/**\n * Provider component that makes diagnostic logger available to all child components.\n *\n * @example\n * ```tsx\n * // Basic usage with default no-op logger\n * <DiagnosticLoggerProvider>\n * <SudokuGrid />\n * </DiagnosticLoggerProvider>\n *\n * // Console logging for development\n * const consoleLogger = new Logging.LogReporter({\n * logger: new Logging.ConsoleLogger('info')\n * });\n * <DiagnosticLoggerProvider logger={consoleLogger}>\n * <SudokuGrid />\n * </DiagnosticLoggerProvider>\n *\n * // In-memory logger for tests\n * const testLogger = new Logging.LogReporter({\n * logger: new Logging.InMemoryLogger('detail')\n * });\n * <DiagnosticLoggerProvider logger={testLogger}>\n * <SudokuGrid />\n * </DiagnosticLoggerProvider>\n * ```\n *\n * @param props - Provider configuration\n * @returns JSX provider element\n * @public\n */\nexport const DiagnosticLoggerProvider: React.FC<IDiagnosticLoggerProviderProps> = ({\n children,\n logger = DefaultDiagnosticLogger\n}) => <DiagnosticLoggerContext.Provider value={logger}>{children}</DiagnosticLoggerContext.Provider>;\n\n/**\n * Hook to access the current diagnostic logger.\n *\n * Provides access to diagnostic logging for development and debugging.\n *\n * @example\n * ```tsx\n * function CageOverlay({ cages }: ICageOverlayProps) {\n * const log = useDiagnosticLogger();\n *\n * useEffect(() => {\n * log.info('CageOverlay rendered', {\n * cageCount: cages.length,\n * cages: cages.map((c) => ({ id: c.cage.id, cellIds: c.cage.cellIds }))\n * });\n * }, [cages, log]);\n *\n * return <div>...</div>;\n * }\n * ```\n *\n * @returns The current diagnostic logger\n * @public\n */\nexport const useDiagnosticLogger = (): Logging.LogReporter<unknown> => {\n return useContext(DiagnosticLoggerContext);\n};\n"]}
|
|
@@ -1,32 +0,0 @@
|
|
|
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.DefaultDiagnosticLogger = exports.useDiagnosticLogger = exports.DiagnosticLoggerProvider = exports.DiagnosticLoggerContext = void 0;
|
|
27
|
-
var DiagnosticLoggerContext_1 = require("./DiagnosticLoggerContext");
|
|
28
|
-
Object.defineProperty(exports, "DiagnosticLoggerContext", { enumerable: true, get: function () { return DiagnosticLoggerContext_1.DiagnosticLoggerContext; } });
|
|
29
|
-
Object.defineProperty(exports, "DiagnosticLoggerProvider", { enumerable: true, get: function () { return DiagnosticLoggerContext_1.DiagnosticLoggerProvider; } });
|
|
30
|
-
Object.defineProperty(exports, "useDiagnosticLogger", { enumerable: true, get: function () { return DiagnosticLoggerContext_1.useDiagnosticLogger; } });
|
|
31
|
-
Object.defineProperty(exports, "DefaultDiagnosticLogger", { enumerable: true, get: function () { return DiagnosticLoggerContext_1.DefaultDiagnosticLogger; } });
|
|
32
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contexts/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;AAEH,qEAKmC;AAJjC,kIAAA,uBAAuB,OAAA;AACvB,mIAAA,wBAAwB,OAAA;AACxB,8HAAA,mBAAmB,OAAA;AACnB,kIAAA,uBAAuB,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\nexport {\n DiagnosticLoggerContext,\n DiagnosticLoggerProvider,\n useDiagnosticLogger,\n DefaultDiagnosticLogger\n} from './DiagnosticLoggerContext';\nexport type { IDiagnosticLoggerProviderProps } from './DiagnosticLoggerContext';\n"]}
|
|
@@ -1,126 +0,0 @@
|
|
|
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.useCombinationElimination = useCombinationElimination;
|
|
27
|
-
const react_1 = require("react");
|
|
28
|
-
/**
|
|
29
|
-
* Generate session storage key for a cage's eliminated combinations
|
|
30
|
-
*/
|
|
31
|
-
function getStorageKey(puzzleId, cageId) {
|
|
32
|
-
return `killer-combinations-${puzzleId}-${cageId}`;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Load eliminated combinations from session storage
|
|
36
|
-
*/
|
|
37
|
-
function loadFromSessionStorage(puzzleId, cageId) {
|
|
38
|
-
try {
|
|
39
|
-
const key = getStorageKey(puzzleId, cageId);
|
|
40
|
-
const stored = sessionStorage.getItem(key);
|
|
41
|
-
if (stored) {
|
|
42
|
-
const parsed = JSON.parse(stored);
|
|
43
|
-
return new Set(parsed);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
// Ignore parse errors
|
|
48
|
-
}
|
|
49
|
-
return new Set();
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Save eliminated combinations to session storage
|
|
53
|
-
*/
|
|
54
|
-
function saveToSessionStorage(puzzleId, cageId, eliminated) {
|
|
55
|
-
try {
|
|
56
|
-
const key = getStorageKey(puzzleId, cageId);
|
|
57
|
-
const array = Array.from(eliminated);
|
|
58
|
-
sessionStorage.setItem(key, JSON.stringify(array));
|
|
59
|
-
}
|
|
60
|
-
catch {
|
|
61
|
-
// Ignore storage errors
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Clear eliminated combinations from session storage
|
|
66
|
-
*/
|
|
67
|
-
function clearFromSessionStorage(puzzleId, cageId) {
|
|
68
|
-
try {
|
|
69
|
-
const key = getStorageKey(puzzleId, cageId);
|
|
70
|
-
sessionStorage.removeItem(key);
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
// Ignore storage errors
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Hook for managing combination elimination state with session storage persistence
|
|
78
|
-
* @param puzzleId - Unique identifier for the puzzle
|
|
79
|
-
* @param cageId - Unique identifier for the cage
|
|
80
|
-
* @returns Elimination state with toggle and clear operations
|
|
81
|
-
* @public
|
|
82
|
-
*/
|
|
83
|
-
function useCombinationElimination(puzzleId, cageId) {
|
|
84
|
-
const [eliminated, setEliminated] = (0, react_1.useState)(() => {
|
|
85
|
-
if (!puzzleId || !cageId) {
|
|
86
|
-
return new Set();
|
|
87
|
-
}
|
|
88
|
-
return loadFromSessionStorage(puzzleId, cageId);
|
|
89
|
-
});
|
|
90
|
-
// Update state when puzzleId or cageId changes
|
|
91
|
-
(0, react_1.useEffect)(() => {
|
|
92
|
-
if (!puzzleId || !cageId) {
|
|
93
|
-
setEliminated(new Set());
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
setEliminated(loadFromSessionStorage(puzzleId, cageId));
|
|
97
|
-
}, [puzzleId, cageId]);
|
|
98
|
-
const toggleElimination = (0, react_1.useCallback)((signature) => {
|
|
99
|
-
setEliminated((prev) => {
|
|
100
|
-
const next = new Set(prev);
|
|
101
|
-
if (next.has(signature)) {
|
|
102
|
-
next.delete(signature);
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
next.add(signature);
|
|
106
|
-
}
|
|
107
|
-
// Persist to session storage
|
|
108
|
-
if (puzzleId && cageId) {
|
|
109
|
-
saveToSessionStorage(puzzleId, cageId, next);
|
|
110
|
-
}
|
|
111
|
-
return next;
|
|
112
|
-
});
|
|
113
|
-
}, [puzzleId, cageId]);
|
|
114
|
-
const clearAll = (0, react_1.useCallback)(() => {
|
|
115
|
-
setEliminated(new Set());
|
|
116
|
-
if (puzzleId && cageId) {
|
|
117
|
-
clearFromSessionStorage(puzzleId, cageId);
|
|
118
|
-
}
|
|
119
|
-
}, [puzzleId, cageId]);
|
|
120
|
-
return {
|
|
121
|
-
eliminatedSignatures: eliminated,
|
|
122
|
-
toggleElimination,
|
|
123
|
-
clearAll
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
//# sourceMappingURL=useCombinationElimination.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useCombinationElimination.js","sourceRoot":"","sources":["../../src/hooks/useCombinationElimination.ts"],"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 { useState, useCallback, useEffect } from 'react';\nimport { IEliminationState } from '../types';\n\n/**\n * Generate session storage key for a cage's eliminated combinations\n */\nfunction getStorageKey(puzzleId: string, cageId: string): string {\n return `killer-combinations-${puzzleId}-${cageId}`;\n}\n\n/**\n * Load eliminated combinations from session storage\n */\nfunction loadFromSessionStorage(puzzleId: string, cageId: string): Set<string> {\n try {\n const key = getStorageKey(puzzleId, cageId);\n const stored = sessionStorage.getItem(key);\n if (stored) {\n const parsed = JSON.parse(stored) as string[];\n return new Set(parsed);\n }\n } catch {\n // Ignore parse errors\n }\n return new Set();\n}\n\n/**\n * Save eliminated combinations to session storage\n */\nfunction saveToSessionStorage(puzzleId: string, cageId: string, eliminated: Set<string>): void {\n try {\n const key = getStorageKey(puzzleId, cageId);\n const array = Array.from(eliminated);\n sessionStorage.setItem(key, JSON.stringify(array));\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Clear eliminated combinations from session storage\n */\nfunction clearFromSessionStorage(puzzleId: string, cageId: string): void {\n try {\n const key = getStorageKey(puzzleId, cageId);\n sessionStorage.removeItem(key);\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Hook for managing combination elimination state with session storage persistence\n * @param puzzleId - Unique identifier for the puzzle\n * @param cageId - Unique identifier for the cage\n * @returns Elimination state with toggle and clear operations\n * @public\n */\nexport function useCombinationElimination(\n puzzleId: string | undefined,\n cageId: string | undefined\n): IEliminationState {\n const [eliminated, setEliminated] = useState<Set<string>>(() => {\n if (!puzzleId || !cageId) {\n return new Set();\n }\n return loadFromSessionStorage(puzzleId, cageId);\n });\n\n // Update state when puzzleId or cageId changes\n useEffect(() => {\n if (!puzzleId || !cageId) {\n setEliminated(new Set());\n return;\n }\n setEliminated(loadFromSessionStorage(puzzleId, cageId));\n }, [puzzleId, cageId]);\n\n const toggleElimination = useCallback(\n (signature: string) => {\n setEliminated((prev) => {\n const next = new Set(prev);\n if (next.has(signature)) {\n next.delete(signature);\n } else {\n next.add(signature);\n }\n\n // Persist to session storage\n if (puzzleId && cageId) {\n saveToSessionStorage(puzzleId, cageId, next);\n }\n\n return next;\n });\n },\n [puzzleId, cageId]\n );\n\n const clearAll = useCallback(() => {\n setEliminated(new Set());\n if (puzzleId && cageId) {\n clearFromSessionStorage(puzzleId, cageId);\n }\n }, [puzzleId, cageId]);\n\n return {\n eliminatedSignatures: eliminated,\n toggleElimination,\n clearAll\n };\n}\n"]}
|
|
@@ -1,58 +0,0 @@
|
|
|
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.useKeyboardShortcut = useKeyboardShortcut;
|
|
27
|
-
const react_1 = require("react");
|
|
28
|
-
/**
|
|
29
|
-
* Hook for registering global keyboard shortcuts
|
|
30
|
-
* @param key - The key to listen for (e.g., 'k', 'Escape')
|
|
31
|
-
* @param callback - Function to call when shortcut is activated
|
|
32
|
-
* @param options - Optional modifier keys and behavior
|
|
33
|
-
* @public
|
|
34
|
-
*/
|
|
35
|
-
function useKeyboardShortcut(key, callback, options) {
|
|
36
|
-
(0, react_1.useEffect)(() => {
|
|
37
|
-
function handleKeyDown(event) {
|
|
38
|
-
const matchesKey = event.key.toLowerCase() === key.toLowerCase();
|
|
39
|
-
// Check modifier keys if specified
|
|
40
|
-
const matchesCtrl = options?.ctrl ? event.ctrlKey : !event.ctrlKey;
|
|
41
|
-
const matchesMeta = options?.meta ? event.metaKey : !event.metaKey;
|
|
42
|
-
const matchesShift = options?.shift ? event.shiftKey : !event.shiftKey;
|
|
43
|
-
// For cross-platform support, treat Ctrl+K on Windows/Linux as Cmd+K on Mac
|
|
44
|
-
const isPlatformShortcut = options?.ctrl && options?.meta
|
|
45
|
-
? (event.ctrlKey || event.metaKey) && !event.shiftKey
|
|
46
|
-
: matchesCtrl && matchesMeta && matchesShift;
|
|
47
|
-
if (matchesKey && isPlatformShortcut) {
|
|
48
|
-
if (options?.preventDefault) {
|
|
49
|
-
event.preventDefault();
|
|
50
|
-
}
|
|
51
|
-
callback();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
window.addEventListener('keydown', handleKeyDown);
|
|
55
|
-
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
56
|
-
}, [key, callback, options]);
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=useKeyboardShortcut.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useKeyboardShortcut.js","sourceRoot":"","sources":["../../src/hooks/useKeyboardShortcut.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;AAsBH,kDA+BC;AAnDD,iCAAkC;AAalC;;;;;;GAMG;AACH,SAAgB,mBAAmB,CACjC,GAAW,EACX,QAAoB,EACpB,OAAkC;IAElC,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,SAAS,aAAa,CAAC,KAAoB;YACzC,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;YAEjE,mCAAmC;YACnC,MAAM,WAAW,GAAG,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;YACnE,MAAM,WAAW,GAAG,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;YACnE,MAAM,YAAY,GAAG,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC;YAEvE,4EAA4E;YAC5E,MAAM,kBAAkB,GACtB,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,IAAI;gBAC5B,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ;gBACrD,CAAC,CAAC,WAAW,IAAI,WAAW,IAAI,YAAY,CAAC;YAEjD,IAAI,UAAU,IAAI,kBAAkB,EAAE,CAAC;gBACrC,IAAI,OAAO,EAAE,cAAc,EAAE,CAAC;oBAC5B,KAAK,CAAC,cAAc,EAAE,CAAC;gBACzB,CAAC;gBACD,QAAQ,EAAE,CAAC;YACb,CAAC;QACH,CAAC;QAED,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAClD,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACpE,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AAC/B,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 { useEffect } from 'react';\n\n/**\n * Options for keyboard shortcut configuration\n * @public\n */\nexport interface IKeyboardShortcutOptions {\n readonly ctrl?: boolean;\n readonly meta?: boolean;\n readonly shift?: boolean;\n readonly preventDefault?: boolean;\n}\n\n/**\n * Hook for registering global keyboard shortcuts\n * @param key - The key to listen for (e.g., 'k', 'Escape')\n * @param callback - Function to call when shortcut is activated\n * @param options - Optional modifier keys and behavior\n * @public\n */\nexport function useKeyboardShortcut(\n key: string,\n callback: () => void,\n options?: IKeyboardShortcutOptions\n): void {\n useEffect(() => {\n function handleKeyDown(event: KeyboardEvent): void {\n const matchesKey = event.key.toLowerCase() === key.toLowerCase();\n\n // Check modifier keys if specified\n const matchesCtrl = options?.ctrl ? event.ctrlKey : !event.ctrlKey;\n const matchesMeta = options?.meta ? event.metaKey : !event.metaKey;\n const matchesShift = options?.shift ? event.shiftKey : !event.shiftKey;\n\n // For cross-platform support, treat Ctrl+K on Windows/Linux as Cmd+K on Mac\n const isPlatformShortcut =\n options?.ctrl && options?.meta\n ? (event.ctrlKey || event.metaKey) && !event.shiftKey\n : matchesCtrl && matchesMeta && matchesShift;\n\n if (matchesKey && isPlatformShortcut) {\n if (options?.preventDefault) {\n event.preventDefault();\n }\n callback();\n }\n }\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [key, callback, options]);\n}\n"]}
|
|
@@ -1,68 +0,0 @@
|
|
|
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.useKillerCombinations = useKillerCombinations;
|
|
27
|
-
const react_1 = require("react");
|
|
28
|
-
const ts_utils_1 = require("@fgv/ts-utils");
|
|
29
|
-
const ts_sudoku_lib_1 = require("@fgv/ts-sudoku-lib");
|
|
30
|
-
/**
|
|
31
|
-
* Generate signature for a combination (sorted numbers joined by commas)
|
|
32
|
-
*/
|
|
33
|
-
function getCombinationSignature(combination) {
|
|
34
|
-
return [...combination].sort((a, b) => a - b).join(',');
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Hook to get all valid killer cage combinations for a selected cage
|
|
38
|
-
* @param cage - The selected killer cage
|
|
39
|
-
* @returns Result containing combination display information
|
|
40
|
-
* @public
|
|
41
|
-
*/
|
|
42
|
-
function useKillerCombinations(cage) {
|
|
43
|
-
return (0, react_1.useMemo)(() => {
|
|
44
|
-
if (!cage) {
|
|
45
|
-
return (0, ts_utils_1.fail)('No cage selected');
|
|
46
|
-
}
|
|
47
|
-
if (cage.cageType !== 'killer') {
|
|
48
|
-
return (0, ts_utils_1.fail)('Cage is not a killer cage');
|
|
49
|
-
}
|
|
50
|
-
if (!cage.total) {
|
|
51
|
-
return (0, ts_utils_1.fail)('Killer cage does not have a total');
|
|
52
|
-
}
|
|
53
|
-
// For now, we don't apply constraints based on current values
|
|
54
|
-
// This can be enhanced later to exclude numbers already in the cage
|
|
55
|
-
const constraints = {
|
|
56
|
-
excludedNumbers: []
|
|
57
|
-
};
|
|
58
|
-
return ts_sudoku_lib_1.Puzzles.KillerCombinations.getCombinations(cage.numCells, cage.total, constraints).onSuccess((combinations) => {
|
|
59
|
-
const displayInfo = combinations.map((combo) => ({
|
|
60
|
-
combination: combo,
|
|
61
|
-
signature: getCombinationSignature(combo),
|
|
62
|
-
isEliminated: false
|
|
63
|
-
}));
|
|
64
|
-
return (0, ts_utils_1.succeed)(displayInfo);
|
|
65
|
-
});
|
|
66
|
-
}, [cage]);
|
|
67
|
-
}
|
|
68
|
-
//# sourceMappingURL=useKillerCombinations.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useKillerCombinations.js","sourceRoot":"","sources":["../../src/hooks/useKillerCombinations.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;AAoBH,sDA+BC;AAjDD,iCAAgC;AAChC,4CAAsD;AACtD,sDAAoD;AAGpD;;GAEG;AACH,SAAS,uBAAuB,CAAC,WAAqB;IACpD,OAAO,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,SAAgB,qBAAqB,CAAC,IAAkB;IACtD,OAAO,IAAA,eAAO,EAAC,GAAG,EAAE;QAClB,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,IAAA,eAAI,EAAC,kBAAkB,CAAC,CAAC;QAClC,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,IAAA,eAAI,EAAC,2BAA2B,CAAC,CAAC;QAC3C,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,OAAO,IAAA,eAAI,EAAC,mCAAmC,CAAC,CAAC;QACnD,CAAC;QAED,8DAA8D;QAC9D,oEAAoE;QACpE,MAAM,WAAW,GAAG;YAClB,eAAe,EAAE,EAAE;SACpB,CAAC;QAEF,OAAO,uBAAO,CAAC,kBAAkB,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,SAAS,CACjG,CAAC,YAAwB,EAAE,EAAE;YAC3B,MAAM,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,KAAe,EAAE,EAAE,CAAC,CAAC;gBACzD,WAAW,EAAE,KAAK;gBAClB,SAAS,EAAE,uBAAuB,CAAC,KAAK,CAAC;gBACzC,YAAY,EAAE,KAAK;aACpB,CAAC,CAAC,CAAC;YACJ,OAAO,IAAA,kBAAO,EAAC,WAAW,CAAC,CAAC;QAC9B,CAAC,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AACb,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 { useMemo } from 'react';\nimport { Result, fail, succeed } from '@fgv/ts-utils';\nimport { ICage, Puzzles } from '@fgv/ts-sudoku-lib';\nimport { ICombinationDisplayInfo } from '../types';\n\n/**\n * Generate signature for a combination (sorted numbers joined by commas)\n */\nfunction getCombinationSignature(combination: number[]): string {\n return [...combination].sort((a, b) => a - b).join(',');\n}\n\n/**\n * Hook to get all valid killer cage combinations for a selected cage\n * @param cage - The selected killer cage\n * @returns Result containing combination display information\n * @public\n */\nexport function useKillerCombinations(cage: ICage | null): Result<ICombinationDisplayInfo[]> {\n return useMemo(() => {\n if (!cage) {\n return fail('No cage selected');\n }\n\n if (cage.cageType !== 'killer') {\n return fail('Cage is not a killer cage');\n }\n\n if (!cage.total) {\n return fail('Killer cage does not have a total');\n }\n\n // For now, we don't apply constraints based on current values\n // This can be enhanced later to exclude numbers already in the cage\n const constraints = {\n excludedNumbers: []\n };\n\n return Puzzles.KillerCombinations.getCombinations(cage.numCells, cage.total, constraints).onSuccess(\n (combinations: number[][]) => {\n const displayInfo = combinations.map((combo: number[]) => ({\n combination: combo,\n signature: getCombinationSignature(combo),\n isEliminated: false\n }));\n return succeed(displayInfo);\n }\n );\n }, [cage]);\n}\n"]}
|
|
@@ -1,72 +0,0 @@
|
|
|
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.useLongPress = useLongPress;
|
|
27
|
-
const react_1 = require("react");
|
|
28
|
-
/**
|
|
29
|
-
* Hook to detect long press gestures on touch and mouse devices
|
|
30
|
-
* @param options - Configuration options for long press detection
|
|
31
|
-
* @returns Event handlers to spread on target element
|
|
32
|
-
* @public
|
|
33
|
-
*/
|
|
34
|
-
function useLongPress(options) {
|
|
35
|
-
const { onLongPress, delay = 500, shouldPreventDefault = true } = options;
|
|
36
|
-
const timeoutRef = (0, react_1.useRef)(undefined);
|
|
37
|
-
const isLongPressRef = (0, react_1.useRef)(false);
|
|
38
|
-
const eventRef = (0, react_1.useRef)(undefined);
|
|
39
|
-
const start = (0, react_1.useCallback)((event) => {
|
|
40
|
-
eventRef.current = event;
|
|
41
|
-
isLongPressRef.current = false;
|
|
42
|
-
if (shouldPreventDefault) {
|
|
43
|
-
event.preventDefault();
|
|
44
|
-
}
|
|
45
|
-
timeoutRef.current = setTimeout(() => {
|
|
46
|
-
isLongPressRef.current = true;
|
|
47
|
-
if (eventRef.current) {
|
|
48
|
-
onLongPress(eventRef.current);
|
|
49
|
-
}
|
|
50
|
-
}, delay);
|
|
51
|
-
}, [onLongPress, delay, shouldPreventDefault]);
|
|
52
|
-
const cancel = (0, react_1.useCallback)(() => {
|
|
53
|
-
if (timeoutRef.current) {
|
|
54
|
-
clearTimeout(timeoutRef.current);
|
|
55
|
-
timeoutRef.current = undefined;
|
|
56
|
-
}
|
|
57
|
-
isLongPressRef.current = false;
|
|
58
|
-
}, []);
|
|
59
|
-
const end = (0, react_1.useCallback)(() => {
|
|
60
|
-
const wasLongPress = isLongPressRef.current;
|
|
61
|
-
cancel();
|
|
62
|
-
return wasLongPress;
|
|
63
|
-
}, [cancel]);
|
|
64
|
-
return {
|
|
65
|
-
onMouseDown: start,
|
|
66
|
-
onMouseUp: end,
|
|
67
|
-
onMouseLeave: cancel,
|
|
68
|
-
onTouchStart: start,
|
|
69
|
-
onTouchEnd: end
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
//# sourceMappingURL=useLongPress.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useLongPress.js","sourceRoot":"","sources":["../../src/hooks/useLongPress.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;AAqCH,oCA+CC;AAlFD,iCAA4C;AA6B5C;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,OAA6B;IACxD,MAAM,EAAE,WAAW,EAAE,KAAK,GAAG,GAAG,EAAE,oBAAoB,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAE1E,MAAM,UAAU,GAAG,IAAA,cAAM,EAA6B,SAAS,CAAC,CAAC;IACjE,MAAM,cAAc,GAAG,IAAA,cAAM,EAAU,KAAK,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,IAAA,cAAM,EAAkD,SAAS,CAAC,CAAC;IAEpF,MAAM,KAAK,GAAG,IAAA,mBAAW,EACvB,CAAC,KAA0C,EAAE,EAAE;QAC7C,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;QACzB,cAAc,CAAC,OAAO,GAAG,KAAK,CAAC;QAE/B,IAAI,oBAAoB,EAAE,CAAC;YACzB,KAAK,CAAC,cAAc,EAAE,CAAC;QACzB,CAAC;QAED,UAAU,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YACnC,cAAc,CAAC,OAAO,GAAG,IAAI,CAAC;YAC9B,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACrB,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAC;IACZ,CAAC,EACD,CAAC,WAAW,EAAE,KAAK,EAAE,oBAAoB,CAAC,CAC3C,CAAC;IAEF,MAAM,MAAM,GAAG,IAAA,mBAAW,EAAC,GAAG,EAAE;QAC9B,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;YACvB,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACjC,UAAU,CAAC,OAAO,GAAG,SAAS,CAAC;QACjC,CAAC;QACD,cAAc,CAAC,OAAO,GAAG,KAAK,CAAC;IACjC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,GAAG,GAAG,IAAA,mBAAW,EAAC,GAAG,EAAE;QAC3B,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,CAAC;QAC5C,MAAM,EAAE,CAAC;QACT,OAAO,YAAY,CAAC;IACtB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO;QACL,WAAW,EAAE,KAAK;QAClB,SAAS,EAAE,GAAG;QACd,YAAY,EAAE,MAAM;QACpB,YAAY,EAAE,KAAK;QACnB,UAAU,EAAE,GAAG;KAChB,CAAC;AACJ,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 { useRef, useCallback } from 'react';\n\n/**\n * Options for the useLongPress hook\n * @public\n */\nexport interface IUseLongPressOptions {\n /** Callback to execute on long press */\n readonly onLongPress: (event: React.TouchEvent | React.MouseEvent) => void;\n\n /** Delay before long press is triggered (ms) */\n readonly delay?: number;\n\n /** Whether to prevent default behavior during long press */\n readonly shouldPreventDefault?: boolean;\n}\n\n/**\n * Result of the useLongPress hook\n * @public\n */\nexport interface ILongPressHandlers {\n readonly onMouseDown: (event: React.MouseEvent) => void;\n readonly onMouseUp: (event: React.MouseEvent) => boolean;\n readonly onMouseLeave: (event: React.MouseEvent) => void;\n readonly onTouchStart: (event: React.TouchEvent) => void;\n readonly onTouchEnd: (event: React.TouchEvent) => boolean;\n}\n\n/**\n * Hook to detect long press gestures on touch and mouse devices\n * @param options - Configuration options for long press detection\n * @returns Event handlers to spread on target element\n * @public\n */\nexport function useLongPress(options: IUseLongPressOptions): ILongPressHandlers {\n const { onLongPress, delay = 500, shouldPreventDefault = true } = options;\n\n const timeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);\n const isLongPressRef = useRef<boolean>(false);\n const eventRef = useRef<React.TouchEvent | React.MouseEvent | undefined>(undefined);\n\n const start = useCallback(\n (event: React.TouchEvent | React.MouseEvent) => {\n eventRef.current = event;\n isLongPressRef.current = false;\n\n if (shouldPreventDefault) {\n event.preventDefault();\n }\n\n timeoutRef.current = setTimeout(() => {\n isLongPressRef.current = true;\n if (eventRef.current) {\n onLongPress(eventRef.current);\n }\n }, delay);\n },\n [onLongPress, delay, shouldPreventDefault]\n );\n\n const cancel = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = undefined;\n }\n isLongPressRef.current = false;\n }, []);\n\n const end = useCallback(() => {\n const wasLongPress = isLongPressRef.current;\n cancel();\n return wasLongPress;\n }, [cancel]);\n\n return {\n onMouseDown: start,\n onMouseUp: end,\n onMouseLeave: cancel,\n onTouchStart: start,\n onTouchEnd: end\n };\n}\n"]}
|