@decky/ui 4.0.0

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.
Files changed (150) hide show
  1. package/LICENSE +504 -0
  2. package/README.md +27 -0
  3. package/dist/class-mapper.d.ts +7 -0
  4. package/dist/class-mapper.js +26 -0
  5. package/dist/components/Button.d.ts +5 -0
  6. package/dist/components/Button.js +2 -0
  7. package/dist/components/ButtonItem.d.ts +7 -0
  8. package/dist/components/ButtonItem.js +3 -0
  9. package/dist/components/Carousel.d.ts +19 -0
  10. package/dist/components/Carousel.js +2 -0
  11. package/dist/components/ControlsList.d.ts +6 -0
  12. package/dist/components/ControlsList.js +2 -0
  13. package/dist/components/Dialog.d.ts +32 -0
  14. package/dist/components/Dialog.js +19 -0
  15. package/dist/components/DialogCheckbox.d.ts +17 -0
  16. package/dist/components/DialogCheckbox.js +14 -0
  17. package/dist/components/Dropdown.d.ts +34 -0
  18. package/dist/components/Dropdown.js +3 -0
  19. package/dist/components/Field.d.ts +22 -0
  20. package/dist/components/Field.js +2 -0
  21. package/dist/components/FocusRing.d.ts +9 -0
  22. package/dist/components/FocusRing.js +2 -0
  23. package/dist/components/Focusable.d.ts +12 -0
  24. package/dist/components/Focusable.js +2 -0
  25. package/dist/components/FooterLegend.d.ts +66 -0
  26. package/dist/components/FooterLegend.js +32 -0
  27. package/dist/components/Item.d.ts +11 -0
  28. package/dist/components/Item.js +1 -0
  29. package/dist/components/Marquee.d.ts +14 -0
  30. package/dist/components/Marquee.js +2 -0
  31. package/dist/components/Menu.d.ts +29 -0
  32. package/dist/components/Menu.js +8 -0
  33. package/dist/components/Modal.d.ts +52 -0
  34. package/dist/components/Modal.js +29 -0
  35. package/dist/components/Panel.d.ts +11 -0
  36. package/dist/components/Panel.js +4 -0
  37. package/dist/components/ProgressBar.d.ts +21 -0
  38. package/dist/components/ProgressBar.js +4 -0
  39. package/dist/components/Scroll.d.ts +7 -0
  40. package/dist/components/Scroll.js +5 -0
  41. package/dist/components/SidebarNavigation.d.ts +21 -0
  42. package/dist/components/SidebarNavigation.js +2 -0
  43. package/dist/components/SliderField.d.ts +26 -0
  44. package/dist/components/SliderField.js +2 -0
  45. package/dist/components/Spinner.d.ts +2 -0
  46. package/dist/components/Spinner.js +2 -0
  47. package/dist/components/SteamSpinner.d.ts +2 -0
  48. package/dist/components/SteamSpinner.js +2 -0
  49. package/dist/components/Tabs.d.ts +16 -0
  50. package/dist/components/Tabs.js +48 -0
  51. package/dist/components/TextField.d.ts +22 -0
  52. package/dist/components/TextField.js +2 -0
  53. package/dist/components/Toggle.d.ts +8 -0
  54. package/dist/components/Toggle.js +2 -0
  55. package/dist/components/ToggleField.d.ts +9 -0
  56. package/dist/components/ToggleField.js +2 -0
  57. package/dist/components/index.d.ts +25 -0
  58. package/dist/components/index.js +25 -0
  59. package/dist/custom-components/ColorPickerModal.d.ts +12 -0
  60. package/dist/custom-components/ColorPickerModal.js +87 -0
  61. package/dist/custom-components/ReorderableList.d.ts +26 -0
  62. package/dist/custom-components/ReorderableList.js +84 -0
  63. package/dist/custom-components/SuspensefulImage.d.ts +7 -0
  64. package/dist/custom-components/SuspensefulImage.js +27 -0
  65. package/dist/custom-components/index.d.ts +3 -0
  66. package/dist/custom-components/index.js +3 -0
  67. package/dist/custom-hooks/index.d.ts +1 -0
  68. package/dist/custom-hooks/index.js +1 -0
  69. package/dist/custom-hooks/useQuickAccessVisible.d.ts +1 -0
  70. package/dist/custom-hooks/useQuickAccessVisible.js +22 -0
  71. package/dist/deck-hooks/index.d.ts +1 -0
  72. package/dist/deck-hooks/index.js +1 -0
  73. package/dist/deck-hooks/useParams.d.ts +1 -0
  74. package/dist/deck-hooks/useParams.js +2 -0
  75. package/dist/globals/SteamClient.d.ts +307 -0
  76. package/dist/globals/SteamClient.js +1 -0
  77. package/dist/globals/index.d.ts +2 -0
  78. package/dist/globals/index.js +2 -0
  79. package/dist/globals/stores.d.ts +50 -0
  80. package/dist/globals/stores.js +1 -0
  81. package/dist/index.d.ts +10 -0
  82. package/dist/index.js +10 -0
  83. package/dist/logger.d.ts +17 -0
  84. package/dist/logger.js +46 -0
  85. package/dist/modules/Router.d.ts +110 -0
  86. package/dist/modules/Router.js +102 -0
  87. package/dist/modules/index.d.ts +1 -0
  88. package/dist/modules/index.js +1 -0
  89. package/dist/plugin.d.ts +68 -0
  90. package/dist/plugin.js +5 -0
  91. package/dist/utils/index.d.ts +12 -0
  92. package/dist/utils/index.js +23 -0
  93. package/dist/utils/patcher.d.ts +18 -0
  94. package/dist/utils/patcher.js +103 -0
  95. package/dist/utils/react.d.ts +18 -0
  96. package/dist/utils/react.js +74 -0
  97. package/dist/utils/static-classes.d.ts +52 -0
  98. package/dist/utils/static-classes.js +28 -0
  99. package/dist/webpack.d.ts +21 -0
  100. package/dist/webpack.js +102 -0
  101. package/package.json +82 -0
  102. package/src/class-mapper.ts +34 -0
  103. package/src/components/Button.tsx +8 -0
  104. package/src/components/ButtonItem.tsx +14 -0
  105. package/src/components/Carousel.ts +25 -0
  106. package/src/components/ControlsList.tsx +13 -0
  107. package/src/components/Dialog.tsx +86 -0
  108. package/src/components/DialogCheckbox.tsx +36 -0
  109. package/src/components/Dropdown.tsx +49 -0
  110. package/src/components/Field.tsx +28 -0
  111. package/src/components/FocusRing.ts +15 -0
  112. package/src/components/Focusable.tsx +18 -0
  113. package/src/components/FooterLegend.ts +67 -0
  114. package/src/components/Item.tsx +12 -0
  115. package/src/components/Marquee.tsx +20 -0
  116. package/src/components/Menu.tsx +57 -0
  117. package/src/components/Modal.tsx +119 -0
  118. package/src/components/Panel.tsx +26 -0
  119. package/src/components/ProgressBar.tsx +35 -0
  120. package/src/components/Scroll.tsx +15 -0
  121. package/src/components/SidebarNavigation.tsx +28 -0
  122. package/src/components/SliderField.tsx +33 -0
  123. package/src/components/Spinner.tsx +8 -0
  124. package/src/components/SteamSpinner.tsx +7 -0
  125. package/src/components/Tabs.tsx +127 -0
  126. package/src/components/TextField.tsx +28 -0
  127. package/src/components/Toggle.tsx +14 -0
  128. package/src/components/ToggleField.tsx +15 -0
  129. package/src/components/index.ts +25 -0
  130. package/src/custom-components/ColorPickerModal.tsx +132 -0
  131. package/src/custom-components/ReorderableList.tsx +183 -0
  132. package/src/custom-components/SuspensefulImage.tsx +44 -0
  133. package/src/custom-components/index.ts +3 -0
  134. package/src/custom-hooks/index.ts +1 -0
  135. package/src/custom-hooks/useQuickAccessVisible.tsx +63 -0
  136. package/src/deck-hooks/index.ts +1 -0
  137. package/src/deck-hooks/useParams.ts +15 -0
  138. package/src/globals/SteamClient.ts +321 -0
  139. package/src/globals/index.ts +2 -0
  140. package/src/globals/stores.ts +50 -0
  141. package/src/index.ts +11 -0
  142. package/src/logger.ts +77 -0
  143. package/src/modules/Router.tsx +174 -0
  144. package/src/modules/index.ts +1 -0
  145. package/src/plugin.tsx +96 -0
  146. package/src/utils/index.ts +43 -0
  147. package/src/utils/patcher.ts +160 -0
  148. package/src/utils/react.ts +119 -0
  149. package/src/utils/static-classes.ts +1104 -0
  150. package/src/webpack.ts +136 -0
