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

import { classes, pureComponentHooks } from 'common/react';
import { Box } from './Box';

export const NoticeBox = props => {
  const {
    className,
    color,
    info,
    warning,
    success,
    danger,
    ...rest
  } = props;
  return (
    <Box
      className={classes([
        'NoticeBox',
        color && 'NoticeBox--color--' + color,
        info && 'NoticeBox--type--info',
        success && 'NoticeBox--type--success',
        danger && 'NoticeBox--type--danger',
        className,
      ])}
      {...rest} />
  );
};

NoticeBox.defaultHooks = pureComponentHooks;


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

import { clamp } from 'common/math';
import { classes, pureComponentHooks } from 'common/react';
import { Component, createRef } from 'inferno';
import { AnimatedNumber } from './AnimatedNumber';
import { Box } from './Box';

const DEFAULT_UPDATE_RATE = 400;

export class NumberInput extends Component {
  constructor(props) {
    super(props);
    const { value } = props;
    this.inputRef = createRef();
    this.state = {
      value,
      dragging: false,
      editing: false,
      internalValue: null,
      origin: null,
      suppressingFlicker: false,
    };

    // Suppresses flickering while the value propagates through the backend
    this.flickerTimer = null;
    this.suppressFlicker = () => {
      const { suppressFlicker } = this.props;
      if (suppressFlicker > 0) {
        this.setState({
          suppressingFlicker: true,
        });
        clearTimeout(this.flickerTimer);
        this.flickerTimer = setTimeout(() => this.setState({
          suppressingFlicker: false,
        }), suppressFlicker);
      }
    };

    this.handleDragStart = e => {
      const { value } = this.props;
      const { editing } = this.state;
      if (editing) {
        return;
      }
      document.body.style['pointer-events'] = 'none';
      this.ref = e.target;
      this.setState({
        dragging: false,
        origin: e.screenY,
        value,
        internalValue: value,
      });
      this.timer = setTimeout(() => {
        this.setState({
          dragging: true,
        });
      }, 250);
      this.dragInterval = setInterval(() => {
        const { dragging, value } = this.state;
        const { onDrag } = this.props;
        if (dragging && onDrag) {
          onDrag(e, value);
        }
      }, this.props.updateRate || DEFAULT_UPDATE_RATE);
      document.addEventListener('mousemove', this.handleDragMove);
      document.addEventListener('mouseup', this.handleDragEnd);
    };

    this.handleDragMove = e => {
      const { minValue, maxValue, step, stepPixelSize } = this.props;
      this.setState(prevState => {
        const state = { ...prevState };
        const offset = state.origin - e.screenY;
        if (prevState.dragging) {
          const stepOffset = Number.isFinite(minValue)
            ? minValue % step
            : 0;
          // Translate mouse movement to value
          // Give it some headroom (by increasing clamp range by 1 step)
          state.internalValue = clamp(
            state.internalValue + offset * step / stepPixelSize,
            minValue - step,
            maxValue + step);
          // Clamp the final value
          state.value = clamp(
            state.internalValue
              - state.internalValue % step
              + stepOffset,
            minValue,
            maxValue);
          state.origin = e.screenY;
        }
        else if (Math.abs(offset) > 4) {
          state.dragging = true;
        }
        return state;
      });
    };

    this.handleDragEnd = e => {
      const { onChange, onDrag } = this.props;
      const { dragging, value, internalValue } = this.state;
      document.body.style['pointer-events'] = 'auto';
      clearTimeout(this.timer);
      clearInterval(this.dragInterval);
      this.setState({
        dragging: false,
        editing: !dragging,
        origin: null,
      });
      document.removeEventListener('mousemove', this.handleDragMove);
      document.removeEventListener('mouseup', this.handleDragEnd);
      if (dragging) {
        this.suppressFlicker();
        if (onChange) {
          onChange(e, value);
        }
        if (onDrag) {
          onDrag(e, value);
        }
      }
      else if (this.inputRef) {
        const input = this.inputRef.current;
        input.value = internalValue;
        // IE8: Dies when trying to focus a hidden element
        // (Error: Object does not support this action)
        try {
          input.focus();
          input.select();
        }
        catch {}
      }
    };
  }

  render() {
    const {
      dragging,
      editing,
      value: intermediateValue,
      suppressingFlicker,
    } = this.state;
    const {
      className,
      fluid,
      animated,
      value,
      unit,
      minValue,
      maxValue,
      height,
      width,
      lineHeight,
      fontSize,
      format,
      onChange,
      onDrag,
    } = this.props;
    let displayValue = value;
    if (dragging || suppressingFlicker) {
      displayValue = intermediateValue;
    }
    // IE8: Use an "unselectable" prop because "user-select" doesn't work.
    const renderContentElement = value => (
      <div
        className="NumberInput__content"
        unselectable={Byond.IS_LTE_IE8}>
        {value + (unit ? ' ' + unit : '')}
      </div>
    );
    const contentElement = (animated && !dragging && !suppressingFlicker && (
      <AnimatedNumber
        value={displayValue}
        format={format}>
        {renderContentElement}
      </AnimatedNumber>
    ) || (
      renderContentElement(format ? format(displayValue) : displayValue)
    ));
    return (
      <Box
        className={classes([
          'NumberInput',
          fluid && 'NumberInput--fluid',
          className,
        ])}
        minWidth={width}
        minHeight={height}
        lineHeight={lineHeight}
        fontSize={fontSize}
        onMouseDown={this.handleDragStart}>
        <div className="NumberInput__barContainer">
          <div
            className="NumberInput__bar"
            style={{
              height: clamp(
                (displayValue - minValue) / (maxValue - minValue) * 100,
                0, 100) + '%',
            }} />
        </div>
        {contentElement}
        <input
          ref={this.inputRef}
          className="NumberInput__input"
          style={{
            display: !editing ? 'none' : undefined,
            height: height,
            'line-height': lineHeight,
            'font-size': fontSize,
          }}
          onBlur={e => {
            if (!editing) {
              return;
            }
            const value = clamp(
              parseFloat(e.target.value),
              minValue,
              maxValue);
            if (Number.isNaN(value)) {
              this.setState({
                editing: false,
              });
              return;
            }
            this.setState({
              editing: false,
              value,
            });
            this.suppressFlicker();
            if (onChange) {
              onChange(e, value);
            }
            if (onDrag) {
              onDrag(e, value);
            }
          }}
          onKeyDown={e => {
            if (e.keyCode === 13) {
              const value = clamp(
                parseFloat(e.target.value),
                minValue,
                maxValue);
              if (Number.isNaN(value)) {
                this.setState({
                  editing: false,
                });
                return;
              }
              this.setState({
                editing: false,
                value,
              });
              this.suppressFlicker();
              if (onChange) {
                onChange(e, value);
              }
              if (onDrag) {
                onDrag(e, value);
              }
              return;
            }
            if (e.keyCode === 27) {
              this.setState({
                editing: false,
              });
              return;
            }
          }} />
      </Box>
    );
  }
}

NumberInput.defaultHooks = pureComponentHooks;
NumberInput.defaultProps = {
  minValue: -Infinity,
  maxValue: +Infinity,
  step: 1,
  stepPixelSize: 1,
  suppressFlicker: 50,
};

repo_name: AnalWerewolf/sundown

license: mit


code:
import { createPopper } from "@popperjs/core";
import { ArgumentsOf } from "common/types";
import { Component, findDOMfromVNode, InfernoNode, render } from "inferno";

type PopperProps = {
  popperContent: InfernoNode;
  options?: ArgumentsOf<typeof createPopper>[2];
  additionalStyles?: CSSProperties,
};

export class Popper extends Component<PopperProps> {
  static id: number = 0;

  renderedContent: HTMLDivElement;
  popperInstance: ReturnType<typeof createPopper>;

  constructor() {
    super();

    Popper.id += 1;
  }

  componentDidMount() {
    const {
      additionalStyles,
      options,
    } = this.props;

    this.renderedContent = document.createElement("div");
    if (additionalStyles) {
      for (const [attribute, value] of Object.entries(additionalStyles)) {
        this.renderedContent.style[attribute] = value;
      }
    }

    this.renderPopperContent(() => {
      document.body.appendChild(this.renderedContent);

      // HACK: We don't want to create a wrapper, as it could break the layout
      // of consumers, so we do the inferno equivalent of `findDOMNode(this)`.
      // This is usually bad as refs are usually better, but refs did
      // not work in this case, as they weren't propagating correctly.
      // A previous attempt was made as a render prop that passed an ID,
      // but this made consuming use too unwieldly.
      // This code is copied from `findDOMNode` in inferno-extras.
      // Because this component is written in TypeScript, we will know
      // immediately if this internal variable is removed.
      const domNode = findDOMfromVNode(this.$LI, true);
      if (!domNode) {
        return;
      }

      this.popperInstance = createPopper(
        domNode,
        this.renderedContent,
        options,
      );
    });
  }

  componentDidUpdate() {
    this.renderPopperContent(() => this.popperInstance?.update());
  }

  componentWillUnmount() {
    this.popperInstance?.destroy();
    render(null, this.renderedContent, () => this.renderedContent.remove());
  }

  renderPopperContent(callback: () => void) {
    // `render` errors when given false, so we convert it to `null`,
    // which is supported.
    render(
      this.props.popperContent || null,
      this.renderedContent,
      callback,
      this.context,
    );
  }

  render() {
    return this.props.children;
  }
}


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

import { clamp01, scale, keyOfMatchingRange, toFixed } from 'common/math';
import { classes, pureComponentHooks } from 'common/react';
import { computeBoxClassName, computeBoxProps } from './Box';
import { CSS_COLORS } from '../constants';

export const ProgressBar = props => {
  const {
    className,
    value,
    minValue = 0,
    maxValue = 1,
    color,
    ranges = {},
    children,
    ...rest
  } = props;
  const scaledValue = scale(value, minValue, maxValue);
  const hasContent = children !== undefined;
  const effectiveColor = color
    || keyOfMatchingRange(value, ranges)
    || 'default';

  // We permit colors to be in hex format, rgb()/rgba() format,
  // a name for a color-<name> class, or a base CSS class.
  const outerProps = computeBoxProps(rest);
  const outerClasses = [
    'ProgressBar',
    className,
    computeBoxClassName(rest),
  ];
  const fillStyles = {
    'width': clamp01(scaledValue) * 100 + '%',
  };
  if (CSS_COLORS.includes(effectiveColor) || effectiveColor === 'default') {
    // If the color is a color-<name> class, just use that.
    outerClasses.push('ProgressBar--color--' + effectiveColor);
  } else {
    // Otherwise, set styles directly.
    outerProps.style = (outerProps.style || "")
      + `border-color: ${effectiveColor};`;
    fillStyles['background-color'] = effectiveColor;
  }

  return (
    <div
      className={classes(outerClasses)}
      {...outerProps}>
      <div
        className="ProgressBar__fill ProgressBar__fill--animated"
        style={fillStyles} />
      <div className="ProgressBar__content">
        {hasContent
          ? children
          : toFixed(scaledValue * 100) + '%'}
      </div>
    </div>
  );
};

ProgressBar.defaultHooks = pureComponentHooks;


code:
/**
 * @file
 * @copyright 2020 bobbahbrown (https://github.com/bobbahbrown)
 * @license MIT
 */

import { clamp01, keyOfMatchingRange, scale } from 'common/math';
import { classes } from 'common/react';
import { AnimatedNumber } from './AnimatedNumber';
import { Box, computeBoxClassName, computeBoxProps } from './Box';

