@decky/ui 4.7.4 → 4.8.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/dist/components/Dialog.js +2 -2
- package/dist/components/DialogCheckbox.js +4 -3
- package/dist/components/FocusRing.js +1 -1
- package/dist/components/Menu.js +2 -2
- package/dist/components/Modal.js +2 -2
- package/dist/components/Panel.js +1 -1
- package/dist/components/ProgressBar.js +2 -2
- package/dist/components/SliderField.js +1 -1
- package/dist/components/Tabs.js +2 -2
- package/dist/components/Toggle.js +1 -1
- package/dist/components/ToggleField.js +1 -1
- package/dist/modules/Router.js +2 -2
- package/dist/utils/react/react.d.ts +3 -0
- package/dist/utils/react/react.js +8 -0
- package/package.json +1 -1
- package/src/components/Dialog.ts +2 -2
- package/src/components/DialogCheckbox.ts +4 -3
- package/src/components/FocusRing.ts +1 -1
- package/src/components/Menu.ts +2 -2
- package/src/components/Modal.ts +2 -2
- package/src/components/Panel.ts +1 -1
- package/src/components/ProgressBar.ts +2 -2
- package/src/components/SliderField.ts +1 -1
- package/src/components/Tabs.tsx +2 -2
- package/src/components/Toggle.ts +1 -1
- package/src/components/ToggleField.ts +1 -1
- package/src/modules/Router.ts +2 -2
- package/src/utils/react/react.ts +19 -0
|
@@ -19,6 +19,6 @@ export const DialogBodyText = MappedDialogDivs.get('DialogBodyText');
|
|
|
19
19
|
export const DialogBody = MappedDialogDivs.get('DialogBody');
|
|
20
20
|
export const DialogControlsSection = MappedDialogDivs.get('DialogControlsSection');
|
|
21
21
|
export const DialogControlsSectionHeader = MappedDialogDivs.get('DialogControlsSectionHeader');
|
|
22
|
-
export const DialogButtonPrimary = Object.values(CommonUIModule).find((mod) => mod?.render?.toString()?.includes('"DialogButton","_DialogLayout","Primary"'));
|
|
23
|
-
export const DialogButtonSecondary = Object.values(CommonUIModule).find((mod) => mod?.render?.toString()?.includes('"DialogButton","_DialogLayout","Secondary"'));
|
|
22
|
+
export const DialogButtonPrimary = Object.values(CommonUIModule).find((mod) => mod?.render?.toString?.()?.includes('"DialogButton","_DialogLayout","Primary"'));
|
|
23
|
+
export const DialogButtonSecondary = Object.values(CommonUIModule).find((mod) => mod?.render?.toString?.()?.includes('"DialogButton","_DialogLayout","Secondary"'));
|
|
24
24
|
export const DialogButton = DialogButtonSecondary;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { findModuleExport } from '../webpack';
|
|
2
|
-
export const DialogCheckbox = findModuleExport(e => e
|
|
2
|
+
export const DialogCheckbox = findModuleExport(e => e?.prototype &&
|
|
3
|
+
typeof e?.prototype == "object" &&
|
|
3
4
|
"GetPanelElementProps" in e?.prototype &&
|
|
4
5
|
"SetChecked" in e?.prototype &&
|
|
5
6
|
"Toggle" in e?.prototype &&
|
|
6
|
-
(e?.prototype?.render?.toString().includes('="DialogCheckbox"') || (e.contextType &&
|
|
7
|
-
e.prototype?.render?.toString().includes('fallback:'))));
|
|
7
|
+
(e?.prototype?.render?.toString?.().includes('="DialogCheckbox"') || (e.contextType &&
|
|
8
|
+
e.prototype?.render?.toString?.().includes('fallback:'))));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { findModuleExport } from '../webpack';
|
|
2
|
-
export const FocusRing = findModuleExport((e) => e?.toString()?.includes('.GetShowDebugFocusRing())'));
|
|
2
|
+
export const FocusRing = findModuleExport((e) => e?.toString?.()?.includes('.GetShowDebugFocusRing())'));
|
package/dist/components/Menu.js
CHANGED
|
@@ -3,5 +3,5 @@ export const showContextMenu = findModuleExport((e) => typeof e === 'function' &
|
|
|
3
3
|
&& e.toString().includes('.CreateContextMenuInstance('));
|
|
4
4
|
export const Menu = findModuleExport((e) => e?.prototype?.HideIfSubmenu && e?.prototype?.HideMenu);
|
|
5
5
|
const MenuGoupModule = findModuleByExport(e => e?.prototype?.Focus && e?.prototype?.OnOKButton && e?.prototype?.render?.toString().includes?.(`"emphasis"==this.props.tone`));
|
|
6
|
-
export const MenuGroup = MenuGoupModule && Object.values(MenuGoupModule).find((e) => typeof e == "function" && e?.toString()?.includes("bInGamepadUI:"));
|
|
7
|
-
export const MenuItem = findModuleExport((e) => e?.render?.toString()?.includes('bPlayAudio:') || (e?.prototype?.OnOKButton && e?.prototype?.OnMouseEnter));
|
|
6
|
+
export const MenuGroup = MenuGoupModule && Object.values(MenuGoupModule).find((e) => typeof e == "function" && e?.toString?.()?.includes("bInGamepadUI:"));
|
|
7
|
+
export const MenuItem = findModuleExport((e) => e?.render?.toString?.()?.includes('bPlayAudio:') || (e?.prototype?.OnOKButton && e?.prototype?.OnMouseEnter));
|
package/dist/components/Modal.js
CHANGED
|
@@ -5,7 +5,7 @@ export const showModal = (modal, parent, props = {
|
|
|
5
5
|
strTitle: 'Decky Dialog',
|
|
6
6
|
bHideMainWindowForPopouts: false,
|
|
7
7
|
}) => {
|
|
8
|
-
return showModalRaw(modal, parent || findSP(), props.strTitle, props, undefined, {
|
|
8
|
+
return showModalRaw(modal, parent || findSP() || window, props.strTitle, props, undefined, {
|
|
9
9
|
bHideActions: props.bHideActionIcons,
|
|
10
10
|
});
|
|
11
11
|
};
|
|
@@ -19,7 +19,7 @@ export const ModalRoot = Object.values(findModule((m) => {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
return false;
|
|
22
|
-
}) || {})?.find((x) => x?.type?.toString()?.includes('((function(){'));
|
|
22
|
+
}) || {})?.find((x) => x?.type?.toString?.()?.includes('((function(){'));
|
|
23
23
|
const [ModalModule, _ModalPosition] = findModuleDetailsByExport((e) => e?.toString().includes('.ModalPosition'), 5);
|
|
24
24
|
const ModalModuleProps = ModalModule ? Object.values(ModalModule) : [];
|
|
25
25
|
export const SimpleModal = ModalModuleProps.find((prop) => {
|
package/dist/components/Panel.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { findModuleDetailsByExport } from '../webpack';
|
|
2
2
|
const [mod, panelSection] = findModuleDetailsByExport((e) => e.toString()?.includes('.PanelSection'));
|
|
3
3
|
export const PanelSection = panelSection;
|
|
4
|
-
export const PanelSectionRow = Object.values(mod).filter((exp) => !exp?.toString()?.includes('.PanelSection'))[0];
|
|
4
|
+
export const PanelSectionRow = Object.values(mod).filter((exp) => !exp?.toString?.()?.includes('.PanelSection'))[0];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { findModuleExport } from '../webpack';
|
|
2
2
|
import { createPropListRegex } from '../utils';
|
|
3
|
-
export const ProgressBar = findModuleExport((e) => e?.toString()?.includes('.ProgressBar,"standard"=='));
|
|
4
|
-
export const ProgressBarWithInfo = findModuleExport((e) => e?.toString()?.includes('.ProgressBarFieldStatus},'));
|
|
3
|
+
export const ProgressBar = findModuleExport((e) => e?.toString?.()?.includes('.ProgressBar,"standard"=='));
|
|
4
|
+
export const ProgressBarWithInfo = findModuleExport((e) => e?.toString?.()?.includes('.ProgressBarFieldStatus},'));
|
|
5
5
|
const progressBarItemRegex = createPropListRegex(["indeterminate", "nTransitionSec", "nProgress"]);
|
|
6
6
|
export const ProgressBarItem = findModuleExport((e) => e?.toString && progressBarItemRegex.test(e.toString()));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { CommonUIModule } from '../webpack';
|
|
2
|
-
export const SliderField = Object.values(CommonUIModule).find((mod) => mod?.toString()?.includes('SliderField,fallback') || mod?.toString()?.includes("SliderField\","));
|
|
2
|
+
export const SliderField = Object.values(CommonUIModule).find((mod) => mod?.toString?.()?.includes('SliderField,fallback') || mod?.toString?.()?.includes("SliderField\","));
|
package/dist/components/Tabs.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { findModuleByExport } from '../webpack';
|
|
2
|
-
const tabsModule = findModuleByExport(e => e?.toString()?.includes(".TabRowTabs") && e?.toString()?.includes("activeTab:"));
|
|
3
|
-
export const Tabs = tabsModule && Object.values(tabsModule).find((e) => e?.type?.toString()?.includes("((function()"));
|
|
2
|
+
const tabsModule = findModuleByExport(e => e?.toString?.()?.includes(".TabRowTabs") && e?.toString?.()?.includes("activeTab:"));
|
|
3
|
+
export const Tabs = tabsModule && Object.values(tabsModule).find((e) => e?.type?.toString?.()?.includes("((function()"));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { CommonUIModule } from '../webpack';
|
|
2
|
-
export const Toggle = Object.values(CommonUIModule).find((mod) => mod?.render?.toString()?.includes('.ToggleOff)'));
|
|
2
|
+
export const Toggle = Object.values(CommonUIModule).find((mod) => mod?.render?.toString?.()?.includes('.ToggleOff)'));
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { CommonUIModule } from '../webpack';
|
|
2
|
-
export const ToggleField = Object.values(CommonUIModule).find((mod) => mod?.render?.toString()?.includes('ToggleField,fallback') || mod?.render?.toString()?.includes("ToggleField\","));
|
|
2
|
+
export const ToggleField = Object.values(CommonUIModule).find((mod) => mod?.render?.toString?.()?.includes('ToggleField,fallback') || mod?.render?.toString?.()?.includes("ToggleField\","));
|
package/dist/modules/Router.js
CHANGED
|
@@ -71,8 +71,8 @@ try {
|
|
|
71
71
|
logger.warn("Navigation interface failed to call GetFocusedWindowInstance", e);
|
|
72
72
|
}
|
|
73
73
|
if (!win) {
|
|
74
|
-
logger.warn("Navigation interface could not find any focused window. Falling back to
|
|
75
|
-
win = Router.WindowStore?.GamepadUIMainWindowInstance;
|
|
74
|
+
logger.warn("Navigation interface could not find any focused window. Falling back to Main Window Instance");
|
|
75
|
+
win = Router.WindowStore?.GamepadUIMainWindowInstance || Router?.WindowStore?.SteamUIWindows?.[0];
|
|
76
76
|
}
|
|
77
77
|
if (win) {
|
|
78
78
|
try {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { Ref } from 'react';
|
|
2
3
|
declare global {
|
|
3
4
|
interface Window {
|
|
4
5
|
SP_REACT: typeof React;
|
|
@@ -19,3 +20,5 @@ export interface findInTreeOpts {
|
|
|
19
20
|
export declare type findInTreeFilter = (element: any) => boolean;
|
|
20
21
|
export declare const findInTree: (parent: any, filter: findInTreeFilter, opts: findInTreeOpts) => any;
|
|
21
22
|
export declare const findInReactTree: (node: any, filter: findInTreeFilter) => any;
|
|
23
|
+
export declare function getParentWindow<WindowType = Window>(elem: HTMLElement | null): WindowType | null | undefined;
|
|
24
|
+
export declare function useWindowRef<RefElementType extends HTMLElement, WindowType = Window>(): [Ref<RefElementType>, WindowType | null | undefined];
|
|
@@ -2,6 +2,7 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
|
|
|
2
2
|
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
|
|
3
3
|
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
|
4
4
|
};
|
|
5
|
+
import { useState } from 'react';
|
|
5
6
|
export function createPropListRegex(propList, fromStart = true) {
|
|
6
7
|
let regexString = fromStart ? "const\{" : "";
|
|
7
8
|
propList.forEach((prop, propIdx) => {
|
|
@@ -98,3 +99,10 @@ export const findInTree = (parent, filter, opts) => {
|
|
|
98
99
|
export const findInReactTree = (node, filter) => findInTree(node, filter, {
|
|
99
100
|
walkable: ['props', 'children', 'child', 'sibling'],
|
|
100
101
|
});
|
|
102
|
+
export function getParentWindow(elem) {
|
|
103
|
+
return elem?.ownerDocument?.defaultView;
|
|
104
|
+
}
|
|
105
|
+
export function useWindowRef() {
|
|
106
|
+
const [win, setWin] = useState(null);
|
|
107
|
+
return [(elem) => setWin(getParentWindow(elem)), win];
|
|
108
|
+
}
|
package/package.json
CHANGED
package/src/components/Dialog.ts
CHANGED
|
@@ -78,11 +78,11 @@ export const DialogControlsSection = MappedDialogDivs.get('DialogControlsSection
|
|
|
78
78
|
export const DialogControlsSectionHeader = MappedDialogDivs.get('DialogControlsSectionHeader') as FC<DialogCommonProps>;
|
|
79
79
|
|
|
80
80
|
export const DialogButtonPrimary = Object.values(CommonUIModule).find(
|
|
81
|
-
(mod: any) => mod?.render?.toString()?.includes('"DialogButton","_DialogLayout","Primary"'),
|
|
81
|
+
(mod: any) => mod?.render?.toString?.()?.includes('"DialogButton","_DialogLayout","Primary"'),
|
|
82
82
|
) as FC<DialogButtonProps>;
|
|
83
83
|
|
|
84
84
|
export const DialogButtonSecondary = Object.values(CommonUIModule).find(
|
|
85
|
-
(mod: any) => mod?.render?.toString()?.includes('"DialogButton","_DialogLayout","Secondary"')
|
|
85
|
+
(mod: any) => mod?.render?.toString?.()?.includes('"DialogButton","_DialogLayout","Secondary"')
|
|
86
86
|
) as FC<DialogButtonProps>;
|
|
87
87
|
|
|
88
88
|
// This is the "main" button. The Primary can act as a submit button,
|
|
@@ -20,13 +20,14 @@ export interface DialogCheckboxProps extends DialogCommonProps, FooterLegendProp
|
|
|
20
20
|
|
|
21
21
|
// Do not access KeyDown, SetChecked, Toggle here as they are getters and accessing them outside of a render breaks them globally
|
|
22
22
|
export const DialogCheckbox = findModuleExport(e =>
|
|
23
|
-
e
|
|
23
|
+
e?.prototype &&
|
|
24
|
+
typeof e?.prototype == "object" &&
|
|
24
25
|
"GetPanelElementProps" in e?.prototype &&
|
|
25
26
|
"SetChecked" in e?.prototype &&
|
|
26
27
|
"Toggle" in e?.prototype &&
|
|
27
28
|
// beta || stable as of oct 2 2024
|
|
28
|
-
(e?.prototype?.render?.toString().includes('="DialogCheckbox"') || (
|
|
29
|
+
(e?.prototype?.render?.toString?.().includes('="DialogCheckbox"') || (
|
|
29
30
|
e.contextType &&
|
|
30
|
-
e.prototype?.render?.toString().includes('fallback:')
|
|
31
|
+
e.prototype?.render?.toString?.().includes('fallback:')
|
|
31
32
|
))
|
|
32
33
|
) as FC<DialogCheckboxProps>;
|
package/src/components/Menu.ts
CHANGED
|
@@ -26,7 +26,7 @@ export interface MenuGroupProps {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const MenuGoupModule = findModuleByExport(e => e?.prototype?.Focus && e?.prototype?.OnOKButton && e?.prototype?.render?.toString().includes?.(`"emphasis"==this.props.tone`));
|
|
29
|
-
export const MenuGroup: FC<MenuGroupProps> = MenuGoupModule && Object.values(MenuGoupModule).find((e: Export) => typeof e == "function" && e?.toString()?.includes("bInGamepadUI:"));
|
|
29
|
+
export const MenuGroup: FC<MenuGroupProps> = MenuGoupModule && Object.values(MenuGoupModule).find((e: Export) => typeof e == "function" && e?.toString?.()?.includes("bInGamepadUI:"));
|
|
30
30
|
export interface MenuItemProps extends FooterLegendProps {
|
|
31
31
|
bInteractableItem?: boolean;
|
|
32
32
|
onClick?(evt: Event): void;
|
|
@@ -42,7 +42,7 @@ export interface MenuItemProps extends FooterLegendProps {
|
|
|
42
42
|
|
|
43
43
|
export const MenuItem: FC<MenuItemProps> = findModuleExport(
|
|
44
44
|
(e: Export) =>
|
|
45
|
-
e?.render?.toString()?.includes('bPlayAudio:') || (e?.prototype?.OnOKButton && e?.prototype?.OnMouseEnter),
|
|
45
|
+
e?.render?.toString?.()?.includes('bPlayAudio:') || (e?.prototype?.OnOKButton && e?.prototype?.OnMouseEnter),
|
|
46
46
|
);
|
|
47
47
|
|
|
48
48
|
/*
|
package/src/components/Modal.ts
CHANGED
|
@@ -50,7 +50,7 @@ export const showModal = (
|
|
|
50
50
|
bHideMainWindowForPopouts: false,
|
|
51
51
|
},
|
|
52
52
|
): ShowModalResult => {
|
|
53
|
-
return showModalRaw(modal, parent || findSP(), props.strTitle, props, undefined, {
|
|
53
|
+
return showModalRaw(modal, parent || findSP() || window, props.strTitle, props, undefined, {
|
|
54
54
|
bHideActions: props.bHideActionIcons,
|
|
55
55
|
});
|
|
56
56
|
};
|
|
@@ -98,7 +98,7 @@ export const ModalRoot = Object.values(
|
|
|
98
98
|
|
|
99
99
|
return false;
|
|
100
100
|
}) || {},
|
|
101
|
-
)?.find((x: any) => x?.type?.toString()?.includes('((function(){')) as FC<ModalRootProps>;
|
|
101
|
+
)?.find((x: any) => x?.type?.toString?.()?.includes('((function(){')) as FC<ModalRootProps>;
|
|
102
102
|
|
|
103
103
|
interface SimpleModalProps {
|
|
104
104
|
active?: boolean;
|
package/src/components/Panel.ts
CHANGED
|
@@ -22,5 +22,5 @@ export interface PanelSectionRowProps {
|
|
|
22
22
|
children?: ReactNode;
|
|
23
23
|
}
|
|
24
24
|
export const PanelSectionRow = Object.values(mod).filter(
|
|
25
|
-
(exp: any) => !exp?.toString()?.includes('.PanelSection'),
|
|
25
|
+
(exp: any) => !exp?.toString?.()?.includes('.PanelSection'),
|
|
26
26
|
)[0] as FC<PanelSectionRowProps>;
|
|
@@ -24,11 +24,11 @@ export interface ProgressBarWithInfoProps extends ProgressBarItemProps {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export const ProgressBar = findModuleExport((e: Export) =>
|
|
27
|
-
e?.toString()?.includes('.ProgressBar,"standard"=='),
|
|
27
|
+
e?.toString?.()?.includes('.ProgressBar,"standard"=='),
|
|
28
28
|
) as FC<ProgressBarProps>;
|
|
29
29
|
|
|
30
30
|
export const ProgressBarWithInfo = findModuleExport((e: Export) =>
|
|
31
|
-
e?.toString()?.includes('.ProgressBarFieldStatus},'),
|
|
31
|
+
e?.toString?.()?.includes('.ProgressBarFieldStatus},'),
|
|
32
32
|
) as FC<ProgressBarWithInfoProps>;
|
|
33
33
|
|
|
34
34
|
const progressBarItemRegex = createPropListRegex(["indeterminate", "nTransitionSec", "nProgress"]);
|
|
@@ -30,5 +30,5 @@ export interface SliderFieldProps extends ItemProps {
|
|
|
30
30
|
|
|
31
31
|
export const SliderField = Object.values(CommonUIModule).find((mod: any) =>
|
|
32
32
|
// stable || beta as of oct 2 2024
|
|
33
|
-
mod?.toString()?.includes('SliderField,fallback') || mod?.toString()?.includes("SliderField\",")
|
|
33
|
+
mod?.toString?.()?.includes('SliderField,fallback') || mod?.toString?.()?.includes("SliderField\",")
|
|
34
34
|
) as FC<SliderFieldProps>;
|
package/src/components/Tabs.tsx
CHANGED
|
@@ -62,9 +62,9 @@ export interface TabsProps {
|
|
|
62
62
|
autoFocusContents?: boolean;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
const tabsModule = findModuleByExport(e => e?.toString()?.includes(".TabRowTabs") && e?.toString()?.includes("activeTab:"));
|
|
65
|
+
const tabsModule = findModuleByExport(e => e?.toString?.()?.includes(".TabRowTabs") && e?.toString?.()?.includes("activeTab:"));
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* Tabs component as used in the library and media tabs. See {@link TabsProps}.
|
|
69
69
|
*/
|
|
70
|
-
export const Tabs = tabsModule && Object.values(tabsModule).find((e: any) => e?.type?.toString()?.includes("((function()")) as FC<TabsProps>;
|
|
70
|
+
export const Tabs = tabsModule && Object.values(tabsModule).find((e: any) => e?.type?.toString?.()?.includes("((function()")) as FC<TabsProps>;
|
package/src/components/Toggle.ts
CHANGED
|
@@ -12,5 +12,5 @@ export interface ToggleFieldProps extends ItemProps {
|
|
|
12
12
|
|
|
13
13
|
export const ToggleField = Object.values(CommonUIModule).find((mod: any) =>
|
|
14
14
|
// stable || beta as of oct 2 2024
|
|
15
|
-
mod?.render?.toString()?.includes('ToggleField,fallback') || mod?.render?.toString()?.includes("ToggleField\",")
|
|
15
|
+
mod?.render?.toString?.()?.includes('ToggleField,fallback') || mod?.render?.toString?.()?.includes("ToggleField\",")
|
|
16
16
|
) as FC<ToggleFieldProps>;
|
package/src/modules/Router.ts
CHANGED
|
@@ -144,8 +144,8 @@ try {
|
|
|
144
144
|
logger.warn("Navigation interface failed to call GetFocusedWindowInstance", e);
|
|
145
145
|
}
|
|
146
146
|
if (!win) {
|
|
147
|
-
logger.warn("Navigation interface could not find any focused window. Falling back to
|
|
148
|
-
win = Router.WindowStore?.GamepadUIMainWindowInstance;
|
|
147
|
+
logger.warn("Navigation interface could not find any focused window. Falling back to Main Window Instance");
|
|
148
|
+
win = Router.WindowStore?.GamepadUIMainWindowInstance || Router?.WindowStore?.SteamUIWindows?.[0];
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
if (win) {
|
package/src/utils/react/react.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { Ref, useState } from 'react';
|
|
2
3
|
|
|
3
4
|
// this shouldn't need to be redeclared but it does for some reason
|
|
4
5
|
|
|
@@ -150,3 +151,21 @@ export const findInReactTree = (node: any, filter: findInTreeFilter) =>
|
|
|
150
151
|
// Specialised findInTree for React nodes
|
|
151
152
|
walkable: ['props', 'children', 'child', 'sibling'],
|
|
152
153
|
});
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Finds the parent window of a DOM element
|
|
157
|
+
*/
|
|
158
|
+
export function getParentWindow<WindowType = Window>(elem: HTMLElement | null): WindowType | null | undefined {
|
|
159
|
+
return elem?.ownerDocument?.defaultView as any;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* React hook to find the host window of a component
|
|
164
|
+
* Pass the returned ref into a React element and window will be its host window.
|
|
165
|
+
* @returns [ref, window]
|
|
166
|
+
*/
|
|
167
|
+
export function useWindowRef<RefElementType extends HTMLElement, WindowType = Window>(): [Ref<RefElementType>, WindowType | null | undefined] {
|
|
168
|
+
const [win, setWin] = useState<WindowType | null | undefined>(null);
|
|
169
|
+
|
|
170
|
+
return [(elem) => setWin(getParentWindow<WindowType>(elem)), win];
|
|
171
|
+
}
|