react-native-smart-grid 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/LICENSE +20 -0
- package/README.md +554 -0
- package/lib/module/components/DragLayer.js +71 -0
- package/lib/module/components/DragLayer.js.map +1 -0
- package/lib/module/components/DraggableTile.js +79 -0
- package/lib/module/components/DraggableTile.js.map +1 -0
- package/lib/module/components/GhostTile.js +37 -0
- package/lib/module/components/GhostTile.js.map +1 -0
- package/lib/module/components/GridTile.js +25 -0
- package/lib/module/components/GridTile.js.map +1 -0
- package/lib/module/components/ResizeHandle.js +72 -0
- package/lib/module/components/ResizeHandle.js.map +1 -0
- package/lib/module/components/SmartGrid.js +363 -0
- package/lib/module/components/SmartGrid.js.map +1 -0
- package/lib/module/context/GridDragContext.js +130 -0
- package/lib/module/context/GridDragContext.js.map +1 -0
- package/lib/module/engine/GridEngine.js +148 -0
- package/lib/module/engine/GridEngine.js.map +1 -0
- package/lib/module/engine/autoArrange.js +54 -0
- package/lib/module/engine/autoArrange.js.map +1 -0
- package/lib/module/engine/collisions.js +67 -0
- package/lib/module/engine/collisions.js.map +1 -0
- package/lib/module/hooks/useTileGesture.js +62 -0
- package/lib/module/hooks/useTileGesture.js.map +1 -0
- package/lib/module/index.js +9 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/layout/LayoutCalculator.js +29 -0
- package/lib/module/layout/LayoutCalculator.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/utils/pixelToGrid.js +22 -0
- package/lib/module/utils/pixelToGrid.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/components/DragLayer.d.ts +11 -0
- package/lib/typescript/src/components/DragLayer.d.ts.map +1 -0
- package/lib/typescript/src/components/DraggableTile.d.ts +14 -0
- package/lib/typescript/src/components/DraggableTile.d.ts.map +1 -0
- package/lib/typescript/src/components/GhostTile.d.ts +9 -0
- package/lib/typescript/src/components/GhostTile.d.ts.map +1 -0
- package/lib/typescript/src/components/GridTile.d.ts +9 -0
- package/lib/typescript/src/components/GridTile.d.ts.map +1 -0
- package/lib/typescript/src/components/ResizeHandle.d.ts +9 -0
- package/lib/typescript/src/components/ResizeHandle.d.ts.map +1 -0
- package/lib/typescript/src/components/SmartGrid.d.ts +214 -0
- package/lib/typescript/src/components/SmartGrid.d.ts.map +1 -0
- package/lib/typescript/src/context/GridDragContext.d.ts +44 -0
- package/lib/typescript/src/context/GridDragContext.d.ts.map +1 -0
- package/lib/typescript/src/engine/GridEngine.d.ts +35 -0
- package/lib/typescript/src/engine/GridEngine.d.ts.map +1 -0
- package/lib/typescript/src/engine/autoArrange.d.ts +4 -0
- package/lib/typescript/src/engine/autoArrange.d.ts.map +1 -0
- package/lib/typescript/src/engine/collisions.d.ts +3 -0
- package/lib/typescript/src/engine/collisions.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useTileGesture.d.ts +13 -0
- package/lib/typescript/src/hooks/useTileGesture.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +10 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/layout/LayoutCalculator.d.ts +15 -0
- package/lib/typescript/src/layout/LayoutCalculator.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +105 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/utils/pixelToGrid.d.ts +9 -0
- package/lib/typescript/src/utils/pixelToGrid.d.ts.map +1 -0
- package/package.json +161 -0
- package/src/components/DragLayer.tsx +71 -0
- package/src/components/DraggableTile.tsx +88 -0
- package/src/components/GhostTile.tsx +42 -0
- package/src/components/GridTile.tsx +27 -0
- package/src/components/ResizeHandle.tsx +74 -0
- package/src/components/SmartGrid.tsx +506 -0
- package/src/context/GridDragContext.tsx +191 -0
- package/src/engine/GridEngine.ts +148 -0
- package/src/engine/autoArrange.ts +59 -0
- package/src/engine/collisions.ts +87 -0
- package/src/hooks/useTileGesture.ts +88 -0
- package/src/index.tsx +29 -0
- package/src/layout/LayoutCalculator.ts +50 -0
- package/src/types.ts +113 -0
- package/src/utils/pixelToGrid.ts +31 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PlacedTile, GridConfig } from '../types.js';
|
|
2
|
+
type Props = {
|
|
3
|
+
activeTile: PlacedTile;
|
|
4
|
+
config: GridConfig;
|
|
5
|
+
containerWidth: number;
|
|
6
|
+
};
|
|
7
|
+
export declare const GhostTile: import("react").MemoExoticComponent<({ activeTile, config, containerWidth, }: Props) => import("react").JSX.Element | null>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=GhostTile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GhostTile.d.ts","sourceRoot":"","sources":["../../../../src/components/GhostTile.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAU,CAAC;AAIvD,KAAK,KAAK,GAAG;IACX,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,SAAS,gFAInB,KAAK,wCAcN,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { PixelRect } from '../layout/LayoutCalculator.js';
|
|
3
|
+
type Props = {
|
|
4
|
+
rect: PixelRect;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
};
|
|
7
|
+
export declare const GridTile: React.MemoExoticComponent<({ rect, children }: Props) => React.JSX.Element>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=GridTile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GridTile.d.ts","sourceRoot":"","sources":["../../../../src/components/GridTile.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAe,MAAM,OAAO,CAAC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA4B,CAAC;AAE5D,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,QAAQ,iDAA8C,KAAK,uBAWtE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PlacedTile, GridConfig } from '../types.js';
|
|
2
|
+
type Props = {
|
|
3
|
+
tile: PlacedTile;
|
|
4
|
+
config: GridConfig;
|
|
5
|
+
containerWidth: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function ResizeHandle({ tile, config, containerWidth }: Props): import("react").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=ResizeHandle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResizeHandle.d.ts","sourceRoot":"","sources":["../../../../src/components/ResizeHandle.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAY,UAAU,EAAE,MAAM,aAAU,CAAC;AAIjE,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,KAAK,+BA+CnE"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Tile, CollisionBehavior, Gravity, TilePosition, TileSize, HapticEvent, LayoutItem } from '../types.js';
|
|
3
|
+
/** Imperative handle exposed via `ref`. */
|
|
4
|
+
export type SmartGridRef = {
|
|
5
|
+
/** Re-packs all tiles using largest-first bin-packing. Fires `onLayoutChange`. */
|
|
6
|
+
autoArrange: () => void;
|
|
7
|
+
/** Returns a plain `LayoutItem[]` you can JSON.stringify and save anywhere. Does not include tile `data`. */
|
|
8
|
+
serializeLayout: () => LayoutItem[];
|
|
9
|
+
/** Restores a previously serialized layout. Fires `onLayoutChange`. */
|
|
10
|
+
restoreLayout: (layout: LayoutItem[]) => void;
|
|
11
|
+
/** Clears the entire selection. Equivalent to `setSelection([])`. */
|
|
12
|
+
clearSelection: () => void;
|
|
13
|
+
/** Programmatically set the selected tile IDs. Pass `[]` to clear. Fires `onSelectionChange`. */
|
|
14
|
+
setSelection: (ids: string[]) => void;
|
|
15
|
+
};
|
|
16
|
+
/** Argument passed to `renderTile`. */
|
|
17
|
+
export type RenderTileInfo<TData> = {
|
|
18
|
+
/** The tile being rendered, including your custom `data`. */
|
|
19
|
+
item: Tile<TData>;
|
|
20
|
+
/** `true` while this tile is actively being dragged (the placeholder left behind). */
|
|
21
|
+
isActive: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* `true` when this tile is in the current selection.
|
|
24
|
+
* Selection is entered via long press — either immediately (when `draggable={false}`)
|
|
25
|
+
* or on release without moving (when draggable). Use to show contextual actions like a delete button.
|
|
26
|
+
*/
|
|
27
|
+
isSelected: boolean;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Props for `SmartGrid`.
|
|
31
|
+
*
|
|
32
|
+
* `position` and `size` on each tile are optional:
|
|
33
|
+
* - Both provided → tile is placed exactly where specified.
|
|
34
|
+
* - `size` only → tile is auto-placed via bin-packing.
|
|
35
|
+
* - Neither → tile defaults to 1×1 and is auto-placed in order.
|
|
36
|
+
*/
|
|
37
|
+
export type SmartGridProps<TData = unknown> = {
|
|
38
|
+
/** Array of tiles to render. `position` and `size` are optional — omit them to let the grid auto-place. */
|
|
39
|
+
data: Tile<TData>[];
|
|
40
|
+
/** Render function for each tile. Return any React Native view — SmartGrid handles absolute positioning. */
|
|
41
|
+
renderTile: (info: RenderTileInfo<TData>) => React.ReactNode;
|
|
42
|
+
/** Number of grid columns. @default 4 */
|
|
43
|
+
columns?: number;
|
|
44
|
+
/** Height of one grid row in pixels. @default 100 */
|
|
45
|
+
rowHeight?: number;
|
|
46
|
+
/** Gap between tiles in pixels. @default 8 */
|
|
47
|
+
gap?: number;
|
|
48
|
+
/** Outer padding of the grid in pixels. @default 8 */
|
|
49
|
+
padding?: number;
|
|
50
|
+
/**
|
|
51
|
+
* How dropped tiles interact with tiles already occupying the target space.
|
|
52
|
+
* - `'push'` — displaced tiles are moved to the next available slot.
|
|
53
|
+
* - `'swap'` — dragged tile and the tile at the drop center exchange positions.
|
|
54
|
+
* @default 'push'
|
|
55
|
+
*/
|
|
56
|
+
collisionBehavior?: CollisionBehavior;
|
|
57
|
+
/**
|
|
58
|
+
* Compact tiles toward the origin after every drop.
|
|
59
|
+
* - `'none'` — tiles stay where dropped.
|
|
60
|
+
* - `'up'` — tiles slide upward to fill empty rows.
|
|
61
|
+
* - `'left'` — tiles slide left to fill empty columns.
|
|
62
|
+
* @default 'none'
|
|
63
|
+
*/
|
|
64
|
+
gravity?: Gravity;
|
|
65
|
+
/** When `true`, shows a resize handle on each tile's bottom-right corner. @default false */
|
|
66
|
+
isEditing?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Master switch — when `false`, no tile in the grid can be dragged regardless of individual `tile.draggable` flags.
|
|
69
|
+
* @default true
|
|
70
|
+
*/
|
|
71
|
+
draggable?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Master switch — when `false`, no tile in the grid can be selected regardless of individual `tile.selectable` flags.
|
|
74
|
+
* @default true
|
|
75
|
+
*/
|
|
76
|
+
selectable?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* When `true`, long-pressing multiple tiles adds them all to the selection array.
|
|
79
|
+
* When `false`, selecting a tile deselects all others (single-select mode).
|
|
80
|
+
* @default true
|
|
81
|
+
*/
|
|
82
|
+
multiSelect?: boolean;
|
|
83
|
+
/** Called after every drag, drop, or resize with the updated `LayoutItem[]`. Merge this back into your state to keep the grid in sync. */
|
|
84
|
+
onLayoutChange?: (layout: LayoutItem[]) => void;
|
|
85
|
+
/** Called when the user taps a tile (quick press, no drag). Use this to open detail views, modals, folders, etc. */
|
|
86
|
+
onTilePress?: (tile: Tile<TData>) => void;
|
|
87
|
+
/** Called when the user begins dragging a tile (fires after the 300ms long-press activates, before the first move). */
|
|
88
|
+
onTileDragStart?: (tile: Tile<TData>) => void;
|
|
89
|
+
/** Called when a tile is dropped at a new position. */
|
|
90
|
+
onTileDrop?: (tile: Tile<TData>, position: TilePosition) => void;
|
|
91
|
+
/** Called when a tile is resized via the resize handle. */
|
|
92
|
+
onTileResize?: (tile: Tile<TData>, newSize: TileSize) => void;
|
|
93
|
+
/**
|
|
94
|
+
* Called whenever the selection array changes. Receives the full array of currently selected tile IDs.
|
|
95
|
+
*
|
|
96
|
+
* Selection changes when:
|
|
97
|
+
* - Long press on a tile toggles it (immediately if `draggable={false}`, on release otherwise).
|
|
98
|
+
* - Tap on a tile while selection is active toggles it.
|
|
99
|
+
* - A real drag-and-drop clears the entire selection.
|
|
100
|
+
* - `clearSelection()` or `setSelection()` is called on the ref.
|
|
101
|
+
*/
|
|
102
|
+
onSelectionChange?: (ids: string[]) => void;
|
|
103
|
+
/**
|
|
104
|
+
* Called at key interaction moments so you can trigger haptic feedback
|
|
105
|
+
* with whichever haptics library you prefer — no dependency added.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* onHaptic={(event) => {
|
|
109
|
+
* if (event === 'pick-up') HapticFeedback.trigger('impactMedium');
|
|
110
|
+
* if (event === 'snap') HapticFeedback.trigger('selection');
|
|
111
|
+
* if (event === 'drop') HapticFeedback.trigger('notificationSuccess');
|
|
112
|
+
* if (event === 'resize') HapticFeedback.trigger('impactLight');
|
|
113
|
+
* }}
|
|
114
|
+
*/
|
|
115
|
+
onHaptic?: (event: HapticEvent) => void;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* A draggable, variable-sized tile grid for React Native.
|
|
119
|
+
*
|
|
120
|
+
* ---
|
|
121
|
+
*
|
|
122
|
+
* ### Basic usage
|
|
123
|
+
* ```tsx
|
|
124
|
+
* const gridRef = useRef<SmartGridRef>(null);
|
|
125
|
+
*
|
|
126
|
+
* <SmartGrid
|
|
127
|
+
* ref={gridRef}
|
|
128
|
+
* data={tiles}
|
|
129
|
+
* columns={4}
|
|
130
|
+
* rowHeight={100}
|
|
131
|
+
* gap={8}
|
|
132
|
+
* collisionBehavior="push"
|
|
133
|
+
* gravity="up"
|
|
134
|
+
* isEditing={isEditing}
|
|
135
|
+
* onLayoutChange={(layout) =>
|
|
136
|
+
* setTiles(prev =>
|
|
137
|
+
* prev.map(t => {
|
|
138
|
+
* const updated = layout.find(l => l.id === t.id);
|
|
139
|
+
* return updated ? { ...t, ...updated } : t;
|
|
140
|
+
* })
|
|
141
|
+
* )
|
|
142
|
+
* }
|
|
143
|
+
* renderTile={({ item, isActive, isSelected }) => (
|
|
144
|
+
* <View style={{ flex: 1, opacity: isActive ? 0.5 : 1,
|
|
145
|
+
* borderWidth: isSelected ? 2 : 0, borderColor: '#fff' }}>
|
|
146
|
+
* <Text>{item.data.label}</Text>
|
|
147
|
+
* </View>
|
|
148
|
+
* )}
|
|
149
|
+
* />
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* ---
|
|
153
|
+
*
|
|
154
|
+
* ### Selection (long press + release)
|
|
155
|
+
* Long-pressing a tile and releasing without moving selects it.
|
|
156
|
+
* Tapping any tile while a selection is active toggles that tile too.
|
|
157
|
+
*
|
|
158
|
+
* ```tsx
|
|
159
|
+
* // Multi-select (default) — accumulate selections
|
|
160
|
+
* <SmartGrid
|
|
161
|
+
* multiSelect // true by default, can omit
|
|
162
|
+
* onSelectionChange={(ids) => console.log('selected:', ids)}
|
|
163
|
+
* renderTile={({ item, isSelected }) => (
|
|
164
|
+
* <View>
|
|
165
|
+
* <Text>{item.data.label}</Text>
|
|
166
|
+
* {isSelected && <Text>✕ Delete</Text>}
|
|
167
|
+
* </View>
|
|
168
|
+
* )}
|
|
169
|
+
* />
|
|
170
|
+
*
|
|
171
|
+
* // Single-select — picking a new tile deselects the previous one
|
|
172
|
+
* <SmartGrid
|
|
173
|
+
* multiSelect={false}
|
|
174
|
+
* onSelectionChange={([id]) => setActive(id ?? null)}
|
|
175
|
+
* />
|
|
176
|
+
*
|
|
177
|
+
* // Clear selection imperatively
|
|
178
|
+
* gridRef.current?.clearSelection();
|
|
179
|
+
*
|
|
180
|
+
* // Or set it programmatically
|
|
181
|
+
* gridRef.current?.setSelection(['tile-1', 'tile-3']);
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* ---
|
|
185
|
+
*
|
|
186
|
+
* ### Grid-level draggable / selectable master switches
|
|
187
|
+
* These override all per-tile flags when set to `false`.
|
|
188
|
+
* ```tsx
|
|
189
|
+
* // View-only mode — nothing can be dragged or selected
|
|
190
|
+
* <SmartGrid draggable={false} selectable={false} data={tiles} ... />
|
|
191
|
+
*
|
|
192
|
+
* // Read-only layout — tiles are visible but locked in place
|
|
193
|
+
* <SmartGrid draggable={false} data={tiles} ... />
|
|
194
|
+
*
|
|
195
|
+
* // Selection disabled — long press does nothing (onTilePress still fires on tap)
|
|
196
|
+
* <SmartGrid selectable={false} data={tiles} ... />
|
|
197
|
+
* ```
|
|
198
|
+
*
|
|
199
|
+
* ### Per-tile draggable / selectable flags
|
|
200
|
+
* Fine-grained control per tile when the grid-level switches are on.
|
|
201
|
+
* ```tsx
|
|
202
|
+
* const tiles: Tile<MyData>[] = [
|
|
203
|
+
* { id: '1', data: { label: 'Free' } },
|
|
204
|
+
* // Stays pinned in place — cannot be dragged
|
|
205
|
+
* { id: '2', data: { label: 'Pinned' }, draggable: false },
|
|
206
|
+
* // Ignored by selection — tapping fires onTilePress instead
|
|
207
|
+
* { id: '3', data: { label: 'Info' }, selectable: false },
|
|
208
|
+
* ];
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
export declare const SmartGrid: <TData = unknown>(props: SmartGridProps<TData> & {
|
|
212
|
+
ref?: React.Ref<SmartGridRef>;
|
|
213
|
+
}) => React.ReactElement | null;
|
|
214
|
+
//# sourceMappingURL=SmartGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmartGrid.d.ts","sourceRoot":"","sources":["../../../../src/components/SmartGrid.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { SharedValue } from 'react-native-reanimated';
|
|
3
|
+
import type { PlacedTile, TilePosition, TileSize, HapticEvent } from '../types.js';
|
|
4
|
+
import type { PixelRect } from '../layout/LayoutCalculator.js';
|
|
5
|
+
export type DragState = {
|
|
6
|
+
dragAbsX: SharedValue<number>;
|
|
7
|
+
dragAbsY: SharedValue<number>;
|
|
8
|
+
isDragging: SharedValue<boolean>;
|
|
9
|
+
activeTile: PlacedTile | null;
|
|
10
|
+
ghostPosition: TilePosition | null;
|
|
11
|
+
initialRect: PixelRect | null;
|
|
12
|
+
selectedTileIds: string[];
|
|
13
|
+
containerPageX: React.MutableRefObject<number>;
|
|
14
|
+
containerPageY: React.MutableRefObject<number>;
|
|
15
|
+
scrollYRef: React.MutableRefObject<number>;
|
|
16
|
+
startDrag: (tile: PlacedTile, rect: PixelRect) => void;
|
|
17
|
+
updateGhost: (pos: TilePosition) => void;
|
|
18
|
+
endDrag: (finalPosition: TilePosition | null) => void;
|
|
19
|
+
selectTile: (tile: PlacedTile) => void;
|
|
20
|
+
onTilePress: (tile: PlacedTile) => void;
|
|
21
|
+
isEditing: boolean;
|
|
22
|
+
/** Grid-level master switch — false disables drag on every tile. */
|
|
23
|
+
draggable: boolean;
|
|
24
|
+
/** Grid-level master switch — false disables selection on every tile. */
|
|
25
|
+
selectable: boolean;
|
|
26
|
+
commitResize: (tile: PlacedTile, newSize: TileSize) => void;
|
|
27
|
+
};
|
|
28
|
+
export declare function useGridDrag(): DragState;
|
|
29
|
+
type Props = {
|
|
30
|
+
children: React.ReactNode;
|
|
31
|
+
isEditing: boolean;
|
|
32
|
+
draggable: boolean;
|
|
33
|
+
selectable: boolean;
|
|
34
|
+
multiSelect: boolean;
|
|
35
|
+
selectedTileIds: string[];
|
|
36
|
+
onDrop: (tile: PlacedTile, newPosition: TilePosition) => void;
|
|
37
|
+
onResize: (tile: PlacedTile, newSize: TileSize) => void;
|
|
38
|
+
onSelect: (ids: string[]) => void;
|
|
39
|
+
onTilePress?: (tile: PlacedTile) => void;
|
|
40
|
+
onHaptic?: (event: HapticEvent) => void;
|
|
41
|
+
};
|
|
42
|
+
export declare function GridDragProvider({ children, isEditing, draggable, selectable, multiSelect, selectedTileIds, onDrop, onResize, onSelect, onTilePress, onHaptic, }: Props): React.JSX.Element;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=GridDragContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GridDragContext.d.ts","sourceRoot":"","sources":["../../../../src/context/GridDragContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsD,MAAM,OAAO,CAAC;AAE3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAU,CAAC;AAChF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA4B,CAAC;AAE5D,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9B,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAEjC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,WAAW,EAAE,SAAS,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAC;IAE1B,cAAc,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC/C,cAAc,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC/C,UAAU,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAE3C,SAAS,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;IACvD,WAAW,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACzC,OAAO,EAAE,CAAC,aAAa,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAC;IACtD,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,WAAW,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IAExC,SAAS,EAAE,OAAO,CAAC;IACnB,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC7D,CAAC;AAIF,wBAAgB,WAAW,IAAI,SAAS,CAIvC;AAED,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,KAAK,IAAI,CAAC;IAC9D,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;IACxD,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAClC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CACzC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,SAAS,EACT,SAAS,EACT,UAAU,EACV,WAAW,EACX,eAAe,EACf,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,QAAQ,GACT,EAAE,KAAK,qBA0HP"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { LayoutItem, TilePosition, TileSize } from '../types.js';
|
|
2
|
+
export declare class GridEngine {
|
|
3
|
+
private matrix;
|
|
4
|
+
private columns;
|
|
5
|
+
constructor(columns: number, initialRows?: number);
|
|
6
|
+
private static createMatrix;
|
|
7
|
+
get rowCount(): number;
|
|
8
|
+
get columnCount(): number;
|
|
9
|
+
isOccupied(pos: TilePosition, size: TileSize, ignoreId?: string): boolean;
|
|
10
|
+
isInBounds(pos: TilePosition, size: TileSize): boolean;
|
|
11
|
+
placeAt(id: string, pos: TilePosition, size: TileSize): void;
|
|
12
|
+
removeFrom(pos: TilePosition, size: TileSize): void;
|
|
13
|
+
removeById(id: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Scan top-left to bottom-right for the first position where `size` fits.
|
|
16
|
+
* Returns null if the grid (up to maxRows) is full.
|
|
17
|
+
*/
|
|
18
|
+
findFirstFit(size: TileSize, maxRows?: number): TilePosition | null;
|
|
19
|
+
/**
|
|
20
|
+
* Returns ids of all tiles that overlap the given region, excluding ignoreId.
|
|
21
|
+
*/
|
|
22
|
+
getCollisions(pos: TilePosition, size: TileSize, ignoreId?: string): Set<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Rebuild the entire matrix from a layout snapshot.
|
|
25
|
+
* Call this when restoring a saved layout.
|
|
26
|
+
*/
|
|
27
|
+
loadLayout(items: LayoutItem[]): void;
|
|
28
|
+
/**
|
|
29
|
+
* Dump the positions of all occupied cells grouped by tile id.
|
|
30
|
+
* Useful for debugging — not the same as a layout snapshot.
|
|
31
|
+
*/
|
|
32
|
+
debugDump(): Record<string, TilePosition[]>;
|
|
33
|
+
private growIfNeeded;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=GridEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GridEngine.d.ts","sourceRoot":"","sources":["../../../../src/engine/GridEngine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAU,CAAC;AAMnE,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM,EAAE,WAAW,SAAK;IAK7C,OAAO,CAAC,MAAM,CAAC,YAAY;IAM3B,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAID,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAYzE,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO;IAItD,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IAS5D,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI;IASnD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAY5B;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,SAA8B,GAAG,YAAY,GAAG,IAAI;IAWxF;;OAEG;IACH,aAAa,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAehF;;;OAGG;IACH,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAQrC;;;OAGG;IACH,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC;IAgB3C,OAAO,CAAC,YAAY;CAKrB"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PlacedTile, Gravity } from '../types.js';
|
|
2
|
+
export declare function autoArrange<TData>(tiles: PlacedTile<TData>[], columns: number): PlacedTile<TData>[];
|
|
3
|
+
export declare function applyGravity<TData>(tiles: PlacedTile<TData>[], columns: number, gravity: Gravity): PlacedTile<TData>[];
|
|
4
|
+
//# sourceMappingURL=autoArrange.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autoArrange.d.ts","sourceRoot":"","sources":["../../../../src/engine/autoArrange.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAgB,OAAO,EAAE,MAAM,aAAU,CAAC;AAElE,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,CAenG;AAED,wBAAgB,YAAY,CAAC,KAAK,EAChC,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,EAC1B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,GACf,UAAU,CAAC,KAAK,CAAC,EAAE,CAmBrB"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { PlacedTile, TilePosition, CollisionBehavior } from '../types.js';
|
|
2
|
+
export declare function resolveCollisions<TData>(tiles: PlacedTile<TData>[], draggedId: string, targetPosition: TilePosition, behavior: CollisionBehavior, columns: number): PlacedTile<TData>[];
|
|
3
|
+
//# sourceMappingURL=collisions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collisions.d.ts","sourceRoot":"","sources":["../../../../src/engine/collisions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAU,CAAC;AAE5E,wBAAgB,iBAAiB,CAAC,KAAK,EACrC,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,EAC1B,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,YAAY,EAC5B,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,MAAM,GACd,UAAU,CAAC,KAAK,CAAC,EAAE,CAGrB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PlacedTile, GridConfig } from '../types.js';
|
|
2
|
+
import type { PixelRect } from '../layout/LayoutCalculator.js';
|
|
3
|
+
type Options = {
|
|
4
|
+
tile: PlacedTile;
|
|
5
|
+
rect: PixelRect;
|
|
6
|
+
config: GridConfig;
|
|
7
|
+
containerWidth: number;
|
|
8
|
+
};
|
|
9
|
+
export declare function useTileGesture({ tile, rect, config, containerWidth }: Options): {
|
|
10
|
+
gesture: import("react-native-gesture-handler/lib/typescript/handlers/gestures/gestureComposition").SimultaneousGesture;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=useTileGesture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTileGesture.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useTileGesture.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAU,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA4B,CAAC;AAI5D,KAAK,OAAO,GAAG;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,OAAO;;EAyE7E"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type { Tile, PlacedTile, TileSize, TilePosition, GridConfig, CollisionBehavior, Gravity, HapticEvent, LayoutItem, SerializedLayout, } from './types.js';
|
|
2
|
+
export { GridEngine } from './engine/GridEngine.js';
|
|
3
|
+
export { resolveCollisions } from './engine/collisions.js';
|
|
4
|
+
export { autoArrange, applyGravity } from './engine/autoArrange.js';
|
|
5
|
+
export type { PixelRect } from './layout/LayoutCalculator.js';
|
|
6
|
+
export { columnWidth, tileToPixelRect, gridTotalHeight, isInViewport, } from './layout/LayoutCalculator.js';
|
|
7
|
+
export { pixelToGrid } from './utils/pixelToGrid.js';
|
|
8
|
+
export type { SmartGridRef, RenderTileInfo, SmartGridProps } from './components/SmartGrid.js';
|
|
9
|
+
export { SmartGrid } from './components/SmartGrid.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,YAAY,EACV,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,OAAO,EACP,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,MAAM,YAAS,CAAC;AAEjB,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAqB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAqB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,yBAAsB,CAAC;AAEjE,YAAY,EAAE,SAAS,EAAE,MAAM,8BAA2B,CAAC;AAC3D,OAAO,EACL,WAAW,EACX,eAAe,EACf,eAAe,EACf,YAAY,GACb,MAAM,8BAA2B,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAqB,CAAC;AAElD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,2BAAwB,CAAC;AAC3F,OAAO,EAAE,SAAS,EAAE,MAAM,2BAAwB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TilePosition, TileSize, GridConfig } from '../types.js';
|
|
2
|
+
export type PixelRect = {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
};
|
|
8
|
+
export declare function columnWidth(config: GridConfig, containerWidth: number): number;
|
|
9
|
+
export declare function tileToPixelRect(position: TilePosition, size: TileSize, config: GridConfig, containerWidth: number): PixelRect;
|
|
10
|
+
export declare function gridTotalHeight(tiles: Array<{
|
|
11
|
+
position: TilePosition;
|
|
12
|
+
size: TileSize;
|
|
13
|
+
}>, config: GridConfig): number;
|
|
14
|
+
export declare function isInViewport(rect: PixelRect, scrollY: number, viewportHeight: number, overscan?: number): boolean;
|
|
15
|
+
//# sourceMappingURL=LayoutCalculator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LayoutCalculator.d.ts","sourceRoot":"","sources":["../../../../src/layout/LayoutCalculator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAU,CAAC;AAEnE,MAAM,MAAM,SAAS,GAAG;IACtB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAG9E;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,cAAc,EAAE,MAAM,GACrB,SAAS,CASX;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,EACxD,MAAM,EAAE,UAAU,GACjB,MAAM,CAIR;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,MAAM,EACtB,QAAQ,SAAM,GACb,OAAO,CAKT"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/** Width and height of a tile in grid units. */
|
|
2
|
+
export type TileSize = {
|
|
3
|
+
/** Number of grid columns spanned. */
|
|
4
|
+
w: number;
|
|
5
|
+
/** Number of grid rows spanned. */
|
|
6
|
+
h: number;
|
|
7
|
+
};
|
|
8
|
+
/** Column/row position of a tile's top-left corner (0-based). */
|
|
9
|
+
export type TilePosition = {
|
|
10
|
+
/** Column index (0-based). */
|
|
11
|
+
x: number;
|
|
12
|
+
/** Row index (0-based). */
|
|
13
|
+
y: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A single tile in the grid.
|
|
17
|
+
*
|
|
18
|
+
* `position` and `size` are both optional:
|
|
19
|
+
* - Both provided → tile is placed exactly where specified (use when restoring a saved layout).
|
|
20
|
+
* - `size` only → tile is auto-placed via bin-packing.
|
|
21
|
+
* - Neither → tile defaults to 1×1 and is auto-placed in order.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* // Explicit position + size (restored from storage)
|
|
26
|
+
* { id: '1', position: { x: 0, y: 0 }, size: { w: 2, h: 2 }, data: { label: 'Music' } }
|
|
27
|
+
*
|
|
28
|
+
* // Size only — grid chooses placement
|
|
29
|
+
* { id: '2', size: { w: 2, h: 1 }, data: { label: 'Photos' } }
|
|
30
|
+
*
|
|
31
|
+
* // No position, no size — defaults to 1×1, auto-placed in order
|
|
32
|
+
* { id: '3', data: { label: 'Notes' } }
|
|
33
|
+
*
|
|
34
|
+
* // Pinned tile — cannot be dragged
|
|
35
|
+
* { id: '4', data: { label: 'Header' }, draggable: false }
|
|
36
|
+
*
|
|
37
|
+
* // Non-selectable tile — long press fires onTilePress instead of entering selection
|
|
38
|
+
* { id: '5', data: { label: 'Info' }, selectable: false }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export type Tile<TData = unknown> = {
|
|
42
|
+
/** Unique identifier. Must be stable across re-renders. */
|
|
43
|
+
id: string;
|
|
44
|
+
/** Tile dimensions in grid units. Omit to default to 1×1. */
|
|
45
|
+
size?: TileSize;
|
|
46
|
+
/** Top-left position in the grid. Omit to let the grid auto-place. */
|
|
47
|
+
position?: TilePosition;
|
|
48
|
+
/** Your custom data — passed back to `renderTile` as `item.data`. */
|
|
49
|
+
data: TData;
|
|
50
|
+
/** When `true`, prevents both dragging and resizing. @default false */
|
|
51
|
+
locked?: boolean;
|
|
52
|
+
/** Smallest size the tile can be resized to. Only enforced when `isEditing` is true. */
|
|
53
|
+
minSize?: TileSize;
|
|
54
|
+
/** Largest size the tile can be resized to. Only enforced when `isEditing` is true. */
|
|
55
|
+
maxSize?: TileSize;
|
|
56
|
+
/** When `false`, the tile ignores the drag gesture and stays in place. @default true */
|
|
57
|
+
draggable?: boolean;
|
|
58
|
+
/** When `false`, long-pressing this tile fires `onTilePress` instead of entering selection. @default true */
|
|
59
|
+
selectable?: boolean;
|
|
60
|
+
};
|
|
61
|
+
/** A `Tile` with `position` and `size` guaranteed to be present. Used internally after auto-placement. */
|
|
62
|
+
export type PlacedTile<TData = unknown> = Tile<TData> & {
|
|
63
|
+
position: TilePosition;
|
|
64
|
+
size: TileSize;
|
|
65
|
+
};
|
|
66
|
+
/** Internal grid configuration passed through context. */
|
|
67
|
+
export type GridConfig = {
|
|
68
|
+
columns: number;
|
|
69
|
+
rowHeight: number;
|
|
70
|
+
gap: number;
|
|
71
|
+
padding: number;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* How a dragged tile interacts with tiles it overlaps on drop.
|
|
75
|
+
* - `'push'` — displaced tiles are moved to the next available slot.
|
|
76
|
+
* - `'swap'` — the dragged tile and the tile at the drop center exchange positions.
|
|
77
|
+
*/
|
|
78
|
+
export type CollisionBehavior = 'push' | 'swap';
|
|
79
|
+
/**
|
|
80
|
+
* Interaction moments passed to `onHaptic` so you can trigger device feedback.
|
|
81
|
+
* - `'pick-up'` — tile long-press activated (drag started or tile selected).
|
|
82
|
+
* - `'snap'` — ghost tile snapped to a new grid position mid-drag.
|
|
83
|
+
* - `'drop'` — tile released.
|
|
84
|
+
* - `'resize'` — tile resize committed.
|
|
85
|
+
*/
|
|
86
|
+
export type HapticEvent = 'pick-up' | 'snap' | 'drop' | 'resize';
|
|
87
|
+
/**
|
|
88
|
+
* Direction tiles compact toward after every drop.
|
|
89
|
+
* - `'none'` — tiles stay exactly where dropped.
|
|
90
|
+
* - `'up'` — tiles slide upward to fill empty rows.
|
|
91
|
+
* - `'left'` — tiles slide left to fill empty columns.
|
|
92
|
+
*/
|
|
93
|
+
export type Gravity = 'none' | 'up' | 'left';
|
|
94
|
+
/** Position and size of a single tile — the serializable unit returned by `serializeLayout`. */
|
|
95
|
+
export type LayoutItem = {
|
|
96
|
+
/** Tile id — matches the `id` on the original `Tile`. */
|
|
97
|
+
id: string;
|
|
98
|
+
/** Current top-left grid position. */
|
|
99
|
+
position: TilePosition;
|
|
100
|
+
/** Current size in grid units. */
|
|
101
|
+
size: TileSize;
|
|
102
|
+
};
|
|
103
|
+
/** Array of `LayoutItem` — the format used by `serializeLayout` and `restoreLayout`. */
|
|
104
|
+
export type SerializedLayout = LayoutItem[];
|
|
105
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,MAAM,MAAM,QAAQ,GAAG;IACrB,sCAAsC;IACtC,CAAC,EAAE,MAAM,CAAC;IACV,mCAAmC;IACnC,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,iEAAiE;AACjE,MAAM,MAAM,YAAY,GAAG;IACzB,8BAA8B;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,2BAA2B;IAC3B,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,MAAM,IAAI,CAAC,KAAK,GAAG,OAAO,IAAI;IAClC,2DAA2D;IAC3D,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,qEAAqE;IACrE,IAAI,EAAE,KAAK,CAAC;IACZ,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wFAAwF;IACxF,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,uFAAuF;IACvF,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,wFAAwF;IACxF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6GAA6G;IAC7G,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,0GAA0G;AAC1G,MAAM,MAAM,UAAU,CAAC,KAAK,GAAG,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG;IACtD,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC;AAEF,0DAA0D;AAC1D,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,IAAI,GAAG,MAAM,CAAC;AAE7C,gGAAgG;AAChG,MAAM,MAAM,UAAU,GAAG;IACvB,yDAAyD;IACzD,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,QAAQ,EAAE,YAAY,CAAC;IACvB,kCAAkC;IAClC,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC;AAEF,wFAAwF;AACxF,MAAM,MAAM,gBAAgB,GAAG,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GridConfig, TilePosition, TileSize } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert an absolute screen position (from gesture handler) to a grid cell,
|
|
4
|
+
* accounting for the container's page offset and the current scroll position.
|
|
5
|
+
*
|
|
6
|
+
* The returned position is clamped so the tile stays within grid bounds.
|
|
7
|
+
*/
|
|
8
|
+
export declare function pixelToGrid(absX: number, absY: number, containerPageX: number, containerPageY: number, scrollY: number, config: GridConfig, size: TileSize, containerWidth: number): TilePosition;
|
|
9
|
+
//# sourceMappingURL=pixelToGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pixelToGrid.d.ts","sourceRoot":"","sources":["../../../../src/utils/pixelToGrid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAU,CAAC;AAGnE;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,EACd,cAAc,EAAE,MAAM,GACrB,YAAY,CAYd"}
|