@cocreate/position 1.14.0 → 2.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/.github/FUNDING.yml +1 -1
- package/.github/workflows/automated.yml +18 -7
- package/CHANGELOG.md +309 -275
- package/CONTRIBUTING.md +6 -6
- package/README.md +210 -85
- package/demo/index.html +474 -46
- package/docs/index.html +7 -7
- package/package.json +23 -17
- package/src/autoScroll.js +213 -0
- package/src/draggable/engine.js +698 -0
- package/src/draggable.js +64 -0
- package/src/eventOperator.js +15 -0
- package/src/helpers/events.js +34 -0
- package/src/index.css +19 -0
- package/src/index.js +232 -38
- package/src/position.js +443 -349
- package/src/snappable.js +572 -0
- package/test/auto-scroll.browser.cjs +307 -0
- package/webpack.config.js +1 -0
package/src/draggable.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import observer from "@cocreate/observer";
|
|
2
|
+
import Position from "./draggable/engine.js";
|
|
3
|
+
|
|
4
|
+
const selector = "[draggable]";
|
|
5
|
+
|
|
6
|
+
export function initElement(element, options = {}) {
|
|
7
|
+
if (!element?.matches) return;
|
|
8
|
+
const draggable = options.draggable ?? element.matches(selector);
|
|
9
|
+
const previous = element.position;
|
|
10
|
+
const dragScope = options.dragScope || null;
|
|
11
|
+
|
|
12
|
+
if (!previous?._positionController) {
|
|
13
|
+
const position = new Position(element, element.parentElement, {
|
|
14
|
+
draggable,
|
|
15
|
+
dragScope,
|
|
16
|
+
delegated: options.delegated
|
|
17
|
+
});
|
|
18
|
+
if (previous?.place) position.place = previous.place;
|
|
19
|
+
if (previous?.unplace) position.unplace = previous.unplace;
|
|
20
|
+
position._positionController = true;
|
|
21
|
+
element.position = position;
|
|
22
|
+
} else {
|
|
23
|
+
previous.options.draggable = draggable;
|
|
24
|
+
previous.options.dragScope = dragScope;
|
|
25
|
+
if (draggable && !options.delegated && previous.options.delegated) {
|
|
26
|
+
previous.options.delegated = false;
|
|
27
|
+
previous._initEvent();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return element.position;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function initElements(elements) {
|
|
34
|
+
for (const element of elements) initElement(element);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function refresh(node) {
|
|
38
|
+
if (node.nodeType !== 1) return;
|
|
39
|
+
if (node.matches(selector)) initElement(node);
|
|
40
|
+
initElements(node.querySelectorAll(selector));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function init() {
|
|
44
|
+
initElements(document.querySelectorAll(selector));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
observer.init({
|
|
48
|
+
name: "positionDraggableAddedNodes",
|
|
49
|
+
types: ["addedNodes"],
|
|
50
|
+
selector,
|
|
51
|
+
callback: mutation => refresh(mutation.target)
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
observer.init({
|
|
55
|
+
name: "positionDraggableAttributes",
|
|
56
|
+
types: ["attributes"],
|
|
57
|
+
attributeFilter: ["draggable"],
|
|
58
|
+
selector,
|
|
59
|
+
callback: mutation => initElement(mutation.target)
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
init();
|
|
63
|
+
|
|
64
|
+
export default { init, initElement, initElements };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { getValueFromObject } from "@cocreate/utils";
|
|
2
|
+
|
|
3
|
+
export function resolveEventOperator(query, event) {
|
|
4
|
+
if (typeof query !== "string" || !query.startsWith("event."))
|
|
5
|
+
return { handled: false, value: undefined, selector: null };
|
|
6
|
+
|
|
7
|
+
const [, path, remaining = ""] = query.match(/^event\.([^\s]+)(?:\s+([\s\S]*))?$/) || [];
|
|
8
|
+
if (!path) return { handled: true, value: undefined, selector: null };
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
handled: true,
|
|
12
|
+
value: getValueFromObject(event, path),
|
|
13
|
+
selector: remaining.trim() || "$this"
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function normalizeEvent(event) {
|
|
2
|
+
const detail = event?.detail && typeof event.detail === "object" ? event.detail : {};
|
|
3
|
+
const originalEvent = detail.originalEvent || event;
|
|
4
|
+
const target = detail.target ?? originalEvent?.target ?? event?.target ?? null;
|
|
5
|
+
const cursor = detail.cursor || {};
|
|
6
|
+
return {
|
|
7
|
+
type: originalEvent?.type || event?.type || "",
|
|
8
|
+
target,
|
|
9
|
+
relatedTarget: detail.relatedTarget ?? originalEvent?.relatedTarget ?? event?.relatedTarget ?? null,
|
|
10
|
+
document: detail.document ?? originalEvent?.view?.document ?? target?.ownerDocument ?? null,
|
|
11
|
+
clientX: cursor.x ?? originalEvent?.clientX ?? event?.clientX,
|
|
12
|
+
clientY: cursor.y ?? originalEvent?.clientY ?? event?.clientY,
|
|
13
|
+
which: originalEvent?.which ?? event?.which,
|
|
14
|
+
button: originalEvent?.button ?? event?.button,
|
|
15
|
+
touches: originalEvent?.touches ?? event?.touches,
|
|
16
|
+
changedTouches: originalEvent?.changedTouches ?? event?.changedTouches,
|
|
17
|
+
originalEvent,
|
|
18
|
+
detail: event?.detail,
|
|
19
|
+
preventDefault() {
|
|
20
|
+
originalEvent?.preventDefault?.();
|
|
21
|
+
if (event !== originalEvent) event?.preventDefault?.();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function dispatch(element, name, detail = {}) {
|
|
27
|
+
const EventConstructor = element?.ownerDocument?.defaultView?.CustomEvent;
|
|
28
|
+
if (!EventConstructor) return;
|
|
29
|
+
const event = new EventConstructor(name, {
|
|
30
|
+
detail: { element, instance: element.position, ...detail }
|
|
31
|
+
});
|
|
32
|
+
element.dispatchEvent(event);
|
|
33
|
+
return event;
|
|
34
|
+
}
|
package/src/index.css
CHANGED
|
@@ -20,3 +20,22 @@
|
|
|
20
20
|
[drag-area] {
|
|
21
21
|
cursor: move;
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
.position-moving:not(.position-cloning) {
|
|
25
|
+
position: fixed !important;
|
|
26
|
+
width: var(--position-moving-width) !important;
|
|
27
|
+
height: var(--position-moving-height) !important;
|
|
28
|
+
min-width: var(--position-moving-width) !important;
|
|
29
|
+
min-height: var(--position-moving-height) !important;
|
|
30
|
+
max-width: var(--position-moving-width) !important;
|
|
31
|
+
max-height: var(--position-moving-height) !important;
|
|
32
|
+
box-sizing: border-box !important;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.position-cloning {
|
|
36
|
+
opacity: 0.6;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.position-moving-preview {
|
|
40
|
+
pointer-events: none;
|
|
41
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,38 +1,232 @@
|
|
|
1
|
-
import observer from "@cocreate/observer";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
import observer from "@cocreate/observer";
|
|
2
|
+
import "./index.css";
|
|
3
|
+
|
|
4
|
+
const draggableSelector = "[draggable], [draggable-query], [clonable-query]";
|
|
5
|
+
const snappableSelector = "[droppable-query], [snappable-query], [position-reference]";
|
|
6
|
+
const placementSelector = "[position-query], [position-element], [position-events], [position-box]";
|
|
7
|
+
|
|
8
|
+
let draggablePromise;
|
|
9
|
+
let snappablePromise;
|
|
10
|
+
let placementPromise;
|
|
11
|
+
|
|
12
|
+
function load(getPromise, setPromise, importer) {
|
|
13
|
+
let promise = getPromise();
|
|
14
|
+
if (!promise) {
|
|
15
|
+
promise = importer()
|
|
16
|
+
.then(module => {
|
|
17
|
+
module.init?.();
|
|
18
|
+
return module.default || module;
|
|
19
|
+
})
|
|
20
|
+
.catch(error => {
|
|
21
|
+
setPromise(undefined);
|
|
22
|
+
throw error;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
setPromise(promise);
|
|
26
|
+
return promise;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* @public
|
|
32
|
+
* @environment client
|
|
33
|
+
*/
|
|
34
|
+
function loadDraggable() {
|
|
35
|
+
return load(() => draggablePromise, value => { draggablePromise = value; },
|
|
36
|
+
() => import(/* webpackChunkName: "position-draggable" */ "./draggable.js"));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
* @environment client
|
|
43
|
+
*/
|
|
44
|
+
function loadSnappable() {
|
|
45
|
+
return load(() => snappablePromise, value => { snappablePromise = value; },
|
|
46
|
+
() => import(/* webpackChunkName: "position-snappable" */ "./snappable.js"));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @public
|
|
52
|
+
* @environment client
|
|
53
|
+
*/
|
|
54
|
+
function loadPlacement() {
|
|
55
|
+
return load(() => placementPromise, value => { placementPromise = value; },
|
|
56
|
+
() => import(/* webpackChunkName: "position-placement" */ "./position.js"));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function reportError(element, error, feature) {
|
|
60
|
+
const EventConstructor = element?.ownerDocument?.defaultView?.CustomEvent || CustomEvent;
|
|
61
|
+
element?.dispatchEvent(new EventConstructor("position-error", {
|
|
62
|
+
bubbles: true,
|
|
63
|
+
detail: { error, feature }
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function loadForMutation({ target, attributeName }) {
|
|
68
|
+
if (target?.matches?.(draggableSelector) || attributeName === "draggable")
|
|
69
|
+
loadDraggable().catch(error => reportError(target, error, "draggable"));
|
|
70
|
+
if (target?.matches?.(snappableSelector) || ["draggable-query", "clonable-query", "droppable-query", "snappable-query", "position-reference"].includes(attributeName))
|
|
71
|
+
loadSnappable().catch(error => reportError(target, error, "snappable"));
|
|
72
|
+
if (target?.matches?.(placementSelector) || ["position-query", "position-element", "position-events", "position-box"].includes(attributeName))
|
|
73
|
+
loadPlacement().catch(error => reportError(target, error, "placement"));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
observer.init([
|
|
77
|
+
{
|
|
78
|
+
name: "CoCreatePositionLoaderAddedNodes",
|
|
79
|
+
types: ["addedNodes"],
|
|
80
|
+
selector: [draggableSelector, snappableSelector, placementSelector].join(", "),
|
|
81
|
+
callback: loadForMutation
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "CoCreatePositionLoaderAttributes",
|
|
85
|
+
types: ["attributes"],
|
|
86
|
+
attributeFilter: ["draggable", "draggable-query", "clonable-query", "droppable-query", "snappable-query", "position-reference", "position-query", "position-element", "position-events", "position-box"],
|
|
87
|
+
selector: [draggableSelector, snappableSelector, placementSelector].join(", "),
|
|
88
|
+
callback: loadForMutation
|
|
89
|
+
}
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
function start() {
|
|
93
|
+
if (document.querySelector(draggableSelector)) loadDraggable().catch(() => {});
|
|
94
|
+
if (document.querySelector(snappableSelector)) loadSnappable().catch(() => {});
|
|
95
|
+
if (document.querySelector(placementSelector)) loadPlacement().catch(() => {});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
start();
|
|
99
|
+
|
|
100
|
+
/** Load and initialize the requested position feature modules. * @public
|
|
101
|
+
* @environment client
|
|
102
|
+
*/
|
|
103
|
+
export function init() {
|
|
104
|
+
start();
|
|
105
|
+
return Promise.all([draggablePromise, snappablePromise, placementPromise].filter(Boolean));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
*
|
|
110
|
+
* @public
|
|
111
|
+
* @environment client
|
|
112
|
+
*/
|
|
113
|
+
export function initElement(element, options) {
|
|
114
|
+
return loadDraggable().then(module => module.initElement(element, options));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
*
|
|
119
|
+
* @public
|
|
120
|
+
* @environment client
|
|
121
|
+
*/
|
|
122
|
+
export function initElements(elements) {
|
|
123
|
+
return loadDraggable().then(module => module.initElements(elements));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { loadDraggable, loadSnappable, loadPlacement };
|
|
127
|
+
|
|
128
|
+
export default { init, initElement, initElements, loadDraggable, loadSnappable, loadPlacement };
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
*
|
|
132
|
+
* @name clonable-query
|
|
133
|
+
* @kind member
|
|
134
|
+
* @attribute
|
|
135
|
+
* @environment client
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
*
|
|
140
|
+
* @name draggable
|
|
141
|
+
* @kind member
|
|
142
|
+
* @attribute
|
|
143
|
+
* @environment client
|
|
144
|
+
*/
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
*
|
|
148
|
+
* @name draggable-query
|
|
149
|
+
* @kind member
|
|
150
|
+
* @attribute
|
|
151
|
+
* @environment client
|
|
152
|
+
*/
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
*
|
|
156
|
+
* @name droppable-query
|
|
157
|
+
* @kind member
|
|
158
|
+
* @attribute
|
|
159
|
+
* @environment client
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
*
|
|
164
|
+
* @name position-box
|
|
165
|
+
* @kind member
|
|
166
|
+
* @attribute
|
|
167
|
+
* @environment client
|
|
168
|
+
*/
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
*
|
|
172
|
+
* @name position-element
|
|
173
|
+
* @kind member
|
|
174
|
+
* @attribute
|
|
175
|
+
* @environment client
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
*
|
|
180
|
+
* @name position-events
|
|
181
|
+
* @kind member
|
|
182
|
+
* @attribute
|
|
183
|
+
* @environment client
|
|
184
|
+
*/
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
*
|
|
188
|
+
* @name position-query
|
|
189
|
+
* @kind member
|
|
190
|
+
* @attribute
|
|
191
|
+
* @environment client
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
*
|
|
196
|
+
* @name position-reference
|
|
197
|
+
* @kind member
|
|
198
|
+
* @attribute
|
|
199
|
+
* @environment client
|
|
200
|
+
*/
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
*
|
|
204
|
+
* @name snappable-query
|
|
205
|
+
* @kind member
|
|
206
|
+
* @attribute
|
|
207
|
+
* @environment client
|
|
208
|
+
*/
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Declarative DOM positioning, dragging, snapping, and drag-and-drop for web interfaces.
|
|
212
|
+
*
|
|
213
|
+
* @module position
|
|
214
|
+
* @environment client
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Declarative selectors recognized by this module.
|
|
219
|
+
*
|
|
220
|
+
* @name declarative-selectors
|
|
221
|
+
* @kind member
|
|
222
|
+
* @selectors
|
|
223
|
+
* @environment client
|
|
224
|
+
* @example
|
|
225
|
+
* ```json
|
|
226
|
+
* [
|
|
227
|
+
* "[draggable], [draggable-query], [clonable-query]",
|
|
228
|
+
* "[droppable-query], [snappable-query], [position-reference]",
|
|
229
|
+
* "[position-query], [position-element], [position-events], [position-box]"
|
|
230
|
+
* ]
|
|
231
|
+
* ```
|
|
232
|
+
*/
|