export const RoundGauge = props => {
  // Support for IE8 is for losers sorry B)
  if (Byond.IS_LTE_IE8) {
    return (
      <AnimatedNumber {...props} />
    );
  }

  const {
    value,
    minValue = 1,
    maxValue = 1,
    ranges,
    alertAfter,
    alertBefore,
    format,
    size = 1,
    className,
    style,
    ...rest
  } = props;

  const scaledValue = scale(
    value,
    minValue,
    maxValue);
  const clampedValue = clamp01(scaledValue);
  const scaledRanges = ranges ? {} : { "primary": [0, 1] };
  if (ranges) {
    Object.keys(ranges).forEach(x => {
      const range = ranges[x];
      scaledRanges[x] = [
        scale(range[0], minValue, maxValue),
        scale(range[1], minValue, maxValue),
      ];
    });
  }

  const shouldShowAlert = () => {
    // If both after and before alert props are set, attempt to interpret both
    // in a helpful way.
    if (alertAfter && alertBefore && alertAfter < alertBefore) {
      // If alertAfter is before alertBefore, only display an alert if
      // we're between them.
      if (alertAfter < value && alertBefore > value) {
        return true;
      }
    } else if (alertAfter < value || alertBefore > value) {
      // Otherwise, we have distint ranges, or only one or neither are set.
      // Either way, being on the active side of either is sufficient.
      return true;
    }
    return false;
  };

  const alertColor = shouldShowAlert()
    && keyOfMatchingRange(clampedValue, scaledRanges);

  return (
    <Box inline>
      <div
        className={classes([
          'RoundGauge',
          className,
          computeBoxClassName(rest),
        ])}
        {...computeBoxProps({
          style: {
            'font-size': size + 'em',
            ...style,
          },
          ...rest,
        })}>
        <svg
          viewBox="0 0 100 50">
          {(alertAfter || alertBefore) && (
            <g className={classes([
              'RoundGauge__alert',
              alertColor ? `active RoundGauge__alert--${alertColor}` : '',
            ])}>
              <path d="M48.211,14.578C48.55,13.9 49.242,13.472 50,13.472C50.758,13.472 51.45,13.9 51.789,14.578C54.793,20.587 60.795,32.589 63.553,38.106C63.863,38.726 63.83,39.462 63.465,40.051C63.101,40.641 62.457,41 61.764,41C55.996,41 44.004,41 38.236,41C37.543,41 36.899,40.641 36.535,40.051C36.17,39.462 36.137,38.726 36.447,38.106C39.205,32.589 45.207,20.587 48.211,14.578ZM50,34.417C51.426,34.417 52.583,35.574 52.583,37C52.583,38.426 51.426,39.583 50,39.583C48.574,39.583 47.417,38.426 47.417,37C47.417,35.574 48.574,34.417 50,34.417ZM50,32.75C50,32.75 53,31.805 53,22.25C53,20.594 51.656,19.25 50,19.25C48.344,19.25 47,20.594 47,22.25C47,31.805 50,32.75 50,32.75Z" />
            </g>
          )}
          <g>
            <circle
              className="RoundGauge__ringTrack"
              cx="50"
              cy="50"
              r="45" />
          </g>
          <g>
            {Object.keys(scaledRanges).map((x, i) => {
              const col_ranges = scaledRanges[x];
              return (
                <circle
                  className={`RoundGauge__ringFill RoundGauge--color--${x}`}
                  key={i}
                  style={{
                    'stroke-dashoffset': (
                      Math.max((2.0 - (col_ranges[1] - col_ranges[0]))
                        * Math.PI * 50, 0)
                    ),
                  }}
                  transform={`rotate(${180 + 180 * col_ranges[0]} 50 50)`}
                  cx="50"
                  cy="50"
                  r="45" />
              );
            })}
          </g>
          <g
            className="RoundGauge__needle"
            transform={`rotate(${clampedValue * 180 - 90} 50 50)`}>
            <polygon
              className="RoundGauge__needleLine"
              points="46,50 50,0 54,50" />
            <circle
              className="RoundGauge__needleMiddle"
              cx="50"
              cy="50"
              r="8" />
          </g>
        </svg>
      </div>
      <AnimatedNumber
        value={value}
        format={format}
        size={size} />
    </Box>
  );
};


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

import { canRender, classes } from 'common/react';
import { Component, createRef, InfernoNode, RefObject } from 'inferno';
import { addScrollableNode, removeScrollableNode } from '../events';
import { BoxProps, computeBoxClassName, computeBoxProps } from './Box';

interface SectionProps extends BoxProps {
  className?: string;
  title?: string;
  buttons?: InfernoNode;
  fill?: boolean;
  fitted?: boolean;
  scrollable?: boolean;
  /** @deprecated This property no longer works, please remove it. */
  level?: boolean;
  /** @deprecated Please use `scrollable` property */
  overflowY?: any;
}

export class Section extends Component<SectionProps> {
  scrollableRef: RefObject<HTMLDivElement>;
  scrollable: boolean;

  constructor(props) {
    super(props);
    this.scrollableRef = createRef();
    this.scrollable = props.scrollable;
  }

  componentDidMount() {
    if (this.scrollable) {
      addScrollableNode(this.scrollableRef.current);
    }
  }

  componentWillUnmount() {
    if (this.scrollable) {
      removeScrollableNode(this.scrollableRef.current);
    }
  }

  render() {
    const {
      className,
      title,
      buttons,
      fill,
      fitted,
      scrollable,
      children,
      ...rest
    } = this.props;
    const hasTitle = canRender(title) || canRender(buttons);
    return (

        {hasTitle && (

              {title}

              {buttons}

        )}

            {children}

    );
  }
}


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

import { clamp01, keyOfMatchingRange, scale } from 'common/math';
import { classes } from 'common/react';
import { computeBoxClassName, computeBoxProps } from './Box';
import { DraggableControl } from './DraggableControl';
import { NumberInput } from './NumberInput';

export const Slider = props => {
  // IE8: I don't want to support a yet another component on IE8.
  if (Byond.IS_LTE_IE8) {
    return (
      <NumberInput {...props} />
    );
  }
  const {
    // Draggable props (passthrough)
    animated,
    format,
    maxValue,
    minValue,
    onChange,
    onDrag,
    step,
    stepPixelSize,
    suppressFlicker,
    unit,
    value,
    // Own props
    className,
    fillValue,
    color,
    ranges = {},
    children,
    ...rest
  } = props;
  const hasContent = children !== undefined;
  return (
    <DraggableControl
      dragMatrix={[1, 0]}
      {...{
        animated,
        format,
        maxValue,
        minValue,
        onChange,
        onDrag,
        step,
        stepPixelSize,
        suppressFlicker,
        unit,
        value,
      }}>
      {control => {
        const {
          dragging,
          editing,
          value,
          displayValue,
          displayElement,
          inputElement,
          handleDragStart,
        } = control;
        const hasFillValue = fillValue !== undefined
          && fillValue !== null;
        const scaledValue = scale(
          value,
          minValue,
          maxValue);
        const scaledFillValue = scale(
          fillValue ?? displayValue,
          minValue,
          maxValue);
        const scaledDisplayValue = scale(
          displayValue,
          minValue,
          maxValue);
        const effectiveColor = color
          || keyOfMatchingRange(fillValue ?? value, ranges)
          || 'default';
        return (

              {dragging && (

                  {displayElement}

              )}

              {hasContent
                ? children
                : displayElement}

            {inputElement}

        );
      }}
    </DraggableControl>
  );
};


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

import { classes } from 'common/react';
import { RefObject } from 'inferno';
import { computeFlexClassName, computeFlexItemClassName, computeFlexItemProps, computeFlexProps, FlexItemProps, FlexProps } from './Flex';

type StackProps = FlexProps & {
  vertical?: boolean;
  fill?: boolean;
};

export const Stack = (props: StackProps) => {
  const { className, vertical, fill, ...rest } = props;
  return (
    <div
      className={classes([
        'Stack',
        fill && 'Stack--fill',
        vertical
          ? 'Stack--vertical'
          : 'Stack--horizontal',
        className,
        computeFlexClassName(props),
      ])}
      {...computeFlexProps({
        direction: vertical ? 'column' : 'row',
        ...rest,
      })}
    />
  );
};

type StackItemProps = FlexProps & {
  innerRef?: RefObject<HTMLDivElement>,
};

const StackItem = (props: StackItemProps) => {
  const { className, innerRef, ...rest } = props;
  return (
    <div
      className={classes([
        'Stack__item',
        className,
        computeFlexItemClassName(rest),
      ])}
      ref={innerRef}
      {...computeFlexItemProps(rest)}
    />
  );
};

Stack.Item = StackItem;

type StackDividerProps = FlexItemProps & {
  hidden?: boolean;
};

const StackDivider = (props: StackDividerProps) => {
  const { className, hidden, ...rest } = props;
  return (
    <div
      className={classes([
        'Stack__item',
        'Stack__divider',
        hidden && 'Stack__divider--hidden',
        className,
        computeFlexItemClassName(rest),
      ])}
      {...computeFlexItemProps(rest)}
    />
  );
};

Stack.Divider = StackDivider;


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

import { classes, pureComponentHooks } from 'common/react';
import { computeBoxClassName, computeBoxProps } from './Box';

export const Table = props => {
  const {
    className,
    collapsing,
    children,
    ...rest
  } = props;
  return (
    <table
      className={classes([
        'Table',
        collapsing && 'Table--collapsing',
        className,
        computeBoxClassName(rest),
      ])}
      {...computeBoxProps(rest)}>
      <tbody>
        {children}
      </tbody>
    </table>
  );
};

Table.defaultHooks = pureComponentHooks;

export const TableRow = props => {
  const {
    className,
    header,
    ...rest
  } = props;
  return (
    <tr
      className={classes([
        'Table__row',
        header && 'Table__row--header',
        className,
        computeBoxClassName(props),
      ])}
      {...computeBoxProps(rest)} />
  );
};

TableRow.defaultHooks = pureComponentHooks;

export const TableCell = props => {
  const {
    className,
    collapsing,
    header,
    ...rest
  } = props;
  return (
    <td
      className={classes([
        'Table__cell',
        collapsing && 'Table__cell--collapsing',
        header && 'Table__cell--header',
        className,
        computeBoxClassName(props),
      ])}
      {...computeBoxProps(rest)} />
  );
};

TableCell.defaultHooks = pureComponentHooks;

Table.Row = TableRow;
Table.Cell = TableCell;


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

import { canRender, classes } from 'common/react';
import { computeBoxClassName, computeBoxProps } from './Box';
import { Icon } from './Icon';

export const Tabs = props => {
  const {
    className,
    vertical,
    fill,
    fluid,
    children,
    ...rest
  } = props;
  return (

      {children}

  );
};

const Tab = props => {
  const {
    className,
    selected,
    color,
    icon,
    leftSlot,
    rightSlot,
    children,
    ...rest
  } = props;
  return (

      {canRender(leftSlot) && (

          {leftSlot}

      ) || !!icon && (

          <Icon name={icon} />

      )}

        {children}

      {canRender(rightSlot) && (

          {rightSlot}

      )}

  );
};

Tabs.Tab = Tab;


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

import { classes } from 'common/react';
import { Component, createRef } from 'inferno';
import { Box } from './Box';
import { toInputValue } from './Input';
import { KEY_ESCAPE } from 'common/keycodes';

