@gtkx/components 1.0.0-rc.1 → 1.0.0-rc.3
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/adw/combo-row.d.ts +11 -0
- package/dist/adw/combo-row.d.ts.map +1 -0
- package/dist/adw/combo-row.js +14 -0
- package/dist/adw/combo-row.js.map +1 -0
- package/dist/adw/index.d.ts +4 -0
- package/dist/adw/index.d.ts.map +1 -0
- package/dist/adw/index.js +3 -0
- package/dist/adw/index.js.map +1 -0
- package/dist/adw/toast.d.ts +10 -0
- package/dist/adw/toast.d.ts.map +1 -0
- package/dist/adw/toast.js +51 -0
- package/dist/adw/toast.js.map +1 -0
- package/dist/adw/types.d.ts +35 -0
- package/dist/adw/types.d.ts.map +1 -0
- package/dist/adw/types.js +2 -0
- package/dist/adw/types.js.map +1 -0
- package/dist/column-view.d.ts +7 -29
- package/dist/column-view.d.ts.map +1 -1
- package/dist/column-view.js +98 -70
- package/dist/column-view.js.map +1 -1
- package/dist/drop-down.d.ts +7 -28
- package/dist/drop-down.d.ts.map +1 -1
- package/dist/drop-down.js +10 -86
- package/dist/drop-down.js.map +1 -1
- package/dist/grid-view.d.ts +6 -16
- package/dist/grid-view.d.ts.map +1 -1
- package/dist/grid-view.js +25 -33
- package/dist/grid-view.js.map +1 -1
- package/dist/index.d.ts +6 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -6
- package/dist/index.js.map +1 -1
- package/dist/internal/cells.d.ts +50 -0
- package/dist/internal/cells.d.ts.map +1 -0
- package/dist/internal/cells.js +185 -0
- package/dist/internal/cells.js.map +1 -0
- package/dist/internal/collection-index.d.ts +21 -0
- package/dist/internal/collection-index.d.ts.map +1 -0
- package/dist/internal/collection-index.js +106 -0
- package/dist/internal/collection-index.js.map +1 -0
- package/dist/internal/collection-model.d.ts +12 -0
- package/dist/internal/collection-model.d.ts.map +1 -0
- package/dist/internal/collection-model.js +164 -0
- package/dist/internal/collection-model.js.map +1 -0
- package/dist/internal/collection.d.ts +18 -0
- package/dist/internal/collection.d.ts.map +1 -0
- package/dist/internal/collection.js +64 -0
- package/dist/internal/collection.js.map +1 -0
- package/dist/internal/drop-down.d.ts +16 -0
- package/dist/internal/drop-down.d.ts.map +1 -0
- package/dist/internal/drop-down.js +110 -0
- package/dist/internal/drop-down.js.map +1 -0
- package/dist/internal/expansion.d.ts +9 -0
- package/dist/internal/expansion.d.ts.map +1 -0
- package/dist/internal/expansion.js +74 -0
- package/dist/internal/expansion.js.map +1 -0
- package/dist/internal/selection.d.ts +13 -0
- package/dist/internal/selection.d.ts.map +1 -0
- package/dist/internal/selection.js +100 -0
- package/dist/internal/selection.js.map +1 -0
- package/dist/internal/use-collection.d.ts +17 -0
- package/dist/internal/use-collection.d.ts.map +1 -0
- package/dist/internal/use-collection.js +34 -0
- package/dist/internal/use-collection.js.map +1 -0
- package/dist/internal/use-widget-ref.d.ts +4 -0
- package/dist/internal/use-widget-ref.d.ts.map +1 -0
- package/dist/internal/use-widget-ref.js +8 -0
- package/dist/internal/use-widget-ref.js.map +1 -0
- package/dist/list-view.d.ts +5 -20
- package/dist/list-view.d.ts.map +1 -1
- package/dist/list-view.js +32 -53
- package/dist/list-view.js.map +1 -1
- package/dist/size-group.d.ts +8 -16
- package/dist/size-group.d.ts.map +1 -1
- package/dist/size-group.js +35 -51
- package/dist/size-group.js.map +1 -1
- package/dist/types.d.ts +98 -27
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +17 -6
- package/src/adw/combo-row.tsx +20 -0
- package/src/adw/index.ts +9 -0
- package/src/adw/toast.tsx +74 -0
- package/src/adw/types.ts +45 -0
- package/src/column-view.tsx +176 -160
- package/src/drop-down.tsx +12 -185
- package/src/grid-view.tsx +29 -73
- package/src/index.ts +18 -26
- package/src/internal/cells.tsx +345 -0
- package/src/internal/collection-index.ts +168 -0
- package/src/internal/collection-model.ts +246 -0
- package/src/internal/collection.ts +104 -0
- package/src/internal/drop-down.tsx +186 -0
- package/src/internal/expansion.ts +122 -0
- package/src/internal/selection.tsx +162 -0
- package/src/internal/use-collection.tsx +57 -0
- package/src/internal/use-widget-ref.ts +11 -0
- package/src/list-view.tsx +43 -139
- package/src/size-group.tsx +63 -82
- package/src/types.ts +158 -28
- package/dist/cell.d.ts +0 -30
- package/dist/cell.d.ts.map +0 -1
- package/dist/cell.js +0 -45
- package/dist/cell.js.map +0 -1
- package/dist/column-view-column.d.ts +0 -27
- package/dist/column-view-column.d.ts.map +0 -1
- package/dist/column-view-column.js +0 -30
- package/dist/column-view-column.js.map +0 -1
- package/dist/constraint-layout-apply.d.ts +0 -55
- package/dist/constraint-layout-apply.d.ts.map +0 -1
- package/dist/constraint-layout-apply.js +0 -107
- package/dist/constraint-layout-apply.js.map +0 -1
- package/dist/constraint-layout.d.ts +0 -20
- package/dist/constraint-layout.d.ts.map +0 -1
- package/dist/constraint-layout.js +0 -88
- package/dist/constraint-layout.js.map +0 -1
- package/dist/fixed.d.ts +0 -26
- package/dist/fixed.d.ts.map +0 -1
- package/dist/fixed.js +0 -40
- package/dist/fixed.js.map +0 -1
- package/dist/grid.d.ts +0 -27
- package/dist/grid.d.ts.map +0 -1
- package/dist/grid.js +0 -48
- package/dist/grid.js.map +0 -1
- package/dist/hooks/use-cell-containers.d.ts +0 -18
- package/dist/hooks/use-cell-containers.d.ts.map +0 -1
- package/dist/hooks/use-cell-containers.js +0 -67
- package/dist/hooks/use-cell-containers.js.map +0 -1
- package/dist/hooks/use-collection-model.d.ts +0 -26
- package/dist/hooks/use-collection-model.d.ts.map +0 -1
- package/dist/hooks/use-collection-model.js +0 -35
- package/dist/hooks/use-collection-model.js.map +0 -1
- package/dist/hooks/use-collection-widget.d.ts +0 -28
- package/dist/hooks/use-collection-widget.d.ts.map +0 -1
- package/dist/hooks/use-collection-widget.js +0 -21
- package/dist/hooks/use-collection-widget.js.map +0 -1
- package/dist/hooks/use-drop-down-selection.d.ts +0 -16
- package/dist/hooks/use-drop-down-selection.d.ts.map +0 -1
- package/dist/hooks/use-drop-down-selection.js +0 -35
- package/dist/hooks/use-drop-down-selection.js.map +0 -1
- package/dist/hooks/use-expansion-model.d.ts +0 -12
- package/dist/hooks/use-expansion-model.d.ts.map +0 -1
- package/dist/hooks/use-expansion-model.js +0 -71
- package/dist/hooks/use-expansion-model.js.map +0 -1
- package/dist/hooks/use-header-menu.d.ts +0 -4
- package/dist/hooks/use-header-menu.d.ts.map +0 -1
- package/dist/hooks/use-header-menu.js +0 -20
- package/dist/hooks/use-header-menu.js.map +0 -1
- package/dist/hooks/use-installed-model.d.ts +0 -4
- package/dist/hooks/use-installed-model.d.ts.map +0 -1
- package/dist/hooks/use-installed-model.js +0 -15
- package/dist/hooks/use-installed-model.js.map +0 -1
- package/dist/hooks/use-list-model.d.ts +0 -19
- package/dist/hooks/use-list-model.d.ts.map +0 -1
- package/dist/hooks/use-list-model.js +0 -97
- package/dist/hooks/use-list-model.js.map +0 -1
- package/dist/hooks/use-placed-child.d.ts +0 -18
- package/dist/hooks/use-placed-child.d.ts.map +0 -1
- package/dist/hooks/use-placed-child.js +0 -47
- package/dist/hooks/use-placed-child.js.map +0 -1
- package/dist/hooks/use-selection-model.d.ts +0 -13
- package/dist/hooks/use-selection-model.d.ts.map +0 -1
- package/dist/hooks/use-selection-model.js +0 -103
- package/dist/hooks/use-selection-model.js.map +0 -1
- package/dist/hooks/use-sort-handler.d.ts +0 -17
- package/dist/hooks/use-sort-handler.d.ts.map +0 -1
- package/dist/hooks/use-sort-handler.js +0 -87
- package/dist/hooks/use-sort-handler.js.map +0 -1
- package/dist/menu-items.d.ts +0 -5
- package/dist/menu-items.d.ts.map +0 -1
- package/dist/menu-items.js +0 -48
- package/dist/menu-items.js.map +0 -1
- package/dist/menu.d.ts +0 -14
- package/dist/menu.d.ts.map +0 -1
- package/dist/menu.js +0 -24
- package/dist/menu.js.map +0 -1
- package/dist/overlay.d.ts +0 -24
- package/dist/overlay.d.ts.map +0 -1
- package/dist/overlay.js +0 -49
- package/dist/overlay.js.map +0 -1
- package/dist/utils/cell-container-store.d.ts +0 -28
- package/dist/utils/cell-container-store.d.ts.map +0 -1
- package/dist/utils/cell-container-store.js +0 -98
- package/dist/utils/cell-container-store.js.map +0 -1
- package/dist/utils/item-models.d.ts +0 -10
- package/dist/utils/item-models.d.ts.map +0 -1
- package/dist/utils/item-models.js +0 -82
- package/dist/utils/item-models.js.map +0 -1
- package/dist/utils/item-resolver.d.ts +0 -25
- package/dist/utils/item-resolver.d.ts.map +0 -1
- package/dist/utils/item-resolver.js +0 -102
- package/dist/utils/item-resolver.js.map +0 -1
- package/dist/utils/list-item-flatten.d.ts +0 -24
- package/dist/utils/list-item-flatten.d.ts.map +0 -1
- package/dist/utils/list-item-flatten.js +0 -68
- package/dist/utils/list-item-flatten.js.map +0 -1
- package/src/cell.tsx +0 -144
- package/src/column-view-column.tsx +0 -82
- package/src/constraint-layout-apply.ts +0 -173
- package/src/constraint-layout.tsx +0 -135
- package/src/fixed.tsx +0 -86
- package/src/grid.tsx +0 -88
- package/src/hooks/use-cell-containers.ts +0 -93
- package/src/hooks/use-collection-model.ts +0 -60
- package/src/hooks/use-collection-widget.ts +0 -47
- package/src/hooks/use-drop-down-selection.ts +0 -52
- package/src/hooks/use-expansion-model.ts +0 -82
- package/src/hooks/use-header-menu.ts +0 -34
- package/src/hooks/use-installed-model.ts +0 -20
- package/src/hooks/use-list-model.ts +0 -161
- package/src/hooks/use-placed-child.ts +0 -79
- package/src/hooks/use-selection-model.ts +0 -114
- package/src/hooks/use-sort-handler.ts +0 -107
- package/src/menu-items.ts +0 -48
- package/src/menu.tsx +0 -32
- package/src/overlay.tsx +0 -88
- package/src/utils/cell-container-store.ts +0 -114
- package/src/utils/item-models.ts +0 -113
- package/src/utils/item-resolver.ts +0 -138
- package/src/utils/list-item-flatten.ts +0 -90
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
-
import { useObjectAttachment } from "@gtkx/react/internal";
|
|
3
|
-
import { type RefObject, useRef } from "react";
|
|
4
|
-
|
|
5
|
-
export const useInstalledModel = <W extends Gtk.Widget, M>(
|
|
6
|
-
object: RefObject<W | null>,
|
|
7
|
-
model: M,
|
|
8
|
-
install: (widget: W, model: M) => void,
|
|
9
|
-
): void => {
|
|
10
|
-
const installRef = useRef(install);
|
|
11
|
-
installRef.current = install;
|
|
12
|
-
useObjectAttachment<W, { widget: W; model: M }>(object, {
|
|
13
|
-
attach: (widget) => {
|
|
14
|
-
installRef.current(widget, model);
|
|
15
|
-
return { widget, model };
|
|
16
|
-
},
|
|
17
|
-
detach: () => {},
|
|
18
|
-
isSame: (attachment, widget) => attachment.widget === widget && attachment.model === model,
|
|
19
|
-
});
|
|
20
|
-
};
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import type * as Gio from "@gtkx/gi/gio";
|
|
2
|
-
import type * as GObject from "@gtkx/gi/gobject";
|
|
3
|
-
import type * as Gtk from "@gtkx/gi/gtk";
|
|
4
|
-
import { useLayoutEffect, useMemo, useRef } from "react";
|
|
5
|
-
import type { ItemNode, SectionNode } from "../types.js";
|
|
6
|
-
import {
|
|
7
|
-
createFlatModel,
|
|
8
|
-
createSectionModel,
|
|
9
|
-
createTreeModel,
|
|
10
|
-
resizeFlatModel,
|
|
11
|
-
retagRows,
|
|
12
|
-
} from "../utils/item-models.js";
|
|
13
|
-
import {
|
|
14
|
-
createItemResolver,
|
|
15
|
-
createSectionHeaderResolver,
|
|
16
|
-
createTreeResolver,
|
|
17
|
-
type ItemResolver,
|
|
18
|
-
type RowValue,
|
|
19
|
-
} from "../utils/item-resolver.js";
|
|
20
|
-
import { detectStructure, type ListStructure, structuralSignature } from "../utils/list-item-flatten.js";
|
|
21
|
-
|
|
22
|
-
type ListModelInput<T, S> = {
|
|
23
|
-
items: ItemNode<T>[] | undefined;
|
|
24
|
-
sections?: SectionNode<S, T>[] | undefined;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
type ListModelResult<T, S> = {
|
|
28
|
-
model: Gio.ListModel;
|
|
29
|
-
treeModel: Gtk.TreeListModel | null;
|
|
30
|
-
resolver: ItemResolver<T, S>;
|
|
31
|
-
headerResolver: ItemResolver<T, S>;
|
|
32
|
-
rowValues: WeakMap<GObject.Object, RowValue<T>>;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
type ListModelStructure = "sections" | ListStructure;
|
|
36
|
-
|
|
37
|
-
type ListModelState<T, S> = {
|
|
38
|
-
model: Gio.ListModel;
|
|
39
|
-
treeModel: Gtk.TreeListModel | null;
|
|
40
|
-
flatModel: Gtk.StringList | undefined;
|
|
41
|
-
items: ItemNode<T>[] | undefined;
|
|
42
|
-
sections: SectionNode<S, T>[] | undefined;
|
|
43
|
-
structure: ListModelStructure;
|
|
44
|
-
signature: string;
|
|
45
|
-
rowValues: WeakMap<GObject.Object, RowValue<T>>;
|
|
46
|
-
placeholdersById: Map<string, GObject.Object>;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const sectionRows = <T, S>(sections: SectionNode<S, T>[] | undefined): ItemNode<T>[] => {
|
|
50
|
-
if (sections === undefined) return [];
|
|
51
|
-
const rows: ItemNode<T>[] = [];
|
|
52
|
-
for (const section of sections) rows.push(...section.data);
|
|
53
|
-
return rows;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const sectionSignature = <T, S>(sections: SectionNode<S, T>[] | undefined): string => {
|
|
57
|
-
if (sections === undefined) return "";
|
|
58
|
-
const parts: string[] = [];
|
|
59
|
-
for (const section of sections) {
|
|
60
|
-
parts.push(`${section.id}{${structuralSignature(section.data)}}`);
|
|
61
|
-
}
|
|
62
|
-
return parts.join(",");
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const signatureOf = <T, S>(
|
|
66
|
-
structure: ListModelStructure,
|
|
67
|
-
items: ItemNode<T>[] | undefined,
|
|
68
|
-
sections: SectionNode<S, T>[] | undefined,
|
|
69
|
-
): string => {
|
|
70
|
-
if (structure === "sections") return `sections|${sectionSignature(sections)}`;
|
|
71
|
-
return structure === "flat" ? "" : `${structure}|${structuralSignature(items)}`;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
type ListModelInternalInput<T, S> = {
|
|
75
|
-
items: ItemNode<T>[] | undefined;
|
|
76
|
-
sections: SectionNode<S, T>[] | undefined;
|
|
77
|
-
structure: ListModelStructure;
|
|
78
|
-
signature: string;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const buildState = <T, S>(input: ListModelInternalInput<T, S>): ListModelState<T, S> => {
|
|
82
|
-
const { items, sections, structure, signature } = input;
|
|
83
|
-
const rowValues = new WeakMap<GObject.Object, RowValue<T>>();
|
|
84
|
-
const placeholdersById = new Map<string, GObject.Object>();
|
|
85
|
-
let model: Gio.ListModel;
|
|
86
|
-
let treeModel: Gtk.TreeListModel | null = null;
|
|
87
|
-
let flatModel: Gtk.StringList | undefined;
|
|
88
|
-
if (structure === "sections") {
|
|
89
|
-
model = createSectionModel(sections ?? []);
|
|
90
|
-
} else if (structure === "tree") {
|
|
91
|
-
treeModel = createTreeModel(items ?? [], rowValues, placeholdersById);
|
|
92
|
-
model = treeModel;
|
|
93
|
-
} else {
|
|
94
|
-
flatModel = createFlatModel(items?.length ?? 0);
|
|
95
|
-
model = flatModel;
|
|
96
|
-
}
|
|
97
|
-
return { model, treeModel, flatModel, items, sections, structure, signature, rowValues, placeholdersById };
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const resolveState = <T, S>(
|
|
101
|
-
prev: ListModelState<T, S> | null,
|
|
102
|
-
items: ItemNode<T>[] | undefined,
|
|
103
|
-
sections: SectionNode<S, T>[] | undefined,
|
|
104
|
-
): ListModelState<T, S> => {
|
|
105
|
-
if (prev !== null && prev.items === items && prev.sections === sections) {
|
|
106
|
-
return prev;
|
|
107
|
-
}
|
|
108
|
-
const structure: ListModelStructure = sections !== undefined ? "sections" : detectStructure(items);
|
|
109
|
-
const signature = signatureOf(structure, items, sections);
|
|
110
|
-
const input: ListModelInternalInput<T, S> = { items, sections, structure, signature };
|
|
111
|
-
if (prev === null || prev.structure !== structure) {
|
|
112
|
-
return buildState(input);
|
|
113
|
-
}
|
|
114
|
-
if (structure !== "flat" && prev.signature !== signature) {
|
|
115
|
-
return buildState(input);
|
|
116
|
-
}
|
|
117
|
-
if (structure === "tree") {
|
|
118
|
-
retagRows(items ?? [], prev.rowValues, prev.placeholdersById);
|
|
119
|
-
}
|
|
120
|
-
prev.items = items;
|
|
121
|
-
prev.sections = sections;
|
|
122
|
-
prev.signature = signature;
|
|
123
|
-
return prev;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
export const useListModel = <T, S>(input: ListModelInput<T, S>): ListModelResult<T, S> => {
|
|
127
|
-
const { items, sections } = input;
|
|
128
|
-
const stateRef = useRef<ListModelState<T, S> | null>(null);
|
|
129
|
-
const state = resolveState(stateRef.current, items, sections);
|
|
130
|
-
stateRef.current = state;
|
|
131
|
-
const { structure, flatModel } = state;
|
|
132
|
-
|
|
133
|
-
useLayoutEffect(() => {
|
|
134
|
-
if (flatModel !== undefined) {
|
|
135
|
-
resizeFlatModel(flatModel, items?.length ?? 0);
|
|
136
|
-
}
|
|
137
|
-
}, [flatModel, items]);
|
|
138
|
-
|
|
139
|
-
const resolver = useMemo(() => {
|
|
140
|
-
if (structure === "sections") {
|
|
141
|
-
return createItemResolver<T, S>(sectionRows(sections), true, state.rowValues);
|
|
142
|
-
}
|
|
143
|
-
if (structure === "tree" && state.treeModel !== null) {
|
|
144
|
-
return createTreeResolver<T, S>(items, state.rowValues, state.treeModel);
|
|
145
|
-
}
|
|
146
|
-
return createItemResolver<T, S>(items, false, state.rowValues);
|
|
147
|
-
}, [items, sections, structure, state.rowValues, state.treeModel]);
|
|
148
|
-
|
|
149
|
-
const headerResolver = useMemo(
|
|
150
|
-
() => createSectionHeaderResolver<T, S>(structure === "sections" ? sections : undefined),
|
|
151
|
-
[sections, structure],
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
model: state.model,
|
|
156
|
-
treeModel: state.treeModel,
|
|
157
|
-
resolver,
|
|
158
|
-
headerResolver,
|
|
159
|
-
rowValues: state.rowValues,
|
|
160
|
-
};
|
|
161
|
-
};
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import type * as GObject from "@gtkx/gi/gobject";
|
|
2
|
-
import { createPortal, rootElement } from "@gtkx/react";
|
|
3
|
-
import { useMergeRefs } from "@gtkx/react/internal";
|
|
4
|
-
import {
|
|
5
|
-
type Context,
|
|
6
|
-
createContext,
|
|
7
|
-
type ReactNode,
|
|
8
|
-
type Ref,
|
|
9
|
-
type RefCallback,
|
|
10
|
-
type RefObject,
|
|
11
|
-
useCallback,
|
|
12
|
-
useContext,
|
|
13
|
-
useLayoutEffect,
|
|
14
|
-
useRef,
|
|
15
|
-
} from "react";
|
|
16
|
-
|
|
17
|
-
export type ParentContext<T> = {
|
|
18
|
-
Context: Context<RefObject<T | null> | null>;
|
|
19
|
-
useParentRef: () => RefObject<T | null>;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const createParentContext = <T>(orphanMessage: string): ParentContext<T> => {
|
|
23
|
-
const context = createContext<RefObject<T | null> | null>(null);
|
|
24
|
-
return {
|
|
25
|
-
Context: context,
|
|
26
|
-
useParentRef: (): RefObject<T | null> => {
|
|
27
|
-
const ref = useContext(context);
|
|
28
|
-
if (!ref) throw new Error(orphanMessage);
|
|
29
|
-
return ref;
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export type PlacedChildRender<T> = (ref: RefCallback<T>) => ReactNode;
|
|
35
|
-
|
|
36
|
-
export type PlacedChildOptions<T extends GObject.Object, P> = {
|
|
37
|
-
render: PlacedChildRender<T>;
|
|
38
|
-
ref?: Ref<T | null> | undefined;
|
|
39
|
-
placement: P;
|
|
40
|
-
samePlacement: (a: P, b: P) => boolean;
|
|
41
|
-
place: (object: T, placement: P, previous: P | undefined) => void;
|
|
42
|
-
release: (object: T) => void;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export const usePlacedChild = <T extends GObject.Object, P>(options: PlacedChildOptions<T, P>): ReactNode => {
|
|
46
|
-
const { render, ref, placement, samePlacement, place, release } = options;
|
|
47
|
-
const objectRef = useRef<T | null>(null);
|
|
48
|
-
const appliedRef = useRef<{ object: T; placement: P } | null>(null);
|
|
49
|
-
const captureObject = useCallback<RefCallback<T>>((object) => {
|
|
50
|
-
objectRef.current = object;
|
|
51
|
-
}, []);
|
|
52
|
-
const setObjectRef = useMergeRefs<T>(ref, captureObject);
|
|
53
|
-
|
|
54
|
-
useLayoutEffect(() => {
|
|
55
|
-
const object = objectRef.current;
|
|
56
|
-
const applied = appliedRef.current;
|
|
57
|
-
if (applied !== null && applied.object !== object) {
|
|
58
|
-
release(applied.object);
|
|
59
|
-
appliedRef.current = null;
|
|
60
|
-
}
|
|
61
|
-
if (object === null) return;
|
|
62
|
-
const current = appliedRef.current;
|
|
63
|
-
if (current === null || !samePlacement(current.placement, placement)) {
|
|
64
|
-
place(object, placement, current?.placement);
|
|
65
|
-
appliedRef.current = { object, placement };
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
useLayoutEffect(
|
|
70
|
-
() => () => {
|
|
71
|
-
const applied = appliedRef.current;
|
|
72
|
-
if (applied !== null) release(applied.object);
|
|
73
|
-
appliedRef.current = null;
|
|
74
|
-
},
|
|
75
|
-
[],
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
return createPortal(render(setObjectRef), rootElement);
|
|
79
|
-
};
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import type * as Gio from "@gtkx/gi/gio";
|
|
2
|
-
import * as Gtk from "@gtkx/gi/gtk";
|
|
3
|
-
import { useSignal } from "@gtkx/react";
|
|
4
|
-
import { isSameArray } from "@gtkx/utils";
|
|
5
|
-
import { useLayoutEffect, useRef } from "react";
|
|
6
|
-
import type { ItemResolver } from "../utils/item-resolver.js";
|
|
7
|
-
|
|
8
|
-
type SelectionModelOptions<T, S> = {
|
|
9
|
-
base: Gio.ListModel;
|
|
10
|
-
selectionMode: Gtk.SelectionMode | null | undefined;
|
|
11
|
-
selectedIds: string[] | null | undefined;
|
|
12
|
-
onSelectionChanged: ((ids: string[]) => void) | null | undefined;
|
|
13
|
-
resolver: ItemResolver<T, S>;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
type WrappingSelectionModel = (Gtk.SingleSelection | Gtk.MultiSelection | Gtk.NoSelection) & Gtk.SelectionModel;
|
|
17
|
-
|
|
18
|
-
const createSelectionModel = (mode: Gtk.SelectionMode, base: Gio.ListModel): WrappingSelectionModel => {
|
|
19
|
-
if (mode === Gtk.SelectionMode.MULTIPLE) return Gtk.MultiSelection.new(base);
|
|
20
|
-
if (mode === Gtk.SelectionMode.NONE) return Gtk.NoSelection.new(base);
|
|
21
|
-
return new Gtk.SingleSelection({ model: base, autoselect: false, canUnselect: true });
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const bitsetOf = (positions: number[]): Gtk.Bitset => {
|
|
25
|
-
const bitset = Gtk.Bitset.newEmpty();
|
|
26
|
-
for (const position of positions) {
|
|
27
|
-
if (position >= 0) bitset.add(position);
|
|
28
|
-
}
|
|
29
|
-
return bitset;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const applySelectedPositions = (model: Gtk.SelectionModel, positions: number[]): void => {
|
|
33
|
-
if (model instanceof Gtk.MultiSelection) {
|
|
34
|
-
if (positions.length === 0) {
|
|
35
|
-
const current = model.getSelection();
|
|
36
|
-
if (!current.isEmpty()) model.unselectAll();
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const requested = bitsetOf(positions);
|
|
40
|
-
const changed = model.getSelection().copy();
|
|
41
|
-
changed.difference(requested);
|
|
42
|
-
if (changed.isEmpty()) return;
|
|
43
|
-
model.setSelection(requested, changed);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (positions.length === 0) {
|
|
47
|
-
model.unselectAll();
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
const first = positions[0];
|
|
51
|
-
if (first !== undefined && first >= 0) model.selectItem(first, true);
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const readSelectedIds = <T, S>(model: Gtk.SelectionModel, resolver: ItemResolver<T, S>): string[] => {
|
|
55
|
-
const selection = model.getSelection();
|
|
56
|
-
const ids: string[] = [];
|
|
57
|
-
const count = Number(selection.getSize());
|
|
58
|
-
for (let index = 0; index < count; index++) {
|
|
59
|
-
const position = selection.getNth(index);
|
|
60
|
-
const id = resolver.idOf(position);
|
|
61
|
-
if (id !== undefined) ids.push(id);
|
|
62
|
-
}
|
|
63
|
-
return ids;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const idsToPositions = <T, S>(ids: string[] | null | undefined, resolver: ItemResolver<T, S>): number[] => {
|
|
67
|
-
if (ids === undefined || ids === null) return [];
|
|
68
|
-
const positions: number[] = [];
|
|
69
|
-
for (const id of ids) {
|
|
70
|
-
const position = resolver.positionOfId(id);
|
|
71
|
-
if (position >= 0) positions.push(position);
|
|
72
|
-
}
|
|
73
|
-
return positions;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
export const useSelectionModel = <T, S>(options: SelectionModelOptions<T, S>): Gtk.SelectionModel => {
|
|
77
|
-
const { base, selectionMode, selectedIds, onSelectionChanged, resolver } = options;
|
|
78
|
-
const mode = selectionMode ?? Gtk.SelectionMode.SINGLE;
|
|
79
|
-
|
|
80
|
-
const modelRef = useRef<WrappingSelectionModel | null>(null);
|
|
81
|
-
const modeRef = useRef<Gtk.SelectionMode | null>(null);
|
|
82
|
-
if (modelRef.current === null || modeRef.current !== mode) {
|
|
83
|
-
modelRef.current = createSelectionModel(mode, base);
|
|
84
|
-
modeRef.current = mode;
|
|
85
|
-
}
|
|
86
|
-
const model = modelRef.current;
|
|
87
|
-
|
|
88
|
-
const onChangedRef = useRef(onSelectionChanged);
|
|
89
|
-
onChangedRef.current = onSelectionChanged;
|
|
90
|
-
const resolverRef = useRef(resolver);
|
|
91
|
-
resolverRef.current = resolver;
|
|
92
|
-
const lastReportedRef = useRef<string[] | null>(null);
|
|
93
|
-
|
|
94
|
-
const report = (): void => {
|
|
95
|
-
const callback = onChangedRef.current;
|
|
96
|
-
if (!callback) return;
|
|
97
|
-
const ids = readSelectedIds(model, resolverRef.current);
|
|
98
|
-
if (lastReportedRef.current !== null && isSameArray(lastReportedRef.current, ids)) return;
|
|
99
|
-
lastReportedRef.current = ids;
|
|
100
|
-
callback(ids);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
useSignal(model, "selection-changed", report);
|
|
104
|
-
|
|
105
|
-
useLayoutEffect(() => {
|
|
106
|
-
if (model.getModel() !== base) model.setModel(base);
|
|
107
|
-
if (selectedIds !== undefined && selectedIds !== null) {
|
|
108
|
-
applySelectedPositions(model, idsToPositions(selectedIds, resolver));
|
|
109
|
-
}
|
|
110
|
-
report();
|
|
111
|
-
}, [model, base, selectedIds, resolver]);
|
|
112
|
-
|
|
113
|
-
return model;
|
|
114
|
-
};
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
-
import { type ObjectProp, resolveObjectProp } from "@gtkx/react/internal";
|
|
3
|
-
import { useLayoutEffect, useRef } from "react";
|
|
4
|
-
|
|
5
|
-
export type ColumnRegistration = {
|
|
6
|
-
id: string;
|
|
7
|
-
column: Gtk.ColumnViewColumn;
|
|
8
|
-
sortable: boolean;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
type SortHandlerOptions = {
|
|
12
|
-
columnView: ObjectProp<Gtk.ColumnView>;
|
|
13
|
-
sortColumn: string | null | undefined;
|
|
14
|
-
sortOrder: Gtk.SortType | null | undefined;
|
|
15
|
-
onSortChanged: ((column: string | null, order: Gtk.SortType) => void) | null | undefined;
|
|
16
|
-
columns: ColumnRegistration[];
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const neutralSorter = (): Gtk.CustomSorter => Gtk.CustomSorter.new(() => 0);
|
|
20
|
-
|
|
21
|
-
const ensureColumnSorters = (columns: ColumnRegistration[], activeId: string | null): void => {
|
|
22
|
-
for (const registration of columns) {
|
|
23
|
-
const wantsSorter = registration.sortable || registration.id === activeId;
|
|
24
|
-
const hasSorter = registration.column.getSorter() !== null;
|
|
25
|
-
if (wantsSorter && !hasSorter) {
|
|
26
|
-
registration.column.setSorter(neutralSorter());
|
|
27
|
-
} else if (!wantsSorter && hasSorter) {
|
|
28
|
-
registration.column.setSorter(null);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const columnForId = (columns: ColumnRegistration[], id: string | null): Gtk.ColumnViewColumn | null => {
|
|
34
|
-
if (id === null) return null;
|
|
35
|
-
for (const registration of columns) {
|
|
36
|
-
if (registration.id === id) return registration.column;
|
|
37
|
-
}
|
|
38
|
-
return null;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const idForColumn = (columns: ColumnRegistration[], column: Gtk.ColumnViewColumn | null): string | null => {
|
|
42
|
-
if (column === null) return null;
|
|
43
|
-
for (const registration of columns) {
|
|
44
|
-
if (registration.column === column) return registration.id;
|
|
45
|
-
}
|
|
46
|
-
return column.getId();
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const primarySort = (sorter: Gtk.Sorter): { column: Gtk.ColumnViewColumn | null; order: Gtk.SortType } =>
|
|
50
|
-
sorter instanceof Gtk.ColumnViewSorter
|
|
51
|
-
? { column: sorter.getPrimarySortColumn(), order: sorter.getPrimarySortOrder() }
|
|
52
|
-
: { column: null, order: Gtk.SortType.ASCENDING };
|
|
53
|
-
|
|
54
|
-
type SorterSubscription = {
|
|
55
|
-
sorter: Gtk.Sorter | null;
|
|
56
|
-
handler: ((change: Gtk.SorterChange) => void) | null;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const disconnectSorter = (subscription: SorterSubscription): void => {
|
|
60
|
-
if (subscription.sorter !== null && subscription.handler !== null) {
|
|
61
|
-
subscription.sorter.off("changed", subscription.handler);
|
|
62
|
-
}
|
|
63
|
-
subscription.sorter = null;
|
|
64
|
-
subscription.handler = null;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export const useSortHandler = (options: SortHandlerOptions): void => {
|
|
68
|
-
const { columnView, sortColumn, sortOrder, onSortChanged, columns } = options;
|
|
69
|
-
const activeId = sortColumn ?? null;
|
|
70
|
-
const order = sortOrder ?? Gtk.SortType.ASCENDING;
|
|
71
|
-
|
|
72
|
-
const onChangedRef = useRef(onSortChanged);
|
|
73
|
-
onChangedRef.current = onSortChanged;
|
|
74
|
-
const columnsRef = useRef(columns);
|
|
75
|
-
columnsRef.current = columns;
|
|
76
|
-
const suppressRef = useRef(false);
|
|
77
|
-
const subscriptionRef = useRef<SorterSubscription>({ sorter: null, handler: null });
|
|
78
|
-
|
|
79
|
-
const resubscribe = (sorter: Gtk.Sorter | null): void => {
|
|
80
|
-
const subscription = subscriptionRef.current;
|
|
81
|
-
if (sorter === subscription.sorter) return;
|
|
82
|
-
disconnectSorter(subscription);
|
|
83
|
-
if (sorter === null) return;
|
|
84
|
-
const handler = (): void => {
|
|
85
|
-
if (suppressRef.current) return;
|
|
86
|
-
const callback = onChangedRef.current;
|
|
87
|
-
if (!callback) return;
|
|
88
|
-
const { column, order: primaryOrder } = primarySort(sorter);
|
|
89
|
-
callback(idForColumn(columnsRef.current, column), primaryOrder);
|
|
90
|
-
};
|
|
91
|
-
subscription.sorter = sorter;
|
|
92
|
-
subscription.handler = handler;
|
|
93
|
-
sorter.on("changed", handler);
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
useLayoutEffect(() => {
|
|
97
|
-
const view = resolveObjectProp(columnView);
|
|
98
|
-
if (view === null) return;
|
|
99
|
-
ensureColumnSorters(columns, activeId);
|
|
100
|
-
suppressRef.current = true;
|
|
101
|
-
view.sortByColumn(columnForId(columns, activeId), order);
|
|
102
|
-
suppressRef.current = false;
|
|
103
|
-
resubscribe(view.getSorter());
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
useLayoutEffect(() => () => disconnectSorter(subscriptionRef.current), []);
|
|
107
|
-
};
|
package/src/menu-items.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import * as Gio from "@gtkx/gi/gio";
|
|
2
|
-
import type { MenuEntry } from "./types.js";
|
|
3
|
-
|
|
4
|
-
const buildMenuModel = (entries: MenuEntry[]): Gio.Menu => {
|
|
5
|
-
const menu = new Gio.Menu();
|
|
6
|
-
appendEntries(menu, entries);
|
|
7
|
-
return menu;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const appendEntries = (menu: Gio.Menu, entries: MenuEntry[]): void => {
|
|
11
|
-
for (const entry of entries) {
|
|
12
|
-
if (entry.section !== undefined) {
|
|
13
|
-
menu.appendSection(entry.label ?? null, buildMenuModel(entry.section));
|
|
14
|
-
continue;
|
|
15
|
-
}
|
|
16
|
-
if (entry.submenu !== undefined) {
|
|
17
|
-
menu.appendSubmenu(entry.label ?? null, buildMenuModel(entry.submenu));
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
const item = new Gio.MenuItem();
|
|
21
|
-
if (entry.label !== undefined) item.setLabel(entry.label);
|
|
22
|
-
if (entry.action !== undefined) item.setDetailedAction(entry.action);
|
|
23
|
-
menu.appendItem(item);
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const applyMenuItems = (menu: Gio.Menu, entries: MenuEntry[] | null): void => {
|
|
28
|
-
menu.removeAll();
|
|
29
|
-
if (entries) appendEntries(menu, entries);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const entryEqual = (a: MenuEntry, b: MenuEntry): boolean =>
|
|
33
|
-
a.label === b.label &&
|
|
34
|
-
a.action === b.action &&
|
|
35
|
-
entryListEqual(a.submenu, b.submenu) &&
|
|
36
|
-
entryListEqual(a.section, b.section);
|
|
37
|
-
|
|
38
|
-
const entryListEqual = (a: MenuEntry[] | undefined, b: MenuEntry[] | undefined): boolean => {
|
|
39
|
-
if (a === b) return true;
|
|
40
|
-
if (a === undefined || b === undefined) return false;
|
|
41
|
-
return a.length === b.length && a.every((entry, index) => entryEqual(entry, b[index] as MenuEntry));
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const menuItemsEqual = (a: MenuEntry[] | null, b: MenuEntry[] | null): boolean => {
|
|
45
|
-
if (a === b) return true;
|
|
46
|
-
if (a === null || b === null) return false;
|
|
47
|
-
return entryListEqual(a, b);
|
|
48
|
-
};
|
package/src/menu.tsx
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type * as Gio from "@gtkx/gi/gio";
|
|
2
|
-
import { GMenu, type GMenuProps } from "@gtkx/jsx/gio";
|
|
3
|
-
import { useMergeRefs } from "@gtkx/react/internal";
|
|
4
|
-
import { type ReactNode, type Ref, useLayoutEffect, useRef } from "react";
|
|
5
|
-
import { applyMenuItems, menuItemsEqual } from "./menu-items.js";
|
|
6
|
-
import type { MenuEntry } from "./types.js";
|
|
7
|
-
|
|
8
|
-
export type MenuItemsProps = {
|
|
9
|
-
items?: MenuEntry[] | null | undefined;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
/** Props for {@link Menu}, combining Gio.Menu props with a declarative items array. */
|
|
13
|
-
export type MenuProps = Omit<GMenuProps, keyof MenuItemsProps> & MenuItemsProps & { ref?: Ref<Gio.Menu | null> };
|
|
14
|
-
|
|
15
|
-
/** Builds a Gio.Menu model from a declarative array of {@link MenuEntry} items. */
|
|
16
|
-
export const Menu = (props: MenuProps): ReactNode => {
|
|
17
|
-
const { items, ref, ...rest } = props;
|
|
18
|
-
const menuRef = useRef<Gio.Menu | null>(null);
|
|
19
|
-
const mergedRef = useMergeRefs(ref, menuRef);
|
|
20
|
-
const appliedRef = useRef<MenuEntry[] | null>(null);
|
|
21
|
-
|
|
22
|
-
useLayoutEffect(() => {
|
|
23
|
-
const menu = menuRef.current;
|
|
24
|
-
if (!menu) return;
|
|
25
|
-
const entries = items ?? null;
|
|
26
|
-
if (menuItemsEqual(appliedRef.current, entries)) return;
|
|
27
|
-
appliedRef.current = entries;
|
|
28
|
-
applyMenuItems(menu, entries);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
return <GMenu {...rest} ref={mergedRef} />;
|
|
32
|
-
};
|
package/src/overlay.tsx
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
|
-
import { GtkOverlay, type GtkOverlayProps } from "@gtkx/jsx/gtk";
|
|
3
|
-
import { useMergeRefs } from "@gtkx/react/internal";
|
|
4
|
-
import { Children, type ElementType, isValidElement, type ReactNode, type Ref, useRef } from "react";
|
|
5
|
-
import { createParentContext, usePlacedChild } from "./hooks/use-placed-child.js";
|
|
6
|
-
import type { ChildProps } from "./types.js";
|
|
7
|
-
|
|
8
|
-
const { Context: OverlayContext, useParentRef: useOverlayRef } = createParentContext<Gtk.Overlay>(
|
|
9
|
-
"<Overlay.Child> must be a child of <Overlay>",
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
/** Props for {@link Overlay}. */
|
|
13
|
-
export type OverlayProps = GtkOverlayProps & { ref?: Ref<Gtk.Overlay | null> };
|
|
14
|
-
|
|
15
|
-
export type OverlayPlacementProps = {
|
|
16
|
-
/** Whether this overlay contributes to the Overlay's measured size. */
|
|
17
|
-
measure?: boolean | null | undefined;
|
|
18
|
-
/** Whether the overlay is clipped to the main child's allocation. */
|
|
19
|
-
clipOverlay?: boolean | null | undefined;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/** Adds a single widget as an overlay on top of an {@link Overlay}'s main child. */
|
|
23
|
-
export type OverlayChildProps<C extends ElementType> = ChildProps<C, OverlayPlacementProps>;
|
|
24
|
-
|
|
25
|
-
type OverlayPlacement = { measure: boolean; clipOverlay: boolean };
|
|
26
|
-
|
|
27
|
-
const placementOf = (props: OverlayPlacementProps): OverlayPlacement => ({
|
|
28
|
-
measure: props.measure ?? false,
|
|
29
|
-
clipOverlay: props.clipOverlay ?? false,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const samePlacement = (a: OverlayPlacement, b: OverlayPlacement): boolean =>
|
|
33
|
-
a.measure === b.measure && a.clipOverlay === b.clipOverlay;
|
|
34
|
-
|
|
35
|
-
const OverlayChild = <C extends ElementType>({
|
|
36
|
-
component,
|
|
37
|
-
measure,
|
|
38
|
-
clipOverlay,
|
|
39
|
-
ref,
|
|
40
|
-
...rest
|
|
41
|
-
}: OverlayChildProps<C>): ReactNode => {
|
|
42
|
-
const overlayRef = useOverlayRef();
|
|
43
|
-
const Component: ElementType = component;
|
|
44
|
-
return usePlacedChild<Gtk.Widget, OverlayPlacement>({
|
|
45
|
-
render: (placeRef) => <Component {...rest} ref={placeRef} />,
|
|
46
|
-
ref,
|
|
47
|
-
placement: placementOf({ measure, clipOverlay }),
|
|
48
|
-
samePlacement,
|
|
49
|
-
place: (widget, placement) => {
|
|
50
|
-
const overlay = overlayRef.current;
|
|
51
|
-
if (!overlay) return;
|
|
52
|
-
if (widget.getParent() !== overlay) overlay.addOverlay(widget);
|
|
53
|
-
overlay.setMeasureOverlay(widget, placement.measure);
|
|
54
|
-
overlay.setClipOverlay(widget, placement.clipOverlay);
|
|
55
|
-
},
|
|
56
|
-
release: (widget) => {
|
|
57
|
-
const overlay = overlayRef.current;
|
|
58
|
-
if (overlay && widget.getParent() === overlay) overlay.removeOverlay(widget);
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const isOverlayChild = (node: ReactNode): boolean => isValidElement(node) && node.type === OverlayChild;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Renders a Gtk.Overlay: a main child with one or more widgets stacked on top,
|
|
67
|
-
* declared via {@link Overlay.Child}. Non-Child children form the main content.
|
|
68
|
-
*/
|
|
69
|
-
export const Overlay: ((props: OverlayProps) => ReactNode) & {
|
|
70
|
-
Child: <C extends ElementType>(props: OverlayChildProps<C>) => ReactNode;
|
|
71
|
-
} = Object.assign(
|
|
72
|
-
({ children, ref, ...rest }: OverlayProps): ReactNode => {
|
|
73
|
-
const overlayRef = useRef<Gtk.Overlay | null>(null);
|
|
74
|
-
const mergedRef = useMergeRefs<Gtk.Overlay>(ref, overlayRef);
|
|
75
|
-
const items = Children.toArray(children);
|
|
76
|
-
const overlays = items.filter(isOverlayChild);
|
|
77
|
-
const base = items.filter((node) => !isOverlayChild(node));
|
|
78
|
-
return (
|
|
79
|
-
<>
|
|
80
|
-
<GtkOverlay {...rest} ref={mergedRef}>
|
|
81
|
-
{base}
|
|
82
|
-
</GtkOverlay>
|
|
83
|
-
<OverlayContext.Provider value={overlayRef}>{overlays}</OverlayContext.Provider>
|
|
84
|
-
</>
|
|
85
|
-
);
|
|
86
|
-
},
|
|
87
|
-
{ Child: OverlayChild },
|
|
88
|
-
);
|