Skip to content

Commit

Permalink
Remove 'context' parameter from TGUIs (#12172)
Browse files Browse the repository at this point in the history
* Removes context from tgui (#80003)

*Most context
This is a precursor PR for moving to React. Newer React (>16) does not
have the `context` parameter, so it needs removed. I want to make
converting to React look slightly less intimidating, so this is just
short-circuiting context here.

This shouldn't be considered a long term solution.
Moving to react is good actually
N/A hopefully no noticeable change

* Use regex to replace instances of context

In folder: tgui/packages/tgui/interfaces/**

REPLACE: useBackend(<\w+>)?\(([\n ]*?)?(this\.)?context\s?\)
WITH: useBackend$1()

REPLACE: use(Local|Shared)State(<[\S\s]+>)?\(([\n ]*?)?(this\.)?context,? ?
WITH: use$1State$2(

REPLACE: \(([\n ]*?)?((\w+|\{([\S\s]+\}))(: (\w+|\{([\S\s]+\})))?),([\n ]*?)?_?context(: (\w+|\{([\S\s]+\})))?([\n ]*?)?\)
WITH: ($2)

* Remove remaining context uses manually

---------

Co-authored-by: Jeremiah <[email protected]>
  • Loading branch information
itsmeow and jlsnow301 authored Jan 23, 2025
1 parent 0f941e0 commit 6e55c2b
Show file tree
Hide file tree
Showing 341 changed files with 1,998 additions and 2,078 deletions.
19 changes: 9 additions & 10 deletions tgui/docs/tutorial-and-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ recommend getting yourself introduced to

A React component is not a regular HTML template. A component is a
javascript function, which accepts a `props` object (that contains
properties passed to a component) and a `context` object (which is
necessary to access UI data) as arguments, and outputs an HTML-like
properties passed to a component) as an argument, and outputs an HTML-like
structure.

So let's create our first React Component. Create a file with a name
Expand All @@ -119,8 +118,8 @@ import { useBackend } from '../backend';
import { Button, LabeledList, Section } from '../components';
import { Window } from '../layouts';

export const SampleInterface = (props, context) => {
const { act, data } = useBackend(context);
export const SampleInterface = (props) => {
const { act, data } = useBackend();
// Extract `health` and `color` variables from the `data` object.
const {
health,
Expand Down Expand Up @@ -150,7 +149,7 @@ export const SampleInterface = (props, context) => {
};
```

Here are the key variables you get from a `useBackend(context)` function:
Here are the key variables you get from a `useBackend()` function:

- `config` is part of core tgui. It contains meta-information about the
interface and who uses it, BYOND refs to various objects, and so forth.
Expand Down Expand Up @@ -251,7 +250,7 @@ import { useBackend } from '../backend';
import { Button, LabeledList, Section } from '../components';
import { Window } from '../layouts';

export const SampleInterface = (props, context) => {
export const SampleInterface = (props) => {
return (
<Window>
<Window.Content scrollable>
Expand All @@ -261,8 +260,8 @@ export const SampleInterface = (props, context) => {
);
};

const HealthStatus = (props, context) => {
const { act, data } = useBackend(context);
const HealthStatus = (props) => {
const { act, data } = useBackend();
const {
user,
} = props;
Expand Down Expand Up @@ -322,8 +321,8 @@ import { useBackend } from '../backend';
import { Button, LabeledList, Section } from '../components';
import { Window } from '../layouts';

export const SampleInterface = (props, context) => {
const { act, data } = useBackend(context);
export const SampleInterface = (props) => {
const { act, data } = useBackend();
// Extract `health` and `color` variables from the `data` object.
const {
health,
Expand Down
8 changes: 6 additions & 2 deletions tgui/packages/common/redux.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,16 @@ export const createAction = <TAction extends string>(type: TAction, prepare?: (.
export const useDispatch = <TAction extends Action = AnyAction>(context: {
store: Store<unknown, TAction>;
}): Dispatch<TAction> => {
return context.store.dispatch;
return context?.store?.dispatch;
};

export const useSelector = <State, Selected>(
context: { store: Store<State, Action> },
selector: (state: State) => Selected
): Selected => {
return selector(context.store.getState());
if (!context) {
return {} as Selected;
}

return selector(context?.store?.getState());
};
3 changes: 3 additions & 0 deletions tgui/packages/tgui-panel/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { pingMiddleware, pingReducer } from './ping';
import { settingsMiddleware, settingsReducer } from './settings';
import { statMiddleware, statReducer } from './stat';
import { telemetryMiddleware } from './telemetry';
import { setGlobalStore } from 'tgui/backend';

perf.mark('inception', window.performance?.timing?.navigationStart);
perf.mark('init');
Expand Down Expand Up @@ -50,6 +51,8 @@ const store = configureStore({
});

const renderApp = createRenderer(() => {
setGlobalStore(store);

const { Panel } = require('./Panel');
return (
<StoreProvider store={store}>
Expand Down
34 changes: 20 additions & 14 deletions tgui/packages/tgui/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import { resumeRenderer, suspendRenderer } from './renderer';

const logger = createLogger('backend');

export let globalStore;

export const setGlobalStore = (store) => {
globalStore = store;
};

export const backendUpdate = createAction('backend/update');
export const backendSetSharedState = createAction('backend/setSharedState');
export const backendSuspendStart = createAction('backend/suspendStart');
Expand Down Expand Up @@ -246,6 +252,10 @@ type BackendState<TData> = {
shared: Record<string, any>;
suspending: boolean;
suspended: boolean;
debug?: {
debugLayout: boolean;
kitchenSink: boolean;
};
};

/**
Expand All @@ -261,9 +271,9 @@ export const selectBackend = <TData>(state: any): BackendState<TData> => state.b
*
* You can make
*/
export const useBackend = <TData>(context: any) => {
const { store } = context;
const state = selectBackend<TData>(store.getState());
export const useBackend = <TData>() => {
const state: BackendState<TData> = globalStore?.getState()?.backend;

return {
...state,
act: sendAct,
Expand All @@ -284,19 +294,17 @@ type StateWithSetter<T> = [T, (nextState: T) => void];
*
* It is a lot more performant than `setSharedState`.
*
* @param context React context.
* @param key Key which uniquely identifies this state in Redux store.
* @param initialState Initializes your global variable with this value.
*/
export const useLocalState = <T>(context: any, key: string, initialState: T): StateWithSetter<T> => {
const { store } = context;
const state = selectBackend(store.getState());
const sharedStates = state.shared ?? {};
export const useLocalState = <T>(key: string, initialState: T): StateWithSetter<T> => {
const state = globalStore?.getState()?.backend;
const sharedStates = state?.shared ?? {};
const sharedState = key in sharedStates ? sharedStates[key] : initialState;
return [
sharedState,
(nextState) => {
store.dispatch(
globalStore.dispatch(
backendSetSharedState({
key,
nextState: typeof nextState === 'function' ? nextState(sharedState) : nextState,
Expand All @@ -316,14 +324,12 @@ export const useLocalState = <T>(context: any, key: string, initialState: T): St
*
* This makes creation of observable s
*
* @param context React context.
* @param key Key which uniquely identifies this state in Redux store.
* @param initialState Initializes your global variable with this value.
*/
export const useSharedState = <T>(context: any, key: string, initialState: T): StateWithSetter<T> => {
const { store } = context;
const state = selectBackend(store.getState());
const sharedStates = state.shared ?? {};
export const useSharedState = <T>(key: string, initialState: T): StateWithSetter<T> => {
const state = globalStore?.getState()?.backend;
const sharedStates = state?.shared ?? {};
const sharedState = key in sharedStates ? sharedStates[key] : initialState;
return [
sharedState,
Expand Down
4 changes: 2 additions & 2 deletions tgui/packages/tgui/components/CollapsibleSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useLocalState } from '../backend';
import { Section } from './Section';
import { Button } from './Button';

export const CollapsibleSection = (props, context) => {
export const CollapsibleSection = (props) => {
const {
children,
startOpen = true,
Expand All @@ -13,7 +13,7 @@ export const CollapsibleSection = (props, context) => {
showButton = !forceOpen,
...rest
} = props;
const [isOpen, setOpen] = useLocalState(context, `open_collapsible_${sectionKey}`, startOpen);
const [isOpen, setOpen] = useLocalState(`open_collapsible_${sectionKey}`, startOpen);
return (
<Section
fitted={!forceOpen && !isOpen}
Expand Down
41 changes: 18 additions & 23 deletions tgui/packages/tgui/components/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,29 +182,24 @@ export class Dropdown extends Component<DropdownProps, DropdownState> {

const to_render = ops.length ? ops : 'No Options Found';

render(
<div>{to_render}</div>,
renderedMenu,
() => {
let singletonPopper = Dropdown.singletonPopper;
if (singletonPopper === undefined) {
singletonPopper = createPopper(Dropdown.virtualElement, renderedMenu!, {
...DEFAULT_OPTIONS,
placement: 'bottom-start',
});

Dropdown.singletonPopper = singletonPopper;
} else {
singletonPopper.setOptions({
...DEFAULT_OPTIONS,
placement: 'bottom-start',
});

singletonPopper.update();
}
},
this.context
);
render(<div>{to_render}</div>, renderedMenu, () => {
let singletonPopper = Dropdown.singletonPopper;
if (singletonPopper === undefined) {
singletonPopper = createPopper(Dropdown.virtualElement, renderedMenu!, {
...DEFAULT_OPTIONS,
placement: 'bottom-start',
});

Dropdown.singletonPopper = singletonPopper;
} else {
singletonPopper.setOptions({
...DEFAULT_OPTIONS,
placement: 'bottom-start',
});

singletonPopper.update();
}
});
}

setOpen(open: boolean) {
Expand Down
2 changes: 1 addition & 1 deletion tgui/packages/tgui/components/Popper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class Popper extends Component<PopperProps> {
renderPopperContent(callback: () => void) {
// `render` errors when given false, so we convert it to `null`,
// which is supported.
render(this.props.popperContent || null, this.renderedContent, callback, this.context);
render(this.props.popperContent || null, this.renderedContent, callback);
}

render() {
Expand Down
4 changes: 2 additions & 2 deletions tgui/packages/tgui/components/TextArea.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { toInputValue } from './Input';
import { KEY_ENTER, KEY_ESCAPE, KEY_TAB } from 'common/keycodes';

export class TextArea extends Component {
constructor(props, context) {
super(props, context);
constructor(props) {
super(props);
this.textareaRef = props.innerRef || createRef();
this.fillerRef = createRef();
this.state = {
Expand Down
41 changes: 18 additions & 23 deletions tgui/packages/tgui/components/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,29 +100,24 @@ export class Tooltip extends Component<TooltipProps, TooltipState> {
return;
}

render(
<span>{this.props.content}</span>,
renderedTooltip,
() => {
let singletonPopper = Tooltip.singletonPopper;
if (singletonPopper === undefined) {
singletonPopper = createPopper(Tooltip.virtualElement, renderedTooltip!, {
...DEFAULT_OPTIONS,
placement: this.props.position || 'auto',
});

Tooltip.singletonPopper = singletonPopper;
} else {
singletonPopper.setOptions({
...DEFAULT_OPTIONS,
placement: this.props.position || 'auto',
});

singletonPopper.update();
}
},
this.context
);
render(<span>{this.props.content}</span>, renderedTooltip, () => {
let singletonPopper = Tooltip.singletonPopper;
if (singletonPopper === undefined) {
singletonPopper = createPopper(Tooltip.virtualElement, renderedTooltip!, {
...DEFAULT_OPTIONS,
placement: this.props.position || 'auto',
});

Tooltip.singletonPopper = singletonPopper;
} else {
singletonPopper.setOptions({
...DEFAULT_OPTIONS,
placement: this.props.position || 'auto',
});

singletonPopper.update();
}
});
}

componentDidUpdate() {
Expand Down
6 changes: 3 additions & 3 deletions tgui/packages/tgui/debug/KitchenSink.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ const r = require.context('../stories', false, /\.stories\.jsx$/);
*/
const getStories = () => r.keys().map((path) => r(path));

export const KitchenSink = (props, context) => {
export const KitchenSink = (props) => {
const { panel } = props;
const [theme] = useLocalState(context, 'kitchenSinkTheme');
const [pageIndex, setPageIndex] = useLocalState(context, 'pageIndex', 0);
const [theme] = useLocalState('kitchenSinkTheme');
const [pageIndex, setPageIndex] = useLocalState('pageIndex', 0);
const stories = getStories();
const story = stories[pageIndex];
const Layout = panel ? Pane : Window;
Expand Down
11 changes: 5 additions & 6 deletions tgui/packages/tgui/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,28 +43,27 @@ import './styles/themes/retro.scss';
import './styles/themes/syndicate.scss';
import './styles/themes/thinktronic-classic.scss';

import { StoreProvider, configureStore } from './store';
import { configureStore } from './store';

import { captureExternalLinks } from './links';
import { createRenderer } from './renderer';
import { perf } from 'common/perf';
import { setupGlobalEvents } from './events';
import { setupHotKeys } from './hotkeys';
import { setupHotReloading } from 'tgui-dev-server/link/client.cjs';
import { setGlobalStore } from './backend';

perf.mark('inception', window.performance?.timing?.navigationStart);
perf.mark('init');

const store = configureStore();

const renderApp = createRenderer(() => {
setGlobalStore(store);

const { getRoutedComponent } = require('./routes');
const Component = getRoutedComponent(store);
return (
<StoreProvider store={store}>
<Component />
</StoreProvider>
);
return <Component />;
});

const setupApp = () => {
Expand Down
Loading

0 comments on commit 6e55c2b

Please sign in to comment.