export class TextArea extends Component {
  constructor(props, context) {
    super(props, context);
    this.textareaRef = createRef();
    this.fillerRef = createRef();
    this.state = {
      editing: false,
    };
    const {
      dontUseTabForIndent = false,
    } = props;
    this.handleOnInput = e => {
      const { editing } = this.state;
      const { onInput } = this.props;
      if (!editing) {
        this.setEditing(true);
      }
      if (onInput) {
        onInput(e, e.target.value);
      }
    };
    this.handleOnChange = e => {
      const { editing } = this.state;
      const { onChange } = this.props;
      if (editing) {
        this.setEditing(false);
      }
      if (onChange) {
        onChange(e, e.target.value);
      }
    };
    this.handleKeyPress = e => {
      const { editing } = this.state;
      const { onKeyPress } = this.props;
      if (!editing) {
        this.setEditing(true);
      }
      if (onKeyPress) {
        onKeyPress(e, e.target.value);
      }
    };
    this.handleKeyDown = e => {
      const { editing } = this.state;
      const { onKeyDown } = this.props;
      if (e.keyCode === KEY_ESCAPE) {
        this.setEditing(false);
        e.target.value = toInputValue(this.props.value);
        e.target.blur();
        return;
      }
      if (!editing) {
        this.setEditing(true);
      }
      if (!dontUseTabForIndent) {
        const keyCode = e.keyCode || e.which;
        if (keyCode === 9) {
          e.preventDefault();
          const { value, selectionStart, selectionEnd } = e.target;
          e.target.value = (
            value.substring(0, selectionStart) + "\t"
              + value.substring(selectionEnd)
          );
          e.target.selectionEnd = selectionStart + 1;
        }
      }
      if (onKeyDown) {
        onKeyDown(e, e.target.value);
      }
    };
    this.handleFocus = e => {
      const { editing } = this.state;
      if (!editing) {
        this.setEditing(true);
      }
    };
    this.handleBlur = e => {
      const { editing } = this.state;
      const { onChange } = this.props;
      if (editing) {
        this.setEditing(false);
        if (onChange) {
          onChange(e, e.target.value);
        }
      }
    };
  }

  componentDidMount() {
    const nextValue = this.props.value;
    const input = this.textareaRef.current;
    if (input) {
      input.value = toInputValue(nextValue);
    }
  }

  componentDidUpdate(prevProps, prevState) {
    const { editing } = this.state;
    const prevValue = prevProps.value;
    const nextValue = this.props.value;
    const input = this.textareaRef.current;
    if (input && !editing && prevValue !== nextValue) {
      input.value = toInputValue(nextValue);
    }
  }

  setEditing(editing) {
    this.setState({ editing });
  }

  getValue() {
    return this.textareaRef.current && this.textareaRef.current.value;
  }

  render() {
    // Input only props
    const {
      onChange,
      onKeyDown,
      onKeyPress,
      onInput,
      onFocus,
      onBlur,
      onEnter,
      value,
      maxLength,
      placeholder,
      ...boxProps
    } = this.props;
    // Box props
    const {
      className,
      fluid,
      ...rest
    } = boxProps;
    return (
      <Box
        className={classes([
          'TextArea',
          fluid && 'TextArea--fluid',
          className,
        ])}
        {...rest}>
        <textarea
          ref={this.textareaRef}
          className="TextArea__textarea"
          placeholder={placeholder}
          onChange={this.handleOnChange}
          onKeyDown={this.handleKeyDown}
          onKeyPress={this.handleKeyPress}
          onInput={this.handleOnInput}
          onFocus={this.handleFocus}
          onBlur={this.handleBlur}
          maxLength={maxLength} />
      </Box>
    );
  }
}


code:
import { formatTime } from '../format';
import { Component } from 'inferno';

// AnimatedNumber Copypaste
const isSafeNumber = value => {
  return typeof value === 'number'
    && Number.isFinite(value)
    && !Number.isNaN(value);
};

export class TimeDisplay extends Component {
  constructor(props) {
    super(props);
    this.timer = null;
    this.last_seen_value = undefined;
    this.state = {
      value: 0,
    };
    // Set initial state with value provided in props
    if (isSafeNumber(props.value)) {
      this.state.value = Number(props.value);
      this.last_seen_value = Number(props.value);
    }
  }

  componentDidUpdate() {
    if (this.props.auto !== undefined) {
      clearInterval(this.timer);
      this.timer = setInterval(() => this.tick(), 1000); // every 1 s
    }
  }

  tick() {
    let current = Number(this.state.value);
    if (this.props.value !== this.last_seen_value) {
      this.last_seen_value = this.props.value;
      current = this.props.value;
    }
    const mod = this.props.auto === "up" ? 10 : -10; // Time down by default.
    const value = Math.max(0, current + mod); // one sec tick
    this.setState({ value });
  }

  componentDidMount() {
    if (this.props.auto !== undefined) {
      this.timer = setInterval(() => this.tick(), 1000); // every 1 s
    }
  }

  componentWillUnmount() {
    clearInterval(this.timer);
  }

  render() {
    const val = this.state.value;
    // Directly display weird stuff
    if (!isSafeNumber(val)) {
      return this.state.value || null;
    }

    return formatTime(val);
  }
}


code:
import { createPopper, Placement, VirtualElement } from '@popperjs/core';
import { Component, findDOMfromVNode, InfernoNode, render } from 'inferno';

type TooltipProps = {
  children?: InfernoNode;
  content: InfernoNode;
  position?: Placement,
};

type TooltipState = {
  hovered: boolean;
};

const DEFAULT_OPTIONS = {
  modifiers: [{
    name: "eventListeners",
    enabled: false,
  }],
};

const NULL_RECT = {
  width: 0,
  height: 0,
  top: 0,
  right: 0,
  bottom: 0,
  left: 0,
};

export class Tooltip extends Component<TooltipProps, TooltipState> {
  // Mounting poppers is really laggy because popper.js is very slow.
  // Thus, instead of using the Popper component, Tooltip creates ONE popper
  // and stores every tooltip inside that.
  // This means you can never have two tooltips at once, for instance.
  static renderedTooltip: HTMLDivElement | undefined;
  static singletonPopper: ReturnType<typeof createPopper> | undefined;
  static currentHoveredElement: Element | undefined;
  static virtualElement: VirtualElement = {
    getBoundingClientRect: () => (
      Tooltip.currentHoveredElement?.getBoundingClientRect()
        ?? NULL_RECT
    ),
  };

  getDOMNode() {
    // HACK: We don't want to create a wrapper, as it could break the layout
    // of consumers, so we do the inferno equivalent of `findDOMNode(this)`.
    // My attempt to avoid this was a render prop that passed in
    // callbacks to onmouseenter and onmouseleave, but this was unwiedly
    // to consumers, specifically buttons.
    // This code is copied from `findDOMNode` in inferno-extras.
    // Because this component is written in TypeScript, we will know
    // immediately if this internal variable is removed.
    return findDOMfromVNode(this.$LI, true);
  }

  componentDidMount() {
    const domNode = this.getDOMNode();

    if (!domNode) {
      return;
    }

    domNode.addEventListener("mouseenter", () => {
      let renderedTooltip = Tooltip.renderedTooltip;
      if (renderedTooltip === undefined) {
        renderedTooltip = document.createElement("div");
        renderedTooltip.className = "Tooltip";
        document.body.appendChild(renderedTooltip);
        Tooltip.renderedTooltip = renderedTooltip;
      }

      Tooltip.currentHoveredElement = domNode;

      renderedTooltip.style.opacity = "1";

      this.renderPopperContent();
    });

    domNode.addEventListener("mouseleave", () => {
      this.fadeOut();
    });
  }

  fadeOut() {
    if (Tooltip.currentHoveredElement !== this.getDOMNode()) {
      return;
    }

    Tooltip.currentHoveredElement = undefined;
    Tooltip.renderedTooltip!.style.opacity = "0";
  }

  renderPopperContent() {
    const renderedTooltip = Tooltip.renderedTooltip;
    if (!renderedTooltip) {
      return;
    }

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

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

          singletonPopper.update();
        }
      },
      this.context,
    );
  }

  componentDidUpdate() {
    if (Tooltip.currentHoveredElement !== this.getDOMNode()) {
      return;
    }

    this.renderPopperContent();
  }

  componentWillUnmount() {
    this.fadeOut();
  }

  render() {
    return this.props.children;
  }
}


code:
import { Component, createRef } from "inferno";

export class TrackOutsideClicks extends Component<{
  onOutsideClick: () => void,
}> {
  ref = createRef<HTMLDivElement>();

  constructor() {
    super();

    this.handleOutsideClick = this.handleOutsideClick.bind(this);

    document.addEventListener("click", this.handleOutsideClick);
  }

  componentWillUnmount() {
    document.removeEventListener("click", this.handleOutsideClick);
  }

  handleOutsideClick(event: MouseEvent) {
    if (!(event.target instanceof Node)) {
      return;
    }

    if (this.ref.current && !this.ref.current.contains(event.target)) {
      this.props.onOutsideClick();
    }
  }

  render() {
    return (
      <div ref={this.ref}>
        {this.props.children}
      </div>
    );
  }
}


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

export { AnimatedNumber } from './AnimatedNumber';
export { Autofocus } from './Autofocus';
export { Blink } from './Blink';
export { BlockQuote } from './BlockQuote';
export { Box } from './Box';
export { Button } from './Button';
export { ByondUi } from './ByondUi';
export { Chart } from './Chart';
export { Collapsible } from './Collapsible';
export { ColorBox } from './ColorBox';
export { Dimmer } from './Dimmer';
export { Divider } from './Divider';
export { DraggableControl } from './DraggableControl';
export { Dropdown } from './Dropdown';
export { Flex } from './Flex';
export { FitText } from './FitText';
export { Grid } from './Grid';
export { Icon } from './Icon';
export { InfinitePlane } from './InfinitePlane';
export { Input } from './Input';
export { KeyListener } from './KeyListener';
export { Knob } from './Knob';
export { LabeledControls } from './LabeledControls';
export { LabeledList } from './LabeledList';
export { Modal } from './Modal';
export { NoticeBox } from './NoticeBox';
export { NumberInput } from './NumberInput';
export { ProgressBar } from './ProgressBar';
export { Popper } from './Popper';
export { RoundGauge } from './RoundGauge';
export { Section } from './Section';
export { Slider } from './Slider';
export { Stack } from './Stack';
export { Table } from './Table';
export { Tabs } from './Tabs';
export { TextArea } from './TextArea';
export { TimeDisplay } from './TimeDisplay';
export { TrackOutsideClicks } from './TrackOutsideClicks';
export { Tooltip } from './Tooltip';


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

// UI states, which are mirrored from the BYOND code.
export const UI_INTERACTIVE = 2;
export const UI_UPDATE = 1;
export const UI_DISABLED = 0;
export const UI_CLOSE = -1;

// All game related colors are stored here
export const COLORS = {
  // Department colors
  department: {
    captain: '#c06616',
    security: '#e74c3c',
    medbay: '#3498db',
    science: '#9b59b6',
    engineering: '#f1c40f',
    cargo: '#f39c12',
    centcom: '#00c100',
    other: '#c38312',
  },
  // Damage type colors
  damageType: {
    oxy: '#3498db',
    toxin: '#2ecc71',
    burn: '#e67e22',
    brute: '#e74c3c',
  },
  // reagent / chemistry related colours
  reagent: {
    acidicbuffer: "#fbc314",
    basicbuffer: "#3853a4",
  },
};

