@gtkx/react 0.19.0 → 0.20.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.
- package/dist/components/list.d.ts +35 -0
- package/dist/components/list.d.ts.map +1 -0
- package/dist/components/list.js +40 -0
- package/dist/components/list.js.map +1 -0
- package/dist/generated/internal.d.ts +5 -6
- package/dist/generated/internal.d.ts.map +1 -1
- package/dist/generated/internal.js +3473 -260
- package/dist/generated/internal.js.map +1 -1
- package/dist/generated/jsx.d.ts +0 -324
- package/dist/generated/jsx.d.ts.map +1 -1
- package/dist/generated/jsx.js +0 -324
- package/dist/generated/jsx.js.map +1 -1
- package/dist/host-config.d.ts.map +1 -1
- package/dist/host-config.js +2 -0
- package/dist/host-config.js.map +1 -1
- package/dist/jsx.d.ts +42 -105
- package/dist/jsx.d.ts.map +1 -1
- package/dist/jsx.js +2 -66
- package/dist/jsx.js.map +1 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +7 -3
- package/dist/metadata.js.map +1 -1
- package/dist/node.d.ts +0 -4
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +19 -41
- package/dist/node.js.map +1 -1
- package/dist/nodes/application.d.ts.map +1 -1
- package/dist/nodes/application.js +4 -0
- package/dist/nodes/application.js.map +1 -1
- package/dist/nodes/column-view-column.d.ts +19 -19
- package/dist/nodes/column-view-column.d.ts.map +1 -1
- package/dist/nodes/column-view-column.js +130 -119
- package/dist/nodes/column-view-column.js.map +1 -1
- package/dist/nodes/event-controller.d.ts.map +1 -1
- package/dist/nodes/event-controller.js +3 -9
- package/dist/nodes/event-controller.js.map +1 -1
- package/dist/nodes/internal/accessible.d.ts.map +1 -1
- package/dist/nodes/internal/accessible.js.map +1 -1
- package/dist/nodes/internal/bound-item.d.ts +4 -0
- package/dist/nodes/internal/bound-item.d.ts.map +1 -0
- package/dist/nodes/internal/bound-item.js +2 -0
- package/dist/nodes/internal/bound-item.js.map +1 -0
- package/dist/nodes/internal/construct.d.ts +1 -8
- package/dist/nodes/internal/construct.d.ts.map +1 -1
- package/dist/nodes/internal/construct.js +30 -54
- package/dist/nodes/internal/construct.js.map +1 -1
- package/dist/nodes/internal/widget.d.ts.map +1 -1
- package/dist/nodes/internal/widget.js +4 -1
- package/dist/nodes/internal/widget.js.map +1 -1
- package/dist/nodes/list-item-node.d.ts +12 -0
- package/dist/nodes/list-item-node.d.ts.map +1 -0
- package/dist/nodes/list-item-node.js +23 -0
- package/dist/nodes/list-item-node.js.map +1 -0
- package/dist/nodes/list.d.ts +100 -0
- package/dist/nodes/list.d.ts.map +1 -0
- package/dist/nodes/list.js +950 -0
- package/dist/nodes/list.js.map +1 -0
- package/dist/nodes/notebook-page.d.ts.map +1 -1
- package/dist/nodes/notebook-page.js +4 -0
- package/dist/nodes/notebook-page.js.map +1 -1
- package/dist/nodes/widget.d.ts.map +1 -1
- package/dist/nodes/widget.js +9 -8
- package/dist/nodes/widget.js.map +1 -1
- package/dist/nodes/window.d.ts.map +1 -1
- package/dist/nodes/window.js +2 -2
- package/dist/nodes/window.js.map +1 -1
- package/dist/registry.d.ts +0 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +4 -13
- package/dist/registry.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/components/list.tsx +83 -0
- package/src/generated/internal.ts +3479 -258
- package/src/generated/jsx.ts +0 -324
- package/src/host-config.ts +2 -0
- package/src/jsx.ts +49 -141
- package/src/metadata.ts +6 -3
- package/src/node.ts +23 -39
- package/src/nodes/application.ts +5 -0
- package/src/nodes/column-view-column.ts +125 -128
- package/src/nodes/event-controller.ts +3 -11
- package/src/nodes/internal/accessible.ts +0 -1
- package/src/nodes/internal/bound-item.ts +4 -0
- package/src/nodes/internal/construct.ts +38 -68
- package/src/nodes/internal/widget.ts +3 -1
- package/src/nodes/list-item-node.ts +29 -0
- package/src/nodes/list.ts +1082 -0
- package/src/nodes/notebook-page.ts +4 -0
- package/src/nodes/widget.ts +8 -13
- package/src/nodes/window.ts +2 -2
- package/src/registry.ts +11 -19
- package/src/types.ts +7 -2
- package/dist/fiber-root.d.ts +0 -4
- package/dist/fiber-root.d.ts.map +0 -1
- package/dist/fiber-root.js +0 -6
- package/dist/fiber-root.js.map +0 -1
- package/dist/nodes/column-view.d.ts +0 -37
- package/dist/nodes/column-view.d.ts.map +0 -1
- package/dist/nodes/column-view.js +0 -205
- package/dist/nodes/column-view.js.map +0 -1
- package/dist/nodes/drop-down.d.ts +0 -37
- package/dist/nodes/drop-down.d.ts.map +0 -1
- package/dist/nodes/drop-down.js +0 -231
- package/dist/nodes/drop-down.js.map +0 -1
- package/dist/nodes/grid-view.d.ts +0 -30
- package/dist/nodes/grid-view.d.ts.map +0 -1
- package/dist/nodes/grid-view.js +0 -90
- package/dist/nodes/grid-view.js.map +0 -1
- package/dist/nodes/internal/base-item-renderer.d.ts +0 -28
- package/dist/nodes/internal/base-item-renderer.d.ts.map +0 -1
- package/dist/nodes/internal/base-item-renderer.js +0 -85
- package/dist/nodes/internal/base-item-renderer.js.map +0 -1
- package/dist/nodes/internal/grid-item-renderer.d.ts +0 -20
- package/dist/nodes/internal/grid-item-renderer.d.ts.map +0 -1
- package/dist/nodes/internal/grid-item-renderer.js +0 -66
- package/dist/nodes/internal/grid-item-renderer.js.map +0 -1
- package/dist/nodes/internal/header-item-renderer.d.ts +0 -23
- package/dist/nodes/internal/header-item-renderer.d.ts.map +0 -1
- package/dist/nodes/internal/header-item-renderer.js +0 -87
- package/dist/nodes/internal/header-item-renderer.js.map +0 -1
- package/dist/nodes/internal/header-renderer-manager.d.ts +0 -13
- package/dist/nodes/internal/header-renderer-manager.d.ts.map +0 -1
- package/dist/nodes/internal/header-renderer-manager.js +0 -20
- package/dist/nodes/internal/header-renderer-manager.js.map +0 -1
- package/dist/nodes/internal/list-item-renderer.d.ts +0 -27
- package/dist/nodes/internal/list-item-renderer.d.ts.map +0 -1
- package/dist/nodes/internal/list-item-renderer.js +0 -131
- package/dist/nodes/internal/list-item-renderer.js.map +0 -1
- package/dist/nodes/internal/list-store.d.ts +0 -21
- package/dist/nodes/internal/list-store.d.ts.map +0 -1
- package/dist/nodes/internal/list-store.js +0 -90
- package/dist/nodes/internal/list-store.js.map +0 -1
- package/dist/nodes/internal/sectioned-list-store.d.ts +0 -50
- package/dist/nodes/internal/sectioned-list-store.d.ts.map +0 -1
- package/dist/nodes/internal/sectioned-list-store.js +0 -250
- package/dist/nodes/internal/sectioned-list-store.js.map +0 -1
- package/dist/nodes/internal/selection-helpers.d.ts +0 -12
- package/dist/nodes/internal/selection-helpers.d.ts.map +0 -1
- package/dist/nodes/internal/selection-helpers.js +0 -25
- package/dist/nodes/internal/selection-helpers.js.map +0 -1
- package/dist/nodes/internal/selection-model-controller.d.ts +0 -26
- package/dist/nodes/internal/selection-model-controller.d.ts.map +0 -1
- package/dist/nodes/internal/selection-model-controller.js +0 -82
- package/dist/nodes/internal/selection-model-controller.js.map +0 -1
- package/dist/nodes/internal/simple-list-store.d.ts +0 -15
- package/dist/nodes/internal/simple-list-store.d.ts.map +0 -1
- package/dist/nodes/internal/simple-list-store.js +0 -110
- package/dist/nodes/internal/simple-list-store.js.map +0 -1
- package/dist/nodes/internal/tree-store.d.ts +0 -37
- package/dist/nodes/internal/tree-store.d.ts.map +0 -1
- package/dist/nodes/internal/tree-store.js +0 -253
- package/dist/nodes/internal/tree-store.js.map +0 -1
- package/dist/nodes/list-item.d.ts +0 -24
- package/dist/nodes/list-item.d.ts.map +0 -1
- package/dist/nodes/list-item.js +0 -83
- package/dist/nodes/list-item.js.map +0 -1
- package/dist/nodes/list-section.d.ts +0 -27
- package/dist/nodes/list-section.d.ts.map +0 -1
- package/dist/nodes/list-section.js +0 -43
- package/dist/nodes/list-section.js.map +0 -1
- package/dist/nodes/list-view.d.ts +0 -32
- package/dist/nodes/list-view.d.ts.map +0 -1
- package/dist/nodes/list-view.js +0 -123
- package/dist/nodes/list-view.js.map +0 -1
- package/dist/nodes/models/list.d.ts +0 -39
- package/dist/nodes/models/list.d.ts.map +0 -1
- package/dist/nodes/models/list.js +0 -207
- package/dist/nodes/models/list.js.map +0 -1
- package/src/fiber-root.ts +0 -20
- package/src/nodes/column-view.ts +0 -262
- package/src/nodes/drop-down.ts +0 -284
- package/src/nodes/grid-view.ts +0 -119
- package/src/nodes/internal/base-item-renderer.ts +0 -107
- package/src/nodes/internal/grid-item-renderer.ts +0 -78
- package/src/nodes/internal/header-item-renderer.ts +0 -105
- package/src/nodes/internal/header-renderer-manager.ts +0 -33
- package/src/nodes/internal/list-item-renderer.ts +0 -162
- package/src/nodes/internal/list-store.ts +0 -107
- package/src/nodes/internal/sectioned-list-store.ts +0 -287
- package/src/nodes/internal/selection-helpers.ts +0 -35
- package/src/nodes/internal/selection-model-controller.ts +0 -119
- package/src/nodes/internal/simple-list-store.ts +0 -116
- package/src/nodes/internal/tree-store.ts +0 -289
- package/src/nodes/list-item.ts +0 -107
- package/src/nodes/list-section.ts +0 -64
- package/src/nodes/list-view.ts +0 -164
- package/src/nodes/models/list.ts +0 -250
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import type * as Gio from "@gtkx/ffi/gio";
|
|
2
|
-
import * as Gtk from "@gtkx/ffi/gtk";
|
|
3
|
-
import type { GtkListViewProps } from "../../jsx.js";
|
|
4
|
-
import type { SignalStore } from "./signal-store.js";
|
|
5
|
-
|
|
6
|
-
type SelectionModel = Gtk.NoSelection | Gtk.SingleSelection | Gtk.MultiSelection;
|
|
7
|
-
|
|
8
|
-
type SelectionModelConfig = Pick<GtkListViewProps, "selectionMode" | "selected" | "onSelectionChanged"> & {
|
|
9
|
-
owner: object;
|
|
10
|
-
signalStore: SignalStore;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export class SelectionModelController {
|
|
14
|
-
private owner: object;
|
|
15
|
-
private signalStore: SignalStore;
|
|
16
|
-
private selectionModel: SelectionModel;
|
|
17
|
-
private getSelection: () => string[];
|
|
18
|
-
private resolveSelectionIndices: (ids: string[]) => Gtk.Bitset;
|
|
19
|
-
private getItemCount: () => number;
|
|
20
|
-
|
|
21
|
-
constructor(
|
|
22
|
-
config: SelectionModelConfig,
|
|
23
|
-
model: Gio.ListModel,
|
|
24
|
-
getSelection: () => string[],
|
|
25
|
-
resolveSelectionIndices: (ids: string[]) => Gtk.Bitset,
|
|
26
|
-
getItemCount: () => number,
|
|
27
|
-
) {
|
|
28
|
-
this.owner = config.owner;
|
|
29
|
-
this.signalStore = config.signalStore;
|
|
30
|
-
this.selectionModel = this.createSelectionModel(config.selectionMode, model);
|
|
31
|
-
this.selectionModel.setModel(model);
|
|
32
|
-
this.getSelection = getSelection;
|
|
33
|
-
this.resolveSelectionIndices = resolveSelectionIndices;
|
|
34
|
-
this.getItemCount = getItemCount;
|
|
35
|
-
this.initSelectionHandler(config.onSelectionChanged);
|
|
36
|
-
this.setSelection(config.selected);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
public getSelectionModel(): SelectionModel {
|
|
40
|
-
return this.selectionModel;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
public update(
|
|
44
|
-
oldProps: SelectionModelConfig | null,
|
|
45
|
-
newProps: SelectionModelConfig,
|
|
46
|
-
model: Gio.ListModel,
|
|
47
|
-
): SelectionModel {
|
|
48
|
-
if (oldProps && oldProps.selectionMode !== newProps.selectionMode) {
|
|
49
|
-
this.signalStore.set(this.owner, this.selectionModel, "selection-changed", null);
|
|
50
|
-
this.selectionModel = this.createSelectionModel(newProps.selectionMode, model);
|
|
51
|
-
this.selectionModel.setModel(model);
|
|
52
|
-
this.initSelectionHandler(newProps.onSelectionChanged);
|
|
53
|
-
this.setSelection(newProps.selected);
|
|
54
|
-
return this.selectionModel;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (this.selectionModel.getModel() !== model) {
|
|
58
|
-
this.selectionModel.setModel(model);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (!oldProps || oldProps.onSelectionChanged !== newProps.onSelectionChanged) {
|
|
62
|
-
this.initSelectionHandler(newProps.onSelectionChanged);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (!oldProps || oldProps.selected !== newProps.selected) {
|
|
66
|
-
this.setSelection(newProps.selected);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return this.selectionModel;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
private initSelectionHandler(onSelectionChanged?: ((ids: string[]) => void) | null): void {
|
|
73
|
-
if (!onSelectionChanged) {
|
|
74
|
-
this.signalStore.set(this.owner, this.selectionModel, "selection-changed", null);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const handler = () => {
|
|
79
|
-
onSelectionChanged(this.getSelection());
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
this.signalStore.set(this.owner, this.selectionModel, "selection-changed", handler);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private createSelectionModel(mode: Gtk.SelectionMode | null | undefined, model: Gio.ListModel): SelectionModel {
|
|
86
|
-
const selectionMode = mode ?? Gtk.SelectionMode.SINGLE;
|
|
87
|
-
|
|
88
|
-
if (selectionMode === Gtk.SelectionMode.NONE) {
|
|
89
|
-
return new Gtk.NoSelection(model);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (selectionMode === Gtk.SelectionMode.MULTIPLE) {
|
|
93
|
-
return new Gtk.MultiSelection(model);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const selectionModel = new Gtk.SingleSelection(model);
|
|
97
|
-
selectionModel.setAutoselect(selectionMode === Gtk.SelectionMode.BROWSE);
|
|
98
|
-
selectionModel.setCanUnselect(selectionMode !== Gtk.SelectionMode.BROWSE);
|
|
99
|
-
|
|
100
|
-
return selectionModel;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
public reapplySelection(ids?: string[] | null): void {
|
|
104
|
-
this.setSelection(ids);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private setSelection(ids?: string[] | null): void {
|
|
108
|
-
const nItems = this.getItemCount();
|
|
109
|
-
const selected = ids ? this.resolveSelectionIndices(ids) : new Gtk.Bitset();
|
|
110
|
-
const mask = Gtk.Bitset.newRange(0, nItems);
|
|
111
|
-
|
|
112
|
-
if (this.selectionModel instanceof Gtk.SingleSelection) {
|
|
113
|
-
const position = selected.getSize() > 0 ? selected.getNth(0) : Gtk.INVALID_LIST_POSITION;
|
|
114
|
-
this.selectionModel.setSelected(position);
|
|
115
|
-
} else {
|
|
116
|
-
this.selectionModel.setSelection(selected, mask);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { SectionedListStore } from "./sectioned-list-store.js";
|
|
2
|
-
|
|
3
|
-
export class SimpleListStore extends SectionedListStore {
|
|
4
|
-
private batchMode = false;
|
|
5
|
-
|
|
6
|
-
public override beginBatch(): void {
|
|
7
|
-
this.batchMode = true;
|
|
8
|
-
super.beginBatch();
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
public override flushBatch(): void {
|
|
12
|
-
this.batchMode = false;
|
|
13
|
-
super.flushBatch();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
protected override getInitialPendingBatch(): string[] | null {
|
|
17
|
-
return this.batchMode ? [] : null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
protected override getModelString(_itemId: string, item: unknown): string {
|
|
21
|
-
return item as string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public getHeaderValueByLabel(label: string): unknown {
|
|
25
|
-
for (const section of this.sections) {
|
|
26
|
-
if (section.model.getNItems() > 0) {
|
|
27
|
-
const firstLabel = section.model.getString(0);
|
|
28
|
-
if (firstLabel === label) {
|
|
29
|
-
return this.headerValues.get(section.id);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return undefined;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public addItem(id: string, label: string): void {
|
|
37
|
-
this.flushRemovals();
|
|
38
|
-
if (this.sectioned) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
this.idToIndex.set(id, this.ids.length);
|
|
43
|
-
this.ids.push(id);
|
|
44
|
-
|
|
45
|
-
if (this.pendingBatch) {
|
|
46
|
-
this.pendingBatch.push(label);
|
|
47
|
-
} else {
|
|
48
|
-
this.model.append(label);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
public appendItem(id: string, label: string): void {
|
|
53
|
-
this.flushRemovals();
|
|
54
|
-
const existingIndex = this.idToIndex.get(id);
|
|
55
|
-
|
|
56
|
-
if (existingIndex !== undefined) {
|
|
57
|
-
this.model.remove(existingIndex);
|
|
58
|
-
this.ids.splice(existingIndex, 1);
|
|
59
|
-
this.rebuildIndices(existingIndex);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
this.idToIndex.set(id, this.ids.length);
|
|
63
|
-
this.ids.push(id);
|
|
64
|
-
this.model.append(label);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public insertItemBefore(id: string, beforeId: string, label: string): void {
|
|
68
|
-
this.flushRemovals();
|
|
69
|
-
const beforeIndex = this.idToIndex.get(beforeId);
|
|
70
|
-
if (beforeIndex === undefined) {
|
|
71
|
-
this.addItem(id, label);
|
|
72
|
-
} else {
|
|
73
|
-
this.ids.splice(beforeIndex, 0, id);
|
|
74
|
-
this.rebuildIndices(beforeIndex);
|
|
75
|
-
this.model.splice(beforeIndex, 0, [label]);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public updateItem(id: string, item: unknown): void {
|
|
80
|
-
this.flushRemovals();
|
|
81
|
-
const label = item as string;
|
|
82
|
-
if (this.sectioned) {
|
|
83
|
-
const sectionId = this.itemToSection.get(id);
|
|
84
|
-
if (!sectionId) return;
|
|
85
|
-
const section = this.sectionById.get(sectionId);
|
|
86
|
-
if (!section) return;
|
|
87
|
-
const indexInSection = section.itemIds.indexOf(id);
|
|
88
|
-
if (indexInSection >= 0) {
|
|
89
|
-
section.model.splice(indexInSection, 1, [label]);
|
|
90
|
-
}
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
const index = this.idToIndex.get(id);
|
|
94
|
-
if (index === undefined) {
|
|
95
|
-
this.addItem(id, label);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
this.model.splice(index, 1, [label]);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
public getItem(id: string): string | null {
|
|
102
|
-
this.flushRemovals();
|
|
103
|
-
if (this.sectioned) {
|
|
104
|
-
const sectionId = this.itemToSection.get(id);
|
|
105
|
-
if (!sectionId) return null;
|
|
106
|
-
const section = this.sectionById.get(sectionId);
|
|
107
|
-
if (!section) return null;
|
|
108
|
-
const indexInSection = section.itemIds.indexOf(id);
|
|
109
|
-
if (indexInSection < 0) return null;
|
|
110
|
-
return section.model.getString(indexInSection);
|
|
111
|
-
}
|
|
112
|
-
const index = this.idToIndex.get(id);
|
|
113
|
-
if (index === undefined) return null;
|
|
114
|
-
return this.model.getString(index);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
import * as Gtk from "@gtkx/ffi/gtk";
|
|
2
|
-
|
|
3
|
-
type TreeItemUpdatedCallback = (id: string) => void;
|
|
4
|
-
|
|
5
|
-
export type TreeItemData<T = unknown> = {
|
|
6
|
-
value: T;
|
|
7
|
-
indentForDepth?: boolean;
|
|
8
|
-
indentForIcon?: boolean;
|
|
9
|
-
hideExpander?: boolean;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export class TreeStore {
|
|
13
|
-
private rootIds: string[] = [];
|
|
14
|
-
private rootIdToIndex = new Map<string, number>();
|
|
15
|
-
private children = new Map<string, string[]>();
|
|
16
|
-
private childIdToIndex = new Map<string, Map<string, number>>();
|
|
17
|
-
private rootModel = new Gtk.StringList();
|
|
18
|
-
private childModels = new Map<string, Gtk.StringList>();
|
|
19
|
-
private items = new Map<string, TreeItemData>();
|
|
20
|
-
private onItemUpdated: TreeItemUpdatedCallback | null = null;
|
|
21
|
-
private pendingBatch: string[] | null = null;
|
|
22
|
-
private pendingRemovals: Set<string> | null = null;
|
|
23
|
-
private flushScheduled = false;
|
|
24
|
-
|
|
25
|
-
public setOnItemUpdated(callback: TreeItemUpdatedCallback | null): void {
|
|
26
|
-
this.onItemUpdated = callback;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
public beginBatch(): void {
|
|
30
|
-
this.pendingBatch = [];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public flushBatch(): void {
|
|
34
|
-
const batch = this.pendingBatch;
|
|
35
|
-
this.pendingBatch = null;
|
|
36
|
-
if (batch && batch.length > 0) {
|
|
37
|
-
this.rootModel.splice(0, 0, batch);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
public updateItem(id: string, item: TreeItemData): void {
|
|
42
|
-
if (this.items.has(id)) {
|
|
43
|
-
this.items.set(id, item);
|
|
44
|
-
this.onItemUpdated?.(id);
|
|
45
|
-
} else {
|
|
46
|
-
this.addItem(id, item);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
public addItem(id: string, data: TreeItemData, parentId?: string): void {
|
|
51
|
-
if (parentId === undefined) this.flushRemovals();
|
|
52
|
-
this.items.set(id, data);
|
|
53
|
-
|
|
54
|
-
if (parentId === undefined) {
|
|
55
|
-
const existingIndex = this.rootIdToIndex.get(id);
|
|
56
|
-
if (existingIndex !== undefined) {
|
|
57
|
-
this.rootModel.remove(existingIndex);
|
|
58
|
-
this.rootIds.splice(existingIndex, 1);
|
|
59
|
-
this.rebuildRootIndices(existingIndex);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
this.rootIdToIndex.set(id, this.rootIds.length);
|
|
63
|
-
this.rootIds.push(id);
|
|
64
|
-
|
|
65
|
-
if (this.pendingBatch) {
|
|
66
|
-
this.pendingBatch.push(id);
|
|
67
|
-
} else {
|
|
68
|
-
this.rootModel.append(id);
|
|
69
|
-
}
|
|
70
|
-
} else {
|
|
71
|
-
let siblings = this.children.get(parentId);
|
|
72
|
-
let indexMap = this.childIdToIndex.get(parentId);
|
|
73
|
-
if (!siblings) {
|
|
74
|
-
siblings = [];
|
|
75
|
-
this.children.set(parentId, siblings);
|
|
76
|
-
}
|
|
77
|
-
if (!indexMap) {
|
|
78
|
-
indexMap = new Map();
|
|
79
|
-
this.childIdToIndex.set(parentId, indexMap);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const existingIndex = indexMap.get(id);
|
|
83
|
-
if (existingIndex !== undefined) {
|
|
84
|
-
const model = this.childModels.get(parentId);
|
|
85
|
-
if (model) {
|
|
86
|
-
model.remove(existingIndex);
|
|
87
|
-
}
|
|
88
|
-
siblings.splice(existingIndex, 1);
|
|
89
|
-
this.rebuildChildIndices(siblings, indexMap, existingIndex);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
indexMap.set(id, siblings.length);
|
|
93
|
-
siblings.push(id);
|
|
94
|
-
|
|
95
|
-
let model = this.childModels.get(parentId);
|
|
96
|
-
if (!model) {
|
|
97
|
-
model = new Gtk.StringList();
|
|
98
|
-
this.childModels.set(parentId, model);
|
|
99
|
-
}
|
|
100
|
-
model.append(id);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
public removeItem(id: string, parentId?: string): void {
|
|
105
|
-
this.items.delete(id);
|
|
106
|
-
this.children.delete(id);
|
|
107
|
-
this.childIdToIndex.delete(id);
|
|
108
|
-
this.childModels.delete(id);
|
|
109
|
-
|
|
110
|
-
if (parentId !== undefined) {
|
|
111
|
-
const siblings = this.children.get(parentId);
|
|
112
|
-
const indexMap = this.childIdToIndex.get(parentId);
|
|
113
|
-
if (siblings && indexMap) {
|
|
114
|
-
const index = indexMap.get(id);
|
|
115
|
-
if (index !== undefined) {
|
|
116
|
-
siblings.splice(index, 1);
|
|
117
|
-
indexMap.delete(id);
|
|
118
|
-
this.rebuildChildIndices(siblings, indexMap, index);
|
|
119
|
-
const model = this.childModels.get(parentId);
|
|
120
|
-
if (model) {
|
|
121
|
-
model.remove(index);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
if (siblings.length === 0) {
|
|
125
|
-
this.children.delete(parentId);
|
|
126
|
-
this.childIdToIndex.delete(parentId);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (!this.rootIdToIndex.has(id)) return;
|
|
133
|
-
|
|
134
|
-
if (!this.pendingRemovals) {
|
|
135
|
-
this.pendingRemovals = new Set();
|
|
136
|
-
if (!this.flushScheduled) {
|
|
137
|
-
this.flushScheduled = true;
|
|
138
|
-
queueMicrotask(() => this.flushRemovals());
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
this.pendingRemovals.add(id);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
public flushRemovals(): void {
|
|
145
|
-
this.flushScheduled = false;
|
|
146
|
-
const removals = this.pendingRemovals;
|
|
147
|
-
if (!removals || removals.size === 0) {
|
|
148
|
-
this.pendingRemovals = null;
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
this.pendingRemovals = null;
|
|
152
|
-
|
|
153
|
-
const indices: number[] = [];
|
|
154
|
-
for (const id of removals) {
|
|
155
|
-
const index = this.rootIdToIndex.get(id);
|
|
156
|
-
if (index !== undefined) {
|
|
157
|
-
indices.push(index);
|
|
158
|
-
this.rootIdToIndex.delete(id);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (indices.length === 0) return;
|
|
163
|
-
|
|
164
|
-
indices.sort((a, b) => a - b);
|
|
165
|
-
|
|
166
|
-
let i = indices.length - 1;
|
|
167
|
-
while (i >= 0) {
|
|
168
|
-
let rangeStart = indices[i] ?? 0;
|
|
169
|
-
const rangeEnd = rangeStart;
|
|
170
|
-
|
|
171
|
-
while (i > 0) {
|
|
172
|
-
const prev = indices[i - 1];
|
|
173
|
-
if (prev !== rangeStart - 1) break;
|
|
174
|
-
i--;
|
|
175
|
-
rangeStart = prev ?? 0;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const count = rangeEnd - rangeStart + 1;
|
|
179
|
-
this.rootModel.splice(rangeStart, count);
|
|
180
|
-
this.rootIds.splice(rangeStart, count);
|
|
181
|
-
|
|
182
|
-
i--;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
this.rebuildRootIndices(0);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
public insertItemBefore(id: string, beforeId: string, data: TreeItemData, parentId?: string): void {
|
|
189
|
-
if (parentId === undefined) this.flushRemovals();
|
|
190
|
-
this.items.set(id, data);
|
|
191
|
-
|
|
192
|
-
if (parentId === undefined) {
|
|
193
|
-
const existingIndex = this.rootIdToIndex.get(id);
|
|
194
|
-
if (existingIndex !== undefined) {
|
|
195
|
-
this.rootModel.remove(existingIndex);
|
|
196
|
-
this.rootIds.splice(existingIndex, 1);
|
|
197
|
-
this.rootIdToIndex.delete(id);
|
|
198
|
-
this.rebuildRootIndices(existingIndex);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const beforeIndex = this.rootIdToIndex.get(beforeId);
|
|
202
|
-
if (beforeIndex === undefined) {
|
|
203
|
-
this.rootIdToIndex.set(id, this.rootIds.length);
|
|
204
|
-
this.rootIds.push(id);
|
|
205
|
-
this.rootModel.append(id);
|
|
206
|
-
} else {
|
|
207
|
-
this.rootIds.splice(beforeIndex, 0, id);
|
|
208
|
-
this.rebuildRootIndices(beforeIndex);
|
|
209
|
-
this.rootModel.splice(beforeIndex, 0, [id]);
|
|
210
|
-
}
|
|
211
|
-
} else {
|
|
212
|
-
let siblings = this.children.get(parentId);
|
|
213
|
-
let indexMap = this.childIdToIndex.get(parentId);
|
|
214
|
-
if (!siblings) {
|
|
215
|
-
siblings = [];
|
|
216
|
-
this.children.set(parentId, siblings);
|
|
217
|
-
}
|
|
218
|
-
if (!indexMap) {
|
|
219
|
-
indexMap = new Map();
|
|
220
|
-
this.childIdToIndex.set(parentId, indexMap);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
let model = this.childModels.get(parentId);
|
|
224
|
-
if (!model) {
|
|
225
|
-
model = new Gtk.StringList();
|
|
226
|
-
this.childModels.set(parentId, model);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const existingIndex = indexMap.get(id);
|
|
230
|
-
if (existingIndex !== undefined) {
|
|
231
|
-
model.remove(existingIndex);
|
|
232
|
-
siblings.splice(existingIndex, 1);
|
|
233
|
-
indexMap.delete(id);
|
|
234
|
-
this.rebuildChildIndices(siblings, indexMap, existingIndex);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const beforeIndex = indexMap.get(beforeId);
|
|
238
|
-
if (beforeIndex === undefined) {
|
|
239
|
-
indexMap.set(id, siblings.length);
|
|
240
|
-
siblings.push(id);
|
|
241
|
-
model.append(id);
|
|
242
|
-
} else {
|
|
243
|
-
siblings.splice(beforeIndex, 0, id);
|
|
244
|
-
this.rebuildChildIndices(siblings, indexMap, beforeIndex);
|
|
245
|
-
model.splice(beforeIndex, 0, [id]);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
public getItem(id: string): TreeItemData | undefined {
|
|
251
|
-
return this.items.get(id);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
public getRootModel(): Gtk.StringList {
|
|
255
|
-
return this.rootModel;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
public getChildrenModel(parentId: string): Gtk.StringList | null {
|
|
259
|
-
const childIds = this.children.get(parentId);
|
|
260
|
-
if (!childIds || childIds.length === 0) {
|
|
261
|
-
return null;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
let model = this.childModels.get(parentId);
|
|
265
|
-
if (!model) {
|
|
266
|
-
model = new Gtk.StringList(childIds);
|
|
267
|
-
this.childModels.set(parentId, model);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return model;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
public hasChildren(parentId: string): boolean {
|
|
274
|
-
const childIds = this.children.get(parentId);
|
|
275
|
-
return childIds !== undefined && childIds.length > 0;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
private rebuildRootIndices(fromIndex: number): void {
|
|
279
|
-
for (let i = fromIndex; i < this.rootIds.length; i++) {
|
|
280
|
-
this.rootIdToIndex.set(this.rootIds[i] as string, i);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
private rebuildChildIndices(siblings: string[], indexMap: Map<string, number>, fromIndex: number): void {
|
|
285
|
-
for (let i = fromIndex; i < siblings.length; i++) {
|
|
286
|
-
indexMap.set(siblings[i] as string, i);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
package/src/nodes/list-item.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import type { ListItemProps } from "../jsx.js";
|
|
2
|
-
import type { Node } from "../node.js";
|
|
3
|
-
import { hasChanged } from "./internal/props.js";
|
|
4
|
-
import { type TreeItemData, TreeStore } from "./internal/tree-store.js";
|
|
5
|
-
import { VirtualNode } from "./virtual.js";
|
|
6
|
-
|
|
7
|
-
type ItemStore = { updateItem(id: string, value: unknown): void };
|
|
8
|
-
|
|
9
|
-
export class ListItemNode extends VirtualNode<ListItemProps, Node, ListItemNode> {
|
|
10
|
-
private store: ItemStore | null = null;
|
|
11
|
-
private parentItemId: string | null = null;
|
|
12
|
-
|
|
13
|
-
public static createItemData(props: ListItemProps): TreeItemData {
|
|
14
|
-
return {
|
|
15
|
-
value: props.value,
|
|
16
|
-
indentForDepth: props.indentForDepth,
|
|
17
|
-
indentForIcon: props.indentForIcon,
|
|
18
|
-
hideExpander: props.hideExpander,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public override isValidChild(child: Node): boolean {
|
|
23
|
-
return child instanceof ListItemNode;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public override appendChild(child: ListItemNode): void {
|
|
27
|
-
super.appendChild(child);
|
|
28
|
-
child.setParentItemId(this.props.id);
|
|
29
|
-
|
|
30
|
-
if (this.store instanceof TreeStore) {
|
|
31
|
-
this.store.addItem(child.props.id, ListItemNode.createItemData(child.props), this.props.id);
|
|
32
|
-
child.setStore(this.store);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public override insertBefore(child: ListItemNode, before: ListItemNode): void {
|
|
37
|
-
super.insertBefore(child, before);
|
|
38
|
-
child.setParentItemId(this.props.id);
|
|
39
|
-
|
|
40
|
-
if (this.store instanceof TreeStore) {
|
|
41
|
-
this.store.insertItemBefore(
|
|
42
|
-
child.props.id,
|
|
43
|
-
before.props.id,
|
|
44
|
-
ListItemNode.createItemData(child.props),
|
|
45
|
-
this.props.id,
|
|
46
|
-
);
|
|
47
|
-
child.setStore(this.store);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
public override removeChild(child: ListItemNode): void {
|
|
52
|
-
if (this.store instanceof TreeStore) {
|
|
53
|
-
this.store.removeItem(child.props.id, this.props.id);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
child.setStore(null);
|
|
57
|
-
child.setParentItemId(null);
|
|
58
|
-
super.removeChild(child);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
public override commitUpdate(oldProps: ListItemProps | null, newProps: ListItemProps): void {
|
|
62
|
-
super.commitUpdate(oldProps, newProps);
|
|
63
|
-
this.applyOwnProps(oldProps, newProps);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
private applyOwnProps(oldProps: ListItemProps | null, newProps: ListItemProps): void {
|
|
67
|
-
if (!this.store) return;
|
|
68
|
-
|
|
69
|
-
if (this.store instanceof TreeStore) {
|
|
70
|
-
const propsChanged =
|
|
71
|
-
hasChanged(oldProps, newProps, "id") ||
|
|
72
|
-
hasChanged(oldProps, newProps, "value") ||
|
|
73
|
-
hasChanged(oldProps, newProps, "indentForDepth") ||
|
|
74
|
-
hasChanged(oldProps, newProps, "indentForIcon") ||
|
|
75
|
-
hasChanged(oldProps, newProps, "hideExpander");
|
|
76
|
-
|
|
77
|
-
if (propsChanged) {
|
|
78
|
-
this.store.updateItem(newProps.id, ListItemNode.createItemData(newProps));
|
|
79
|
-
}
|
|
80
|
-
} else {
|
|
81
|
-
if (hasChanged(oldProps, newProps, "id") || hasChanged(oldProps, newProps, "value")) {
|
|
82
|
-
this.store.updateItem(newProps.id, newProps.value);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
public setStore(store: ItemStore | null): void {
|
|
88
|
-
this.store = store;
|
|
89
|
-
if (store === null || store instanceof TreeStore) {
|
|
90
|
-
for (const child of this.children) {
|
|
91
|
-
child.setStore(store);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
public getChildNodes(): readonly ListItemNode[] {
|
|
97
|
-
return this.children;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public setParentItemId(parentId: string | null): void {
|
|
101
|
-
this.parentItemId = parentId;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
public getParentItemId(): string | null {
|
|
105
|
-
return this.parentItemId;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { ListSectionProps } from "../jsx.js";
|
|
2
|
-
import type { Node } from "../node.js";
|
|
3
|
-
import { hasChanged } from "./internal/props.js";
|
|
4
|
-
import { ListItemNode } from "./list-item.js";
|
|
5
|
-
import { VirtualNode } from "./virtual.js";
|
|
6
|
-
|
|
7
|
-
type SectionStore = {
|
|
8
|
-
addItemToSection(sectionId: string, itemId: string, item: unknown): void;
|
|
9
|
-
addItemsToSection(sectionId: string, items: { itemId: string; item: unknown }[]): void;
|
|
10
|
-
removeItemFromSection(itemId: string): void;
|
|
11
|
-
updateHeaderValue(sectionId: string, value: unknown): void;
|
|
12
|
-
insertItemToSectionBefore(sectionId: string, itemId: string, beforeId: string, item: unknown): void;
|
|
13
|
-
updateItem(id: string, item: unknown): void;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export class ListSectionNode extends VirtualNode<ListSectionProps, Node, ListItemNode> {
|
|
17
|
-
private store: SectionStore | null = null;
|
|
18
|
-
|
|
19
|
-
public override isValidChild(child: Node): boolean {
|
|
20
|
-
return child instanceof ListItemNode;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
public override appendChild(child: ListItemNode): void {
|
|
24
|
-
super.appendChild(child);
|
|
25
|
-
if (this.store) {
|
|
26
|
-
this.store.addItemToSection(this.props.id, child.props.id, child.props.value);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public override insertBefore(child: ListItemNode, before: ListItemNode): void {
|
|
31
|
-
super.insertBefore(child, before);
|
|
32
|
-
if (this.store) {
|
|
33
|
-
this.store.insertItemToSectionBefore(this.props.id, child.props.id, before.props.id, child.props.value);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
public override removeChild(child: ListItemNode): void {
|
|
38
|
-
if (this.store) {
|
|
39
|
-
this.store.removeItemFromSection(child.props.id);
|
|
40
|
-
}
|
|
41
|
-
super.removeChild(child);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
public override commitUpdate(oldProps: ListSectionProps | null, newProps: ListSectionProps): void {
|
|
45
|
-
super.commitUpdate(oldProps, newProps);
|
|
46
|
-
if (this.store && hasChanged(oldProps, newProps, "value")) {
|
|
47
|
-
this.store.updateHeaderValue(newProps.id, newProps.value);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
public setStore(store: SectionStore | null): void {
|
|
52
|
-
this.store = store;
|
|
53
|
-
if (store && this.children.length > 0) {
|
|
54
|
-
store.addItemsToSection(
|
|
55
|
-
this.props.id,
|
|
56
|
-
this.children.map((child) => ({ itemId: child.props.id, item: child.props.value })),
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
public getChildNodes(): readonly ListItemNode[] {
|
|
62
|
-
return this.children;
|
|
63
|
-
}
|
|
64
|
-
}
|