board-game-engine-react 0.0.1 → 0.0.3

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.
@@ -1,20 +1,249 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react')) :
3
- typeof define === 'function' && define.amd ? define(['react'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.BoardGameEngineReact = factory(global.React));
5
- })(this, (function (React) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.BoardGameEngineReact = {}, global.React));
5
+ })(this, (function (exports, React) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
9
9
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
10
10
 
11
- function BoardGameEngineReact({}) {
11
+ const GameContext = /*#__PURE__*/React.createContext({
12
+ clickTarget: () => {}
13
+ });
14
+
15
+ // do we need isSpectator
16
+ function GameProvider({
17
+ gameConnection,
18
+ children,
19
+ isSpectator
20
+ }) {
21
+ React.useEffect(() => {
22
+ if (gameConnection.state._stateID === 0) {
23
+ gameConnection.reset();
24
+ }
25
+ }, [gameConnection.state._stateID]);
26
+ return /*#__PURE__*/React__default["default"].createElement(GameContext.Provider, {
27
+ value: {
28
+ clickTarget: target => {
29
+ if (!isSpectator) {
30
+ gameConnection.doStep(target);
31
+ }
32
+ },
33
+ undoStep: () => {
34
+ gameConnection.undoStep();
35
+ },
36
+ allClickable: gameConnection.optimisticWinner || isSpectator ? new Set() : gameConnection.allClickable,
37
+ currentMoveTargets: gameConnection.optimisticWinner || isSpectator ? [] : gameConnection.moveBuilder.targets
38
+ }
39
+ }, children);
40
+ }
41
+ const useGame = () => React.useContext(GameContext);
42
+
43
+ function Grid({
44
+ grid
45
+ }) {
46
+ const {
47
+ width,
48
+ height,
49
+ spaces
50
+ } = grid.attributes;
51
+ return /*#__PURE__*/React__default["default"].createElement("div", {
52
+ className: "grid",
53
+ style: {
54
+ display: 'inline-grid',
55
+ width: '100%',
56
+ gridTemplateColumns: `repeat(${width}, 1fr)`,
57
+ gridTemplateRows: `repeat(${height}, 1fr)`
58
+ }
59
+ }, spaces.map((space, index) => {
60
+ return /*#__PURE__*/React__default["default"].createElement("div", {
61
+ key: index,
62
+ className: "grid__cell"
63
+ }, /*#__PURE__*/React__default["default"].createElement(Entity, {
64
+ entity: space
65
+ }));
66
+ }));
67
+ }
68
+
69
+ function Space({
70
+ space
71
+ }) {
72
+ const {
73
+ clickTarget,
74
+ allClickable,
75
+ currentMoveTargets
76
+ } = useGame();
77
+ const {
78
+ entities,
79
+ entityId
80
+ } = space.attributes;
81
+ const clickable = [...allClickable].map(e => e.entityId).includes(entityId);
82
+ const targeted = currentMoveTargets?.map(e => e.entityId).includes(entityId);
83
+ return /*#__PURE__*/React__default["default"].createElement("a", {
84
+ className: ['space', clickable && 'space--clickable', targeted && 'space--targeted'].filter(Boolean).join(' '),
85
+ onClick: () => clickTarget(space),
86
+ style: {
87
+ display: 'inline-block',
88
+ flex: '1'
89
+ }
90
+ }, /*#__PURE__*/React__default["default"].createElement("div", {
91
+ className: "space__entity-grid",
92
+ style: {
93
+ display: 'flex',
94
+ height: '100%',
95
+ width: '100%',
96
+ flexWrap: 'wrap'
97
+ }
98
+ }, Array.from({
99
+ length: entities.length
100
+ }, (_, i) => /*#__PURE__*/React__default["default"].createElement("div", {
101
+ className: "space__entity-grid__cell",
102
+ style: {
103
+ display: 'inline-block'
104
+ },
105
+ key: i
106
+ }, /*#__PURE__*/React__default["default"].createElement(Entity, {
107
+ entity: entities[i]
108
+ }))), !entities.length && space.attributes.name));
109
+ }
110
+
111
+ function Entity({
112
+ entity
113
+ }) {
114
+ const {
115
+ clickTarget,
116
+ allClickable
117
+ } = useGame();
118
+ const isClickable = allClickable.has(entity);
119
+ const attributes = entity.attributes;
120
+ switch (attributes.type) {
121
+ case 'Grid':
122
+ return /*#__PURE__*/React__default["default"].createElement(Grid, {
123
+ grid: entity,
124
+ isClickable: isClickable
125
+ });
126
+ case 'Space':
127
+ return /*#__PURE__*/React__default["default"].createElement(Space, {
128
+ space: entity,
129
+ isClickable: isClickable
130
+ });
131
+ default:
132
+ return /*#__PURE__*/React__default["default"].createElement("div", {
133
+ onClick: e => {
134
+ if (isClickable) {
135
+ e.stopPropagation();
136
+ clickTarget(entity);
137
+ }
138
+ },
139
+ className: ['entity', attributes.player && `player-${attributes.player}`, allClickable.has(entity) && 'entity--clickable'].filter(Boolean).join(' ')
140
+ }, entity.rule.displayProperties?.map((property, i) => /*#__PURE__*/React__default["default"].createElement("div", {
141
+ key: i
142
+ }, property, ": ", entity.attributes[property]?.toString())));
143
+ }
144
+ }
145
+
146
+ function AbstractChoices() {
147
+ const {
148
+ clickTarget,
149
+ allClickable,
150
+ undoStep,
151
+ currentMoveTargets
152
+ } = useGame();
153
+ const abstractChoices = [...allClickable].filter(c => c.abstract);
154
+
155
+ // spacer assumes only one row of choices.
156
+ // could save and store biggest height instead?
12
157
  return /*#__PURE__*/React__default["default"].createElement("div", {
13
- className: "board-game-engine-react"
14
- });
158
+ style: {
159
+ position: 'relative'
160
+ }
161
+ }, /*#__PURE__*/React__default["default"].createElement("button", {
162
+ style: {
163
+ visibility: 'hidden'
164
+ },
165
+ className: "button button--style-b button--x-small abstract-choices__choice"
166
+ }, "Spacer"), /*#__PURE__*/React__default["default"].createElement("div", {
167
+ style: {
168
+ position: 'absolute',
169
+ top: 0,
170
+ width: '100%'
171
+ }
172
+ }, !!currentMoveTargets.length && /*#__PURE__*/React__default["default"].createElement("button", {
173
+ className: "button button--style-c button--x-small abstract-choices__choice abstract-choices__choice--undo",
174
+ onClick: undoStep
175
+ }, "Undo"), abstractChoices.map((choice, i) => /*#__PURE__*/React__default["default"].createElement("button", {
176
+ key: i,
177
+ className: "button button--style-b button--x-small abstract-choices__choice",
178
+ onClick: () => clickTarget(choice)
179
+ }, choice.value))));
180
+ }
181
+
182
+ function GameStatus({
183
+ gameConnection
184
+ }) {
185
+ const players = gameConnection.client.matchData;
186
+ const winner = gameConnection.state.ctx.gameover?.winner;
187
+ const draw = gameConnection.state.ctx.gameover?.draw;
188
+ let winnerString = '';
189
+ if (draw) {
190
+ winnerString = 'Draw!';
191
+ } else if (players && winner) {
192
+ winnerString = `${players[winner].name} Wins!`;
193
+ } else if (winner) {
194
+ winnerString = `Player ${winner} Wins!`;
195
+ }
196
+ return gameConnection.state.ctx.gameover && /*#__PURE__*/React__default["default"].createElement("div", {
197
+ className: "game-status"
198
+ }, winnerString);
199
+ }
200
+
201
+ function Game({
202
+ gameConnection,
203
+ loading
204
+ }) {
205
+ console.log('555gameConnection', gameConnection);
206
+ const G = gameConnection?.state;
207
+ return G ? /*#__PURE__*/React__default["default"].createElement(GameProvider, {
208
+ gameConnection: gameConnection,
209
+ isSpectator: true
210
+ }, /*#__PURE__*/React__default["default"].createElement("div", {
211
+ className: "game"
212
+ }, /*#__PURE__*/React__default["default"].createElement(AbstractChoices, null), /*#__PURE__*/React__default["default"].createElement("div", {
213
+ className: "shared-board",
214
+ style: {
215
+ width: '100%',
216
+ display: 'flex',
217
+ flexWrap: 'wrap',
218
+ justifyContent: 'center',
219
+ alignItems: 'center',
220
+ gap: '1em'
221
+ }
222
+ }, G.sharedBoard.entities.map((entity, i) => /*#__PURE__*/React__default["default"].createElement(Entity, {
223
+ key: i,
224
+ entity: entity
225
+ }))), G.personalBoards && /*#__PURE__*/React__default["default"].createElement("div", {
226
+ className: "personal-boards"
227
+ }, G.personalBoards.map((board, i) => /*#__PURE__*/React__default["default"].createElement("div", {
228
+ key: i,
229
+ className: "personal-board",
230
+ style: {
231
+ width: '100%',
232
+ display: 'grid',
233
+ gridAutoFlow: 'column',
234
+ gridAutoRows: '1fr',
235
+ gap: '1em'
236
+ }
237
+ }, board.entities.map((entity, j) => /*#__PURE__*/React__default["default"].createElement(Entity, {
238
+ key: j,
239
+ entity: entity
240
+ }))))), /*#__PURE__*/React__default["default"].createElement(GameStatus, {
241
+ gameConnection: gameConnection
242
+ }))) : loading;
15
243
  }
16
- BoardGameEngineReact.propTypes = {};
17
244
 
18
- return BoardGameEngineReact;
245
+ exports.Game = Game;
246
+
247
+ Object.defineProperty(exports, '__esModule', { value: true });
19
248
 
20
249
  }));
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).BoardGameEngineReact=t(e.React)}(this,function(e){"use strict";function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var n=t(e);function o({}){return n.default.createElement("div",{className:"board-game-engine-react"})}return o.propTypes={},o});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).BoardGameEngineReact={},e.React)}(this,function(e,t){"use strict";function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var l=a(t);const n=t.createContext({clickTarget:()=>{}});function i({gameConnection:e,children:a,isSpectator:i}){return t.useEffect(()=>{0===e.state._stateID&&e.reset()},[e.state._stateID]),l.default.createElement(n.Provider,{value:{clickTarget:t=>{i||e.doStep(t)},undoStep:()=>{e.undoStep()},allClickable:e.optimisticWinner||i?new Set:e.allClickable,currentMoveTargets:e.optimisticWinner||i?[]:e.moveBuilder.targets}},a)}const c=()=>t.useContext(n);function r({grid:e}){const{width:t,height:a,spaces:n}=e.attributes;return l.default.createElement("div",{className:"grid",style:{display:"inline-grid",width:"100%",gridTemplateColumns:`repeat(${t}, 1fr)`,gridTemplateRows:`repeat(${a}, 1fr)`}},n.map((e,t)=>l.default.createElement("div",{key:t,className:"grid__cell"},l.default.createElement(o,{entity:e}))))}function s({space:e}){const{clickTarget:t,allClickable:a,currentMoveTargets:n}=c(),{entities:i,entityId:r}=e.attributes,s=[...a].map(e=>e.entityId).includes(r),d=n?.map(e=>e.entityId).includes(r);return l.default.createElement("a",{className:["space",s&&"space--clickable",d&&"space--targeted"].filter(Boolean).join(" "),onClick:()=>t(e),style:{display:"inline-block",flex:"1"}},l.default.createElement("div",{className:"space__entity-grid",style:{display:"flex",height:"100%",width:"100%",flexWrap:"wrap"}},Array.from({length:i.length},(e,t)=>l.default.createElement("div",{className:"space__entity-grid__cell",style:{display:"inline-block"},key:t},l.default.createElement(o,{entity:i[t]}))),!i.length&&e.attributes.name))}function o({entity:e}){const{clickTarget:t,allClickable:a}=c(),n=a.has(e),i=e.attributes;switch(i.type){case"Grid":return l.default.createElement(r,{grid:e,isClickable:n});case"Space":return l.default.createElement(s,{space:e,isClickable:n});default:return l.default.createElement("div",{onClick:a=>{n&&(a.stopPropagation(),t(e))},className:["entity",i.player&&`player-${i.player}`,a.has(e)&&"entity--clickable"].filter(Boolean).join(" ")},e.rule.displayProperties?.map((t,a)=>l.default.createElement("div",{key:a},t,": ",e.attributes[t]?.toString())))}}function d(){const{clickTarget:e,allClickable:t,undoStep:a,currentMoveTargets:n}=c(),i=[...t].filter(e=>e.abstract);return l.default.createElement("div",{style:{position:"relative"}},l.default.createElement("button",{style:{visibility:"hidden"},className:"button button--style-b button--x-small abstract-choices__choice"},"Spacer"),l.default.createElement("div",{style:{position:"absolute",top:0,width:"100%"}},!!n.length&&l.default.createElement("button",{className:"button button--style-c button--x-small abstract-choices__choice abstract-choices__choice--undo",onClick:a},"Undo"),i.map((t,a)=>l.default.createElement("button",{key:a,className:"button button--style-b button--x-small abstract-choices__choice",onClick:()=>e(t)},t.value))))}function u({gameConnection:e}){const t=e.client.matchData,a=e.state.ctx.gameover?.winner,n=e.state.ctx.gameover?.draw;let i="";return n?i="Draw!":t&&a?i=`${t[a].name} Wins!`:a&&(i=`Player ${a} Wins!`),e.state.ctx.gameover&&l.default.createElement("div",{className:"game-status"},i)}e.Game=function({gameConnection:e,loading:t}){console.log("555gameConnection",e);const a=e?.state;return a?l.default.createElement(i,{gameConnection:e,isSpectator:!0},l.default.createElement("div",{className:"game"},l.default.createElement(d,null),l.default.createElement("div",{className:"shared-board",style:{width:"100%",display:"flex",flexWrap:"wrap",justifyContent:"center",alignItems:"center",gap:"1em"}},a.sharedBoard.entities.map((e,t)=>l.default.createElement(o,{key:t,entity:e}))),a.personalBoards&&l.default.createElement("div",{className:"personal-boards"},a.personalBoards.map((e,t)=>l.default.createElement("div",{key:t,className:"personal-board",style:{width:"100%",display:"grid",gridAutoFlow:"column",gridAutoRows:"1fr",gap:"1em"}},e.entities.map((e,t)=>l.default.createElement(o,{key:t,entity:e}))))),l.default.createElement(u,{gameConnection:e}))):t},Object.defineProperty(e,"__esModule",{value:!0})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "board-game-engine-react",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "React library for using board-game-engine",
5
5
  "main": "dist/board-game-engine-react.js",
6
6
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import { useGame } from "../contexts/game-context.js";
2
+ import { useGame } from "../../contexts/game-context.js";
3
3
 
4
4
  export default function AbstractChoices () {
5
5
  const { clickTarget, allClickable, undoStep, currentMoveTargets } = useGame()
@@ -0,0 +1,58 @@
1
+ import React from 'react'
2
+ import Entity from '../entity/entity.js'
3
+ import AbstractChoices from '../abstract-choices/abstract-choices.js'
4
+ import GameStatus from '../game-status/game-status.js'
5
+ import { GameProvider } from "../../contexts/game-context.js";
6
+
7
+ export default function Game ({ gameConnection, loading }) {
8
+ console.log('555gameConnection', gameConnection)
9
+ const G = gameConnection?.state
10
+
11
+ return G
12
+ ? (
13
+ <GameProvider
14
+ gameConnection={gameConnection}
15
+ isSpectator
16
+ >
17
+ <div className="game">
18
+ <AbstractChoices />
19
+ <div
20
+ className="shared-board"
21
+ style={{
22
+ width: '100%',
23
+ display: 'flex',
24
+ flexWrap: 'wrap',
25
+ justifyContent: 'center',
26
+ alignItems: 'center',
27
+ gap: '1em',
28
+ }}
29
+ >
30
+ {G.sharedBoard.entities.map((entity, i) => <Entity key={i} entity={entity} />)}
31
+ </div>
32
+ {G.personalBoards && (
33
+ <div className="personal-boards">
34
+ {G.personalBoards.map((board, i) => (
35
+ <div
36
+ key={i}
37
+ className="personal-board"
38
+ style={{
39
+ width: '100%',
40
+ display: 'grid',
41
+ gridAutoFlow: 'column',
42
+ gridAutoRows: '1fr',
43
+ gap: '1em',
44
+ }}
45
+ >
46
+ {board.entities.map((entity, j) => (
47
+ <Entity key={j} entity={entity} />
48
+ ))}
49
+ </div>
50
+ ))}
51
+ </div>
52
+ )}
53
+ <GameStatus gameConnection={gameConnection} />
54
+ </div>
55
+ </GameProvider>
56
+ )
57
+ : loading
58
+ }
package/src/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import './styles.scss'
2
2
 
3
- export { default } from './BoardGameEngineReact.js'
3
+ export { default as Game } from './components/game/game.js'
@@ -1,12 +0,0 @@
1
- import React, { useRef } from 'react'
2
- import PropTypes from 'prop-types'
3
-
4
- export default function BoardGameEngineReact ({}) {
5
- return (
6
- <div className="board-game-engine-react">
7
- </div>
8
- )
9
- }
10
-
11
- BoardGameEngineReact.propTypes = {
12
- }
package/src/game/game.js DELETED
@@ -1,56 +0,0 @@
1
- import React from 'react'
2
- import Entity from '../entity/entity.js'
3
- import AbstractChoices from '../abstract-choices/abstract-choices.js'
4
- import GameStatus from '../game-status/game-status.js'
5
- import { GameProvider } from "../../contexts/game-context.js";
6
-
7
- export default function Game ({ gameConnection }) {
8
- console.log('555gameConnection', gameConnection)
9
- const { G } = gameConnection.state
10
-
11
- return (
12
- <GameProvider
13
- gameConnection={gameConnection}
14
- isSpectator
15
- >
16
- <div className="game">
17
- <AbstractChoices />
18
- <div
19
- className="shared-board"
20
- style={{
21
- width: '100%',
22
- display: 'flex',
23
- flexWrap: 'wrap',
24
- justifyContent: 'center',
25
- alignItems: 'center',
26
- gap: '1em',
27
- }}
28
- >
29
- {G.sharedBoard.entities.map((entity, i) => <Entity key={i} entity={entity} />)}
30
- </div>
31
- {G.personalBoards && (
32
- <div className="personal-boards">
33
- {G.personalBoards.map((board, i) => (
34
- <div
35
- key={i}
36
- className="personal-board"
37
- style={{
38
- width: '100%',
39
- display: 'grid',
40
- gridAutoFlow: 'column',
41
- gridAutoRows: '1fr',
42
- gap: '1em',
43
- }}
44
- >
45
- {board.entities.map((entity, j) => (
46
- <Entity key={j} entity={entity} />
47
- ))}
48
- </div>
49
- ))}
50
- </div>
51
- )}
52
- <GameStatus gameConnection={gameConnection} />
53
- </div>
54
- </GameProvider>
55
- )
56
- }
File without changes
File without changes
File without changes