Added prettierx

This commit is contained in:
ItsSelis
2022-06-25 18:55:15 +02:00
parent e30409dc7d
commit a8b458dcc9
424 changed files with 14661 additions and 20149 deletions
+2 -1
View File
@@ -9,6 +9,7 @@
"dbaeumer.vscode-eslint",
"editorconfig.editorconfig",
"donkie.vscode-tgstation-test-adapter",
"icrawl.discord-vscode"
"icrawl.discord-vscode",
"esbenp.prettier-vscode"
]
}
+26 -13
View File
@@ -1,8 +1,7 @@
{
"eslint.nodePath": "./tgui/.yarn/sdks",
"eslint.workingDirectories": [
"./tgui"
],
"eslint.workingDirectories": ["./tgui"],
"prettier.prettierPath": "./tgui/.yarn/sdks/prettier/index.js",
"typescript.tsdk": "./tgui/.yarn/sdks/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"search.exclude": {
@@ -13,24 +12,38 @@
"*.dmi": "imagePreview.previewEditor"
},
"files.eol": "\n",
"files.encoding": "utf8",
"files.associations": {
"*.{dme,dmf,dmm,dm}": "dm",
},
"gitlens.advanced.blame.customArguments": [
"-w"
],
"tgstationTestExplorer.project.resultsType": "json",
"[javascript]": {
"editor.rulers": [
120
]
"editor.rulers": [120],
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[javascriptreact]": {
"editor.rulers": [120],
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[typescript]": {
"editor.rulers": [
120
]
"editor.rulers": [120],
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[typescriptreact]": {
"editor.rulers": [120],
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[scss]": {
"editor.rulers": [
120
]
"editor.rulers": [120],
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"tgstationTestExplorer.project.DMEName": "tgmc.dme"
}
}
+28 -27
View File
@@ -1,4 +1,5 @@
root: true
extends: prettier
parser: '@typescript-eslint/parser'
parserOptions:
ecmaVersion: 2020
@@ -349,15 +350,15 @@ rules:
## Enforce the location of arrow function bodies
# implicit-arrow-linebreak: error
## Enforce consistent indentation
indent: [error, 2, { SwitchCase: 1 }]
# indent: [warn, 2, { SwitchCase: 1 }]
## Enforce the consistent use of either double or single quotes in JSX
## attributes
jsx-quotes: [error, prefer-double]
# jsx-quotes: [warn, prefer-double]
## Enforce consistent spacing between keys and values in object literal
## properties
key-spacing: [error, { beforeColon: false, afterColon: true }]
# key-spacing: [warn, { beforeColon: false, afterColon: true }]
## Enforce consistent spacing before and after keywords
keyword-spacing: [error, { before: true, after: true }]
# keyword-spacing: [warn, { before: true, after: true }]
## Enforce position of line comments
# line-comment-position: error
## Enforce consistent linebreak style
@@ -369,15 +370,15 @@ rules:
## Enforce a maximum depth that blocks can be nested
# max-depth: error
## Enforce a maximum line length
max-len: [error, {
code: 120,
## Ignore imports
ignorePattern: '^(import\s.+\sfrom\s|.*require\()',
ignoreUrls: true,
ignoreRegExpLiterals: true,
ignoreStrings: true,
ignoreTemplateLiterals: true,
}]
# max-len: [warn, {
# code: 120,
# ## Ignore imports
# ignorePattern: '^(import\s.+\sfrom\s|.*require\()',
# ignoreUrls: true,
# ignoreRegExpLiterals: true,
# ignoreStrings: true,
# ignoreTemplateLiterals: true,
# }]
## Enforce a maximum number of lines per file
# max-lines: error
## Enforce a maximum number of line of code in a function
@@ -414,7 +415,7 @@ rules:
## Disallow mixed binary operators
# no-mixed-operators: error
## Disallow mixed spaces and tabs for indentation
no-mixed-spaces-and-tabs: error
no-mixed-spaces-and-tabs: warn
## Disallow use of chained assignment expressions
# no-multi-assign: error
## Disallow multiple empty lines
@@ -440,7 +441,7 @@ rules:
## Disallow ternary operators when simpler alternatives exist
# no-unneeded-ternary: error
## Disallow whitespace before properties
no-whitespace-before-property: error
# no-whitespace-before-property: warn
## Enforce the location of single-line statements
# nonblock-statement-body-position: error
## Enforce consistent line breaks inside braces
@@ -457,7 +458,7 @@ rules:
## Require or disallow assignment operator shorthand where possible
# operator-assignment: error
## Enforce consistent linebreak style for operators
operator-linebreak: [error, before]
# operator-linebreak: [warn, before]
## Require or disallow padding within blocks
# padded-blocks: error
## Require or disallow padding lines between statements
@@ -482,11 +483,11 @@ rules:
## Enforce consistent spacing before blocks
space-before-blocks: [error, always]
## Enforce consistent spacing before function definition opening parenthesis
space-before-function-paren: [error, {
anonymous: always,
named: never,
asyncArrow: always,
}]
# space-before-function-paren: [warn, {
# anonymous: always,
# named: never,
# asyncArrow: always,
# }]
## Enforce consistent spacing inside parentheses
space-in-parens: [error, never]
## Require spacing around infix operators
@@ -695,7 +696,7 @@ rules:
react/jsx-closing-tag-location: error
## Enforce or disallow newlines inside of curly braces in JSX attributes and
## expressions (fixable)
react/jsx-curly-newline: error
# react/jsx-curly-newline: warn
## Enforce or disallow spaces inside of curly braces in JSX attributes and
## expressions (fixable)
react/jsx-curly-spacing: error
@@ -708,13 +709,13 @@ rules:
## Enforce event handler naming conventions in JSX
react/jsx-handler-names: error
## Validate JSX indentation (fixable)
react/jsx-indent: [error, 2, {
checkAttributes: true,
}]
# react/jsx-indent: [warn, 2, {
# checkAttributes: true,
# }]
## Validate props indentation in JSX (fixable)
react/jsx-indent-props: [error, 2]
# react/jsx-indent-props: [warn, 2]
## Validate JSX has key prop when in array or iterator
react/jsx-key: error
# react/jsx-key: warn
## Validate JSX maximum depth
react/jsx-max-depth: [error, { max: 10 }] ## Generous
## Limit maximum of props on a single line in JSX (fixable)
+19
View File
@@ -0,0 +1,19 @@
## NPM
/**/node_modules
## Yarn
/.yarn
/yarn.lock
/.pnp.*
/docs
/public
/packages/tgui-polyfill
/packages/tgfont/static
**/*.json
**/*.yml
**/*.md
## Build artifacts
/public/.tmp/**/*
/public/*.map
+4 -1
View File
@@ -1,8 +1,10 @@
arrowParens: always
bracketSpacing: true
breakLongMethodChains: true
endOfLine: lf
importFormatting: oneline
jsxBracketSameLine: true
jsxSingleQuote: false
offsetTernaryExpressions: true
printWidth: 120
proseWrap: preserve
quoteProps: preserve
@@ -10,3 +12,4 @@ semi: true
singleQuote: true
tabWidth: 2
trailingComma: es5
useTabs: false
+3 -3
View File
@@ -11,10 +11,10 @@ const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require eslint/lib/api.js
// Setup the environment to be able to require eslint
require(absPnpApiPath).setup();
}
}
// Defer to the real eslint/lib/api.js your application uses
module.exports = absRequire(`eslint/lib/api.js`);
// Defer to the real eslint your application uses
module.exports = absRequire(`eslint`);
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env node
const {existsSync} = require(`fs`);
const {createRequire, createRequireFromPath} = require(`module`);
const {resolve} = require(`path`);
const relPnpApiPath = "../../../.pnp.cjs";
const absPnpApiPath = resolve(__dirname, relPnpApiPath);
const absRequire = (createRequire || createRequireFromPath)(absPnpApiPath);
if (existsSync(absPnpApiPath)) {
if (!process.versions.pnp) {
// Setup the environment to be able to require prettier/index.js
require(absPnpApiPath).setup();
}
}
// Defer to the real prettier/index.js your application uses
module.exports = absRequire(`prettier/index.js`);
+6
View File
@@ -0,0 +1,6 @@
{
"name": "prettier",
"version": "0.19.0-sdk",
"main": "./index.js",
"type": "commonjs"
}
+78 -12
View File
@@ -18,6 +18,7 @@ const moduleWrapper = tsserver => {
const pnpApi = require(`pnpapi`);
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
const isPortal = str => str.startsWith("portal:/");
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
@@ -30,7 +31,7 @@ const moduleWrapper = tsserver => {
function toEditorPath(str) {
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
if (isAbsolute(str) && !str.match(/^\^zip:/) && (str.match(/\.zip\//) || isVirtual(str))) {
if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) {
// We also take the opportunity to turn virtual paths into physical ones;
// this makes it much easier to work with workspaces that list peer
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
@@ -44,7 +45,7 @@ const moduleWrapper = tsserver => {
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
if (resolved) {
const locator = pnpApi.findPackageLocator(resolved);
if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) {
if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) {
str = resolved;
}
}
@@ -60,10 +61,34 @@ const moduleWrapper = tsserver => {
//
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
//
case `vscode`: {
// 2021-10-08: VSCode changed the format in 1.61.
// Before | ^zip:/c:/foo/bar.zip/package.json
// After | ^/zip//c:/foo/bar.zip/package.json
//
// 2022-04-06: VSCode changed the format in 1.66.
// Before | ^/zip//c:/foo/bar.zip/package.json
// After | ^/zip/c:/foo/bar.zip/package.json
//
// 2022-05-06: VSCode changed the format in 1.68
// Before | ^/zip/c:/foo/bar.zip/package.json
// After | ^/zip//c:/foo/bar.zip/package.json
//
case `vscode <1.61`: {
str = `^zip:${str}`;
} break;
case `vscode <1.66`: {
str = `^/zip/${str}`;
} break;
case `vscode <1.68`: {
str = `^/zip${str}`;
} break;
case `vscode`: {
str = `^/zip/${str}`;
} break;
// To make "go to definition" work,
// We have to resolve the actual file system path from virtual path
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
@@ -77,7 +102,7 @@ const moduleWrapper = tsserver => {
// everything else is up to neovim
case `neovim`: {
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
str = `zipfile:${str}`;
str = `zipfile://${str}`;
} break;
default: {
@@ -91,9 +116,28 @@ const moduleWrapper = tsserver => {
}
function fromEditorPath(str) {
return process.platform === `win32`
? str.replace(/^\^?zip:\//, ``)
: str.replace(/^\^?zip:/, ``);
switch (hostInfo) {
case `coc-nvim`: {
str = str.replace(/\.zip::/, `.zip/`);
// The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...
// So in order to convert it back, we use .* to match all the thing
// before `zipfile:`
return process.platform === `win32`
? str.replace(/^.*zipfile:\//, ``)
: str.replace(/^.*zipfile:/, ``);
} break;
case `neovim`: {
str = str.replace(/\.zip::/, `.zip/`);
// The path for neovim is in format of zipfile:///<pwd>/.yarn/...
return str.replace(/^zipfile:\/\//, ``);
} break;
case `vscode`:
default: {
return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`)
} break;
}
}
// Force enable 'allowLocalPluginLoads'
@@ -119,8 +163,9 @@ const moduleWrapper = tsserver => {
let hostInfo = `unknown`;
Object.assign(Session.prototype, {
onMessage(/** @type {string} */ message) {
const parsedMessage = JSON.parse(message)
onMessage(/** @type {string | object} */ message) {
const isStringMessage = typeof message === 'string';
const parsedMessage = isStringMessage ? JSON.parse(message) : message;
if (
parsedMessage != null &&
@@ -129,11 +174,32 @@ const moduleWrapper = tsserver => {
typeof parsedMessage.arguments.hostInfo === `string`
) {
hostInfo = parsedMessage.arguments.hostInfo;
if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) {
const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match(
// The RegExp from https://semver.org/ but without the caret at the start
/(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
) ?? []).map(Number)
if (major === 1) {
if (minor < 61) {
hostInfo += ` <1.61`;
} else if (minor < 66) {
hostInfo += ` <1.66`;
} else if (minor < 68) {
hostInfo += ` <1.68`;
}
}
}
}
return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => {
return typeof value === `string` ? fromEditorPath(value) : value;
}));
const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => {
return typeof value === 'string' ? fromEditorPath(value) : value;
});
return originalOnMessage.call(
this,
isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON)
);
},
send(/** @type {any} */ msg) {
+78 -12
View File
@@ -18,6 +18,7 @@ const moduleWrapper = tsserver => {
const pnpApi = require(`pnpapi`);
const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
const isPortal = str => str.startsWith("portal:/");
const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);
const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
@@ -30,7 +31,7 @@ const moduleWrapper = tsserver => {
function toEditorPath(str) {
// We add the `zip:` prefix to both `.zip/` paths and virtual paths
if (isAbsolute(str) && !str.match(/^\^zip:/) && (str.match(/\.zip\//) || isVirtual(str))) {
if (isAbsolute(str) && !str.match(/^\^?(zip:|\/zip\/)/) && (str.match(/\.zip\//) || isVirtual(str))) {
// We also take the opportunity to turn virtual paths into physical ones;
// this makes it much easier to work with workspaces that list peer
// dependencies, since otherwise Ctrl+Click would bring us to the virtual
@@ -44,7 +45,7 @@ const moduleWrapper = tsserver => {
const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
if (resolved) {
const locator = pnpApi.findPackageLocator(resolved);
if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) {
if (locator && (dependencyTreeRoots.has(`${locator.name}@${locator.reference}`) || isPortal(locator.reference))) {
str = resolved;
}
}
@@ -60,10 +61,34 @@ const moduleWrapper = tsserver => {
//
// Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
//
case `vscode`: {
// 2021-10-08: VSCode changed the format in 1.61.
// Before | ^zip:/c:/foo/bar.zip/package.json
// After | ^/zip//c:/foo/bar.zip/package.json
//
// 2022-04-06: VSCode changed the format in 1.66.
// Before | ^/zip//c:/foo/bar.zip/package.json
// After | ^/zip/c:/foo/bar.zip/package.json
//
// 2022-05-06: VSCode changed the format in 1.68
// Before | ^/zip/c:/foo/bar.zip/package.json
// After | ^/zip//c:/foo/bar.zip/package.json
//
case `vscode <1.61`: {
str = `^zip:${str}`;
} break;
case `vscode <1.66`: {
str = `^/zip/${str}`;
} break;
case `vscode <1.68`: {
str = `^/zip${str}`;
} break;
case `vscode`: {
str = `^/zip/${str}`;
} break;
// To make "go to definition" work,
// We have to resolve the actual file system path from virtual path
// and convert scheme to supported by [vim-rzip](https://github.com/lbrayner/vim-rzip)
@@ -77,7 +102,7 @@ const moduleWrapper = tsserver => {
// everything else is up to neovim
case `neovim`: {
str = normalize(resolved).replace(/\.zip\//, `.zip::`);
str = `zipfile:${str}`;
str = `zipfile://${str}`;
} break;
default: {
@@ -91,9 +116,28 @@ const moduleWrapper = tsserver => {
}
function fromEditorPath(str) {
return process.platform === `win32`
? str.replace(/^\^?zip:\//, ``)
: str.replace(/^\^?zip:/, ``);
switch (hostInfo) {
case `coc-nvim`: {
str = str.replace(/\.zip::/, `.zip/`);
// The path for coc-nvim is in format of /<pwd>/zipfile:/<pwd>/.yarn/...
// So in order to convert it back, we use .* to match all the thing
// before `zipfile:`
return process.platform === `win32`
? str.replace(/^.*zipfile:\//, ``)
: str.replace(/^.*zipfile:/, ``);
} break;
case `neovim`: {
str = str.replace(/\.zip::/, `.zip/`);
// The path for neovim is in format of zipfile:///<pwd>/.yarn/...
return str.replace(/^zipfile:\/\//, ``);
} break;
case `vscode`:
default: {
return str.replace(/^\^?(zip:|\/zip(\/ts-nul-authority)?)\/+/, process.platform === `win32` ? `` : `/`)
} break;
}
}
// Force enable 'allowLocalPluginLoads'
@@ -119,8 +163,9 @@ const moduleWrapper = tsserver => {
let hostInfo = `unknown`;
Object.assign(Session.prototype, {
onMessage(/** @type {string} */ message) {
const parsedMessage = JSON.parse(message)
onMessage(/** @type {string | object} */ message) {
const isStringMessage = typeof message === 'string';
const parsedMessage = isStringMessage ? JSON.parse(message) : message;
if (
parsedMessage != null &&
@@ -129,11 +174,32 @@ const moduleWrapper = tsserver => {
typeof parsedMessage.arguments.hostInfo === `string`
) {
hostInfo = parsedMessage.arguments.hostInfo;
if (hostInfo === `vscode` && process.env.VSCODE_IPC_HOOK) {
const [, major, minor] = (process.env.VSCODE_IPC_HOOK.match(
// The RegExp from https://semver.org/ but without the caret at the start
/(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
) ?? []).map(Number)
if (major === 1) {
if (minor < 61) {
hostInfo += ` <1.61`;
} else if (minor < 66) {
hostInfo += ` <1.66`;
} else if (minor < 68) {
hostInfo += ` <1.68`;
}
}
}
}
return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => {
return typeof value === `string` ? fromEditorPath(value) : value;
}));
const processedMessageJSON = JSON.stringify(parsedMessage, (key, value) => {
return typeof value === 'string' ? fromEditorPath(value) : value;
});
return originalOnMessage.call(
this,
isStringMessage ? processedMessageJSON : JSON.parse(processedMessageJSON)
);
},
send(/** @type {any} */ msg) {
+3 -2
View File
@@ -4,8 +4,9 @@
* @license MIT
*/
const createBabelConfig = options => {
const createBabelConfig = (options) => {
const { presets = [], plugins = [], removeConsole } = options;
// prettier-ignore
return {
presets: [
[require.resolve('@babel/preset-typescript'), {
@@ -34,7 +35,7 @@ const createBabelConfig = options => {
};
};
module.exports = api => {
module.exports = (api) => {
api.cache(true);
const mode = process.env.NODE_ENV;
return createBabelConfig({ mode });
+5
View File
@@ -54,6 +54,10 @@ function task-bench {
yarn tgui:bench @Args
}
function task-prettier {
yarn tgui:prettier @Args
}
## Run a linter through all packages
function task-lint {
yarn run tsc
@@ -148,6 +152,7 @@ if ($Args.Length -gt 0) {
## Make a production webpack build
if ($Args.Length -eq 0) {
task-install
task-prettier
task-lint
task-webpack --mode=production
exit 0
+12 -13
View File
@@ -27,12 +27,11 @@ type TguiMessage = {
[key: string]: any;
};
type ByondType = {
/**
* ID of the Byond window this script is running on.
* Can be used as a parameter to winget/winset.
*/
* ID of the Byond window this script is running on.
* Can be used as a parameter to winget/winset.
*/
windowId: string;
/**
@@ -41,8 +40,8 @@ type ByondType = {
IS_BYOND: boolean;
/**
* Version of Trident engine of Internet Explorer. Null if N/A.
*/
* Version of Trident engine of Internet Explorer. Null if N/A.
*/
TRIDENT: number | null;
/**
@@ -145,20 +144,20 @@ type ByondType = {
parseJson(text: string): any;
/**
* Sends a message to `/datum/tgui_window` which hosts this window instance.
*/
* Sends a message to `/datum/tgui_window` which hosts this window instance.
*/
sendMessage(type: string, payload?: any): void;
sendMessage(message: TguiMessage): void;
/**
* Subscribe to incoming messages that were sent from `/datum/tgui_window`.
*/
* Subscribe to incoming messages that were sent from `/datum/tgui_window`.
*/
subscribe(listener: (type: string, payload: any) => void): void;
/**
* Subscribe to incoming messages *of some specific type*
* that were sent from `/datum/tgui_window`.
*/
* Subscribe to incoming messages *of some specific type*
* that were sent from `/datum/tgui_window`.
*/
subscribeTo(type: string, listener: (payload: any) => void): void;
/**
+2 -7
View File
@@ -1,12 +1,7 @@
module.exports = {
roots: ['<rootDir>/packages'],
testMatch: [
'<rootDir>/packages/**/__tests__/*.{js,ts,tsx}',
'<rootDir>/packages/**/*.{spec,test}.{js,ts,tsx}',
],
testPathIgnorePatterns: [
'<rootDir>/packages/tgui-bench',
],
testMatch: ['<rootDir>/packages/**/__tests__/*.{js,ts,tsx}', '<rootDir>/packages/**/*.{spec,test}.{js,ts,tsx}'],
testPathIgnorePatterns: ['<rootDir>/packages/tgui-bench'],
testEnvironment: 'jsdom',
testRunner: require.resolve('jest-circus/runner'),
transform: {
+6 -3
View File
@@ -7,16 +7,17 @@
"packages/*"
],
"scripts": {
"tgui:build": "webpack",
"tgui:analyze": "webpack --analyze",
"tgui:bench": "webpack --env TGUI_BENCH=1 && node packages/tgui-bench/index.js",
"tgui:build": "webpack",
"tgui:dev": "node --experimental-modules packages/tgui-dev-server/index.js",
"tgui:lint": "eslint packages --ext .js,.cjs,.ts,.tsx",
"tgui:prettier": "prettierx --check .",
"tgui:sonar": "eslint packages --ext .js,.cjs,.ts,.tsx -c .eslintrc-harder.yml",
"tgui:tsc": "tsc",
"tgui:test": "jest --watch",
"tgui:test-simple": "CI=true jest --color",
"tgui:test-ci": "CI=true jest --color --collect-coverage",
"tgui:bench": "webpack --env TGUI_BENCH=1 && node packages/tgui-bench/index.js"
"tgui:tsc": "tsc"
},
"dependencies": {
"@babel/core": "^7.18.0",
@@ -38,6 +39,7 @@
"common": "workspace:*",
"css-loader": "^6.7.1",
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-radar": "^0.2.1",
"eslint-plugin-react": "^7.30.0",
"eslint-plugin-unused-imports": "^2.0.0",
@@ -48,6 +50,7 @@
"jest-environment-jsdom": "^28.1.0",
"jsdom": "^19.0.0",
"mini-css-extract-plugin": "^2.6.0",
"prettier": "npm:prettierx@0.19.0",
"sass": "^1.52.1",
"sass-loader": "^13.0.0",
"style-loader": "^3.3.1",
+9 -9
View File
@@ -1,20 +1,20 @@
import { range, zip } from "./collections";
import { range, zip } from './collections';
// Type assertions, these will lint if the types are wrong.
const _zip1: [string, number] = zip(["a"], [1])[0];
const _zip1: [string, number] = zip(['a'], [1])[0];
describe("range", () => {
test("range(0, 5)", () => {
describe('range', () => {
test('range(0, 5)', () => {
expect(range(0, 5)).toEqual([0, 1, 2, 3, 4]);
});
});
describe("zip", () => {
describe('zip', () => {
test("zip(['a', 'b', 'c'], [1, 2, 3, 4])", () => {
expect(zip(["a", "b", "c"], [1, 2, 3, 4])).toEqual([
["a", 1],
["b", 2],
["c", 3],
expect(zip(['a', 'b', 'c'], [1, 2, 3, 4])).toEqual([
['a', 1],
['b', 2],
['c', 3],
]);
});
});
+37 -47
View File
@@ -14,40 +14,31 @@
*
* @returns {any[]}
*/
export const filter = <T>(iterateeFn: (
input: T,
index: number,
collection: T[],
) => boolean) =>
(collection: T[]): T[] => {
if (collection === null || collection === undefined) {
return collection;
}
if (Array.isArray(collection)) {
const result: T[] = [];
for (let i = 0; i < collection.length; i++) {
const item = collection[i];
if (iterateeFn(item, i, collection)) {
result.push(item);
}
export const filter =
<T>(iterateeFn: (input: T, index: number, collection: T[]) => boolean) =>
(collection: T[]): T[] => {
if (collection === null || collection === undefined) {
return collection;
}
if (Array.isArray(collection)) {
const result: T[] = [];
for (let i = 0; i < collection.length; i++) {
const item = collection[i];
if (iterateeFn(item, i, collection)) {
result.push(item);
}
return result;
}
throw new Error(`filter() can't iterate on type ${typeof collection}`);
};
return result;
}
throw new Error(`filter() can't iterate on type ${typeof collection}`);
};
type MapFunction = {
<T, U>(iterateeFn: (
value: T,
index: number,
collection: T[],
) => U): (collection: T[]) => U[];
<T, U>(iterateeFn: (value: T, index: number, collection: T[]) => U): (collection: T[]) => U[];
<T, U, K extends string | number>(iterateeFn: (
value: T,
index: K,
collection: Record<K, T>,
) => U): (collection: Record<K, T>) => U[];
<T, U, K extends string | number>(iterateeFn: (value: T, index: K, collection: Record<K, T>) => U): (
collection: Record<K, T>
) => U[];
};
/**
@@ -58,7 +49,8 @@ type MapFunction = {
* If collection is 'null' or 'undefined', it will be returned "as is"
* without emitting any errors (which can be useful in some cases).
*/
export const map: MapFunction = <T, U>(iterateeFn) =>
export const map: MapFunction =
<T, U>(iterateeFn) =>
(collection: T[]): U[] => {
if (collection === null || collection === undefined) {
return collection;
@@ -102,22 +94,22 @@ const COMPARATOR = (objA, objB) => {
*
* @returns {any[]}
*/
export const sortBy = <T>(
...iterateeFns: ((input: T) => unknown)[]
) => (array: T[]): T[] => {
export const sortBy =
<T>(...iterateeFns: ((input: T) => unknown)[]) =>
(array: T[]): T[] => {
if (!Array.isArray(array)) {
return array;
}
let length = array.length;
// Iterate over the array to collect criteria to sort it by
let mappedArray: {
criteria: unknown[],
value: T,
criteria: unknown[];
value: T;
}[] = [];
for (let i = 0; i < length; i++) {
const value = array[i];
mappedArray.push({
criteria: iterateeFns.map(fn => fn(value)),
criteria: iterateeFns.map((fn) => fn(value)),
value,
});
}
@@ -144,15 +136,14 @@ export const range = (start: number, end: number): number[] =>
/**
* A fast implementation of reduce.
*/
export const reduce = (reducerFn, initialValue) => array => {
export const reduce = (reducerFn, initialValue) => (array) => {
const length = array.length;
let i;
let result;
if (initialValue === undefined) {
i = 1;
result = array[0];
}
else {
} else {
i = 0;
result = initialValue;
}
@@ -173,15 +164,14 @@ export const reduce = (reducerFn, initialValue) => array => {
* is determined by the order they occur in the array. The iteratee is
* invoked with one argument: value.
*/
export const uniqBy = <T extends unknown>(
iterateeFn?: (value: T) => unknown
) => (array: T[]): T[] => {
export const uniqBy =
<T extends unknown>(iterateeFn?: (value: T) => unknown) =>
(array: T[]): T[] => {
const { length } = array;
const result: T[] = [];
const seen: unknown[] = iterateeFn ? [] : result;
let index = -1;
outer:
while (++index < length) {
outer: while (++index < length) {
let value: T | 0 = array[index];
const computed = iterateeFn ? iterateeFn(value) : value;
if (computed === computed) {
@@ -195,8 +185,7 @@ export const uniqBy = <T extends unknown>(
seen.push(computed);
}
result.push(value);
}
else if (!seen.includes(computed)) {
} else if (!seen.includes(computed)) {
if (seen !== result) {
seen.push(computed);
}
@@ -242,7 +231,8 @@ export const zip = <T extends unknown[][]>(...arrays: T): Zip<T> => {
* specify how grouped values should be combined. The iteratee is
* invoked with the elements of each group.
*/
export const zipWith = <T, U>(iterateeFn: (...values: T[]) => U) =>
export const zipWith =
<T, U>(iterateeFn: (...values: T[]) => U) =>
(...arrays: T[][]): U[] => {
return map((values: T[]) => iterateeFn(...values))(zip(...arrays));
};
+4 -13
View File
@@ -22,23 +22,14 @@ export class Color {
/**
* Creates a color from the CSS hex color notation.
*/
Color.fromHex = hex => (
new Color(
parseInt(hex.substr(1, 2), 16),
parseInt(hex.substr(3, 2), 16),
parseInt(hex.substr(5, 2), 16))
);
Color.fromHex = (hex) =>
new Color(parseInt(hex.substr(1, 2), 16), parseInt(hex.substr(3, 2), 16), parseInt(hex.substr(5, 2), 16));
/**
* Linear interpolation of two colors.
*/
Color.lerp = (c1, c2, n) => (
new Color(
(c2.r - c1.r) * n + c1.r,
(c2.g - c1.g) * n + c1.g,
(c2.b - c1.b) * n + c1.b,
(c2.a - c1.a) * n + c1.a)
);
Color.lerp = (c1, c2, n) =>
new Color((c2.r - c1.r) * n + c1.r, (c2.g - c1.g) * n + c1.g, (c2.b - c1.b) * n + c1.b, (c2.a - c1.a) * n + c1.a);
/**
* Loops up the color in the provided list of colors
+3 -4
View File
@@ -19,10 +19,9 @@ export class EventEmitter {
if (!listeners) {
throw new Error(`There is no listeners for "${name}"`);
}
this.listeners[name] = listeners
.filter(existingListener => {
return existingListener !== listener;
});
this.listeners[name] = listeners.filter((existingListener) => {
return existingListener !== listener;
});
}
emit(name, ...params) {
+19 -15
View File
@@ -9,19 +9,20 @@
* functions, where each successive invocation is supplied the return
* value of the previous.
*/
export const flow = (...funcs) => (input, ...rest) => {
let output = input;
for (let func of funcs) {
// Recurse into the array of functions
if (Array.isArray(func)) {
output = flow(...func)(output, ...rest);
export const flow =
(...funcs) =>
(input, ...rest) => {
let output = input;
for (let func of funcs) {
// Recurse into the array of functions
if (Array.isArray(func)) {
output = flow(...func)(output, ...rest);
} else if (func) {
output = func(output, ...rest);
}
}
else if (func) {
output = func(output, ...rest);
}
}
return output;
};
return output;
};
/**
* Composes single-argument functions from right to left.
@@ -37,11 +38,14 @@ export const flow = (...funcs) => (input, ...rest) => {
*/
export const compose = (...funcs) => {
if (funcs.length === 0) {
return arg => arg;
return (arg) => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce((a, b) => (value, ...rest) =>
a(b(value, ...rest), ...rest));
return funcs.reduce(
(a, b) =>
(value, ...rest) =>
a(b(value, ...rest), ...rest)
);
};
+3 -5
View File
@@ -14,7 +14,7 @@ export const clamp = (value, min, max) => {
/**
* Limits a number between 0 and 1.
*/
export const clamp01 = value => {
export const clamp01 = (value) => {
return value < 0 ? 0 : value > 1 ? 1 : value;
};
@@ -69,9 +69,7 @@ export const toFixed = (value, fractionDigits = 0) => {
* Range is an array of two numbers, for example: [0, 15].
*/
export const inRange = (value, range) => {
return range
&& value >= range[0]
&& value <= range[1];
return range && value >= range[0] && value <= range[1];
};
/**
@@ -92,7 +90,7 @@ export const keyOfMatchingRange = (value, ranges) => {
/**
* Get number of digits following the decimal point in a number
*/
export const numberOfDecimalDigits = value => {
export const numberOfDecimalDigits = (value) => {
if (Math.floor(value) !== value) {
return value.toString().split('.')[1].length || 0;
}
+2 -3
View File
@@ -48,10 +48,9 @@ const measure = (markerNameA, markerNameB) => {
}
};
const formatDuration = duration => {
const formatDuration = (duration) => {
const durationInFrames = duration / FRAME_DURATION;
return duration.toFixed(duration < 10 ? 1 : 0) + 'ms '
+ '(' + durationInFrames.toFixed(2) + ' frames)';
return duration.toFixed(duration < 10 ? 1 : 0) + 'ms ' + '(' + durationInFrames.toFixed(2) + ' frames)';
};
export const perf = {
+2 -4
View File
@@ -24,7 +24,7 @@ export const classes = (classNames: (string | BooleanLike)[]) => {
*/
export const normalizeChildren = <T>(children: T | T[]) => {
if (Array.isArray(children)) {
return children.flat().filter(value => value) as T[];
return children.flat().filter((value) => value) as T[];
}
if (typeof children === 'object') {
return [children];
@@ -64,9 +64,7 @@ export const pureComponentHooks = {
* A helper to determine whether the object is renderable by React.
*/
export const canRender = (value: unknown) => {
return value !== undefined
&& value !== null
&& typeof value !== 'boolean';
return value !== undefined && value !== null && typeof value !== 'boolean';
};
/**
+25 -28
View File
@@ -20,11 +20,11 @@ export const createStore = (reducer, enhancer) => {
const getState = () => currentState;
const subscribe = listener => {
const subscribe = (listener) => {
listeners.push(listener);
};
const dispatch = action => {
const dispatch = (action) => {
currentState = reducer(currentState, action);
for (let i = 0; i < listeners.length; i++) {
listeners[i]();
@@ -49,27 +49,27 @@ export const createStore = (reducer, enhancer) => {
* actions.
*/
export const applyMiddleware = (...middlewares) => {
return createStore => (reducer, ...args) => {
const store = createStore(reducer, ...args);
return (createStore) =>
(reducer, ...args) => {
const store = createStore(reducer, ...args);
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed.');
let dispatch = () => {
throw new Error('Dispatching while constructing your middleware is not allowed.');
};
const storeApi = {
getState: store.getState,
dispatch: (action, ...args) => dispatch(action, ...args),
};
const chain = middlewares.map((middleware) => middleware(storeApi));
dispatch = compose(...chain)(store.dispatch);
return {
...store,
dispatch,
};
};
const storeApi = {
getState: store.getState,
dispatch: (action, ...args) => dispatch(action, ...args),
};
const chain = middlewares.map(middleware => middleware(storeApi));
dispatch = compose(...chain)(store.dispatch);
return {
...store,
dispatch,
};
};
};
/**
@@ -80,7 +80,7 @@ export const applyMiddleware = (...middlewares) => {
* in the state that are not present in the reducers object. This function
* is also more flexible than the redux counterpart.
*/
export const combineReducers = reducersObj => {
export const combineReducers = (reducersObj) => {
const keys = Object.keys(reducersObj);
let hasChanged = false;
return (prevState = {}, action) => {
@@ -94,9 +94,7 @@ export const combineReducers = reducersObj => {
nextState[key] = nextDomainState;
}
}
return hasChanged
? nextState
: prevState;
return hasChanged ? nextState : prevState;
};
};
@@ -136,15 +134,14 @@ export const createAction = (type, prepare = null) => {
};
actionCreator.toString = () => '' + type;
actionCreator.type = type;
actionCreator.match = action => action.type === type;
actionCreator.match = (action) => action.type === type;
return actionCreator;
};
// Implementation specific
// --------------------------------------------------------
export const useDispatch = context => {
export const useDispatch = (context) => {
return context.store.dispatch;
};
+9 -17
View File
@@ -17,11 +17,10 @@ const INDEXED_DB_STORE_NAME = 'storage-v1';
const READ_ONLY = 'readonly';
const READ_WRITE = 'readwrite';
const testGeneric = testFn => () => {
const testGeneric = (testFn) => () => {
try {
return Boolean(testFn());
}
catch {
} catch {
return false;
}
};
@@ -29,14 +28,11 @@ const testGeneric = testFn => () => {
// Localstorage can sometimes throw an error, even if DOM storage is not
// disabled in IE11 settings.
// See: https://superuser.com/questions/1080011
const testLocalStorage = testGeneric(() => (
window.localStorage && window.localStorage.getItem
));
const testLocalStorage = testGeneric(() => window.localStorage && window.localStorage.getItem);
const testIndexedDb = testGeneric(() => (
(window.indexedDB || window.msIndexedDB)
&& (window.IDBTransaction || window.msIDBTransaction)
));
const testIndexedDb = testGeneric(
() => (window.indexedDB || window.msIndexedDB) && (window.IDBTransaction || window.msIDBTransaction)
);
class MemoryBackend {
constructor() {
@@ -96,8 +92,7 @@ class IndexedDbBackend {
req.onupgradeneeded = () => {
try {
req.result.createObjectStore(INDEXED_DB_STORE_NAME);
}
catch (err) {
} catch (err) {
reject(new Error('Failed to upgrade IDB: ' + req.error));
}
};
@@ -109,9 +104,7 @@ class IndexedDbBackend {
}
getStore(mode) {
return this.dbPromise.then(db => db
.transaction(INDEXED_DB_STORE_NAME, mode)
.objectStore(INDEXED_DB_STORE_NAME));
return this.dbPromise.then((db) => db.transaction(INDEXED_DB_STORE_NAME, mode).objectStore(INDEXED_DB_STORE_NAME));
}
async get(key) {
@@ -161,8 +154,7 @@ class StorageProxy {
const backend = new IndexedDbBackend();
await backend.dbPromise;
return backend;
}
catch {}
} catch {}
}
if (testLocalStorage()) {
return new LocalStorageBackend();
+4 -4
View File
@@ -19,7 +19,7 @@
/**
* Removes excess whitespace and indentation from the string.
*/
const multiline = str => {
const multiline = (str) => {
const lines = str.split('\n');
// Determine base indentation
let minIndent;
@@ -40,15 +40,15 @@ const multiline = str => {
// Remove this base indentation and trim the resulting string
// from both ends.
return lines
.map(line => line.substr(minIndent).trimRight())
.map((line) => line.substr(minIndent).trimRight())
.join('\n')
.trim();
};
const StringPlugin = ref => {
const StringPlugin = (ref) => {
return {
visitor: {
TaggedTemplateExpression: path => {
TaggedTemplateExpression: (path) => {
if (path.node.tag.name === 'multiline') {
const { quasi } = path.node;
if (quasi.expressions.length > 0) {
+66 -42
View File
@@ -7,7 +7,7 @@
/**
* Removes excess whitespace and indentation from the string.
*/
export const multiline = str => {
export const multiline = (str) => {
if (Array.isArray(str)) {
// Small stub to allow usage as a template tag
return multiline(str.join(''));
@@ -32,7 +32,7 @@ export const multiline = str => {
// Remove this base indentation and trim the resulting string
// from both ends.
return lines
.map(line => line.substr(minIndent).trimRight())
.map((line) => line.substr(minIndent).trimRight())
.join('\n')
.trim();
};
@@ -44,12 +44,17 @@ export const multiline = str => {
*
* Example: createGlobPattern('*@domain')('user@domain') === true
*/
export const createGlobPattern = pattern => {
const escapeString = str => str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
const regex = new RegExp('^'
+ pattern.split(/\*+/).map(escapeString).join('.*')
+ '$');
return str => regex.test(str);
export const createGlobPattern = (pattern) => {
const escapeString = (str) => str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
const regex = new RegExp(
'^' +
pattern
.split(/\*+/)
.map(escapeString)
.join('.*') +
'$'
);
return (str) => regex.test(str);
};
/**
@@ -64,7 +69,7 @@ export const createGlobPattern = pattern => {
*/
export const createSearch = (searchText, stringifier) => {
const preparedSearchText = searchText.toLowerCase().trim();
return obj => {
return (obj) => {
if (!preparedSearchText) {
return true;
}
@@ -72,17 +77,15 @@ export const createSearch = (searchText, stringifier) => {
if (!str) {
return false;
}
return str
.toLowerCase()
.includes(preparedSearchText);
return str.toLowerCase().includes(preparedSearchText);
};
};
export const isUppercase = chr => {
export const isUppercase = (chr) => {
return chr.toUpperCase() === chr;
};
export const capitalize = str => {
export const capitalize = (str) => {
// Handle array
if (Array.isArray(str)) {
return str.map(capitalize);
@@ -95,7 +98,7 @@ export const capitalize = str => {
return chr.toUpperCase() + str.slice(1).toLowerCase();
};
export const toTitleCase = str => {
export const toTitleCase = (str) => {
// Handle array
if (Array.isArray(str)) {
return str.map(toTitleCase);
@@ -107,19 +110,38 @@ export const toTitleCase = str => {
// Handle string
const WORDS_UPPER = ['Id', 'Tv', 'Rcd']; // VOREStation Edit
const WORDS_LOWER = [
'A', 'An', 'And', 'As', 'At', 'But', 'By', 'For', 'For', 'From', 'In',
'Into', 'Near', 'Nor', 'Of', 'On', 'Onto', 'Or', 'The', 'To', 'With',
'A',
'An',
'And',
'As',
'At',
'But',
'By',
'For',
'For',
'From',
'In',
'Into',
'Near',
'Nor',
'Of',
'On',
'Onto',
'Or',
'The',
'To',
'With',
];
let currentStr = str.replace(/([^\W_]+[^\s-]*) */g, str => {
let currentStr = str.replace(/([^\W_]+[^\s-]*) */g, (str) => {
return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase();
});
for (let word of WORDS_LOWER) {
const regex = new RegExp('\\s' + word + '\\s', 'g');
currentStr = currentStr.replace(regex, str => str.toLowerCase());
currentStr = currentStr.replace(regex, (str) => str.toLowerCase());
}
for (let word of WORDS_UPPER) {
const regex = new RegExp('\\b' + word + '\\b', 'g');
currentStr = currentStr.replace(regex, str => str.toUpperCase());
currentStr = currentStr.replace(regex, (str) => str.toUpperCase());
}
return currentStr;
};
@@ -130,7 +152,7 @@ export const toTitleCase = str => {
* @param {String} str Encoded HTML string
* @return {String} Decoded HTML string
*/
export const decodeHtmlEntities = str => {
export const decodeHtmlEntities = (str) => {
if (!str) {
return str;
}
@@ -142,31 +164,33 @@ export const decodeHtmlEntities = str => {
quot: '"',
lt: '<',
gt: '>',
apos: '\'',
apos: "'",
trade: '™',
};
return str
// Newline tags
.replace(/<br>/gi, '\n')
.replace(/<\/?[a-z0-9-_]+[^>]*>/gi, '')
// Basic entities
.replace(translate_re, (match, entity) => translate[entity])
// Decimal entities
.replace(/&#?([0-9]+);/gi, (match, numStr) => {
const num = parseInt(numStr, 10);
return String.fromCharCode(num);
})
// Hex entities
.replace(/&#x?([0-9a-f]+);/gi, (match, numStr) => {
const num = parseInt(numStr, 16);
return String.fromCharCode(num);
});
return (
str
// Newline tags
.replace(/<br>/gi, '\n')
.replace(/<\/?[a-z0-9-_]+[^>]*>/gi, '')
// Basic entities
.replace(translate_re, (match, entity) => translate[entity])
// Decimal entities
.replace(/&#?([0-9]+);/gi, (match, numStr) => {
const num = parseInt(numStr, 10);
return String.fromCharCode(num);
})
// Hex entities
.replace(/&#x?([0-9a-f]+);/gi, (match, numStr) => {
const num = parseInt(numStr, 16);
return String.fromCharCode(num);
})
);
};
/**
* Converts an object into a query string,
*/
export const buildQueryString = obj => Object.keys(obj)
.map(key => encodeURIComponent(key)
+ '=' + encodeURIComponent(obj[key]))
.join('&');
export const buildQueryString = (obj) =>
Object.keys(obj)
.map((key) => encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]))
.join('&');
+1 -3
View File
@@ -33,6 +33,4 @@ export const debounce = (fn, time, immediate = false) => {
*
* @param {number} time
*/
export const sleep = time => (
new Promise(resolve => setTimeout(resolve, time))
);
export const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
+1 -2
View File
@@ -1,5 +1,4 @@
/**
* Returns the arguments of a function F as an array.
*/
export type ArgumentsOf<F extends Function>
= F extends (...args: infer A) => unknown ? A : never;
export type ArgumentsOf<F extends Function> = F extends (...args: infer A) => unknown ? A : never;
+2 -2
View File
@@ -11,9 +11,9 @@
*/
export const createUuid = () => {
let d = new Date().getTime();
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
});
};
+5 -5
View File
@@ -32,17 +32,17 @@ export const vecDivide = (...vecs) => {
};
export const vecScale = (vec, n) => {
return map(x => x * n)(vec);
return map((x) => x * n)(vec);
};
export const vecInverse = vec => {
return map(x => -x)(vec);
export const vecInverse = (vec) => {
return map((x) => -x)(vec);
};
export const vecLength = vec => {
export const vecLength = (vec) => {
return Math.sqrt(reduce(ADD)(zipWith(MUL)(vec, vec)));
};
export const vecNormalize = vec => {
export const vecNormalize = (vec) => {
return vecDivide(vec, vecLength(vec));
};
+24 -23
View File
@@ -1,50 +1,51 @@
@font-face {
font-family: "tgfont";
src: url("./tgfont.woff2?45c3c7acc69dd413375d77898d24e41e") format("woff2"),
url("./tgfont.eot?45c3c7acc69dd413375d77898d24e41e#iefix") format("embedded-opentype");
font-family: 'tgfont';
src: url('./tgfont.woff2?45c3c7acc69dd413375d77898d24e41e') format('woff2'),
url('./tgfont.eot?45c3c7acc69dd413375d77898d24e41e#iefix') format('embedded-opentype');
}
i[class^="tg-"]:before, i[class*=" tg-"]:before {
font-family: tgfont !important;
font-style: normal;
font-weight: normal !important;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
i[class^='tg-']:before,
i[class*=' tg-']:before {
font-family: tgfont !important;
font-style: normal;
font-weight: normal !important;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.tg-air-tank-slash:before {
content: "\f101";
content: '\f101';
}
.tg-air-tank:before {
content: "\f102";
content: '\f102';
}
.tg-bad-touch:before {
content: "\f103";
content: '\f103';
}
.tg-image-minus:before {
content: "\f104";
content: '\f104';
}
.tg-image-plus:before {
content: "\f105";
content: '\f105';
}
.tg-nanotrasen-logo:before {
content: "\f106";
content: '\f106';
}
.tg-non-binary:before {
content: "\f107";
content: '\f107';
}
.tg-prosthetic-leg:before {
content: "\f108";
content: '\f108';
}
.tg-sound-minus:before {
content: "\f109";
content: '\f109';
}
.tg-sound-plus:before {
content: "\f10a";
content: '\f10a';
}
.tg-syndicate-logo:before {
content: "\f10b";
content: '\f10b';
}
@@ -1,6 +1,8 @@
bad-touch.svg contains:
- hug by Phạm Thanh Lộc from the Noun Project
- Fight by Rudez Studio from the Noun Project
prosthetic-leg.svg contains:
- prosthetic leg by Gan Khoon Lay from the Noun Project
+1 -2
View File
@@ -10,5 +10,4 @@ process.chdir(__dirname);
// Silently make a dist folder
try {
require('fs').mkdirSync('dist');
}
catch (err) {}
} catch (err) {}
+1 -2
View File
@@ -62,8 +62,7 @@ const setupApp = async () => {
}
suite.run();
});
}
catch (error) {
} catch (error) {
sendMessage({ type: 'error', error });
}
}
+2 -4
View File
@@ -27,8 +27,7 @@ const setup = async () => {
assets += `</script>\n`;
const publicDir = path.resolve(__dirname, '../../public');
const page = fs.readFileSync(path.join(publicDir, 'tgui.html'), 'utf-8')
.replace('<!-- tgui:assets -->\n', assets);
const page = fs.readFileSync(path.join(publicDir, 'tgui.html'), 'utf-8').replace('<!-- tgui:assets -->\n', assets);
server.register(require('@fastify/static'), {
root: publicDir,
@@ -67,8 +66,7 @@ const setup = async () => {
try {
await server.listen(3002, '0.0.0.0');
}
catch (err) {
} catch (err) {
console.error(err);
process.exit(1);
}
+2 -10
View File
@@ -11,11 +11,7 @@ declare class Benchmark {
static filter<T>(arr: T[], filter: string, thisArg?: any): T[];
static formatNumber(num: number): string;
static join(obj: Object, separator1?: string, separator2?: string): string;
static invoke(
benches: Benchmark[],
name: string | Object,
...args: any[]
): any[];
static invoke(benches: Benchmark[], name: string | Object, ...args: any[]): any[];
static runInContext(context: Object): Function;
static each(obj: Object | any[], callback: Function, thisArg?: any): void;
@@ -24,11 +20,7 @@ declare class Benchmark {
static has(obj: Object, path: any[] | string): boolean;
static indexOf<T>(arr: T[], value: T, fromIndex?: number): number;
static map<T, K>(arr: T[], callback: (value: T) => K, thisArg?: any): K[];
static reduce<T, K>(
arr: T[],
callback: (accumulator: K, value: T) => K,
thisArg?: any
): K;
static reduce<T, K>(arr: T[], callback: (accumulator: K, value: T) => K, thisArg?: any): K;
static options: Benchmark.Options;
static platform: Benchmark.Platform;
File diff suppressed because it is too large Load Diff
+4 -20
View File
@@ -7,40 +7,24 @@ const render = createRenderer();
const handleClick = () => undefined;
export const SingleButton = () => {
const node = (
<Button>
Hello world!
</Button>
);
const node = <Button>Hello world!</Button>;
render(node);
};
export const SingleButtonWithCallback = () => {
const node = (
<Button onClick={() => undefined}>
Hello world!
</Button>
);
const node = <Button onClick={() => undefined}>Hello world!</Button>;
render(node);
};
export const SingleButtonWithLinkEvent = () => {
const node = (
<Button onClick={linkEvent(null, handleClick)}>
Hello world!
</Button>
);
const node = <Button onClick={linkEvent(null, handleClick)}>Hello world!</Button>;
render(node);
};
export const ListOfButtons = () => {
const nodes: JSX.Element[] = [];
for (let i = 0; i < 100; i++) {
const node = (
<Button key={i}>
Hello world! {i}
</Button>
);
const node = <Button key={i}>Hello world! {i}</Button>;
nodes.push(node);
}
render(<div>{nodes}</div>);
@@ -6,9 +6,11 @@ import { configureStore, StoreProvider } from 'tgui/store';
const store = configureStore({ sideEffets: false });
const renderUi = createRenderer((dataJson: string) => {
store.dispatch(backendUpdate({
data: Byond.parseJson(dataJson),
}));
store.dispatch(
backendUpdate({
data: Byond.parseJson(dataJson),
})
);
return (
<StoreProvider store={store}>
<DisposalBin />
+1 -3
View File
@@ -6,9 +6,7 @@ const render = createRenderer();
export const Default = () => {
const node = (
<Flex align="baseline">
<Flex.Item mr={1}>
Text {Math.random()}
</Flex.Item>
<Flex.Item mr={1}>Text {Math.random()}</Flex.Item>
<Flex.Item grow={1} basis={0}>
Text {Math.random()}
</Flex.Item>
@@ -6,9 +6,7 @@ const render = createRenderer();
export const Default = () => {
const node = (
<Stack align="baseline">
<Stack.Item>
Text {Math.random()}
</Stack.Item>
<Stack.Item>Text {Math.random()}</Stack.Item>
<Stack.Item grow={1} basis={0}>
Text {Math.random()}
</Stack.Item>
@@ -1,5 +1,5 @@
import { Box, Tooltip } from "tgui/components";
import { createRenderer } from "tgui/renderer";
import { Box, Tooltip } from 'tgui/components';
import { createRenderer } from 'tgui/renderer';
const render = createRenderer();
+6 -10
View File
@@ -25,8 +25,7 @@ export class DreamSeeker {
topic(params = {}) {
const query = Object.keys(params)
.map(key => encodeURIComponent(key)
+ '=' + encodeURIComponent(params[key]))
.map((key) => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]))
.join('&');
return this.client.get('/dummy?' + query);
}
@@ -36,7 +35,7 @@ export class DreamSeeker {
* @param {number[]} pids
* @returns {DreamSeeker[]}
*/
DreamSeeker.getInstancesByPids = async pids => {
DreamSeeker.getInstancesByPids = async (pids) => {
if (process.platform !== 'win32') {
return [];
}
@@ -46,8 +45,7 @@ DreamSeeker.getInstancesByPids = async pids => {
const instance = instanceByPid.get(pid);
if (instance) {
instances.push(instance);
}
else {
} else {
pidsToResolve.push(pid);
}
}
@@ -83,12 +81,10 @@ DreamSeeker.getInstancesByPids = async pids => {
instances.push(instance);
instanceByPid.set(pid, instance);
}
}
catch (err) {
} catch (err) {
if (err.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') {
logger.error(err.message, err.code);
}
else {
} else {
logger.error(err);
}
return [];
@@ -97,4 +93,4 @@ DreamSeeker.getInstancesByPids = async pids => {
return instances;
};
const plural = (word, n) => n !== 1 ? word + 's' : word;
const plural = (word, n) => (n !== 1 ? word + 's' : word);
+12 -18
View File
@@ -23,7 +23,7 @@ const ensureConnection = () => {
socket.send(msg);
}
};
socket.onmessage = event => {
socket.onmessage = (event) => {
const msg = JSON.parse(event.data);
for (let subscriber of subscribers) {
subscriber(msg);
@@ -37,14 +37,14 @@ if (process.env.NODE_ENV !== 'production') {
window.onunload = () => socket && socket.close();
}
const subscribe = fn => subscribers.push(fn);
const subscribe = (fn) => subscribers.push(fn);
/**
* A json serializer which handles circular references and other junk.
*/
const serializeObject = obj => {
const serializeObject = (obj) => {
let refs = [];
const primitiveReviver = value => {
const primitiveReviver = (value) => {
if (typeof value === 'number' && !Number.isFinite(value)) {
return {
__number__: String(value),
@@ -68,9 +68,7 @@ const serializeObject = obj => {
}
refs.push(value);
// Error object
const isError = value instanceof Error || (
value.code && value.message && value.message.includes('Error')
);
const isError = value instanceof Error || (value.code && value.message && value.message.includes('Error'));
if (isError) {
return {
__error__: true,
@@ -91,7 +89,7 @@ const serializeObject = obj => {
return json;
};
const sendMessage = msg => {
const sendMessage = (msg) => {
if (process.env.NODE_ENV !== 'production') {
const json = serializeObject(msg);
// Send message using WebSocket
@@ -99,8 +97,7 @@ const sendMessage = msg => {
ensureConnection();
if (socket.readyState === WebSocket.OPEN) {
socket.send(json);
}
else {
} else {
// Keep only 100 latest messages in the queue
if (queue.length > 100) {
queue.shift();
@@ -130,19 +127,16 @@ const sendLogEntry = (level, ns, ...args) => {
args,
},
});
}
catch (err) {}
} catch (err) {}
}
};
const setupHotReloading = () => {
if (process.env.NODE_ENV !== 'production'
&& process.env.WEBPACK_HMR_ENABLED
&& window.WebSocket) {
if (process.env.NODE_ENV !== 'production' && process.env.WEBPACK_HMR_ENABLED && window.WebSocket) {
if (module.hot) {
ensureConnection();
sendLogEntry(0, null, 'setting up hot reloading');
subscribe(msg => {
subscribe((msg) => {
const { type } = msg;
sendLogEntry(0, null, 'received', type);
if (type === 'hotUpdate') {
@@ -157,10 +151,10 @@ const setupHotReloading = () => {
ignoreDeclined: true,
ignoreErrored: true,
})
.then(modules => {
.then((modules) => {
sendLogEntry(0, null, 'outdated modules', modules);
})
.catch(err => {
.catch((err) => {
sendLogEntry(0, null, 'reload error', err);
});
}
+8 -12
View File
@@ -18,7 +18,7 @@ const logger = createLogger('retrace');
const { SourceMapConsumer } = SourceMap;
const sourceMaps = [];
export const loadSourceMaps = async bundleDir => {
export const loadSourceMaps = async (bundleDir) => {
// Destroy and garbage collect consumers
while (sourceMaps.length !== 0) {
const { consumer } = sourceMaps.shift();
@@ -29,30 +29,28 @@ export const loadSourceMaps = async bundleDir => {
for (let path of paths) {
try {
const file = basename(path).replace('.map', '');
const consumer = await new SourceMapConsumer(
JSON.parse(fs.readFileSync(path, 'utf8')));
const consumer = await new SourceMapConsumer(JSON.parse(fs.readFileSync(path, 'utf8')));
sourceMaps.push({ file, consumer });
}
catch (err) {
} catch (err) {
logger.error(err);
}
}
logger.log(`loaded ${sourceMaps.length} source maps`);
};
export const retrace = stack => {
export const retrace = (stack) => {
if (typeof stack !== 'string') {
logger.log('ERROR: Stack is not a string!', stack);
return stack;
}
const header = stack.split(/\n\s.*at/)[0];
const mappedStack = parseStackTrace(stack)
.map(frame => {
.map((frame) => {
if (!frame.file) {
return frame;
}
// Find the correct source map
const sourceMap = sourceMaps.find(sourceMap => {
const sourceMap = sourceMaps.find((sourceMap) => {
return frame.file.includes(sourceMap.file);
});
if (!sourceMap) {
@@ -72,15 +70,13 @@ export const retrace = stack => {
column: mappedFrame.column,
};
})
.map(frame => {
.map((frame) => {
// Stringify the frame
const { file, methodName, lineNumber } = frame;
if (!file) {
return ` at ${methodName}`;
}
const compactPath = file
.replace(/^webpack:\/\/\/?/, './')
.replace(/.*node_modules\//, '');
const compactPath = file.replace(/^webpack:\/\/\/?/, './').replace(/.*node_modules\//, '');
return ` at ${methodName} (${compactPath}:${lineNumber})`;
})
.join('\n');
+17 -14
View File
@@ -32,9 +32,9 @@ class LinkServer {
setupWebSocketLink() {
const port = 3000;
this.wss = new WebSocket.Server({ port });
this.wss.on('connection', ws => {
this.wss.on('connection', (ws) => {
logger.log('client connected');
ws.on('message', json => {
ws.on('message', (json) => {
const msg = deserializeObject(json);
this.handleLinkMessage(ws, msg);
});
@@ -51,7 +51,7 @@ class LinkServer {
this.httpServer = http.createServer((req, res) => {
if (req.method === 'POST') {
let body = '';
req.on('data', chunk => {
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
@@ -76,16 +76,19 @@ class LinkServer {
if (level <= 0 && !DEBUG) {
return;
}
directLog(ns, ...args.map(arg => {
if (typeof arg === 'object') {
return inspect(arg, {
depth: Infinity,
colors: true,
compact: 8,
});
}
return arg;
}));
directLog(
ns,
...args.map((arg) => {
if (typeof arg === 'object') {
return inspect(arg, {
depth: Infinity,
colors: true,
compact: 8,
});
}
return arg;
})
);
return;
}
if (type === 'relay') {
@@ -117,7 +120,7 @@ class LinkServer {
}
}
const deserializeObject = str => {
const deserializeObject = (str) => {
return JSON.parse(str, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (value.__undefined__) {
+6 -16
View File
@@ -11,8 +11,7 @@ const isNode = process && process.release && process.release.name === 'node';
let isChrome = false;
try {
isChrome = window.navigator.userAgent.toLowerCase().includes('chrome');
}
catch {}
} catch {}
// Timestamping function
const getTimestamp = () => {
@@ -32,9 +31,7 @@ const getPrefix = (() => {
bright: '\x1b[37;1m',
reset: '\x1b[0m',
};
return ns => [
`${ESC.dimmed}${getTimestamp()} ${ESC.bright}${ns}${ESC.reset}`,
];
return (ns) => [`${ESC.dimmed}${getTimestamp()} ${ESC.bright}${ns}${ESC.reset}`];
}
if (isChrome) {
// Styles
@@ -42,21 +39,15 @@ const getPrefix = (() => {
dimmed: 'color: #888',
bright: 'font-weight: bold',
};
return ns => [
`%c${getTimestamp()}%c ${ns}`,
styles.dimmed,
styles.bright,
];
return (ns) => [`%c${getTimestamp()}%c ${ns}`, styles.dimmed, styles.bright];
}
return ns => [
`${getTimestamp()} ${ns}`,
];
return (ns) => [`${getTimestamp()} ${ns}`];
})();
/**
* Creates a logger object.
*/
export const createLogger = ns => ({
export const createLogger = (ns) => ({
log: (...args) => console.log(...getPrefix(ns), ...args),
trace: (...args) => console.trace(...getPrefix(ns), ...args),
debug: (...args) => console.debug(...getPrefix(ns), ...args),
@@ -68,5 +59,4 @@ export const createLogger = ns => ({
/**
* Explicitly log with chosen namespace.
*/
export const directLog = (ns, ...args) =>
console.log(...getPrefix(ns), ...args);
export const directLog = (ns, ...args) => console.log(...getPrefix(ns), ...args);
+6 -14
View File
@@ -50,14 +50,9 @@ export const findCacheRoot = async () => {
// Query the Windows Registry
if (process.platform === 'win32') {
logger.log('querying windows registry');
let userpath = await regQuery(
'HKCU\\Software\\Dantom\\BYOND',
'userpath');
let userpath = await regQuery('HKCU\\Software\\Dantom\\BYOND', 'userpath');
if (userpath) {
cacheRoot = userpath
.replace(/\\$/, '')
.replace(/\\/g, '/')
+ '/cache';
cacheRoot = userpath.replace(/\\$/, '').replace(/\\/g, '/') + '/cache';
onCacheRootFound(cacheRoot);
return cacheRoot;
}
@@ -65,13 +60,13 @@ export const findCacheRoot = async () => {
logger.log('found no cache directories');
};
const onCacheRootFound = cacheRoot => {
const onCacheRootFound = (cacheRoot) => {
logger.log(`found cache at '${cacheRoot}'`);
// Plant a dummy
fs.closeSync(fs.openSync(cacheRoot + '/dummy', 'w'));
};
export const reloadByondCache = async bundleDir => {
export const reloadByondCache = async (bundleDir) => {
const cacheRoot = await findCacheRoot();
if (!cacheRoot) {
return;
@@ -83,9 +78,7 @@ export const reloadByondCache = async bundleDir => {
return;
}
// Get dreamseeker instances
const pids = cacheDirs.map(cacheDir => (
parseInt(cacheDir.split('/cache/tmp').pop(), 10)
));
const pids = cacheDirs.map((cacheDir) => parseInt(cacheDir.split('/cache/tmp').pop(), 10));
const dssPromise = DreamSeeker.getInstancesByPids(pids);
// Copy assets
const assets = await resolveGlob(bundleDir, './*.+(bundle|chunk|hot-update).*');
@@ -102,8 +95,7 @@ export const reloadByondCache = async bundleDir => {
fs.writeFileSync(destination, fs.readFileSync(asset));
}
logger.log(`copied ${assets.length} files to '${cacheDir}'`);
}
catch (err) {
} catch (err) {
logger.error(`failed copying to '${cacheDir}'`);
logger.error(err);
}
+1 -2
View File
@@ -25,8 +25,7 @@ export const resolveGlob = (...sections) => {
try {
fs.statSync(path);
safePaths.push(path);
}
catch {}
} catch {}
}
return safePaths;
};
+3 -3
View File
@@ -18,7 +18,7 @@ const logger = createLogger('webpack');
* @param {any} config
* @return {WebpackCompiler}
*/
export const createCompiler = async options => {
export const createCompiler = async (options) => {
const compiler = new WebpackCompiler();
await compiler.setup(options);
return compiler;
@@ -57,7 +57,7 @@ class WebpackCompiler {
logger.log('compiling');
});
// Start reloading when it's finished
compiler.hooks.done.tap('tgui-dev-server', async stats => {
compiler.hooks.done.tap('tgui-dev-server', async (stats) => {
// Load source maps
await loadSourceMaps(this.bundleDir);
// Reload cache
@@ -77,7 +77,7 @@ class WebpackCompiler {
stats
.toString(this.config.devServer.stats)
.split('\n')
.forEach(line => logger.log(line));
.forEach((line) => logger.log(line));
});
}
}
+2 -5
View File
@@ -30,17 +30,14 @@ export const regQuery = async (path, key) => {
logger.error('could not find the end of the line');
return null;
}
const indexOfValue = stdout.indexOf(
' ',
indexOfKey + keyPattern.length);
const indexOfValue = stdout.indexOf(' ', indexOfKey + keyPattern.length);
if (indexOfValue === -1) {
logger.error('could not find the start of the key value');
return null;
}
const value = stdout.substring(indexOfValue + 4, indexOfEol);
return value;
}
catch (err) {
} catch (err) {
logger.error(err);
return null;
}
+76 -70
View File
@@ -5,8 +5,8 @@
*/
/* eslint-disable */
(function(window, document) {
/*jshint evil:true */
(function (window, document) {
/*jshint evil:true */
/** version */
var version = '3.7.3';
@@ -17,7 +17,8 @@
var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
/** Not all elements can be cloned in IE **/
var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
var saveClones =
/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
/** Detect whether the browser supports default html5 styles */
var supportsHtml5Styles;
@@ -34,30 +35,31 @@
/** Detect whether the browser supports unknown elements */
var supportsUnknownElements;
(function() {
(function () {
try {
var a = document.createElement('a');
a.innerHTML = '<xyz></xyz>';
//if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
supportsHtml5Styles = ('hidden' in a);
var a = document.createElement('a');
a.innerHTML = '<xyz></xyz>';
//if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
supportsHtml5Styles = 'hidden' in a;
supportsUnknownElements = a.childNodes.length == 1 || (function() {
supportsUnknownElements =
a.childNodes.length == 1 ||
(function () {
// assign a false positive if unable to shiv
(document.createElement)('a');
document.createElement('a');
var frag = document.createDocumentFragment();
return (
typeof frag.cloneNode == 'undefined' ||
typeof frag.createDocumentFragment == 'undefined' ||
typeof frag.createElement == 'undefined'
);
}());
} catch(e) {
})();
} catch (e) {
// assign a false positive if detection fails => unable to shiv
supportsHtml5Styles = true;
supportsUnknownElements = true;
}
}());
})();
/*--------------------------------------------------------------------------*/
@@ -70,7 +72,7 @@
*/
function addStyleSheet(ownerDocument, cssText) {
var p = ownerDocument.createElement('p'),
parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
p.innerHTML = 'x<style>' + cssText + '</style>';
return parent.insertBefore(p.lastChild, parent.firstChild);
@@ -94,17 +96,17 @@
*/
function addElements(newElements, ownerDocument) {
var elements = html5.elements;
if(typeof elements != 'string'){
if (typeof elements != 'string') {
elements = elements.join(' ');
}
if(typeof newElements != 'string'){
if (typeof newElements != 'string') {
newElements = newElements.join(' ');
}
html5.elements = elements +' '+ newElements;
html5.elements = elements + ' ' + newElements;
shivDocument(ownerDocument);
}
/**
/**
* Returns the data associated to the given document
* @private
* @param {Document} ownerDocument The document.
@@ -113,10 +115,10 @@
function getExpandoData(ownerDocument) {
var data = expandoData[ownerDocument[expando]];
if (!data) {
data = {};
expanID++;
ownerDocument[expando] = expanID;
expandoData[expanID] = data;
data = {};
expanID++;
ownerDocument[expando] = expanID;
expandoData[expanID] = data;
}
return data;
}
@@ -128,24 +130,24 @@
* @param {Document|DocumentFragment} ownerDocument The context document.
* @returns {Object} The shived element.
*/
function createElement(nodeName, ownerDocument, data){
function createElement(nodeName, ownerDocument, data) {
if (!ownerDocument) {
ownerDocument = document;
ownerDocument = document;
}
if(supportsUnknownElements){
return ownerDocument.createElement(nodeName);
if (supportsUnknownElements) {
return ownerDocument.createElement(nodeName);
}
if (!data) {
data = getExpandoData(ownerDocument);
data = getExpandoData(ownerDocument);
}
var node;
if (data.cache[nodeName]) {
node = data.cache[nodeName].cloneNode();
node = data.cache[nodeName].cloneNode();
} else if (saveClones.test(nodeName)) {
node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
} else {
node = data.createElem(nodeName);
node = data.createElem(nodeName);
}
// Avoid adding some elements to fragments in IE < 9 because
@@ -164,20 +166,20 @@
* @param {Document} ownerDocument The context document.
* @returns {Object} The shived DocumentFragment.
*/
function createDocumentFragment(ownerDocument, data){
function createDocumentFragment(ownerDocument, data) {
if (!ownerDocument) {
ownerDocument = document;
ownerDocument = document;
}
if(supportsUnknownElements){
return ownerDocument.createDocumentFragment();
if (supportsUnknownElements) {
return ownerDocument.createDocumentFragment();
}
data = data || getExpandoData(ownerDocument);
var clone = data.frag.cloneNode(),
i = 0,
elems = getElements(),
l = elems.length;
for(;i<l;i++){
clone.createElement(elems[i]);
i = 0,
elems = getElements(),
l = elems.length;
for (; i < l; i++) {
clone.createElement(elems[i]);
}
return clone;
}
@@ -190,31 +192,34 @@
*/
function shivMethods(ownerDocument, data) {
if (!data.cache) {
data.cache = {};
data.createElem = ownerDocument.createElement;
data.createFrag = ownerDocument.createDocumentFragment;
data.frag = data.createFrag();
data.cache = {};
data.createElem = ownerDocument.createElement;
data.createFrag = ownerDocument.createDocumentFragment;
data.frag = data.createFrag();
}
ownerDocument.createElement = function(nodeName) {
ownerDocument.createElement = function (nodeName) {
//abort shiv
if (!html5.shivMethods) {
return data.createElem(nodeName);
return data.createElem(nodeName);
}
return createElement(nodeName, ownerDocument, data);
};
ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
'var n=f.cloneNode(),c=n.createElement;' +
'h.shivMethods&&(' +
ownerDocument.createDocumentFragment = Function(
'h,f',
'return function(){' +
'var n=f.cloneNode(),c=n.createElement;' +
'h.shivMethods&&(' +
// unroll the `createElement` calls
getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
data.createElem(nodeName);
data.frag.createElement(nodeName);
return 'c("' + nodeName + '")';
}) +
');return n}'
getElements()
.join()
.replace(/[\w\-:]+/g, function (nodeName) {
data.createElem(nodeName);
data.frag.createElement(nodeName);
return 'c("' + nodeName + '")';
}) +
');return n}'
)(html5, data.frag);
}
@@ -228,18 +233,19 @@
*/
function shivDocument(ownerDocument) {
if (!ownerDocument) {
ownerDocument = document;
ownerDocument = document;
}
var data = getExpandoData(ownerDocument);
if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
data.hasCSS = !!addStyleSheet(ownerDocument,
data.hasCSS = !!addStyleSheet(
ownerDocument,
// corrects block display not defined in IE6/7/8/9
'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
// adds styling not present in IE6/7/8/9
'mark{background:#FF0;color:#000}' +
// hides non-rendered elements
'template{display:none}'
// adds styling not present in IE6/7/8/9
'mark{background:#FF0;color:#000}' +
// hides non-rendered elements
'template{display:none}'
);
}
if (!supportsUnknownElements) {
@@ -260,13 +266,14 @@
* html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
*/
var html5 = {
/**
* An array or space separated string of node names of the elements to shiv.
* @memberOf html5
* @type Array|String
*/
'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
'elements':
options.elements ||
'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
/**
* current version of html5shiv
@@ -278,7 +285,7 @@
* @memberOf html5
* @type Boolean
*/
'shivCSS': (options.shivCSS !== false),
'shivCSS': options.shivCSS !== false,
/**
* Is equal to true if a browser supports creating unknown/HTML5 elements
@@ -293,7 +300,7 @@
* @memberOf html5
* @type Boolean
*/
'shivMethods': (options.shivMethods !== false),
'shivMethods': options.shivMethods !== false,
/**
* A string to describe the type of `html5` object ("default" or "default print").
@@ -312,7 +319,7 @@
createDocumentFragment: createDocumentFragment,
//extends list of elements
addElements: addElements
addElements: addElements,
};
/*--------------------------------------------------------------------------*/
@@ -323,8 +330,7 @@
// shiv the document
shivDocument(document);
if(typeof module == 'object' && module.exports){
if (typeof module == 'object' && module.exports) {
module.exports = html5;
}
}(window, document));
})(window, document);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -9,7 +9,7 @@
*/
/* eslint-disable */
(function(Proto) {
(function (Proto) {
'use strict';
if (typeof Proto.setAttribute !== 'undefined') {
@@ -40,5 +40,4 @@
return value;
};
}
})(CSSStyleDeclaration.prototype);
+18 -18
View File
@@ -9,23 +9,24 @@
'use strict';
// Necessary polyfill to make Webpack code splitting work on IE8
if (!Function.prototype.bind) (function () {
var slice = Array.prototype.slice;
Function.prototype.bind = function () {
var thatFunc = this, thatArg = arguments[0];
var args = slice.call(arguments, 1);
if (typeof thatFunc !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - ' +
'what is trying to be bound is not callable');
}
return function () {
var funcArgs = args.concat(slice.call(arguments))
return thatFunc.apply(thatArg, funcArgs);
if (!Function.prototype.bind)
(function () {
var slice = Array.prototype.slice;
Function.prototype.bind = function () {
var thatFunc = this,
thatArg = arguments[0];
var args = slice.call(arguments, 1);
if (typeof thatFunc !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - ' + 'what is trying to be bound is not callable');
}
return function () {
var funcArgs = args.concat(slice.call(arguments));
return thatFunc.apply(thatArg, funcArgs);
};
};
};
})();
})();
if (!Array.prototype['forEach']) {
Array.prototype.forEach = function (callback, thisArg) {
@@ -35,7 +36,7 @@
var T, k;
var O = Object(this);
var len = O.length >>> 0;
if (typeof callback !== "function") {
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
@@ -57,5 +58,4 @@
if (!window.Int32Array) {
window.Int32Array = Array;
}
})();
+3 -5
View File
@@ -7,11 +7,9 @@
const EXCLUDED_PATTERNS = [/v4shim/i];
const loadedMappings = {};
export const resolveAsset = name => (
loadedMappings[name] || name
);
export const resolveAsset = (name) => loadedMappings[name] || name;
export const assetMiddleware = store => next => action => {
export const assetMiddleware = (store) => (next) => (action) => {
const { type, payload } = action;
if (type === 'asset/stylesheet') {
Byond.loadCss(payload);
@@ -20,7 +18,7 @@ export const assetMiddleware = store => next => action => {
if (type === 'asset/mappings') {
for (let name of Object.keys(payload)) {
// Skip anything that matches excluded patterns
if (EXCLUDED_PATTERNS.some(regex => regex.test(name))) {
if (EXCLUDED_PATTERNS.some((regex) => regex.test(name))) {
continue;
}
const url = payload[name];
+40 -64
View File
@@ -62,8 +62,7 @@ export const backendReducer = (state = initialState, action) => {
const value = payload.shared[key];
if (value === '') {
shared[key] = undefined;
}
else {
} else {
shared[key] = JSON.parse(value);
}
}
@@ -115,11 +114,11 @@ export const backendReducer = (state = initialState, action) => {
return state;
};
export const backendMiddleware = store => {
export const backendMiddleware = (store) => {
let fancyState;
let suspendInterval;
return next => action => {
return (next) => (action) => {
const { suspended } = selectBackend(store.getState());
const { type, payload } = action;
@@ -196,8 +195,7 @@ export const backendMiddleware = store => {
});
perf.mark('resume/finish');
if (process.env.NODE_ENV !== 'production') {
logger.log('visible in',
perf.measure('render/finish', 'resume/finish'));
logger.log('visible in', perf.measure('render/finish', 'resume/finish'));
}
});
}
@@ -212,9 +210,7 @@ export const backendMiddleware = store => {
*/
export const sendAct = (action: string, payload: object = {}) => {
// Validate that payload is an object
const isObject = typeof payload === 'object'
&& payload !== null
&& !Array.isArray(payload);
const isObject = typeof payload === 'object' && payload !== null && !Array.isArray(payload);
if (!isObject) {
logger.error(`Payload for act() must be an object, got this:`, payload);
return;
@@ -224,38 +220,36 @@ export const sendAct = (action: string, payload: object = {}) => {
type BackendState<TData> = {
config: {
title: string,
status: number,
interface: string,
refreshing: boolean,
title: string;
status: number;
interface: string;
refreshing: boolean;
window: {
key: string,
size: [number, number],
fancy: boolean,
locked: boolean,
},
key: string;
size: [number, number];
fancy: boolean;
locked: boolean;
};
client: {
ckey: string,
address: string,
computer_id: string,
},
ckey: string;
address: string;
computer_id: string;
};
user: {
name: string,
observer: number,
},
},
data: TData,
shared: Record<string, any>,
suspending: boolean,
suspended: boolean,
name: string;
observer: number;
};
};
data: TData;
shared: Record<string, any>;
suspending: boolean;
suspended: boolean;
};
/**
* Selects a backend-related slice of Redux state
*/
export const selectBackend = <TData>(state: any): BackendState<TData> => (
state.backend || {}
);
export const selectBackend = <TData>(state: any): BackendState<TData> => state.backend || {};
/**
* Get data from tgui backend.
@@ -289,28 +283,20 @@ type StateWithSetter<T> = [T, (nextState: T) => void];
* @param key Key which uniquely identifies this state in Redux store.
* @param initialState Initializes your global variable with this value.
*/
export const useLocalState = <T>(
context: any,
key: string,
initialState: T,
): StateWithSetter<T> => {
export const useLocalState = <T>(context: any, key: string, initialState: T): StateWithSetter<T> => {
const { store } = context;
const state = selectBackend(store.getState());
const sharedStates = state.shared ?? {};
const sharedState = (key in sharedStates)
? sharedStates[key]
: initialState;
const sharedState = key in sharedStates ? sharedStates[key] : initialState;
return [
sharedState,
nextState => {
store.dispatch(backendSetSharedState({
key,
nextState: (
typeof nextState === 'function'
? nextState(sharedState)
: nextState
),
}));
(nextState) => {
store.dispatch(
backendSetSharedState({
key,
nextState: typeof nextState === 'function' ? nextState(sharedState) : nextState,
})
);
},
];
};
@@ -329,28 +315,18 @@ export const useLocalState = <T>(
* @param key Key which uniquely identifies this state in Redux store.
* @param initialState Initializes your global variable with this value.
*/
export const useSharedState = <T>(
context: any,
key: string,
initialState: T,
): StateWithSetter<T> => {
export const useSharedState = <T>(context: any, key: string, initialState: T): StateWithSetter<T> => {
const { store } = context;
const state = selectBackend(store.getState());
const sharedStates = state.shared ?? {};
const sharedState = (key in sharedStates)
? sharedStates[key]
: initialState;
const sharedState = key in sharedStates ? sharedStates[key] : initialState;
return [
sharedState,
nextState => {
(nextState) => {
Byond.sendMessage({
type: 'setSharedState',
key,
value: JSON.stringify(
typeof nextState === 'function'
? nextState(sharedState)
: nextState
) || '',
value: JSON.stringify(typeof nextState === 'function' ? nextState(sharedState) : nextState) || '',
});
},
];
@@ -10,10 +10,8 @@ import { Component } from 'inferno';
const FPS = 20;
const Q = 0.5;
const isSafeNumber = value => {
return typeof value === 'number'
&& Number.isFinite(value)
&& !Number.isNaN(value);
const isSafeNumber = (value) => {
return typeof value === 'number' && Number.isFinite(value) && !Number.isNaN(value);
};
export class AnimatedNumber extends Component {
+1 -1
View File
@@ -1,4 +1,4 @@
import { Component, createRef } from "inferno";
import { Component, createRef } from 'inferno';
export class Autofocus extends Component {
ref = createRef<HTMLDivElement>();
+6 -9
View File
@@ -12,10 +12,7 @@ export class Blink extends Component {
}
createTimer() {
const {
interval = DEFAULT_BLINKING_INTERVAL,
time = DEFAULT_BLINKING_TIME,
} = this.props;
const { interval = DEFAULT_BLINKING_INTERVAL, time = DEFAULT_BLINKING_TIME } = this.props;
clearInterval(this.interval);
clearTimeout(this.timer);
@@ -42,8 +39,7 @@ export class Blink extends Component {
}
componentDidUpdate(prevProps) {
if (prevProps.interval !== this.props.interval
|| prevProps.time !== this.props.time) {
if (prevProps.interval !== this.props.interval || prevProps.time !== this.props.time) {
this.createTimer();
}
}
@@ -55,9 +51,10 @@ export class Blink extends Component {
render(props) {
return (
<span style={{
visibility: this.state.hidden ? "hidden" : "visible",
}}>
<span
style={{
visibility: this.state.hidden ? 'hidden' : 'visible',
}}>
{props.children}
</span>
);
+2 -9
View File
@@ -7,14 +7,7 @@
import { classes } from 'common/react';
import { Box } from './Box';
export const BlockQuote = props => {
export const BlockQuote = (props) => {
const { className, ...rest } = props;
return (
<Box
className={classes([
'BlockQuote',
className,
])}
{...rest} />
);
return <Box className={classes(['BlockQuote', className])} {...rest} />;
};
+26 -46
View File
@@ -60,17 +60,17 @@ export interface BoxProps {
backgroundColor?: string | BooleanLike;
// VOREStation Addition Start
// Flex props
order?: string | BooleanLike,
flexDirection?: string | BooleanLike,
flexGrow?: string | BooleanLike,
flexShrink?: string | BooleanLike,
flexWrap?: string | BooleanLike,
flexFlow?: string | BooleanLike,
flexBasis?: string | BooleanLike,
flex?: string | BooleanLike,
alignItems?: string | BooleanLike,
justifyContent?: string | BooleanLike,
alignSelf?: string | BooleanLike,
order?: string | BooleanLike;
flexDirection?: string | BooleanLike;
flexGrow?: string | BooleanLike;
flexShrink?: string | BooleanLike;
flexWrap?: string | BooleanLike;
flexFlow?: string | BooleanLike;
flexBasis?: string | BooleanLike;
flex?: string | BooleanLike;
alignItems?: string | BooleanLike;
justifyContent?: string | BooleanLike;
alignSelf?: string | BooleanLike;
// VOREStation Addition End
fillPositionedParent?: boolean;
}
@@ -109,10 +109,10 @@ export const halfUnit = (value: unknown): string | undefined => {
const isColorCode = (str: unknown) => !isColorClass(str);
const isColorClass = (str: unknown): boolean => {
return typeof str === "string" && CSS_COLORS.includes(str);
return typeof str === 'string' && CSS_COLORS.includes(str);
};
const mapRawPropTo = attrName => (style, value) => {
const mapRawPropTo = (attrName) => (style, value) => {
if (typeof value === 'number' || typeof value === 'string') {
style[attrName] = value;
}
@@ -138,7 +138,7 @@ const mapDirectionalUnitPropTo = (attrName, unit, dirs) => (style, value) => {
}
};
const mapColorPropTo = attrName => (style, value) => {
const mapColorPropTo = (attrName) => (style, value) => {
if (isColorCode(value)) {
style[attrName] = value;
}
@@ -165,8 +165,7 @@ const styleMapperByPropName = {
lineHeight: (style, value) => {
if (typeof value === 'number') {
style['line-height'] = value;
}
else if (typeof value === 'string') {
} else if (typeof value === 'string') {
style['line-height'] = unit(value);
}
},
@@ -182,29 +181,17 @@ const styleMapperByPropName = {
nowrap: mapBooleanPropTo('white-space', 'nowrap'),
preserveWhitespace: mapBooleanPropTo('white-space', 'pre-wrap'),
// Margins
m: mapDirectionalUnitPropTo('margin', halfUnit, [
'top', 'bottom', 'left', 'right',
]),
mx: mapDirectionalUnitPropTo('margin', halfUnit, [
'left', 'right',
]),
my: mapDirectionalUnitPropTo('margin', halfUnit, [
'top', 'bottom',
]),
m: mapDirectionalUnitPropTo('margin', halfUnit, ['top', 'bottom', 'left', 'right']),
mx: mapDirectionalUnitPropTo('margin', halfUnit, ['left', 'right']),
my: mapDirectionalUnitPropTo('margin', halfUnit, ['top', 'bottom']),
mt: mapUnitPropTo('margin-top', halfUnit),
mb: mapUnitPropTo('margin-bottom', halfUnit),
ml: mapUnitPropTo('margin-left', halfUnit),
mr: mapUnitPropTo('margin-right', halfUnit),
// Margins
p: mapDirectionalUnitPropTo('padding', halfUnit, [
'top', 'bottom', 'left', 'right',
]),
px: mapDirectionalUnitPropTo('padding', halfUnit, [
'left', 'right',
]),
py: mapDirectionalUnitPropTo('padding', halfUnit, [
'top', 'bottom',
]),
p: mapDirectionalUnitPropTo('padding', halfUnit, ['top', 'bottom', 'left', 'right']),
px: mapDirectionalUnitPropTo('padding', halfUnit, ['left', 'right']),
py: mapDirectionalUnitPropTo('padding', halfUnit, ['top', 'bottom']),
pt: mapUnitPropTo('padding-top', halfUnit),
pb: mapUnitPropTo('padding-bottom', halfUnit),
pl: mapUnitPropTo('padding-left', halfUnit),
@@ -256,8 +243,7 @@ export const computeBoxProps = (props: BoxProps) => {
const mapPropToStyle = styleMapperByPropName[propName];
if (mapPropToStyle) {
mapPropToStyle(computedStyles, propValue);
}
else {
} else {
computedProps[propName] = propValue;
}
}
@@ -289,19 +275,13 @@ export const computeBoxClassName = (props: BoxProps) => {
};
export const Box: SFC<BoxProps> = (props: BoxProps) => {
const {
as = 'div',
className,
children,
...rest
} = props;
const { as = 'div', className, children, ...rest } = props;
// Render props
if (typeof children === 'function') {
return children(computeBoxProps(props));
}
const computedClassName = typeof className === 'string'
? className + ' ' + computeBoxClassName(rest)
: computeBoxClassName(rest);
const computedClassName =
typeof className === 'string' ? className + ' ' + computeBoxClassName(rest) : computeBoxClassName(rest);
const computedProps = computeBoxProps(rest);
// Render a wrapper element
return createVNode(
@@ -311,7 +291,7 @@ export const Box: SFC<BoxProps> = (props: BoxProps) => {
children,
ChildFlags.UnknownChildren,
computedProps,
undefined,
undefined
);
};
+27 -53
View File
@@ -14,7 +14,7 @@ import { Tooltip } from './Tooltip';
const logger = createLogger('Button');
export const Button = props => {
export const Button = (props) => {
const {
className,
fluid,
@@ -42,12 +42,13 @@ export const Button = props => {
// A warning about the lowercase onclick
if (onclick) {
logger.warn(
`Lowercase 'onclick' is not supported on Button and lowercase`
+ ` prop names are discouraged in general. Please use a camelCase`
+ `'onClick' instead and read: `
+ `https://infernojs.org/docs/guides/event-handling`);
`Lowercase 'onclick' is not supported on Button and lowercase` +
` prop names are discouraged in general. Please use a camelCase` +
`'onClick' instead and read: ` +
`https://infernojs.org/docs/guides/event-handling`
);
}
rest.onClick = e => {
rest.onClick = (e) => {
if (!disabled && onClick) {
onClick(e);
}
@@ -68,14 +69,12 @@ export const Button = props => {
circular && 'Button--circular',
compact && 'Button--compact',
iconPosition && 'Button--iconPosition--' + iconPosition,
(color && typeof color === 'string')
? 'Button--color--' + color
: 'Button--color--default',
color && typeof color === 'string' ? 'Button--color--' + color : 'Button--color--default',
className,
computeBoxClassName(rest),
])}
tabIndex={!disabled && '0'}
onKeyDown={e => {
onKeyDown={(e) => {
if (props.captureKeys === false) {
return;
}
@@ -96,16 +95,12 @@ export const Button = props => {
}
}}
{...computeBoxProps(rest)}>
{(icon && iconPosition !== 'right') && (
<Icon
name={icon}
color={iconColor}
rotation={iconRotation}
spin={iconSpin} />
{icon && iconPosition !== 'right' && (
<Icon name={icon} color={iconColor} rotation={iconRotation} spin={iconSpin} />
)}
{content}
{children}
{(icon && iconPosition === 'right') && (
{icon && iconPosition === 'right' && (
<Icon
name={icon}
color={iconColor}
@@ -130,15 +125,9 @@ export const Button = props => {
Button.defaultHooks = pureComponentHooks;
export const ButtonCheckbox = props => {
export const ButtonCheckbox = (props) => {
const { checked, ...rest } = props;
return (
<Button
color="transparent"
icon={checked ? 'check-square-o' : 'square-o'}
selected={checked}
{...rest} />
);
return <Button color="transparent" icon={checked ? 'check-square-o' : 'square-o'} selected={checked} {...rest} />;
};
Button.Checkbox = ButtonCheckbox;
@@ -162,16 +151,15 @@ export class ButtonConfirm extends Component {
});
if (clickedOnce) {
setTimeout(() => window.addEventListener('click', this.handleClick));
}
else {
} else {
window.removeEventListener('click', this.handleClick);
}
}
render() {
const {
confirmContent = "Confirm?",
confirmColor = "bad",
confirmContent = 'Confirm?',
confirmColor = 'bad',
confirmIcon,
icon,
color,
@@ -184,9 +172,7 @@ export class ButtonConfirm extends Component {
content={this.state.clickedOnce ? confirmContent : content}
icon={this.state.clickedOnce ? confirmIcon : icon}
color={this.state.clickedOnce ? confirmColor : color}
onClick={() => this.state.clickedOnce
? onClick()
: this.setClickedOnce(true)}
onClick={() => (this.state.clickedOnce ? onClick() : this.setClickedOnce(true))}
{...rest}
/>
);
@@ -211,12 +197,11 @@ export class ButtonInput extends Component {
if (this.inputRef) {
const input = this.inputRef.current;
if (inInput) {
input.value = this.props.currentValue || "";
input.value = this.props.currentValue || '';
try {
input.focus();
input.select();
}
catch {}
} catch {}
}
}
}
@@ -224,7 +209,7 @@ export class ButtonInput extends Component {
commitResult(e) {
if (this.inputRef) {
const input = this.inputRef.current;
const hasValue = (input.value !== "");
const hasValue = input.value !== '';
if (hasValue) {
this.props.onCommit(e, input.value);
return;
@@ -254,19 +239,11 @@ export class ButtonInput extends Component {
let buttonContent = (
<Box
className={classes([
'Button',
fluid && 'Button--fluid',
'Button--color--' + color,
])}
className={classes(['Button', fluid && 'Button--fluid', 'Button--color--' + color])}
{...rest}
onClick={() => this.setInInput(true)}>
{icon && (
<Icon name={icon} rotation={iconRotation} spin={iconSpin} />
)}
<div>
{content}
</div>
{icon && <Icon name={icon} rotation={iconRotation} spin={iconSpin} />}
<div>{content}</div>
<input
ref={this.inputRef}
className="NumberInput__input"
@@ -274,14 +251,14 @@ export class ButtonInput extends Component {
'display': !this.state.inInput ? 'none' : undefined,
'text-align': 'left',
}}
onBlur={e => {
onBlur={(e) => {
if (!this.state.inInput) {
return;
}
this.setInInput(false);
this.commitResult(e);
}}
onKeyDown={e => {
onKeyDown={(e) => {
if (e.keyCode === KEY_ENTER) {
this.setInInput(false);
this.commitResult(e);
@@ -297,10 +274,7 @@ export class ButtonInput extends Component {
if (tooltip) {
buttonContent = (
<Tooltip
content={tooltip}
position={tooltipPosition}
>
<Tooltip content={tooltip} position={tooltipPosition}>
{buttonContent}
</Tooltip>
);
+10 -27
View File
@@ -15,7 +15,7 @@ const logger = createLogger('ByondUi');
// Stack of currently allocated BYOND UI element ids.
const byondUiStack = [];
const createByondUiElement = elementId => {
const createByondUiElement = (elementId) => {
// Reserve an index in the stack
const index = byondUiStack.length;
byondUiStack.push(null);
@@ -24,7 +24,7 @@ const createByondUiElement = elementId => {
logger.log(`allocated '${id}'`);
// Return a control structure
return {
render: params => {
render: (params) => {
logger.log(`rendering '${id}'`);
byondUiStack[index] = id;
Byond.winset(id, params);
@@ -56,18 +56,12 @@ window.addEventListener('beforeunload', () => {
/**
* Get the bounding box of the DOM element in display-pixels.
*/
const getBoundingBox = element => {
const getBoundingBox = (element) => {
const pixelRatio = window.devicePixelRatio ?? 1;
const rect = element.getBoundingClientRect();
return {
pos: [
rect.left * pixelRatio,
rect.top * pixelRatio,
],
size: [
(rect.right - rect.left) * pixelRatio,
(rect.bottom - rect.top) * pixelRatio,
],
pos: [rect.left * pixelRatio, rect.top * pixelRatio],
size: [(rect.right - rect.left) * pixelRatio, (rect.bottom - rect.top) * pixelRatio],
};
};
@@ -82,16 +76,9 @@ export class ByondUi extends Component {
}
shouldComponentUpdate(nextProps) {
const {
params: prevParams = {},
...prevRest
} = this.props;
const {
params: nextParams = {},
...nextRest
} = nextProps;
return shallowDiffers(prevParams, nextParams)
|| shallowDiffers(prevRest, nextRest);
const { params: prevParams = {}, ...prevRest } = this.props;
const { params: nextParams = {}, ...nextRest } = nextProps;
return shallowDiffers(prevParams, nextParams) || shallowDiffers(prevRest, nextRest);
}
componentDidMount() {
@@ -109,9 +96,7 @@ export class ByondUi extends Component {
if (Byond.IS_LTE_IE10) {
return;
}
const {
params = {},
} = this.props;
const { params = {} } = this.props;
const box = getBoundingBox(this.containerRef.current);
logger.debug('bounding box', box);
this.byondUiElement.render({
@@ -134,9 +119,7 @@ export class ByondUi extends Component {
render() {
const { params, ...rest } = this.props;
return (
<div
ref={this.containerRef}
{...computeBoxProps(rest)}>
<div ref={this.containerRef} {...computeBoxProps(rest)}>
{/* Filler */}
<div style={{ 'min-height': '22px' }} />
</div>
+7 -6
View File
@@ -23,15 +23,15 @@ const normalizeData = (data, scale, rangeX, rangeY) => {
min[1] = rangeY[0];
max[1] = rangeY[1];
}
const normalized = map(point => {
const normalized = map((point) => {
return zipWith((value, min, max, scale) => {
return (value - min) / (max - min) * scale;
return ((value - min) / (max - min)) * scale;
})(point, min, max, scale);
})(data);
return normalized;
};
const dataToPolylinePoints = data => {
const dataToPolylinePoints = (data) => {
let points = '';
for (let i = 0; i < data.length; i++) {
const point = data[i];
@@ -89,7 +89,7 @@ class LineChart extends Component {
const points = dataToPolylinePoints(normalized);
return (
<Box position="relative" {...rest}>
{props => (
{(props) => (
<div ref={this.ref} {...props}>
<svg
viewBox={`0 0 ${viewBox[0]} ${viewBox[1]}`}
@@ -107,7 +107,8 @@ class LineChart extends Component {
fill={fillColor}
stroke={strokeColor}
strokeWidth={strokeWidth}
points={points} />
points={points}
/>
</svg>
</div>
)}
@@ -118,7 +119,7 @@ class LineChart extends Component {
LineChart.defaultHooks = pureComponentHooks;
const Stub = props => null;
const Stub = (props) => null;
// IE8: No inline svg support
export const Chart = {
+3 -17
View File
@@ -20,13 +20,7 @@ export class Collapsible extends Component {
render() {
const { props } = this;
const { open } = this.state;
const {
children,
color = 'default',
title,
buttons,
...rest
} = props;
const { children, color = 'default', title, buttons, ...rest } = props;
return (
<Box mb={1}>
<div className="Table">
@@ -40,17 +34,9 @@ export class Collapsible extends Component {
{title}
</Button>
</div>
{buttons && (
<div className="Table__cell Table__cell--collapsing">
{buttons}
</div>
)}
{buttons && <div className="Table__cell Table__cell--collapsing">{buttons}</div>}
</div>
{open && (
<Box mt={1}>
{children}
</Box>
)}
{open && <Box mt={1}>{children}</Box>}
</Box>
);
}
+3 -16
View File
@@ -7,25 +7,12 @@
import { classes, pureComponentHooks } from 'common/react';
import { computeBoxClassName, computeBoxProps } from './Box';
export const ColorBox = props => {
const {
content,
children,
className,
color,
backgroundColor,
...rest
} = props;
export const ColorBox = (props) => {
const { content, children, className, color, backgroundColor, ...rest } = props;
rest.color = content ? null : 'transparent';
rest.backgroundColor = color || backgroundColor;
return (
<div
className={classes([
'ColorBox',
className,
computeBoxClassName(rest),
])}
{...computeBoxProps(rest)}>
<div className={classes(['ColorBox', className, computeBoxClassName(rest)])} {...computeBoxProps(rest)}>
{content || '.'}
</div>
);
+3 -10
View File
@@ -7,18 +7,11 @@
import { classes } from 'common/react';
import { Box } from './Box';
export const Dimmer = props => {
export const Dimmer = (props) => {
const { className, children, ...rest } = props;
return (
<Box
className={classes([
'Dimmer',
...className,
])}
{...rest}>
<div className="Dimmer__inner">
{children}
</div>
<Box className={classes(['Dimmer', ...className])} {...rest}>
<div className="Dimmer__inner">{children}</div>
</Box>
);
};
+5 -9
View File
@@ -6,19 +6,15 @@
import { classes } from 'common/react';
export const Divider = props => {
const {
vertical,
hidden,
} = props;
export const Divider = (props) => {
const { vertical, hidden } = props;
return (
<div
className={classes([
'Divider',
hidden && 'Divider--hidden',
vertical
? 'Divider--vertical'
: 'Divider--horizontal',
])} />
vertical ? 'Divider--vertical' : 'Divider--horizontal',
])}
/>
);
};
@@ -40,17 +40,18 @@ export class DraggableControl extends Component {
suppressingFlicker: true,
});
clearTimeout(this.flickerTimer);
this.flickerTimer = setTimeout(() => this.setState({
suppressingFlicker: false,
}), suppressFlicker);
this.flickerTimer = setTimeout(
() =>
this.setState({
suppressingFlicker: false,
}),
suppressFlicker
);
}
};
this.handleDragStart = e => {
const {
value,
dragMatrix,
} = this.props;
this.handleDragStart = (e) => {
const { value, dragMatrix } = this.props;
const { editing } = this.state;
if (editing) {
return;
@@ -79,54 +80,33 @@ export class DraggableControl extends Component {
document.addEventListener('mouseup', this.handleDragEnd);
};
this.handleDragMove = e => {
const {
minValue,
maxValue,
step,
stepPixelSize,
dragMatrix,
} = this.props;
this.setState(prevState => {
this.handleDragMove = (e) => {
const { minValue, maxValue, step, stepPixelSize, dragMatrix } = this.props;
this.setState((prevState) => {
const state = { ...prevState };
const offset = getScalarScreenOffset(e, dragMatrix) - state.origin;
if (prevState.dragging) {
const stepOffset = Number.isFinite(minValue)
? minValue % step
: 0;
const stepOffset = Number.isFinite(minValue) ? minValue % step : 0;
// Translate mouse movement to value
// Give it some headroom (by increasing clamp range by 1 step)
state.internalValue = clamp(
state.internalValue
+ offset * step / stepPixelSize,
state.internalValue + (offset * step) / stepPixelSize,
minValue - step,
maxValue + step);
maxValue + step
);
// Clamp the final value
state.value = clamp(
state.internalValue
- state.internalValue % step
+ stepOffset,
minValue,
maxValue);
state.value = clamp(state.internalValue - (state.internalValue % step) + stepOffset, minValue, maxValue);
state.origin = getScalarScreenOffset(e, dragMatrix);
}
else if (Math.abs(offset) > 4) {
} else if (Math.abs(offset) > 4) {
state.dragging = true;
}
return state;
});
};
this.handleDragEnd = e => {
const {
onChange,
onDrag,
} = this.props;
const {
dragging,
value,
internalValue,
} = this.state;
this.handleDragEnd = (e) => {
const { onChange, onDrag } = this.props;
const { dragging, value, internalValue } = this.state;
document.body.style['pointer-events'] = 'auto';
clearTimeout(this.timer);
clearInterval(this.dragInterval);
@@ -145,8 +125,7 @@ export class DraggableControl extends Component {
if (onDrag) {
onDrag(e, value);
}
}
else if (this.inputRef) {
} else if (this.inputRef) {
const input = this.inputRef.current;
input.value = internalValue;
// IE8: Dies when trying to focus a hidden element
@@ -154,19 +133,13 @@ export class DraggableControl extends Component {
try {
input.focus();
input.select();
}
catch {}
} catch {}
}
};
}
render() {
const {
dragging,
editing,
value: intermediateValue,
suppressingFlicker,
} = this.state;
const { dragging, editing, value: intermediateValue, suppressingFlicker } = this.state;
const {
animated,
value,
@@ -190,22 +163,14 @@ export class DraggableControl extends Component {
// Setup a display element
// Shows a formatted number based on what we are currently doing
// with the draggable surface.
const renderDisplayElement = value => (
value + (unit ? ' ' + unit : '')
);
const displayElement = (
animated && !dragging && !suppressingFlicker && (
<AnimatedNumber
value={displayValue}
format={format}>
const renderDisplayElement = (value) => value + (unit ? ' ' + unit : '');
const displayElement =
(animated && !dragging && !suppressingFlicker && (
<AnimatedNumber value={displayValue} format={format}>
{renderDisplayElement}
</AnimatedNumber>
) || (
renderDisplayElement(format
? format(displayValue)
: displayValue)
)
);
)) ||
renderDisplayElement(format ? format(displayValue) : displayValue);
// Setup an input element
// Handles direct input via the keyboard
const inputElement = (
@@ -218,19 +183,15 @@ export class DraggableControl extends Component {
'line-height': lineHeight,
'font-size': fontSize,
}}
onBlur={e => {
onBlur={(e) => {
if (!editing) {
return;
}
let value;
if (unclamped) {
value = parseFloat(e.target.value);
}
else {
value = clamp(
parseFloat(e.target.value),
minValue,
maxValue);
} else {
value = clamp(parseFloat(e.target.value), minValue, maxValue);
}
if (Number.isNaN(value)) {
this.setState({
@@ -250,17 +211,13 @@ export class DraggableControl extends Component {
onDrag(e, value);
}
}}
onKeyDown={e => {
onKeyDown={(e) => {
if (e.keyCode === 13) {
let value;
if (unclamped) {
value = parseFloat(e.target.value);
}
else {
value = clamp(
parseFloat(e.target.value),
minValue,
maxValue);
} else {
value = clamp(parseFloat(e.target.value), minValue, maxValue);
}
if (Number.isNaN(value)) {
this.setState({
@@ -287,7 +244,8 @@ export class DraggableControl extends Component {
});
return;
}
}} />
}}
/>
);
// Return a part of the state for higher-level components to use.
return children({
+11 -22
View File
@@ -32,8 +32,7 @@ export class Dropdown extends Component {
if (open) {
setTimeout(() => window.addEventListener('click', this.handleClick));
this.menuRef.focus();
}
else {
} else {
window.removeEventListener('click', this.handleClick);
}
}
@@ -48,7 +47,7 @@ export class Dropdown extends Component {
buildMenu() {
const { options = [], placeholder } = this.props; // VOREStation edit
const ops = options.map(option => (
const ops = options.map((option) => (
<Box
key={option}
className="Dropdown__menuentry"
@@ -60,7 +59,7 @@ export class Dropdown extends Component {
));
// VOREStation addition start
if (placeholder) {
ops.unshift((
ops.unshift(
<div
key={placeholder}
className="Dropdown__menuentry"
@@ -69,7 +68,7 @@ export class Dropdown extends Component {
}}>
-- {placeholder} --
</div>
));
);
}
// VOREStation addition end
return ops.length ? ops : 'No Options Found';
@@ -93,24 +92,20 @@ export class Dropdown extends Component {
placeholder, // VOREStation Addition
...boxProps
} = props;
const {
className,
...rest
} = boxProps;
const { className, ...rest } = boxProps;
const adjustedOpen = over ? !this.state.open : this.state.open;
const menu = this.state.open ? (
<div
ref={menu => { this.menuRef = menu; }}
ref={(menu) => {
this.menuRef = menu;
}}
tabIndex="-1"
style={{
'width': width,
}}
className={classes([
noscroll && 'Dropdown__menu-noscroll' || 'Dropdown__menu',
over && 'Dropdown__over',
])}>
className={classes([(noscroll && 'Dropdown__menu-noscroll') || 'Dropdown__menu', over && 'Dropdown__over'])}>
{this.buildMenu()}
</div>
) : null;
@@ -133,15 +128,9 @@ export class Dropdown extends Component {
}
this.setOpen(!this.state.open);
}}>
{icon && (
<Icon
name={icon}
rotation={iconRotation}
spin={iconSpin}
mr={1} />
)}
{icon && <Icon name={icon} rotation={iconRotation} spin={iconSpin} mr={1} />}
<span className="Dropdown__selected-text">
{displayText ? displayText : (this.state.selected || placeholder) /* VOREStation Edit */ }
{displayText ? displayText : this.state.selected || placeholder /* VOREStation Edit */}
</span>
{!!nochevron || (
<span className="Dropdown__arrow-button">
+5 -21
View File
@@ -50,17 +50,9 @@ export const computeFlexProps = (props: FlexProps) => {
});
};
export const Flex = props => {
export const Flex = (props) => {
const { className, ...rest } = props;
return (
<div
className={classes([
className,
computeFlexClassName(rest),
])}
{...computeFlexProps(rest)}
/>
);
return <div className={classes([className, computeFlexClassName(rest)])} {...computeFlexProps(rest)} />;
};
Flex.defaultHooks = pureComponentHooks;
@@ -74,11 +66,7 @@ export type FlexItemProps = BoxProps & {
};
export const computeFlexItemClassName = (props: FlexItemProps) => {
return classes([
'Flex__item',
Byond.IS_LTE_IE10 && 'Flex__item--iefix',
computeBoxClassName(props),
]);
return classes(['Flex__item', Byond.IS_LTE_IE10 && 'Flex__item--iefix', computeBoxClassName(props)]);
};
export const computeFlexItemProps = (props: FlexItemProps) => {
@@ -107,15 +95,11 @@ export const computeFlexItemProps = (props: FlexItemProps) => {
});
};
const FlexItem = props => {
const FlexItem = (props) => {
const { className, ...rest } = props;
return (
<div
className={classes([
className,
computeFlexItemClassName(props),
computeBoxClassName(props),
])}
className={classes([className, computeFlexItemClassName(props), computeBoxClassName(props)])}
{...computeFlexItemProps(rest)}
/>
);
+5 -6
View File
@@ -8,13 +8,11 @@ import { Table } from './Table';
import { pureComponentHooks } from 'common/react';
/** @deprecated */
export const Grid = props => {
export const Grid = (props) => {
const { children, ...rest } = props;
return (
<Table {...rest}>
<Table.Row>
{children}
</Table.Row>
<Table.Row>{children}</Table.Row>
</Table>
);
};
@@ -22,7 +20,7 @@ export const Grid = props => {
Grid.defaultHooks = pureComponentHooks;
/** @deprecated */
export const GridColumn = props => {
export const GridColumn = (props) => {
const { size = 1, style, ...rest } = props;
return (
<Table.Cell
@@ -30,7 +28,8 @@ export const GridColumn = props => {
width: size + '%',
...style,
}}
{...rest} />
{...rest}
/>
);
};
+10 -37
View File
@@ -11,22 +11,14 @@ import { computeBoxClassName, computeBoxProps } from './Box';
const FA_OUTLINE_REGEX = /-o$/;
export const Icon = props => {
const {
name,
size,
spin,
className,
rotation,
inverse,
...rest
} = props;
export const Icon = (props) => {
const { name, size, spin, className, rotation, inverse, ...rest } = props;
if (size) {
if (!rest.style) {
rest.style = {};
}
rest.style['font-size'] = (size * 100) + '%';
rest.style['font-size'] = size * 100 + '%';
}
if (typeof rotation === 'number') {
if (!rest.style) {
@@ -37,44 +29,25 @@ export const Icon = props => {
const boxProps = computeBoxProps(rest);
let iconClass = "";
if (name.startsWith("tg-")) {
let iconClass = '';
if (name.startsWith('tg-')) {
// tgfont icon
iconClass = name;
} else {
// font awesome icon
const faRegular = FA_OUTLINE_REGEX.test(name);
const faName = name.replace(FA_OUTLINE_REGEX, '');
iconClass = (faRegular ? 'far ' : 'fas ') + 'fa-'+ faName + (spin ? " fa-spin" : "");
iconClass = (faRegular ? 'far ' : 'fas ') + 'fa-' + faName + (spin ? ' fa-spin' : '');
}
return (
<i
className={classes([
'Icon',
iconClass,
className,
computeBoxClassName(rest),
])}
{...boxProps} />
);
return <i className={classes(['Icon', iconClass, className, computeBoxClassName(rest)])} {...boxProps} />;
};
Icon.defaultHooks = pureComponentHooks;
export const IconStack = props => {
const {
className,
children,
...rest
} = props;
export const IconStack = (props) => {
const { className, children, ...rest } = props;
return (
<span
class={classes([
'IconStack',
className,
computeBoxClassName(rest),
])}
{...computeBoxProps(rest)}>
<span class={classes(['IconStack', className, computeBoxClassName(rest)])} {...computeBoxProps(rest)}>
{children}
</span>
);
+42 -56
View File
@@ -1,7 +1,7 @@
import { computeBoxProps } from "./Box";
import { Stack } from "./Stack";
import { ProgressBar } from "./ProgressBar";
import { Button } from "./Button";
import { computeBoxProps } from './Box';
import { Stack } from './Stack';
import { ProgressBar } from './ProgressBar';
import { Button } from './Button';
import { Component } from 'inferno';
const ZOOM_MIN_VAL = 0.5;
@@ -33,19 +33,19 @@ export class InfinitePlane extends Component {
}
componentDidMount() {
window.addEventListener("mouseup", this.onMouseUp);
window.addEventListener('mouseup', this.onMouseUp);
window.addEventListener("mousedown", this.doOffsetMouse);
window.addEventListener("mousemove", this.doOffsetMouse);
window.addEventListener("mouseup", this.doOffsetMouse);
window.addEventListener('mousedown', this.doOffsetMouse);
window.addEventListener('mousemove', this.doOffsetMouse);
window.addEventListener('mouseup', this.doOffsetMouse);
}
componentWillUnmount() {
window.removeEventListener("mouseup", this.onMouseUp);
window.removeEventListener('mouseup', this.onMouseUp);
window.removeEventListener("mousedown", this.doOffsetMouse);
window.removeEventListener("mousemove", this.doOffsetMouse);
window.removeEventListener("mouseup", this.doOffsetMouse);
window.removeEventListener('mousedown', this.doOffsetMouse);
window.removeEventListener('mousemove', this.doOffsetMouse);
window.removeEventListener('mouseup', this.doOffsetMouse);
}
doOffsetMouse(event) {
@@ -82,17 +82,8 @@ export class InfinitePlane extends Component {
}
render() {
const {
children,
backgroundImage,
imageWidth,
...rest
} = this.props;
const {
left,
top,
zoom,
} = this.state;
const { children, backgroundImage, imageWidth, ...rest } = this.props;
const { left, top, zoom } = this.state;
return (
<div
@@ -101,65 +92,60 @@ export class InfinitePlane extends Component {
...rest,
style: {
...rest.style,
overflow: "hidden",
position: "relative",
overflow: 'hidden',
position: 'relative',
},
})}
>
})}>
<div
onMouseDown={this.handleMouseDown}
onMouseMove={this.handleMouseMove}
style={{
"position": "fixed",
"height": "100%",
"width": "100%",
"background-image": `url("${backgroundImage}")`,
"background-position": `${left}px ${top}px`,
"background-repeat": "repeat",
"background-size": `${zoom*imageWidth}px`,
'position': 'fixed',
'height': '100%',
'width': '100%',
'background-image': `url("${backgroundImage}")`,
'background-position': `${left}px ${top}px`,
'background-repeat': 'repeat',
'background-size': `${zoom * imageWidth}px`,
}}
/>
<div
onMouseDown={this.handleMouseDown}
onMouseMove={this.handleMouseMove}
style={{
"position": "fixed",
"transform": `translate(${left}px, ${top}px) scale(${zoom})`,
"transform-origin": "top left",
"height": "100%",
"width": "100%",
}}
>
'position': 'fixed',
'transform': `translate(${left}px, ${top}px) scale(${zoom})`,
'transform-origin': 'top left',
'height': '100%',
'width': '100%',
}}>
{children}
</div>
<Stack
position="absolute"
width="100%"
>
<Stack position="absolute" width="100%">
<Stack.Item>
<Button
icon="minus"
onClick={() => this.setState({
zoom: Math.max(zoom-ZOOM_INCREMENT, ZOOM_MIN_VAL),
})}
onClick={() =>
this.setState({
zoom: Math.max(zoom - ZOOM_INCREMENT, ZOOM_MIN_VAL),
})
}
/>
</Stack.Item>
<Stack.Item grow={1}>
<ProgressBar
minValue={ZOOM_MIN_VAL}
value={zoom}
maxValue={ZOOM_MAX_VAL}
>
<ProgressBar minValue={ZOOM_MIN_VAL} value={zoom} maxValue={ZOOM_MAX_VAL}>
{zoom}x
</ProgressBar>
</Stack.Item>
<Stack.Item>
<Button
icon="plus"
onClick={() => this.setState({
zoom: Math.min(zoom+ZOOM_INCREMENT, ZOOM_MAX_VAL),
})}
onClick={() =>
this.setState({
zoom: Math.min(zoom + ZOOM_INCREMENT, ZOOM_MAX_VAL),
})
}
/>
</Stack.Item>
</Stack>
+11 -35
View File
@@ -9,11 +9,7 @@ import { Component, createRef } from 'inferno';
import { Box } from './Box';
import { KEY_ESCAPE, KEY_ENTER } from 'common/keycodes';
export const toInputValue = value => (
typeof value !== 'number' && typeof value !== 'string'
? ''
: String(value)
);
export const toInputValue = (value) => (typeof value !== 'number' && typeof value !== 'string' ? '' : String(value));
export class Input extends Component {
constructor() {
@@ -22,7 +18,7 @@ export class Input extends Component {
this.state = {
editing: false,
};
this.handleInput = e => {
this.handleInput = (e) => {
const { editing } = this.state;
const { onInput } = this.props;
if (!editing) {
@@ -32,7 +28,7 @@ export class Input extends Component {
onInput(e, e.target.value);
}
};
this.handleFocus = e => {
this.handleFocus = (e) => {
const { editing } = this.state;
const { autoSelect } = this.props;
if (!editing) {
@@ -42,7 +38,7 @@ export class Input extends Component {
e.target.select();
}
};
this.handleBlur = e => {
this.handleBlur = (e) => {
const { editing } = this.state;
const { onChange } = this.props;
if (editing) {
@@ -52,7 +48,7 @@ export class Input extends Component {
}
}
};
this.handleKeyDown = e => {
this.handleKeyDown = (e) => {
const { onInput, onChange, onEnter } = this.props;
if (e.keyCode === KEY_ENTER) {
this.setEditing(false);
@@ -121,35 +117,14 @@ export class Input extends Component {
render() {
const { props } = this;
// Input only props
const {
selfClear,
onInput,
onChange,
onEnter,
value,
maxLength,
placeholder,
...boxProps
} = props;
const { selfClear, onInput, onChange, onEnter, value, maxLength, placeholder, ...boxProps } = props;
// Box props
const {
className,
fluid,
monospace,
...rest
} = boxProps;
const { className, fluid, monospace, ...rest } = boxProps;
return (
<Box
className={classes([
'Input',
fluid && 'Input--fluid',
monospace && 'Input--monospace',
className,
])}
className={classes(['Input', fluid && 'Input--fluid', monospace && 'Input--monospace', className])}
{...rest}>
<div className="Input__baseline">
.
</div>
<div className="Input__baseline">.</div>
<input
ref={this.inputRef}
className="Input__input"
@@ -158,7 +133,8 @@ export class Input extends Component {
onFocus={this.handleFocus}
onBlur={this.handleBlur}
onKeyDown={this.handleKeyDown}
maxLength={maxLength} />
maxLength={maxLength}
/>
</Box>
);
}
@@ -1,11 +1,11 @@
import { Component } from "inferno";
import { KeyEvent } from "../events";
import { listenForKeyEvents } from "../hotkeys";
import { Component } from 'inferno';
import { KeyEvent } from '../events';
import { listenForKeyEvents } from '../hotkeys';
type KeyListenerProps = Partial<{
onKey: (key: KeyEvent) => void,
onKeyDown: (key: KeyEvent) => void,
onKeyUp: (key: KeyEvent) => void,
onKey: (key: KeyEvent) => void;
onKeyDown: (key: KeyEvent) => void;
onKeyUp: (key: KeyEvent) => void;
}>;
export class KeyListener extends Component<KeyListenerProps> {
@@ -14,7 +14,7 @@ export class KeyListener extends Component<KeyListenerProps> {
constructor() {
super();
this.dispose = listenForKeyEvents(key => {
this.dispose = listenForKeyEvents((key) => {
if (this.props.onKey) {
this.props.onKey(key);
}
+14 -46
View File
@@ -10,13 +10,11 @@ import { computeBoxClassName, computeBoxProps } from './Box';
import { DraggableControl } from './DraggableControl';
import { NumberInput } from './NumberInput';
export const Knob = props => {
export const Knob = (props) => {
// IE8: I don't want to support a yet another component on IE8.
// IE8: It also can't handle SVG.
if (Byond.IS_LTE_IE8) {
return (
<NumberInput {...props} />
);
return <NumberInput {...props} />;
}
const {
// Draggable props (passthrough)
@@ -60,27 +58,11 @@ export const Knob = props => {
unit,
value,
}}>
{control => {
const {
dragging,
editing,
value,
displayValue,
displayElement,
inputElement,
handleDragStart,
} = control;
const scaledFillValue = scale(
fillValue ?? displayValue,
minValue,
maxValue);
const scaledDisplayValue = scale(
displayValue,
minValue,
maxValue);
const effectiveColor = color
|| keyOfMatchingRange(fillValue ?? value, ranges)
|| 'default';
{(control) => {
const { dragging, editing, value, displayValue, displayElement, inputElement, handleDragStart } = control;
const scaledFillValue = scale(fillValue ?? displayValue, minValue, maxValue);
const scaledDisplayValue = scale(displayValue, minValue, maxValue);
const effectiveColor = color || keyOfMatchingRange(fillValue ?? value, ranges) || 'default';
const rotation = Math.min((scaledDisplayValue - 0.5) * 270, 225);
return (
<div
@@ -108,34 +90,20 @@ export const Knob = props => {
<div className="Knob__cursor" />
</div>
</div>
{dragging && (
<div className="Knob__popupValue">
{displayElement}
</div>
)}
<svg
className="Knob__ring Knob__ringTrackPivot"
viewBox="0 0 100 100">
<circle
className="Knob__ringTrack"
cx="50"
cy="50"
r="50" />
{dragging && <div className="Knob__popupValue">{displayElement}</div>}
<svg className="Knob__ring Knob__ringTrackPivot" viewBox="0 0 100 100">
<circle className="Knob__ringTrack" cx="50" cy="50" r="50" />
</svg>
<svg
className="Knob__ring Knob__ringFillPivot"
viewBox="0 0 100 100">
<svg className="Knob__ring Knob__ringFillPivot" viewBox="0 0 100 100">
<circle
className="Knob__ringFill"
style={{
'stroke-dashoffset': (
Math.max(((bipolar ? 2.75 : 2.00) - scaledFillValue * 1.5)
* Math.PI * 50, 0)
),
'stroke-dashoffset': Math.max(((bipolar ? 2.75 : 2.0) - scaledFillValue * 1.5) * Math.PI * 50, 0),
}}
cx="50"
cy="50"
r="50" />
r="50"
/>
</svg>
{inputElement}
</div>
@@ -6,47 +6,23 @@
import { Flex } from './Flex';
export const LabeledControls = props => {
const {
children,
wrap,
...rest
} = props;
export const LabeledControls = (props) => {
const { children, wrap, ...rest } = props;
return (
<Flex
mx={-0.5}
wrap={wrap}
align="stretch"
justify="space-between"
{...rest}>
<Flex mx={-0.5} wrap={wrap} align="stretch" justify="space-between" {...rest}>
{children}
</Flex>
);
};
const LabeledControlsItem = props => {
const {
label,
children,
mx = 1,
...rest
} = props;
const LabeledControlsItem = (props) => {
const { label, children, mx = 1, ...rest } = props;
return (
<Flex.Item mx={mx}>
<Flex
height="100%"
direction="column"
align="center"
textAlign="center"
justify="space-between"
{...rest}>
<Flex height="100%" direction="column" align="center" textAlign="center" justify="space-between" {...rest}>
<Flex.Item />
<Flex.Item>
{children}
</Flex.Item>
<Flex.Item color="label">
{label}
</Flex.Item>
<Flex.Item>{children}</Flex.Item>
<Flex.Item color="label">{label}</Flex.Item>
</Flex>
</Flex.Item>
);
+10 -29
View File
@@ -15,11 +15,7 @@ type LabeledListProps = {
export const LabeledList = (props: LabeledListProps) => {
const { children } = props;
return (
<table className="LabeledList">
{children}
</table>
);
return <table className="LabeledList">{children}</table>;
};
LabeledList.defaultHooks = pureComponentHooks;
@@ -31,9 +27,9 @@ type LabeledListItemProps = {
color?: string | BooleanLike;
textAlign?: string | BooleanLike;
verticalAlign?: string | BooleanLike; // VOREStation Addition
buttons?: InfernoNode,
buttons?: InfernoNode;
/** @deprecated */
content?: any,
content?: any;
children?: InfernoNode;
};
@@ -51,19 +47,12 @@ const LabeledListItem = (props: LabeledListItemProps) => {
...rest // VOREStation Addition
} = props;
return (
<tr
className={classes([
'LabeledList__row',
className,
])}>
<tr className={classes(['LabeledList__row', className])}>
<Box
as="td"
verticalAlign={verticalAlign} // VOREStation Addition
color={labelColor}
className={classes([
'LabeledList__cell',
'LabeledList__label',
])}>
className={classes(['LabeledList__cell', 'LabeledList__label'])}>
{label ? label + ':' : null}
</Box>
<Box
@@ -71,20 +60,14 @@ const LabeledListItem = (props: LabeledListItemProps) => {
color={color}
textAlign={textAlign}
verticalAlign={verticalAlign} // VOREStation Addition
className={classes([
'LabeledList__cell',
'LabeledList__content',
])}
className={classes(['LabeledList__cell', 'LabeledList__content'])}
colSpan={buttons ? undefined : 2}
{...rest} /* VOREStation Addition*/>
{...rest} /* VOREStation Addition*/
>
{content}
{children}
</Box>
{buttons && (
<td className="LabeledList__cell LabeledList__buttons">
{buttons}
</td>
)}
{buttons && <td className="LabeledList__cell LabeledList__buttons">{buttons}</td>}
</tr>
);
};
@@ -96,9 +79,7 @@ type LabeledListDividerProps = {
};
const LabeledListDivider = (props: LabeledListDividerProps) => {
const padding = props.size
? unit(Math.max(0, props.size - 1))
: 0;
const padding = props.size ? unit(Math.max(0, props.size - 1)) : 0;
return (
<tr className="LabeledList__row">
<td
+4 -11
View File
@@ -8,7 +8,7 @@ import { classes } from 'common/react';
import { computeBoxClassName, computeBoxProps } from './Box';
import { Dimmer } from './Dimmer';
export const Modal = props => {
export const Modal = (props) => {
const {
className,
children,
@@ -18,7 +18,7 @@ export const Modal = props => {
// VOREStation Addition Start
let handleKeyDown;
if (onEnter) {
handleKeyDown = e => {
handleKeyDown = (e) => {
let key = e.which || e.keyCode;
if (key === 13) {
onEnter(e);
@@ -27,15 +27,8 @@ export const Modal = props => {
}
// VOREStation Addition End
return (
<Dimmer
onKeyDown={handleKeyDown /* VOREStation Edit */}>
<div
className={classes([
'Modal',
className,
computeBoxClassName(rest),
])}
{...computeBoxProps(rest)}>
<Dimmer onKeyDown={handleKeyDown /* VOREStation Edit */}>
<div className={classes(['Modal', className, computeBoxClassName(rest)])} {...computeBoxProps(rest)}>
{children}
</div>
</Dimmer>
+60 -66
View File
@@ -1,10 +1,14 @@
import { Component } from 'inferno';
import { Box, Button, Icon, Tooltip, LabeledList, Slider } from '.';
import { useBackend } from "../backend";
import { useBackend } from '../backend';
const pauseEvent = e => {
if (e.stopPropagation) { e.stopPropagation(); }
if (e.preventDefault) { e.preventDefault(); }
const pauseEvent = (e) => {
if (e.stopPropagation) {
e.stopPropagation();
}
if (e.preventDefault) {
e.preventDefault();
}
e.cancelBubble = true;
e.returnValue = false;
return false;
@@ -17,8 +21,8 @@ export class NanoMap extends Component {
super(props);
// Auto center based on window size
const Xcenter = (window.innerWidth / 2) - 256;
const Ycenter = (window.innerHeight / 2) - 256;
const Xcenter = window.innerWidth / 2 - 256;
const Ycenter = window.innerHeight / 2 - 256;
this.state = {
offsetX: Xcenter,
@@ -31,7 +35,7 @@ export class NanoMap extends Component {
};
// Dragging
this.handleDragStart = e => {
this.handleDragStart = (e) => {
this.ref = e.target;
this.setState({
dragging: false,
@@ -43,8 +47,8 @@ export class NanoMap extends Component {
pauseEvent(e);
};
this.handleDragMove = e => {
this.setState(prevState => {
this.handleDragMove = (e) => {
this.setState((prevState) => {
const state = { ...prevState };
const newOffsetX = e.screenX - state.originX;
const newOffsetY = e.screenY - state.originY;
@@ -61,7 +65,7 @@ export class NanoMap extends Component {
pauseEvent(e);
};
this.handleDragEnd = e => {
this.handleDragEnd = (e) => {
this.setState({
dragging: false,
originX: null,
@@ -72,30 +76,38 @@ export class NanoMap extends Component {
pauseEvent(e);
};
this.handleOnClick = e => {
let byondX = (e.offsetX/this.state.zoom)/zoomScale;
let byondY = 1-(e.offsetY/this.state.zoom)/zoomScale; // Byond origin is bottom left, this is top left
this.handleOnClick = (e) => {
let byondX = e.offsetX / this.state.zoom / zoomScale;
let byondY = 1 - e.offsetY / this.state.zoom / zoomScale; // Byond origin is bottom left, this is top left
e.byondX = byondX;
e.byondY = byondY;
if (typeof(this.props.onClick) === "function") {
if (typeof this.props.onClick === 'function') {
this.props.onClick(e);
}
};
this.handleZoom = (_e, value) => {
this.setState(state => {
this.setState((state) => {
const newZoom = Math.min(Math.max(value, 1), 8);
let zoomDiff = (newZoom - state.zoom) * 1.5;
state.zoom = newZoom;
let newOffsetX = state.offsetX - 262 * zoomDiff;
if (newOffsetX < -500) { newOffsetX = -500; }
if (newOffsetX > 500) { newOffsetX = 500; }
if (newOffsetX < -500) {
newOffsetX = -500;
}
if (newOffsetX > 500) {
newOffsetX = 500;
}
let newOffsetY = state.offsetY - 256 * zoomDiff;
if (newOffsetY < -200) { newOffsetY = -200; }
if (newOffsetY > 200) { newOffsetY = 200; }
if (newOffsetY < -200) {
newOffsetY = -200;
}
if (newOffsetY > 200) {
newOffsetY = 200;
}
state.offsetX = newOffsetX;
state.offsetY = newOffsetY;
@@ -105,41 +117,34 @@ export class NanoMap extends Component {
return state;
});
};
}
render() {
const { config } = useBackend(this.context);
const { dragging, offsetX, offsetY, zoom = 1 } = this.state;
const { children } = this.props;
const mapUrl = config.map + "_nanomap_z" + config.mapZLevel + ".png";
const mapUrl = config.map + '_nanomap_z' + config.mapZLevel + '.png';
// (x * zoom), x Needs to be double the turf- map size. (for virgo, 140x140)
const mapSize = (zoomScale * zoom) + 'px';
const mapSize = zoomScale * zoom + 'px';
const newStyle = {
width: mapSize,
height: mapSize,
"margin-top": offsetY + "px",
"margin-left": offsetX + "px",
"overflow": "hidden",
"position": "relative",
"background-image": "url(" + mapUrl + ")",
"background-size": "cover",
"background-repeat": "no-repeat",
"text-align": "center",
"cursor": dragging ? "move" : "auto",
'margin-top': offsetY + 'px',
'margin-left': offsetX + 'px',
'overflow': 'hidden',
'position': 'relative',
'background-image': 'url(' + mapUrl + ')',
'background-size': 'cover',
'background-repeat': 'no-repeat',
'text-align': 'center',
'cursor': dragging ? 'move' : 'auto',
};
return (
<Box className="NanoMap__container">
<Box
style={newStyle}
textAlign="center"
onMouseDown={this.handleDragStart}
onClick={this.handleOnClick}>
<Box>
{children}
</Box>
<Box style={newStyle} textAlign="center" onMouseDown={this.handleDragStart} onClick={this.handleOnClick}>
<Box>{children}</Box>
</Box>
<NanoMapZoomer zoom={zoom} onZoom={this.handleZoom} />
</Box>
@@ -148,39 +153,27 @@ export class NanoMap extends Component {
}
const NanoMapMarker = (props, context) => {
const {
x,
y,
zoom = 1,
icon,
tooltip,
color,
onClick,
} = props;
const { x, y, zoom = 1, icon, tooltip, color, onClick } = props;
const handleOnClick = e => {
const handleOnClick = (e) => {
pauseEvent(e);
if (onClick) {
onClick(e);
}
};
const rx = ((x * 2 * zoom) - zoom) - 3;
const ry = ((y * 2 * zoom) - zoom) - 3;
const rx = x * 2 * zoom - zoom - 3;
const ry = y * 2 * zoom - zoom - 3;
return (
<div>
<Box
position="absolute"
className="NanoMap__marker"
lineHeight="0"
bottom={ry + "px"}
left={rx + "px"}
bottom={ry + 'px'}
left={rx + 'px'}
onMouseDown={handleOnClick}>
<Icon
name={icon}
color={color}
fontSize="6px"
/>
<Icon name={icon} color={color} fontSize="6px" />
<Tooltip content={tooltip} />
</Box>
</div>
@@ -199,7 +192,7 @@ const NanoMapZoomer = (props, context) => {
minValue="1"
maxValue="8"
stepPixelSize="10"
format={v => v + "x"}
format={(v) => v + 'x'}
value={props.zoom}
onDrag={(e, v) => props.onZoom(e, v)}
/>
@@ -207,14 +200,15 @@ const NanoMapZoomer = (props, context) => {
<LabeledList.Item label="Z-Level">
{data.map_levels
.sort((a, b) => Number(a) - Number(b))
.map(level => (
.map((level) => (
<Button
key={level}
selected={~~level === ~~config.mapZLevel}
content={level}
onClick={() => {
act("setZLevel", { "mapZLevel": level });
}} />
act('setZLevel', { 'mapZLevel': level });
}}
/>
))}
</LabeledList.Item>
</LabeledList>
+4 -11
View File
@@ -7,16 +7,8 @@
import { classes, pureComponentHooks } from 'common/react';
import { Box } from './Box';
export const NoticeBox = props => {
const {
className,
color,
info,
warning,
success,
danger,
...rest
} = props;
export const NoticeBox = (props) => {
const { className, color, info, warning, success, danger, ...rest } = props;
return (
<Box
className={classes([
@@ -27,7 +19,8 @@ export const NoticeBox = props => {
danger && 'NoticeBox--type--danger',
className,
])}
{...rest} />
{...rest}
/>
);
};
+39 -63
View File
@@ -35,13 +35,17 @@ export class NumberInput extends Component {
suppressingFlicker: true,
});
clearTimeout(this.flickerTimer);
this.flickerTimer = setTimeout(() => this.setState({
suppressingFlicker: false,
}), suppressFlicker);
this.flickerTimer = setTimeout(
() =>
this.setState({
suppressingFlicker: false,
}),
suppressFlicker
);
}
};
this.handleDragStart = e => {
this.handleDragStart = (e) => {
const { value } = this.props;
const { editing } = this.state;
if (editing) {
@@ -71,38 +75,31 @@ export class NumberInput extends Component {
document.addEventListener('mouseup', this.handleDragEnd);
};
this.handleDragMove = e => {
this.handleDragMove = (e) => {
const { minValue, maxValue, step, stepPixelSize } = this.props;
this.setState(prevState => {
this.setState((prevState) => {
const state = { ...prevState };
const offset = state.origin - e.screenY;
if (prevState.dragging) {
const stepOffset = Number.isFinite(minValue)
? minValue % step
: 0;
const stepOffset = Number.isFinite(minValue) ? minValue % step : 0;
// Translate mouse movement to value
// Give it some headroom (by increasing clamp range by 1 step)
state.internalValue = clamp(
state.internalValue + offset * step / stepPixelSize,
state.internalValue + (offset * step) / stepPixelSize,
minValue - step,
maxValue + step);
maxValue + step
);
// Clamp the final value
state.value = clamp(
state.internalValue
- state.internalValue % step
+ stepOffset,
minValue,
maxValue);
state.value = clamp(state.internalValue - (state.internalValue % step) + stepOffset, minValue, maxValue);
state.origin = e.screenY;
}
else if (Math.abs(offset) > 4) {
} else if (Math.abs(offset) > 4) {
state.dragging = true;
}
return state;
});
};
this.handleDragEnd = e => {
this.handleDragEnd = (e) => {
const { onChange, onDrag } = this.props;
const { dragging, value, internalValue } = this.state;
document.body.style['pointer-events'] = 'auto';
@@ -123,8 +120,7 @@ export class NumberInput extends Component {
if (onDrag) {
onDrag(e, value);
}
}
else if (this.inputRef) {
} else if (this.inputRef) {
const input = this.inputRef.current;
input.value = internalValue;
// IE8: Dies when trying to focus a hidden element
@@ -132,19 +128,13 @@ export class NumberInput extends Component {
try {
input.focus();
input.select();
}
catch {}
} catch {}
}
};
}
render() {
const {
dragging,
editing,
value: intermediateValue,
suppressingFlicker,
} = this.state;
const { dragging, editing, value: intermediateValue, suppressingFlicker } = this.state;
const {
className,
fluid,
@@ -166,29 +156,21 @@ export class NumberInput extends Component {
displayValue = intermediateValue;
}
// IE8: Use an "unselectable" prop because "user-select" doesn't work.
const renderContentElement = value => (
<div
className="NumberInput__content"
unselectable={Byond.IS_LTE_IE8}>
const renderContentElement = (value) => (
<div className="NumberInput__content" unselectable={Byond.IS_LTE_IE8}>
{value + (unit ? ' ' + unit : '')}
</div>
);
const contentElement = (animated && !dragging && !suppressingFlicker && (
<AnimatedNumber
value={displayValue}
format={format}>
{renderContentElement}
</AnimatedNumber>
) || (
renderContentElement(format ? format(displayValue) : displayValue)
));
const contentElement =
(animated && !dragging && !suppressingFlicker && (
<AnimatedNumber value={displayValue} format={format}>
{renderContentElement}
</AnimatedNumber>
)) ||
renderContentElement(format ? format(displayValue) : displayValue);
return (
<Box
className={classes([
'NumberInput',
fluid && 'NumberInput--fluid',
className,
])}
className={classes(['NumberInput', fluid && 'NumberInput--fluid', className])}
minWidth={width}
minHeight={height}
lineHeight={lineHeight}
@@ -198,10 +180,9 @@ export class NumberInput extends Component {
<div
className="NumberInput__bar"
style={{
height: clamp(
(displayValue - minValue) / (maxValue - minValue) * 100,
0, 100) + '%',
}} />
height: clamp(((displayValue - minValue) / (maxValue - minValue)) * 100, 0, 100) + '%',
}}
/>
</div>
{contentElement}
<input
@@ -213,14 +194,11 @@ export class NumberInput extends Component {
'line-height': lineHeight,
'font-size': fontSize,
}}
onBlur={e => {
onBlur={(e) => {
if (!editing) {
return;
}
const value = clamp(
parseFloat(e.target.value),
minValue,
maxValue);
const value = clamp(parseFloat(e.target.value), minValue, maxValue);
if (Number.isNaN(value)) {
this.setState({
editing: false,
@@ -239,12 +217,9 @@ export class NumberInput extends Component {
onDrag(e, value);
}
}}
onKeyDown={e => {
onKeyDown={(e) => {
if (e.keyCode === 13) {
const value = clamp(
parseFloat(e.target.value),
minValue,
maxValue);
const value = clamp(parseFloat(e.target.value), minValue, maxValue);
if (Number.isNaN(value)) {
this.setState({
editing: false,
@@ -270,7 +245,8 @@ export class NumberInput extends Component {
});
return;
}
}} />
}}
/>
</Box>
);
}
+2 -11
View File
@@ -47,11 +47,7 @@ export class Popper extends Component<PopperProps> {
return;
}
this.popperInstance = createPopper(
domNode,
this.renderedContent,
options
);
this.popperInstance = createPopper(domNode, this.renderedContent, options);
});
}
@@ -69,12 +65,7 @@ export class Popper extends Component<PopperProps> {
renderPopperContent(callback: () => void) {
// `render` errors when given false, so we convert it to `null`,
// which is supported.
render(
this.props.popperContent || null,
this.renderedContent,
callback,
this.context,
);
render(this.props.popperContent || null, this.renderedContent, callback, this.context);
}
render() {
+6 -20
View File
@@ -8,22 +8,11 @@ import { clamp01, scale, keyOfMatchingRange, toFixed } from 'common/math';
import { classes, pureComponentHooks } from 'common/react';
import { computeBoxClassName, computeBoxProps } from './Box';
export const ProgressBar = props => {
const {
className,
value,
minValue = 0,
maxValue = 1,
color,
ranges = {},
children,
...rest
} = props;
export const ProgressBar = (props) => {
const { className, value, minValue = 0, maxValue = 1, color, ranges = {}, children, ...rest } = props;
const scaledValue = scale(value, minValue, maxValue);
const hasContent = children !== undefined;
const effectiveColor = color
|| keyOfMatchingRange(value, ranges)
|| 'default';
const effectiveColor = color || keyOfMatchingRange(value, ranges) || 'default';
return (
<div
className={classes([
@@ -37,12 +26,9 @@ export const ProgressBar = props => {
className="ProgressBar__fill ProgressBar__fill--animated"
style={{
width: clamp01(scaledValue) * 100 + '%',
}} />
<div className="ProgressBar__content">
{hasContent
? children
: toFixed(scaledValue * 100) + '%'}
</div>
}}
/>
<div className="ProgressBar__content">{hasContent ? children : toFixed(scaledValue * 100) + '%'}</div>
</div>
);
};
@@ -131,12 +131,7 @@ export class RestrictedInput extends Component {
const { className, fluid, monospace, ...rest } = boxProps;
return (
<Box
className={classes([
'Input',
fluid && 'Input--fluid',
monospace && 'Input--monospace',
className,
])}
className={classes(['Input', fluid && 'Input--fluid', monospace && 'Input--monospace', className])}
{...rest}>
<div className="Input__baseline">.</div>
<input
+22 -65
View File
@@ -9,41 +9,23 @@ import { classes } from 'common/react';
import { AnimatedNumber } from './AnimatedNumber';
import { Box, computeBoxClassName, computeBoxProps } from './Box';
export const RoundGauge = props => {
export const RoundGauge = (props) => {
// Support for IE8 is for losers sorry B)
if (Byond.IS_LTE_IE8) {
return (
<AnimatedNumber {...props} />
);
return <AnimatedNumber {...props} />;
}
const {
value,
minValue = 1,
maxValue = 1,
ranges,
alertAfter,
format,
size = 1,
className,
style,
...rest
} = props;
const { value, minValue = 1, maxValue = 1, ranges, alertAfter, format, size = 1, className, style, ...rest } = props;
const scaledValue = scale(
value,
minValue,
maxValue);
const scaledValue = scale(value, minValue, maxValue);
const clampedValue = clamp01(scaledValue);
let scaledRanges = ranges ? {} : { "primary": [0, 1] };
if (ranges)
{ Object.keys(ranges).forEach(x => {
const range = ranges[x];
scaledRanges[x] = [
scale(range[0], minValue, maxValue),
scale(range[1], minValue, maxValue),
];
}); }
let scaledRanges = ranges ? {} : { 'primary': [0, 1] };
if (ranges) {
Object.keys(ranges).forEach((x) => {
const range = ranges[x];
scaledRanges[x] = [scale(range[0], minValue, maxValue), scale(range[1], minValue, maxValue)];
});
}
let alertColor = null;
if (alertAfter < value) {
@@ -53,11 +35,7 @@ export const RoundGauge = props => {
return (
<Box inline>
<div
className={classes([
'RoundGauge',
className,
computeBoxClassName(rest),
])}
className={classes(['RoundGauge', className, computeBoxClassName(rest)])}
{...computeBoxProps({
style: {
'font-size': size + 'em',
@@ -65,22 +43,14 @@ export const RoundGauge = props => {
},
...rest,
})}>
<svg
viewBox="0 0 100 50">
<svg viewBox="0 0 100 50">
{alertAfter && (
<g className={classes([
'RoundGauge__alert',
alertColor ? `active RoundGauge__alert--${alertColor}` : '',
])}>
<g className={classes(['RoundGauge__alert', alertColor ? `active RoundGauge__alert--${alertColor}` : ''])}>
<path d="M48.211,14.578C48.55,13.9 49.242,13.472 50,13.472C50.758,13.472 51.45,13.9 51.789,14.578C54.793,20.587 60.795,32.589 63.553,38.106C63.863,38.726 63.83,39.462 63.465,40.051C63.101,40.641 62.457,41 61.764,41C55.996,41 44.004,41 38.236,41C37.543,41 36.899,40.641 36.535,40.051C36.17,39.462 36.137,38.726 36.447,38.106C39.205,32.589 45.207,20.587 48.211,14.578ZM50,34.417C51.426,34.417 52.583,35.574 52.583,37C52.583,38.426 51.426,39.583 50,39.583C48.574,39.583 47.417,38.426 47.417,37C47.417,35.574 48.574,34.417 50,34.417ZM50,32.75C50,32.75 53,31.805 53,22.25C53,20.594 51.656,19.25 50,19.25C48.344,19.25 47,20.594 47,22.25C47,31.805 50,32.75 50,32.75Z" />
</g>
)}
<g>
<circle
className="RoundGauge__ringTrack"
cx="50"
cy="50"
r="45" />
<circle className="RoundGauge__ringTrack" cx="50" cy="50" r="45" />
</g>
<g>
{Object.keys(scaledRanges).map((x, i) => {
@@ -90,36 +60,23 @@ export const RoundGauge = props => {
className={`RoundGauge__ringFill RoundGauge--color--${x}`}
key={i}
style={{
'stroke-dashoffset': (
Math.max((2.0 - (col_ranges[1] - col_ranges[0]))
* Math.PI * 50, 0)
),
'stroke-dashoffset': Math.max((2.0 - (col_ranges[1] - col_ranges[0])) * Math.PI * 50, 0),
}}
transform={`rotate(${180 + 180 * col_ranges[0]} 50 50)`}
cx="50"
cy="50"
r="45" />
r="45"
/>
);
})}
</g>
<g
className="RoundGauge__needle"
transform={`rotate(${clampedValue * 180 - 90} 50 50)`}>
<polygon
className="RoundGauge__needleLine"
points="46,50 50,0 54,50" />
<circle
className="RoundGauge__needleMiddle"
cx="50"
cy="50"
r="8" />
<g className="RoundGauge__needle" transform={`rotate(${clampedValue * 180 - 90} 50 50)`}>
<polygon className="RoundGauge__needleLine" points="46,50 50,0 54,50" />
<circle className="RoundGauge__needleMiddle" cx="50" cy="50" r="8" />
</g>
</svg>
</div>
<AnimatedNumber
value={value}
format={format}
size={size} />
<AnimatedNumber value={value} format={format} size={size} />
</Box>
);
};
+9 -11
View File
@@ -84,21 +84,19 @@ export class Section extends Component<SectionProps> {
{...computeBoxProps(rest)}>
{hasTitle && (
<div className="Section__title">
<span className="Section__titleText">
{title}
</span>
<div className="Section__buttons">
{buttons}
</div>
<span className="Section__titleText">{title}</span>
<div className="Section__buttons">{buttons}</div>
</div>
)}
<div className="Section__rest">
{/* Vorestation Edit Start */}
<div ref={this.scrollableRef} className={classes([
"Section__content",
!!stretchContents && "Section__content--stretchContents",
!!noTopPadding && "Section__content--noTopPadding",
])}>
<div
ref={this.scrollableRef}
className={classes([
'Section__content',
!!stretchContents && 'Section__content--stretchContents',
!!noTopPadding && 'Section__content--noTopPadding',
])}>
{children}
</div>
{/* Vorestation Edit End */}
+17 -49
View File
@@ -10,12 +10,10 @@ import { computeBoxClassName, computeBoxProps } from './Box';
import { DraggableControl } from './DraggableControl';
import { NumberInput } from './NumberInput';
export const Slider = props => {
export const Slider = (props) => {
// IE8: I don't want to support a yet another component on IE8.
if (Byond.IS_LTE_IE8) {
return (
<NumberInput {...props} />
);
return <NumberInput {...props} />;
}
const {
// Draggable props (passthrough)
@@ -55,33 +53,13 @@ export const Slider = props => {
unit,
value,
}}>
{control => {
const {
dragging,
editing,
value,
displayValue,
displayElement,
inputElement,
handleDragStart,
} = control;
const hasFillValue = fillValue !== undefined
&& fillValue !== null;
const scaledValue = scale(
value,
minValue,
maxValue);
const scaledFillValue = scale(
fillValue ?? displayValue,
minValue,
maxValue);
const scaledDisplayValue = scale(
displayValue,
minValue,
maxValue);
const effectiveColor = color
|| keyOfMatchingRange(fillValue ?? value, ranges)
|| 'default';
{(control) => {
const { dragging, editing, value, displayValue, displayElement, inputElement, handleDragStart } = control;
const hasFillValue = fillValue !== undefined && fillValue !== null;
const scaledValue = scale(value, minValue, maxValue);
const scaledFillValue = scale(fillValue ?? displayValue, minValue, maxValue);
const scaledDisplayValue = scale(displayValue, minValue, maxValue);
const effectiveColor = color || keyOfMatchingRange(fillValue ?? value, ranges) || 'default';
return (
<div
className={classes([
@@ -94,20 +72,18 @@ export const Slider = props => {
{...computeBoxProps(rest)}
onMouseDown={handleDragStart}>
<div
className={classes([
'ProgressBar__fill',
hasFillValue && 'ProgressBar__fill--animated',
])}
className={classes(['ProgressBar__fill', hasFillValue && 'ProgressBar__fill--animated'])}
style={{
width: clamp01(scaledFillValue) * 100 + '%',
opacity: 0.4,
}} />
}}
/>
<div
className="ProgressBar__fill"
style={{
width: clamp01(Math.min(scaledFillValue, scaledDisplayValue))
* 100 + '%',
}} />
width: clamp01(Math.min(scaledFillValue, scaledDisplayValue)) * 100 + '%',
}}
/>
<div
className="Slider__cursorOffset"
style={{
@@ -115,17 +91,9 @@ export const Slider = props => {
}}>
<div className="Slider__cursor" />
<div className="Slider__pointer" />
{dragging && (
<div className="Slider__popupValue">
{displayElement}
</div>
)}
</div>
<div className="ProgressBar__content">
{hasContent
? children
: displayElement}
{dragging && <div className="Slider__popupValue">{displayElement}</div>}
</div>
<div className="ProgressBar__content">{hasContent ? children : displayElement}</div>
{inputElement}
</div>
);
+8 -21
View File
@@ -20,31 +20,22 @@ export const Stack = (props: StackProps) => {
className={classes([
'Stack',
fill && 'Stack--fill',
vertical
? 'Stack--vertical'
: 'Stack--horizontal',
vertical ? 'Stack--vertical' : 'Stack--horizontal',
className,
])}
direction={vertical ? 'column' : 'row'}
{...rest} />
{...rest}
/>
);
};
type StackItemProps = FlexProps & {
innerRef?: RefObject<HTMLDivElement>,
innerRef?: RefObject<HTMLDivElement>;
};
const StackItem = (props: StackItemProps) => {
const { className, innerRef, ...rest } = props;
return (
<Flex.Item
className={classes([
'Stack__item',
className,
])}
ref={innerRef}
{...rest} />
);
return <Flex.Item className={classes(['Stack__item', className])} ref={innerRef} {...rest} />;
};
Stack.Item = StackItem;
@@ -57,13 +48,9 @@ const StackDivider = (props: StackDividerProps) => {
const { className, hidden, ...rest } = props;
return (
<Flex.Item
className={classes([
'Stack__item',
'Stack__divider',
hidden && 'Stack__divider--hidden',
className,
])}
{...rest} />
className={classes(['Stack__item', 'Stack__divider', hidden && 'Stack__divider--hidden', className])}
{...rest}
/>
);
};
+13 -37
View File
@@ -7,58 +7,33 @@
import { classes, pureComponentHooks } from 'common/react';
import { computeBoxClassName, computeBoxProps } from './Box';
export const Table = props => {
const {
className,
collapsing,
children,
...rest
} = props;
export const Table = (props) => {
const { className, collapsing, children, ...rest } = props;
return (
<table
className={classes([
'Table',
collapsing && 'Table--collapsing',
className,
computeBoxClassName(rest),
])}
className={classes(['Table', collapsing && 'Table--collapsing', className, computeBoxClassName(rest)])}
{...computeBoxProps(rest)}>
<tbody>
{children}
</tbody>
<tbody>{children}</tbody>
</table>
);
};
Table.defaultHooks = pureComponentHooks;
export const TableRow = props => {
const {
className,
header,
...rest
} = props;
export const TableRow = (props) => {
const { className, header, ...rest } = props;
return (
<tr
className={classes([
'Table__row',
header && 'Table__row--header',
className,
computeBoxClassName(props),
])}
{...computeBoxProps(rest)} />
className={classes(['Table__row', header && 'Table__row--header', className, computeBoxClassName(props)])}
{...computeBoxProps(rest)}
/>
);
};
TableRow.defaultHooks = pureComponentHooks;
export const TableCell = props => {
const {
className,
collapsing,
header,
...rest
} = props;
export const TableCell = (props) => {
const { className, collapsing, header, ...rest } = props;
return (
<td
className={classes([
@@ -68,7 +43,8 @@ export const TableCell = props => {
className,
computeBoxClassName(props),
])}
{...computeBoxProps(rest)} />
{...computeBoxProps(rest)}
/>
);
};
+13 -40
View File
@@ -8,22 +8,13 @@ import { canRender, classes } from 'common/react';
import { computeBoxClassName, computeBoxProps } from './Box';
import { Icon } from './Icon';
export const Tabs = props => {
const {
className,
vertical,
fill,
fluid,
children,
...rest
} = props;
export const Tabs = (props) => {
const { className, vertical, fill, fluid, children, ...rest } = props;
return (
<div
className={classes([
'Tabs',
vertical
? 'Tabs--vertical'
: 'Tabs--horizontal',
vertical ? 'Tabs--vertical' : 'Tabs--horizontal',
fill && 'Tabs--fill',
fluid && 'Tabs--fluid',
className,
@@ -35,17 +26,8 @@ export const Tabs = props => {
);
};
const Tab = props => {
const {
className,
selected,
color,
icon,
leftSlot,
rightSlot,
children,
...rest
} = props;
const Tab = (props) => {
const { className, selected, color, icon, leftSlot, rightSlot, children, ...rest } = props;
return (
<div
className={classes([
@@ -57,23 +39,14 @@ const Tab = props => {
...computeBoxClassName(rest),
])}
{...computeBoxProps(rest)}>
{canRender(leftSlot) && (
<div className="Tab__left">
{leftSlot}
</div>
) || !!icon && (
<div className="Tab__left">
<Icon name={icon} />
</div>
)}
<div className="Tab__text">
{children}
</div>
{canRender(rightSlot) && (
<div className="Tab__right">
{rightSlot}
</div>
)}
{(canRender(leftSlot) && <div className="Tab__left">{leftSlot}</div>) ||
(!!icon && (
<div className="Tab__left">
<Icon name={icon} />
</div>
))}
<div className="Tab__text">{children}</div>
{canRender(rightSlot) && <div className="Tab__right">{rightSlot}</div>}
</div>
);
};
+13 -27
View File
@@ -19,10 +19,8 @@ export class TextArea extends Component {
this.state = {
editing: false,
};
const {
dontUseTabForIndent = false,
} = props;
this.handleOnInput = e => {
const { dontUseTabForIndent = false } = props;
this.handleOnInput = (e) => {
const { editing } = this.state;
const { onInput } = this.props;
if (!editing) {
@@ -32,7 +30,7 @@ export class TextArea extends Component {
onInput(e, e.target.value);
}
};
this.handleOnChange = e => {
this.handleOnChange = (e) => {
const { editing } = this.state;
const { onChange } = this.props;
if (editing) {
@@ -42,7 +40,7 @@ export class TextArea extends Component {
onChange(e, e.target.value);
}
};
this.handleKeyPress = e => {
this.handleKeyPress = (e) => {
const { editing } = this.state;
const { onKeyPress } = this.props;
if (!editing) {
@@ -52,7 +50,7 @@ export class TextArea extends Component {
onKeyPress(e, e.target.value);
}
};
this.handleKeyDown = e => {
this.handleKeyDown = (e) => {
const { editing } = this.state;
const { onChange, onInput, onEnter, onKeyDown } = this.props;
if (e.keyCode === KEY_ENTER) {
@@ -96,21 +94,18 @@ export class TextArea extends Component {
if (keyCode === KEY_TAB) {
e.preventDefault();
const { value, selectionStart, selectionEnd } = e.target;
e.target.value = (
value.substring(0, selectionStart) + "\t"
+ value.substring(selectionEnd)
);
e.target.value = value.substring(0, selectionStart) + '\t' + value.substring(selectionEnd);
e.target.selectionEnd = selectionStart + 1;
}
}
};
this.handleFocus = e => {
this.handleFocus = (e) => {
const { editing } = this.state;
if (!editing) {
this.setEditing(true);
}
};
this.handleBlur = e => {
this.handleBlur = (e) => {
const { editing } = this.state;
const { onChange } = this.props;
if (editing) {
@@ -137,7 +132,7 @@ export class TextArea extends Component {
const prevValue = prevProps.value;
const nextValue = this.props.value;
const input = this.textareaRef.current;
if (input && typeof nextValue === "string" && prevValue !== nextValue) {
if (input && typeof nextValue === 'string' && prevValue !== nextValue) {
input.value = toInputValue(nextValue);
}
}
@@ -166,19 +161,9 @@ export class TextArea extends Component {
...boxProps
} = this.props;
// Box props
const {
className,
fluid,
...rest
} = boxProps;
const { className, fluid, ...rest } = boxProps;
return (
<Box
className={classes([
'TextArea',
fluid && 'TextArea--fluid',
className,
])}
{...rest}>
<Box className={classes(['TextArea', fluid && 'TextArea--fluid', className])} {...rest}>
<textarea
ref={this.textareaRef}
className="TextArea__textarea"
@@ -189,7 +174,8 @@ export class TextArea extends Component {
onInput={this.handleOnInput}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
maxLength={maxLength} />
maxLength={maxLength}
/>
</Box>
);
}
+3 -5
View File
@@ -2,10 +2,8 @@ import { formatTime } from '../format';
import { Component } from 'inferno';
// AnimatedNumber Copypaste
const isSafeNumber = value => {
return typeof value === 'number'
&& Number.isFinite(value)
&& !Number.isNaN(value);
const isSafeNumber = (value) => {
return typeof value === 'number' && Number.isFinite(value) && !Number.isNaN(value);
};
export class TimeDisplay extends Component {
@@ -36,7 +34,7 @@ export class TimeDisplay extends Component {
this.last_seen_value = this.props.value;
current = this.props.value;
}
const mod = this.props.auto === "up" ? 10 : -10; // Time down by default.
const mod = this.props.auto === 'up' ? 10 : -10; // Time down by default.
const value = Math.max(0, current + mod); // one sec tick
this.setState({ value });
}
+14 -13
View File
@@ -1,24 +1,25 @@
import { Placement } from '@popperjs/core';
import { Component, findDOMfromVNode, InfernoNode } from 'inferno';
import { Popper } from "./Popper";
import { Popper } from './Popper';
const DEFAULT_PLACEMENT = "top";
const DEFAULT_PLACEMENT = 'top';
type TooltipProps = {
children?: InfernoNode;
content: InfernoNode;
position?: Placement,
position?: Placement;
};
type TooltipState = {
hovered: boolean;
};
const DISABLE_EVENT_LISTENERS = [{
name: "eventListeners",
enabled: false,
}];
const DISABLE_EVENT_LISTENERS = [
{
name: 'eventListeners',
enabled: false,
},
];
export class Tooltip extends Component<TooltipProps, TooltipState> {
state = {
@@ -40,13 +41,13 @@ export class Tooltip extends Component<TooltipProps, TooltipState> {
return;
}
domNode.addEventListener("mouseenter", () => {
domNode.addEventListener('mouseenter', () => {
this.setState({
hovered: true,
});
});
domNode.addEventListener("mouseleave", () => {
domNode.addEventListener('mouseleave', () => {
this.setState({
hovered: false,
});
@@ -57,7 +58,7 @@ export class Tooltip extends Component<TooltipProps, TooltipState> {
return (
<Popper
options={{
placement: this.props.position || "auto",
placement: this.props.position || 'auto',
modifiers: DISABLE_EVENT_LISTENERS,
}}
popperContent={
@@ -70,8 +71,8 @@ export class Tooltip extends Component<TooltipProps, TooltipState> {
</div>
}
additionalStyles={{
"pointer-events": "none",
"z-index": 2,
'pointer-events': 'none',
'z-index': 2,
}}>
{this.props.children}
</Popper>
@@ -1,7 +1,7 @@
import { Component, createRef } from "inferno";
import { Component, createRef } from 'inferno';
export class TrackOutsideClicks extends Component<{
onOutsideClick: () => void,
onOutsideClick: () => void;
}> {
ref = createRef<HTMLDivElement>();
@@ -10,11 +10,11 @@ export class TrackOutsideClicks extends Component<{
this.handleOutsideClick = this.handleOutsideClick.bind(this);
document.addEventListener("click", this.handleOutsideClick);
document.addEventListener('click', this.handleOutsideClick);
}
componentWillUnmount() {
document.removeEventListener("click", this.handleOutsideClick);
document.removeEventListener('click', this.handleOutsideClick);
}
handleOutsideClick(event: MouseEvent) {
@@ -28,10 +28,6 @@ export class TrackOutsideClicks extends Component<{
}
render() {
return (
<div ref={this.ref}>
{this.props.children}
</div>
);
return <div ref={this.ref}>{this.props.children}</div>;
}
}
+71 -76
View File
@@ -25,16 +25,16 @@ export const COLORS = {
},
// VOREStation Addition begin
manifest: {
command: "#3333FF",
security: "#8e0000",
medical: "#006600",
engineering: "#b27300",
science: "#a65ba6",
cargo: "#bb9040",
planetside: "#555555",
civilian: "#a32800",
miscellaneous: "#666666",
silicon: "#222222",
command: '#3333FF',
security: '#8e0000',
medical: '#006600',
engineering: '#b27300',
science: '#a65ba6',
cargo: '#bb9040',
planetside: '#555555',
civilian: '#a32800',
miscellaneous: '#666666',
silicon: '#222222',
},
// VOREStation Addition end
// Damage type colors
@@ -46,8 +46,8 @@ export const COLORS = {
},
// reagent / chemistry related colours
reagent: {
acidicbuffer: "#fbc314",
basicbuffer: "#3853a4",
acidicbuffer: '#fbc314',
basicbuffer: '#3853a4',
},
};
@@ -78,94 +78,94 @@ export const CSS_COLORS = [
// go use /client/verb/generate_tgui_radio_constants() in communications.dm.
export const RADIO_CHANNELS = [
{
"name": "Mercenary",
"freq": 1213,
"color": "#6D3F40",
'name': 'Mercenary',
'freq': 1213,
'color': '#6D3F40',
},
{
"name": "Raider",
"freq": 1277,
"color": "#6D3F40",
'name': 'Raider',
'freq': 1277,
'color': '#6D3F40',
},
{
"name": "Special Ops",
"freq": 1341,
"color": "#5C5C8A",
'name': 'Special Ops',
'freq': 1341,
'color': '#5C5C8A',
},
{
"name": "AI Private",
"freq": 1343,
"color": "#FF00FF",
'name': 'AI Private',
'freq': 1343,
'color': '#FF00FF',
},
{
"name": "Response Team",
"freq": 1345,
"color": "#5C5C8A",
'name': 'Response Team',
'freq': 1345,
'color': '#5C5C8A',
},
{
"name": "Supply",
"freq": 1347,
"color": "#5F4519",
'name': 'Supply',
'freq': 1347,
'color': '#5F4519',
},
{
"name": "Service",
"freq": 1349,
"color": "#6eaa2c",
'name': 'Service',
'freq': 1349,
'color': '#6eaa2c',
},
{
"name": "Science",
"freq": 1351,
"color": "#993399",
'name': 'Science',
'freq': 1351,
'color': '#993399',
},
{
"name": "Command",
"freq": 1353,
"color": "#193A7A",
'name': 'Command',
'freq': 1353,
'color': '#193A7A',
},
{
"name": "Medical",
"freq": 1355,
"color": "#008160",
'name': 'Medical',
'freq': 1355,
'color': '#008160',
},
{
"name": "Engineering",
"freq": 1357,
"color": "#A66300",
'name': 'Engineering',
'freq': 1357,
'color': '#A66300',
},
{
"name": "Security",
"freq": 1359,
"color": "#A30000",
'name': 'Security',
'freq': 1359,
'color': '#A30000',
},
{
"name": "Explorer",
"freq": 1361,
"color": "#555555",
'name': 'Explorer',
'freq': 1361,
'color': '#555555',
},
{
"name": "Talon",
"freq": 1363,
"color": "#555555",
'name': 'Talon',
'freq': 1363,
'color': '#555555',
},
{
"name": "Common",
"freq": 1459,
"color": "#008000",
'name': 'Common',
'freq': 1459,
'color': '#008000',
},
{
"name": "Entertainment",
"freq": 1461,
"color": "#339966",
'name': 'Entertainment',
'freq': 1461,
'color': '#339966',
},
{
"name": "Security(I)",
"freq": 1475,
"color": "#008000",
'name': 'Security(I)',
'freq': 1475,
'color': '#008000',
},
{
"name": "Medical(I)",
"freq": 1485,
"color": "#008000",
'name': 'Medical(I)',
'freq': 1485,
'color': '#008000',
},
];
@@ -278,22 +278,17 @@ const GASES = [
export const getGasLabel = (gasId, fallbackValue) => {
const gasSearchString = String(gasId).toLowerCase();
const gas = GASES.find(gas => gas.id === gasSearchString
|| gas.name.toLowerCase() === gasSearchString);
return gas && gas.label
|| fallbackValue
|| gasId;
const gas = GASES.find((gas) => gas.id === gasSearchString || gas.name.toLowerCase() === gasSearchString);
return (gas && gas.label) || fallbackValue || gasId;
};
export const getGasColor = gasId => {
export const getGasColor = (gasId) => {
const gasSearchString = String(gasId).toLowerCase();
const gas = GASES.find(gas => gas.id === gasSearchString
|| gas.name.toLowerCase() === gasSearchString);
const gas = GASES.find((gas) => gas.id === gasSearchString || gas.name.toLowerCase() === gasSearchString);
return gas && gas.color;
};
// VOREStation Addition start
/** 0.0 Degrees Celsius in Kelvin */
export const T0C = 273.15;
// VOREStation Addition end
// VOREStation Addition end

Some files were not shown because too many files have changed in this diff Show More