@mborecki/crossword 0.0.2 → 0.2.0
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/dist/cjs/{index-TyGpRn4d.js → index-BlTGwvVC.js} +63 -2
- package/dist/cjs/{index-CwHIXXW5.js → index-CEGyCfpa.js} +29 -1
- package/dist/cjs/index.cjs.js +2 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/mb-crossword.cjs.entry.js +159 -38
- package/dist/cjs/mb-crossword.cjs.js +2 -2
- package/dist/collection/components/crossword/cell.js +7 -2
- package/dist/collection/components/crossword/clue.js +2 -2
- package/dist/collection/components/crossword/mb-crossword.css +107 -13
- package/dist/collection/components/crossword/mb-crossword.js +189 -32
- package/dist/collection/utils/utils.js +6 -0
- package/dist/components/index.js +1 -1
- package/dist/components/mb-crossword.js +1 -1
- package/dist/esm/{index-B4XIBYtu.js → index-BGHKtxML.js} +63 -2
- package/dist/esm/{index-0i8AYf_G.js → index-Dn3GSx6U.js} +29 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/mb-crossword.entry.js +159 -38
- package/dist/esm/mb-crossword.js +3 -3
- package/dist/mb-crossword/index.esm.js +1 -1
- package/dist/mb-crossword/mb-crossword.esm.js +1 -1
- package/dist/mb-crossword/p-34ea8cf1.entry.js +1 -0
- package/dist/mb-crossword/{p-B4XIBYtu.js → p-BGHKtxML.js} +2 -2
- package/dist/mb-crossword/p-Dn3GSx6U.js +1 -0
- package/dist/types/components/crossword/cell.d.ts +3 -1
- package/dist/types/components/crossword/clue.d.ts +5 -3
- package/dist/types/components/crossword/mb-crossword.d.ts +18 -6
- package/dist/types/components/crossword/types.d.ts +21 -2
- package/dist/types/components.d.ts +9 -0
- package/dist/types/roboczy/mb-puzzle/apps/crossword/.stencil/shared/grid/src/grid.d.ts +12 -0
- package/dist/types/roboczy/mb-puzzle/apps/crossword/.stencil/shared/grid/vitest.config.d.ts +2 -0
- package/dist/types/roboczy/mb-puzzle/apps/crossword/.stencil/shared/vec2/src/vec2.d.ts +9 -2
- package/dist/types/utils/utils.d.ts +1 -0
- package/package.json +6 -1
- package/dist/mb-crossword/p-0i8AYf_G.js +0 -1
- package/dist/mb-crossword/p-5b227b8e.entry.js +0 -1
|
@@ -3,5 +3,7 @@ export interface Props {
|
|
|
3
3
|
data: CellData;
|
|
4
4
|
isInCurrentClue: boolean;
|
|
5
5
|
isSelected: boolean;
|
|
6
|
+
isSpecial: boolean;
|
|
7
|
+
onPointerDown?(): void;
|
|
6
8
|
}
|
|
7
|
-
export declare function Cell({ data, isInCurrentClue, isSelected }: Props): any;
|
|
9
|
+
export declare function Cell({ data, isInCurrentClue, isSelected, isSpecial, onPointerDown }: Props): any;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PuzzleClue } from './types';
|
|
2
2
|
export interface Props {
|
|
3
3
|
isCurrent: boolean;
|
|
4
|
-
word:
|
|
4
|
+
word: PuzzleClue;
|
|
5
5
|
onPointerDown(event: PointerEvent): void;
|
|
6
|
+
preview: string;
|
|
7
|
+
showPreview: boolean;
|
|
6
8
|
}
|
|
7
|
-
export declare function Clue({ isCurrent, word, onPointerDown }: Props): any;
|
|
9
|
+
export declare function Clue({ isCurrent, word, onPointerDown, preview, showPreview }: Props): any;
|
|
@@ -1,30 +1,40 @@
|
|
|
1
|
-
import { CellData, PuzzleData,
|
|
1
|
+
import { CellData, PuzzleData, PuzzleClue, Border, SpecialCell, PuzzleLabel } from './types';
|
|
2
2
|
import { Vec2 } from '@mb-puzzle/vec2';
|
|
3
3
|
export declare class MBCrossword {
|
|
4
4
|
init: boolean;
|
|
5
5
|
data: PuzzleData;
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
showCluePreview: boolean;
|
|
7
|
+
textInput: HTMLInputElement;
|
|
8
|
+
hWords: PuzzleClue[];
|
|
9
|
+
vWords: PuzzleClue[];
|
|
8
10
|
currentClueId: string | null;
|
|
9
|
-
currentClue:
|
|
11
|
+
currentClue: PuzzleClue | null;
|
|
10
12
|
isFocused: boolean;
|
|
11
13
|
selectedCell: CellData | null;
|
|
12
14
|
componentWillLoad(): void;
|
|
13
|
-
|
|
15
|
+
watchData(): void;
|
|
16
|
+
get allWords(): PuzzleClue[];
|
|
14
17
|
initGame(data?: PuzzleData): Promise<void>;
|
|
18
|
+
checkAnswer(): Promise<boolean>;
|
|
19
|
+
specialBorders: Border[];
|
|
20
|
+
specialCells: SpecialCell[];
|
|
21
|
+
labels: PuzzleLabel[];
|
|
15
22
|
boardWidth: number;
|
|
16
23
|
boardHeight: number;
|
|
17
24
|
cells: CellData[];
|
|
18
25
|
buildBoard(): void;
|
|
26
|
+
getClueById(id: string): PuzzleClue | null;
|
|
19
27
|
isInClue(xy: {
|
|
20
28
|
x: number;
|
|
21
29
|
y: number;
|
|
22
|
-
}, clue?:
|
|
30
|
+
}, clue?: PuzzleClue): boolean;
|
|
23
31
|
isSelectedCell(cell: CellData): boolean;
|
|
24
32
|
getNextClueId(): string | null;
|
|
25
33
|
getPrevClueId(): string | null;
|
|
26
34
|
inputLetter(char: string): void;
|
|
35
|
+
backspace(): void;
|
|
27
36
|
selectNextCell(): void;
|
|
37
|
+
selectPrevCell(): void;
|
|
28
38
|
onFocusin(): void;
|
|
29
39
|
onFocusOut(): void;
|
|
30
40
|
selectClue(id: string, { row, col }?: {
|
|
@@ -35,6 +45,8 @@ export declare class MBCrossword {
|
|
|
35
45
|
findNonblockedCell(source: Vec2, vector: Vec2): Vec2;
|
|
36
46
|
isCellBlocked(v: Vec2): boolean;
|
|
37
47
|
selectClueByXY(v: Vec2): void;
|
|
48
|
+
getCluePreview(clue: PuzzleClue): string;
|
|
38
49
|
onKeyPress(event: KeyboardEvent): void;
|
|
50
|
+
onInput(event: InputEvent): void;
|
|
39
51
|
render(): any;
|
|
40
52
|
}
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
export interface PuzzleData {
|
|
2
|
-
words:
|
|
2
|
+
words: PuzzleClue[];
|
|
3
|
+
specialBorders?: Border[];
|
|
4
|
+
specialCells?: SpecialCell[];
|
|
5
|
+
labels?: PuzzleLabel[];
|
|
3
6
|
}
|
|
4
|
-
export interface
|
|
7
|
+
export interface Border {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
border: number;
|
|
11
|
+
}
|
|
12
|
+
export interface SpecialCell {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
}
|
|
16
|
+
export interface PuzzleClue {
|
|
5
17
|
id: string;
|
|
6
18
|
word: string;
|
|
7
19
|
x: number;
|
|
@@ -9,6 +21,12 @@ export interface PuzzleWord {
|
|
|
9
21
|
orientation: 'horizontal' | 'vertical';
|
|
10
22
|
clue: string;
|
|
11
23
|
}
|
|
24
|
+
export interface PuzzleLabel {
|
|
25
|
+
text: string;
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
clueId: string;
|
|
29
|
+
}
|
|
12
30
|
export interface CellData {
|
|
13
31
|
index: number;
|
|
14
32
|
x: number;
|
|
@@ -17,4 +35,5 @@ export interface CellData {
|
|
|
17
35
|
isCurrent: boolean;
|
|
18
36
|
isInCurrentWord: boolean;
|
|
19
37
|
isBlocked: boolean;
|
|
38
|
+
answer?: string;
|
|
20
39
|
}
|
|
@@ -9,12 +9,17 @@ import { PuzzleData } from "./components/crossword/types";
|
|
|
9
9
|
export { PuzzleData } from "./components/crossword/types";
|
|
10
10
|
export namespace Components {
|
|
11
11
|
interface MbCrossword {
|
|
12
|
+
"checkAnswer": () => Promise<boolean>;
|
|
12
13
|
"data": PuzzleData;
|
|
13
14
|
/**
|
|
14
15
|
* @default true
|
|
15
16
|
*/
|
|
16
17
|
"init": boolean;
|
|
17
18
|
"initGame": (data?: PuzzleData) => Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* @default true
|
|
21
|
+
*/
|
|
22
|
+
"showCluePreview": boolean;
|
|
18
23
|
}
|
|
19
24
|
}
|
|
20
25
|
declare global {
|
|
@@ -35,6 +40,10 @@ declare namespace LocalJSX {
|
|
|
35
40
|
* @default true
|
|
36
41
|
*/
|
|
37
42
|
"init"?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
"showCluePreview"?: boolean;
|
|
38
47
|
}
|
|
39
48
|
interface IntrinsicElements {
|
|
40
49
|
"mb-crossword": MbCrossword;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Vec2 } from '@mb-puzzle/vec2';
|
|
2
|
+
export declare class Grid {
|
|
3
|
+
private size;
|
|
4
|
+
constructor(size: Vec2);
|
|
5
|
+
getIndexFromVec(v: Vec2): number;
|
|
6
|
+
getVecFromIndex(index: number): Vec2;
|
|
7
|
+
isBlack(v: Vec2): boolean;
|
|
8
|
+
isWhite(v: Vec2): boolean;
|
|
9
|
+
isInGrid(v: Vec2): boolean;
|
|
10
|
+
static getVecFromIndex(index: number, width: number): Vec2;
|
|
11
|
+
static getIndexFromVec(v: Vec2, width: number): number;
|
|
12
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface Vec2ParsableObject {
|
|
2
2
|
x: number;
|
|
3
3
|
y: number;
|
|
4
4
|
}
|
|
5
|
-
export type Vec2Source = number | number[] | Required<
|
|
5
|
+
export type Vec2Source = number | number[] | Required<Vec2ParsableObject>;
|
|
6
6
|
export declare class Vec2 {
|
|
7
7
|
x: number;
|
|
8
8
|
y: number;
|
|
@@ -10,8 +10,15 @@ export declare class Vec2 {
|
|
|
10
10
|
set 0(x: number);
|
|
11
11
|
get 1(): number;
|
|
12
12
|
set 1(y: number);
|
|
13
|
+
get width(): number;
|
|
14
|
+
set width(x: number);
|
|
15
|
+
get height(): number;
|
|
16
|
+
set height(y: number);
|
|
13
17
|
get xy(): number[];
|
|
14
18
|
[Symbol.iterator](): Generator<number, void, unknown>;
|
|
15
19
|
constructor(x: number, y: number);
|
|
20
|
+
add(v: Vec2): Vec2;
|
|
21
|
+
eq(v: Vec2): boolean;
|
|
22
|
+
clone(): Vec2;
|
|
16
23
|
static from(source: Vec2Source): Vec2;
|
|
17
24
|
}
|
|
@@ -2,3 +2,4 @@ import { Vec2 } from '@mb-puzzle/vec2';
|
|
|
2
2
|
export declare function Vec2fromIndex(index: number, width: number): Vec2;
|
|
3
3
|
export declare function indexFromXY(v: Vec2, width: number): number;
|
|
4
4
|
export declare function isKeyboardEventLetter(event: KeyboardEvent): boolean;
|
|
5
|
+
export declare function isInputEventLetter(event: InputEvent): boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mborecki/crossword",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Crossword Puzzle",
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"types": "./dist/components/*.d.ts"
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/mborecki/mb-puzzle"
|
|
35
|
+
},
|
|
32
36
|
"files": [
|
|
33
37
|
"dist/",
|
|
34
38
|
"loader/"
|
|
@@ -48,6 +52,7 @@
|
|
|
48
52
|
"scripts": {
|
|
49
53
|
"test": "vitest",
|
|
50
54
|
"build": "stencil build",
|
|
55
|
+
"postbuild": "pnpm exec rm -rf ../shared",
|
|
51
56
|
"start": "stencil build --dev --watch --serve"
|
|
52
57
|
}
|
|
53
58
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
class t{x;y;get 0(){return this.x}set 0(t){this.x=t}get 1(){return this.y}set 1(t){this.y=t}get xy(){return[this.x,this.y]}*[Symbol.iterator](){yield this.x,yield this.y}constructor(t,r){this.x=t,this.y=r}static from(r){if("number"==typeof r)return new t(r,r);if(Array.isArray(r))return new t(r[0],r[1]);if("object"==typeof r&&"number"==typeof r.x&&"number"==typeof r.y)return new t(r.x,r.y);throw new Error("Wrong Vec2 source")}}function r(r,e){const n=r%e,u=Math.floor(r/e);return new t(n,u)}function e(t,r){return t.y*r+t.x}function n(t){if(1!==t.key.length)return!1;const r=t.key.toLowerCase();return/[0-9a-zA-Z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u024F]/.test(r)}export{r as V,t as a,e as b,n as i}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{h as t,r as i,f as s}from"./p-B4XIBYtu.js";import{V as e,a as r,i as n,b as l}from"./p-0i8AYf_G.js";function o({isCurrent:i,word:s,onPointerDown:e}){return t("p",{onPointerDown:e,part:"clue",class:{"--current":i}},s.clue)}function h({data:i,isInCurrentClue:s,isSelected:e}){return t("div",{part:"cell",class:{"--blocked":i.isBlocked,"--in-current-clue":s,"--selected":e}},t("div",{class:"_inner",style:{position:"absolute",width:"100%"}},i.value))}const a=class{constructor(t){i(this,t)}init=!0;data;hWords=[];vWords=[];currentClueId=null;currentClue=null;isFocused=!1;selectedCell=null;componentWillLoad(){this.init&&this.data&&this.initGame()}get allWords(){return[...this.hWords,...this.vWords]}async initGame(t=this.data){if(!t.words)throw new Error("Words definition missing");this.hWords=[],this.vWords=[],t.words.forEach(((t,i)=>{const s=Math.random();void 0===t.id&&(t.id=`${s}_${i}`),"horizontal"===t.orientation&&(this.hWords=[...this.hWords,t]),"vertical"===t.orientation&&(this.vWords=[...this.vWords,t])})),this.buildBoard()}boardWidth=0;boardHeight=0;cells=[];buildBoard(){let t=0,i=0;this.allWords.forEach((s=>{"horizontal"===s.orientation&&(t=Math.max(t,s.x+s.word.length),i=Math.max(i,s.y+1)),"vertical"===s.orientation&&(t=Math.max(t,s.x+1),i=Math.max(i,s.y+s.word.length))}));const s=Array(i*t).fill(null).map(((i,s)=>{const[r,n]=e(s,t);return{index:s,x:r,y:n,value:null,isCurrent:!1,isInCurrentWord:!1,isBlocked:!0}}));this.allWords.forEach((i=>{if("horizontal"===i.orientation)for(let e=0;e<i.word.length;e++){const n=r.from(i),o=l(new r(n.x+e,n.y),t);s[o].isBlocked=!1}if("vertical"===i.orientation)for(let e=0;e<i.word.length;e++){const n=r.from(i),o=l(new r(n.x,n.y+e),t);s[o].isBlocked=!1}})),this.cells=s,this.boardWidth=t,this.boardHeight=i}isInClue(t,i=this.currentClue){return null!==i&&(t.x===i.x||t.y===i.y)&&("horizontal"===i.orientation?!(t.y!==i.y||t.x<i.x||t.x>=i.x+i.word.length):"vertical"===i.orientation?!(t.x!==i.x||t.y<i.y||t.y>=i.y+i.word.length):void 0)}isSelectedCell(t){return!!this.selectedCell&&t.x===this.selectedCell.x&&t.y===this.selectedCell.y}getNextClueId(){if(!this.currentClueId)return this.allWords[0]?.id??null;const t=this.allWords.findIndex((t=>t.id===this.currentClueId));return t<0?this.allWords[0]?.id??null:this.allWords[t+1]?.id??null}getPrevClueId(){if(!this.currentClueId)return this.allWords[0]?.id??null;const t=this.allWords.findIndex((t=>t.id===this.currentClueId));return t<0?this.allWords[0]?.id??null:this.allWords[t-1]?.id??null}inputLetter(t){this.selectedCell&&(this.selectedCell.value=t,this.selectNextCell(),s(this))}selectNextCell(){if(!this.selectedCell||!this.currentClue)return;const t=this.currentClue.orientation;if(function(t,i){const s=[t.x+("horizontal"===t.orientation?t.word.length-1:0),t.y+("vertical"===t.orientation?t.word.length-1:0)];return i.x===s[0]&&i.y===s[1]}(this.currentClue,this.selectedCell)){const t=this.getNextClueId();this.selectClue(t||(this.hWords[0]?.id??this.vWords[0]?.id))}else"horizontal"===t&&this.selectCellByXY(new r(this.selectedCell.x+1,this.selectedCell.y)),"vertical"===t&&this.selectCellByXY(new r(this.selectedCell.x,this.selectedCell.y+1))}onFocusin(){this.isFocused=!0,this.currentClueId||(this.currentClueId=this.allWords[0]?.id??null)}onFocusOut(){this.isFocused=!1}selectClue(t,{row:i,col:s}={}){if(!t)return;this.currentClueId=t;const e=this.allWords.find((i=>i.id===t));e||(this.currentClueId=null,this.currentClue=null),this.currentClue=e;const n=[e.x,e.y];void 0!==i&&"vertical"===e.orientation&&i>=e.y&&i<e.y+e.word.length&&(n[1]=i),void 0!==s&&"horizontal"===e.orientation&&s>=e.x&&s<e.x+e.word.length&&(n[0]=s),this.selectCellByXY(r.from(n))}selectCellByXY(t){const i=l(t,this.boardWidth);this.selectedCell=this.cells[i]??null}findNonblockedCell(t,i){const s=new r(t[0]+i[0],t[1]+i[1]),e=this.boardWidth*this.boardHeight;let n=0;for(;this.isCellBlocked(s)&&n<e;)n++,s[0]+=i[0],s[1]+=i[1],s[0]<0&&(s[0]=this.boardWidth-1),s[0]>=this.boardWidth&&(s[0]=0),s[1]<0&&(s[1]=this.boardHeight-1),s[1]>=this.boardHeight&&(s[1]=0);return s}isCellBlocked(t){const i=this.cells[l(t,this.boardWidth)];return i?.isBlocked??!0}selectClueByXY(t){const i=this.allWords.filter((i=>this.isInClue(t,i)));if(!i.length)return;const s=i.find((t=>t.orientation===this.currentClue?.orientation));this.selectClue(s?.id??i[0].id,{row:t.y,col:t.x})}onKeyPress(t){if(console.log(t),"Tab"===t.key){const i=t.shiftKey?this.getPrevClueId():this.getNextClueId();i&&(t.preventDefault(),this.selectClue(i))}if(n(t)&&this.inputLetter(t.key.toLowerCase()[0]),this.selectedCell)switch(t.key){case"ArrowLeft":return this.selectClueByXY(this.findNonblockedCell(new r(this.selectedCell.x,this.selectedCell.y),new r(-1,0))),void t.preventDefault();case"ArrowRight":return this.selectClueByXY(this.findNonblockedCell(new r(this.selectedCell.x,this.selectedCell.y),new r(1,0))),void t.preventDefault();case"ArrowUp":return this.selectClueByXY(this.findNonblockedCell(new r(this.selectedCell.x,this.selectedCell.y),new r(0,-1))),void t.preventDefault();case"ArrowDown":return this.selectClueByXY(this.findNonblockedCell(new r(this.selectedCell.x,this.selectedCell.y),new r(0,1))),void t.preventDefault()}}render(){return t("div",{key:"e298ac6f3a1d95bc41c4854b39600f8ac7f1696d",part:"main",class:{"--focused":this.isFocused},onFocusin:this.onFocusin.bind(this),onFocusout:this.onFocusOut.bind(this),tabIndex:0,onKeyDown:this.onKeyPress.bind(this)},t("div",{key:"74be935779266effb4605f2aa5883bf564610bc0",part:"clues"},t("div",{key:"125d8938e4f084562b54794158074bdaeda722b5",part:"clue-list"},this.hWords.map((i=>t(o,{word:i,isCurrent:i.id===this.currentClueId,onPointerDown:()=>this.selectClue(i.id)})))),t("div",{key:"4469227db5156a2d0b30e4dc7ef9ea8f8a1fc3bc",part:"clue-list"},this.vWords.map((i=>t(o,{word:i,isCurrent:i.id===this.currentClueId,onPointerDown:()=>this.selectClue(i.id)}))))),t("div",{key:"965b2e99d1fbf273907f722e8b15749fbd728070",part:"board",style:{"--test":"12","grid-template-columns":`repeat(${this.boardWidth}, 1fr)`}},this.cells.map((i=>{const s=this.isInClue(i),e=this.isSelectedCell(i);return t(h,{isInCurrentClue:s,isSelected:e,data:i})}))),t("div",{key:"3d97bcc65c5eb1d25b60aa5183a7c63f6eecebf9",part:"preview"},"Tu bedzie podgląd: ",this.currentClueId))}};a.style='*[part=main]{display:grid;grid-template-areas:"clues board";grid-template-columns:1fr 1fr}*[part=main].--focused{background:lightgrey}[part=clues]{grid-area:clues;display:grid;grid-template-columns:1fr 1fr}[part=clue].--current{background:lightcyan}[part=board]{grid-area:board;display:grid}[part=cell]{aspect-ratio:1;background:#d9d9d9;position:relative;container-type:size}[part=cell]:nth-child(2n){background:#999}[part=cell].--blocked{background:black}[part=cell].--in-current-clue{box-shadow:inset 0 0 2px 2px lightblue}[part=cell].--selected{background:lightblue}[part=cell] ._inner{position:absolute;top:0;left:0;right:0;bottom:0;display:grid;place-content:center;text-transform:uppercase;font-size:80cqh}[part=preview]{display:none}';export{a as mb_crossword}
|