saccade 0.0.2 → 0.0.3
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 +6 -6
- package/dist/core.cjs +72 -57
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +4 -4
- package/dist/core.d.ts +4 -4
- package/dist/core.mjs +71 -56
- package/dist/core.mjs.map +1 -1
- package/dist/index.cjs +103 -84
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -11
- package/dist/index.d.ts +11 -11
- package/dist/index.mjs +99 -80
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -21,20 +21,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
// src/index.ts
|
|
22
22
|
var src_exports = {};
|
|
23
23
|
__export(src_exports, {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
Saccade: () => Saccade,
|
|
25
|
+
SaccadeEngine: () => SaccadeEngine,
|
|
26
|
+
SaccadeProvider: () => SaccadeProvider,
|
|
27
|
+
useSaccadeEngine: () => useSaccadeEngine,
|
|
28
28
|
useSpeed: () => useSpeed,
|
|
29
29
|
useTimeline: () => useTimeline
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(src_exports);
|
|
32
32
|
|
|
33
|
-
// src/react/
|
|
33
|
+
// src/react/Saccade.tsx
|
|
34
34
|
var import_react7 = require("react");
|
|
35
35
|
var import_react_dom = require("react-dom");
|
|
36
36
|
|
|
37
|
-
// src/react/
|
|
37
|
+
// src/react/SaccadeContext.tsx
|
|
38
38
|
var import_react = require("react");
|
|
39
39
|
|
|
40
40
|
// src/core/timing.ts
|
|
@@ -1060,64 +1060,61 @@ var _TimelineRecorder = class _TimelineRecorder {
|
|
|
1060
1060
|
blocker.title = "Clear the timeline to interact with the page";
|
|
1061
1061
|
document.body.appendChild(blocker);
|
|
1062
1062
|
this.blockerEl = blocker;
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
if (t && (t.includes(":hover") || t.includes(":focus"))) {
|
|
1081
|
-
allCss += t + "\n";
|
|
1063
|
+
setTimeout(() => {
|
|
1064
|
+
try {
|
|
1065
|
+
const lapseStyle = document.createElement("style");
|
|
1066
|
+
lapseStyle.id = "__lapse-state-rules";
|
|
1067
|
+
const hoverFocusRules = [];
|
|
1068
|
+
for (const sheet of document.styleSheets) {
|
|
1069
|
+
try {
|
|
1070
|
+
const walk = (rules) => {
|
|
1071
|
+
for (const rule of rules) {
|
|
1072
|
+
if (rule.cssRules) {
|
|
1073
|
+
walk(rule.cssRules);
|
|
1074
|
+
continue;
|
|
1075
|
+
}
|
|
1076
|
+
const t = rule.cssText;
|
|
1077
|
+
if (t && (t.includes(":hover") || t.includes(":focus"))) {
|
|
1078
|
+
hoverFocusRules.push(t);
|
|
1079
|
+
}
|
|
1082
1080
|
}
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
walk2(sheet.cssRules);
|
|
1087
|
-
} catch (_) {
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
const stateRegex = /([^{}]*(?::hover|:focus-visible|:focus-within|:focus(?!-))[^{}]*)\{([^{}]*)\}/g;
|
|
1091
|
-
let match;
|
|
1092
|
-
while ((match = stateRegex.exec(allCss)) !== null) {
|
|
1093
|
-
const selector = match[1].trim();
|
|
1094
|
-
const body = match[2].trim();
|
|
1095
|
-
if (!body) continue;
|
|
1096
|
-
const newBody = body.replace(
|
|
1097
|
-
/([^;:]+):\s*([^;]+)(;|$)/g,
|
|
1098
|
-
(m, prop, val, end) => {
|
|
1099
|
-
if (val.includes("!important")) return m;
|
|
1100
|
-
return prop + ": " + val.trim() + " !important" + end;
|
|
1081
|
+
};
|
|
1082
|
+
walk(sheet.cssRules);
|
|
1083
|
+
} catch (_) {
|
|
1101
1084
|
}
|
|
1102
|
-
);
|
|
1103
|
-
if (selector.includes(":hover")) {
|
|
1104
|
-
lapseStyle.textContent += selector.replace(/:hover/g, "[data-lapse-hover]") + " { " + newBody + " }\n";
|
|
1105
1085
|
}
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1086
|
+
const parts = [];
|
|
1087
|
+
for (const ruleText of hoverFocusRules) {
|
|
1088
|
+
const braceIdx = ruleText.indexOf("{");
|
|
1089
|
+
if (braceIdx === -1) continue;
|
|
1090
|
+
const selector = ruleText.slice(0, braceIdx).trim();
|
|
1091
|
+
const bodyEnd = ruleText.lastIndexOf("}");
|
|
1092
|
+
const body = ruleText.slice(braceIdx + 1, bodyEnd).trim();
|
|
1093
|
+
if (!body) continue;
|
|
1094
|
+
const newBody = body.replace(
|
|
1095
|
+
/([^;:]+):\s*([^;]+)(;|$)/g,
|
|
1096
|
+
(m, prop, val, end) => {
|
|
1097
|
+
if (val.includes("!important")) return m;
|
|
1098
|
+
return prop + ": " + val.trim() + " !important" + end;
|
|
1099
|
+
}
|
|
1100
|
+
);
|
|
1101
|
+
if (selector.includes(":hover")) {
|
|
1102
|
+
parts.push(selector.replace(/:hover/g, "[data-lapse-hover]") + " { " + newBody + " }");
|
|
1103
|
+
}
|
|
1104
|
+
if (selector.includes(":focus-visible")) {
|
|
1105
|
+
parts.push(selector.replace(/:focus-visible/g, "[data-lapse-focus]") + " { " + newBody + " }");
|
|
1106
|
+
} else if (selector.includes(":focus-within")) {
|
|
1107
|
+
parts.push(selector.replace(/:focus-within/g, ":has([data-lapse-focus])") + " { " + newBody + " }");
|
|
1108
|
+
} else if (selector.includes(":focus")) {
|
|
1109
|
+
parts.push(selector.replace(/:focus(?!-)/g, "[data-lapse-focus]") + " { " + newBody + " }");
|
|
1110
|
+
}
|
|
1115
1111
|
}
|
|
1112
|
+
lapseStyle.textContent = parts.join("\n");
|
|
1113
|
+
document.head.appendChild(lapseStyle);
|
|
1114
|
+
this.lapseStyleEl = lapseStyle;
|
|
1115
|
+
} catch (_) {
|
|
1116
1116
|
}
|
|
1117
|
-
|
|
1118
|
-
this.lapseStyleEl = lapseStyle;
|
|
1119
|
-
} catch (_) {
|
|
1120
|
-
}
|
|
1117
|
+
}, 0);
|
|
1121
1118
|
if (this.frames.length > 0) {
|
|
1122
1119
|
const frame0 = this.frames[0];
|
|
1123
1120
|
if (frame0.elementSnapshots) {
|
|
@@ -1630,7 +1627,7 @@ function formatExportForLLM(exp, detail = "standard") {
|
|
|
1630
1627
|
}
|
|
1631
1628
|
|
|
1632
1629
|
// src/core/engine.ts
|
|
1633
|
-
var
|
|
1630
|
+
var SaccadeEngine = class {
|
|
1634
1631
|
constructor() {
|
|
1635
1632
|
this.timing = new TimingController();
|
|
1636
1633
|
this.recorder = new TimelineRecorder();
|
|
@@ -1672,7 +1669,25 @@ var LapseEngine = class {
|
|
|
1672
1669
|
boundingBox: null
|
|
1673
1670
|
};
|
|
1674
1671
|
}
|
|
1675
|
-
|
|
1672
|
+
let capture;
|
|
1673
|
+
try {
|
|
1674
|
+
capture = this.recorder.stopRecording();
|
|
1675
|
+
} catch (e) {
|
|
1676
|
+
console.error("[Saccade] stopRecording failed:", e);
|
|
1677
|
+
document.getElementById("__lapse-scrub-blocker")?.remove();
|
|
1678
|
+
document.getElementById("__lapse-no-transitions")?.remove();
|
|
1679
|
+
document.getElementById("__lapse-state-rules")?.remove();
|
|
1680
|
+
this._state = "idle";
|
|
1681
|
+
this.notify();
|
|
1682
|
+
return {
|
|
1683
|
+
startTime: 0,
|
|
1684
|
+
endTime: 0,
|
|
1685
|
+
duration: 0,
|
|
1686
|
+
animations: [],
|
|
1687
|
+
frames: [],
|
|
1688
|
+
boundingBox: null
|
|
1689
|
+
};
|
|
1690
|
+
}
|
|
1676
1691
|
this.capture = capture;
|
|
1677
1692
|
const scrubberState = {
|
|
1678
1693
|
elements: this.recorder.elements,
|
|
@@ -1732,23 +1747,23 @@ var LapseEngine = class {
|
|
|
1732
1747
|
}
|
|
1733
1748
|
};
|
|
1734
1749
|
|
|
1735
|
-
// src/react/
|
|
1750
|
+
// src/react/SaccadeContext.tsx
|
|
1736
1751
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1737
|
-
var
|
|
1738
|
-
function
|
|
1752
|
+
var SaccadeContext = (0, import_react.createContext)(null);
|
|
1753
|
+
function SaccadeProvider({ children }) {
|
|
1739
1754
|
const engineRef = (0, import_react.useRef)(null);
|
|
1740
1755
|
if (!engineRef.current) {
|
|
1741
|
-
engineRef.current = new
|
|
1756
|
+
engineRef.current = new SaccadeEngine();
|
|
1742
1757
|
}
|
|
1743
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1758
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SaccadeContext.Provider, { value: engineRef.current, children });
|
|
1744
1759
|
}
|
|
1745
|
-
function
|
|
1746
|
-
const engine = (0, import_react.useContext)(
|
|
1747
|
-
if (!engine) throw new Error("
|
|
1760
|
+
function useSaccadeEngine() {
|
|
1761
|
+
const engine = (0, import_react.useContext)(SaccadeContext);
|
|
1762
|
+
if (!engine) throw new Error("useSaccadeEngine must be used within <SaccadeProvider>");
|
|
1748
1763
|
return engine;
|
|
1749
1764
|
}
|
|
1750
1765
|
|
|
1751
|
-
// src/react/
|
|
1766
|
+
// src/react/SaccadePanel.tsx
|
|
1752
1767
|
var import_react6 = require("react");
|
|
1753
1768
|
|
|
1754
1769
|
// src/react/Timeline.tsx
|
|
@@ -2142,7 +2157,7 @@ function SpeedControl({ speed, isPaused, onSetSpeed, onTogglePause }) {
|
|
|
2142
2157
|
var import_react4 = require("react");
|
|
2143
2158
|
var DETAIL_LEVELS = ["compact", "standard", "detailed", "forensic"];
|
|
2144
2159
|
function useTimeline() {
|
|
2145
|
-
const engine =
|
|
2160
|
+
const engine = useSaccadeEngine();
|
|
2146
2161
|
const state = (0, import_react4.useSyncExternalStore)(
|
|
2147
2162
|
(cb) => engine.subscribe(cb),
|
|
2148
2163
|
() => engine.state
|
|
@@ -2176,9 +2191,13 @@ function useTimeline() {
|
|
|
2176
2191
|
[engine]
|
|
2177
2192
|
);
|
|
2178
2193
|
const stopRecording = (0, import_react4.useCallback)(() => {
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2194
|
+
try {
|
|
2195
|
+
const result = engine.stopRecording();
|
|
2196
|
+
setCapture(result);
|
|
2197
|
+
setScrubTime(0);
|
|
2198
|
+
} catch (e) {
|
|
2199
|
+
console.error("[Saccade] stopRecording failed:", e);
|
|
2200
|
+
}
|
|
2182
2201
|
}, [engine]);
|
|
2183
2202
|
const seek = (0, import_react4.useCallback)(
|
|
2184
2203
|
(timeMs) => {
|
|
@@ -2247,7 +2266,7 @@ function useTimeline() {
|
|
|
2247
2266
|
// src/react/useSpeed.ts
|
|
2248
2267
|
var import_react5 = require("react");
|
|
2249
2268
|
function useSpeed() {
|
|
2250
|
-
const engine =
|
|
2269
|
+
const engine = useSaccadeEngine();
|
|
2251
2270
|
const [speed, setSpeedState] = (0, import_react5.useState)(1);
|
|
2252
2271
|
const [previousSpeed, setPreviousSpeed] = (0, import_react5.useState)(1);
|
|
2253
2272
|
const [isPaused, setIsPaused] = (0, import_react5.useState)(false);
|
|
@@ -2310,9 +2329,9 @@ function useSpeed() {
|
|
|
2310
2329
|
return { speed, isPaused, setSpeed, togglePause };
|
|
2311
2330
|
}
|
|
2312
2331
|
|
|
2313
|
-
// src/react/
|
|
2332
|
+
// src/react/SaccadePanel.tsx
|
|
2314
2333
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2315
|
-
function
|
|
2334
|
+
function SaccadePanel() {
|
|
2316
2335
|
const timeline = useTimeline();
|
|
2317
2336
|
const { speed, isPaused, setSpeed, togglePause } = useSpeed();
|
|
2318
2337
|
const panelRef = (0, import_react6.useRef)(null);
|
|
@@ -2772,9 +2791,9 @@ var PANEL_STYLES = (
|
|
|
2772
2791
|
`
|
|
2773
2792
|
);
|
|
2774
2793
|
|
|
2775
|
-
// src/react/
|
|
2794
|
+
// src/react/Saccade.tsx
|
|
2776
2795
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2777
|
-
function
|
|
2796
|
+
function Saccade({ position = "bottom-left" }) {
|
|
2778
2797
|
const hostRef = (0, import_react7.useRef)(null);
|
|
2779
2798
|
const [shadowRoot, setShadowRoot] = (0, import_react7.useState)(null);
|
|
2780
2799
|
(0, import_react7.useEffect)(() => {
|
|
@@ -2805,7 +2824,7 @@ function Lapse({ position = "bottom-left" }) {
|
|
|
2805
2824
|
...positionOffset
|
|
2806
2825
|
},
|
|
2807
2826
|
children: shadowRoot && (0, import_react_dom.createPortal)(
|
|
2808
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2827
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SaccadeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SaccadePanel, {}) }),
|
|
2809
2828
|
shadowRoot.lastElementChild || shadowRoot
|
|
2810
2829
|
)
|
|
2811
2830
|
}
|
|
@@ -2813,10 +2832,10 @@ function Lapse({ position = "bottom-left" }) {
|
|
|
2813
2832
|
}
|
|
2814
2833
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2815
2834
|
0 && (module.exports = {
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2835
|
+
Saccade,
|
|
2836
|
+
SaccadeEngine,
|
|
2837
|
+
SaccadeProvider,
|
|
2838
|
+
useSaccadeEngine,
|
|
2820
2839
|
useSpeed,
|
|
2821
2840
|
useTimeline
|
|
2822
2841
|
});
|