@gtkx/components 0.21.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/collection-view.d.ts +30 -0
- package/dist/collection-view.d.ts.map +1 -0
- package/dist/collection-view.js +52 -0
- package/dist/collection-view.js.map +1 -0
- package/dist/column-view-column.d.ts +17 -0
- package/dist/column-view-column.d.ts.map +1 -0
- package/dist/column-view-column.js +51 -0
- package/dist/column-view-column.js.map +1 -0
- package/dist/column-view.d.ts +18 -0
- package/dist/column-view.d.ts.map +1 -0
- package/dist/column-view.js +108 -0
- package/dist/column-view.js.map +1 -0
- package/dist/constraint-layout-apply.d.ts +6 -0
- package/dist/constraint-layout-apply.d.ts.map +1 -0
- package/dist/constraint-layout-apply.js +107 -0
- package/dist/constraint-layout-apply.js.map +1 -0
- package/dist/constraint-layout.d.ts +13 -0
- package/dist/constraint-layout.d.ts.map +1 -0
- package/dist/constraint-layout.js +85 -0
- package/dist/constraint-layout.js.map +1 -0
- package/dist/contexts/column-view-context.d.ts +17 -0
- package/dist/contexts/column-view-context.d.ts.map +1 -0
- package/dist/contexts/column-view-context.js +10 -0
- package/dist/contexts/column-view-context.js.map +1 -0
- package/dist/drop-down.d.ts +41 -0
- package/dist/drop-down.d.ts.map +1 -0
- package/dist/drop-down.js +129 -0
- package/dist/drop-down.js.map +1 -0
- package/dist/grid-view.d.ts +16 -0
- package/dist/grid-view.d.ts.map +1 -0
- package/dist/grid-view.js +22 -0
- package/dist/grid-view.js.map +1 -0
- package/dist/hooks/use-drop-down-selection.d.ts +15 -0
- package/dist/hooks/use-drop-down-selection.d.ts.map +1 -0
- package/dist/hooks/use-drop-down-selection.js +35 -0
- package/dist/hooks/use-drop-down-selection.js.map +1 -0
- package/dist/hooks/use-header-menu.d.ts +4 -0
- package/dist/hooks/use-header-menu.d.ts.map +1 -0
- package/dist/hooks/use-header-menu.js +32 -0
- package/dist/hooks/use-header-menu.js.map +1 -0
- package/dist/hooks/use-list-model.d.ts +20 -0
- package/dist/hooks/use-list-model.d.ts.map +1 -0
- package/dist/hooks/use-list-model.js +70 -0
- package/dist/hooks/use-list-model.js.map +1 -0
- package/dist/hooks/use-model-installation.d.ts +9 -0
- package/dist/hooks/use-model-installation.d.ts.map +1 -0
- package/dist/hooks/use-model-installation.js +20 -0
- package/dist/hooks/use-model-installation.js.map +1 -0
- package/dist/hooks/use-realized-slots.d.ts +20 -0
- package/dist/hooks/use-realized-slots.d.ts.map +1 -0
- package/dist/hooks/use-realized-slots.js +66 -0
- package/dist/hooks/use-realized-slots.js.map +1 -0
- package/dist/hooks/use-selection-model.d.ts +12 -0
- package/dist/hooks/use-selection-model.d.ts.map +1 -0
- package/dist/hooks/use-selection-model.js +111 -0
- package/dist/hooks/use-selection-model.js.map +1 -0
- package/dist/hooks/use-sort-handler.d.ts +12 -0
- package/dist/hooks/use-sort-handler.d.ts.map +1 -0
- package/dist/hooks/use-sort-handler.js +87 -0
- package/dist/hooks/use-sort-handler.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/list-portal-host.d.ts +11 -0
- package/dist/list-portal-host.d.ts.map +1 -0
- package/dist/list-portal-host.js +8 -0
- package/dist/list-portal-host.js.map +1 -0
- package/dist/list-slot.d.ts +14 -0
- package/dist/list-slot.d.ts.map +1 -0
- package/dist/list-slot.js +29 -0
- package/dist/list-slot.js.map +1 -0
- package/dist/list-view.d.ts +16 -0
- package/dist/list-view.d.ts.map +1 -0
- package/dist/list-view.js +31 -0
- package/dist/list-view.js.map +1 -0
- package/dist/menu-items.d.ts +5 -0
- package/dist/menu-items.d.ts.map +1 -0
- package/dist/menu-items.js +48 -0
- package/dist/menu-items.js.map +1 -0
- package/dist/menu.d.ts +18 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +26 -0
- package/dist/menu.js.map +1 -0
- package/dist/types.d.ts +198 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/item-resolver.d.ts +28 -0
- package/dist/utils/item-resolver.d.ts.map +1 -0
- package/dist/utils/item-resolver.js +111 -0
- package/dist/utils/item-resolver.js.map +1 -0
- package/dist/utils/list-item-flatten.d.ts +32 -0
- package/dist/utils/list-item-flatten.d.ts.map +1 -0
- package/dist/utils/list-item-flatten.js +88 -0
- package/dist/utils/list-item-flatten.js.map +1 -0
- package/dist/utils/position-only-model.d.ts +10 -0
- package/dist/utils/position-only-model.d.ts.map +1 -0
- package/dist/utils/position-only-model.js +83 -0
- package/dist/utils/position-only-model.js.map +1 -0
- package/dist/utils/realized-slot-store.d.ts +30 -0
- package/dist/utils/realized-slot-store.d.ts.map +1 -0
- package/dist/utils/realized-slot-store.js +103 -0
- package/dist/utils/realized-slot-store.js.map +1 -0
- package/package.json +55 -0
- package/src/collection-view.tsx +125 -0
- package/src/column-view-column.tsx +73 -0
- package/src/column-view.tsx +206 -0
- package/src/constraint-layout-apply.ts +121 -0
- package/src/constraint-layout.tsx +130 -0
- package/src/contexts/column-view-context.ts +28 -0
- package/src/drop-down.tsx +259 -0
- package/src/grid-view.tsx +73 -0
- package/src/hooks/use-drop-down-selection.ts +53 -0
- package/src/hooks/use-header-menu.ts +33 -0
- package/src/hooks/use-list-model.ts +145 -0
- package/src/hooks/use-model-installation.ts +25 -0
- package/src/hooks/use-realized-slots.ts +93 -0
- package/src/hooks/use-selection-model.ts +121 -0
- package/src/hooks/use-sort-handler.ts +102 -0
- package/src/index.ts +31 -0
- package/src/list-portal-host.tsx +27 -0
- package/src/list-slot.tsx +56 -0
- package/src/list-view.tsx +85 -0
- package/src/menu-items.ts +48 -0
- package/src/menu.tsx +34 -0
- package/src/types.ts +227 -0
- package/src/utils/item-resolver.ts +143 -0
- package/src/utils/list-item-flatten.ts +113 -0
- package/src/utils/position-only-model.ts +115 -0
- package/src/utils/realized-slot-store.ts +126 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as Gio from "@gtkx/gi/gio";
|
|
2
|
+
import type * as GObject from "@gtkx/gi/gobject";
|
|
3
|
+
import * as Gtk from "@gtkx/gi/gtk";
|
|
4
|
+
import type { ListItem } from "../types.js";
|
|
5
|
+
import type { RowValue } from "./item-resolver.js";
|
|
6
|
+
import { treeItemMetadata } from "./list-item-flatten.js";
|
|
7
|
+
|
|
8
|
+
const emptyStrings = (count: number): string[] => new Array<string>(Math.max(0, count)).fill("");
|
|
9
|
+
|
|
10
|
+
export const retagRows = <T, S>(
|
|
11
|
+
items: ListItem<T, S>[],
|
|
12
|
+
rowValues: WeakMap<GObject.Object, RowValue<T, S>>,
|
|
13
|
+
placeholdersById: Map<string, GObject.Object>,
|
|
14
|
+
): void => {
|
|
15
|
+
const walk = (list: ListItem<T, S>[]): void => {
|
|
16
|
+
for (const item of list) {
|
|
17
|
+
const placeholder = placeholdersById.get(item.id);
|
|
18
|
+
if (placeholder !== undefined) {
|
|
19
|
+
rowValues.set(placeholder, {
|
|
20
|
+
id: item.id,
|
|
21
|
+
value: item.value,
|
|
22
|
+
isHeader: item.section === true,
|
|
23
|
+
metadata: treeItemMetadata(item),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (item.children !== undefined && item.children.length > 0) walk(item.children);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
walk(items);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const createFlatModel = (count: number): Gtk.StringList => Gtk.StringList.new(emptyStrings(count));
|
|
33
|
+
|
|
34
|
+
export const resizeFlatModel = (model: Gtk.StringList, count: number): void => {
|
|
35
|
+
const target = Math.max(0, count);
|
|
36
|
+
const current = model.getNItems();
|
|
37
|
+
if (current === target) return;
|
|
38
|
+
if (target > current) {
|
|
39
|
+
model.splice(current, 0, emptyStrings(target - current));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
model.splice(target, current - target, null);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const createTaggedRow = <T, S>(
|
|
46
|
+
row: RowValue<T, S>,
|
|
47
|
+
rowValues: WeakMap<GObject.Object, RowValue<T, S>>,
|
|
48
|
+
placeholdersById?: Map<string, GObject.Object>,
|
|
49
|
+
): GObject.Object => {
|
|
50
|
+
const placeholder = Gtk.StringObject.new("");
|
|
51
|
+
rowValues.set(placeholder, row);
|
|
52
|
+
if (placeholdersById !== undefined) placeholdersById.set(row.id, placeholder);
|
|
53
|
+
return placeholder;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const childModelOf = <T, S>(
|
|
57
|
+
children: ListItem<T, S>[],
|
|
58
|
+
rowValues: WeakMap<GObject.Object, RowValue<T, S>>,
|
|
59
|
+
placeholdersById: Map<string, GObject.Object>,
|
|
60
|
+
): Gio.ListStore => {
|
|
61
|
+
const store = Gio.ListStore.new(Gtk.StringObject.prototype.__gtype__);
|
|
62
|
+
for (const child of children) {
|
|
63
|
+
store.append(
|
|
64
|
+
createTaggedRow(
|
|
65
|
+
{ id: child.id, value: child.value, isHeader: false, metadata: treeItemMetadata(child) },
|
|
66
|
+
rowValues,
|
|
67
|
+
placeholdersById,
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return store;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const createTreeModel = <T, S>(
|
|
75
|
+
items: ListItem<T, S>[],
|
|
76
|
+
autoexpand: boolean,
|
|
77
|
+
rowValues: WeakMap<GObject.Object, RowValue<T, S>>,
|
|
78
|
+
placeholdersById: Map<string, GObject.Object>,
|
|
79
|
+
): Gtk.TreeListModel => {
|
|
80
|
+
const childrenByRow = new WeakMap<GObject.Object, ListItem<T, S>[]>();
|
|
81
|
+
const root = Gio.ListStore.new(Gtk.StringObject.prototype.__gtype__);
|
|
82
|
+
for (const item of items) {
|
|
83
|
+
const placeholder = createTaggedRow(
|
|
84
|
+
{ id: item.id, value: item.value, isHeader: item.section === true, metadata: treeItemMetadata(item) },
|
|
85
|
+
rowValues,
|
|
86
|
+
placeholdersById,
|
|
87
|
+
);
|
|
88
|
+
if (item.children !== undefined && item.children.length > 0) {
|
|
89
|
+
childrenByRow.set(placeholder, item.children);
|
|
90
|
+
}
|
|
91
|
+
root.append(placeholder);
|
|
92
|
+
}
|
|
93
|
+
const createFunc = (rowItem: GObject.Object): Gio.ListModel | null => {
|
|
94
|
+
const children = childrenByRow.get(rowItem);
|
|
95
|
+
if (children === undefined) return null;
|
|
96
|
+
const store = childModelOf(children, rowValues, placeholdersById);
|
|
97
|
+
for (let index = 0; index < children.length; index++) {
|
|
98
|
+
const child = children[index];
|
|
99
|
+
if (child !== undefined && child.children !== undefined && child.children.length > 0) {
|
|
100
|
+
const placeholder = store.getItem(index);
|
|
101
|
+
if (placeholder !== null) childrenByRow.set(placeholder, child.children);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return store;
|
|
105
|
+
};
|
|
106
|
+
return Gtk.TreeListModel.new(root, false, autoexpand, createFunc);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const createSectionModel = <T, S>(items: ListItem<T, S>[]): Gtk.FlattenListModel => {
|
|
110
|
+
const sections = Gio.ListStore.new(Gtk.StringList.prototype.__gtype__);
|
|
111
|
+
for (const section of items) {
|
|
112
|
+
sections.append(Gtk.StringList.new(emptyStrings(section.children?.length ?? 0)));
|
|
113
|
+
}
|
|
114
|
+
return Gtk.FlattenListModel.new(sections);
|
|
115
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type * as GObject from "@gtkx/gi/gobject";
|
|
2
|
+
import type * as Gtk from "@gtkx/gi/gtk";
|
|
3
|
+
|
|
4
|
+
export interface SlotEntry {
|
|
5
|
+
container: GObject.Object;
|
|
6
|
+
position: number;
|
|
7
|
+
treeRow: Gtk.TreeListRow | null;
|
|
8
|
+
item: GObject.Object | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let nextKey = 0;
|
|
12
|
+
|
|
13
|
+
export class RealizedSlotStore {
|
|
14
|
+
private entries = new Map<GObject.Object, SlotEntry>();
|
|
15
|
+
|
|
16
|
+
private published = new Map<GObject.Object, SlotEntry>();
|
|
17
|
+
|
|
18
|
+
private setListeners = new Set<() => void>();
|
|
19
|
+
|
|
20
|
+
private positionListeners = new Map<GObject.Object, Set<() => void>>();
|
|
21
|
+
|
|
22
|
+
private positionFlushers = new Map<GObject.Object, () => void>();
|
|
23
|
+
|
|
24
|
+
private keys = new WeakMap<GObject.Object, string>();
|
|
25
|
+
|
|
26
|
+
private snapshot: GObject.Object[] = [];
|
|
27
|
+
|
|
28
|
+
subscribeSet = (onChange: () => void): (() => void) => {
|
|
29
|
+
this.setListeners.add(onChange);
|
|
30
|
+
return () => {
|
|
31
|
+
this.setListeners.delete(onChange);
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
getSlotsSnapshot = (): GObject.Object[] => this.snapshot;
|
|
36
|
+
|
|
37
|
+
subscribePosition = (container: GObject.Object, onChange: () => void): (() => void) => {
|
|
38
|
+
let listeners = this.positionListeners.get(container);
|
|
39
|
+
if (listeners === undefined) {
|
|
40
|
+
listeners = new Set();
|
|
41
|
+
this.positionListeners.set(container, listeners);
|
|
42
|
+
}
|
|
43
|
+
listeners.add(onChange);
|
|
44
|
+
return () => {
|
|
45
|
+
const current = this.positionListeners.get(container);
|
|
46
|
+
if (current === undefined) return;
|
|
47
|
+
current.delete(onChange);
|
|
48
|
+
if (current.size === 0) this.positionListeners.delete(container);
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
getPosition = (container: GObject.Object): SlotEntry => {
|
|
53
|
+
let entry = this.published.get(container);
|
|
54
|
+
if (entry === undefined) {
|
|
55
|
+
entry = { container, position: -1, treeRow: null, item: null };
|
|
56
|
+
this.published.set(container, entry);
|
|
57
|
+
}
|
|
58
|
+
return entry;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
keyFor = (container: GObject.Object): string => {
|
|
62
|
+
const existing = this.keys.get(container);
|
|
63
|
+
if (existing !== undefined) return existing;
|
|
64
|
+
const key = `slot-${nextKey++}`;
|
|
65
|
+
this.keys.set(container, key);
|
|
66
|
+
return key;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
addContainer = (container: GObject.Object): void => {
|
|
70
|
+
if (this.entries.has(container)) return;
|
|
71
|
+
this.entries.set(container, { container, position: -1, treeRow: null, item: null });
|
|
72
|
+
this.notifySet();
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
bind = (
|
|
76
|
+
container: GObject.Object,
|
|
77
|
+
position: number,
|
|
78
|
+
treeRow: Gtk.TreeListRow | null,
|
|
79
|
+
item: GObject.Object | null,
|
|
80
|
+
): void => {
|
|
81
|
+
if (!this.entries.has(container)) {
|
|
82
|
+
this.entries.set(container, { container, position, treeRow, item });
|
|
83
|
+
this.notifySet();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.entries.set(container, { container, position, treeRow, item });
|
|
87
|
+
this.notifyPosition(container);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
unbind = (container: GObject.Object): void => {
|
|
91
|
+
if (!this.entries.has(container)) return;
|
|
92
|
+
this.entries.set(container, { container, position: -1, treeRow: null, item: null });
|
|
93
|
+
this.notifyPosition(container);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
removeContainer = (container: GObject.Object): void => {
|
|
97
|
+
if (!this.entries.delete(container)) return;
|
|
98
|
+
this.published.delete(container);
|
|
99
|
+
this.positionFlushers.delete(container);
|
|
100
|
+
this.notifySet();
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
private flushSet = (): void => {
|
|
104
|
+
this.snapshot = [...this.entries.keys()];
|
|
105
|
+
for (const listener of [...this.setListeners]) listener();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
private notifySet(): void {
|
|
109
|
+
this.flushSet();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private notifyPosition(container: GObject.Object): void {
|
|
113
|
+
let flush = this.positionFlushers.get(container);
|
|
114
|
+
if (flush === undefined) {
|
|
115
|
+
flush = (): void => {
|
|
116
|
+
const live = this.entries.get(container);
|
|
117
|
+
if (live !== undefined) this.published.set(container, live);
|
|
118
|
+
const listeners = this.positionListeners.get(container);
|
|
119
|
+
if (listeners === undefined) return;
|
|
120
|
+
for (const listener of [...listeners]) listener();
|
|
121
|
+
};
|
|
122
|
+
this.positionFlushers.set(container, flush);
|
|
123
|
+
}
|
|
124
|
+
flush();
|
|
125
|
+
}
|
|
126
|
+
}
|