lynx-console 0.5.0 → 0.6.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/README.md +1 -0
- package/dist/index.cjs +87 -40
- package/dist/index.d.cts +6 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +6 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +87 -40
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/FloatingButton.tsx +15 -7
- package/src/components/LogPanel.tsx +2 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useLatestFcp.ts +48 -0
- package/src/hooks/useLongPressDrag.ts +97 -21
- package/src/index.tsx +18 -32
package/README.md
CHANGED
|
@@ -182,6 +182,7 @@ You can also integrate it with a back press handler so that the console closes w
|
|
|
182
182
|
| `theme` | `"light" \| "dark"` | `"light"` | Console UI theme |
|
|
183
183
|
| `safeAreaInsetBottom` | `string` | `"50px"` | Bottom safe area inset |
|
|
184
184
|
| `customTabs` | `CustomTab[]` | `undefined` | Additional custom tabs to display in the console |
|
|
185
|
+
| `initialPosition` | `{ top?: number; left?: number; right?: number; bottom?: number }` | `{ right: 16, bottom: 84 }` | Initial position (px) of the floating button. Each side is independent, so you can anchor it to any corner (e.g. `{ top: 50, left: 16 }`). When both `top` and `bottom` (or both `left` and `right`) are set, `top`/`left` win. Once the user drags the button, the saved position takes precedence. |
|
|
185
186
|
|
|
186
187
|
### `CustomTab`
|
|
187
188
|
|
package/dist/index.cjs
CHANGED
|
@@ -222,6 +222,35 @@ const useConsole = () => {
|
|
|
222
222
|
};
|
|
223
223
|
};
|
|
224
224
|
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/hooks/useLatestFcp.ts
|
|
227
|
+
const pickFcp = (entry) => {
|
|
228
|
+
if (entry.entryType !== "metric" || entry.name !== "fcp") return void 0;
|
|
229
|
+
const raw = entry.rawEntry;
|
|
230
|
+
if (raw?.totalFcp?.duration !== void 0) return raw.totalFcp;
|
|
231
|
+
if (raw?.lynxFcp?.duration !== void 0) return raw.lynxFcp;
|
|
232
|
+
};
|
|
233
|
+
const useLatestFcp = () => {
|
|
234
|
+
const [fcp, setFcp] = (0, _lynx_js_react.useState)(() => {
|
|
235
|
+
const performances = globalThis.__LYNX_CONSOLE__?.state?.performances ?? [];
|
|
236
|
+
for (let i = performances.length - 1; i >= 0; i--) {
|
|
237
|
+
const entry = performances[i];
|
|
238
|
+
if (!entry) continue;
|
|
239
|
+
const found = pickFcp(entry);
|
|
240
|
+
if (found) return found;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
(0, _lynx_js_react.useEffect)(() => {
|
|
244
|
+
const state = globalThis.__LYNX_CONSOLE__?.state;
|
|
245
|
+
if (!state?.subscribePerformance) return;
|
|
246
|
+
return state.subscribePerformance((entry) => {
|
|
247
|
+
const found = pickFcp(entry);
|
|
248
|
+
if (found) setFcp(found);
|
|
249
|
+
});
|
|
250
|
+
}, []);
|
|
251
|
+
return fcp;
|
|
252
|
+
};
|
|
253
|
+
|
|
225
254
|
//#endregion
|
|
226
255
|
//#region src/hooks/useNetwork.ts
|
|
227
256
|
const useNetwork = () => {
|
|
@@ -484,7 +513,8 @@ const LogPanel = ({ logs, clearLogs }) => {
|
|
|
484
513
|
params: {
|
|
485
514
|
position: logsRef.current.length - 1,
|
|
486
515
|
smooth
|
|
487
|
-
}
|
|
516
|
+
},
|
|
517
|
+
fail: () => {}
|
|
488
518
|
}).exec();
|
|
489
519
|
};
|
|
490
520
|
(0, _lynx_js_react.useEffect)(() => {
|
|
@@ -1368,22 +1398,42 @@ const LONG_PRESS_DURATION = 400;
|
|
|
1368
1398
|
const MOVE_THRESHOLD = 5;
|
|
1369
1399
|
const DEFAULT_RIGHT = 16;
|
|
1370
1400
|
const DEFAULT_BOTTOM = 84;
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
const
|
|
1375
|
-
|
|
1401
|
+
function resolveAnchors(initial) {
|
|
1402
|
+
const vertical = initial?.top !== void 0 ? "top" : "bottom";
|
|
1403
|
+
const horizontal = initial?.left !== void 0 ? "left" : "right";
|
|
1404
|
+
const y = vertical === "top" ? initial?.top ?? 0 : initial?.bottom ?? DEFAULT_BOTTOM;
|
|
1405
|
+
return {
|
|
1406
|
+
vertical,
|
|
1407
|
+
horizontal,
|
|
1408
|
+
x: horizontal === "left" ? initial?.left ?? 0 : initial?.right ?? DEFAULT_RIGHT,
|
|
1409
|
+
y
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
let saved = null;
|
|
1413
|
+
function useLongPressDrag(onTap, options) {
|
|
1414
|
+
const anchors = resolveAnchors(options?.initialPosition);
|
|
1415
|
+
const snapshot = saved;
|
|
1416
|
+
let initX = anchors.x;
|
|
1417
|
+
let initY = anchors.y;
|
|
1418
|
+
if (snapshot !== null && snapshot.vertical === anchors.vertical && snapshot.horizontal === anchors.horizontal) {
|
|
1419
|
+
initX = snapshot.x;
|
|
1420
|
+
initY = snapshot.y;
|
|
1421
|
+
}
|
|
1422
|
+
const [x, setX] = (0, _lynx_js_react.useState)(initX);
|
|
1423
|
+
const [y, setY] = (0, _lynx_js_react.useState)(initY);
|
|
1376
1424
|
const [phase, setPhase] = (0, _lynx_js_react.useState)("idle");
|
|
1377
|
-
const [
|
|
1378
|
-
const [
|
|
1425
|
+
const [tempX, setTempX] = (0, _lynx_js_react.useState)(initX);
|
|
1426
|
+
const [tempY, setTempY] = (0, _lynx_js_react.useState)(initY);
|
|
1379
1427
|
const timerRef = (0, _lynx_js_react.useRef)(null);
|
|
1380
1428
|
const draggingRef = (0, _lynx_js_react.useRef)(false);
|
|
1381
1429
|
const startRef = (0, _lynx_js_react.useRef)({
|
|
1382
1430
|
x: 0,
|
|
1383
1431
|
y: 0,
|
|
1384
|
-
|
|
1385
|
-
|
|
1432
|
+
ax: 0,
|
|
1433
|
+
ay: 0
|
|
1386
1434
|
});
|
|
1435
|
+
const xSign = anchors.horizontal === "right" ? -1 : 1;
|
|
1436
|
+
const ySign = anchors.vertical === "bottom" ? -1 : 1;
|
|
1387
1437
|
const clearTimer = () => {
|
|
1388
1438
|
if (timerRef.current) {
|
|
1389
1439
|
clearTimeout(timerRef.current);
|
|
@@ -1394,15 +1444,15 @@ function useLongPressDrag(onTap) {
|
|
|
1394
1444
|
startRef.current = {
|
|
1395
1445
|
x: e.detail.x,
|
|
1396
1446
|
y: e.detail.y,
|
|
1397
|
-
|
|
1398
|
-
|
|
1447
|
+
ax: x,
|
|
1448
|
+
ay: y
|
|
1399
1449
|
};
|
|
1400
1450
|
draggingRef.current = false;
|
|
1401
1451
|
timerRef.current = setTimeout(() => {
|
|
1402
1452
|
draggingRef.current = true;
|
|
1403
1453
|
setPhase("dragging");
|
|
1404
|
-
|
|
1405
|
-
|
|
1454
|
+
setTempX(x);
|
|
1455
|
+
setTempY(y);
|
|
1406
1456
|
}, LONG_PRESS_DURATION);
|
|
1407
1457
|
};
|
|
1408
1458
|
const handleTouchMove = (e) => {
|
|
@@ -1410,26 +1460,34 @@ function useLongPressDrag(onTap) {
|
|
|
1410
1460
|
const dy = e.detail.y - startRef.current.y;
|
|
1411
1461
|
if (!draggingRef.current && (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)) clearTimer();
|
|
1412
1462
|
if (!draggingRef.current) return;
|
|
1413
|
-
|
|
1414
|
-
|
|
1463
|
+
setTempX(startRef.current.ax + xSign * dx);
|
|
1464
|
+
setTempY(startRef.current.ay + ySign * dy);
|
|
1415
1465
|
};
|
|
1416
1466
|
const handleTouchEnd = () => {
|
|
1417
1467
|
clearTimer();
|
|
1418
1468
|
if (draggingRef.current) {
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1469
|
+
setX(tempX);
|
|
1470
|
+
setY(tempY);
|
|
1471
|
+
saved = {
|
|
1472
|
+
vertical: anchors.vertical,
|
|
1473
|
+
horizontal: anchors.horizontal,
|
|
1474
|
+
x: tempX,
|
|
1475
|
+
y: tempY
|
|
1476
|
+
};
|
|
1423
1477
|
setPhase("releasing");
|
|
1424
1478
|
draggingRef.current = false;
|
|
1425
1479
|
setTimeout(() => setPhase("idle"), 300);
|
|
1426
1480
|
} else onTap();
|
|
1427
1481
|
};
|
|
1428
1482
|
const isDragging = phase === "dragging";
|
|
1483
|
+
const currentX = isDragging ? tempX : x;
|
|
1484
|
+
const currentY = isDragging ? tempY : y;
|
|
1429
1485
|
return {
|
|
1430
1486
|
phase,
|
|
1431
|
-
|
|
1432
|
-
|
|
1487
|
+
positionStyle: {
|
|
1488
|
+
[anchors.horizontal]: `${currentX}px`,
|
|
1489
|
+
[anchors.vertical]: `${currentY}px`
|
|
1490
|
+
},
|
|
1433
1491
|
clearTimer,
|
|
1434
1492
|
handlers: {
|
|
1435
1493
|
catchtouchstart: handleTouchStart,
|
|
@@ -1457,9 +1515,9 @@ const SHINE_STYLES = {
|
|
|
1457
1515
|
transition: "opacity 300ms cubic-bezier(0.4, 0, 0.2, 1)"
|
|
1458
1516
|
}
|
|
1459
1517
|
};
|
|
1460
|
-
const FloatingButton = ({ bindtap, children }) => {
|
|
1518
|
+
const FloatingButton = ({ bindtap, children, initialPosition }) => {
|
|
1461
1519
|
const colors = useThemeColors();
|
|
1462
|
-
const { phase,
|
|
1520
|
+
const { phase, positionStyle, clearTimer, handlers } = useLongPressDrag(bindtap, { initialPosition });
|
|
1463
1521
|
const handleReload = () => {
|
|
1464
1522
|
try {
|
|
1465
1523
|
lynx.reload({}, () => {
|
|
@@ -1470,9 +1528,8 @@ const FloatingButton = ({ bindtap, children }) => {
|
|
|
1470
1528
|
}
|
|
1471
1529
|
};
|
|
1472
1530
|
const isDragging = phase === "dragging";
|
|
1473
|
-
return <view className={"fb-wrapper"}
|
|
1474
|
-
|
|
1475
|
-
bottom: `${bottom}px`,
|
|
1531
|
+
return <view className={"fb-wrapper"} style={{
|
|
1532
|
+
...positionStyle,
|
|
1476
1533
|
transform: isDragging ? "scale(1.05)" : "scale(1)",
|
|
1477
1534
|
transition: `transform ${duration.d4} cubic-bezier(0.4, 0, 0.2, 1)`
|
|
1478
1535
|
}} {...handlers}>
|
|
@@ -1490,21 +1547,11 @@ const FloatingButton = ({ bindtap, children }) => {
|
|
|
1490
1547
|
|
|
1491
1548
|
//#endregion
|
|
1492
1549
|
//#region src/index.tsx
|
|
1493
|
-
const LynxConsole = (0, _lynx_js_react.forwardRef)(({ theme = "light", safeAreaInsetBottom = "50px", customTabs }, ref) => {
|
|
1550
|
+
const LynxConsole = (0, _lynx_js_react.forwardRef)(({ theme = "light", safeAreaInsetBottom = "50px", customTabs, initialPosition }, ref) => {
|
|
1494
1551
|
const [isOpen, setIsOpen] = (0, _lynx_js_react.useState)(false);
|
|
1495
1552
|
const [shouldClose, setShouldClose] = (0, _lynx_js_react.useState)(false);
|
|
1496
|
-
const
|
|
1553
|
+
const latestFcp = useLatestFcp();
|
|
1497
1554
|
const colors = (0, _lynx_js_react.useMemo)(() => getColors(theme), [theme]);
|
|
1498
|
-
const latestFcp = (0, _lynx_js_react.useMemo)(() => {
|
|
1499
|
-
for (let i = performances.length - 1; i >= 0; i--) {
|
|
1500
|
-
const perf = performances[i];
|
|
1501
|
-
if (perf && perf.entryType === "metric" && perf.name === "fcp") {
|
|
1502
|
-
const metricEntry = perf.rawEntry;
|
|
1503
|
-
if (metricEntry?.totalFcp?.duration !== void 0) return metricEntry.totalFcp;
|
|
1504
|
-
if (metricEntry?.lynxFcp?.duration !== void 0) return metricEntry.lynxFcp;
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
}, [performances]);
|
|
1508
1555
|
(0, _lynx_js_react.useImperativeHandle)(ref, () => ({
|
|
1509
1556
|
open: () => {
|
|
1510
1557
|
setIsOpen(true);
|
|
@@ -1528,7 +1575,7 @@ const LynxConsole = (0, _lynx_js_react.forwardRef)(({ theme = "light", safeAreaI
|
|
|
1528
1575
|
backgroundColor: colors.bg.layerDefault,
|
|
1529
1576
|
color: colors.fg.neutral
|
|
1530
1577
|
}}>
|
|
1531
|
-
<FloatingButton bindtap={handleOpenBottomSheet}>
|
|
1578
|
+
<FloatingButton bindtap={handleOpenBottomSheet} initialPosition={initialPosition}>
|
|
1532
1579
|
<text className="fb-title t4" style={{
|
|
1533
1580
|
fontWeight: "400",
|
|
1534
1581
|
color: colors.palette.staticWhite
|
package/dist/index.d.cts
CHANGED
|
@@ -88,6 +88,12 @@ interface LynxConsoleProps {
|
|
|
88
88
|
theme?: "light" | "dark";
|
|
89
89
|
safeAreaInsetBottom?: string;
|
|
90
90
|
customTabs?: CustomTab[];
|
|
91
|
+
initialPosition?: {
|
|
92
|
+
top?: number;
|
|
93
|
+
left?: number;
|
|
94
|
+
right?: number;
|
|
95
|
+
bottom?: number;
|
|
96
|
+
};
|
|
91
97
|
}
|
|
92
98
|
declare const LynxConsole: react.ForwardRefExoticComponent<LynxConsoleProps & react.RefAttributes<LynxConsoleHandle>>;
|
|
93
99
|
//#endregion
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;;;UAIiB,SAAA;EACf,GAAA;EACA,KAAA;EACA,aAAA,QAAqB,SAAA;AAAA;AAAA,KAKX,QAAA;AAAA,UAEK,QAAA;EACf,EAAA;EACA,KAAA,EAAO,QAAA;EACP,OAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,KAIU,aAAA;AAAA,UAEK,YAAA;EACf,EAAA;EACA,GAAA;EACA,MAAA;EACA,MAAA,EAAQ,aAAA;EACR,UAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA,GAAiB,MAAA;EACjB,WAAA;EACA,eAAA,GAAkB,MAAA;EAClB,YAAA;EACA,KAAA;AAAA;AAAA,KAIU,oBAAA;AAAA,UAEK,iBAAA;EACf,IAAA;EACA,QAAA;EACA,kBAAA;EACA,cAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,UAGe,oBAAA;EACf,EAAA;EACA,SAAA,EAAW,oBAAA;EACX,IAAA;EACA,SAAA;EACA,OAAA,GAAU,iBAAA;EACV,QAAA;AAAA;AAAA,QAIM,MAAA;EAAA,IACF,aAAA;IACF,KAAA;IAAA,CACC,GAAA;EAAA;EAAA,IAGC,gBAAA;IAGE,eAAA;MACE,GAAA,MAAS,IAAA;MACT,IAAA,MAAU,IAAA;MACV,KAAA,MAAW,IAAA;MACX,IAAA,MAAU,IAAA;IAAA;IAIZ,KAAA;MACE,IAAA,GAAO,QAAA;MACP,YAAA,GAAe,GAAA,EAAK,KAAA,EAAO,QAAA;MAC3B,YAAA,IAAgB,QAAA,GAAW,KAAA,EAAO,QAAA;MAElC,QAAA,GAAW,YAAA;MACX,WAAA,GAAc,GAAA,SAAY,YAAA;MAC1B,gBAAA,GAAmB,GAAA,EAAK,KAAA,EAAO,YAAA;MAC/B,gBAAA,IACE,QAAA,GAAW,KAAA,EAAO,YAAA;MAGpB,YAAA,GAAe,oBAAA;MACf,oBAAA,GAAuB,GAAA,EAAK,KAAA,EAAO,oBAAA;MACnC,oBAAA,IACE,QAAA,GAAW,KAAA,EAAO,oBAAA;IAAA;IAItB,qBAAA;EAAA;AAAA;;;UCnFS,iBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA;EACA,mBAAA;EACA,UAAA,GAAa,SAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;;;UAIiB,SAAA;EACf,GAAA;EACA,KAAA;EACA,aAAA,QAAqB,SAAA;AAAA;AAAA,KAKX,QAAA;AAAA,UAEK,QAAA;EACf,EAAA;EACA,KAAA,EAAO,QAAA;EACP,OAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,KAIU,aAAA;AAAA,UAEK,YAAA;EACf,EAAA;EACA,GAAA;EACA,MAAA;EACA,MAAA,EAAQ,aAAA;EACR,UAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA,GAAiB,MAAA;EACjB,WAAA;EACA,eAAA,GAAkB,MAAA;EAClB,YAAA;EACA,KAAA;AAAA;AAAA,KAIU,oBAAA;AAAA,UAEK,iBAAA;EACf,IAAA;EACA,QAAA;EACA,kBAAA;EACA,cAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,UAGe,oBAAA;EACf,EAAA;EACA,SAAA,EAAW,oBAAA;EACX,IAAA;EACA,SAAA;EACA,OAAA,GAAU,iBAAA;EACV,QAAA;AAAA;AAAA,QAIM,MAAA;EAAA,IACF,aAAA;IACF,KAAA;IAAA,CACC,GAAA;EAAA;EAAA,IAGC,gBAAA;IAGE,eAAA;MACE,GAAA,MAAS,IAAA;MACT,IAAA,MAAU,IAAA;MACV,KAAA,MAAW,IAAA;MACX,IAAA,MAAU,IAAA;IAAA;IAIZ,KAAA;MACE,IAAA,GAAO,QAAA;MACP,YAAA,GAAe,GAAA,EAAK,KAAA,EAAO,QAAA;MAC3B,YAAA,IAAgB,QAAA,GAAW,KAAA,EAAO,QAAA;MAElC,QAAA,GAAW,YAAA;MACX,WAAA,GAAc,GAAA,SAAY,YAAA;MAC1B,gBAAA,GAAmB,GAAA,EAAK,KAAA,EAAO,YAAA;MAC/B,gBAAA,IACE,QAAA,GAAW,KAAA,EAAO,YAAA;MAGpB,YAAA,GAAe,oBAAA;MACf,oBAAA,GAAuB,GAAA,EAAK,KAAA,EAAO,oBAAA;MACnC,oBAAA,IACE,QAAA,GAAW,KAAA,EAAO,oBAAA;IAAA;IAItB,qBAAA;EAAA;AAAA;;;UCnFS,iBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA;EACA,mBAAA;EACA,UAAA,GAAa,SAAA;EACb,eAAA;IACE,GAAA;IACA,IAAA;IACA,KAAA;IACA,MAAA;EAAA;AAAA;AAAA,cAIE,WAAA,EAAW,KAAA,CAAA,yBAAA,CAAA,gBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -88,6 +88,12 @@ interface LynxConsoleProps {
|
|
|
88
88
|
theme?: "light" | "dark";
|
|
89
89
|
safeAreaInsetBottom?: string;
|
|
90
90
|
customTabs?: CustomTab[];
|
|
91
|
+
initialPosition?: {
|
|
92
|
+
top?: number;
|
|
93
|
+
left?: number;
|
|
94
|
+
right?: number;
|
|
95
|
+
bottom?: number;
|
|
96
|
+
};
|
|
91
97
|
}
|
|
92
98
|
declare const LynxConsole: react.ForwardRefExoticComponent<LynxConsoleProps & react.RefAttributes<LynxConsoleHandle>>;
|
|
93
99
|
//#endregion
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;;;UAIiB,SAAA;EACf,GAAA;EACA,KAAA;EACA,aAAA,QAAqB,SAAA;AAAA;AAAA,KAKX,QAAA;AAAA,UAEK,QAAA;EACf,EAAA;EACA,KAAA,EAAO,QAAA;EACP,OAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,KAIU,aAAA;AAAA,UAEK,YAAA;EACf,EAAA;EACA,GAAA;EACA,MAAA;EACA,MAAA,EAAQ,aAAA;EACR,UAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA,GAAiB,MAAA;EACjB,WAAA;EACA,eAAA,GAAkB,MAAA;EAClB,YAAA;EACA,KAAA;AAAA;AAAA,KAIU,oBAAA;AAAA,UAEK,iBAAA;EACf,IAAA;EACA,QAAA;EACA,kBAAA;EACA,cAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,UAGe,oBAAA;EACf,EAAA;EACA,SAAA,EAAW,oBAAA;EACX,IAAA;EACA,SAAA;EACA,OAAA,GAAU,iBAAA;EACV,QAAA;AAAA;AAAA,QAIM,MAAA;EAAA,IACF,aAAA;IACF,KAAA;IAAA,CACC,GAAA;EAAA;EAAA,IAGC,gBAAA;IAGE,eAAA;MACE,GAAA,MAAS,IAAA;MACT,IAAA,MAAU,IAAA;MACV,KAAA,MAAW,IAAA;MACX,IAAA,MAAU,IAAA;IAAA;IAIZ,KAAA;MACE,IAAA,GAAO,QAAA;MACP,YAAA,GAAe,GAAA,EAAK,KAAA,EAAO,QAAA;MAC3B,YAAA,IAAgB,QAAA,GAAW,KAAA,EAAO,QAAA;MAElC,QAAA,GAAW,YAAA;MACX,WAAA,GAAc,GAAA,SAAY,YAAA;MAC1B,gBAAA,GAAmB,GAAA,EAAK,KAAA,EAAO,YAAA;MAC/B,gBAAA,IACE,QAAA,GAAW,KAAA,EAAO,YAAA;MAGpB,YAAA,GAAe,oBAAA;MACf,oBAAA,GAAuB,GAAA,EAAK,KAAA,EAAO,oBAAA;MACnC,oBAAA,IACE,QAAA,GAAW,KAAA,EAAO,oBAAA;IAAA;IAItB,qBAAA;EAAA;AAAA;;;UCnFS,iBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA;EACA,mBAAA;EACA,UAAA,GAAa,SAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.tsx"],"mappings":";;;;;UAIiB,SAAA;EACf,GAAA;EACA,KAAA;EACA,aAAA,QAAqB,SAAA;AAAA;AAAA,KAKX,QAAA;AAAA,UAEK,QAAA;EACf,EAAA;EACA,KAAA,EAAO,QAAA;EACP,OAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,KAIU,aAAA;AAAA,UAEK,YAAA;EACf,EAAA;EACA,GAAA;EACA,MAAA;EACA,MAAA,EAAQ,aAAA;EACR,UAAA;EACA,UAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA,GAAiB,MAAA;EACjB,WAAA;EACA,eAAA,GAAkB,MAAA;EAClB,YAAA;EACA,KAAA;AAAA;AAAA,KAIU,oBAAA;AAAA,UAEK,iBAAA;EACf,IAAA;EACA,QAAA;EACA,kBAAA;EACA,cAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,UAGe,oBAAA;EACf,EAAA;EACA,SAAA,EAAW,oBAAA;EACX,IAAA;EACA,SAAA;EACA,OAAA,GAAU,iBAAA;EACV,QAAA;AAAA;AAAA,QAIM,MAAA;EAAA,IACF,aAAA;IACF,KAAA;IAAA,CACC,GAAA;EAAA;EAAA,IAGC,gBAAA;IAGE,eAAA;MACE,GAAA,MAAS,IAAA;MACT,IAAA,MAAU,IAAA;MACV,KAAA,MAAW,IAAA;MACX,IAAA,MAAU,IAAA;IAAA;IAIZ,KAAA;MACE,IAAA,GAAO,QAAA;MACP,YAAA,GAAe,GAAA,EAAK,KAAA,EAAO,QAAA;MAC3B,YAAA,IAAgB,QAAA,GAAW,KAAA,EAAO,QAAA;MAElC,QAAA,GAAW,YAAA;MACX,WAAA,GAAc,GAAA,SAAY,YAAA;MAC1B,gBAAA,GAAmB,GAAA,EAAK,KAAA,EAAO,YAAA;MAC/B,gBAAA,IACE,QAAA,GAAW,KAAA,EAAO,YAAA;MAGpB,YAAA,GAAe,oBAAA;MACf,oBAAA,GAAuB,GAAA,EAAK,KAAA,EAAO,oBAAA;MACnC,oBAAA,IACE,QAAA,GAAW,KAAA,EAAO,oBAAA;IAAA;IAItB,qBAAA;EAAA;AAAA;;;UCnFS,iBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,KAAA;EACA,mBAAA;EACA,UAAA,GAAa,SAAA;EACb,eAAA;IACE,GAAA;IACA,IAAA;IACA,KAAA;IACA,MAAA;EAAA;AAAA;AAAA,cAIE,WAAA,EAAW,KAAA,CAAA,yBAAA,CAAA,gBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -222,6 +222,35 @@ const useConsole = () => {
|
|
|
222
222
|
};
|
|
223
223
|
};
|
|
224
224
|
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/hooks/useLatestFcp.ts
|
|
227
|
+
const pickFcp = (entry) => {
|
|
228
|
+
if (entry.entryType !== "metric" || entry.name !== "fcp") return void 0;
|
|
229
|
+
const raw = entry.rawEntry;
|
|
230
|
+
if (raw?.totalFcp?.duration !== void 0) return raw.totalFcp;
|
|
231
|
+
if (raw?.lynxFcp?.duration !== void 0) return raw.lynxFcp;
|
|
232
|
+
};
|
|
233
|
+
const useLatestFcp = () => {
|
|
234
|
+
const [fcp, setFcp] = useState(() => {
|
|
235
|
+
const performances = globalThis.__LYNX_CONSOLE__?.state?.performances ?? [];
|
|
236
|
+
for (let i = performances.length - 1; i >= 0; i--) {
|
|
237
|
+
const entry = performances[i];
|
|
238
|
+
if (!entry) continue;
|
|
239
|
+
const found = pickFcp(entry);
|
|
240
|
+
if (found) return found;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
const state = globalThis.__LYNX_CONSOLE__?.state;
|
|
245
|
+
if (!state?.subscribePerformance) return;
|
|
246
|
+
return state.subscribePerformance((entry) => {
|
|
247
|
+
const found = pickFcp(entry);
|
|
248
|
+
if (found) setFcp(found);
|
|
249
|
+
});
|
|
250
|
+
}, []);
|
|
251
|
+
return fcp;
|
|
252
|
+
};
|
|
253
|
+
|
|
225
254
|
//#endregion
|
|
226
255
|
//#region src/hooks/useNetwork.ts
|
|
227
256
|
const useNetwork = () => {
|
|
@@ -484,7 +513,8 @@ const LogPanel = ({ logs, clearLogs }) => {
|
|
|
484
513
|
params: {
|
|
485
514
|
position: logsRef.current.length - 1,
|
|
486
515
|
smooth
|
|
487
|
-
}
|
|
516
|
+
},
|
|
517
|
+
fail: () => {}
|
|
488
518
|
}).exec();
|
|
489
519
|
};
|
|
490
520
|
useEffect(() => {
|
|
@@ -1368,22 +1398,42 @@ const LONG_PRESS_DURATION = 400;
|
|
|
1368
1398
|
const MOVE_THRESHOLD = 5;
|
|
1369
1399
|
const DEFAULT_RIGHT = 16;
|
|
1370
1400
|
const DEFAULT_BOTTOM = 84;
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
const
|
|
1375
|
-
|
|
1401
|
+
function resolveAnchors(initial) {
|
|
1402
|
+
const vertical = initial?.top !== void 0 ? "top" : "bottom";
|
|
1403
|
+
const horizontal = initial?.left !== void 0 ? "left" : "right";
|
|
1404
|
+
const y = vertical === "top" ? initial?.top ?? 0 : initial?.bottom ?? DEFAULT_BOTTOM;
|
|
1405
|
+
return {
|
|
1406
|
+
vertical,
|
|
1407
|
+
horizontal,
|
|
1408
|
+
x: horizontal === "left" ? initial?.left ?? 0 : initial?.right ?? DEFAULT_RIGHT,
|
|
1409
|
+
y
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
let saved = null;
|
|
1413
|
+
function useLongPressDrag(onTap, options) {
|
|
1414
|
+
const anchors = resolveAnchors(options?.initialPosition);
|
|
1415
|
+
const snapshot = saved;
|
|
1416
|
+
let initX = anchors.x;
|
|
1417
|
+
let initY = anchors.y;
|
|
1418
|
+
if (snapshot !== null && snapshot.vertical === anchors.vertical && snapshot.horizontal === anchors.horizontal) {
|
|
1419
|
+
initX = snapshot.x;
|
|
1420
|
+
initY = snapshot.y;
|
|
1421
|
+
}
|
|
1422
|
+
const [x, setX] = useState(initX);
|
|
1423
|
+
const [y, setY] = useState(initY);
|
|
1376
1424
|
const [phase, setPhase] = useState("idle");
|
|
1377
|
-
const [
|
|
1378
|
-
const [
|
|
1425
|
+
const [tempX, setTempX] = useState(initX);
|
|
1426
|
+
const [tempY, setTempY] = useState(initY);
|
|
1379
1427
|
const timerRef = useRef(null);
|
|
1380
1428
|
const draggingRef = useRef(false);
|
|
1381
1429
|
const startRef = useRef({
|
|
1382
1430
|
x: 0,
|
|
1383
1431
|
y: 0,
|
|
1384
|
-
|
|
1385
|
-
|
|
1432
|
+
ax: 0,
|
|
1433
|
+
ay: 0
|
|
1386
1434
|
});
|
|
1435
|
+
const xSign = anchors.horizontal === "right" ? -1 : 1;
|
|
1436
|
+
const ySign = anchors.vertical === "bottom" ? -1 : 1;
|
|
1387
1437
|
const clearTimer = () => {
|
|
1388
1438
|
if (timerRef.current) {
|
|
1389
1439
|
clearTimeout(timerRef.current);
|
|
@@ -1394,15 +1444,15 @@ function useLongPressDrag(onTap) {
|
|
|
1394
1444
|
startRef.current = {
|
|
1395
1445
|
x: e.detail.x,
|
|
1396
1446
|
y: e.detail.y,
|
|
1397
|
-
|
|
1398
|
-
|
|
1447
|
+
ax: x,
|
|
1448
|
+
ay: y
|
|
1399
1449
|
};
|
|
1400
1450
|
draggingRef.current = false;
|
|
1401
1451
|
timerRef.current = setTimeout(() => {
|
|
1402
1452
|
draggingRef.current = true;
|
|
1403
1453
|
setPhase("dragging");
|
|
1404
|
-
|
|
1405
|
-
|
|
1454
|
+
setTempX(x);
|
|
1455
|
+
setTempY(y);
|
|
1406
1456
|
}, LONG_PRESS_DURATION);
|
|
1407
1457
|
};
|
|
1408
1458
|
const handleTouchMove = (e) => {
|
|
@@ -1410,26 +1460,34 @@ function useLongPressDrag(onTap) {
|
|
|
1410
1460
|
const dy = e.detail.y - startRef.current.y;
|
|
1411
1461
|
if (!draggingRef.current && (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)) clearTimer();
|
|
1412
1462
|
if (!draggingRef.current) return;
|
|
1413
|
-
|
|
1414
|
-
|
|
1463
|
+
setTempX(startRef.current.ax + xSign * dx);
|
|
1464
|
+
setTempY(startRef.current.ay + ySign * dy);
|
|
1415
1465
|
};
|
|
1416
1466
|
const handleTouchEnd = () => {
|
|
1417
1467
|
clearTimer();
|
|
1418
1468
|
if (draggingRef.current) {
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1469
|
+
setX(tempX);
|
|
1470
|
+
setY(tempY);
|
|
1471
|
+
saved = {
|
|
1472
|
+
vertical: anchors.vertical,
|
|
1473
|
+
horizontal: anchors.horizontal,
|
|
1474
|
+
x: tempX,
|
|
1475
|
+
y: tempY
|
|
1476
|
+
};
|
|
1423
1477
|
setPhase("releasing");
|
|
1424
1478
|
draggingRef.current = false;
|
|
1425
1479
|
setTimeout(() => setPhase("idle"), 300);
|
|
1426
1480
|
} else onTap();
|
|
1427
1481
|
};
|
|
1428
1482
|
const isDragging = phase === "dragging";
|
|
1483
|
+
const currentX = isDragging ? tempX : x;
|
|
1484
|
+
const currentY = isDragging ? tempY : y;
|
|
1429
1485
|
return {
|
|
1430
1486
|
phase,
|
|
1431
|
-
|
|
1432
|
-
|
|
1487
|
+
positionStyle: {
|
|
1488
|
+
[anchors.horizontal]: `${currentX}px`,
|
|
1489
|
+
[anchors.vertical]: `${currentY}px`
|
|
1490
|
+
},
|
|
1433
1491
|
clearTimer,
|
|
1434
1492
|
handlers: {
|
|
1435
1493
|
catchtouchstart: handleTouchStart,
|
|
@@ -1457,9 +1515,9 @@ const SHINE_STYLES = {
|
|
|
1457
1515
|
transition: "opacity 300ms cubic-bezier(0.4, 0, 0.2, 1)"
|
|
1458
1516
|
}
|
|
1459
1517
|
};
|
|
1460
|
-
const FloatingButton = ({ bindtap, children }) => {
|
|
1518
|
+
const FloatingButton = ({ bindtap, children, initialPosition }) => {
|
|
1461
1519
|
const colors = useThemeColors();
|
|
1462
|
-
const { phase,
|
|
1520
|
+
const { phase, positionStyle, clearTimer, handlers } = useLongPressDrag(bindtap, { initialPosition });
|
|
1463
1521
|
const handleReload = () => {
|
|
1464
1522
|
try {
|
|
1465
1523
|
lynx.reload({}, () => {
|
|
@@ -1470,9 +1528,8 @@ const FloatingButton = ({ bindtap, children }) => {
|
|
|
1470
1528
|
}
|
|
1471
1529
|
};
|
|
1472
1530
|
const isDragging = phase === "dragging";
|
|
1473
|
-
return <view className={"fb-wrapper"}
|
|
1474
|
-
|
|
1475
|
-
bottom: `${bottom}px`,
|
|
1531
|
+
return <view className={"fb-wrapper"} style={{
|
|
1532
|
+
...positionStyle,
|
|
1476
1533
|
transform: isDragging ? "scale(1.05)" : "scale(1)",
|
|
1477
1534
|
transition: `transform ${duration.d4} cubic-bezier(0.4, 0, 0.2, 1)`
|
|
1478
1535
|
}} {...handlers}>
|
|
@@ -1490,21 +1547,11 @@ const FloatingButton = ({ bindtap, children }) => {
|
|
|
1490
1547
|
|
|
1491
1548
|
//#endregion
|
|
1492
1549
|
//#region src/index.tsx
|
|
1493
|
-
const LynxConsole = forwardRef(({ theme = "light", safeAreaInsetBottom = "50px", customTabs }, ref) => {
|
|
1550
|
+
const LynxConsole = forwardRef(({ theme = "light", safeAreaInsetBottom = "50px", customTabs, initialPosition }, ref) => {
|
|
1494
1551
|
const [isOpen, setIsOpen] = useState(false);
|
|
1495
1552
|
const [shouldClose, setShouldClose] = useState(false);
|
|
1496
|
-
const
|
|
1553
|
+
const latestFcp = useLatestFcp();
|
|
1497
1554
|
const colors = useMemo(() => getColors(theme), [theme]);
|
|
1498
|
-
const latestFcp = useMemo(() => {
|
|
1499
|
-
for (let i = performances.length - 1; i >= 0; i--) {
|
|
1500
|
-
const perf = performances[i];
|
|
1501
|
-
if (perf && perf.entryType === "metric" && perf.name === "fcp") {
|
|
1502
|
-
const metricEntry = perf.rawEntry;
|
|
1503
|
-
if (metricEntry?.totalFcp?.duration !== void 0) return metricEntry.totalFcp;
|
|
1504
|
-
if (metricEntry?.lynxFcp?.duration !== void 0) return metricEntry.lynxFcp;
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
}, [performances]);
|
|
1508
1555
|
useImperativeHandle(ref, () => ({
|
|
1509
1556
|
open: () => {
|
|
1510
1557
|
setIsOpen(true);
|
|
@@ -1528,7 +1575,7 @@ const LynxConsole = forwardRef(({ theme = "light", safeAreaInsetBottom = "50px",
|
|
|
1528
1575
|
backgroundColor: colors.bg.layerDefault,
|
|
1529
1576
|
color: colors.fg.neutral
|
|
1530
1577
|
}}>
|
|
1531
|
-
<FloatingButton bindtap={handleOpenBottomSheet}>
|
|
1578
|
+
<FloatingButton bindtap={handleOpenBottomSheet} initialPosition={initialPosition}>
|
|
1532
1579
|
<text className="fb-title t4" style={{
|
|
1533
1580
|
fontWeight: "400",
|
|
1534
1581
|
color: colors.palette.staticWhite
|