@omercnet/paseo-queens 0.1.0-next.128.1 → 0.1.0-next.130.1

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.
@@ -134,10 +134,10 @@ function createStyles(theme: PluginSurfaceProps["theme"], compact: boolean): Sel
134
134
  flexDirection: "row",
135
135
  flexWrap: "wrap",
136
136
  justifyContent: "center",
137
- gap: compact ? 8 : 12,
137
+ gap: compact ? 6 : 12,
138
138
  },
139
139
  step: {
140
- minWidth: compact ? 136 : 152,
140
+ minWidth: compact ? 132 : 152,
141
141
  minHeight: 44,
142
142
  flexDirection: "row",
143
143
  alignItems: "center",
@@ -161,7 +161,7 @@ function createStyles(theme: PluginSurfaceProps["theme"], compact: boolean): Sel
161
161
  fontWeight: "500",
162
162
  },
163
163
  valueBlock: {
164
- minWidth: compact ? 56 : 68,
164
+ minWidth: compact ? 52 : 68,
165
165
  flex: 1,
166
166
  alignItems: "center",
167
167
  gap: 1,
@@ -32,18 +32,44 @@ type BoardLayout = {
32
32
 
33
33
  type DragReplacement = "empty" | "excluded";
34
34
 
35
+ type DragSelection = {
36
+ readonly indexes: ReadonlySet<number>;
37
+ readonly replacement: DragReplacement;
38
+ };
39
+
35
40
  type DragGesture = {
36
41
  readonly startIndex: number;
37
- readonly indexes: Set<number>;
38
- readonly replacement: DragReplacement;
42
+ indexes: Set<number>;
43
+ replacement: DragReplacement;
39
44
  moved: boolean;
40
45
  cancelled: boolean;
41
46
  };
42
47
 
43
- type DragPreview = {
44
- readonly indexes: ReadonlySet<number>;
45
- readonly replacement: DragReplacement;
46
- };
48
+ export function resolveDraggedCellState(
49
+ index: number,
50
+ persistedState: CellState,
51
+ dragSelection: DragSelection | null,
52
+ ): CellState {
53
+ if (persistedState === "marked" || dragSelection === null || !dragSelection.indexes.has(index)) {
54
+ return persistedState;
55
+ }
56
+
57
+ if (dragSelection.replacement === "empty") {
58
+ return persistedState === "excluded" ? "empty" : persistedState;
59
+ }
60
+
61
+ return persistedState === "empty" ? "excluded" : persistedState;
62
+ }
63
+
64
+ export function collectDragIndexes(
65
+ cells: readonly CellState[],
66
+ selection: DragSelection,
67
+ ): number[] {
68
+ return [...selection.indexes].filter((index) => {
69
+ const persistedState = cells[index] ?? "empty";
70
+ return resolveDraggedCellState(index, persistedState, selection) !== persistedState;
71
+ });
72
+ }
47
73
 
48
74
  type PendingTap = {
49
75
  readonly releasedAt: number;
@@ -200,7 +226,7 @@ export function QueensBoard({
200
226
  const cellsRef = useRef(cells);
201
227
  const onSetCellsRef = useRef(onSetCells);
202
228
  const onGestureActiveChangeRef = useRef(onGestureActiveChange);
203
- const [dragPreview, setDragPreview] = useState<DragPreview | null>(null);
229
+ const [dragPreview, setDragPreview] = useState<DragSelection | null>(null);
204
230
  cellsRef.current = cells;
205
231
  onSetCellsRef.current = onSetCells;
206
232
  onGestureActiveChangeRef.current = onGestureActiveChange;
@@ -291,6 +317,7 @@ export function QueensBoard({
291
317
  },
292
318
  [dragEnabled, puzzle.size],
293
319
  );
320
+
294
321
  const finishGesture = useCallback(() => {
295
322
  const gesture = gestureRef.current;
296
323
  gestureRef.current = null;
@@ -309,11 +336,9 @@ export function QueensBoard({
309
336
  pending?.cancel();
310
337
  pendingTapsRef.current.delete(index);
311
338
  }
312
- const indexes =
313
- gesture.replacement === "empty"
314
- ? [...gesture.indexes].filter((index) => cellsRef.current[index] === "excluded")
315
- : [...gesture.indexes];
316
- onSetCellsRef.current(indexes, gesture.replacement);
339
+
340
+ const indexes = collectDragIndexes(cellsRef.current, gesture);
341
+ if (indexes.length > 0) onSetCellsRef.current(indexes, gesture.replacement);
317
342
  }, [handleTapRelease]);
318
343
 
319
344
  const cancelGesture = useCallback(() => {
@@ -330,13 +355,8 @@ export function QueensBoard({
330
355
  {coordinates.map((column) => {
331
356
  const index = row * puzzle.size + column;
332
357
  const persistedState = cells[index] ?? "empty";
333
- let state = persistedState;
334
- if (dragPreview?.indexes.has(index)) {
335
- if (dragPreview.replacement === "excluded" || persistedState === "excluded") {
336
- state = dragPreview.replacement;
337
- }
338
- }
339
358
  const region = puzzle.regions[index] ?? 0;
359
+ const state = resolveDraggedCellState(index, persistedState, dragPreview);
340
360
  const conflicted = conflicts.has(index);
341
361
  const markColor = solved
342
362
  ? theme.colors.statusSuccess
@@ -74,7 +74,6 @@ function QueensPopoverGame({
74
74
  theme,
75
75
  host,
76
76
  layout,
77
- close,
78
77
  deck,
79
78
  catalog,
80
79
  }: PluginButtonContentProps & {
@@ -151,25 +150,6 @@ function QueensPopoverGame({
151
150
 
152
151
  return (
153
152
  <View style={styles.root}>
154
- {!layout.compact ? (
155
- <View style={styles.header}>
156
- <View style={styles.titleRow}>
157
- <GameMark size={22} color={theme.colors.accent} />
158
- <Text accessibilityRole="header" style={styles.title}>
159
- Queens
160
- </Text>
161
- </View>
162
- <Pressable
163
- accessibilityRole="button"
164
- accessibilityLabel="Close Queens"
165
- onPress={close}
166
- style={styles.doneButton}
167
- >
168
- <Text style={styles.doneText}>Done</Text>
169
- </Pressable>
170
- </View>
171
- ) : null}
172
-
173
153
  <View style={styles.metaRow}>
174
154
  <Text style={styles.metaText}>
175
155
  #{puzzleNumber}/{state.puzzles.length}
@@ -207,7 +187,7 @@ function QueensPopoverGame({
207
187
  <QueensBoard
208
188
  key={`${host.id}:${puzzle.id}:popover`}
209
189
  dragEnabled={!layout.compact}
210
- maxSize={layout.compact ? 296 : 184}
190
+ maxSize={layout.compact ? 296 : 146}
211
191
  puzzle={puzzle}
212
192
  cells={progress.cells}
213
193
  conflicts={conflicts}
@@ -252,28 +232,11 @@ function QueensPopoverGame({
252
232
  function createStyles(theme: PluginButtonContentProps["theme"], compact: boolean) {
253
233
  return StyleSheet.create({
254
234
  root: {
255
- width: compact ? "100%" : 300,
235
+ width: "100%",
256
236
  alignSelf: "center",
257
237
  alignItems: "center",
258
238
  gap: compact ? 12 : 6,
259
239
  },
260
- header: {
261
- width: "100%",
262
- flexDirection: "row",
263
- alignItems: "center",
264
- justifyContent: "space-between",
265
- gap: 12,
266
- },
267
- titleRow: {
268
- flexDirection: "row",
269
- alignItems: "center",
270
- gap: 8,
271
- },
272
- title: {
273
- color: theme.colors.foreground,
274
- fontSize: 18,
275
- fontWeight: "800",
276
- },
277
240
  doneButton: {
278
241
  minHeight: 36,
279
242
  justifyContent: "center",
@@ -307,7 +270,7 @@ function createStyles(theme: PluginButtonContentProps["theme"], compact: boolean
307
270
  },
308
271
  boardFrame: {
309
272
  width: "100%",
310
- maxWidth: compact ? 296 : 184,
273
+ maxWidth: compact ? 296 : 146,
311
274
  },
312
275
  statusCard: {
313
276
  minHeight: 30,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omercnet/paseo-queens",
3
- "version": "0.1.0-next.128.1",
3
+ "version": "0.1.0-next.130.1",
4
4
  "type": "module",
5
5
  "description": "A cross-platform Queens logic puzzle for Paseo.",
6
6
  "license": "MIT",
@@ -38,17 +38,22 @@
38
38
  "paseo-plugin.json"
39
39
  ],
40
40
  "scripts": {
41
- "check": "biome check .",
41
+ "check": "biome check --error-on-warnings .",
42
42
  "import:puzzles": "node scripts/import-curated-puzzles.mjs",
43
- "test": "vitest run",
43
+ "test": "run-s test:ci:*",
44
44
  "typecheck": "tsc --noEmit",
45
- "verify:package": "npm pack --dry-run"
45
+ "verify:package": "npm pack --dry-run",
46
+ "check:write": "biome check --write .",
47
+ "test:ci:unit": "vitest run",
48
+ "build": "node ../.github/scripts/build-plugin.mjs"
46
49
  },
47
50
  "devDependencies": {
48
- "@biomejs/biome": "^2.5.10",
51
+ "@biomejs/biome": "^2.5.14",
49
52
  "@getpaseo/plugin": "0.9.0-beta.1",
53
+ "@getpaseo/server": "0.9.0-beta.1",
50
54
  "@types/node": "^24.5.2",
51
55
  "@types/react": "~19.2.0",
56
+ "npm-run-all2": "^9.0.3",
52
57
  "react": "19.1.0",
53
58
  "react-native": "0.81.5",
54
59
  "typescript": "^7.0.0",