@gtkx/components 0.21.0 → 1.0.0-rc.1
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/LICENSE +373 -0
- package/README.md +173 -0
- package/dist/cell.d.ts +30 -0
- package/dist/cell.d.ts.map +1 -0
- package/dist/cell.js +45 -0
- package/dist/cell.js.map +1 -0
- package/dist/column-view-column.d.ts +24 -14
- package/dist/column-view-column.d.ts.map +1 -1
- package/dist/column-view-column.js +19 -40
- package/dist/column-view-column.js.map +1 -1
- package/dist/column-view.d.ts +25 -11
- package/dist/column-view.d.ts.map +1 -1
- package/dist/column-view.js +53 -83
- package/dist/column-view.js.map +1 -1
- package/dist/constraint-layout-apply.d.ts +50 -1
- package/dist/constraint-layout-apply.d.ts.map +1 -1
- package/dist/constraint-layout-apply.js.map +1 -1
- package/dist/constraint-layout.d.ts +8 -1
- package/dist/constraint-layout.d.ts.map +1 -1
- package/dist/constraint-layout.js +12 -9
- package/dist/constraint-layout.js.map +1 -1
- package/dist/drop-down.d.ts +26 -36
- package/dist/drop-down.d.ts.map +1 -1
- package/dist/drop-down.js +47 -87
- package/dist/drop-down.js.map +1 -1
- package/dist/fixed.d.ts +26 -0
- package/dist/fixed.d.ts.map +1 -0
- package/dist/fixed.js +40 -0
- package/dist/fixed.js.map +1 -0
- package/dist/grid-view.d.ts +13 -10
- package/dist/grid-view.d.ts.map +1 -1
- package/dist/grid-view.js +30 -16
- package/dist/grid-view.js.map +1 -1
- package/dist/grid.d.ts +27 -0
- package/dist/grid.d.ts.map +1 -0
- package/dist/grid.js +48 -0
- package/dist/grid.js.map +1 -0
- package/dist/hooks/use-cell-containers.d.ts +18 -0
- package/dist/hooks/use-cell-containers.d.ts.map +1 -0
- package/dist/hooks/{use-realized-slots.js → use-cell-containers.js} +18 -17
- package/dist/hooks/use-cell-containers.js.map +1 -0
- package/dist/hooks/use-collection-model.d.ts +26 -0
- package/dist/hooks/use-collection-model.d.ts.map +1 -0
- package/dist/hooks/use-collection-model.js +35 -0
- package/dist/hooks/use-collection-model.js.map +1 -0
- package/dist/hooks/use-collection-widget.d.ts +28 -0
- package/dist/hooks/use-collection-widget.d.ts.map +1 -0
- package/dist/hooks/use-collection-widget.js +21 -0
- package/dist/hooks/use-collection-widget.js.map +1 -0
- package/dist/hooks/use-drop-down-selection.d.ts +7 -6
- package/dist/hooks/use-drop-down-selection.d.ts.map +1 -1
- package/dist/hooks/use-drop-down-selection.js +6 -6
- package/dist/hooks/use-drop-down-selection.js.map +1 -1
- package/dist/hooks/use-expansion-model.d.ts +12 -0
- package/dist/hooks/use-expansion-model.d.ts.map +1 -0
- package/dist/hooks/use-expansion-model.js +71 -0
- package/dist/hooks/use-expansion-model.js.map +1 -0
- package/dist/hooks/use-header-menu.d.ts.map +1 -1
- package/dist/hooks/use-header-menu.js +12 -24
- package/dist/hooks/use-header-menu.js.map +1 -1
- package/dist/hooks/use-installed-model.d.ts +4 -0
- package/dist/hooks/use-installed-model.d.ts.map +1 -0
- package/dist/hooks/use-installed-model.js +15 -0
- package/dist/hooks/use-installed-model.js.map +1 -0
- package/dist/hooks/use-list-model.d.ts +14 -15
- package/dist/hooks/use-list-model.d.ts.map +1 -1
- package/dist/hooks/use-list-model.js +61 -34
- package/dist/hooks/use-list-model.js.map +1 -1
- package/dist/hooks/use-placed-child.d.ts +18 -0
- package/dist/hooks/use-placed-child.d.ts.map +1 -0
- package/dist/hooks/use-placed-child.js +47 -0
- package/dist/hooks/use-placed-child.js.map +1 -0
- package/dist/hooks/use-selection-model.d.ts +4 -3
- package/dist/hooks/use-selection-model.d.ts.map +1 -1
- package/dist/hooks/use-selection-model.js +8 -16
- package/dist/hooks/use-selection-model.js.map +1 -1
- package/dist/hooks/use-sort-handler.d.ts +10 -5
- package/dist/hooks/use-sort-handler.d.ts.map +1 -1
- package/dist/hooks/use-sort-handler.js +2 -2
- package/dist/hooks/use-sort-handler.js.map +1 -1
- package/dist/index.d.ts +11 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -13
- package/dist/index.js.map +1 -1
- package/dist/list-view.d.ts +17 -9
- package/dist/list-view.d.ts.map +1 -1
- package/dist/list-view.js +49 -24
- package/dist/list-view.js.map +1 -1
- package/dist/menu-items.d.ts.map +1 -1
- package/dist/menu-items.js.map +1 -1
- package/dist/menu.d.ts +6 -10
- package/dist/menu.d.ts.map +1 -1
- package/dist/menu.js +7 -9
- package/dist/menu.js.map +1 -1
- package/dist/overlay.d.ts +24 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +49 -0
- package/dist/overlay.js.map +1 -0
- package/dist/size-group.d.ts +20 -0
- package/dist/size-group.d.ts.map +1 -0
- package/dist/size-group.js +57 -0
- package/dist/size-group.js.map +1 -0
- package/dist/types.d.ts +43 -173
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/{realized-slot-store.d.ts → cell-container-store.d.ts} +7 -9
- package/dist/utils/cell-container-store.d.ts.map +1 -0
- package/dist/utils/{realized-slot-store.js → cell-container-store.js} +9 -14
- package/dist/utils/cell-container-store.js.map +1 -0
- package/dist/utils/item-models.d.ts +10 -0
- package/dist/utils/item-models.d.ts.map +1 -0
- package/dist/utils/{position-only-model.js → item-models.js} +13 -14
- package/dist/utils/item-models.js.map +1 -0
- package/dist/utils/item-resolver.d.ts +14 -17
- package/dist/utils/item-resolver.d.ts.map +1 -1
- package/dist/utils/item-resolver.js +34 -43
- package/dist/utils/item-resolver.js.map +1 -1
- package/dist/utils/list-item-flatten.d.ts +16 -24
- package/dist/utils/list-item-flatten.d.ts.map +1 -1
- package/dist/utils/list-item-flatten.js +16 -36
- package/dist/utils/list-item-flatten.js.map +1 -1
- package/package.json +52 -53
- package/src/cell.tsx +144 -0
- package/src/column-view-column.tsx +57 -48
- package/src/column-view.tsx +130 -146
- package/src/constraint-layout-apply.ts +53 -1
- package/src/constraint-layout.tsx +18 -13
- package/src/drop-down.tsx +129 -196
- package/src/fixed.tsx +86 -0
- package/src/grid-view.tsx +52 -44
- package/src/grid.tsx +88 -0
- package/src/hooks/{use-realized-slots.ts → use-cell-containers.ts} +30 -30
- package/src/hooks/use-collection-model.ts +60 -0
- package/src/hooks/use-collection-widget.ts +47 -0
- package/src/hooks/use-drop-down-selection.ts +12 -13
- package/src/hooks/use-expansion-model.ts +82 -0
- package/src/hooks/use-header-menu.ts +24 -23
- package/src/hooks/use-installed-model.ts +20 -0
- package/src/hooks/use-list-model.ts +103 -87
- package/src/hooks/use-placed-child.ts +79 -0
- package/src/hooks/use-selection-model.ts +11 -18
- package/src/hooks/use-sort-handler.ts +13 -8
- package/src/index.ts +25 -27
- package/src/list-view.tsx +120 -57
- package/src/menu.tsx +12 -14
- package/src/overlay.tsx +88 -0
- package/src/size-group.tsx +96 -0
- package/src/types.ts +55 -206
- package/src/utils/{realized-slot-store.ts → cell-container-store.ts} +13 -25
- package/src/utils/{position-only-model.ts → item-models.ts} +26 -28
- package/src/utils/item-resolver.ts +54 -59
- package/src/utils/list-item-flatten.ts +33 -56
- package/dist/collection-view.d.ts +0 -30
- package/dist/collection-view.d.ts.map +0 -1
- package/dist/collection-view.js +0 -52
- package/dist/collection-view.js.map +0 -1
- package/dist/contexts/column-view-context.d.ts +0 -17
- package/dist/contexts/column-view-context.d.ts.map +0 -1
- package/dist/contexts/column-view-context.js +0 -10
- package/dist/contexts/column-view-context.js.map +0 -1
- package/dist/hooks/use-model-installation.d.ts +0 -9
- package/dist/hooks/use-model-installation.d.ts.map +0 -1
- package/dist/hooks/use-model-installation.js +0 -20
- package/dist/hooks/use-model-installation.js.map +0 -1
- package/dist/hooks/use-realized-slots.d.ts +0 -20
- package/dist/hooks/use-realized-slots.d.ts.map +0 -1
- package/dist/hooks/use-realized-slots.js.map +0 -1
- package/dist/list-portal-host.d.ts +0 -11
- package/dist/list-portal-host.d.ts.map +0 -1
- package/dist/list-portal-host.js +0 -8
- package/dist/list-portal-host.js.map +0 -1
- package/dist/list-slot.d.ts +0 -14
- package/dist/list-slot.d.ts.map +0 -1
- package/dist/list-slot.js +0 -29
- package/dist/list-slot.js.map +0 -1
- package/dist/utils/position-only-model.d.ts +0 -10
- package/dist/utils/position-only-model.d.ts.map +0 -1
- package/dist/utils/position-only-model.js.map +0 -1
- package/dist/utils/realized-slot-store.d.ts.map +0 -1
- package/dist/utils/realized-slot-store.js.map +0 -1
- package/src/collection-view.tsx +0 -125
- package/src/contexts/column-view-context.ts +0 -28
- package/src/hooks/use-model-installation.ts +0 -25
- package/src/list-portal-host.tsx +0 -27
- package/src/list-slot.tsx +0 -56
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { flattenListItems } from "./list-item-flatten.js";
|
|
1
|
+
import { countDescendants, flattenListItems } from "./list-item-flatten.js";
|
|
2
2
|
const NO_TREE_METADATA = { hideExpander: false, indentForDepth: true, indentForIcon: true };
|
|
3
3
|
const treeItemCache = new WeakMap();
|
|
4
4
|
const treeRowItem = (treeRow) => {
|
|
@@ -10,18 +10,21 @@ const treeRowItem = (treeRow) => {
|
|
|
10
10
|
treeItemCache.set(treeRow, item);
|
|
11
11
|
return item;
|
|
12
12
|
};
|
|
13
|
-
export const
|
|
13
|
+
export const rowIdOf = (rowValues, row) => {
|
|
14
|
+
const item = row.getItem();
|
|
15
|
+
return item === null ? undefined : rowValues.get(item)?.id;
|
|
16
|
+
};
|
|
17
|
+
export const createItemResolver = (items, flattenTreeChildren, rowValues) => {
|
|
14
18
|
const flattened = flattenListItems(items, flattenTreeChildren);
|
|
15
19
|
return {
|
|
16
|
-
|
|
17
|
-
positionOf(id) {
|
|
20
|
+
positionOfId(id) {
|
|
18
21
|
const position = flattened.idToPosition.get(id);
|
|
19
22
|
return position === undefined ? -1 : position;
|
|
20
23
|
},
|
|
21
24
|
idOf(position) {
|
|
22
25
|
return flattened.positionToId.get(position);
|
|
23
26
|
},
|
|
24
|
-
resolve(position, treeRow
|
|
27
|
+
resolve(position, treeRow) {
|
|
25
28
|
if (treeRow !== null && !flattenTreeChildren) {
|
|
26
29
|
const rowItem = treeRowItem(treeRow);
|
|
27
30
|
if (rowItem !== null) {
|
|
@@ -30,8 +33,7 @@ export const createControlledResolver = (items, flattenTreeChildren, rowValues)
|
|
|
30
33
|
return {
|
|
31
34
|
value: tagged.value,
|
|
32
35
|
present: true,
|
|
33
|
-
isHeader:
|
|
34
|
-
treeRow,
|
|
36
|
+
isHeader: false,
|
|
35
37
|
metadata: tagged.metadata,
|
|
36
38
|
};
|
|
37
39
|
}
|
|
@@ -43,69 +45,58 @@ export const createControlledResolver = (items, flattenTreeChildren, rowValues)
|
|
|
43
45
|
value: undefined,
|
|
44
46
|
present: false,
|
|
45
47
|
isHeader: false,
|
|
46
|
-
treeRow,
|
|
47
48
|
metadata: NO_TREE_METADATA,
|
|
48
49
|
};
|
|
49
50
|
}
|
|
50
51
|
return {
|
|
51
52
|
value: record.value,
|
|
52
53
|
present: true,
|
|
53
|
-
isHeader: record.isHeader,
|
|
54
|
-
treeRow,
|
|
55
|
-
metadata: record.metadata,
|
|
56
|
-
};
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
export const createModelResolver = (model) => {
|
|
61
|
-
return {
|
|
62
|
-
get count() {
|
|
63
|
-
return model.getNItems();
|
|
64
|
-
},
|
|
65
|
-
positionOf(id) {
|
|
66
|
-
const numeric = Number(id);
|
|
67
|
-
return Number.isInteger(numeric) ? numeric : -1;
|
|
68
|
-
},
|
|
69
|
-
idOf(position) {
|
|
70
|
-
return String(position);
|
|
71
|
-
},
|
|
72
|
-
resolve(position, treeRow, boundItem) {
|
|
73
|
-
const item = boundItem ?? model.getItem(position);
|
|
74
|
-
return {
|
|
75
|
-
value: (item ?? undefined),
|
|
76
|
-
present: item !== null,
|
|
77
54
|
isHeader: false,
|
|
78
|
-
|
|
79
|
-
metadata: NO_TREE_METADATA,
|
|
55
|
+
metadata: record.metadata,
|
|
80
56
|
};
|
|
81
57
|
},
|
|
82
58
|
};
|
|
83
59
|
};
|
|
84
|
-
export const createSectionHeaderResolver = (
|
|
60
|
+
export const createSectionHeaderResolver = (sections) => {
|
|
85
61
|
const valueByStart = new Map();
|
|
86
62
|
let start = 0;
|
|
87
|
-
for (const section of
|
|
88
|
-
if (section.section !== true)
|
|
89
|
-
continue;
|
|
63
|
+
for (const section of sections ?? []) {
|
|
90
64
|
valueByStart.set(start, section.value);
|
|
91
|
-
start += section.
|
|
65
|
+
start += countDescendants(section.data);
|
|
92
66
|
}
|
|
93
67
|
return {
|
|
94
|
-
|
|
95
|
-
positionOf: () => -1,
|
|
68
|
+
positionOfId: () => -1,
|
|
96
69
|
idOf: () => undefined,
|
|
97
70
|
resolve(position) {
|
|
98
71
|
if (!valueByStart.has(position)) {
|
|
99
|
-
return { value: undefined, present: false, isHeader: true,
|
|
72
|
+
return { value: undefined, present: false, isHeader: true, metadata: NO_TREE_METADATA };
|
|
100
73
|
}
|
|
101
74
|
return {
|
|
102
75
|
value: valueByStart.get(position),
|
|
103
76
|
present: true,
|
|
104
77
|
isHeader: true,
|
|
105
|
-
treeRow: null,
|
|
106
78
|
metadata: NO_TREE_METADATA,
|
|
107
79
|
};
|
|
108
80
|
},
|
|
109
81
|
};
|
|
110
82
|
};
|
|
83
|
+
export const createTreeResolver = (items, rowValues, model) => {
|
|
84
|
+
const base = createItemResolver(items, false, rowValues);
|
|
85
|
+
return {
|
|
86
|
+
resolve: base.resolve,
|
|
87
|
+
idOf: (position) => {
|
|
88
|
+
const row = model.getRow(position);
|
|
89
|
+
return row === null ? undefined : rowIdOf(rowValues, row);
|
|
90
|
+
},
|
|
91
|
+
positionOfId: (id) => {
|
|
92
|
+
const count = model.getNItems();
|
|
93
|
+
for (let position = 0; position < count; position++) {
|
|
94
|
+
const row = model.getRow(position);
|
|
95
|
+
if (row !== null && rowIdOf(rowValues, row) === id)
|
|
96
|
+
return position;
|
|
97
|
+
}
|
|
98
|
+
return -1;
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
};
|
|
111
102
|
//# sourceMappingURL=item-resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"item-resolver.js","sourceRoot":"","sources":["../../src/utils/item-resolver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"item-resolver.js","sourceRoot":"","sources":["../../src/utils/item-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import type * as GObject from \"@gtkx/gi/gobject\";\nimport type * as Gtk from \"@gtkx/gi/gtk\";\nimport type { ItemNode, SectionNode } from \"../types.js\";\nimport { countDescendants, flattenListItems, type TreeItemMetadata } from \"./list-item-flatten.js\";\n\nconst NO_TREE_METADATA: TreeItemMetadata = { hideExpander: false, indentForDepth: true, indentForIcon: true };\n\nconst treeItemCache = new WeakMap<Gtk.TreeListRow, GObject.Object>();\n\nconst treeRowItem = (treeRow: Gtk.TreeListRow): GObject.Object | null => {\n const cached = treeItemCache.get(treeRow);\n if (cached !== undefined) return cached;\n const item = treeRow.getItem();\n if (item !== null) treeItemCache.set(treeRow, item);\n return item;\n};\n\nexport type Resolved<T = unknown, S = unknown> = {\n value: T | S | undefined;\n present: boolean;\n isHeader: boolean;\n metadata: TreeItemMetadata;\n};\n\nexport type ItemResolver<T = unknown, S = unknown> = {\n resolve(position: number, treeRow: Gtk.TreeListRow | null): Resolved<T, S>;\n positionOfId(id: string): number;\n idOf(position: number): string | undefined;\n};\n\nexport type RowValue<T = unknown> = {\n id: string;\n value: T;\n metadata: TreeItemMetadata;\n};\n\nexport const rowIdOf = <T>(\n rowValues: WeakMap<GObject.Object, RowValue<T>>,\n row: Gtk.TreeListRow,\n): string | undefined => {\n const item = row.getItem();\n return item === null ? undefined : rowValues.get(item)?.id;\n};\n\nexport const createItemResolver = <T, S>(\n items: ItemNode<T>[] | undefined,\n flattenTreeChildren: boolean,\n rowValues: WeakMap<GObject.Object, RowValue<T>>,\n): ItemResolver<T, S> => {\n const flattened = flattenListItems(items, flattenTreeChildren);\n return {\n positionOfId(id: string): number {\n const position = flattened.idToPosition.get(id);\n return position === undefined ? -1 : position;\n },\n idOf(position: number): string | undefined {\n return flattened.positionToId.get(position);\n },\n resolve(position: number, treeRow: Gtk.TreeListRow | null): Resolved<T, S> {\n if (treeRow !== null && !flattenTreeChildren) {\n const rowItem = treeRowItem(treeRow);\n if (rowItem !== null) {\n const tagged = rowValues.get(rowItem);\n if (tagged !== undefined) {\n return {\n value: tagged.value,\n present: true,\n isHeader: false,\n metadata: tagged.metadata,\n };\n }\n }\n }\n const record = flattened.records[position];\n if (record === undefined) {\n return {\n value: undefined,\n present: false,\n isHeader: false,\n metadata: NO_TREE_METADATA,\n };\n }\n return {\n value: record.value,\n present: true,\n isHeader: false,\n metadata: record.metadata,\n };\n },\n };\n};\n\nexport const createSectionHeaderResolver = <T, S>(sections: SectionNode<S, T>[] | undefined): ItemResolver<T, S> => {\n const valueByStart = new Map<number, S>();\n let start = 0;\n for (const section of sections ?? []) {\n valueByStart.set(start, section.value);\n start += countDescendants(section.data);\n }\n return {\n positionOfId: () => -1,\n idOf: () => undefined,\n resolve(position: number): Resolved<T, S> {\n if (!valueByStart.has(position)) {\n return { value: undefined, present: false, isHeader: true, metadata: NO_TREE_METADATA };\n }\n return {\n value: valueByStart.get(position),\n present: true,\n isHeader: true,\n metadata: NO_TREE_METADATA,\n };\n },\n };\n};\n\nexport const createTreeResolver = <T, S>(\n items: ItemNode<T>[] | undefined,\n rowValues: WeakMap<GObject.Object, RowValue<T>>,\n model: Gtk.TreeListModel,\n): ItemResolver<T, S> => {\n const base = createItemResolver<T, S>(items, false, rowValues);\n return {\n resolve: base.resolve,\n idOf: (position: number): string | undefined => {\n const row = model.getRow(position);\n return row === null ? undefined : rowIdOf(rowValues, row);\n },\n positionOfId: (id: string): number => {\n const count = model.getNItems();\n for (let position = 0; position < count; position++) {\n const row = model.getRow(position);\n if (row !== null && rowIdOf(rowValues, row) === id) return position;\n }\n return -1;\n },\n };\n};\n"]}
|
|
@@ -1,32 +1,24 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export
|
|
1
|
+
import type { ItemNode } from "../types.js";
|
|
2
|
+
export type TreeItemMetadata = {
|
|
3
3
|
hideExpander: boolean;
|
|
4
4
|
indentForDepth: boolean;
|
|
5
5
|
indentForIcon: boolean;
|
|
6
|
-
}
|
|
7
|
-
|
|
6
|
+
};
|
|
7
|
+
type FlattenedRecord<T = unknown> = {
|
|
8
8
|
id: string;
|
|
9
|
-
value: T
|
|
10
|
-
isHeader: boolean;
|
|
11
|
-
hasChildren: boolean;
|
|
12
|
-
children: ListItem<T, S>[];
|
|
9
|
+
value: T;
|
|
13
10
|
metadata: TreeItemMetadata;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
records: FlattenedRecord<T
|
|
11
|
+
};
|
|
12
|
+
type FlattenResult<T = unknown> = {
|
|
13
|
+
records: FlattenedRecord<T>[];
|
|
17
14
|
idToPosition: Map<string, number>;
|
|
18
15
|
positionToId: Map<number, string>;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*/
|
|
28
|
-
export declare const detectStructure: <T, S>(items: ListItem<T, S>[] | undefined) => ListStructure;
|
|
29
|
-
export declare const structuralSignature: <T, S>(items: ListItem<T, S>[] | undefined) => string;
|
|
30
|
-
export declare const treeItemMetadata: <T, S>(item: ListItem<T, S>) => TreeItemMetadata;
|
|
31
|
-
export declare const flattenListItems: <T, S>(items: ListItem<T, S>[] | undefined, flattenTreeChildren: boolean) => FlattenResult<T, S>;
|
|
16
|
+
};
|
|
17
|
+
export type ListStructure = "flat" | "tree";
|
|
18
|
+
export declare const detectStructure: <T>(items: ItemNode<T>[] | undefined) => ListStructure;
|
|
19
|
+
export declare const structuralSignature: <T>(items: ItemNode<T>[] | undefined) => string;
|
|
20
|
+
export declare const countDescendants: <T>(items: ItemNode<T>[]) => number;
|
|
21
|
+
export declare const treeItemMetadata: <T>(item: ItemNode<T>) => TreeItemMetadata;
|
|
22
|
+
export declare const flattenListItems: <T>(items: ItemNode<T>[] | undefined, flattenTreeChildren: boolean) => FlattenResult<T>;
|
|
23
|
+
export {};
|
|
32
24
|
//# sourceMappingURL=list-item-flatten.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-item-flatten.d.ts","sourceRoot":"","sources":["../../src/utils/list-item-flatten.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,
|
|
1
|
+
{"version":3,"file":"list-item-flatten.d.ts","sourceRoot":"","sources":["../../src/utils/list-item-flatten.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,MAAM,gBAAgB,GAAG;IAC3B,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,KAAK,eAAe,CAAC,CAAC,GAAG,OAAO,IAAI;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,gBAAgB,CAAC;CAC9B,CAAC;AAEF,KAAK,aAAa,CAAC,CAAC,GAAG,OAAO,IAAI;IAC9B,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,KAAG,aAMrE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,KAAG,MAczE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAG,MAO1D,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,CAAC,QAAQ,QAAQ,CAAC,CAAC,CAAC,KAAG,gBAItD,CAAC;AAgBH,eAAO,MAAM,gBAAgB,GAAI,CAAC,SACvB,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,uBACX,OAAO,KAC7B,aAAa,CAAC,CAAC,CAWjB,CAAC"}
|
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Classify a controlled item list as flat, tree, or sectioned without building a
|
|
3
|
-
* {@link FlattenResult}. A list is sectioned if any top-level item is a section, a
|
|
4
|
-
* tree if any top-level item carries children, and flat otherwise.
|
|
5
|
-
*/
|
|
6
1
|
export const detectStructure = (items) => {
|
|
7
2
|
if (items === undefined)
|
|
8
3
|
return "flat";
|
|
9
|
-
let sawTree = false;
|
|
10
4
|
for (const item of items) {
|
|
11
|
-
if (item.section === true)
|
|
12
|
-
return "sections";
|
|
13
5
|
if (item.children !== undefined && item.children.length > 0)
|
|
14
|
-
|
|
6
|
+
return "tree";
|
|
15
7
|
}
|
|
16
|
-
return
|
|
8
|
+
return "flat";
|
|
17
9
|
};
|
|
18
10
|
export const structuralSignature = (items) => {
|
|
19
11
|
if (items === undefined)
|
|
@@ -22,8 +14,8 @@ export const structuralSignature = (items) => {
|
|
|
22
14
|
const walk = (list) => {
|
|
23
15
|
parts.push("[");
|
|
24
16
|
for (const item of list) {
|
|
25
|
-
const hidden = item.
|
|
26
|
-
parts.push(`${item.id}|${
|
|
17
|
+
const hidden = item.hideExpander === true;
|
|
18
|
+
parts.push(`${item.id}|${hidden ? 1 : 0}`);
|
|
27
19
|
if (item.children !== undefined && item.children.length > 0)
|
|
28
20
|
walk(item.children);
|
|
29
21
|
}
|
|
@@ -32,17 +24,20 @@ export const structuralSignature = (items) => {
|
|
|
32
24
|
walk(items);
|
|
33
25
|
return parts.join(",");
|
|
34
26
|
};
|
|
35
|
-
export const
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
export const countDescendants = (items) => {
|
|
28
|
+
let total = 0;
|
|
29
|
+
for (const item of items) {
|
|
30
|
+
total += 1;
|
|
31
|
+
if (item.children !== undefined && item.children.length > 0)
|
|
32
|
+
total += countDescendants(item.children);
|
|
38
33
|
}
|
|
39
|
-
return
|
|
40
|
-
hideExpander: item.hideExpander ?? false,
|
|
41
|
-
indentForDepth: item.indentForDepth ?? true,
|
|
42
|
-
indentForIcon: item.indentForIcon ?? true,
|
|
43
|
-
};
|
|
34
|
+
return total;
|
|
44
35
|
};
|
|
45
|
-
const
|
|
36
|
+
export const treeItemMetadata = (item) => ({
|
|
37
|
+
hideExpander: item.hideExpander ?? false,
|
|
38
|
+
indentForDepth: item.indentForDepth ?? true,
|
|
39
|
+
indentForIcon: item.indentForIcon ?? true,
|
|
40
|
+
});
|
|
46
41
|
const appendRecord = (item, result, includeChildren) => {
|
|
47
42
|
const position = result.records.length;
|
|
48
43
|
result.idToPosition.set(item.id, position);
|
|
@@ -50,9 +45,6 @@ const appendRecord = (item, result, includeChildren) => {
|
|
|
50
45
|
result.records.push({
|
|
51
46
|
id: item.id,
|
|
52
47
|
value: item.value,
|
|
53
|
-
isHeader: item.section === true,
|
|
54
|
-
hasChildren: hasChildren(item),
|
|
55
|
-
children: item.children ?? [],
|
|
56
48
|
metadata: treeItemMetadata(item),
|
|
57
49
|
});
|
|
58
50
|
if (includeChildren && item.children !== undefined) {
|
|
@@ -65,22 +57,10 @@ export const flattenListItems = (items, flattenTreeChildren) => {
|
|
|
65
57
|
records: [],
|
|
66
58
|
idToPosition: new Map(),
|
|
67
59
|
positionToId: new Map(),
|
|
68
|
-
isTree: false,
|
|
69
|
-
isSectioned: false,
|
|
70
60
|
};
|
|
71
61
|
if (items === undefined)
|
|
72
62
|
return result;
|
|
73
63
|
for (const item of items) {
|
|
74
|
-
if (item.section === true) {
|
|
75
|
-
result.isSectioned = true;
|
|
76
|
-
if (item.children !== undefined) {
|
|
77
|
-
for (const child of item.children)
|
|
78
|
-
appendRecord(child, result, true);
|
|
79
|
-
}
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
if (hasChildren(item))
|
|
83
|
-
result.isTree = true;
|
|
84
64
|
appendRecord(item, result, flattenTreeChildren);
|
|
85
65
|
}
|
|
86
66
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-item-flatten.js","sourceRoot":"","sources":["../../src/utils/list-item-flatten.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"list-item-flatten.js","sourceRoot":"","sources":["../../src/utils/list-item-flatten.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ItemNode } from \"../types.js\";\n\nexport type TreeItemMetadata = {\n hideExpander: boolean;\n indentForDepth: boolean;\n indentForIcon: boolean;\n};\n\ntype FlattenedRecord<T = unknown> = {\n id: string;\n value: T;\n metadata: TreeItemMetadata;\n};\n\ntype FlattenResult<T = unknown> = {\n records: FlattenedRecord<T>[];\n idToPosition: Map<string, number>;\n positionToId: Map<number, string>;\n};\n\nexport type ListStructure = \"flat\" | \"tree\";\n\nexport const detectStructure = <T>(items: ItemNode<T>[] | undefined): ListStructure => {\n if (items === undefined) return \"flat\";\n for (const item of items) {\n if (item.children !== undefined && item.children.length > 0) return \"tree\";\n }\n return \"flat\";\n};\n\nexport const structuralSignature = <T>(items: ItemNode<T>[] | undefined): string => {\n if (items === undefined) return \"\";\n const parts: string[] = [];\n const walk = (list: ItemNode<T>[]): void => {\n parts.push(\"[\");\n for (const item of list) {\n const hidden = item.hideExpander === true;\n parts.push(`${item.id}|${hidden ? 1 : 0}`);\n if (item.children !== undefined && item.children.length > 0) walk(item.children);\n }\n parts.push(\"]\");\n };\n walk(items);\n return parts.join(\",\");\n};\n\nexport const countDescendants = <T>(items: ItemNode<T>[]): number => {\n let total = 0;\n for (const item of items) {\n total += 1;\n if (item.children !== undefined && item.children.length > 0) total += countDescendants(item.children);\n }\n return total;\n};\n\nexport const treeItemMetadata = <T>(item: ItemNode<T>): TreeItemMetadata => ({\n hideExpander: item.hideExpander ?? false,\n indentForDepth: item.indentForDepth ?? true,\n indentForIcon: item.indentForIcon ?? true,\n});\n\nconst appendRecord = <T>(item: ItemNode<T>, result: FlattenResult<T>, includeChildren: boolean): void => {\n const position = result.records.length;\n result.idToPosition.set(item.id, position);\n result.positionToId.set(position, item.id);\n result.records.push({\n id: item.id,\n value: item.value,\n metadata: treeItemMetadata(item),\n });\n if (includeChildren && item.children !== undefined) {\n for (const child of item.children) appendRecord(child, result, includeChildren);\n }\n};\n\nexport const flattenListItems = <T>(\n items: ItemNode<T>[] | undefined,\n flattenTreeChildren: boolean,\n): FlattenResult<T> => {\n const result: FlattenResult<T> = {\n records: [],\n idToPosition: new Map(),\n positionToId: new Map(),\n };\n if (items === undefined) return result;\n for (const item of items) {\n appendRecord(item, result, flattenTreeChildren);\n }\n return result;\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,55 +1,54 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"default": "./dist/index.js"
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
"sideEffects": false,
|
|
36
|
-
"files": [
|
|
37
|
-
"dist",
|
|
38
|
-
"src"
|
|
39
|
-
],
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "tsc -b"
|
|
42
|
-
},
|
|
43
|
-
"engines": {
|
|
44
|
-
"node": ">=24"
|
|
45
|
-
},
|
|
46
|
-
"dependencies": {
|
|
47
|
-
"@gtkx/react": "workspace:*"
|
|
48
|
-
},
|
|
49
|
-
"devDependencies": {
|
|
50
|
-
"@gtkx/vitest": "workspace:*"
|
|
51
|
-
},
|
|
52
|
-
"peerDependencies": {
|
|
53
|
-
"react": "^19"
|
|
2
|
+
"name": "@gtkx/components",
|
|
3
|
+
"version": "1.0.0-rc.1",
|
|
4
|
+
"description": "High-level GTKX components for declarative collection views, menus, and containers with attach-time placement",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"gtkx",
|
|
7
|
+
"gtk",
|
|
8
|
+
"gtk4",
|
|
9
|
+
"adwaita",
|
|
10
|
+
"react",
|
|
11
|
+
"components",
|
|
12
|
+
"linux",
|
|
13
|
+
"desktop"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://gtkx.dev",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/gtkx-org/gtkx/issues"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/gtkx-org/gtkx.git",
|
|
22
|
+
"directory": "packages/components"
|
|
23
|
+
},
|
|
24
|
+
"license": "MPL-2.0",
|
|
25
|
+
"author": "Eugenio Depalo <eugeniodepalo@gmail.com>",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
"./package.json": "./package.json",
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
54
32
|
}
|
|
55
|
-
}
|
|
33
|
+
},
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"src"
|
|
38
|
+
],
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=24"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@gtkx/utils": "1.0.0-rc.1",
|
|
44
|
+
"@gtkx/react": "1.0.0-rc.1"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"react": "^19"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc -b tsconfig.lib.json",
|
|
51
|
+
"typecheck": "tsc -b --emitDeclarationOnly",
|
|
52
|
+
"release": "tsx ../../scripts/release-package.ts"
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/cell.tsx
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type * as GObject from "@gtkx/gi/gobject";
|
|
2
|
+
import type * as Gtk from "@gtkx/gi/gtk";
|
|
3
|
+
import { GtkTreeExpander } from "@gtkx/jsx/gtk";
|
|
4
|
+
import { createPortal } from "@gtkx/react";
|
|
5
|
+
import { Fragment, memo, type ReactNode, useCallback, useSyncExternalStore } from "react";
|
|
6
|
+
import type { RenderItemProps } from "./types.js";
|
|
7
|
+
import type { CellContainerStore, CellEntry } from "./utils/cell-container-store.js";
|
|
8
|
+
import type { ItemResolver } from "./utils/item-resolver.js";
|
|
9
|
+
import type { TreeItemMetadata } from "./utils/list-item-flatten.js";
|
|
10
|
+
|
|
11
|
+
export type CellRenderer<T, S> = (
|
|
12
|
+
value: T | S | undefined,
|
|
13
|
+
treeRow: Gtk.TreeListRow | null,
|
|
14
|
+
position: number,
|
|
15
|
+
) => ReactNode;
|
|
16
|
+
|
|
17
|
+
interface CellProps<T, S> {
|
|
18
|
+
container: GObject.Object;
|
|
19
|
+
store: CellContainerStore;
|
|
20
|
+
resolver: ItemResolver<T, S>;
|
|
21
|
+
render: CellRenderer<T, S>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface CellRenderHostProps<T, S> {
|
|
25
|
+
store: CellContainerStore;
|
|
26
|
+
resolver: ItemResolver<T, S>;
|
|
27
|
+
render: CellRenderer<T, S>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface TreeExpanderCellProps {
|
|
31
|
+
treeRow: Gtk.TreeListRow;
|
|
32
|
+
metadata: TreeItemMetadata;
|
|
33
|
+
children: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const TreeExpanderCell = ({ treeRow, metadata, children }: TreeExpanderCellProps): ReactNode => (
|
|
37
|
+
<GtkTreeExpander
|
|
38
|
+
ref={(expander: Gtk.TreeExpander | null) => {
|
|
39
|
+
if (expander !== null) expander.setListRow(treeRow);
|
|
40
|
+
}}
|
|
41
|
+
hideExpander={metadata.hideExpander}
|
|
42
|
+
indentForDepth={metadata.indentForDepth}
|
|
43
|
+
indentForIcon={metadata.indentForIcon}
|
|
44
|
+
>
|
|
45
|
+
{children}
|
|
46
|
+
</GtkTreeExpander>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const Cell = memo(<T, S>({ container, store, resolver, render }: CellProps<T, S>): ReactNode => {
|
|
50
|
+
const subscribe = useCallback(
|
|
51
|
+
(onChange: () => void) => store.subscribePosition(container, onChange),
|
|
52
|
+
[store, container],
|
|
53
|
+
);
|
|
54
|
+
const getSnapshot = useCallback((): CellEntry => store.getPosition(container), [store, container]);
|
|
55
|
+
const entry = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
56
|
+
|
|
57
|
+
if (entry.position < 0) return null;
|
|
58
|
+
const resolved = resolver.resolve(entry.position, entry.treeRow);
|
|
59
|
+
if (!resolved.present) return null;
|
|
60
|
+
const content = render(resolved.value, entry.treeRow, entry.position);
|
|
61
|
+
const portalled =
|
|
62
|
+
entry.treeRow !== null && !resolved.isHeader ? (
|
|
63
|
+
<TreeExpanderCell treeRow={entry.treeRow} metadata={resolved.metadata}>
|
|
64
|
+
{content}
|
|
65
|
+
</TreeExpanderCell>
|
|
66
|
+
) : (
|
|
67
|
+
content
|
|
68
|
+
);
|
|
69
|
+
return createPortal(portalled, container, store.keyFor(container));
|
|
70
|
+
}) as <T, S>(props: CellProps<T, S>) => ReactNode;
|
|
71
|
+
|
|
72
|
+
export const CellRenderHost = <T, S>({ store, resolver, render }: CellRenderHostProps<T, S>): ReactNode => {
|
|
73
|
+
const containers = useSyncExternalStore(
|
|
74
|
+
store.subscribeSet,
|
|
75
|
+
store.getContainersSnapshot,
|
|
76
|
+
store.getContainersSnapshot,
|
|
77
|
+
);
|
|
78
|
+
return (
|
|
79
|
+
<Fragment>
|
|
80
|
+
{containers.map((container) => (
|
|
81
|
+
<Cell
|
|
82
|
+
key={store.keyFor(container)}
|
|
83
|
+
container={container}
|
|
84
|
+
store={store}
|
|
85
|
+
resolver={resolver}
|
|
86
|
+
render={render}
|
|
87
|
+
/>
|
|
88
|
+
))}
|
|
89
|
+
</Fragment>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export type TreeRenderContext = {
|
|
94
|
+
controlled: boolean;
|
|
95
|
+
expandedIds: Set<string>;
|
|
96
|
+
rowId: (row: Gtk.TreeListRow) => string | undefined;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const createTreeRenderContext = (
|
|
100
|
+
expandedIds: string[] | null | undefined,
|
|
101
|
+
rowId: (row: Gtk.TreeListRow) => string | undefined,
|
|
102
|
+
): TreeRenderContext => ({
|
|
103
|
+
controlled: expandedIds !== undefined && expandedIds !== null,
|
|
104
|
+
expandedIds: new Set(expandedIds ?? []),
|
|
105
|
+
rowId,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const treeFields = (
|
|
109
|
+
treeRow: Gtk.TreeListRow | null,
|
|
110
|
+
context: TreeRenderContext | undefined,
|
|
111
|
+
): { depth?: number; isExpanded?: boolean } => {
|
|
112
|
+
if (treeRow === null) return {};
|
|
113
|
+
const depth = treeRow.getDepth();
|
|
114
|
+
if (context === undefined || !treeRow.isExpandable()) return { depth };
|
|
115
|
+
const isExpanded = context.controlled
|
|
116
|
+
? context.expandedIds.has(context.rowId(treeRow) ?? "")
|
|
117
|
+
: treeRow.getExpanded();
|
|
118
|
+
return { depth, isExpanded };
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const itemRenderer =
|
|
122
|
+
<T, S>(render: (props: RenderItemProps<T>) => ReactNode, context?: TreeRenderContext): CellRenderer<T, S> =>
|
|
123
|
+
(value, treeRow, position) =>
|
|
124
|
+
render({ item: value as T, index: position, ...treeFields(treeRow, context) });
|
|
125
|
+
|
|
126
|
+
const headerRenderer =
|
|
127
|
+
<T, S>(renderHeader: ((info: { section: S }) => ReactNode) | null | undefined): CellRenderer<T, S> =>
|
|
128
|
+
(value) =>
|
|
129
|
+
renderHeader ? renderHeader({ section: value as S }) : null;
|
|
130
|
+
|
|
131
|
+
interface HeaderRenderHostProps<T, S> {
|
|
132
|
+
useHeader: boolean;
|
|
133
|
+
store: CellContainerStore;
|
|
134
|
+
resolver: ItemResolver<T, S>;
|
|
135
|
+
renderHeader: ((info: { section: S }) => ReactNode) | null | undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export const HeaderRenderHost = <T, S>({
|
|
139
|
+
useHeader,
|
|
140
|
+
store,
|
|
141
|
+
resolver,
|
|
142
|
+
renderHeader,
|
|
143
|
+
}: HeaderRenderHostProps<T, S>): ReactNode =>
|
|
144
|
+
useHeader ? <CellRenderHost store={store} resolver={resolver} render={headerRenderer<T, S>(renderHeader)} /> : null;
|