@gjsify/gtk-host 0.48.0 → 0.49.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 (38) hide show
  1. package/README.md +108 -6
  2. package/lib/esm/adjustment.js +1 -0
  3. package/lib/esm/conformance/diagnostics.js +1 -1
  4. package/lib/esm/conformance/index.js +1 -1
  5. package/lib/esm/descriptors/adw.js +1 -1
  6. package/lib/esm/descriptors/gtk.js +1 -1
  7. package/lib/esm/descriptors/index.js +1 -1
  8. package/lib/esm/errors.js +1 -1
  9. package/lib/esm/font-families.js +1 -0
  10. package/lib/esm/fonts.js +1 -1
  11. package/lib/esm/host.js +1 -1
  12. package/lib/esm/index.js +1 -1
  13. package/lib/esm/list-model.js +1 -0
  14. package/lib/esm/menu.js +1 -1
  15. package/lib/esm/policies.js +1 -1
  16. package/lib/esm/props.js +1 -1
  17. package/lib/types/adjustment.d.ts +28 -0
  18. package/lib/types/attrs.d.ts +49 -1
  19. package/lib/types/conformance/index.d.ts +14 -4
  20. package/lib/types/descriptors/gtk.d.ts +32 -1
  21. package/lib/types/errors.d.ts +34 -2
  22. package/lib/types/font-families.d.ts +40 -0
  23. package/lib/types/font-families.spec.d.ts +2 -0
  24. package/lib/types/fonts.d.ts +45 -1
  25. package/lib/types/generated/enum-values.d.mts +38 -0
  26. package/lib/types/generated/methods.d.mts +46 -0
  27. package/lib/types/jsx-runtime.d.ts +2 -2
  28. package/lib/types/list-model.d.ts +38 -0
  29. package/lib/types/list-model.spec.d.ts +2 -0
  30. package/lib/types/placement.spec.d.ts +2 -0
  31. package/lib/types/policies.d.ts +177 -1
  32. package/lib/types/react-jsx-runtime.d.ts +2 -2
  33. package/lib/types/shared-trees.spec.d.ts +2 -0
  34. package/lib/types/testing/refusal.d.mts +2 -0
  35. package/lib/types/types.d.ts +99 -2
  36. package/lib/types/vue-components.d.ts +2 -2
  37. package/package.json +7 -5
  38. /package/lib/types/{portal.spec.d.ts → adjustment.spec.d.ts} +0 -0
@@ -107,13 +107,32 @@ export type HostNode = HostElement | HostText | HostAnchor;
107
107
  * accepts the very same append in silence at exit 0 — re-testing this on a bare
108
108
  * box "disproves" it and puts the append back.
109
109
  *
110
+ * THE ABORT IS THE LOUD HALF OF A CLASS, and its quiet half arrives through the
111
+ * same door (ADR 0054). MEASURED on the same libraries, one process per case:
112
+ * `box.append(new Gtk.Window())` with the box rooted is **exit 0, silent**, and
113
+ * afterwards `win.get_parent()` is the box while `win.get_root()` is the window
114
+ * ITSELF — a `GtkRoot` with a parent, which is a contradiction GTK states nowhere.
115
+ * Presenting that window then draws it as a toplevel AND leaves it in the box's
116
+ * child list, so the container measures and allocates a window. One node kind
117
+ * aborts, its neighbour says nothing; both are the same question answered wrong,
118
+ * so both are answered here.
119
+ *
110
120
  * So the descriptor declares the axis, and `policies.ts` is the only reader.
111
121
  * `parented` is every other widget and is what an ABSENT `placement` means; the
112
122
  * union still cannot be forgotten because there is exactly one normaliser
113
123
  * (`placementOf`) and every switch over it ends in `unhandledPlacement`.
114
124
  */
115
125
  export type NodePlacement =
116
- /** The parent's `ChildPolicy` places it. Every widget but the dialog family. */
126
+ /**
127
+ * The parent's `ChildPolicy` places it — every widget but the two families below.
128
+ *
129
+ * DECLARING it is not the same as leaving it out, and the difference is an
130
+ * escape hatch rather than a nicety: the host refuses a node whose CLASS says
131
+ * it cannot be parented (`unparentableChild`), and that refusal fires only
132
+ * where the descriptor is SILENT. A consumer whose own widget trips the
133
+ * structural oracle — a `present(parent)` method on a widget that really is a
134
+ * child — writes this arm and is placed by its parent again.
135
+ */
117
136
  {
118
137
  readonly kind: 'parented';
119
138
  }
@@ -141,6 +160,44 @@ export type NodePlacement =
141
160
  readonly kind: 'portal';
142
161
  readonly present: string;
143
162
  readonly close: string;