// Colors defined in CSS
export const CSS_COLORS = [
  'black',
  'white',
  'red',
  'orange',
  'yellow',
  'olive',
  'green',
  'teal',
  'blue',
  'violet',
  'purple',
  'pink',
  'brown',
  'grey',
  'good',
  'average',
  'bad',
  'label',
];

/* IF YOU CHANGE THIS KEEP IT IN SYNC WITH CHAT CSS */
export const RADIO_CHANNELS = [
  {
    name: 'Syndicate',
    freq: 1213,
    color: '#8f4a4b',
  },
  {
    name: 'Red Team',
    freq: 1215,
    color: '#ff4444',
  },
  {
    name: 'Blue Team',
    freq: 1217,
    color: '#3434fd',
  },
  {
    name: 'Green Team',
    freq: 1219,
    color: '#34fd34',
  },
  {
    name: 'Yellow Team',
    freq: 1221,
    color: '#fdfd34',
  },
  {
    name: 'CentCom',
    freq: 1337,
    color: '#2681a5',
  },
  {
    name: 'Supply',
    freq: 1347,
    color: '#b88646',
  },
  {
    name: 'Service',
    freq: 1349,
    color: '#6ca729',
  },
  {
    name: 'Science',
    freq: 1351,
    color: '#c68cfa',
  },
  {
    name: 'Command',
    freq: 1353,
    color: '#fcdf03',
  },
  {
    name: 'Medical',
    freq: 1355,
    color: '#57b8f0',
  },
  {
    name: 'Engineering',
    freq: 1357,
    color: '#f37746',
  },
  {
    name: 'Security',
    freq: 1359,
    color: '#dd3535',
  },
  {
    name: 'AI Private',
    freq: 1447,
    color: '#d65d95',
  },
  {
    name: 'Common',
    freq: 1459,
    color: '#1ecc43',
  },
];

const GASES = [
  {
    'id': 'o2',
    'name': 'Oxygen',
    'label': 'O₂',
    'color': 'blue',
  },
  {
    'id': 'n2',
    'name': 'Nitrogen',
    'label': 'N₂',
    'color': 'red',
  },
  {
    'id': 'co2',
    'name': 'Carbon Dioxide',
    'label': 'CO₂',
    'color': 'grey',
  },
  {
    'id': 'plasma',
    'name': 'Plasma',
    'label': 'Plasma',
    'color': 'pink',
  },
  {
    'id': 'water_vapor',
    'name': 'Water Vapor',
    'label': 'H₂O',
    'color': 'lightsteelblue',
  },
  {
    'id': 'nob',
    'name': 'Hyper-noblium',
    'label': 'Hyper-nob',
    'color': 'teal',
  },
  {
    'id': 'n2o',
    'name': 'Nitrous Oxide',
    'label': 'N₂O',
    'color': 'bisque',
  },
  {
    'id': 'no2',
    'name': 'Nitryl',
    'label': 'NO₂',
    'color': 'brown',
  },
  {
    'id': 'tritium',
    'name': 'Tritium',
    'label': 'Tritium',
    'color': 'limegreen',
  },
  {
    'id': 'bz',
    'name': 'BZ',
    'label': 'BZ',
    'color': 'mediumpurple',
  },
  {
    'id': 'stim',
    'name': 'Stimulum',
    'label': 'Stimulum',
    'color': 'darkviolet',
  },
  {
    'id': 'pluox',
    'name': 'Pluoxium',
    'label': 'Pluoxium',
    'color': 'mediumslateblue',
  },
  {
    'id': 'miasma',
    'name': 'Miasma',
    'label': 'Miasma',
    'color': 'olive',
  },
  {
    'id': 'Freon',
    'name': 'Freon',
    'label': 'Freon',
    'color': 'paleturquoise',
  },
  {
    'id': 'hydrogen',
    'name': 'Hydrogen',
    'label': 'H₂',
    'color': 'white',
  },
  {
    'id': 'healium',
    'name': 'Healium',
    'label': 'Healium',
    'color': 'salmon',
  },
  {
    'id': 'proto_nitrate',
    'name': 'Proto Nitrate',
    'label': 'Proto-Nitrate',
    'color': 'greenyellow',
  },
  {
    'id': 'zauker',
    'name': 'Zauker',
    'label': 'Zauker',
    'color': 'darkgreen',
  },
  {
    'id': 'halon',
    'name': 'Halon',
    'label': 'Halon',
    'color': 'purple',
  },
  {
    'id': 'helium',
    'name': 'Helium',
    'label': 'He',
    'color': 'aliceblue',
  },
  {
    'id': 'antinoblium',
    'name': 'Antinoblium',
    'label': 'Anti-Noblium',
    'color': 'maroon',
  },
];

export const getGasLabel = (gasId, fallbackValue) => {
  const gasSearchString = String(gasId).toLowerCase();
  const gas = GASES.find(gas => gas.id === gasSearchString
    || gas.name.toLowerCase() === gasSearchString);
  return gas && gas.label
    || fallbackValue
    || gasId;
};

export const getGasColor = gasId => {
  const gasSearchString = String(gasId).toLowerCase();
  const gas = GASES.find(gas => gas.id === gasSearchString
    || gas.name.toLowerCase() === gasSearchString);
  return gas && gas.color;
};


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

import { useLocalState } from '../backend';
import { Flex, Section, Tabs } from '../components';
import { Pane, Window } from '../layouts';

const r = require.context('../stories', false, /\.stories\.js$/);

/**
 * @returns {{
 *   meta: {
 *     title: string,
 *     render: () => any,
 *   },
 * }[]}
 */
const getStories = () => r.keys().map(path => r(path));

export const KitchenSink = (props, context) => {
  const { panel } = props;
  const [theme] = useLocalState(context, 'kitchenSinkTheme');
  const [pageIndex, setPageIndex] = useLocalState(context, 'pageIndex', 0);
  const stories = getStories();
  const story = stories[pageIndex];
  const Layout = panel ? Pane : Window;
  return (
    <Layout
      title="Kitchen Sink"
      width={600}
      height={500}
      theme={theme}>
      <Flex height="100%">
        <Flex.Item m={1} mr={0}>
          <Section fill fitted>
            <Tabs vertical>
              {stories.map((story, i) => (
                <Tabs.Tab
                  key={i}
                  color="transparent"
                  selected={i === pageIndex}
                  onClick={() => setPageIndex(i)}>
                  {story.meta.title}
                </Tabs.Tab>
              ))}
            </Tabs>
          </Section>
        </Flex.Item>
        <Flex.Item
          position="relative"
          grow={1}>
          <Layout.Content scrollable>
            {story.meta.render()}
          </Layout.Content>
        </Flex.Item>
      </Flex>
    </Layout>
  );
};


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

import { createAction } from 'common/redux';

export const toggleKitchenSink = createAction('debug/toggleKitchenSink');
export const toggleDebugLayout = createAction('debug/toggleDebugLayout');
export const openExternalBrowser = createAction('debug/openExternalBrowser');


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

import { useSelector } from 'common/redux';
import { selectDebug } from './selectors';

export const useDebug = context => useSelector(context, selectDebug);


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

export { useDebug } from './hooks';
export { KitchenSink } from './KitchenSink';
export { debugMiddleware, relayMiddleware } from './middleware';
export { debugReducer } from './reducer';


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

import { KEY_BACKSPACE, KEY_F10, KEY_F11, KEY_F12 } from 'common/keycodes';
import { globalEvents } from '../events';
import { acquireHotKey } from '../hotkeys';
import { openExternalBrowser, toggleDebugLayout, toggleKitchenSink } from './actions';

const relayedTypes = [
  'backend/update',
  'chat/message',
];

export const debugMiddleware = store => {
  acquireHotKey(KEY_F11);
  acquireHotKey(KEY_F12);
  globalEvents.on('keydown', key => {
    if (key.code === KEY_F11) {
      store.dispatch(toggleDebugLayout());
    }
    if (key.code === KEY_F12) {
      store.dispatch(toggleKitchenSink());
    }
    if (key.ctrl && key.alt && key.code === KEY_BACKSPACE) {
      // NOTE: We need to call this in a timeout, because we need a clean
      // stack in order for this to be a fatal error.
      setTimeout(() => {
        throw new Error(
          'OOPSIE WOOPSIE!! UwU We made a fucky wucky!! A wittle'
          + ' fucko boingo! The code monkeys at our headquarters are'
          + ' working VEWY HAWD to fix this!');
      });
    }
  });
  return next => action => next(action);
};

export const relayMiddleware = store => {
  const devServer = require('tgui-dev-server/link/client.cjs');
  const externalBrowser = location.search === '?external';
  if (externalBrowser) {
    devServer.subscribe(msg => {
      const { type, payload } = msg;
      if (type === 'relay' && payload.windowId === window.__windowId__) {
        store.dispatch({
          ...payload.action,
          relayed: true,
        });
      }
    });
  }
  else {
    acquireHotKey(KEY_F10);
    globalEvents.on('keydown', key => {
      if (key === KEY_F10) {
        store.dispatch(openExternalBrowser());
      }
    });
  }
  return next => action => {
    const { type, payload, relayed } = action;
    if (type === openExternalBrowser.type) {
      window.open(location.href + '?external', '_blank');
      return;
    }
    if (relayedTypes.includes(type) && !relayed && !externalBrowser) {
      devServer.sendMessage({
        type: 'relay',
        payload: {
          windowId: window.__windowId__,
          action,
        },
      });
    }
    return next(action);
  };
};


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

export const debugReducer = (state = {}, action) => {
  const { type, payload } = action;
  if (type === 'debug/toggleKitchenSink') {
    return {
      ...state,
      kitchenSink: !state.kitchenSink,
    };
  }
  if (type === 'debug/toggleDebugLayout') {
    return {
      ...state,
      debugLayout: !state.debugLayout,
    };
  }
  return state;
};


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

export const selectDebug = state => state.debug;


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

import { storage } from 'common/storage';
import { vecAdd, vecInverse, vecMultiply, vecScale } from 'common/vector';
import { createLogger } from './logging';

const logger = createLogger('drag');

let windowKey = window.__windowId__;
let dragging = false;
let resizing = false;
let screenOffset = [0, 0];
let screenOffsetPromise;
let dragPointOffset;
let resizeMatrix;
let initialSize;
let size;

export const setWindowKey = key => {
  windowKey = key;
};

export const getWindowPosition = () => [
  window.screenLeft,
  window.screenTop,
];

export const getWindowSize = () => [
  window.innerWidth,
  window.innerHeight,
];

export const setWindowPosition = vec => {
  const byondPos = vecAdd(vec, screenOffset);
  return Byond.winset(window.__windowId__, {
    pos: byondPos[0] + ',' + byondPos[1],
  });
};

export const setWindowSize = vec => {
  return Byond.winset(window.__windowId__, {
    size: vec[0] + 'x' + vec[1],
  });
};

export const getScreenPosition = () => [
  0 - screenOffset[0],
  0 - screenOffset[1],
];

export const getScreenSize = () => [
  window.screen.availWidth,
  window.screen.availHeight,
];

/**
 * Moves an item to the top of the recents array, and keeps its length
 * limited to the number in `limit` argument.
 *
 * Uses a strict equality check for comparisons.
 *
 * Returns new recents and an item which was trimmed.
 */
