code:
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

repo_name: AnalWerewolf/sundown

license: mit


code:
/.yarn/**
/**/node_modules
/**/*.bundle.*
/**/*.chunk.*
/**/*.hot-update.*
/packages/inferno/**


code:
rules:
  # radar/cognitive-complexity: error
  radar/max-switch-cases: error
  radar/no-all-duplicated-branches: error
  radar/no-collapsible-if: error
  radar/no-collection-size-mischeck: error
  radar/no-duplicate-string: error
  radar/no-duplicated-branches: error
  radar/no-element-overwrite: error
  radar/no-extra-arguments: error
  radar/no-identical-conditions: error
  radar/no-identical-expressions: error
  radar/no-identical-functions: error
  radar/no-inverted-boolean-check: error
  radar/no-one-iteration-loop: error
  radar/no-redundant-boolean: error
  radar/no-redundant-jump: error
  radar/no-same-line-conditional: error
  radar/no-small-switch: error
  radar/no-unused-collection: error
  radar/no-use-of-empty-return-value: error
  radar/no-useless-catch: error
  radar/prefer-immediate-return: error
  radar/prefer-object-literal: error
  radar/prefer-single-boolean-return: error
  radar/prefer-while: error


code:
root: true
parser: '@typescript-eslint/parser'
parserOptions:
  ecmaVersion: 2020
  sourceType: module
  ecmaFeatures:
    jsx: true
env:
  es6: true
  browser: true
  node: true
plugins:
  - radar
  - react
  - unused-imports
settings:
  react:
    version: '16.10'
rules:

  ## Possible Errors
  ## ----------------------------------------
  ## Enforce “for” loop update clause moving the counter in the right
  ## direction.
  # for-direction: error
  ## Enforce return statements in getters
  # getter-return: error
  ## Disallow using an async function as a Promise executor
  no-async-promise-executor: error
  ## Disallow await inside of loops
  # no-await-in-loop: error
  ## Disallow comparing against -0
  # no-compare-neg-zero: error
  ## Disallow assignment operators in conditional expressions
  no-cond-assign: error
  ## Disallow the use of console
  # no-console: error
  ## Disallow constant expressions in conditions
  # no-constant-condition: error
  ## Disallow control characters in regular expressions
  # no-control-regex: error
  ## Disallow the use of debugger
  no-debugger: error
  ## Disallow duplicate arguments in function definitions
  no-dupe-args: error
  ## Disallow duplicate keys in object literals
  no-dupe-keys: error
  ## Disallow duplicate case labels
  no-duplicate-case: error
  ## Disallow empty block statements
  # no-empty: error
  ## Disallow empty character classes in regular expressions
  no-empty-character-class: error
  ## Disallow reassigning exceptions in catch clauses
  no-ex-assign: error
  ## Disallow unnecessary boolean casts
  no-extra-boolean-cast: error
  ## Disallow unnecessary parentheses
  # no-extra-parens: warn
  ## Disallow unnecessary semicolons
  no-extra-semi: error
  ## Disallow reassigning function declarations
  no-func-assign: error
  ## Disallow assigning to imported bindings
  no-import-assign: error
  ## Disallow variable or function declarations in nested blocks
  no-inner-declarations: error
  ## Disallow invalid regular expression strings in RegExp constructors
  no-invalid-regexp: error
  ## Disallow irregular whitespace
  no-irregular-whitespace: error
  ## Disallow characters which are made with multiple code points in character
  ## class syntax
  no-misleading-character-class: error
  ## Disallow calling global object properties as functions
  no-obj-calls: error
  ## Disallow calling some Object.prototype methods directly on objects
  no-prototype-builtins: error
  ## Disallow multiple spaces in regular expressions
  no-regex-spaces: error
  ## Disallow sparse arrays
  no-sparse-arrays: error
  ## Disallow template literal placeholder syntax in regular strings
  no-template-curly-in-string: error
  ## Disallow confusing multiline expressions
  no-unexpected-multiline: error
  ## Disallow unreachable code after return, throw, continue, and break
  ## statements
  # no-unreachable: warn
  ## Disallow control flow statements in finally blocks
  no-unsafe-finally: error
  ## Disallow negating the left operand of relational operators
  no-unsafe-negation: error
  ## Disallow assignments that can lead to race conditions due to usage of
  ## await or yield
  # require-atomic-updates: error
  ## Require calls to isNaN() when checking for NaN
  use-isnan: error
  ## Enforce comparing typeof expressions against valid strings
  valid-typeof: error

  ## Best practices
  ## ----------------------------------------
  ## Enforce getter and setter pairs in objects and classes
  # accessor-pairs: error
  ## Enforce return statements in callbacks of array methods
  # array-callback-return: error
  ## Enforce the use of variables within the scope they are defined
  # block-scoped-var: error
  ## Enforce that class methods utilize this
  # class-methods-use-this: error
  ## Enforce a maximum cyclomatic complexity allowed in a program
  complexity: [error, { max: 50 }]
  ## Require return statements to either always or never specify values
  # consistent-return: error
  ## Enforce consistent brace style for all control statements
  curly: [error, multi-line]
  ## Require default cases in switch statements
  # default-case: error
  ## Enforce default parameters to be last
  # default-param-last: error
  ## Enforce consistent newlines before and after dots
  dot-location: [error, property]
  ## Enforce dot notation whenever possible
  # dot-notation: error
  ## Require the use of === and !==
  eqeqeq: [error, always]
  ## Require for-in loops to include an if statement
  # guard-for-in: error
  ## Enforce a maximum number of classes per file
  # max-classes-per-file: error
  ## Disallow the use of alert, confirm, and prompt
  # no-alert: error
  ## Disallow the use of arguments.caller or arguments.callee
  # no-caller: error
  ## Disallow lexical declarations in case clauses
  no-case-declarations: error
  ## Disallow division operators explicitly at the beginning of regular
  ## expressions
  # no-div-regex: error
  ## Disallow else blocks after return statements in if statements
  # no-else-return: error
  ## Disallow empty functions
  # no-empty-function: error
  ## Disallow empty destructuring patterns
  no-empty-pattern: error
  ## Disallow null comparisons without type-checking operators
  # no-eq-null: error
  ## Disallow the use of eval()
  # no-eval: error
  ## Disallow extending native types
  # no-extend-native: error
  ## Disallow unnecessary calls to .bind()
  # no-extra-bind: error
  ## Disallow unnecessary labels
  # no-extra-label: error
  ## Disallow fallthrough of case statements
  no-fallthrough: error
  ## Disallow leading or trailing decimal points in numeric literals
  # no-floating-decimal: error
  ## Disallow assignments to native objects or read-only global variables
  no-global-assign: error
  ## Disallow shorthand type conversions
  # no-implicit-coercion: error
  ## Disallow variable and function declarations in the global scope
  # no-implicit-globals: error
  ## Disallow the use of eval()-like methods
  # no-implied-eval: error
  ## Disallow this keywords outside of classes or class-like objects
  # no-invalid-this: error
  ## Disallow the use of the __iterator__ property
  # no-iterator: error
  ## Disallow labeled statements
  # no-labels: error
  ## Disallow unnecessary nested blocks
  # no-lone-blocks: error
  ## Disallow function declarations that contain unsafe references inside
  ## loop statements
  # no-loop-func: error
  ## Disallow magic numbers
  # no-magic-numbers: error
  ## Disallow multiple spaces
  no-multi-spaces: warn
  ## Disallow multiline strings
  # no-multi-str: error
  ## Disallow new operators outside of assignments or comparisons
  # no-new: error
  ## Disallow new operators with the Function object
  # no-new-func: error
  ## Disallow new operators with the String, Number, and Boolean objects
  # no-new-wrappers: error
  ## Disallow octal literals
  no-octal: error
  ## Disallow octal escape sequences in string literals
  no-octal-escape: error
  ## Disallow reassigning function parameters
  # no-param-reassign: error
  ## Disallow the use of the __proto__ property
  # no-proto: error
  ## Disallow variable redeclaration
  no-redeclare: error
  ## Disallow certain properties on certain objects
  # no-restricted-properties: error
  ## Disallow assignment operators in return statements
  no-return-assign: error
  ## Disallow unnecessary return await
  # no-return-await: error
  ## Disallow javascript: urls
  # no-script-url: error
  ## Disallow assignments where both sides are exactly the same
  no-self-assign: error
  ## Disallow comparisons where both sides are exactly the same
  # no-self-compare: error
  ## Disallow comma operators
  no-sequences: error
  ## Disallow throwing literals as exceptions
  # no-throw-literal: error
  ## Disallow unmodified loop conditions
  # no-unmodified-loop-condition: error
  ## Disallow unused expressions
  # no-unused-expressions: error
  ## Disallow unused labels
  no-unused-labels: warn
  ## Disallow unnecessary calls to .call() and .apply()
  # no-useless-call: error
  ## Disallow unnecessary catch clauses
  # no-useless-catch: error
  ## Disallow unnecessary concatenation of literals or template literals
  # no-useless-concat: error
  ## Disallow unnecessary escape characters
  no-useless-escape: warn
  ## Disallow redundant return statements
  # no-useless-return: error
  ## Disallow void operators
  # no-void: error
  ## Disallow specified warning terms in comments
  # no-warning-comments: error
  ## Disallow with statements
  no-with: error
  ## Enforce using named capture group in regular expression
  # prefer-named-capture-group: error
  ## Require using Error objects as Promise rejection reasons
  # prefer-promise-reject-errors: error
  ## Disallow use of the RegExp constructor in favor of regular expression
  ## literals
  # prefer-regex-literals: error
  ## Enforce the consistent use of the radix argument when using parseInt()
  radix: error
  ## Disallow async functions which have no await expression
  # require-await: error
  ## Enforce the use of u flag on RegExp
  # require-unicode-regexp: error
  ## Require var declarations be placed at the top of their containing scope
  # vars-on-top: error
  ## Require parentheses around immediate function invocations
  # wrap-iife: error
  ## Require or disallow “Yoda” conditions
  # yoda: error

  ## Strict mode
  ## ----------------------------------------
  ## Require or disallow strict mode directives
  strict: error

  ## Variables
  ## ----------------------------------------
  ## Require or disallow initialization in variable declarations
  # init-declarations: error
  ## Disallow deleting variables
  no-delete-var: error
  ## Disallow labels that share a name with a variable
  # no-label-var: error
  ## Disallow specified global variables
  # no-restricted-globals: error
  ## Disallow variable declarations from shadowing variables declared in
  ## the outer scope
  # no-shadow: error
  ## Disallow identifiers from shadowing restricted names
  no-shadow-restricted-names: error
  ## Disallow the use of undeclared variables unless mentioned
  ## in /*global*/ comments
  ## NOTE: Pointless when TypeScript can check for this
  # no-undef: error
  ## Disallow initializing variables to undefined
  no-undef-init: error
  ## Disallow the use of undefined as an identifier
  # no-undefined: error
  ## Disallow unused variables
  # no-unused-vars: error
  ## Disallow the use of variables before they are defined
  # no-use-before-define: error

  ## Code style
  ## ----------------------------------------
  ## Enforce linebreaks after opening and before closing array brackets
  array-bracket-newline: [error, consistent]
  ## Enforce consistent spacing inside array brackets
  array-bracket-spacing: [error, never]
  ## Enforce line breaks after each array element
  # array-element-newline: error
  ## Disallow or enforce spaces inside of blocks after opening block and
  ## before closing block
  block-spacing: [error, always]
  ## Enforce consistent brace style for blocks
  # brace-style: [error, stroustrup, { allowSingleLine: false }]
  ## Enforce camelcase naming convention
  # camelcase: error
  ## Enforce or disallow capitalization of the first letter of a comment
  # capitalized-comments: error
  ## Require or disallow trailing commas
  comma-dangle: [error, {
    arrays: always-multiline,
    objects: always-multiline,
    imports: always-multiline,
    exports: always-multiline,
    functions: only-multiline, ## Optional on functions
  }]
  ## Enforce consistent spacing before and after commas
  comma-spacing: [error, { before: false, after: true }]
  ## Enforce consistent comma style
  comma-style: [error, last]
  ## Enforce consistent spacing inside computed property brackets
  computed-property-spacing: [error, never]
  ## Enforce consistent naming when capturing the current execution context
  # consistent-this: error
  ## Require or disallow newline at the end of files
  # eol-last: error
  ## Require or disallow spacing between function identifiers and their
  ## invocations
  func-call-spacing: [error, never]
  ## Require function names to match the name of the variable or property
  ## to which they are assigned
  # func-name-matching: error
  ## Require or disallow named function expressions
  # func-names: error
  ## Enforce the consistent use of either function declarations or expressions
  func-style: [error, expression]
  ## Enforce line breaks between arguments of a function call
  # function-call-argument-newline: error
  ## Enforce consistent line breaks inside function parentheses
  ## NOTE: This rule does not honor a newline on opening paren.
  # function-paren-newline: [error, never]
  ## Disallow specified identifiers
  # id-blacklist: error
  ## Enforce minimum and maximum identifier lengths
  # id-length: error
  ## Require identifiers to match a specified regular expression
  # id-match: error
  ## Enforce the location of arrow function bodies
  # implicit-arrow-linebreak: error
  ## Enforce consistent indentation
  indent: [error, 2, { SwitchCase: 1 }]
  ## Enforce the consistent use of either double or single quotes in JSX
  ## attributes
  jsx-quotes: [error, prefer-double]
  ## Enforce consistent spacing between keys and values in object literal
  ## properties
  key-spacing: [error, { beforeColon: false, afterColon: true }]
  ## Enforce consistent spacing before and after keywords
  keyword-spacing: [error, { before: true, after: true }]
  ## Enforce position of line comments
  # line-comment-position: error
  ## Enforce consistent linebreak style
  # linebreak-style: error
  ## Require empty lines around comments
  # lines-around-comment: error
  ## Require or disallow an empty line between class members
  # lines-between-class-members: error
  ## Enforce a maximum depth that blocks can be nested
  # max-depth: error
  ## Enforce a maximum line length
  max-len: [error, {
    code: 80,
    ## Ignore imports
    ignorePattern: '^(import\s.+\sfrom\s|.*require\()',
    ignoreUrls: true,
    ignoreRegExpLiterals: true,
    ignoreStrings: true,
  }]
  ## Enforce a maximum number of lines per file
  # max-lines: error
  ## Enforce a maximum number of line of code in a function
  # max-lines-per-function: error
  ## Enforce a maximum depth that callbacks can be nested
  # max-nested-callbacks: error
  ## Enforce a maximum number of parameters in function definitions
  # max-params: error
  ## Enforce a maximum number of statements allowed in function blocks
  # max-statements: error
  ## Enforce a maximum number of statements allowed per line
  # max-statements-per-line: error
  ## Enforce a particular style for multiline comments
  # multiline-comment-style: error
  ## Enforce newlines between operands of ternary expressions
  # multiline-ternary: [error, always-multiline]
  ## Require constructor names to begin with a capital letter
  # new-cap: error
  ## Enforce or disallow parentheses when invoking a constructor with no
  ## arguments
  # new-parens: error
  ## Require a newline after each call in a method chain
  # newline-per-chained-call: error
  ## Disallow Array constructors
  # no-array-constructor: error
  ## Disallow bitwise operators
  # no-bitwise: error
  ## Disallow continue statements
  # no-continue: error
  ## Disallow inline comments after code
  # no-inline-comments: error
  ## Disallow if statements as the only statement in else blocks
  # no-lonely-if: error
  ## Disallow mixed binary operators
  # no-mixed-operators: error
  ## Disallow mixed spaces and tabs for indentation
  no-mixed-spaces-and-tabs: error
  ## Disallow use of chained assignment expressions
  # no-multi-assign: error
  ## Disallow multiple empty lines
  # no-multiple-empty-lines: error
  ## Disallow negated conditions
  # no-negated-condition: error
  ## Disallow nested ternary expressions
  # no-nested-ternary: error
  ## Disallow Object constructors
  # no-new-object: error
  ## Disallow the unary operators ++ and --
  # no-plusplus: error
  ## Disallow specified syntax
  # no-restricted-syntax: error
  ## Disallow all tabs
  # no-tabs: error
  ## Disallow ternary operators
  # no-ternary: error
  ## Disallow trailing whitespace at the end of lines
  # no-trailing-spaces: error
  ## Disallow dangling underscores in identifiers
  # no-underscore-dangle: error
  ## Disallow ternary operators when simpler alternatives exist
  # no-unneeded-ternary: error
  ## Disallow whitespace before properties
  no-whitespace-before-property: error
  ## Enforce the location of single-line statements
  # nonblock-statement-body-position: error
  ## Enforce consistent line breaks inside braces
  # object-curly-newline: [error, { multiline: true }]
  ## Enforce consistent spacing inside braces
  object-curly-spacing: [error, always]
  ## Enforce placing object properties on separate lines
  # object-property-newline: error
  ## Enforce variables to be declared either together or separately in
  ## functions
  # one-var: error
  ## Require or disallow newlines around variable declarations
  # one-var-declaration-per-line: error
  ## Require or disallow assignment operator shorthand where possible
  # operator-assignment: error
  ## Enforce consistent linebreak style for operators
  operator-linebreak: [error, before]
  ## Require or disallow padding within blocks
  # padded-blocks: error
  ## Require or disallow padding lines between statements
  # padding-line-between-statements: error
  ## Disallow using Object.assign with an object literal as the first
  ## argument and prefer the use of object spread instead.
  # prefer-object-spread: error
  ## Require quotes around object literal property names
  # quote-props: error
  ## Enforce the consistent use of either backticks, double, or single quotes
  # quotes: [error, single]
  ## Require or disallow semicolons instead of ASI
  semi: error
  ## Enforce consistent spacing before and after semicolons
  semi-spacing: [error, { before: false, after: true }]
  ## Enforce location of semicolons
  semi-style: [error, last]
  ## Require object keys to be sorted
  # sort-keys: error
  ## Require variables within the same declaration block to be sorted
  # sort-vars: error
  ## 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,
  }]
  ## Enforce consistent spacing inside parentheses
  space-in-parens: [error, never]
  ## Require spacing around infix operators
  # space-infix-ops: error
  ## Enforce consistent spacing before or after unary operators
  # space-unary-ops: error
  ## Enforce consistent spacing after the // or /* in a comment
  spaced-comment: [error, always]
  ## Enforce spacing around colons of switch statements
  switch-colon-spacing: [error, { before: false, after: true }]
  ## Require or disallow spacing between template tags and their literals
  template-tag-spacing: [error, never]
  ## Require or disallow Unicode byte order mark (BOM)
  # unicode-bom: [error, never]
  ## Require parenthesis around regex literals
  # wrap-regex: error

  ## ES6
  ## ----------------------------------------
  ## Require braces around arrow function bodies
  # arrow-body-style: error
  ## Require parentheses around arrow function arguments
  # arrow-parens: [error, as-needed]
  ## Enforce consistent spacing before and after the arrow in arrow functions
  arrow-spacing: [error, { before: true, after: true }]
  ## Require super() calls in constructors
  # constructor-super: error
  ## Enforce consistent spacing around * operators in generator functions
  generator-star-spacing: [error, { before: false, after: true }]
  ## Disallow reassigning class members
  no-class-assign: error
  ## Disallow arrow functions where they could be confused with comparisons
  # no-confusing-arrow: error
  ## Disallow reassigning const variables
  no-const-assign: error
  ## Disallow duplicate class members
  no-dupe-class-members: error
  ## Disallow duplicate module imports
  # no-duplicate-imports: error
  ## Disallow new operators with the Symbol object
  no-new-symbol: error
  ## Disallow specified modules when loaded by import
  # no-restricted-imports: error
  ## Disallow this/super before calling super() in constructors
  no-this-before-super: error
  ## Disallow unnecessary computed property keys in object literals
  # no-useless-computed-key: error
  ## Disallow unnecessary constructors
  # no-useless-constructor: error
  ## Disallow renaming import, export, and destructured assignments to the
  ## same name
  # no-useless-rename: error
  ## Require let or const instead of var
  no-var: error
  ## Require or disallow method and property shorthand syntax for object
  ## literals
  # object-shorthand: error
  ## Require using arrow functions for callbacks
  prefer-arrow-callback: error
  ## Require const declarations for variables that are never reassigned after
  ## declared
  # prefer-const: error
  ## Require destructuring from arrays and/or objects
  # prefer-destructuring: error
  ## Disallow parseInt() and Number.parseInt() in favor of binary, octal, and
  ## hexadecimal literals
  # prefer-numeric-literals: error
  ## Require rest parameters instead of arguments
  # prefer-rest-params: error
  ## Require spread operators instead of .apply()
  # prefer-spread: error
  ## Require template literals instead of string concatenation
  # prefer-template: error
  ## Require generator functions to contain yield
  # require-yield: error
  ## Enforce spacing between rest and spread operators and their expressions
  # rest-spread-spacing: error
  ## Enforce sorted import declarations within modules
  # sort-imports: error
  ## Require symbol descriptions
  # symbol-description: error
  ## Require or disallow spacing around embedded expressions of template
  ## strings
  # template-curly-spacing: error
  ## Require or disallow spacing around the * in yield* expressions
  yield-star-spacing: [error, { before: false, after: true }]

  ## React
  ## ----------------------------------------
  ## Enforces consistent naming for boolean props
  react/boolean-prop-naming: error
  ## Forbid "button" element without an explicit "type" attribute
  react/button-has-type: error
  ## Prevent extraneous defaultProps on components
  react/default-props-match-prop-types: error
  ## Rule enforces consistent usage of destructuring assignment in component
  # react/destructuring-assignment: [error, always, { ignoreClassFields: true }]
  ## Prevent missing displayName in a React component definition
  # react/display-name: error
  ## Forbid certain props on Components
  # react/forbid-component-props: error
  ## Forbid certain props on DOM Nodes
  # react/forbid-dom-props: error
  ## Forbid certain elements
  # react/forbid-elements: error
  ## Forbid certain propTypes
  # react/forbid-prop-types: error
  ## Forbid foreign propTypes
  # react/forbid-foreign-prop-types: error
  ## Prevent using this.state inside this.setState
  react/no-access-state-in-setstate: error
  ## Prevent using Array index in key props
  # react/no-array-index-key: error
  ## Prevent passing children as props
  react/no-children-prop: error
  ## Prevent usage of dangerous JSX properties
  react/no-danger: error
  ## Prevent problem with children and props.dangerouslySetInnerHTML
  react/no-danger-with-children: error
  ## Prevent usage of deprecated methods, including component lifecycle
  ## methods
  react/no-deprecated: error
  ## Prevent usage of setState in componentDidMount
  react/no-did-mount-set-state: error
  ## Prevent usage of setState in componentDidUpdate
  react/no-did-update-set-state: error
  ## Prevent direct mutation of this.state
  react/no-direct-mutation-state: error
  ## Prevent usage of findDOMNode
  react/no-find-dom-node: error
  ## Prevent usage of isMounted
  react/no-is-mounted: error
  ## Prevent multiple component definition per file
  # react/no-multi-comp: error
  ## Prevent usage of shouldComponentUpdate when extending React.PureComponent
  react/no-redundant-should-component-update: error
  ## Prevent usage of the return value of React.render
  react/no-render-return-value: error
  ## Prevent usage of setState
  # react/no-set-state: error
  ## Prevent common casing typos
  react/no-typos: error
  ## Prevent using string references in ref attribute.
  react/no-string-refs: error
  ## Prevent using this in stateless functional components
  react/no-this-in-sfc: error
  ## Prevent invalid characters from appearing in markup
  react/no-unescaped-entities: error
  ## Prevent usage of unknown DOM property (fixable)
  # react/no-unknown-property: error
  ## Prevent usage of unsafe lifecycle methods
  react/no-unsafe: error
  ## Prevent definitions of unused prop types
  react/no-unused-prop-types: error
  ## Prevent definitions of unused state properties
  react/no-unused-state: error
  ## Prevent usage of setState in componentWillUpdate
  react/no-will-update-set-state: error
  ## Enforce ES5 or ES6 class for React Components
  react/prefer-es6-class: error
  ## Enforce that props are read-only
  react/prefer-read-only-props: error
  ## Enforce stateless React Components to be written as a pure function
  react/prefer-stateless-function: error
  ## Prevent missing props validation in a React component definition
  # react/prop-types: error
  ## Prevent missing React when using JSX
  # react/react-in-jsx-scope: error
  ## Enforce a defaultProps definition for every prop that is not a required
  ## prop
  # react/require-default-props: error
  ## Enforce React components to have a shouldComponentUpdate method
  # react/require-optimization: error
  ## Enforce ES5 or ES6 class for returning value in render function
  react/require-render-return: error
  ## Prevent extra closing tags for components without children (fixable)
  react/self-closing-comp: error
  ## Enforce component methods order (fixable)
  # react/sort-comp: error
  ## Enforce propTypes declarations alphabetical sorting
  # react/sort-prop-types: error
  ## Enforce the state initialization style to be either in a constructor or
  ## with a class property
  # react/state-in-constructor: error
  ## Enforces where React component static properties should be positioned.
  # react/static-property-placement: error
  ## Enforce style prop value being an object
  react/style-prop-object: error
  ## Prevent void DOM elements (e.g. <img />, <br />) from receiving children
  react/void-dom-elements-no-children: error

  ## JSX-specific rules
  ## ----------------------------------------
  ## Enforce boolean attributes notation in JSX (fixable)
  react/jsx-boolean-value: error
  ## Enforce or disallow spaces inside of curly braces in JSX attributes and
  ## expressions.
  # react/jsx-child-element-spacing: error
  ## Validate closing bracket location in JSX (fixable)
  # react/jsx-closing-bracket-location: [error, {
  #   ## NOTE: Not really sure about enforcing this one
  #   selfClosing: false,
  #   nonEmpty: after-props,
  # }]
  ## Validate closing tag location in JSX (fixable)
  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
  ## Enforce or disallow spaces inside of curly braces in JSX attributes and
  ## expressions (fixable)
  react/jsx-curly-spacing: error
  ## Enforce or disallow spaces around equal signs in JSX attributes (fixable)
  react/jsx-equals-spacing: error
  ## Restrict file extensions that may contain JSX
  # react/jsx-filename-extension: error
  ## Enforce position of the first prop in JSX (fixable)
  # react/jsx-first-prop-new-line: error
  ## Enforce event handler naming conventions in JSX
  react/jsx-handler-names: error
  ## Validate JSX indentation (fixable)
  react/jsx-indent: [error, 2, {
    checkAttributes: true,
  }]
  ## Validate props indentation in JSX (fixable)
  react/jsx-indent-props: [error, 2]
  ## Validate JSX has key prop when in array or iterator
  react/jsx-key: error
  ## Validate JSX maximum depth
  react/jsx-max-depth: [error, { max: 10 }] ## Generous
  ## Limit maximum of props on a single line in JSX (fixable)
  # react/jsx-max-props-per-line: error
  ## Prevent usage of .bind() and arrow functions in JSX props
  # react/jsx-no-bind: error
  ## Prevent comments from being inserted as text nodes
  react/jsx-no-comment-textnodes: error
  ## Prevent duplicate props in JSX
  react/jsx-no-duplicate-props: error
  ## Prevent usage of unwrapped JSX strings
  # react/jsx-no-literals: error
  ## Prevent usage of unsafe target='_blank'
  react/jsx-no-target-blank: error
  ## Disallow undeclared variables in JSX
  react/jsx-no-undef: error
  ## Disallow unnecessary fragments (fixable)
  react/jsx-no-useless-fragment: error
  ## Limit to one expression per line in JSX
  # react/jsx-one-expression-per-line: error
  ## Enforce curly braces or disallow unnecessary curly braces in JSX
  # react/jsx-curly-brace-presence: error
  ## Enforce shorthand or standard form for React fragments
  react/jsx-fragments: error
  ## Enforce PascalCase for user-defined JSX components
  react/jsx-pascal-case: error
  ## Disallow multiple spaces between inline JSX props (fixable)
  react/jsx-props-no-multi-spaces: error
  ## Disallow JSX props spreading
  # react/jsx-props-no-spreading: error
  ## Enforce default props alphabetical sorting
  # react/jsx-sort-default-props: error
  ## Enforce props alphabetical sorting (fixable)
  # react/jsx-sort-props: error
  ## Validate whitespace in and around the JSX opening and closing brackets
  ## (fixable)
  react/jsx-tag-spacing: error
  ## Prevent React to be incorrectly marked as unused
  react/jsx-uses-react: error
  ## Prevent variables used in JSX to be incorrectly marked as unused
  react/jsx-uses-vars: error
  ## Prevent missing parentheses around multilines JSX (fixable)
  react/jsx-wrap-multilines: error
  ## Prevents the use of unused imports.
  ## This could be done by enabling no-unused-vars, but we're doing this for now
  unused-imports/no-unused-imports: error


