react-edge-dock 1.0.3 → 1.0.5
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/README.md +23 -3
- package/dist/types.d.ts +11 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/useEdgeDock.d.ts.map +1 -1
- package/dist/useEdgeDock.js +25 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ export default function MyComponent() {
|
|
|
65
65
|
- `dockMode`: `"free"` | `"auto"` | `"manual"` - Docking behavior
|
|
66
66
|
- `dockEdge`: `"left"` | `"right"` | `"top"` | `"bottom"` - Fixed edge (manual mode)
|
|
67
67
|
- `allowedEdges`: `DockEdge[]` - Restrict docking to specific edges (e.g., `['left', 'right']` for horizontal only)
|
|
68
|
-
- `edgeOffset`: `number` - Gap from
|
|
68
|
+
- `edgeOffset`: `number | { left?: number; right?: number; top?: number; bottom?: number }` - Gap from edges in pixels
|
|
69
69
|
- `animation`: `boolean` - Enable snap animations
|
|
70
70
|
- `popupGap`: `number` - Gap between button and popup
|
|
71
71
|
- `position`: `{ x: number; y: number }` - Initial/controlled position
|
|
@@ -75,13 +75,33 @@ export default function MyComponent() {
|
|
|
75
75
|
|
|
76
76
|
## Examples
|
|
77
77
|
|
|
78
|
+
### Same offset for all edges
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
<EdgeDock
|
|
82
|
+
dockMode="auto"
|
|
83
|
+
edgeOffset={16}
|
|
84
|
+
button={<button>🚀</button>}
|
|
85
|
+
/>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Different offset for each edge
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<EdgeDock
|
|
92
|
+
dockMode="auto"
|
|
93
|
+
edgeOffset={{ left: 10, right: 20, top: 15, bottom: 25 }}
|
|
94
|
+
button={<button>🎯</button>}
|
|
95
|
+
/>
|
|
96
|
+
```
|
|
97
|
+
|
|
78
98
|
### Restrict to horizontal edges only (left/right)
|
|
79
99
|
|
|
80
100
|
```tsx
|
|
81
101
|
<EdgeDock
|
|
82
102
|
dockMode="auto"
|
|
83
103
|
allowedEdges={['left', 'right']}
|
|
84
|
-
edgeOffset={16}
|
|
104
|
+
edgeOffset={{ left: 16, right: 24 }}
|
|
85
105
|
button={<button>📱</button>}
|
|
86
106
|
/>
|
|
87
107
|
```
|
|
@@ -102,7 +122,7 @@ export default function MyComponent() {
|
|
|
102
122
|
<EdgeDock
|
|
103
123
|
dockMode="manual"
|
|
104
124
|
dockEdge="right"
|
|
105
|
-
edgeOffset={20}
|
|
125
|
+
edgeOffset={{ right: 20 }}
|
|
106
126
|
button={<button>➡️</button>}
|
|
107
127
|
/>
|
|
108
128
|
```
|
package/dist/types.d.ts
CHANGED
|
@@ -27,6 +27,15 @@ export interface DockState {
|
|
|
27
27
|
/** Whether the popup is currently open */
|
|
28
28
|
isPopupOpen: boolean;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Edge offset configuration - can be a single number for all edges or individual values
|
|
32
|
+
*/
|
|
33
|
+
export type EdgeOffset = number | {
|
|
34
|
+
left?: number;
|
|
35
|
+
right?: number;
|
|
36
|
+
top?: number;
|
|
37
|
+
bottom?: number;
|
|
38
|
+
};
|
|
30
39
|
/**
|
|
31
40
|
* Configuration for EdgeDock component
|
|
32
41
|
*/
|
|
@@ -43,8 +52,8 @@ export interface EdgeDockConfig {
|
|
|
43
52
|
animation?: boolean;
|
|
44
53
|
/** Gap between button and popup in pixels */
|
|
45
54
|
popupGap?: number;
|
|
46
|
-
/** Offset from edge when docked
|
|
47
|
-
edgeOffset?:
|
|
55
|
+
/** Offset from edge when docked - number for all edges or object for individual edges */
|
|
56
|
+
edgeOffset?: EdgeOffset;
|
|
48
57
|
/** z-index for the dock container */
|
|
49
58
|
zIndex?: number;
|
|
50
59
|
/** Callback when dock state changes */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE3D;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,iCAAiC;IACjC,QAAQ,EAAE,QAAQ,CAAC;IACnB,iDAAiD;IACjD,UAAU,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5B,oDAAoD;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,0CAA0C;IAC1C,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC1B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEdgeDock.d.ts","sourceRoot":"","sources":["../src/useEdgeDock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EAId,iBAAiB,
|
|
1
|
+
{"version":3,"file":"useEdgeDock.d.ts","sourceRoot":"","sources":["../src/useEdgeDock.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EAId,iBAAiB,EAIlB,MAAM,SAAS,CAAC;AAwLjB;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,GAAE,cAAmB,GAAG,iBAAiB,CAgV1E"}
|
package/dist/useEdgeDock.js
CHANGED
|
@@ -12,6 +12,16 @@ function getViewport() {
|
|
|
12
12
|
}
|
|
13
13
|
return { width: window.innerWidth, height: window.innerHeight };
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Get offset value for a specific edge
|
|
17
|
+
*/
|
|
18
|
+
function getOffsetForEdge(edgeOffset, edge) {
|
|
19
|
+
if (!edgeOffset)
|
|
20
|
+
return 0;
|
|
21
|
+
if (typeof edgeOffset === 'number')
|
|
22
|
+
return edgeOffset;
|
|
23
|
+
return edgeOffset[edge] ?? 0;
|
|
24
|
+
}
|
|
15
25
|
/**
|
|
16
26
|
* Calculate which edge is closest to the given position
|
|
17
27
|
*/
|
|
@@ -38,9 +48,10 @@ function getClosestEdge(pos, viewport, allowedEdges) {
|
|
|
38
48
|
/**
|
|
39
49
|
* Snap position to edge based on dock mode
|
|
40
50
|
*/
|
|
41
|
-
function snapToEdge(pos, edge, viewport, buttonDimensions,
|
|
51
|
+
function snapToEdge(pos, edge, viewport, buttonDimensions, edgeOffset) {
|
|
42
52
|
const halfWidth = buttonDimensions.width / 2;
|
|
43
53
|
const halfHeight = buttonDimensions.height / 2;
|
|
54
|
+
const offset = getOffsetForEdge(edgeOffset, edge);
|
|
44
55
|
switch (edge) {
|
|
45
56
|
case 'left':
|
|
46
57
|
return {
|
|
@@ -65,14 +76,18 @@ function snapToEdge(pos, edge, viewport, buttonDimensions, offset = 0) {
|
|
|
65
76
|
}
|
|
66
77
|
}
|
|
67
78
|
/**
|
|
68
|
-
* Constrain position within viewport bounds
|
|
79
|
+
* Constrain position within viewport bounds, respecting edge offsets
|
|
69
80
|
*/
|
|
70
|
-
function constrainToViewport(pos, viewport, buttonDimensions) {
|
|
81
|
+
function constrainToViewport(pos, viewport, buttonDimensions, edgeOffset) {
|
|
71
82
|
const halfWidth = buttonDimensions.width / 2;
|
|
72
83
|
const halfHeight = buttonDimensions.height / 2;
|
|
84
|
+
const leftOffset = getOffsetForEdge(edgeOffset, 'left');
|
|
85
|
+
const rightOffset = getOffsetForEdge(edgeOffset, 'right');
|
|
86
|
+
const topOffset = getOffsetForEdge(edgeOffset, 'top');
|
|
87
|
+
const bottomOffset = getOffsetForEdge(edgeOffset, 'bottom');
|
|
73
88
|
return {
|
|
74
|
-
x: Math.max(halfWidth, Math.min(viewport.width - halfWidth, pos.x)),
|
|
75
|
-
y: Math.max(halfHeight, Math.min(viewport.height - halfHeight, pos.y)),
|
|
89
|
+
x: Math.max(halfWidth + leftOffset, Math.min(viewport.width - halfWidth - rightOffset, pos.x)),
|
|
90
|
+
y: Math.max(halfHeight + topOffset, Math.min(viewport.height - halfHeight - bottomOffset, pos.y)),
|
|
76
91
|
};
|
|
77
92
|
}
|
|
78
93
|
/**
|
|
@@ -128,7 +143,7 @@ function calculatePopupPosition(buttonPos, buttonDimensions, popupDimensions, vi
|
|
|
128
143
|
* Main hook for edge dock functionality
|
|
129
144
|
*/
|
|
130
145
|
export function useEdgeDock(config = {}) {
|
|
131
|
-
const { dockMode = 'auto', dockEdge, allowedEdges, position: controlledPosition, animation = true, popupGap = 12, edgeOffset
|
|
146
|
+
const { dockMode = 'auto', dockEdge, allowedEdges, position: controlledPosition, animation = true, popupGap = 12, edgeOffset, zIndex = 9999, onDockChange, isPopupOpen: controlledPopupOpen, onPopupChange, } = config;
|
|
132
147
|
const buttonRef = useRef(null);
|
|
133
148
|
const popupRef = useRef(null);
|
|
134
149
|
const isMountedRef = useRef(false);
|
|
@@ -167,7 +182,7 @@ export function useEdgeDock(config = {}) {
|
|
|
167
182
|
const buttonDimensions = { width: buttonRect.width, height: buttonRect.height };
|
|
168
183
|
// Set initial position on client after mount
|
|
169
184
|
let initialPos = { x: viewport.width - 60, y: viewport.height - 60 };
|
|
170
|
-
initialPos = constrainToViewport(initialPos, viewport, buttonDimensions);
|
|
185
|
+
initialPos = constrainToViewport(initialPos, viewport, buttonDimensions, edgeOffset);
|
|
171
186
|
if (dockMode === 'auto') {
|
|
172
187
|
const edge = getClosestEdge(initialPos, viewport, allowedEdges);
|
|
173
188
|
initialPos = snapToEdge(initialPos, edge, viewport, buttonDimensions, edgeOffset);
|
|
@@ -209,7 +224,7 @@ export function useEdgeDock(config = {}) {
|
|
|
209
224
|
const buttonRect = buttonRef.current.getBoundingClientRect();
|
|
210
225
|
const viewport = getViewport();
|
|
211
226
|
const buttonDimensions = { width: buttonRect.width, height: buttonRect.height };
|
|
212
|
-
let finalPos = constrainToViewport(newPos, viewport, buttonDimensions);
|
|
227
|
+
let finalPos = constrainToViewport(newPos, viewport, buttonDimensions, edgeOffset);
|
|
213
228
|
if (dockMode === 'auto') {
|
|
214
229
|
const edge = getClosestEdge(finalPos, viewport, allowedEdges);
|
|
215
230
|
finalPos = snapToEdge(finalPos, edge, viewport, buttonDimensions, edgeOffset);
|
|
@@ -286,7 +301,7 @@ export function useEdgeDock(config = {}) {
|
|
|
286
301
|
const viewport = { width: window.innerWidth, height: window.innerHeight };
|
|
287
302
|
const buttonDimensions = { width: buttonRect.width, height: buttonRect.height };
|
|
288
303
|
// During drag, only constrain to viewport (no snapping)
|
|
289
|
-
const constrainedPos = constrainToViewport(newPos, viewport, buttonDimensions);
|
|
304
|
+
const constrainedPos = constrainToViewport(newPos, viewport, buttonDimensions, edgeOffset);
|
|
290
305
|
setPositionInternal(constrainedPos);
|
|
291
306
|
};
|
|
292
307
|
const handlePointerUp = () => {
|
|
@@ -341,7 +356,7 @@ export function useEdgeDock(config = {}) {
|
|
|
341
356
|
const buttonRect = buttonRef.current.getBoundingClientRect();
|
|
342
357
|
const viewport = getViewport();
|
|
343
358
|
const buttonDimensions = { width: buttonRect.width, height: buttonRect.height };
|
|
344
|
-
let newPos = constrainToViewport(position, viewport, buttonDimensions);
|
|
359
|
+
let newPos = constrainToViewport(position, viewport, buttonDimensions, edgeOffset);
|
|
345
360
|
if (dockMode === 'auto') {
|
|
346
361
|
const edge = getClosestEdge(newPos, viewport, allowedEdges);
|
|
347
362
|
newPos = snapToEdge(newPos, edge, viewport, buttonDimensions, edgeOffset);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-edge-dock",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "A zero-dependency React TypeScript library for customizable draggable edge-docked floating buttons with popup support",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|