@@ -0,0 +1,19 @@
1
+ import { CommonUIModule } from '../webpack';
2
+ const CommonDialogDivs = Object.values(CommonUIModule).filter((m) => typeof m === 'object' && m?.render?.toString().includes('"div",Object.assign({},'));
3
+ const MappedDialogDivs = new Map(Object.values(CommonDialogDivs).map((m) => {
4
+ const renderedDiv = m.render({});
5
+ return [renderedDiv.props.className.split(' ')[0], m];
6
+ }));
7
+ export const DialogHeader = MappedDialogDivs.get('DialogHeader');
8
+ export const DialogSubHeader = MappedDialogDivs.get('DialogSubHeader');
9
+ export const DialogFooter = MappedDialogDivs.get('DialogFooter');
10
+ export const DialogLabel = MappedDialogDivs.get('DialogLabel');
11
+ export const DialogBodyText = MappedDialogDivs.get('DialogBodyText');
12
+ export const DialogBody = MappedDialogDivs.get('DialogBody');
13
+ export const DialogControlsSection = MappedDialogDivs.get('DialogControlsSection');
14
+ export const DialogControlsSectionHeader = MappedDialogDivs.get('DialogControlsSectionHeader');
15
+ export const DialogButtonPrimary = Object.values(CommonUIModule).find((mod) => mod?.render?.toString()?.includes('DialogButton') && mod?.render?.toString()?.includes('Primary'));
16
+ export const DialogButtonSecondary = Object.values(CommonUIModule).find((mod) => mod?.render?.toString()?.includes('Object.assign({type:"button"') &&
17
+ mod?.render?.toString()?.includes('DialogButton') &&
18
+ mod?.render?.toString()?.includes('Secondary'));
19
+ export const DialogButton = DialogButtonSecondary;
@@ -0,0 +1,17 @@
1
+ import { FC, ReactNode } from 'react';
2
+ import { DialogCommonProps } from './Dialog';
3
+ import { FooterLegendProps } from './FooterLegend';
4
+ export interface DialogCheckboxProps extends DialogCommonProps, FooterLegendProps {
5
+ onChange?(checked: boolean): void;
6
+ label?: ReactNode;
7
+ description?: ReactNode;
8
+ disabled?: boolean;
9
+ tooltip?: string;
10
+ color?: string;
11
+ highlightColor?: string;
12
+ bottomSeparator?: 'standard' | 'thick' | 'none';
13
+ controlled?: boolean;
14
+ checked?: boolean;
15
+ onClick?(evt: Event): void;
16
+ }
17
+ export declare const DialogCheckbox: FC<DialogCheckboxProps>;
@@ -0,0 +1,14 @@
1
+ import { findModule } from '../webpack';
2
+ export const DialogCheckbox = Object.values(findModule((m) => {
3
+ if (typeof m !== 'object')
4
+ return false;
5
+ for (const prop in m) {
6
+ if (m[prop]?.prototype?.GetPanelElementProps)
7
+ return true;
8
+ }
9
+ return false;
10
+ })).find((m) => m.contextType &&
11
+ m.prototype?.render.toString().includes('fallback:') &&
12
+ m?.prototype?.SetChecked &&
13
+ m?.prototype?.Toggle &&
14
+ m?.prototype?.GetPanelElementProps);
@@ -0,0 +1,34 @@
1
+ import { ReactNode, VFC } from 'react';
2
+ import { ItemProps } from './Item';
3
+ export interface SingleDropdownOption {
4
+ data: any;
5
+ label: ReactNode;
6
+ options?: never;
7
+ }
8
+ export interface MultiDropdownOption {
9
+ label: ReactNode;
10
+ options: DropdownOption[];
11
+ data?: never;
12
+ }
13
+ export type DropdownOption = SingleDropdownOption | MultiDropdownOption;
14
+ export interface DropdownMenuPositionOptions {
15
+ [_: string]: unknown;
16
+ bMatchWidth?: boolean;
17
+ }
18
+ export interface DropdownProps {
19
+ rgOptions: DropdownOption[];
20
+ selectedOption: any;
21
+ disabled?: boolean;
22
+ onMenuWillOpen?(showMenu: () => void): void;
23
+ onMenuOpened?(): void;
24
+ onChange?(data: SingleDropdownOption): void;
25
+ contextMenuPositionOptions?: DropdownMenuPositionOptions;
26
+ menuLabel?: string;
27
+ strDefaultLabel?: string;
28
+ renderButtonValue?(element: ReactNode): ReactNode;
29
+ focusable?: boolean;
30
+ }
31
+ export declare const Dropdown: VFC<DropdownProps>;
32
+ export interface DropdownItemProps extends DropdownProps, ItemProps {
33
+ }
34
+ export declare const DropdownItem: VFC<DropdownItemProps>;
@@ -0,0 +1,3 @@
1
+ import { CommonUIModule } from '../webpack';
2
+ export const Dropdown = Object.values(CommonUIModule).find((mod) => mod?.prototype?.SetSelectedOption && mod?.prototype?.BuildMenu);
3
+ export const DropdownItem = Object.values(CommonUIModule).find((mod) => mod?.toString()?.includes('"dropDownControlRef","description"'));
@@ -0,0 +1,22 @@
1
+ import { FC, ReactNode, RefAttributes } from 'react';
2
+ import { FooterLegendProps } from './FooterLegend';
3
+ export interface FieldProps extends FooterLegendProps {
4
+ label?: ReactNode;
5
+ bottomSeparator?: 'standard' | 'thick' | 'none';
6
+ description?: ReactNode;
7
+ disabled?: boolean;
8
+ icon?: ReactNode;
9
+ inlineWrap?: 'keep-inline' | 'shift-children-below';
10
+ childrenLayout?: 'below' | 'inline';
11
+ childrenContainerWidth?: 'min' | 'max' | 'fixed';
12
+ spacingBetweenLabelAndChild?: 'none';
13
+ padding?: 'none' | 'standard' | 'compact';
14
+ className?: string;
15
+ highlightOnFocus?: boolean;
16
+ indentLevel?: number;
17
+ verticalAlignment?: 'center' | 'none';
18
+ focusable?: boolean;
19
+ onActivate?: (e: CustomEvent | MouseEvent) => void;
20
+ onClick?: (e: CustomEvent | MouseEvent) => void;
21
+ }
22
+ export declare const Field: FC<FieldProps & RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,2 @@
1
+ import { findModuleExport } from '../webpack';
2
+ export const Field = findModuleExport((e) => e?.render?.toString().includes('"shift-children-below"'));
@@ -0,0 +1,9 @@
1
+ import { ElementType, FC, ReactNode } from 'react';
2
+ export interface FocusRingProps {
3
+ className?: string;
4
+ rootClassName?: string;
5
+ render?: ElementType;
6
+ children?: ReactNode;
7
+ NavigationManager?: any;
8
+ }
9
+ export declare const FocusRing: FC<FocusRingProps>;
@@ -0,0 +1,2 @@
1
+ import { findModuleExport } from '../webpack';
2
+ export const FocusRing = findModuleExport((e) => e?.toString()?.includes('.GetShowDebugFocusRing())'));
@@ -0,0 +1,12 @@
1
+ import { HTMLAttributes, ReactNode, RefAttributes, VFC } from 'react';
2
+ import { FooterLegendProps } from './FooterLegend';
3
+ export interface FocusableProps extends HTMLAttributes<HTMLDivElement>, FooterLegendProps {
4
+ children: ReactNode;
5
+ 'flow-children'?: string;
6
+ focusClassName?: string;
7
+ focusWithinClassName?: string;
8
+ noFocusRing?: boolean;
9
+ onActivate?: (e: CustomEvent) => void;
10
+ onCancel?: (e: CustomEvent) => void;
11
+ }
12
+ export declare const Focusable: VFC<FocusableProps & RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,2 @@
1
+ import { findModuleExport } from '../webpack';
2
+ export const Focusable = findModuleExport((e) => e?.render?.toString()?.includes('["flow-children","onActivate","onCancel","focusClassName",'));
@@ -0,0 +1,66 @@
1
+ import { ReactNode } from 'react';
2
+ export declare enum GamepadButton {
3
+ INVALID = 0,
4
+ OK = 1,
5
+ CANCEL = 2,
6
+ SECONDARY = 3,
7
+ OPTIONS = 4,
8
+ BUMPER_LEFT = 5,
9
+ BUMPER_RIGHT = 6,
10
+ TRIGGER_LEFT = 7,
11
+ TRIGGER_RIGHT = 8,
12
+ DIR_UP = 9,
13
+ DIR_DOWN = 10,
14
+ DIR_LEFT = 11,
15
+ DIR_RIGHT = 12,
16
+ SELECT = 13,
17
+ START = 14,
18
+ LSTICK_CLICK = 15,
19
+ RSTICK_CLICK = 16,
20
+ LSTICK_TOUCH = 17,
21
+ RSTICK_TOUCH = 18,
22
+ LPAD_TOUCH = 19,
23
+ LPAD_CLICK = 20,
24
+ RPAD_TOUCH = 21,
25
+ RPAD_CLICK = 22,
26
+ REAR_LEFT_UPPER = 23,
27
+ REAR_LEFT_LOWER = 24,
28
+ REAR_RIGHT_UPPER = 25,
29
+ REAR_RIGHT_LOWER = 26,
30
+ STEAM_GUIDE = 27,
31
+ STEAM_QUICK_MENU = 28
32
+ }
33
+ export declare enum NavEntryPositionPreferences {
34
+ FIRST,
35
+ LAST,
36
+ MAINTAIN_X,
37
+ MAINTAIN_Y,
38
+ PREFERRED_CHILD
39
+ }
40
+ export interface GamepadEventDetail {
41
+ button: number;
42
+ is_repeat?: boolean;
43
+ source: number;
44
+ }
45
+ export declare type ActionDescriptionMap = {
46
+ [key in GamepadButton]?: ReactNode;
47
+ };
48
+ export declare type GamepadEvent = CustomEvent<GamepadEventDetail>;
49
+ export interface FooterLegendProps {
50
+ actionDescriptionMap?: ActionDescriptionMap;
51
+ onOKActionDescription?: ReactNode;
52
+ onCancelActionDescription?: ReactNode;
53
+ onSecondaryActionDescription?: ReactNode;
54
+ onOptionsActionDescription?: ReactNode;
55
+ onMenuActionDescription?: ReactNode;
56
+ onButtonDown?: (evt: GamepadEvent) => void;
57
+ onButtonUp?: (evt: GamepadEvent) => void;
58
+ onOKButton?: (evt: GamepadEvent) => void;
59
+ onCancelButton?: (evt: GamepadEvent) => void;
60
+ onSecondaryButton?: (evt: GamepadEvent) => void;
61
+ onOptionsButton?: (evt: GamepadEvent) => void;
62
+ onGamepadDirection?: (evt: GamepadEvent) => void;
63
+ onGamepadFocus?: (evt: GamepadEvent) => void;
64
+ onGamepadBlur?: (evt: GamepadEvent) => void;
65
+ onMenuButton?: (evt: GamepadEvent) => void;
66
+ }
@@ -0,0 +1,32 @@
1
+ export var GamepadButton;
2
+ (function (GamepadButton) {
3
+ GamepadButton[GamepadButton["INVALID"] = 0] = "INVALID";
4
+ GamepadButton[GamepadButton["OK"] = 1] = "OK";
5
+ GamepadButton[GamepadButton["CANCEL"] = 2] = "CANCEL";
6
+ GamepadButton[GamepadButton["SECONDARY"] = 3] = "SECONDARY";
7
+ GamepadButton[GamepadButton["OPTIONS"] = 4] = "OPTIONS";
8
+ GamepadButton[GamepadButton["BUMPER_LEFT"] = 5] = "BUMPER_LEFT";
9
+ GamepadButton[GamepadButton["BUMPER_RIGHT"] = 6] = "BUMPER_RIGHT";
10
+ GamepadButton[GamepadButton["TRIGGER_LEFT"] = 7] = "TRIGGER_LEFT";
11
+ GamepadButton[GamepadButton["TRIGGER_RIGHT"] = 8] = "TRIGGER_RIGHT";
12
+ GamepadButton[GamepadButton["DIR_UP"] = 9] = "DIR_UP";
13
+ GamepadButton[GamepadButton["DIR_DOWN"] = 10] = "DIR_DOWN";
14
+ GamepadButton[GamepadButton["DIR_LEFT"] = 11] = "DIR_LEFT";
15
+ GamepadButton[GamepadButton["DIR_RIGHT"] = 12] = "DIR_RIGHT";
16
+ GamepadButton[GamepadButton["SELECT"] = 13] = "SELECT";
17
+ GamepadButton[GamepadButton["START"] = 14] = "START";
18
+ GamepadButton[GamepadButton["LSTICK_CLICK"] = 15] = "LSTICK_CLICK";
19
+ GamepadButton[GamepadButton["RSTICK_CLICK"] = 16] = "RSTICK_CLICK";
20
+ GamepadButton[GamepadButton["LSTICK_TOUCH"] = 17] = "LSTICK_TOUCH";
21
+ GamepadButton[GamepadButton["RSTICK_TOUCH"] = 18] = "RSTICK_TOUCH";
22
+ GamepadButton[GamepadButton["LPAD_TOUCH"] = 19] = "LPAD_TOUCH";
23
+ GamepadButton[GamepadButton["LPAD_CLICK"] = 20] = "LPAD_CLICK";
24
+ GamepadButton[GamepadButton["RPAD_TOUCH"] = 21] = "RPAD_TOUCH";
25
+ GamepadButton[GamepadButton["RPAD_CLICK"] = 22] = "RPAD_CLICK";
26
+ GamepadButton[GamepadButton["REAR_LEFT_UPPER"] = 23] = "REAR_LEFT_UPPER";
27
+ GamepadButton[GamepadButton["REAR_LEFT_LOWER"] = 24] = "REAR_LEFT_LOWER";
28
+ GamepadButton[GamepadButton["REAR_RIGHT_UPPER"] = 25] = "REAR_RIGHT_UPPER";
29
+ GamepadButton[GamepadButton["REAR_RIGHT_LOWER"] = 26] = "REAR_RIGHT_LOWER";
30
+ GamepadButton[GamepadButton["STEAM_GUIDE"] = 27] = "STEAM_GUIDE";
31
+ GamepadButton[GamepadButton["STEAM_QUICK_MENU"] = 28] = "STEAM_QUICK_MENU";
32
+ })(GamepadButton || (GamepadButton = {}));
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ export interface ItemProps {
3
+ label?: ReactNode;
4
+ description?: ReactNode;
5
+ layout?: 'below' | 'inline';
6
+ icon?: ReactNode;
7
+ bottomSeparator?: 'standard' | 'thick' | 'none';
8
+ indentLevel?: number;
9
+ tooltip?: string;
10
+ highlightOnFocus?: boolean;
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { CSSProperties, FC } from 'react';
2
+ export interface MarqueeProps {
3
+ play?: boolean;
4
+ direction?: 'left' | 'right';
5
+ speed?: number;
6
+ delay?: number;
7
+ fadeLength?: number;
8
+ center?: boolean;
9
+ resetOnPause?: boolean;
10
+ style?: CSSProperties;
11
+ className?: string;
12
+ children: React.ReactNode;
13
+ }
14
+ export declare const Marquee: FC<MarqueeProps>;
@@ -0,0 +1,2 @@
1
+ import { findModuleExport } from '../webpack';
2
+ export const Marquee = findModuleExport((e) => e?.toString && e.toString().includes('.Marquee') && e.toString().includes('--fade-length'));
@@ -0,0 +1,29 @@
1
+ import { FC, ReactNode } from 'react';
2
+ import { FooterLegendProps } from './FooterLegend';
3
+ export declare const showContextMenu: (children: ReactNode, parent?: EventTarget) => void;
4
+ export interface MenuProps extends FooterLegendProps {
5
+ label: string;
6
+ onCancel?(): void;
7
+ cancelText?: string;
8
+ children?: ReactNode;
9
+ }
10
+ export declare const Menu: FC<MenuProps>;
11
+ export interface MenuGroupProps {
12
+ label: string;
13
+ disabled?: boolean;
14
+ children?: ReactNode;
15
+ }
16
+ export declare const MenuGroup: FC<MenuGroupProps>;
17
+ export interface MenuItemProps extends FooterLegendProps {
18
+ bInteractableItem?: boolean;
19
+ onClick?(evt: Event): void;
20
+ onSelected?(evt: Event): void;
21
+ onMouseEnter?(evt: MouseEvent): void;
22
+ onMoveRight?(): void;
23
+ selected?: boolean;
24
+ disabled?: boolean;
25
+ bPlayAudio?: boolean;
26
+ tone?: 'positive' | 'emphasis' | 'destructive';
27
+ children?: ReactNode;
28
+ }
29
+ export declare const MenuItem: FC<MenuItemProps>;
@@ -0,0 +1,8 @@
1
+ import { fakeRenderComponent } from '../utils';
2
+ import { findModuleExport } from '../webpack';
3
+ export const showContextMenu = findModuleExport((e) => typeof e === 'function' && e.toString().includes('stopPropagation))'));
4
+ export const Menu = findModuleExport((e) => e?.prototype?.HideIfSubmenu && e?.prototype?.HideMenu);
5
+ export const MenuGroup = findModuleExport((e) => (e?.toString()?.includes?.('bInGamepadUI:') &&
6
+ fakeRenderComponent(() => e({ overview: { appid: 7 } }))?.type?.prototype?.RenderSubMenu) ||
7
+ (e?.prototype?.RenderSubMenu && e?.prototype?.ShowSubMenu));
8
+ export const MenuItem = findModuleExport((e) => e?.render?.toString()?.includes('bPlayAudio:') || (e?.prototype?.OnOKButton && e?.prototype?.OnMouseEnter));
@@ -0,0 +1,52 @@
1
+ import { FC, ReactNode } from 'react';
2
+ export interface ShowModalProps {
3
+ browserContext?: unknown;
4
+ bForcePopOut?: boolean;
5
+ bHideActionIcons?: boolean;
6
+ bHideMainWindowForPopouts?: boolean;
7
+ bNeverPopOut?: boolean;
8
+ fnOnClose?: () => void;
9
+ popupHeight?: number;
10
+ popupWidth?: number;
11
+ promiseRenderComplete?: Promise<void>;
12
+ strTitle?: string;
13
+ }
14
+ export interface ShowModalResult {
15
+ Close: () => void;
16
+ Update: (modal: ReactNode) => void;
17
+ }
18
+ export declare const showModal: (modal: ReactNode, parent?: EventTarget, props?: ShowModalProps) => ShowModalResult;
19
+ export interface ModalRootProps {
20
+ children?: ReactNode;
21
+ onCancel?(): void;
22
+ closeModal?(): void;
23
+ onOK?(): void;
24
+ onEscKeypress?(): void;
25
+ className?: string;
26
+ modalClassName?: string;
27
+ bAllowFullSize?: boolean;
28
+ bDestructiveWarning?: boolean;
29
+ bDisableBackgroundDismiss?: boolean;
30
+ bHideCloseIcon?: boolean;
31
+ bOKDisabled?: boolean;
32
+ bCancelDisabled?: boolean;
33
+ }
34
+ export interface ConfirmModalProps extends ModalRootProps {
35
+ onMiddleButton?(): void;
36
+ strTitle?: ReactNode;
37
+ strDescription?: ReactNode;
38
+ strOKButtonText?: ReactNode;
39
+ strCancelButtonText?: ReactNode;
40
+ strMiddleButtonText?: ReactNode;
41
+ bAlertDialog?: boolean;
42
+ bMiddleDisabled?: boolean;
43
+ }
44
+ export declare const ConfirmModal: FC<ConfirmModalProps>;
45
+ export declare const ModalRoot: FC<ModalRootProps>;
46
+ interface SimpleModalProps {
47
+ active?: boolean;
48
+ children: ReactNode;
49
+ }
50
+ export declare const SimpleModal: FC<SimpleModalProps>;
51
+ export declare const ModalPosition: FC<SimpleModalProps>;
52
+ export {};
@@ -0,0 +1,29 @@
1
+ import { findSP } from '../utils';
2
+ import { findModule, findModuleByExport, findModuleExport } from '../webpack';
3
+ const showModalRaw = findModuleExport((e) => typeof e === 'function' && e.toString().includes('props.bDisableBackgroundDismiss') && !e?.prototype?.Cancel);
4
+ export const showModal = (modal, parent, props = {
5
+ strTitle: 'Decky Dialog',
6
+ bHideMainWindowForPopouts: false,
7
+ }) => {
8
+ return showModalRaw(modal, parent || findSP(), props.strTitle, props, undefined, {
9
+ bHideActions: props.bHideActionIcons,
10
+ });
11
+ };
12
+ export const ConfirmModal = findModuleExport((e) => !e?.prototype?.OK && e?.prototype?.Cancel && e?.prototype?.render);
13
+ export const ModalRoot = Object.values(findModule((m) => {
14
+ if (typeof m !== 'object')
15
+ return false;
16
+ for (let prop in m) {
17
+ if (m[prop]?.m_mapModalManager && Object.values(m)?.find((x) => x?.type)) {
18
+ return true;
19
+ }
20
+ }
21
+ return false;
22
+ }) || {})?.find((x) => x?.type?.toString()?.includes('((function(){'));
23
+ const ModalModule = findModuleByExport((e) => e?.toString().includes('.ModalPosition,fallback:'), 5);
24
+ const ModalModuleProps = ModalModule ? Object.values(ModalModule) : [];
25
+ export const SimpleModal = ModalModuleProps.find((prop) => {
26
+ const string = prop?.toString();
27
+ return string?.includes('.ShowPortalModal()') && string?.includes('.OnElementReadyCallbacks.Register(');
28
+ });
29
+ export const ModalPosition = ModalModuleProps.find((prop) => prop?.toString().includes('.ModalPosition,fallback:'));
@@ -0,0 +1,11 @@
1
+ import { FC, ReactNode } from 'react';
2
+ export interface PanelSectionProps {
3
+ title?: string;
4
+ spinner?: boolean;
5
+ children?: ReactNode;
6
+ }
7
+ export declare const PanelSection: FC<PanelSectionProps>;
8
+ export interface PanelSectionRowProps {
9
+ children?: ReactNode;
10
+ }
11
+ export declare const PanelSectionRow: FC<PanelSectionRowProps>;
@@ -0,0 +1,4 @@
1
+ import { findModuleDetailsByExport } from '../webpack';
2
+ const [mod, panelSection] = findModuleDetailsByExport((e) => e.toString()?.includes('.PanelSection'));
3
+ export const PanelSection = panelSection;
4
+ export const PanelSectionRow = Object.values(mod).filter((exp) => !exp?.toString()?.includes('.PanelSection'))[0];
@@ -0,0 +1,21 @@
1
+ import { ReactNode, VFC } from 'react';
2
+ import { ItemProps } from './Item';
3
+ export interface ProgressBarItemProps extends ItemProps {
4
+ indeterminate?: boolean;
5
+ nTransitionSec?: number;
6
+ nProgress?: number;
7
+ focusable?: boolean;
8
+ }
9
+ export interface ProgressBarProps {
10
+ indeterminate?: boolean;
11
+ nTransitionSec?: number;
12
+ nProgress?: number;
13
+ focusable?: boolean;
14
+ }
15
+ export interface ProgressBarWithInfoProps extends ProgressBarItemProps {
16
+ sTimeRemaining?: ReactNode;
17
+ sOperationText?: ReactNode;
18
+ }
19
+ export declare const ProgressBar: VFC<ProgressBarProps>;
20
+ export declare const ProgressBarWithInfo: VFC<ProgressBarWithInfoProps>;
21
+ export declare const ProgressBarItem: VFC<ProgressBarItemProps>;
@@ -0,0 +1,4 @@
1
+ import { findModuleExport } from '../webpack';
2
+ export const ProgressBar = findModuleExport((e) => e?.toString()?.includes('.ProgressBar,"standard"=='));
3
+ export const ProgressBarWithInfo = findModuleExport((e) => e?.toString()?.includes('.ProgressBarFieldStatus},'));
4
+ export const ProgressBarItem = findModuleExport((e) => e?.toString()?.includes('"indeterminate","nTransitionSec"'));
@@ -0,0 +1,7 @@
1
+ import { FC, ReactNode } from 'react';
2
+ export declare const ScrollPanel: FC<{
3
+ children?: ReactNode;
4
+ }>;
5
+ export declare const ScrollPanelGroup: FC<{
6
+ children?: ReactNode;
7
+ }>;
@@ -0,0 +1,5 @@
1
+ import { findModuleByExport, findModuleExport } from '../webpack';
2
+ const ScrollingModule = findModuleByExport((e) => e?.render?.toString?.().includes('{case"x":'));
3
+ const ScrollingModuleProps = ScrollingModule ? Object.values(ScrollingModule) : [];
4
+ export const ScrollPanel = ScrollingModuleProps.find((prop) => prop?.render?.toString?.().includes('{case"x":'));
5
+ export const ScrollPanelGroup = findModuleExport((e) => e?.render?.toString().includes('.FocusVisibleChild()),[])'));
@@ -0,0 +1,21 @@
1
+ import { ReactNode, VFC } from 'react';
2
+ export interface SidebarNavigationPage {
3
+ title: ReactNode;
4
+ content: ReactNode;
5
+ icon?: ReactNode;
6
+ visible?: boolean;
7
+ hideTitle?: boolean;
8
+ identifier?: string;
9
+ route?: string;
10
+ link?: string;
11
+ padding?: 'none' | 'compact';
12
+ }
13
+ export interface SidebarNavigationProps {
14
+ title?: string;
15
+ pages: (SidebarNavigationPage | 'separator')[];
16
+ showTitle?: boolean;
17
+ disableRouteReporting?: boolean;
18
+ page?: string;
19
+ onPageRequested?: (page: string) => void;
20
+ }
21
+ export declare const SidebarNavigation: VFC<SidebarNavigationProps>;
@@ -0,0 +1,2 @@
1
+ import { findModuleExport } from '../webpack';
2
+ export const SidebarNavigation = findModuleExport((e) => e?.toString()?.includes('"disableRouteReporting"'));
@@ -0,0 +1,26 @@
1
+ import { FC } from 'react';
2
+ import { ItemProps } from './Item';
3
+ export interface NotchLabel {
4
+ notchIndex: number;
5
+ label: string;
6
+ value?: number;
7
+ }
8
+ export interface SliderFieldProps extends ItemProps {
9
+ value: number;
10
+ min?: number;
11
+ max?: number;
12
+ step?: number;
13
+ notchCount?: number;
14
+ notchLabels?: NotchLabel[];
15
+ notchTicksVisible?: boolean;
16
+ showValue?: boolean;
17
+ resetValue?: number;
18
+ disabled?: boolean;
19
+ editableValue?: boolean;
20
+ validValues?: 'steps' | 'range' | ((value: number) => boolean);
21
+ valueSuffix?: string;
22
+ minimumDpadGranularity?: number;
23
+ onChange?(value: number): void;
24
+ className?: string;
25
+ }
26
+ export declare const SliderField: FC<SliderFieldProps>;
@@ -0,0 +1,2 @@
1
+ import { CommonUIModule } from '../webpack';
2
+ export const SliderField = Object.values(CommonUIModule).find((mod) => mod?.toString()?.includes('SliderField,fallback'));
@@ -0,0 +1,2 @@
1
+ import { FC, SVGAttributes } from 'react';
2
+ export declare const Spinner: FC<SVGAttributes<SVGElement>>;
@@ -0,0 +1,2 @@
1
+ import { IconsModule } from '../webpack';
2
+ export const Spinner = Object.values(IconsModule).find((mod) => mod?.toString && /Spinner\)}\),.\.createElement\(\"path\",{d:\"M18 /.test(mod.toString()));
@@ -0,0 +1,2 @@
1
+ import { FC, SVGAttributes } from 'react';
2
+ export declare const SteamSpinner: FC<SVGAttributes<SVGElement>>;
@@ -0,0 +1,2 @@
1
+ import { findModuleExport } from '../webpack';
2
+ export const SteamSpinner = findModuleExport((e) => e?.toString?.()?.includes('Steam Spinner') && e?.toString?.()?.includes('src'));
@@ -0,0 +1,16 @@
1
+ import { FC, ReactNode } from 'react';
2
+ import { FooterLegendProps } from './FooterLegend';
3
+ export interface Tab {
4
+ id: string;
5
+ title: string;
6
+ renderTabAddon?: () => ReactNode;
7
+ content: ReactNode;
8
+ footer?: FooterLegendProps;
9
+ }
10
+ export interface TabsProps {
11
+ tabs: Tab[];
12
+ activeTab: string;
13
+ onShowTab: (tab: string) => void;
14
+ autoFocusContents?: boolean;
15
+ }
16
+ export declare const Tabs: FC<TabsProps>;
@@ -0,0 +1,48 @@
1
+ import { createElement, useEffect, useState } from 'react';
2
+ import { fakeRenderComponent, findInReactTree, sleep } from '../utils';
3
+ import { findModuleByExport } from '../webpack';
4
+ import { SteamSpinner } from './SteamSpinner';
5
+ let tabsComponent;
6
+ const getTabs = async () => {
7
+ if (tabsComponent)
8
+ return tabsComponent;
9
+ while (!window?.DeckyPluginLoader?.routerHook?.routes) {
10
+ console.debug('[DFL:Tabs]: Waiting for Decky router...');
11
+ await sleep(500);
12
+ }
13
+ return (tabsComponent = fakeRenderComponent(() => {
14
+ return findInReactTree(findInReactTree(window.DeckyPluginLoader.routerHook.routes
15
+ .find((x) => x.props.path == '/library/app/:appid/achievements')
16
+ .props.children.type(), (x) => x?.props?.scrollTabsTop).type({ appid: 1 }), (x) => x?.props?.tabs).type;
17
+ }, {
18
+ useRef: () => ({ current: { reaction: { track: () => { } } } }),
19
+ useContext: () => ({ match: { params: { appid: 1 } } }),
20
+ useMemo: () => ({ data: {} }),
21
+ }));
22
+ };
23
+ let oldTabs;
24
+ try {
25
+ const oldTabsModule = findModuleByExport((e) => e.Unbleed);
26
+ if (oldTabsModule)
27
+ oldTabs = Object.values(oldTabsModule).find((x) => x?.type?.toString()?.includes('((function(){'));
28
+ }
29
+ catch (e) {
30
+ console.error('Error finding oldTabs:', e);
31
+ }
32
+ export const Tabs = (oldTabs ||
33
+ ((props) => {
34
+ const found = tabsComponent;
35
+ const [tc, setTC] = useState(found);
36
+ useEffect(() => {
37
+ if (found)
38
+ return;
39
+ (async () => {
40
+ console.debug('[DFL:Tabs]: Finding component...');
41
+ const t = await getTabs();
42
+ console.debug('[DFL:Tabs]: Found!');
43
+ setTC(t);
44
+ })();
45
+ }, []);
46
+ console.log('tc', tc);
47
+ return tc ? createElement(tc, props) : window.SP_REACT.createElement(SteamSpinner, null);
48
+ }));
@@ -0,0 +1,22 @@
1
+ import { ChangeEventHandler, HTMLAttributes, ReactNode, VFC } from 'react';
2
+ export interface TextFieldProps extends HTMLAttributes<HTMLInputElement> {
3
+ label?: ReactNode;
4
+ requiredLabel?: ReactNode;
5
+ description?: ReactNode;
6
+ disabled?: boolean;
7
+ bShowCopyAction?: boolean;
8
+ bShowClearAction?: boolean;
9
+ bAlwaysShowClearAction?: boolean;
10
+ bIsPassword?: boolean;
11
+ rangeMin?: number;
12
+ rangeMax?: number;
13
+ mustBeNumeric?: boolean;
14
+ mustBeURL?: boolean;
15
+ mustBeEmail?: boolean;
16
+ focusOnMount?: boolean;
17
+ tooltip?: string;
18
+ inlineControls?: ReactNode;
19
+ onChange?: ChangeEventHandler<HTMLInputElement>;
20
+ value?: string;
21
+ }
22
+ export declare const TextField: VFC<TextFieldProps>;
@@ -0,0 +1,2 @@
1
+ import { CommonUIModule } from '../webpack';
2
+ export const TextField = Object.values(CommonUIModule).find((mod) => mod?.validateUrl && mod?.validateEmail);