lynx-console 0.4.0 → 0.6.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/README.md +1 -0
- package/dist/index.cjs +68 -30
- 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 +69 -31
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/BottomSheet.tsx +17 -3
- package/src/components/FloatingButton.tsx +15 -6
- package/src/hooks/useKeyboardHeight.ts +14 -0
- package/src/hooks/useLongPressDrag.ts +97 -21
- package/src/index.tsx +16 -2
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
|
@@ -2,6 +2,16 @@ import "./index.css";
|
|
|
2
2
|
let _lynx_js_react = require("@lynx-js/react");
|
|
3
3
|
let javascript_stringify = require("javascript-stringify");
|
|
4
4
|
|
|
5
|
+
//#region src/hooks/useKeyboardHeight.ts
|
|
6
|
+
function useKeyboardHeight() {
|
|
7
|
+
const [keyboardHeight, setKeyboardHeight] = (0, _lynx_js_react.useState)(0);
|
|
8
|
+
(0, _lynx_js_react.useLynxGlobalEventListener)("keyboardstatuschanged", (status, height) => {
|
|
9
|
+
setKeyboardHeight(status === "on" ? height : 0);
|
|
10
|
+
});
|
|
11
|
+
return keyboardHeight;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
5
15
|
//#region src/styles/theme.ts
|
|
6
16
|
const colorMap = {
|
|
7
17
|
light: {
|
|
@@ -114,6 +124,7 @@ function BottomSheet({ children, title, footer, onClose, isOpen, shouldClose = f
|
|
|
114
124
|
const [dragStartHeight, setDragStartHeight] = (0, _lynx_js_react.useState)(savedHeight ?? DEFAULT_HEIGHT);
|
|
115
125
|
const [isOpening, setIsOpening] = (0, _lynx_js_react.useState)(true);
|
|
116
126
|
const [isClosing, setIsClosing] = (0, _lynx_js_react.useState)(false);
|
|
127
|
+
const keyboardHeight = useKeyboardHeight();
|
|
117
128
|
const handleClose = () => {
|
|
118
129
|
setIsClosing(true);
|
|
119
130
|
setTimeout(() => {
|
|
@@ -157,9 +168,9 @@ function BottomSheet({ children, title, footer, onClose, isOpen, shouldClose = f
|
|
|
157
168
|
<view className="bs-overlay" bindtap={handleClose}>
|
|
158
169
|
<view className="bs-content" catchtap={() => {}} style={{
|
|
159
170
|
background: colors.bg.layerFloating,
|
|
160
|
-
height: `${isDragging ? tempHeight : sheetHeight}px`,
|
|
171
|
+
height: `${keyboardHeight > 0 ? Math.min(MAX_HEIGHT, (isDragging ? tempHeight : sheetHeight) + keyboardHeight) : isDragging ? tempHeight : sheetHeight}px`,
|
|
161
172
|
transform: isOpening || isClosing ? "translateY(100%)" : "translateY(0)",
|
|
162
|
-
transition: isDragging ? "none" : `transform ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`
|
|
173
|
+
transition: isDragging ? "none" : `transform ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1), height ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`
|
|
163
174
|
}}>
|
|
164
175
|
{}
|
|
165
176
|
<view className="bs-handleContainer" bindtouchstart={handleTouchStart} bindtouchmove={handleTouchMove} bindtouchend={handleTouchEnd}>
|
|
@@ -173,7 +184,7 @@ function BottomSheet({ children, title, footer, onClose, isOpen, shouldClose = f
|
|
|
173
184
|
{title}
|
|
174
185
|
</text>}
|
|
175
186
|
</view>
|
|
176
|
-
<view className="bs-body" style={{ paddingBottom: safeAreaInsetBottom }}>
|
|
187
|
+
<view className="bs-body" style={{ paddingBottom: keyboardHeight > 0 ? `${keyboardHeight}px` : safeAreaInsetBottom }}>
|
|
177
188
|
{children}
|
|
178
189
|
</view>
|
|
179
190
|
{footer && <view className="bs-footer">{footer}</view>}
|
|
@@ -1357,22 +1368,42 @@ const LONG_PRESS_DURATION = 400;
|
|
|
1357
1368
|
const MOVE_THRESHOLD = 5;
|
|
1358
1369
|
const DEFAULT_RIGHT = 16;
|
|
1359
1370
|
const DEFAULT_BOTTOM = 84;
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1371
|
+
function resolveAnchors(initial) {
|
|
1372
|
+
const vertical = initial?.top !== void 0 ? "top" : "bottom";
|
|
1373
|
+
const horizontal = initial?.left !== void 0 ? "left" : "right";
|
|
1374
|
+
const y = vertical === "top" ? initial?.top ?? 0 : initial?.bottom ?? DEFAULT_BOTTOM;
|
|
1375
|
+
return {
|
|
1376
|
+
vertical,
|
|
1377
|
+
horizontal,
|
|
1378
|
+
x: horizontal === "left" ? initial?.left ?? 0 : initial?.right ?? DEFAULT_RIGHT,
|
|
1379
|
+
y
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
let saved = null;
|
|
1383
|
+
function useLongPressDrag(onTap, options) {
|
|
1384
|
+
const anchors = resolveAnchors(options?.initialPosition);
|
|
1385
|
+
const snapshot = saved;
|
|
1386
|
+
let initX = anchors.x;
|
|
1387
|
+
let initY = anchors.y;
|
|
1388
|
+
if (snapshot !== null && snapshot.vertical === anchors.vertical && snapshot.horizontal === anchors.horizontal) {
|
|
1389
|
+
initX = snapshot.x;
|
|
1390
|
+
initY = snapshot.y;
|
|
1391
|
+
}
|
|
1392
|
+
const [x, setX] = (0, _lynx_js_react.useState)(initX);
|
|
1393
|
+
const [y, setY] = (0, _lynx_js_react.useState)(initY);
|
|
1365
1394
|
const [phase, setPhase] = (0, _lynx_js_react.useState)("idle");
|
|
1366
|
-
const [
|
|
1367
|
-
const [
|
|
1395
|
+
const [tempX, setTempX] = (0, _lynx_js_react.useState)(initX);
|
|
1396
|
+
const [tempY, setTempY] = (0, _lynx_js_react.useState)(initY);
|
|
1368
1397
|
const timerRef = (0, _lynx_js_react.useRef)(null);
|
|
1369
1398
|
const draggingRef = (0, _lynx_js_react.useRef)(false);
|
|
1370
1399
|
const startRef = (0, _lynx_js_react.useRef)({
|
|
1371
1400
|
x: 0,
|
|
1372
1401
|
y: 0,
|
|
1373
|
-
|
|
1374
|
-
|
|
1402
|
+
ax: 0,
|
|
1403
|
+
ay: 0
|
|
1375
1404
|
});
|
|
1405
|
+
const xSign = anchors.horizontal === "right" ? -1 : 1;
|
|
1406
|
+
const ySign = anchors.vertical === "bottom" ? -1 : 1;
|
|
1376
1407
|
const clearTimer = () => {
|
|
1377
1408
|
if (timerRef.current) {
|
|
1378
1409
|
clearTimeout(timerRef.current);
|
|
@@ -1383,15 +1414,15 @@ function useLongPressDrag(onTap) {
|
|
|
1383
1414
|
startRef.current = {
|
|
1384
1415
|
x: e.detail.x,
|
|
1385
1416
|
y: e.detail.y,
|
|
1386
|
-
|
|
1387
|
-
|
|
1417
|
+
ax: x,
|
|
1418
|
+
ay: y
|
|
1388
1419
|
};
|
|
1389
1420
|
draggingRef.current = false;
|
|
1390
1421
|
timerRef.current = setTimeout(() => {
|
|
1391
1422
|
draggingRef.current = true;
|
|
1392
1423
|
setPhase("dragging");
|
|
1393
|
-
|
|
1394
|
-
|
|
1424
|
+
setTempX(x);
|
|
1425
|
+
setTempY(y);
|
|
1395
1426
|
}, LONG_PRESS_DURATION);
|
|
1396
1427
|
};
|
|
1397
1428
|
const handleTouchMove = (e) => {
|
|
@@ -1399,26 +1430,34 @@ function useLongPressDrag(onTap) {
|
|
|
1399
1430
|
const dy = e.detail.y - startRef.current.y;
|
|
1400
1431
|
if (!draggingRef.current && (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)) clearTimer();
|
|
1401
1432
|
if (!draggingRef.current) return;
|
|
1402
|
-
|
|
1403
|
-
|
|
1433
|
+
setTempX(startRef.current.ax + xSign * dx);
|
|
1434
|
+
setTempY(startRef.current.ay + ySign * dy);
|
|
1404
1435
|
};
|
|
1405
1436
|
const handleTouchEnd = () => {
|
|
1406
1437
|
clearTimer();
|
|
1407
1438
|
if (draggingRef.current) {
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1439
|
+
setX(tempX);
|
|
1440
|
+
setY(tempY);
|
|
1441
|
+
saved = {
|
|
1442
|
+
vertical: anchors.vertical,
|
|
1443
|
+
horizontal: anchors.horizontal,
|
|
1444
|
+
x: tempX,
|
|
1445
|
+
y: tempY
|
|
1446
|
+
};
|
|
1412
1447
|
setPhase("releasing");
|
|
1413
1448
|
draggingRef.current = false;
|
|
1414
1449
|
setTimeout(() => setPhase("idle"), 300);
|
|
1415
1450
|
} else onTap();
|
|
1416
1451
|
};
|
|
1417
1452
|
const isDragging = phase === "dragging";
|
|
1453
|
+
const currentX = isDragging ? tempX : x;
|
|
1454
|
+
const currentY = isDragging ? tempY : y;
|
|
1418
1455
|
return {
|
|
1419
1456
|
phase,
|
|
1420
|
-
|
|
1421
|
-
|
|
1457
|
+
positionStyle: {
|
|
1458
|
+
[anchors.horizontal]: `${currentX}px`,
|
|
1459
|
+
[anchors.vertical]: `${currentY}px`
|
|
1460
|
+
},
|
|
1422
1461
|
clearTimer,
|
|
1423
1462
|
handlers: {
|
|
1424
1463
|
catchtouchstart: handleTouchStart,
|
|
@@ -1446,9 +1485,9 @@ const SHINE_STYLES = {
|
|
|
1446
1485
|
transition: "opacity 300ms cubic-bezier(0.4, 0, 0.2, 1)"
|
|
1447
1486
|
}
|
|
1448
1487
|
};
|
|
1449
|
-
const FloatingButton = ({ bindtap, children }) => {
|
|
1488
|
+
const FloatingButton = ({ bindtap, children, initialPosition }) => {
|
|
1450
1489
|
const colors = useThemeColors();
|
|
1451
|
-
const { phase,
|
|
1490
|
+
const { phase, positionStyle, clearTimer, handlers } = useLongPressDrag(bindtap, { initialPosition });
|
|
1452
1491
|
const handleReload = () => {
|
|
1453
1492
|
try {
|
|
1454
1493
|
lynx.reload({}, () => {
|
|
@@ -1460,8 +1499,7 @@ const FloatingButton = ({ bindtap, children }) => {
|
|
|
1460
1499
|
};
|
|
1461
1500
|
const isDragging = phase === "dragging";
|
|
1462
1501
|
return <view className={"fb-wrapper"} consume-slide-event={[[-180, 180]]} style={{
|
|
1463
|
-
|
|
1464
|
-
bottom: `${bottom}px`,
|
|
1502
|
+
...positionStyle,
|
|
1465
1503
|
transform: isDragging ? "scale(1.05)" : "scale(1)",
|
|
1466
1504
|
transition: `transform ${duration.d4} cubic-bezier(0.4, 0, 0.2, 1)`
|
|
1467
1505
|
}} {...handlers}>
|
|
@@ -1479,7 +1517,7 @@ const FloatingButton = ({ bindtap, children }) => {
|
|
|
1479
1517
|
|
|
1480
1518
|
//#endregion
|
|
1481
1519
|
//#region src/index.tsx
|
|
1482
|
-
const LynxConsole = (0, _lynx_js_react.forwardRef)(({ theme = "light", safeAreaInsetBottom = "50px", customTabs }, ref) => {
|
|
1520
|
+
const LynxConsole = (0, _lynx_js_react.forwardRef)(({ theme = "light", safeAreaInsetBottom = "50px", customTabs, initialPosition }, ref) => {
|
|
1483
1521
|
const [isOpen, setIsOpen] = (0, _lynx_js_react.useState)(false);
|
|
1484
1522
|
const [shouldClose, setShouldClose] = (0, _lynx_js_react.useState)(false);
|
|
1485
1523
|
const { performances } = usePerformance();
|
|
@@ -1517,7 +1555,7 @@ const LynxConsole = (0, _lynx_js_react.forwardRef)(({ theme = "light", safeAreaI
|
|
|
1517
1555
|
backgroundColor: colors.bg.layerDefault,
|
|
1518
1556
|
color: colors.fg.neutral
|
|
1519
1557
|
}}>
|
|
1520
|
-
<FloatingButton bindtap={handleOpenBottomSheet}>
|
|
1558
|
+
<FloatingButton bindtap={handleOpenBottomSheet} initialPosition={initialPosition}>
|
|
1521
1559
|
<text className="fb-title t4" style={{
|
|
1522
1560
|
fontWeight: "400",
|
|
1523
1561
|
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,cAeE,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,cAeE,WAAA,EAAW,KAAA,CAAA,yBAAA,CAAA,gBAAA,GAAA,KAAA,CAAA,aAAA,CAAA,iBAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import "./index.css";
|
|
2
|
-
import { createContext, forwardRef, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "@lynx-js/react";
|
|
2
|
+
import { createContext, forwardRef, useContext, useEffect, useImperativeHandle, useLynxGlobalEventListener, useMemo, useRef, useState } from "@lynx-js/react";
|
|
3
3
|
import { stringify } from "javascript-stringify";
|
|
4
4
|
|
|
5
|
+
//#region src/hooks/useKeyboardHeight.ts
|
|
6
|
+
function useKeyboardHeight() {
|
|
7
|
+
const [keyboardHeight, setKeyboardHeight] = useState(0);
|
|
8
|
+
useLynxGlobalEventListener("keyboardstatuschanged", (status, height) => {
|
|
9
|
+
setKeyboardHeight(status === "on" ? height : 0);
|
|
10
|
+
});
|
|
11
|
+
return keyboardHeight;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
5
15
|
//#region src/styles/theme.ts
|
|
6
16
|
const colorMap = {
|
|
7
17
|
light: {
|
|
@@ -114,6 +124,7 @@ function BottomSheet({ children, title, footer, onClose, isOpen, shouldClose = f
|
|
|
114
124
|
const [dragStartHeight, setDragStartHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);
|
|
115
125
|
const [isOpening, setIsOpening] = useState(true);
|
|
116
126
|
const [isClosing, setIsClosing] = useState(false);
|
|
127
|
+
const keyboardHeight = useKeyboardHeight();
|
|
117
128
|
const handleClose = () => {
|
|
118
129
|
setIsClosing(true);
|
|
119
130
|
setTimeout(() => {
|
|
@@ -157,9 +168,9 @@ function BottomSheet({ children, title, footer, onClose, isOpen, shouldClose = f
|
|
|
157
168
|
<view className="bs-overlay" bindtap={handleClose}>
|
|
158
169
|
<view className="bs-content" catchtap={() => {}} style={{
|
|
159
170
|
background: colors.bg.layerFloating,
|
|
160
|
-
height: `${isDragging ? tempHeight : sheetHeight}px`,
|
|
171
|
+
height: `${keyboardHeight > 0 ? Math.min(MAX_HEIGHT, (isDragging ? tempHeight : sheetHeight) + keyboardHeight) : isDragging ? tempHeight : sheetHeight}px`,
|
|
161
172
|
transform: isOpening || isClosing ? "translateY(100%)" : "translateY(0)",
|
|
162
|
-
transition: isDragging ? "none" : `transform ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`
|
|
173
|
+
transition: isDragging ? "none" : `transform ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1), height ${duration.d6} cubic-bezier(0.4, 0, 0.2, 1)`
|
|
163
174
|
}}>
|
|
164
175
|
{}
|
|
165
176
|
<view className="bs-handleContainer" bindtouchstart={handleTouchStart} bindtouchmove={handleTouchMove} bindtouchend={handleTouchEnd}>
|
|
@@ -173,7 +184,7 @@ function BottomSheet({ children, title, footer, onClose, isOpen, shouldClose = f
|
|
|
173
184
|
{title}
|
|
174
185
|
</text>}
|
|
175
186
|
</view>
|
|
176
|
-
<view className="bs-body" style={{ paddingBottom: safeAreaInsetBottom }}>
|
|
187
|
+
<view className="bs-body" style={{ paddingBottom: keyboardHeight > 0 ? `${keyboardHeight}px` : safeAreaInsetBottom }}>
|
|
177
188
|
{children}
|
|
178
189
|
</view>
|
|
179
190
|
{footer && <view className="bs-footer">{footer}</view>}
|
|
@@ -1357,22 +1368,42 @@ const LONG_PRESS_DURATION = 400;
|
|
|
1357
1368
|
const MOVE_THRESHOLD = 5;
|
|
1358
1369
|
const DEFAULT_RIGHT = 16;
|
|
1359
1370
|
const DEFAULT_BOTTOM = 84;
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1371
|
+
function resolveAnchors(initial) {
|
|
1372
|
+
const vertical = initial?.top !== void 0 ? "top" : "bottom";
|
|
1373
|
+
const horizontal = initial?.left !== void 0 ? "left" : "right";
|
|
1374
|
+
const y = vertical === "top" ? initial?.top ?? 0 : initial?.bottom ?? DEFAULT_BOTTOM;
|
|
1375
|
+
return {
|
|
1376
|
+
vertical,
|
|
1377
|
+
horizontal,
|
|
1378
|
+
x: horizontal === "left" ? initial?.left ?? 0 : initial?.right ?? DEFAULT_RIGHT,
|
|
1379
|
+
y
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
let saved = null;
|
|
1383
|
+
function useLongPressDrag(onTap, options) {
|
|
1384
|
+
const anchors = resolveAnchors(options?.initialPosition);
|
|
1385
|
+
const snapshot = saved;
|
|
1386
|
+
let initX = anchors.x;
|
|
1387
|
+
let initY = anchors.y;
|
|
1388
|
+
if (snapshot !== null && snapshot.vertical === anchors.vertical && snapshot.horizontal === anchors.horizontal) {
|
|
1389
|
+
initX = snapshot.x;
|
|
1390
|
+
initY = snapshot.y;
|
|
1391
|
+
}
|
|
1392
|
+
const [x, setX] = useState(initX);
|
|
1393
|
+
const [y, setY] = useState(initY);
|
|
1365
1394
|
const [phase, setPhase] = useState("idle");
|
|
1366
|
-
const [
|
|
1367
|
-
const [
|
|
1395
|
+
const [tempX, setTempX] = useState(initX);
|
|
1396
|
+
const [tempY, setTempY] = useState(initY);
|
|
1368
1397
|
const timerRef = useRef(null);
|
|
1369
1398
|
const draggingRef = useRef(false);
|
|
1370
1399
|
const startRef = useRef({
|
|
1371
1400
|
x: 0,
|
|
1372
1401
|
y: 0,
|
|
1373
|
-
|
|
1374
|
-
|
|
1402
|
+
ax: 0,
|
|
1403
|
+
ay: 0
|
|
1375
1404
|
});
|
|
1405
|
+
const xSign = anchors.horizontal === "right" ? -1 : 1;
|
|
1406
|
+
const ySign = anchors.vertical === "bottom" ? -1 : 1;
|
|
1376
1407
|
const clearTimer = () => {
|
|
1377
1408
|
if (timerRef.current) {
|
|
1378
1409
|
clearTimeout(timerRef.current);
|
|
@@ -1383,15 +1414,15 @@ function useLongPressDrag(onTap) {
|
|
|
1383
1414
|
startRef.current = {
|
|
1384
1415
|
x: e.detail.x,
|
|
1385
1416
|
y: e.detail.y,
|
|
1386
|
-
|
|
1387
|
-
|
|
1417
|
+
ax: x,
|
|
1418
|
+
ay: y
|
|
1388
1419
|
};
|
|
1389
1420
|
draggingRef.current = false;
|
|
1390
1421
|
timerRef.current = setTimeout(() => {
|
|
1391
1422
|
draggingRef.current = true;
|
|
1392
1423
|
setPhase("dragging");
|
|
1393
|
-
|
|
1394
|
-
|
|
1424
|
+
setTempX(x);
|
|
1425
|
+
setTempY(y);
|
|
1395
1426
|
}, LONG_PRESS_DURATION);
|
|
1396
1427
|
};
|
|
1397
1428
|
const handleTouchMove = (e) => {
|
|
@@ -1399,26 +1430,34 @@ function useLongPressDrag(onTap) {
|
|
|
1399
1430
|
const dy = e.detail.y - startRef.current.y;
|
|
1400
1431
|
if (!draggingRef.current && (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)) clearTimer();
|
|
1401
1432
|
if (!draggingRef.current) return;
|
|
1402
|
-
|
|
1403
|
-
|
|
1433
|
+
setTempX(startRef.current.ax + xSign * dx);
|
|
1434
|
+
setTempY(startRef.current.ay + ySign * dy);
|
|
1404
1435
|
};
|
|
1405
1436
|
const handleTouchEnd = () => {
|
|
1406
1437
|
clearTimer();
|
|
1407
1438
|
if (draggingRef.current) {
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1439
|
+
setX(tempX);
|
|
1440
|
+
setY(tempY);
|
|
1441
|
+
saved = {
|
|
1442
|
+
vertical: anchors.vertical,
|
|
1443
|
+
horizontal: anchors.horizontal,
|
|
1444
|
+
x: tempX,
|
|
1445
|
+
y: tempY
|
|
1446
|
+
};
|
|
1412
1447
|
setPhase("releasing");
|
|
1413
1448
|
draggingRef.current = false;
|
|
1414
1449
|
setTimeout(() => setPhase("idle"), 300);
|
|
1415
1450
|
} else onTap();
|
|
1416
1451
|
};
|
|
1417
1452
|
const isDragging = phase === "dragging";
|
|
1453
|
+
const currentX = isDragging ? tempX : x;
|
|
1454
|
+
const currentY = isDragging ? tempY : y;
|
|
1418
1455
|
return {
|
|
1419
1456
|
phase,
|
|
1420
|
-
|
|
1421
|
-
|
|
1457
|
+
positionStyle: {
|
|
1458
|
+
[anchors.horizontal]: `${currentX}px`,
|
|
1459
|
+
[anchors.vertical]: `${currentY}px`
|
|
1460
|
+
},
|
|
1422
1461
|
clearTimer,
|
|
1423
1462
|
handlers: {
|
|
1424
1463
|
catchtouchstart: handleTouchStart,
|
|
@@ -1446,9 +1485,9 @@ const SHINE_STYLES = {
|
|
|
1446
1485
|
transition: "opacity 300ms cubic-bezier(0.4, 0, 0.2, 1)"
|
|
1447
1486
|
}
|
|
1448
1487
|
};
|
|
1449
|
-
const FloatingButton = ({ bindtap, children }) => {
|
|
1488
|
+
const FloatingButton = ({ bindtap, children, initialPosition }) => {
|
|
1450
1489
|
const colors = useThemeColors();
|
|
1451
|
-
const { phase,
|
|
1490
|
+
const { phase, positionStyle, clearTimer, handlers } = useLongPressDrag(bindtap, { initialPosition });
|
|
1452
1491
|
const handleReload = () => {
|
|
1453
1492
|
try {
|
|
1454
1493
|
lynx.reload({}, () => {
|
|
@@ -1460,8 +1499,7 @@ const FloatingButton = ({ bindtap, children }) => {
|
|
|
1460
1499
|
};
|
|
1461
1500
|
const isDragging = phase === "dragging";
|
|
1462
1501
|
return <view className={"fb-wrapper"} consume-slide-event={[[-180, 180]]} style={{
|
|
1463
|
-
|
|
1464
|
-
bottom: `${bottom}px`,
|
|
1502
|
+
...positionStyle,
|
|
1465
1503
|
transform: isDragging ? "scale(1.05)" : "scale(1)",
|
|
1466
1504
|
transition: `transform ${duration.d4} cubic-bezier(0.4, 0, 0.2, 1)`
|
|
1467
1505
|
}} {...handlers}>
|
|
@@ -1479,7 +1517,7 @@ const FloatingButton = ({ bindtap, children }) => {
|
|
|
1479
1517
|
|
|
1480
1518
|
//#endregion
|
|
1481
1519
|
//#region src/index.tsx
|
|
1482
|
-
const LynxConsole = forwardRef(({ theme = "light", safeAreaInsetBottom = "50px", customTabs }, ref) => {
|
|
1520
|
+
const LynxConsole = forwardRef(({ theme = "light", safeAreaInsetBottom = "50px", customTabs, initialPosition }, ref) => {
|
|
1483
1521
|
const [isOpen, setIsOpen] = useState(false);
|
|
1484
1522
|
const [shouldClose, setShouldClose] = useState(false);
|
|
1485
1523
|
const { performances } = usePerformance();
|
|
@@ -1517,7 +1555,7 @@ const LynxConsole = forwardRef(({ theme = "light", safeAreaInsetBottom = "50px",
|
|
|
1517
1555
|
backgroundColor: colors.bg.layerDefault,
|
|
1518
1556
|
color: colors.fg.neutral
|
|
1519
1557
|
}}>
|
|
1520
|
-
<FloatingButton bindtap={handleOpenBottomSheet}>
|
|
1558
|
+
<FloatingButton bindtap={handleOpenBottomSheet} initialPosition={initialPosition}>
|
|
1521
1559
|
<text className="fb-title t4" style={{
|
|
1522
1560
|
fontWeight: "400",
|
|
1523
1561
|
color: colors.palette.staticWhite
|