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.*
|
/**/*.chunk.*
|
||||||
/**/*.hot-update.*
|
/**/*.hot-update.*
|
||||||
|
|
||||||
|
**.lock
|
||||||
|
**.log
|
||||||
|
**.json
|
||||||
|
**.svg
|
||||||
|
**.scss
|
||||||
|
**.md
|
||||||
|
**.css
|
||||||
|
**.txt
|
||||||
|
**.woff2
|
||||||
|
**.eot
|
||||||
|
**.ttf
|
||||||
|
|
||||||
# CHOMPEdit - Until removed
|
# CHOMPEdit - Until removed
|
||||||
/packages/tgui_ch/**
|
/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
|
browser: true
|
||||||
node: true
|
node: true
|
||||||
plugins:
|
plugins:
|
||||||
- radar
|
- sonarjs
|
||||||
- react
|
- react
|
||||||
- unused-imports
|
- unused-imports
|
||||||
|
- simple-import-sort
|
||||||
settings:
|
settings:
|
||||||
react:
|
react:
|
||||||
version: '16.10'
|
version: '18.2'
|
||||||
rules:
|
rules:
|
||||||
|
|
||||||
## Possible Errors
|
## Possible Errors
|
||||||
## ----------------------------------------
|
## ----------------------------------------
|
||||||
## Enforce “for” loop update clause moving the counter in the right
|
## 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
|
## Enforce or disallow capitalization of the first letter of a comment
|
||||||
# capitalized-comments: error
|
# capitalized-comments: error
|
||||||
## Require or disallow trailing commas
|
## Require or disallow trailing commas
|
||||||
comma-dangle: [error, {
|
comma-dangle: [
|
||||||
arrays: always-multiline,
|
error,
|
||||||
objects: always-multiline,
|
{
|
||||||
imports: always-multiline,
|
arrays: always-multiline,
|
||||||
exports: always-multiline,
|
objects: always-multiline,
|
||||||
functions: only-multiline, ## Optional on functions
|
imports: always-multiline,
|
||||||
}]
|
exports: always-multiline,
|
||||||
|
functions: only-multiline, ## Optional on functions
|
||||||
|
},
|
||||||
|
]
|
||||||
## Enforce consistent spacing before and after commas
|
## Enforce consistent spacing before and after commas
|
||||||
comma-spacing: [error, { before: false, after: true }]
|
comma-spacing: [error, { before: false, after: true }]
|
||||||
## Enforce consistent comma style
|
## Enforce consistent comma style
|
||||||
@@ -350,15 +353,15 @@ rules:
|
|||||||
## Enforce the location of arrow function bodies
|
## Enforce the location of arrow function bodies
|
||||||
# implicit-arrow-linebreak: error
|
# implicit-arrow-linebreak: error
|
||||||
## Enforce consistent indentation
|
## 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
|
## Enforce the consistent use of either double or single quotes in JSX
|
||||||
## attributes
|
## attributes
|
||||||
# jsx-quotes: [warn, prefer-double]
|
# jsx-quotes: [error, prefer-double]
|
||||||
## Enforce consistent spacing between keys and values in object literal
|
## Enforce consistent spacing between keys and values in object literal
|
||||||
## properties
|
## properties
|
||||||
# key-spacing: [warn, { beforeColon: false, afterColon: true }]
|
# key-spacing: [error, { beforeColon: false, afterColon: true }]
|
||||||
## Enforce consistent spacing before and after keywords
|
## 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
|
## Enforce position of line comments
|
||||||
# line-comment-position: error
|
# line-comment-position: error
|
||||||
## Enforce consistent linebreak style
|
## Enforce consistent linebreak style
|
||||||
@@ -370,8 +373,8 @@ rules:
|
|||||||
## Enforce a maximum depth that blocks can be nested
|
## Enforce a maximum depth that blocks can be nested
|
||||||
# max-depth: error
|
# max-depth: error
|
||||||
## Enforce a maximum line length
|
## Enforce a maximum line length
|
||||||
# max-len: [warn, {
|
# max-len: [error, {
|
||||||
# code: 120,
|
# code: 80,
|
||||||
# ## Ignore imports
|
# ## Ignore imports
|
||||||
# ignorePattern: '^(import\s.+\sfrom\s|.*require\()',
|
# ignorePattern: '^(import\s.+\sfrom\s|.*require\()',
|
||||||
# ignoreUrls: true,
|
# ignoreUrls: true,
|
||||||
@@ -415,7 +418,7 @@ rules:
|
|||||||
## Disallow mixed binary operators
|
## Disallow mixed binary operators
|
||||||
# no-mixed-operators: error
|
# no-mixed-operators: error
|
||||||
## Disallow mixed spaces and tabs for indentation
|
## 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
|
## Disallow use of chained assignment expressions
|
||||||
# no-multi-assign: error
|
# no-multi-assign: error
|
||||||
## Disallow multiple empty lines
|
## Disallow multiple empty lines
|
||||||
@@ -441,7 +444,7 @@ rules:
|
|||||||
## Disallow ternary operators when simpler alternatives exist
|
## Disallow ternary operators when simpler alternatives exist
|
||||||
# no-unneeded-ternary: error
|
# no-unneeded-ternary: error
|
||||||
## Disallow whitespace before properties
|
## Disallow whitespace before properties
|
||||||
# no-whitespace-before-property: warn
|
# no-whitespace-before-property: error
|
||||||
## Enforce the location of single-line statements
|
## Enforce the location of single-line statements
|
||||||
# nonblock-statement-body-position: error
|
# nonblock-statement-body-position: error
|
||||||
## Enforce consistent line breaks inside braces
|
## Enforce consistent line breaks inside braces
|
||||||
@@ -458,7 +461,7 @@ rules:
|
|||||||
## Require or disallow assignment operator shorthand where possible
|
## Require or disallow assignment operator shorthand where possible
|
||||||
# operator-assignment: error
|
# operator-assignment: error
|
||||||
## Enforce consistent linebreak style for operators
|
## Enforce consistent linebreak style for operators
|
||||||
# operator-linebreak: [warn, before]
|
# operator-linebreak: [error, before]
|
||||||
## Require or disallow padding within blocks
|
## Require or disallow padding within blocks
|
||||||
# padded-blocks: error
|
# padded-blocks: error
|
||||||
## Require or disallow padding lines between statements
|
## Require or disallow padding lines between statements
|
||||||
@@ -483,7 +486,7 @@ rules:
|
|||||||
## Enforce consistent spacing before blocks
|
## Enforce consistent spacing before blocks
|
||||||
space-before-blocks: [error, always]
|
space-before-blocks: [error, always]
|
||||||
## Enforce consistent spacing before function definition opening parenthesis
|
## Enforce consistent spacing before function definition opening parenthesis
|
||||||
# space-before-function-paren: [warn, {
|
# space-before-function-paren: [error, {
|
||||||
# anonymous: always,
|
# anonymous: always,
|
||||||
# named: never,
|
# named: never,
|
||||||
# asyncArrow: always,
|
# asyncArrow: always,
|
||||||
@@ -696,7 +699,7 @@ rules:
|
|||||||
react/jsx-closing-tag-location: error
|
react/jsx-closing-tag-location: error
|
||||||
## Enforce or disallow newlines inside of curly braces in JSX attributes and
|
## Enforce or disallow newlines inside of curly braces in JSX attributes and
|
||||||
## expressions (fixable)
|
## expressions (fixable)
|
||||||
# react/jsx-curly-newline: warn
|
# react/jsx-curly-newline: error
|
||||||
## Enforce or disallow spaces inside of curly braces in JSX attributes and
|
## Enforce or disallow spaces inside of curly braces in JSX attributes and
|
||||||
## expressions (fixable)
|
## expressions (fixable)
|
||||||
react/jsx-curly-spacing: error
|
react/jsx-curly-spacing: error
|
||||||
@@ -709,13 +712,13 @@ rules:
|
|||||||
## Enforce event handler naming conventions in JSX
|
## Enforce event handler naming conventions in JSX
|
||||||
react/jsx-handler-names: error
|
react/jsx-handler-names: error
|
||||||
## Validate JSX indentation (fixable)
|
## Validate JSX indentation (fixable)
|
||||||
# react/jsx-indent: [warn, 2, {
|
# react/jsx-indent: [error, 2, {
|
||||||
# checkAttributes: true,
|
# checkAttributes: true,
|
||||||
# }]
|
# }]
|
||||||
## Validate props indentation in JSX (fixable)
|
## 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
|
## Validate JSX has key prop when in array or iterator
|
||||||
# react/jsx-key: warn
|
react/jsx-key: error
|
||||||
## Validate JSX maximum depth
|
## Validate JSX maximum depth
|
||||||
react/jsx-max-depth: [error, { max: 10 }] ## Generous
|
react/jsx-max-depth: [error, { max: 10 }] ## Generous
|
||||||
## Limit maximum of props on a single line in JSX (fixable)
|
## Limit maximum of props on a single line in JSX (fixable)
|
||||||
@@ -762,3 +765,6 @@ rules:
|
|||||||
## Prevents the use of unused imports.
|
## Prevents the use of unused imports.
|
||||||
## This could be done by enabling no-unused-vars, but we're doing this for now
|
## This could be done by enabling no-unused-vars, but we're doing this for now
|
||||||
unused-imports/no-unused-imports: error
|
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/*.map
|
||||||
/public/tgui-bench.bundle.js
|
/public/tgui-bench.bundle.js
|
||||||
/public/tgui-bench.bundle.css
|
/public/tgui-bench.bundle.css
|
||||||
|
/coverage
|
||||||
|
|
||||||
## Previously ignored locations that are kept to avoid confusing git
|
## Previously ignored locations that are kept to avoid confusing git
|
||||||
## while transitioning to a new project structure.
|
## 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:**
|
**Props:**
|
||||||
|
|
||||||
- `popperContent: ReactNode` - The content that will be put inside the popper.
|
- `content: 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.
|
- `isOpen: boolean` - Whether or not the popper is open.
|
||||||
- `additionalStyles: { ... }` - A map of CSS styles to add to the element that will contain the popper.
|
- `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`
|
### `ProgressBar`
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module.exports = {
|
|||||||
testEnvironment: 'jsdom',
|
testEnvironment: 'jsdom',
|
||||||
testRunner: require.resolve('jest-circus/runner'),
|
testRunner: require.resolve('jest-circus/runner'),
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.(js|cjs|ts|tsx)$': require.resolve('babel-jest'),
|
'^.+\\.(js|cjs|ts|tsx)$': require.resolve('@swc/jest'),
|
||||||
},
|
},
|
||||||
moduleFileExtensions: ['js', 'cjs', 'ts', 'tsx', 'json'],
|
moduleFileExtensions: ['js', 'cjs', 'ts', 'tsx', 'json'],
|
||||||
resetMocks: true,
|
resetMocks: true,
|
||||||
|
|||||||
@@ -9,41 +9,33 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"tgui:analyze": "webpack --analyze",
|
"tgui:analyze": "webpack --analyze",
|
||||||
"tgui:bench": "webpack --env TGUI_BENCH=1 && node packages/tgui-bench/index.js",
|
"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:dev": "node --experimental-modules packages/tgui-dev-server/index.js",
|
||||||
"tgui:lint": "eslint packages --ext .js,.cjs,.ts,.tsx",
|
"tgui:lint": "eslint packages --ext .js,.cjs,.ts,.tsx",
|
||||||
"tgui:prettier": "prettierx --check .",
|
"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": "jest --watch",
|
||||||
"tgui:test-simple": "CI=true jest --color",
|
"tgui:test-simple": "CI=true jest --color",
|
||||||
"tgui:test-ci": "CI=true jest --color --collect-coverage",
|
"tgui:test-ci": "CI=true jest --color --collect-coverage",
|
||||||
"tgui:tsc": "tsc"
|
"tgui:tsc": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.23.3",
|
"@swc/core": "^1.3.100",
|
||||||
"@babel/eslint-parser": "^7.23.3",
|
"@swc/jest": "^0.2.29",
|
||||||
"@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",
|
|
||||||
"@types/jest": "^29.5.10",
|
"@types/jest": "^29.5.10",
|
||||||
"@types/jsdom": "^21.1.6",
|
"@types/jsdom": "^21.1.6",
|
||||||
"@types/node": "^14.x",
|
"@types/node": "^14.x",
|
||||||
"@types/webpack": "^5.28.5",
|
"@types/webpack": "^5.28.5",
|
||||||
"@types/webpack-env": "^1.18.4",
|
"@types/webpack-env": "^1.18.4",
|
||||||
"@typescript-eslint/parser": "^5.62.0",
|
"@typescript-eslint/parser": "^6.14.0",
|
||||||
"babel-jest": "^29.7.0",
|
|
||||||
"babel-loader": "^8.3.0",
|
|
||||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
|
||||||
"common": "workspace:*",
|
|
||||||
"css-loader": "^6.8.1",
|
"css-loader": "^6.8.1",
|
||||||
"esbuild-loader": "^4.0.2",
|
"esbuild-loader": "^4.0.2",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-radar": "^0.2.1",
|
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"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",
|
"file-loader": "^6.2.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-circus": "^29.7.0",
|
"jest-circus": "^29.7.0",
|
||||||
@@ -54,6 +46,7 @@
|
|||||||
"sass": "^1.69.5",
|
"sass": "^1.69.5",
|
||||||
"sass-loader": "^13.3.2",
|
"sass-loader": "^13.3.2",
|
||||||
"style-loader": "^3.3.3",
|
"style-loader": "^3.3.3",
|
||||||
|
"swc-loader": "^0.2.3",
|
||||||
"typescript": "^4.9.4",
|
"typescript": "^4.9.4",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"webpack": "^5.89.0",
|
"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
|
// Dummy Reducer
|
||||||
const counterReducer: Reducer<number, Action<string>> = (state = 0, action) => {
|
const counterReducer: Reducer<number, Action<string>> = (state = 0, action) => {
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { setupGlobalEvents } from 'tgui/events';
|
|
||||||
import 'tgui/styles/main.scss';
|
import 'tgui/styles/main.scss';
|
||||||
|
|
||||||
|
import { setupGlobalEvents } from 'tgui/events';
|
||||||
|
|
||||||
import Benchmark from './lib/benchmark';
|
import Benchmark from './lib/benchmark';
|
||||||
|
|
||||||
const sendMessage = (obj: any) => {
|
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 { backendUpdate, setGlobalStore } from 'tgui/backend';
|
||||||
|
import { DisposalBin } from 'tgui/interfaces/DisposalBin';
|
||||||
import { createRenderer } from 'tgui/renderer';
|
import { createRenderer } from 'tgui/renderer';
|
||||||
|
import { configureStore } from 'tgui/store';
|
||||||
|
|
||||||
const store = configureStore({ sideEffects: false });
|
const store = configureStore({ sideEffects: false });
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
import { promisify } from 'util';
|
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 axios = require('axios');
|
||||||
const logger = createLogger('dreamseeker');
|
const logger = createLogger('dreamseeker');
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createCompiler } from './webpack';
|
import { reloadByondCache } from './reloader.js';
|
||||||
import { reloadByondCache } from './reloader';
|
import { createCompiler } from './webpack.js';
|
||||||
|
|
||||||
const noHot = process.argv.includes('--no-hot');
|
const noHot = process.argv.includes('--no-hot');
|
||||||
const noTmp = process.argv.includes('--no-tmp');
|
const noTmp = process.argv.includes('--no-tmp');
|
||||||
|
|||||||
@@ -31,11 +31,9 @@ const ensureConnection = () => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
|
||||||
window.onunload = () => socket && socket.close();
|
window.onunload = () => socket && socket.close();
|
||||||
}
|
};
|
||||||
|
|
||||||
const subscribe = (fn) => subscribers.push(fn);
|
const subscribe = (fn) => subscribers.push(fn);
|
||||||
|
|
||||||
@@ -136,38 +134,38 @@ const sendLogEntry = (level, ns, ...args) => {
|
|||||||
|
|
||||||
const setupHotReloading = () => {
|
const setupHotReloading = () => {
|
||||||
if (
|
if (
|
||||||
// prettier-ignore
|
process.env.NODE_ENV === 'production' ||
|
||||||
process.env.NODE_ENV !== 'production'
|
!process.env.WEBPACK_HMR_ENABLED ||
|
||||||
&& process.env.WEBPACK_HMR_ENABLED
|
!window.WebSocket
|
||||||
&& window.WebSocket
|
|
||||||
) {
|
) {
|
||||||
if (module.hot) {
|
return;
|
||||||
ensureConnection();
|
}
|
||||||
sendLogEntry(0, null, 'setting up hot reloading');
|
if (module.hot) {
|
||||||
subscribe((msg) => {
|
ensureConnection();
|
||||||
const { type } = msg;
|
sendLogEntry(0, null, 'setting up hot reloading');
|
||||||
sendLogEntry(0, null, 'received', type);
|
subscribe((msg) => {
|
||||||
if (type === 'hotUpdate') {
|
const { type } = msg;
|
||||||
const status = module.hot.status();
|
sendLogEntry(0, null, 'received', type);
|
||||||
if (status !== 'idle') {
|
if (type === 'hotUpdate') {
|
||||||
sendLogEntry(0, null, 'hot reload status:', status);
|
const status = module.hot.status();
|
||||||
return;
|
if (status !== 'idle') {
|
||||||
}
|
sendLogEntry(0, null, 'hot reload status:', status);
|
||||||
module.hot
|
return;
|
||||||
.check({
|
|
||||||
ignoreUnaccepted: true,
|
|
||||||
ignoreDeclined: true,
|
|
||||||
ignoreErrored: true,
|
|
||||||
})
|
|
||||||
.then((modules) => {
|
|
||||||
sendLogEntry(0, null, 'outdated modules', modules);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
sendLogEntry(0, null, 'reload error', err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
module.hot
|
||||||
}
|
.check({
|
||||||
|
ignoreUnaccepted: true,
|
||||||
|
ignoreDeclined: true,
|
||||||
|
ignoreErrored: true,
|
||||||
|
})
|
||||||
|
.then((modules) => {
|
||||||
|
sendLogEntry(0, null, 'outdated modules', modules);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
sendLogEntry(0, null, 'reload error', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,10 @@
|
|||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { basename } from 'path';
|
import { basename } from 'path';
|
||||||
import { createLogger } from '../logging';
|
|
||||||
import { require } from '../require';
|
import { createLogger } from '../logging.js';
|
||||||
import { resolveGlob } from '../util';
|
import { require } from '../require.js';
|
||||||
|
import { resolveGlob } from '../util.js';
|
||||||
|
|
||||||
const SourceMap = require('source-map');
|
const SourceMap = require('source-map');
|
||||||
const { parse: parseStackTrace } = require('stacktrace-parser');
|
const { parse: parseStackTrace } = require('stacktrace-parser');
|
||||||
|
|||||||
@@ -6,9 +6,10 @@
|
|||||||
|
|
||||||
import http from 'http';
|
import http from 'http';
|
||||||
import { inspect } from 'util';
|
import { inspect } from 'util';
|
||||||
import { createLogger, directLog } from '../logging';
|
|
||||||
import { require } from '../require';
|
import { createLogger, directLog } from '../logging.js';
|
||||||
import { loadSourceMaps, retrace } from './retrace';
|
import { require } from '../require.js';
|
||||||
|
import { loadSourceMaps, retrace } from './retrace.js';
|
||||||
|
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import { basename } from 'path';
|
import { basename } from 'path';
|
||||||
import { DreamSeeker } from './dreamseeker';
|
|
||||||
import { createLogger } from './logging';
|
import { DreamSeeker } from './dreamseeker.js';
|
||||||
import { resolveGlob, resolvePath } from './util';
|
import { createLogger } from './logging.js';
|
||||||
import { regQuery } from './winreg';
|
import { resolveGlob, resolvePath } from './util.js';
|
||||||
|
import { regQuery } from './winreg.js';
|
||||||
|
|
||||||
const logger = createLogger('reloader');
|
const logger = createLogger('reloader');
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { require } from './require';
|
|
||||||
|
import { require } from './require.js';
|
||||||
|
|
||||||
const globPkg = require('glob');
|
const globPkg = require('glob');
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { createRequire } from 'module';
|
import { createRequire } from 'module';
|
||||||
import { dirname } from 'path';
|
import { dirname } from 'path';
|
||||||
import { loadSourceMaps, setupLink } from './link/server';
|
|
||||||
import { createLogger } from './logging';
|
import { loadSourceMaps, setupLink } from './link/server.js';
|
||||||
import { reloadByondCache } from './reloader';
|
import { createLogger } from './logging.js';
|
||||||
import { resolveGlob } from './util';
|
import { reloadByondCache } from './reloader.js';
|
||||||
|
import { resolveGlob } from './util.js';
|
||||||
|
|
||||||
const logger = createLogger('webpack');
|
const logger = createLogger('webpack');
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
import { exec } from 'child_process';
|
import { exec } from 'child_process';
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
import { createLogger } from './logging';
|
|
||||||
|
import { createLogger } from './logging.js';
|
||||||
|
|
||||||
const logger = createLogger('winreg');
|
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');
|
logger.error('could not find the start of the key value');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const value = stdout.substring(indexOfValue + 4, indexOfEol);
|
|
||||||
return value;
|
return stdout.substring(indexOfValue + 4, indexOfEol);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { Button, Section, Stack } from 'tgui/components';
|
import { Button, Section, Stack } from 'tgui/components';
|
||||||
import { Pane } from 'tgui/layouts';
|
import { Pane } from 'tgui/layouts';
|
||||||
|
|
||||||
import { NowPlayingWidget, useAudio } from './audio';
|
import { NowPlayingWidget, useAudio } from './audio';
|
||||||
import { ChatPanel, ChatTabs } from './chat';
|
import { ChatPanel, ChatTabs } from './chat';
|
||||||
import { useGame } from './game';
|
import { useGame } from './game';
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useSelector, useDispatch } from 'tgui/backend';
|
import { useDispatch, useSelector } from 'tgui/backend';
|
||||||
|
|
||||||
import { selectAudio } from './selectors';
|
import { selectAudio } from './selectors';
|
||||||
|
|
||||||
export const useAudio = () => {
|
export const useAudio = () => {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { createAction } from 'common/redux';
|
import { createAction } from 'common/redux';
|
||||||
|
|
||||||
import { createPage } from './model';
|
import { createPage } from './model';
|
||||||
|
|
||||||
export const loadChat = createAction('chat/load');
|
export const loadChat = createAction('chat/load');
|
||||||
|
|||||||
@@ -4,11 +4,12 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import DOMPurify from 'dompurify';
|
|
||||||
import { storage } from 'common/storage';
|
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 { 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 { MESSAGE_SAVE_INTERVAL } from './constants';
|
||||||
import { createMessage, serializeMessage } from './model';
|
import { createMessage, serializeMessage } from './model';
|
||||||
import { chatRenderer } from './renderer';
|
import { chatRenderer } from './renderer';
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { createUuid } from 'common/uuid';
|
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) =>
|
export const canPageAcceptType = (page, type) =>
|
||||||
type.startsWith(MESSAGE_TYPE_INTERNAL) || page.acceptedTypes[type];
|
type.startsWith(MESSAGE_TYPE_INTERNAL) || page.acceptedTypes[type];
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* @license MIT
|
* @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';
|
import { canPageAcceptType, createMainPage } from './model';
|
||||||
|
|
||||||
const mainPage = createMainPage();
|
const mainPage = createMainPage();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useSelector } from 'tgui/backend';
|
import { useSelector } from 'tgui/backend';
|
||||||
|
|
||||||
import { selectGame } from './selectors';
|
import { selectGame } from './selectors';
|
||||||
|
|
||||||
export const useGame = () => {
|
export const useGame = () => {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
import { pingSoft, pingSuccess } from '../ping/actions';
|
import { pingSoft, pingSuccess } from '../ping/actions';
|
||||||
import { connectionLost, connectionRestored, roundRestarted } from './actions';
|
import { connectionLost, connectionRestored, roundRestarted } from './actions';
|
||||||
import { selectGame } from './selectors';
|
|
||||||
import { CONNECTION_LOST_AFTER } from './constants';
|
import { CONNECTION_LOST_AFTER } from './constants';
|
||||||
|
import { selectGame } from './selectors';
|
||||||
|
|
||||||
const withTimestamp = (action) => ({
|
const withTimestamp = (action) => ({
|
||||||
...action,
|
...action,
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ import './styles/themes/vchatdark.scss';
|
|||||||
|
|
||||||
import { perf } from 'common/perf';
|
import { perf } from 'common/perf';
|
||||||
import { combineReducers } from 'common/redux';
|
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 { setupGlobalEvents } from 'tgui/events';
|
||||||
import { captureExternalLinks } from 'tgui/links';
|
import { captureExternalLinks } from 'tgui/links';
|
||||||
import { createRenderer } from 'tgui/renderer';
|
import { createRenderer } from 'tgui/renderer';
|
||||||
import { configureStore } from 'tgui/store';
|
import { configureStore } from 'tgui/store';
|
||||||
|
import { setupHotReloading } from 'tgui-dev-server/link/client.cjs';
|
||||||
|
|
||||||
import { audioMiddleware, audioReducer } from './audio';
|
import { audioMiddleware, audioReducer } from './audio';
|
||||||
import { chatMiddleware, chatReducer } from './chat';
|
import { chatMiddleware, chatReducer } from './chat';
|
||||||
import { gameMiddleware, gameReducer } from './game';
|
import { gameMiddleware, gameReducer } from './game';
|
||||||
@@ -23,7 +25,6 @@ import { setupPanelFocusHacks } from './panelFocus';
|
|||||||
import { pingMiddleware, pingReducer } from './ping';
|
import { pingMiddleware, pingReducer } from './ping';
|
||||||
import { settingsMiddleware, settingsReducer } from './settings';
|
import { settingsMiddleware, settingsReducer } from './settings';
|
||||||
import { telemetryMiddleware } from './telemetry';
|
import { telemetryMiddleware } from './telemetry';
|
||||||
import { setGlobalStore } from 'tgui/backend';
|
|
||||||
|
|
||||||
perf.mark('inception', window.performance?.timing?.navigationStart);
|
perf.mark('inception', window.performance?.timing?.navigationStart);
|
||||||
perf.mark('init');
|
perf.mark('init');
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { clamp01, scale } from 'common/math';
|
import { clamp01, scale } from 'common/math';
|
||||||
|
|
||||||
import { pingFail, pingSuccess } from './actions';
|
import { pingFail, pingSuccess } from './actions';
|
||||||
import { PING_MAX_FAILS, PING_ROUNDTRIP_BEST, PING_ROUNDTRIP_WORST } from './constants';
|
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 { useDispatch } from 'tgui/backend';
|
||||||
|
import { Button } from 'tgui/components';
|
||||||
|
|
||||||
import { dismissWarning } from './game/actions';
|
import { dismissWarning } from './game/actions';
|
||||||
|
|
||||||
let url: string | null = null;
|
let url: string | null = null;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { createAction } from 'common/redux';
|
import { createAction } from 'common/redux';
|
||||||
|
|
||||||
import { createHighlightSetting } from './model';
|
import { createHighlightSetting } from './model';
|
||||||
|
|
||||||
export const updateSettings = createAction('settings/update');
|
export const updateSettings = createAction('settings/update');
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useDispatch, useSelector } from 'tgui/backend';
|
import { useDispatch, useSelector } from 'tgui/backend';
|
||||||
import { updateSettings, toggleSettings } from './actions';
|
|
||||||
|
import { toggleSettings, updateSettings } from './actions';
|
||||||
import { selectSettings } from './selectors';
|
import { selectSettings } from './selectors';
|
||||||
|
|
||||||
export const useSettings = () => {
|
export const useSettings = () => {
|
||||||
|
|||||||
@@ -5,10 +5,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { storage } from 'common/storage';
|
import { storage } from 'common/storage';
|
||||||
|
|
||||||
import { setClientTheme } from '../themes';
|
import { setClientTheme } from '../themes';
|
||||||
import { loadSettings, updateSettings, addHighlightSetting, removeHighlightSetting, updateHighlightSetting } from './actions';
|
import { addHighlightSetting, loadSettings, removeHighlightSetting, updateHighlightSetting, updateSettings } from './actions';
|
||||||
import { selectSettings } from './selectors';
|
|
||||||
import { FONTS_DISABLED } from './constants';
|
import { FONTS_DISABLED } from './constants';
|
||||||
|
import { selectSettings } from './selectors';
|
||||||
|
|
||||||
let overrideRule = null;
|
let overrideRule = null;
|
||||||
let overrideFontFamily = null;
|
let overrideFontFamily = null;
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* @license MIT
|
* @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 { createDefaultHighlightSetting } from './model';
|
||||||
import { SETTINGS_TABS, FONTS, MAX_HIGHLIGHT_SETTINGS } from './constants';
|
|
||||||
|
|
||||||
const defaultHighlightSetting = createDefaultHighlightSetting();
|
const defaultHighlightSetting = createDefaultHighlightSetting();
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Action, AnyAction, Middleware } from '../common/redux';
|
|
||||||
|
|
||||||
import { Dispatch } from 'common/redux';
|
import { Dispatch } from 'common/redux';
|
||||||
|
|
||||||
|
import { Action, AnyAction, Middleware } from '../common/redux';
|
||||||
|
|
||||||
const EXCLUDED_PATTERNS = [/v4shim/i];
|
const EXCLUDED_PATTERNS = [/v4shim/i];
|
||||||
const loadedMappings: Record<string, string> = {};
|
const loadedMappings: Record<string, string> = {};
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
import { perf } from 'common/perf';
|
import { perf } from 'common/perf';
|
||||||
import { createAction } from 'common/redux';
|
import { createAction } from 'common/redux';
|
||||||
|
|
||||||
import { setupDrag } from './drag';
|
import { setupDrag } from './drag';
|
||||||
import { globalEvents } from './events';
|
import { globalEvents } from './events';
|
||||||
import { focusMap } from './focus';
|
import { focusMap } from './focus';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Component, createRef } from 'react';
|
import { Component, createRef } from 'react';
|
||||||
|
|
||||||
import { resolveAsset } from '../assets';
|
import { resolveAsset } from '../assets';
|
||||||
import { Box } from './Box';
|
import { Box } from './Box';
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { BooleanLike, classes } from 'common/react';
|
import { BooleanLike, classes } from 'common/react';
|
||||||
import { createElement, ReactNode } from 'react';
|
import { createElement, ReactNode } from 'react';
|
||||||
|
|
||||||
import { CSS_COLORS } from '../constants';
|
import { CSS_COLORS } from '../constants';
|
||||||
|
|
||||||
export type BoxProps = {
|
export type BoxProps = {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { map, zipWith } from 'common/collections';
|
import { map, zipWith } from 'common/collections';
|
||||||
import { Component, createRef, RefObject } from 'react';
|
import { Component, createRef, RefObject } from 'react';
|
||||||
|
|
||||||
import { Box, BoxProps } from './Box';
|
import { Box, BoxProps } from './Box';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|||||||
@@ -1,337 +1,177 @@
|
|||||||
import { createPopper, VirtualElement } from '@popperjs/core';
|
|
||||||
import { classes } from 'common/react';
|
import { classes } from 'common/react';
|
||||||
import { Component, ReactNode } from 'react';
|
import { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { findDOMNode, render } from 'react-dom';
|
|
||||||
import { Box, BoxProps } from './Box';
|
import { BoxProps, unit } from './Box';
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon';
|
||||||
import { Stack } from './Stack';
|
import { Popper } from './Popper';
|
||||||
|
|
||||||
export interface DropdownEntry {
|
type DropdownEntry = {
|
||||||
displayText: string | number | ReactNode;
|
displayText: ReactNode;
|
||||||
value: string | number | Enumerator;
|
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<{
|
export function Dropdown(props: Props) {
|
||||||
buttons: boolean;
|
const {
|
||||||
clipSelectedText: boolean;
|
buttons,
|
||||||
color: string;
|
className,
|
||||||
disabled: boolean;
|
clipSelectedText = true,
|
||||||
displayText: string | number | ReactNode;
|
color = 'default',
|
||||||
dropdownStyle: any;
|
disabled,
|
||||||
icon: string;
|
displayText,
|
||||||
iconRotation: number;
|
icon,
|
||||||
iconSpin: boolean;
|
iconRotation,
|
||||||
menuWidth: string;
|
iconSpin,
|
||||||
nochevron: boolean;
|
menuWidth = '15rem',
|
||||||
onClick: (event) => void;
|
noChevron,
|
||||||
onSelected: (selected: any) => void;
|
onClick,
|
||||||
over: boolean;
|
onSelected,
|
||||||
// you freaks really are just doing anything with this shit
|
options = [],
|
||||||
selected: any;
|
over,
|
||||||
width: string;
|
selected,
|
||||||
}>;
|
width,
|
||||||
|
} = props;
|
||||||
|
|
||||||
export type DropdownProps = BoxProps & DropdownUniqueProps;
|
const [open, setOpen] = useState(false);
|
||||||
|
const adjustedOpen = over ? !open : open;
|
||||||
|
const innerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const DEFAULT_OPTIONS = {
|
/** Update the selected value when clicking the left/right buttons */
|
||||||
placement: 'left-start',
|
const updateSelected = useCallback(
|
||||||
modifiers: [
|
(direction: 'previous' | 'next') => {
|
||||||
{
|
if (options.length < 1 || disabled) {
|
||||||
name: 'eventListeners',
|
return;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
const startIndex = 0;
|
||||||
|
const endIndex = options.length - 1;
|
||||||
|
|
||||||
return (
|
let selectedIndex = options.findIndex(
|
||||||
<div
|
(option) => getOptionValue(option) === selected
|
||||||
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';
|
if (selectedIndex < 0) {
|
||||||
|
selectedIndex = direction === 'next' ? endIndex : startIndex;
|
||||||
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) {
|
let newIndex = selectedIndex;
|
||||||
this.setState((state) => ({
|
if (direction === 'next') {
|
||||||
...state,
|
newIndex = selectedIndex === endIndex ? startIndex : selectedIndex++;
|
||||||
open,
|
} else {
|
||||||
}));
|
newIndex = selectedIndex === startIndex ? endIndex : selectedIndex--;
|
||||||
if (open) {
|
}
|
||||||
setTimeout(() => {
|
|
||||||
this.openMenu();
|
|
||||||
window.addEventListener('click', this.handleClick);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.closeMenu();
|
|
||||||
window.removeEventListener('click', this.handleClick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelected(selected: string) {
|
onSelected?.(getOptionValue(options[newIndex]));
|
||||||
this.setState((state) => ({
|
},
|
||||||
...state,
|
[disabled, onSelected, options, selected]
|
||||||
selected,
|
);
|
||||||
}));
|
|
||||||
this.setOpen(false);
|
|
||||||
if (this.props.onSelected) {
|
|
||||||
this.props.onSelected(selected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getOptionValue(option): string {
|
/** Allows the menu to be scrollable on open */
|
||||||
return typeof option === 'string' ? option : option.value;
|
useEffect(() => {
|
||||||
}
|
if (!open) return;
|
||||||
|
|
||||||
getSelectedIndex(): number {
|
innerRef.current?.focus();
|
||||||
const selected = this.state.selected || this.props.selected;
|
}, [open]);
|
||||||
const { options = [] } = this.props;
|
|
||||||
|
|
||||||
return options.findIndex((option) => {
|
return (
|
||||||
return this.getOptionValue(option) === selected;
|
<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>
|
||||||
|
)}
|
||||||
|
|
||||||
toPrevious(): void {
|
{options.map((option, index) => {
|
||||||
if (this.props.options.length < 1) {
|
const value = getOptionValue(option);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let selectedIndex = this.getSelectedIndex();
|
return (
|
||||||
const startIndex = 0;
|
<div
|
||||||
const endIndex = this.props.options.length - 1;
|
className={classes([
|
||||||
|
'Dropdown__menuentry',
|
||||||
const hasSelected = selectedIndex >= 0;
|
selected === value && 'selected',
|
||||||
if (!hasSelected) {
|
])}
|
||||||
selectedIndex = startIndex;
|
key={index}
|
||||||
}
|
onClick={() => {
|
||||||
|
setOpen(false);
|
||||||
const previousIndex =
|
onSelected?.(value);
|
||||||
selectedIndex === startIndex ? endIndex : selectedIndex - 1;
|
}}>
|
||||||
|
{typeof option === 'string' ? option : option.displayText}
|
||||||
this.setSelected(this.getOptionValue(this.props.options[previousIndex]));
|
</div>
|
||||||
}
|
);
|
||||||
|
})}
|
||||||
toNext(): void {
|
</div>
|
||||||
if (this.props.options.length < 1) {
|
}>
|
||||||
return;
|
<div>
|
||||||
}
|
<div className="Dropdown" style={{ width: unit(width) }}>
|
||||||
|
<div
|
||||||
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;
|
|
||||||
const {
|
|
||||||
icon,
|
|
||||||
iconRotation,
|
|
||||||
iconSpin,
|
|
||||||
clipSelectedText = true,
|
|
||||||
color = 'default',
|
|
||||||
dropdownStyle,
|
|
||||||
over,
|
|
||||||
nochevron,
|
|
||||||
width,
|
|
||||||
onClick,
|
|
||||||
onSelected,
|
|
||||||
selected,
|
|
||||||
disabled,
|
|
||||||
displayText,
|
|
||||||
buttons,
|
|
||||||
...boxProps
|
|
||||||
} = props;
|
|
||||||
const { className, ...rest } = boxProps;
|
|
||||||
|
|
||||||
const adjustedOpen = over ? !this.state.open : this.state.open;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack fill>
|
|
||||||
<Stack.Item width={width}>
|
|
||||||
<Box
|
|
||||||
width={'100%'}
|
|
||||||
className={classes([
|
className={classes([
|
||||||
'Dropdown__control',
|
'Dropdown__control',
|
||||||
'Button',
|
'Button',
|
||||||
|
'Button--dropdown',
|
||||||
'Button--color--' + color,
|
'Button--color--' + color,
|
||||||
disabled && 'Button--disabled',
|
disabled && 'Button--disabled',
|
||||||
className,
|
className,
|
||||||
])}
|
])}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
if (disabled && !this.state.open) {
|
if (disabled && !open) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setOpen(!this.state.open);
|
setOpen(!open);
|
||||||
if (onClick) {
|
onClick?.(event);
|
||||||
onClick(event);
|
}}>
|
||||||
}
|
|
||||||
}}
|
|
||||||
{...rest}>
|
|
||||||
{icon && (
|
{icon && (
|
||||||
<Icon
|
<Icon
|
||||||
|
mr={1}
|
||||||
name={icon}
|
name={icon}
|
||||||
rotation={iconRotation}
|
rotation={iconRotation}
|
||||||
spin={iconSpin}
|
spin={iconSpin}
|
||||||
mr={1}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span
|
<span
|
||||||
@@ -339,48 +179,37 @@ export class Dropdown extends Component<DropdownProps, DropdownState> {
|
|||||||
style={{
|
style={{
|
||||||
overflow: clipSelectedText ? 'hidden' : 'visible',
|
overflow: clipSelectedText ? 'hidden' : 'visible',
|
||||||
}}>
|
}}>
|
||||||
{displayText || this.state.selected}
|
{displayText || selected}
|
||||||
</span>
|
</span>
|
||||||
{nochevron || (
|
{!noChevron && (
|
||||||
<span className="Dropdown__arrow-button">
|
<span className="Dropdown__arrow-button">
|
||||||
<Icon name={adjustedOpen ? 'chevron-up' : 'chevron-down'} />
|
<Icon name={adjustedOpen ? 'chevron-up' : 'chevron-down'} />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</div>
|
||||||
</Stack.Item>
|
{buttons && (
|
||||||
{buttons && (
|
<>
|
||||||
<>
|
|
||||||
<Stack.Item height={'100%'}>
|
|
||||||
<Button
|
<Button
|
||||||
height={'100%'}
|
disabled={disabled}
|
||||||
|
height={1.8}
|
||||||
icon="chevron-left"
|
icon="chevron-left"
|
||||||
disabled={disabled}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (disabled) {
|
updateSelected('previous');
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.toPrevious();
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack.Item>
|
|
||||||
<Stack.Item height={'100%'}>
|
|
||||||
<Button
|
<Button
|
||||||
height={'100%'}
|
|
||||||
icon="chevron-right"
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
height={1.8}
|
||||||
|
icon="chevron-right"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (disabled) {
|
updateSelected('next');
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.toNext();
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack.Item>
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
</div>
|
||||||
</Stack>
|
</div>
|
||||||
);
|
</Popper>
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { classes } from 'common/react';
|
import { classes } from 'common/react';
|
||||||
|
|
||||||
import { BoxProps, computeBoxClassName, computeBoxProps, unit } from './Box';
|
import { BoxProps, computeBoxClassName, computeBoxProps, unit } from './Box';
|
||||||
|
|
||||||
export type FlexProps = Partial<{
|
export type FlexProps = Partial<{
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import { classes } from 'common/react';
|
import { classes } from 'common/react';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
||||||
|
|
||||||
const FA_OUTLINE_REGEX = /-o$/;
|
const FA_OUTLINE_REGEX = /-o$/;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Component } from 'react';
|
import { Component } from 'react';
|
||||||
|
|
||||||
import { KeyEvent } from '../events';
|
import { KeyEvent } from '../events';
|
||||||
import { listenForKeyEvents } from '../hotkeys';
|
import { listenForKeyEvents } from '../hotkeys';
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
import { classes } from 'common/react';
|
import { classes } from 'common/react';
|
||||||
import { Component, createRef, ReactNode, RefObject } from 'react';
|
import { Component, createRef, ReactNode, RefObject } from 'react';
|
||||||
import { Box } from './Box';
|
|
||||||
import { logger } from '../logging';
|
import { logger } from '../logging';
|
||||||
|
import { Box } from './Box';
|
||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon';
|
||||||
|
|
||||||
type MenuProps = {
|
type MenuProps = {
|
||||||
|
|||||||
@@ -1,82 +1,88 @@
|
|||||||
import { createPopper } from '@popperjs/core';
|
import { Placement } from '@popperjs/core';
|
||||||
import { ArgumentsOf } from 'common/types';
|
import { PropsWithChildren, ReactNode, useEffect, useRef, useState } from 'react';
|
||||||
import { Component, CSSProperties, JSXElementConstructor, PropsWithChildren, ReactElement, RefObject } from 'react';
|
import { usePopper } from 'react-popper';
|
||||||
import { findDOMNode, render } from 'react-dom';
|
|
||||||
|
|
||||||
type PopperProps = {
|
type RequiredProps = {
|
||||||
popperContent: ReactElement<any, string | JSXElementConstructor<any>>;
|
/** The content to display in the popper */
|
||||||
options?: ArgumentsOf<typeof createPopper>[2];
|
content: ReactNode;
|
||||||
additionalStyles?: CSSProperties;
|
/** Whether the popper is open */
|
||||||
} & PropsWithChildren;
|
isOpen: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export class Popper extends Component<PopperProps> {
|
type OptionalProps = Partial<{
|
||||||
static id: number = 0;
|
/** Called when the user clicks outside the popper */
|
||||||
popperRef: RefObject<HTMLDivElement>;
|
onClickOutside: () => void;
|
||||||
|
/** Where to place the popper relative to the reference element */
|
||||||
|
placement: Placement;
|
||||||
|
}>;
|
||||||
|
|
||||||
renderedContent: HTMLDivElement;
|
type Props = RequiredProps & OptionalProps;
|
||||||
popperInstance: ReturnType<typeof createPopper>;
|
|
||||||
|
|
||||||
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;
|
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?.();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
useEffect(() => {
|
||||||
const { additionalStyles, options } = this.props;
|
if (isOpen) {
|
||||||
|
document.addEventListener('mousedown', handleClickOutside);
|
||||||
this.renderedContent = document.createElement('div');
|
} else {
|
||||||
|
document.removeEventListener('mousedown', handleClickOutside);
|
||||||
if (additionalStyles) {
|
|
||||||
for (const [attribute, value] of Object.entries(additionalStyles)) {
|
|
||||||
this.renderedContent.style[attribute] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderPopperContent(() => {
|
return () => {
|
||||||
document.body.appendChild(this.renderedContent);
|
document.removeEventListener('mousedown', handleClickOutside);
|
||||||
|
};
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
// HACK: We don't want to create a wrapper, as it could break the layout
|
return (
|
||||||
// of consumers, so we use findDOMNode.
|
<>
|
||||||
// This is usually bad as refs are usually better, but refs did
|
<div
|
||||||
// not work in this case, as they weren't propagating correctly.
|
ref={(node) => {
|
||||||
// A previous attempt was made as a render prop that passed an ID,
|
setReferenceElement(node);
|
||||||
// but this made consuming use too unwieldly.
|
parentRef.current = node;
|
||||||
// Because this component is written in TypeScript, we will know
|
}}>
|
||||||
// immediately if this internal variable is removed.
|
{children}
|
||||||
//
|
</div>
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
{isOpen && (
|
||||||
const domNode = findDOMNode(this) as Element;
|
<div
|
||||||
if (!domNode) {
|
ref={(node) => {
|
||||||
return;
|
setPopperElement(node);
|
||||||
}
|
popperRef.current = node;
|
||||||
|
}}
|
||||||
this.popperInstance = createPopper(
|
style={{ ...styles.popper, zIndex: 5 }}
|
||||||
domNode,
|
{...attributes.popper}>
|
||||||
this.renderedContent,
|
{content}
|
||||||
options
|
</div>
|
||||||
);
|
)}
|
||||||
});
|
</>
|
||||||
}
|
);
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
this.renderPopperContent(() => this.popperInstance?.update());
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.popperInstance?.destroy();
|
|
||||||
render(<> </>, this.renderedContent, () => {
|
|
||||||
this.renderedContent.remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,13 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { clamp01, scale, keyOfMatchingRange, toFixed } from 'common/math';
|
import { clamp01, keyOfMatchingRange, scale, toFixed } from 'common/math';
|
||||||
import { classes } from 'common/react';
|
import { classes } from 'common/react';
|
||||||
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
|
||||||
import { CSS_COLORS } from '../constants';
|
|
||||||
import { PropsWithChildren } from 'react';
|
import { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
import { CSS_COLORS } from '../constants';
|
||||||
|
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
value: number;
|
value: number;
|
||||||
} & Partial<{
|
} & Partial<{
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { canRender, classes } from 'common/react';
|
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 { addScrollableNode, removeScrollableNode } from '../events';
|
||||||
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { classes } from 'common/react';
|
import { classes } from 'common/react';
|
||||||
import { RefObject } from 'react';
|
import { RefObject } from 'react';
|
||||||
|
|
||||||
import { computeFlexClassName, computeFlexItemClassName, computeFlexItemProps, computeFlexProps, FlexItemProps, FlexProps } from './Flex';
|
import { computeFlexClassName, computeFlexItemClassName, computeFlexItemProps, computeFlexProps, FlexItemProps, FlexProps } from './Flex';
|
||||||
|
|
||||||
type Props = Partial<{
|
type Props = Partial<{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PropsWithChildren, ReactNode } from 'react';
|
import { PropsWithChildren, ReactNode } from 'react';
|
||||||
|
|
||||||
import { Box } from './Box';
|
import { Box } from './Box';
|
||||||
|
|
||||||
type Props = Partial<{
|
type Props = Partial<{
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { canRender, classes } from 'common/react';
|
import { canRender, classes } from 'common/react';
|
||||||
import { PropsWithChildren, ReactNode } from 'react';
|
import { PropsWithChildren, ReactNode } from 'react';
|
||||||
|
|
||||||
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';
|
||||||
import { Icon } from './Icon';
|
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 { createPopper, Placement, VirtualElement } from '@popperjs/core';
|
||||||
import { Component, ReactNode } from 'react';
|
import { Component, ReactNode } from 'react';
|
||||||
import { findDOMNode, render } from 'react-dom';
|
import { findDOMNode, render } from 'react-dom';
|
||||||
|
|||||||
@@ -14,12 +14,13 @@ export { ByondUi } from './ByondUi';
|
|||||||
export { Chart } from './Chart';
|
export { Chart } from './Chart';
|
||||||
export { Collapsible } from './Collapsible';
|
export { Collapsible } from './Collapsible';
|
||||||
export { ColorBox } from './ColorBox';
|
export { ColorBox } from './ColorBox';
|
||||||
|
export { Dialog } from './Dialog';
|
||||||
export { Dimmer } from './Dimmer';
|
export { Dimmer } from './Dimmer';
|
||||||
export { Divider } from './Divider';
|
export { Divider } from './Divider';
|
||||||
export { DraggableControl } from './DraggableControl';
|
export { DraggableControl } from './DraggableControl';
|
||||||
export { Dropdown } from './Dropdown';
|
export { Dropdown } from './Dropdown';
|
||||||
export { Flex } from './Flex';
|
|
||||||
export { FitText } from './FitText';
|
export { FitText } from './FitText';
|
||||||
|
export { Flex } from './Flex';
|
||||||
export { Grid } from './Grid';
|
export { Grid } from './Grid';
|
||||||
export { Icon } from './Icon';
|
export { Icon } from './Icon';
|
||||||
export { InfinitePlane } from './InfinitePlane';
|
export { InfinitePlane } from './InfinitePlane';
|
||||||
@@ -32,18 +33,17 @@ export { MenuBar } from './MenuBar';
|
|||||||
export { Modal } from './Modal';
|
export { Modal } from './Modal';
|
||||||
export { NoticeBox } from './NoticeBox';
|
export { NoticeBox } from './NoticeBox';
|
||||||
export { NumberInput } from './NumberInput';
|
export { NumberInput } from './NumberInput';
|
||||||
export { ProgressBar } from './ProgressBar';
|
|
||||||
export { Popper } from './Popper';
|
export { Popper } from './Popper';
|
||||||
|
export { ProgressBar } from './ProgressBar';
|
||||||
export { RestrictedInput } from './RestrictedInput';
|
export { RestrictedInput } from './RestrictedInput';
|
||||||
export { RoundGauge } from './RoundGauge';
|
export { RoundGauge } from './RoundGauge';
|
||||||
export { Section } from './Section';
|
export { Section } from './Section';
|
||||||
export { Slider } from './Slider';
|
export { Slider } from './Slider';
|
||||||
export { StyleableSection } from './StyleableSection';
|
|
||||||
export { Stack } from './Stack';
|
export { Stack } from './Stack';
|
||||||
|
export { StyleableSection } from './StyleableSection';
|
||||||
export { Table } from './Table';
|
export { Table } from './Table';
|
||||||
export { Tabs } from './Tabs';
|
export { Tabs } from './Tabs';
|
||||||
export { TextArea } from './TextArea';
|
export { TextArea } from './TextArea';
|
||||||
export { TimeDisplay } from './TimeDisplay';
|
export { TimeDisplay } from './TimeDisplay';
|
||||||
export { TrackOutsideClicks } from './TrackOutsideClicks';
|
|
||||||
export { Tooltip } from './Tooltip';
|
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 { KEY_BACKSPACE, KEY_F10, KEY_F11, KEY_F12 } from 'common/keycodes';
|
||||||
|
|
||||||
import { globalEvents } from '../events';
|
import { globalEvents } from '../events';
|
||||||
import { acquireHotKey } from '../hotkeys';
|
import { acquireHotKey } from '../hotkeys';
|
||||||
import { openExternalBrowser, toggleDebugLayout, toggleKitchenSink } from './actions';
|
import { openExternalBrowser, toggleDebugLayout, toggleKitchenSink } from './actions';
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { storage } from 'common/storage';
|
||||||
import { vecAdd, vecMultiply, vecScale, vecSubtract } from 'common/vector';
|
import { vecAdd, vecMultiply, vecScale, vecSubtract } from 'common/vector';
|
||||||
|
|
||||||
import { createLogger } from './logging';
|
import { createLogger } from './logging';
|
||||||
import { storage } from 'common/storage';
|
|
||||||
|
|
||||||
const logger = createLogger('drag');
|
const logger = createLogger('drag');
|
||||||
const pixelRatio = window.devicePixelRatio ?? 1;
|
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', () => {
|
describe('focusEvents', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|||||||
@@ -6,9 +6,8 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { KEY_ALT, KEY_CTRL, KEY_F1, KEY_F12, KEY_SHIFT } from 'common/keycodes';
|
|
||||||
|
|
||||||
import { EventEmitter } from 'common/events';
|
import { EventEmitter } from 'common/events';
|
||||||
|
import { KEY_ALT, KEY_CTRL, KEY_F1, KEY_F12, KEY_SHIFT } from 'common/keycodes';
|
||||||
|
|
||||||
export const globalEvents = new EventEmitter();
|
export const globalEvents = new EventEmitter();
|
||||||
let ignoreWindowFocus = false;
|
let ignoreWindowFocus = false;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as keycodes from 'common/keycodes';
|
import * as keycodes from 'common/keycodes';
|
||||||
|
|
||||||
import { globalEvents, KeyEvent } from './events';
|
import { globalEvents, KeyEvent } from './events';
|
||||||
import { createLogger } from './logging';
|
import { createLogger } from './logging';
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,15 @@ import './styles/themes/syndicate.scss';
|
|||||||
import './styles/themes/wizard.scss';
|
import './styles/themes/wizard.scss';
|
||||||
import './styles/themes/abstract.scss';
|
import './styles/themes/abstract.scss';
|
||||||
|
|
||||||
import { configureStore } from './store';
|
|
||||||
|
|
||||||
import { captureExternalLinks } from './links';
|
|
||||||
import { createRenderer } from './renderer';
|
|
||||||
import { perf } from 'common/perf';
|
import { perf } from 'common/perf';
|
||||||
|
import { setupHotReloading } from 'tgui-dev-server/link/client.cjs';
|
||||||
|
|
||||||
|
import { setGlobalStore } from './backend';
|
||||||
import { setupGlobalEvents } from './events';
|
import { setupGlobalEvents } from './events';
|
||||||
import { setupHotKeys } from './hotkeys';
|
import { setupHotKeys } from './hotkeys';
|
||||||
import { setupHotReloading } from 'tgui-dev-server/link/client.cjs';
|
import { captureExternalLinks } from './links';
|
||||||
import { setGlobalStore } from './backend';
|
import { createRenderer } from './renderer';
|
||||||
|
import { configureStore } from './store';
|
||||||
|
|
||||||
perf.mark('inception', window.performance?.timing?.navigationStart);
|
perf.mark('inception', window.performance?.timing?.navigationStart);
|
||||||
perf.mark('init');
|
perf.mark('init');
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { sortBy } from 'common/collections';
|
import { sortBy } from 'common/collections';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, Section, Table } from '../components';
|
import { Button, Section, Table } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ export const AdminTicketPanel = (props) => {
|
|||||||
<div dangerouslySetInnerHTML={{ __html: actions }} />
|
<div dangerouslySetInnerHTML={{ __html: actions }} />
|
||||||
</LabeledList.Item>
|
</LabeledList.Item>
|
||||||
<LabeledList.Item label="Log">
|
<LabeledList.Item label="Log">
|
||||||
{Object.keys(log).map((L) => (
|
{Object.keys(log).map((L, i) => (
|
||||||
<div dangerouslySetInnerHTML={{ __html: log[L] }} />
|
<div key={i} dangerouslySetInnerHTML={{ __html: log[L] }} />
|
||||||
))}
|
))}
|
||||||
</LabeledList.Item>
|
</LabeledList.Item>
|
||||||
</LabeledList>
|
</LabeledList>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, Section, Table } from '../components';
|
import { Button, Section, Table } from '../components';
|
||||||
import { Window } from '../layouts';
|
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 { 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 { Autofocus, Box, Button, Flex, Section, Stack } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
import { Loader } from './common/Loader';
|
||||||
|
|
||||||
type AlertModalData = {
|
type AlertModalData = {
|
||||||
autofocus: boolean;
|
autofocus: boolean;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, LabeledList, Section } from '../components';
|
import { Button, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
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 { Button, Icon, Input, NoticeBox, Section, Stack, Table, Tooltip } from '../components';
|
||||||
import { TableCell, TableRow } from '../components/Table';
|
import { TableCell, TableRow } from '../components/Table';
|
||||||
import { createSearch, decodeHtmlEntities } from 'common/string';
|
import { Window } from '../layouts';
|
||||||
import { useBackend, useLocalState } from '../backend';
|
|
||||||
|
|
||||||
import { InputButtons } from './common/InputButtons';
|
import { InputButtons } from './common/InputButtons';
|
||||||
import { Loader } from './common/Loader';
|
import { Loader } from './common/Loader';
|
||||||
import { Window } from '../layouts';
|
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
items: string[];
|
items: string[];
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Box, Button, Flex, Section } from '../components';
|
import { Box, Button, Flex, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import { filter } from 'common/collections';
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
import { decodeHtmlEntities, toTitleCase } from 'common/string';
|
import { decodeHtmlEntities, toTitleCase } from 'common/string';
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
|
|
||||||
import { useBackend, useLocalState } from '../backend';
|
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 { Window } from '../layouts';
|
||||||
import { CrewManifestContent } from './CrewManifest';
|
import { CrewManifestContent } from './CrewManifest';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import { decodeHtmlEntities } from 'common/string';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Box, Section, Table } from '../components';
|
import { Box, Section, Table } from '../components';
|
||||||
import { Window } from '../layouts';
|
|
||||||
import { COLORS } from '../constants';
|
import { COLORS } from '../constants';
|
||||||
import { decodeHtmlEntities } from 'common/string';
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shared by the following templates (and used individually too)
|
* Shared by the following templates (and used individually too)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, LabeledList, Section, Box, ProgressBar } from '../components';
|
import { Box, Button, LabeledList, ProgressBar, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend, useLocalState } from '../backend';
|
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';
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
type data = {
|
type data = {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, Box, Flex, LabeledList, Section } from '../components';
|
import { Box, Button, Flex, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import { classes } from 'common/react';
|
|||||||
import { uniqBy } from 'common/collections';
|
import { uniqBy } from 'common/collections';
|
||||||
import { useBackend, useSharedState } from '../backend';
|
import { useBackend, useSharedState } from '../backend';
|
||||||
import { formatSiUnit, formatMoney } from '../format';
|
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 { Window } from '../layouts';
|
||||||
import { createSearch, toTitleCase } from 'common/string';
|
import { createSearch, toTitleCase } from 'common/string';
|
||||||
import { toFixed } from 'common/math';
|
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 { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
|
import { useBackend } from '../backend';
|
||||||
|
import { Button, Knob, Section, Table } from '../components';
|
||||||
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
export const GyrotronControl = () => (
|
export const GyrotronControl = () => (
|
||||||
<Window width={627} height={700}>
|
<Window width={627} height={700}>
|
||||||
<Window.Content>
|
<Window.Content>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, LabeledList, Section } from '../components';
|
import { Button, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Loader } from './common/Loader';
|
import { KEY_A, KEY_DOWN, KEY_ENTER, KEY_ESCAPE, KEY_UP, KEY_Z } from '../../common/keycodes';
|
||||||
import { InputButtons } from './common/InputButtons';
|
|
||||||
import { Button, Input, Section, Stack } from '../components';
|
|
||||||
import { useBackend, useLocalState } from '../backend';
|
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 { Window } from '../layouts';
|
||||||
|
import { InputButtons } from './common/InputButtons';
|
||||||
|
import { Loader } from './common/Loader';
|
||||||
|
|
||||||
type ListInputData = {
|
type ListInputData = {
|
||||||
init_value: string;
|
init_value: string;
|
||||||
|
|||||||
@@ -72,8 +72,8 @@ export const MentorTicketPanel = (props) => {
|
|||||||
<div dangerouslySetInnerHTML={{ __html: actions }} />
|
<div dangerouslySetInnerHTML={{ __html: actions }} />
|
||||||
</LabeledList.Item>
|
</LabeledList.Item>
|
||||||
<LabeledList.Item label="Log">
|
<LabeledList.Item label="Log">
|
||||||
{Object.keys(log).map((L) => (
|
{Object.keys(log).map((L, i) => (
|
||||||
<div dangerouslySetInnerHTML={{ __html: log[L] }} />
|
<div key={i} dangerouslySetInnerHTML={{ __html: log[L] }} />
|
||||||
))}
|
))}
|
||||||
</LabeledList.Item>
|
</LabeledList.Item>
|
||||||
</LabeledList>
|
</LabeledList>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Box, Button, LabeledList, Section } from '../components';
|
import { Box, Button, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Box, Button, LabeledList, Section } from '../components';
|
import { Box, Button, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
|
import { Box, Button, NoticeBox, Section } from '../components';
|
||||||
import { NtosWindow } from '../layouts';
|
import { NtosWindow } from '../layouts';
|
||||||
import { IdentificationComputerRegions } from './IdentificationComputer';
|
import { IdentificationComputerRegions } from './IdentificationComputer';
|
||||||
import { NoticeBox, Box, Section, Button } from '../components';
|
|
||||||
import { BooleanLike } from 'common/react';
|
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
message: string;
|
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 { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
|
import { useBackend } from '../backend';
|
||||||
|
import { Button, LabeledList, Section } from '../components';
|
||||||
|
import { NtosWindow } from '../layouts';
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
armed: BooleanLike;
|
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 { KEY_ENTER, KEY_ESCAPE } from '../../common/keycodes';
|
||||||
import { useBackend, useLocalState } from '../backend';
|
import { useBackend, useLocalState } from '../backend';
|
||||||
import { Box, Button, RestrictedInput, Section, Stack } from '../components';
|
import { Box, Button, RestrictedInput, Section, Stack } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
import { InputButtons } from './common/InputButtons';
|
||||||
|
import { Loader } from './common/Loader';
|
||||||
|
|
||||||
type NumberInputData = {
|
type NumberInputData = {
|
||||||
init_value: number;
|
init_value: number;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { useBackend } from '../backend';
|
import { BooleanLike } from 'common/react';
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
|
|
||||||
|
import { useBackend } from '../backend';
|
||||||
import { Box, Button, LabeledList, Section } from '../components';
|
import { Box, Button, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
import { BooleanLike } from 'common/react';
|
|
||||||
|
|
||||||
const getStatusText = (port) => {
|
const getStatusText = (port) => {
|
||||||
if (port.input) {
|
if (port.input) {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { useBackend } from '../backend';
|
import { BooleanLike } from 'common/react';
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
|
|
||||||
|
import { useBackend } from '../backend';
|
||||||
import { Box, Button, LabeledList, Section, Table } from '../components';
|
import { Box, Button, LabeledList, Section, Table } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
import { BooleanLike } from 'common/react';
|
|
||||||
|
|
||||||
const getStatusText = (port) => {
|
const getStatusText = (port) => {
|
||||||
if (port.input) {
|
if (port.input) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
import { Fragment } from 'react';
|
import { Fragment } from 'react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, LabeledList, Section } from '../components';
|
import { Button, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Box, Button, LabeledList, Section } from '../components';
|
import { Box, Button, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Box, Button, LabeledList, Section } from '../components';
|
import { Box, Button, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Slider, Section, LabeledList } from '../components';
|
import { LabeledList, Section, Slider } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
import { PortableBasicInfo } from './common/PortableAtmos';
|
import { PortableBasicInfo } from './common/PortableAtmos';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { map, sortBy } from 'common/collections';
|
import { map, sortBy } from 'common/collections';
|
||||||
import { flow } from 'common/fp';
|
import { flow } from 'common/fp';
|
||||||
import { toFixed } from 'common/math';
|
import { toFixed } from 'common/math';
|
||||||
import { pureComponentHooks } from 'common/react';
|
|
||||||
import { Fragment } from 'react';
|
|
||||||
import { useBackend, useLocalState } from '../backend';
|
import { useBackend, useLocalState } from '../backend';
|
||||||
import { Box, Button, Chart, ColorBox, Flex, Icon, LabeledList, ProgressBar, Section, Table } from '../components';
|
import { Box, Button, Chart, ColorBox, Flex, Icon, LabeledList, ProgressBar, Section, Table } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
@@ -254,8 +252,6 @@ export const AreaCharge = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
AreaCharge.defaultHooks = pureComponentHooks;
|
|
||||||
|
|
||||||
const AreaStatusColorBox = (props) => {
|
const AreaStatusColorBox = (props) => {
|
||||||
const { status } = props;
|
const { status } = props;
|
||||||
const power = Boolean(status & 2);
|
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 { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
|
import { useBackend } from '../backend';
|
||||||
|
import { Button, Knob, Section, Table } from '../components';
|
||||||
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
export const RustCoreMonitor = () => (
|
export const RustCoreMonitor = () => (
|
||||||
<Window width={627} height={700}>
|
<Window width={627} height={700}>
|
||||||
<Window.Content>
|
<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 { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
|
import { useBackend } from '../backend';
|
||||||
|
import { Button, Section, Table } from '../components';
|
||||||
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
export const RustFuelControl = () => (
|
export const RustFuelControl = () => (
|
||||||
<Window width={627} height={700}>
|
<Window width={627} height={700}>
|
||||||
<Window.Content>
|
<Window.Content>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { toFixed } from 'common/math';
|
import { toFixed } from 'common/math';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, Grid, NumberInput, Section } from '../components';
|
import { Button, Grid, NumberInput, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
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 { 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 = {
|
type Data = {
|
||||||
temp: number;
|
temp: number;
|
||||||
minTemp: number;
|
minTemp: number;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, LabeledList, Section } from '../components';
|
import { Button, LabeledList, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
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 { KEY_ENTER, KEY_ESCAPE } from '../../common/keycodes'; // CHOMPedit
|
||||||
|
import { useBackend, useLocalState } from '../backend';
|
||||||
import { Box, Section, Stack, TextArea } from '../components';
|
import { Box, Section, Stack, TextArea } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
import { InputButtons } from './common/InputButtons';
|
||||||
|
import { Loader } from './common/Loader';
|
||||||
|
|
||||||
type TextInputData = {
|
type TextInputData = {
|
||||||
large_buttons: boolean;
|
large_buttons: boolean;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable react/no-danger */
|
/* eslint-disable react/no-danger */
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Stack, Tabs, Section, Box } from '../components';
|
import { Box, Section, Stack, Tabs } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
type data = {
|
type data = {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BooleanLike } from 'common/react';
|
import { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, LabeledList, NoticeBox, Section } from '../components';
|
import { Button, LabeledList, NoticeBox, Section } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useBackend } from '../backend';
|
import { useBackend } from '../backend';
|
||||||
import { Button, LabeledList, Slider, Section } from '../components';
|
import { Button, LabeledList, Section, Slider } from '../components';
|
||||||
import { Window } from '../layouts';
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
type Data = {
|
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 { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
|
import { useBackend } from '../backend';
|
||||||
|
import { Button, Section } from '../components';
|
||||||
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
const ModeSpan = {
|
const ModeSpan = {
|
||||||
'Hold': '<span class="badge text-bg-secondary">Hold</span>',
|
'Hold': '<span class="badge text-bg-secondary">Hold</span>',
|
||||||
'Digest': '<span class="badge text-bg-danger">Digest</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 { BooleanLike } from 'common/react';
|
||||||
|
|
||||||
|
import { useBackend } from '../backend';
|
||||||
|
import { Box, Button, Section } from '../components';
|
||||||
|
import { Window } from '../layouts';
|
||||||
|
|
||||||
export const XenoarchArtifactAnalyzer = () => {
|
export const XenoarchArtifactAnalyzer = () => {
|
||||||
return (
|
return (
|
||||||
<Window width={250} height={140}>
|
<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