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 @@
|
|
|
1
|
+
{"version":3,"file":"gradients.js","sourceRoot":"","sources":["../../../src/components/svg/gradients.tsx"],"names":[],"mappings":"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","sourcesContent":["// <Defs>/<LinearGradient>/<RadialGradient>/<Stop> — paint resources, not\n// visible nodes. They ride the same RnGtkxSvgNode tree as everything else\n// (so the bridge's snapshot() can walk <Defs> separately, before the main\n// paint pass, to build an id → gradient map — see svg-node.ts), but are\n// never part of the Animated numeric channel: gradients are definitions,\n// not painted geometry, and nothing in scope needs an animated stop.\nimport { useLayoutEffect, useRef, type ReactNode } from \"react\"\nimport {\n Gdk,\n resolveSvgColor,\n setSvgNodeDescriptor,\n type Gtk,\n type SvgGradientUnits,\n} from \"../../gtkx/bridge/index\"\nimport { SvgNodeElement } from \"./node\"\n\nexport type DefsProps = { children?: ReactNode }\n\nexport const Defs = ({ children }: DefsProps) => {\n const widgetRef = useRef<Gtk.Widget | null>(null)\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (widget) {\n setSvgNodeDescriptor(widget, { kind: \"defs\" })\n }\n }, [])\n return <SvgNodeElement widgetRef={widgetRef}>{children}</SvgNodeElement>\n}\n\nexport type LinearGradientProps = {\n id: string\n x1?: number\n y1?: number\n x2?: number\n y2?: number\n gradientUnits?: SvgGradientUnits\n children?: ReactNode\n}\n\nexport const LinearGradient = ({\n id,\n x1 = 0,\n y1 = 0,\n x2 = 1,\n y2 = 0,\n gradientUnits = \"objectBoundingBox\",\n children,\n}: LinearGradientProps) => {\n const widgetRef = useRef<Gtk.Widget | null>(null)\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (widget) {\n setSvgNodeDescriptor(widget, {\n kind: \"gradient\",\n type: \"linear\",\n id,\n units: gradientUnits,\n x1,\n y1,\n x2,\n y2,\n })\n }\n }, [id, x1, y1, x2, y2, gradientUnits])\n return <SvgNodeElement widgetRef={widgetRef}>{children}</SvgNodeElement>\n}\n\nexport type RadialGradientProps = {\n id: string\n cx?: number\n cy?: number\n r?: number\n gradientUnits?: SvgGradientUnits\n children?: ReactNode\n}\n\nexport const RadialGradient = ({\n id,\n cx = 0.5,\n cy = 0.5,\n r = 0.5,\n gradientUnits = \"objectBoundingBox\",\n children,\n}: RadialGradientProps) => {\n const widgetRef = useRef<Gtk.Widget | null>(null)\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (widget) {\n setSvgNodeDescriptor(widget, {\n kind: \"gradient\",\n type: \"radial\",\n id,\n units: gradientUnits,\n cx,\n cy,\n r,\n })\n }\n }, [id, cx, cy, r, gradientUnits])\n return <SvgNodeElement widgetRef={widgetRef}>{children}</SvgNodeElement>\n}\n\n// \"50%\" or 0.5 — both spellings are common in real SVGO output.\nconst parseOffset = (offset: number | string): number => {\n if (typeof offset === \"number\") {\n return offset\n }\n const trimmed = offset.trim()\n return trimmed.endsWith(\"%\")\n ? Number.parseFloat(trimmed.slice(0, -1)) / 100\n : Number.parseFloat(trimmed)\n}\n\nexport type StopProps = {\n offset: number | string\n stopColor?: string\n stopOpacity?: number\n}\n\nexport const Stop = ({\n offset,\n stopColor = \"black\",\n stopOpacity = 1,\n}: StopProps) => {\n const widgetRef = useRef<Gtk.Widget | null>(null)\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n const color =\n resolveSvgColor(stopColor) ??\n new Gdk.RGBA({ red: 0, green: 0, blue: 0, alpha: 1 })\n const clampedOpacity = Math.max(0, Math.min(1, stopOpacity))\n setSvgNodeDescriptor(widget, {\n kind: \"stop\",\n offset: Math.max(0, Math.min(1, parseOffset(offset))),\n color:\n clampedOpacity >= 1\n ? color\n : new Gdk.RGBA({\n red: color.red,\n green: color.green,\n blue: color.blue,\n alpha: color.alpha * clampedOpacity,\n }),\n })\n }, [offset, stopColor, stopOpacity])\n return <SvgNodeElement widgetRef={widgetRef} />\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type AnimatableNumber } from "./animated-support";
|
|
3
|
+
export type GProps = {
|
|
4
|
+
transform?: string;
|
|
5
|
+
opacity?: AnimatableNumber;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
export declare const G: ({ transform, opacity, children }: GProps) => React.JSX.Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// <G> — a grouping node: applies an SVG transform-list string and/or opacity
|
|
3
|
+
// to every descendant, then recurses. transform accepts translate/scale/
|
|
4
|
+
// rotate/matrix (no skewX/skewY, no per-axis object form — see epic.md).
|
|
5
|
+
import { useRef } from "react";
|
|
6
|
+
import { setSvgNodeDescriptor } from "../../gtkx/bridge/index";
|
|
7
|
+
import { parseSvgTransform } from "../../svg/transform";
|
|
8
|
+
import { useAnimatedShapeBuild, } from "./animated-support";
|
|
9
|
+
import { useSvgRoot } from "./context";
|
|
10
|
+
import { SvgNodeElement } from "./node";
|
|
11
|
+
export const G = ({ transform, opacity = 1, children }) => {
|
|
12
|
+
const widgetRef = useRef(null);
|
|
13
|
+
const { requestRedraw } = useSvgRoot("G");
|
|
14
|
+
// transform is a static string (not part of the Animated channel — see
|
|
15
|
+
// epic.md); only opacity can be an Animated node here.
|
|
16
|
+
useAnimatedShapeBuild({ opacity }, (resolved) => {
|
|
17
|
+
const widget = widgetRef.current;
|
|
18
|
+
if (!widget) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
setSvgNodeDescriptor(widget, {
|
|
22
|
+
kind: "g",
|
|
23
|
+
transformOps: parseSvgTransform(transform),
|
|
24
|
+
opacity: resolved.opacity,
|
|
25
|
+
});
|
|
26
|
+
requestRedraw();
|
|
27
|
+
}, [transform]);
|
|
28
|
+
return _jsx(SvgNodeElement, { widgetRef: widgetRef, children: children });
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"group.js","sourceRoot":"","sources":["../../../src/components/svg/group.tsx"],"names":[],"mappings":";AAAA,6EAA6E;AAC7E,yEAAyE;AACzE,yEAAyE;AACzE,OAAO,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAY,MAAM,yBAAyB,CAAA;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EACL,qBAAqB,GAEtB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAQvC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,GAAG,CAAC,EAAE,QAAQ,EAAU,EAAE,EAAE;IAChE,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IACjD,MAAM,EAAE,aAAa,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAA;IAEzC,uEAAuE;IACvE,uDAAuD;IACvD,qBAAqB,CACnB,EAAE,OAAO,EAAE,EACX,CAAC,QAAQ,EAAE,EAAE;QACX,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;QAChC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAM;QACR,CAAC;QACD,oBAAoB,CAAC,MAAM,EAAE;YAC3B,IAAI,EAAE,GAAG;YACT,YAAY,EAAE,iBAAiB,CAAC,SAAS,CAAC;YAC1C,OAAO,EAAE,QAAQ,CAAC,OAAQ;SAC3B,CAAC,CAAA;QACF,aAAa,EAAE,CAAA;IACjB,CAAC,EACD,CAAC,SAAS,CAAC,CACZ,CAAA;IAED,OAAO,KAAC,cAAc,IAAC,SAAS,EAAE,SAAS,YAAG,QAAQ,GAAkB,CAAA;AAC1E,CAAC,CAAA","sourcesContent":["// <G> — a grouping node: applies an SVG transform-list string and/or opacity\n// to every descendant, then recurses. transform accepts translate/scale/\n// rotate/matrix (no skewX/skewY, no per-axis object form — see epic.md).\nimport { useRef, type ReactNode } from \"react\"\nimport { setSvgNodeDescriptor, type Gtk } from \"../../gtkx/bridge/index\"\nimport { parseSvgTransform } from \"../../svg/transform\"\nimport {\n useAnimatedShapeBuild,\n type AnimatableNumber,\n} from \"./animated-support\"\nimport { useSvgRoot } from \"./context\"\nimport { SvgNodeElement } from \"./node\"\n\nexport type GProps = {\n transform?: string\n opacity?: AnimatableNumber\n children?: ReactNode\n}\n\nexport const G = ({ transform, opacity = 1, children }: GProps) => {\n const widgetRef = useRef<Gtk.Widget | null>(null)\n const { requestRedraw } = useSvgRoot(\"G\")\n\n // transform is a static string (not part of the Animated channel — see\n // epic.md); only opacity can be an Animated node here.\n useAnimatedShapeBuild(\n { opacity },\n (resolved) => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n setSvgNodeDescriptor(widget, {\n kind: \"g\",\n transformOps: parseSvgTransform(transform),\n opacity: resolved.opacity!,\n })\n requestRedraw()\n },\n [transform],\n )\n\n return <SvgNodeElement widgetRef={widgetRef}>{children}</SvgNodeElement>\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Defs, LinearGradient, RadialGradient, Stop, type DefsProps, type LinearGradientProps, type RadialGradientProps, type StopProps, } from "./gradients";
|
|
2
|
+
export { G, type GProps } from "./group";
|
|
3
|
+
export { Circle, Ellipse, Line, Path, Polygon, Polyline, Rect, type CircleProps, type EllipseProps, type LineProps, type PathProps, type PolygonProps, type PolylineProps, type RectProps, } from "./shapes";
|
|
4
|
+
export { Svg, type SvgProps } from "./svg";
|
|
5
|
+
export type { AnimatableNumber } from "./animated-support";
|
|
6
|
+
export type { SvgFillRule, SvgLineCap, SvgLineJoin } from "./paint";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/svg/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,cAAc,EACd,cAAc,EACd,IAAI,GAKL,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,CAAC,EAAe,MAAM,SAAS,CAAA;AACxC,OAAO,EACL,MAAM,EACN,OAAO,EACP,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,IAAI,GAQL,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,GAAG,EAAiB,MAAM,OAAO,CAAA","sourcesContent":["export {\n Defs,\n LinearGradient,\n RadialGradient,\n Stop,\n type DefsProps,\n type LinearGradientProps,\n type RadialGradientProps,\n type StopProps,\n} from \"./gradients\"\nexport { G, type GProps } from \"./group\"\nexport {\n Circle,\n Ellipse,\n Line,\n Path,\n Polygon,\n Polyline,\n Rect,\n type CircleProps,\n type EllipseProps,\n type LineProps,\n type PathProps,\n type PolygonProps,\n type PolylineProps,\n type RectProps,\n} from \"./shapes\"\nexport { Svg, type SvgProps } from \"./svg\"\nexport type { AnimatableNumber } from \"./animated-support\"\nexport type { SvgFillRule, SvgLineCap, SvgLineJoin } from \"./paint\"\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReactNode, RefObject } from "react";
|
|
2
|
+
import { type Gtk } from "../../gtkx/bridge/index";
|
|
3
|
+
export type SvgNodeElementRefProps = {
|
|
4
|
+
widgetRef: RefObject<Gtk.Widget | null>;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
};
|
|
7
|
+
export declare const SvgNodeElement: ({ widgetRef, children, }: SvgNodeElementRefProps) => React.JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { getSvgNodeComponent } from "../../gtkx/bridge/index";
|
|
3
|
+
export const SvgNodeElement = ({ widgetRef, children, }) => {
|
|
4
|
+
const Node = getSvgNodeComponent();
|
|
5
|
+
return _jsx(Node, { ref: widgetRef, children: children });
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../../src/components/svg/node.tsx"],"names":[],"mappings":";AASA,OAAO,EAAE,mBAAmB,EAAY,MAAM,yBAAyB,CAAA;AAcvE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAC7B,SAAS,EACT,QAAQ,GACe,EAAE,EAAE;IAC3B,MAAM,IAAI,GAAG,mBAAmB,EAAwC,CAAA;IACxE,OAAO,KAAC,IAAI,IAAC,GAAG,EAAE,SAAS,YAAG,QAAQ,GAAQ,CAAA;AAChD,CAAC,CAAA","sourcesContent":["// Thin typed wrapper around the shared RnGtkxSvgNode intrinsic (bridge/\n// svg-node.ts) — every SVG element below <Svg> itself renders exactly this;\n// they differ only in what they write into the node's WeakMap descriptor.\n// JSX nesting is enough to build the GTK parent-child chain the bridge's\n// snapshot() walks (the reconciler's generic ref/set_parent attachment, the\n// same one View relies on for real Yoga children) — nothing here\n// participates in Yoga, so the props are deliberately minimal: no layout,\n// no name/cssClasses (unlike View, no <Path>/<G>/... needs a CSS identity).\nimport type { ReactNode, RefObject } from \"react\"\nimport { getSvgNodeComponent, type Gtk } from \"../../gtkx/bridge/index\"\n\ntype SvgNodeElementProps = {\n ref?: RefObject<Gtk.Widget | null> | null\n children?: ReactNode\n}\n\ntype SvgNodeElementComponent = (props: SvgNodeElementProps) => ReactNode\n\nexport type SvgNodeElementRefProps = {\n widgetRef: RefObject<Gtk.Widget | null>\n children?: ReactNode\n}\n\nexport const SvgNodeElement = ({\n widgetRef,\n children,\n}: SvgNodeElementRefProps) => {\n const Node = getSvgNodeComponent() as unknown as SvgNodeElementComponent\n return <Node ref={widgetRef}>{children}</Node>\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type SvgShapeDescriptor } from "../../gtkx/bridge/index";
|
|
2
|
+
export type SvgFillRule = "nonzero" | "evenodd";
|
|
3
|
+
export type SvgLineCap = "butt" | "round" | "square";
|
|
4
|
+
export type SvgLineJoin = "miter" | "round" | "bevel";
|
|
5
|
+
export type SvgPaintProps = {
|
|
6
|
+
fill?: string;
|
|
7
|
+
fillRule?: SvgFillRule;
|
|
8
|
+
stroke?: string;
|
|
9
|
+
strokeLinecap?: SvgLineCap;
|
|
10
|
+
strokeLinejoin?: SvgLineJoin;
|
|
11
|
+
strokeDasharray?: string | number[];
|
|
12
|
+
};
|
|
13
|
+
export type SvgPaintNumbers = {
|
|
14
|
+
fillOpacity: number;
|
|
15
|
+
strokeOpacity: number;
|
|
16
|
+
strokeWidth: number;
|
|
17
|
+
strokeDashoffset: number;
|
|
18
|
+
opacity: number;
|
|
19
|
+
};
|
|
20
|
+
export declare const DEFAULT_PAINT_NUMBERS: SvgPaintNumbers;
|
|
21
|
+
/** `d` may be empty (e.g. a Polygon with no points) — that shape simply
|
|
22
|
+
* paints nothing, it is not an error. Fill defaults to black, stroke to
|
|
23
|
+
* none, exactly like react-native-svg. */
|
|
24
|
+
export declare const buildShapeDescriptor: (d: string, paint: SvgPaintProps, numbers: SvgPaintNumbers) => SvgShapeDescriptor;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Shared fill/stroke prop shape and the descriptor builder every shape
|
|
2
|
+
// component (Path/Rect/Circle/Ellipse/Line/Polygon/Polyline) feeds its
|
|
3
|
+
// generated `d` string through. Defaults match react-native-svg: fill
|
|
4
|
+
// defaults to black, stroke to none.
|
|
5
|
+
import { Gsk, resolveSvgPaint, } from "../../gtkx/bridge/index";
|
|
6
|
+
export const DEFAULT_PAINT_NUMBERS = {
|
|
7
|
+
fillOpacity: 1,
|
|
8
|
+
strokeOpacity: 1,
|
|
9
|
+
strokeWidth: 1,
|
|
10
|
+
strokeDashoffset: 0,
|
|
11
|
+
opacity: 1,
|
|
12
|
+
};
|
|
13
|
+
const FILL_RULES = {
|
|
14
|
+
nonzero: Gsk.FillRule.WINDING,
|
|
15
|
+
evenodd: Gsk.FillRule.EVEN_ODD,
|
|
16
|
+
};
|
|
17
|
+
const LINE_CAPS = {
|
|
18
|
+
butt: Gsk.LineCap.BUTT,
|
|
19
|
+
round: Gsk.LineCap.ROUND,
|
|
20
|
+
square: Gsk.LineCap.SQUARE,
|
|
21
|
+
};
|
|
22
|
+
const LINE_JOINS = {
|
|
23
|
+
miter: Gsk.LineJoin.MITER,
|
|
24
|
+
round: Gsk.LineJoin.ROUND,
|
|
25
|
+
bevel: Gsk.LineJoin.BEVEL,
|
|
26
|
+
};
|
|
27
|
+
// RN-svg accepts both a comma/space-separated string and a number array.
|
|
28
|
+
const parseDasharray = (value) => {
|
|
29
|
+
if (value === undefined) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const tokens = Array.isArray(value) ? value : value.split(/[\s,]+/);
|
|
33
|
+
const numbers = tokens
|
|
34
|
+
.map((token) => typeof token === "number" ? token : Number.parseFloat(String(token)))
|
|
35
|
+
.filter((n) => Number.isFinite(n) && n >= 0);
|
|
36
|
+
return numbers.length > 0 ? numbers : null;
|
|
37
|
+
};
|
|
38
|
+
/** `d` may be empty (e.g. a Polygon with no points) — that shape simply
|
|
39
|
+
* paints nothing, it is not an error. Fill defaults to black, stroke to
|
|
40
|
+
* none, exactly like react-native-svg. */
|
|
41
|
+
export const buildShapeDescriptor = (d, paint, numbers) => ({
|
|
42
|
+
kind: "shape",
|
|
43
|
+
path: d ? Gsk.Path.parse(d) : null,
|
|
44
|
+
fill: resolveSvgPaint(paint.fill ?? "black"),
|
|
45
|
+
fillOpacity: numbers.fillOpacity,
|
|
46
|
+
fillRule: FILL_RULES[paint.fillRule ?? "nonzero"],
|
|
47
|
+
stroke: resolveSvgPaint(paint.stroke ?? "none"),
|
|
48
|
+
strokeOpacity: numbers.strokeOpacity,
|
|
49
|
+
strokeWidth: numbers.strokeWidth,
|
|
50
|
+
strokeLinecap: LINE_CAPS[paint.strokeLinecap ?? "butt"],
|
|
51
|
+
strokeLinejoin: LINE_JOINS[paint.strokeLinejoin ?? "miter"],
|
|
52
|
+
strokeMiterlimit: 4,
|
|
53
|
+
strokeDasharray: parseDasharray(paint.strokeDasharray),
|
|
54
|
+
strokeDashoffset: numbers.strokeDashoffset,
|
|
55
|
+
opacity: numbers.opacity,
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=paint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paint.js","sourceRoot":"","sources":["../../../src/components/svg/paint.ts"],"names":[],"mappings":"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","sourcesContent":["// Shared fill/stroke prop shape and the descriptor builder every shape\n// component (Path/Rect/Circle/Ellipse/Line/Polygon/Polyline) feeds its\n// generated `d` string through. Defaults match react-native-svg: fill\n// defaults to black, stroke to none.\nimport {\n Gsk,\n resolveSvgPaint,\n type SvgShapeDescriptor,\n} from \"../../gtkx/bridge/index\"\n\nexport type SvgFillRule = \"nonzero\" | \"evenodd\"\nexport type SvgLineCap = \"butt\" | \"round\" | \"square\"\nexport type SvgLineJoin = \"miter\" | \"round\" | \"bevel\"\n\nexport type SvgPaintProps = {\n fill?: string\n fillRule?: SvgFillRule\n stroke?: string\n strokeLinecap?: SvgLineCap\n strokeLinejoin?: SvgLineJoin\n strokeDasharray?: string | number[]\n}\n\n// The subset of paint that can be Animated (see animated-support.ts) — kept\n// separate from SvgPaintProps because those fields are always resolved to\n// plain numbers by the caller before this function ever sees them.\nexport type SvgPaintNumbers = {\n fillOpacity: number\n strokeOpacity: number\n strokeWidth: number\n strokeDashoffset: number\n opacity: number\n}\n\nexport const DEFAULT_PAINT_NUMBERS: SvgPaintNumbers = {\n fillOpacity: 1,\n strokeOpacity: 1,\n strokeWidth: 1,\n strokeDashoffset: 0,\n opacity: 1,\n}\n\nconst FILL_RULES: Record<SvgFillRule, Gsk.FillRule> = {\n nonzero: Gsk.FillRule.WINDING,\n evenodd: Gsk.FillRule.EVEN_ODD,\n}\n\nconst LINE_CAPS: Record<SvgLineCap, Gsk.LineCap> = {\n butt: Gsk.LineCap.BUTT,\n round: Gsk.LineCap.ROUND,\n square: Gsk.LineCap.SQUARE,\n}\n\nconst LINE_JOINS: Record<SvgLineJoin, Gsk.LineJoin> = {\n miter: Gsk.LineJoin.MITER,\n round: Gsk.LineJoin.ROUND,\n bevel: Gsk.LineJoin.BEVEL,\n}\n\n// RN-svg accepts both a comma/space-separated string and a number array.\nconst parseDasharray = (\n value: SvgPaintProps[\"strokeDasharray\"],\n): number[] | null => {\n if (value === undefined) {\n return null\n }\n const tokens = Array.isArray(value) ? value : value.split(/[\\s,]+/)\n const numbers = tokens\n .map((token) =>\n typeof token === \"number\" ? token : Number.parseFloat(String(token)),\n )\n .filter((n) => Number.isFinite(n) && n >= 0)\n return numbers.length > 0 ? numbers : null\n}\n\n/** `d` may be empty (e.g. a Polygon with no points) — that shape simply\n * paints nothing, it is not an error. Fill defaults to black, stroke to\n * none, exactly like react-native-svg. */\nexport const buildShapeDescriptor = (\n d: string,\n paint: SvgPaintProps,\n numbers: SvgPaintNumbers,\n): SvgShapeDescriptor => ({\n kind: \"shape\",\n path: d ? Gsk.Path.parse(d) : null,\n fill: resolveSvgPaint(paint.fill ?? \"black\"),\n fillOpacity: numbers.fillOpacity,\n fillRule: FILL_RULES[paint.fillRule ?? \"nonzero\"],\n stroke: resolveSvgPaint(paint.stroke ?? \"none\"),\n strokeOpacity: numbers.strokeOpacity,\n strokeWidth: numbers.strokeWidth,\n strokeLinecap: LINE_CAPS[paint.strokeLinecap ?? \"butt\"],\n strokeLinejoin: LINE_JOINS[paint.strokeLinejoin ?? \"miter\"],\n strokeMiterlimit: 4,\n strokeDasharray: parseDasharray(paint.strokeDasharray),\n strokeDashoffset: numbers.strokeDashoffset,\n opacity: numbers.opacity,\n})\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type Point } from "../../svg/geometry";
|
|
2
|
+
import type { AnimatableNumber } from "./animated-support";
|
|
3
|
+
import type { SvgPaintProps } from "./paint";
|
|
4
|
+
import { type ShapeNumericPaintProps } from "./use-shape-node";
|
|
5
|
+
type ShapePaintProps = SvgPaintProps & ShapeNumericPaintProps;
|
|
6
|
+
export type PathProps = ShapePaintProps & {
|
|
7
|
+
d: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const Path: ({ d, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }: PathProps) => React.JSX.Element;
|
|
10
|
+
export type RectProps = ShapePaintProps & {
|
|
11
|
+
x?: AnimatableNumber;
|
|
12
|
+
y?: AnimatableNumber;
|
|
13
|
+
width: AnimatableNumber;
|
|
14
|
+
height: AnimatableNumber;
|
|
15
|
+
rx?: AnimatableNumber;
|
|
16
|
+
ry?: AnimatableNumber;
|
|
17
|
+
};
|
|
18
|
+
export declare const Rect: ({ x, y, width, height, rx, ry, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }: RectProps) => React.JSX.Element;
|
|
19
|
+
export type CircleProps = ShapePaintProps & {
|
|
20
|
+
cx?: AnimatableNumber;
|
|
21
|
+
cy?: AnimatableNumber;
|
|
22
|
+
r: AnimatableNumber;
|
|
23
|
+
};
|
|
24
|
+
export declare const Circle: ({ cx, cy, r, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }: CircleProps) => React.JSX.Element;
|
|
25
|
+
export type EllipseProps = ShapePaintProps & {
|
|
26
|
+
cx?: AnimatableNumber;
|
|
27
|
+
cy?: AnimatableNumber;
|
|
28
|
+
rx: AnimatableNumber;
|
|
29
|
+
ry: AnimatableNumber;
|
|
30
|
+
};
|
|
31
|
+
export declare const Ellipse: ({ cx, cy, rx, ry, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }: EllipseProps) => React.JSX.Element;
|
|
32
|
+
export type LineProps = Omit<ShapePaintProps, "fill" | "fillRule"> & {
|
|
33
|
+
x1?: AnimatableNumber;
|
|
34
|
+
y1?: AnimatableNumber;
|
|
35
|
+
x2?: AnimatableNumber;
|
|
36
|
+
y2?: AnimatableNumber;
|
|
37
|
+
};
|
|
38
|
+
export declare const Line: ({ x1, y1, x2, y2, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }: LineProps) => React.JSX.Element;
|
|
39
|
+
export type PolygonProps = ShapePaintProps & {
|
|
40
|
+
points: string | Point[];
|
|
41
|
+
};
|
|
42
|
+
export declare const Polygon: ({ points, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }: PolygonProps) => React.JSX.Element;
|
|
43
|
+
export type PolylineProps = ShapePaintProps & {
|
|
44
|
+
points: string | Point[];
|
|
45
|
+
};
|
|
46
|
+
export declare const Polyline: ({ points, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }: PolylineProps) => React.JSX.Element;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// Path/Rect/Circle/Ellipse/Line/Polygon/Polyline. Each is geometry (fed to
|
|
3
|
+
// the pure src/svg/geometry.ts generators, or passed straight through for
|
|
4
|
+
// Path's `d`) + the shared paint props (paint.ts). Geometry fields may be
|
|
5
|
+
// Animated (see use-shape-node.ts); `d`/`points`/the paint strings are not.
|
|
6
|
+
import { circleToPathData, ellipseToPathData, lineToPathData, polygonToPathData, polylineToPathData, rectToPathData, } from "../../svg/geometry";
|
|
7
|
+
import { SvgNodeElement } from "./node";
|
|
8
|
+
import { useShapeNode } from "./use-shape-node";
|
|
9
|
+
export const Path = ({ d, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }) => {
|
|
10
|
+
const widgetRef = useShapeNode("Path", {}, () => d, paint, { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity }, [d]);
|
|
11
|
+
return _jsx(SvgNodeElement, { widgetRef: widgetRef });
|
|
12
|
+
};
|
|
13
|
+
export const Rect = ({ x = 0, y = 0, width, height, rx, ry, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }) => {
|
|
14
|
+
const geometry = { x, y, width, height };
|
|
15
|
+
if (rx !== undefined) {
|
|
16
|
+
geometry.rx = rx;
|
|
17
|
+
}
|
|
18
|
+
if (ry !== undefined) {
|
|
19
|
+
geometry.ry = ry;
|
|
20
|
+
}
|
|
21
|
+
const widgetRef = useShapeNode("Rect", geometry, (v) => rectToPathData({
|
|
22
|
+
x: v.x,
|
|
23
|
+
y: v.y,
|
|
24
|
+
width: v.width,
|
|
25
|
+
height: v.height,
|
|
26
|
+
rx: v.rx,
|
|
27
|
+
ry: v.ry,
|
|
28
|
+
}), paint, { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity }, []);
|
|
29
|
+
return _jsx(SvgNodeElement, { widgetRef: widgetRef });
|
|
30
|
+
};
|
|
31
|
+
export const Circle = ({ cx = 0, cy = 0, r, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }) => {
|
|
32
|
+
const widgetRef = useShapeNode("Circle", { cx, cy, r }, (v) => circleToPathData(v.cx, v.cy, v.r), paint, { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity }, []);
|
|
33
|
+
return _jsx(SvgNodeElement, { widgetRef: widgetRef });
|
|
34
|
+
};
|
|
35
|
+
export const Ellipse = ({ cx = 0, cy = 0, rx, ry, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }) => {
|
|
36
|
+
const widgetRef = useShapeNode("Ellipse", { cx, cy, rx, ry }, (v) => ellipseToPathData(v.cx, v.cy, v.rx, v.ry), paint, { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity }, []);
|
|
37
|
+
return _jsx(SvgNodeElement, { widgetRef: widgetRef });
|
|
38
|
+
};
|
|
39
|
+
export const Line = ({ x1 = 0, y1 = 0, x2 = 0, y2 = 0, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }) => {
|
|
40
|
+
const widgetRef = useShapeNode("Line", { x1, y1, x2, y2 }, (v) => lineToPathData(v.x1, v.y1, v.x2, v.y2), { ...paint, fill: "none" }, { strokeOpacity, strokeWidth, strokeDashoffset, opacity }, []);
|
|
41
|
+
return _jsx(SvgNodeElement, { widgetRef: widgetRef });
|
|
42
|
+
};
|
|
43
|
+
export const Polygon = ({ points, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }) => {
|
|
44
|
+
const widgetRef = useShapeNode("Polygon", {}, () => polygonToPathData(points), paint, { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity }, [points]);
|
|
45
|
+
return _jsx(SvgNodeElement, { widgetRef: widgetRef });
|
|
46
|
+
};
|
|
47
|
+
export const Polyline = ({ points, fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity, ...paint }) => {
|
|
48
|
+
const widgetRef = useShapeNode("Polyline", {}, () => polylineToPathData(points), paint, { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity }, [points]);
|
|
49
|
+
return _jsx(SvgNodeElement, { widgetRef: widgetRef });
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=shapes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../../../src/components/svg/shapes.tsx"],"names":[],"mappings":"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","sourcesContent":["// Path/Rect/Circle/Ellipse/Line/Polygon/Polyline. Each is geometry (fed to\n// the pure src/svg/geometry.ts generators, or passed straight through for\n// Path's `d`) + the shared paint props (paint.ts). Geometry fields may be\n// Animated (see use-shape-node.ts); `d`/`points`/the paint strings are not.\nimport {\n circleToPathData,\n ellipseToPathData,\n lineToPathData,\n polygonToPathData,\n polylineToPathData,\n rectToPathData,\n type Point,\n} from \"../../svg/geometry\"\nimport type { AnimatableNumber } from \"./animated-support\"\nimport { SvgNodeElement } from \"./node\"\nimport type { SvgPaintProps } from \"./paint\"\nimport { useShapeNode, type ShapeNumericPaintProps } from \"./use-shape-node\"\n\ntype ShapePaintProps = SvgPaintProps & ShapeNumericPaintProps\n\nexport type PathProps = ShapePaintProps & { d: string }\n\nexport const Path = ({\n d,\n fillOpacity,\n strokeOpacity,\n strokeWidth,\n strokeDashoffset,\n opacity,\n ...paint\n}: PathProps) => {\n const widgetRef = useShapeNode(\n \"Path\",\n {},\n () => d,\n paint,\n { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity },\n [d],\n )\n return <SvgNodeElement widgetRef={widgetRef} />\n}\n\nexport type RectProps = ShapePaintProps & {\n x?: AnimatableNumber\n y?: AnimatableNumber\n width: AnimatableNumber\n height: AnimatableNumber\n rx?: AnimatableNumber\n ry?: AnimatableNumber\n}\n\nexport const Rect = ({\n x = 0,\n y = 0,\n width,\n height,\n rx,\n ry,\n fillOpacity,\n strokeOpacity,\n strokeWidth,\n strokeDashoffset,\n opacity,\n ...paint\n}: RectProps) => {\n const geometry: Record<string, AnimatableNumber> = { x, y, width, height }\n if (rx !== undefined) {\n geometry.rx = rx\n }\n if (ry !== undefined) {\n geometry.ry = ry\n }\n const widgetRef = useShapeNode(\n \"Rect\",\n geometry,\n (v) =>\n rectToPathData({\n x: v.x!,\n y: v.y!,\n width: v.width!,\n height: v.height!,\n rx: v.rx,\n ry: v.ry,\n }),\n paint,\n { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity },\n [],\n )\n return <SvgNodeElement widgetRef={widgetRef} />\n}\n\nexport type CircleProps = ShapePaintProps & {\n cx?: AnimatableNumber\n cy?: AnimatableNumber\n r: AnimatableNumber\n}\n\nexport const Circle = ({\n cx = 0,\n cy = 0,\n r,\n fillOpacity,\n strokeOpacity,\n strokeWidth,\n strokeDashoffset,\n opacity,\n ...paint\n}: CircleProps) => {\n const widgetRef = useShapeNode(\n \"Circle\",\n { cx, cy, r },\n (v) => circleToPathData(v.cx!, v.cy!, v.r!),\n paint,\n { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity },\n [],\n )\n return <SvgNodeElement widgetRef={widgetRef} />\n}\n\nexport type EllipseProps = ShapePaintProps & {\n cx?: AnimatableNumber\n cy?: AnimatableNumber\n rx: AnimatableNumber\n ry: AnimatableNumber\n}\n\nexport const Ellipse = ({\n cx = 0,\n cy = 0,\n rx,\n ry,\n fillOpacity,\n strokeOpacity,\n strokeWidth,\n strokeDashoffset,\n opacity,\n ...paint\n}: EllipseProps) => {\n const widgetRef = useShapeNode(\n \"Ellipse\",\n { cx, cy, rx, ry },\n (v) => ellipseToPathData(v.cx!, v.cy!, v.rx!, v.ry!),\n paint,\n { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity },\n [],\n )\n return <SvgNodeElement widgetRef={widgetRef} />\n}\n\n// Line never fills (a zero-area contour) — the `fill` prop is intentionally\n// not part of LineProps at all rather than silently ignored.\nexport type LineProps = Omit<ShapePaintProps, \"fill\" | \"fillRule\"> & {\n x1?: AnimatableNumber\n y1?: AnimatableNumber\n x2?: AnimatableNumber\n y2?: AnimatableNumber\n}\n\nexport const Line = ({\n x1 = 0,\n y1 = 0,\n x2 = 0,\n y2 = 0,\n strokeOpacity,\n strokeWidth,\n strokeDashoffset,\n opacity,\n ...paint\n}: LineProps) => {\n const widgetRef = useShapeNode(\n \"Line\",\n { x1, y1, x2, y2 },\n (v) => lineToPathData(v.x1!, v.y1!, v.x2!, v.y2!),\n { ...paint, fill: \"none\" },\n { strokeOpacity, strokeWidth, strokeDashoffset, opacity },\n [],\n )\n return <SvgNodeElement widgetRef={widgetRef} />\n}\n\n// points is a plain string/array (not part of the Animated field set — same\n// cut as Path's `d`, see epic.md).\nexport type PolygonProps = ShapePaintProps & { points: string | Point[] }\n\nexport const Polygon = ({\n points,\n fillOpacity,\n strokeOpacity,\n strokeWidth,\n strokeDashoffset,\n opacity,\n ...paint\n}: PolygonProps) => {\n const widgetRef = useShapeNode(\n \"Polygon\",\n {},\n () => polygonToPathData(points),\n paint,\n { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity },\n [points],\n )\n return <SvgNodeElement widgetRef={widgetRef} />\n}\n\nexport type PolylineProps = ShapePaintProps & { points: string | Point[] }\n\nexport const Polyline = ({\n points,\n fillOpacity,\n strokeOpacity,\n strokeWidth,\n strokeDashoffset,\n opacity,\n ...paint\n}: PolylineProps) => {\n const widgetRef = useShapeNode(\n \"Polyline\",\n {},\n () => polylineToPathData(points),\n paint,\n { fillOpacity, strokeOpacity, strokeWidth, strokeDashoffset, opacity },\n [points],\n )\n return <SvgNodeElement widgetRef={widgetRef} />\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { DimensionValue, StyleProp } from "../../contracts";
|
|
3
|
+
import { type LayoutEvent } from "../use-layout-child";
|
|
4
|
+
export type SvgProps = {
|
|
5
|
+
width?: DimensionValue;
|
|
6
|
+
height?: DimensionValue;
|
|
7
|
+
viewBox?: string;
|
|
8
|
+
preserveAspectRatio?: string;
|
|
9
|
+
style?: StyleProp;
|
|
10
|
+
onLayout?: (event: LayoutEvent) => void;
|
|
11
|
+
testID?: string;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
};
|
|
14
|
+
export declare const Svg: ({ width, height, viewBox, preserveAspectRatio, style, onLayout, testID, children, }: SvgProps) => React.JSX.Element;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// <Svg> — the one part of this API that touches Yoga at all. Sized purely
|
|
3
|
+
// by style (width/height/flex), no measureFromWidget: same precedent as
|
|
4
|
+
// Image (verified while researching the epic — Image does not introspect
|
|
5
|
+
// GtkPicture's natural size either, it is entirely style-driven). viewBox +
|
|
6
|
+
// preserveAspectRatio only reshape the coordinate space INSIDE the
|
|
7
|
+
// allocated rect; Yoga never sees them.
|
|
8
|
+
import { useLayoutEffect, useMemo, useRef, } from "react";
|
|
9
|
+
import { getSvgNodeComponent, queueSvgRedraw, setSvgNodeDescriptor, } from "../../gtkx/bridge/index";
|
|
10
|
+
import { parsePreserveAspectRatio, parseViewBox } from "../../svg/view-box";
|
|
11
|
+
import { useLayoutChild } from "../use-layout-child";
|
|
12
|
+
import { SvgRootContext } from "./context";
|
|
13
|
+
export const Svg = ({ width, height, viewBox, preserveAspectRatio, style, onLayout, testID, children, }) => {
|
|
14
|
+
const widgetRef = useRef(null);
|
|
15
|
+
// width/height are RN-svg convenience props layered onto style, the same
|
|
16
|
+
// relationship style has to every other layout prop in this codebase.
|
|
17
|
+
const sizeStyle = useMemo(() => width === undefined && height === undefined ? null : { width, height }, [width, height]);
|
|
18
|
+
const { cssClass } = useLayoutChild(widgetRef, {
|
|
19
|
+
style: [style, sizeStyle],
|
|
20
|
+
onLayout,
|
|
21
|
+
});
|
|
22
|
+
const parsedViewBox = useMemo(() => parseViewBox(viewBox), [viewBox]);
|
|
23
|
+
const parsedPreserveAspectRatio = useMemo(() => parsePreserveAspectRatio(preserveAspectRatio), [preserveAspectRatio]);
|
|
24
|
+
useLayoutEffect(() => {
|
|
25
|
+
const widget = widgetRef.current;
|
|
26
|
+
if (!widget) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
setSvgNodeDescriptor(widget, {
|
|
30
|
+
kind: "svg",
|
|
31
|
+
viewBox: parsedViewBox,
|
|
32
|
+
preserveAspectRatio: parsedPreserveAspectRatio,
|
|
33
|
+
});
|
|
34
|
+
queueSvgRedraw(widget);
|
|
35
|
+
}, [parsedViewBox, parsedPreserveAspectRatio]);
|
|
36
|
+
const contextValue = useMemo(() => ({
|
|
37
|
+
rootRef: widgetRef,
|
|
38
|
+
requestRedraw: () => {
|
|
39
|
+
const widget = widgetRef.current;
|
|
40
|
+
if (widget) {
|
|
41
|
+
queueSvgRedraw(widget);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
}), []);
|
|
45
|
+
const SvgElement = getSvgNodeComponent();
|
|
46
|
+
return (_jsx(SvgElement, { ref: widgetRef, name: testID, cssClasses: cssClass ? [cssClass] : [], children: _jsx(SvgRootContext.Provider, { value: contextValue, children: children }) }));
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=svg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg.js","sourceRoot":"","sources":["../../../src/components/svg/svg.tsx"],"names":[],"mappings":";AAAA,0EAA0E;AAC1E,wEAAwE;AACxE,yEAAyE;AACzE,4EAA4E;AAC5E,mEAAmE;AACnE,wCAAwC;AACxC,OAAO,EACL,eAAe,EACf,OAAO,EACP,MAAM,GAGP,MAAM,OAAO,CAAA;AAEd,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,oBAAoB,GAErB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAC3E,OAAO,EAAE,cAAc,EAAoB,MAAM,qBAAqB,CAAA;AACtE,OAAO,EAAE,cAAc,EAA4B,MAAM,WAAW,CAAA;AAsBpE,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,EAClB,KAAK,EACL,MAAM,EACN,OAAO,EACP,mBAAmB,EACnB,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,GACC,EAAE,EAAE;IACb,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IAEjD,yEAAyE;IACzE,sEAAsE;IACtE,MAAM,SAAS,GAAG,OAAO,CACvB,GAAG,EAAE,CACH,KAAK,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EACxE,CAAC,KAAK,EAAE,MAAM,CAAC,CAChB,CAAA;IACD,MAAM,EAAE,QAAQ,EAAE,GAAG,cAAc,CAAC,SAAS,EAAE;QAC7C,KAAK,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC;QACzB,QAAQ;KACT,CAAC,CAAA;IAEF,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IACrE,MAAM,yBAAyB,GAAG,OAAO,CACvC,GAAG,EAAE,CAAC,wBAAwB,CAAC,mBAAmB,CAAC,EACnD,CAAC,mBAAmB,CAAC,CACtB,CAAA;IAED,eAAe,CAAC,GAAG,EAAE;QACnB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;QAChC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAM;QACR,CAAC;QACD,oBAAoB,CAAC,MAAM,EAAE;YAC3B,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,aAAa;YACtB,mBAAmB,EAAE,yBAAyB;SAC/C,CAAC,CAAA;QACF,cAAc,CAAC,MAAM,CAAC,CAAA;IACxB,CAAC,EAAE,CAAC,aAAa,EAAE,yBAAyB,CAAC,CAAC,CAAA;IAE9C,MAAM,YAAY,GAAG,OAAO,CAC1B,GAAG,EAAE,CAAC,CAAC;QACL,OAAO,EAAE,SAAS;QAClB,aAAa,EAAE,GAAG,EAAE;YAClB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;YAChC,IAAI,MAAM,EAAE,CAAC;gBACX,cAAc,CAAC,MAAM,CAAC,CAAA;YACxB,CAAC;QACH,CAAC;KACF,CAAC,EACF,EAAE,CACH,CAAA;IAED,MAAM,UAAU,GAAG,mBAAmB,EAAoC,CAAA;IAC1E,OAAO,CACL,KAAC,UAAU,IACT,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,YAEtC,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,YAAY,YACzC,QAAQ,GACe,GACf,CACd,CAAA;AACH,CAAC,CAAA","sourcesContent":["// <Svg> — the one part of this API that touches Yoga at all. Sized purely\n// by style (width/height/flex), no measureFromWidget: same precedent as\n// Image (verified while researching the epic — Image does not introspect\n// GtkPicture's natural size either, it is entirely style-driven). viewBox +\n// preserveAspectRatio only reshape the coordinate space INSIDE the\n// allocated rect; Yoga never sees them.\nimport {\n useLayoutEffect,\n useMemo,\n useRef,\n type ReactNode,\n type RefObject,\n} from \"react\"\nimport type { DimensionValue, StyleProp } from \"../../contracts\"\nimport {\n getSvgNodeComponent,\n queueSvgRedraw,\n setSvgNodeDescriptor,\n type Gtk,\n} from \"../../gtkx/bridge/index\"\nimport { parsePreserveAspectRatio, parseViewBox } from \"../../svg/view-box\"\nimport { useLayoutChild, type LayoutEvent } from \"../use-layout-child\"\nimport { SvgRootContext, type SvgRootContextValue } from \"./context\"\n\nexport type SvgProps = {\n width?: DimensionValue\n height?: DimensionValue\n viewBox?: string\n preserveAspectRatio?: string\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n testID?: string\n children?: ReactNode\n}\n\ntype SvgElementProps = {\n ref?: RefObject<Gtk.Widget | null> | null\n name?: string\n cssClasses?: string[]\n children?: ReactNode\n}\n\ntype SvgElementComponent = (props: SvgElementProps) => ReactNode\n\nexport const Svg = ({\n width,\n height,\n viewBox,\n preserveAspectRatio,\n style,\n onLayout,\n testID,\n children,\n}: SvgProps) => {\n const widgetRef = useRef<Gtk.Widget | null>(null)\n\n // width/height are RN-svg convenience props layered onto style, the same\n // relationship style has to every other layout prop in this codebase.\n const sizeStyle = useMemo(\n () =>\n width === undefined && height === undefined ? null : { width, height },\n [width, height],\n )\n const { cssClass } = useLayoutChild(widgetRef, {\n style: [style, sizeStyle],\n onLayout,\n })\n\n const parsedViewBox = useMemo(() => parseViewBox(viewBox), [viewBox])\n const parsedPreserveAspectRatio = useMemo(\n () => parsePreserveAspectRatio(preserveAspectRatio),\n [preserveAspectRatio],\n )\n\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n setSvgNodeDescriptor(widget, {\n kind: \"svg\",\n viewBox: parsedViewBox,\n preserveAspectRatio: parsedPreserveAspectRatio,\n })\n queueSvgRedraw(widget)\n }, [parsedViewBox, parsedPreserveAspectRatio])\n\n const contextValue = useMemo<SvgRootContextValue>(\n () => ({\n rootRef: widgetRef,\n requestRedraw: () => {\n const widget = widgetRef.current\n if (widget) {\n queueSvgRedraw(widget)\n }\n },\n }),\n [],\n )\n\n const SvgElement = getSvgNodeComponent() as unknown as SvgElementComponent\n return (\n <SvgElement\n ref={widgetRef}\n name={testID}\n cssClasses={cssClass ? [cssClass] : []}\n >\n <SvgRootContext.Provider value={contextValue}>\n {children}\n </SvgRootContext.Provider>\n </SvgElement>\n )\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
import { type Gtk } from "../../gtkx/bridge/index";
|
|
3
|
+
import { type AnimatableNumber } from "./animated-support";
|
|
4
|
+
import { type SvgPaintProps } from "./paint";
|
|
5
|
+
export type ShapeNumericPaintProps = {
|
|
6
|
+
fillOpacity?: AnimatableNumber;
|
|
7
|
+
strokeOpacity?: AnimatableNumber;
|
|
8
|
+
strokeWidth?: AnimatableNumber;
|
|
9
|
+
strokeDashoffset?: AnimatableNumber;
|
|
10
|
+
opacity?: AnimatableNumber;
|
|
11
|
+
};
|
|
12
|
+
export declare const useShapeNode: (componentName: string, geometry: Record<string, AnimatableNumber>, computeD: (resolvedGeometry: Record<string, number>) => string, paint: SvgPaintProps, numeric: ShapeNumericPaintProps, extraDeps: readonly unknown[]) => RefObject<Gtk.Widget | null>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Shared plumbing for every shape component (Path/Rect/Circle/Ellipse/Line/
|
|
2
|
+
// Polygon/Polyline): resolves geometry + numeric paint fields (any of which
|
|
3
|
+
// may be Animated), builds the `d` string and the descriptor, writes it, and
|
|
4
|
+
// requests a redraw. `extraDeps` must list every non-numeric prop `computeD`
|
|
5
|
+
// or `paint` close over (a plain string like `d`/`points`/`fill` changing is
|
|
6
|
+
// not itself part of the Animated field set, but must still re-run `build`).
|
|
7
|
+
import { useRef } from "react";
|
|
8
|
+
import { setSvgNodeDescriptor } from "../../gtkx/bridge/index";
|
|
9
|
+
import { useAnimatedShapeBuild, } from "./animated-support";
|
|
10
|
+
import { useSvgRoot } from "./context";
|
|
11
|
+
import { buildShapeDescriptor, DEFAULT_PAINT_NUMBERS, } from "./paint";
|
|
12
|
+
export const useShapeNode = (componentName, geometry, computeD, paint, numeric, extraDeps) => {
|
|
13
|
+
const widgetRef = useRef(null);
|
|
14
|
+
const { requestRedraw } = useSvgRoot(componentName);
|
|
15
|
+
const geometryKeys = Object.keys(geometry);
|
|
16
|
+
const fields = {
|
|
17
|
+
...geometry,
|
|
18
|
+
fillOpacity: numeric.fillOpacity ?? DEFAULT_PAINT_NUMBERS.fillOpacity,
|
|
19
|
+
strokeOpacity: numeric.strokeOpacity ?? DEFAULT_PAINT_NUMBERS.strokeOpacity,
|
|
20
|
+
strokeWidth: numeric.strokeWidth ?? DEFAULT_PAINT_NUMBERS.strokeWidth,
|
|
21
|
+
strokeDashoffset: numeric.strokeDashoffset ?? DEFAULT_PAINT_NUMBERS.strokeDashoffset,
|
|
22
|
+
opacity: numeric.opacity ?? DEFAULT_PAINT_NUMBERS.opacity,
|
|
23
|
+
};
|
|
24
|
+
useAnimatedShapeBuild(fields, (resolved) => {
|
|
25
|
+
const widget = widgetRef.current;
|
|
26
|
+
if (!widget) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const geometryValues = {};
|
|
30
|
+
for (const key of geometryKeys) {
|
|
31
|
+
geometryValues[key] = resolved[key];
|
|
32
|
+
}
|
|
33
|
+
setSvgNodeDescriptor(widget, buildShapeDescriptor(computeD(geometryValues), paint, {
|
|
34
|
+
fillOpacity: resolved.fillOpacity,
|
|
35
|
+
strokeOpacity: resolved.strokeOpacity,
|
|
36
|
+
strokeWidth: resolved.strokeWidth,
|
|
37
|
+
strokeDashoffset: resolved.strokeDashoffset,
|
|
38
|
+
opacity: resolved.opacity,
|
|
39
|
+
}));
|
|
40
|
+
requestRedraw();
|
|
41
|
+
}, [
|
|
42
|
+
paint.fill,
|
|
43
|
+
paint.fillRule,
|
|
44
|
+
paint.stroke,
|
|
45
|
+
paint.strokeLinecap,
|
|
46
|
+
paint.strokeLinejoin,
|
|
47
|
+
paint.strokeDasharray,
|
|
48
|
+
...extraDeps,
|
|
49
|
+
]);
|
|
50
|
+
return widgetRef;
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=use-shape-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-shape-node.js","sourceRoot":"","sources":["../../../src/components/svg/use-shape-node.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,4EAA4E;AAC5E,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,OAAO,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAY,MAAM,yBAAyB,CAAA;AACxE,OAAO,EACL,qBAAqB,GAEtB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACtC,OAAO,EACL,oBAAoB,EACpB,qBAAqB,GAEtB,MAAM,SAAS,CAAA;AAUhB,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,aAAqB,EACrB,QAA0C,EAC1C,QAA8D,EAC9D,KAAoB,EACpB,OAA+B,EAC/B,SAA6B,EACC,EAAE;IAChC,MAAM,SAAS,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IACjD,MAAM,EAAE,aAAa,EAAE,GAAG,UAAU,CAAC,aAAa,CAAC,CAAA;IACnD,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAE1C,MAAM,MAAM,GAAqC;QAC/C,GAAG,QAAQ;QACX,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,qBAAqB,CAAC,WAAW;QACrE,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,qBAAqB,CAAC,aAAa;QAC3E,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,qBAAqB,CAAC,WAAW;QACrE,gBAAgB,EACd,OAAO,CAAC,gBAAgB,IAAI,qBAAqB,CAAC,gBAAgB;QACpE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,qBAAqB,CAAC,OAAO;KAC1D,CAAA;IAED,qBAAqB,CACnB,MAAM,EACN,CAAC,QAAQ,EAAE,EAAE;QACX,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;QAChC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAM;QACR,CAAC;QACD,MAAM,cAAc,GAA2B,EAAE,CAAA;QACjD,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YAC/B,cAAc,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAE,CAAA;QACtC,CAAC;QACD,oBAAoB,CAClB,MAAM,EACN,oBAAoB,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE;YACpD,WAAW,EAAE,QAAQ,CAAC,WAAY;YAClC,aAAa,EAAE,QAAQ,CAAC,aAAc;YACtC,WAAW,EAAE,QAAQ,CAAC,WAAY;YAClC,gBAAgB,EAAE,QAAQ,CAAC,gBAAiB;YAC5C,OAAO,EAAE,QAAQ,CAAC,OAAQ;SAC3B,CAAC,CACH,CAAA;QACD,aAAa,EAAE,CAAA;IACjB,CAAC,EACD;QACE,KAAK,CAAC,IAAI;QACV,KAAK,CAAC,QAAQ;QACd,KAAK,CAAC,MAAM;QACZ,KAAK,CAAC,aAAa;QACnB,KAAK,CAAC,cAAc;QACpB,KAAK,CAAC,eAAe;QACrB,GAAG,SAAS;KACb,CACF,CAAA;IAED,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA","sourcesContent":["// Shared plumbing for every shape component (Path/Rect/Circle/Ellipse/Line/\n// Polygon/Polyline): resolves geometry + numeric paint fields (any of which\n// may be Animated), builds the `d` string and the descriptor, writes it, and\n// requests a redraw. `extraDeps` must list every non-numeric prop `computeD`\n// or `paint` close over (a plain string like `d`/`points`/`fill` changing is\n// not itself part of the Animated field set, but must still re-run `build`).\nimport { useRef, type RefObject } from \"react\"\nimport { setSvgNodeDescriptor, type Gtk } from \"../../gtkx/bridge/index\"\nimport {\n useAnimatedShapeBuild,\n type AnimatableNumber,\n} from \"./animated-support\"\nimport { useSvgRoot } from \"./context\"\nimport {\n buildShapeDescriptor,\n DEFAULT_PAINT_NUMBERS,\n type SvgPaintProps,\n} from \"./paint\"\n\nexport type ShapeNumericPaintProps = {\n fillOpacity?: AnimatableNumber\n strokeOpacity?: AnimatableNumber\n strokeWidth?: AnimatableNumber\n strokeDashoffset?: AnimatableNumber\n opacity?: AnimatableNumber\n}\n\nexport const useShapeNode = (\n componentName: string,\n geometry: Record<string, AnimatableNumber>,\n computeD: (resolvedGeometry: Record<string, number>) => string,\n paint: SvgPaintProps,\n numeric: ShapeNumericPaintProps,\n extraDeps: readonly unknown[],\n): RefObject<Gtk.Widget | null> => {\n const widgetRef = useRef<Gtk.Widget | null>(null)\n const { requestRedraw } = useSvgRoot(componentName)\n const geometryKeys = Object.keys(geometry)\n\n const fields: Record<string, AnimatableNumber> = {\n ...geometry,\n fillOpacity: numeric.fillOpacity ?? DEFAULT_PAINT_NUMBERS.fillOpacity,\n strokeOpacity: numeric.strokeOpacity ?? DEFAULT_PAINT_NUMBERS.strokeOpacity,\n strokeWidth: numeric.strokeWidth ?? DEFAULT_PAINT_NUMBERS.strokeWidth,\n strokeDashoffset:\n numeric.strokeDashoffset ?? DEFAULT_PAINT_NUMBERS.strokeDashoffset,\n opacity: numeric.opacity ?? DEFAULT_PAINT_NUMBERS.opacity,\n }\n\n useAnimatedShapeBuild(\n fields,\n (resolved) => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n const geometryValues: Record<string, number> = {}\n for (const key of geometryKeys) {\n geometryValues[key] = resolved[key]!\n }\n setSvgNodeDescriptor(\n widget,\n buildShapeDescriptor(computeD(geometryValues), paint, {\n fillOpacity: resolved.fillOpacity!,\n strokeOpacity: resolved.strokeOpacity!,\n strokeWidth: resolved.strokeWidth!,\n strokeDashoffset: resolved.strokeDashoffset!,\n opacity: resolved.opacity!,\n }),\n )\n requestRedraw()\n },\n [\n paint.fill,\n paint.fillRule,\n paint.stroke,\n paint.strokeLinecap,\n paint.strokeLinejoin,\n paint.strokeDasharray,\n ...extraDeps,\n ],\n )\n\n return widgetRef\n}\n"]}
|
|
@@ -10,7 +10,7 @@ const INPUT_PURPOSE = {
|
|
|
10
10
|
"phone-pad": Gtk.InputPurpose.PHONE,
|
|
11
11
|
url: Gtk.InputPurpose.URL,
|
|
12
12
|
};
|
|
13
|
-
// The focus controller is attached imperatively (rc.
|
|
13
|
+
// The focus controller is attached imperatively (rc.3 also offers a
|
|
14
14
|
// declarative `controllers` slot): one wiring per widget, handlers read from a
|
|
15
15
|
// ref, so changing onFocus/onBlur never re-creates the controller.
|
|
16
16
|
const useFocusController = (widgetRef, onFocus, onBlur) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-input.js","sourceRoot":"","sources":["../../src/components/text-input.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, useState } from \"react\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n Gtk,\n GtkEntry,\n GtkLabel,\n GtkScrolledWindow,\n GtkTextView,\n type Gtk as GtkNs,\n} from \"../gtkx/bridge/index\"\nimport { useLayoutChild, type LayoutEvent } from \"./use-layout-child\"\nimport { View } from \"./view\"\n\nexport type TextInputProps = {\n value?: string\n defaultValue?: string\n onChangeText?: (text: string) => void\n onSubmitEditing?: (event: { nativeEvent: { text: string } }) => void\n onFocus?: () => void\n onBlur?: () => void\n placeholder?: string\n secureTextEntry?: boolean\n editable?: boolean\n keyboardType?: \"default\" | \"numeric\" | \"email-address\" | \"phone-pad\" | \"url\"\n // RN: a multiline input needs a height in the style; Enter inserts a\n // newline and never fires onSubmitEditing.\n multiline?: boolean\n // RN's iOS-only clear affordance, native here: GtkEntry's built-in\n // secondary icon (inside the field, so nothing shifts around it).\n // Single-line only, like RN.\n clearButtonMode?: \"never\" | \"while-editing\" | \"unless-editing\" | \"always\"\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n testID?: string\n}\n\nconst INPUT_PURPOSE: Record<\n NonNullable<TextInputProps[\"keyboardType\"]>,\n Gtk.InputPurpose\n> = {\n default: Gtk.InputPurpose.FREE_FORM,\n numeric: Gtk.InputPurpose.NUMBER,\n \"email-address\": Gtk.InputPurpose.EMAIL,\n \"phone-pad\": Gtk.InputPurpose.PHONE,\n url: Gtk.InputPurpose.URL,\n}\n\n// The focus controller is attached imperatively (rc.2 also offers a\n// declarative `controllers` slot): one wiring per widget, handlers read from a\n// ref, so changing onFocus/onBlur never re-creates the controller.\nconst useFocusController = (\n widgetRef: React.RefObject<GtkNs.Widget | null>,\n onFocus?: () => void,\n onBlur?: () => void,\n): void => {\n const handlers = useRef({ onFocus, onBlur })\n handlers.current = { onFocus, onBlur }\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n const focus = new Gtk.EventControllerFocus()\n const enter = (): void => handlers.current.onFocus?.()\n const leave = (): void => handlers.current.onBlur?.()\n focus.on(\"enter\", enter)\n focus.on(\"leave\", leave)\n widget.addController(focus)\n return () => {\n widget.removeController(focus)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n\n// Single-line input over GtkEntry. gtkx's controlled-text behavior keeps the\n// widget in sync with the `text` prop (RN controlled semantics); uncontrolled\n// usage passes defaultValue once.\nconst SingleLineTextInput = ({\n value,\n defaultValue,\n onChangeText,\n onSubmitEditing,\n onFocus,\n onBlur,\n placeholder,\n secureTextEntry = false,\n editable = true,\n keyboardType = \"default\",\n clearButtonMode = \"never\",\n style,\n onLayout,\n testID,\n}: TextInputProps) => {\n const widgetRef = useRef<GtkNs.Entry | null>(null)\n const [focused, setFocused] = useState(false)\n\n useLayoutChild(widgetRef, {\n style,\n onLayout,\n // The entry measures itself (theme-accurate height); width is driven by\n // the style (flex/width), with a small floor for usability.\n measureFromWidget: true,\n extraLayout: { minWidth: 60 },\n })\n\n const controlled = value !== undefined\n\n useFocusController(\n widgetRef,\n () => {\n setFocused(true)\n onFocus?.()\n },\n () => {\n setFocused(false)\n onBlur?.()\n },\n )\n\n // RN semantics: the affordance only shows when there is something to\n // clear, and while-editing / unless-editing follow focus.\n const text = controlled ? value : undefined\n const hasText =\n text !== undefined\n ? text.length > 0\n : (widgetRef.current?.getText().length ?? 0) > 0\n const showClear =\n hasText &&\n (clearButtonMode === \"always\" ||\n (clearButtonMode === \"while-editing\" && focused) ||\n (clearButtonMode === \"unless-editing\" && !focused))\n\n return (\n <GtkEntry\n ref={widgetRef}\n name={testID}\n secondaryIconName={showClear ? \"edit-clear-symbolic\" : null}\n secondaryIconActivatable={showClear}\n secondaryIconTooltipText={showClear ? \"Clear\" : null}\n onIconRelease={() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n // Uncontrolled inputs clear themselves; controlled ones report an\n // empty string and let the owner drive the value (RN contract).\n if (!controlled) {\n widget.setText(\"\")\n }\n onChangeText?.(\"\")\n }}\n text={controlled ? value : (defaultValue ?? \"\")}\n placeholderText={placeholder ?? \"\"}\n visibility={!secureTextEntry}\n editable={editable}\n sensitive={editable}\n inputPurpose={INPUT_PURPOSE[keyboardType]}\n onChanged={() => {\n const widget = widgetRef.current\n if (widget) {\n onChangeText?.(widget.getText())\n }\n }}\n onActivate={() => {\n const widget = widgetRef.current\n if (widget) {\n onSubmitEditing?.({ nativeEvent: { text: widget.getText() } })\n }\n }}\n />\n )\n}\n\nconst readBuffer = (buffer: GtkNs.TextBuffer): string =>\n buffer.getText(buffer.getStartIter(), buffer.getEndIter(), true)\n\n// GtkTextView has no native placeholder — a dim, click-transparent label\n// sits over the empty view (RN shows the placeholder while empty, focused\n// or not).\nconst MultilinePlaceholder = ({ text }: { text: string }) => {\n const labelRef = useRef<GtkNs.Label | null>(null)\n useLayoutChild(labelRef, {\n style: { position: \"absolute\", left: 12, top: 8 },\n onLayout: undefined,\n })\n useLayoutEffect(() => {\n labelRef.current?.setCanTarget(false)\n labelRef.current?.addCssClass(\"dim-label\")\n }, [])\n return (\n <GtkLabel\n ref={labelRef}\n label={text}\n />\n )\n}\n\n// Multiline input over GtkTextView in a GtkScrolledWindow: word wrap, the\n// style sets the box (RN requires a height for multiline), overflowing\n// content scrolls inside. The buffer syncs with `value` under RN controlled\n// semantics; Enter inserts a newline (onSubmitEditing never fires — RN\n// multiline behavior).\nconst MultilineTextInput = ({\n value,\n defaultValue,\n onChangeText,\n onFocus,\n onBlur,\n placeholder,\n editable = true,\n style,\n onLayout,\n testID,\n}: TextInputProps) => {\n const scrolledRef = useRef<GtkNs.ScrolledWindow | null>(null)\n const viewRef = useRef<GtkNs.TextView | null>(null)\n const controlled = value !== undefined\n const [empty, setEmpty] = useState(\n (controlled ? (value ?? \"\") : (defaultValue ?? \"\")) === \"\",\n )\n\n const suppressEcho = useRef(false)\n const latest = useRef({ onChangeText })\n latest.current = { onChangeText }\n\n useLayoutEffect(() => {\n const view = viewRef.current\n if (!view) {\n return\n }\n // Breathing room akin to GtkEntry's built-in padding.\n view.setLeftMargin(10)\n view.setRightMargin(10)\n view.setTopMargin(8)\n view.setBottomMargin(8)\n const buffer = view.getBuffer()\n const initial = controlled ? (value ?? \"\") : (defaultValue ?? \"\")\n if (initial !== \"\") {\n suppressEcho.current = true\n buffer.setText(initial, -1)\n suppressEcho.current = false\n }\n const changed = (): void => {\n const text = readBuffer(buffer)\n setEmpty(text === \"\")\n if (!suppressEcho.current) {\n latest.current.onChangeText?.(text)\n }\n }\n buffer.on(\"changed\", changed)\n return () => {\n buffer.off(\"changed\", changed)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // RN controlled semantics: the prop wins over whatever was typed.\n useLayoutEffect(() => {\n if (!controlled) {\n return\n }\n const view = viewRef.current\n if (!view) {\n return\n }\n const buffer = view.getBuffer()\n const next = value ?? \"\"\n if (readBuffer(buffer) !== next) {\n suppressEcho.current = true\n buffer.setText(next, -1)\n suppressEcho.current = false\n setEmpty(next === \"\")\n }\n }, [controlled, value])\n\n useFocusController(viewRef, onFocus, onBlur)\n\n return (\n <View\n style={[style, { minHeight: 36, minWidth: 60 }]}\n onLayout={onLayout}\n >\n <ScrolledFill scrolledRef={scrolledRef}>\n <GtkTextView\n ref={viewRef}\n name={testID}\n editable={editable}\n sensitive={editable}\n wrapMode={Gtk.WrapMode.WORD_CHAR}\n />\n </ScrolledFill>\n {empty && placeholder ? (\n <MultilinePlaceholder text={placeholder} />\n ) : null}\n </View>\n )\n}\n\n// The scrolled window fills the styled box exactly (its own layout child).\nconst ScrolledFill = ({\n scrolledRef,\n children,\n}: {\n scrolledRef: React.RefObject<GtkNs.ScrolledWindow | null>\n children: React.ReactNode\n}) => {\n useLayoutChild(scrolledRef, {\n style: { position: \"absolute\", left: 0, right: 0, top: 0, bottom: 0 },\n onLayout: undefined,\n })\n return <GtkScrolledWindow ref={scrolledRef}>{children}</GtkScrolledWindow>\n}\n\nexport const TextInput = (props: TextInputProps) =>\n props.multiline ? (\n <MultilineTextInput {...props} />\n ) : (\n <SingleLineTextInput {...props} />\n )\n"]}
|
|
1
|
+
{"version":3,"file":"text-input.js","sourceRoot":"","sources":["../../src/components/text-input.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, useState } from \"react\"\nimport type { StyleProp } from \"../contracts\"\nimport {\n Gtk,\n GtkEntry,\n GtkLabel,\n GtkScrolledWindow,\n GtkTextView,\n type Gtk as GtkNs,\n} from \"../gtkx/bridge/index\"\nimport { useLayoutChild, type LayoutEvent } from \"./use-layout-child\"\nimport { View } from \"./view\"\n\nexport type TextInputProps = {\n value?: string\n defaultValue?: string\n onChangeText?: (text: string) => void\n onSubmitEditing?: (event: { nativeEvent: { text: string } }) => void\n onFocus?: () => void\n onBlur?: () => void\n placeholder?: string\n secureTextEntry?: boolean\n editable?: boolean\n keyboardType?: \"default\" | \"numeric\" | \"email-address\" | \"phone-pad\" | \"url\"\n // RN: a multiline input needs a height in the style; Enter inserts a\n // newline and never fires onSubmitEditing.\n multiline?: boolean\n // RN's iOS-only clear affordance, native here: GtkEntry's built-in\n // secondary icon (inside the field, so nothing shifts around it).\n // Single-line only, like RN.\n clearButtonMode?: \"never\" | \"while-editing\" | \"unless-editing\" | \"always\"\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n testID?: string\n}\n\nconst INPUT_PURPOSE: Record<\n NonNullable<TextInputProps[\"keyboardType\"]>,\n Gtk.InputPurpose\n> = {\n default: Gtk.InputPurpose.FREE_FORM,\n numeric: Gtk.InputPurpose.NUMBER,\n \"email-address\": Gtk.InputPurpose.EMAIL,\n \"phone-pad\": Gtk.InputPurpose.PHONE,\n url: Gtk.InputPurpose.URL,\n}\n\n// The focus controller is attached imperatively (rc.3 also offers a\n// declarative `controllers` slot): one wiring per widget, handlers read from a\n// ref, so changing onFocus/onBlur never re-creates the controller.\nconst useFocusController = (\n widgetRef: React.RefObject<GtkNs.Widget | null>,\n onFocus?: () => void,\n onBlur?: () => void,\n): void => {\n const handlers = useRef({ onFocus, onBlur })\n handlers.current = { onFocus, onBlur }\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n const focus = new Gtk.EventControllerFocus()\n const enter = (): void => handlers.current.onFocus?.()\n const leave = (): void => handlers.current.onBlur?.()\n focus.on(\"enter\", enter)\n focus.on(\"leave\", leave)\n widget.addController(focus)\n return () => {\n widget.removeController(focus)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n\n// Single-line input over GtkEntry. gtkx's controlled-text behavior keeps the\n// widget in sync with the `text` prop (RN controlled semantics); uncontrolled\n// usage passes defaultValue once.\nconst SingleLineTextInput = ({\n value,\n defaultValue,\n onChangeText,\n onSubmitEditing,\n onFocus,\n onBlur,\n placeholder,\n secureTextEntry = false,\n editable = true,\n keyboardType = \"default\",\n clearButtonMode = \"never\",\n style,\n onLayout,\n testID,\n}: TextInputProps) => {\n const widgetRef = useRef<GtkNs.Entry | null>(null)\n const [focused, setFocused] = useState(false)\n\n useLayoutChild(widgetRef, {\n style,\n onLayout,\n // The entry measures itself (theme-accurate height); width is driven by\n // the style (flex/width), with a small floor for usability.\n measureFromWidget: true,\n extraLayout: { minWidth: 60 },\n })\n\n const controlled = value !== undefined\n\n useFocusController(\n widgetRef,\n () => {\n setFocused(true)\n onFocus?.()\n },\n () => {\n setFocused(false)\n onBlur?.()\n },\n )\n\n // RN semantics: the affordance only shows when there is something to\n // clear, and while-editing / unless-editing follow focus.\n const text = controlled ? value : undefined\n const hasText =\n text !== undefined\n ? text.length > 0\n : (widgetRef.current?.getText().length ?? 0) > 0\n const showClear =\n hasText &&\n (clearButtonMode === \"always\" ||\n (clearButtonMode === \"while-editing\" && focused) ||\n (clearButtonMode === \"unless-editing\" && !focused))\n\n return (\n <GtkEntry\n ref={widgetRef}\n name={testID}\n secondaryIconName={showClear ? \"edit-clear-symbolic\" : null}\n secondaryIconActivatable={showClear}\n secondaryIconTooltipText={showClear ? \"Clear\" : null}\n onIconRelease={() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n // Uncontrolled inputs clear themselves; controlled ones report an\n // empty string and let the owner drive the value (RN contract).\n if (!controlled) {\n widget.setText(\"\")\n }\n onChangeText?.(\"\")\n }}\n text={controlled ? value : (defaultValue ?? \"\")}\n placeholderText={placeholder ?? \"\"}\n visibility={!secureTextEntry}\n editable={editable}\n sensitive={editable}\n inputPurpose={INPUT_PURPOSE[keyboardType]}\n onChanged={() => {\n const widget = widgetRef.current\n if (widget) {\n onChangeText?.(widget.getText())\n }\n }}\n onActivate={() => {\n const widget = widgetRef.current\n if (widget) {\n onSubmitEditing?.({ nativeEvent: { text: widget.getText() } })\n }\n }}\n />\n )\n}\n\nconst readBuffer = (buffer: GtkNs.TextBuffer): string =>\n buffer.getText(buffer.getStartIter(), buffer.getEndIter(), true)\n\n// GtkTextView has no native placeholder — a dim, click-transparent label\n// sits over the empty view (RN shows the placeholder while empty, focused\n// or not).\nconst MultilinePlaceholder = ({ text }: { text: string }) => {\n const labelRef = useRef<GtkNs.Label | null>(null)\n useLayoutChild(labelRef, {\n style: { position: \"absolute\", left: 12, top: 8 },\n onLayout: undefined,\n })\n useLayoutEffect(() => {\n labelRef.current?.setCanTarget(false)\n labelRef.current?.addCssClass(\"dim-label\")\n }, [])\n return (\n <GtkLabel\n ref={labelRef}\n label={text}\n />\n )\n}\n\n// Multiline input over GtkTextView in a GtkScrolledWindow: word wrap, the\n// style sets the box (RN requires a height for multiline), overflowing\n// content scrolls inside. The buffer syncs with `value` under RN controlled\n// semantics; Enter inserts a newline (onSubmitEditing never fires — RN\n// multiline behavior).\nconst MultilineTextInput = ({\n value,\n defaultValue,\n onChangeText,\n onFocus,\n onBlur,\n placeholder,\n editable = true,\n style,\n onLayout,\n testID,\n}: TextInputProps) => {\n const scrolledRef = useRef<GtkNs.ScrolledWindow | null>(null)\n const viewRef = useRef<GtkNs.TextView | null>(null)\n const controlled = value !== undefined\n const [empty, setEmpty] = useState(\n (controlled ? (value ?? \"\") : (defaultValue ?? \"\")) === \"\",\n )\n\n const suppressEcho = useRef(false)\n const latest = useRef({ onChangeText })\n latest.current = { onChangeText }\n\n useLayoutEffect(() => {\n const view = viewRef.current\n if (!view) {\n return\n }\n // Breathing room akin to GtkEntry's built-in padding.\n view.setLeftMargin(10)\n view.setRightMargin(10)\n view.setTopMargin(8)\n view.setBottomMargin(8)\n const buffer = view.getBuffer()\n const initial = controlled ? (value ?? \"\") : (defaultValue ?? \"\")\n if (initial !== \"\") {\n suppressEcho.current = true\n buffer.setText(initial, -1)\n suppressEcho.current = false\n }\n const changed = (): void => {\n const text = readBuffer(buffer)\n setEmpty(text === \"\")\n if (!suppressEcho.current) {\n latest.current.onChangeText?.(text)\n }\n }\n buffer.on(\"changed\", changed)\n return () => {\n buffer.off(\"changed\", changed)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // RN controlled semantics: the prop wins over whatever was typed.\n useLayoutEffect(() => {\n if (!controlled) {\n return\n }\n const view = viewRef.current\n if (!view) {\n return\n }\n const buffer = view.getBuffer()\n const next = value ?? \"\"\n if (readBuffer(buffer) !== next) {\n suppressEcho.current = true\n buffer.setText(next, -1)\n suppressEcho.current = false\n setEmpty(next === \"\")\n }\n }, [controlled, value])\n\n useFocusController(viewRef, onFocus, onBlur)\n\n return (\n <View\n style={[style, { minHeight: 36, minWidth: 60 }]}\n onLayout={onLayout}\n >\n <ScrolledFill scrolledRef={scrolledRef}>\n <GtkTextView\n ref={viewRef}\n name={testID}\n editable={editable}\n sensitive={editable}\n wrapMode={Gtk.WrapMode.WORD_CHAR}\n />\n </ScrolledFill>\n {empty && placeholder ? (\n <MultilinePlaceholder text={placeholder} />\n ) : null}\n </View>\n )\n}\n\n// The scrolled window fills the styled box exactly (its own layout child).\nconst ScrolledFill = ({\n scrolledRef,\n children,\n}: {\n scrolledRef: React.RefObject<GtkNs.ScrolledWindow | null>\n children: React.ReactNode\n}) => {\n useLayoutChild(scrolledRef, {\n style: { position: \"absolute\", left: 0, right: 0, top: 0, bottom: 0 },\n onLayout: undefined,\n })\n return <GtkScrolledWindow ref={scrolledRef}>{children}</GtkScrolledWindow>\n}\n\nexport const TextInput = (props: TextInputProps) =>\n props.multiline ? (\n <MultilineTextInput {...props} />\n ) : (\n <SingleLineTextInput {...props} />\n )\n"]}
|