@gtkx/components 1.0.0-rc.2 → 1.0.0-rc.4
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 +4 -5
- package/dist/adw/combo-row.d.ts +12 -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 +2 -1
- package/dist/adw/index.d.ts.map +1 -1
- package/dist/adw/index.js +1 -0
- package/dist/adw/index.js.map +1 -1
- package/dist/adw/types.d.ts +11 -3
- package/dist/adw/types.d.ts.map +1 -1
- package/dist/adw/types.js.map +1 -1
- package/dist/column-view.d.ts.map +1 -1
- package/dist/column-view.js +4 -4
- package/dist/column-view.js.map +1 -1
- package/dist/drop-down.d.ts +4 -5
- package/dist/drop-down.d.ts.map +1 -1
- package/dist/drop-down.js +5 -112
- package/dist/drop-down.js.map +1 -1
- package/dist/grid-view.js +1 -1
- package/dist/grid-view.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/cells.d.ts +3 -3
- package/dist/internal/cells.d.ts.map +1 -1
- package/dist/internal/cells.js.map +1 -1
- package/dist/internal/collection-index.d.ts +5 -5
- package/dist/internal/collection-index.d.ts.map +1 -1
- package/dist/internal/collection-index.js +3 -3
- package/dist/internal/collection-index.js.map +1 -1
- package/dist/internal/collection-model.d.ts.map +1 -1
- package/dist/internal/collection-model.js +2 -5
- package/dist/internal/collection-model.js.map +1 -1
- package/dist/internal/collection.d.ts +2 -2
- package/dist/internal/collection.d.ts.map +1 -1
- package/dist/internal/collection.js.map +1 -1
- 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 +1 -1
- package/dist/internal/expansion.d.ts.map +1 -1
- package/dist/internal/expansion.js +3 -4
- package/dist/internal/expansion.js.map +1 -1
- package/dist/internal/selection.d.ts +1 -0
- package/dist/internal/selection.d.ts.map +1 -1
- package/dist/internal/selection.js +1 -0
- package/dist/internal/selection.js.map +1 -1
- package/dist/internal/use-collection.d.ts +5 -6
- package/dist/internal/use-collection.d.ts.map +1 -1
- package/dist/internal/use-collection.js +10 -18
- package/dist/internal/use-collection.js.map +1 -1
- package/dist/types.d.ts +70 -48
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +7 -7
- package/src/adw/combo-row.tsx +21 -0
- package/src/adw/index.ts +8 -1
- package/src/adw/types.ts +17 -3
- package/src/column-view.tsx +13 -13
- package/src/drop-down.tsx +10 -195
- package/src/grid-view.tsx +1 -1
- package/src/index.ts +7 -12
- package/src/internal/cells.tsx +12 -12
- package/src/internal/collection-index.ts +16 -16
- package/src/internal/collection-model.ts +2 -5
- package/src/internal/collection.ts +2 -2
- package/src/internal/drop-down.tsx +186 -0
- package/src/internal/expansion.ts +5 -6
- package/src/internal/selection.tsx +3 -0
- package/src/internal/use-collection.tsx +16 -29
- package/src/types.ts +83 -66
- package/dist/size-group.d.ts +0 -12
- package/dist/size-group.d.ts.map +0 -1
- package/dist/size-group.js +0 -41
- package/dist/size-group.js.map +0 -1
- package/src/size-group.tsx +0 -77
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type * as GObject from "@gtkx/gi/gobject";
|
|
2
|
+
import type { ElementType, ReactNode, Ref } from "react";
|
|
3
|
+
import { GtkLabel, GtkSignalListItemFactory } from "@gtkx/jsx/gtk";
|
|
4
|
+
import { applyWrite } from "@gtkx/react/internal";
|
|
5
|
+
import { omit } from "@gtkx/utils";
|
|
6
|
+
import { useEffectEvent, useLayoutEffect, useRef } from "react";
|
|
7
|
+
import type { DropDownOwnProps, ListItemRenderArgs, ListItemRenderer } from "../types.js";
|
|
8
|
+
import type { Collection } from "./collection.js";
|
|
9
|
+
import { HeaderPortals, ItemPortals, useHeaderCells, useItemCells } from "./cells.js";
|
|
10
|
+
import { useCollectionData } from "./use-collection.js";
|
|
11
|
+
import { useWidgetRef } from "./use-widget-ref.js";
|
|
12
|
+
|
|
13
|
+
type SelectableWidget = GObject.Object & { getSelected: () => number; selected: number };
|
|
14
|
+
|
|
15
|
+
type DropDownBaseProps = DropDownOwnProps<unknown, unknown> & {
|
|
16
|
+
onNotifySelected?: ((value: number | null, self: SelectableWidget) => void) | null | undefined;
|
|
17
|
+
ref?: Ref<SelectableWidget | null> | undefined;
|
|
18
|
+
} & Record<string, unknown>;
|
|
19
|
+
|
|
20
|
+
type SelectionOptions = {
|
|
21
|
+
widget: SelectableWidget | null;
|
|
22
|
+
collection: Collection;
|
|
23
|
+
props: DropDownBaseProps;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type NotifySelectedHandler = NonNullable<DropDownBaseProps["onNotifySelected"]>;
|
|
27
|
+
|
|
28
|
+
type KnownSelection = {
|
|
29
|
+
known: { current: string | null };
|
|
30
|
+
onSelectionChanged: ((id: string) => void) | null | undefined;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const DROP_DOWN_PROPS: string[] = [
|
|
34
|
+
"component",
|
|
35
|
+
"items",
|
|
36
|
+
"sections",
|
|
37
|
+
"selectedId",
|
|
38
|
+
"onSelectionChanged",
|
|
39
|
+
"onNotifySelected",
|
|
40
|
+
"renderItem",
|
|
41
|
+
"renderListItem",
|
|
42
|
+
"renderHeader",
|
|
43
|
+
"ref",
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const describeValue = (value: unknown): string => {
|
|
47
|
+
if (typeof value === "string") {
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
return JSON.stringify(value);
|
|
53
|
+
} catch {
|
|
54
|
+
return String(value);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const defaultItemContent = (value: unknown): ReactNode =>
|
|
59
|
+
value == null ? null : <GtkLabel>{describeValue(value)}</GtkLabel>;
|
|
60
|
+
|
|
61
|
+
const defaultRenderItem = ({ item }: ListItemRenderArgs<unknown>): ReactNode => defaultItemContent(item);
|
|
62
|
+
const faceRenderer = (props: DropDownBaseProps): ListItemRenderer<never> => props.renderItem ?? defaultRenderItem;
|
|
63
|
+
|
|
64
|
+
const listRenderer = (props: DropDownBaseProps): ListItemRenderer<never> =>
|
|
65
|
+
props.renderListItem ?? props.renderItem ?? defaultRenderItem;
|
|
66
|
+
|
|
67
|
+
const resolvePosition = (
|
|
68
|
+
widget: SelectableWidget,
|
|
69
|
+
collection: Collection,
|
|
70
|
+
selectedId: string | null | undefined,
|
|
71
|
+
): number => {
|
|
72
|
+
const requested = selectedId == null ? -1 : collection.positionFor(selectedId);
|
|
73
|
+
|
|
74
|
+
return requested >= 0 ? requested : widget.getSelected();
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const updateKnownSelection = (
|
|
78
|
+
tracker: KnownSelection,
|
|
79
|
+
effectiveId: string,
|
|
80
|
+
selectedId: string | null | undefined,
|
|
81
|
+
): void => {
|
|
82
|
+
const { known, onSelectionChanged } = tracker;
|
|
83
|
+
const expectedId = selectedId ?? known.current;
|
|
84
|
+
const isNew = effectiveId !== known.current;
|
|
85
|
+
known.current = effectiveId;
|
|
86
|
+
|
|
87
|
+
if (expectedId !== null && effectiveId !== expectedId && isNew) {
|
|
88
|
+
onSelectionChanged?.(effectiveId);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const reportKnownSelection = (tracker: KnownSelection, id: string | null): void => {
|
|
93
|
+
const { known, onSelectionChanged } = tracker;
|
|
94
|
+
|
|
95
|
+
if (id === null || id === known.current) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
known.current = id;
|
|
100
|
+
onSelectionChanged?.(id);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const reportSelectedNotify = (options: SelectionOptions, tracker: KnownSelection): void => {
|
|
104
|
+
const { widget, collection } = options;
|
|
105
|
+
|
|
106
|
+
if (widget === null) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
reportKnownSelection(tracker, collection.idAt(widget.getSelected()));
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const applySelectedPosition = (widget: SelectableWidget, position: number): void => {
|
|
114
|
+
applyWrite(() => {
|
|
115
|
+
widget.selected = position;
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const useDropDownSelection = (options: SelectionOptions): NotifySelectedHandler => {
|
|
120
|
+
const { widget, collection } = options;
|
|
121
|
+
const { selectedId } = options.props;
|
|
122
|
+
const known = useRef<string | null>(null);
|
|
123
|
+
|
|
124
|
+
const syncKnownSelection = useEffectEvent((position: number): void => {
|
|
125
|
+
const effectiveId = collection.idAt(position);
|
|
126
|
+
|
|
127
|
+
if (effectiveId === null) {
|
|
128
|
+
known.current = null;
|
|
129
|
+
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const { onSelectionChanged } = options.props;
|
|
134
|
+
updateKnownSelection({ known, onSelectionChanged }, effectiveId, selectedId);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
useLayoutEffect(() => {
|
|
138
|
+
if (widget === null) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const position = resolvePosition(widget, collection, selectedId);
|
|
143
|
+
applySelectedPosition(widget, position);
|
|
144
|
+
syncKnownSelection(position);
|
|
145
|
+
}, [widget, collection, selectedId]);
|
|
146
|
+
|
|
147
|
+
return (value, self) => {
|
|
148
|
+
reportSelectedNotify(options, { known, onSelectionChanged: options.props.onSelectionChanged });
|
|
149
|
+
options.props.onNotifySelected?.(value, self);
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
function DropDownBase(props: DropDownBaseProps & { component: ElementType }): ReactNode {
|
|
154
|
+
const { component: Component, items, sections, renderListItem, renderHeader, ref } = props;
|
|
155
|
+
const rest = omit(props, DROP_DOWN_PROPS);
|
|
156
|
+
const [widget, refCallback] = useWidgetRef<SelectableWidget>(ref);
|
|
157
|
+
const collection = useCollectionData({ items, sections });
|
|
158
|
+
const faceCells = useItemCells({ width: -1, height: -1 });
|
|
159
|
+
const listCells = useItemCells({ width: -1, height: -1 });
|
|
160
|
+
const headerCells = useHeaderCells({ width: -1, height: -1 });
|
|
161
|
+
const handleNotifySelected = useDropDownSelection({ widget, collection, props });
|
|
162
|
+
const hasHeader = typeof renderHeader === "function";
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<>
|
|
166
|
+
<Component
|
|
167
|
+
ref={refCallback}
|
|
168
|
+
model={collection.model}
|
|
169
|
+
factory={<GtkSignalListItemFactory {...faceCells.handlers} />}
|
|
170
|
+
{...(renderListItem != null && {
|
|
171
|
+
listFactory: <GtkSignalListItemFactory {...listCells.handlers} />,
|
|
172
|
+
})}
|
|
173
|
+
{...(hasHeader && { headerFactory: <GtkSignalListItemFactory {...headerCells.handlers} /> })}
|
|
174
|
+
{...rest}
|
|
175
|
+
onNotifySelected={handleNotifySelected}
|
|
176
|
+
/>
|
|
177
|
+
<ItemPortals store={faceCells} render={faceRenderer(props)} collection={collection} />
|
|
178
|
+
{renderListItem != null && (
|
|
179
|
+
<ItemPortals store={listCells} render={listRenderer(props)} collection={collection} />
|
|
180
|
+
)}
|
|
181
|
+
{hasHeader && <HeaderPortals store={headerCells} render={renderHeader} collection={collection} />}
|
|
182
|
+
</>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export { DropDownBase, type DropDownBaseProps };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type * as Gtk from "@gtkx/gi/gtk";
|
|
2
2
|
import type { RefObject } from "react";
|
|
3
|
-
import { useSignal } from "@gtkx/react";
|
|
4
3
|
import { useEffectEvent, useLayoutEffect, useRef, useState } from "react";
|
|
5
4
|
import type { Collection } from "./collection.js";
|
|
6
5
|
import { eachRow } from "./collection.js";
|
|
@@ -102,7 +101,7 @@ function runControlledExpansion(
|
|
|
102
101
|
report();
|
|
103
102
|
}
|
|
104
103
|
|
|
105
|
-
function useExpansion(options: ExpansionOptions): void {
|
|
104
|
+
function useExpansion(options: ExpansionOptions): () => void {
|
|
106
105
|
const { collection, expandedIds, onExpandedChange } = options;
|
|
107
106
|
const [last] = useState<LastExpansion>(newLastExpansion);
|
|
108
107
|
const expanding = useRef(false);
|
|
@@ -111,13 +110,13 @@ function useExpansion(options: ExpansionOptions): void {
|
|
|
111
110
|
reportWhenIdle(collection, last, expanding, onExpandedChange);
|
|
112
111
|
});
|
|
113
112
|
|
|
114
|
-
useSignal(collection.isTree ? collection.model : null, "items-changed", () => {
|
|
115
|
-
reportWhenIdle(collection, last, expanding, onExpandedChange);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
113
|
useLayoutEffect(() => {
|
|
119
114
|
runControlledExpansion(collection, expandedIds, expanding, report);
|
|
120
115
|
}, [collection, expandedIds]);
|
|
116
|
+
|
|
117
|
+
return () => {
|
|
118
|
+
reportWhenIdle(collection, last, expanding, onExpandedChange);
|
|
119
|
+
};
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
export { useExpansion, type ExpansionOptions };
|
|
@@ -10,6 +10,7 @@ type SelectionOptions = {
|
|
|
10
10
|
selectedIds?: string[] | null | undefined;
|
|
11
11
|
onSelectionChanged?: ((ids: string[]) => void) | null | undefined;
|
|
12
12
|
selectionMode?: Gtk.SelectionMode | null | undefined;
|
|
13
|
+
onItemsChanged: () => void;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
type LastSelection = {
|
|
@@ -21,6 +22,7 @@ type SelectionElementProps = {
|
|
|
21
22
|
ref: (value: Gtk.SelectionModel | null) => void;
|
|
22
23
|
model: Gio.ListModel;
|
|
23
24
|
onSelectionChanged: () => void;
|
|
25
|
+
onItemsChanged: () => void;
|
|
24
26
|
};
|
|
25
27
|
|
|
26
28
|
function getSelectedIds(selection: Gtk.SelectionModel, collection: Collection): string[] {
|
|
@@ -153,6 +155,7 @@ function useSelection(options: SelectionOptions): ReactElement {
|
|
|
153
155
|
onSelectionChanged: () => {
|
|
154
156
|
reportSelection(selection, collection, last, onSelectionChanged);
|
|
155
157
|
},
|
|
158
|
+
onItemsChanged: options.onItemsChanged,
|
|
156
159
|
});
|
|
157
160
|
}
|
|
158
161
|
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import type { ReactElement
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
2
|
import { useLayoutEffect, useMemo, useState } from "react";
|
|
3
|
-
import type { ExpansionProps,
|
|
4
|
-
import type { CollectionIndex } from "./collection-index.js";
|
|
5
|
-
import type { CollectionModel } from "./collection-model.js";
|
|
3
|
+
import type { ExpansionProps, ListItem, ListSection, SelectionProps } from "../types.js";
|
|
6
4
|
import type { Collection } from "./collection.js";
|
|
7
5
|
import { createCollectionIndex } from "./collection-index.js";
|
|
8
6
|
import { createCollectionModel } from "./collection-model.js";
|
|
@@ -11,10 +9,9 @@ import { useExpansion } from "./expansion.js";
|
|
|
11
9
|
import { useSelection } from "./selection.js";
|
|
12
10
|
|
|
13
11
|
type CollectionDataOptions = {
|
|
14
|
-
items?:
|
|
15
|
-
sections?:
|
|
16
|
-
|
|
17
|
-
applying?: RefObject<boolean> | undefined;
|
|
12
|
+
items?: ListItem[] | undefined;
|
|
13
|
+
sections?: ListSection[] | undefined;
|
|
14
|
+
isFlat?: boolean | undefined;
|
|
18
15
|
};
|
|
19
16
|
|
|
20
17
|
type CollectionOptions = CollectionDataOptions & SelectionProps & ExpansionProps;
|
|
@@ -24,44 +21,34 @@ type CollectionResult = {
|
|
|
24
21
|
selection: ReactElement;
|
|
25
22
|
};
|
|
26
23
|
|
|
27
|
-
function runSync(gtk: CollectionModel, index: CollectionIndex, applying: RefObject<boolean> | undefined): void {
|
|
28
|
-
if (applying === undefined) {
|
|
29
|
-
gtk.sync(index);
|
|
30
|
-
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
applying.current = true;
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
gtk.sync(index);
|
|
38
|
-
} finally {
|
|
39
|
-
applying.current = false;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
24
|
function useCollectionData(options: CollectionDataOptions): Collection {
|
|
44
|
-
const { items, sections,
|
|
25
|
+
const { items, sections, isFlat } = options;
|
|
45
26
|
const [gtk] = useState(createCollectionModel);
|
|
46
|
-
const index = useMemo(() => createCollectionIndex(items, sections,
|
|
27
|
+
const index = useMemo(() => createCollectionIndex(items, sections, isFlat === true), [items, sections, isFlat]);
|
|
47
28
|
const collection = useMemo(() => createCollection(gtk, index), [gtk, index]);
|
|
48
29
|
|
|
49
30
|
useLayoutEffect(() => {
|
|
50
|
-
|
|
51
|
-
}, [gtk, index
|
|
31
|
+
gtk.sync(index);
|
|
32
|
+
}, [gtk, index]);
|
|
52
33
|
|
|
53
34
|
return collection;
|
|
54
35
|
}
|
|
55
36
|
|
|
56
37
|
function useCollection(options: CollectionOptions): CollectionResult {
|
|
57
38
|
const collection = useCollectionData(options);
|
|
58
|
-
|
|
39
|
+
|
|
40
|
+
const onItemsChanged = useExpansion({
|
|
41
|
+
collection,
|
|
42
|
+
expandedIds: options.expandedIds,
|
|
43
|
+
onExpandedChange: options.onExpandedChange,
|
|
44
|
+
});
|
|
59
45
|
|
|
60
46
|
const selection = useSelection({
|
|
61
47
|
collection,
|
|
62
48
|
selectedIds: options.selectedIds,
|
|
63
49
|
onSelectionChanged: options.onSelectionChanged,
|
|
64
50
|
selectionMode: options.selectionMode,
|
|
51
|
+
onItemsChanged,
|
|
65
52
|
});
|
|
66
53
|
|
|
67
54
|
return { collection, selection };
|
package/src/types.ts
CHANGED
|
@@ -2,31 +2,23 @@ import type * as Gtk from "@gtkx/gi/gtk";
|
|
|
2
2
|
import type {
|
|
3
3
|
GtkColumnViewColumnProps,
|
|
4
4
|
GtkColumnViewProps,
|
|
5
|
-
|
|
5
|
+
GtkDropDownProps,
|
|
6
6
|
GtkGridViewProps,
|
|
7
7
|
GtkListViewProps,
|
|
8
8
|
} from "@gtkx/jsx/gtk";
|
|
9
|
-
import type {
|
|
10
|
-
|
|
11
|
-
/** Props of a container's Child component: the widget to render and its own props. */
|
|
12
|
-
type ChildProps<C extends ElementType> = {
|
|
13
|
-
component: C;
|
|
14
|
-
} & ComponentPropsWithRef<C>;
|
|
15
|
-
|
|
16
|
-
/** Props of a component whose backing widget defaults to one type but can be swapped through `component`. */
|
|
17
|
-
type WidgetProps<C extends ElementType, Own = unknown, ExtraOmit extends string = never> = Own & {
|
|
18
|
-
component?: C;
|
|
19
|
-
} & Omit<ComponentPropsWithRef<C>, ExtraOmit | keyof Own>;
|
|
9
|
+
import type { ReactNode } from "react";
|
|
20
10
|
|
|
21
11
|
/**
|
|
22
12
|
* A single item in a collection model, identified by a stable id and holding an
|
|
23
13
|
* arbitrary value. Nested items form a tree.
|
|
24
14
|
*/
|
|
25
|
-
type
|
|
15
|
+
type ListItem<T = unknown> = {
|
|
26
16
|
/** Stable identifier used to track the item across updates and selection. */
|
|
27
17
|
id: string;
|
|
18
|
+
/** Payload handed to the cell renderer as `ListItemRenderArgs.item`. */
|
|
28
19
|
value: T;
|
|
29
|
-
|
|
20
|
+
/** Child items nested under this one, which turn a plain item list into a tree. */
|
|
21
|
+
children?: ListItem<T>[] | undefined;
|
|
30
22
|
/** Hides the tree expander arrow even when the item has children. */
|
|
31
23
|
hideExpander?: boolean | undefined;
|
|
32
24
|
/** Adds indentation matching the item's depth in the tree. */
|
|
@@ -36,17 +28,20 @@ type Item<T = unknown> = {
|
|
|
36
28
|
};
|
|
37
29
|
|
|
38
30
|
/** A group of items rendered under a shared section header. */
|
|
39
|
-
type
|
|
31
|
+
type ListSection<S = unknown, T = unknown> = {
|
|
40
32
|
/** Stable identifier used to track the section across updates. */
|
|
41
33
|
id: string;
|
|
34
|
+
/** Payload handed to the section header renderer as `ListSectionRenderArgs.section`. */
|
|
42
35
|
value: S;
|
|
43
36
|
/** Items belonging to this section. */
|
|
44
|
-
data:
|
|
37
|
+
data: ListItem<T>[];
|
|
45
38
|
};
|
|
46
39
|
|
|
47
|
-
/** Arguments passed to
|
|
48
|
-
type
|
|
40
|
+
/** Arguments passed to a {@link ListItemRenderer} when rendering one cell. */
|
|
41
|
+
type ListItemRenderArgs<T> = {
|
|
42
|
+
/** Value of the `ListItem` being rendered. */
|
|
49
43
|
item: T;
|
|
44
|
+
/** Position of the item in the flattened item list, which excludes section headers and collapsed tree rows. */
|
|
50
45
|
index: number;
|
|
51
46
|
/** Depth of the item within a tree, starting at zero for top-level items. */
|
|
52
47
|
depth?: number | undefined;
|
|
@@ -54,57 +49,79 @@ type RenderItemArgs<T> = {
|
|
|
54
49
|
isExpanded?: boolean | undefined;
|
|
55
50
|
};
|
|
56
51
|
|
|
57
|
-
/** Arguments passed to a {@link
|
|
58
|
-
type
|
|
52
|
+
/** Arguments passed to a {@link ListSectionRenderer} when rendering one section header. */
|
|
53
|
+
type ListSectionRenderArgs<S> = {
|
|
54
|
+
/** Value of the `ListSection` whose header is being rendered. */
|
|
59
55
|
section: S;
|
|
60
56
|
};
|
|
61
57
|
|
|
62
58
|
/** Renders the contents of one cell of a collection view. */
|
|
63
|
-
type
|
|
59
|
+
type ListItemRenderer<T> = (args: ListItemRenderArgs<T>) => ReactNode;
|
|
64
60
|
/** Renders the contents of one section header of a collection view. */
|
|
65
|
-
type
|
|
61
|
+
type ListSectionRenderer<S> = (args: ListSectionRenderArgs<S>) => ReactNode;
|
|
66
62
|
|
|
63
|
+
/** Size a collection view requests for each cell before its contents render, keeping scroll estimates steady. */
|
|
67
64
|
type ItemSizeProps = {
|
|
65
|
+
/** Height in pixels every cell asks for until its contents render; unset lets each cell size itself. */
|
|
68
66
|
estimatedItemHeight?: number | undefined;
|
|
67
|
+
/** Width in pixels every cell asks for until its contents render; unset lets each cell size itself. */
|
|
69
68
|
estimatedItemWidth?: number | undefined;
|
|
70
69
|
};
|
|
71
70
|
|
|
71
|
+
/** Controlled selection shared by the multi-item collection views. */
|
|
72
72
|
type SelectionProps = {
|
|
73
|
+
/** Ids of the items to keep selected; omitting it leaves the view's own selection alone. */
|
|
73
74
|
selectedIds?: string[] | null | undefined;
|
|
75
|
+
/** Called with the ids of every selected item whenever the selection changes, and once on mount. */
|
|
74
76
|
onSelectionChanged?: ((ids: string[]) => void) | null | undefined;
|
|
77
|
+
/** How much the user may select, one item at a time unless `MULTIPLE` or `NONE` is given. */
|
|
75
78
|
selectionMode?: Gtk.SelectionMode | null | undefined;
|
|
76
79
|
};
|
|
77
80
|
|
|
81
|
+
/** Controlled expansion for the views that turn nested `ListItem.children` into a tree. */
|
|
78
82
|
type ExpansionProps = {
|
|
83
|
+
/** Ids of the items to keep expanded; omitting it leaves the rows' own expanded state alone. */
|
|
79
84
|
expandedIds?: string[] | null | undefined;
|
|
85
|
+
/** Called with the ids of every expanded row whenever expansion changes. */
|
|
80
86
|
onExpandedChange?: ((ids: string[]) => void) | null | undefined;
|
|
81
87
|
};
|
|
82
88
|
|
|
89
|
+
/** The data a collection view renders, either as a plain item list or grouped into sections. */
|
|
83
90
|
type SourceProps<T, S> = {
|
|
84
|
-
|
|
85
|
-
|
|
91
|
+
/** Items to render, nesting through `ListItem.children` for a tree; ignored once `sections` is given. */
|
|
92
|
+
items?: ListItem<T>[] | undefined;
|
|
93
|
+
/** Items grouped under section headers, rendered in place of `items`. */
|
|
94
|
+
sections?: ListSection<S, T>[] | undefined;
|
|
86
95
|
};
|
|
87
96
|
|
|
88
97
|
/** One column of a {@link ColumnView}, pairing Gtk.ColumnViewColumn props with a cell renderer. */
|
|
89
|
-
type
|
|
98
|
+
type ColumnViewColumn<T = unknown> = Omit<GtkColumnViewColumnProps, "factory" | "sorter" | "id" | "title"> & {
|
|
90
99
|
/** Stable identifier, also used to address the column through sorting props. */
|
|
91
100
|
id: string;
|
|
101
|
+
/** Text shown in the column header. */
|
|
92
102
|
title: string;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
/** Renders the contents of this column's cell for one item. */
|
|
104
|
+
renderCell: ListItemRenderer<T>;
|
|
105
|
+
/** Makes the column header clickable, reporting the choice through `onSortChanged`. */
|
|
106
|
+
isSortable?: boolean | undefined;
|
|
107
|
+
/** Menu element popped up as the column header's context menu, on a right-click. */
|
|
96
108
|
headerMenu?: ReactNode;
|
|
97
109
|
};
|
|
98
110
|
|
|
111
|
+
/** The declarative collection props {@link ColumnView} adds on top of Gtk.ColumnView's own. */
|
|
99
112
|
type ColumnViewOwnProps<T, S> = SelectionProps &
|
|
100
113
|
ExpansionProps &
|
|
101
114
|
SourceProps<T, S> &
|
|
102
115
|
Omit<ItemSizeProps, "estimatedItemWidth"> & {
|
|
103
|
-
|
|
104
|
-
|
|
116
|
+
/** Columns to render, in order; each carries its own cell renderer. */
|
|
117
|
+
columns: ColumnViewColumn<T>[];
|
|
118
|
+
/** Renders the header shown above each section. */
|
|
119
|
+
renderHeader?: ListSectionRenderer<S> | null | undefined;
|
|
105
120
|
/** Id of the column the view is sorted by, making sorting controlled. */
|
|
106
121
|
sortColumn?: string | null | undefined;
|
|
122
|
+
/** Direction `sortColumn` is sorted in, defaulting to ascending. */
|
|
107
123
|
sortOrder?: Gtk.SortType | null | undefined;
|
|
124
|
+
/** Called when the user sorts from a header, with the primary column's id, or null, and its order. */
|
|
108
125
|
onSortChanged?: ((column: string | null, order: Gtk.SortType) => void) | null | undefined;
|
|
109
126
|
};
|
|
110
127
|
|
|
@@ -120,31 +137,41 @@ type ColumnViewProps<T = unknown, S = unknown> = Omit<
|
|
|
120
137
|
> &
|
|
121
138
|
ColumnViewOwnProps<T, S>;
|
|
122
139
|
|
|
140
|
+
/** The declarative collection props {@link DropDown} and `ComboRow` add on top of their widget's own. */
|
|
123
141
|
type DropDownOwnProps<T, S> = SourceProps<T, S> & {
|
|
124
142
|
/** Id of the currently selected item, making the selection controlled. */
|
|
125
143
|
selectedId?: string | null | undefined;
|
|
144
|
+
/** Called with the id of the item that became selected. */
|
|
126
145
|
onSelectionChanged?: ((id: string) => void) | null | undefined;
|
|
127
|
-
|
|
146
|
+
/** Renders the collapsed display, and the popup rows too unless `renderListItem` is given. */
|
|
147
|
+
renderItem?: ListItemRenderer<T> | null | undefined;
|
|
128
148
|
/** Renderer for items in the open popup list, falling back to renderItem when omitted. */
|
|
129
|
-
renderListItem?:
|
|
149
|
+
renderListItem?: ListItemRenderer<T> | null | undefined;
|
|
130
150
|
/** Renderer for section headers in the popup list. */
|
|
131
|
-
renderHeader?:
|
|
151
|
+
renderHeader?: ListSectionRenderer<S> | null | undefined;
|
|
132
152
|
};
|
|
133
153
|
|
|
154
|
+
/** A drop-down-shaped widget's props with its model and factories swapped for the declarative collection props. */
|
|
155
|
+
type DropDownWidgetProps<Widget, T, S> = Omit<
|
|
156
|
+
Widget,
|
|
157
|
+
"model" | "factory" | "listFactory" | "headerFactory" | keyof DropDownOwnProps<T, S>
|
|
158
|
+
> &
|
|
159
|
+
DropDownOwnProps<T, S>;
|
|
160
|
+
|
|
134
161
|
/**
|
|
135
|
-
* Props for {@link DropDown}.
|
|
136
|
-
*
|
|
162
|
+
* Props for {@link DropDown}. Combines the underlying Gtk.DropDown props with the declarative
|
|
163
|
+
* collection props: flat items or grouped sections, controlled single selection, and renderers
|
|
164
|
+
* for the collapsed display, popup rows, and popup section headers.
|
|
137
165
|
*/
|
|
138
|
-
type DropDownProps<T = unknown, S = unknown
|
|
139
|
-
C,
|
|
140
|
-
DropDownOwnProps<T, S>,
|
|
141
|
-
"model" | "factory" | "listFactory" | "headerFactory"
|
|
142
|
-
>;
|
|
166
|
+
type DropDownProps<T = unknown, S = unknown> = DropDownWidgetProps<GtkDropDownProps, T, S>;
|
|
143
167
|
|
|
168
|
+
/** The declarative collection props {@link GridView} adds on top of Gtk.GridView's own. */
|
|
144
169
|
type GridViewOwnProps<T> = ItemSizeProps &
|
|
145
170
|
SelectionProps & {
|
|
146
|
-
|
|
147
|
-
|
|
171
|
+
/** Items to render as cells; a grid is always flat, so `ListItem.children` is ignored. */
|
|
172
|
+
items?: ListItem<T>[] | undefined;
|
|
173
|
+
/** Renders the contents of one cell. */
|
|
174
|
+
renderItem: ListItemRenderer<T>;
|
|
148
175
|
};
|
|
149
176
|
|
|
150
177
|
/**
|
|
@@ -155,12 +182,15 @@ type GridViewOwnProps<T> = ItemSizeProps &
|
|
|
155
182
|
type GridViewProps<T = unknown> = Omit<GtkGridViewProps, "model" | "factory" | keyof GridViewOwnProps<T>> &
|
|
156
183
|
GridViewOwnProps<T>;
|
|
157
184
|
|
|
185
|
+
/** The declarative collection props {@link ListView} adds on top of Gtk.ListView's own. */
|
|
158
186
|
type ListViewOwnProps<T, S> = ItemSizeProps &
|
|
159
187
|
SelectionProps &
|
|
160
188
|
ExpansionProps &
|
|
161
189
|
SourceProps<T, S> & {
|
|
162
|
-
|
|
163
|
-
|
|
190
|
+
/** Renders the contents of one row. */
|
|
191
|
+
renderItem: ListItemRenderer<T>;
|
|
192
|
+
/** Renders the header shown above each section. */
|
|
193
|
+
renderHeader?: ListSectionRenderer<S> | null | undefined;
|
|
164
194
|
};
|
|
165
195
|
|
|
166
196
|
/**
|
|
@@ -175,33 +205,20 @@ type ListViewProps<T = unknown, S = unknown> = Omit<
|
|
|
175
205
|
> &
|
|
176
206
|
ListViewOwnProps<T, S>;
|
|
177
207
|
|
|
178
|
-
/** Props for {@link SizeGroup}. */
|
|
179
|
-
type SizeGroupProps = {
|
|
180
|
-
/** How the group equalizes sizes: horizontal, vertical, or both. */
|
|
181
|
-
mode?: Gtk.SizeGroupMode | null | undefined;
|
|
182
|
-
ref?: Ref<Gtk.SizeGroup | null>;
|
|
183
|
-
children?: ReactNode;
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
/** Adds a single widget, rendered by the given component, to the enclosing {@link SizeGroup}. */
|
|
187
|
-
type SizeGroupChildProps<C extends ElementType> = ChildProps<C>;
|
|
188
|
-
|
|
189
208
|
export {
|
|
190
209
|
type SelectionProps,
|
|
191
210
|
type ExpansionProps,
|
|
192
|
-
type
|
|
193
|
-
type
|
|
194
|
-
type
|
|
195
|
-
type
|
|
196
|
-
type
|
|
197
|
-
type
|
|
198
|
-
type
|
|
199
|
-
type
|
|
200
|
-
type
|
|
211
|
+
type DropDownOwnProps,
|
|
212
|
+
type DropDownWidgetProps,
|
|
213
|
+
type ListItem,
|
|
214
|
+
type ListSection,
|
|
215
|
+
type ListItemRenderArgs,
|
|
216
|
+
type ListSectionRenderArgs,
|
|
217
|
+
type ListItemRenderer,
|
|
218
|
+
type ListSectionRenderer,
|
|
219
|
+
type ColumnViewColumn,
|
|
201
220
|
type ColumnViewProps,
|
|
202
221
|
type DropDownProps,
|
|
203
222
|
type GridViewProps,
|
|
204
223
|
type ListViewProps,
|
|
205
|
-
type SizeGroupProps,
|
|
206
|
-
type SizeGroupChildProps,
|
|
207
224
|
};
|
package/dist/size-group.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ElementType, ReactNode } from "react";
|
|
2
|
-
import type { SizeGroupChildProps, SizeGroupProps } from "./types.js";
|
|
3
|
-
type SizeGroupComponent = ((props: SizeGroupProps) => ReactNode) & {
|
|
4
|
-
Child: <C extends ElementType>(props: SizeGroupChildProps<C>) => ReactNode;
|
|
5
|
-
};
|
|
6
|
-
/**
|
|
7
|
-
* Creates a Gtk.SizeGroup that keeps widgets joined through `SizeGroup.Child`
|
|
8
|
-
* at a common size in the given mode, without contributing a widget of its own.
|
|
9
|
-
*/
|
|
10
|
-
declare const SizeGroup: SizeGroupComponent;
|
|
11
|
-
export { SizeGroup };
|
|
12
|
-
//# sourceMappingURL=size-group.d.ts.map
|
package/dist/size-group.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"size-group.d.ts","sourceRoot":"","sources":["../src/size-group.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAoB,MAAM,OAAO,CAAC;AAItE,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAStE,KAAK,kBAAkB,GAAG,CAAC,CAAC,KAAK,EAAE,cAAc,KAAK,SAAS,CAAC,GAAG;IAC/D,KAAK,EAAE,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;CAC9E,CAAC;AAIF;;;GAGG;AACH,QAAA,MAAM,SAAS,EAAE,kBAA4E,CAAC;AAoD9F,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
package/dist/size-group.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { GtkSizeGroup } from "@gtkx/jsx/gtk";
|
|
3
|
-
import { useMergedRef } from "@gtkx/react/internal";
|
|
4
|
-
import { createContext, useCallback, useContext, useState } from "react";
|
|
5
|
-
const SizeGroupContext = createContext(null);
|
|
6
|
-
const SizeGroupChild = SizeGroupChildImpl;
|
|
7
|
-
/**
|
|
8
|
-
* Creates a Gtk.SizeGroup that keeps widgets joined through `SizeGroup.Child`
|
|
9
|
-
* at a common size in the given mode, without contributing a widget of its own.
|
|
10
|
-
*/
|
|
11
|
-
const SizeGroup = Object.assign(SizeGroupRoot, { Child: SizeGroupChild });
|
|
12
|
-
const useRegister = () => {
|
|
13
|
-
const register = useContext(SizeGroupContext);
|
|
14
|
-
if (register === null) {
|
|
15
|
-
throw new Error("<SizeGroup.Child> must be a child of <SizeGroup>");
|
|
16
|
-
}
|
|
17
|
-
return register;
|
|
18
|
-
};
|
|
19
|
-
function SizeGroupChildImpl(props) {
|
|
20
|
-
const { component: Component, ref, ...rest } = props;
|
|
21
|
-
const refCallback = useMergedRef(ref, useRegister());
|
|
22
|
-
return _jsx(Component, { ...rest, ref: refCallback });
|
|
23
|
-
}
|
|
24
|
-
const addWidget = (widgets, widget) => widgets.includes(widget) ? widgets : [...widgets, widget];
|
|
25
|
-
const removeWidget = (widgets, widget) => widgets.filter((entry) => entry !== widget);
|
|
26
|
-
function SizeGroupRoot(props) {
|
|
27
|
-
const { mode, ref, children } = props;
|
|
28
|
-
const [widgets, setWidgets] = useState([]);
|
|
29
|
-
const register = useCallback((widget) => {
|
|
30
|
-
if (widget === null) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
setWidgets((previous) => addWidget(previous, widget));
|
|
34
|
-
return () => {
|
|
35
|
-
setWidgets((previous) => removeWidget(previous, widget));
|
|
36
|
-
};
|
|
37
|
-
}, [setWidgets]);
|
|
38
|
-
return (_jsxs(_Fragment, { children: [_jsx(GtkSizeGroup, { ref: ref, mode: mode, widgets: widgets }), _jsx(SizeGroupContext.Provider, { value: register, children: children })] }));
|
|
39
|
-
}
|
|
40
|
-
export { SizeGroup };
|
|
41
|
-
//# sourceMappingURL=size-group.js.map
|
package/dist/size-group.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"size-group.js","sourceRoot":"","sources":["../src/size-group.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAczE,MAAM,gBAAgB,GAAG,aAAa,CAAkB,IAAI,CAAC,CAAC;AAC9D,MAAM,cAAc,GAAG,kBAAyF,CAAC;AACjH;;;GAGG;AACH,MAAM,SAAS,GAAuB,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;AAE9F,MAAM,WAAW,GAAG,GAAa,EAAE;IAC/B,MAAM,QAAQ,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAE9C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAC;AAEF,SAAS,kBAAkB,CAAC,KAAiC;IACzD,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IACrD,MAAM,WAAW,GAAG,YAAY,CAAoB,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;IAExE,OAAO,KAAC,SAAS,OAAK,IAAI,EAAE,GAAG,EAAE,WAAW,GAAI,CAAC;AACrD,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,OAAqB,EAAE,MAAkB,EAAgB,EAAE,CAC1E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;AAE9D,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAE,MAAkB,EAAgB,EAAE,CAC7E,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;AAEhD,SAAS,aAAa,CAAC,KAAqB;IACxC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACtC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAe,EAAE,CAAC,CAAC;IAEzD,MAAM,QAAQ,GAAG,WAAW,CACxB,CAAC,MAAM,EAAE,EAAE;QACP,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO;QACX,CAAC;QAED,UAAU,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QAEtD,OAAO,GAAG,EAAE;YACR,UAAU,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC;IACN,CAAC,EACD,CAAC,UAAU,CAAC,CACf,CAAC;IAEF,OAAO,CACH,8BACI,KAAC,YAAY,IAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAI,EACxD,KAAC,gBAAgB,CAAC,QAAQ,IAAC,KAAK,EAAE,QAAQ,YAAG,QAAQ,GAA6B,IACnF,CACN,CAAC;AACN,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,CAAC","sourcesContent":["import type * as Gtk from \"@gtkx/gi/gtk\";\nimport type { ElementType, ReactNode, Ref, RefCallback } from \"react\";\nimport { GtkSizeGroup } from \"@gtkx/jsx/gtk\";\nimport { useMergedRef } from \"@gtkx/react/internal\";\nimport { createContext, useCallback, useContext, useState } from \"react\";\nimport type { SizeGroupChildProps, SizeGroupProps } from \"./types.js\";\n\ntype Register = RefCallback<Gtk.Widget | null>;\n\ntype SizeGroupChildRuntimeProps = {\n component: ElementType;\n ref?: Ref<Gtk.Widget | null> | undefined;\n} & Record<string, unknown>;\n\ntype SizeGroupComponent = ((props: SizeGroupProps) => ReactNode) & {\n Child: <C extends ElementType>(props: SizeGroupChildProps<C>) => ReactNode;\n};\n\nconst SizeGroupContext = createContext<Register | null>(null);\nconst SizeGroupChild = SizeGroupChildImpl as <C extends ElementType>(props: SizeGroupChildProps<C>) => ReactNode;\n/**\n * Creates a Gtk.SizeGroup that keeps widgets joined through `SizeGroup.Child`\n * at a common size in the given mode, without contributing a widget of its own.\n */\nconst SizeGroup: SizeGroupComponent = Object.assign(SizeGroupRoot, { Child: SizeGroupChild });\n\nconst useRegister = (): Register => {\n const register = useContext(SizeGroupContext);\n\n if (register === null) {\n throw new Error(\"<SizeGroup.Child> must be a child of <SizeGroup>\");\n }\n\n return register;\n};\n\nfunction SizeGroupChildImpl(props: SizeGroupChildRuntimeProps): ReactNode {\n const { component: Component, ref, ...rest } = props;\n const refCallback = useMergedRef<Gtk.Widget | null>(ref, useRegister());\n\n return <Component {...rest} ref={refCallback} />;\n}\n\nconst addWidget = (widgets: Gtk.Widget[], widget: Gtk.Widget): Gtk.Widget[] =>\n widgets.includes(widget) ? widgets : [...widgets, widget];\n\nconst removeWidget = (widgets: Gtk.Widget[], widget: Gtk.Widget): Gtk.Widget[] =>\n widgets.filter((entry) => entry !== widget);\n\nfunction SizeGroupRoot(props: SizeGroupProps): ReactNode {\n const { mode, ref, children } = props;\n const [widgets, setWidgets] = useState<Gtk.Widget[]>([]);\n\n const register = useCallback<Register>(\n (widget) => {\n if (widget === null) {\n return;\n }\n\n setWidgets((previous) => addWidget(previous, widget));\n\n return () => {\n setWidgets((previous) => removeWidget(previous, widget));\n };\n },\n [setWidgets],\n );\n\n return (\n <>\n <GtkSizeGroup ref={ref} mode={mode} widgets={widgets} />\n <SizeGroupContext.Provider value={register}>{children}</SizeGroupContext.Provider>\n </>\n );\n}\n\nexport { SizeGroup };\n"]}
|