@react-shimeji/core 0.2.0 → 0.2.2
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/dist/index.cjs +38 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -6
- package/dist/index.d.ts +4 -6
- package/dist/index.js +38 -55
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -219,7 +219,7 @@ interface ShimejiEngineOptions {
|
|
|
219
219
|
gravity?: number;
|
|
220
220
|
/** Maximum elapsed time applied to one animation update. Defaults to 100 ms. */
|
|
221
221
|
maxDeltaTime?: number;
|
|
222
|
-
/**
|
|
222
|
+
/** @deprecated There is no shared work area; retained for source compatibility. */
|
|
223
223
|
workAreaClassName?: string;
|
|
224
224
|
/** CSS class added to each generated mascot element. */
|
|
225
225
|
mascotClassName?: string;
|
|
@@ -326,8 +326,6 @@ declare class ShimejiEngine {
|
|
|
326
326
|
private readonly disposers;
|
|
327
327
|
private readonly intervals;
|
|
328
328
|
private readonly options;
|
|
329
|
-
private readonly originalContainerPosition;
|
|
330
|
-
private readonly adjustedContainerPosition;
|
|
331
329
|
private pointer;
|
|
332
330
|
private animationFrame;
|
|
333
331
|
private lastFrameTime;
|
|
@@ -464,7 +462,7 @@ interface PlatformRectangle extends Rectangle {
|
|
|
464
462
|
}
|
|
465
463
|
/** Resolves a platform option into DOM elements, excluding engine-owned nodes. */
|
|
466
464
|
declare function resolvePlatformElements(source: string | readonly HTMLElement[], document: Document, excludedRoot?: HTMLElement): HTMLElement[];
|
|
467
|
-
/** Reads platform bounds once and converts viewport coordinates to
|
|
465
|
+
/** Reads platform bounds once and converts viewport coordinates to the supplied origin. */
|
|
468
466
|
declare function readPlatformRectangles(elements: readonly HTMLElement[], workAreaRectangle: Pick<DOMRect, "left" | "top">): PlatformRectangle[];
|
|
469
467
|
|
|
470
468
|
/** A resolved image and optional atlas crop for one sprite frame. */
|
|
@@ -496,9 +494,9 @@ declare function isIndividualSprite(sprite: SpriteRectangle | IndividualSprite |
|
|
|
496
494
|
|
|
497
495
|
/** DOM nodes and resources owned by one mascot. */
|
|
498
496
|
interface MascotDomHandle {
|
|
499
|
-
/**
|
|
497
|
+
/** Fixed, pointer-transparent mascot wrapper. */
|
|
500
498
|
element: HTMLDivElement;
|
|
501
|
-
/**
|
|
499
|
+
/** Pointer-interactive child element on which sprite images are painted. */
|
|
502
500
|
spriteElement: HTMLDivElement;
|
|
503
501
|
/** Per-mascot spritesheet URL lease. */
|
|
504
502
|
spriteLease: SpriteLease;
|
package/dist/index.d.ts
CHANGED
|
@@ -219,7 +219,7 @@ interface ShimejiEngineOptions {
|
|
|
219
219
|
gravity?: number;
|
|
220
220
|
/** Maximum elapsed time applied to one animation update. Defaults to 100 ms. */
|
|
221
221
|
maxDeltaTime?: number;
|
|
222
|
-
/**
|
|
222
|
+
/** @deprecated There is no shared work area; retained for source compatibility. */
|
|
223
223
|
workAreaClassName?: string;
|
|
224
224
|
/** CSS class added to each generated mascot element. */
|
|
225
225
|
mascotClassName?: string;
|
|
@@ -326,8 +326,6 @@ declare class ShimejiEngine {
|
|
|
326
326
|
private readonly disposers;
|
|
327
327
|
private readonly intervals;
|
|
328
328
|
private readonly options;
|
|
329
|
-
private readonly originalContainerPosition;
|
|
330
|
-
private readonly adjustedContainerPosition;
|
|
331
329
|
private pointer;
|
|
332
330
|
private animationFrame;
|
|
333
331
|
private lastFrameTime;
|
|
@@ -464,7 +462,7 @@ interface PlatformRectangle extends Rectangle {
|
|
|
464
462
|
}
|
|
465
463
|
/** Resolves a platform option into DOM elements, excluding engine-owned nodes. */
|
|
466
464
|
declare function resolvePlatformElements(source: string | readonly HTMLElement[], document: Document, excludedRoot?: HTMLElement): HTMLElement[];
|
|
467
|
-
/** Reads platform bounds once and converts viewport coordinates to
|
|
465
|
+
/** Reads platform bounds once and converts viewport coordinates to the supplied origin. */
|
|
468
466
|
declare function readPlatformRectangles(elements: readonly HTMLElement[], workAreaRectangle: Pick<DOMRect, "left" | "top">): PlatformRectangle[];
|
|
469
467
|
|
|
470
468
|
/** A resolved image and optional atlas crop for one sprite frame. */
|
|
@@ -496,9 +494,9 @@ declare function isIndividualSprite(sprite: SpriteRectangle | IndividualSprite |
|
|
|
496
494
|
|
|
497
495
|
/** DOM nodes and resources owned by one mascot. */
|
|
498
496
|
interface MascotDomHandle {
|
|
499
|
-
/**
|
|
497
|
+
/** Fixed, pointer-transparent mascot wrapper. */
|
|
500
498
|
element: HTMLDivElement;
|
|
501
|
-
/**
|
|
499
|
+
/** Pointer-interactive child element on which sprite images are painted. */
|
|
502
500
|
spriteElement: HTMLDivElement;
|
|
503
501
|
/** Per-mascot spritesheet URL lease. */
|
|
504
502
|
spriteLease: SpriteLease;
|
package/dist/index.js
CHANGED
|
@@ -1,41 +1,23 @@
|
|
|
1
1
|
// src/dom.ts
|
|
2
2
|
var DomManager = class {
|
|
3
|
-
/**
|
|
4
|
-
constructor(container, sprites
|
|
3
|
+
/** Uses the supplied element only as a mount point for independent mascots. */
|
|
4
|
+
constructor(container, sprites) {
|
|
5
5
|
this.container = container;
|
|
6
6
|
this.sprites = sprites;
|
|
7
|
-
const workArea = document.createElement("div");
|
|
8
|
-
workArea.dataset.reactShimejiWorkArea = "true";
|
|
9
|
-
if (workAreaClassName) workArea.className = workAreaClassName;
|
|
10
|
-
Object.assign(workArea.style, {
|
|
11
|
-
position: "absolute",
|
|
12
|
-
inset: "0",
|
|
13
|
-
width: "100%",
|
|
14
|
-
height: "100%",
|
|
15
|
-
overflow: "hidden",
|
|
16
|
-
pointerEvents: "none",
|
|
17
|
-
zIndex: "2147483643"
|
|
18
|
-
});
|
|
19
|
-
this.workArea = workArea;
|
|
20
|
-
this.ensureMounted();
|
|
21
7
|
}
|
|
22
8
|
container;
|
|
23
9
|
sprites;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/** Reattaches the work area if application code temporarily removed it. */
|
|
10
|
+
handles = /* @__PURE__ */ new Set();
|
|
11
|
+
/** Reattaches mascot elements if application code temporarily removed them. */
|
|
27
12
|
ensureMounted() {
|
|
28
|
-
|
|
13
|
+
for (const handle of this.handles) {
|
|
14
|
+
if (handle.element.parentElement !== this.container) this.container.appendChild(handle.element);
|
|
15
|
+
}
|
|
29
16
|
}
|
|
30
|
-
/** Returns
|
|
17
|
+
/** Returns viewport bounds because fixed mascots use viewport coordinates. */
|
|
31
18
|
getBounds() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/** Converts a previously-read work-area client rectangle into local bounds. */
|
|
35
|
-
getBoundsFromClientRectangle(rectangle) {
|
|
36
|
-
const width = rectangle.width || this.container.clientWidth || window.innerWidth;
|
|
37
|
-
const height = rectangle.height || this.container.clientHeight || window.innerHeight;
|
|
38
|
-
return { x: 0, y: 0, width, height };
|
|
19
|
+
const view = this.container.ownerDocument.defaultView ?? window;
|
|
20
|
+
return { x: 0, y: 0, width: view.innerWidth, height: view.innerHeight };
|
|
39
21
|
}
|
|
40
22
|
/** Creates a mascot node and acquires its spritesheet resource. */
|
|
41
23
|
createMascot(spec, mascotId, mascotClassName) {
|
|
@@ -43,12 +25,14 @@ var DomManager = class {
|
|
|
43
25
|
const element = document.createElement("div");
|
|
44
26
|
element.dataset.shimejiId = mascotId;
|
|
45
27
|
if (mascotClassName) element.className = mascotClassName;
|
|
46
|
-
Object.assign(element.style, { position: "
|
|
28
|
+
Object.assign(element.style, { position: "fixed", left: "0", top: "0", width: "0", height: "0", pointerEvents: "none", zIndex: "9999", userSelect: "none", willChange: "transform" });
|
|
47
29
|
const spriteElement = document.createElement("div");
|
|
48
|
-
Object.assign(spriteElement.style, { position: "absolute", left: "0", top: "0", backgroundRepeat: "no-repeat", transformOrigin: "center center", pointerEvents: "none" });
|
|
30
|
+
Object.assign(spriteElement.style, { position: "absolute", left: "0", top: "0", backgroundRepeat: "no-repeat", transformOrigin: "center center", pointerEvents: "auto", touchAction: "none", userSelect: "none" });
|
|
49
31
|
element.appendChild(spriteElement);
|
|
50
|
-
|
|
51
|
-
|
|
32
|
+
const handle = { element, spriteElement, spriteLease };
|
|
33
|
+
this.handles.add(handle);
|
|
34
|
+
this.container.appendChild(element);
|
|
35
|
+
return handle;
|
|
52
36
|
}
|
|
53
37
|
/** Paints one mascot state into its existing DOM nodes. */
|
|
54
38
|
render(handle, spec, state) {
|
|
@@ -80,12 +64,18 @@ var DomManager = class {
|
|
|
80
64
|
}
|
|
81
65
|
/** Removes one mascot node and releases its temporary image URL. */
|
|
82
66
|
removeMascot(handle) {
|
|
67
|
+
if (!this.handles.delete(handle)) return;
|
|
83
68
|
handle.element.remove();
|
|
84
69
|
handle.spriteLease.release();
|
|
85
70
|
}
|
|
86
|
-
/**
|
|
71
|
+
/** Returns whether an element belongs to one of this manager's mascots. */
|
|
72
|
+
owns(element) {
|
|
73
|
+
for (const handle of this.handles) if (handle.element === element || handle.element.contains(element)) return true;
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
/** Removes every mascot element and releases its temporary image URL. */
|
|
87
77
|
destroy() {
|
|
88
|
-
this.
|
|
78
|
+
for (const handle of [...this.handles]) this.removeMascot(handle);
|
|
89
79
|
}
|
|
90
80
|
};
|
|
91
81
|
|
|
@@ -939,6 +929,7 @@ function environmentRectangle(bounds) {
|
|
|
939
929
|
};
|
|
940
930
|
}
|
|
941
931
|
var PLATFORM_NEARBY_DISTANCE = 400;
|
|
932
|
+
var PLATFORM_EDGE_TOLERANCE = 16;
|
|
942
933
|
function distanceToRectangle(point, rectangle) {
|
|
943
934
|
const dx = Math.max(rectangle.x - point.x, 0, point.x - rectangle.x - rectangle.width);
|
|
944
935
|
const dy = Math.max(rectangle.y - point.y, 0, point.y - rectangle.y - rectangle.height);
|
|
@@ -1012,9 +1003,11 @@ var Mascot = class {
|
|
|
1012
1003
|
}
|
|
1013
1004
|
if (!started) break;
|
|
1014
1005
|
}
|
|
1015
|
-
const
|
|
1006
|
+
const activeIE = environment.mascot.environment.activeIE;
|
|
1007
|
+
const wasOnPlatformTop = activeIE.visible && activeIE.topBorder.isOn(this.state);
|
|
1016
1008
|
const completed = this.actions.tick(deltaMs, environment, bounds);
|
|
1017
|
-
|
|
1009
|
+
const remainedNearPlatform = this.state.x >= activeIE.left - PLATFORM_EDGE_TOLERANCE && this.state.x <= activeIE.right + PLATFORM_EDGE_TOLERANCE;
|
|
1010
|
+
if (wasOnPlatformTop && !remainedNearPlatform && !platforms.some((platform) => isOnTop(this.state, platform))) {
|
|
1018
1011
|
this.actions.cancel();
|
|
1019
1012
|
this.currentBehavior = this.findFallBehavior();
|
|
1020
1013
|
if (this.currentBehavior) this.startBehavior(this.createEnvironment(bounds, platforms));
|
|
@@ -1099,7 +1092,7 @@ var Mascot = class {
|
|
|
1099
1092
|
return nearby;
|
|
1100
1093
|
}
|
|
1101
1094
|
installPointerHandlers() {
|
|
1102
|
-
const element = this.domHandle.
|
|
1095
|
+
const element = this.domHandle.spriteElement;
|
|
1103
1096
|
const listen = (target, type, listener) => {
|
|
1104
1097
|
target.addEventListener(type, listener);
|
|
1105
1098
|
this.disposers.push(() => target.removeEventListener(type, listener));
|
|
@@ -1108,8 +1101,7 @@ var Mascot = class {
|
|
|
1108
1101
|
const pointerEvent = event;
|
|
1109
1102
|
if (pointerEvent.button !== 0) return;
|
|
1110
1103
|
event.preventDefault();
|
|
1111
|
-
const
|
|
1112
|
-
const point = { x: pointerEvent.clientX - bounds.left, y: pointerEvent.clientY - bounds.top };
|
|
1104
|
+
const point = { x: pointerEvent.clientX, y: pointerEvent.clientY };
|
|
1113
1105
|
this.pointerId = pointerEvent.pointerId;
|
|
1114
1106
|
this.pointerDown = point;
|
|
1115
1107
|
this.lastPointer = point;
|
|
@@ -1123,8 +1115,7 @@ var Mascot = class {
|
|
|
1123
1115
|
listen(document, "pointermove", (event) => {
|
|
1124
1116
|
const pointerEvent = event;
|
|
1125
1117
|
if (!this.state.dragging || pointerEvent.pointerId !== this.pointerId) return;
|
|
1126
|
-
const
|
|
1127
|
-
const point = { x: pointerEvent.clientX - bounds.left, y: pointerEvent.clientY - bounds.top };
|
|
1118
|
+
const point = { x: pointerEvent.clientX, y: pointerEvent.clientY };
|
|
1128
1119
|
const previous = this.lastPointer ?? point;
|
|
1129
1120
|
this.state.vx = (point.x - previous.x) * 0.8;
|
|
1130
1121
|
this.state.vy = (point.y - previous.y) * 0.8;
|
|
@@ -1272,10 +1263,7 @@ var ShimejiEngine = class {
|
|
|
1272
1263
|
if (!container) throw new TypeError("ShimejiEngine requires a container element");
|
|
1273
1264
|
this.options = { ...defaults, ...options, random: options.random };
|
|
1274
1265
|
this.platformSource = this.options.platforms;
|
|
1275
|
-
this.
|
|
1276
|
-
this.adjustedContainerPosition = getComputedStyle(container).position === "static";
|
|
1277
|
-
if (this.adjustedContainerPosition) container.style.position = "relative";
|
|
1278
|
-
this.dom = new DomManager(container, this.sprites, this.options.workAreaClassName || void 0);
|
|
1266
|
+
this.dom = new DomManager(container, this.sprites);
|
|
1279
1267
|
this.initialize();
|
|
1280
1268
|
}
|
|
1281
1269
|
container;
|
|
@@ -1287,8 +1275,6 @@ var ShimejiEngine = class {
|
|
|
1287
1275
|
disposers = [];
|
|
1288
1276
|
intervals = /* @__PURE__ */ new Set();
|
|
1289
1277
|
options;
|
|
1290
|
-
originalContainerPosition;
|
|
1291
|
-
adjustedContainerPosition;
|
|
1292
1278
|
pointer = { x: 0, y: 0, dx: 0, dy: 0 };
|
|
1293
1279
|
animationFrame;
|
|
1294
1280
|
lastFrameTime;
|
|
@@ -1303,9 +1289,8 @@ var ShimejiEngine = class {
|
|
|
1303
1289
|
this.initialized = true;
|
|
1304
1290
|
this.listen(document, "pointermove", (event) => {
|
|
1305
1291
|
const pointerEvent = event;
|
|
1306
|
-
const
|
|
1307
|
-
const
|
|
1308
|
-
const y = pointerEvent.clientY - rectangle.top;
|
|
1292
|
+
const x = pointerEvent.clientX;
|
|
1293
|
+
const y = pointerEvent.clientY;
|
|
1309
1294
|
this.pointer = { x, y, dx: x - this.pointer.x, dy: y - this.pointer.y };
|
|
1310
1295
|
});
|
|
1311
1296
|
this.listen(window, "resize", () => this.renderAll());
|
|
@@ -1409,7 +1394,6 @@ var ShimejiEngine = class {
|
|
|
1409
1394
|
this.sprites.destroy();
|
|
1410
1395
|
this.specs.clear();
|
|
1411
1396
|
this.events.clear();
|
|
1412
|
-
if (this.adjustedContainerPosition && this.container.style.position === "relative") this.container.style.position = this.originalContainerPosition;
|
|
1413
1397
|
this.destroyed = true;
|
|
1414
1398
|
this.initialized = false;
|
|
1415
1399
|
}
|
|
@@ -1432,10 +1416,9 @@ var ShimejiEngine = class {
|
|
|
1432
1416
|
for (const mascot of this.mascots.values()) mascot.tick(0, bounds, platforms);
|
|
1433
1417
|
}
|
|
1434
1418
|
readFrameGeometry() {
|
|
1435
|
-
const
|
|
1436
|
-
const
|
|
1437
|
-
|
|
1438
|
-
return { bounds, platforms: readPlatformRectangles(elements, workAreaRectangle) };
|
|
1419
|
+
const bounds = this.dom.getBounds();
|
|
1420
|
+
const elements = resolvePlatformElements(this.platformSource, this.container.ownerDocument).filter((element) => !this.dom.owns(element));
|
|
1421
|
+
return { bounds, platforms: readPlatformRectangles(elements, { left: 0, top: 0 }) };
|
|
1439
1422
|
}
|
|
1440
1423
|
emitState() {
|
|
1441
1424
|
this.events.emit("statechange", this.getState());
|