const touchRecents = (recents, touchedItem, limit = 50) => {
  const nextRecents = [touchedItem];
  let trimmedItem;
  for (let i = 0; i < recents.length; i++) {
    const item = recents[i];
    if (item === touchedItem) {
      continue;
    }
    if (nextRecents.length < limit) {
      nextRecents.push(item);
    }
    else {
      trimmedItem = item;
    }
  }
  return [nextRecents, trimmedItem];
};

export const storeWindowGeometry = async () => {
  logger.log('storing geometry');
  const geometry = {
    pos: getWindowPosition(),
    size: getWindowSize(),
  };
  storage.set(windowKey, geometry);
  // Update the list of stored geometries
  const [geometries, trimmedKey] = touchRecents(
    await storage.get('geometries') || [],
    windowKey);
  if (trimmedKey) {
    storage.remove(trimmedKey);
  }
  storage.set('geometries', geometries);
};

export const recallWindowGeometry = async (options = {}) => {
  // Only recall geometry in fancy mode
  const geometry = options.fancy && await storage.get(windowKey);
  if (geometry) {
    logger.log('recalled geometry:', geometry);
  }
  let pos = geometry?.pos || options.pos;
  let size = options.size;
  // Wait until screen offset gets resolved
  await screenOffsetPromise;
  const areaAvailable = [
    window.screen.availWidth,
    window.screen.availHeight,
  ];
  // Set window size
  if (size) {
    // Constraint size to not exceed available screen area.
    size = [
      Math.min(areaAvailable[0], size[0]),
      Math.min(areaAvailable[1], size[1]),
    ];
    setWindowSize(size);
  }
  // Set window position
  if (pos) {
    // Constraint window position if monitor lock was set in preferences.
    if (size && options.locked) {
      pos = constraintPosition(pos, size)[1];
    }
    setWindowPosition(pos);
  }
  // Set window position at the center of the screen.
  else if (size) {
    pos = vecAdd(
      vecScale(areaAvailable, 0.5),
      vecScale(size, -0.5),
      vecScale(screenOffset, -1.0));
    setWindowPosition(pos);
  }
};

export const setupDrag = async () => {
  // Calculate screen offset caused by the windows taskbar
  screenOffsetPromise = Byond.winget(window.__windowId__, 'pos')
    .then(pos => [
      pos.x - window.screenLeft,
      pos.y - window.screenTop,
    ]);
  screenOffset = await screenOffsetPromise;
  logger.debug('screen offset', screenOffset);
};

/**
 * Constraints window position to safe screen area, accounting for safe
 * margins which could be a system taskbar.
 */
const constraintPosition = (pos, size) => {
  const screenPos = getScreenPosition();
  const screenSize = getScreenSize();
  const nextPos = [pos[0], pos[1]];
  let relocated = false;
  for (let i = 0; i < 2; i++) {
    const leftBoundary = screenPos[i];
    const rightBoundary = screenPos[i] + screenSize[i];
    if (pos[i] < leftBoundary) {
      nextPos[i] = leftBoundary;
      relocated = true;
    }
    else if (pos[i] + size[i] > rightBoundary) {
      nextPos[i] = rightBoundary - size[i];
      relocated = true;
    }
  }
  return [relocated, nextPos];
};

export const dragStartHandler = event => {
  logger.log('drag start');
  dragging = true;
  dragPointOffset = [
    window.screenLeft - event.screenX,
    window.screenTop - event.screenY,
  ];
  // Focus click target
  event.target?.focus();
  document.addEventListener('mousemove', dragMoveHandler);
  document.addEventListener('mouseup', dragEndHandler);
  dragMoveHandler(event);
};

const dragEndHandler = event => {
  logger.log('drag end');
  dragMoveHandler(event);
  document.removeEventListener('mousemove', dragMoveHandler);
  document.removeEventListener('mouseup', dragEndHandler);
  dragging = false;
  storeWindowGeometry();
};

const dragMoveHandler = event => {
  if (!dragging) {
    return;
  }
  event.preventDefault();
  setWindowPosition(vecAdd(
    [event.screenX, event.screenY],
    dragPointOffset));
};

export const resizeStartHandler = (x, y) => event => {
  resizeMatrix = [x, y];
  logger.log('resize start', resizeMatrix);
  resizing = true;
  dragPointOffset = [
    window.screenLeft - event.screenX,
    window.screenTop - event.screenY,
  ];
  initialSize = [
    window.innerWidth,
    window.innerHeight,
  ];
  // Focus click target
  event.target?.focus();
  document.addEventListener('mousemove', resizeMoveHandler);
  document.addEventListener('mouseup', resizeEndHandler);
  resizeMoveHandler(event);
};

const resizeEndHandler = event => {
  logger.log('resize end', size);
  resizeMoveHandler(event);
  document.removeEventListener('mousemove', resizeMoveHandler);
  document.removeEventListener('mouseup', resizeEndHandler);
  resizing = false;
  storeWindowGeometry();
};

const resizeMoveHandler = event => {
  if (!resizing) {
    return;
  }
  event.preventDefault();
  size = vecAdd(initialSize, vecMultiply(resizeMatrix, vecAdd(
    [event.screenX, event.screenY],
    vecInverse([window.screenLeft, window.screenTop]),
    dragPointOffset,
    [1, 1])));
  // Sane window size values
  size[0] = Math.max(size[0], 150);
  size[1] = Math.max(size[1], 50);
  setWindowSize(size);
};


code:
/**
 * Normalized browser focus events and BYOND-specific focus helpers.
 *
 * @file
 * @copyright 2020 Aleksej Komarov
 * @license MIT
 */

import { EventEmitter } from 'common/events';
import { KEY_ALT, KEY_CTRL, KEY_F1, KEY_F12, KEY_SHIFT } from 'common/keycodes';

export const globalEvents = new EventEmitter();
let ignoreWindowFocus = false;

export const setupGlobalEvents = (options = {}) => {
  ignoreWindowFocus = !!options.ignoreWindowFocus;
};

// Window focus
// --------------------------------------------------------

let windowFocusTimeout;
let windowFocused = true;

const setWindowFocus = (value, delayed) => {
  // Pretend to always be in focus.
  if (ignoreWindowFocus) {
    windowFocused = true;
    return;
  }
  if (windowFocusTimeout) {
    clearTimeout(windowFocusTimeout);
    windowFocusTimeout = null;
  }
  if (delayed) {
    windowFocusTimeout = setTimeout(() => setWindowFocus(value));
    return;
  }
  if (windowFocused !== value) {
    windowFocused = value;
    globalEvents.emit(value ? 'window-focus' : 'window-blur');
    globalEvents.emit('window-focus-change', value);
  }
};

// Focus stealing
// --------------------------------------------------------

let focusStolenBy = null;

export const canStealFocus = node => {
  const tag = String(node.tagName).toLowerCase();
  return tag === 'input' || tag === 'textarea';
};

const stealFocus = node => {
  releaseStolenFocus();
  focusStolenBy = node;
  focusStolenBy.addEventListener('blur', releaseStolenFocus);
};

const releaseStolenFocus = () => {
  if (focusStolenBy) {
    focusStolenBy.removeEventListener('blur', releaseStolenFocus);
    focusStolenBy = null;
  }
};

// Focus follows the mouse
// --------------------------------------------------------

let focusedNode = null;
let lastVisitedNode = null;
const trackedNodes = [];

export const addScrollableNode = node => {
  trackedNodes.push(node);
};

export const removeScrollableNode = node => {
  const index = trackedNodes.indexOf(node);
  if (index >= 0) {
    trackedNodes.splice(index, 1);
  }
};

const focusNearestTrackedParent = node => {
  if (focusStolenBy || !windowFocused) {
    return;
  }
  const body = document.body;
  while (node && node !== body) {
    if (trackedNodes.includes(node)) {
      // NOTE: Contains is a DOM4 method
      if (node.contains(focusedNode)) {
        return;
      }
      focusedNode = node;
      node.focus();
      return;
    }
    node = node.parentNode;
  }
};

window.addEventListener('mousemove', e => {
  const node = e.target;
  if (node !== lastVisitedNode) {
    lastVisitedNode = node;
    focusNearestTrackedParent(node);
  }
});

// Focus event hooks
// --------------------------------------------------------

window.addEventListener('focusin', e => {
  lastVisitedNode = null;
  focusedNode = e.target;
  setWindowFocus(true);
  if (canStealFocus(e.target)) {
    stealFocus(e.target);
    return;
  }
});

window.addEventListener('focusout', e => {
  lastVisitedNode = null;
  setWindowFocus(false, true);
});

window.addEventListener('blur', e => {
  lastVisitedNode = null;
  setWindowFocus(false, true);
});

window.addEventListener('beforeunload', e => {
  setWindowFocus(false);
});

// Key events
// --------------------------------------------------------

const keyHeldByCode = {};

export class KeyEvent {
  constructor(e, type, repeat) {
    this.event = e;
    this.type = type;
    this.code = window.event ? e.which : e.keyCode;
    this.ctrl = e.ctrlKey;
    this.shift = e.shiftKey;
    this.alt = e.altKey;
    this.repeat = !!repeat;
  }

  hasModifierKeys() {
    return this.ctrl || this.alt || this.shift;
  }

  isModifierKey() {
    return this.code === KEY_CTRL
      || this.code === KEY_SHIFT
      || this.code === KEY_ALT;
  }

  isDown() {
    return this.type === 'keydown';
  }

  isUp() {
    return this.type === 'keyup';
  }

  toString() {
    if (this._str) {
      return this._str;
    }
    this._str = '';
    if (this.ctrl) {
      this._str += 'Ctrl+';
    }
    if (this.alt) {
      this._str += 'Alt+';
    }
    if (this.shift) {
      this._str += 'Shift+';
    }
    if (this.code >= 48 && this.code <= 90) {
      this._str += String.fromCharCode(this.code);
    }
    else if (this.code >= KEY_F1 && this.code <= KEY_F12) {
      this._str += 'F' + (this.code - 111);
    }
    else {
      this._str += '[' + this.code + ']';
    }
    return this._str;
  }
}

// IE8: Keydown event is only available on document.
document.addEventListener('keydown', e => {
  if (canStealFocus(e.target)) {
    return;
  }
  const code = e.keyCode;
  const key = new KeyEvent(e, 'keydown', keyHeldByCode[code]);
  globalEvents.emit('keydown', key);
  globalEvents.emit('key', key);
  keyHeldByCode[code] = true;
});

document.addEventListener('keyup', e => {
  if (canStealFocus(e.target)) {
    return;
  }
  const code = e.keyCode;
  const key = new KeyEvent(e, 'keyup');
  globalEvents.emit('keyup', key);
  globalEvents.emit('key', key);
  keyHeldByCode[code] = false;
});


code:
/**
 * Various focus helpers.
 *
 * @file
 * @copyright 2020 Aleksej Komarov
 * @license MIT
 */

/**
 * Moves focus to the BYOND map window.
 */
export const focusMap = () => {
  Byond.winset('mapwindow.map', {
    focus: true,
  });
};

/**
 * Moves focus to the browser window.
 */
export const focusWindow = () => {
  Byond.winset(window.__windowId__, {
    focus: true,
  });
};


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

import { clamp, round, toFixed } from 'common/math';

