@gtkx/components 2.0.0-beta.1 → 2.0.0-beta.10
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/README.md +43 -40
- package/dist/column-view.d.ts.map +1 -1
- package/dist/column-view.js +1 -0
- package/dist/column-view.js.map +1 -1
- package/dist/internal/cells.d.ts +11 -1
- package/dist/internal/cells.d.ts.map +1 -1
- package/dist/internal/cells.js +124 -26
- package/dist/internal/cells.js.map +1 -1
- package/dist/internal/collection-model.d.ts +5 -5
- package/dist/internal/collection-model.d.ts.map +1 -1
- package/dist/internal/collection-model.js +35 -35
- package/dist/internal/collection-model.js.map +1 -1
- package/dist/list-view.d.ts.map +1 -1
- package/dist/list-view.js +1 -0
- package/dist/list-view.js.map +1 -1
- package/dist/types.d.ts +11 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -9
- package/src/column-view.tsx +1 -0
- package/src/internal/cells.tsx +200 -40
- package/src/internal/collection-model.ts +41 -41
- package/src/list-view.tsx +1 -0
- package/src/types.ts +13 -1
|
@@ -11,7 +11,7 @@ import { adoptIndex, createTreeExpansion, pruneSlots } from "./tree-expansion.js
|
|
|
11
11
|
type LevelStore = Gio.ListModel & LazyLevelStore;
|
|
12
12
|
|
|
13
13
|
type SlotRef = {
|
|
14
|
-
store:
|
|
14
|
+
store: LazyLevelStore;
|
|
15
15
|
slot: number;
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -93,22 +93,13 @@ function slotRefFor(value: GObject.Object | null): SlotRef | null {
|
|
|
93
93
|
return ref === undefined || ref.slot === -1 ? null : ref;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
function slotPathAt(store:
|
|
96
|
+
function slotPathAt(store: LazyLevelStore, slot: number): string {
|
|
97
97
|
return store.level.path + encodePart(String(slot));
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
function growStore(store: LevelStore): void {
|
|
101
|
-
for (let slot = store.refs.length; slot < store.level.items.length; slot++) {
|
|
102
|
-
store.refs.push({ store, slot });
|
|
103
|
-
store.objects.push(null);
|
|
104
|
-
store.childStores.push(null);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
100
|
function newLevelStore(level: Level): LevelStore {
|
|
109
101
|
const store = new (registeredStoreClass())() as LevelStore;
|
|
110
102
|
store.level = level;
|
|
111
|
-
growStore(store);
|
|
112
103
|
|
|
113
104
|
return store;
|
|
114
105
|
}
|
|
@@ -116,6 +107,10 @@ function newLevelStore(level: Level): LevelStore {
|
|
|
116
107
|
function collectFlips(previous: Level, next: Level, overlap: number): Set<number> {
|
|
117
108
|
const flipped: Set<number> = new Set();
|
|
118
109
|
|
|
110
|
+
if (previous.expandableFlags.length === 0 && next.expandableFlags.length === 0) {
|
|
111
|
+
return flipped;
|
|
112
|
+
}
|
|
113
|
+
|
|
119
114
|
for (let slot = 0; slot < overlap; slot++) {
|
|
120
115
|
if ((previous.expandableFlags[slot] ?? false) !== (next.expandableFlags[slot] ?? false)) {
|
|
121
116
|
flipped.add(slot);
|
|
@@ -133,30 +128,30 @@ function pruneFlips(context: SyncContext, store: LevelStore, flipped: Set<number
|
|
|
133
128
|
pruneSlots(context.expansion, store.level.path, (slot) => flipped.has(slot));
|
|
134
129
|
|
|
135
130
|
for (const slot of flipped) {
|
|
136
|
-
store.childStores
|
|
131
|
+
store.childStores.delete(slot);
|
|
137
132
|
}
|
|
138
133
|
}
|
|
139
134
|
|
|
140
135
|
function detachRefs(store: LevelStore, nextLength: number): void {
|
|
141
|
-
for (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if (ref !== undefined) {
|
|
145
|
-
ref.slot = -1;
|
|
136
|
+
for (const [slot, ref] of store.refs) {
|
|
137
|
+
if (slot < nextLength) {
|
|
138
|
+
continue;
|
|
146
139
|
}
|
|
140
|
+
|
|
141
|
+
ref.slot = -1;
|
|
142
|
+
store.refs.delete(slot);
|
|
143
|
+
store.objects.delete(slot);
|
|
144
|
+
store.childStores.delete(slot);
|
|
147
145
|
}
|
|
148
146
|
}
|
|
149
147
|
|
|
150
|
-
function shrinkStore(context: SyncContext, store: LevelStore, nextLength: number): void {
|
|
151
|
-
if (
|
|
148
|
+
function shrinkStore(context: SyncContext, store: LevelStore, previousLength: number, nextLength: number): void {
|
|
149
|
+
if (previousLength <= nextLength) {
|
|
152
150
|
return;
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
detachRefs(store, nextLength);
|
|
156
154
|
pruneSlots(context.expansion, store.level.path, (slot) => slot >= nextLength);
|
|
157
|
-
store.refs.length = nextLength;
|
|
158
|
-
store.objects.length = nextLength;
|
|
159
|
-
store.childStores.length = nextLength;
|
|
160
155
|
}
|
|
161
156
|
|
|
162
157
|
function emitTailSplice(store: LevelStore, previousLength: number, nextLength: number): void {
|
|
@@ -205,7 +200,7 @@ function childSync(
|
|
|
205
200
|
slot: number,
|
|
206
201
|
flipped: Set<number>,
|
|
207
202
|
): LevelSync | undefined {
|
|
208
|
-
const child = store.childStores
|
|
203
|
+
const child = store.childStores.get(slot) ?? null;
|
|
209
204
|
|
|
210
205
|
if (child === null || flipped.has(slot)) {
|
|
211
206
|
return undefined;
|
|
@@ -218,8 +213,13 @@ function childSync(
|
|
|
218
213
|
|
|
219
214
|
function childSyncs(context: SyncContext, store: LevelStore, overlap: number, flipped: Set<number>): LevelSync[] {
|
|
220
215
|
const syncs: LevelSync[] = [];
|
|
216
|
+
const slots = store.childStores.keys().toArray().toSorted((left, right) => left - right);
|
|
217
|
+
|
|
218
|
+
for (const slot of slots) {
|
|
219
|
+
if (slot >= overlap) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
221
222
|
|
|
222
|
-
for (let slot = 0; slot < overlap; slot++) {
|
|
223
223
|
const sync = childSync(context, store, slot, flipped);
|
|
224
224
|
|
|
225
225
|
if (sync !== undefined) {
|
|
@@ -232,13 +232,13 @@ function childSyncs(context: SyncContext, store: LevelStore, overlap: number, fl
|
|
|
232
232
|
|
|
233
233
|
function syncEntry(context: SyncContext, entry: LevelSync): LevelSync[] {
|
|
234
234
|
const { store, level } = entry;
|
|
235
|
-
const
|
|
235
|
+
const previous = store.level;
|
|
236
|
+
const previousLength = previous.items.length;
|
|
236
237
|
const overlap = Math.min(previousLength, level.items.length);
|
|
237
|
-
const flipped = collectFlips(
|
|
238
|
+
const flipped = collectFlips(previous, level, overlap);
|
|
238
239
|
store.level = level;
|
|
239
240
|
pruneFlips(context, store, flipped);
|
|
240
|
-
shrinkStore(context, store, level.items.length);
|
|
241
|
-
growStore(store);
|
|
241
|
+
shrinkStore(context, store, previousLength, level.items.length);
|
|
242
242
|
emitTailSplice(store, previousLength, level.items.length);
|
|
243
243
|
emitFlips(store, flipped);
|
|
244
244
|
|
|
@@ -257,8 +257,8 @@ function syncLevel(context: SyncContext, store: LevelStore, level: Level): void
|
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
function ensureChildStore(index: CollectionIndex, store:
|
|
261
|
-
const existing = store.childStores
|
|
260
|
+
function ensureChildStore(index: CollectionIndex, store: LazyLevelStore, slot: number): LevelStore | null {
|
|
261
|
+
const existing = store.childStores.get(slot) ?? null;
|
|
262
262
|
|
|
263
263
|
if (existing !== null || !(store.level.expandableFlags[slot] ?? false)) {
|
|
264
264
|
return existing;
|
|
@@ -271,7 +271,7 @@ function ensureChildStore(index: CollectionIndex, store: LevelStore, slot: numbe
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
const created = newLevelStore(level);
|
|
274
|
-
store.childStores
|
|
274
|
+
store.childStores.set(slot, created);
|
|
275
275
|
|
|
276
276
|
return created;
|
|
277
277
|
}
|
|
@@ -418,13 +418,15 @@ function createCollectionModel(): CollectionModel {
|
|
|
418
418
|
class LazyLevelStore extends GObject.Object implements Gio.ListModelImpl {
|
|
419
419
|
declare itemsChanged: Gio.ListModel["itemsChanged"];
|
|
420
420
|
level: Level = { path: "", items: [], expandableFlags: [] };
|
|
421
|
-
refs: SlotRef
|
|
422
|
-
objects:
|
|
423
|
-
childStores:
|
|
421
|
+
refs: Map<number, SlotRef> = new Map();
|
|
422
|
+
objects: Map<number, Gtk.StringObject> = new Map();
|
|
423
|
+
childStores: Map<number, LevelStore> = new Map();
|
|
424
424
|
|
|
425
|
-
private createItem(position: number
|
|
425
|
+
private createItem(position: number): Gtk.StringObject {
|
|
426
|
+
const ref = { store: this, slot: position };
|
|
426
427
|
const created = Gtk.StringObject.new("");
|
|
427
|
-
this.
|
|
428
|
+
this.refs.set(position, ref);
|
|
429
|
+
this.objects.set(position, created);
|
|
428
430
|
SLOTS.set(created, ref);
|
|
429
431
|
|
|
430
432
|
return created;
|
|
@@ -435,17 +437,15 @@ class LazyLevelStore extends GObject.Object implements Gio.ListModelImpl {
|
|
|
435
437
|
}
|
|
436
438
|
|
|
437
439
|
vfuncGetNItems(): number {
|
|
438
|
-
return this.
|
|
440
|
+
return this.level.items.length;
|
|
439
441
|
}
|
|
440
442
|
|
|
441
443
|
vfuncGetItem(position: number): GObject.Object | null {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
if (ref === undefined) {
|
|
444
|
+
if (position < 0 || position >= this.level.items.length) {
|
|
445
445
|
return null;
|
|
446
446
|
}
|
|
447
447
|
|
|
448
|
-
return this.objects
|
|
448
|
+
return this.objects.get(position) ?? this.createItem(position);
|
|
449
449
|
}
|
|
450
450
|
}
|
|
451
451
|
|
package/src/list-view.tsx
CHANGED
package/src/types.ts
CHANGED
|
@@ -90,6 +90,16 @@ type ItemSizeProps = {
|
|
|
90
90
|
estimatedItemWidth?: number | undefined;
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
+
/** The flat-collection hint shared by {@link ListView} and {@link ColumnView}. */
|
|
94
|
+
type FlatnessProps = {
|
|
95
|
+
/**
|
|
96
|
+
* Declares every item a leaf, so the view skips tree discovery when synchronising a large collection
|
|
97
|
+
* instead of scanning each item for `children`. Must not be set when any item has children: those
|
|
98
|
+
* items would render as plain rows that never expand.
|
|
99
|
+
*/
|
|
100
|
+
isFlat?: boolean | undefined;
|
|
101
|
+
};
|
|
102
|
+
|
|
93
103
|
/** Controlled selection shared by the multi-item collection views. */
|
|
94
104
|
type SelectionProps = {
|
|
95
105
|
/**
|
|
@@ -172,6 +182,7 @@ type ColumnViewOwnProps<T, S> = SelectionProps &
|
|
|
172
182
|
ExpansionProps &
|
|
173
183
|
SortProps &
|
|
174
184
|
SourceProps<T, S> &
|
|
185
|
+
FlatnessProps &
|
|
175
186
|
Omit<ItemSizeProps, "estimatedItemWidth"> & {
|
|
176
187
|
/** Columns to render, in order; each carries its own cell renderer. */
|
|
177
188
|
columns: ColumnViewColumn<T>[];
|
|
@@ -242,7 +253,8 @@ type GridViewProps<T = unknown> = Omit<GtkGridViewProps, "model" | "factory" | k
|
|
|
242
253
|
type ListViewOwnProps<T, S> = ItemSizeProps &
|
|
243
254
|
SelectionProps &
|
|
244
255
|
ExpansionProps &
|
|
245
|
-
SourceProps<T, S> &
|
|
256
|
+
SourceProps<T, S> &
|
|
257
|
+
FlatnessProps & {
|
|
246
258
|
/** Renders the contents of one row. */
|
|
247
259
|
renderItem: ListItemRenderer<T>;
|
|
248
260
|
/** Renders the header shown above each section. */
|