code:
* text=auto

## Enforce text mode and LF line breaks
*.js text eol=lf
*.jsx text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.css text eol=lf
*.scss text eol=lf
*.html text eol=lf
*.json text eol=lf
*.yml text eol=lf
*.md text eol=lf
*.bat text eol=lf
yarn.lock text eol=lf

## Treat bundles as binary
*.bundle.* binary
*.chunk.* binary
.yarn/releases/**/* binary
.yarn/plugins/**/* binary


code:
## NPM garbage
node_modules
*.log
package-lock.json

## Yarn stuff
/.pnp.*
/.yarn/*
!/.yarn/releases
!/.yarn/plugins
!/.yarn/sdks
!/.yarn/versions
!/.yarn/lock.yml

## Build artifacts
/public/.tmp/**/*
/public/**/*
!/public/*.html
/coverage

## Previously ignored locations that are kept to avoid confusing git
## while transitioning to a new project structure.
/packages/tgui/public/**


code:
arrowParens: always
bracketSpacing: true
endOfLine: lf
jsxBracketSameLine: true
jsxSingleQuote: false
printWidth: 80
proseWrap: preserve
quoteProps: preserve
semi: true
singleQuote: true
tabWidth: 2
trailingComma: es5


code:
#!/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 eslint/bin/eslint.js
    require(absPnpApiPath).setup();
  }
}

// Defer to the real eslint/bin/eslint.js your application uses
module.exports = absRequire(`eslint/bin/eslint.js`);


code:
#!/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 eslint/lib/api.js
    require(absPnpApiPath).setup();
  }
}

// Defer to the real eslint/lib/api.js your application uses
module.exports = absRequire(`eslint/lib/api.js`);


code:
# This file is automatically generated by @yarnpkg/sdks.
# Manual changes might be lost!

integrations:
  - vscode


code:
#!/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 typescript/bin/tsc
    require(absPnpApiPath).setup();
  }
}

// Defer to the real typescript/bin/tsc your application uses
module.exports = absRequire(`typescript/bin/tsc`);


code:
#!/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 typescript/bin/tsserver
    require(absPnpApiPath).setup();
  }
}

// Defer to the real typescript/bin/tsserver your application uses
module.exports = absRequire(`typescript/bin/tsserver`);


code:
#!/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 typescript/lib/tsc.js
    require(absPnpApiPath).setup();
  }
}

// Defer to the real typescript/lib/tsc.js your application uses
module.exports = absRequire(`typescript/lib/tsc.js`);


code:
#!/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);

const moduleWrapper = tsserver => {
  if (!process.versions.pnp) {
    return tsserver;
  }

  const {isAbsolute} = require(`path`);
  const pnpApi = require(`pnpapi`);

  const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
  const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);

  const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
    return `${locator.name}@${locator.reference}`;
  }));

  // VSCode sends the zip paths to TS using the "zip://" prefix, that TS
  // doesn't understand. This layer makes sure to remove the protocol
  // before forwarding it to TS, and to add it back on all returned paths.

  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))) {
      // 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
      // file instances instead of the real ones.
      //
      // We only do this to modules owned by the the dependency tree roots.
      // This avoids breaking the resolution when jumping inside a vendor
      // with peer dep (otherwise jumping into react-dom would show resolution
      // errors on react).
      //
      const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
      if (resolved) {
        const locator = pnpApi.findPackageLocator(resolved);
        if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) {
          str = resolved;
        }
      }

      str = normalize(str);

      if (str.match(/\.zip\//)) {
        switch (hostInfo) {
          // Absolute VSCode `Uri.fsPath`s need to start with a slash.
          // VSCode only adds it automatically for supported schemes,
          // so we have to do it manually for the `zip` scheme.
          // The path needs to start with a caret otherwise VSCode doesn't handle the protocol
          //
          // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
          //
          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)
          case `coc-nvim`: {
            str = normalize(resolved).replace(/\.zip\//, `.zip::`);
            str = resolve(`zipfile:${str}`);
          } break;

          // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)
          // We have to resolve the actual file system path from virtual path,
          // everything else is up to neovim
          case `neovim`: {
            str = normalize(resolved).replace(/\.zip\//, `.zip::`);
            str = `zipfile:${str}`;
          } break;

          default: {
            str = `zip:${str}`;
          } break;
        }
      }
    }

    return str;
  }

  function fromEditorPath(str) {
    return process.platform === `win32`
      ? str.replace(/^\^?zip:\//, ``)
      : str.replace(/^\^?zip:/, ``);
  }

  // Force enable 'allowLocalPluginLoads'
  // TypeScript tries to resolve plugins using a path relative to itself
  // which doesn't work when using the global cache
  // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238
  // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but
  // TypeScript already does local loads and if this code is running the user trusts the workspace
  // https://github.com/microsoft/vscode/issues/45856
  const ConfiguredProject = tsserver.server.ConfiguredProject;
  const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;
  ConfiguredProject.prototype.enablePluginsWithOptions = function() {
    this.projectService.allowLocalPluginLoads = true;
    return originalEnablePluginsWithOptions.apply(this, arguments);
  };

  // And here is the point where we hijack the VSCode <-> TS communications
  // by adding ourselves in the middle. We locate everything that looks
  // like an absolute path of ours and normalize it.

  const Session = tsserver.server.Session;
  const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
  let hostInfo = `unknown`;

  Object.assign(Session.prototype, {
    onMessage(/** @type {string} */ message) {
      const parsedMessage = JSON.parse(message)

      if (
        parsedMessage != null &&
        typeof parsedMessage === `object` &&
        parsedMessage.arguments &&
        typeof parsedMessage.arguments.hostInfo === `string`
      ) {
        hostInfo = parsedMessage.arguments.hostInfo;
      }

      return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => {
        return typeof value === `string` ? fromEditorPath(value) : value;
      }));
    },

    send(/** @type {any} */ msg) {
      return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {
        return typeof value === `string` ? toEditorPath(value) : value;
      })));
    }
  });

  return tsserver;
};

