@gjsify/react-native 0.44.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/PROPS.md +525 -0
  2. package/README.md +49 -167
  3. package/SUPPORT.md +472 -0
  4. package/lib/esm/accessor.js +1 -0
  5. package/lib/esm/animated/brand.js +1 -0
  6. package/lib/esm/animated/easing.js +1 -0
  7. package/lib/esm/animated/index.js +1 -0
  8. package/lib/esm/animated/properties.js +1 -0
  9. package/lib/esm/animated/timing.js +1 -0
  10. package/lib/esm/animated/value.js +1 -0
  11. package/lib/esm/announce.js +1 -0
  12. package/lib/esm/app-registry.js +1 -1
  13. package/lib/esm/components.js +1 -1
  14. package/lib/esm/generated/own-exports.js +1 -0
  15. package/lib/esm/generated/unsupported-async-storage.js +0 -0
  16. package/lib/esm/generated/unsupported-expo-audio.js +1 -0
  17. package/lib/esm/generated/unsupported-expo-constants.js +1 -0
  18. package/lib/esm/generated/unsupported-expo-font.js +1 -0
  19. package/lib/esm/generated/unsupported-expo-image.js +1 -0
  20. package/lib/esm/generated/unsupported-expo-linking.js +1 -0
  21. package/lib/esm/generated/unsupported-expo-splash-screen.js +1 -0
  22. package/lib/esm/generated/unsupported-expo-status-bar.js +1 -0
  23. package/lib/esm/generated/unsupported-expo-system-ui.js +1 -0
  24. package/lib/esm/generated/unsupported-expo-video.js +1 -0
  25. package/lib/esm/generated/unsupported-expo-web-browser.js +1 -0
  26. package/lib/esm/generated/unsupported-nativewind.js +1 -0
  27. package/lib/esm/generated/unsupported-react-native-gesture-handler.js +1 -0
  28. package/lib/esm/generated/unsupported-react-native-safe-area-context.js +1 -0
  29. package/lib/esm/generated/unsupported-react-native-webview.js +1 -0
  30. package/lib/esm/generated/unsupported-react-native.js +1 -0
  31. package/lib/esm/generated/unsupported-router.js +1 -0
  32. package/lib/esm/generated/unsupported-vector-icons.js +1 -0
  33. package/lib/esm/index.js +1 -1
  34. package/lib/esm/lists/components.js +1 -1
  35. package/lib/esm/lists/controller.js +1 -1
  36. package/lib/esm/primitives/answers.js +1 -0
  37. package/lib/esm/primitives/defaults.js +1 -0
  38. package/lib/esm/primitives/errors.js +1 -1
  39. package/lib/esm/primitives/handles.js +1 -0
  40. package/lib/esm/primitives/index.js +1 -1
  41. package/lib/esm/primitives/intents.js +1 -1
  42. package/lib/esm/primitives/resolve.js +1 -1
  43. package/lib/esm/primitives/style.js +1 -1
  44. package/lib/esm/primitives/table.js +1 -1
  45. package/lib/esm/prop-table.js +1 -0
  46. package/lib/esm/router/href.js +1 -0
  47. package/lib/esm/router/index.js +1 -1
  48. package/lib/esm/router/navigation.js +1 -1
  49. package/lib/esm/router/tabs.js +1 -1
  50. package/lib/esm/solid/index.js +1 -1
  51. package/lib/esm/stylesheet.js +1 -1
  52. package/lib/esm/support-table.js +1 -1
  53. package/lib/esm/surfaces/async-storage.js +1 -0
  54. package/lib/esm/surfaces/expo-audio.js +1 -0
  55. package/lib/esm/surfaces/expo-constants.js +1 -0
  56. package/lib/esm/surfaces/expo-font.js +1 -0
  57. package/lib/esm/surfaces/expo-image.js +1 -0
  58. package/lib/esm/surfaces/expo-linking.js +1 -0
  59. package/lib/esm/surfaces/expo-splash-screen.js +1 -0
  60. package/lib/esm/surfaces/expo-status-bar.js +1 -0
  61. package/lib/esm/surfaces/expo-system-ui.js +1 -0
  62. package/lib/esm/surfaces/expo-video.js +1 -0
  63. package/lib/esm/surfaces/expo-web-browser.js +1 -0
  64. package/lib/esm/surfaces/icon-map.js +1 -0
  65. package/lib/esm/surfaces/nativewind.js +1 -0
  66. package/lib/esm/surfaces/react-native-gesture-handler.js +1 -0
  67. package/lib/esm/surfaces/react-native-safe-area-context.js +1 -0
  68. package/lib/esm/surfaces/react-native-webview.js +1 -0
  69. package/lib/esm/surfaces/vector-icons.js +1 -0
  70. package/lib/esm/unsupported.js +1 -1
  71. package/lib/types/accessor.d.ts +10 -0
  72. package/lib/types/animated/animated.spec.d.ts +2 -0
  73. package/lib/types/animated/brand.d.ts +8 -0
  74. package/lib/types/animated/easing.d.ts +70 -0
  75. package/lib/types/animated/easing.spec.d.ts +2 -0
  76. package/lib/types/animated/index.d.ts +55 -0
  77. package/lib/types/animated/properties.d.ts +33 -0
  78. package/lib/types/animated/timing.d.ts +37 -0
  79. package/lib/types/animated/value.d.ts +103 -0
  80. package/lib/types/announce.d.ts +18 -0
  81. package/lib/types/components.d.ts +82 -3
  82. package/lib/types/generated/own-exports.d.ts +1 -0
  83. package/lib/types/generated/unsupported-async-storage.d.ts +1 -0
  84. package/lib/types/generated/unsupported-expo-audio.d.ts +4 -0
  85. package/lib/types/generated/unsupported-expo-constants.d.ts +2 -0
  86. package/lib/types/generated/unsupported-expo-font.d.ts +4 -0
  87. package/lib/types/generated/unsupported-expo-image.d.ts +3 -0
  88. package/lib/types/generated/unsupported-expo-linking.d.ts +4 -0
  89. package/lib/types/generated/unsupported-expo-splash-screen.d.ts +5 -0
  90. package/lib/types/generated/unsupported-expo-status-bar.d.ts +5 -0
  91. package/lib/types/generated/unsupported-expo-system-ui.d.ts +2 -0
  92. package/lib/types/generated/unsupported-expo-video.d.ts +3 -0
  93. package/lib/types/generated/unsupported-expo-web-browser.d.ts +6 -0
  94. package/lib/types/generated/unsupported-nativewind.d.ts +5 -0
  95. package/lib/types/generated/unsupported-react-native-gesture-handler.d.ts +10 -0
  96. package/lib/types/generated/unsupported-react-native-safe-area-context.d.ts +4 -0
  97. package/lib/types/generated/unsupported-react-native-webview.d.ts +1 -0
  98. package/lib/types/generated/{unsupported-exports.d.ts → unsupported-react-native.d.ts} +0 -2
  99. package/lib/types/generated/unsupported-vector-icons.d.ts +11 -0
  100. package/lib/types/index.d.ts +6 -2
  101. package/lib/types/lists/controller.d.ts +14 -58
  102. package/lib/types/primitives/answers.d.ts +69 -0
  103. package/lib/types/primitives/defaults.d.ts +52 -0
  104. package/lib/types/primitives/defaults.spec.d.ts +2 -0
  105. package/lib/types/primitives/errors.d.ts +9 -0
  106. package/lib/types/primitives/handles.d.ts +56 -0
  107. package/lib/types/primitives/index.d.ts +8 -2
  108. package/lib/types/primitives/intents.d.ts +36 -0
  109. package/lib/types/primitives/resolve.d.ts +25 -1
  110. package/lib/types/primitives/table.d.ts +63 -1
  111. package/lib/types/prop-table.d.ts +56 -0
  112. package/lib/types/prop-table.spec.d.ts +2 -0
  113. package/lib/types/router/href.d.ts +58 -0
  114. package/lib/types/router/href.spec.d.ts +2 -0
  115. package/lib/types/router/index.d.ts +3 -1
  116. package/lib/types/router/navigation.d.ts +47 -5
  117. package/lib/types/router/tabs.d.ts +35 -0
  118. package/lib/types/solid/index.d.ts +15 -1
  119. package/lib/types/support-table.d.ts +95 -3
  120. package/lib/types/surfaces/async-storage.d.ts +57 -0
  121. package/lib/types/surfaces/expo-audio.d.ts +1 -0
  122. package/lib/types/surfaces/expo-constants.d.ts +11 -0
  123. package/lib/types/surfaces/expo-font.d.ts +34 -0
  124. package/lib/types/surfaces/expo-image.d.ts +1 -0
  125. package/lib/types/surfaces/expo-linking.d.ts +36 -0
  126. package/lib/types/surfaces/expo-splash-screen.d.ts +1 -0
  127. package/lib/types/surfaces/expo-status-bar.d.ts +16 -0
  128. package/lib/types/surfaces/expo-system-ui.d.ts +1 -0
  129. package/lib/types/surfaces/expo-video.d.ts +1 -0
  130. package/lib/types/surfaces/expo-web-browser.d.ts +21 -0
  131. package/lib/types/surfaces/icon-map.d.ts +14 -0
  132. package/lib/types/surfaces/nativewind.d.ts +1 -0
  133. package/lib/types/surfaces/react-native-gesture-handler.d.ts +10 -0
  134. package/lib/types/surfaces/react-native-safe-area-context.d.ts +60 -0
  135. package/lib/types/surfaces/react-native-webview.d.ts +4 -0
  136. package/lib/types/surfaces/surfaces.spec.d.ts +2 -0
  137. package/lib/types/surfaces/vector-icons.d.ts +15 -0
  138. package/lib/types/unsupported.d.ts +12 -3
  139. package/package.json +85 -14
  140. package/lib/esm/generated/unsupported-exports.js +0 -1
  141. package/lib/esm/generated/unsupported-router-exports.js +0 -1
  142. /package/lib/types/generated/{unsupported-router-exports.d.ts → unsupported-router.d.ts} +0 -0
