@griddle/react 0.1.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/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { GriddleGrid } from './GriddleGrid.js';
2
+ export type { GriddleGridProps } from './GriddleGrid.js';
3
+ export { GriddleLoopGrid } from './LoopGrid.js';
4
+ export { useGriddle, useGridVersion } from './useGriddle.js';
5
+ export type { GriddleApi, UseGriddleInit } from './useGriddle.js';
@@ -0,0 +1,70 @@
1
+ // React hook that wraps a Grid instance and provides reactive state.
2
+
3
+ import { useEffect, useMemo, useState, useSyncExternalStore } from 'react';
4
+ import { Grid } from '@griddle/core';
5
+ import type { GridConfig, Tile, GridSnapshot } from '@griddle/core';
6
+
7
+ export interface UseGriddleInit {
8
+ config: GridConfig;
9
+ tiles?: Tile[];
10
+ }
11
+
12
+ export interface GriddleApi {
13
+ readonly grid: Grid;
14
+ readonly tiles: Tile[];
15
+ readonly config: GridConfig;
16
+ moveTile: (id: string, target: { col: number; row: number }) => boolean;
17
+ resizeTile: (id: string, size: { w: number; h: number }) => boolean;
18
+ addTile: (tile: Tile) => void;
19
+ removeTile: (id: string) => void;
20
+ updateConfig: (patch: Partial<GridConfig>) => void;
21
+ toJSON: () => GridSnapshot;
22
+ loadJSON: (snap: GridSnapshot) => void;
23
+ /** monotonic version used to trigger re-renders */
24
+ readonly version: number;
25
+ }
26
+
27
+ export function useGriddle(init: UseGriddleInit | (() => UseGriddleInit)): GriddleApi {
28
+ const [grid] = useState(() => {
29
+ const i = typeof init === 'function' ? init() : init;
30
+ return new Grid(i.config, i.tiles ?? []);
31
+ });
32
+
33
+ const version = useSyncExternalStore(
34
+ (cb) => {
35
+ const off = grid.changes.on(() => cb());
36
+ return off;
37
+ },
38
+ () => grid.tiles.length + '|' + JSON.stringify(grid.config),
39
+ () => grid.tiles.length + '|' + JSON.stringify(grid.config),
40
+ );
41
+
42
+ // Stable API object
43
+ const api = useMemo<GriddleApi>(() => {
44
+ return {
45
+ grid,
46
+ get tiles() { return grid.tiles; },
47
+ get config() { return grid.config; },
48
+ moveTile: (id, target) => grid.moveTile(id, target),
49
+ resizeTile: (id, size) => grid.resizeTile(id, size),
50
+ addTile: (t) => grid.addTile(t),
51
+ removeTile: (id) => grid.removeTile(id),
52
+ updateConfig: (patch) => grid.updateConfig(patch),
53
+ toJSON: () => grid.toJSON(),
54
+ loadJSON: (snap) => grid.loadJSON(snap),
55
+ version: 0,
56
+ };
57
+ }, [grid]);
58
+
59
+ // version bump for consumers that prefer plain re-renders
60
+ (api as { version: number }).version = typeof version === 'string' ? version.length : version;
61
+
62
+ return api;
63
+ }
64
+
65
+ /** Subscribe to grid changes in any component. */
66
+ export function useGridVersion(grid: Grid): number {
67
+ const [v, setV] = useState(0);
68
+ useEffect(() => grid.changes.on(() => setV((x) => x + 1)), [grid]);
69
+ return v;
70
+ }