163
+ }
164
+ /**
165
+ * The node IS a root: `present()` / `destroy()`, and no parent anywhere.
166
+ *
167
+ * WHAT SEPARATES IT FROM A PORTAL IS THE ARITY, and that is a fact about the
168
+ * two libraries rather than a convention: measured, `adw_dialog_present` takes
169
+ * 1 argument and `gtk_window_present` takes 0. A portal has two positions in
170
+ * the tree and the parent is what joins them; a toplevel has ONE, its own, so
171
+ * there is nothing to present it against. `descriptorProblems()` holds both
172
+ * arities, so the two arms cannot be swapped by a copy/paste.
173
+ *
174
+ * MEMBERSHIP IS `Gtk.Root`, measured with `GObject.type_is_a` and not read
175
+ * from documentation — `GtkWindow` and `AdwApplicationWindow` down to
176
+ * `GtkPrintUnixDialog`. It is GTK's own word for "this widget is a toplevel",
177
+ * which is why the generic code asks it instead of forming a second opinion,
178
+ * and `placement.spec.ts` is where the membership is walked and counted.
179
+ *
180
+ * `close: 'destroy'` IS THE FORCED ONE, the same choice the portal arm makes
181
+ * and for the same measured reason. On GTK 4.22.4: `gtk_window_close()` emits
182
+ * `close-request`, and a handler returning TRUE leaves the window mapped and
183
+ * visible — which is exactly how an application vetoes a user's close. An
184
+ * unmount is not a user request, so the conditional call is the wrong one;
185
+ * `gtk_window_destroy()` takes it down regardless. Both are silent on a window
186
+ * that was never presented (measured), so the host needs no "is it up?" probe.
187
+ *
188
+ * AND THE FORCED CALL IS TERMINAL HERE, which is where this arm stops being a
189
+ * copy of the portal one. MEASURED: `present()` after either `close()` or
190
+ * `destroy()` answers `Gtk-WARNING **: A window is shown after it has been
191
+ * destroyed. This will leave the window in an inconsistent state.` — GTK4's
192
+ * default `close-request` handler destroys the window, so `close()` is a
193
+ * conditional destroy rather than a hide. A retracted toplevel is therefore
194
+ * gone for good, and a re-mount is a fresh widget (which is what `rebuild`
195
+ * already does for a construct-only write).
196
+ */
197
+ | {
198
+ readonly kind: 'toplevel';
199
+ readonly present: string;
200
+ readonly close: string;
144
201
  };
145
202
  export type PolicyKind = 'none' | 'single' | 'ordered' | 'indexed' | 'slotted' | 'keyed' | 'coords';
146
203
  /**
@@ -176,12 +233,52 @@ export type ChildPolicy = {
176
233
  remove: string;
177
234
  reorder: 'native' | 'remove-all';
178
235
  }
179
- /** `Gtk.ListBox`/`Gtk.FlowBox`: index-addressed, and the parent addresses a WRAPPER row. */
236
+ /**
237
+ * `Gtk.ListBox`/`Gtk.FlowBox`: index-addressed, and the parent addresses a WRAPPER row.
238
+ *
239
+ * `perLineCap` names a property the host keeps EQUAL TO THE CHILD COUNT, and
240
+ * `Gtk.FlowBox:max-children-per-line` is the only one. It is a cap, so every
241
+ * value at or above the child count lays the children out identically — and
242
+ * that equivalence is exactly what hid the cost, because GTK MEASURES THE CAP
243
+ * RATHER THAN THE CHILDREN.
244
+ *
245
+ * MEASURED on GTK 4.22.4, one `Gtk.FlowBox` holding TWO children, per
246
+ * HEIGHT-FOR-WIDTH measure — `measure(VERTICAL, 400)`, which is the one a
247
+ * container in a window asks for:
248
+ *
249
+ * | cap | 7 | 64 | 1024 | 8192 | 32768 | 65535 |
250
+ * | --- | --- | --- | --- | --- | --- | --- |
251
+ * | ms | 0.021 | 0.025 | 0.43 | 18.6 | 391.5 | 1393.2 |
252
+ *
253
+ * Quadratic in the cap, so "as many as fit" spelled as G_MAXUINT cost a second
254
+ * and a half to measure two chips, and a real application froze its main loop
255
+ * for 12.7 s at startup over five two-child rows. The ORIENTATION is part of
256
+ * the claim and not a detail: `measure(HORIZONTAL, -1)` stays under 0.1 ms at
257
+ * every one of those caps, so a re-measurement that asks for the width alone
258
+ * reproduces none of this.
259
+ *
260
+ * The cap is wrong in the ANSWER too, not only in what the answer costs.
261
+ * Natural width is `content + column-spacing × (cap - 1)` — measured, exactly,
262
+ * over five caps — so a cap above the child count `n` carries
263
+ * `column-spacing × (cap - n)` px of gaps that do not exist. 12 children at
264
+ * `column-spacing: 8`: 683 px natural at a cap of 12 and 524 867 px at 65535,
265
+ * the excess exactly 8 × 65 523. At `column-spacing: 0` there is no difference
266
+ * at all, which is how a pinned cap passed for as long as it did.
267
+ *
268
+ * The child count is the exact answer rather than a smaller cap chosen to be
269
+ * safe: a line can never hold more children than exist, so it forbids nothing
270
+ * G_MAXUINT allowed, and it is the largest value that costs nothing.
271
+ *
272
+ * An AUTHORED value wins. `<GtkFlowBox maxChildrenPerLine={3}>` is someone
273
+ * asking for three per line, and a sync that overwrote it would be the same
274
+ * silent kind of wrong this field exists to remove.
275
+ */
180
276
  | {
181
277
  kind: 'indexed';
182
278
  insert: string;
183
279
  remove: string;
184
280
  wrap: 'list-box-row' | 'flow-box-child' | null;
281
+ perLineCap?: string;
185
282
  }
