mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 02:09:41 +00:00
[MIRROR] TGUI 5.0 Patch 1 (#7701)
Co-authored-by: Selis <sirlionfur@hotmail.de>
This commit is contained in:
@@ -4,5 +4,17 @@
|
||||
/**/*.chunk.*
|
||||
/**/*.hot-update.*
|
||||
|
||||
**.lock
|
||||
**.log
|
||||
**.json
|
||||
**.svg
|
||||
**.scss
|
||||
**.md
|
||||
**.css
|
||||
**.txt
|
||||
**.woff2
|
||||
**.eot
|
||||
**.ttf
|
||||
|
||||
# CHOMPEdit - Until removed
|
||||
/packages/tgui_ch/**
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
rules:
|
||||
## Enforce a maximum cyclomatic complexity allowed in a program
|
||||
# complexity: [warn, { max: 25 }]
|
||||
## Enforce consistent brace style for blocks
|
||||
# brace-style: [warn, stroustrup, { allowSingleLine: false }]
|
||||
## Enforce the consistent use of either backticks, double, or single quotes
|
||||
# quotes: [warn, single, {
|
||||
# avoidEscape: true,
|
||||
# allowTemplateLiterals: true,
|
||||
# }]
|
||||
# react/jsx-closing-bracket-location: [warn, {
|
||||
# selfClosing: after-props,
|
||||
# nonEmpty: after-props,
|
||||
# }]
|
||||
# react/display-name: warn
|
||||
|
||||
## Radar
|
||||
## ------------------------------------------------------
|
||||
# radar/cognitive-complexity: warn
|
||||
radar/max-switch-cases: warn
|
||||
radar/no-all-duplicated-branches: warn
|
||||
radar/no-collapsible-if: warn
|
||||
radar/no-collection-size-mischeck: warn
|
||||
radar/no-duplicate-string: warn
|
||||
radar/no-duplicated-branches: warn
|
||||
radar/no-element-overwrite: warn
|
||||
radar/no-extra-arguments: warn
|
||||
radar/no-identical-conditions: warn
|
||||
radar/no-identical-expressions: warn
|
||||
radar/no-identical-functions: warn
|
||||
radar/no-inverted-boolean-check: warn
|
||||
radar/no-one-iteration-loop: warn
|
||||
radar/no-redundant-boolean: warn
|
||||
radar/no-redundant-jump: warn
|
||||
radar/no-same-line-conditional: warn
|
||||
radar/no-small-switch: warn
|
||||
radar/no-unused-collection: warn
|
||||
radar/no-use-of-empty-return-value: warn
|
||||
radar/no-useless-catch: warn
|
||||
radar/prefer-immediate-return: warn
|
||||
radar/prefer-object-literal: warn
|
||||
radar/prefer-single-boolean-return: warn
|
||||
radar/prefer-while: warn
|
||||
1
tgui/.eslintrc-sonar.yml
Normal file
1
tgui/.eslintrc-sonar.yml
Normal file
@@ -0,0 +1 @@
|
||||
extends: 'plugin:sonarjs/recommended'
|
||||
@@ -11,14 +11,14 @@ env:
|
||||
browser: true
|
||||
node: true
|
||||
plugins:
|
||||
- radar
|
||||
- sonarjs
|
||||
- react
|
||||
- unused-imports
|
||||
- simple-import-sort
|
||||
settings:
|
||||
react:
|
||||
version: '16.10'
|
||||
version: '18.2'
|
||||
rules:
|
||||
|
||||
## Possible Errors
|
||||
## ----------------------------------------
|
||||
## Enforce “for” loop update clause moving the counter in the right
|
||||
@@ -309,13 +309,16 @@ rules:
|
||||
## Enforce or disallow capitalization of the first letter of a comment
|
||||
# capitalized-comments: error
|
||||
## Require or disallow trailing commas
|
||||
comma-dangle: [error, {
|
||||
comma-dangle: [
|
||||
error,
|
||||
{
|
||||
arrays: always-multiline,
|
||||
objects: always-multiline,
|
||||
imports: always-multiline,
|
||||
exports: always-multiline,
|
||||
functions: only-multiline, ## Optional on functions
|
||||
}]
|
||||
},
|
||||
]
|
||||
## Enforce consistent spacing before and after commas
|
||||
comma-spacing: [error, { before: false, after: true }]
|
||||
## Enforce consistent comma style
|
||||
@@ -350,15 +353,15 @@ rules:
|
||||
## Enforce the location of arrow function bodies
|
||||
# implicit-arrow-linebreak: error
|
||||
## Enforce consistent indentation
|
||||
# indent: [warn, 2, { SwitchCase: 1 }]
|
||||
# indent: [error, 2, { SwitchCase: 1 }]
|
||||
## Enforce the consistent use of either double or single quotes in JSX
|
||||
## attributes
|
||||
# jsx-quotes: [warn, prefer-double]
|
||||
# jsx-quotes: [error, prefer-double]
|
||||
## Enforce consistent spacing between keys and values in object literal
|
||||
## properties
|
||||
# key-spacing: [warn, { beforeColon: false, afterColon: true }]
|
||||
# key-spacing: [error, { beforeColon: false, afterColon: true }]
|
||||
## Enforce consistent spacing before and after keywords
|
||||
# keyword-spacing: [warn, { before: true, after: true }]
|
||||
# keyword-spacing: [error, { before: true, after: true }]
|
||||
## Enforce position of line comments
|
||||
# line-comment-position: error
|
||||
## Enforce consistent linebreak style
|
||||
@@ -370,8 +373,8 @@ rules:
|
||||
## Enforce a maximum depth that blocks can be nested
|
||||
# max-depth: error
|
||||
## Enforce a maximum line length
|
||||
# max-len: [warn, {
|
||||
# code: 120,
|
||||
# max-len: [error, {
|
||||
# code: 80,
|
||||
# ## Ignore imports
|
||||
# ignorePattern: '^(import\s.+\sfrom\s|.*require\()',
|
||||
# ignoreUrls: true,
|
||||
@@ -415,7 +418,7 @@ rules:
|
||||
## Disallow mixed binary operators
|
||||
# no-mixed-operators: error
|
||||
## Disallow mixed spaces and tabs for indentation
|
||||
no-mixed-spaces-and-tabs: warn
|
||||
# no-mixed-spaces-and-tabs: error
|
||||
## Disallow use of chained assignment expressions
|
||||
# no-multi-assign: error
|
||||
## Disallow multiple empty lines
|
||||
@@ -441,7 +444,7 @@ rules:
|
||||
## Disallow ternary operators when simpler alternatives exist
|
||||
# no-unneeded-ternary: error
|
||||
## Disallow whitespace before properties
|
||||
# no-whitespace-before-property: warn
|
||||
# no-whitespace-before-property: error
|
||||
## Enforce the location of single-line statements
|
||||
# nonblock-statement-body-position: error
|
||||
## Enforce consistent line breaks inside braces
|
||||
@@ -458,7 +461,7 @@ rules:
|
||||
## Require or disallow assignment operator shorthand where possible
|
||||
# operator-assignment: error
|
||||
## Enforce consistent linebreak style for operators
|
||||
# operator-linebreak: [warn, before]
|
||||
# operator-linebreak: [error, before]
|
||||
## Require or disallow padding within blocks
|
||||
# padded-blocks: error
|
||||
## Require or disallow padding lines between statements
|
||||
@@ -483,7 +486,7 @@ rules:
|
||||
## Enforce consistent spacing before blocks
|
||||
space-before-blocks: [error, always]
|
||||
## Enforce consistent spacing before function definition opening parenthesis
|
||||
# space-before-function-paren: [warn, {
|
||||
# space-before-function-paren: [error, {
|
||||
# anonymous: always,
|
||||
# named: never,
|
||||
# asyncArrow: always,
|
||||
@@ -696,7 +699,7 @@ rules:
|
||||
react/jsx-closing-tag-location: error
|
||||
## Enforce or disallow newlines inside of curly braces in JSX attributes and
|
||||
## expressions (fixable)
|
||||
# react/jsx-curly-newline: warn
|
||||
# react/jsx-curly-newline: error
|
||||
## Enforce or disallow spaces inside of curly braces in JSX attributes and
|
||||
## expressions (fixable)
|
||||
react/jsx-curly-spacing: error
|
||||
@@ -709,13 +712,13 @@ rules:
|
||||
## Enforce event handler naming conventions in JSX
|
||||
react/jsx-handler-names: error
|
||||
## Validate JSX indentation (fixable)
|
||||
# react/jsx-indent: [warn, 2, {
|
||||
# react/jsx-indent: [error, 2, {
|
||||
# checkAttributes: true,
|
||||
# }]
|
||||
## Validate props indentation in JSX (fixable)
|
||||
# react/jsx-indent-props: [warn, 2]
|
||||
# react/jsx-indent-props: [error, 2]
|
||||
## Validate JSX has key prop when in array or iterator
|
||||
# react/jsx-key: warn
|
||||
react/jsx-key: error
|
||||
## Validate JSX maximum depth
|
||||
react/jsx-max-depth: [error, { max: 10 }] ## Generous
|
||||
## Limit maximum of props on a single line in JSX (fixable)
|
||||
@@ -762,3 +765,6 @@ rules:
|
||||
## Prevents the use of unused imports.
|
||||
## This could be done by enabling no-unused-vars, but we're doing this for now
|
||||
unused-imports/no-unused-imports: error
|
||||
## https://github.com/lydell/eslint-plugin-simple-import-sort/
|
||||
simple-import-sort/imports: error
|
||||
simple-import-sort/exports: error
|
||||
|
||||
1
tgui/.gitignore
vendored
1
tgui/.gitignore
vendored
@@ -17,6 +17,7 @@ package-lock.json
|
||||
/public/*.map
|
||||
/public/tgui-bench.bundle.js
|
||||
/public/tgui-bench.bundle.css
|
||||
/coverage
|
||||
|
||||
## Previously ignored locations that are kept to avoid confusing git
|
||||
## while transitioning to a new project structure.
|
||||
|
||||
15
tgui/.swcrc
Normal file
15
tgui/.swcrc
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
"jsc": {
|
||||
"loose": true,
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": true
|
||||
},
|
||||
"transform": {
|
||||
"react": {
|
||||
"runtime": "automatic"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -740,9 +740,10 @@ Popper lets you position elements so that they don't go out of the bounds of the
|
||||
|
||||
**Props:**
|
||||
|
||||
- `popperContent: ReactNode` - The content that will be put inside the popper.
|
||||
- `options?: { ... }` - An object of options to pass to `createPopper`. See [https://popper.js.org/docs/v2/constructors/#options], but the one you want most is `placement`. Valid placements are "bottom", "top", "left", and "right". You can affix "-start" and "-end" to achieve something like top left or top right respectively. You can also use "auto" (with an optional "-start" or "-end"), where a best fit will be chosen.
|
||||
- `additionalStyles: { ... }` - A map of CSS styles to add to the element that will contain the popper.
|
||||
- `content: ReactNode` - The content that will be put inside the popper.
|
||||
- `isOpen: boolean` - Whether or not the popper is open.
|
||||
- `onClickOutside?: (e) => void` - A function that will be called when the user clicks outside of the popper.
|
||||
- `placement?: string` - The placement of the popper. See [https://popper.js.org/docs/v2/constructors/#placement]
|
||||
|
||||
### `ProgressBar`
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ module.exports = {
|
||||
testEnvironment: 'jsdom',
|
||||
testRunner: require.resolve('jest-circus/runner'),
|
||||
transform: {
|
||||
'^.+\\.(js|cjs|ts|tsx)$': require.resolve('babel-jest'),
|
||||
'^.+\\.(js|cjs|ts|tsx)$': require.resolve('@swc/jest'),
|
||||
},
|
||||
moduleFileExtensions: ['js', 'cjs', 'ts', 'tsx', 'json'],
|
||||
resetMocks: true,
|
||||
|
||||
@@ -9,41 +9,33 @@
|
||||
"scripts": {
|
||||
"tgui:analyze": "webpack --analyze",
|
||||
"tgui:bench": "webpack --env TGUI_BENCH=1 && node packages/tgui-bench/index.js",
|
||||
"tgui:build": "webpack",
|
||||
"tgui:build": "BROWSERSLIST_IGNORE_OLD_DATA=true webpack",
|
||||
"tgui:dev": "node --experimental-modules packages/tgui-dev-server/index.js",
|
||||
"tgui:lint": "eslint packages --ext .js,.cjs,.ts,.tsx",
|
||||
"tgui:prettier": "prettierx --check .",
|
||||
"tgui:sonar": "eslint packages --ext .js,.cjs,.ts,.tsx -c .eslintrc-harder.yml",
|
||||
"tgui:sonar": "eslint packages -c .eslintrc-sonar.yml",
|
||||
"tgui:test": "jest --watch",
|
||||
"tgui:test-simple": "CI=true jest --color",
|
||||
"tgui:test-ci": "CI=true jest --color --collect-coverage",
|
||||
"tgui:tsc": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.23.3",
|
||||
"@babel/eslint-parser": "^7.23.3",
|
||||
"@babel/plugin-transform-class-properties": "^7.23.3",
|
||||
"@babel/plugin-transform-jscript": "^7.23.3",
|
||||
"@babel/preset-env": "^7.23.3",
|
||||
"@babel/preset-react": "^7.23.3",
|
||||
"@babel/preset-typescript": "^7.23.3",
|
||||
"@swc/core": "^1.3.100",
|
||||
"@swc/jest": "^0.2.29",
|
||||
"@types/jest": "^29.5.10",
|
||||
"@types/jsdom": "^21.1.6",
|
||||
"@types/node": "^14.x",
|
||||
"@types/webpack": "^5.28.5",
|
||||
"@types/webpack-env": "^1.18.4",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"babel-jest": "^29.7.0",
|
||||
"babel-loader": "^8.3.0",
|
||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||
"common": "workspace:*",
|
||||
"@typescript-eslint/parser": "^6.14.0",
|
||||
"css-loader": "^6.8.1",
|
||||
"esbuild-loader": "^4.0.2",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-radar": "^0.2.1",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-unused-imports": "^1.1.5",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"eslint-plugin-sonarjs": "^0.23.0",
|
||||
"eslint-plugin-unused-imports": "^3.0.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-circus": "^29.7.0",
|
||||
@@ -54,6 +46,7 @@
|
||||
"sass": "^1.69.5",
|
||||
"sass-loader": "^13.3.2",
|
||||
"style-loader": "^3.3.3",
|
||||
"swc-loader": "^0.2.3",
|
||||
"typescript": "^4.9.4",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.89.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Action, Reducer, applyMiddleware, combineReducers, createAction, createStore } from './redux';
|
||||
import { Action, applyMiddleware, combineReducers, createAction, createStore, Reducer } from './redux';
|
||||
|
||||
// Dummy Reducer
|
||||
const counterReducer: Reducer<number, Action<string>> = (state = 0, action) => {
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { setupGlobalEvents } from 'tgui/events';
|
||||
import 'tgui/styles/main.scss';
|
||||
|
||||
import { setupGlobalEvents } from 'tgui/events';
|
||||
|
||||
import Benchmark from './lib/benchmark';
|
||||
|
||||
const sendMessage = (obj: any) => {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { configureStore } from 'tgui/store';
|
||||
|
||||
import { DisposalBin } from 'tgui/interfaces/DisposalBin';
|
||||
import { backendUpdate, setGlobalStore } from 'tgui/backend';
|
||||
import { DisposalBin } from 'tgui/interfaces/DisposalBin';
|
||||
import { createRenderer } from 'tgui/renderer';
|
||||
import { configureStore } from 'tgui/store';
|
||||
|
||||
const store = configureStore({ sideEffects: false });
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import { createLogger } from './logging';
|
||||
import { require } from './require';
|
||||
|
||||
import { createLogger } from './logging.js';
|
||||
import { require } from './require.js';
|
||||
|
||||
const axios = require('axios');
|
||||
const logger = createLogger('dreamseeker');
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { createCompiler } from './webpack';
|
||||
import { reloadByondCache } from './reloader';
|
||||
import { reloadByondCache } from './reloader.js';
|
||||
import { createCompiler } from './webpack.js';
|
||||
|
||||
const noHot = process.argv.includes('--no-hot');
|
||||
const noTmp = process.argv.includes('--no-tmp');
|
||||
|
||||
@@ -31,11 +31,9 @@ const ensureConnection = () => {
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
window.onunload = () => socket && socket.close();
|
||||
}
|
||||
};
|
||||
|
||||
const subscribe = (fn) => subscribers.push(fn);
|
||||
|
||||
@@ -136,11 +134,12 @@ const sendLogEntry = (level, ns, ...args) => {
|
||||
|
||||
const setupHotReloading = () => {
|
||||
if (
|
||||
// prettier-ignore
|
||||
process.env.NODE_ENV !== 'production'
|
||||
&& process.env.WEBPACK_HMR_ENABLED
|
||||
&& window.WebSocket
|
||||
process.env.NODE_ENV === 'production' ||
|
||||
!process.env.WEBPACK_HMR_ENABLED ||
|
||||
!window.WebSocket
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (module.hot) {
|
||||
ensureConnection();
|
||||
sendLogEntry(0, null, 'setting up hot reloading');
|
||||
@@ -168,7 +167,6 @@ const setupHotReloading = () => {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import { basename } from 'path';
|
||||
import { createLogger } from '../logging';
|
||||
import { require } from '../require';
|
||||
import { resolveGlob } from '../util';
|
||||
|
||||
import { createLogger } from '../logging.js';
|
||||
import { require } from '../require.js';
|
||||
import { resolveGlob } from '../util.js';
|
||||
|
||||
const SourceMap = require('source-map');
|
||||
const { parse: parseStackTrace } = require('stacktrace-parser');
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
|
||||
import http from 'http';
|
||||
import { inspect } from 'util';
|
||||
import { createLogger, directLog } from '../logging';
|
||||
import { require } from '../require';
|
||||
import { loadSourceMaps, retrace } from './retrace';
|
||||
|
||||
import { createLogger, directLog } from '../logging.js';
|
||||
import { require } from '../require.js';
|
||||
import { loadSourceMaps, retrace } from './retrace.js';
|
||||
|
||||
const WebSocket = require('ws');
|
||||
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import { basename } from 'path';
|
||||
import { DreamSeeker } from './dreamseeker';
|
||||
import { createLogger } from './logging';
|
||||
import { resolveGlob, resolvePath } from './util';
|
||||
import { regQuery } from './winreg';
|
||||
|
||||
import { DreamSeeker } from './dreamseeker.js';
|
||||
import { createLogger } from './logging.js';
|
||||
import { resolveGlob, resolvePath } from './util.js';
|
||||
import { regQuery } from './winreg.js';
|
||||
|
||||
const logger = createLogger('reloader');
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { require } from './require';
|
||||
|
||||
import { require } from './require.js';
|
||||
|
||||
const globPkg = require('glob');
|
||||
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
import fs from 'fs';
|
||||
import { createRequire } from 'module';
|
||||
import { dirname } from 'path';
|
||||
import { loadSourceMaps, setupLink } from './link/server';
|
||||
import { createLogger } from './logging';
|
||||
import { reloadByondCache } from './reloader';
|
||||
import { resolveGlob } from './util';
|
||||
|
||||
import { loadSourceMaps, setupLink } from './link/server.js';
|
||||
import { createLogger } from './logging.js';
|
||||
import { reloadByondCache } from './reloader.js';
|
||||
import { resolveGlob } from './util.js';
|
||||
|
||||
const logger = createLogger('webpack');
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import { createLogger } from './logging';
|
||||
|
||||
import { createLogger } from './logging.js';
|
||||
|
||||
const logger = createLogger('winreg');
|
||||
|
||||
@@ -35,8 +36,8 @@ export const regQuery = async (path, key) => {
|
||||
logger.error('could not find the start of the key value');
|
||||
return null;
|
||||
}
|
||||
const value = stdout.substring(indexOfValue + 4, indexOfEol);
|
||||
return value;
|
||||
|
||||
return stdout.substring(indexOfValue + 4, indexOfEol);
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
return null;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import { Button, Section, Stack } from 'tgui/components';
|
||||
import { Pane } from 'tgui/layouts';
|
||||
|
||||
import { NowPlayingWidget, useAudio } from './audio';
|
||||
import { ChatPanel, ChatTabs } from './chat';
|
||||
import { useGame } from './game';
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { useSelector, useDispatch } from 'tgui/backend';
|
||||
import { useDispatch, useSelector } from 'tgui/backend';
|
||||
|
||||
import { selectAudio } from './selectors';
|
||||
|
||||
export const useAudio = () => {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { createAction } from 'common/redux';
|
||||
|
||||
import { createPage } from './model';
|
||||
|
||||
export const loadChat = createAction('chat/load');
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import DOMPurify from 'dompurify';
|
||||
import { storage } from 'common/storage';
|
||||
import { loadSettings, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from '../settings/actions';
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
import { addHighlightSetting, loadSettings, removeHighlightSetting, updateHighlightSetting, updateSettings } from '../settings/actions';
|
||||
import { selectSettings } from '../settings/selectors';
|
||||
import { addChatPage, changeChatPage, changeScrollTracking, loadChat, rebuildChat, moveChatPageLeft, moveChatPageRight, removeChatPage, saveChatToDisk, purgeChatMessageArchive, toggleAcceptedType, updateMessageCount } from './actions';
|
||||
import { addChatPage, changeChatPage, changeScrollTracking, loadChat, moveChatPageLeft, moveChatPageRight, purgeChatMessageArchive, rebuildChat, removeChatPage, saveChatToDisk, toggleAcceptedType, updateMessageCount } from './actions';
|
||||
import { MESSAGE_SAVE_INTERVAL } from './constants';
|
||||
import { createMessage, serializeMessage } from './model';
|
||||
import { chatRenderer } from './renderer';
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
import { createUuid } from 'common/uuid';
|
||||
import { MESSAGE_TYPES, MESSAGE_TYPE_INTERNAL } from './constants';
|
||||
|
||||
import { MESSAGE_TYPE_INTERNAL, MESSAGE_TYPES } from './constants';
|
||||
|
||||
export const canPageAcceptType = (page, type) =>
|
||||
type.startsWith(MESSAGE_TYPE_INTERNAL) || page.acceptedTypes[type];
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { addChatPage, changeChatPage, loadChat, removeChatPage, moveChatPageLeft, moveChatPageRight, toggleAcceptedType, updateChatPage, updateMessageCount, changeScrollTracking } from './actions';
|
||||
import { addChatPage, changeChatPage, changeScrollTracking, loadChat, moveChatPageLeft, moveChatPageRight, removeChatPage, toggleAcceptedType, updateChatPage, updateMessageCount } from './actions';
|
||||
import { canPageAcceptType, createMainPage } from './model';
|
||||
|
||||
const mainPage = createMainPage();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { useSelector } from 'tgui/backend';
|
||||
|
||||
import { selectGame } from './selectors';
|
||||
|
||||
export const useGame = () => {
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
import { pingSoft, pingSuccess } from '../ping/actions';
|
||||
import { connectionLost, connectionRestored, roundRestarted } from './actions';
|
||||
import { selectGame } from './selectors';
|
||||
import { CONNECTION_LOST_AFTER } from './constants';
|
||||
import { selectGame } from './selectors';
|
||||
|
||||
const withTimestamp = (action) => ({
|
||||
...action,
|
||||
|
||||
@@ -11,11 +11,13 @@ import './styles/themes/vchatdark.scss';
|
||||
|
||||
import { perf } from 'common/perf';
|
||||
import { combineReducers } from 'common/redux';
|
||||
import { setupHotReloading } from 'tgui-dev-server/link/client.cjs';
|
||||
import { setGlobalStore } from 'tgui/backend';
|
||||
import { setupGlobalEvents } from 'tgui/events';
|
||||
import { captureExternalLinks } from 'tgui/links';
|
||||
import { createRenderer } from 'tgui/renderer';
|
||||
import { configureStore } from 'tgui/store';
|
||||
import { setupHotReloading } from 'tgui-dev-server/link/client.cjs';
|
||||
|
||||
import { audioMiddleware, audioReducer } from './audio';
|
||||
import { chatMiddleware, chatReducer } from './chat';
|
||||
import { gameMiddleware, gameReducer } from './game';
|
||||
@@ -23,7 +25,6 @@ import { setupPanelFocusHacks } from './panelFocus';
|
||||
import { pingMiddleware, pingReducer } from './ping';
|
||||
import { settingsMiddleware, settingsReducer } from './settings';
|
||||
import { telemetryMiddleware } from './telemetry';
|
||||
import { setGlobalStore } from 'tgui/backend';
|
||||
|
||||
perf.mark('inception', window.performance?.timing?.navigationStart);
|
||||
perf.mark('init');
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { clamp01, scale } from 'common/math';
|
||||
|
||||
import { pingFail, pingSuccess } from './actions';
|
||||
import { PING_MAX_FAILS, PING_ROUNDTRIP_BEST, PING_ROUNDTRIP_WORST } from './constants';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Button } from 'tgui/components';
|
||||
import { useDispatch } from 'tgui/backend';
|
||||
import { Button } from 'tgui/components';
|
||||
|
||||
import { dismissWarning } from './game/actions';
|
||||
|
||||
let url: string | null = null;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { createAction } from 'common/redux';
|
||||
|
||||
import { createHighlightSetting } from './model';
|
||||
|
||||
export const updateSettings = createAction('settings/update');
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
import { useDispatch, useSelector } from 'tgui/backend';
|
||||
import { updateSettings, toggleSettings } from './actions';
|
||||
|
||||
import { toggleSettings, updateSettings } from './actions';
|
||||
import { selectSettings } from './selectors';
|
||||
|
||||
export const useSettings = () => {
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
*/
|
||||
|
||||
import { storage } from 'common/storage';
|
||||
|
||||
import { setClientTheme } from '../themes';
|
||||
import { loadSettings, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from './actions';
|
||||
import { selectSettings } from './selectors';
|
||||
import { addHighlightSetting, loadSettings, removeHighlightSetting, updateHighlightSetting, updateSettings } from './actions';
|
||||
import { FONTS_DISABLED } from './constants';
|
||||
import { selectSettings } from './selectors';
|
||||
|
||||
let overrideRule = null;
|
||||
let overrideFontFamily = null;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { changeSettingsTab, loadSettings, openChatSettings, toggleSettings, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from './actions';
|
||||
import { addHighlightSetting, changeSettingsTab, loadSettings, openChatSettings, removeHighlightSetting, toggleSettings, updateHighlightSetting, updateSettings } from './actions';
|
||||
import { FONTS, MAX_HIGHLIGHT_SETTINGS, SETTINGS_TABS } from './constants';
|
||||
import { createDefaultHighlightSetting } from './model';
|
||||
import { SETTINGS_TABS, FONTS, MAX_HIGHLIGHT_SETTINGS } from './constants';
|
||||
|
||||
const defaultHighlightSetting = createDefaultHighlightSetting();
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { Action, AnyAction, Middleware } from '../common/redux';
|
||||
|
||||
import { Dispatch } from 'common/redux';
|
||||
|
||||
import { Action, AnyAction, Middleware } from '../common/redux';
|
||||
|
||||
const EXCLUDED_PATTERNS = [/v4shim/i];
|
||||
const loadedMappings: Record<string, string> = {};
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
import { perf } from 'common/perf';
|
||||
import { createAction } from 'common/redux';
|
||||
|
||||
import { setupDrag } from './drag';
|
||||
import { globalEvents } from './events';
|
||||
import { focusMap } from './focus';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, createRef } from 'react';
|
||||
|
||||
import { resolveAsset } from '../assets';
|
||||
import { Box } from './Box';
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import { BooleanLike, classes } from 'common/react';
|
||||
import { createElement, ReactNode } from 'react';
|
||||
|
||||
import { CSS_COLORS } from '../constants';
|
||||
|
||||
export type BoxProps = {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import { map, zipWith } from 'common/collections';
|
||||
import { Component, createRef, RefObject } from 'react';
|
||||
|
||||
import { Box, BoxProps } from './Box';
|
||||
|
||||
type Props = {
|
||||
|
||||
@@ -1,337 +1,177 @@
|
||||
import { createPopper, VirtualElement } from '@popperjs/core';
|
||||
import { classes } from 'common/react';
|
||||
import { Component, ReactNode } from 'react';
|
||||
import { findDOMNode, render } from 'react-dom';
|
||||
import { Box, BoxProps } from './Box';
|
||||
import { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { BoxProps, unit } from './Box';
|
||||
import { Button } from './Button';
|
||||
import { Icon } from './Icon';
|
||||
import { Stack } from './Stack';
|
||||
import { Popper } from './Popper';
|
||||
|
||||
export interface DropdownEntry {
|
||||
displayText: string | number | ReactNode;
|
||||
value: string | number | Enumerator;
|
||||
type DropdownEntry = {
|
||||
displayText: ReactNode;
|
||||
value: string | number;
|
||||
};
|
||||
|
||||
type DropdownOption = string | DropdownEntry;
|
||||
|
||||
type Props = {
|
||||
/** An array of strings which will be displayed in the
|
||||
dropdown when open. See Dropdown.tsx for more advanced usage with DropdownEntry */
|
||||
options: DropdownOption[];
|
||||
/** Called when a value is picked from the list, `value` is the value that was picked */
|
||||
onSelected: (value: any) => void;
|
||||
} & Partial<{
|
||||
/** Whether to display previous / next buttons */
|
||||
buttons: boolean;
|
||||
/** Whether to clip the selected text */
|
||||
clipSelectedText: boolean;
|
||||
/** Color of dropdown button */
|
||||
color: string;
|
||||
/** Disables the dropdown */
|
||||
disabled: boolean;
|
||||
/** Text to always display in place of the selected text */
|
||||
displayText: ReactNode;
|
||||
/** Icon to display in dropdown button */
|
||||
icon: string;
|
||||
/** Angle of the icon */
|
||||
iconRotation: number;
|
||||
/** Whether or not the icon should spin */
|
||||
iconSpin: boolean;
|
||||
/** Width of the dropdown menu. Default: 15rem */
|
||||
menuWidth: string;
|
||||
/** Whether or not the arrow on the right hand side of the dropdown button is visible */
|
||||
noChevron: boolean;
|
||||
/** Called when dropdown button is clicked */
|
||||
onClick: (event) => void;
|
||||
/** Dropdown renders over instead of below */
|
||||
over: boolean;
|
||||
/** Currently selected entry */
|
||||
selected: string | number;
|
||||
}> &
|
||||
BoxProps;
|
||||
|
||||
function getOptionValue(option: DropdownOption) {
|
||||
return typeof option === 'string' ? option : option.value;
|
||||
}
|
||||
|
||||
type DropdownUniqueProps = { options: string[] | DropdownEntry[] } & Partial<{
|
||||
buttons: boolean;
|
||||
clipSelectedText: boolean;
|
||||
color: string;
|
||||
disabled: boolean;
|
||||
displayText: string | number | ReactNode;
|
||||
dropdownStyle: any;
|
||||
icon: string;
|
||||
iconRotation: number;
|
||||
iconSpin: boolean;
|
||||
menuWidth: string;
|
||||
nochevron: boolean;
|
||||
onClick: (event) => void;
|
||||
onSelected: (selected: any) => void;
|
||||
over: boolean;
|
||||
// you freaks really are just doing anything with this shit
|
||||
selected: any;
|
||||
width: string;
|
||||
}>;
|
||||
|
||||
export type DropdownProps = BoxProps & DropdownUniqueProps;
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
placement: 'left-start',
|
||||
modifiers: [
|
||||
{
|
||||
name: 'eventListeners',
|
||||
enabled: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
const NULL_RECT: DOMRect = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
toJSON: () => null,
|
||||
} as const;
|
||||
|
||||
type DropdownState = {
|
||||
selected?: string;
|
||||
open: boolean;
|
||||
};
|
||||
|
||||
const DROPDOWN_DEFAULT_CLASSNAMES = 'Layout Dropdown__menu';
|
||||
const DROPDOWN_SCROLL_CLASSNAMES = 'Layout Dropdown__menu-scroll';
|
||||
|
||||
export class Dropdown extends Component<DropdownProps, DropdownState> {
|
||||
static renderedMenu: HTMLDivElement | undefined;
|
||||
static singletonPopper: ReturnType<typeof createPopper> | undefined;
|
||||
static currentOpenMenu: Element | undefined;
|
||||
static virtualElement: VirtualElement = {
|
||||
getBoundingClientRect: () =>
|
||||
Dropdown.currentOpenMenu?.getBoundingClientRect() ?? NULL_RECT,
|
||||
};
|
||||
menuContents: any;
|
||||
state: DropdownState = {
|
||||
open: false,
|
||||
selected: this.props.selected,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
if (this.state.open) {
|
||||
this.setOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
getDOMNode() {
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
return findDOMNode(this) as Element;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const domNode = this.getDOMNode();
|
||||
|
||||
if (!domNode) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
openMenu() {
|
||||
let renderedMenu = Dropdown.renderedMenu;
|
||||
if (renderedMenu === undefined) {
|
||||
renderedMenu = document.createElement('div');
|
||||
renderedMenu.className = DROPDOWN_DEFAULT_CLASSNAMES;
|
||||
document.body.appendChild(renderedMenu);
|
||||
Dropdown.renderedMenu = renderedMenu;
|
||||
}
|
||||
|
||||
const domNode = this.getDOMNode()!;
|
||||
Dropdown.currentOpenMenu = domNode;
|
||||
|
||||
renderedMenu.scrollTop = 0;
|
||||
renderedMenu.style.width = this.props.menuWidth || '10rem';
|
||||
renderedMenu.style.opacity = '1';
|
||||
renderedMenu.style.pointerEvents = 'auto';
|
||||
|
||||
// ie hack
|
||||
// ie has this bizarre behavior where focus just silently fails if the
|
||||
// element being targeted "isn't ready"
|
||||
// 400 is probably way too high, but the lack of hotloading is testing my
|
||||
// patience on tuning it
|
||||
// I'm beyond giving a shit at this point it fucking works whatever
|
||||
setTimeout(() => {
|
||||
Dropdown.renderedMenu?.focus();
|
||||
}, 400);
|
||||
this.renderMenuContent();
|
||||
}
|
||||
|
||||
closeMenu() {
|
||||
if (Dropdown.currentOpenMenu !== this.getDOMNode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Dropdown.currentOpenMenu = undefined;
|
||||
Dropdown.renderedMenu!.style.opacity = '0';
|
||||
Dropdown.renderedMenu!.style.pointerEvents = 'none';
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.closeMenu();
|
||||
this.setOpen(false);
|
||||
}
|
||||
|
||||
renderMenuContent() {
|
||||
const renderedMenu = Dropdown.renderedMenu;
|
||||
if (!renderedMenu) {
|
||||
return;
|
||||
}
|
||||
if (renderedMenu.offsetHeight > 200) {
|
||||
renderedMenu.className = DROPDOWN_SCROLL_CLASSNAMES;
|
||||
} else {
|
||||
renderedMenu.className = DROPDOWN_DEFAULT_CLASSNAMES;
|
||||
}
|
||||
|
||||
const { options = [] } = this.props;
|
||||
const ops = options.map((option) => {
|
||||
let value, displayText;
|
||||
|
||||
if (typeof option === 'string') {
|
||||
displayText = option;
|
||||
value = option;
|
||||
} else if (option !== null) {
|
||||
displayText = option.displayText;
|
||||
value = option.value;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={value}
|
||||
className={classes([
|
||||
'Dropdown__menuentry',
|
||||
this.state.selected === value && 'selected',
|
||||
])}
|
||||
onClick={() => {
|
||||
this.setSelected(value);
|
||||
}}>
|
||||
{displayText}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setOpen(open: boolean) {
|
||||
this.setState((state) => ({
|
||||
...state,
|
||||
open,
|
||||
}));
|
||||
if (open) {
|
||||
setTimeout(() => {
|
||||
this.openMenu();
|
||||
window.addEventListener('click', this.handleClick);
|
||||
});
|
||||
} else {
|
||||
this.closeMenu();
|
||||
window.removeEventListener('click', this.handleClick);
|
||||
}
|
||||
}
|
||||
|
||||
setSelected(selected: string) {
|
||||
this.setState((state) => ({
|
||||
...state,
|
||||
selected,
|
||||
}));
|
||||
this.setOpen(false);
|
||||
if (this.props.onSelected) {
|
||||
this.props.onSelected(selected);
|
||||
}
|
||||
}
|
||||
|
||||
getOptionValue(option): string {
|
||||
return typeof option === 'string' ? option : option.value;
|
||||
}
|
||||
|
||||
getSelectedIndex(): number {
|
||||
const selected = this.state.selected || this.props.selected;
|
||||
const { options = [] } = this.props;
|
||||
|
||||
return options.findIndex((option) => {
|
||||
return this.getOptionValue(option) === selected;
|
||||
});
|
||||
}
|
||||
|
||||
toPrevious(): void {
|
||||
if (this.props.options.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
let selectedIndex = this.getSelectedIndex();
|
||||
const startIndex = 0;
|
||||
const endIndex = this.props.options.length - 1;
|
||||
|
||||
const hasSelected = selectedIndex >= 0;
|
||||
if (!hasSelected) {
|
||||
selectedIndex = startIndex;
|
||||
}
|
||||
|
||||
const previousIndex =
|
||||
selectedIndex === startIndex ? endIndex : selectedIndex - 1;
|
||||
|
||||
this.setSelected(this.getOptionValue(this.props.options[previousIndex]));
|
||||
}
|
||||
|
||||
toNext(): void {
|
||||
if (this.props.options.length < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
let selectedIndex = this.getSelectedIndex();
|
||||
const startIndex = 0;
|
||||
const endIndex = this.props.options.length - 1;
|
||||
|
||||
const hasSelected = selectedIndex >= 0;
|
||||
if (!hasSelected) {
|
||||
selectedIndex = endIndex;
|
||||
}
|
||||
|
||||
const nextIndex =
|
||||
selectedIndex === endIndex ? startIndex : selectedIndex + 1;
|
||||
|
||||
this.setSelected(this.getOptionValue(this.props.options[nextIndex]));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { props } = this;
|
||||
export function Dropdown(props: Props) {
|
||||
const {
|
||||
buttons,
|
||||
className,
|
||||
clipSelectedText = true,
|
||||
color = 'default',
|
||||
disabled,
|
||||
displayText,
|
||||
icon,
|
||||
iconRotation,
|
||||
iconSpin,
|
||||
clipSelectedText = true,
|
||||
color = 'default',
|
||||
dropdownStyle,
|
||||
over,
|
||||
nochevron,
|
||||
width,
|
||||
menuWidth = '15rem',
|
||||
noChevron,
|
||||
onClick,
|
||||
onSelected,
|
||||
options = [],
|
||||
over,
|
||||
selected,
|
||||
disabled,
|
||||
displayText,
|
||||
buttons,
|
||||
...boxProps
|
||||
width,
|
||||
} = props;
|
||||
const { className, ...rest } = boxProps;
|
||||
|
||||
const adjustedOpen = over ? !this.state.open : this.state.open;
|
||||
const [open, setOpen] = useState(false);
|
||||
const adjustedOpen = over ? !open : open;
|
||||
const innerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
/** Update the selected value when clicking the left/right buttons */
|
||||
const updateSelected = useCallback(
|
||||
(direction: 'previous' | 'next') => {
|
||||
if (options.length < 1 || disabled) {
|
||||
return;
|
||||
}
|
||||
const startIndex = 0;
|
||||
const endIndex = options.length - 1;
|
||||
|
||||
let selectedIndex = options.findIndex(
|
||||
(option) => getOptionValue(option) === selected
|
||||
);
|
||||
|
||||
if (selectedIndex < 0) {
|
||||
selectedIndex = direction === 'next' ? endIndex : startIndex;
|
||||
}
|
||||
|
||||
let newIndex = selectedIndex;
|
||||
if (direction === 'next') {
|
||||
newIndex = selectedIndex === endIndex ? startIndex : selectedIndex++;
|
||||
} else {
|
||||
newIndex = selectedIndex === startIndex ? endIndex : selectedIndex--;
|
||||
}
|
||||
|
||||
onSelected?.(getOptionValue(options[newIndex]));
|
||||
},
|
||||
[disabled, onSelected, options, selected]
|
||||
);
|
||||
|
||||
/** Allows the menu to be scrollable on open */
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
|
||||
innerRef.current?.focus();
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Stack fill>
|
||||
<Stack.Item width={width}>
|
||||
<Box
|
||||
width={'100%'}
|
||||
<Popper
|
||||
isOpen={open}
|
||||
onClickOutside={() => setOpen(false)}
|
||||
placement={over ? 'top-start' : 'bottom-start'}
|
||||
content={
|
||||
<div
|
||||
className="Layout Dropdown__menu"
|
||||
style={{ minWidth: menuWidth }}
|
||||
ref={innerRef}>
|
||||
{options.length === 0 && (
|
||||
<div className="Dropdown__menuentry">No options</div>
|
||||
)}
|
||||
|
||||
{options.map((option, index) => {
|
||||
const value = getOptionValue(option);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes([
|
||||
'Dropdown__menuentry',
|
||||
selected === value && 'selected',
|
||||
])}
|
||||
key={index}
|
||||
onClick={() => {
|
||||
setOpen(false);
|
||||
onSelected?.(value);
|
||||
}}>
|
||||
{typeof option === 'string' ? option : option.displayText}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
}>
|
||||
<div>
|
||||
<div className="Dropdown" style={{ width: unit(width) }}>
|
||||
<div
|
||||
className={classes([
|
||||
'Dropdown__control',
|
||||
'Button',
|
||||
'Button--dropdown',
|
||||
'Button--color--' + color,
|
||||
disabled && 'Button--disabled',
|
||||
className,
|
||||
])}
|
||||
onClick={(event) => {
|
||||
if (disabled && !this.state.open) {
|
||||
if (disabled && !open) {
|
||||
return;
|
||||
}
|
||||
this.setOpen(!this.state.open);
|
||||
if (onClick) {
|
||||
onClick(event);
|
||||
}
|
||||
}}
|
||||
{...rest}>
|
||||
setOpen(!open);
|
||||
onClick?.(event);
|
||||
}}>
|
||||
{icon && (
|
||||
<Icon
|
||||
mr={1}
|
||||
name={icon}
|
||||
rotation={iconRotation}
|
||||
spin={iconSpin}
|
||||
mr={1}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
@@ -339,48 +179,37 @@ export class Dropdown extends Component<DropdownProps, DropdownState> {
|
||||
style={{
|
||||
overflow: clipSelectedText ? 'hidden' : 'visible',
|
||||
}}>
|
||||
{displayText || this.state.selected}
|
||||
{displayText || selected}
|
||||
</span>
|
||||
{nochevron || (
|
||||
{!noChevron && (
|
||||
<span className="Dropdown__arrow-button">
|
||||
<Icon name={adjustedOpen ? 'chevron-up' : 'chevron-down'} />
|
||||
</span>
|
||||
)}
|
||||
</Box>
|
||||
</Stack.Item>
|
||||
</div>
|
||||
{buttons && (
|
||||
<>
|
||||
<Stack.Item height={'100%'}>
|
||||
<Button
|
||||
height={'100%'}
|
||||
disabled={disabled}
|
||||
height={1.8}
|
||||
icon="chevron-left"
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toPrevious();
|
||||
updateSelected('previous');
|
||||
}}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item height={'100%'}>
|
||||
|
||||
<Button
|
||||
height={'100%'}
|
||||
icon="chevron-right"
|
||||
disabled={disabled}
|
||||
height={1.8}
|
||||
icon="chevron-right"
|
||||
onClick={() => {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toNext();
|
||||
updateSelected('next');
|
||||
}}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</div>
|
||||
</div>
|
||||
</Popper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { classes } from 'common/react';
|
||||
|
||||
import { BoxProps, computeBoxClassName, computeBoxProps, unit } from './Box';
|
||||
|
||||
export type FlexProps = Partial<{
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import { classes } from 'common/react';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
||||
|
||||
const FA_OUTLINE_REGEX = /-o$/;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component } from 'react';
|
||||
|
||||
import { KeyEvent } from '../events';
|
||||
import { listenForKeyEvents } from '../hotkeys';
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
|
||||
import { classes } from 'common/react';
|
||||
import { Component, createRef, ReactNode, RefObject } from 'react';
|
||||
import { Box } from './Box';
|
||||
|
||||
import { logger } from '../logging';
|
||||
import { Box } from './Box';
|
||||
import { Icon } from './Icon';
|
||||
|
||||
type MenuProps = {
|
||||
|
||||
@@ -1,82 +1,88 @@
|
||||
import { createPopper } from '@popperjs/core';
|
||||
import { ArgumentsOf } from 'common/types';
|
||||
import { Component, CSSProperties, JSXElementConstructor, PropsWithChildren, ReactElement, RefObject } from 'react';
|
||||
import { findDOMNode, render } from 'react-dom';
|
||||
import { Placement } from '@popperjs/core';
|
||||
import { PropsWithChildren, ReactNode, useEffect, useRef, useState } from 'react';
|
||||
import { usePopper } from 'react-popper';
|
||||
|
||||
type PopperProps = {
|
||||
popperContent: ReactElement<any, string | JSXElementConstructor<any>>;
|
||||
options?: ArgumentsOf<typeof createPopper>[2];
|
||||
additionalStyles?: CSSProperties;
|
||||
} & PropsWithChildren;
|
||||
type RequiredProps = {
|
||||
/** The content to display in the popper */
|
||||
content: ReactNode;
|
||||
/** Whether the popper is open */
|
||||
isOpen: boolean;
|
||||
};
|
||||
|
||||
export class Popper extends Component<PopperProps> {
|
||||
static id: number = 0;
|
||||
popperRef: RefObject<HTMLDivElement>;
|
||||
type OptionalProps = Partial<{
|
||||
/** Called when the user clicks outside the popper */
|
||||
onClickOutside: () => void;
|
||||
/** Where to place the popper relative to the reference element */
|
||||
placement: Placement;
|
||||
}>;
|
||||
|
||||
renderedContent: HTMLDivElement;
|
||||
popperInstance: ReturnType<typeof createPopper>;
|
||||
type Props = RequiredProps & OptionalProps;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
/**
|
||||
* ## Popper
|
||||
* Popper lets you position elements so that they don't go out of the bounds of the window.
|
||||
* @url https://popper.js.org/react-popper/ for more information.
|
||||
*/
|
||||
export function Popper(props: PropsWithChildren<Props>) {
|
||||
const { children, content, isOpen, onClickOutside, placement } = props;
|
||||
|
||||
Popper.id += 1;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { additionalStyles, options } = this.props;
|
||||
|
||||
this.renderedContent = document.createElement('div');
|
||||
|
||||
if (additionalStyles) {
|
||||
for (const [attribute, value] of Object.entries(additionalStyles)) {
|
||||
this.renderedContent.style[attribute] = value;
|
||||
}
|
||||
}
|
||||
|
||||
this.renderPopperContent(() => {
|
||||
document.body.appendChild(this.renderedContent);
|
||||
|
||||
// HACK: We don't want to create a wrapper, as it could break the layout
|
||||
// of consumers, so we use findDOMNode.
|
||||
// This is usually bad as refs are usually better, but refs did
|
||||
// not work in this case, as they weren't propagating correctly.
|
||||
// A previous attempt was made as a render prop that passed an ID,
|
||||
// but this made consuming use too unwieldly.
|
||||
// Because this component is written in TypeScript, we will know
|
||||
// immediately if this internal variable is removed.
|
||||
//
|
||||
// eslint-disable-next-line react/no-find-dom-node
|
||||
const domNode = findDOMNode(this) as Element;
|
||||
if (!domNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.popperInstance = createPopper(
|
||||
domNode,
|
||||
this.renderedContent,
|
||||
options
|
||||
const [referenceElement, setReferenceElement] =
|
||||
useState<HTMLDivElement | null>(null);
|
||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(
|
||||
null
|
||||
);
|
||||
|
||||
// One would imagine we could just use useref here, but it's against react-popper documentation and causes a positioning bug
|
||||
// We still need them to call focus and clickoutside events :(
|
||||
const popperRef = useRef<HTMLDivElement | null>(null);
|
||||
const parentRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
||||
placement,
|
||||
});
|
||||
|
||||
/** Close the popper when the user clicks outside */
|
||||
function handleClickOutside(event: MouseEvent) {
|
||||
if (
|
||||
!popperRef.current?.contains(event.target as Node) &&
|
||||
!parentRef.current?.contains(event.target as Node)
|
||||
) {
|
||||
onClickOutside?.();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.renderPopperContent(() => this.popperInstance?.update());
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
} else {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.popperInstance?.destroy();
|
||||
render(<> </>, this.renderedContent, () => {
|
||||
this.renderedContent.remove();
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.children;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={(node) => {
|
||||
setReferenceElement(node);
|
||||
parentRef.current = node;
|
||||
}}>
|
||||
{children}
|
||||
</div>
|
||||
{isOpen && (
|
||||
<div
|
||||
ref={(node) => {
|
||||
setPopperElement(node);
|
||||
popperRef.current = node;
|
||||
}}
|
||||
style={{ ...styles.popper, zIndex: 5 }}
|
||||
{...attributes.popper}>
|
||||
{content}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { clamp01, scale, keyOfMatchingRange, toFixed } from 'common/math';
|
||||
import { clamp01, keyOfMatchingRange, scale, toFixed } from 'common/math';
|
||||
import { classes } from 'common/react';
|
||||
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
||||
import { CSS_COLORS } from '../constants';
|
||||
import { PropsWithChildren } from 'react';
|
||||
|
||||
import { CSS_COLORS } from '../constants';
|
||||
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
||||
|
||||
type Props = {
|
||||
value: number;
|
||||
} & Partial<{
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
import { canRender, classes } from 'common/react';
|
||||
import { ReactNode, RefObject, createRef, useEffect } from 'react';
|
||||
import { createRef, ReactNode, RefObject, useEffect } from 'react';
|
||||
|
||||
import { addScrollableNode, removeScrollableNode } from '../events';
|
||||
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import { classes } from 'common/react';
|
||||
import { RefObject } from 'react';
|
||||
|
||||
import { computeFlexClassName, computeFlexItemClassName, computeFlexItemProps, computeFlexProps, FlexItemProps, FlexProps } from './Flex';
|
||||
|
||||
type Props = Partial<{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PropsWithChildren, ReactNode } from 'react';
|
||||
|
||||
import { Box } from './Box';
|
||||
|
||||
type Props = Partial<{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import { canRender, classes } from 'common/react';
|
||||
import { PropsWithChildren, ReactNode } from 'react';
|
||||
|
||||
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
||||
import { Icon } from './Icon';
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable react/no-deprecated */
|
||||
// TODO: Rewrite as an FC, remove this lint disable
|
||||
import { createPopper, Placement, VirtualElement } from '@popperjs/core';
|
||||
import { Component, ReactNode } from 'react';
|
||||
import { findDOMNode, render } from 'react-dom';
|
||||
|
||||
@@ -14,12 +14,13 @@ export { ByondUi } from './ByondUi';
|
||||
export { Chart } from './Chart';
|
||||
export { Collapsible } from './Collapsible';
|
||||
export { ColorBox } from './ColorBox';
|
||||
export { Dialog } from './Dialog';
|
||||
export { Dimmer } from './Dimmer';
|
||||
export { Divider } from './Divider';
|
||||
export { DraggableControl } from './DraggableControl';
|
||||
export { Dropdown } from './Dropdown';
|
||||
export { Flex } from './Flex';
|
||||
export { FitText } from './FitText';
|
||||
export { Flex } from './Flex';
|
||||
export { Grid } from './Grid';
|
||||
export { Icon } from './Icon';
|
||||
export { InfinitePlane } from './InfinitePlane';
|
||||
@@ -32,18 +33,17 @@ export { MenuBar } from './MenuBar';
|
||||
export { Modal } from './Modal';
|
||||
export { NoticeBox } from './NoticeBox';
|
||||
export { NumberInput } from './NumberInput';
|
||||
export { ProgressBar } from './ProgressBar';
|
||||
export { Popper } from './Popper';
|
||||
export { ProgressBar } from './ProgressBar';
|
||||
export { RestrictedInput } from './RestrictedInput';
|
||||
export { RoundGauge } from './RoundGauge';
|
||||
export { Section } from './Section';
|
||||
export { Slider } from './Slider';
|
||||
export { StyleableSection } from './StyleableSection';
|
||||
export { Stack } from './Stack';
|
||||
export { StyleableSection } from './StyleableSection';
|
||||
export { Table } from './Table';
|
||||
export { Tabs } from './Tabs';
|
||||
export { TextArea } from './TextArea';
|
||||
export { TimeDisplay } from './TimeDisplay';
|
||||
export { TrackOutsideClicks } from './TrackOutsideClicks';
|
||||
export { Tooltip } from './Tooltip';
|
||||
export { Dialog } from './Dialog';
|
||||
export { TrackOutsideClicks } from './TrackOutsideClicks';
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import { KEY_BACKSPACE, KEY_F10, KEY_F11, KEY_F12 } from 'common/keycodes';
|
||||
|
||||
import { globalEvents } from '../events';
|
||||
import { acquireHotKey } from '../hotkeys';
|
||||
import { openExternalBrowser, toggleDebugLayout, toggleKitchenSink } from './actions';
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { storage } from 'common/storage';
|
||||
import { vecAdd, vecMultiply, vecScale, vecSubtract } from 'common/vector';
|
||||
|
||||
import { createLogger } from './logging';
|
||||
import { storage } from 'common/storage';
|
||||
|
||||
const logger = createLogger('drag');
|
||||
const pixelRatio = window.devicePixelRatio ?? 1;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { KeyEvent, addScrollableNode, canStealFocus, removeScrollableNode, setupGlobalEvents } from './events';
|
||||
import { addScrollableNode, canStealFocus, KeyEvent, removeScrollableNode, setupGlobalEvents } from './events';
|
||||
|
||||
describe('focusEvents', () => {
|
||||
afterEach(() => {
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { KEY_ALT, KEY_CTRL, KEY_F1, KEY_F12, KEY_SHIFT } from 'common/keycodes';
|
||||
|
||||
import { EventEmitter } from 'common/events';
|
||||
import { KEY_ALT, KEY_CTRL, KEY_F1, KEY_F12, KEY_SHIFT } from 'common/keycodes';
|
||||
|
||||
export const globalEvents = new EventEmitter();
|
||||
let ignoreWindowFocus = false;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import * as keycodes from 'common/keycodes';
|
||||
|
||||
import { globalEvents, KeyEvent } from './events';
|
||||
import { createLogger } from './logging';
|
||||
|
||||
|
||||
@@ -19,15 +19,15 @@ import './styles/themes/syndicate.scss';
|
||||
import './styles/themes/wizard.scss';
|
||||
import './styles/themes/abstract.scss';
|
||||
|
||||
import { configureStore } from './store';
|
||||
|
||||
import { captureExternalLinks } from './links';
|
||||
import { createRenderer } from './renderer';
|
||||
import { perf } from 'common/perf';
|
||||
import { setupHotReloading } from 'tgui-dev-server/link/client.cjs';
|
||||
|
||||
import { setGlobalStore } from './backend';
|
||||
import { setupGlobalEvents } from './events';
|
||||
import { setupHotKeys } from './hotkeys';
|
||||
import { setupHotReloading } from 'tgui-dev-server/link/client.cjs';
|
||||
import { setGlobalStore } from './backend';
|
||||
import { captureExternalLinks } from './links';
|
||||
import { createRenderer } from './renderer';
|
||||
import { configureStore } from './store';
|
||||
|
||||
perf.mark('inception', window.performance?.timing?.navigationStart);
|
||||
perf.mark('init');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { sortBy } from 'common/collections';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Section, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -73,8 +73,8 @@ export const AdminTicketPanel = (props) => {
|
||||
<div dangerouslySetInnerHTML={{ __html: actions }} />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Log">
|
||||
{Object.keys(log).map((L) => (
|
||||
<div dangerouslySetInnerHTML={{ __html: log[L] }} />
|
||||
{Object.keys(log).map((L, i) => (
|
||||
<div key={i} dangerouslySetInnerHTML={{ __html: log[L] }} />
|
||||
))}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Section, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Loader } from './common/Loader';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { KEY_ENTER, KEY_ESCAPE, KEY_LEFT, KEY_RIGHT, KEY_SPACE, KEY_TAB } from '../../common/keycodes';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Autofocus, Box, Button, Flex, Section, Stack } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { Loader } from './common/Loader';
|
||||
|
||||
type AlertModalData = {
|
||||
autofocus: boolean;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { createSearch, decodeHtmlEntities } from 'common/string';
|
||||
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Button, Icon, Input, NoticeBox, Section, Stack, Table, Tooltip } from '../components';
|
||||
import { TableCell, TableRow } from '../components/Table';
|
||||
import { createSearch, decodeHtmlEntities } from 'common/string';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
|
||||
import { Window } from '../layouts';
|
||||
import { InputButtons } from './common/InputButtons';
|
||||
import { Loader } from './common/Loader';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type Data = {
|
||||
items: string[];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Fragment } from 'react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, Flex, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -2,8 +2,9 @@ import { filter } from 'common/collections';
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { decodeHtmlEntities, toTitleCase } from 'common/string';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Box, ByondUi, Button, Flex, Icon, LabeledList, Input, Section, Table } from '../components';
|
||||
import { Box, Button, ByondUi, Flex, Icon, Input, LabeledList, Section, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { CrewManifestContent } from './CrewManifest';
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { decodeHtmlEntities } from 'common/string';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Section, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { COLORS } from '../constants';
|
||||
import { decodeHtmlEntities } from 'common/string';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
/*
|
||||
* Shared by the following templates (and used individually too)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, LabeledList, Section, Box, ProgressBar } from '../components';
|
||||
import { Box, Button, LabeledList, ProgressBar, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type Data = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Flex, Tabs, Section, Button, Box, TextArea, Divider } from '../components';
|
||||
import { Box, Button, Divider, Flex, Section, Tabs, TextArea } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type data = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Box, Flex, LabeledList, Section } from '../components';
|
||||
import { Box, Button, Flex, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type Data = {
|
||||
|
||||
@@ -2,7 +2,8 @@ import { classes } from 'common/react';
|
||||
import { uniqBy } from 'common/collections';
|
||||
import { useBackend, useSharedState } from '../backend';
|
||||
import { formatSiUnit, formatMoney } from '../format';
|
||||
import { Flex, Section, Tabs, Box, Button, Fragment, ProgressBar, NumberInput, Icon, Input, Tooltip } from '../components';
|
||||
import { Flex, Section, Tabs, Box, Button, ProgressBar, NumberInput, Icon, Input, Tooltip } from '../components';
|
||||
import { Fragment } from 'react';
|
||||
import { Window } from '../layouts';
|
||||
import { createSearch, toTitleCase } from 'common/string';
|
||||
import { toFixed } from 'common/math';
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
import { Button, Section, Table, Knob } from '../components';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Knob, Section, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
export const GyrotronControl = () => (
|
||||
<Window width={627} height={700}>
|
||||
<Window.Content>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Loader } from './common/Loader';
|
||||
import { InputButtons } from './common/InputButtons';
|
||||
import { Button, Input, Section, Stack } from '../components';
|
||||
import { KEY_A, KEY_DOWN, KEY_ENTER, KEY_ESCAPE, KEY_UP, KEY_Z } from '../../common/keycodes';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { KEY_A, KEY_DOWN, KEY_ESCAPE, KEY_ENTER, KEY_UP, KEY_Z } from '../../common/keycodes';
|
||||
import { Button, Input, Section, Stack } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { InputButtons } from './common/InputButtons';
|
||||
import { Loader } from './common/Loader';
|
||||
|
||||
type ListInputData = {
|
||||
init_value: string;
|
||||
|
||||
@@ -72,8 +72,8 @@ export const MentorTicketPanel = (props) => {
|
||||
<div dangerouslySetInnerHTML={{ __html: actions }} />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Log">
|
||||
{Object.keys(log).map((L) => (
|
||||
<div dangerouslySetInnerHTML={{ __html: log[L] }} />
|
||||
{Object.keys(log).map((L, i) => (
|
||||
<div key={i} dangerouslySetInnerHTML={{ __html: log[L] }} />
|
||||
))}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, NoticeBox, Section } from '../components';
|
||||
import { NtosWindow } from '../layouts';
|
||||
import { IdentificationComputerRegions } from './IdentificationComputer';
|
||||
import { NoticeBox, Box, Section, Button } from '../components';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
type Data = {
|
||||
message: string;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Section, Button, LabeledList } from '../components';
|
||||
import { useBackend } from '../backend';
|
||||
import { NtosWindow } from '../layouts';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, LabeledList, Section } from '../components';
|
||||
import { NtosWindow } from '../layouts';
|
||||
|
||||
type Data = {
|
||||
armed: BooleanLike;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Loader } from './common/Loader';
|
||||
import { InputButtons } from './common/InputButtons';
|
||||
import { KEY_ENTER, KEY_ESCAPE } from '../../common/keycodes';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Box, Button, RestrictedInput, Section, Stack } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { InputButtons } from './common/InputButtons';
|
||||
import { Loader } from './common/Loader';
|
||||
|
||||
type NumberInputData = {
|
||||
init_value: number;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
const getStatusText = (port) => {
|
||||
if (port.input) {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, LabeledList, Section, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
const getStatusText = (port) => {
|
||||
if (port.input) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { Fragment } from 'react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Slider, Section, LabeledList } from '../components';
|
||||
import { LabeledList, Section, Slider } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { PortableBasicInfo } from './common/PortableAtmos';
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { map, sortBy } from 'common/collections';
|
||||
import { flow } from 'common/fp';
|
||||
import { toFixed } from 'common/math';
|
||||
import { pureComponentHooks } from 'common/react';
|
||||
import { Fragment } from 'react';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Box, Button, Chart, ColorBox, Flex, Icon, LabeledList, ProgressBar, Section, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
@@ -254,8 +252,6 @@ export const AreaCharge = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
AreaCharge.defaultHooks = pureComponentHooks;
|
||||
|
||||
const AreaStatusColorBox = (props) => {
|
||||
const { status } = props;
|
||||
const power = Boolean(status & 2);
|
||||
@@ -269,5 +265,3 @@ const AreaStatusColorBox = (props) => {
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
AreaStatusColorBox.defaultHooks = pureComponentHooks;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
import { Button, Section, Table, Knob } from '../components';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Knob, Section, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
export const RustCoreMonitor = () => (
|
||||
<Window width={627} height={700}>
|
||||
<Window.Content>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
import { Button, Section, Table } from '../components';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Section, Table } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
export const RustFuelControl = () => (
|
||||
<Window width={627} height={700}>
|
||||
<Window.Content>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { toFixed } from 'common/math';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Grid, NumberInput, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { T0C } from '../constants';
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Knob, Section, LabeledControls, LabeledList } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Knob, LabeledControls, LabeledList, Section } from '../components';
|
||||
import { T0C } from '../constants';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type Data = {
|
||||
temp: number;
|
||||
minTemp: number;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, LabeledList, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Loader } from './common/Loader';
|
||||
import { InputButtons } from './common/InputButtons';
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { KEY_ENTER, KEY_ESCAPE } from '../../common/keycodes'; // CHOMPedit
|
||||
import { useBackend, useLocalState } from '../backend';
|
||||
import { Box, Section, Stack, TextArea } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { InputButtons } from './common/InputButtons';
|
||||
import { Loader } from './common/Loader';
|
||||
|
||||
type TextInputData = {
|
||||
large_buttons: boolean;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable react/no-danger */
|
||||
import { useBackend } from '../backend';
|
||||
import { Stack, Tabs, Section, Box } from '../components';
|
||||
import { Box, Section, Stack, Tabs } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type data = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, LabeledList, NoticeBox, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, LabeledList, Slider, Section } from '../components';
|
||||
import { Button, LabeledList, Section, Slider } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type Data = {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
import { Button, Section } from '../components';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
const ModeSpan = {
|
||||
'Hold': '<span class="badge text-bg-secondary">Hold</span>',
|
||||
'Digest': '<span class="badge text-bg-danger">Digest</span>',
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
import { Box, Button, Section } from '../components';
|
||||
import { BooleanLike } from 'common/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Button, Section } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
export const XenoarchArtifactAnalyzer = () => {
|
||||
return (
|
||||
<Window width={250} height={140}>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user