1 | A tile manager for React that supports
|
---|
2 |
|
---|
3 | - dynamic grid: if the viewport resizes, you can shrink the grid size or shrink the number of columns and rows
|
---|
4 | - tiles in multiple sizes: each tile can span an arbitrary number of columns and rows of the grid
|
---|
5 | - drag and drop, both for reorder and for dropping one tile in another
|
---|
6 |
|
---|
7 | # Install
|
---|
8 |
|
---|
9 | ```
|
---|
10 | npm i -s react-tiles-dnd
|
---|
11 | ```
|
---|
12 |
|
---|
13 | # Example
|
---|
14 |
|
---|
15 | [Show in CodeSandbox](https://codesandbox.io/s/react-tiles-dnd-responsive-bd0ly?file=/src/App.tsx)
|
---|
16 |
|
---|
17 | ![https://codesandbox.io/s/react-tiles-dnd-responsive-bd0ly?file=/src/App.tsx](https://raw.githubusercontent.com/marcoromag/react-tiles-dnd/main/docs/demo.gif)
|
---|
18 |
|
---|
19 | # Use
|
---|
20 |
|
---|
21 | ## The grid
|
---|
22 |
|
---|
23 | To understand the use of the TilesContainer, we need first of all to understand the grid concept behind the component.
|
---|
24 |
|
---|
25 | **Remember: Every tile spans a number of grid columns and row**
|
---|
26 |
|
---|
27 | When a TilesContainer mounts, it will take all the width of the parent, its height will vary depending on the number of rows to display.
|
---|
28 |
|
---|
29 | The number of columns of the grid can be:
|
---|
30 |
|
---|
31 | - **fixed**: in this case if the container resize, each column will change its width. If you want to have a TilesContainer with a fixed number of columns, you must set the `columns` property in `<TilesContainer>`. TilesContainer will calculate the width of the column automatically.
|
---|
32 | - **variable**: the number of columns is calculated dividing the container available space by the column pre-set width. If you want a variable number of columns and a fixed column size, you must set the `forceTileWidth` property in `<TilesContainer>` to the number of pixels you desire. TilesContainer will calculate the number of columns automatically
|
---|
33 |
|
---|
34 | As for columns, also row height can be
|
---|
35 |
|
---|
36 | - **fixed**: the row height is pre-set by you. If you want to have a fixed row height, you shall set the `forceTileHeight` property in `<TilesContainer>`
|
---|
37 | - **variable**: the row height depends on the column width multiplied by a `ratio`. It is irrelevant if columns are fixed or variable. In this case, you can set the `ratio` property in `<TilesContainer>` and the component will calculate the row height accordingly. Example: `<TilesContainer fixedColumnWidth={200} ratio={1.5} .../>` will always produce a row height of 300px (200 _ 1.5). `<div style={{width:500}}><TilesContainer columns={5} ratio={1.5} .../></div>` will produce a row height of 150px ((parent container / number of columns) _ ratio)
|
---|
38 |
|
---|
39 | ## Tiles
|
---|
40 |
|
---|
41 | A tile is the component that is placed on the grid. Every tile has a colspan and a rowspan.
|
---|
42 | When the user starts to drag a tile, the TilesContainer will observe the movement to understand what the user is doing. If the drag operation hovers a **hot area** (top, bottom, left, right, center) of a cell, the TilesContainer will try to rearrange the grid.
|
---|
43 |
|
---|
44 | - If the dragging cell comes from the top, only bottom, left, right are hot areas triggering a reflow.
|
---|
45 | - If the dragging cell comes from the bottom, only top, left, right are hot areas triggering a reflow.
|
---|
46 | - If the dragging cell comes from the left, only top, bottom, right are hot areas triggering a reflow.
|
---|
47 | - If the dragging cell comes from the right, only top, bottom, left are hot areas triggering a reflow.
|
---|
48 |
|
---|
49 | The size of the **hot areas** (top, bottom, left, right) can be set by passing the `activeBorderSize` prop to <TilesContainer>`. If not passed, it is defaulted to 24.
|
---|
50 |
|
---|
51 | The center hot area is only taken into account if the target cell can accept the source cell.
|
---|
52 |
|
---|
53 | TilesContainer is a data-driven component. It accepts an array of data, and each element of the data represent a tile. Data is passed throught the property
|
---|
54 |
|
---|
55 | ```
|
---|
56 | data: T[];
|
---|
57 | ```
|
---|
58 |
|
---|
59 | Together with data, TilesContainer needs a couple of helper functions to understand what shall be rendered for each element of the data array:
|
---|
60 |
|
---|
61 | ```
|
---|
62 | tileSize?: (data: T) => { rowSpan: number; colSpan: number };
|
---|
63 | ```
|
---|
64 |
|
---|
65 | Given a data element, returns the number of rows and cols the tile spans. If not set, the TileContainer will assume each function is a tile of 1x1
|
---|
66 |
|
---|
67 | ```
|
---|
68 | onReorderTiles?: (reorderedData: T[]) => void;
|
---|
69 | ```
|
---|
70 |
|
---|
71 | Every time a drag-n-drop is completed, the TileContainer will call this function with the new array order.
|
---|
72 |
|
---|
73 | ```
|
---|
74 | acceptsDrop?: (source: T, target: T) => boolean;
|
---|
75 | ```
|
---|
76 |
|
---|
77 | This function is called during the drag and drop operations, when a source tile hovers another tile. If the response it true, TilesContainer assumes that the target tile can accept the source tile (similar to a folder).
|
---|
78 |
|
---|
79 | ```
|
---|
80 | onTileDrop?: (source: T, target: T) => boolean;
|
---|
81 | ```
|
---|
82 |
|
---|
83 | This function is called when a target tile is a valid target (acceptDrop returned true) and the user dropped the source tile in the center of the target tile.
|
---|
84 |
|
---|
85 | ```
|
---|
86 | renderTile: RenderTileFunction<T>;
|
---|
87 | ```
|
---|
88 |
|
---|
89 | The rendering function, called every time a re-render is needed.
|
---|
90 |
|
---|
91 | ## Tile rendering
|
---|
92 |
|
---|
93 | TilesContainer invokes the rendering function whenever there are relevant tile changes during the drag-n-drop operation.
|
---|
94 |
|
---|
95 | - whenever a tile starts to drag
|
---|
96 | - whenever a tile is identified as a drop target
|
---|
97 | - whenever a tile drag is over
|
---|
98 |
|
---|
99 | The properties contain the data of the tile, its current position, size, and the flags `isDragging`, `isDropTarget`, `isDroppable`
|
---|
100 |
|
---|
101 | ```
|
---|
102 | export interface RenderTileProps<T> {
|
---|
103 | data: T;
|
---|
104 | id: string;
|
---|
105 | row: number;
|
---|
106 | col: number;
|
---|
107 | rowSpan: number;
|
---|
108 | colSpan: number;
|
---|
109 | tileWidth: number;
|
---|
110 | tileHeight: number;
|
---|
111 | isDragging: boolean;
|
---|
112 | isDropTarget: boolean;
|
---|
113 | isDroppable: boolean;
|
---|
114 | }
|
---|
115 |
|
---|
116 | export type RenderTileFunction<T> = (
|
---|
117 | props: RenderTileProps<T>
|
---|
118 | ) => React.ReactElement | null;
|
---|
119 | ```
|
---|