@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.
- package/LICENSE +504 -0
- package/README.md +27 -0
- package/dist/class-mapper.d.ts +7 -0
- package/dist/class-mapper.js +26 -0
- package/dist/components/Button.d.ts +5 -0
- package/dist/components/Button.js +2 -0
- package/dist/components/ButtonItem.d.ts +7 -0
- package/dist/components/ButtonItem.js +3 -0
- package/dist/components/Carousel.d.ts +19 -0
- package/dist/components/Carousel.js +2 -0
- package/dist/components/ControlsList.d.ts +6 -0
- package/dist/components/ControlsList.js +2 -0
- package/dist/components/Dialog.d.ts +32 -0
- package/dist/components/Dialog.js +19 -0
- package/dist/components/DialogCheckbox.d.ts +17 -0
- package/dist/components/DialogCheckbox.js +14 -0
- package/dist/components/Dropdown.d.ts +34 -0
- package/dist/components/Dropdown.js +3 -0
- package/dist/components/Field.d.ts +22 -0
- package/dist/components/Field.js +2 -0
- package/dist/components/FocusRing.d.ts +9 -0
- package/dist/components/FocusRing.js +2 -0
- package/dist/components/Focusable.d.ts +12 -0
- package/dist/components/Focusable.js +2 -0
- package/dist/components/FooterLegend.d.ts +66 -0
- package/dist/components/FooterLegend.js +32 -0
- package/dist/components/Item.d.ts +11 -0
- package/dist/components/Item.js +1 -0
- package/dist/components/Marquee.d.ts +14 -0
- package/dist/components/Marquee.js +2 -0
- package/dist/components/Menu.d.ts +29 -0
- package/dist/components/Menu.js +8 -0
- package/dist/components/Modal.d.ts +52 -0
- package/dist/components/Modal.js +29 -0
- package/dist/components/Panel.d.ts +11 -0
- package/dist/components/Panel.js +4 -0
- package/dist/components/ProgressBar.d.ts +21 -0
- package/dist/components/ProgressBar.js +4 -0
- package/dist/components/Scroll.d.ts +7 -0
- package/dist/components/Scroll.js +5 -0
- package/dist/components/SidebarNavigation.d.ts +21 -0
- package/dist/components/SidebarNavigation.js +2 -0
- package/dist/components/SliderField.d.ts +26 -0
- package/dist/components/SliderField.js +2 -0
- package/dist/components/Spinner.d.ts +2 -0
- package/dist/components/Spinner.js +2 -0
- package/dist/components/SteamSpinner.d.ts +2 -0
- package/dist/components/SteamSpinner.js +2 -0
- package/dist/components/Tabs.d.ts +16 -0
- package/dist/components/Tabs.js +48 -0
- package/dist/components/TextField.d.ts +22 -0
- package/dist/components/TextField.js +2 -0
- package/dist/components/Toggle.d.ts +8 -0
- package/dist/components/Toggle.js +2 -0
- package/dist/components/ToggleField.d.ts +9 -0
- package/dist/components/ToggleField.js +2 -0
- package/dist/components/index.d.ts +25 -0
- package/dist/components/index.js +25 -0
- package/dist/custom-components/ColorPickerModal.d.ts +12 -0
- package/dist/custom-components/ColorPickerModal.js +87 -0
- package/dist/custom-components/ReorderableList.d.ts +26 -0
- package/dist/custom-components/ReorderableList.js +84 -0
- package/dist/custom-components/SuspensefulImage.d.ts +7 -0
- package/dist/custom-components/SuspensefulImage.js +27 -0
- package/dist/custom-components/index.d.ts +3 -0
- package/dist/custom-components/index.js +3 -0
- package/dist/custom-hooks/index.d.ts +1 -0
- package/dist/custom-hooks/index.js +1 -0
- package/dist/custom-hooks/useQuickAccessVisible.d.ts +1 -0
- package/dist/custom-hooks/useQuickAccessVisible.js +22 -0
- package/dist/deck-hooks/index.d.ts +1 -0
- package/dist/deck-hooks/index.js +1 -0
- package/dist/deck-hooks/useParams.d.ts +1 -0
- package/dist/deck-hooks/useParams.js +2 -0
- package/dist/globals/SteamClient.d.ts +307 -0
- package/dist/globals/SteamClient.js +1 -0
- package/dist/globals/index.d.ts +2 -0
- package/dist/globals/index.js +2 -0
- package/dist/globals/stores.d.ts +50 -0
- package/dist/globals/stores.js +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.js +46 -0
- package/dist/modules/Router.d.ts +110 -0
- package/dist/modules/Router.js +102 -0
- package/dist/modules/index.d.ts +1 -0
- package/dist/modules/index.js +1 -0
- package/dist/plugin.d.ts +68 -0
- package/dist/plugin.js +5 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.js +23 -0
- package/dist/utils/patcher.d.ts +18 -0
- package/dist/utils/patcher.js +103 -0
- package/dist/utils/react.d.ts +18 -0
- package/dist/utils/react.js +74 -0
- package/dist/utils/static-classes.d.ts +52 -0
- package/dist/utils/static-classes.js +28 -0
- package/dist/webpack.d.ts +21 -0
- package/dist/webpack.js +102 -0
- package/package.json +82 -0
- package/src/class-mapper.ts +34 -0
- package/src/components/Button.tsx +8 -0
- package/src/components/ButtonItem.tsx +14 -0
- package/src/components/Carousel.ts +25 -0
- package/src/components/ControlsList.tsx +13 -0
- package/src/components/Dialog.tsx +86 -0
- package/src/components/DialogCheckbox.tsx +36 -0
- package/src/components/Dropdown.tsx +49 -0
- package/src/components/Field.tsx +28 -0
- package/src/components/FocusRing.ts +15 -0
- package/src/components/Focusable.tsx +18 -0
- package/src/components/FooterLegend.ts +67 -0
- package/src/components/Item.tsx +12 -0
- package/src/components/Marquee.tsx +20 -0
- package/src/components/Menu.tsx +57 -0
- package/src/components/Modal.tsx +119 -0
- package/src/components/Panel.tsx +26 -0
- package/src/components/ProgressBar.tsx +35 -0
- package/src/components/Scroll.tsx +15 -0
- package/src/components/SidebarNavigation.tsx +28 -0
- package/src/components/SliderField.tsx +33 -0
- package/src/components/Spinner.tsx +8 -0
- package/src/components/SteamSpinner.tsx +7 -0
- package/src/components/Tabs.tsx +127 -0
- package/src/components/TextField.tsx +28 -0
- package/src/components/Toggle.tsx +14 -0
- package/src/components/ToggleField.tsx +15 -0
- package/src/components/index.ts +25 -0
- package/src/custom-components/ColorPickerModal.tsx +132 -0
- package/src/custom-components/ReorderableList.tsx +183 -0
- package/src/custom-components/SuspensefulImage.tsx +44 -0
- package/src/custom-components/index.ts +3 -0
- package/src/custom-hooks/index.ts +1 -0
- package/src/custom-hooks/useQuickAccessVisible.tsx +63 -0
- package/src/deck-hooks/index.ts +1 -0
- package/src/deck-hooks/useParams.ts +15 -0
- package/src/globals/SteamClient.ts +321 -0
- package/src/globals/index.ts +2 -0
- package/src/globals/stores.ts +50 -0
- package/src/index.ts +11 -0
- package/src/logger.ts +77 -0
- package/src/modules/Router.tsx +174 -0
- package/src/modules/index.ts +1 -0
- package/src/plugin.tsx +96 -0
- package/src/utils/index.ts +43 -0
- package/src/utils/patcher.ts +160 -0
- package/src/utils/react.ts +119 -0
- package/src/utils/static-classes.ts +1104 -0
- package/src/webpack.ts +136 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { ItemProps } from './Item';
|
|
3
|
+
export interface ToggleFieldProps extends ItemProps {
|
|
4
|
+
highlightOnFocus?: boolean;
|
|
5
|
+
checked: boolean;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
onChange?(checked: boolean): void;
|
|
8
|
+
}
|
|
9
|
+
export declare const ToggleField: FC<ToggleFieldProps>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export * from './Button';
|
|
2
|
+
export * from './ButtonItem';
|
|
3
|
+
export * from './Carousel';
|
|
4
|
+
export * from './ControlsList';
|
|
5
|
+
export * from './Dialog';
|
|
6
|
+
export * from './DialogCheckbox';
|
|
7
|
+
export * from './Dropdown';
|
|
8
|
+
export * from './Field';
|
|
9
|
+
export * from './Focusable';
|
|
10
|
+
export * from './FocusRing';
|
|
11
|
+
export * from './FooterLegend';
|
|
12
|
+
export * from './Marquee';
|
|
13
|
+
export * from './Menu';
|
|
14
|
+
export * from './Modal';
|
|
15
|
+
export * from './Panel';
|
|
16
|
+
export * from './ProgressBar';
|
|
17
|
+
export * from './SidebarNavigation';
|
|
18
|
+
export * from './SliderField';
|
|
19
|
+
export * from './Spinner';
|
|
20
|
+
export * from './SteamSpinner';
|
|
21
|
+
export * from './Tabs';
|
|
22
|
+
export * from './TextField';
|
|
23
|
+
export * from './Toggle';
|
|
24
|
+
export * from './ToggleField';
|
|
25
|
+
export * from './Scroll';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export * from './Button';
|
|
2
|
+
export * from './ButtonItem';
|
|
3
|
+
export * from './Carousel';
|
|
4
|
+
export * from './ControlsList';
|
|
5
|
+
export * from './Dialog';
|
|
6
|
+
export * from './DialogCheckbox';
|
|
7
|
+
export * from './Dropdown';
|
|
8
|
+
export * from './Field';
|
|
9
|
+
export * from './Focusable';
|
|
10
|
+
export * from './FocusRing';
|
|
11
|
+
export * from './FooterLegend';
|
|
12
|
+
export * from './Marquee';
|
|
13
|
+
export * from './Menu';
|
|
14
|
+
export * from './Modal';
|
|
15
|
+
export * from './Panel';
|
|
16
|
+
export * from './ProgressBar';
|
|
17
|
+
export * from './SidebarNavigation';
|
|
18
|
+
export * from './SliderField';
|
|
19
|
+
export * from './Spinner';
|
|
20
|
+
export * from './SteamSpinner';
|
|
21
|
+
export * from './Tabs';
|
|
22
|
+
export * from './TextField';
|
|
23
|
+
export * from './Toggle';
|
|
24
|
+
export * from './ToggleField';
|
|
25
|
+
export * from './Scroll';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
interface ColorPickerModalProps {
|
|
3
|
+
closeModal: () => void;
|
|
4
|
+
onConfirm?(HSLString: string): any;
|
|
5
|
+
title?: string;
|
|
6
|
+
defaultH?: number;
|
|
7
|
+
defaultS?: number;
|
|
8
|
+
defaultL?: number;
|
|
9
|
+
defaultA?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const ColorPickerModal: FC<ColorPickerModalProps>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { ConfirmModal, SliderField } from '../components';
|
|
3
|
+
import { gamepadSliderClasses } from '../utils/static-classes';
|
|
4
|
+
export const ColorPickerModal = ({ closeModal, onConfirm = () => { }, title = 'Color Picker', defaultH = 0, defaultS = 100, defaultL = 50, defaultA = 1, }) => {
|
|
5
|
+
const [H, setH] = useState(defaultH);
|
|
6
|
+
const [S, setS] = useState(defaultS);
|
|
7
|
+
const [L, setL] = useState(defaultL);
|
|
8
|
+
const [A, setA] = useState(defaultA);
|
|
9
|
+
const colorPickerCSSVars = {
|
|
10
|
+
'--decky-color-picker-hvalue': `${H}`,
|
|
11
|
+
'--decky-color-picker-svalue': `${S}%`,
|
|
12
|
+
'--decky-color-picker-lvalue': `${L}%`,
|
|
13
|
+
'--decky-color-picker-avalue': `${A}`,
|
|
14
|
+
};
|
|
15
|
+
return (window.SP_REACT.createElement(ConfirmModal, { bAllowFullSize: true, onCancel: closeModal, onOK: () => {
|
|
16
|
+
onConfirm(`hsla(${H}, ${S}%, ${L}%, ${A})`);
|
|
17
|
+
closeModal();
|
|
18
|
+
} },
|
|
19
|
+
window.SP_REACT.createElement("style", null, `
|
|
20
|
+
/* This removes the cyan track color that is behind the slider head */
|
|
21
|
+
.ColorPicker_Container .${gamepadSliderClasses.SliderTrack} {
|
|
22
|
+
--left-track-color: #0000;
|
|
23
|
+
/* This is for compatibility with the "Colored Toggles" CSSLoader Theme*/
|
|
24
|
+
--colored-toggles-main-color: #0000;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.ColorPicker_HSlider .${gamepadSliderClasses.SliderTrack} {
|
|
28
|
+
background: linear-gradient(
|
|
29
|
+
270deg,
|
|
30
|
+
hsla(360, var(--decky-color-picker-svalue), var(--decky-color-picker-lvalue), var(--decky-color-picker-avalue)),
|
|
31
|
+
hsla(270, var(--decky-color-picker-svalue), var(--decky-color-picker-lvalue), var(--decky-color-picker-avalue)),
|
|
32
|
+
hsla(180, var(--decky-color-picker-svalue), var(--decky-color-picker-lvalue), var(--decky-color-picker-avalue)),
|
|
33
|
+
hsla(90, var(--decky-color-picker-svalue), var(--decky-color-picker-lvalue), var(--decky-color-picker-avalue)),
|
|
34
|
+
hsla(0, var(--decky-color-picker-svalue), var(--decky-color-picker-lvalue), var(--decky-color-picker-avalue))
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.ColorPicker_SSlider .${gamepadSliderClasses.SliderTrack} {
|
|
39
|
+
background: linear-gradient(
|
|
40
|
+
90deg,
|
|
41
|
+
hsla(var(--decky-color-picker-hvalue), 0%, var(--decky-color-picker-lvalue), var(--decky-color-picker-avalue)),
|
|
42
|
+
hsla(var(--decky-color-picker-hvalue), 100%, var(--decky-color-picker-lvalue), var(--decky-color-picker-avalue))
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.ColorPicker_LSlider .${gamepadSliderClasses.SliderTrack} {
|
|
47
|
+
background: linear-gradient(
|
|
48
|
+
90deg,
|
|
49
|
+
hsla(var(--decky-color-picker-hvalue), var(--decky-color-picker-svalue), 0%, var(--decky-color-picker-avalue)),
|
|
50
|
+
hsla(var(--decky-color-picker-hvalue), var(--decky-color-picker-svalue), 50%, var(--decky-color-picker-avalue)),
|
|
51
|
+
hsla(var(--decky-color-picker-hvalue), var(--decky-color-picker-svalue), 100%, var(--decky-color-picker-avalue))
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.ColorPicker_ASlider .${gamepadSliderClasses.SliderTrack} {
|
|
56
|
+
background: linear-gradient(
|
|
57
|
+
90deg,
|
|
58
|
+
hsla(var(--decky-color-picker-hvalue), var(--decky-color-picker-svalue), var(--decky-color-picker-lvalue), 0),
|
|
59
|
+
hsla(var(--decky-color-picker-hvalue), var(--decky-color-picker-svalue), var(--decky-color-picker-lvalue), 1)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
`),
|
|
63
|
+
window.SP_REACT.createElement("div", { className: "ColorPicker_ColorDisplayContainer", style: {
|
|
64
|
+
display: 'flex',
|
|
65
|
+
justifyContent: 'space-between',
|
|
66
|
+
alignItems: 'center',
|
|
67
|
+
marginBottom: '1em',
|
|
68
|
+
marginTop: '-2.5em',
|
|
69
|
+
} },
|
|
70
|
+
window.SP_REACT.createElement("div", null,
|
|
71
|
+
window.SP_REACT.createElement("span", { style: { fontSize: '1.5em' } },
|
|
72
|
+
window.SP_REACT.createElement("b", null, title))),
|
|
73
|
+
window.SP_REACT.createElement("div", { style: {
|
|
74
|
+
backgroundColor: `hsla(${H}, ${S}%, ${L}%, ${A})`,
|
|
75
|
+
width: '40px',
|
|
76
|
+
height: '40px',
|
|
77
|
+
} })),
|
|
78
|
+
window.SP_REACT.createElement("div", { className: "ColorPicker_Container", style: colorPickerCSSVars },
|
|
79
|
+
window.SP_REACT.createElement("div", { className: "ColorPicker_HSlider" },
|
|
80
|
+
window.SP_REACT.createElement(SliderField, { showValue: true, editableValue: true, label: "Hue", value: H, min: 0, max: 360, onChange: setH })),
|
|
81
|
+
window.SP_REACT.createElement("div", { className: "ColorPicker_SSlider" },
|
|
82
|
+
window.SP_REACT.createElement(SliderField, { showValue: true, editableValue: true, label: "Saturation", value: S, min: 0, max: 100, onChange: setS })),
|
|
83
|
+
window.SP_REACT.createElement("div", { className: "ColorPicker_LSlider" },
|
|
84
|
+
window.SP_REACT.createElement(SliderField, { showValue: true, editableValue: true, label: "Lightness", value: L, min: 0, max: 100, onChange: setL })),
|
|
85
|
+
window.SP_REACT.createElement("div", { className: "ColorPicker_ASlider" },
|
|
86
|
+
window.SP_REACT.createElement(SliderField, { showValue: true, editableValue: true, label: "Alpha", value: A, step: 0.1, min: 0, max: 1, onChange: setA })))));
|
|
87
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { JSXElementConstructor, ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { FieldProps } from '../components';
|
|
3
|
+
export type ReorderableEntry<T> = {
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
data?: T;
|
|
6
|
+
position: number;
|
|
7
|
+
};
|
|
8
|
+
export type ReorderableListProps<T> = {
|
|
9
|
+
entries: ReorderableEntry<T>[];
|
|
10
|
+
onSave: (entries: ReorderableEntry<T>[]) => void;
|
|
11
|
+
interactables?: JSXElementConstructor<{
|
|
12
|
+
entry: ReorderableEntry<T>;
|
|
13
|
+
}>;
|
|
14
|
+
fieldProps?: FieldProps;
|
|
15
|
+
animate?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export declare function ReorderableList<T>(props: ReorderableListProps<T>): JSX.Element;
|
|
18
|
+
export type ReorderableListEntryProps<T> = {
|
|
19
|
+
fieldProps?: FieldProps;
|
|
20
|
+
listData: ReorderableEntry<T>[];
|
|
21
|
+
entryData: ReorderableEntry<T>;
|
|
22
|
+
reorderEntryFunc: CallableFunction;
|
|
23
|
+
reorderEnabled: boolean;
|
|
24
|
+
animate: boolean;
|
|
25
|
+
children: ReactElement | null;
|
|
26
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Fragment, useEffect, useState } from 'react';
|
|
2
|
+
import { Field, Focusable, GamepadButton } from '../components';
|
|
3
|
+
export function ReorderableList(props) {
|
|
4
|
+
if (props.animate === undefined)
|
|
5
|
+
props.animate = true;
|
|
6
|
+
const [entryList, setEntryList] = useState(props.entries.sort((a, b) => a.position - b.position));
|
|
7
|
+
const [reorderEnabled, setReorderEnabled] = useState(false);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
setEntryList(props.entries.sort((a, b) => a.position - b.position));
|
|
10
|
+
}, [props.entries]);
|
|
11
|
+
function toggleReorderEnabled() {
|
|
12
|
+
let newReorderValue = !reorderEnabled;
|
|
13
|
+
setReorderEnabled(newReorderValue);
|
|
14
|
+
if (!newReorderValue) {
|
|
15
|
+
props.onSave(entryList);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function saveOnBackout(e) {
|
|
19
|
+
const event = e;
|
|
20
|
+
if (event.detail.button == GamepadButton.CANCEL && reorderEnabled) {
|
|
21
|
+
setReorderEnabled(!reorderEnabled);
|
|
22
|
+
props.onSave(entryList);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return (window.SP_REACT.createElement(Fragment, null,
|
|
26
|
+
window.SP_REACT.createElement("div", { style: {
|
|
27
|
+
width: 'inherit',
|
|
28
|
+
height: 'inherit',
|
|
29
|
+
flex: '1 1 1px',
|
|
30
|
+
scrollPadding: '48px 0px',
|
|
31
|
+
display: 'flex',
|
|
32
|
+
flexDirection: 'column',
|
|
33
|
+
justifyContent: 'flex-start',
|
|
34
|
+
alignContent: 'stretch',
|
|
35
|
+
} },
|
|
36
|
+
window.SP_REACT.createElement(Focusable, { onSecondaryButton: toggleReorderEnabled, onSecondaryActionDescription: reorderEnabled ? 'Save Order' : 'Reorder', onClick: toggleReorderEnabled, onButtonDown: saveOnBackout }, entryList.map((entry) => (window.SP_REACT.createElement(ReorderableItem, { animate: props.animate, listData: entryList, entryData: entry, reorderEntryFunc: setEntryList, reorderEnabled: reorderEnabled, fieldProps: props.fieldProps }, props.interactables ? window.SP_REACT.createElement(props.interactables, { entry: entry }) : null)))))));
|
|
37
|
+
}
|
|
38
|
+
function ReorderableItem(props) {
|
|
39
|
+
const [isSelected, _setIsSelected] = useState(false);
|
|
40
|
+
const [isSelectedLastFrame, setIsSelectedLastFrame] = useState(false);
|
|
41
|
+
const listEntries = props.listData;
|
|
42
|
+
function onReorder(e) {
|
|
43
|
+
if (!props.reorderEnabled)
|
|
44
|
+
return;
|
|
45
|
+
const event = e;
|
|
46
|
+
const currentIdx = listEntries.findIndex((entryData) => entryData === props.entryData);
|
|
47
|
+
const currentIdxValue = listEntries[currentIdx];
|
|
48
|
+
if (currentIdx < 0)
|
|
49
|
+
return;
|
|
50
|
+
let targetPosition = -1;
|
|
51
|
+
if (event.detail.button == GamepadButton.DIR_DOWN) {
|
|
52
|
+
targetPosition = currentIdxValue.position + 1;
|
|
53
|
+
}
|
|
54
|
+
else if (event.detail.button == GamepadButton.DIR_UP) {
|
|
55
|
+
targetPosition = currentIdxValue.position - 1;
|
|
56
|
+
}
|
|
57
|
+
if (targetPosition >= listEntries.length || targetPosition < 0)
|
|
58
|
+
return;
|
|
59
|
+
let otherToUpdate = listEntries.find((entryData) => entryData.position === targetPosition);
|
|
60
|
+
if (!otherToUpdate)
|
|
61
|
+
return;
|
|
62
|
+
let currentPosition = currentIdxValue.position;
|
|
63
|
+
currentIdxValue.position = otherToUpdate.position;
|
|
64
|
+
otherToUpdate.position = currentPosition;
|
|
65
|
+
props.reorderEntryFunc([...listEntries].sort((a, b) => a.position - b.position));
|
|
66
|
+
}
|
|
67
|
+
async function setIsSelected(val) {
|
|
68
|
+
_setIsSelected(val);
|
|
69
|
+
for (let i = 0; i < 3; i++)
|
|
70
|
+
await new Promise((res) => requestAnimationFrame(res));
|
|
71
|
+
setIsSelectedLastFrame(val);
|
|
72
|
+
}
|
|
73
|
+
return (window.SP_REACT.createElement("div", { style: props.animate
|
|
74
|
+
? {
|
|
75
|
+
transition: isSelected || isSelectedLastFrame
|
|
76
|
+
? ''
|
|
77
|
+
: 'transform 0.3s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.3s cubic-bezier(0.25, 1, 0.5, 1)',
|
|
78
|
+
transform: !props.reorderEnabled || isSelected ? 'scale(1)' : 'scale(0.9)',
|
|
79
|
+
opacity: !props.reorderEnabled || isSelected ? 1 : 0.7,
|
|
80
|
+
}
|
|
81
|
+
: {} },
|
|
82
|
+
window.SP_REACT.createElement(Field, { label: props.entryData.label, ...props.fieldProps, focusable: !props.children, onButtonDown: onReorder, onGamepadBlur: () => setIsSelected(false), onGamepadFocus: () => setIsSelected(true) },
|
|
83
|
+
window.SP_REACT.createElement(Focusable, { style: { display: 'flex', width: '100%', position: 'relative' } }, props.children))));
|
|
84
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FC, ImgHTMLAttributes } from 'react';
|
|
2
|
+
interface SuspensefulImageProps extends ImgHTMLAttributes<HTMLImageElement> {
|
|
3
|
+
suspenseWidth?: string | number;
|
|
4
|
+
suspenseHeight?: string | number;
|
|
5
|
+
}
|
|
6
|
+
export declare const SuspensefulImage: FC<SuspensefulImageProps>;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Spinner } from '../components';
|
|
4
|
+
export const SuspensefulImage = (props) => {
|
|
5
|
+
const [loading, setLoading] = useState(true);
|
|
6
|
+
const [error, setError] = useState(false);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
setLoading(true);
|
|
9
|
+
setError(false);
|
|
10
|
+
const img = new Image();
|
|
11
|
+
img.src = props.src || '';
|
|
12
|
+
img.addEventListener('load', () => {
|
|
13
|
+
setLoading(false);
|
|
14
|
+
});
|
|
15
|
+
img.addEventListener('error', () => {
|
|
16
|
+
setError(true);
|
|
17
|
+
});
|
|
18
|
+
}, [props.src]);
|
|
19
|
+
return loading ? (window.SP_REACT.createElement("div", { style: {
|
|
20
|
+
width: props.suspenseWidth || props.style?.width,
|
|
21
|
+
height: props.suspenseHeight || props.style?.height,
|
|
22
|
+
background: 'rgba(255, 255, 255, 0.2)',
|
|
23
|
+
display: 'flex',
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
justifyContent: 'center',
|
|
26
|
+
} }, error ? 'Missing image' : window.SP_REACT.createElement(Spinner, { style: { height: '48px' } }))) : (window.SP_REACT.createElement("img", { ...props }));
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useQuickAccessVisible';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useQuickAccessVisible';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useQuickAccessVisible(): boolean;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { getGamepadNavigationTrees } from '../utils';
|
|
3
|
+
function getQuickAccessWindow() {
|
|
4
|
+
const navTrees = getGamepadNavigationTrees();
|
|
5
|
+
return (navTrees.find((tree) => tree?.id === 'QuickAccess-NA')?.m_Root?.m_element?.ownerDocument.defaultView ?? null);
|
|
6
|
+
}
|
|
7
|
+
export function useQuickAccessVisible() {
|
|
8
|
+
const [isHidden, setIsHidden] = useState(getQuickAccessWindow()?.document.hidden ?? false);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const quickAccessWindow = getQuickAccessWindow();
|
|
11
|
+
if (quickAccessWindow === null) {
|
|
12
|
+
console.error('Could not get window of QuickAccess menu!');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const onVisibilityChange = () => setIsHidden(quickAccessWindow.document.hidden);
|
|
16
|
+
quickAccessWindow.addEventListener('visibilitychange', onVisibilityChange);
|
|
17
|
+
return () => {
|
|
18
|
+
quickAccessWindow.removeEventListener('visibilitychange', onVisibilityChange);
|
|
19
|
+
};
|
|
20
|
+
}, []);
|
|
21
|
+
return !isHidden;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useParams';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useParams';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useParams: <T>() => T;
|