if (existsSync(absPnpApiPath)) {
  if (!process.versions.pnp) {
    // Setup the environment to be able to require typescript/lib/tsserver.js
    require(absPnpApiPath).setup();
  }
}

// Defer to the real typescript/lib/tsserver.js your application uses
module.exports = moduleWrapper(absRequire(`typescript/lib/tsserver.js`));


code:
#!/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);

const moduleWrapper = tsserver => {
  if (!process.versions.pnp) {
    return tsserver;
  }

  const {isAbsolute} = require(`path`);
  const pnpApi = require(`pnpapi`);

  const isVirtual = str => str.match(/\/(\$\$virtual|__virtual__)\//);
  const normalize = str => str.replace(/\\/g, `/`).replace(/^\/?/, `/`);

  const dependencyTreeRoots = new Set(pnpApi.getDependencyTreeRoots().map(locator => {
    return `${locator.name}@${locator.reference}`;
  }));

  // VSCode sends the zip paths to TS using the "zip://" prefix, that TS
  // doesn't understand. This layer makes sure to remove the protocol
  // before forwarding it to TS, and to add it back on all returned paths.

  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))) {
      // 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
      // file instances instead of the real ones.
      //
      // We only do this to modules owned by the the dependency tree roots.
      // This avoids breaking the resolution when jumping inside a vendor
      // with peer dep (otherwise jumping into react-dom would show resolution
      // errors on react).
      //
      const resolved = isVirtual(str) ? pnpApi.resolveVirtual(str) : str;
      if (resolved) {
        const locator = pnpApi.findPackageLocator(resolved);
        if (locator && dependencyTreeRoots.has(`${locator.name}@${locator.reference}`)) {
          str = resolved;
        }
      }

      str = normalize(str);

      if (str.match(/\.zip\//)) {
        switch (hostInfo) {
          // Absolute VSCode `Uri.fsPath`s need to start with a slash.
          // VSCode only adds it automatically for supported schemes,
          // so we have to do it manually for the `zip` scheme.
          // The path needs to start with a caret otherwise VSCode doesn't handle the protocol
          //
          // Ref: https://github.com/microsoft/vscode/issues/105014#issuecomment-686760910
          //
          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)
          case `coc-nvim`: {
            str = normalize(resolved).replace(/\.zip\//, `.zip::`);
            str = resolve(`zipfile:${str}`);
          } break;

          // Support neovim native LSP and [typescript-language-server](https://github.com/theia-ide/typescript-language-server)
          // We have to resolve the actual file system path from virtual path,
          // everything else is up to neovim
          case `neovim`: {
            str = normalize(resolved).replace(/\.zip\//, `.zip::`);
            str = `zipfile:${str}`;
          } break;

          default: {
            str = `zip:${str}`;
          } break;
        }
      }
    }

    return str;
  }

  function fromEditorPath(str) {
    return process.platform === `win32`
      ? str.replace(/^\^?zip:\//, ``)
      : str.replace(/^\^?zip:/, ``);
  }

  // Force enable 'allowLocalPluginLoads'
  // TypeScript tries to resolve plugins using a path relative to itself
  // which doesn't work when using the global cache
  // https://github.com/microsoft/TypeScript/blob/1b57a0395e0bff191581c9606aab92832001de62/src/server/project.ts#L2238
  // VSCode doesn't want to enable 'allowLocalPluginLoads' due to security concerns but
  // TypeScript already does local loads and if this code is running the user trusts the workspace
  // https://github.com/microsoft/vscode/issues/45856
  const ConfiguredProject = tsserver.server.ConfiguredProject;
  const {enablePluginsWithOptions: originalEnablePluginsWithOptions} = ConfiguredProject.prototype;
  ConfiguredProject.prototype.enablePluginsWithOptions = function() {
    this.projectService.allowLocalPluginLoads = true;
    return originalEnablePluginsWithOptions.apply(this, arguments);
  };

  // And here is the point where we hijack the VSCode <-> TS communications
  // by adding ourselves in the middle. We locate everything that looks
  // like an absolute path of ours and normalize it.

  const Session = tsserver.server.Session;
  const {onMessage: originalOnMessage, send: originalSend} = Session.prototype;
  let hostInfo = `unknown`;

  Object.assign(Session.prototype, {
    onMessage(/** @type {string} */ message) {
      const parsedMessage = JSON.parse(message)

      if (
        parsedMessage != null &&
        typeof parsedMessage === `object` &&
        parsedMessage.arguments &&
        typeof parsedMessage.arguments.hostInfo === `string`
      ) {
        hostInfo = parsedMessage.arguments.hostInfo;
      }

      return originalOnMessage.call(this, JSON.stringify(parsedMessage, (key, value) => {
        return typeof value === `string` ? fromEditorPath(value) : value;
      }));
    },

    send(/** @type {any} */ msg) {
      return originalSend.call(this, JSON.parse(JSON.stringify(msg, (key, value) => {
        return typeof value === `string` ? toEditorPath(value) : value;
      })));
    }
  });

  return tsserver;
};

if (existsSync(absPnpApiPath)) {
  if (!process.versions.pnp) {
    // Setup the environment to be able to require typescript/lib/tsserverlibrary.js
    require(absPnpApiPath).setup();
  }
}

// Defer to the real typescript/lib/tsserverlibrary.js your application uses
module.exports = moduleWrapper(absRequire(`typescript/lib/tsserverlibrary.js`));


code:
#!/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 typescript/lib/typescript.js
    require(absPnpApiPath).setup();
  }
}

