@pictor-sdk/ui 0.2.1 → 0.3.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/dist/index.d.mts +38 -2
- package/dist/index.d.ts +38 -2
- package/dist/index.js +108 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +103 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/composer/TextComposer.tsx +64 -22
- package/src/composer/keyboardLayout.ts +83 -0
- package/src/gestures/LayerGestureSurface.tsx +54 -9
- package/src/index.ts +1 -1
- package/src/panels/layoutMath.ts +23 -0
package/dist/index.mjs
CHANGED
|
@@ -803,6 +803,7 @@ function LayerGestureSurface({ onSnap }) {
|
|
|
803
803
|
const focalY = useSharedValue3(0.5);
|
|
804
804
|
const pointers = useSharedValue3(0);
|
|
805
805
|
const active = useSharedValue3(false);
|
|
806
|
+
const livePointers = useSharedValue3(0);
|
|
806
807
|
const snapCX = useSharedValue3(false);
|
|
807
808
|
const snapCY = useSharedValue3(false);
|
|
808
809
|
const snapR = useSharedValue3(false);
|
|
@@ -977,7 +978,23 @@ function LayerGestureSurface({ onSnap }) {
|
|
|
977
978
|
deleted
|
|
978
979
|
);
|
|
979
980
|
};
|
|
980
|
-
const
|
|
981
|
+
const releaseIfEmpty = () => {
|
|
982
|
+
"worklet";
|
|
983
|
+
if (livePointers.value > 0) return;
|
|
984
|
+
endIfIdle();
|
|
985
|
+
};
|
|
986
|
+
const pan = Gesture4.Pan().minPointers(1).maxPointers(2).onTouchesDown((e) => {
|
|
987
|
+
"worklet";
|
|
988
|
+
livePointers.value = e.allTouches.length;
|
|
989
|
+
}).onTouchesUp((e) => {
|
|
990
|
+
"worklet";
|
|
991
|
+
livePointers.value = Math.max(0, e.allTouches.length - e.changedTouches.length);
|
|
992
|
+
releaseIfEmpty();
|
|
993
|
+
}).onTouchesCancelled(() => {
|
|
994
|
+
"worklet";
|
|
995
|
+
livePointers.value = 0;
|
|
996
|
+
releaseIfEmpty();
|
|
997
|
+
}).onBegin((e) => {
|
|
981
998
|
"worklet";
|
|
982
999
|
if (active.value) return;
|
|
983
1000
|
rawPanX.value = 0;
|
|
@@ -1024,7 +1041,7 @@ function LayerGestureSurface({ onSnap }) {
|
|
|
1024
1041
|
recompute(false);
|
|
1025
1042
|
}).onFinalize(() => {
|
|
1026
1043
|
"worklet";
|
|
1027
|
-
|
|
1044
|
+
releaseIfEmpty();
|
|
1028
1045
|
});
|
|
1029
1046
|
const pinch = Gesture4.Pinch().onUpdate((e) => {
|
|
1030
1047
|
"worklet";
|
|
@@ -1033,6 +1050,9 @@ function LayerGestureSurface({ onSnap }) {
|
|
|
1033
1050
|
focalY.value = e.focalY / metricsHeight;
|
|
1034
1051
|
syncPointers(e.numberOfPointers);
|
|
1035
1052
|
recompute(false);
|
|
1053
|
+
}).onFinalize(() => {
|
|
1054
|
+
"worklet";
|
|
1055
|
+
releaseIfEmpty();
|
|
1036
1056
|
});
|
|
1037
1057
|
const rotate = Gesture4.Rotation().enabled(config.rotationEnabled).onUpdate((e) => {
|
|
1038
1058
|
"worklet";
|
|
@@ -1041,6 +1061,9 @@ function LayerGestureSurface({ onSnap }) {
|
|
|
1041
1061
|
focalY.value = e.anchorY / metricsHeight;
|
|
1042
1062
|
syncPointers(e.numberOfPointers);
|
|
1043
1063
|
recompute(false);
|
|
1064
|
+
}).onFinalize(() => {
|
|
1065
|
+
"worklet";
|
|
1066
|
+
releaseIfEmpty();
|
|
1044
1067
|
});
|
|
1045
1068
|
const tap = Gesture4.Tap().onEnd((e) => {
|
|
1046
1069
|
"worklet";
|
|
@@ -2865,6 +2888,13 @@ function fitImageToLayoutCell(cell, documentSize, intrinsic, options = {}) {
|
|
|
2865
2888
|
function cellToTransformPatch(cell) {
|
|
2866
2889
|
return { x: cell.x, y: cell.y, scale: cell.scale, rotation: 0 };
|
|
2867
2890
|
}
|
|
2891
|
+
function layoutCellBox(cell, documentSize) {
|
|
2892
|
+
"worklet";
|
|
2893
|
+
return {
|
|
2894
|
+
width: cell.width * documentSize.width,
|
|
2895
|
+
height: cell.height * documentSize.height
|
|
2896
|
+
};
|
|
2897
|
+
}
|
|
2868
2898
|
|
|
2869
2899
|
// src/panels/LayoutPanel.tsx
|
|
2870
2900
|
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
@@ -3499,17 +3529,21 @@ import {
|
|
|
3499
3529
|
TextInput,
|
|
3500
3530
|
View as View18
|
|
3501
3531
|
} from "react-native";
|
|
3532
|
+
import { useRenderer as useRenderer4 } from "@pictor-sdk/skia";
|
|
3502
3533
|
|
|
3503
3534
|
// src/composer/keyboardLayout.ts
|
|
3504
3535
|
var HIDDEN_KEYBOARD = { height: 0 };
|
|
3505
3536
|
var MAX_DURATION = 400;
|
|
3506
3537
|
var FALLBACK_DURATION = 180;
|
|
3507
|
-
function composerInsets(frame, safeAreaBottom = 0) {
|
|
3538
|
+
function composerInsets(frame, safeAreaBottom = 0, safeAreaTop = 0) {
|
|
3508
3539
|
const height = Number.isFinite(frame.height) ? Math.max(0, frame.height) : 0;
|
|
3509
3540
|
const visible = height > 0;
|
|
3510
3541
|
const raw = frame.duration;
|
|
3511
3542
|
const duration = raw === void 0 || !Number.isFinite(raw) || raw <= 0 ? FALLBACK_DURATION : Math.min(MAX_DURATION, raw);
|
|
3512
3543
|
return {
|
|
3544
|
+
// The keyboard never covers the top, so this one is the safe area and
|
|
3545
|
+
// nothing else.
|
|
3546
|
+
top: Number.isFinite(safeAreaTop) ? Math.max(0, safeAreaTop) : 0,
|
|
3513
3547
|
bottom: visible ? height : Math.max(0, safeAreaBottom),
|
|
3514
3548
|
keyboardVisible: visible,
|
|
3515
3549
|
duration
|
|
@@ -3529,6 +3563,31 @@ function fitCanvasRect(container, document) {
|
|
|
3529
3563
|
top: (container.height - height) / 2
|
|
3530
3564
|
};
|
|
3531
3565
|
}
|
|
3566
|
+
function composerInputBox(request) {
|
|
3567
|
+
const canvas = fitCanvasRect(request.container, request.document);
|
|
3568
|
+
const fontSize = Math.max(1, request.fontSize * canvas.width);
|
|
3569
|
+
const lineHeight = Math.max(1, fontSize * request.lineHeight);
|
|
3570
|
+
const scale = request.document.width > 0 ? canvas.width / request.document.width : 0;
|
|
3571
|
+
const measuredHeight = request.measured && request.measured.height > 0 ? request.measured.height * scale : 0;
|
|
3572
|
+
const estimated = lineHeight * Math.max(1, request.lines);
|
|
3573
|
+
const height = Math.min(
|
|
3574
|
+
Math.max(lineHeight, measuredHeight > 0 ? measuredHeight : estimated),
|
|
3575
|
+
Math.max(lineHeight, canvas.height)
|
|
3576
|
+
);
|
|
3577
|
+
const centre = canvas.top + request.centerY * canvas.height;
|
|
3578
|
+
const top = Math.min(
|
|
3579
|
+
Math.max(0, centre - height / 2),
|
|
3580
|
+
Math.max(0, request.container.height - height)
|
|
3581
|
+
);
|
|
3582
|
+
return {
|
|
3583
|
+
left: canvas.left,
|
|
3584
|
+
width: Math.max(1, canvas.width),
|
|
3585
|
+
top,
|
|
3586
|
+
height: Math.max(1, height),
|
|
3587
|
+
fontSize,
|
|
3588
|
+
lineHeight
|
|
3589
|
+
};
|
|
3590
|
+
}
|
|
3532
3591
|
|
|
3533
3592
|
// src/composer/useTextSession.ts
|
|
3534
3593
|
import {
|
|
@@ -3676,26 +3735,45 @@ function TextComposer({ session, insets, onDone, onCancel }) {
|
|
|
3676
3735
|
const store = useEditorStore5();
|
|
3677
3736
|
const { document } = useEditor22();
|
|
3678
3737
|
const [container, setContainer] = useState10({ width: 0, height: 0 });
|
|
3738
|
+
const renderer = useRenderer4();
|
|
3679
3739
|
const input = useRef13(null);
|
|
3680
3740
|
const [selectionRange, setSelectionRange] = useState10(
|
|
3681
3741
|
void 0
|
|
3682
3742
|
);
|
|
3683
3743
|
const data = session.data;
|
|
3684
3744
|
const span = session.span;
|
|
3685
|
-
const
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3745
|
+
const layerId = session.layer?.id;
|
|
3746
|
+
const [measured, setMeasured] = useState10(null);
|
|
3747
|
+
useEffect8(() => {
|
|
3748
|
+
if (!layerId) {
|
|
3749
|
+
setMeasured(null);
|
|
3750
|
+
return;
|
|
3751
|
+
}
|
|
3752
|
+
const refresh = () => setMeasured(renderer.textMeasures.get(layerId) ?? null);
|
|
3753
|
+
const unsubscribe = renderer.textMeasures.subscribe(refresh);
|
|
3754
|
+
refresh();
|
|
3755
|
+
return unsubscribe;
|
|
3756
|
+
}, [renderer, layerId]);
|
|
3757
|
+
const layout = useMemo11(
|
|
3758
|
+
() => composerInputBox({
|
|
3759
|
+
container,
|
|
3760
|
+
document: document.size,
|
|
3761
|
+
fontSize: span?.fontSize ?? 0.08,
|
|
3762
|
+
lineHeight: span?.lineHeight ?? 1.2,
|
|
3763
|
+
centerY: session.layer?.transform.y ?? 0.42,
|
|
3764
|
+
measured,
|
|
3765
|
+
lines: session.value.split("\n").length
|
|
3766
|
+
}),
|
|
3767
|
+
[
|
|
3768
|
+
container,
|
|
3769
|
+
document.size,
|
|
3770
|
+
span?.fontSize,
|
|
3771
|
+
span?.lineHeight,
|
|
3772
|
+
session.layer?.transform.y,
|
|
3773
|
+
session.value,
|
|
3774
|
+
measured
|
|
3775
|
+
]
|
|
3776
|
+
);
|
|
3699
3777
|
const fonts = useMemo11(() => fontChoices(store.registry.fonts), [store.registry.fonts]);
|
|
3700
3778
|
useEffect8(() => {
|
|
3701
3779
|
const handle = setTimeout(() => input.current?.focus(), 50);
|
|
@@ -3834,7 +3912,7 @@ function TextComposer({ session, insets, onDone, onCancel }) {
|
|
|
3834
3912
|
position: "absolute",
|
|
3835
3913
|
left: 0,
|
|
3836
3914
|
right: 0,
|
|
3837
|
-
top:
|
|
3915
|
+
top: insets.top,
|
|
3838
3916
|
height: 56,
|
|
3839
3917
|
flexDirection: "row",
|
|
3840
3918
|
alignItems: "center",
|
|
@@ -4025,7 +4103,8 @@ function TextComposer({ session, insets, onDone, onCancel }) {
|
|
|
4025
4103
|
);
|
|
4026
4104
|
}
|
|
4027
4105
|
function TextComposerHost({
|
|
4028
|
-
Composer = TextComposer
|
|
4106
|
+
Composer = TextComposer,
|
|
4107
|
+
safeArea
|
|
4029
4108
|
}) {
|
|
4030
4109
|
const { setActiveTool } = useEditor22();
|
|
4031
4110
|
const session = useTextSession();
|
|
@@ -4054,7 +4133,10 @@ function TextComposerHost({
|
|
|
4054
4133
|
hide.remove();
|
|
4055
4134
|
};
|
|
4056
4135
|
}, []);
|
|
4057
|
-
const insets = useMemo11(
|
|
4136
|
+
const insets = useMemo11(
|
|
4137
|
+
() => composerInsets(frame, safeArea?.bottom ?? 0, safeArea?.top ?? 0),
|
|
4138
|
+
[frame, safeArea?.bottom, safeArea?.top]
|
|
4139
|
+
);
|
|
4058
4140
|
const finish = useCallback6(
|
|
4059
4141
|
(commit) => {
|
|
4060
4142
|
if (commit) session.commit();
|
|
@@ -4666,6 +4748,7 @@ export {
|
|
|
4666
4748
|
defaultTheme,
|
|
4667
4749
|
fitImageToLayoutCell,
|
|
4668
4750
|
layoutCellBounds,
|
|
4751
|
+
layoutCellBox,
|
|
4669
4752
|
layoutCells,
|
|
4670
4753
|
mergeSlots,
|
|
4671
4754
|
mergeTheme,
|