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
package/dist/components/text.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
3
|
-
import { textAlignToLabelProps } from "../style/index";
|
|
3
|
+
import { textAlignToLabelProps, textDecorationToAttrs } from "../style/index";
|
|
4
4
|
import { createTextProbe, Gtk, GtkLabel, measureWidget, Pango, } from "../gtkx/bridge/index";
|
|
5
5
|
import { useLayoutChild } from "./use-layout-child";
|
|
6
6
|
const flattenToString = (children) => {
|
|
@@ -33,10 +33,19 @@ export const Text = ({ style, onLayout, numberOfLines, children, testID, }) => {
|
|
|
33
33
|
const measuredLines = useRef(1);
|
|
34
34
|
const measure = useMemo(() => {
|
|
35
35
|
return (width, widthMode) => {
|
|
36
|
-
const natural = measureWidget(probe, "horizontal")
|
|
36
|
+
const { minimum, natural } = measureWidget(probe, "horizontal");
|
|
37
|
+
// Floor at the probe's own minimum width, not at 1: gtk_widget_measure()
|
|
38
|
+
// clamps a height-for-width query up to the widget's minimum before
|
|
39
|
+
// computing regardless of what we pass (logging "Trying to measure
|
|
40
|
+
// GtkLabel for width of N, but it needs at least M" while doing it), so
|
|
41
|
+
// asking for anything below `minimum` was never honored — the height
|
|
42
|
+
// below was already being computed at `minimum`, not at our `used`.
|
|
43
|
+
// Clamping here ourselves gets the same height GTK would give us
|
|
44
|
+
// anyway, keeps the returned width consistent with it, and drops the
|
|
45
|
+
// warning as a side effect rather than the goal.
|
|
37
46
|
const used = widthMode === "undefined"
|
|
38
47
|
? natural
|
|
39
|
-
: Math.min(natural, Math.max(
|
|
48
|
+
: Math.min(natural, Math.max(minimum, Math.floor(width)));
|
|
40
49
|
const height = measureWidget(probe, "vertical", used).natural;
|
|
41
50
|
const singleLine = measureWidget(probe, "vertical", natural).natural;
|
|
42
51
|
measuredLines.current =
|
|
@@ -88,6 +97,30 @@ export const Text = ({ style, onLayout, numberOfLines, children, testID, }) => {
|
|
|
88
97
|
node.markDirty();
|
|
89
98
|
}, [probe, node, text, numberOfLines, cssClass]);
|
|
90
99
|
const align = textAlignToLabelProps(flat.textAlign);
|
|
100
|
+
// textDecorationLine goes through Pango, not CSS: GTK4 has no widget
|
|
101
|
+
// `text-decoration`. Built here rather than in the style module so that
|
|
102
|
+
// module stays bridge-free and unit-testable off Linux — the same split
|
|
103
|
+
// textAlign already uses.
|
|
104
|
+
//
|
|
105
|
+
// The attribute list is applied to the PROBE as well, because it is what
|
|
106
|
+
// Yoga measures: Pango reserves room for an underline below the baseline,
|
|
107
|
+
// so a decorated label measured undecorated would be a pixel short.
|
|
108
|
+
const decoration = textDecorationToAttrs(flat.textDecorationLine);
|
|
109
|
+
const decorated = decoration.underline || decoration.strikethrough;
|
|
110
|
+
useLayoutEffect(() => {
|
|
111
|
+
const attrs = decorated ? Pango.AttrList.new() : null;
|
|
112
|
+
if (attrs) {
|
|
113
|
+
if (decoration.underline) {
|
|
114
|
+
attrs.insert(Pango.attrUnderlineNew(Pango.Underline.SINGLE));
|
|
115
|
+
}
|
|
116
|
+
if (decoration.strikethrough) {
|
|
117
|
+
attrs.insert(Pango.attrStrikethroughNew(true));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
widgetRef.current?.setAttributes(attrs);
|
|
121
|
+
probe.setAttributes(attrs);
|
|
122
|
+
node.markDirty();
|
|
123
|
+
}, [probe, node, decorated, decoration.underline, decoration.strikethrough]);
|
|
91
124
|
return (_jsx(GtkLabel, { ref: widgetRef, name: testID, label: text, wrap: true, xalign: align.xalign, yalign: 0, justify: JUSTIFICATION[align.justification], lines: numberOfLines,
|
|
92
125
|
// RN semantics: the ellipsis is opt-in via numberOfLines. Plain text
|
|
93
126
|
// wraps naturally; an unbreakable word wider than the rect just clips
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/components/text.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,eAAe,EACf,OAAO,EACP,MAAM,EACN,QAAQ,GAET,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,OAAO,EACL,eAAe,EACf,GAAG,EACH,QAAQ,EACR,aAAa,EACb,KAAK,GACN,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,cAAc,EAAoB,MAAM,oBAAoB,CAAA;AAUrE,MAAM,eAAe,GAAG,CAAC,QAAmB,EAAU,EAAE;IACtD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;QACtE,OAAO,EAAE,CAAA;IACX,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,OAAO,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC/C,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAA;AACzB,CAAC,CAAA;AAED,MAAM,aAAa,GAAG;IACpB,IAAI,EAAE,GAAG,CAAC,aAAa,CAAC,IAAI;IAC5B,KAAK,EAAE,GAAG,CAAC,aAAa,CAAC,KAAK;IAC9B,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,MAAM;IAChC,IAAI,EAAE,GAAG,CAAC,aAAa,CAAC,IAAI;CACpB,CAAA;AAEV,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EACnB,KAAK,EACL,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,MAAM,GACI,EAAE,EAAE;IACd,MAAM,SAAS,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAA;IAChD,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAA;IAEtC,6EAA6E;IAC7E,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAY,GAAG,EAAE,CAAC,eAAe,EAAE,CAAC,CAAA;IAE5D,MAAM,cAAc,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAA;IAElD,yEAAyE;IACzE,uEAAuE;IACvE,oDAAoD;IACpD,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IAE/B,MAAM,OAAO,GAAG,OAAO,CAAY,GAAG,EAAE;QACtC,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YAC1B,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,OAAO,CAAA;YAC1D,MAAM,IAAI,GACR,SAAS,KAAK,WAAW;gBACvB,CAAC,CAAC,OAAO;gBACT,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YACvD,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC,OAAO,CAAA;YAC7D,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,OAAO,CAAA;YACpE,aAAa,CAAC,OAAO;gBACnB,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACnE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QAChC,CAAC,CAAA;QACD,oEAAoE;QACpE,uDAAuD;IACzD,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,eAAe,GAAG,OAAO,CAC7B,GAAG,EAAE,CAAC,CAAC,KAAkB,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAA;QAC/B,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,QAAQ,CAAC,aAAa,IAAI,aAAa,CAAC,OAAO,CAAC,CAAA;QACxD,CAAC;QACD,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAA;IACnB,CAAC,EACD,CAAC,aAAa,EAAE,QAAQ,CAAC,CAC1B,CAAA;IAED,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,SAAS,EAAE;QACzD,KAAK;QACL,QAAQ,EAAE,eAAe;QACzB,OAAO;KACR,CAAC,CAAA;IAEF,wEAAwE;IACxE,2EAA2E;IAC3E,0DAA0D;IAC1D,eAAe,CAAC,GAAG,EAAE;QACnB,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACrD,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,oEAAoE;IACpE,yDAAyD;IACzD,eAAe,CAAC,GAAG,EAAE;QACnB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACnB,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAA;YAC7B,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;QAC7C,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;YAClB,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;QAC9C,CAAC;QACD,IAAI,cAAc,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACxC,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;gBAC3B,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;YAC9C,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBACb,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;YAC7B,CAAC;YACD,cAAc,CAAC,OAAO,GAAG,QAAQ,CAAA;QACnC,CAAC;QACD,IAAI,CAAC,SAAS,EAAE,CAAA;IAClB,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEhD,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAEnD,OAAO,CACL,KAAC,QAAQ,IACP,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,IAAI,EACX,IAAI,QACJ,MAAM,EAAE,KAAK,CAAC,MAAM,EACpB,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,aAAa,CAAC,EAC3C,KAAK,EAAE,aAAa;QACpB,qEAAqE;QACrE,sEAAsE;QACtE,kEAAkE;QAClE,qEAAqE;QACrE,SAAS,EACP,aAAa,KAAK,SAAS;YACzB,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG;YACzB,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAE9B,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,GACtC,CACH,CAAA;AACH,CAAC,CAAA","sourcesContent":["import {\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\"\nimport { textAlignToLabelProps } from \"../style/index\"\nimport type { MeasureFn, StyleProp } from \"../contracts\"\nimport {\n createTextProbe,\n Gtk,\n GtkLabel,\n measureWidget,\n Pango,\n} from \"../gtkx/bridge/index\"\nimport { useLayoutChild, type LayoutEvent } from \"./use-layout-child\"\n\nexport type TextProps = {\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n numberOfLines?: number\n children?: ReactNode\n testID?: string\n}\n\nconst flattenToString = (children: ReactNode): string => {\n if (children === null || children === undefined || children === false) {\n return \"\"\n }\n if (Array.isArray(children)) {\n return children.map(flattenToString).join(\"\")\n }\n return String(children)\n}\n\nconst JUSTIFICATION = {\n left: Gtk.Justification.LEFT,\n right: Gtk.Justification.RIGHT,\n center: Gtk.Justification.CENTER,\n fill: Gtk.Justification.FILL,\n} as const\n\n// Text is a measured Yoga leaf: an offscreen probe label (with the same CSS\n// class, so fonts match) feeds Pango metrics into the layout engine; the\n// visible GtkLabel is positioned by the commit hook like any other widget.\nexport const Text = ({\n style,\n onLayout,\n numberOfLines,\n children,\n testID,\n}: TextProps) => {\n const widgetRef = useRef<Gtk.Label | null>(null)\n const text = flattenToString(children)\n\n // useState lazy init — see the note in use-layout-child.ts (React Compiler).\n const [probe] = useState<Gtk.Label>(() => createTextProbe())\n\n const lastProbeClass = useRef<string | null>(null)\n\n // GTK collapses wrap+ellipsize labels to a single line unless `lines` is\n // set explicitly — remember how many lines the probe wrapped into, the\n // layout callback pushes it onto the visible label.\n const measuredLines = useRef(1)\n\n const measure = useMemo<MeasureFn>(() => {\n return (width, widthMode) => {\n const natural = measureWidget(probe, \"horizontal\").natural\n const used =\n widthMode === \"undefined\"\n ? natural\n : Math.min(natural, Math.max(1, Math.floor(width)))\n const height = measureWidget(probe, \"vertical\", used).natural\n const singleLine = measureWidget(probe, \"vertical\", natural).natural\n measuredLines.current =\n singleLine > 0 ? Math.max(1, Math.round(height / singleLine)) : 1\n return { width: used, height }\n }\n // The probe is stable; re-measure is triggered via markDirty below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const layoutWithLines = useMemo(\n () => (event: LayoutEvent) => {\n const label = widgetRef.current\n if (label) {\n label.setLines(numberOfLines ?? measuredLines.current)\n }\n onLayout?.(event)\n },\n [numberOfLines, onLayout],\n )\n\n const { node, cssClass, flat } = useLayoutChild(widgetRef, {\n style,\n onLayout: layoutWithLines,\n measure,\n })\n\n // RN text clips to its box: an under-allocated GtkLabel would otherwise\n // paint its full text past the allocation (spike finding). Containers keep\n // overflow VISIBLE (paint-overflow); the text leaf clips.\n useLayoutEffect(() => {\n widgetRef.current?.setOverflow(Gtk.Overflow.HIDDEN)\n }, [])\n\n // Keep the probe in sync with everything that affects metrics, then\n // invalidate the Yoga leaf so the next pass re-measures.\n useLayoutEffect(() => {\n probe.setText(text)\n if (numberOfLines !== undefined) {\n probe.setLines(numberOfLines)\n probe.setEllipsize(Pango.EllipsizeMode.END)\n } else {\n probe.setLines(-1)\n probe.setEllipsize(Pango.EllipsizeMode.NONE)\n }\n if (lastProbeClass.current !== cssClass) {\n if (lastProbeClass.current) {\n probe.removeCssClass(lastProbeClass.current)\n }\n if (cssClass) {\n probe.addCssClass(cssClass)\n }\n lastProbeClass.current = cssClass\n }\n node.markDirty()\n }, [probe, node, text, numberOfLines, cssClass])\n\n const align = textAlignToLabelProps(flat.textAlign)\n\n return (\n <GtkLabel\n ref={widgetRef}\n name={testID}\n label={text}\n wrap\n xalign={align.xalign}\n yalign={0}\n justify={JUSTIFICATION[align.justification]}\n lines={numberOfLines}\n // RN semantics: the ellipsis is opt-in via numberOfLines. Plain text\n // wraps naturally; an unbreakable word wider than the rect just clips\n // (overflow HIDDEN above) — the layout manager allocates the rect\n // regardless of the label's own minimum, so nothing pushes siblings.\n ellipsize={\n numberOfLines !== undefined\n ? Pango.EllipsizeMode.END\n : Pango.EllipsizeMode.NONE\n }\n cssClasses={cssClass ? [cssClass] : []}\n />\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/components/text.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\"\nimport { textAlignToLabelProps, textDecorationToAttrs } from \"../style/index\"\nimport type { MeasureFn, StyleProp } from \"../contracts\"\nimport {\n createTextProbe,\n Gtk,\n GtkLabel,\n measureWidget,\n Pango,\n} from \"../gtkx/bridge/index\"\nimport { useLayoutChild, type LayoutEvent } from \"./use-layout-child\"\n\nexport type TextProps = {\n style?: StyleProp\n onLayout?: (event: LayoutEvent) => void\n numberOfLines?: number\n children?: ReactNode\n testID?: string\n}\n\nconst flattenToString = (children: ReactNode): string => {\n if (children === null || children === undefined || children === false) {\n return \"\"\n }\n if (Array.isArray(children)) {\n return children.map(flattenToString).join(\"\")\n }\n return String(children)\n}\n\nconst JUSTIFICATION = {\n left: Gtk.Justification.LEFT,\n right: Gtk.Justification.RIGHT,\n center: Gtk.Justification.CENTER,\n fill: Gtk.Justification.FILL,\n} as const\n\n// Text is a measured Yoga leaf: an offscreen probe label (with the same CSS\n// class, so fonts match) feeds Pango metrics into the layout engine; the\n// visible GtkLabel is positioned by the commit hook like any other widget.\nexport const Text = ({\n style,\n onLayout,\n numberOfLines,\n children,\n testID,\n}: TextProps) => {\n const widgetRef = useRef<Gtk.Label | null>(null)\n const text = flattenToString(children)\n\n // useState lazy init — see the note in use-layout-child.ts (React Compiler).\n const [probe] = useState<Gtk.Label>(() => createTextProbe())\n\n const lastProbeClass = useRef<string | null>(null)\n\n // GTK collapses wrap+ellipsize labels to a single line unless `lines` is\n // set explicitly — remember how many lines the probe wrapped into, the\n // layout callback pushes it onto the visible label.\n const measuredLines = useRef(1)\n\n const measure = useMemo<MeasureFn>(() => {\n return (width, widthMode) => {\n const { minimum, natural } = measureWidget(probe, \"horizontal\")\n // Floor at the probe's own minimum width, not at 1: gtk_widget_measure()\n // clamps a height-for-width query up to the widget's minimum before\n // computing regardless of what we pass (logging \"Trying to measure\n // GtkLabel for width of N, but it needs at least M\" while doing it), so\n // asking for anything below `minimum` was never honored — the height\n // below was already being computed at `minimum`, not at our `used`.\n // Clamping here ourselves gets the same height GTK would give us\n // anyway, keeps the returned width consistent with it, and drops the\n // warning as a side effect rather than the goal.\n const used =\n widthMode === \"undefined\"\n ? natural\n : Math.min(natural, Math.max(minimum, Math.floor(width)))\n const height = measureWidget(probe, \"vertical\", used).natural\n const singleLine = measureWidget(probe, \"vertical\", natural).natural\n measuredLines.current =\n singleLine > 0 ? Math.max(1, Math.round(height / singleLine)) : 1\n return { width: used, height }\n }\n // The probe is stable; re-measure is triggered via markDirty below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const layoutWithLines = useMemo(\n () => (event: LayoutEvent) => {\n const label = widgetRef.current\n if (label) {\n label.setLines(numberOfLines ?? measuredLines.current)\n }\n onLayout?.(event)\n },\n [numberOfLines, onLayout],\n )\n\n const { node, cssClass, flat } = useLayoutChild(widgetRef, {\n style,\n onLayout: layoutWithLines,\n measure,\n })\n\n // RN text clips to its box: an under-allocated GtkLabel would otherwise\n // paint its full text past the allocation (spike finding). Containers keep\n // overflow VISIBLE (paint-overflow); the text leaf clips.\n useLayoutEffect(() => {\n widgetRef.current?.setOverflow(Gtk.Overflow.HIDDEN)\n }, [])\n\n // Keep the probe in sync with everything that affects metrics, then\n // invalidate the Yoga leaf so the next pass re-measures.\n useLayoutEffect(() => {\n probe.setText(text)\n if (numberOfLines !== undefined) {\n probe.setLines(numberOfLines)\n probe.setEllipsize(Pango.EllipsizeMode.END)\n } else {\n probe.setLines(-1)\n probe.setEllipsize(Pango.EllipsizeMode.NONE)\n }\n if (lastProbeClass.current !== cssClass) {\n if (lastProbeClass.current) {\n probe.removeCssClass(lastProbeClass.current)\n }\n if (cssClass) {\n probe.addCssClass(cssClass)\n }\n lastProbeClass.current = cssClass\n }\n node.markDirty()\n }, [probe, node, text, numberOfLines, cssClass])\n\n const align = textAlignToLabelProps(flat.textAlign)\n\n // textDecorationLine goes through Pango, not CSS: GTK4 has no widget\n // `text-decoration`. Built here rather than in the style module so that\n // module stays bridge-free and unit-testable off Linux — the same split\n // textAlign already uses.\n //\n // The attribute list is applied to the PROBE as well, because it is what\n // Yoga measures: Pango reserves room for an underline below the baseline,\n // so a decorated label measured undecorated would be a pixel short.\n const decoration = textDecorationToAttrs(flat.textDecorationLine)\n const decorated = decoration.underline || decoration.strikethrough\n useLayoutEffect(() => {\n const attrs = decorated ? Pango.AttrList.new() : null\n if (attrs) {\n if (decoration.underline) {\n attrs.insert(Pango.attrUnderlineNew(Pango.Underline.SINGLE))\n }\n if (decoration.strikethrough) {\n attrs.insert(Pango.attrStrikethroughNew(true))\n }\n }\n widgetRef.current?.setAttributes(attrs)\n probe.setAttributes(attrs)\n node.markDirty()\n }, [probe, node, decorated, decoration.underline, decoration.strikethrough])\n\n return (\n <GtkLabel\n ref={widgetRef}\n name={testID}\n label={text}\n wrap\n xalign={align.xalign}\n yalign={0}\n justify={JUSTIFICATION[align.justification]}\n lines={numberOfLines}\n // RN semantics: the ellipsis is opt-in via numberOfLines. Plain text\n // wraps naturally; an unbreakable word wider than the rect just clips\n // (overflow HIDDEN above) — the layout manager allocates the rect\n // regardless of the label's own minimum, so nothing pushes siblings.\n ellipsize={\n numberOfLines !== undefined\n ? Pango.EllipsizeMode.END\n : Pango.EllipsizeMode.NONE\n }\n cssClasses={cssClass ? [cssClass] : []}\n />\n )\n}\n"]}
|
|
@@ -4,7 +4,7 @@ import { defaultCssRegistry } from "../style/registry.gtkx";
|
|
|
4
4
|
import { allocateChild, attachRnLayout, detachRnLayout, measureWidget, queueAllocate, queueResize, } from "../gtkx/bridge/index";
|
|
5
5
|
import { perfAddTime, perfBurst, perfCount, perfEnabled, perfNow, } from "../perf";
|
|
6
6
|
import { useHostNode } from "./host-node";
|
|
7
|
-
import { deferDuringAllocate, getStoredOffset, getStoredRect, setStoredRect, } from "./rect-store";
|
|
7
|
+
import { deferDuringAllocate, getStoredOffset, getStoredRect, setStoredRect, setStoredTransform, } from "./rect-store";
|
|
8
8
|
// Perf: sizeAllocate recurses synchronously into child containers, so a
|
|
9
9
|
// naive per-pass timer double-counts nested passes. Track depth and time
|
|
10
10
|
// only the outermost (top-level) allocate — that is the real wall time GTK
|
|
@@ -32,6 +32,25 @@ export const useLayoutChild = (widgetRef, options) => {
|
|
|
32
32
|
node.setStyle(JSON.parse(layoutKey));
|
|
33
33
|
}, [node, layoutKey]);
|
|
34
34
|
const cssClass = defaultCssRegistry.getClassName(visual);
|
|
35
|
+
// RN transforms are visual only: the widget keeps the box Yoga gave it, so
|
|
36
|
+
// a transform never touches the shadow tree — it only asks the parent
|
|
37
|
+
// container to run its allocate hook again. Keyed on the serialized array
|
|
38
|
+
// so a re-render with the same transform costs nothing.
|
|
39
|
+
// (Animated.View owns its own transform and strips it from the static
|
|
40
|
+
// style before it gets here, so the two writers never race.)
|
|
41
|
+
const transformKey = JSON.stringify(visual.transform ?? null);
|
|
42
|
+
useLayoutEffect(() => {
|
|
43
|
+
const widget = widgetRef.current;
|
|
44
|
+
if (!widget) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
setStoredTransform(widget, JSON.parse(transformKey));
|
|
48
|
+
const parentWidget = host.widgetRef.current;
|
|
49
|
+
if (parentWidget) {
|
|
50
|
+
queueAllocate(parentWidget);
|
|
51
|
+
}
|
|
52
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
53
|
+
}, [transformKey]);
|
|
35
54
|
useLayoutEffect(() => {
|
|
36
55
|
const parent = host.node;
|
|
37
56
|
// The reconciler has already attached our widget in JSX order, so its
|
|
@@ -59,6 +78,29 @@ export const useLayoutChild = (widgetRef, options) => {
|
|
|
59
78
|
return;
|
|
60
79
|
}
|
|
61
80
|
const previous = getStoredRect(widget);
|
|
81
|
+
// A commit does not imply a change. The engine may hand us the rect a
|
|
82
|
+
// widget already has — nodes carrying a measure function are visited
|
|
83
|
+
// even when Yoga did not move them — and queueing an allocation for
|
|
84
|
+
// those makes GTK re-allocate and re-snapshot the container for nothing.
|
|
85
|
+
//
|
|
86
|
+
// `rect.skip` counts how often this guard actually fires and
|
|
87
|
+
// `rect.change` how often it does not, because a guard nobody can see
|
|
88
|
+
// firing is a guard nobody can attribute a measurement to: this one was
|
|
89
|
+
// once credited with a large maximized-window win that a later, properly
|
|
90
|
+
// geometry-controlled run could not reproduce (docs/research/
|
|
91
|
+
// scroll-performance.md, round six). Keep it — it is correct and free —
|
|
92
|
+
// but read the counter before crediting it with anything.
|
|
93
|
+
const unchanged = previous !== undefined &&
|
|
94
|
+
previous.x === rect.x &&
|
|
95
|
+
previous.y === rect.y &&
|
|
96
|
+
previous.width === rect.width &&
|
|
97
|
+
previous.height === rect.height;
|
|
98
|
+
if (perfEnabled) {
|
|
99
|
+
perfCount(unchanged ? "rect.skip" : "rect.change");
|
|
100
|
+
}
|
|
101
|
+
if (unchanged) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
62
104
|
setStoredRect(widget, rect);
|
|
63
105
|
const sizeChanged = !previous ||
|
|
64
106
|
previous.width !== rect.width ||
|
|
@@ -102,10 +144,14 @@ export const useLayoutChild = (widgetRef, options) => {
|
|
|
102
144
|
if (!widget) {
|
|
103
145
|
return { width: 0, height: 0 };
|
|
104
146
|
}
|
|
105
|
-
const natural = measureWidget(widget, "horizontal")
|
|
147
|
+
const { minimum, natural } = measureWidget(widget, "horizontal");
|
|
148
|
+
// Floor at the widget's own minimum width, not at 1 — see the same
|
|
149
|
+
// clamp in text.tsx's measure for why: gtk_widget_measure() enforces
|
|
150
|
+
// this floor internally regardless of what we request (warning while
|
|
151
|
+
// it does), so anything below `minimum` was never actually honored.
|
|
106
152
|
const used = widthMode === "undefined"
|
|
107
153
|
? natural
|
|
108
|
-
: Math.min(natural, Math.max(
|
|
154
|
+
: Math.min(natural, Math.max(minimum, Math.floor(width)));
|
|
109
155
|
return {
|
|
110
156
|
width: used,
|
|
111
157
|
height: measureWidget(widget, "vertical", used).natural,
|
|
@@ -171,7 +217,7 @@ export const useRnContainer = (widgetRef, node, options) => {
|
|
|
171
217
|
const rect = getStoredRect(child);
|
|
172
218
|
if (rect) {
|
|
173
219
|
const offset = getStoredOffset(child);
|
|
174
|
-
allocateChild(child, rect.x + offset.dx, rect.y + offset.dy, rect.width, rect.height);
|
|
220
|
+
allocateChild(child, rect.x + offset.dx, rect.y + offset.dy, rect.width, rect.height, offset.matrix);
|
|
175
221
|
children += 1;
|
|
176
222
|
}
|
|
177
223
|
child = child.getNextSibling();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-layout-child.js","sourceRoot":"","sources":["../../src/components/use-layout-child.ts"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, useState, type RefObject } from \"react\"\nimport type { LayoutNode } from \"../layout/index\"\nimport { splitStyle, StyleSheet } from \"../style/index\"\nimport { defaultCssRegistry } from \"../style/registry.gtkx\"\nimport type {\n LayoutStyle,\n MeasureFn,\n Rect,\n StyleProp,\n VisualStyle,\n} from \"../contracts\"\nimport {\n allocateChild,\n attachRnLayout,\n detachRnLayout,\n measureWidget,\n queueAllocate,\n queueResize,\n type Gtk,\n} from \"../gtkx/bridge/index\"\nimport {\n perfAddTime,\n perfBurst,\n perfCount,\n perfEnabled,\n perfNow,\n} from \"../perf\"\nimport { useHostNode, type HostNode } from \"./host-node\"\nimport {\n deferDuringAllocate,\n getStoredOffset,\n getStoredRect,\n setStoredRect,\n} from \"./rect-store\"\n\nexport type LayoutEvent = {\n nativeEvent: {\n layout: { x: number; y: number; width: number; height: number }\n }\n}\n\n// Perf: sizeAllocate recurses synchronously into child containers, so a\n// naive per-pass timer double-counts nested passes. Track depth and time\n// only the outermost (top-level) allocate — that is the real wall time GTK\n// spends in OUR layout code for the frame.\nlet perfAllocDepth = 0\n\nexport type LayoutChildOptions = {\n style: StyleProp | undefined\n onLayout: ((event: LayoutEvent) => void) | undefined\n measure?: MeasureFn\n // Leaves with intrinsic GTK sizes (Entry, Switch, Spinner) measure their\n // own widget so Yoga reserves exactly what the theme will draw.\n measureFromWidget?: boolean\n extraLayout?: LayoutStyle\n}\n\nexport type LayoutChild = {\n host: HostNode\n node: LayoutNode\n flat: ReturnType<typeof StyleSheet.flatten>\n visual: VisualStyle\n cssClass: string | null\n}\n\n// Shared plumbing for every leaf/container component: owns one LayoutNode,\n// keeps it in the parent's shadow tree for the component lifetime, applies\n// the layout half of the style and commits Yoga rects into the rect store,\n// where the parent container's RnGtkxLayout allocate() picks them up.\nexport const useLayoutChild = (\n widgetRef: RefObject<Gtk.Widget | null>,\n options: LayoutChildOptions,\n): LayoutChild => {\n const host = useHostNode()\n\n // useState's lazy initializer is guaranteed once-per-instance even under\n // the React Compiler — a lazy ref here got its creation memoized ACROSS\n // component instances, sharing one Yoga node and double-freeing it.\n const [node] = useState<LayoutNode>(() => host.engine.createNode())\n\n const flat = StyleSheet.flatten(options.style)\n const { layout, visual } = splitStyle(flat)\n const effectiveLayout = options.extraLayout\n ? { ...layout, ...options.extraLayout }\n : layout\n\n // Re-apply layout style only when it actually changed (keyed effect) —\n // setStyle dirties the whole tree.\n const layoutKey = JSON.stringify(effectiveLayout)\n useLayoutEffect(() => {\n node.setStyle(JSON.parse(layoutKey) as LayoutStyle)\n }, [node, layoutKey])\n\n const cssClass = defaultCssRegistry.getClassName(visual)\n\n useLayoutEffect(() => {\n const parent = host.node\n // The reconciler has already attached our widget in JSX order, so its\n // sibling position is the correct Yoga index — this keeps the shadow tree\n // ordered even for mid-list mounts (conditional children, list inserts).\n const widget = widgetRef.current\n const parentWidget = host.widgetRef.current\n let index = parent.children.length\n if (widget && parentWidget) {\n let position = 0\n let sibling = parentWidget.getFirstChild()\n while (sibling !== null && sibling !== widget) {\n position += 1\n sibling = sibling.getNextSibling()\n }\n if (sibling === widget) {\n index = Math.min(position, parent.children.length)\n }\n }\n parent.insertChild(node, index)\n node.setCommit((rect: Rect) => {\n const widget = widgetRef.current\n const parentWidget = host.widgetRef.current\n if (!widget || !parentWidget) {\n return\n }\n const previous = getStoredRect(widget)\n setStoredRect(widget, rect)\n const sizeChanged =\n !previous ||\n previous.width !== rect.width ||\n previous.height !== rect.height\n const queue = (): void => {\n if (sizeChanged) {\n // A size change invalidates this widget's cached measure (nested\n // managers, ScrolledWindow ranges) and re-allocates the ancestors.\n queueResize(widget)\n } else {\n // Pure move: the parent just needs another allocation pass. GTK\n // dedupes queued allocates, so per-child calls batch into one.\n queueAllocate(parentWidget)\n }\n }\n if (!deferDuringAllocate(widget, queue)) {\n queue()\n }\n })\n return () => {\n node.setCommit(null)\n parent.removeChild(node)\n node.free()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const onLayout = options.onLayout\n useLayoutEffect(() => {\n node.setOnLayout(\n onLayout\n ? (rect: Rect) => {\n onLayout({ nativeEvent: { layout: rect } })\n }\n : null,\n )\n }, [node, onLayout])\n\n // The explicit return type keeps the inner params contextually typed: with a\n // bare lazy initializer TS may match the outer arrow against MeasureFn\n // itself (useState accepts S | () => S) and drop the context.\n const [widgetMeasure] = useState<MeasureFn>(\n (): MeasureFn => (width, widthMode) => {\n const widget = widgetRef.current\n if (!widget) {\n return { width: 0, height: 0 }\n }\n const natural = measureWidget(widget, \"horizontal\").natural\n const used =\n widthMode === \"undefined\"\n ? natural\n : Math.min(natural, Math.max(1, Math.floor(width)))\n return {\n width: used,\n height: measureWidget(widget, \"vertical\", used).natural,\n }\n },\n )\n const measure =\n options.measure ?? (options.measureFromWidget ? widgetMeasure : undefined)\n useLayoutEffect(() => {\n if (!measure) {\n return\n }\n node.setMeasureFn(measure)\n // Widgets measured before their window is mapped report zero (no realized\n // theme context yet, unlike offscreen probes) and Yoga caches it —\n // invalidate once the widget actually maps.\n const widget = widgetRef.current\n const remeasure = (): void => {\n node.markDirty()\n }\n if (options.measureFromWidget && widget) {\n widget.on(\"map\", remeasure)\n }\n return () => {\n if (options.measureFromWidget && widget) {\n widget.off(\"map\", remeasure)\n }\n // Cleared by free() on unmount; explicit unset only when measure is\n // removed while mounted.\n node.setMeasureFn(null)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [node, measure])\n\n return { host, node, flat, visual, cssClass }\n}\n\nexport type RnContainerOptions = {\n // Overrides the default engine-rect measure (the window root reports 0 so\n // the window can shrink freely below the current content size; the\n // intrinsic root measures its content through Yoga, honoring forSize for\n // height-for-width).\n measure?: (orientation: \"horizontal\" | \"vertical\", forSize: number) => number\n // Runs before children are placed — the window root syncs the engine\n // viewport to the actual allocation here.\n beforeAllocate?: (width: number, height: number) => void\n}\n\n// Containers (Root, View, Animated.View, ScrollView content) drive their GTK\n// side with an RnGtkxLayout: measure() reports the engine rect of `node`\n// (minimum == natural — GTK minimums of children never leak upward), and\n// allocate() places every child widget at exactly its stored engine rect\n// plus the Animated offset.\nexport const useRnContainer = (\n widgetRef: RefObject<Gtk.Widget | null>,\n node: LayoutNode,\n options?: RnContainerOptions,\n): void => {\n const optionsRef = useRef<RnContainerOptions | undefined>(options)\n optionsRef.current = options\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n attachRnLayout(widget, {\n measure: (orientation, forSize) => {\n const custom = optionsRef.current?.measure\n if (custom) {\n return custom(orientation, forSize)\n }\n const rect = node.getRect()\n return Math.round(\n (orientation === \"horizontal\" ? rect?.width : rect?.height) ?? 0,\n )\n },\n allocate: (width, height) => {\n const start = perfEnabled ? perfNow() : 0\n perfAllocDepth += 1\n optionsRef.current?.beforeAllocate?.(width, height)\n let child = widget.getFirstChild()\n let children = 0\n while (child) {\n const rect = getStoredRect(child)\n if (rect) {\n const offset = getStoredOffset(child)\n allocateChild(\n child,\n rect.x + offset.dx,\n rect.y + offset.dy,\n rect.width,\n rect.height,\n )\n children += 1\n }\n child = child.getNextSibling()\n }\n perfAllocDepth -= 1\n if (perfEnabled) {\n perfCount(\"gtk.allocPass\")\n perfCount(\"gtk.allocChild\", children)\n if (perfAllocDepth === 0) {\n const elapsed = perfNow() - start\n perfAddTime(\"gtk.allocTop\", elapsed)\n perfBurst(\"gtk.allocMsPerFrame\", elapsed)\n }\n }\n },\n })\n return () => {\n detachRnLayout(widget)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n"]}
|
|
1
|
+
{"version":3,"file":"use-layout-child.js","sourceRoot":"","sources":["../../src/components/use-layout-child.ts"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, useState, type RefObject } from \"react\"\nimport type { LayoutNode } from \"../layout/index\"\nimport { splitStyle, StyleSheet } from \"../style/index\"\nimport { defaultCssRegistry } from \"../style/registry.gtkx\"\nimport type {\n LayoutStyle,\n MeasureFn,\n Rect,\n StyleProp,\n TransformPart,\n VisualStyle,\n} from \"../contracts\"\nimport {\n allocateChild,\n attachRnLayout,\n detachRnLayout,\n measureWidget,\n queueAllocate,\n queueResize,\n type Gtk,\n} from \"../gtkx/bridge/index\"\nimport {\n perfAddTime,\n perfBurst,\n perfCount,\n perfEnabled,\n perfNow,\n} from \"../perf\"\nimport { useHostNode, type HostNode } from \"./host-node\"\nimport {\n deferDuringAllocate,\n getStoredOffset,\n getStoredRect,\n setStoredRect,\n setStoredTransform,\n} from \"./rect-store\"\n\nexport type LayoutEvent = {\n nativeEvent: {\n layout: { x: number; y: number; width: number; height: number }\n }\n}\n\n// Perf: sizeAllocate recurses synchronously into child containers, so a\n// naive per-pass timer double-counts nested passes. Track depth and time\n// only the outermost (top-level) allocate — that is the real wall time GTK\n// spends in OUR layout code for the frame.\nlet perfAllocDepth = 0\n\nexport type LayoutChildOptions = {\n style: StyleProp | undefined\n onLayout: ((event: LayoutEvent) => void) | undefined\n measure?: MeasureFn\n // Leaves with intrinsic GTK sizes (Entry, Switch, Spinner) measure their\n // own widget so Yoga reserves exactly what the theme will draw.\n measureFromWidget?: boolean\n extraLayout?: LayoutStyle\n}\n\nexport type LayoutChild = {\n host: HostNode\n node: LayoutNode\n flat: ReturnType<typeof StyleSheet.flatten>\n visual: VisualStyle\n cssClass: string | null\n}\n\n// Shared plumbing for every leaf/container component: owns one LayoutNode,\n// keeps it in the parent's shadow tree for the component lifetime, applies\n// the layout half of the style and commits Yoga rects into the rect store,\n// where the parent container's RnGtkxLayout allocate() picks them up.\nexport const useLayoutChild = (\n widgetRef: RefObject<Gtk.Widget | null>,\n options: LayoutChildOptions,\n): LayoutChild => {\n const host = useHostNode()\n\n // useState's lazy initializer is guaranteed once-per-instance even under\n // the React Compiler — a lazy ref here got its creation memoized ACROSS\n // component instances, sharing one Yoga node and double-freeing it.\n const [node] = useState<LayoutNode>(() => host.engine.createNode())\n\n const flat = StyleSheet.flatten(options.style)\n const { layout, visual } = splitStyle(flat)\n const effectiveLayout = options.extraLayout\n ? { ...layout, ...options.extraLayout }\n : layout\n\n // Re-apply layout style only when it actually changed (keyed effect) —\n // setStyle dirties the whole tree.\n const layoutKey = JSON.stringify(effectiveLayout)\n useLayoutEffect(() => {\n node.setStyle(JSON.parse(layoutKey) as LayoutStyle)\n }, [node, layoutKey])\n\n const cssClass = defaultCssRegistry.getClassName(visual)\n\n // RN transforms are visual only: the widget keeps the box Yoga gave it, so\n // a transform never touches the shadow tree — it only asks the parent\n // container to run its allocate hook again. Keyed on the serialized array\n // so a re-render with the same transform costs nothing.\n // (Animated.View owns its own transform and strips it from the static\n // style before it gets here, so the two writers never race.)\n const transformKey = JSON.stringify(visual.transform ?? null)\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n setStoredTransform(widget, JSON.parse(transformKey) as TransformPart[])\n const parentWidget = host.widgetRef.current\n if (parentWidget) {\n queueAllocate(parentWidget)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [transformKey])\n\n useLayoutEffect(() => {\n const parent = host.node\n // The reconciler has already attached our widget in JSX order, so its\n // sibling position is the correct Yoga index — this keeps the shadow tree\n // ordered even for mid-list mounts (conditional children, list inserts).\n const widget = widgetRef.current\n const parentWidget = host.widgetRef.current\n let index = parent.children.length\n if (widget && parentWidget) {\n let position = 0\n let sibling = parentWidget.getFirstChild()\n while (sibling !== null && sibling !== widget) {\n position += 1\n sibling = sibling.getNextSibling()\n }\n if (sibling === widget) {\n index = Math.min(position, parent.children.length)\n }\n }\n parent.insertChild(node, index)\n node.setCommit((rect: Rect) => {\n const widget = widgetRef.current\n const parentWidget = host.widgetRef.current\n if (!widget || !parentWidget) {\n return\n }\n const previous = getStoredRect(widget)\n // A commit does not imply a change. The engine may hand us the rect a\n // widget already has — nodes carrying a measure function are visited\n // even when Yoga did not move them — and queueing an allocation for\n // those makes GTK re-allocate and re-snapshot the container for nothing.\n //\n // `rect.skip` counts how often this guard actually fires and\n // `rect.change` how often it does not, because a guard nobody can see\n // firing is a guard nobody can attribute a measurement to: this one was\n // once credited with a large maximized-window win that a later, properly\n // geometry-controlled run could not reproduce (docs/research/\n // scroll-performance.md, round six). Keep it — it is correct and free —\n // but read the counter before crediting it with anything.\n const unchanged =\n previous !== undefined &&\n previous.x === rect.x &&\n previous.y === rect.y &&\n previous.width === rect.width &&\n previous.height === rect.height\n if (perfEnabled) {\n perfCount(unchanged ? \"rect.skip\" : \"rect.change\")\n }\n if (unchanged) {\n return\n }\n setStoredRect(widget, rect)\n const sizeChanged =\n !previous ||\n previous.width !== rect.width ||\n previous.height !== rect.height\n const queue = (): void => {\n if (sizeChanged) {\n // A size change invalidates this widget's cached measure (nested\n // managers, ScrolledWindow ranges) and re-allocates the ancestors.\n queueResize(widget)\n } else {\n // Pure move: the parent just needs another allocation pass. GTK\n // dedupes queued allocates, so per-child calls batch into one.\n queueAllocate(parentWidget)\n }\n }\n if (!deferDuringAllocate(widget, queue)) {\n queue()\n }\n })\n return () => {\n node.setCommit(null)\n parent.removeChild(node)\n node.free()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const onLayout = options.onLayout\n useLayoutEffect(() => {\n node.setOnLayout(\n onLayout\n ? (rect: Rect) => {\n onLayout({ nativeEvent: { layout: rect } })\n }\n : null,\n )\n }, [node, onLayout])\n\n // The explicit return type keeps the inner params contextually typed: with a\n // bare lazy initializer TS may match the outer arrow against MeasureFn\n // itself (useState accepts S | () => S) and drop the context.\n const [widgetMeasure] = useState<MeasureFn>(\n (): MeasureFn => (width, widthMode) => {\n const widget = widgetRef.current\n if (!widget) {\n return { width: 0, height: 0 }\n }\n const { minimum, natural } = measureWidget(widget, \"horizontal\")\n // Floor at the widget's own minimum width, not at 1 — see the same\n // clamp in text.tsx's measure for why: gtk_widget_measure() enforces\n // this floor internally regardless of what we request (warning while\n // it does), so anything below `minimum` was never actually honored.\n const used =\n widthMode === \"undefined\"\n ? natural\n : Math.min(natural, Math.max(minimum, Math.floor(width)))\n return {\n width: used,\n height: measureWidget(widget, \"vertical\", used).natural,\n }\n },\n )\n const measure =\n options.measure ?? (options.measureFromWidget ? widgetMeasure : undefined)\n useLayoutEffect(() => {\n if (!measure) {\n return\n }\n node.setMeasureFn(measure)\n // Widgets measured before their window is mapped report zero (no realized\n // theme context yet, unlike offscreen probes) and Yoga caches it —\n // invalidate once the widget actually maps.\n const widget = widgetRef.current\n const remeasure = (): void => {\n node.markDirty()\n }\n if (options.measureFromWidget && widget) {\n widget.on(\"map\", remeasure)\n }\n return () => {\n if (options.measureFromWidget && widget) {\n widget.off(\"map\", remeasure)\n }\n // Cleared by free() on unmount; explicit unset only when measure is\n // removed while mounted.\n node.setMeasureFn(null)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [node, measure])\n\n return { host, node, flat, visual, cssClass }\n}\n\nexport type RnContainerOptions = {\n // Overrides the default engine-rect measure (the window root reports 0 so\n // the window can shrink freely below the current content size; the\n // intrinsic root measures its content through Yoga, honoring forSize for\n // height-for-width).\n measure?: (orientation: \"horizontal\" | \"vertical\", forSize: number) => number\n // Runs before children are placed — the window root syncs the engine\n // viewport to the actual allocation here.\n beforeAllocate?: (width: number, height: number) => void\n}\n\n// Containers (Root, View, Animated.View, ScrollView content) drive their GTK\n// side with an RnGtkxLayout: measure() reports the engine rect of `node`\n// (minimum == natural — GTK minimums of children never leak upward), and\n// allocate() places every child widget at exactly its stored engine rect\n// plus the Animated offset.\nexport const useRnContainer = (\n widgetRef: RefObject<Gtk.Widget | null>,\n node: LayoutNode,\n options?: RnContainerOptions,\n): void => {\n const optionsRef = useRef<RnContainerOptions | undefined>(options)\n optionsRef.current = options\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n attachRnLayout(widget, {\n measure: (orientation, forSize) => {\n const custom = optionsRef.current?.measure\n if (custom) {\n return custom(orientation, forSize)\n }\n const rect = node.getRect()\n return Math.round(\n (orientation === \"horizontal\" ? rect?.width : rect?.height) ?? 0,\n )\n },\n allocate: (width, height) => {\n const start = perfEnabled ? perfNow() : 0\n perfAllocDepth += 1\n optionsRef.current?.beforeAllocate?.(width, height)\n let child = widget.getFirstChild()\n let children = 0\n while (child) {\n const rect = getStoredRect(child)\n if (rect) {\n const offset = getStoredOffset(child)\n allocateChild(\n child,\n rect.x + offset.dx,\n rect.y + offset.dy,\n rect.width,\n rect.height,\n offset.matrix,\n )\n children += 1\n }\n child = child.getNextSibling()\n }\n perfAllocDepth -= 1\n if (perfEnabled) {\n perfCount(\"gtk.allocPass\")\n perfCount(\"gtk.allocChild\", children)\n if (perfAllocDepth === 0) {\n const elapsed = perfNow() - start\n perfAddTime(\"gtk.allocTop\", elapsed)\n perfBurst(\"gtk.allocMsPerFrame\", elapsed)\n }\n }\n },\n })\n return () => {\n detachRnLayout(widget)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n}\n"]}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { type ReactNode } from "react";
|
|
1
|
+
import { type ReactNode, type Ref } from "react";
|
|
2
2
|
import type { PointerEventsValue, StyleProp } from "../contracts";
|
|
3
|
+
import type { ResponderProps } from "../responder/types";
|
|
4
|
+
import { type MeasureHandle } from "./measure";
|
|
3
5
|
import { type LayoutEvent } from "./use-layout-child";
|
|
4
|
-
|
|
6
|
+
/** RN's imperative geometry methods, on a `View` ref. */
|
|
7
|
+
export type ViewHandle = MeasureHandle;
|
|
8
|
+
export type ViewProps = ResponderProps & {
|
|
5
9
|
style?: StyleProp;
|
|
6
10
|
pointerEvents?: PointerEventsValue;
|
|
7
11
|
onLayout?: (event: LayoutEvent) => void;
|
|
8
12
|
children?: ReactNode;
|
|
9
13
|
testID?: string;
|
|
14
|
+
ref?: Ref<ViewHandle>;
|
|
10
15
|
};
|
|
11
|
-
export declare const View: ({ style, pointerEvents, onLayout, children, testID, }: ViewProps) => React.JSX.Element;
|
|
12
|
-
export declare const SafeAreaView: ({ style, pointerEvents, onLayout, children, testID, }: ViewProps) => React.JSX.Element;
|
|
16
|
+
export declare const View: ({ style, pointerEvents, onLayout, children, testID, ref, ...responderProps }: ViewProps) => React.JSX.Element;
|
|
17
|
+
export declare const SafeAreaView: ({ style, pointerEvents, onLayout, children, testID, ref, ...responderProps }: ViewProps) => React.JSX.Element;
|
|
13
18
|
export declare const StatusBar: () => null;
|
package/dist/components/view.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useLayoutEffect, useRef } from "react";
|
|
2
|
+
import { useImperativeHandle, useLayoutEffect, useRef, } from "react";
|
|
3
3
|
import { StyleSheet } from "../style/index";
|
|
4
4
|
import { getViewBoxComponent, setBoxPassthrough, } from "../gtkx/bridge/index";
|
|
5
|
+
import { useResponder } from "../responder/use-responder";
|
|
5
6
|
import { HostNodeContext } from "./host-node";
|
|
7
|
+
import { createMeasureHandle } from "./measure";
|
|
6
8
|
import { useLayoutChild, useRnContainer, } from "./use-layout-child";
|
|
7
9
|
// Every View is a GtkBox subclass (RnGtkxViewBox) driven by RnGtkxLayout:
|
|
8
10
|
// Yoga computes the children's rects, the manager's allocate() applies
|
|
@@ -17,13 +19,17 @@ import { useLayoutChild, useRnContainer, } from "./use-layout-child";
|
|
|
17
19
|
// can-target=false; restored when the mode changes. Nesting another
|
|
18
20
|
// pointerEvents INSIDE a box-only view is not supported (the restore
|
|
19
21
|
// pass cannot know about it).
|
|
20
|
-
export const View = ({ style, pointerEvents, onLayout, children, testID, }) => {
|
|
22
|
+
export const View = ({ style, pointerEvents, onLayout, children, testID, ref, ...responderProps }) => {
|
|
21
23
|
const widgetRef = useRef(null);
|
|
22
24
|
const { host, node, cssClass } = useLayoutChild(widgetRef, {
|
|
23
25
|
style,
|
|
24
26
|
onLayout,
|
|
25
27
|
});
|
|
26
28
|
useRnContainer(widgetRef, node);
|
|
29
|
+
useImperativeHandle(ref, () => createMeasureHandle(widgetRef, node), [node]);
|
|
30
|
+
// Spreading PanResponder's panHandlers onto a View is the portable RN
|
|
31
|
+
// idiom, so every responder prop arrives here as a rest prop.
|
|
32
|
+
useResponder(widgetRef, responderProps);
|
|
27
33
|
const mode = pointerEvents ?? StyleSheet.flatten(style)?.pointerEvents ?? "auto";
|
|
28
34
|
useLayoutEffect(() => {
|
|
29
35
|
const widget = widgetRef.current;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/components/view.tsx"],"names":[],"mappings":";AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/components/view.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n type ReactNode,\n type Ref,\n} from \"react\"\nimport { StyleSheet } from \"../style/index\"\nimport type { PointerEventsValue, StyleProp } from \"../contracts\"\nimport {\n getViewBoxComponent,\n GtkBox,\n setBoxPassthrough,\n type Gtk,\n} from \"../gtkx/bridge/index\"\nimport type { ResponderProps } from \"../responder/types\"\nimport { useResponder } from \"../responder/use-responder\"\nimport { HostNodeContext } from \"./host-node\"\nimport { createMeasureHandle, type MeasureHandle } from \"./measure\"\nimport {\n useLayoutChild,\n useRnContainer,\n type LayoutEvent,\n} from \"./use-layout-child\"\n\n/** RN's imperative geometry methods, on a `View` ref. */\nexport type ViewHandle = MeasureHandle\n\nexport type ViewProps = ResponderProps & {\n style?: StyleProp\n // RN pointerEvents; the prop wins over style.pointerEvents (RN 0.71+).\n pointerEvents?: PointerEventsValue\n onLayout?: (event: LayoutEvent) => void\n children?: ReactNode\n testID?: string\n // React 19 takes `ref` as an ordinary prop, which is what we want here:\n // forwardRef is booby-trapped on this stack (useEffectEvent never\n // refreshes inside it — see gtkx/bridge/use-signal.ts).\n ref?: Ref<ViewHandle>\n}\n\n// Every View is a GtkBox subclass (RnGtkxViewBox) driven by RnGtkxLayout:\n// Yoga computes the children's rects, the manager's allocate() applies\n// them. Visual styles arrive as a GTK CSS class produced by the style\n// system. pointerEvents maps onto GTK picking:\n// - none: can-target=false — GTK skips the widget WITHOUT descending, the\n// whole subtree is transparent (exact RN semantics);\n// - box-none: the subclass' contains() fails for this widget (see\n// view-box.ts) — the box is never the pick target while children stay\n// pickable, and toggling never remounts the subtree;\n// - box-only: direct children (and thus their subtrees) get\n// can-target=false; restored when the mode changes. Nesting another\n// pointerEvents INSIDE a box-only view is not supported (the restore\n// pass cannot know about it).\nexport const View = ({\n style,\n pointerEvents,\n onLayout,\n children,\n testID,\n ref,\n ...responderProps\n}: ViewProps) => {\n const widgetRef = useRef<Gtk.Box | null>(null)\n const { host, node, cssClass } = useLayoutChild(widgetRef, {\n style,\n onLayout,\n })\n useRnContainer(widgetRef, node)\n\n useImperativeHandle(ref, () => createMeasureHandle(widgetRef, node), [node])\n\n // Spreading PanResponder's panHandlers onto a View is the portable RN\n // idiom, so every responder prop arrives here as a rest prop.\n useResponder(widgetRef, responderProps)\n\n const mode: PointerEventsValue =\n pointerEvents ?? StyleSheet.flatten(style)?.pointerEvents ?? \"auto\"\n\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n widget.setCanTarget(mode !== \"none\")\n setBoxPassthrough(widget, mode === \"box-none\")\n }, [mode])\n\n // box-only walks the current children every commit (the set changes with\n // renders) and restores once when the mode moves away.\n const wasBoxOnly = useRef(false)\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n const boxOnly = mode === \"box-only\"\n if (boxOnly || wasBoxOnly.current) {\n let child = widget.getFirstChild()\n while (child) {\n child.setCanTarget(!boxOnly)\n child = child.getNextSibling()\n }\n }\n wasBoxOnly.current = boxOnly\n })\n\n const ViewBox = getViewBoxComponent() as typeof GtkBox\n return (\n <ViewBox\n ref={widgetRef}\n name={testID}\n cssClasses={cssClass ? [cssClass] : []}\n >\n <HostNodeContext.Provider\n value={{ engine: host.engine, node, widgetRef }}\n >\n {children}\n </HostNodeContext.Provider>\n </ViewBox>\n )\n}\n\n// RN parity aliases (no notches or status bars on the Linux desktop).\nexport const SafeAreaView = View\n\nexport const StatusBar = (): null => null\n"]}
|
package/dist/contracts.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export type LayoutStyle = Partial<{
|
|
|
44
44
|
top: DimensionValue;
|
|
45
45
|
width: DimensionValue;
|
|
46
46
|
}>;
|
|
47
|
+
export type Angle = `${number}deg` | `${number}rad`;
|
|
47
48
|
export type TransformPart = {
|
|
48
49
|
translateX: number;
|
|
49
50
|
} | {
|
|
@@ -55,10 +56,30 @@ export type TransformPart = {
|
|
|
55
56
|
} | {
|
|
56
57
|
scaleY: number;
|
|
57
58
|
} | {
|
|
58
|
-
rotate:
|
|
59
|
+
rotate: Angle;
|
|
60
|
+
} | {
|
|
61
|
+
rotateZ: Angle;
|
|
62
|
+
};
|
|
63
|
+
export type Transform2D = {
|
|
64
|
+
xx: number;
|
|
65
|
+
yx: number;
|
|
66
|
+
xy: number;
|
|
67
|
+
yy: number;
|
|
68
|
+
dx: number;
|
|
69
|
+
dy: number;
|
|
70
|
+
};
|
|
71
|
+
export type BoxShadowValue = {
|
|
72
|
+
offsetX: number | string;
|
|
73
|
+
offsetY: number | string;
|
|
74
|
+
color?: string;
|
|
75
|
+
blurRadius?: number | string;
|
|
76
|
+
spreadDistance?: number | string;
|
|
77
|
+
inset?: boolean;
|
|
59
78
|
};
|
|
79
|
+
export type TextDecorationLine = "none" | "underline" | "line-through" | "underline line-through";
|
|
60
80
|
export type VisualStyle = Partial<{
|
|
61
81
|
backgroundColor: string;
|
|
82
|
+
boxShadow: string | readonly BoxShadowValue[];
|
|
62
83
|
borderBottomColor: string;
|
|
63
84
|
borderBottomLeftRadius: number;
|
|
64
85
|
borderBottomRightRadius: number;
|
|
@@ -83,13 +104,19 @@ export type VisualStyle = Partial<{
|
|
|
83
104
|
letterSpacing: number;
|
|
84
105
|
lineHeight: number;
|
|
85
106
|
opacity: number;
|
|
107
|
+
outlineColor: string;
|
|
108
|
+
outlineOffset: number;
|
|
109
|
+
outlineStyle: "solid" | "dotted" | "dashed";
|
|
110
|
+
outlineWidth: number;
|
|
86
111
|
textAlign: "auto" | "left" | "right" | "center" | "justify";
|
|
112
|
+
textDecorationLine: TextDecorationLine;
|
|
87
113
|
transform: TransformPart[];
|
|
88
114
|
}>;
|
|
89
115
|
export type PointerEventsValue = "auto" | "none" | "box-none" | "box-only";
|
|
90
|
-
export type
|
|
91
|
-
pointerEvents
|
|
92
|
-
}
|
|
116
|
+
export type BehavioralStyle = Partial<{
|
|
117
|
+
pointerEvents: PointerEventsValue;
|
|
118
|
+
}>;
|
|
119
|
+
export type FlatStyle = LayoutStyle & VisualStyle & BehavioralStyle;
|
|
93
120
|
export type StyleProp<T = FlatStyle> = T | null | undefined | false | ReadonlyArray<StyleProp<T>>;
|
|
94
121
|
export type SplitStyle = {
|
|
95
122
|
layout: LayoutStyle;
|
package/dist/contracts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,sEAAsE","sourcesContent":["// Shared contracts between the layout engine, the style system, the API\n// modules and the components — the one module every layer may import.\n\n// --- style ------------------------------------------------------------------\n\nexport type DimensionValue = number | `${number}%` | \"auto\"\n\nexport type FlexAlignType =\n \"flex-start\" | \"flex-end\" | \"center\" | \"stretch\" | \"baseline\"\n\n// Layout-affecting props: classified by the style system, consumed by the\n// layout engine, which maps them onto Yoga node setters.\nexport type LayoutStyle = Partial<{\n alignContent:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"stretch\"\n | \"space-between\"\n | \"space-around\"\n alignItems: FlexAlignType\n alignSelf: \"auto\" | FlexAlignType\n aspectRatio: number | string\n bottom: DimensionValue\n columnGap: number\n direction: \"inherit\" | \"ltr\" | \"rtl\"\n display: \"none\" | \"flex\"\n flex: number\n flexBasis: DimensionValue\n flexDirection: \"row\" | \"row-reverse\" | \"column\" | \"column-reverse\"\n flexGrow: number\n flexShrink: number\n flexWrap: \"wrap\" | \"nowrap\" | \"wrap-reverse\"\n gap: number\n height: DimensionValue\n justifyContent:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\"\n left: DimensionValue\n margin: DimensionValue\n marginBottom: DimensionValue\n marginHorizontal: DimensionValue\n marginLeft: DimensionValue\n marginRight: DimensionValue\n marginTop: DimensionValue\n marginVertical: DimensionValue\n maxHeight: DimensionValue\n maxWidth: DimensionValue\n minHeight: DimensionValue\n minWidth: DimensionValue\n overflow: \"visible\" | \"hidden\" | \"scroll\"\n padding: DimensionValue\n paddingBottom: DimensionValue\n paddingHorizontal: DimensionValue\n paddingLeft: DimensionValue\n paddingRight: DimensionValue\n paddingTop: DimensionValue\n paddingVertical: DimensionValue\n position: \"absolute\" | \"relative\" | \"static\"\n right: DimensionValue\n rowGap: number\n top: DimensionValue\n width: DimensionValue\n}>\n\nexport type TransformPart =\n | { translateX: number }\n | { translateY: number }\n | { scale: number }\n | { scaleX: number }\n | { scaleY: number }\n | { rotate:
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,sEAAsE","sourcesContent":["// Shared contracts between the layout engine, the style system, the API\n// modules and the components — the one module every layer may import.\n\n// --- style ------------------------------------------------------------------\n\nexport type DimensionValue = number | `${number}%` | \"auto\"\n\nexport type FlexAlignType =\n \"flex-start\" | \"flex-end\" | \"center\" | \"stretch\" | \"baseline\"\n\n// Layout-affecting props: classified by the style system, consumed by the\n// layout engine, which maps them onto Yoga node setters.\nexport type LayoutStyle = Partial<{\n alignContent:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"stretch\"\n | \"space-between\"\n | \"space-around\"\n alignItems: FlexAlignType\n alignSelf: \"auto\" | FlexAlignType\n aspectRatio: number | string\n bottom: DimensionValue\n columnGap: number\n direction: \"inherit\" | \"ltr\" | \"rtl\"\n display: \"none\" | \"flex\"\n flex: number\n flexBasis: DimensionValue\n flexDirection: \"row\" | \"row-reverse\" | \"column\" | \"column-reverse\"\n flexGrow: number\n flexShrink: number\n flexWrap: \"wrap\" | \"nowrap\" | \"wrap-reverse\"\n gap: number\n height: DimensionValue\n justifyContent:\n | \"flex-start\"\n | \"flex-end\"\n | \"center\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\"\n left: DimensionValue\n margin: DimensionValue\n marginBottom: DimensionValue\n marginHorizontal: DimensionValue\n marginLeft: DimensionValue\n marginRight: DimensionValue\n marginTop: DimensionValue\n marginVertical: DimensionValue\n maxHeight: DimensionValue\n maxWidth: DimensionValue\n minHeight: DimensionValue\n minWidth: DimensionValue\n overflow: \"visible\" | \"hidden\" | \"scroll\"\n padding: DimensionValue\n paddingBottom: DimensionValue\n paddingHorizontal: DimensionValue\n paddingLeft: DimensionValue\n paddingRight: DimensionValue\n paddingTop: DimensionValue\n paddingVertical: DimensionValue\n position: \"absolute\" | \"relative\" | \"static\"\n right: DimensionValue\n rowGap: number\n top: DimensionValue\n width: DimensionValue\n}>\n\nexport type Angle = `${number}deg` | `${number}rad`\n\nexport type TransformPart =\n | { translateX: number }\n | { translateY: number }\n | { scale: number }\n | { scaleX: number }\n | { scaleY: number }\n | { rotate: Angle }\n // RN's 2D alias for `rotate` (rotation about the Z axis).\n | { rotateZ: Angle }\n\n// A 2D affine transform in the component order GSK and cairo use:\n// x' = xx * x + xy * y + dx\n// y' = yx * x + yy * y + dy\n// This is exactly the argument order of gsk_transform_matrix2d(), so a\n// composed TransformPart[] reaches GTK in a single FFI call.\nexport type Transform2D = {\n xx: number\n yx: number\n xy: number\n yy: number\n dx: number\n dy: number\n}\n\n// Visual props: classified by the style system, compiled into GTK CSS\n// classes via the bridge `css` helper. Text-specific props apply to <Text>.\n// One shadow of a `boxShadow`, field for field react-native's own\n// `BoxShadowValue` (RN 0.76+). Lengths are RN DIPs when numeric; the string\n// form accepts a bare number or `px` and nothing else, which is exactly what\n// RN's processBoxShadow.js accepts.\nexport type BoxShadowValue = {\n offsetX: number | string\n offsetY: number | string\n color?: string\n blurRadius?: number | string\n spreadDistance?: number | string\n inset?: boolean\n}\n\nexport type TextDecorationLine =\n \"none\" | \"underline\" | \"line-through\" | \"underline line-through\"\n\nexport type VisualStyle = Partial<{\n backgroundColor: string\n // RN 0.76+. Both forms RN takes: a CSS `box-shadow` string or the\n // structured array. Compiled by style/box-shadow.ts rather than forwarded,\n // so colours go through the same normalizer as every other colour prop.\n boxShadow: string | readonly BoxShadowValue[]\n borderBottomColor: string\n borderBottomLeftRadius: number\n borderBottomRightRadius: number\n borderBottomWidth: number\n borderColor: string\n borderLeftColor: string\n borderLeftWidth: number\n borderRadius: number\n borderRightColor: string\n borderRightWidth: number\n borderStyle: \"solid\" | \"dotted\" | \"dashed\"\n borderTopColor: string\n borderTopLeftRadius: number\n borderTopRightRadius: number\n borderTopWidth: number\n borderWidth: number\n color: string\n fontFamily: string\n fontSize: number\n fontStyle: \"normal\" | \"italic\"\n fontWeight:\n | \"normal\"\n | \"bold\"\n | \"100\"\n | \"200\"\n | \"300\"\n | \"400\"\n | \"500\"\n | \"600\"\n | \"700\"\n | \"800\"\n | \"900\"\n letterSpacing: number\n lineHeight: number\n opacity: number\n // RN 0.77+. A ring drawn around the border box that takes no layout space\n // — CSS `outline`, which GTK4 implements natively and Adwaita itself uses\n // for every focus ring in the theme.\n outlineColor: string\n outlineOffset: number\n outlineStyle: \"solid\" | \"dotted\" | \"dashed\"\n outlineWidth: number\n // NOT emitted to CSS (no such GTK CSS property): the Text component applies\n // it via label props using the pure style/text-align helper.\n textAlign: \"auto\" | \"left\" | \"right\" | \"center\" | \"justify\"\n // NOT emitted to CSS either — GTK4 CSS has no widget `text-decoration`.\n // Pango carries it, so the Text component turns it into the label's\n // attribute list using the pure style/text-decoration helper.\n textDecorationLine: TextDecorationLine\n // NOT emitted to CSS (GTK4 has no widget `transform` property): composed\n // into a Transform2D by style/transform.ts and applied as the GskTransform\n // of the child's allocation by the container's layout manager.\n transform: TransformPart[]\n}>\n\n// RN pointerEvents (also allowed in styles since RN 0.71); behavioral, so\n// it belongs to neither the layout nor the visual bucket — splitStyle\n// consumes it without routing it and View reads it from the flattened style.\nexport type PointerEventsValue = \"auto\" | \"none\" | \"box-none\" | \"box-only\"\n\n// The third bucket, named rather than inlined into FlatStyle below: props\n// that are supported but consumed by the component that owns the behavior,\n// not by either half of the style pipeline. Having a name for it is what\n// lets splitStyle state which keys it deliberately routes nowhere, instead\n// of reporting them as unknown — the drift this type was born from.\nexport type BehavioralStyle = Partial<{\n pointerEvents: PointerEventsValue\n}>\n\nexport type FlatStyle = LayoutStyle & VisualStyle & BehavioralStyle\n\n// Style prop as components accept it: single object, array (with falsy holes).\nexport type StyleProp<T = FlatStyle> =\n T | null | undefined | false | ReadonlyArray<StyleProp<T>>\n\n// Result of classifying a flattened style (produced by the style system):\nexport type SplitStyle = {\n layout: LayoutStyle\n visual: VisualStyle\n}\n\n// --- layout engine ----------------------------------------------------------\n\nexport type Rect = {\n x: number\n y: number\n width: number\n height: number\n}\n\nexport type MeasureConstraintMode = \"undefined\" | \"exactly\" | \"at-most\"\n\nexport type MeasureSize = { width: number; height: number }\n\n// Measure callback for leaf nodes (text, images): implemented by components\n// using bridge probes; called by the engine during Yoga layout passes.\nexport type MeasureFn = (\n width: number,\n widthMode: MeasureConstraintMode,\n height: number,\n heightMode: MeasureConstraintMode,\n) => MeasureSize\n\n// Handle the layout engine gives every mounted component.\nexport interface LayoutNodeApi {\n setStyle(style: LayoutStyle): void\n setMeasureFn(measure: MeasureFn | null): void\n markDirty(): void\n getRect(): Rect | null\n setOnLayout(callback: ((rect: Rect) => void) | null): void\n}\n\n// --- subscriptions ----------------------------------------------------------\n\nexport type SubscriptionHandle = { remove(): void }\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./widgets.generated";
|
|
2
|
+
export { Gdk, Gio, GLib, GObject, Gtk, Pango } from "../gtkx/bridge/index";
|
|
3
|
+
export { GMenu, GtkAdjustment, GtkDragSource, GtkDropTarget, GtkShortcut, GtkShortcutController, GtkTextBuffer, } from "../gtkx/bridge/index";
|
|
4
|
+
export { ApplicationActions, GSimpleAction, WindowActions, WindowControllers, type ApplicationActionsProps, type GSimpleActionProps, type WindowActionsProps, type WindowControllersProps, } from "./window-actions";
|
|
5
|
+
export { useBindSetting, useSetting, type SettingsSchema, type SettingsSchemaKeys, type SettingValue, } from "../gtkx/bridge/index";
|
|
6
|
+
export { css, cx, injectGlobal } from "../gtkx/bridge/index";
|
|
7
|
+
export { quit, useApplication, useParentWindow } from "../gtkx/bridge/index";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// The full GTK widget surface lives in a generated file: every Gtk.Widget
|
|
2
|
+
// subclass gtkx binds, wrapped so React Native drives it. See
|
|
3
|
+
// scripts/generate-widget-surface.ts and
|
|
4
|
+
// scripts/widget-surface/classification.json for how the list is derived.
|
|
5
|
+
export * from "./widgets.generated";
|
|
6
|
+
// The GTK namespaces themselves, exported as values because they carry both
|
|
7
|
+
// the enums you need at runtime — `hscrollbarPolicy={Gtk.PolicyType.NEVER}` —
|
|
8
|
+
// and the types you need for refs.
|
|
9
|
+
export { Gdk, Gio, GLib, GObject, Gtk, Pango } from "../gtkx/bridge/index";
|
|
10
|
+
// Auxiliary JSX elements that are not Gtk.Widget subclasses, so the
|
|
11
|
+
// generated widget surface above never sees them — real building blocks a
|
|
12
|
+
// non-trivial app still needs: actions and menus (Gio, used through
|
|
13
|
+
// `Gtk.Application`/`Gtk.ApplicationWindow`), a text buffer and an
|
|
14
|
+
// adjustment (the model objects `GtkTextView`/`GtkSpinRow`-style widgets
|
|
15
|
+
// bind to), keyboard shortcuts, and the two drag-and-drop controllers. See
|
|
16
|
+
// docs/platform-layer.md "Unwrapped by necessity".
|
|
17
|
+
export { GMenu, GtkAdjustment, GtkDragSource, GtkDropTarget, GtkShortcut, GtkShortcutController, GtkTextBuffer, } from "../gtkx/bridge/index";
|
|
18
|
+
// Window and application actions declared inside the app tree instead of
|
|
19
|
+
// around it (the AppRegistry options they replace cannot see app context —
|
|
20
|
+
// see window-actions.tsx). GSimpleAction comes from here rather than
|
|
21
|
+
// straight from the bridge because inside these components it arbitrates
|
|
22
|
+
// duplicate action names; on every other path it is gtkx's element,
|
|
23
|
+
// unchanged.
|
|
24
|
+
export { ApplicationActions, GSimpleAction, WindowActions, WindowControllers, } from "./window-actions";
|
|
25
|
+
// GSettings: reads and writes backed by a compiled `.gschema.xml` schema.
|
|
26
|
+
// `useSetting`/`useBindSetting` come straight from @gtkx/react; loading a
|
|
27
|
+
// `.gschema.xml` file into the `SettingsSchema` object they expect is a
|
|
28
|
+
// build-time concern (see docs/platform-layer.md).
|
|
29
|
+
export { useBindSetting, useSetting, } from "../gtkx/bridge/index";
|
|
30
|
+
// @gtkx/css — a real GTK CSS class from a tagged template, the same
|
|
31
|
+
// mechanism the style prop's visual half uses under the hood. Re-exported
|
|
32
|
+
// here rather than left to a direct @gtkx/css dependency for the same
|
|
33
|
+
// reason the namespaces above are: one subpath for the whole gtkx toolkit
|
|
34
|
+
// surface, not just Gtk.Widget subclasses. `GObject` above is exported
|
|
35
|
+
// mainly for `GObject.Value` — constructing a boxed value is required by
|
|
36
|
+
// APIs like `Adw.Breakpoint.addSetter`, which reject a bare JS primitive
|
|
37
|
+
// (see docs/platform-layer.md, "Two ways to react to size").
|
|
38
|
+
export { css, cx, injectGlobal } from "../gtkx/bridge/index";
|
|
39
|
+
// The window and application AppRegistry itself sits on: useParentWindow
|
|
40
|
+
// reaches the Gtk.Window ancestor (for anything not modeled by a prop —
|
|
41
|
+
// e.g. binding a GSettings key to its own defaultWidth/defaultHeight),
|
|
42
|
+
// useApplication reaches the Adw.Application (e.g. to send a
|
|
43
|
+
// Gio.Notification), quit tears the whole app down programmatically (the
|
|
44
|
+
// same function AppRegistry wires to a window's own close button).
|
|
45
|
+
export { quit, useApplication, useParentWindow } from "../gtkx/bridge/index";
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gtk/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8DAA8D;AAC9D,yCAAyC;AACzC,0EAA0E;AAC1E,cAAc,qBAAqB,CAAA;AAEnC,4EAA4E;AAC5E,8EAA8E;AAC9E,mCAAmC;AACnC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAE1E,oEAAoE;AACpE,0EAA0E;AAC1E,oEAAoE;AACpE,mEAAmE;AACnE,yEAAyE;AACzE,2EAA2E;AAC3E,mDAAmD;AACnD,OAAO,EACL,KAAK,EACL,aAAa,EACb,aAAa,EACb,aAAa,EACb,WAAW,EACX,qBAAqB,EACrB,aAAa,GACd,MAAM,sBAAsB,CAAA;AAE7B,yEAAyE;AACzE,2EAA2E;AAC3E,qEAAqE;AACrE,yEAAyE;AACzE,oEAAoE;AACpE,aAAa;AACb,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,iBAAiB,GAKlB,MAAM,kBAAkB,CAAA;AAEzB,0EAA0E;AAC1E,0EAA0E;AAC1E,wEAAwE;AACxE,mDAAmD;AACnD,OAAO,EACL,cAAc,EACd,UAAU,GAIX,MAAM,sBAAsB,CAAA;AAE7B,oEAAoE;AACpE,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E;AAC1E,uEAAuE;AACvE,yEAAyE;AACzE,yEAAyE;AACzE,6DAA6D;AAC7D,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAE5D,yEAAyE;AACzE,wEAAwE;AACxE,uEAAuE;AACvE,6DAA6D;AAC7D,yEAAyE;AACzE,mEAAmE;AACnE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA","sourcesContent":["// The full GTK widget surface lives in a generated file: every Gtk.Widget\n// subclass gtkx binds, wrapped so React Native drives it. See\n// scripts/generate-widget-surface.ts and\n// scripts/widget-surface/classification.json for how the list is derived.\nexport * from \"./widgets.generated\"\n\n// The GTK namespaces themselves, exported as values because they carry both\n// the enums you need at runtime — `hscrollbarPolicy={Gtk.PolicyType.NEVER}` —\n// and the types you need for refs.\nexport { Gdk, Gio, GLib, GObject, Gtk, Pango } from \"../gtkx/bridge/index\"\n\n// Auxiliary JSX elements that are not Gtk.Widget subclasses, so the\n// generated widget surface above never sees them — real building blocks a\n// non-trivial app still needs: actions and menus (Gio, used through\n// `Gtk.Application`/`Gtk.ApplicationWindow`), a text buffer and an\n// adjustment (the model objects `GtkTextView`/`GtkSpinRow`-style widgets\n// bind to), keyboard shortcuts, and the two drag-and-drop controllers. See\n// docs/platform-layer.md \"Unwrapped by necessity\".\nexport {\n GMenu,\n GtkAdjustment,\n GtkDragSource,\n GtkDropTarget,\n GtkShortcut,\n GtkShortcutController,\n GtkTextBuffer,\n} from \"../gtkx/bridge/index\"\n\n// Window and application actions declared inside the app tree instead of\n// around it (the AppRegistry options they replace cannot see app context —\n// see window-actions.tsx). GSimpleAction comes from here rather than\n// straight from the bridge because inside these components it arbitrates\n// duplicate action names; on every other path it is gtkx's element,\n// unchanged.\nexport {\n ApplicationActions,\n GSimpleAction,\n WindowActions,\n WindowControllers,\n type ApplicationActionsProps,\n type GSimpleActionProps,\n type WindowActionsProps,\n type WindowControllersProps,\n} from \"./window-actions\"\n\n// GSettings: reads and writes backed by a compiled `.gschema.xml` schema.\n// `useSetting`/`useBindSetting` come straight from @gtkx/react; loading a\n// `.gschema.xml` file into the `SettingsSchema` object they expect is a\n// build-time concern (see docs/platform-layer.md).\nexport {\n useBindSetting,\n useSetting,\n type SettingsSchema,\n type SettingsSchemaKeys,\n type SettingValue,\n} from \"../gtkx/bridge/index\"\n\n// @gtkx/css — a real GTK CSS class from a tagged template, the same\n// mechanism the style prop's visual half uses under the hood. Re-exported\n// here rather than left to a direct @gtkx/css dependency for the same\n// reason the namespaces above are: one subpath for the whole gtkx toolkit\n// surface, not just Gtk.Widget subclasses. `GObject` above is exported\n// mainly for `GObject.Value` — constructing a boxed value is required by\n// APIs like `Adw.Breakpoint.addSetter`, which reject a bare JS primitive\n// (see docs/platform-layer.md, \"Two ways to react to size\").\nexport { css, cx, injectGlobal } from \"../gtkx/bridge/index\"\n\n// The window and application AppRegistry itself sits on: useParentWindow\n// reaches the Gtk.Window ancestor (for anything not modeled by a prop —\n// e.g. binding a GSettings key to its own defaultWidth/defaultHeight),\n// useApplication reaches the Adw.Application (e.g. to send a\n// Gio.Notification), quit tears the whole app down programmatically (the\n// same function AppRegistry wires to a window's own close button).\nexport { quit, useApplication, useParentWindow } from \"../gtkx/bridge/index\"\n"]}
|