@@ -1,3 +1,12 @@
1
+ /**
2
+ * The sentence, without throwing it.
3
+ *
4
+ * `@gjsify/react-native/prop-table` has to hand a consumer the message a render WOULD
5
+ * have thrown, and ADR 0039 § 1 says it is the same string rather than a paraphrase.
6
+ * Two template literals that happen to agree are not that: the format is here once and
7
+ * both the throw and the static answer are built from it.
8
+ */
9
+ export declare const primitiveErrorMessage: (primitive: string, subject: string, detail: string) => string;
1
10
  /** A primitive, prop or combination this layer cannot answer for, and why. */
2
11
  export declare class PrimitiveError extends Error {
3
12
  readonly name = "PrimitiveError";
@@ -0,0 +1,56 @@
1
+ import type { HandleKind } from './table.js';
2
+ /**
3
+ * The imperative handle a `<TextInput ref>` receives.
4
+ *
5
+ * React Native's own member list, with every one of them answered — five over GTK
6
+ * and four refused by name. `widget` is the one addition, and it is not decoration:
7
+ * the ref used to BE the widget, so a port that already reached for `Gtk.Entry` API
8
+ * through it keeps working by spelling `ref.current.widget` — and it is also the way
9
+ * out of every refusal below.
10
+ */
11
+ export interface TextInputHandle {
12
+ /** `Gtk.Widget.grab_focus()`. */
13
+ focus(): void;
14
+ /**
15
+ * Give up the focus — `Gtk.Root.set_focus(null)`, and ONLY when this widget holds it.
16
+ *
17
+ * The guard is the whole of the correctness here: `set_focus(null)` unsets the
18
+ * root's focus widget whoever it is, so an unguarded `blur()` on an unfocused
19
+ * input would take the focus away from whatever really had it.
20
+ */
21
+ blur(): void;
22
+ /** Remove all text. `Gtk.Editable.set_text('')`, or the buffer's own for a multiline input. */
23
+ clear(): void;
24
+ /**
25
+ * Is this the widget its root delivers keys to?
26
+ *
27
+ * `Gtk.Widget.is_focus()` and NOT `has-focus`: the latter is the GLOBAL input
28
+ * focus and is false whenever the window is not the compositor's active one
29
+ * (MEASURED on gtk 4.22.4 — a mapped, presented window that the compositor never
30
+ * activated reports `has_focus` false for the widget `grab_focus()` just
31
+ * returned true for). React Native's `isFocused()` is the per-application
32
+ * question, which is `is_focus()`.
33
+ */
34
+ isFocused(): boolean;
35
+ /** `Gtk.Editable.select_region(start, end)`, or `Gtk.TextBuffer.select_range` for a multiline input. */
36
+ setSelection(start: number, end: number): void;
37
+ /** The `Gtk.Entry` or `Gtk.TextView` itself — everything this handle does not answer. */
38
+ readonly widget: unknown;
39
+ /** Refused by name. GTK measures on allocation; see the message. */
40
+ measure(callback: unknown): never;
41
+ /** Refused by name — see `measure`. */
42
+ measureInWindow(callback: unknown): never;
43
+ /** Refused by name — see `measure`. */
44
+ measureLayout(relativeTo: unknown, onSuccess: unknown, onFail?: unknown): never;
45
+ /** Refused by name: the widget is right here, and every GTK property is settable on it. */
46
+ setNativeProps(props: object): never;
47
+ }
48
+ /**
49
+ * The handle a plan asks for, or the widget itself.
50
+ *
51
+ * `null` for `kind` is the ordinary case and is not an omission: React Native gives
52
+ * an imperative handle only to the components that document one, and every other
53
+ * primitive here hands a `ref` the `Gtk.Widget` — which is what it did before this
54
+ * file existed and what a port that reaches for GTK API relies on.
55
+ */
56
+ export declare function createHandle(kind: HandleKind | null, widget: unknown, tag: string): unknown;
@@ -1,11 +1,17 @@
1
+ export { answerFor, isAccepted, propNamesOf, unknownPrimitiveDetail, unknownPropDetail } from './answers.js';
2
+ export type { PropAnswer, PropStatus } from './answers.js';
1
3
  export { splitVariants } from './classes.js';
4
+ export { createHandle } from './handles.js';
5
+ export type { TextInputHandle } from './handles.js';
6
+ export { DEFAULT_ROWS, NORMALISED_DEFAULTS, defaultRowFor } from './defaults.js';
7
+ export type { DefaultRow, DefaultVerdict } from './defaults.js';
2
8
  export type { ClassGroups, ClassNameInput } from './classes.js';
3
9
  export { PrimitiveError } from './errors.js';
4
10
  export { resolveIntent } from './intents.js';
5
11
  export type { ChildContext, ChildFacts, IntentInput, IntentResolution, Orientation, WidgetFacts } from './intents.js';
6
12
  export { declaresAbsolute, resolvePrimitive } from './resolve.js';
7
- export type { PrimitiveContext, PrimitivePlan, PrimitiveProps, ResolvedEvent, ResolvedFile, ResolvedGesture, WidgetNode, } from './resolve.js';
13
+ export type { PrimitiveContext, PrimitivePlan, PrimitiveProps, ResolvedAnnouncement, ResolvedEvent, ResolvedFile, ResolvedGesture, WidgetNode, } from './resolve.js';
8
14
  export { flattenStyle, mintClass, normalise, variantDeclarations } from './style.js';
9
15
  export type { ClassNameSink, StyleAuthored, StyleInput, StyleObject } from './style.js';
10
16
  export { FRAMEWORK_PROPS, PRIMITIVE_NAMES, PRIMITIVES } from './table.js';
11
- export type { Coercion, ContentSpec, EventRoute, FileRoute, GestureRoute, IgnoredRoute, NodeKind, PrimitiveSpec, PropRoute, PropertyRoute, RefusedRoute, StylePropertyRoute, } from './table.js';
17
+ export type { AnnounceRoute, Coercion, ContentSpec, EventRoute, FileRoute, GestureRoute, HandleKind, IgnoredRoute, NodeKind, PrimitiveSpec, PropRoute, PropertyRoute, RefusedRoute, StylePropertyRoute, } from './table.js';
@@ -32,12 +32,33 @@ export interface ChildFacts {
32
32
  /** Whether any child is a text run, which competes with a prop for the text sink. */
33
33
  readonly text: boolean;
34
34
  }
35
+ /**
36
+ * The widget an element becomes when its children WRAP, and what that class needs.
37
+ *
38
+ * Data rather than code because it is a fact about GTK's class hierarchy, the same
39
+ * way `overlayOnAbsoluteChild` is: a `Gtk.Box` has one line and a `Gtk.FlowBox` has
40
+ * as many as it needs, and neither is reachable from the other by setting a
41
+ * property. `null` is a primitive whose widget has no wrapping counterpart at all.
42
+ */
43
+ export interface WrapsInto {
44
+ /** GType name of the wrapping class. */
45
+ readonly tag: string;
46
+ /**
47
+ * Properties the swapped-in class needs before a single utility is read.
48
+ *
49
+ * Not cosmetic: `Gtk.FlowBox` ships two defaults that make it something other
50
+ * than a wrapping box (measured, gtk 4.22.4), and both are corrected here.
51
+ */
52
+ readonly widgetProps: Readonly<Record<string, unknown>>;
53
+ }
35
54
  /** What the element's own widget can take. Declared per primitive, measured in the spec. */
36
55
  export interface WidgetFacts {
37
56
  /** Installs `orientation` and `spacing` — a `Gtk.Box`. */
38
57
  readonly box: boolean;
39
58
  /** Installs `xalign` and `justify` — a `Gtk.Label`. */
40
59
  readonly alignsText: boolean;
60
+ /** What this element becomes when its children wrap, or `null` when nothing can. */
61
+ readonly wrapsInto: WrapsInto | null;
41
62
  }
42
63
  export interface IntentInput {
43
64
  readonly primitive: string;
@@ -50,6 +71,13 @@ export interface IntentInput {
50
71
  /** Widget properties already emitted by L1, read only to catch a clash. */
51
72
  readonly emittedProps: Readonly<Record<string, unknown>>;
52
73
  }
74
+ /** The widget swap a wrap asks for, for the caller that owns the plan's tags. */
75
+ export interface WrapResolution {
76
+ /** GType name the node the children go into takes instead of its own. */
77
+ readonly tag: string;
78
+ /** Properties that belong to the swapped-in class, the spacings included. */
79
+ readonly props: Readonly<Record<string, unknown>>;
80
+ }
53
81
  export interface IntentResolution {
54
82
  /** Widget properties this resolution adds, GTK spelling. */
55
83
  readonly props: Readonly<Record<string, unknown>>;
@@ -59,6 +87,14 @@ export interface IntentResolution {
59
87
  readonly childContext: ChildContext;
60
88
  /** The `slot` this element declares to its parent, or null. */
61
89
  readonly slot: string | null;
90
+ /**
91
+ * The tag the node holding the children takes instead of its own, or null.
92
+ *
93
+ * Returned rather than applied because this function answers for PROPERTIES and
94
+ * the plan's tags belong to `resolve.ts` — the same division that keeps
95
+ * `overlayOnAbsoluteChild` out of here.
96
+ */
97
+ readonly wrapping: WrapResolution | null;
62
98
  /** What is still unresolved, for a caller that knows more. */
63
99
  readonly remaining: LayoutIntent;
64
100
  }
@@ -2,7 +2,7 @@ import type { LayoutIntent, StyleTokens } from '@gjsify/gtk-host/style';
2
2
  import type { ClassNameInput } from './classes.js';
3
3
  import { type ChildContext, type ChildFacts, type Orientation, type WidgetFacts } from './intents.js';
4
4
  import { type ClassNameSink, type StyleInput } from './style.js';
5
- import { type NodeKind } from './table.js';
5
+ import { type HandleKind, type NodeKind } from './table.js';
6
6
  /** Everything L2 needs that is not the primitive and not its props. */
7
7
  export interface PrimitiveContext {
8
8
  /** The project's own token scales. ADR 0032 § 3: the families are declared, the values are the project's. */
@@ -57,6 +57,26 @@ export interface ResolvedGesture {
57
57
  /** The `Gtk.GestureClick` signal — `released` is a completed press. */
58
58
  readonly signal: string;
59
59
  }
60
+ /**
61
+ * A live region: announce this widget's own text when the signal says it changed.
62
+ *
63
+ * Decided here and CALLED one layer up, for the reason {@link ResolvedFile} is:
64
+ * `Gtk.Accessible.announce()` takes a `Gtk.AccessibleAnnouncementPriority` enum
65
+ * member, and nothing under `primitives/` imports `gi://`. L2 holds the whole of the
66
+ * decision — which primitive can answer the prop at all, which signal reports the
67
+ * change, which property carries the message, and which GTK priority each React
68
+ * Native level is — and none of the call.
69
+ */
70
+ export interface ResolvedAnnouncement {
71
+ /** The React Native prop that asked for it. */
72
+ readonly prop: string;
73
+ /** The GObject signal that means "the content changed". */
74
+ readonly signal: string;
75
+ /** The widget property holding the message. */
76
+ readonly read: string;
77
+ /** The `Gtk.AccessibleAnnouncementPriority` nick. */
78
+ readonly priority: 'low' | 'medium' | 'high';
79
+ }
60
80
  export interface PrimitivePlan {
61
81
  readonly primitive: string;
62
82
  /** The node the PARENT adopts. */
@@ -78,6 +98,10 @@ export interface PrimitivePlan {
78
98
  readonly files: readonly ResolvedFile[];
79
99
  /** Presses that arrive through a gesture controller instead of a signal. */
80
100
  readonly gestures: readonly ResolvedGesture[];
101
+ /** Live regions this element declares. At most one, and empty for every primitive but `Text`. */
102
+ readonly announcements: readonly ResolvedAnnouncement[];
103
+ /** What a `ref` on this element receives, or null for the widget itself. */
104
+ readonly handle: HandleKind | null;
81
105
  /** Where a text child goes, or null when text under this primitive is refused. */
82
106
  readonly textSink: string | null;
83
107
  /** What this element publishes to its children. */
@@ -58,6 +58,44 @@ export interface RefusedRoute {
58
58
  /** One line: why GTK cannot answer it, and what to do instead. */
59
59
  readonly why: string;
60
60
  }
61
+ /**
62
+ * A prop the LAYER answers by calling a method when a signal fires.
63
+ *
64
+ * `accessibilityLiveRegion` is the whole of it, and the shape is forced by the
65
+ * mismatch between the two platforms' models. React Native's prop is a DECLARATION
66
+ * — "when this element's content changes, tell the user" — and the platform's
67
+ * accessibility layer watches for the change. GTK has no such declaration: since
68
+ * 4.14 it has `gtk_accessible_announce(self, message, priority)` (MEASURED on
69
+ * gtk 4.22.4 — the method is on the `Gtk.Accessible` interface, so every widget has
70
+ * it, and it takes a `GtkAccessibleAnnouncementPriority` of LOW/MEDIUM/HIGH), which
71
+ * is an IMPERATIVE call: the caller supplies both the moment and the message.
72
+ *
73
+ * So a live region can only be built where this layer knows both. It knows both on
74
+ * exactly one primitive — `Text`, whose content IS one widget property, so
75
+ * `notify::label` is the moment and `label` is the message. Everywhere else the
76
+ * content is a SUBTREE and GTK emits nothing when one changes, which is why the
77
+ * common route refuses the prop by name rather than this route answering it.
78
+ *
79
+ * Like {@link FileRoute} and {@link GestureRoute}, the table holds the whole of the
80
+ * DECISION and none of the call: the priority is a `gi://Gtk` enum member and
81
+ * nothing under `primitives/` imports `gi://`.
82
+ */
83
+ export interface AnnounceRoute {
84
+ readonly to: 'announce';
85
+ /** The signal whose emission means "the content this element shows has changed". */
86
+ readonly signal: string;
87
+ /** The widget property holding the message to announce. */
88
+ readonly read: string;
89
+ /**
90
+ * React Native's values → `Gtk.AccessibleAnnouncementPriority` nicks; `null` is
91
+ * "recognised, announce nothing".
92
+ *
93
+ * GTK's `low` is deliberately absent as a TARGET: React Native has three values
94
+ * and ARIA has two live-region levels, so a third GTK priority would have no
95
+ * spelling to arrive from.
96
+ */
97
+ readonly map: Readonly<Record<string, 'low' | 'medium' | 'high' | null>>;
98
+ }
61
99
  /**
62
100
  * A prop that is a DECLARED no-op.
63
101
  *
@@ -106,7 +144,20 @@ export interface GestureRoute {
106
144
  /** The `Gtk.GestureClick` signal — `released` for a completed press. */
107
145
  readonly signal: string;
108
146
  }
109
- export type PropRoute = PropertyRoute | StylePropertyRoute | EventRoute | RefusedRoute | IgnoredRoute | FileRoute | GestureRoute;
147
+ export type PropRoute = PropertyRoute | StylePropertyRoute | EventRoute | RefusedRoute | IgnoredRoute | FileRoute | GestureRoute | AnnounceRoute;
148
+ /**
149
+ * The imperative handle a `ref` on this primitive receives, instead of the widget.
150
+ *
151
+ * DATA and not a per-binding decision, for the reason every other field here is
152
+ * data: React and Solid both hand a `ref` its value, and a handle built in one L3
153
+ * would be a second vocabulary the other one does not have. `handles.ts` turns the
154
+ * kind into the object; the table only says which primitives have one.
155
+ *
156
+ * A primitive with NO kind hands back the `Gtk.Widget` itself, which is what every
157
+ * primitive did before and still does — React Native only gives an imperative
158
+ * handle to the components that document one.
159
+ */
160
+ export type HandleKind = 'text-input';
110
161
  /** A second styleable node inside the element, which the children go into. */
111
162
  export interface ContentSpec {
112
163
  readonly tag: string;
@@ -191,6 +242,17 @@ export interface PrimitiveSpec {
191
242
  * a silent drop for the reason every other one in this file is.
192
243
  */
193
244
  readonly refusesStyle?: string;
245
+ /**
246
+ * What a `ref` on this primitive receives, when it is not the widget.
247
+ *
248
+ * `TextInput` only, and it is React Native's own rule rather than a convenience:
249
+ * `TextInput` is a CLASS there, so `useRef<TextInput>(null)` is ordinary code and
250
+ * `ref.current.focus()` is documented API. Handing back the bare `Gtk.Widget`
251
+ * type-checked as `unknown` and answered `undefined is not a function` at the
252
+ * call — the shape this whole layer refuses to ship for props, arriving through
253
+ * the one channel that had no table.
254
+ */
255
+ readonly handle?: HandleKind;
194
256
  }
195
257
  export declare const PRIMITIVES: Readonly<Record<string, PrimitiveSpec>>;
196
258
  /** The primitives this layer answers for. Derived, so it cannot disagree with the table. */
@@ -0,0 +1,56 @@
1
+ import { type PropAnswer, type PropStatus } from './primitives/answers.js';
2
+ import { PRIMITIVE_NAMES } from './primitives/table.js';
3
+ export type { PropAnswer, PropStatus };
4
+ /**
5
+ * Every primitive this layer answers for.
6
+ *
7
+ * The table's own constant, re-exported rather than recomputed: a second
8
+ * `Object.keys(PRIMITIVES)` is a second thing to keep in step for no gain, and this
9
+ * subpath exists precisely so there is one answer.
10
+ */
11
+ export { PRIMITIVE_NAMES };
12
+ /**
13
+ * One React Native prop that selects a DIFFERENT widget, and therefore a different
14
+ * prop set.
15
+ *
16
+ * `TextInput`'s `multiline` is the only one: `false` is a `Gtk.Entry` and `true` is a
17
+ * `Gtk.TextView`, whose content lives in a buffer rather than a property, so `value`
18
+ * is answered on one and refused on the other. A caller that does not say which gets
19
+ * the base variant, which is what an element with the prop absent resolves to.
20
+ */
21
+ export declare const PRIMITIVE_VARIANTS: Readonly<Record<string, string>>;
22
+ /** Which variant of a primitive to ask about — `{ multiline: true }` for a `TextInput`. */
23
+ export type PropVariant = Readonly<Record<string, boolean>>;
24
+ /**
25
+ * What this layer does about `prop` on `primitive`.
26
+ *
27
+ * The whole answer, not a boolean: the STATUS says which route it takes, `why` is the
28
+ * reason for the two statuses that throw and for the declared no-ops, and `gtk` names
29
+ * what it reaches — the properties, the signal, or nothing.
30
+ */
31
+ export declare function propAnswer(primitive: string, prop: string, variant?: PropVariant): PropAnswer;
32
+ /**
33
+ * Would rendering this prop on this primitive succeed?
34
+ *
35
+ * `true` for every prop that reaches GTK **and** for a declared no-op: `ignored` is an
36
+ * answer, not a refusal, and a test that treated it as one would fail on
37
+ * `autoCapitalize` — an ordinary prop that a desktop correctly does nothing with.
38
+ */
39
+ export declare function acceptsProp(primitive: string, prop: string, variant?: PropVariant): boolean;
40
+ /**
41
+ * The sentence a render would print, for a prop that would not render.
42
+ *
43
+ * `null` for a prop this layer accepts, so `explainProp(…) === null` is the assertion
44
+ * a consumer's test makes and the message is what it prints when it fails.
45
+ */
46
+ export declare function explainProp(primitive: string, prop: string, variant?: PropVariant): string | null;
47
+ /** Every prop name this primitive's table row carries, sorted. Framework props are not among them. */
48
+ export declare function propNames(primitive: string, variant?: PropVariant): readonly string[];
49
+ /**
50
+ * The whole surface as plain data — one entry per primitive per prop.
51
+ *
52
+ * For tooling that wants to walk it rather than ask about one name: a lint rule, a
53
+ * migration script, a dashboard. Built on demand rather than exported as a constant,
54
+ * so a consumer that only asks `acceptsProp` never pays for it.
55
+ */
56
+ export declare function propTable(variant?: PropVariant): readonly PropAnswer[];
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -0,0 +1,58 @@
1
+ /** What `router.push` and its siblings accept, as `expo-router` spells it. */
2
+ export type Href = string | HrefObject;
3
+ export interface HrefObject {
4
+ /** A route pattern — `/detail/[id]` — or a plain path. */
5
+ readonly pathname: string;
6
+ /** Values for the pattern's `[name]` segments; the rest become a query string. */
7
+ readonly params?: Readonly<Record<string, unknown>>;
8
+ }
9
+ /**
10
+ * React Navigation's own nesting keys, which are not the author's params.
11
+ *
12
+ * `screen`, `params`, `initial`, `state`, `path`, `pop` and `merge` are how a nested
13
+ * NAVIGATE addresses a child navigator. Handing them back as though the author had
14
+ * written them makes those seven param names silently unusable, which is why
15
+ * `useLocalSearchParams` has always filtered them — and why `hrefFrom` refuses to
16
+ * SEND one: a param this layer would not read back is a param that vanishes.
17
+ */
18
+ export declare const INTERNAL_PARAMS: ReadonlySet<string>;
19
+ /**
20
+ * A param value → the string a URL can carry, or `null` for one it cannot.
21
+ *
22
+ * `null` rather than a throw, because the two callers want different things from the
23
+ * same answer: `paramsSeenBy` DROPS what it cannot represent (a route really can
24
+ * arrive carrying a dispatched object, and `useLocalSearchParams` has always left it
25
+ * out), while `hrefFrom` REFUSES it by name (an author writing one meant it to
26
+ * survive the trip).
27
+ */
28
+ export declare const scalar: (value: unknown) => string | null;
29
+ /**
30
+ * What `useLocalSearchParams` will hand back for a route carrying `params`.
31
+ *
32
+ * The OUT direction of this file's one rule. Shared with `useLocalSearchParams`
33
+ * itself rather than reimplemented there: two copies of "what counts as a param"
34
+ * would be exactly the mismatch the round-trip test exists to catch, sitting on both
35
+ * sides of it.
36
+ */
37
+ export declare function paramsSeenBy(params: Readonly<Record<string, unknown>> | undefined): Record<string, string>;
38
+ /** `/detail/[id]` → the param names it carries, in order. */
39
+ export declare function patternParams(pathname: string): readonly string[];
40
+ /**
41
+ * An `Href` → the URL string the router resolves.
42
+ *
43
+ * A STRING PASSES THROUGH UNTOUCHED, which is not laziness: expo-router's string
44
+ * form is already a URL, params and all, and re-encoding one would double-escape a
45
+ * query string an author wrote by hand.
46
+ */
47
+ export declare function hrefFrom(call: string, href: Href): string;
48
+ /**
49
+ * The inverse: the params a URL built from `pathname` carries.
50
+ *
51
+ * Pure, and it exists for the round-trip property rather than for the runtime — the
52
+ * real read-back goes through React Navigation's own state. What this gives is a
53
+ * check the layer can run on ITSELF: whatever `hrefFrom` writes into a pattern, this
54
+ * reads out, and the two must agree with `paramsSeenBy`. A drift between the writer
55
+ * and the reader is the defect that produced this file, so it is the one thing here
56
+ * that is asserted rather than argued.
57
+ */
58
+ export declare function paramsInHref(pathname: string, url: string): Record<string, string>;
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -1,3 +1,5 @@
1
+ export { hrefFrom, paramsInHref, paramsSeenBy, patternParams } from './href.js';
2
+ export type { Href, HrefObject } from './href.js';
1
3
  export { router, usePathname, useLocalSearchParams, navigationRef } from './navigation.js';
2
4
  export { Stack, type StackProps, type StackScreenOptions } from './stack.js';
3
5
  export { Tabs, type TabsProps, type TabScreenOptions } from './tabs.js';
@@ -5,6 +7,6 @@ export { RouterRoot, type RouterRootProps } from './root.js';
5
7
  export { RouterError, type RouterErrorCode } from './errors.js';
6
8
  export { buildRouteTree, pathConfigOf, screenUrls, type PathConfigLeaf, type PathConfigNode, type PathConfigTree, type RouteManifest, type RouteManifestEntry, type RouteNode, } from './routes.js';
7
9
  export { componentFor, provideRouteNode, screenOptionsFrom, useRouteNode, useSynthesisedScreens, type ScreenDeclaration, } from './screens.js';
8
- export * from '../generated/unsupported-router-exports.js';
10
+ export * from '../generated/unsupported-router.js';
9
11
  export { ROUTER_NAMES, ROUTER_SUPPORT_TABLE, explainUnsupported, isImportable } from '../support-table.js';
10
12
  export type { SupportEntry, SupportStatus, SupportTier } from '../support-table.js';
@@ -1,3 +1,4 @@
1
+ import { type Href } from './href.js';
1
2
  import { type RouteNode } from './routes.js';
2
3
  /** The container ref every navigator in the tree hangs under. */
3
4
  export declare const navigationRef: import("@react-navigation/core").NavigationContainerRefWithCurrent<ReactNavigation.RootParamList>;
@@ -18,18 +19,31 @@ export declare function uninstallRouter(): void;
18
19
  */
19
20
  export declare function notifyStateChanged(): void;
20
21
  /**
21
- * `expo-router`'s `router`: four methods, and every argument a URL.
22
+ * `expo-router`'s `router`.
22
23
  *
23
24
  * ADR 0032 measured the calls — `push` 19 times, `back` and `replace` a handful
24
- * each, `navigate` where a screen must not stack up. That is the whole object.
25
+ * each, `navigate` where a screen must not stack up.
26
+ *
27
+ * EVERY ARGUMENT IS AN `Href`, which is `string | { pathname, params }`, and the
28
+ * second half of that used to be missing: an object reached the router interpolated
29
+ * as `[object Object]`, matched no route, and landed on `+not-found` — silently, on
30
+ * 10 measured call sites. `href.ts` holds the resolution and the rule it shares with
31
+ * `useLocalSearchParams`.
32
+ *
33
+ * AND THE THREE NAMES THIS OBJECT REFUSES ARE PRESENT. The support table already
34
+ * called `dismiss`, `dismissAll`, `dismissTo`, `setParams` and `canGoBack` "a named
35
+ * refusal rather than an undefined property read" — and they were absent, so reaching
36
+ * for one was `router.dismissTo is not a function`, which names nothing. `canGoBack`
37
+ * is now answered for real, because a back button calls it before deciding whether to
38
+ * render at all.
25
39
  */
26
40
  export declare const router: {
27
41
  /** Go to `href`, adding a history entry even when that screen is already showing. */
28
- readonly push: (href: string) => void;
42
+ readonly push: (href: Href) => void;
29
43
  /** Go to `href`, reusing the screen when it is already the current one. */
30
- readonly navigate: (href: string) => void;
44
+ readonly navigate: (href: Href) => void;
31
45
  /** Replace the current screen with `href`, leaving the history length alone. */
32
- readonly replace: (href: string) => void;
46
+ readonly replace: (href: Href) => void;
33
47
  /**
34
48
  * Go back one entry.
35
49
  *
@@ -39,6 +53,34 @@ export declare const router: {
39
53
  * and nothing anywhere says why.
40
54
  */
41
55
  readonly back: () => void;
56
+ /**
57
+ * Is there anywhere to go back to?
58
+ *
59
+ * The question `back()` refuses to answer for you, and the reason it has to exist:
60
+ * a screen calls this to decide whether to render a back affordance AT ALL, so a
61
+ * missing method is a `router.canGoBack is not a function` the moment anything
62
+ * asks — latent until the first screen that guards its own back button.
63
+ *
64
+ * `false` BEFORE THE CONTAINER IS READY, and that is an answer rather than a
65
+ * placeholder: nothing has been navigated to yet, so there is genuinely nowhere to
66
+ * go back to. `usePathname` answers `/` in the same window for the same reason.
67
+ * Refusing here instead would make the guard need a guard.
68
+ */
69
+ readonly canGoBack: () => boolean;
70
+ /** A modal stack this layer does not have. */
71
+ readonly dismiss: () => never;
72
+ readonly dismissAll: () => never;
73
+ readonly dismissTo: () => never;
74
+ /**
75
+ * Change the current route's params without navigating.
76
+ *
77
+ * Refused rather than built, and the reason is this file's own rule: params travel
78
+ * INTO a route through the pattern (`href.ts`) and back OUT through
79
+ * `useLocalSearchParams`. `setParams` writes them at neither end — it edits the
80
+ * route object in place — so the URL and the params would stop agreeing, and
81
+ * `usePathname` would answer for a URL that no longer describes the screen.
82
+ */
83
+ readonly setParams: () => never;
42
84
  };
43
85
  /**
44
86
  * The current URL, without its query string.
@@ -1,10 +1,45 @@
1
1
  import { type ReactElement, type ReactNode } from 'react';
2
+ import type Adw from '@girs/adw-1';
2
3
  import { type ScreenDeclaration } from './screens.js';
3
4
  /** What one tab can be told. */
4
5
  export interface TabScreenOptions {
5
6
  /** The switcher button's label. Defaults to the route name. */
6
7
  title?: string;
7
8
  }
9
+ /**
10
+ * Put the stack on the focused page, or leave it alone because that page is not there yet.
11
+ *
12
+ * THE PRESENCE CHECK IS THE TERMINATING CONDITION, and the reason it has to be explicit is
13
+ * that the obvious guard is a bet rather than a test. Writing
14
+ *
15
+ * if (stack.get_visible_child_name() !== focused) stack.set_visible_child_name(focused);
16
+ *
17
+ * reads as "set it unless it is already set", and it terminates only when the set TAKES.
18
+ * MEASURED on libadwaita 1.9.3: `set_visible_child_name` with a name the stack does not hold
19
+ * changes nothing, emits NO `notify::visible-child-name`, and prints
20
+ * `Adwaita-WARNING: Child name '…' not found in AdwViewStack`. So `get_visible_child_name()`
21
+ * still answers the old page, the comparison is still unequal, and the effect — which has no
22
+ * dependency array on purpose, because a page can materialise on a render where `focused` did
23
+ * not change — repeats the failing call on every render for as long as the mismatch lasts.
24
+ *
25
+ * A focused route whose page React has not committed yet is an ORDINARY intermediate state,
26
+ * not a fault: the effect runs after the commit that added the OTHER pages, and the missing
27
+ * one arrives on a later commit. So the answer is to do nothing and let the next render try,
28
+ * which is what "not there yet" deserves — and one warning per render for a normal state is
29
+ * how a log stops being read.
30
+ *
31
+ * AND THE SET HAS A SECOND WAY TO DO NOTHING, which is why presence alone is not the whole
32
+ * gate. `adw_view_stack_set_visible_child_name` ends on
33
+ * `if (gtk_widget_get_visible (page->widget)) set_visible_child (...)`, so a page that is
34
+ * there but HIDDEN changes nothing, emits no notify and — unlike the missing name — prints
35
+ * NOTHING AT ALL (measured). That is the same non-terminating state by the quieter road: the
36
+ * caller would be told the stack shows `focused` while it shows the other page, and no log
37
+ * anywhere would disagree. Both no-op paths are therefore asked about BEFORE the write, which
38
+ * is also what keeps each one attributable to its own failing assertion.
39
+ *
40
+ * @returns whether the stack now shows `focused`.
41
+ */
42
+ export declare function showFocusedPage(stack: Adw.ViewStack, focused: string): boolean;
8
43
  /** A `<Tabs.Screen>` declaration. Read as data by `<Tabs>`; never rendered. */
9
44
  declare function TabsScreen(_props: ScreenDeclaration & {
10
45
  options?: TabScreenOptions;
@@ -1,5 +1,6 @@
1
1
  import { createElement, mount } from '@gjsify/gtk-host/solid';
2
2
  import type { ClassNameInput } from '../primitives/classes.js';
3
+ import { type TextInputHandle } from '../primitives/handles.js';
3
4
  import type { StyleInput } from '../primitives/style.js';
4
5
  /**
5
6
  * The host's node type, named through the adapter rather than imported.
@@ -39,6 +40,8 @@ export interface TextProps extends CommonProps {
39
40
  numberOfLines?: number;
40
41
  ellipsizeMode?: 'head' | 'middle' | 'tail';
41
42
  selectable?: boolean;
43
+ /** Announce this label's text when it changes. `Text` alone — see the React binding's own note. */
44
+ accessibilityLiveRegion?: 'none' | 'polite' | 'assertive';
42
45
  }
43
46
  export declare function Text(props: TextProps): HostNode;
44
47
  export interface PressableProps extends CommonProps {
@@ -77,7 +80,7 @@ export interface ActivityIndicatorProps extends CommonProps {
77
80
  hidesWhenStopped?: boolean;
78
81
  }
79
82
  export declare function ActivityIndicator(props: ActivityIndicatorProps): HostNode;
80
- export interface TextInputProps extends CommonProps {
83
+ export interface TextInputProps extends Omit<CommonProps, 'ref'> {
81
84
  value?: string;
82
85
  defaultValue?: string;
83
86
  placeholder?: string;
@@ -89,6 +92,17 @@ export interface TextInputProps extends CommonProps {
89
92
  maxLength?: number;
90
93
  secureTextEntry?: boolean;
91
94
  keyboardType?: 'default' | 'email-address' | 'phone-pad' | 'number-pad' | 'numeric' | 'decimal-pad' | 'url';
95
+ /** A declared no-op: there is no autofill service on a GTK desktop. */
96
+ autoComplete?: string;
97
+ /** `autoComplete`'s iOS spelling, and the same absent addressee. */
98
+ textContentType?: string;
99
+ /** A declared no-op: each widget has one Return behaviour, and `multiline` picks the widget. */
100
+ submitBehavior?: 'submit' | 'blurAndSubmit' | 'newline';
101
+ /** The imperative handle, not the widget — L2 decides that, so both bindings agree. */
102
+ ref?: (handle: TextInputHandle) => void;
103
+ }
104
+ /** The instance type, merged with the component below. React Native's `TextInput` is a class. */
105
+ export interface TextInput extends TextInputHandle {
92
106
  }
93
107
  export declare function TextInput(props: TextInputProps): HostNode;
94
108
  export interface SwitchProps extends CommonProps {