// Defer to the real typescript/lib/typescript.js your application uses
module.exports = absRequire(`typescript/lib/typescript.js`);


code:
enableScripts: false

logFilters:
  - code: YN0004
    level: discard
  - code: YN0062
    level: discard

plugins:
  - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
    spec: "@yarnpkg/plugin-interactive-tools"

preferAggregateCacheInfo: true

preferInteractive: true

yarnPath: .yarn/releases/yarn-3.0.1.cjs


code:
# tgui

## Introduction

tgui is a robust user interface framework of /tg/station.

tgui is very different from most UIs you will encounter in BYOND programming. It is heavily reliant on Javascript and web technologies as opposed to DM. If you are familiar with NanoUI (a library which can be found on almost every other SS13 codebase), tgui should be fairly easy to pick up.

## Learn tgui

People come to tgui from different backgrounds and with different learning styles. Whether you prefer a more theoretical or a practical approach, we hope you’ll find this section helpful.

### Practical Tutorial

If you are completely new to frontend and prefer to **learn by doing**, start with our [practical tutorial](docs/tutorial-and-examples.md).

### Guides

This project uses **Inferno** - a very fast UI rendering engine with a similar API to React. Take your time to read these guides:

- [React guide](https://reactjs.org/docs/hello-world.html)
- [Inferno documentation](https://infernojs.org/docs/guides/components) - highlights differences with React.

If you were already familiar with an older, Ractive-based tgui, and want to translate concepts between old and new tgui, read this [interface conversion guide](docs/converting-old-tgui-interfaces.md).

## Pre-requisites

If you are using the tooling provided in this repo, everything is included! Feel free to skip this step.

However, if you want finer control over the installation or build process, you will need these:

- [Node v12.20+](https://nodejs.org/en/download/)
  - **DO NOT install Chocolatey if Node installer asks you to!**
- [Yarn v1.22.4+](https://yarnpkg.com/getting-started/install)
  - You only need to run `npm install -g yarn`.

## Usage

**Via provided cmd scripts (Windows)**:

- `bin/tgui-build` - Build tgui in production mode and run a full suite of code checks.
- `bin/tgui-dev` - Launch a development server.
  - `bin/tgui-dev --reload` - Reload byond cache once.
  - `bin/tgui-dev --debug` - Run server with debug logging enabled.
  - `bin/tgui-dev --no-hot` - Disable hot module replacement (helps when doing development on IE8).
- `bin/tgui-sonar` - Analyze code with SonarQube.
- `bin/tgui-bench` - Run benchmarks.

> To open a CMD or PowerShell window in any open folder, right click **while holding Shift** on any free space in the folder, then click on either `Open command window here` or `Open PowerShell window here`.

**Via Juke Build (cross-platform)**:

- `tools/build/build tgui` - Build tgui in production mode.
- `tools/build/build tgui-dev` - Build tgui in production mode.
  - `tools/build/build tgui-dev --reload` - Reload byond cache once.
  - `tools/build/build tgui-dev --debug` - Run server with debug logging enabled.
  - `tools/build/build tgui-dev --no-hot` - Disable hot module replacement (helps when doing development on IE8).
- `tools/build/build tgui-lint` - Show (and auto-fix) problems with the code.
- `tools/build/build tgui-sonar` - Analyze code with SonarQube.
- `tools/build/build tgui-test` - Run unit and integration tests.
- `tools/build/build tgui-analyze` - Run a bundle analyzer.
- `tools/build/build tgui-bench` - Run benchmarks.
- `tools/build/build tgui-clean` - Clean up tgui folder.

> With Juke Build, you can run multiple targets together, e.g.:
> ```
> tools/build/build tgui tgui-lint tgui-tsc tgui-test
> ```

**Via Yarn (cross-platform)**:

Run `yarn install` once to install tgui dependencies.

- `yarn tgui:build` - Build tgui in production mode.
  - `yarn tgui:build [options]` - Build tgui with custom webpack options.
- `yarn tgui:dev` - Launch a development server.
  - `yarn tgui:dev --reload` - Reload byond cache once.
  - `yarn tgui:dev --debug` - Run server with debug logging enabled.
  - `yarn tgui:dev --no-hot` - Disable hot module replacement (helps when doing development on IE8).
- `yarn tgui:lint` - Show (and auto-fix) problems with the code.
- `yarn tgui:sonar` - Analyze code with SonarQube.
- `yarn tgui:tsc` - Check code with TypeScript compiler.
- `yarn tgui:test` - Run unit and integration tests.
- `yarn tgui:analyze` - Run a bundle analyzer.
- `yarn tgui:bench` - Run benchmarks.

## Important memo

Remember to always run a full build of tgui before submitting a PR, because it comes with the full suite of CI checks, and runs much faster on your computer than on GitHub servers. It will save you some time and possibly a few broken commits! Address the issues that are reported by the tooling as much as possible, because maintainers will beat you with a ruler and force you to address them anyway (unless it's a false positive or something unfixable).

## Troubleshooting

**Development server is crashing**

Make sure path to your working directory does not contain spaces, special unicode characters, exclamation marks or any other special symbols. If so, move codebase to a location which does not contain these characters.

This is a known issue with Yarn (and some other tools, like Webpack), and fix is going to happen eventually.

**Development server doesn't find my BYOND cache!**

This happens if your Documents folder in Windows has a custom location, for example in `E:\Libraries\Documents`. Development server tries its best to find this non-standard location (searches for a Windows Registry key), but it can fail. You have to run the dev server with an additional environmental variable, with a full path to BYOND cache.

```
BYOND_CACHE="E:/Libraries/Documents/BYOND/cache"
```

**Webpack errors out with some cryptic messages!**

> Example: `No template for dependency: PureExpressionDependency`

Webpack stores its cache on disk since tgui 4.3, and it is very sensitive to build configuration. So if you update webpack, or share the same cache directory between development and production build, it will start hallucinating.

To fix this kind of problem, run `bin/tgui --clean` and try again.

## Developer Tools

When developing with `tgui-dev-server`, you will have access to certain development only features.

**Debug Logs**. When running server via `bin/tgui --dev --debug`, server will print debug logs and time spent on rendering. Use this information to optimize your code, and try to keep re-renders below 16ms.

**Kitchen Sink**. Press `F12` to open the KitchenSink interface. This interface is a playground to test various tgui components.

**Layout Debugger**. Press `F11` to toggle the *layout debugger*. It will show outlines of all tgui elements, which makes it easy to understand how everything comes together, and can reveal certain layout bugs which are not normally visible.

## Project Structure

- `/packages` - Each folder here represents a self-contained Node module.
- `/packages/common` - Helper functions that are used throughout all packages.
- `/packages/tgui/index.js` - Application entry point.
- `/packages/tgui/components` - Basic UI building blocks.
- `/packages/tgui/interfaces` - Actual in-game interfaces.
- `/packages/tgui/layouts` - Root level UI components, that affect the final look and feel of the browser window. These hold various window elements, like the titlebar and resize handlers, and control the UI theme.
- `/packages/tgui/routes.js` - This is where tgui decides which interface to pull and render.
- `/packages/tgui/styles/main.scss` - CSS entry point.
- `/packages/tgui/styles/functions.scss` - Useful SASS functions. Stuff like `lighten`, `darken`, `luminance` are defined here.
- `/packages/tgui/styles/atomic` - Atomic CSS classes. These are very simple, tiny, reusable CSS classes which you can use and combine to change appearance of your elements. Keep them small.
- `/packages/tgui/styles/components` - CSS classes which are used in UI components. These stylesheets closely follow the [BEM](https://en.bem.info/methodology/) methodology.
- `/packages/tgui/styles/interfaces` - Custom stylesheets for your interfaces. Add stylesheets here if you really need a fine control over your UI styles.
- `/packages/tgui/styles/layouts` - Layout-related styles.
- `/packages/tgui/styles/themes` - Contains themes that you can use in tgui. Each theme must be registered in `/packages/tgui/index.js` file.

## Component Reference

See: [Component Reference](docs/component-reference.md).

## License

Source code is covered by /tg/station's parent license - **AGPL-3.0** (see the main [README](../README.md)), unless otherwise indicated.

Some files are annotated with a copyright header, which explicitly states the copyright holder and license of the file. Most of the core tgui source code is available under the **MIT** license.

The Authors retain all copyright to their respective work here submitted.


code:
/**
 * @file
 * @copyright 2020 Aleksej Komarov
 * @license MIT
 */

const createBabelConfig = options => {
  const { presets = [], plugins = [], removeConsole } = options;
  return {
    presets: [
      [require.resolve('@babel/preset-typescript'), {
        allowDeclareFields: true,
      }],
      [require.resolve('@babel/preset-env'), {
        modules: 'commonjs',
        useBuiltIns: 'entry',
        corejs: '3',
        spec: false,
        loose: true,
        targets: [],
      }],
      ...presets,
    ].filter(Boolean),
    plugins: [
      [require.resolve('@babel/plugin-proposal-class-properties'), {
        loose: true,
      }],
      require.resolve('@babel/plugin-transform-jscript'),
      require.resolve('babel-plugin-inferno'),
      removeConsole && require.resolve('babel-plugin-transform-remove-console'),
      require.resolve('common/string.babel-plugin.cjs'),
      ...plugins,
    ].filter(Boolean),
  };
};

module.exports = api => {
  api.cache(true);
  const mode = process.env.NODE_ENV;
  return createBabelConfig({ mode });
};

module.exports.createBabelConfig = createBabelConfig;


code:
# Component Reference

> Notice: This documentation might be out of date, so always check the source
> code to see the most up-to-date information.

<!--
This table of contents must be manually maintained.
Make sure to add new items to this list if you document new components.
-->

- [General Concepts](#general-concepts)
- [`tgui/components`](#tguicomponents)
  - [`AnimatedNumber`](#animatednumber)
  - [`BlockQuote`](#blockquote)
  - [`Box`](#box)
  - [`Button`](#button)
  - [`Button.Checkbox`](#buttoncheckbox)
  - [`Button.Confirm`](#buttonconfirm)
  - [`Button.Input`](#buttoninput)
  - [`ByondUi`](#byondui)
  - [`Collapsible`](#collapsible)
  - [`ColorBox`](#colorbox)
  - [`Dimmer`](#dimmer)
  - [`Divider`](#divider)
  - [`Dropdown`](#dropdown)
  - [`Flex`](#flex)
  - [`Flex.Item`](#flexitem)
  - [`Grid`](#grid)
  - [`Grid.Column`](#gridcolumn)
  - [`Icon`](#icon)
  - [`Icon.Stack`](#iconstack)
  - [`Input`](#input)
  - [`Knob`](#knob)
  - [`LabeledControls`](#labeledcontrols)
  - [`LabeledControls.Item`](#labeledcontrolsitem)
  - [`LabeledList`](#labeledlist)
  - [`LabeledList.Item`](#labeledlistitem)
  - [`LabeledList.Divider`](#labeledlistdivider)
  - [`Modal`](#modal)
  - [`NoticeBox`](#noticebox)
  - [`NumberInput`](#numberinput)
  - [`ProgressBar`](#progressbar)
  - [`RoundGauge`](#roundgauge)
  - [`Section`](#section)
  - [`Slider`](#slider)
  - [`Stack`](#stack)
  - [`Table`](#table)
  - [`Table.Row`](#tablerow)
  - [`Table.Cell`](#tablecell)
  - [`Tabs`](#tabs)
  - [`Tabs.Tab`](#tabstab)
  - [`Tooltip`](#tooltip)
- [`tgui/layouts`](#tguilayouts)
  - [`Window`](#window)
  - [`Window.Content`](#windowcontent)

## General Concepts

These are the components which you can use for interface construction.
If you have trouble finding the exact prop you need on a component,
please note, that most of these components inherit from other basic
components, such as [Box](#box). This component in particular provides a lot
of styling options for all components, e.g. `color` and `opacity`, thus
it is used a lot in this framework.

**Event handlers.**
Event handlers are callbacks that you can attack to various element to
listen for browser events. Inferno supports camelcase (`onClick`) and
lowercase (`onclick`) event names.

- Camel case names are what's called *synthetic* events, and are the
**preferred way** of handling events in React, for efficiency and
performance reasons. Please read
[Inferno Event Handling](https://infernojs.org/docs/guides/event-handling)
to understand what this is about.
- Lower case names are native browser events and should be used sparingly,
for example when you need an explicit IE8 support. **DO NOT** use
lowercase event handlers unless you really know what you are doing.
- [Button](#button) component does not support the lowercase `onclick` event.
Use the camel case `onClick` instead.

## `tgui/components`

### `AnimatedNumber`

This component provides animations for numeric values.

**Props:**

- `value: number` - Value to animate.
- `initial: number` - Initial value to use in animation when element
first appears. If you set initial to `0` for example, number will always
animate starting from `0`, and if omitted, it will not play an initial
animation.
- `format: value => value` - Output formatter.
  - Example: `value => Math.round(value)`.
- `children: (formattedValue, rawValue) => any` - Pull the animated number to
animate more complex things deeper in the DOM tree.
  - Example: `(_, value) => <Icon rotation={value} />`

### `BlockQuote`

Just a block quote, just like this example in markdown:

> Here's an example of a block quote.

**Props:**

- See inherited props: [Box](#box)

### `Box`

The Box component serves as a wrapper component for most of the CSS utility
needs. It creates a new DOM element, a `<div>` by default that can be changed
with the `as` property. Let's say you want to use a `<span>` instead:

```jsx
<Box as="span" m={1}>
  <Button />
</Box>
```

This works great when the changes can be isolated to a new DOM element.
For instance, you can change the margin this way.

However, sometimes you have to target the underlying DOM element.
For instance, you want to change the text color of the button. The Button
component defines its own color. CSS inheritance doesn't help.

To workaround this problem, the Box children accept a render props function.
This way, `Button` can pull out the `className` generated by the `Box`.

```jsx
<Box color="primary">
  {props => <Button {...props} />}
</Box>
```

**Box Units**

`Box` units, like width, height and margins can be defined in two ways:

- By plain numbers
  - 1 unit equals `1rem` for width, height and positioning properties.
  - 1 unit equals `0.5rem` for margins and paddings.
- By strings with proper CSS units
  - For example: `100px`, `2em`, `1rem`, `100%`, etc.

If you need more precision, you can always use fractional numbers.

Default font size (`1rem`) is equal to `12px`.

**Props:**

- `as: string` - The component used for the root node.
- `color: string` - Applies an atomic `color-<name>` class to the element.
  - See `styles/atomic/color.scss`.
- `width: number` - Box width.
- `minWidth: number` - Box minimum width.
- `maxWidth: number` - Box maximum width.
- `height: number` - Box height.
- `minHeight: number` - Box minimum height.
- `maxHeight: number` - Box maximum height.
- `fontSize: number` - Font size.
- `fontFamily: string` - Font family.
- `lineHeight: number` - Directly affects the height of text lines.
Useful for adjusting button height.
- `inline: boolean` - Forces the `Box` to appear as an `inline-block`,
or in other words, makes the `Box` flow with the text instead of taking
all available horizontal space.
- `m: number` - Margin on all sides.
- `mx: number` - Horizontal margin.
- `my: number` - Vertical margin.
- `mt: number` - Top margin.
- `mb: number` - Bottom margin.
- `ml: number` - Left margin.
- `mr: number` - Right margin.
- `p: number` - Padding on all sides.
- `px: number` - Horizontal padding.
- `py: number` - Vertical padding.
- `pt: number` - Top padding.
- `pb: number` - Bottom padding.
- `pl: number` - Left padding.
- `pr: number` - Right padding.
- `opacity: number` - Opacity, from 0 to 1.
- `bold: boolean` - Make text bold.
- `italic: boolean` - Make text italic.
- `nowrap: boolean` - Stops text from wrapping.
- `preserveWhitespace: boolean` - Preserves line-breaks and spacing in text.
- `textAlign: string` - Align text inside the box.
  - `left` (default)
  - `center`
  - `right`
- `position: string` - A direct mapping to `position` CSS property.
  - `relative` - Relative positioning.
  - `absolute` - Absolute positioning.
  - `fixed` - Fixed positioning.
- `color: string` - An alias to `textColor`.
- `textColor: string` - Sets text color.
  - `#ffffff` - Hex format
  - `rgba(255, 255, 255, 1)` - RGB format
  - `purple` - Applies an atomic `color-<name>` class to the element.
  See `styles/color-map.scss`.
- `backgroundColor: string` - Sets background color.
  - `#ffffff` - Hex format
  - `rgba(255, 255, 255, 1)` - RGB format

### `Button`

Buttons allow users to take actions, and make choices, with a single click.

**Props:**

- See inherited props: [Box](#box)
- `fluid: boolean` - Fill all available horizontal space.
- `icon: string` - Adds an icon to the button.
- `color: string` - Button color, as defined in `variables.scss`.
  - There is also a special color `transparent` - makes the button
  transparent and slightly dim when inactive.
- `disabled: boolean` - Disables and greys out the button.
- `selected: boolean` - Activates the button (gives it a green color).
- `tooltip: string` - A fancy, boxy tooltip, which appears when hovering
over the button.
- `tooltipPosition?: string` - Position of the tooltip. See [`Popper`](#Popper) for valid options.
- `ellipsis: boolean` - If button width is constrained, button text will
be truncated with an ellipsis. Be careful however, because this prop breaks
the baseline alignment.
- `title: string` - A native browser tooltip, which appears when hovering
over the button.
- `children: any` - Content to render inside the button.
- `onClick: function` - Called when element is clicked.

### `Button.Checkbox`

A ghetto checkbox, made entirely using existing Button API.

**Props:**

- See inherited props: [Button](#button)
- `checked: boolean` - Boolean value, which marks the checkbox as checked.

### `Button.Confirm`

A button with an extra confirmation step, using native button component.

**Props:**

- See inherited props: [Button](#button)
- `confirmContent: string` - Text to display after first click; defaults to "Confirm?"
- `confirmColor: string` - Color to display after first click; defaults to "bad"

### `Button.Input`

A button that turns into an input box after the first click. Turns back into a
button after the user hits enter, defocuses, or hits escape. Enter and defocus
commit, while escape cancels.

**Props:**

- See inherited props: [Box](#box)
- `fluid`: fill available horizontal space
- `onCommit: (e, value) => void`: function that is called after the user
defocuses the input or presses enter
- `currentValue: string`: default string to display when the input is shown
- `defaultValue: string`: default value emitted if the user leaves the box
blank when hitting enter or defocusing. If left undefined, will cancel the
change on a blank defocus/enter

### `ByondUi`

Displays a BYOND UI element on top of the browser, and leverages browser's
layout engine to position it just like any other HTML element. It is
especially useful if you want to display a secondary game map in your
interface.

Example (button):

```
<ByondUi
  params={{
    id: 'test_button', // optional, can be auto-generated
    parent: 'some_container', // optional, defaults to the current window
    type: 'button',
    text: 'Hello, world!',
  }} />
```

Example (map):

```
<ByondUi
  params={{
    id: 'test_map',
    type: 'map',
  }} />
```

It supports a full set of `Box` properties for layout purposes.

**Props:**

- See inherited props: [Box](#box)
- `params: any` - An object with parameters, which are directly passed to
the `winset` proc call. You can find a full reference of these parameters
in [BYOND controls and parameters guide](https://secure.byond.com/docs/ref/skinparams.html).

### `Collapsible`

Displays contents when open, acts as a fluid button when closed. Click to
toggle, closed by default.

**Props:**

- See inherited props: [Box](#box)
- `children: any` - What is collapsed when closed
- `title: string` - Text to display on the button for collapsing
- `color: string` - Color of the button; see [Button](#button)
- `buttons: any` - Buttons or other content to render inline with the button

### `ColorBox`

Displays a 1-character wide colored square. Can be used as a status indicator,
or for visually representing a color.

If you want to set a background color on an element, use a plain
[Box](#box) instead.

**Props:**

- See inherited props: [Box](#box)
- `color: string` - Color of the box.

### `Dimmer`

Dims surrounding area to emphasize content placed inside.

Content is automatically centered inside the dimmer.

**Props:**

- See inherited props: [Box](#box)

### `Divider`

Draws a horizontal or vertical line, dividing a section into groups.
Works like the good old `<hr>` element, but it's fancier.

**Props:**

- `vertical: boolean` - Divide content vertically.
- `hidden: boolean` - Divider can divide content without creating a dividing
line.

### `Dropdown`

A simple dropdown box component. Lets the user select from a list of options
and displays selected entry.

**Props:**

- See inherited props: [Box](#box)
- See inherited props: [Icon](#icon)
- `options: string[]` - An array of strings which will be displayed in the
dropdown when open
- `selected: string` - Currently selected entry
- `width: number` - Width of dropdown button and resulting menu
- `over: boolean` - Dropdown renders over instead of below
- `color: string` - Color of dropdown button
- `nochevron: boolean` - Whether or not the arrow on the right hand side of the dropdown button is visible
- `noscroll: boolean` - Whether or not the dropdown menu should have a scroll bar
- `displayText: string` - Text to always display in place of the selected text
- `onClick: (e) => void` - Called when dropdown button is clicked
- `onSelected: (value) => void` - Called when a value is picked from the list, `value` is the value that was picked

### `Flex`

Quickly manage the layout, alignment, and sizing of grid columns, navigation,
components, and more with a full suite of responsive flexbox utilities.

If you are new to or unfamiliar with flexbox, we encourage you to read this
[CSS-Tricks flexbox guide](https://css-tricks.com/snippets/css/a-guide-to-flexbox/).

Consists of two elements: `<Flex>` and `<Flex.Item>`. Both of them provide
the most straight-forward mapping to flex CSS properties as possible.

One of the most basic usage of flex, is to align certain elements
to the left, and certain elements to the right:

```jsx
<Flex>
  <Flex.Item grow={1}>
    Button description
  </Flex.Item>
  <Flex.Item>
    <Button>
      Perform an action
    </Button>
  </Flex.Item>
</Flex>
```

Flex item with `grow` property will grow to take all available empty space,
while flex items without grow will take the minimum amount of space. This
effectively places the last flex item to the very end of the flex container.

**Props:**

- See inherited props: [Box](#box)
- ~~`spacing: number`~~ - **Removed in tgui 4.3**,
use [Stack](#stack) instead.
- `inline: boolean` - Makes flexbox container inline, with similar behavior
to an `inline` property on a `Box`.
- `direction: string` - This establishes the main-axis, thus defining the
direction flex items are placed in the flex container.
  - `row` (default) - left to right.
  - `row-reverse` - right to left.
  - `column` - top to bottom.
  - `column-reverse` - bottom to top.
- `wrap: string` - By default, flex items will all try to fit onto one line.
You can change that and allow the items to wrap as needed with this property.
  - `nowrap` (default) - all flex items will be on one line
  - `wrap` - flex items will wrap onto multiple lines, from top to bottom.
  - `wrap-reverse` - flex items will wrap onto multiple lines from bottom to top.
- `align: string` - Default alignment of all children.
  - `stretch` (default) - stretch to fill the container.
  - `start` - items are placed at the start of the cross axis.
  - `end` - items are placed at the end of the cross axis.
  - `center` - items are centered on the cross axis.
  - `baseline` - items are aligned such as their baselines align.
- `justify: string` - This defines the alignment along the main axis.
It helps distribute extra free space leftover when either all the flex
items on a line are inflexible, or are flexible but have reached their
maximum size. It also exerts some control over the alignment of items
when they overflow the line.
  - `flex-start` (default) - items are packed toward the start of the
  flex-direction.
  - `flex-end` - items are packed toward the end of the flex-direction.
  - `space-between` - items are evenly distributed in the line; first item is
  on the start line, last item on the end line
  - `space-around` - items are evenly distributed in the line with equal space
  around them. Note that visually the spaces aren't equal, since all the items
  have equal space on both sides. The first item will have one unit of space
  against the container edge, but two units of space between the next item
  because that next item has its own spacing that applies.
  - `space-evenly` - items are distributed so that the spacing between any two
  items (and the space to the edges) is equal.
  - TBD (not all properties are supported in IE11).

### `Flex.Item`

**Props:**

- See inherited props: [Box](#box)
- `order: number` - By default, flex items are laid out in the source order.
However, the order property controls the order in which they appear in the
flex container.
- `grow: number | boolean` - This defines the ability for a flex item to grow
if necessary. It accepts a unitless value that serves as a proportion. It
dictates what amount of the available space inside the flex container the
item should take up. This number is unit-less and is relative to other
siblings.
- `shrink: number | boolean` - This defines the ability for a flex item to
shrink if necessary. Inverse of `grow`.
- `basis: number | string` - This defines the default size of an element
before any flex-related calculations are done. Has to be a length
(e.g. `20%`, `5rem`), an `auto` or `content` keyword.
  - **Important:** IE11 flex is buggy, and auto width/height calculations
  can sometimes end up in a circular dependency. This usually happens, when
  working with tables inside flex (they have wacky internal widths and such).
  Setting basis to `0` breaks the loop and fixes all of the problems.
- `align: string` - This allows the default alignment (or the one specified by
align-items) to be overridden for individual flex items. See: [Flex](#flex).

### `Grid`

> **Deprecated:** This component is no longer recommended due to the variety
> of bugs that come with table-based layouts.
> We recommend using [Flex](#flex) instead.

Helps you to divide horizontal space into two or more equal sections.
It is essentially a single-row `Table`, but with some extra features.

Example:

```jsx
<Grid>
  <Grid.Column>
    <Section title="Section 1">
      Hello world!
    </Section>
  </Grid.Column>
  <Grid.Column size={2}>
    <Section title="Section 2">
      Hello world!
    </Section>
  </Grid.Column>
</Grid>
```

**Props:**

- See inherited props: [Table](#table)

### `Grid.Column`

**Props:**

- See inherited props: [Table.Cell](#tablecell)
- `size: number` (default: 1) - Size of the column relative to other columns.

### `Icon`

Renders one of the FontAwesome icons of your choice.

```jsx
<Icon name="plus" />
```

To smoothen the transition from v4 to v5, we have added a v4 semantic to
transform names with `-o` suffixes to FA Regular icons. For example:
- `square` will get transformed to `fas square`
- `square-o` will get transformed to `far square`

**Props:**

- See inherited props: [Box](#box)
- `name: string` - Icon name.
- `size: number` - Icon size. `1` is normal size, `2` is two times bigger.
Fractional numbers are supported.
- `rotation: number` - Icon rotation, in degrees.
- `spin: boolean` - Whether an icon should be spinning. Good for load
indicators.

### `Icon.Stack`

Renders children icons on top of each other in order to make your own icon.

```jsx
<Icon.Stack>
  <Icon name="pen" />
  <Icon name="slash" />
</Icon.Stack>
```

**Props:**

- See inherited props: [Box](#box)
- `children: Icon` - Icons to stack.

### `Input`

A basic text input, which allow users to enter text into a UI.

> Input does not support custom font size and height due to the way
> it's implemented in CSS. Eventually, this needs to be fixed.

**Props:**

- See inherited props: [Box](#box)
- `value: string` - Value of an input.
- `placeholder: string` - Text placed into Input box when it's empty,
otherwise nothing. Clears automatically when focused.
- `fluid: boolean` - Fill all available horizontal space.
- `selfClear: boolean` - Clear after hitting enter, as well as remain focused
when this happens. Useful for things like chat inputs.
- `onChange: (e, value) => void` - An event, which fires when you commit
the text by either unfocusing the input box, or by pressing the Enter key.
- `onInput: (e, value) => void` - An event, which fires on every keypress.

### `Knob`

A radial control, which allows dialing in precise values by dragging it
up and down.

Single click opens an input box to manually type in a number.

**Props:**

- See inherited props: [Box](#box)
- `animated: boolean` - Animates the value if it was changed externally.
- `bipolar: boolean` - Knob can be bipolar or unipolar.
- `size: number` - Relative size of the knob. `1` is normal size, `2` is two
times bigger. Fractional numbers are supported.
- `color: string` - Color of the outer ring around the knob.
- `value: number` - Value itself, controls the position of the cursor.
- `unit: string` - Unit to display to the right of value.
- `minValue: number` - Lowest possible value.
- `maxValue: number` - Highest possible value.
- `fillValue: number` - If set, this value will be used to set the fill
percentage of the outer ring independently of the main value.
- `ranges: { color: [from, to] }` - Applies a `color` to the outer ring around
the knob based on whether the value lands in the range between `from` and `to`.
See an example of this prop in [ProgressBar](#progressbar).
- `step: number` (default: 1) - Adjust value by this amount when
dragging the input.
- `stepPixelSize: number` (default: 1) - Screen distance mouse needs
to travel to adjust value by one `step`.
- `format: value => value` - Format value using this function before
displaying it.
- `suppressFlicker: number` - A number in milliseconds, for which the input
will hold off from updating while events propagate through the backend.
Default is about 250ms, increase it if you still see flickering.
- `onChange: (e, value) => void` - An event, which fires when you release
the input, or successfully enter a number.
- `onDrag: (e, value) => void` - An event, which fires about every 500ms
when you drag the input up and down, on release and on manual editing.

### `LabeledControls`

LabeledControls is a horizontal grid, that is designed to hold various
controls, like [Knobs](#knob) or small [Buttons](#button). Every item in
this grid is labeled at the bottom.

**Props:**

- See inherited props: [Box](#box)
- `children: LabeledControls.Item` - Items to render.

### `LabeledControls.Item`

**Props:**

- See inherited props: [Box](#box)
- `label: string` - Item label.

### `LabeledList`

LabeledList is a continuous, vertical list of text and other content, where
every item is labeled. It works just like a two column table, where first
column is labels, and second column is content.

```jsx
<LabeledList>
  <LabeledList.Item label="Item">
    Content
  </LabeledList.Item>
</LabeledList>
```

If you want to have a button on the right side of an item (for example,
to perform some sort of action), there is a way to do that:

```jsx
<LabeledList>
  <LabeledList.Item
    label="Item"
    buttons={(
      <Button>
        Click me!
      </Button>
    )}>
    Content
  </LabeledList.Item>
</LabeledList>
```

**Props:**

- `children: LabeledList.Item` - Items to render.

### `LabeledList.Item`

**Props:**

- `label: string|InfernoNode` - Item label.
- `color: string` - Sets the color of the text.
- `buttons: any` - Buttons to render aside the content.
- `children: any` - Content of this labeled item.

### `LabeledList.Divider`

Adds some empty space between LabeledList items.

Example:

```jsx
<LabeledList>
  <LabeledList.Item label="Foo">
    Content
  </LabeledList.Item>
  <LabeledList.Divider size={1} />
</LabeledList>
```

**Props:**

- `size: number` - Size of the divider.

### `Modal`

A modal window. Uses a [Dimmer](#dimmer) under the hood, and dynamically
adjusts its own size to fit the content you're trying to display.

Must be a direct child of a layout component (e.g. [Window](#window)).

**Props:**

- See inherited props: [Box](#box)

### `NoticeBox`

A notice box, which warns you about something very important.

**Props:**

- See inherited props: [Box](#box)
- `info: boolean` - Info box
- `success: boolean` - Success box
- `warning: bolean` - Warning box
- `danger: boolean` - Danger box

### `NumberInput`

A fancy, interactive number input, which you can either drag up and down
to fine tune the value, or single click it to manually type a number.

**Props:**

- `animated: boolean` - Animates the value if it was changed externally.
- `fluid: boolean` - Fill all available horizontal space.
- `value: number` - Value itself.
- `unit: string` - Unit to display to the right of value.
- `minValue: number` - Lowest possible value.
- `maxValue: number` - Highest possible value.
- `step: number` (default: 1) - Adjust value by this amount when
dragging the input.
- `stepPixelSize: number` (default: 1) - Screen distance mouse needs
to travel to adjust value by one `step`.
- `width: string|number` - Width of the element, in `Box` units or pixels.
- `height: string|numer` - Height of the element, in `Box` units or pixels.
- `lineHeight: string|number` - lineHeight of the element, in `Box` units or pixels.
- `fontSize: string|number` - fontSize of the element, in `Box` units or pixels.
- `format: value => value` - Format value using this function before
displaying it.
- `suppressFlicker: number` - A number in milliseconds, for which the input
will hold off from updating while events propagate through the backend.
Default is about 250ms, increase it if you still see flickering.
- `onChange: (e, value) => void` - An event, which fires when you release
the input, or successfully enter a number.
- `onDrag: (e, value) => void` - An event, which fires about every 500ms
when you drag the input up and down, on release and on manual editing.

### `Popper`

Popper lets you position elements so that they don't go out of the bounds of the window. See [popper.js](https://popper.js.org/) for more information.

**Props:**

- `popperContent: InfernoNode` - The content that will be put inside the popper.
- `options?: { ... }` - An object of options to pass to `createPopper`. See [https://popper.js.org/docs/v2/constructors/#options], but the one you want most is `placement`. Valid placements are "bottom", "top", "left", and "right". You can affix "-start" and "-end" to achieve something like top left or top right respectively. You can also use "auto" (with an optional "-start" or "-end"), where a best fit will be chosen.
- `additionalStyles: { ... }` - A map of CSS styles to add to the element that will contain the popper.

### `ProgressBar`

Progress indicators inform users about the status of ongoing processes.

```jsx
<ProgressBar value={0.6} />
```

Usage of `ranges` prop:

```jsx
<ProgressBar
  ranges={{
    good: [0.5, Infinity],
    average: [0.25, 0.5],
    bad: [-Infinity, 0.25],
  }}
  value={0.6} />
```

**Props:**

- `value: number` - Current progress as a floating point number between
`minValue` (default: 0) and `maxValue` (default: 1). Determines the
percentage and how filled the bar is.
- `minValue: number` - Lowest possible value.
- `maxValue: number` - Highest possible value.
- `ranges: { color: [from, to] }` - Applies a `color` to the progress bar
based on whether the value lands in the range between `from` and `to`.
- `color: string` - Color of the progress bar. Can take any of the following formats:
  - `#ffffff` - Hex format
  - `rgb(r,g,b) / rgba(r,g,b,a)` - RGB format
  - `<name>` - the name of a `color-<name>` CSS class. See `CSS_COLORS` in `constants.js`.
  - `<name>` - the name of a base CSS color, if not overridden by the definitions above.
- `children: any` - Content to render inside the progress bar.

### `RoundGauge`

The RoundGauge component provides a visual representation of a single metric, as well as being capable of showing informational or cautionary boundaries related to that metric.

```jsx
<RoundGauge
  size={1.75}
  value={tankPressure}
  minValue={0}
  maxValue={pressureLimit}
  alertAfter={pressureLimit * 0.70}
  ranges={{
    "good": [0, pressureLimit * 0.70],
    "average": [pressureLimit * 0.70, pressureLimit * 0.85],
    "bad": [pressureLimit * 0.85, pressureLimit],
  }}
  format={formatPressure} />
```

The alert on the gauge is optional, and will only be shown if the `alertAfter` prop is defined. When defined, the alert will begin to flash the respective color upon which the needle currently rests, as defined in the `ranges` prop.

**Props:**

- See inherited props: [Box](#box)
- `value: number` - The current value of the metric.
- `minValue: number` (default: 0) - The lower bound of the guage.
- `maxValue: number` (default: 1) - The upper bound of the guage.
- `ranges: { color: [from, to] }` (default: `{ "good": [0, 1] }`) - Provide regions of the guage to color between two specified values of the metric.
- `alertAfter: number` (optional) - When provided, will cause an alert symbol on the gauge to begin flashing in the color upon which the needle currently rests, as defined in `ranges`.
- `alertBefore: number` (optional) - As with alertAfter, but alerts below a value. If both are set, and alertAfter comes earlier, the alert will only flash when the needle is between both values. Otherwise, the alert will flash when on the active side of either threshold.
- `format: function(value) => string` (optional) - When provided, will be used to format the value of the metric for display.
- `size: number` (default: 1) - When provided scales the gauge.

### `Section`

Section is a surface that displays content and actions on a single topic.

They should be easy to scan for relevant and actionable information.
Elements, like text and images, should be placed in them in a way that
clearly indicates hierarchy.

Section can also be titled to clearly define its purpose.

```jsx
<Section title="Cargo">
  Here you can order supply crates.
</Section>
```

If you want to have a button on the right side of an section title
(for example, to perform some sort of action), there is a way to do that:

```jsx
<Section
  title="Cargo"
  buttons={(
    <Button>
      Send shuttle
    </Button>
  )}>
  Here you can order supply crates.
</Section>
```

**New:** Sections can now be nested, and will automatically font size of the
header according to their nesting level. Previously this was done via `level`
prop, but now it is automatically calculated.

- See inherited props: [Box](#box)
- `title: string` - Title of the section.
- `buttons: any` - Buttons to render aside the section title.
- `fill: boolean` - If true, fills all available vertical space.
- `fitted: boolean` - If true, removes all section padding.
- `scrollable: boolean` - Shows or hides the scrollbar.
- `children: any` - Content of this section.

### `Slider`

A horizontal, [ProgressBar](#progressbar)-like control, which allows dialing
in precise values by dragging it left and right.

Single click opens an input box to manually type in a number.

**Props:**

- See inherited props: [Box](#box)
- `animated: boolean` - Animates the value if it was changed externally.
- `color: string` - Color of the slider.
- `value: number` - Value itself, controls the position of the cursor.
- `unit: string` - Unit to display to the right of value.
- `minValue: number` - Lowest possible value.
- `maxValue: number` - Highest possible value.
- `fillValue: number` - If set, this value will be used to set the fill
percentage of the progress bar filler independently of the main value.
- `ranges: { color: [from, to] }` - Applies a `color` to the slider
based on whether the value lands in the range between `from` and `to`.
See an example of this prop in [ProgressBar](#progressbar).
- `step: number` (default: 1) - Adjust value by this amount when
dragging the input.
- `stepPixelSize: number` (default: 1) - Screen distance mouse needs
to travel to adjust value by one `step`.
- `format: value => value` - Format value using this function before
displaying it.
- `suppressFlicker: number` - A number in milliseconds, for which the input
will hold off from updating while events propagate through the backend.
Default is about 250ms, increase it if you still see flickering.
- `onChange: (e, value) => void` - An event, which fires when you release
the input, or successfully enter a number.
- `onDrag: (e, value) => void` - An event, which fires about every 500ms
when you drag the input up and down, on release and on manual editing.

### `Stack`

A higher-level component, that is based on [Flex](#flex). The main difference
from `Flex`, is that this component automatically adds spacing between
all stack items, reducing the boilerplate that you have to write!

Consists of two elements: `<Stack>` and `<Stack.Item>`.

Stacks can be vertical by adding a `vertical` property.

**Example:**

```jsx
<Stack>
  <Stack.Item grow>
    Button description
  </Stack.Item>
  <Stack.Item>
    <Button>
      Perform an action
    </Button>
  </Stack.Item>
</Stack>
```

**Example of a high-level window layout:**

Stacks can be used for high level window layout.
Make sure to use the `fill` property.

```jsx
<Window>
  <Window.Content>
    <Stack fill>
      <Stack.Item>
        <Section fill>
          Sidebar
        </Section>
      </Stack.Item>
      <Stack.Item grow>
        <Stack fill vertical>
          <Stack.Item grow>
            <Section fill scrollable>
              Main content
            </Section>
          </Stack.Item>
          <Stack.Item>
            <Section>
              Bottom pane
            </Section>
          </Stack.Item>
        </Stack>
      </Stack.Item>
    </Stack>
  </Window.Content>
</Window>
```

**Props:**

- See inherited props: [Flex](#flex)
- `fill: boolean` - If set, stack will fill all available height.
- `vertical: boolean` - If set, stack will work in vertical mode.

### `Stack.Item`

**Props:**

- See inherited props: [Flex.Item](#flexitem)

### `Table`

A straight forward mapping to a standard html table, which is slightly
simplified (does not need a `<tbody>` tag) and with sane default styles
(e.g. table width is 100% by default).

Example:

```jsx
<Table>
  <Table.Row>
    <Table.Cell bold>
      Hello world!
    </Table.Cell>
    <Table.Cell collapsing color="label">
      Label
    </Table.Cell>
  </Table.Row>
</Table>
```

**Props:**

- See inherited props: [Box](#box)
- `collapsing: boolean` - Collapses table to the smallest possible size.

### `Table.Row`

A straight forward mapping to `<tr>` element.

**Props:**

- See inherited props: [Box](#box)

### `Table.Cell`

A straight forward mapping to `<td>` element.

**Props:**

- See inherited props: [Box](#box)
- `collapsing: boolean` - Collapses table cell to the smallest possible size,
and stops any text inside from wrapping.

### `Tabs`

Tabs make it easy to explore and switch between different views.

Here is an example of how you would construct a simple tabbed view:

```jsx
<Tabs>
  <Tabs.Tab
    selected={tabIndex === 1}
    onClick={() => setTabIndex(1)}>
    Tab one
  </Tabs.Tab>
  <Tabs.Tab
    selected={tabIndex === 2}
    onClick={() => setTabIndex(2)}>
    Tab two
  </Tabs.Tab>
</Tabs>
<Box>
  Tab selected: {tabIndex}
</Box>
```

Notice that tabs do not contain state. It is your job to track the selected
tab, handle clicks and place tab content where you need it. In return, you get
a lot of flexibility in regards to how you can layout your tabs.

Tabs also support a vertical configuration. This is usually paired with
[Stack](#stack) to render tab content to the right.

```jsx
<Stack>
  <Stack.Item>
    <Tabs vertical>
      ...
    </Tabs>
  </Stack.Item>
  <Stack.Item grow={1} basis={0}>
    Tab content.
  </Stack.Item>
</Stack>
```

If you need to combine a tab section with other elements, or if you want to
add scrollable functionality to tabs, pair them with the [Section](#section)
component:

```jsx
<Section fill fitted scrollable width="128px">
  <Tabs vertical>
    ...
  </Tabs>
  ... other things ...
</Section>
```

**Props:**

- See inherited props: [Box](#box)
- `fluid: boolean` - If true, tabs will take all available horizontal space.
- `fill: boolean` - Similarly to `fill` on [Section](#section), tabs will fill
all available vertical space. Only makes sense in a vertical configuration.
- `vertical: boolean` - Use a vertical configuration, where tabs will be
stacked vertically.
- `children: Tab[]` - This component only accepts tabs as its children.

### `Tabs.Tab`

An individual tab element. Tabs function like buttons, so they inherit
a lot of `Button` props.

**Props:**

- See inherited props: [Button](#button)
- `altSelection` - Whether the tab buttons select via standard select (color
change) or by adding a white indicator to the selected tab.
Intended for usage on interfaces where tab color has relevance.
- `icon: string` - Tab icon.
- `children: any` - Tab text.
- `onClick: function` - Called when element is clicked.

### `Tooltip`

A boxy tooltip from tgui 1. It is very hacky in its current state, and
requires setting `position: relative` on the container.

Please note, that [Button](#button) component has a `tooltip` prop, and
it is recommended to use that prop instead.

Usage:

```jsx
<Tooltip position="bottom" content="Box tooltip">
  <Box position="relative">
    Sample text.
  </Box>
</Tooltip>
```

**Props:**

- `position?: string` - Tooltip position. See [`Popper`](#Popper) for valid options. Defaults to "auto".
- `content: string` - Content of the tooltip. Must be a plain string.
Fragments or other elements are **not** supported.

## `tgui/layouts`

### `Window`

A root-level component, which draws the window chrome, titlebar, resize
handlers, and controls the UI theme. All tgui interfaces must implement
it in one way or another.

Example:

```jsx
<Window theme="hackerman">
  <Window.Content scrollable>
    Hello, world!
  </Window.Content>
</Window>
```

**Props:**

- See inherited props: [Box](#box)
- `className: string` - Applies a CSS class to the element.
- `theme: string` - A name of the theme.
  - For a list of themes, see `packages/tgui/styles/themes`.
- `title: string` - Window title.
- `width: number` - Window width.
- `height: number` - Window height.
- `canClose: boolean` - Controls the ability to close the window.
- `children: any` - Child elements, which are rendered directly inside the
window. If you use a [Dimmer](#dimmer) or [Modal](#modal) in your UI,
they should be put as direct childs of a Window, otherwise you should be
putting your content into [Window.Content](#windowcontent).

### `Window.Content`

Canonical window content, which is usually the main target of window focus.
Can be scrollable.

**Props:**

- See inherited props: [Box](#box)
- `className: string` - Applies a CSS class to the element.
- `fitted: boolean` - If true, removes all padding.
- `scrollable: boolean` - Shows or hides the scrollbar.
- `children: any` - Main content of your window.