@ulgaal/react-grid-layout 1.0.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 ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Ulrich Gaal
4
+ Copyright (c) 2016 Samuel Reed
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Fork of the of the [react-grid-layout](https://github.com/react-grid-layout/react-grid-layout) library.
2
+
3
+ This library addresses several issues with regards to the original version
4
+ * The code is rewritten in [typescript](https://www.typescriptlang.org/)
5
+ * The code uses only [functional react components](https://react.dev/learn/your-first-component) and [hooks](https://react.dev/reference/react/hooks)
6
+ * The project is based on a [Vitejs](https://vite.dev/) toolchain
7
+ * The code does not have external dependencies (notably, no dependency on [react-draggable](https://www.npmjs.com/package/react-draggable) and [react-resizable](https://www.npmjs.com/package/react-resizable))
8
+ * The code relies on actual [HTML Drag and Drop events](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API), which enables scenarii where one drags a cell from a grid-layout to another, which was not possible with the original version (Indeed, react-draggable is not based on HTML Drag and Drop events)
9
+
10
+ ## Table of Contents
11
+
12
+ - [Demo and samples](#demo-and-samples)
13
+
14
+ ## Installing
15
+
16
+ ```sh
17
+ npm install @ulgaal/react-grid-layout
18
+
19
+ # or if you use yarn
20
+
21
+ yarn add @ulgaal/react-grid-layout
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```jsx
27
+ // ES6
28
+ import { GridLayout } from "@ulgaal/react-grid-layout";
29
+
30
+ const MyComponent = () => (
31
+ <div>
32
+ <GridLayout
33
+ id={rowId}
34
+ layout={[{i:0, x:0,y:0,w:1,h:1},{i:1, x:1,y:0,w:2,h:1}]}
35
+ cols={5}
36
+ rowHeight={30}
37
+ width={400}
38
+ >
39
+ <span data-id={0}>Hello</span>
40
+ <span data-id={1}>World</span>
41
+ </GridLayout>
42
+ </div>
43
+ );
44
+ ```
45
+
46
+ ## Documentation
47
+
48
+ - [Reference documentation](./markdown/index.md) provides a component-level autogenerated doc
49
+
50
+ # Demo and samples
51
+
52
+ Be sure to check the [kitchen-sink app](https://gitlab.com/coder-tribe-group/react-infra/react-grid-layout/demo) as it contains a sample with two grids, cell resizing, cell transfer between grids, ..., complete with source-code, documentation.
@@ -0,0 +1,94 @@
1
+ import { LEVELS as e, log as t } from "./logs.js";
2
+ import { GRID_MIME_TYPE as n } from "./types.js";
3
+ import { clamp as r, getCellSize as i, getCellStyle as a, getColWidth_ as o, getRowHeight as s } from "./utils.js";
4
+ import { DragDataStore as c, GridDispatch as l } from "./ReactGridLayoutReducer.js";
5
+ import { useCallback as u, useContext as d, useState as f } from "react";
6
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
7
+ //#region src/GridItem.tsx
8
+ var h = (h) => {
9
+ t("GridItem", e.INFO, h);
10
+ let { gridId: g, item: _, metrics: v, children: y, moved: b, isResizable: x } = h, S = d(l), C = d(c), [w, T] = f(null), E = w || !b, D = a(v, _, w || i(v, _)), { isDraggable: O = !0, isResizable: k = !0 } = _, A = o(v), j = s(v), M = u((r) => {
11
+ t("GridItem", e.DEBUG, "handleDragStart", r);
12
+ let { i, w: a, h: o } = _, s = {
13
+ operation: "move",
14
+ gridId: g,
15
+ id: i,
16
+ size: {
17
+ w: a,
18
+ h: o
19
+ }
20
+ };
21
+ r.dataTransfer.setData(n, JSON.stringify(s)), C[n] = s, r.stopPropagation();
22
+ }, [
23
+ g,
24
+ _,
25
+ C
26
+ ]), N = u((n) => {
27
+ t("GridItem", e.DEBUG, "handleDrag", n);
28
+ }, []), P = u((r) => {
29
+ t("GridItem", e.DEBUG, "handleDragEnd", r), delete C[n], S && setTimeout(() => {
30
+ S({
31
+ type: "DRAG_END",
32
+ id: _.i,
33
+ event: r
34
+ });
35
+ }, 0);
36
+ }, [
37
+ S,
38
+ _,
39
+ C
40
+ ]), F = u((n) => {
41
+ t("GridItem", e.DEBUG, "handleMouseDown", n), n.preventDefault(), n.stopPropagation();
42
+ let { paddingX: a, paddingY: o, cols: s, div: c } = v;
43
+ if (c) {
44
+ let { minW: l = 1, minH: u = 1, maxH: d = Infinity } = _, { width: f } = c.getBoundingClientRect(), { w: p, h: m } = i(v, {
45
+ w: l,
46
+ h: u
47
+ }), { w: h, h: g } = i(v, _), { clientX: y, clientY: b } = n, x = {};
48
+ x.handleMouseMove = (n) => {
49
+ t("GridItem", e.DEBUG, "handleMouseMove", n);
50
+ let { clientX: i, clientY: c } = n, v = {
51
+ w: Math.max(h + (Math.min(f, i) - y), p),
52
+ h: Math.max(g + (c - b), m)
53
+ };
54
+ T(v);
55
+ let x = Math.ceil((v.w + a - 1) / A), C = Math.ceil((v.h + o) / j);
56
+ S && S({
57
+ type: "RESIZE",
58
+ id: _.i,
59
+ size: {
60
+ w: r(x, l, s - _.x),
61
+ h: r(C, u, d)
62
+ }
63
+ });
64
+ }, x.handleMouseUp = (n) => {
65
+ t("GridItem", e.DEBUG, "handleMouseUp", n), T(null), S && S({ type: "RESIZE_END" }), window.removeEventListener("mousemove", x.handleMouseMove, !0), window.removeEventListener("mouseup", x.handleMouseUp, !0);
66
+ }, window.addEventListener("mousemove", x.handleMouseMove, !0), window.addEventListener("mouseup", x.handleMouseUp, !0);
67
+ }
68
+ }, [
69
+ S,
70
+ _,
71
+ A,
72
+ j,
73
+ v
74
+ ]);
75
+ return /* @__PURE__ */ m("div", {
76
+ className: "react-grid-item",
77
+ style: D,
78
+ ...v.isDraggable && O ? {
79
+ draggable: !0,
80
+ onDragStart: M,
81
+ onDrag: N,
82
+ onDragEnd: P
83
+ } : {},
84
+ children: [E ? y : null, k && x && E ? /* @__PURE__ */ p("span", {
85
+ className: "react-resizable-handle react-resizable-handle-se",
86
+ onMouseDown: F
87
+ }) : null]
88
+ });
89
+ };
90
+ h.displayName = "GridItem";
91
+ //#endregion
92
+ export { h as GridItem };
93
+
94
+ //# sourceMappingURL=GridItem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GridItem.js","names":[],"sources":["../src/GridItem.tsx"],"sourcesContent":["import { useCallback, useContext, useState, type DragEventHandler, type FunctionComponent, type ReactNode } from 'react'\nimport './GridItem.css'\nimport { LEVELS, log } from './logs'\nimport { DragDataStore, GridDispatch } from './ReactGridLayoutReducer'\nimport { GRID_MIME_TYPE, type DimensionsType, type GridMetrics, type GridMoveOperation, type LayoutItemType } from './types'\nimport { clamp, getCellSize, getCellStyle, getColWidth_, getRowHeight } from './utils'\n\ninterface GridItemProps {\n gridId: string,\n item: LayoutItemType,\n metrics: GridMetrics,\n children: ReactNode,\n moved: boolean,\n isResizable: boolean\n}\n\nexport const GridItem: FunctionComponent<GridItemProps> = props => {\n log('GridItem', LEVELS.INFO, props)\n const { gridId, item, metrics, children, moved, isResizable: gridIsResizable } = props\n const dispatch = useContext(GridDispatch)\n const dragDataStore = useContext(DragDataStore)\n\n const [pixelSize, setPixelSize] = useState<DimensionsType | null>(null)\n const visible = pixelSize || !moved\n const size = pixelSize || getCellSize(metrics, item)\n const style = getCellStyle(metrics, item, size)\n const { isDraggable = true, isResizable = true } = item\n const colWidth = getColWidth_(metrics)\n const rowHeight = getRowHeight(metrics)\n\n const handleDragStart = useCallback<DragEventHandler<HTMLDivElement>>(\n event => {\n log('GridItem', LEVELS.DEBUG, 'handleDragStart', event)\n const { i, w, h } = item\n const op: GridMoveOperation = {\n operation: 'move',\n gridId,\n id: i,\n size: {\n w, h\n }\n }\n event.dataTransfer.setData(\n GRID_MIME_TYPE,\n JSON.stringify(op)\n )\n // eslint-disable-next-line react-hooks/immutability\n dragDataStore[GRID_MIME_TYPE] = op\n event.stopPropagation()\n },\n [gridId, item, dragDataStore]\n )\n const handleDrag = useCallback<DragEventHandler<HTMLDivElement>>(\n event => {\n log('GridItem', LEVELS.DEBUG, 'handleDrag', event)\n },\n []\n )\n const handleDragEnd = useCallback<DragEventHandler<HTMLDivElement>>(\n event => {\n log('GridItem', LEVELS.DEBUG, 'handleDragEnd', event)\n // eslint-disable-next-line react-hooks/immutability\n delete dragDataStore[GRID_MIME_TYPE]\n if (dispatch) {\n setTimeout(() => {\n dispatch({\n type: 'DRAG_END',\n id: item.i,\n event\n })\n }, 0)\n }\n },\n [dispatch, item, dragDataStore]\n )\n\n const handleMouseDown = useCallback<DragEventHandler<HTMLSpanElement>>(\n event => {\n log('GridItem', LEVELS.DEBUG, 'handleMouseDown', event)\n event.preventDefault()\n event.stopPropagation()\n const { paddingX, paddingY, cols, div } = metrics\n if (div) {\n const {\n minW = 1,\n minH = 1,\n maxH = Number.POSITIVE_INFINITY\n } = item\n const { width } = div.getBoundingClientRect()\n const { w: minWidth, h: minHeight } = getCellSize(metrics, { w: minW, h: minH })\n const { w: w0, h: h0 } = getCellSize(metrics, item)\n const { clientX: x0, clientY: y0 } = event\n const handlers = {} as {\n handleMouseMove: (event: MouseEvent) => void,\n handleMouseUp: (event: MouseEvent) => void\n }\n handlers.handleMouseMove = event => {\n log('GridItem', LEVELS.DEBUG, 'handleMouseMove', event)\n const { clientX: x1, clientY: y1 } = event\n const itemSize: DimensionsType = {\n w: Math.max(w0 + (Math.min(width, x1) - x0), minWidth),\n h: Math.max(h0 + (y1 - y0), minHeight)\n }\n setPixelSize(itemSize)\n const w = Math.ceil((itemSize.w + paddingX - 1) / colWidth)\n const h = Math.ceil((itemSize.h + paddingY) / rowHeight)\n if (dispatch) {\n dispatch({\n type: 'RESIZE',\n id: item.i,\n size: {\n w: clamp(w, minW, cols - item.x),\n h: clamp(h, minH, maxH)\n }\n })\n }\n }\n handlers.handleMouseUp = event => {\n log('GridItem', LEVELS.DEBUG, 'handleMouseUp', event)\n setPixelSize(null)\n if (dispatch) {\n dispatch({\n type: 'RESIZE_END',\n })\n }\n window.removeEventListener<'mousemove'>('mousemove', handlers.handleMouseMove, true)\n window.removeEventListener<'mouseup'>('mouseup', handlers.handleMouseUp, true)\n }\n window.addEventListener<'mousemove'>('mousemove', handlers.handleMouseMove, true)\n window.addEventListener<'mouseup'>('mouseup', handlers.handleMouseUp, true)\n }\n },\n [dispatch, item, colWidth, rowHeight, metrics]\n )\n\n return (\n <div\n className='react-grid-item'\n style={style}\n {\n ...(metrics.isDraggable && isDraggable)\n ? {\n draggable: true,\n onDragStart: handleDragStart,\n onDrag: handleDrag,\n onDragEnd: handleDragEnd,\n }\n : {}\n }\n >\n {visible ? children : null}\n {\n isResizable && gridIsResizable && visible\n ? <span\n className='react-resizable-handle react-resizable-handle-se'\n onMouseDown={handleMouseDown}\n />\n : null\n }\n </div>\n )\n}\n\nGridItem.displayName = 'GridItem'\n"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { LEVELS as e, log as t } from "./logs.js";
2
+ import "./types.js";
3
+ import { getCellSize as n, getCellStyle as r } from "./utils.js";
4
+ import "react";
5
+ import { jsx as i } from "react/jsx-runtime";
6
+ //#region src/PlaceHolder.tsx
7
+ var a = (a) => {
8
+ t("PlaceHolder", e.INFO, a);
9
+ let { item: o, metrics: s } = a;
10
+ return /* @__PURE__ */ i("div", {
11
+ style: r(s, o, n(s, o)),
12
+ children: /* @__PURE__ */ i("div", { className: "react-grid-placeholder react-grid-item" })
13
+ });
14
+ };
15
+ a.displayName = "PlaceHolder";
16
+ //#endregion
17
+ export { a as PlaceHolder };
18
+
19
+ //# sourceMappingURL=PlaceHolder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PlaceHolder.js","names":[],"sources":["../src/PlaceHolder.tsx"],"sourcesContent":["import { type FunctionComponent } from 'react'\nimport { LEVELS, log } from './logs'\nimport './PlaceHolder.css'\nimport { type GridMetrics, type LayoutItemType } from './types'\nimport { getCellSize, getCellStyle } from './utils'\n\ninterface PlaceHolderProps {\n item: LayoutItemType,\n metrics: GridMetrics,\n}\n\nexport const PlaceHolder: FunctionComponent<PlaceHolderProps> = props => {\n log('PlaceHolder', LEVELS.INFO, props)\n const { item, metrics } = props\n const style = getCellStyle(metrics, item, getCellSize(metrics, item))\n\n return (\n <div style={style}>\n <div className='react-grid-placeholder react-grid-item' />\n </div>\n )\n}\n\nPlaceHolder.displayName = 'PlaceHolder'\n"],"mappings":";;;;;;AAWA,IAAa,KAAmD,MAAS;CACvE,EAAI,eAAe,EAAO,MAAM,CAAK;CACrC,IAAM,EAAE,SAAM,eAAY;CAG1B,OACE,kBAAC,OAAD;EAAY,OAHA,EAAa,GAAS,GAAM,EAAY,GAAS,CAAI,CAGrD;YACV,kBAAC,OAAD,EAAK,WAAU,yCAA0C,CAAA;CACtD,CAAA;AAET;AAEA,EAAY,cAAc"}
@@ -0,0 +1,212 @@
1
+ import { LEVELS as e, log as t } from "./logs.js";
2
+ import { GRID_MIME_TYPE as n, NEW_ITEM_ID as r } from "./types.js";
3
+ import { containerHeight as i } from "./utils.js";
4
+ import { DragDataStore as a, GridDispatch as o, gridLayoutReducer as s } from "./ReactGridLayoutReducer.js";
5
+ import { GridItem as c } from "./GridItem.js";
6
+ import { PlaceHolder as l } from "./PlaceHolder.js";
7
+ import { useCallback as u, useContext as d, useEffect as f, useMemo as p, useReducer as m, useRef as h } from "react";
8
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
9
+ //#region src/ReactGridLayout.tsx
10
+ var v = ({ id: v, width: y, cols: b = 12, rowHeight: x = 150, minHeight: S = 0, layout: C, children: w, paddingX: T = 10, paddingY: E = 10, marginX: D = 10, marginY: O = 10, style: k, className: A, isDraggable: j = !0, isResizable: M = !0, onLayoutChange: N, onAdd: P, onRemove: F, onDragOver: I }) => {
11
+ let L = {
12
+ id: v,
13
+ width: y,
14
+ cols: b,
15
+ rowHeight: x,
16
+ minHeight: S,
17
+ layout: C,
18
+ children: w,
19
+ paddingX: T,
20
+ paddingY: E,
21
+ marginX: D,
22
+ marginY: O,
23
+ style: k,
24
+ className: A,
25
+ isDraggable: j,
26
+ isResizable: M,
27
+ onLayoutChange: N,
28
+ onAdd: P,
29
+ onRemove: F,
30
+ onDragOver: I
31
+ }, R = h(null), [z, B] = m(s, {
32
+ id: v,
33
+ idToChild: {},
34
+ current: { idToLayoutItem: {} },
35
+ next: { idToLayoutItem: {} },
36
+ extent: {
37
+ xMax: 0,
38
+ yMax: 0
39
+ },
40
+ metrics: {
41
+ id: v,
42
+ width: y,
43
+ cols: b,
44
+ rowHeight: x,
45
+ paddingX: T,
46
+ paddingY: E,
47
+ marginX: D,
48
+ marginY: O,
49
+ isDraggable: j,
50
+ isResizable: M,
51
+ div: null
52
+ },
53
+ movedId: null,
54
+ dragIsOutside: !1,
55
+ onLayoutChange: N,
56
+ onRemove: F,
57
+ p0: null
58
+ });
59
+ t("GridLayout", e.INFO, L, z);
60
+ let { current: V, next: H, movedId: U, extent: W, metrics: G, dragIsOutside: K, idToChild: q, p0: J } = z, { idToLayoutItem: Y } = U === null ? V : H, X = d(a), Z = p(() => {
61
+ let { yMax: e } = W;
62
+ return {
63
+ ...k,
64
+ height: `${i({
65
+ paddingY: E,
66
+ marginY: O,
67
+ rowHeight: x,
68
+ yMax: e,
69
+ minHeight: S
70
+ })}px`
71
+ };
72
+ }, [
73
+ E,
74
+ O,
75
+ k,
76
+ x,
77
+ S,
78
+ W
79
+ ]), Q = u((r) => {
80
+ t("GridLayout", e.DEBUG, "handleDragOver", r, X);
81
+ let i = X[n];
82
+ if (i) i.gridId === v ? J && (B({
83
+ type: "MOVE_CELL",
84
+ delta: {
85
+ x: r.clientX - J.x,
86
+ y: r.clientY - J.y
87
+ },
88
+ id: i.id
89
+ }), r.preventDefault()) : (B({
90
+ type: "ADD_CELL",
91
+ coordinates: {
92
+ x: r.clientX,
93
+ y: r.clientY
94
+ },
95
+ size: i.size
96
+ }), r.preventDefault());
97
+ else if (I) {
98
+ let e = I(v, r);
99
+ e && (B({
100
+ type: "ADD_CELL",
101
+ coordinates: {
102
+ x: r.clientX,
103
+ y: r.clientY
104
+ },
105
+ size: e
106
+ }), r.preventDefault(), r.dataTransfer.dropEffect = "copy");
107
+ }
108
+ }, [
109
+ B,
110
+ v,
111
+ I,
112
+ X,
113
+ J
114
+ ]), $ = u((i) => {
115
+ t("GridLayout", e.DEBUG, "handleDrop", i, X);
116
+ let a = !1, o = X[n];
117
+ if (o && o.gridId === v && (a = !0, N && setTimeout(() => {
118
+ N(v, Object.values(Y));
119
+ }, 0)), !a) {
120
+ let e = Object.keys(Y).indexOf(r);
121
+ e !== -1 && P && P(v, Object.values(Y), e, i);
122
+ }
123
+ B({
124
+ type: "COMMIT_CHANGE",
125
+ idToLayoutItem: Y
126
+ });
127
+ }, [
128
+ B,
129
+ v,
130
+ Y,
131
+ P,
132
+ N,
133
+ X
134
+ ]), ee = u((n) => {
135
+ t("GridLayout", e.DEBUG, "handleDragEnter", n, n.relatedTarget), K && (B({ type: "DRAG_ENTER" }), n.preventDefault());
136
+ }, [B, K]), te = u((n) => {
137
+ t("GridLayout", e.DEBUG, "handleDragLeave", n.relatedTarget);
138
+ let r = n.relatedTarget, { current: i } = R;
139
+ r !== null && i !== null && !i.contains(r) && B({ type: "DRAG_LEAVE" });
140
+ }, [B]), ne = u((n) => {
141
+ t("GridLayout", e.DEBUG, "handleMouseDown", n), B({
142
+ type: "SET_PO",
143
+ p0: {
144
+ x: n.clientX,
145
+ y: n.clientY
146
+ }
147
+ });
148
+ }, [B]);
149
+ return f(() => {
150
+ t("GridLayout", e.DEBUG, "SYNC");
151
+ let { current: n } = R;
152
+ B({
153
+ type: "SYNC",
154
+ id: v,
155
+ layout: C,
156
+ children: w,
157
+ metrics: {
158
+ id: v,
159
+ width: y,
160
+ cols: b,
161
+ rowHeight: x,
162
+ paddingX: T,
163
+ paddingY: E,
164
+ marginX: D,
165
+ marginY: O,
166
+ isDraggable: j,
167
+ isResizable: M,
168
+ div: n
169
+ }
170
+ });
171
+ }, [
172
+ C,
173
+ w,
174
+ y,
175
+ b,
176
+ x,
177
+ T,
178
+ D,
179
+ O,
180
+ j,
181
+ M,
182
+ v,
183
+ E
184
+ ]), /* @__PURE__ */ g("div", {
185
+ style: Z,
186
+ className: `react-grid-layout${A ? ` ${A}` : ""}`,
187
+ ref: R,
188
+ onDragOver: Q,
189
+ onDrop: $,
190
+ onDragEnter: ee,
191
+ onDragLeave: te,
192
+ onMouseDown: ne,
193
+ children: /* @__PURE__ */ _(o.Provider, {
194
+ value: B,
195
+ children: [U && !K ? /* @__PURE__ */ g(l, {
196
+ item: Y[U],
197
+ metrics: G
198
+ }) : null, Object.entries(q).map(([e, t]) => /* @__PURE__ */ g(c, {
199
+ gridId: v,
200
+ item: Y[e] || V.idToLayoutItem[U || ""],
201
+ metrics: G,
202
+ moved: U === e,
203
+ isResizable: M,
204
+ children: t
205
+ }, e))]
206
+ })
207
+ });
208
+ };
209
+ //#endregion
210
+ export { v as GridLayout };
211
+
212
+ //# sourceMappingURL=ReactGridLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReactGridLayout.js","names":[],"sources":["../src/ReactGridLayout.tsx"],"sourcesContent":["import { useCallback, useContext, useEffect, useMemo, useReducer, useRef, type CSSProperties, type DragEventHandler, type FunctionComponent, type MouseEventHandler } from 'react'\nimport { GridItem } from './GridItem'\nimport { LEVELS, log } from './logs'\nimport { PlaceHolder } from './PlaceHolder'\nimport { DragDataStore, GridDispatch, gridLayoutReducer } from './ReactGridLayoutReducer'\nimport './resizable.css'\nimport './styles.css'\nimport { GRID_MIME_TYPE, NEW_ITEM_ID, type GridLayoutProps, type GridMoveOperation } from './types'\nimport { containerHeight } from './utils'\n\n/**\n * A reactive, fluid grid layout with draggable, resizable components.\n * The grid supports the following operations:\n * Re-arranging its children by dragging them to their new position (triggers onLayoutChange)\n * Resizing its children using their resize handles (triggers onLayoutChange)\n * Remove one of its children, by dragging it outside the grid boundaries (triggers onRemove)\n * Accepting (by implementing onDragOver) new children from drag and drop (triggers onAdd) ;\n * these new children may come from another grid (in this case, onRemove in called on\n * the source grid and onAdd in called on the destination grid)\n */\nexport const GridLayout: FunctionComponent<GridLayoutProps> = ({\n id,\n width,\n cols = 12,\n rowHeight = 150,\n minHeight = 0,\n layout,\n children,\n paddingX = 10,\n paddingY = 10,\n marginX = 10,\n marginY = 10,\n style,\n className,\n isDraggable = true,\n isResizable = true,\n onLayoutChange,\n onAdd,\n onRemove,\n onDragOver,\n }) => {\n const props = {\n id,\n width,\n cols,\n rowHeight,\n minHeight,\n layout,\n children,\n paddingX,\n paddingY,\n marginX,\n marginY,\n style,\n className,\n isDraggable,\n isResizable,\n onLayoutChange,\n onAdd,\n onRemove,\n onDragOver\n }\n const ref = useRef<HTMLDivElement | null>(null)\n const [state, dispatch] = useReducer(gridLayoutReducer, {\n id,\n idToChild: {},\n current: {\n idToLayoutItem: {},\n },\n next: {\n idToLayoutItem: {},\n },\n extent: {\n xMax: 0,\n yMax: 0\n },\n metrics: {\n id,\n width,\n cols,\n rowHeight,\n paddingX,\n paddingY,\n marginX,\n marginY,\n isDraggable,\n isResizable,\n div: null\n },\n movedId: null,\n dragIsOutside: false,\n onLayoutChange,\n onRemove,\n p0: null\n })\n log('GridLayout', LEVELS.INFO, props, state)\n const { current, next, movedId, extent, metrics, dragIsOutside, idToChild, p0 } = state\n const { idToLayoutItem } = movedId !== null ? next : current\n const dragDataStore = useContext(DragDataStore)\n\n const gridStyle = useMemo<CSSProperties>(() => {\n const { yMax } = extent\n return {\n ...style,\n height: `${containerHeight({ paddingY, marginY, rowHeight, yMax, minHeight })}px`,\n }\n }, [paddingY, marginY, style, rowHeight, minHeight, extent])\n\n const handleDragOver = useCallback<DragEventHandler<HTMLDivElement>>(\n event => {\n log('GridLayout', LEVELS.DEBUG, 'handleDragOver', event, dragDataStore)\n const op: GridMoveOperation | undefined = dragDataStore[GRID_MIME_TYPE]\n if (op) {\n if (op.gridId === id) {\n if (p0) {\n // The user wants to change layout\n dispatch({\n type: 'MOVE_CELL',\n delta: {\n x: event.clientX - p0.x,\n y: event.clientY - p0.y\n },\n id: op.id\n })\n event.preventDefault()\n }\n } else {\n // The user wants to transfer an element from another grid\n dispatch({\n type: 'ADD_CELL',\n coordinates: {\n x: event.clientX,\n y: event.clientY\n },\n size: op.size,\n })\n event.preventDefault()\n }\n } else if (onDragOver) {\n // The use wants to add an element from an external drag source\n const size = onDragOver(id, event)\n if (size) {\n dispatch({\n type: 'ADD_CELL',\n coordinates: {\n x: event.clientX,\n y: event.clientY\n },\n size,\n })\n event.preventDefault()\n event.dataTransfer.dropEffect = 'copy'\n }\n }\n },\n [dispatch, id, onDragOver, dragDataStore, p0]\n )\n\n const handleDrop = useCallback<DragEventHandler<HTMLDivElement>>(\n event => {\n log('GridLayout', LEVELS.DEBUG, 'handleDrop', event, dragDataStore)\n let internalMove = false\n const op: GridMoveOperation | undefined = dragDataStore[GRID_MIME_TYPE]\n if (op) {\n if (op.gridId === id) {\n internalMove = true\n if (onLayoutChange) {\n setTimeout(() => {\n onLayoutChange(id, Object.values(idToLayoutItem))\n }, 0)\n }\n }\n }\n if (!internalMove) {\n const index = Object.keys(idToLayoutItem).indexOf(NEW_ITEM_ID)\n if (index !== -1) {\n if (onAdd) {\n onAdd(id, Object.values(idToLayoutItem), index, event)\n }\n }\n }\n dispatch({\n type: 'COMMIT_CHANGE',\n idToLayoutItem\n })\n },\n [dispatch, id, idToLayoutItem, onAdd, onLayoutChange, dragDataStore]\n )\n\n const handleDragEnter = useCallback<DragEventHandler<HTMLDivElement>>(\n event => {\n log('GridLayout', LEVELS.DEBUG, 'handleDragEnter', event, event.relatedTarget)\n if (dragIsOutside) {\n dispatch({\n type: 'DRAG_ENTER'\n })\n event.preventDefault()\n }\n },\n [dispatch, dragIsOutside]\n )\n\n const handleDragLeave = useCallback<DragEventHandler<HTMLDivElement>>(\n event => {\n log('GridLayout', LEVELS.DEBUG, 'handleDragLeave', event.relatedTarget)\n const elt = event.relatedTarget as HTMLElement | null\n const { current } = ref\n if (elt !== null && current !== null && !current.contains(elt)) {\n dispatch({\n type: 'DRAG_LEAVE'\n })\n }\n },\n [dispatch]\n )\n\n const handleMouseDown = useCallback<MouseEventHandler<HTMLDivElement>>(\n event => {\n log('GridLayout', LEVELS.DEBUG, 'handleMouseDown', event)\n dispatch({ type: 'SET_PO', p0: { x: event.clientX, y: event.clientY } })\n },\n [dispatch]\n )\n\n useEffect(() => {\n log('GridLayout', LEVELS.DEBUG, 'SYNC')\n const { current } = ref\n dispatch({\n type: 'SYNC',\n id,\n layout,\n children,\n metrics: {\n id,\n width,\n cols,\n rowHeight,\n paddingX,\n paddingY,\n marginX,\n marginY,\n isDraggable,\n isResizable,\n div: current\n },\n })\n }, [layout, children, width, cols, rowHeight, paddingX, marginX, marginY, isDraggable, isResizable, id, paddingY])\n\n return (\n <div\n style={gridStyle}\n className={`react-grid-layout${className ? ` ${className}` : ''}`}\n ref={ref}\n onDragOver={handleDragOver}\n onDrop={handleDrop}\n onDragEnter={handleDragEnter}\n onDragLeave={handleDragLeave}\n onMouseDown={handleMouseDown}\n >\n <GridDispatch.Provider value={dispatch}>\n {\n (movedId && !dragIsOutside)\n ? (\n <PlaceHolder\n item={idToLayoutItem[movedId]}\n metrics={metrics}\n />\n )\n : null\n }\n {Object.entries(idToChild).map(([itemId, node]) => {\n const item = idToLayoutItem[itemId] || current.idToLayoutItem[movedId || '']\n return (\n <GridItem\n key={itemId}\n gridId={id}\n item={item}\n metrics={metrics}\n moved={movedId === itemId}\n isResizable={isResizable}\n >\n {node}\n </GridItem>\n )\n })}\n </GridDispatch.Provider>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,163 @@
1
+ import { LEVELS as e, log as t } from "./logs.js";
2
+ import { NEW_ITEM_ID as n } from "./types.js";
3
+ import { byId as r, clampX as i, compact as a, getExtent as o, moveElement as s, toGridCoordinates as c, toGridCoordinates2 as l } from "./utils.js";
4
+ import { Children as u, createContext as d, isValidElement as f } from "react";
5
+ //#region src/ReactGridLayoutReducer.tsx
6
+ var p = d(null), m = d({}), h = (d, p) => {
7
+ t("gridLayoutReducer", e.INFO, d, p);
8
+ let { type: m } = p;
9
+ switch (m) {
10
+ case "SET_PO": {
11
+ let { p0: e } = p;
12
+ return {
13
+ ...d,
14
+ p0: e
15
+ };
16
+ }
17
+ case "MOVE_CELL": {
18
+ let { delta: e, id: t } = p, { metrics: n, current: c, movedId: u } = d, f = { ...d.next };
19
+ if (u === null) {
20
+ let { idToLayoutItem: e } = c;
21
+ f.idToLayoutItem = structuredClone(e);
22
+ }
23
+ let m = f.idToLayoutItem[t], { x: h, y: g } = l(n, e, c.idToLayoutItem[t]);
24
+ return f.idToLayoutItem = r(a(s(Object.values(f.idToLayoutItem), m, i(h, m, n), g, !0, !1))), {
25
+ ...d,
26
+ movedId: t,
27
+ next: f,
28
+ extent: o(Object.values(f.idToLayoutItem))
29
+ };
30
+ }
31
+ case "ADD_CELL": {
32
+ let { coordinates: e, size: t } = p, { w: l, h: u } = t, { metrics: f, next: m, current: h, movedId: g } = d, { x: _, y: v } = c(f, e, t);
33
+ if (g === null) {
34
+ let { idToLayoutItem: e } = h;
35
+ m.idToLayoutItem = {
36
+ ...structuredClone(e),
37
+ [n]: {
38
+ i: n,
39
+ x: _,
40
+ y: v,
41
+ w: l,
42
+ h: u
43
+ }
44
+ };
45
+ }
46
+ let y = m.idToLayoutItem[n];
47
+ return g !== null && y.x === _ && y.y === v ? d : (m.idToLayoutItem = r(a(s(Object.values(m.idToLayoutItem), y, i(_, y, f), v, !0, !1))), {
48
+ ...d,
49
+ movedId: n,
50
+ next: m,
51
+ extent: o(Object.values(m.idToLayoutItem))
52
+ });
53
+ }
54
+ case "COMMIT_CHANGE": {
55
+ let { idToLayoutItem: e } = p;
56
+ return {
57
+ ...d,
58
+ movedId: null,
59
+ current: { idToLayoutItem: e }
60
+ };
61
+ }
62
+ case "DRAG_ENTER": return {
63
+ ...d,
64
+ dragIsOutside: !1,
65
+ movedId: null
66
+ };
67
+ case "DRAG_LEAVE": {
68
+ let { next: e, movedId: t } = d;
69
+ if (e.idToLayoutItem.__dropped__) {
70
+ let t = { ...e.idToLayoutItem };
71
+ delete t[n];
72
+ let i = r(a(Object.values(t)));
73
+ return {
74
+ ...d,
75
+ movedId: null,
76
+ next: { idToLayoutItem: i },
77
+ extent: o(Object.values(i))
78
+ };
79
+ }
80
+ if (t) {
81
+ let n = { ...e.idToLayoutItem };
82
+ delete n[t];
83
+ let i = r(a(Object.values(n)));
84
+ return {
85
+ ...d,
86
+ dragIsOutside: !0,
87
+ next: { idToLayoutItem: i },
88
+ extent: o(Object.values(i))
89
+ };
90
+ }
91
+ return d;
92
+ }
93
+ case "DRAG_END": {
94
+ let { id: e, dragIsOutside: t, movedId: n, onRemove: r, next: { idToLayoutItem: i } } = d;
95
+ if (n !== null) {
96
+ if (t && n && r) {
97
+ let t = Object.values(i);
98
+ setTimeout(() => {
99
+ r(e, t, n, p.event);
100
+ }, 0);
101
+ let a = { ...d.idToChild };
102
+ return delete a[n], {
103
+ ...d,
104
+ movedId: null,
105
+ current: { idToLayoutItem: i },
106
+ idToChild: a
107
+ };
108
+ }
109
+ return {
110
+ ...d,
111
+ movedId: null
112
+ };
113
+ }
114
+ return d;
115
+ }
116
+ case "RESIZE": {
117
+ let { size: e, id: t } = p, { current: n, movedId: i } = d, c = { ...d.next };
118
+ if (i === null) {
119
+ let { idToLayoutItem: e } = n;
120
+ c.idToLayoutItem = structuredClone(e);
121
+ }
122
+ let l = c.idToLayoutItem[t];
123
+ return Object.assign(l, e), c.idToLayoutItem = r(a(s(Object.values(c.idToLayoutItem), l, l.x, l.y, !0, !1))), {
124
+ ...d,
125
+ movedId: t,
126
+ next: c,
127
+ extent: o(Object.values(c.idToLayoutItem))
128
+ };
129
+ }
130
+ case "RESIZE_END": {
131
+ let { id: e, onLayoutChange: t, next: { idToLayoutItem: n } } = d;
132
+ return t && setTimeout(() => {
133
+ t(e, Object.values(n));
134
+ }, 0), {
135
+ ...d,
136
+ current: { idToLayoutItem: n },
137
+ movedId: null
138
+ };
139
+ }
140
+ case "SYNC": {
141
+ let { layout: e, children: t, metrics: n } = p, i = r(e), a = u.toArray(t).reduce((e, t) => {
142
+ if (f(t)) {
143
+ let n = t.props["data-id"];
144
+ e[n] = t;
145
+ }
146
+ return e;
147
+ }, {}), s = o(e);
148
+ return {
149
+ ...d,
150
+ id: p.id,
151
+ extent: s,
152
+ metrics: n,
153
+ idToChild: a,
154
+ current: { idToLayoutItem: i }
155
+ };
156
+ }
157
+ default: throw Error(`Unknown action type: ${m}`);
158
+ }
159
+ };
160
+ //#endregion
161
+ export { m as DragDataStore, p as GridDispatch, h as gridLayoutReducer };
162
+
163
+ //# sourceMappingURL=ReactGridLayoutReducer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReactGridLayoutReducer.js","names":[],"sources":["../src/ReactGridLayoutReducer.tsx"],"sourcesContent":["import { Children, createContext, isValidElement, type Dispatch, type DragEvent } from 'react'\nimport { LEVELS, log } from './logs'\nimport { NEW_ITEM_ID, type ChildById, type DimensionsType, type Extent, type GridLayoutById, type GridMetrics, type LayoutChangeHandler, type LayoutItemType, type PointType, type RemoveHandler } from './types'\nimport { byId, clampX, compact, getExtent, moveElement, toGridCoordinates, toGridCoordinates2 } from './utils'\n\nexport type GridLayoutAction =\n | {\n type: 'SYNC',\n id: string,\n layout: LayoutItemType[],\n children: React.ReactNode,\n metrics: GridMetrics\n }\n | {\n type: 'MOVE_CELL',\n delta: PointType,\n id: string\n }\n | {\n type: 'ADD_CELL',\n coordinates: PointType,\n size: DimensionsType\n }\n | {\n type: 'DRAG_ENTER'\n }\n | {\n type: 'DRAG_LEAVE'\n }\n | {\n type: 'DRAG_END',\n id: string\n event: DragEvent<HTMLElement>\n }\n | {\n type: 'COMMIT_CHANGE',\n idToLayoutItem: GridLayoutById\n }\n | {\n type: 'RESIZE',\n id: string,\n size: DimensionsType\n }\n | {\n type: 'RESIZE_END'\n }\n | {\n type: 'SET_PO',\n p0: PointType\n }\nexport const GridDispatch = createContext<Dispatch<GridLayoutAction> | null>(null)\n\n/**\n * Interface for the drag data store used to bypass the drag-end-drop protected mode\n */\nexport interface DragStoreType {\n [key: string]: any\n}\n/**\n * A context to store a drag data store which is available throughout the API\n * and bypasses drag-end-drop protected mode\n */\nexport const DragDataStore = createContext<DragStoreType>({})\n\nexport interface GridLayoutState {\n id: string,\n metrics: GridMetrics,\n extent: Extent,\n idToChild: ChildById,\n current: {\n idToLayoutItem: GridLayoutById,\n }\n next: {\n idToLayoutItem: GridLayoutById,\n }\n movedId: string | null,\n dragIsOutside: boolean,\n onRemove: RemoveHandler | undefined,\n onLayoutChange: LayoutChangeHandler | undefined,\n p0: PointType | null\n}\n\n/**\n * GridLayout reducer\n * Implementation notes\n *\n * Implementation must workaround https://bugzilla.mozilla.org/show_bug.cgi?id=460801\n * so DOM nodes must not be removed during an operation, otherwise dragEnd will never be fired\n *\n * Because of DND protected mode, one cannot query the data during onDragOver, hence the use\n * of a datastore context object as a more permissive substitute to the DND datastore\n *\n * Changes are meant to be transactional: during an interaction, the temporary new layout\n * is store in the 'next' property\n *\n * Layout change scenario\n * The actual react node is hidden and replaced by its DND drag ghost. A temporary placeholder\n * child is created to materialize the spot of the moved node in the new layout\n *\n * Child removal scenario\n * The actual react node is hidden and replaced by its DND drag ghost. No temporary placeholder\n * child gets created since the drag occurs outside of the grid boundaries\n *\n * Add child scenario\n * A new temporary item with id NEW_ITEM_ID is created. The DND drag ghost represents the new item.\n * A temporary placeholder child is created to materialize the spot of the item in the new layout\n *\n * Resize scenario\n * A temporary placeholder child is created to materialize the spot of the resized node in the new layout\n */\nexport const gridLayoutReducer = (state: GridLayoutState, action: GridLayoutAction): GridLayoutState => {\n log('gridLayoutReducer', LEVELS.INFO, state, action)\n const { type } = action\n switch (type) {\n case 'SET_PO': {\n const { p0 } = action\n return { ...state, p0 }\n }\n\n case 'MOVE_CELL': {\n const { delta, id } = action\n const { metrics, current, movedId } = state\n const next = { ...state.next }\n if (movedId === null) {\n const { idToLayoutItem } = current\n next.idToLayoutItem = structuredClone(idToLayoutItem)\n }\n const item = next.idToLayoutItem[id]\n const { x, y } = toGridCoordinates2(metrics, delta, current.idToLayoutItem[id])\n next.idToLayoutItem = byId(\n compact(\n moveElement(\n Object.values(next.idToLayoutItem),\n item,\n clampX(x, item, metrics),\n y,\n true,\n false\n )\n )\n )\n return {\n ...state,\n movedId: id,\n next,\n extent: getExtent(Object.values(next.idToLayoutItem))\n }\n }\n\n case 'ADD_CELL': {\n const { coordinates, size } = action\n const { w, h } = size\n const { metrics, next, current, movedId } = state\n const { x, y } = toGridCoordinates(metrics, coordinates, size)\n if (movedId === null) {\n const { idToLayoutItem } = current\n next.idToLayoutItem = {\n ...structuredClone(idToLayoutItem),\n [NEW_ITEM_ID]: {\n i: NEW_ITEM_ID,\n x,\n y,\n w,\n h\n }\n }\n }\n const item = next.idToLayoutItem[NEW_ITEM_ID]\n if (movedId !== null && item.x === x && item.y === y) {\n return state\n }\n next.idToLayoutItem = byId(\n compact(\n moveElement(\n Object.values(next.idToLayoutItem),\n item,\n clampX(x, item, metrics),\n y,\n true,\n false\n )\n )\n )\n return {\n ...state,\n movedId: NEW_ITEM_ID,\n next,\n extent: getExtent(Object.values(next.idToLayoutItem))\n }\n }\n\n case 'COMMIT_CHANGE': {\n const { idToLayoutItem } = action\n return { ...state, movedId: null, current: { idToLayoutItem } }\n }\n\n case 'DRAG_ENTER': {\n return {\n ...state,\n dragIsOutside: false,\n movedId: null\n }\n }\n\n case 'DRAG_LEAVE': {\n const { next, movedId } = state\n if (next.idToLayoutItem[NEW_ITEM_ID]) {\n const idToLayoutItem = { ...next.idToLayoutItem }\n delete idToLayoutItem[NEW_ITEM_ID]\n const idToLayoutItem_ = byId(\n compact(\n Object.values(idToLayoutItem)\n )\n )\n return {\n ...state,\n movedId: null,\n next: {\n idToLayoutItem: idToLayoutItem_,\n },\n extent: getExtent(Object.values(idToLayoutItem_)),\n }\n }\n if (movedId) {\n const idToLayoutItem = { ...next.idToLayoutItem }\n delete idToLayoutItem[movedId]\n const idToLayoutItem_ = byId(\n compact(\n Object.values(idToLayoutItem)\n )\n )\n return {\n ...state,\n dragIsOutside: true,\n next: {\n idToLayoutItem: idToLayoutItem_,\n },\n extent: getExtent(Object.values(idToLayoutItem_)),\n }\n }\n return state\n }\n\n case 'DRAG_END': {\n const { id, dragIsOutside, movedId, onRemove, next: { idToLayoutItem } } = state\n if (movedId !== null) {\n if (dragIsOutside && movedId && onRemove) {\n const layout = Object.values(idToLayoutItem)\n setTimeout(() => {\n onRemove(id, layout, movedId, action.event)\n }, 0)\n const idToChild = { ...state.idToChild }\n delete idToChild[movedId]\n return { ...state, movedId: null, current: { idToLayoutItem }, idToChild }\n }\n return { ...state, movedId: null }\n }\n return state\n }\n\n case 'RESIZE': {\n const { size, id } = action\n const { current, movedId } = state\n const next = { ...state.next }\n if (movedId === null) {\n const { idToLayoutItem } = current\n next.idToLayoutItem = structuredClone(idToLayoutItem)\n }\n const item = next.idToLayoutItem[id]\n Object.assign(item, size)\n next.idToLayoutItem = byId(\n compact(\n moveElement(\n Object.values(next.idToLayoutItem),\n item,\n item.x,\n item.y,\n true,\n false\n )\n )\n )\n return {\n ...state,\n movedId: id,\n next,\n extent: getExtent(Object.values(next.idToLayoutItem))\n }\n }\n\n case 'RESIZE_END': {\n const { id, onLayoutChange, next: { idToLayoutItem } } = state\n if (onLayoutChange) {\n setTimeout(() => {\n onLayoutChange(id, Object.values(idToLayoutItem))\n }, 0)\n }\n return { ...state, current: { idToLayoutItem }, movedId: null }\n }\n\n case 'SYNC': {\n const {\n layout,\n children,\n metrics,\n } = action\n const idToLayoutItem = byId(layout)\n const idToChild = Children.toArray(children).reduce<ChildById>((acc, child) => {\n if (isValidElement(child)) {\n const id = child.props['data-id']\n acc[id] = child\n }\n return acc\n }, {})\n const extent = getExtent(layout)\n return {\n ...state,\n id: action.id,\n extent,\n metrics,\n idToChild,\n current: {\n idToLayoutItem,\n },\n }\n }\n\n default: {\n throw new Error(`Unknown action type: ${type}`)\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ .react-grid-item{transition:transform .2s}.react-grid-placeholder{opacity:.2;z-index:2;-webkit-user-select:none;user-select:none;-o-user-select:none;background:red;transition-duration:.1s;position:absolute;inset:0}.react-resizable{position:relative}.react-resizable-handle{box-sizing:border-box;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+);background-position:100% 100%;background-repeat:no-repeat;background-origin:content-box;width:20px;height:20px;padding:0 3px 3px 0;position:absolute}.react-resizable-handle-sw{cursor:sw-resize;bottom:0;left:0;transform:rotate(90deg)}.react-resizable-handle-se{cursor:se-resize;bottom:0;right:0}.react-resizable-handle-nw{cursor:nw-resize;top:0;left:0;transform:rotate(180deg)}.react-resizable-handle-ne{cursor:ne-resize;top:0;right:0;transform:rotate(270deg)}.react-resizable-handle-w,.react-resizable-handle-e{cursor:ew-resize;margin-top:-10px;top:50%}.react-resizable-handle-w{left:0;transform:rotate(135deg)}.react-resizable-handle-e{right:0;transform:rotate(315deg)}.react-resizable-handle-n,.react-resizable-handle-s{cursor:ns-resize;margin-left:-10px;left:50%}.react-resizable-handle-n{top:0;transform:rotate(225deg)}.react-resizable-handle-s{bottom:0;transform:rotate(45deg)}.react-grid-layout{will-change:height;transition:height .2s;display:block;position:relative}
2
+ /*$vite$:1*/
@@ -0,0 +1,271 @@
1
+ import { Context } from 'react';
2
+ import { DragEvent as DragEvent_2 } from 'react';
3
+ import { FunctionComponent } from 'react';
4
+
5
+ /**
6
+ * Callback function invoked a new item is added to the grid layout
7
+ */
8
+ export declare type AddHandler = (id: string, layout: LayoutItemType[], droppedItemIndex: number, event: DragEvent_2<HTMLElement>) => void;
9
+
10
+ /**
11
+ * Function to transform an array of layout items
12
+ * into a dictionary of layout items (using the item id as the key)
13
+ */
14
+ export declare const byId: (layout: LayoutItemType[]) => GridLayoutById;
15
+
16
+ declare interface DimensionsType {
17
+ w: number;
18
+ h: number;
19
+ }
20
+
21
+ /**
22
+ * A context to store a drag data store which is available throughout the API
23
+ * and bypasses drag-end-drop protected mode
24
+ */
25
+ export declare const DragDataStore: Context<DragStoreType>;
26
+
27
+ /**
28
+ * Callback function invoked a droppable item is dragged over the grid layout.
29
+ * If the grid layout accepts the item, it should return the size the new item
30
+ * will have in the layout. If the grid layout rejects the item, it must return 'undefined'.
31
+ */
32
+ export declare type DragOverHandler = (id: string, event: DragEvent_2<HTMLElement>) => DimensionsType | undefined;
33
+
34
+ /**
35
+ * Interface for the drag data store used to bypass the drag-end-drop protected mode
36
+ */
37
+ export declare interface DragStoreType {
38
+ [key: string]: any;
39
+ }
40
+
41
+ /**
42
+ * Custom MIME type for grid to grid drag-and-drop operations
43
+ */
44
+ export declare const GRID_MIME_TYPE = "x-com.dassault_systemes.grid+json";
45
+
46
+ /**
47
+ * A reactive, fluid grid layout with draggable, resizable components.
48
+ * The grid supports the following operations:
49
+ * Re-arranging its children by dragging them to their new position (triggers onLayoutChange)
50
+ * Resizing its children using their resize handles (triggers onLayoutChange)
51
+ * Remove one of its children, by dragging it outside the grid boundaries (triggers onRemove)
52
+ * Accepting (by implementing onDragOver) new children from drag and drop (triggers onAdd) ;
53
+ * these new children may come from another grid (in this case, onRemove in called on
54
+ * the source grid and onAdd in called on the destination grid)
55
+ */
56
+ export declare const GridLayout: FunctionComponent<GridLayoutProps>;
57
+
58
+ declare interface GridLayoutById {
59
+ [key: string]: LayoutItemType;
60
+ }
61
+
62
+ /**
63
+ * Grid component with draggable and resizable cells.
64
+ * Grid cells use absolute positionning
65
+ * The cells in the grid a defined by the 'children' and the 'layout' properties.
66
+ * The association between child nodes and layout info is guaranteed by
67
+ * a 'data-id' DOM attribute on child nodes (its value must match the id of the
68
+ * corresponding LayoutItemType object)
69
+ */
70
+ export declare interface GridLayoutProps {
71
+ /**
72
+ * Grid unique identifier
73
+ */
74
+ id: string;
75
+ /**
76
+ * An array of react nodes to populate grid cells
77
+ */
78
+ children: React.ReactNode;
79
+ /**
80
+ * An array of grid cell attributes
81
+ */
82
+ layout: LayoutItemType[];
83
+ /**
84
+ * Pixel width of the grid
85
+ */
86
+ width: number;
87
+ /**
88
+ * Number of columns of the grid
89
+ */
90
+ cols: number;
91
+ /**
92
+ * Height of a widget row
93
+ */
94
+ rowHeight: number;
95
+ /**
96
+ * Minimum height of the widget grid (if the grid does not contain any cell)
97
+ */
98
+ minHeight?: number;
99
+ /**
100
+ * Horizonal padding between the grid border and its content cells
101
+ */
102
+ paddingX?: number;
103
+ /**
104
+ * Vertical padding between the grid border and its content cells
105
+ */
106
+ paddingY?: number;
107
+ /**
108
+ * Horizonal margin between adjacent cells
109
+ */
110
+ marginX?: number;
111
+ /**
112
+ * Vertical margin between adjacent cells
113
+ */
114
+ marginY?: number;
115
+ /**
116
+ * Optional CSS classname
117
+ */
118
+ className?: string;
119
+ /**
120
+ * Optional style
121
+ */
122
+ style?: React.CSSProperties;
123
+ /**
124
+ * True if grid elements can be dragged around
125
+ * (defaults to true)
126
+ */
127
+ isDraggable?: boolean;
128
+ /**
129
+ * True if grid elements can be resized
130
+ * (defaults to true)
131
+ */
132
+ isResizable?: boolean;
133
+ /**
134
+ * True if grid accepts dnd elements
135
+ * (defaults to true)
136
+ */
137
+ isDroppable?: boolean;
138
+ /**
139
+ * Invoked when the layout is updated.
140
+ * This handler is not invoked during user interactions,
141
+ * only at the end of completed interactions (once the layout has actually
142
+ * changed)
143
+ */
144
+ onLayoutChange?: LayoutChangeHandler;
145
+ onAdd?: AddHandler;
146
+ onRemove?: RemoveHandler;
147
+ onDragOver?: DragOverHandler;
148
+ /**
149
+ * Optional max number of rows
150
+ */
151
+ maxRows?: number;
152
+ /**
153
+ * True if cells can be dragged beyond
154
+ * the current grid size (defaults to false)
155
+ */
156
+ isBounded?: boolean;
157
+ }
158
+
159
+ /**
160
+ * Interface for grid to grid drag-and-drop operations
161
+ */
162
+ export declare interface GridMoveOperation {
163
+ /**
164
+ * Operation type
165
+ */
166
+ operation: 'move';
167
+ /**
168
+ * Id of the grid acting as the source of the drag operation
169
+ */
170
+ gridId: string;
171
+ /**
172
+ * Id of the cell being dragged in the source grid
173
+ */
174
+ id: string;
175
+ /**
176
+ * Size of of the cell being dragged in the source grid
177
+ */
178
+ size: DimensionsType;
179
+ }
180
+
181
+ /**
182
+ * Callback function invoked when the grid layout changes
183
+ */
184
+ export declare type LayoutChangeHandler = (id: string, layout: LayoutItemType[]) => void;
185
+
186
+ /**
187
+ * Interface to represent a grid cell
188
+ */
189
+ export declare interface LayoutItemType {
190
+ /**
191
+ * unique cell identifier
192
+ */
193
+ i: string;
194
+ /**
195
+ * x in grid coordinates
196
+ */
197
+ x: number;
198
+ /**
199
+ * u in grid coordinates
200
+ */
201
+ y: number;
202
+ /**
203
+ * width in grid coordinates
204
+ */
205
+ w: number;
206
+ /**
207
+ * height in grid coordinates
208
+ */
209
+ h: number;
210
+ /**
211
+ * optional max width
212
+ */
213
+ maxW?: number;
214
+ /**
215
+ * optional max height
216
+ */
217
+ maxH?: number;
218
+ /**
219
+ * optional min width
220
+ */
221
+ minW?: number;
222
+ /**
223
+ * optional min height
224
+ */
225
+ minH?: number;
226
+ /**
227
+ * true if the cell can be dragged
228
+ */
229
+ isDraggable?: boolean;
230
+ /**
231
+ * true if the cell can be resized
232
+ */
233
+ isResizable?: boolean;
234
+ /**
235
+ * true if the call must stay at this location
236
+ */
237
+ static?: boolean;
238
+ /**
239
+ * Temporary
240
+ */
241
+ moved?: boolean;
242
+ }
243
+
244
+ /**
245
+ * Object to control logs
246
+ */
247
+ export declare const Logs: LogsType;
248
+
249
+ /**
250
+ * Interface to activate logs for debugging purposes.
251
+ * The keys are the name of trace to activate.
252
+ * The value is a log level. There are 3 levels of traces:
253
+ * <dl>
254
+ * <dt>0</dt>
255
+ * <dd>errors</dd>
256
+ * <dt>1</dt>
257
+ * <dd>info</dd>
258
+ * <dt>2</dt>
259
+ * <dd>debug</dd>
260
+ * </dl>
261
+ */
262
+ declare type LogsType = {
263
+ [key: string]: number;
264
+ };
265
+
266
+ /**
267
+ * Callback function invoked an item is removed from the grid layout
268
+ */
269
+ export declare type RemoveHandler = (id: string, layout: LayoutItemType[], removedId: string, event: DragEvent_2<HTMLElement>) => void;
270
+
271
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import { Logs as e } from "./logs.js";
2
+ import { GRID_MIME_TYPE as t } from "./types.js";
3
+ import { byId as n } from "./utils.js";
4
+ import { DragDataStore as r } from "./ReactGridLayoutReducer.js";
5
+ import { GridLayout as i } from "./ReactGridLayout.js";
6
+ export { r as DragDataStore, t as GRID_MIME_TYPE, i as GridLayout, e as Logs, n as byId };
package/dist/logs.js ADDED
@@ -0,0 +1,21 @@
1
+ //#region src/logs.ts
2
+ var e = {
3
+ ERROR: 0,
4
+ INFO: 1,
5
+ DEBUG: 2
6
+ }, t = {
7
+ GridItem: 0,
8
+ GridLayout: 0,
9
+ gridLayoutReducer: 0,
10
+ compact: 0,
11
+ moveElement: 0,
12
+ moveElementAwayFromCollision: 0,
13
+ PlaceHolder: 0
14
+ }, n = (e, n, ...r) => {
15
+ let i = t[e];
16
+ typeof i == "number" && n <= i && console.log(e, ...r);
17
+ };
18
+ //#endregion
19
+ export { e as LEVELS, t as Logs, n as log };
20
+
21
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","names":[],"sources":["../src/logs.ts"],"sourcesContent":["export const LEVELS = {\n ERROR: 0,\n INFO: 1,\n DEBUG: 2\n}\n\n/**\n * Interface to activate logs for debugging purposes.\n * The keys are the name of trace to activate.\n * The value is a log level. There are 3 levels of traces:\n * <dl>\n * <dt>0</dt>\n * <dd>errors</dd>\n * <dt>1</dt>\n * <dd>info</dd>\n * <dt>2</dt>\n * <dd>debug</dd>\n * </dl>\n */\ntype LogsType = {\n [key: string]: number\n}\n\n/**\n * Object to control logs\n */\nexport const Logs: LogsType = {\n GridItem: 0,\n GridLayout: 0,\n gridLayoutReducer: 0,\n compact: 0,\n moveElement: 0,\n moveElementAwayFromCollision: 0,\n PlaceHolder: 0\n}\n\nexport const log = (facility: string, severity: number, ...args: any[]) => {\n const sev = Logs[facility]\n if (typeof sev === 'number' && severity <= sev) {\n console.log(facility, ...args)\n }\n}\n"],"mappings":";AAAA,IAAa,IAAS;CACpB,OAAO;CACP,MAAM;CACN,OAAO;AACT,GAsBa,IAAiB;CAC5B,UAAU;CACV,YAAY;CACZ,mBAAmB;CACnB,SAAS;CACT,aAAa;CACb,8BAA8B;CAC9B,aAAa;AACf,GAEa,KAAO,GAAkB,GAAkB,GAAG,MAAgB;CACzE,IAAM,IAAM,EAAK;CACjB,AAAI,OAAO,KAAQ,YAAY,KAAY,KACzC,QAAQ,IAAI,GAAU,GAAG,CAAI;AAEjC"}
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ //#region src/types.ts
2
+ var e = "x-com.dassault_systemes.grid+json", t = "__dropped__";
3
+ //#endregion
4
+ export { e as GRID_MIME_TYPE, t as NEW_ITEM_ID };
5
+
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import type { DragEvent } from 'react'\n\n/**\n * Interface to represent a grid cell\n */\nexport interface LayoutItemType {\n /**\n * unique cell identifier\n */\n i: string,\n /**\n * x in grid coordinates\n */\n x: number,\n /**\n * u in grid coordinates\n */\n y: number,\n /**\n * width in grid coordinates\n */\n w: number,\n /**\n * height in grid coordinates\n */\n h: number,\n /**\n * optional max width\n */\n maxW?: number,\n /**\n * optional max height\n */\n maxH?: number,\n /**\n * optional min width\n */\n minW?: number,\n /**\n * optional min height\n */\n minH?: number,\n /**\n * true if the cell can be dragged\n */\n isDraggable?: boolean,\n /**\n * true if the cell can be resized\n */\n isResizable?: boolean,\n /**\n * true if the call must stay at this location\n */\n static?: boolean\n /**\n * Temporary\n */\n moved?: boolean\n}\n\n/**\n * The grid extend\n */\nexport interface Extent {\n xMax: number,\n yMax: number\n}\n\nexport interface DimensionsType {\n w: number,\n h: number\n}\n\nexport interface PointType {\n x: number,\n y: number,\n}\n\nexport interface GridLayoutById {\n [key: string]: LayoutItemType\n}\n\nexport interface ChildById {\n [key: string]: React.ReactNode\n}\n\n/**\n * Callback function invoked when the grid layout changes\n */\nexport type LayoutChangeHandler = (id: string, layout: LayoutItemType[]) => void\n/**\n * Callback function invoked a new item is added to the grid layout\n */\nexport type AddHandler = (id: string, layout: LayoutItemType[], droppedItemIndex: number, event: DragEvent<HTMLElement>) => void\n/**\n * Callback function invoked an item is removed from the grid layout\n */\nexport type RemoveHandler = (id: string, layout: LayoutItemType[], removedId: string, event: DragEvent<HTMLElement>) => void\n/**\n * Callback function invoked a droppable item is dragged over the grid layout.\n * If the grid layout accepts the item, it should return the size the new item\n * will have in the layout. If the grid layout rejects the item, it must return 'undefined'.\n */\nexport type DragOverHandler = (id: string, event: DragEvent<HTMLElement>) => DimensionsType | undefined\n\n/**\n * Grid component with draggable and resizable cells.\n * Grid cells use absolute positionning\n * The cells in the grid a defined by the 'children' and the 'layout' properties.\n * The association between child nodes and layout info is guaranteed by\n * a 'data-id' DOM attribute on child nodes (its value must match the id of the\n * corresponding LayoutItemType object)\n */\nexport interface GridLayoutProps {\n /**\n * Grid unique identifier\n */\n id: string,\n /**\n * An array of react nodes to populate grid cells\n */\n children: React.ReactNode,\n /**\n * An array of grid cell attributes\n */\n layout: LayoutItemType[],\n /**\n * Pixel width of the grid\n */\n width: number,\n /**\n * Number of columns of the grid\n */\n cols: number,\n /**\n * Height of a widget row\n */\n rowHeight: number,\n /**\n * Minimum height of the widget grid (if the grid does not contain any cell)\n */\n minHeight?: number,\n /**\n * Horizonal padding between the grid border and its content cells\n */\n paddingX?: number,\n /**\n * Vertical padding between the grid border and its content cells\n */\n paddingY?: number,\n /**\n * Horizonal margin between adjacent cells\n */\n marginX?: number,\n /**\n * Vertical margin between adjacent cells\n */\n marginY?: number,\n /**\n * Optional CSS classname\n */\n className?: string,\n /**\n * Optional style\n */\n style?: React.CSSProperties,\n /**\n * True if grid elements can be dragged around\n * (defaults to true)\n */\n isDraggable?: boolean,\n /**\n * True if grid elements can be resized\n * (defaults to true)\n */\n isResizable?: boolean,\n /**\n * True if grid accepts dnd elements\n * (defaults to true)\n */\n isDroppable?: boolean,\n /**\n * Invoked when the layout is updated.\n * This handler is not invoked during user interactions,\n * only at the end of completed interactions (once the layout has actually\n * changed)\n */\n onLayoutChange?: LayoutChangeHandler,\n onAdd?: AddHandler,\n onRemove?: RemoveHandler,\n onDragOver?: DragOverHandler,\n /**\n * Optional max number of rows\n */\n maxRows?: number,\n /**\n * True if cells can be dragged beyond\n * the current grid size (defaults to false)\n */\n isBounded?: boolean,\n}\n\nexport interface GridMetrics {\n id: string,\n cols: number,\n rowHeight: number,\n width: number,\n marginX: number,\n marginY: number\n paddingX: number,\n paddingY: number,\n isDraggable: boolean,\n isResizable: boolean,\n div: HTMLDivElement | null\n}\n\n/**\n * Interface for grid to grid drag-and-drop operations\n */\nexport interface GridMoveOperation {\n /**\n * Operation type\n */\n operation: 'move',\n /**\n * Id of the grid acting as the source of the drag operation\n */\n gridId: string,\n /**\n * Id of the cell being dragged in the source grid\n */\n id: string,\n /**\n * Size of of the cell being dragged in the source grid\n */\n size: DimensionsType\n}\n\n/**\n * Custom MIME type for grid to grid drag-and-drop operations\n */\nexport const GRID_MIME_TYPE = 'x-com.dassault_systemes.grid+json'\nexport const NEW_ITEM_ID = '__dropped__'\n"],"mappings":";AAiPA,IAAa,IAAiB,qCACjB,IAAc"}
package/dist/utils.js ADDED
@@ -0,0 +1,139 @@
1
+ import { LEVELS as e, log as t } from "./logs.js";
2
+ import "./types.js";
3
+ //#region src/utils.ts
4
+ function n(e, t, n) {
5
+ return Math.max(Math.min(e, n), t);
6
+ }
7
+ var r = (e) => e.reduce((e, t) => {
8
+ let { i: n } = t;
9
+ return e[n] = t, e;
10
+ }, {}), i = (e) => {
11
+ let { width: t, cols: n, paddingX: r } = e;
12
+ return (t - 2 * r) / n;
13
+ }, a = (e) => {
14
+ let { width: t, cols: n, marginX: r, paddingX: i } = e;
15
+ return r + (t - 2 * i - r * (n - 1)) / n;
16
+ }, o = (e) => {
17
+ let { rowHeight: t, marginY: n } = e;
18
+ return t + n;
19
+ }, s = (e, t) => {
20
+ let { w: n, h: r } = t, { width: i, rowHeight: a, cols: o, marginX: s, marginY: c, paddingX: l } = e;
21
+ return {
22
+ w: n * ((i - 2 * l - s * (o - 1)) / o) + (n - 1) * s,
23
+ h: r * a + (r - 1) * c
24
+ };
25
+ }, c = (e, t, n) => {
26
+ let { x: r, y: i } = t, { paddingX: s, paddingY: c } = e, l = a(e), u = o(e), { w: d, h: f } = n;
27
+ return {
28
+ position: "absolute",
29
+ width: `${d}px`,
30
+ height: `${f}px`,
31
+ transform: `translate(${s + r * l}px, ${c + i * u}px)`
32
+ };
33
+ }, l = (e, t, n) => {
34
+ let r = {
35
+ x: 0,
36
+ y: 0
37
+ }, { w: a, h: s } = n, { paddingX: c, paddingY: l, div: u } = e;
38
+ if (u) {
39
+ let n = i(e), d = o(e), { x: f, y: p } = u.getBoundingClientRect();
40
+ r.x = Math.ceil((t.x - (f + c) - .5 * n * a) / n), r.y = Math.ceil((t.y - (p + l) - .5 * d * s) / d);
41
+ }
42
+ return r;
43
+ }, u = (e, t, n) => {
44
+ let r = {
45
+ x: 0,
46
+ y: 0
47
+ }, i = a(e), s = o(e);
48
+ return r.x = Math.ceil((n.x * i - .5 * i + t.x) / i), r.y = Math.ceil((n.y * s - .5 * s + t.y) / s), r;
49
+ }, d = (e) => e.reduce((e, t) => {
50
+ let { x: n, y: r, w: i, h: a } = t;
51
+ return e.xMax = Math.max(e.xMax, n + i), e.yMax = Math.max(e.yMax, r + a), e;
52
+ }, {
53
+ xMax: 0,
54
+ yMax: 0
55
+ }), f = (e) => {
56
+ let { paddingY: t, marginY: n, rowHeight: r, yMax: i, minHeight: a } = e;
57
+ return Math.max(a, i * r + n * (i - 1) + 2 * t);
58
+ }, p = (e, t, n) => {
59
+ let { cols: r } = n, { w: i } = t;
60
+ return e + i < r ? e : r - i;
61
+ };
62
+ function m(e, t) {
63
+ return !(e.i === t.i || e.x + e.w <= t.x || e.x >= t.x + t.w || e.y + e.h <= t.y || e.y >= t.y + t.h);
64
+ }
65
+ function h(e, t) {
66
+ for (let n = 0, r = e.length; n < r; n++) if (m(e[n], t)) return e[n];
67
+ }
68
+ function g(e, t) {
69
+ return e.filter((e) => m(e, t));
70
+ }
71
+ function _(e) {
72
+ return e.slice(0).sort(function(e, t) {
73
+ return e.x > t.x || e.x === t.x && e.y > t.y ? 1 : -1;
74
+ });
75
+ }
76
+ function v(e) {
77
+ return e.filter((e) => e.static);
78
+ }
79
+ function y(n) {
80
+ t("compact", e.INFO, n);
81
+ let r = v(n), i = _(n), a = Array(n.length);
82
+ for (let e = 0, t = i.length; e < t; e++) {
83
+ let t = { ...i[e] };
84
+ t.static || (t = x(r, t, i), r.push(t)), a[n.indexOf(i[e])] = t, t.moved = !1;
85
+ }
86
+ return a;
87
+ }
88
+ function b(e, t, n) {
89
+ t.y += 1;
90
+ let r = e.findIndex((e) => e.i === t.i);
91
+ for (let i = r + 1, a = e.length; i < a; i++) {
92
+ let r = e[i];
93
+ if (!r.static) {
94
+ if (r.y > t.y + t.h) break;
95
+ m(t, r) && b(e, r, n + t.h);
96
+ }
97
+ }
98
+ t.y = n;
99
+ }
100
+ function x(e, t, n) {
101
+ for (t.y = Math.min(d(e).yMax, t.y); t.y > 0 && !h(e, t);) t.y--;
102
+ let r;
103
+ for (; r = h(e, t);) b(n, t, r.y + r.h);
104
+ return t.y = Math.max(t.y, 0), t.x = Math.max(t.x, 0), t;
105
+ }
106
+ var S = (n, r, i, a, o, s) => {
107
+ if (r.static && r.isDraggable !== !0 || r.y === a && r.x === i) return n;
108
+ t("moveElement", e.DEBUG, `Moving element "${r.i}"@[${r.x},${r.y}] => [${i},${a}]`);
109
+ let c = r.x, l = r.y;
110
+ typeof i == "number" && (r.x = i), typeof a == "number" && (r.y = a), r.moved = !0;
111
+ let u = _(n);
112
+ typeof a == "number" && l >= a && (u = u.reverse());
113
+ let d = g(u, r);
114
+ if (d.length > 0 && s) return t("moveElement", e.DEBUG, `Collision prevented on ${r.i}, reverting.`), r.x = c, r.y = l, r.moved = !1, n;
115
+ for (let i = 0, a = d.length; i < a; i++) {
116
+ let a = d[i];
117
+ t("moveElement", e.DEBUG, `Resolving collision between "${r.i}"@[${r.x},${r.y}] and "${a.i}"@[${a.x},${a.y}]`), !a.moved && (n = a.static ? C(n, a, r, o) : C(n, r, a, o));
118
+ }
119
+ return n;
120
+ }, C = (n, r, i, a) => {
121
+ let o = r.static;
122
+ if (a) {
123
+ a = !1;
124
+ let s = {
125
+ x: i.x,
126
+ y: Math.max(r.y - i.h, 0),
127
+ w: i.w,
128
+ h: i.h,
129
+ i: "-1"
130
+ }, c = h(n, s), l = c && c.y + c.h > r.y;
131
+ if (!c) return t("moveElementAwayFromCollision", e.DEBUG, `Doing reverse collision on ${i.i} up to [${s.x},${s.y}].`), S(n, i, void 0, s.y, a, o);
132
+ if (l) return S(n, i, void 0, r.y + 1, a, o);
133
+ }
134
+ return i.y + 1 == null ? n : S(n, i, void 0, i.y + 1, a, o);
135
+ };
136
+ //#endregion
137
+ export { r as byId, n as clamp, p as clampX, m as collides, y as compact, x as compactItem, f as containerHeight, g as getAllCollisions, s as getCellSize, c as getCellStyle, i as getColWidth, a as getColWidth_, d as getExtent, h as getFirstCollision, o as getRowHeight, v as getStatics, S as moveElement, C as moveElementAwayFromCollision, _ as sortLayoutItems, l as toGridCoordinates, u as toGridCoordinates2 };
138
+
139
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import type { CSSProperties } from 'react'\nimport { LEVELS, log } from './logs'\nimport { type DimensionsType, type Extent, type GridLayoutById, type GridMetrics, type LayoutItemType, type PointType } from './types'\n\nexport function clamp (num: number, lowerBound: number, upperBound: number): number {\n return Math.max(Math.min(num, upperBound), lowerBound)\n}\n\n/**\n * Function to transform an array of layout items\n * into a dictionary of layout items (using the item id as the key)\n */\nexport const byId = (layout: LayoutItemType[]): GridLayoutById => {\n return layout.reduce<GridLayoutById>((acc, item) => {\n const { i } = item\n acc[i] = item\n return acc\n }, {})\n}\n\nexport const getColWidth = (params: GridMetrics): number => {\n const {\n width,\n cols,\n paddingX\n } = params\n return (width - 2 * paddingX) / cols\n}\n\nexport const getColWidth_ = (params: GridMetrics): number => {\n const {\n width,\n cols,\n marginX,\n paddingX\n } = params\n return marginX + (width - 2 * paddingX - marginX * (cols - 1)) / cols\n}\n\nexport const getRowHeight = (params: GridMetrics): number => {\n const {\n rowHeight,\n marginY,\n } = params\n return rowHeight + marginY\n}\n\nexport const getCellSize = (params: GridMetrics, cell: DimensionsType): DimensionsType => {\n const { w, h } = cell\n const {\n width,\n rowHeight,\n cols,\n marginX,\n marginY,\n paddingX\n } = params\n const colWidth = (width - 2 * paddingX - marginX * (cols - 1)) / cols\n return {\n w: w * colWidth + (w - 1) * marginX,\n h: h * rowHeight + (h - 1) * marginY\n }\n}\n\nexport const getCellStyle = (params: GridMetrics, cell: LayoutItemType, size: DimensionsType): CSSProperties => {\n const { x, y } = cell\n const {\n paddingX,\n paddingY,\n } = params\n const colWidth = getColWidth_(params)\n const rowHeight = getRowHeight(params)\n const { w, h } = size\n return {\n position: 'absolute',\n width: `${w}px`,\n height: `${h}px`,\n transform: `translate(${paddingX + x * colWidth}px, ${paddingY + y * (rowHeight)}px)`\n }\n}\n\nexport const toGridCoordinates = (params: GridMetrics, coordinates: PointType, size: DimensionsType): PointType => {\n const point = { x: 0, y: 0 }\n const { w, h } = size\n const {\n paddingX,\n paddingY,\n div\n } = params\n if (div) {\n const colWidth = getColWidth(params)\n const rowHeight = getRowHeight(params)\n const { x, y } = div.getBoundingClientRect()\n point.x = Math.ceil((coordinates.x - (x + paddingX) - 0.5 * colWidth * w) / colWidth)\n point.y = Math.ceil((coordinates.y - (y + paddingY) - 0.5 * rowHeight * h) / rowHeight)\n }\n return point\n}\n\nexport const toGridCoordinates2 = (params: GridMetrics, delta: PointType, item: LayoutItemType): PointType => {\n const point = { x: 0, y: 0 }\n const colWidth = getColWidth_(params)\n const rowHeight = getRowHeight(params)\n point.x = Math.ceil((item.x * colWidth - 0.5 * colWidth + delta.x) / colWidth)\n point.y = Math.ceil((item.y * rowHeight - 0.5 * rowHeight + delta.y) / rowHeight)\n return point\n}\n\nexport const getExtent = (layout: LayoutItemType[]): Extent => {\n return layout.reduce<Extent>(\n (acc, item) => {\n const { x, y, w, h } = item\n acc.xMax = Math.max(acc.xMax, x + w)\n acc.yMax = Math.max(acc.yMax, y + h)\n return acc\n },\n {\n xMax: 0,\n yMax: 0\n }\n )\n}\n\nexport const containerHeight = (params: { paddingY: number, marginY: number, rowHeight: number, yMax: number, minHeight: number }): number => {\n const { paddingY, marginY, rowHeight, yMax, minHeight } = params\n return Math.max(minHeight, yMax * rowHeight + marginY * (yMax - 1) + 2 * paddingY)\n}\n\nexport const clampX = (x: number, item: LayoutItemType, metrics: GridMetrics): number => {\n const { cols } = metrics\n const { w } = item\n return x + w < cols ? x : cols - w\n}\n\n/**\n * Given two layoutitems, check if they collide.\n */\nexport function collides (l1: LayoutItemType, l2: LayoutItemType): boolean {\n if (l1.i === l2.i) return false // same element\n if (l1.x + l1.w <= l2.x) return false // l1 is left of l2\n if (l1.x >= l2.x + l2.w) return false // l1 is right of l2\n if (l1.y + l1.h <= l2.y) return false // l1 is above l2\n if (l1.y >= l2.y + l2.h) return false // l1 is below l2\n return true // boxes overlap\n}\n\n/**\n * Returns the first item this layout collides with.\n * It doesn't appear to matter which order we approach this from, although\n * perhaps that is the wrong thing to do.\n *\n * @param {Object} layoutItem Layout item.\n * @return {Object|undefined} A colliding layout item, or undefined.\n */\nexport function getFirstCollision (layout: LayoutItemType[], layoutItem: LayoutItemType): LayoutItemType | undefined {\n for (let i = 0, len = layout.length; i < len; i++) {\n if (collides(layout[i], layoutItem)) return layout[i]\n }\n}\n\nexport function getAllCollisions (layout: LayoutItemType[], layoutItem: LayoutItemType): LayoutItemType[] {\n return layout.filter(l => collides(l, layoutItem))\n}\n\n/**\n * Sort layout items by column ascending then row ascending.\n * @return {Array} Array of layout objects.\n * @return {Array} Layout, sorted static items first.\n */\nexport function sortLayoutItems (layout: LayoutItemType[]): LayoutItemType[] {\n return layout.slice(0).sort(function (a, b) {\n if (a.x > b.x || (a.x === b.x && a.y > b.y)) {\n return 1\n }\n return -1\n })\n}\n\n/**\n * Get all static elements.\n */\nexport function getStatics (layout: LayoutItemType[]) {\n return layout.filter(l => l.static)\n}\n\n/**\n * Given a layout, compact it. This involves going down each y coordinate and removing gaps\n * between items.\n * Creates a new layout array.\n */\nexport function compact (layout: LayoutItemType[]): LayoutItemType[] {\n log('compact', LEVELS.INFO, layout)\n // Statics go in the compareWith array right away so items flow around them.\n const compareWith = getStatics(layout)\n // We go through the items by row and column.\n const sorted = sortLayoutItems(layout)\n // Holding for new items.\n const out = Array(layout.length)\n\n for (let i = 0, len = sorted.length; i < len; i++) {\n let l = { ...sorted[i] }\n\n // Don't move static elements\n if (!l.static) {\n l = compactItem(compareWith, l, sorted)\n\n // Add to comparison array. We only collide with items before this one.\n // Statics are already in this array.\n compareWith.push(l)\n }\n\n // Add to output array to make sure they still come out in the right order.\n out[layout.indexOf(sorted[i])] = l\n\n // Clear moved flag, if it exists.\n l.moved = false\n }\n\n return out\n}\n\n/**\n * Before moving item down, it will check if the movement will cause collisions and move those items down before.\n */\nfunction resolveCompactionCollision (layout: LayoutItemType[], item: LayoutItemType, moveToCoord: number) {\n item.y += 1\n const itemIndex = layout.findIndex(l => l.i === item.i)\n\n // Go through each item we collide with.\n for (let i = itemIndex + 1, len = layout.length; i < len; i++) {\n const otherItem = layout[i]\n // Ignore static items\n if (otherItem.static) {\n continue\n }\n\n // Optimization: we can break early if we know we're past this el\n // We can do this b/c it's a sorted layout\n if (otherItem.y > item.y + item.h) {\n break\n }\n\n if (collides(item, otherItem)) {\n resolveCompactionCollision(\n layout,\n otherItem,\n moveToCoord + item.h\n )\n }\n }\n item.y = moveToCoord\n}\n\n/**\n * Compact an item in the layout.\n * Modifies item.\n */\nexport function compactItem (compareWith: LayoutItemType[], l: LayoutItemType, fullLayout: LayoutItemType[]) {\n // Bottom 'y' possible is the bottom of the layout.\n // This allows you to do nice stuff like specify {y: Infinity}\n // This is here because the layout must be sorted in order to get the correct bottom `y`.\n l.y = Math.min(getExtent(compareWith).yMax, l.y)\n // Move the element up as far as it can go without colliding.\n while (l.y > 0 && !getFirstCollision(compareWith, l)) {\n l.y--\n }\n\n // Move it down, and keep moving it down if it's colliding.\n let collides\n // Checking the compactType null value to avoid breaking the layout when overlapping is allowed.\n while ((collides = getFirstCollision(compareWith, l))) {\n resolveCompactionCollision(fullLayout, l, collides.y + collides.h)\n }\n\n // Ensure that there are no negative positions\n l.y = Math.max(l.y, 0)\n l.x = Math.max(l.x, 0)\n\n return l\n}\n\n/**\n * Move an element. Responsible for doing cascading movements of other elements.\n *\n * Modifies layout items.\n *\n * @param {Array} layout Full layout to modify.\n * @param {LayoutItem} l element to move.\n * @param {Number} [x] X position in grid units.\n * @param {Number} [y] Y position in grid units.\n */\nexport const moveElement = (\n layout: LayoutItemType[],\n l: LayoutItemType,\n x: number | undefined,\n y: number | undefined,\n isUserAction: boolean,\n preventCollision: boolean | undefined\n): LayoutItemType[] => {\n // If this is static and not explicitly enabled as draggable,\n // no move is possible, so we can short-circuit this immediately.\n if (l.static && l.isDraggable !== true) return layout\n\n // Short-circuit if nothing to do.\n if (l.y === y && l.x === x) return layout\n\n log(\n 'moveElement',\n LEVELS.DEBUG,\n `Moving element \"${l.i}\"@[${l.x},${l.y}] => [${x},${y}]`\n )\n const oldX = l.x\n const oldY = l.y\n\n // This is quite a bit faster than extending the object\n if (typeof x === 'number') l.x = x\n if (typeof y === 'number') l.y = y\n l.moved = true\n\n // If this collides with anything, move it.\n // When doing this comparison, we have to sort the items we compare with\n // to ensure, in the case of multiple collisions, that we're getting the\n // nearest collision.\n let sorted = sortLayoutItems(layout)\n const movingUp = typeof y === 'number'\n ? oldY >= y\n : false\n // $FlowIgnore acceptable modification of read-only array as it was recently cloned\n if (movingUp) sorted = sorted.reverse()\n const collisions = getAllCollisions(sorted, l)\n const hasCollisions = collisions.length > 0\n\n // We may have collisions. We can short-circuit if we've turned off collisions or\n // allowed overlap.\n if (hasCollisions && preventCollision) {\n // If we are preventing collision but not allowing overlap, we need to\n // revert the position of this element so it goes to where it came from, rather\n // than the user's desired location.\n log(\n 'moveElement',\n LEVELS.DEBUG,\n `Collision prevented on ${l.i}, reverting.`\n )\n l.x = oldX\n l.y = oldY\n l.moved = false\n return layout // did not change so don't clone\n }\n\n // Move each item that collides away from this element.\n for (let i = 0, len = collisions.length; i < len; i++) {\n const collision = collisions[i]\n log(\n 'moveElement',\n LEVELS.DEBUG,\n `Resolving collision between \"${l.i}\"@[${l.x},${l.y}] and \"${collision.i}\"@[${collision.x},${collision.y}]`\n )\n\n // Short circuit so we can't infinite loop\n if (collision.moved) {\n continue\n }\n\n // Don't move static items - we have to move *this* element away\n if (collision.static) {\n layout = moveElementAwayFromCollision(\n layout,\n collision,\n l,\n isUserAction\n )\n } else {\n layout = moveElementAwayFromCollision(\n layout,\n l,\n collision,\n isUserAction\n )\n }\n }\n\n return layout\n}\n\n/**\n * This is where the magic needs to happen - given a collision, move an element away from the collision.\n * We attempt to move it up if there's room, otherwise it goes below.\n *\n * @param {Array} layout Full layout to modify.\n * @param {LayoutItem} collidesWith Layout item we're colliding with.\n * @param {LayoutItem} itemToMove Layout item we're moving.\n */\nexport const moveElementAwayFromCollision = (\n layout: LayoutItemType[],\n collidesWith: LayoutItemType,\n itemToMove: LayoutItemType,\n isUserAction: boolean\n) => {\n const preventCollision = collidesWith.static // we're already colliding (not for static items)\n\n // If there is enough space above the collision to put this element, move it there.\n // We only do this on the main collision as this can get funky in cascades and cause\n // unwanted swapping behavior.\n if (isUserAction) {\n // Reset isUserAction flag because we're not in the main collision anymore.\n isUserAction = false\n\n // Make a mock item so we don't modify the item here, only modify in moveElement.\n const fakeItem = {\n x: itemToMove.x,\n y: Math.max(collidesWith.y - itemToMove.h, 0),\n w: itemToMove.w,\n h: itemToMove.h,\n i: '-1'\n }\n\n const firstCollision = getFirstCollision(layout, fakeItem)\n const collisionNorth =\n firstCollision && firstCollision.y + firstCollision.h > collidesWith.y\n\n // No collision? If so, we can go up there; otherwise, we'll end up moving down as normal\n if (!firstCollision) {\n log(\n 'moveElementAwayFromCollision',\n LEVELS.DEBUG,\n `Doing reverse collision on ${itemToMove.i} up to [${fakeItem.x},${fakeItem.y}].`\n )\n return moveElement(\n layout,\n itemToMove,\n undefined,\n fakeItem.y,\n isUserAction,\n preventCollision\n )\n } else if (collisionNorth) {\n return moveElement(\n layout,\n itemToMove,\n undefined,\n collidesWith.y + 1,\n isUserAction,\n preventCollision\n )\n }\n }\n\n const newX = undefined\n const newY = itemToMove.y + 1\n\n if (newX == null && newY == null) {\n return layout\n }\n return moveElement(\n layout,\n itemToMove,\n undefined,\n itemToMove.y + 1,\n isUserAction,\n preventCollision\n )\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@ulgaal/react-grid-layout",
3
+ "version": "1.0.0",
4
+ "description": "A library to provide a grid layout system with on-the-fly adjustement in response to native HTML5 mouse and drag-and-drop events",
5
+ "keywords": [
6
+ "react",
7
+ "table",
8
+ "grid",
9
+ "datagrid",
10
+ "reducer",
11
+ "useReducer"
12
+ ],
13
+ "homepage": "https://gitlab.com/coder-tribe-group/react-infra",
14
+ "bugs": {
15
+ "url": "https://gitlab.com/coder-tribe-group/react-infra/-/incidents"
16
+ },
17
+ "license": "Apache-2.0",
18
+ "author": {
19
+ "name": "Ulrich Gaal",
20
+ "email": "react-grid-layout@coder-tribe.ovh"
21
+ },
22
+ "type": "module",
23
+ "module": "dist/index.js",
24
+ "types": "dist/index.d.ts",
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "scripts": {
29
+ "lib": "tsc --p ./tsconfig.app.json && vite build --config vite.config-lib.ts",
30
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
31
+ "docs": "api-extractor --debug run ; api-documenter markdown"
32
+ },
33
+ "dependencies": {
34
+ },
35
+ "peerDependencies": {
36
+ "react": "^16.x || ^17.x || ^18.x || ^19.x",
37
+ "react-dom": "16.x || ^17.x || ^18.x || ^19.x",
38
+ "@types/react": "^18.x || ^19.x",
39
+ "@types/react-dom": "^18.x || ^19.x"
40
+ },
41
+ "devDependencies": {
42
+ "@eslint/js": "^9.38.0",
43
+ "@microsoft/api-documenter": "^7.30.6",
44
+ "@microsoft/api-extractor": "^7.58.8",
45
+ "@types/lodash": "^4.17.24",
46
+ "@types/react": "^18.3.12",
47
+ "@types/react-dom": "^18.3.1",
48
+ "@vitejs/plugin-react": "^6.0.2",
49
+ "@vitest/ui": "^4.1.8",
50
+ "eslint": "^9.38.0",
51
+ "eslint-plugin-react": "^7.37.5",
52
+ "eslint-plugin-react-hooks": "^7.1.1",
53
+ "eslint-plugin-react-refresh": "^0.5.2",
54
+ "eslint-plugin-simple-import-sort": "^13.0.0",
55
+ "glob": "^13.0.6",
56
+ "globals": "^17.6.0",
57
+ "jsdom": "^29.1.1",
58
+ "neostandard": "^0.13.0",
59
+ "react": "^18.3.1",
60
+ "react-dom": "^18.3.1",
61
+ "typescript": "~5.9.3",
62
+ "typescript-eslint": "^8.59.4",
63
+ "vite": "^8.0.16",
64
+ "vite-plugin-checker": "^0.14.1",
65
+ "vite-plugin-dts": "^5.0.2",
66
+ "vitest": "^4.1.8"
67
+ }
68
+ }