react-native-gtkx 0.1.0-alpha.4 → 0.2.0-alpha.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/README.md +22 -9
- package/dist/adw/index.d.ts +3 -0
- package/dist/adw/index.js +41 -0
- package/dist/adw/index.js.map +1 -0
- package/dist/adw/widgets.generated.d.ts +63 -0
- package/dist/adw/widgets.generated.js +125 -0
- package/dist/adw/widgets.generated.js.map +1 -0
- package/dist/animated/create-animated.d.ts +2 -0
- package/dist/animated/create-animated.js +2 -0
- package/dist/animated/create-animated.js.map +1 -1
- package/dist/animated/index.d.ts +2 -0
- package/dist/animated/index.js +1 -0
- package/dist/animated/index.js.map +1 -1
- package/dist/animated/value-xy.d.ts +41 -0
- package/dist/animated/value-xy.js +90 -0
- package/dist/animated/value-xy.js.map +1 -0
- package/dist/animated/value.d.ts +9 -0
- package/dist/animated/value.js +30 -2
- package/dist/animated/value.js.map +1 -1
- package/dist/common/content.d.ts +69 -0
- package/dist/common/content.js +84 -0
- package/dist/common/content.js.map +1 -0
- package/dist/common/icon.d.ts +23 -0
- package/dist/common/icon.js +14 -0
- package/dist/common/icon.js.map +1 -0
- package/dist/common/index.d.ts +5 -0
- package/dist/common/index.js +21 -0
- package/dist/common/index.js.map +1 -0
- package/dist/common/list.d.ts +82 -0
- package/dist/common/list.js +166 -0
- package/dist/common/list.js.map +1 -0
- package/dist/common/navigation-stack.d.ts +84 -0
- package/dist/common/navigation-stack.js +313 -0
- package/dist/common/navigation-stack.js.map +1 -0
- package/dist/common/widget.d.ts +62 -0
- package/dist/common/widget.js +209 -0
- package/dist/common/widget.js.map +1 -0
- package/dist/components/animated.d.ts +7 -4
- package/dist/components/animated.js +88 -67
- package/dist/components/animated.js.map +1 -1
- package/dist/components/app-registry.d.ts +36 -1
- package/dist/components/app-registry.js +8 -3
- package/dist/components/app-registry.js.map +1 -1
- package/dist/components/host-node.d.ts +7 -0
- package/dist/components/host-node.js +26 -1
- package/dist/components/host-node.js.map +1 -1
- package/dist/components/index.d.ts +6 -2
- package/dist/components/index.js +2 -1
- package/dist/components/index.js.map +1 -1
- package/dist/components/measure.d.ts +13 -0
- package/dist/components/measure.js +51 -0
- package/dist/components/measure.js.map +1 -0
- package/dist/components/modal.d.ts +1 -1
- package/dist/components/press-event.d.ts +28 -0
- package/dist/components/press-event.js +46 -0
- package/dist/components/press-event.js.map +1 -0
- package/dist/components/pressable.d.ts +2 -6
- package/dist/components/pressable.js +119 -20
- package/dist/components/pressable.js.map +1 -1
- package/dist/components/rect-store.d.ts +11 -1
- package/dist/components/rect-store.js +27 -3
- package/dist/components/rect-store.js.map +1 -1
- package/dist/components/scroll-view.d.ts +4 -0
- package/dist/components/scroll-view.js +8 -2
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/svg/animated-support.d.ts +19 -0
- package/dist/components/svg/animated-support.js +64 -0
- package/dist/components/svg/animated-support.js.map +1 -0
- package/dist/components/svg/context.d.ts +8 -0
- package/dist/components/svg/context.js +15 -0
- package/dist/components/svg/context.js.map +1 -0
- package/dist/components/svg/gradients.d.ts +31 -0
- package/dist/components/svg/gradients.js +93 -0
- package/dist/components/svg/gradients.js.map +1 -0
- package/dist/components/svg/group.d.ts +8 -0
- package/dist/components/svg/group.js +30 -0
- package/dist/components/svg/group.js.map +1 -0
- package/dist/components/svg/index.d.ts +6 -0
- package/dist/components/svg/index.js +5 -0
- package/dist/components/svg/index.js.map +1 -0
- package/dist/components/svg/node.d.ts +7 -0
- package/dist/components/svg/node.js +7 -0
- package/dist/components/svg/node.js.map +1 -0
- package/dist/components/svg/paint.d.ts +24 -0
- package/dist/components/svg/paint.js +57 -0
- package/dist/components/svg/paint.js.map +1 -0
- package/dist/components/svg/shapes.d.ts +47 -0
- package/dist/components/svg/shapes.js +51 -0
- package/dist/components/svg/shapes.js.map +1 -0
- package/dist/components/svg/svg.d.ts +14 -0
- package/dist/components/svg/svg.js +48 -0
- package/dist/components/svg/svg.js.map +1 -0
- package/dist/components/svg/use-shape-node.d.ts +12 -0
- package/dist/components/svg/use-shape-node.js +52 -0
- package/dist/components/svg/use-shape-node.js.map +1 -0
- package/dist/components/text-input.js +1 -1
- package/dist/components/text-input.js.map +1 -1
- package/dist/components/text.js +36 -3
- package/dist/components/text.js.map +1 -1
- package/dist/components/use-layout-child.js +50 -4
- package/dist/components/use-layout-child.js.map +1 -1
- package/dist/components/view.d.ts +9 -4
- package/dist/components/view.js +8 -2
- package/dist/components/view.js.map +1 -1
- package/dist/contracts.d.ts +31 -4
- package/dist/contracts.js.map +1 -1
- package/dist/gtk/index.d.ts +7 -0
- package/dist/gtk/index.js +46 -0
- package/dist/gtk/index.js.map +1 -0
- package/dist/gtk/widgets.generated.d.ts +103 -0
- package/dist/gtk/widgets.generated.js +205 -0
- package/dist/gtk/widgets.generated.js.map +1 -0
- package/dist/gtk/window-actions.d.ts +77 -0
- package/dist/gtk/window-actions.js +193 -0
- package/dist/gtk/window-actions.js.map +1 -0
- package/dist/gtkx/bridge/geometry.d.ts +15 -0
- package/dist/gtkx/bridge/geometry.js +38 -0
- package/dist/gtkx/bridge/geometry.js.map +1 -0
- package/dist/gtkx/bridge/index.d.ts +11 -4
- package/dist/gtkx/bridge/index.js +47 -6
- package/dist/gtkx/bridge/index.js.map +1 -1
- package/dist/gtkx/bridge/layout-manager.d.ts +2 -1
- package/dist/gtkx/bridge/layout-manager.js +31 -9
- package/dist/gtkx/bridge/layout-manager.js.map +1 -1
- package/dist/gtkx/bridge/slot-portal.d.ts +12 -0
- package/dist/gtkx/bridge/slot-portal.js +17 -0
- package/dist/gtkx/bridge/slot-portal.js.map +1 -0
- package/dist/gtkx/bridge/svg-node.d.ts +79 -0
- package/dist/gtkx/bridge/svg-node.js +323 -0
- package/dist/gtkx/bridge/svg-node.js.map +1 -0
- package/dist/gtkx/bridge/use-signal.js +19 -9
- package/dist/gtkx/bridge/use-signal.js.map +1 -1
- package/dist/gtkx/bridge/widgets.generated.d.ts +2 -0
- package/dist/gtkx/bridge/widgets.generated.js +14 -0
- package/dist/gtkx/bridge/widgets.generated.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/bin.d.ts +2 -0
- package/dist/mcp/bin.js +17 -0
- package/dist/mcp/bin.js.map +1 -0
- package/dist/mcp/data/generated.d.ts +1304 -0
- package/dist/mcp/data/generated.js +1179 -0
- package/dist/mcp/data/generated.js.map +1 -0
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.js +9 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/list.d.ts +4 -0
- package/dist/mcp/list.js +56 -0
- package/dist/mcp/list.js.map +1 -0
- package/dist/mcp/resolve.d.ts +55 -0
- package/dist/mcp/resolve.js +151 -0
- package/dist/mcp/resolve.js.map +1 -0
- package/dist/mcp/search.d.ts +13 -0
- package/dist/mcp/search.js +48 -0
- package/dist/mcp/search.js.map +1 -0
- package/dist/mcp/server.d.ts +7 -0
- package/dist/mcp/server.js +135 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tool.d.ts +21 -0
- package/dist/mcp/tool.js +36 -0
- package/dist/mcp/tool.js.map +1 -0
- package/dist/metro/index.js +10 -0
- package/dist/metro/index.js.map +1 -1
- package/dist/navigation/index.d.ts +50 -13
- package/dist/navigation/index.js +183 -148
- package/dist/navigation/index.js.map +1 -1
- package/dist/navigation/option-warnings.js +9 -1
- package/dist/navigation/option-warnings.js.map +1 -1
- package/dist/navigation/sidebar.d.ts +207 -9
- package/dist/navigation/sidebar.js +294 -10
- package/dist/navigation/sidebar.js.map +1 -1
- package/dist/responder/system.d.ts +27 -0
- package/dist/responder/system.js +184 -0
- package/dist/responder/system.js.map +1 -0
- package/dist/responder/touch-history.d.ts +10 -0
- package/dist/responder/touch-history.js +78 -0
- package/dist/responder/touch-history.js.map +1 -0
- package/dist/responder/types.d.ts +63 -0
- package/dist/responder/types.js +29 -0
- package/dist/responder/types.js.map +1 -0
- package/dist/responder/use-responder.d.ts +12 -0
- package/dist/responder/use-responder.js +98 -0
- package/dist/responder/use-responder.js.map +1 -0
- package/dist/runner/host-dev.js +3 -1
- package/dist/runner/host-dev.js.map +1 -1
- package/dist/runner/host.js +5 -1
- package/dist/runner/host.js.map +1 -1
- package/dist/runner/index.d.ts +22 -2
- package/dist/runner/index.js +163 -13
- package/dist/runner/index.js.map +1 -1
- package/dist/sea/assemble.d.ts +29 -0
- package/dist/sea/assemble.js +129 -0
- package/dist/sea/assemble.js.map +1 -0
- package/dist/sea/bundle.d.ts +61 -0
- package/dist/sea/bundle.js +202 -0
- package/dist/sea/bundle.js.map +1 -0
- package/dist/sea/gtkx-config-module.d.ts +18 -0
- package/dist/sea/gtkx-config-module.js +67 -0
- package/dist/sea/gtkx-config-module.js.map +1 -0
- package/dist/sea/native-shim.d.ts +40 -0
- package/dist/sea/native-shim.js +121 -0
- package/dist/sea/native-shim.js.map +1 -0
- package/dist/sea/react-anchor-plugin.d.ts +2 -0
- package/dist/sea/react-anchor-plugin.js +30 -0
- package/dist/sea/react-anchor-plugin.js.map +1 -0
- package/dist/style/box-shadow.d.ts +7 -0
- package/dist/style/box-shadow.js +197 -0
- package/dist/style/box-shadow.js.map +1 -0
- package/dist/style/index.d.ts +3 -0
- package/dist/style/index.js +3 -0
- package/dist/style/index.js.map +1 -1
- package/dist/style/split-style.d.ts +5 -2
- package/dist/style/split-style.js +33 -5
- package/dist/style/split-style.js.map +1 -1
- package/dist/style/text-decoration.d.ts +15 -0
- package/dist/style/text-decoration.js +26 -0
- package/dist/style/text-decoration.js.map +1 -0
- package/dist/style/transform.d.ts +22 -0
- package/dist/style/transform.js +137 -0
- package/dist/style/transform.js.map +1 -0
- package/dist/style/visual-css.js +40 -3
- package/dist/style/visual-css.js.map +1 -1
- package/dist/svg/geometry.d.ts +19 -0
- package/dist/svg/geometry.js +80 -0
- package/dist/svg/geometry.js.map +1 -0
- package/dist/svg/gradient-geometry.d.ts +15 -0
- package/dist/svg/gradient-geometry.js +15 -0
- package/dist/svg/gradient-geometry.js.map +1 -0
- package/dist/svg/transform.d.ts +22 -0
- package/dist/svg/transform.js +74 -0
- package/dist/svg/transform.js.map +1 -0
- package/dist/svg/view-box.d.ts +34 -0
- package/dist/svg/view-box.js +108 -0
- package/dist/svg/view-box.js.map +1 -0
- package/dist/svg-compat/index.d.ts +1 -0
- package/dist/svg-compat/index.js +16 -0
- package/dist/svg-compat/index.js.map +1 -0
- package/dist/testing/index.d.ts +14 -0
- package/dist/testing/index.js +14 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/vendor/react-native/pan-responder.d.ts +102 -0
- package/dist/vendor/react-native/pan-responder.js +196 -0
- package/dist/vendor/react-native/pan-responder.js.map +1 -0
- package/dist/vendor/react-native/touch-history-math.d.ts +18 -0
- package/dist/vendor/react-native/touch-history-math.js +102 -0
- package/dist/vendor/react-native/touch-history-math.js.map +1 -0
- package/dist/vite/index.d.ts +7 -3
- package/dist/vite/index.js +16 -4
- package/dist/vite/index.js.map +1 -1
- package/dist/vitest/index.d.ts +52 -0
- package/dist/vitest/index.js +58 -0
- package/dist/vitest/index.js.map +1 -0
- package/dist/vitest/setup.d.ts +4 -0
- package/dist/vitest/setup.js +22 -0
- package/dist/vitest/setup.js.map +1 -0
- package/package.json +52 -13
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Pure viewBox / preserveAspectRatio math (SVG 1.1 §7.11). No gtkx imports —
|
|
2
|
+
// the bridge feeds the result into Gtk.Snapshot.scale()/translate(), but the
|
|
3
|
+
// arithmetic itself has nothing to do with GTK and is fully unit-testable.
|
|
4
|
+
// "minX minY width height", comma or whitespace separated (SVG allows
|
|
5
|
+
// either). Returns null for anything that doesn't parse to exactly 4
|
|
6
|
+
// numbers or has a non-positive size — callers fall back to the identity
|
|
7
|
+
// transform, same as SVG does when viewBox is absent.
|
|
8
|
+
export const parseViewBox = (value) => {
|
|
9
|
+
if (!value) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const parts = value
|
|
13
|
+
.trim()
|
|
14
|
+
.split(/[\s,]+/)
|
|
15
|
+
.map(Number);
|
|
16
|
+
if (parts.length !== 4 || parts.some((n) => Number.isNaN(n))) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const [minX, minY, width, height] = parts;
|
|
20
|
+
if (width <= 0 || height <= 0) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return { minX, minY, width, height };
|
|
24
|
+
};
|
|
25
|
+
const ALIGN_PATTERN = /^x(Min|Mid|Max)Y(Min|Mid|Max)$/;
|
|
26
|
+
export const DEFAULT_PRESERVE_ASPECT_RATIO = {
|
|
27
|
+
align: { x: "mid", y: "mid" },
|
|
28
|
+
meetOrSlice: "meet",
|
|
29
|
+
};
|
|
30
|
+
// Tolerant like the transform-string parser: unrecognized tokens fall back
|
|
31
|
+
// to the SVG default (xMidYMid meet) rather than throwing.
|
|
32
|
+
export const parsePreserveAspectRatio = (value) => {
|
|
33
|
+
if (!value) {
|
|
34
|
+
return DEFAULT_PRESERVE_ASPECT_RATIO;
|
|
35
|
+
}
|
|
36
|
+
const tokens = value.trim().split(/\s+/);
|
|
37
|
+
const alignToken = tokens[0] ?? "";
|
|
38
|
+
const meetOrSlice = tokens[1] === "slice" ? "slice" : "meet";
|
|
39
|
+
if (alignToken === "none") {
|
|
40
|
+
return { align: "none", meetOrSlice };
|
|
41
|
+
}
|
|
42
|
+
const match = ALIGN_PATTERN.exec(alignToken);
|
|
43
|
+
if (!match) {
|
|
44
|
+
return DEFAULT_PRESERVE_ASPECT_RATIO;
|
|
45
|
+
}
|
|
46
|
+
const x = match[1].toLowerCase();
|
|
47
|
+
const y = match[2].toLowerCase();
|
|
48
|
+
return { align: { x, y }, meetOrSlice };
|
|
49
|
+
};
|
|
50
|
+
const IDENTITY = {
|
|
51
|
+
scaleX: 1,
|
|
52
|
+
scaleY: 1,
|
|
53
|
+
translateX: 0,
|
|
54
|
+
translateY: 0,
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Maps viewBox user-space coordinates onto a `viewportWidth` x
|
|
58
|
+
* `viewportHeight` box: `screen = user * scale + translate`. Mirrors the SVG
|
|
59
|
+
* algorithm exactly (see spec §7.11) — "none" stretches independently per
|
|
60
|
+
* axis, "meet" fits the whole viewBox inside the viewport (letterboxing),
|
|
61
|
+
* "slice" fills the viewport and overflows the viewBox (the bridge clips to
|
|
62
|
+
* the viewport bounds, same as a real SVG renderer).
|
|
63
|
+
*/
|
|
64
|
+
export const resolveViewBoxTransform = (viewBox, viewportWidth, viewportHeight, preserveAspectRatio = DEFAULT_PRESERVE_ASPECT_RATIO) => {
|
|
65
|
+
if (!viewBox || viewportWidth <= 0 || viewportHeight <= 0) {
|
|
66
|
+
return IDENTITY;
|
|
67
|
+
}
|
|
68
|
+
const rawScaleX = viewportWidth / viewBox.width;
|
|
69
|
+
const rawScaleY = viewportHeight / viewBox.height;
|
|
70
|
+
let scaleX;
|
|
71
|
+
let scaleY;
|
|
72
|
+
if (preserveAspectRatio.align === "none") {
|
|
73
|
+
scaleX = rawScaleX;
|
|
74
|
+
scaleY = rawScaleY;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const scale = preserveAspectRatio.meetOrSlice === "meet"
|
|
78
|
+
? Math.min(rawScaleX, rawScaleY)
|
|
79
|
+
: Math.max(rawScaleX, rawScaleY);
|
|
80
|
+
scaleX = scale;
|
|
81
|
+
scaleY = scale;
|
|
82
|
+
}
|
|
83
|
+
let alignOffsetX = 0;
|
|
84
|
+
let alignOffsetY = 0;
|
|
85
|
+
if (preserveAspectRatio.align !== "none") {
|
|
86
|
+
const extraX = viewportWidth - viewBox.width * scaleX;
|
|
87
|
+
const extraY = viewportHeight - viewBox.height * scaleY;
|
|
88
|
+
if (preserveAspectRatio.align.x === "mid") {
|
|
89
|
+
alignOffsetX = extraX / 2;
|
|
90
|
+
}
|
|
91
|
+
else if (preserveAspectRatio.align.x === "max") {
|
|
92
|
+
alignOffsetX = extraX;
|
|
93
|
+
}
|
|
94
|
+
if (preserveAspectRatio.align.y === "mid") {
|
|
95
|
+
alignOffsetY = extraY / 2;
|
|
96
|
+
}
|
|
97
|
+
else if (preserveAspectRatio.align.y === "max") {
|
|
98
|
+
alignOffsetY = extraY;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
scaleX,
|
|
103
|
+
scaleY,
|
|
104
|
+
translateX: alignOffsetX - viewBox.minX * scaleX,
|
|
105
|
+
translateY: alignOffsetY - viewBox.minY * scaleY,
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=view-box.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-box.js","sourceRoot":"","sources":["../../src/svg/view-box.ts"],"names":[],"mappings":"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","sourcesContent":["// Pure viewBox / preserveAspectRatio math (SVG 1.1 §7.11). No gtkx imports —\n// the bridge feeds the result into Gtk.Snapshot.scale()/translate(), but the\n// arithmetic itself has nothing to do with GTK and is fully unit-testable.\n\nexport type ViewBox = {\n minX: number\n minY: number\n width: number\n height: number\n}\n\n// \"minX minY width height\", comma or whitespace separated (SVG allows\n// either). Returns null for anything that doesn't parse to exactly 4\n// numbers or has a non-positive size — callers fall back to the identity\n// transform, same as SVG does when viewBox is absent.\nexport const parseViewBox = (value: string | undefined): ViewBox | null => {\n if (!value) {\n return null\n }\n const parts = value\n .trim()\n .split(/[\\s,]+/)\n .map(Number)\n if (parts.length !== 4 || parts.some((n) => Number.isNaN(n))) {\n return null\n }\n const [minX, minY, width, height] = parts as [number, number, number, number]\n if (width <= 0 || height <= 0) {\n return null\n }\n return { minX, minY, width, height }\n}\n\nexport type AlignX = \"min\" | \"mid\" | \"max\"\nexport type AlignY = \"min\" | \"mid\" | \"max\"\nexport type MeetOrSlice = \"meet\" | \"slice\"\n\nexport type PreserveAspectRatio = {\n align: \"none\" | { x: AlignX; y: AlignY }\n meetOrSlice: MeetOrSlice\n}\n\nconst ALIGN_PATTERN = /^x(Min|Mid|Max)Y(Min|Mid|Max)$/\n\nexport const DEFAULT_PRESERVE_ASPECT_RATIO: PreserveAspectRatio = {\n align: { x: \"mid\", y: \"mid\" },\n meetOrSlice: \"meet\",\n}\n\n// Tolerant like the transform-string parser: unrecognized tokens fall back\n// to the SVG default (xMidYMid meet) rather than throwing.\nexport const parsePreserveAspectRatio = (\n value: string | undefined,\n): PreserveAspectRatio => {\n if (!value) {\n return DEFAULT_PRESERVE_ASPECT_RATIO\n }\n const tokens = value.trim().split(/\\s+/)\n const alignToken = tokens[0] ?? \"\"\n const meetOrSlice: MeetOrSlice = tokens[1] === \"slice\" ? \"slice\" : \"meet\"\n if (alignToken === \"none\") {\n return { align: \"none\", meetOrSlice }\n }\n const match = ALIGN_PATTERN.exec(alignToken)\n if (!match) {\n return DEFAULT_PRESERVE_ASPECT_RATIO\n }\n const x = match[1]!.toLowerCase() as AlignX\n const y = match[2]!.toLowerCase() as AlignY\n return { align: { x, y }, meetOrSlice }\n}\n\nexport type ViewBoxTransform = {\n scaleX: number\n scaleY: number\n translateX: number\n translateY: number\n}\n\nconst IDENTITY: ViewBoxTransform = {\n scaleX: 1,\n scaleY: 1,\n translateX: 0,\n translateY: 0,\n}\n\n/**\n * Maps viewBox user-space coordinates onto a `viewportWidth` x\n * `viewportHeight` box: `screen = user * scale + translate`. Mirrors the SVG\n * algorithm exactly (see spec §7.11) — \"none\" stretches independently per\n * axis, \"meet\" fits the whole viewBox inside the viewport (letterboxing),\n * \"slice\" fills the viewport and overflows the viewBox (the bridge clips to\n * the viewport bounds, same as a real SVG renderer).\n */\nexport const resolveViewBoxTransform = (\n viewBox: ViewBox | null,\n viewportWidth: number,\n viewportHeight: number,\n preserveAspectRatio: PreserveAspectRatio = DEFAULT_PRESERVE_ASPECT_RATIO,\n): ViewBoxTransform => {\n if (!viewBox || viewportWidth <= 0 || viewportHeight <= 0) {\n return IDENTITY\n }\n const rawScaleX = viewportWidth / viewBox.width\n const rawScaleY = viewportHeight / viewBox.height\n\n let scaleX: number\n let scaleY: number\n if (preserveAspectRatio.align === \"none\") {\n scaleX = rawScaleX\n scaleY = rawScaleY\n } else {\n const scale =\n preserveAspectRatio.meetOrSlice === \"meet\"\n ? Math.min(rawScaleX, rawScaleY)\n : Math.max(rawScaleX, rawScaleY)\n scaleX = scale\n scaleY = scale\n }\n\n let alignOffsetX = 0\n let alignOffsetY = 0\n if (preserveAspectRatio.align !== \"none\") {\n const extraX = viewportWidth - viewBox.width * scaleX\n const extraY = viewportHeight - viewBox.height * scaleY\n if (preserveAspectRatio.align.x === \"mid\") {\n alignOffsetX = extraX / 2\n } else if (preserveAspectRatio.align.x === \"max\") {\n alignOffsetX = extraX\n }\n if (preserveAspectRatio.align.y === \"mid\") {\n alignOffsetY = extraY / 2\n } else if (preserveAspectRatio.align.y === \"max\") {\n alignOffsetY = extraY\n }\n }\n\n return {\n scaleX,\n scaleY,\n translateX: alignOffsetX - viewBox.minX * scaleX,\n translateY: alignOffsetY - viewBox.minY * scaleY,\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Circle, Defs, Ellipse, G, Line, LinearGradient, Path, Polygon, Polyline, RadialGradient, Rect, Stop, Svg, Svg as default, type AnimatableNumber, type CircleProps, type DefsProps, type EllipseProps, type GProps, type LinearGradientProps, type LineProps, type PathProps, type PolygonProps, type PolylineProps, type RadialGradientProps, type RectProps, type StopProps, type SvgFillRule, type SvgLineCap, type SvgLineJoin, type SvgProps, } from "../components/svg/index";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// react-native-svg compatibility subpath (by the same pattern as
|
|
2
|
+
// react-native-gtkx/navigation): re-exports our SVG component set in the
|
|
3
|
+
// shape portable code expects — `Svg` as both the default and a named
|
|
4
|
+
// export, everything else named — once an app aliases the bare
|
|
5
|
+
// react-native-svg package name to this subpath. See the alias the metro/
|
|
6
|
+
// vite presets add automatically (packages/react-native-gtkx/src/metro/
|
|
7
|
+
// index.ts, src/vite/index.ts), or a manual bundler alias for apps using
|
|
8
|
+
// neither. The upstream package itself is never a dependency of this one;
|
|
9
|
+
// nothing here imports it — this module only mirrors its export shape.
|
|
10
|
+
//
|
|
11
|
+
// Deliberate gaps against react-native-svg's full surface (see docs/api.md
|
|
12
|
+
// "Svg" for the complete list and the reasoning): no SvgXml/SvgUri (SVG
|
|
13
|
+
// files already load through Image, a different mechanism), no Text/
|
|
14
|
+
// TSpan/TextPath, no Mask/ClipPath/Filter/Marker/Symbol/Use/Pattern.
|
|
15
|
+
export { Circle, Defs, Ellipse, G, Line, LinearGradient, Path, Polygon, Polyline, RadialGradient, Rect, Stop, Svg, Svg as default, } from "../components/svg/index";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/svg-compat/index.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,yEAAyE;AACzE,sEAAsE;AACtE,+DAA+D;AAC/D,0EAA0E;AAC1E,wEAAwE;AACxE,yEAAyE;AACzE,0EAA0E;AAC1E,uEAAuE;AACvE,EAAE;AACF,2EAA2E;AAC3E,wEAAwE;AACxE,qEAAqE;AACrE,qEAAqE;AACrE,OAAO,EACL,MAAM,EACN,IAAI,EACJ,OAAO,EACP,CAAC,EACD,IAAI,EACJ,cAAc,EACd,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,cAAc,EACd,IAAI,EACJ,IAAI,EACJ,GAAG,EACH,GAAG,IAAI,OAAO,GAkBf,MAAM,yBAAyB,CAAA","sourcesContent":["// react-native-svg compatibility subpath (by the same pattern as\n// react-native-gtkx/navigation): re-exports our SVG component set in the\n// shape portable code expects — `Svg` as both the default and a named\n// export, everything else named — once an app aliases the bare\n// react-native-svg package name to this subpath. See the alias the metro/\n// vite presets add automatically (packages/react-native-gtkx/src/metro/\n// index.ts, src/vite/index.ts), or a manual bundler alias for apps using\n// neither. The upstream package itself is never a dependency of this one;\n// nothing here imports it — this module only mirrors its export shape.\n//\n// Deliberate gaps against react-native-svg's full surface (see docs/api.md\n// \"Svg\" for the complete list and the reasoning): no SvgXml/SvgUri (SVG\n// files already load through Image, a different mechanism), no Text/\n// TSpan/TextPath, no Mask/ClipPath/Filter/Marker/Symbol/Use/Pattern.\nexport {\n Circle,\n Defs,\n Ellipse,\n G,\n Line,\n LinearGradient,\n Path,\n Polygon,\n Polyline,\n RadialGradient,\n Rect,\n Stop,\n Svg,\n Svg as default,\n type AnimatableNumber,\n type CircleProps,\n type DefsProps,\n type EllipseProps,\n type GProps,\n type LinearGradientProps,\n type LineProps,\n type PathProps,\n type PolygonProps,\n type PolylineProps,\n type RadialGradientProps,\n type RectProps,\n type StopProps,\n type SvgFillRule,\n type SvgLineCap,\n type SvgLineJoin,\n type SvgProps,\n} from \"../components/svg/index\"\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RenderHookOptions, RenderHookResult, RenderResult } from "@gtkx/testing";
|
|
2
|
+
export * from "@gtkx/testing";
|
|
3
|
+
/**
|
|
4
|
+
* Like `renderHook`, but first creates and presents a harness window (via
|
|
5
|
+
* `render(null)`), so window-dependent hooks have a toplevel to read.
|
|
6
|
+
* Cleanup is automatic — @gtkx/testing tears down every active render
|
|
7
|
+
* (including the harness window) after each test.
|
|
8
|
+
*/
|
|
9
|
+
export declare function renderHookWithWindow<Result>(callback: () => Result, options?: RenderHookOptions<undefined>): Promise<RenderHookResult<Result, undefined> & {
|
|
10
|
+
window: RenderResult["container"];
|
|
11
|
+
}>;
|
|
12
|
+
export declare function renderHookWithWindow<Result, Props>(callback: (props: Props) => Result, options: RenderHookOptions<Props>): Promise<RenderHookResult<Result, Props> & {
|
|
13
|
+
window: RenderResult["container"];
|
|
14
|
+
}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { render, renderHook } from "@gtkx/testing";
|
|
2
|
+
// react-native-gtkx/testing — @gtkx/testing's queries, render, renderHook,
|
|
3
|
+
// fireEvent and userEvent already operate on the real GTK widget tree our
|
|
4
|
+
// RN components render into, so `getByText` on a `Text` or `userEvent.click`
|
|
5
|
+
// on a `Pressable` already work with no RN-flavoured wrapper: this subpath
|
|
6
|
+
// re-exports that surface as-is, one import source for a consumer, plus the
|
|
7
|
+
// one genuinely repeated workaround (see below).
|
|
8
|
+
export * from "@gtkx/testing";
|
|
9
|
+
export async function renderHookWithWindow(callback, options) {
|
|
10
|
+
const { container: window } = await render(null);
|
|
11
|
+
const hook = await renderHook(callback, options);
|
|
12
|
+
return { ...hook, window };
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAOlD,2EAA2E;AAC3E,0EAA0E;AAC1E,6EAA6E;AAC7E,2EAA2E;AAC3E,4EAA4E;AAC5E,iDAAiD;AACjD,cAAc,eAAe,CAAA;AA2B7B,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,QAAmC,EACnC,OAAkC;IAIlC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;IAChD,MAAM,IAAI,GAAG,MAAM,UAAU,CAC3B,QAAoC,EACpC,OAAmC,CACpC,CAAA;IACD,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAA;AAC5B,CAAC","sourcesContent":["import { render, renderHook } from \"@gtkx/testing\"\nimport type {\n RenderHookOptions,\n RenderHookResult,\n RenderResult,\n} from \"@gtkx/testing\"\n\n// react-native-gtkx/testing — @gtkx/testing's queries, render, renderHook,\n// fireEvent and userEvent already operate on the real GTK widget tree our\n// RN components render into, so `getByText` on a `Text` or `userEvent.click`\n// on a `Pressable` already work with no RN-flavoured wrapper: this subpath\n// re-exports that surface as-is, one import source for a consumer, plus the\n// one genuinely repeated workaround (see below).\nexport * from \"@gtkx/testing\"\n\n// RC3-WORKAROUND(renderhook-no-window): see docs/gtkx-rc3-notes.md\n// @gtkx/testing's renderHook() always mounts its test component into a bare\n// Gtk.Box, so a hook that reads the active toplevel (useWindowDimensions,\n// anything through Gtk.Window.getToplevels()) has nothing to read. render()\n// always creates and presents a harness window when no container is given,\n// regardless of what it renders — rendering null is enough to get one.\n\n/**\n * Like `renderHook`, but first creates and presents a harness window (via\n * `render(null)`), so window-dependent hooks have a toplevel to read.\n * Cleanup is automatic — @gtkx/testing tears down every active render\n * (including the harness window) after each test.\n */\nexport function renderHookWithWindow<Result>(\n callback: () => Result,\n options?: RenderHookOptions<undefined>,\n): Promise<\n RenderHookResult<Result, undefined> & { window: RenderResult[\"container\"] }\n>\nexport function renderHookWithWindow<Result, Props>(\n callback: (props: Props) => Result,\n options: RenderHookOptions<Props>,\n): Promise<\n RenderHookResult<Result, Props> & { window: RenderResult[\"container\"] }\n>\nexport async function renderHookWithWindow<Result, Props>(\n callback: (props?: Props) => Result,\n options?: RenderHookOptions<Props>,\n): Promise<\n RenderHookResult<Result, Props> & { window: RenderResult[\"container\"] }\n> {\n const { container: window } = await render(null)\n const hook = await renderHook(\n callback as (props: Props) => Result,\n options as RenderHookOptions<Props>,\n )\n return { ...hook, window }\n}\n"]}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { GestureResponderEvent } from "../../responder/types";
|
|
8
|
+
export type PanResponderGestureState = {
|
|
9
|
+
/** ID of the gestureState - persisted as long as there's a touch on screen */
|
|
10
|
+
stateID: number;
|
|
11
|
+
/** the latest screen coordinates of the recently-moved touch */
|
|
12
|
+
moveX: number;
|
|
13
|
+
/** the latest screen coordinates of the recently-moved touch */
|
|
14
|
+
moveY: number;
|
|
15
|
+
/** the screen coordinates of the responder grant */
|
|
16
|
+
x0: number;
|
|
17
|
+
/** the screen coordinates of the responder grant */
|
|
18
|
+
y0: number;
|
|
19
|
+
/** accumulated distance of the gesture since the touch started */
|
|
20
|
+
dx: number;
|
|
21
|
+
/** accumulated distance of the gesture since the touch started */
|
|
22
|
+
dy: number;
|
|
23
|
+
/** current velocity of the gesture */
|
|
24
|
+
vx: number;
|
|
25
|
+
/** current velocity of the gesture */
|
|
26
|
+
vy: number;
|
|
27
|
+
/** Number of touches currently on screen */
|
|
28
|
+
numberActiveTouches: number;
|
|
29
|
+
/** All `gestureState` accounts for timeStamps up until this value */
|
|
30
|
+
_accountsForMovesUpTo: number;
|
|
31
|
+
};
|
|
32
|
+
type ActiveCallback = (event: GestureResponderEvent, gestureState: PanResponderGestureState) => boolean;
|
|
33
|
+
type PassiveCallback = (event: GestureResponderEvent, gestureState: PanResponderGestureState) => unknown;
|
|
34
|
+
export type GestureResponderHandlerMethods = {
|
|
35
|
+
onMoveShouldSetResponder: (event: GestureResponderEvent) => boolean;
|
|
36
|
+
onMoveShouldSetResponderCapture: (event: GestureResponderEvent) => boolean;
|
|
37
|
+
onResponderEnd: (event: GestureResponderEvent) => void;
|
|
38
|
+
onResponderGrant: (event: GestureResponderEvent) => boolean;
|
|
39
|
+
onResponderMove: (event: GestureResponderEvent) => void;
|
|
40
|
+
onResponderReject: (event: GestureResponderEvent) => void;
|
|
41
|
+
onResponderRelease: (event: GestureResponderEvent) => void;
|
|
42
|
+
onResponderStart: (event: GestureResponderEvent) => void;
|
|
43
|
+
onResponderTerminate: (event: GestureResponderEvent) => void;
|
|
44
|
+
onResponderTerminationRequest: (event: GestureResponderEvent) => boolean;
|
|
45
|
+
onStartShouldSetResponder: (event: GestureResponderEvent) => boolean;
|
|
46
|
+
onStartShouldSetResponderCapture: (event: GestureResponderEvent) => boolean;
|
|
47
|
+
};
|
|
48
|
+
export type PanResponderCallbacks = Readonly<{
|
|
49
|
+
onMoveShouldSetPanResponder?: ActiveCallback;
|
|
50
|
+
onMoveShouldSetPanResponderCapture?: ActiveCallback;
|
|
51
|
+
onStartShouldSetPanResponder?: ActiveCallback;
|
|
52
|
+
onStartShouldSetPanResponderCapture?: ActiveCallback;
|
|
53
|
+
onPanResponderGrant?: PassiveCallback;
|
|
54
|
+
onPanResponderMove?: PassiveCallback;
|
|
55
|
+
onPanResponderRelease?: PassiveCallback;
|
|
56
|
+
onPanResponderTerminate?: PassiveCallback;
|
|
57
|
+
onPanResponderReject?: PassiveCallback;
|
|
58
|
+
onPanResponderStart?: PassiveCallback;
|
|
59
|
+
onPanResponderEnd?: PassiveCallback;
|
|
60
|
+
onPanResponderTerminationRequest?: ActiveCallback;
|
|
61
|
+
onShouldBlockNativeResponder?: ActiveCallback;
|
|
62
|
+
}>;
|
|
63
|
+
declare const PanResponder: {
|
|
64
|
+
_initializeGestureState(gestureState: PanResponderGestureState): void;
|
|
65
|
+
/**
|
|
66
|
+
* This is nuanced and is necessary. It is incorrect to continuously take all
|
|
67
|
+
* active *and* recently moved touches, find the centroid, and track how that
|
|
68
|
+
* result changes over time. Instead, we must take all recently moved
|
|
69
|
+
* touches, and calculate how the centroid has changed just for those
|
|
70
|
+
* recently moved touches, and append that change to an accumulator. This is
|
|
71
|
+
* to (at least) handle the case where the user is moving three fingers, and
|
|
72
|
+
* then one of the fingers stops but the other two continue.
|
|
73
|
+
*
|
|
74
|
+
* This is very different than taking all of the recently moved touches and
|
|
75
|
+
* storing their centroid as `dx/dy`. For correctness, we must *accumulate
|
|
76
|
+
* changes* in the centroid of recently moved touches.
|
|
77
|
+
*
|
|
78
|
+
* There is also some nuance with how we handle multiple moved touches in a
|
|
79
|
+
* single event. With the way `ReactNativeEventEmitter` dispatches touches as
|
|
80
|
+
* individual events, multiple touches generate two 'move' events, each of
|
|
81
|
+
* them triggering `onResponderMove`. But with the way `PanResponder` works,
|
|
82
|
+
* all of the gesture inference is performed on the first dispatch, since it
|
|
83
|
+
* looks at all of the touches (even the ones for which there hasn't been a
|
|
84
|
+
* native dispatch yet). Therefore, `PanResponder` does not call
|
|
85
|
+
* `onResponderMove` passed the first dispatch. This diverges from the
|
|
86
|
+
* typical responder callback pattern (without using `PanResponder`), but
|
|
87
|
+
* avoids more dispatches than necessary.
|
|
88
|
+
*/
|
|
89
|
+
_updateGestureStateOnMove(gestureState: PanResponderGestureState, touchHistory: GestureResponderEvent["touchHistory"]): void;
|
|
90
|
+
/**
|
|
91
|
+
* @param config Enhanced versions of all of the responder callbacks that
|
|
92
|
+
* provide not only the typical `ResponderSyntheticEvent`, but also the
|
|
93
|
+
* `PanResponder` gesture state. Simply replace the word `Responder` with
|
|
94
|
+
* `PanResponder` in each of the typical `onResponder*` callbacks.
|
|
95
|
+
*/
|
|
96
|
+
create(config: PanResponderCallbacks): {
|
|
97
|
+
getInteractionHandle: () => number | null;
|
|
98
|
+
panHandlers: GestureResponderHandlerMethods;
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
export type PanResponderInstance = ReturnType<(typeof PanResponder)["create"]>;
|
|
102
|
+
export default PanResponder;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import TouchHistoryMath from "./touch-history-math";
|
|
8
|
+
const currentCentroidXOfTouchesChangedAfter = TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
|
|
9
|
+
const currentCentroidYOfTouchesChangedAfter = TouchHistoryMath.currentCentroidYOfTouchesChangedAfter;
|
|
10
|
+
const previousCentroidXOfTouchesChangedAfter = TouchHistoryMath.previousCentroidXOfTouchesChangedAfter;
|
|
11
|
+
const previousCentroidYOfTouchesChangedAfter = TouchHistoryMath.previousCentroidYOfTouchesChangedAfter;
|
|
12
|
+
const currentCentroidX = TouchHistoryMath.currentCentroidX;
|
|
13
|
+
const currentCentroidY = TouchHistoryMath.currentCentroidY;
|
|
14
|
+
const PanResponder = {
|
|
15
|
+
_initializeGestureState(gestureState) {
|
|
16
|
+
gestureState.moveX = 0;
|
|
17
|
+
gestureState.moveY = 0;
|
|
18
|
+
gestureState.x0 = 0;
|
|
19
|
+
gestureState.y0 = 0;
|
|
20
|
+
gestureState.dx = 0;
|
|
21
|
+
gestureState.dy = 0;
|
|
22
|
+
gestureState.vx = 0;
|
|
23
|
+
gestureState.vy = 0;
|
|
24
|
+
gestureState.numberActiveTouches = 0;
|
|
25
|
+
// All `gestureState` accounts for timeStamps up until:
|
|
26
|
+
gestureState._accountsForMovesUpTo = 0;
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* This is nuanced and is necessary. It is incorrect to continuously take all
|
|
30
|
+
* active *and* recently moved touches, find the centroid, and track how that
|
|
31
|
+
* result changes over time. Instead, we must take all recently moved
|
|
32
|
+
* touches, and calculate how the centroid has changed just for those
|
|
33
|
+
* recently moved touches, and append that change to an accumulator. This is
|
|
34
|
+
* to (at least) handle the case where the user is moving three fingers, and
|
|
35
|
+
* then one of the fingers stops but the other two continue.
|
|
36
|
+
*
|
|
37
|
+
* This is very different than taking all of the recently moved touches and
|
|
38
|
+
* storing their centroid as `dx/dy`. For correctness, we must *accumulate
|
|
39
|
+
* changes* in the centroid of recently moved touches.
|
|
40
|
+
*
|
|
41
|
+
* There is also some nuance with how we handle multiple moved touches in a
|
|
42
|
+
* single event. With the way `ReactNativeEventEmitter` dispatches touches as
|
|
43
|
+
* individual events, multiple touches generate two 'move' events, each of
|
|
44
|
+
* them triggering `onResponderMove`. But with the way `PanResponder` works,
|
|
45
|
+
* all of the gesture inference is performed on the first dispatch, since it
|
|
46
|
+
* looks at all of the touches (even the ones for which there hasn't been a
|
|
47
|
+
* native dispatch yet). Therefore, `PanResponder` does not call
|
|
48
|
+
* `onResponderMove` passed the first dispatch. This diverges from the
|
|
49
|
+
* typical responder callback pattern (without using `PanResponder`), but
|
|
50
|
+
* avoids more dispatches than necessary.
|
|
51
|
+
*/
|
|
52
|
+
_updateGestureStateOnMove(gestureState, touchHistory) {
|
|
53
|
+
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
|
54
|
+
gestureState.moveX = currentCentroidXOfTouchesChangedAfter(touchHistory, gestureState._accountsForMovesUpTo);
|
|
55
|
+
gestureState.moveY = currentCentroidYOfTouchesChangedAfter(touchHistory, gestureState._accountsForMovesUpTo);
|
|
56
|
+
const movedAfter = gestureState._accountsForMovesUpTo;
|
|
57
|
+
const prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
|
58
|
+
const x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
|
59
|
+
const prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
|
60
|
+
const y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
|
61
|
+
const nextDX = gestureState.dx + (x - prevX);
|
|
62
|
+
const nextDY = gestureState.dy + (y - prevY);
|
|
63
|
+
// TODO: This must be filtered intelligently.
|
|
64
|
+
const dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
|
|
65
|
+
gestureState.vx = (nextDX - gestureState.dx) / dt;
|
|
66
|
+
gestureState.vy = (nextDY - gestureState.dy) / dt;
|
|
67
|
+
gestureState.dx = nextDX;
|
|
68
|
+
gestureState.dy = nextDY;
|
|
69
|
+
gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp;
|
|
70
|
+
},
|
|
71
|
+
/**
|
|
72
|
+
* @param config Enhanced versions of all of the responder callbacks that
|
|
73
|
+
* provide not only the typical `ResponderSyntheticEvent`, but also the
|
|
74
|
+
* `PanResponder` gesture state. Simply replace the word `Responder` with
|
|
75
|
+
* `PanResponder` in each of the typical `onResponder*` callbacks.
|
|
76
|
+
*/
|
|
77
|
+
create(config) {
|
|
78
|
+
const gestureState = {
|
|
79
|
+
// Useful for debugging
|
|
80
|
+
stateID: Math.random(),
|
|
81
|
+
moveX: 0,
|
|
82
|
+
moveY: 0,
|
|
83
|
+
x0: 0,
|
|
84
|
+
y0: 0,
|
|
85
|
+
dx: 0,
|
|
86
|
+
dy: 0,
|
|
87
|
+
vx: 0,
|
|
88
|
+
vy: 0,
|
|
89
|
+
numberActiveTouches: 0,
|
|
90
|
+
_accountsForMovesUpTo: 0,
|
|
91
|
+
};
|
|
92
|
+
const panHandlers = {
|
|
93
|
+
onStartShouldSetResponder(event) {
|
|
94
|
+
return config.onStartShouldSetPanResponder == null
|
|
95
|
+
? false
|
|
96
|
+
: config.onStartShouldSetPanResponder(event, gestureState);
|
|
97
|
+
},
|
|
98
|
+
onMoveShouldSetResponder(event) {
|
|
99
|
+
return config.onMoveShouldSetPanResponder == null
|
|
100
|
+
? false
|
|
101
|
+
: config.onMoveShouldSetPanResponder(event, gestureState);
|
|
102
|
+
},
|
|
103
|
+
onStartShouldSetResponderCapture(event) {
|
|
104
|
+
// TODO: Actually, we should reinitialize the state any time
|
|
105
|
+
// touches.length increases from 0 active to > 0 active.
|
|
106
|
+
if (event.nativeEvent.touches.length === 1) {
|
|
107
|
+
PanResponder._initializeGestureState(gestureState);
|
|
108
|
+
}
|
|
109
|
+
gestureState.numberActiveTouches =
|
|
110
|
+
event.touchHistory.numberActiveTouches;
|
|
111
|
+
return config.onStartShouldSetPanResponderCapture != null
|
|
112
|
+
? config.onStartShouldSetPanResponderCapture(event, gestureState)
|
|
113
|
+
: false;
|
|
114
|
+
},
|
|
115
|
+
onMoveShouldSetResponderCapture(event) {
|
|
116
|
+
const touchHistory = event.touchHistory;
|
|
117
|
+
// Responder system incorrectly dispatches should* to current responder
|
|
118
|
+
// Filter out any touch moves past the first one - we would have
|
|
119
|
+
// already processed multi-touch geometry during the first event.
|
|
120
|
+
if (gestureState._accountsForMovesUpTo ===
|
|
121
|
+
touchHistory.mostRecentTimeStamp) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
|
|
125
|
+
return config.onMoveShouldSetPanResponderCapture
|
|
126
|
+
? config.onMoveShouldSetPanResponderCapture(event, gestureState)
|
|
127
|
+
: false;
|
|
128
|
+
},
|
|
129
|
+
onResponderGrant(event) {
|
|
130
|
+
gestureState.x0 = currentCentroidX(event.touchHistory);
|
|
131
|
+
gestureState.y0 = currentCentroidY(event.touchHistory);
|
|
132
|
+
gestureState.dx = 0;
|
|
133
|
+
gestureState.dy = 0;
|
|
134
|
+
if (config.onPanResponderGrant) {
|
|
135
|
+
config.onPanResponderGrant(event, gestureState);
|
|
136
|
+
}
|
|
137
|
+
// TODO: t7467124 investigate if this can be removed
|
|
138
|
+
return config.onShouldBlockNativeResponder == null
|
|
139
|
+
? true
|
|
140
|
+
: config.onShouldBlockNativeResponder(event, gestureState);
|
|
141
|
+
},
|
|
142
|
+
onResponderReject(event) {
|
|
143
|
+
config.onPanResponderReject?.call(undefined, event, gestureState);
|
|
144
|
+
},
|
|
145
|
+
onResponderRelease(event) {
|
|
146
|
+
config.onPanResponderRelease?.call(undefined, event, gestureState);
|
|
147
|
+
PanResponder._initializeGestureState(gestureState);
|
|
148
|
+
},
|
|
149
|
+
onResponderStart(event) {
|
|
150
|
+
const touchHistory = event.touchHistory;
|
|
151
|
+
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
|
152
|
+
if (config.onPanResponderStart) {
|
|
153
|
+
config.onPanResponderStart(event, gestureState);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
onResponderMove(event) {
|
|
157
|
+
const touchHistory = event.touchHistory;
|
|
158
|
+
// Guard against the dispatch of two touch moves when there are two
|
|
159
|
+
// simultaneously changed touches.
|
|
160
|
+
if (gestureState._accountsForMovesUpTo ===
|
|
161
|
+
touchHistory.mostRecentTimeStamp) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Filter out any touch moves past the first one - we would have
|
|
165
|
+
// already processed multi-touch geometry during the first event.
|
|
166
|
+
PanResponder._updateGestureStateOnMove(gestureState, touchHistory);
|
|
167
|
+
if (config.onPanResponderMove) {
|
|
168
|
+
config.onPanResponderMove(event, gestureState);
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
onResponderEnd(event) {
|
|
172
|
+
const touchHistory = event.touchHistory;
|
|
173
|
+
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
|
174
|
+
config.onPanResponderEnd?.call(undefined, event, gestureState);
|
|
175
|
+
},
|
|
176
|
+
onResponderTerminate(event) {
|
|
177
|
+
config.onPanResponderTerminate?.call(undefined, event, gestureState);
|
|
178
|
+
PanResponder._initializeGestureState(gestureState);
|
|
179
|
+
},
|
|
180
|
+
onResponderTerminationRequest(event) {
|
|
181
|
+
return config.onPanResponderTerminationRequest == null
|
|
182
|
+
? true
|
|
183
|
+
: config.onPanResponderTerminationRequest(event, gestureState);
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
return {
|
|
187
|
+
panHandlers,
|
|
188
|
+
getInteractionHandle() {
|
|
189
|
+
// TODO: Deprecate and delete this method.
|
|
190
|
+
return null;
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
export default PanResponder;
|
|
196
|
+
//# sourceMappingURL=pan-responder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pan-responder.js","sourceRoot":"","sources":["../../../src/vendor/react-native/pan-responder.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n// VENDORED from react-native (MIT), Libraries/Interaction/PanResponder.js.\n//\n// react-native-web re-exports Meta's file directly and it works untouched,\n// because RNW reproduces the touchHistory structure PanResponder expects. We\n// reproduce the same structure (src/responder/touch-history.ts), so the\n// algorithm below is upstream's, unmodified in substance.\n//\n// We cannot re-export it the way RNW does: upstream ships Flow, and this\n// package is one tsc emit. So it is transliterated, and ONLY transliterated:\n// - Flow annotations to TypeScript (`?number` to `number | null`,\n// inexact object types to plain ones, `Readonly<{}>` kept as-is);\n// - `GestureResponderEvent` imported from our responder types instead of\n// RN's CoreEventTypes;\n// - `require` to `import`.\n//\n// The logic is deliberately untouched, comments included — especially the\n// clustered multi-touch accumulation in _updateGestureStateOnMove, which is\n// the part with no obvious specification and the reason vendoring beats\n// reimplementing.\nimport type { GestureResponderEvent } from \"../../responder/types\"\nimport TouchHistoryMath from \"./touch-history-math\"\n\nconst currentCentroidXOfTouchesChangedAfter =\n TouchHistoryMath.currentCentroidXOfTouchesChangedAfter\nconst currentCentroidYOfTouchesChangedAfter =\n TouchHistoryMath.currentCentroidYOfTouchesChangedAfter\nconst previousCentroidXOfTouchesChangedAfter =\n TouchHistoryMath.previousCentroidXOfTouchesChangedAfter\nconst previousCentroidYOfTouchesChangedAfter =\n TouchHistoryMath.previousCentroidYOfTouchesChangedAfter\nconst currentCentroidX = TouchHistoryMath.currentCentroidX\nconst currentCentroidY = TouchHistoryMath.currentCentroidY\n\nexport type PanResponderGestureState = {\n /** ID of the gestureState - persisted as long as there's a touch on screen */\n stateID: number\n /** the latest screen coordinates of the recently-moved touch */\n moveX: number\n /** the latest screen coordinates of the recently-moved touch */\n moveY: number\n /** the screen coordinates of the responder grant */\n x0: number\n /** the screen coordinates of the responder grant */\n y0: number\n /** accumulated distance of the gesture since the touch started */\n dx: number\n /** accumulated distance of the gesture since the touch started */\n dy: number\n /** current velocity of the gesture */\n vx: number\n /** current velocity of the gesture */\n vy: number\n /** Number of touches currently on screen */\n numberActiveTouches: number\n /** All `gestureState` accounts for timeStamps up until this value */\n _accountsForMovesUpTo: number\n}\n\ntype ActiveCallback = (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n) => boolean\n\ntype PassiveCallback = (\n event: GestureResponderEvent,\n gestureState: PanResponderGestureState,\n) => unknown\n\nexport type GestureResponderHandlerMethods = {\n onMoveShouldSetResponder: (event: GestureResponderEvent) => boolean\n onMoveShouldSetResponderCapture: (event: GestureResponderEvent) => boolean\n onResponderEnd: (event: GestureResponderEvent) => void\n onResponderGrant: (event: GestureResponderEvent) => boolean\n onResponderMove: (event: GestureResponderEvent) => void\n onResponderReject: (event: GestureResponderEvent) => void\n onResponderRelease: (event: GestureResponderEvent) => void\n onResponderStart: (event: GestureResponderEvent) => void\n onResponderTerminate: (event: GestureResponderEvent) => void\n onResponderTerminationRequest: (event: GestureResponderEvent) => boolean\n onStartShouldSetResponder: (event: GestureResponderEvent) => boolean\n onStartShouldSetResponderCapture: (event: GestureResponderEvent) => boolean\n}\n\nexport type PanResponderCallbacks = Readonly<{\n onMoveShouldSetPanResponder?: ActiveCallback\n onMoveShouldSetPanResponderCapture?: ActiveCallback\n onStartShouldSetPanResponder?: ActiveCallback\n onStartShouldSetPanResponderCapture?: ActiveCallback\n onPanResponderGrant?: PassiveCallback\n onPanResponderMove?: PassiveCallback\n onPanResponderRelease?: PassiveCallback\n onPanResponderTerminate?: PassiveCallback\n onPanResponderReject?: PassiveCallback\n onPanResponderStart?: PassiveCallback\n onPanResponderEnd?: PassiveCallback\n onPanResponderTerminationRequest?: ActiveCallback\n onShouldBlockNativeResponder?: ActiveCallback\n}>\n\nconst PanResponder = {\n _initializeGestureState(gestureState: PanResponderGestureState): void {\n gestureState.moveX = 0\n gestureState.moveY = 0\n gestureState.x0 = 0\n gestureState.y0 = 0\n gestureState.dx = 0\n gestureState.dy = 0\n gestureState.vx = 0\n gestureState.vy = 0\n gestureState.numberActiveTouches = 0\n // All `gestureState` accounts for timeStamps up until:\n gestureState._accountsForMovesUpTo = 0\n },\n\n /**\n * This is nuanced and is necessary. It is incorrect to continuously take all\n * active *and* recently moved touches, find the centroid, and track how that\n * result changes over time. Instead, we must take all recently moved\n * touches, and calculate how the centroid has changed just for those\n * recently moved touches, and append that change to an accumulator. This is\n * to (at least) handle the case where the user is moving three fingers, and\n * then one of the fingers stops but the other two continue.\n *\n * This is very different than taking all of the recently moved touches and\n * storing their centroid as `dx/dy`. For correctness, we must *accumulate\n * changes* in the centroid of recently moved touches.\n *\n * There is also some nuance with how we handle multiple moved touches in a\n * single event. With the way `ReactNativeEventEmitter` dispatches touches as\n * individual events, multiple touches generate two 'move' events, each of\n * them triggering `onResponderMove`. But with the way `PanResponder` works,\n * all of the gesture inference is performed on the first dispatch, since it\n * looks at all of the touches (even the ones for which there hasn't been a\n * native dispatch yet). Therefore, `PanResponder` does not call\n * `onResponderMove` passed the first dispatch. This diverges from the\n * typical responder callback pattern (without using `PanResponder`), but\n * avoids more dispatches than necessary.\n */\n _updateGestureStateOnMove(\n gestureState: PanResponderGestureState,\n touchHistory: GestureResponderEvent[\"touchHistory\"],\n ): void {\n gestureState.numberActiveTouches = touchHistory.numberActiveTouches\n gestureState.moveX = currentCentroidXOfTouchesChangedAfter(\n touchHistory,\n gestureState._accountsForMovesUpTo,\n )\n gestureState.moveY = currentCentroidYOfTouchesChangedAfter(\n touchHistory,\n gestureState._accountsForMovesUpTo,\n )\n const movedAfter = gestureState._accountsForMovesUpTo\n const prevX = previousCentroidXOfTouchesChangedAfter(\n touchHistory,\n movedAfter,\n )\n const x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter)\n const prevY = previousCentroidYOfTouchesChangedAfter(\n touchHistory,\n movedAfter,\n )\n const y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter)\n const nextDX = gestureState.dx + (x - prevX)\n const nextDY = gestureState.dy + (y - prevY)\n\n // TODO: This must be filtered intelligently.\n const dt =\n touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo\n gestureState.vx = (nextDX - gestureState.dx) / dt\n gestureState.vy = (nextDY - gestureState.dy) / dt\n\n gestureState.dx = nextDX\n gestureState.dy = nextDY\n gestureState._accountsForMovesUpTo = touchHistory.mostRecentTimeStamp\n },\n\n /**\n * @param config Enhanced versions of all of the responder callbacks that\n * provide not only the typical `ResponderSyntheticEvent`, but also the\n * `PanResponder` gesture state. Simply replace the word `Responder` with\n * `PanResponder` in each of the typical `onResponder*` callbacks.\n */\n create(config: PanResponderCallbacks): {\n getInteractionHandle: () => number | null\n panHandlers: GestureResponderHandlerMethods\n } {\n const gestureState: PanResponderGestureState = {\n // Useful for debugging\n stateID: Math.random(),\n moveX: 0,\n moveY: 0,\n x0: 0,\n y0: 0,\n dx: 0,\n dy: 0,\n vx: 0,\n vy: 0,\n numberActiveTouches: 0,\n _accountsForMovesUpTo: 0,\n }\n const panHandlers: GestureResponderHandlerMethods = {\n onStartShouldSetResponder(event: GestureResponderEvent): boolean {\n return config.onStartShouldSetPanResponder == null\n ? false\n : config.onStartShouldSetPanResponder(event, gestureState)\n },\n onMoveShouldSetResponder(event: GestureResponderEvent): boolean {\n return config.onMoveShouldSetPanResponder == null\n ? false\n : config.onMoveShouldSetPanResponder(event, gestureState)\n },\n onStartShouldSetResponderCapture(event: GestureResponderEvent): boolean {\n // TODO: Actually, we should reinitialize the state any time\n // touches.length increases from 0 active to > 0 active.\n if (event.nativeEvent.touches.length === 1) {\n PanResponder._initializeGestureState(gestureState)\n }\n gestureState.numberActiveTouches =\n event.touchHistory.numberActiveTouches\n return config.onStartShouldSetPanResponderCapture != null\n ? config.onStartShouldSetPanResponderCapture(event, gestureState)\n : false\n },\n\n onMoveShouldSetResponderCapture(event: GestureResponderEvent): boolean {\n const touchHistory = event.touchHistory\n // Responder system incorrectly dispatches should* to current responder\n // Filter out any touch moves past the first one - we would have\n // already processed multi-touch geometry during the first event.\n if (\n gestureState._accountsForMovesUpTo ===\n touchHistory.mostRecentTimeStamp\n ) {\n return false\n }\n PanResponder._updateGestureStateOnMove(gestureState, touchHistory)\n return config.onMoveShouldSetPanResponderCapture\n ? config.onMoveShouldSetPanResponderCapture(event, gestureState)\n : false\n },\n\n onResponderGrant(event: GestureResponderEvent): boolean {\n gestureState.x0 = currentCentroidX(event.touchHistory)\n gestureState.y0 = currentCentroidY(event.touchHistory)\n gestureState.dx = 0\n gestureState.dy = 0\n if (config.onPanResponderGrant) {\n config.onPanResponderGrant(event, gestureState)\n }\n // TODO: t7467124 investigate if this can be removed\n return config.onShouldBlockNativeResponder == null\n ? true\n : config.onShouldBlockNativeResponder(event, gestureState)\n },\n\n onResponderReject(event: GestureResponderEvent): void {\n config.onPanResponderReject?.call(undefined, event, gestureState)\n },\n\n onResponderRelease(event: GestureResponderEvent): void {\n config.onPanResponderRelease?.call(undefined, event, gestureState)\n PanResponder._initializeGestureState(gestureState)\n },\n\n onResponderStart(event: GestureResponderEvent): void {\n const touchHistory = event.touchHistory\n gestureState.numberActiveTouches = touchHistory.numberActiveTouches\n if (config.onPanResponderStart) {\n config.onPanResponderStart(event, gestureState)\n }\n },\n\n onResponderMove(event: GestureResponderEvent): void {\n const touchHistory = event.touchHistory\n // Guard against the dispatch of two touch moves when there are two\n // simultaneously changed touches.\n if (\n gestureState._accountsForMovesUpTo ===\n touchHistory.mostRecentTimeStamp\n ) {\n return\n }\n // Filter out any touch moves past the first one - we would have\n // already processed multi-touch geometry during the first event.\n PanResponder._updateGestureStateOnMove(gestureState, touchHistory)\n if (config.onPanResponderMove) {\n config.onPanResponderMove(event, gestureState)\n }\n },\n\n onResponderEnd(event: GestureResponderEvent): void {\n const touchHistory = event.touchHistory\n gestureState.numberActiveTouches = touchHistory.numberActiveTouches\n config.onPanResponderEnd?.call(undefined, event, gestureState)\n },\n\n onResponderTerminate(event: GestureResponderEvent): void {\n config.onPanResponderTerminate?.call(undefined, event, gestureState)\n PanResponder._initializeGestureState(gestureState)\n },\n\n onResponderTerminationRequest(event: GestureResponderEvent): boolean {\n return config.onPanResponderTerminationRequest == null\n ? true\n : config.onPanResponderTerminationRequest(event, gestureState)\n },\n }\n return {\n panHandlers,\n getInteractionHandle(): number | null {\n // TODO: Deprecate and delete this method.\n return null\n },\n }\n },\n}\n\nexport type PanResponderInstance = ReturnType<(typeof PanResponder)[\"create\"]>\n\nexport default PanResponder\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import type { TouchHistory } from "../../responder/types";
|
|
8
|
+
declare const TouchHistoryMath: {
|
|
9
|
+
centroidDimension: (touchHistory: TouchHistory, touchesChangedAfter: number, isXAxis: boolean, ofCurrent: boolean) => number;
|
|
10
|
+
currentCentroidXOfTouchesChangedAfter(touchHistory: TouchHistory, touchesChangedAfter: number): number;
|
|
11
|
+
currentCentroidYOfTouchesChangedAfter(touchHistory: TouchHistory, touchesChangedAfter: number): number;
|
|
12
|
+
previousCentroidXOfTouchesChangedAfter(touchHistory: TouchHistory, touchesChangedAfter: number): number;
|
|
13
|
+
previousCentroidYOfTouchesChangedAfter(touchHistory: TouchHistory, touchesChangedAfter: number): number;
|
|
14
|
+
currentCentroidX(touchHistory: TouchHistory): number;
|
|
15
|
+
currentCentroidY(touchHistory: TouchHistory): number;
|
|
16
|
+
noCentroid: number;
|
|
17
|
+
};
|
|
18
|
+
export default TouchHistoryMath;
|