186
283
  /**
187
284
  * `Adw.HeaderBar`, `Adw.ToolbarView`, `Adw.ActionRow`: named attachment points.
@@ -33,11 +33,11 @@
33
33
  * resolve goes unchecked.
34
34
  */
35
35
  import type { DefineComponent } from '@vue/runtime-core';
36
- import type { VueAttributes, WithOnce, WithPortableMenu } from './attrs.js';
36
+ import type { VueAttributes, WithOnce, WithPortableValues } from './attrs.js';
37
37
  import type { WidgetPropsByGType, WidgetPropsVueAliases } from './generated/props.js';
38
38
  type VueWidgetProps = WidgetPropsByGType & WidgetPropsVueAliases;
39
39
  export type GtkGlobalComponents = {
40
- [K in keyof VueWidgetProps]: DefineComponent<WithOnce<WithPortableMenu<VueWidgetProps[K]>> & VueAttributes>;
40
+ [K in keyof VueWidgetProps]: DefineComponent<WithOnce<WithPortableValues<VueWidgetProps[K]>> & VueAttributes>;
41
41
  };
42
42
  declare module '@vue/runtime-core' {
43
43
  interface GlobalComponents extends GtkGlobalComponents {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/gtk-host",
3
- "version": "0.48.0",
3
+ "version": "0.49.0",
4
4
  "description": "Framework-agnostic GTK4/Adwaita host: the element model UI-framework renderers bind to",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -80,7 +80,9 @@
80
80
  "test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:gjs",
81
81
  "test:gjs": "gjsify run test.gjs.mjs",
82
82
  "test:gjs-on-node": "gjsify run build:gjsify && gjsify run build:test:node && node dist/test.node.mjs",
83
- "generate": "gjsify build src/generator/main.mts --app gjs --outfile tmp/generate.gjs.mjs && gjsify run tmp/generate.gjs.mjs -- --out src/generated && gjsify format src/generated"
83
+ "generate": "gjsify build src/generator/main.mts --app gjs --outfile tmp/generate.gjs.mjs && gjsify run tmp/generate.gjs.mjs -- --out src/generated && gjsify format src/generated",
84
+ "generate:enum-values": "gjs -m ../../../scripts/generate-enum-values.mjs",
85
+ "generate:methods": "gjs -m ../../../scripts/generate-widget-methods.mjs"
84
86
  },
85
87
  "keywords": [
86
88
  "gjs",
@@ -99,7 +101,7 @@
99
101
  "@girs/gtk-4.0": "4.6.0",
100
102
  "@girs/pango-1.0": "4.6.0",
101
103
  "@girs/pangocairo-1.0": "4.6.0",
102
- "@gjsify/adwaita-core": "^0.48.0"
104
+ "@gjsify/adwaita-core": "^0.49.0"
103
105
  },
104
106
  "peerDependencies": {
105
107
  "@vue/runtime-core": "^3.5.0",
@@ -122,10 +124,10 @@
122
124
  }
123
125
  },
124
126
  "devDependencies": {
125
- "@gjsify/cli": "^0.48.0",
127
+ "@gjsify/cli": "^0.49.0",
126
128
  "@vue/runtime-core": "^3.5.0",
127
129
  "solid-js": "^1.9.0",
128
- "@gjsify/unit": "^0.48.0",
130
+ "@gjsify/unit": "^0.49.0",
129
131
  "@types/node": "^25.9.2",
130
132
  "typescript": "^6.0.3",
131
133
  "@gjsify/node-gi": "file:../../node-gi/node-gi",