sliftutils 1.9.0 → 1.9.1
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/.cursor/rules/coding-styles.mdc +0 -1
- package/.cursor/rules/styling-css.mdc +1 -1
- package/CLAUDE.md +1 -1
- package/index.d.ts +19 -0
- package/package.json +1 -1
- package/render-utils/drag.d.ts +15 -0
- package/render-utils/drag.ts +161 -0
|
@@ -14,7 +14,6 @@ alwaysApply: true
|
|
|
14
14
|
- When functions have more than one primitive parameter, such that you could confuse them (even something as simple as start time and end time), you should put them inside of an object and call that object `config`, so the function only has a single parameter.
|
|
15
15
|
- Never use return codes, always prefer to throw on error. Include a lot of context information in the error. If any values might be extremely large, such as parsing a file, limit them (ex, to 500 characters).
|
|
16
16
|
- Use double quotes, not single quotes.
|
|
17
|
-
- Never use the ternary operator. Instead, do this: `x ? y : z` => `x && y || z`.
|
|
18
17
|
- Never use non-null assertion operator, instead check the value, and if necessary (because it is accessed in nested functions), use a `const` variable to preserve the type.
|
|
19
18
|
- Errors should almost always use a template string to include the expected value, and the actual value, as in: `throw new Error(\`Expected X, was \${Y}\`);`
|
|
20
19
|
- Don't use switch statements. Use if/else statements instead.
|
|
@@ -34,7 +34,7 @@ className={css
|
|
|
34
34
|
+ (conditionalExample && css.opacity(0.5))
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
|
-
Specifically, it should be a value that you check for, and then the value. Don't
|
|
37
|
+
Specifically, it should be a value that you check for, and then the value. Don't do `|| ""`. If you have multiple values, chain them with `||` and `&&`. Keep the CSS simple, don't add too much, because it's easier to add than to remove.
|
|
38
38
|
|
|
39
39
|
## Aliases and Helpers
|
|
40
40
|
|
package/CLAUDE.md
CHANGED
package/index.d.ts
CHANGED
|
@@ -852,6 +852,25 @@ declare module "sliftutils/render-utils/colors" {
|
|
|
852
852
|
|
|
853
853
|
}
|
|
854
854
|
|
|
855
|
+
declare module "sliftutils/render-utils/drag" {
|
|
856
|
+
export declare let dragCount: number;
|
|
857
|
+
type DragOffset = {
|
|
858
|
+
x: number;
|
|
859
|
+
y: number;
|
|
860
|
+
};
|
|
861
|
+
export declare function performDrag(e: MouseEvent, onMove: (offset: DragOffset) => void, onDone?: (offset: DragOffset) => void): void;
|
|
862
|
+
export declare function performDrag2(config: {
|
|
863
|
+
e: MouseEvent;
|
|
864
|
+
onMove?: (offset: DragOffset) => void;
|
|
865
|
+
onDone?: (offset: DragOffset) => void;
|
|
866
|
+
onFinally?: (passedSlop: boolean) => void;
|
|
867
|
+
slop?: number;
|
|
868
|
+
}): void;
|
|
869
|
+
export declare function cancelDrag(): void;
|
|
870
|
+
export {};
|
|
871
|
+
|
|
872
|
+
}
|
|
873
|
+
|
|
855
874
|
declare module "sliftutils/render-utils/mobxTyped" {
|
|
856
875
|
import { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved, Reaction } from "mobx";
|
|
857
876
|
export { observable, runInAction, computed, autorun, onBecomeObserved, onBecomeUnobserved, Reaction };
|
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare let dragCount: number;
|
|
2
|
+
type DragOffset = {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
};
|
|
6
|
+
export declare function performDrag(e: MouseEvent, onMove: (offset: DragOffset) => void, onDone?: (offset: DragOffset) => void): void;
|
|
7
|
+
export declare function performDrag2(config: {
|
|
8
|
+
e: MouseEvent;
|
|
9
|
+
onMove?: (offset: DragOffset) => void;
|
|
10
|
+
onDone?: (offset: DragOffset) => void;
|
|
11
|
+
onFinally?: (passedSlop: boolean) => void;
|
|
12
|
+
slop?: number;
|
|
13
|
+
}): void;
|
|
14
|
+
export declare function cancelDrag(): void;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { MaybePromise } from "socket-function/src/types";
|
|
2
|
+
import { runInAction } from "./mobxTyped";
|
|
3
|
+
|
|
4
|
+
export let dragCount = 0;
|
|
5
|
+
|
|
6
|
+
type DragOffset = { x: number; y: number };
|
|
7
|
+
|
|
8
|
+
function throttleFunctionFast<Args extends unknown[]>(
|
|
9
|
+
fnc: (...args: Args) => MaybePromise<void>
|
|
10
|
+
): (...args: Args) => void {
|
|
11
|
+
let pendingCall: { args: Args } | undefined;
|
|
12
|
+
let inCall = false;
|
|
13
|
+
return async (...args: Args) => {
|
|
14
|
+
if (inCall) {
|
|
15
|
+
pendingCall = { args };
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
inCall = true;
|
|
19
|
+
try {
|
|
20
|
+
await fnc(...args);
|
|
21
|
+
} finally {
|
|
22
|
+
inCall = false;
|
|
23
|
+
if (pendingCall) {
|
|
24
|
+
let call = pendingCall;
|
|
25
|
+
pendingCall = undefined;
|
|
26
|
+
void fnc(...call.args);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function inAction<Args extends unknown[]>(fnc: (...args: Args) => void): (...args: Args) => void {
|
|
33
|
+
return (...args: Args) => runInAction(() => fnc(...args));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function performDrag(
|
|
37
|
+
e: MouseEvent,
|
|
38
|
+
onMove: (offset: DragOffset) => void,
|
|
39
|
+
onDone?: (offset: DragOffset) => void,
|
|
40
|
+
) {
|
|
41
|
+
return performDrag2({ e, onMove, onDone });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function performDrag2(
|
|
45
|
+
config: {
|
|
46
|
+
e: MouseEvent;
|
|
47
|
+
onMove?: (offset: DragOffset) => void;
|
|
48
|
+
onDone?: (offset: DragOffset) => void;
|
|
49
|
+
onFinally?: (passedSlop: boolean) => void;
|
|
50
|
+
slop?: number;
|
|
51
|
+
}
|
|
52
|
+
) {
|
|
53
|
+
let { e, slop } = config;
|
|
54
|
+
let onMove = inAction(config.onMove ?? (() => { }));
|
|
55
|
+
let onDone = config.onDone && inAction(config.onDone);
|
|
56
|
+
let onFinally = config.onFinally && inAction(config.onFinally);
|
|
57
|
+
dragCount++;
|
|
58
|
+
|
|
59
|
+
let startMouseX = e.clientX;
|
|
60
|
+
let startMouseY = e.clientY;
|
|
61
|
+
let lastMouseX = e.clientX;
|
|
62
|
+
let lastMouseY = e.clientY;
|
|
63
|
+
|
|
64
|
+
let passedSlop = !slop;
|
|
65
|
+
|
|
66
|
+
function cancel() {
|
|
67
|
+
lastMouseX = startMouseX;
|
|
68
|
+
lastMouseY = startMouseY;
|
|
69
|
+
finish();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let finished = false;
|
|
73
|
+
let disposed = false;
|
|
74
|
+
|
|
75
|
+
const triggerMove = throttleFunctionFast(async () => {
|
|
76
|
+
if (disposed) return;
|
|
77
|
+
let deltaX = lastMouseX - startMouseX;
|
|
78
|
+
let deltaY = lastMouseY - startMouseY;
|
|
79
|
+
if (slop) {
|
|
80
|
+
let dist = Math.sqrt(deltaX ** 2 + deltaY ** 2);
|
|
81
|
+
if (dist > slop) passedSlop = true;
|
|
82
|
+
if (!passedSlop) return;
|
|
83
|
+
}
|
|
84
|
+
onMove({ x: deltaX, y: deltaY });
|
|
85
|
+
await new Promise(r => requestAnimationFrame(r));
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const onMouseMove = (e: MouseEvent) => {
|
|
89
|
+
if (finished) return;
|
|
90
|
+
if (e.buttons === 0) {
|
|
91
|
+
finish();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (lastMouseX === e.clientX && lastMouseY === e.clientY) return;
|
|
95
|
+
lastMouseX = e.clientX;
|
|
96
|
+
lastMouseY = e.clientY;
|
|
97
|
+
triggerMove();
|
|
98
|
+
};
|
|
99
|
+
let finish = () => {
|
|
100
|
+
selfCancelCallback.delete(cancel);
|
|
101
|
+
try {
|
|
102
|
+
if (finished) return;
|
|
103
|
+
finished = true;
|
|
104
|
+
dragCount--;
|
|
105
|
+
window.removeEventListener("mousemove", onMouseMove);
|
|
106
|
+
window.removeEventListener("mouseup", finish, { capture: true });
|
|
107
|
+
window.removeEventListener("blur", onBlur);
|
|
108
|
+
document.removeEventListener("keydown", keyDown);
|
|
109
|
+
triggerMove();
|
|
110
|
+
if (onDone) {
|
|
111
|
+
let deltaX = lastMouseX - startMouseX;
|
|
112
|
+
let deltaY = lastMouseY - startMouseY;
|
|
113
|
+
if (slop) {
|
|
114
|
+
let dist = Math.sqrt(deltaX ** 2 + deltaY ** 2);
|
|
115
|
+
if (dist > slop) passedSlop = true;
|
|
116
|
+
if (!passedSlop) return;
|
|
117
|
+
}
|
|
118
|
+
onDone({ x: deltaX, y: deltaY });
|
|
119
|
+
}
|
|
120
|
+
} finally {
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
onFinally?.(passedSlop);
|
|
123
|
+
}, 0);
|
|
124
|
+
}
|
|
125
|
+
disposed = true;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const keyDown = (e: KeyboardEvent) => {
|
|
129
|
+
if (finished) return;
|
|
130
|
+
if (e.code === "Escape") {
|
|
131
|
+
cancel();
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const onBlur = () => {
|
|
136
|
+
if (finished) return;
|
|
137
|
+
cancel();
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
window.addEventListener("mousemove", onMouseMove);
|
|
141
|
+
window.addEventListener("mouseup", finish, { capture: true });
|
|
142
|
+
window.addEventListener("blur", onBlur);
|
|
143
|
+
document.addEventListener("keydown", keyDown);
|
|
144
|
+
selfCancelCallback.add(cancel);
|
|
145
|
+
|
|
146
|
+
if (!slop) {
|
|
147
|
+
onMove({ x: 0, y: 0 });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let selfCancelCallback = new Set<() => void>();
|
|
152
|
+
export function cancelDrag() {
|
|
153
|
+
for (let callback of selfCancelCallback) {
|
|
154
|
+
try {
|
|
155
|
+
callback();
|
|
156
|
+
} catch (e) {
|
|
157
|
+
console.error(`Error in drag cancel callback: ${(e as Error).stack ?? e}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
selfCancelCallback.clear();
|
|
161
|
+
}
|