const SI_SYMBOLS = [
  'f', // femto
  'p', // pico
  'n', // nano
  'μ', // micro
  'm', // milli
  // NOTE: This is a space for a reason. When we right align si numbers,
  // in monospace mode, we want to units and numbers stay in their respective
  // columns. If rendering in HTML mode, this space will collapse into
  // a single space anyway.
  ' ',
  'k', // kilo
  'M', // mega
  'G', // giga
  'T', // tera
  'P', // peta
  'E', // exa
  'Z', // zetta
  'Y', // yotta
  'R', // ronna
  'Q', // quecca
  'F',
  'N',
  'H',
];

const SI_BASE_INDEX = SI_SYMBOLS.indexOf(' ');

/**
 * Formats a number to a human readable form, by reducing it to SI units.
 * TODO: This is quite a shit code and shit math, needs optimization.
 */
export const formatSiUnit = (
  value,
  minBase1000 = -SI_BASE_INDEX,
  unit = ''
) => {
  if (typeof value !== 'number' || !Number.isFinite(value)) {
    return value;
  }
  const realBase10 = Math.floor(Math.log10(value));
  const base10 = Math.floor(Math.max(minBase1000 * 3, realBase10));
  const realBase1000 = Math.floor(realBase10 / 3);
  const base1000 = Math.floor(base10 / 3);
  const symbolIndex = clamp(
    SI_BASE_INDEX + base1000,
    0,
    SI_SYMBOLS.length);
  const symbol = SI_SYMBOLS[symbolIndex];
  const scaledNumber = value / Math.pow(1000, base1000);
  const scaledPrecision = realBase1000 > minBase1000
    ? (2 + base1000 * 3 - base10)
    : 0;
  // TODO: Make numbers bigger than precision value show
  // up to 2 decimal numbers.
  const finalString = (
    toFixed(scaledNumber, scaledPrecision)
    + ' ' + symbol + unit
  );
  return finalString.trim();
};

export const formatPower = (value, minBase1000 = 0) => {
  return formatSiUnit(value, minBase1000, 'W');
};

export const formatMoney = (value, precision = 0) => {
  if (!Number.isFinite(value)) {
    return value;
  }
  // Round the number and make it fixed precision
  let fixed = round(value, precision);
  if (precision > 0) {
    fixed = toFixed(value, precision);
  }
  fixed = String(fixed);
  // Place thousand separators
  const length = fixed.length;
  let indexOfPoint = fixed.indexOf('.');
  if (indexOfPoint === -1) {
    indexOfPoint = length;
  }
  let result = '';
  for (let i = 0; i < length; i++) {
    if (i > 0 && i < indexOfPoint && (indexOfPoint - i) % 3 === 0) {
      // Thin space
      result += '\u2009';
    }
    result += fixed.charAt(i);
  }
  return result;
};

/**
 * Formats a floating point number as a number on the decibel scale.
 */
export const formatDb = value => {
  const db = 20 * Math.log(value) / Math.log(10);
  const sign = db >= 0 ? '+' : '–';
  let formatted = Math.abs(db);
  if (formatted === Infinity) {
    formatted = 'Inf';
  }
  else {
    formatted = toFixed(formatted, 2);
  }
  return sign + formatted + ' dB';
};

const SI_BASE_TEN_UNIT = [
  '',
  '· 10³', // kilo
  '· 10⁶', // mega
  '· 10⁹', // giga
  '· 10¹²', // tera
  '· 10¹⁵', // peta
  '· 10¹⁸', // exa
  '· 10²¹', // zetta
  '· 10²⁴', // yotta
  '· 10²⁷', // ronna
  '· 10³⁰', // quecca
  '· 10³³',
  '· 10³⁶',
  '· 10³⁹',
];

const SI_BASE_TEN_INDEX = SI_BASE_TEN_UNIT.indexOf(' ');

/**
 * Formats a number to a human readable form, by reducing it to SI units.
 * TODO: This is quite a shit code and shit math, needs optimization.
 */
export const formatSiBaseTenUnit = (
  value,
  minBase1000 = -SI_BASE_TEN_INDEX,
  unit = ''
) => {
  if (typeof value !== 'number' || !Number.isFinite(value)) {
    return value;
  }
  const realBase10 = Math.floor(Math.log10(value));
  const base10 = Math.floor(Math.max(minBase1000 * 3, realBase10));
  const realBase1000 = Math.floor(realBase10 / 3);
  const base1000 = Math.floor(base10 / 3);
  const symbolIndex = clamp(
    SI_BASE_TEN_INDEX + base1000,
    0,
    SI_BASE_TEN_UNIT.length);
  const symbol = SI_BASE_TEN_UNIT[symbolIndex];
  const scaledNumber = value / Math.pow(1000, base1000);
  const scaledPrecision = realBase1000 > minBase1000
    ? (2 + base1000 * 3 - base10)
    : 0;
  // TODO: Make numbers bigger than precision value show
  // up to 2 decimal numbers.
  const finalString = (
    toFixed(scaledNumber, scaledPrecision)
    + ' ' + symbol + ' ' + unit
  );
  return finalString.trim();
};

/**
 * Formats decisecond count into HH::MM::SS display by default
 * "short" format does not pad and adds hms suffixes
 */
export const formatTime = (val, formatType) => {
  // THERE IS AS YET INSUFFICIENT DATA FOR A MEANINGFUL ANSWER
  // HH:MM:SS
  // 00:02:13
  const seconds = toFixed(Math.floor((val/10) % 60));
  const minutes = toFixed(Math.floor((val/(10*60)) % 60));
  const hours = toFixed(Math.floor((val/(10*60*60)) % 24));
  switch (formatType) {
    case "short": {
      const hours_truncated = hours > 0 ? `${hours}h` : "";
      const minutes_truncated = minutes > 0 ? `${minutes}m` : "";
      const seconds_truncated = seconds > 0 ? `${seconds}s` : "";
      return `${hours_truncated}${minutes_truncated}${seconds_truncated}`;
    }
    default: {
      const seconds_padded = seconds.padStart(2, "0");
      const minutes_padded = minutes.padStart(2, "0");
      const hours_padded = hours.padStart(2, "0");
      return `${hours_padded}:${minutes_padded}:${seconds_padded}`;
    }
  }
};


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

import * as keycodes from 'common/keycodes';
import { globalEvents, KeyEvent } from './events';
import { createLogger } from './logging';

const logger = createLogger('hotkeys');

// BYOND macros, in `key: command` format.
const byondMacros: Record<string, string> = {};

// Default set of acquired keys, which will not be sent to BYOND.
const hotKeysAcquired = [
  keycodes.KEY_ESCAPE,
  keycodes.KEY_ENTER,
  keycodes.KEY_SPACE,
  keycodes.KEY_TAB,
  keycodes.KEY_CTRL,
  keycodes.KEY_SHIFT,
  keycodes.KEY_UP,
  keycodes.KEY_DOWN,
  keycodes.KEY_LEFT,
  keycodes.KEY_RIGHT,
  keycodes.KEY_F5,
];

// State of passed-through keys.
const keyState: Record<string, boolean> = {};

// Custom listeners for key events
const keyListeners: ((key: KeyEvent) => void)[] = [];

/**
 * Converts a browser keycode to BYOND keycode.
 */
const keyCodeToByond = (keyCode: number) => {
  if (keyCode === 16) return 'Shift';
  if (keyCode === 17) return 'Ctrl';
  if (keyCode === 18) return 'Alt';
  if (keyCode === 33) return 'Northeast';
  if (keyCode === 34) return 'Southeast';
  if (keyCode === 35) return 'Southwest';
  if (keyCode === 36) return 'Northwest';
  if (keyCode === 37) return 'West';
  if (keyCode === 38) return 'North';
  if (keyCode === 39) return 'East';
  if (keyCode === 40) return 'South';
  if (keyCode === 45) return 'Insert';
  if (keyCode === 46) return 'Delete';
  if (keyCode >= 48 && keyCode <= 57 || keyCode >= 65 && keyCode <= 90) {
    return String.fromCharCode(keyCode);
  }
  if (keyCode >= 96 && keyCode <= 105) {
    return 'Numpad' + (keyCode - 96);
  }
  if (keyCode >= 112 && keyCode <= 123) {
    return 'F' + (keyCode - 111);
  }
  if (keyCode === 188) return ',';
  if (keyCode === 189) return '-';
  if (keyCode === 190) return '.';
};

/**
 * Keyboard passthrough logic. This allows you to keep doing things
 * in game while the browser window is focused.
 */
const handlePassthrough = (key: KeyEvent) => {
  const keyString = String(key);
  // In addition to F5, support reloading with Ctrl+R and Ctrl+F5
  if (keyString === 'Ctrl+F5' || keyString === 'Ctrl+R') {
    location.reload();
    return;
  }
  // Prevent passthrough on Ctrl+F
  if (keyString === 'Ctrl+F') {
    return;
  }
  // NOTE: Alt modifier is pretty bad and sticky in IE11.
  if (key.event.defaultPrevented
      || key.isModifierKey()
      || hotKeysAcquired.includes(key.code)) {
    return;
  }
  const byondKeyCode = keyCodeToByond(key.code);
  if (!byondKeyCode) {
    return;
  }
  // Macro
  const macro = byondMacros[byondKeyCode];
  if (macro) {
    logger.debug('macro', macro);
    return Byond.command(macro);
  }
  // KeyDown
  if (key.isDown() && !keyState[byondKeyCode]) {
    keyState[byondKeyCode] = true;
    const command = `KeyDown "${byondKeyCode}"`;
    logger.debug(command);
    return Byond.command(command);
  }
  // KeyUp
  if (key.isUp() && keyState[byondKeyCode]) {
    keyState[byondKeyCode] = false;
    const command = `KeyUp "${byondKeyCode}"`;
    logger.debug(command);
    return Byond.command(command);
  }
};

/**
 * Acquires a lock on the hotkey, which prevents it from being
 * passed through to BYOND.
 */
export const acquireHotKey = (keyCode: number) => {
  hotKeysAcquired.push(keyCode);
};

/**
 * Makes the hotkey available to BYOND again.
 */
export const releaseHotKey = (keyCode: number) => {
  const index = hotKeysAcquired.indexOf(keyCode);
  if (index >= 0) {
    hotKeysAcquired.splice(index, 1);
  }
};

export const releaseHeldKeys = () => {
  for (let byondKeyCode of Object.keys(keyState)) {
    if (keyState[byondKeyCode]) {
      keyState[byondKeyCode] = false;
      logger.log(`releasing key "${byondKeyCode}"`);
      Byond.command(`KeyUp "${byondKeyCode}"`);
    }
  }
};

type ByondSkinMacro = {
  command: string;
  name: string;
};

export const setupHotKeys = () => {
  // Read macros
  Byond.winget('default.*').then((data: Record<string, string>) => {
    // Group each macro by ref
    const groupedByRef: Record<string, ByondSkinMacro> = {};
    for (let key of Object.keys(data)) {
      const keyPath = key.split('.');
      const ref = keyPath[1];
      const prop = keyPath[2];
      if (ref && prop) {
        // This piece of code imperatively adds each property to a
        // ByondSkinMacro object in the order we meet it, which is hard
        // to express safely in typescript.
        if (!groupedByRef[ref]) {
          groupedByRef[ref] = {} as any;
        }
        groupedByRef[ref][prop] = data[key];
      }
    }
    // Insert macros
    const escapedQuotRegex = /\\"/g;
    const unescape = (str: string) => str
      .substring(1, str.length - 1)
      .replace(escapedQuotRegex, '"');
    for (let ref of Object.keys(groupedByRef)) {
      const macro = groupedByRef[ref];
      const byondKeyName = unescape(macro.name);
      byondMacros[byondKeyName] = unescape(macro.command);
    }
    logger.debug('loaded macros', byondMacros);
  });
  // Setup event handlers
  globalEvents.on('window-blur', () => {
    releaseHeldKeys();
  });
  globalEvents.on('key', (key: KeyEvent) => {
    for (const keyListener of keyListeners) {
      keyListener(key);
    }

    handlePassthrough(key);
  });
};

