@gtkx/react 1.2.1 → 1.3.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.
@@ -31,6 +31,7 @@ import {
31
31
  } from "./node.js";
32
32
  import { isRootElement, type RootElement } from "./root-element.js";
33
33
  import { disconnectAllHandlers } from "./signals.js";
34
+ import { releaseStyle } from "./style.js";
34
35
  import {
35
36
  didUpdateTextSurgically,
36
37
  enclosingHost,
@@ -133,7 +134,7 @@ const hostConfig = {
133
134
  unhideTextInstance: (): void => undefined,
134
135
  detachDeletedInstance: (instance: Instance): void => {
135
136
  if (instance.kind === ELEMENT_KIND) {
136
- disconnectAllHandlers(instance);
137
+ detachElement(instance);
137
138
  } else if (instance.kind === LAZY_KIND && instance.adopted !== null) {
138
139
  disconnectAllHandlers(lazyTarget(instance, instance.adopted));
139
140
  }
@@ -187,6 +188,14 @@ function createPriorityTracker(): PriorityTracker {
187
188
  };
188
189
  }
189
190
 
191
+ const detachElement = (instance: ElementNode): void => {
192
+ disconnectAllHandlers(instance);
193
+
194
+ if (instance.object instanceof Gtk.Widget) {
195
+ releaseStyle(instance.object);
196
+ }
197
+ };
198
+
190
199
  const updateInstance = (instance: Instance, prev: Props, next: Props): void => {
191
200
  if (instance.kind === ELEMENT_KIND) {
192
201
  assertPropsCanChange(instance.typeName, prev, next);
@@ -0,0 +1,83 @@
1
+ import type * as Gtk from "@gtkx/gi/gtk";
2
+ import { attachParsingErrorLogger, registerProviderForDefaultDisplay, scopedRule } from "@gtkx/css/internal";
3
+ import { STYLE_PROVIDER_PRIORITY_APPLICATION } from "@gtkx/gi/gtk";
4
+ import { createLogger, type Logger } from "@gtkx/utils";
5
+ import { applyWrite } from "./signals.js";
6
+
7
+ type StyleSlot = { provider: Gtk.CssProvider; className: string; css: string };
8
+
9
+ const CLASS_PREFIX = "gtkx-s";
10
+ const STYLE_PRIORITY = STYLE_PROVIDER_PRIORITY_APPLICATION + 1;
11
+ const log: Logger = createLogger("react");
12
+ const styles: WeakMap<Gtk.Widget, StyleSlot> = new WeakMap();
13
+ const pool: StyleSlot[] = [];
14
+ const counter: { next: number } = { next: 0 };
15
+
16
+ const reclaimed: FinalizationRegistry<StyleSlot> = new FinalizationRegistry((slot) => {
17
+ pool.push(slot);
18
+ });
19
+
20
+ const createSlot = (): StyleSlot => {
21
+ counter.next += 1;
22
+ const provider = registerProviderForDefaultDisplay({ priority: STYLE_PRIORITY, followsPreferences: false });
23
+ attachParsingErrorLogger(provider, log, "a style prop");
24
+
25
+ return { provider, className: `${CLASS_PREFIX}${counter.next.toString()}`, css: "" };
26
+ };
27
+
28
+ const styleClass = (widget: Gtk.Widget): string | null => styles.get(widget)?.className ?? null;
29
+
30
+ const releaseStyle = (widget: Gtk.Widget): void => {
31
+ const slot = styles.get(widget);
32
+
33
+ if (slot === undefined) {
34
+ return;
35
+ }
36
+
37
+ styles.delete(widget);
38
+ reclaimed.unregister(widget);
39
+
40
+ applyWrite(() => {
41
+ widget.removeCssClass(slot.className);
42
+ });
43
+
44
+ pool.push(slot);
45
+ };
46
+
47
+ const ensureSlot = (widget: Gtk.Widget): StyleSlot => {
48
+ const existing = styles.get(widget);
49
+
50
+ if (existing !== undefined) {
51
+ return existing;
52
+ }
53
+
54
+ const slot = pool.pop() ?? createSlot();
55
+ styles.set(widget, slot);
56
+ reclaimed.register(widget, slot, widget);
57
+
58
+ applyWrite(() => {
59
+ widget.addCssClass(slot.className);
60
+ });
61
+
62
+ return slot;
63
+ };
64
+
65
+ const applyStyle = (widget: Gtk.Widget, style: unknown): string | null => {
66
+ if (typeof style !== "object" || style === null) {
67
+ releaseStyle(widget);
68
+
69
+ return null;
70
+ }
71
+
72
+ const slot = ensureSlot(widget);
73
+ const css = scopedRule(slot.className, style);
74
+
75
+ if (css !== slot.css) {
76
+ slot.css = css;
77
+ slot.provider.loadFromString(css);
78
+ }
79
+
80
+ return slot.className;
81
+ };
82
+
83
+ export { applyStyle, releaseStyle, styleClass };
@@ -201,42 +201,50 @@ function buildRelation(relation: Gtk.AccessibleRelation, type: AccessibleValueTy
201
201
  };
202
202
  }
203
203
 
204
+ const initValue = (gtype: GObject.Type, populate: (value: GObject.Value) => void): GObject.Value => {
205
+ const value = new GObject.Value();
206
+ value.init(gtype);
207
+ populate(value);
208
+
209
+ return value;
210
+ };
211
+
204
212
  const buildValue = (descriptor: AccessibleDescriptor, jsValue: unknown): GObject.Value => {
205
213
  switch (descriptor.type) {
206
214
  case "string": {
207
- return GObject.buildValue(GObject.TYPE_STRING, (v) => {
215
+ return initValue(GObject.TYPE_STRING, (v) => {
208
216
  v.setString(jsValue as string);
209
217
  });
210
218
  }
211
219
  case "boolean": {
212
- return GObject.buildValue(GObject.TYPE_BOOLEAN, (v) => {
220
+ return initValue(GObject.TYPE_BOOLEAN, (v) => {
213
221
  v.setBoolean(jsValue as boolean);
214
222
  });
215
223
  }
216
224
  case "optionalBoolean": {
217
- return GObject.buildValue(GObject.TYPE_INT, (v) => {
225
+ return initValue(GObject.TYPE_INT, (v) => {
218
226
  v.setInt(jsValue === true ? 1 : 0);
219
227
  });
220
228
  }
221
229
  case "int": {
222
- return GObject.buildValue(GObject.TYPE_INT, (v) => {
230
+ return initValue(GObject.TYPE_INT, (v) => {
223
231
  v.setInt(jsValue as number);
224
232
  });
225
233
  }
226
234
  case "double": {
227
- return GObject.buildValue(GObject.TYPE_DOUBLE, (v) => {
235
+ return initValue(GObject.TYPE_DOUBLE, (v) => {
228
236
  v.setDouble(jsValue as number);
229
237
  });
230
238
  }
231
239
  case "object": {
232
- return GObject.buildValue(GObject.TYPE_OBJECT, (v) => {
240
+ return initValue(GObject.TYPE_OBJECT, (v) => {
233
241
  v.setObject(jsValue as GObject.Object | null);
234
242
  });
235
243
  }
236
244
  case "list": {
237
245
  const list = Gtk.AccessibleList.newFromList(jsValue as Gtk.Accessible[]);
238
246
 
239
- return GObject.buildValue(Gtk.AccessibleList.prototype.__type__, (v) => {
247
+ return initValue(Gtk.AccessibleList.prototype.__type__, (v) => {
240
248
  v.setBoxed(list);
241
249
  });
242
250
  }