/**
 * Registers for any key events, such as key down or key up.
 * This should be preferred over directly connecting to keydown/keyup
 * as it lets tgui prevent the key from reaching BYOND.
 *
 * If using in a component, prefer KeyListener, which automatically handles
 * stopping listening when unmounting.
 *
 * @param callback The function to call whenever a key event occurs
 * @returns A callback to stop listening
 */
export const listenForKeyEvents = (
  callback: (key: KeyEvent) => void,
): () => void => {
  keyListeners.push(callback);

  let removed = false;

  return () => {
    if (removed) {
      return;
    }

    removed = true;
    keyListeners.splice(keyListeners.indexOf(callback), 1);
  };
};


code:
/**
 * An equivalent to `fetch`, except will automatically retry.
 */
export const fetchRetry
  = (
    url: string,
    options?: RequestInit,
    retryTimer: number = 1000,
  ): Promise<Response> => {
    return fetch(url, options).catch(() => {
      return new Promise(resolve => {
        setTimeout(() => {
          fetchRetry(url, options, retryTimer).then(resolve);
        }, retryTimer);
      });
    });
  };


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

// Themes
import './styles/main.scss';
import './styles/themes/abductor.scss';
import './styles/themes/cardtable.scss';
import './styles/themes/hackerman.scss';
import './styles/themes/malfunction.scss';
import './styles/themes/neutral.scss';
import './styles/themes/ntos.scss';
import './styles/themes/paper.scss';
import './styles/themes/retro.scss';
import './styles/themes/syndicate.scss';
import './styles/themes/wizard.scss';
import './styles/themes/admin.scss';
import './styles/themes/cutesy.scss';

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

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

const store = configureStore();

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

const setupApp = () => {
  // Delay setup
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', setupApp);
    return;
  }

  setupGlobalEvents();
  setupHotKeys();
  captureExternalLinks();

  // Subscribe for state updates
  store.subscribe(renderApp);

  // Dispatch incoming messages
  window.update = msg => store.dispatch(Byond.parseJson(msg));

  // Process the early update queue
  while (true) {
    const msg = window.__updateQueue__.shift();
    if (!msg) {
      break;
    }
    window.update(msg);
  }

  // Enable hot module reloading
  if (module.hot) {
    setupHotReloading();
    module.hot.accept([
      './components',
      './debug',
      './layouts',
      './routes',
    ], () => {
      renderApp();
    });
  }
};

setupApp();


code:
import { useBackend, useSharedState } from '../backend';
import { Button, LabeledList, NoticeBox, Section, Tabs } from '../components';
import { Window } from '../layouts';
import { GenericUplink } from './Uplink';

export const AbductorConsole = (props, context) => {
  const [tab, setTab] = useSharedState(context, 'tab', 1);
  return (
    <Window
      theme="abductor"
      width={600}
      height={532}>
      <Window.Content scrollable>
        <Tabs>
          <Tabs.Tab
            icon="list"
            lineHeight="23px"
            selected={tab === 1}
            onClick={() => setTab(1)}>
            Abductsoft 3000
          </Tabs.Tab>
          <Tabs.Tab
            icon="list"
            lineHeight="23px"
            selected={tab === 2}
            onClick={() => setTab(2)}>
            Mission Settings
          </Tabs.Tab>
        </Tabs>
        {tab === 1 && (
          <Abductsoft />
        )}
        {tab === 2 && (
          <>
            <EmergencyTeleporter />
            <VestSettings />
          </>
        )}
      </Window.Content>
    </Window>
  );
};

const Abductsoft = (props, context) => {
  const { act, data } = useBackend(context);
  const {
    experiment,
    points,
    credits,
  } = data;

  if (!experiment) {
    return (
      <NoticeBox danger>
        No Experiment Machine Detected
      </NoticeBox>
    );
  }

  return (
    <>
      <Section>
        <LabeledList>
          <LabeledList.Item label="Collected Samples">
            {points}
          </LabeledList.Item>
        </LabeledList>
      </Section>
      <GenericUplink
        currencyAmount={credits}
        currencySymbol="Credits" />
    </>
  );
};

const EmergencyTeleporter = (props, context) => {
  const { act, data } = useBackend(context);
  const {
    pad,
    gizmo,
  } = data;

  if (!pad) {
    return (
      <NoticeBox danger>
        No Telepad Detected
      </NoticeBox>
    );
  }

  return (
    <Section
      title="Emergency Teleport"
      buttons={(
        <Button
          icon="exclamation-circle"
          content="Activate"
          color="bad"
          onClick={() => act('teleporter_send')} />
      )}>
      <LabeledList>
        <LabeledList.Item label="Mark Retrieval">
          <Button
            icon={gizmo ? "user-plus" : "user-slash"}
            content={gizmo ? "Retrieve" : "No Mark"}
            disabled={!gizmo}
            onClick={() => act('teleporter_retrieve')} />
        </LabeledList.Item>
      </LabeledList>
    </Section>
  );
};

const VestSettings = (props, context) => {
  const { act, data } = useBackend(context);
  const {
    vest,
    vest_mode,
    vest_lock,
  } = data;

  if (!vest) {
    return (
      <NoticeBox danger>
        No Agent Vest Detected
      </NoticeBox>
    );
  }

  return (
    <Section
      title="Agent Vest Settings"
      buttons={(
        <Button
          icon={vest_lock ? 'lock' : 'unlock'}
          content={vest_lock ? 'Locked' : 'Unlocked'}
          onClick={() => act('toggle_vest')} />
      )}>
      <LabeledList>
        <LabeledList.Item label="Mode">
          <Button
            icon={vest_mode === 1 ? 'eye-slash' : 'fist-raised'}
            content={vest_mode === 1 ? "Stealth" : "Combat"}
            onClick={() => act('flip_vest')} />
        </LabeledList.Item>
        <LabeledList.Item label="Disguise">
          <Button
            icon="user-secret"
            content="Select"
            onClick={() => act('select_disguise')} />
        </LabeledList.Item>
      </LabeledList>
    </Section>
  );
};


code:
import { useBackend, useLocalState } from '../backend';
import { Box, Flex, Icon, Table, Tabs } from '../components';
import { Window } from '../layouts';

export const Achievements = (props, context) => {
  const { data } = useBackend(context);
  const { categories } = data;
  const [
    selectedCategory,
    setSelectedCategory,
  ] = useLocalState(context, 'category', categories[0]);
  const achievements = data.achievements
    .filter(x => x.category === selectedCategory);
  return (
    <Window
      title="Achievements"
      width={540}
      height={680}>
      <Window.Content scrollable>
        <Tabs>
          {categories.map(category => (
            <Tabs.Tab
              key={category}
              selected={selectedCategory === category}
              onClick={() => setSelectedCategory(category)}>
              {category}
            </Tabs.Tab>
          ))}
          <Tabs.Tab
            selected={selectedCategory === 'High Scores'}
            onClick={() => setSelectedCategory('High Scores')}>
            High Scores
          </Tabs.Tab>
        </Tabs>
        {selectedCategory === 'High Scores' && (
          <HighScoreTable />
        ) || (
          <AchievementTable achievements={achievements} />
        )}
      </Window.Content>
    </Window>
  );
};

const AchievementTable = (props, context) => {
  const { achievements } = props;
  return (

      {achievements.map(achievement => (
        <Achievement
          key={achievement.name}
          achievement={achievement} />
      ))}

  );
};

const Achievement = props => {
  const { achievement } = props;
  const {
    name,
    desc,
    icon_class,
    value,
    score,
  } = achievement;
  return (

        <Box m={1} className={icon_class} />

{name}

        {desc}
        {score && (
          <Box color={value > 0 ? 'good' : 'bad'}>
            {value > 0 ? `Earned ${value} times` : 'Locked'}
          </Box>
        ) || (
          <Box color={value ? 'good' : 'bad'}>
            {value ? 'Unlocked' : 'Locked'}
          </Box>
        )}

  );
};

const HighScoreTable = (props, context) => {
  const { data } = useBackend(context);
  const {
    highscore: highscores,
    user_ckey,
  } = data;
  const [
    highScoreIndex,
    setHighScoreIndex,
  ] = useLocalState(context, 'highscore', 0);
  const highscore = highscores[highScoreIndex];
  if (!highscore) {
    return null;
  }
  const scores = Object
    .keys(highscore.scores)
    .map(key => ({
      ckey: key,
      value: highscore.scores[key],
    }));
  return (
    <Flex>
      <Flex.Item>
        <Tabs vertical>
          {highscores.map((highscore, i) => (
            <Tabs.Tab
              key={highscore.name}
              selected={highScoreIndex === i}
              onClick={() => setHighScoreIndex(i)}>
              {highscore.name}
            </Tabs.Tab>
          ))}
        </Tabs>
      </Flex.Item>
      <Flex.Item grow={1} basis={0}>

              #

              Key

              Score

          {scores.map((score, i) => (

                {i + 1}

                {i === 0 && (
                  <Icon name="crown" color="yellow" mr={2} />
                )}
                {score.ckey}
                {i === 0 && (
                  <Icon name="crown" color="yellow" ml={2} />
                )}

                {score.value}

          ))}

      </Flex.Item>
    </Flex>
  );
};


code:
import { useBackend } from "../backend";
import { Box, Section, Table } from '../components';
import { Window } from "../layouts";

export const AdminWhoMenu = (props, context) => {
  const { data } = useBackend(context);
  const {
    admins = [],
    total_admins,
  } = data;

  return (
    <Window
      title="Admin Who"
      width={400}
      height={600}>
      <Window.Content scrollable>

                Key

                Rank

            {admins.map(admin => (

                  {admin.key}

                  {admin.rank}

            ))}

          <Box mt={1} textAlign="center">
            <Box inline mx={1}>
              Total Admins:
            </Box>
            <Box inline>
              {total_admins}
            </Box>
          </Box>

      </Window.Content>
    </Window>
  );
};


code:
import { useBackend, useLocalState } from '../backend';
import { Button, LabeledList, Section, Box, NoticeBox, Table } from '../components';
import { Window } from '../layouts';
import { AdventureDataProvider, AdventureScreen } from './ExodroneConsole';
import { formatTime } from '../format';

type Adventure = {
  ref: string;
  name: string;
  id: string;
  approved: boolean;
  uploader: string;
  version: number;
  timestamp: string;
  json_status: string;
};

type AdventureBrowserData = AdventureDataProvider & {
  adventures: Array<Adventure>;
  feedback_message: string;
  play_mode: boolean;
  adventure_data: any;
  delay_time: number;
  delay_message: string;
};

const AdventureEntry = (props, context) => {
  const { data, act } = useBackend<AdventureBrowserData>(context);
  const { entry_ref, close }: { entry_ref: string, close: () => void } = props;
  const entry = data.adventures.find(x => x.ref === entry_ref);

  if (!entry) {
    return null;
  }

  return (

      <LabeledList>
        <LabeledList.Item label="ID">{entry.id}</LabeledList.Item>
        <LabeledList.Item label="Name">{entry.name}</LabeledList.Item>
        <LabeledList.Item label="JSON Version">{entry.version}</LabeledList.Item>
        <LabeledList.Item label="Uploader">{entry.uploader}</LabeledList.Item>
        <LabeledList.Item label="Last Update">{entry.timestamp}</LabeledList.Item>
        <LabeledList.Item label="Approved">
          <Button.Checkbox
            checked={entry.approved}
            onClick={() => act("approve", { ref: entry.ref })}
          />
        </LabeledList.Item>
        <LabeledList.Item label="JSON">
          {entry.json_status}
          <Button onClick={() => act("upload", { ref: entry.ref })} content="Upload" />
          <Button onClick={() => act("download", { ref: entry.ref })} content="Download" />
        </LabeledList.Item>
      </LabeledList>
      <Button.Confirm onClick={() => { close(); act("delete", { ref: entry.ref }); }} content="Delete" />
      <Button onClick={() => act("play", { ref: entry.ref })} content="Play" />
      <Button onClick={() => act("refresh", { ref: entry.ref })} content="Refresh" />
      <Button.Confirm onClick={() => act("save", { ref: entry.ref })} content="Save" />
      <Button onClick={close} content="Close" />

  );
};

const AdventureList = (props, context) => {
  const { data, act } = useBackend<AdventureBrowserData>(context);
  const [
    openAdventure,
    setOpenAdventure,
  ] = useLocalState<string | null>(context, 'openAdventure', null);

  return (
    <>
      {openAdventure && (
        <AdventureEntry
          entry_ref={openAdventure}
          close={() => setOpenAdventure(null)} />
      )}
      {!openAdventure && (

ID

Title

Edit

          {data.adventures.map(adventure => (

{adventure.id}

{adventure.name}

<Button icon="edit" onClick={() => setOpenAdventure(adventure.ref)} />

          ))}

            <Button onClick={() => act("create")}>Create New</Button>

      )}
    </>
  );
};

const DebugPlayer = (props, context) => {
  const { data, act } = useBackend<AdventureBrowserData>(context);
  return (
    <Section
      title="Playtest"
      buttons={<Button onClick={() => act("end_play")}>End Playtest</Button>}>
      {data.delay_time > 0
        ? <Box>DELAY {formatTime(data.delay_time)} / {data.delay_message}</Box>
        : (
          <AdventureScreen
            adventure_data={data.adventure_data}
            drone_integrity={100}
            drone_max_integrity={100}
            hide_status
          />
        )}

);
};

export const AdventureBrowser = (props, context) => {
  const { data } = useBackend<AdventureBrowserData>(context);

  return (
    <Window width={650} height={500} title="Adventure Manager">
      <Window.Content>
        {!!data.feedback_message && (
          <NoticeBox>
            {data.feedback_message}
          </NoticeBox>
        )}
        {data.play_mode ? (<DebugPlayer />) : (<AdventureList />)}
      </Window.Content>
    </Window>
  );
};


code:
import { useBackend } from '../backend';
import { Button, LabeledList, Section } from '../components';
import { Window } from '../layouts';

const dangerMap = {
  2: {
    color: 'good',
    localStatusText: 'Offline',
  },
  1: {
    color: 'average',
    localStatusText: 'Caution',
  },
  0: {
    color: 'bad',
    localStatusText: 'Optimal',
  },
};

export const AiAirlock = (props, context) => {
  const { act, data } = useBackend(context);
  const statusMain = dangerMap[data.power.main] || dangerMap[0];
  const statusBackup = dangerMap[data.power.backup] || dangerMap[0];
  const statusElectrify = dangerMap[data.shock] || dangerMap[0];
  return (
    <Window
      width={500}
      height={390}>
      <Window.Content>

          <LabeledList>
            <LabeledList.Item
              label="Main"
              color={statusMain.color}
              buttons={(
                <Button
                  icon="lightbulb-o"
                  disabled={!data.power.main}
                  content="Disrupt"
                  onClick={() => act('disrupt-main')} />
              )}>
              {data.power.main ? 'Online' : 'Offline'}
              {' '}
              {(!data.wires.main_1 || !data.wires.main_2)
                && '[Wires have been cut!]'
                || (data.power.main_timeleft > 0
                  && `[${data.power.main_timeleft}s]`)}
            </LabeledList.Item>
            <LabeledList.Item
              label="Backup"
              color={statusBackup.color}
              buttons={(
                <Button
                  icon="lightbulb-o"
                  disabled={!data.power.backup}
                  content="Disrupt"
                  onClick={() => act('disrupt-backup')} />
              )}>
              {data.power.backup ? 'Online' : 'Offline'}
              {' '}
              {(!data.wires.backup_1 || !data.wires.backup_2)
                && '[Wires have been cut!]'
                || (data.power.backup_timeleft > 0
                  && `[${data.power.backup_timeleft}s]`)}
            </LabeledList.Item>
            <LabeledList.Item
              label="Electrify"
              color={statusElectrify.color}
              buttons={(
                <>
                  <Button
                    icon="wrench"
                    disabled={!(data.wires.shock && data.shock === 0)}
                    content="Restore"
                    onClick={() => act('shock-restore')} />
                  <Button
                    icon="bolt"
                    disabled={!data.wires.shock}
                    content="Temporary"
                    onClick={() => act('shock-temp')} />
                  <Button
                    icon="bolt"
                    disabled={!data.wires.shock}
                    content="Permanent"
                    onClick={() => act('shock-perm')} />
                </>
              )}>
              {data.shock === 2 ? 'Safe' : 'Electrified'}
              {' '}
              {!data.wires.shock
                && '[Wires have been cut!]'
                || (data.shock_timeleft > 0
                  && `[${data.shock_timeleft}s]`)
                || (data.shock_timeleft === -1
                  && '[Permanent]')}
            </LabeledList.Item>
          </LabeledList>

          <LabeledList>
            <LabeledList.Item
              label="ID Scan"
              color="bad"
              buttons={(
                <Button
                  icon={data.id_scanner ? 'power-off' : 'times'}
                  content={data.id_scanner ? 'Enabled' : 'Disabled'}
                  selected={data.id_scanner}
                  disabled={!data.wires.id_scanner}
                  onClick={() => act('idscan-toggle')} />
              )}>
              {!data.wires.id_scanner && '[Wires have been cut!]'}
            </LabeledList.Item>
            <LabeledList.Item
              label="Emergency Access"
              buttons={(
                <Button
                  icon={data.emergency ? 'power-off' : 'times'}
                  content={data.emergency ? 'Enabled' : 'Disabled'}
                  selected={data.emergency}
                  onClick={() => act('emergency-toggle')} />
              )} />
            <LabeledList.Divider />
            <LabeledList.Item
              label="Door Bolts"
              color="bad"
              buttons={(
                <Button
                  icon={data.locked ? 'lock' : 'unlock'}
                  content={data.locked ? 'Lowered' : 'Raised'}
                  selected={data.locked}
                  disabled={!data.wires.bolts}
                  onClick={() => act('bolt-toggle')} />
              )}>
              {!data.wires.bolts && '[Wires have been cut!]'}
            </LabeledList.Item>
            <LabeledList.Item
              label="Door Bolt Lights"
              color="bad"
              buttons={(
                <Button
                  icon={data.lights ? 'power-off' : 'times'}
                  content={data.lights ? 'Enabled' : 'Disabled'}
                  selected={data.lights}
                  disabled={!data.wires.lights}
                  onClick={() => act('light-toggle')} />
              )}>
              {!data.wires.lights && '[Wires have been cut!]'}
            </LabeledList.Item>
            <LabeledList.Item
              label="Door Force Sensors"
              color="bad"
              buttons={(
                <Button
                  icon={data.safe ? 'power-off' : 'times'}
                  content={data.safe ? 'Enabled' : 'Disabled'}
                  selected={data.safe}
                  disabled={!data.wires.safe}
                  onClick={() => act('safe-toggle')} />
              )}>
              {!data.wires.safe && '[Wires have been cut!]'}
            </LabeledList.Item>
            <LabeledList.Item
              label="Door Timing Safety"
              color="bad"
              buttons={(
                <Button
                  icon={data.speed ? 'power-off' : 'times'}
                  content={data.speed ? 'Enabled' : 'Disabled'}
                  selected={data.speed}
                  disabled={!data.wires.timing}
                  onClick={() => act('speed-toggle')} />
              )}>
              {!data.wires.timing && '[Wires have been cut!]'}
            </LabeledList.Item>
            <LabeledList.Divider />
            <LabeledList.Item
              label="Door Control"
              color="bad"
              buttons={(
                <Button
                  icon={data.opened ? 'sign-out-alt' : 'sign-in-alt'}
                  content={data.opened ? 'Open' : 'Closed'}
                  selected={data.opened}
                  disabled={(data.locked || data.welded)}
                  onClick={() => act('open-close')} />
              )}>
              {!!(data.locked || data.welded) && (

                  [Door is {data.locked ? 'bolted' : ''}
                  {(data.locked && data.welded) ? ' and ' : ''}
                  {data.welded ? 'welded' : ''}!]

              )}
            </LabeledList.Item>
          </LabeledList>

      </Window.Content>
    </Window>
  );
};


code:
import { useBackend } from '../backend';
import { Box, Button, LabeledList, NoticeBox, ProgressBar, Section } from '../components';
import { Window } from '../layouts';

export const AiRestorer = () => {
  return (
    <Window
      width={370}
      height={360}>
      <Window.Content scrollable>
        <AiRestorerContent />
      </Window.Content>
    </Window>
  );
};

export const AiRestorerContent = (props, context) => {
  const { act, data } = useBackend(context);
  const {
    AI_present,
    error,
    name,
    laws,
    isDead,
    restoring,
    health,
    ejectable,
  } = data;
  return (
    <>
      {error && (
        <NoticeBox textAlign="center">
          {error}
        </NoticeBox>
      )}
      {!!ejectable && (
        <Button
          fluid
          icon="eject"
          content={AI_present ? name : "----------"}
          disabled={!AI_present}
          onClick={() => act('PRG_eject')} />
      )}
      {!!AI_present && (
        <Section
          title={ejectable ? "System Status" : name}
          buttons={(
            <Box
              inline
              bold
              color={isDead ? 'bad' : 'good'}>
              {isDead ? "Nonfunctional" : "Functional"}
            </Box>
          )}>
          <LabeledList>
            <LabeledList.Item label="Integrity">
              <ProgressBar
                value={health}
                minValue={0}
                maxValue={100}
                ranges={{
                  good: [70, Infinity],
                  average: [50, 70],
                  bad: [-Infinity, 50],
                }} />
            </LabeledList.Item>
          </LabeledList>
          {!!restoring && (
            <Box
              bold
              textAlign="center"
              fontSize="20px"
              color="good"
              mt={1}>
              RECONSTRUCTION IN PROGRESS
            </Box>
          )}
          <Button
            fluid
            icon="plus"
            content="Begin Reconstruction"
            disabled={restoring}
            mt={1}
            onClick={() => act('PRG_beginReconstruction')} />
          <Section title="Laws" level={2}>
            {laws.map(law => (
              <Box key={law} className="candystripe">
                {law}
              </Box>
            ))}
          </Section>
        </Section>
      )}
    </>
  );
};