mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-01-02 13:34:49 +00:00
Bundle Copy
This commit is contained in:
298
tgui/packages/tgui_ch/components/Box.tsx
Normal file
298
tgui/packages/tgui_ch/components/Box.tsx
Normal file
@@ -0,0 +1,298 @@
|
||||
/**
|
||||
* @file
|
||||
* @copyright 2020 Aleksej Komarov
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { BooleanLike, classes, pureComponentHooks } from 'common/react';
|
||||
import { createVNode, InfernoNode, SFC } from 'inferno';
|
||||
import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags';
|
||||
import { CSS_COLORS } from '../constants';
|
||||
|
||||
export interface BoxProps {
|
||||
[key: string]: any;
|
||||
as?: string;
|
||||
className?: string | BooleanLike;
|
||||
children?: InfernoNode;
|
||||
position?: string | BooleanLike;
|
||||
overflow?: string | BooleanLike;
|
||||
overflowX?: string | BooleanLike;
|
||||
overflowY?: string | BooleanLike;
|
||||
top?: string | BooleanLike;
|
||||
bottom?: string | BooleanLike;
|
||||
left?: string | BooleanLike;
|
||||
right?: string | BooleanLike;
|
||||
width?: string | BooleanLike;
|
||||
minWidth?: string | BooleanLike;
|
||||
maxWidth?: string | BooleanLike;
|
||||
height?: string | BooleanLike;
|
||||
minHeight?: string | BooleanLike;
|
||||
maxHeight?: string | BooleanLike;
|
||||
fontSize?: string | BooleanLike;
|
||||
fontFamily?: string;
|
||||
lineHeight?: string | BooleanLike;
|
||||
opacity?: number;
|
||||
textAlign?: string | BooleanLike;
|
||||
verticalAlign?: string | BooleanLike;
|
||||
textTransform?: string | BooleanLike; // VOREStation Addition
|
||||
unselectable?: string | BooleanLike; // VOREStation Addition
|
||||
inline?: BooleanLike;
|
||||
bold?: BooleanLike;
|
||||
italic?: BooleanLike;
|
||||
nowrap?: BooleanLike;
|
||||
preserveWhitespace?: BooleanLike;
|
||||
m?: string | BooleanLike;
|
||||
mx?: string | BooleanLike;
|
||||
my?: string | BooleanLike;
|
||||
mt?: string | BooleanLike;
|
||||
mb?: string | BooleanLike;
|
||||
ml?: string | BooleanLike;
|
||||
mr?: string | BooleanLike;
|
||||
p?: string | BooleanLike;
|
||||
px?: string | BooleanLike;
|
||||
py?: string | BooleanLike;
|
||||
pt?: string | BooleanLike;
|
||||
pb?: string | BooleanLike;
|
||||
pl?: string | BooleanLike;
|
||||
pr?: string | BooleanLike;
|
||||
color?: string | BooleanLike;
|
||||
textColor?: string | BooleanLike;
|
||||
backgroundColor?: string | BooleanLike;
|
||||
// VOREStation Addition Start
|
||||
// Flex props
|
||||
order?: string | BooleanLike;
|
||||
flexDirection?: string | BooleanLike;
|
||||
flexGrow?: string | BooleanLike;
|
||||
flexShrink?: string | BooleanLike;
|
||||
flexWrap?: string | BooleanLike;
|
||||
flexFlow?: string | BooleanLike;
|
||||
flexBasis?: string | BooleanLike;
|
||||
flex?: string | BooleanLike;
|
||||
alignItems?: string | BooleanLike;
|
||||
justifyContent?: string | BooleanLike;
|
||||
alignSelf?: string | BooleanLike;
|
||||
// VOREStation Addition End
|
||||
fillPositionedParent?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Coverts our rem-like spacing unit into a CSS unit.
|
||||
*/
|
||||
export const unit = (value: unknown): string | undefined => {
|
||||
if (typeof value === 'string') {
|
||||
// Transparently convert pixels into rem units
|
||||
if (value.endsWith('px') && !Byond.IS_LTE_IE8) {
|
||||
return parseFloat(value) / 12 + 'rem';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
if (Byond.IS_LTE_IE8) {
|
||||
return value * 12 + 'px';
|
||||
}
|
||||
return value + 'rem';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Same as `unit`, but half the size for integers numbers.
|
||||
*/
|
||||
export const halfUnit = (value: unknown): string | undefined => {
|
||||
if (typeof value === 'string') {
|
||||
return unit(value);
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
return unit(value * 0.5);
|
||||
}
|
||||
};
|
||||
|
||||
const isColorCode = (str: unknown) => !isColorClass(str);
|
||||
|
||||
const isColorClass = (str: unknown): boolean => {
|
||||
return typeof str === 'string' && CSS_COLORS.includes(str);
|
||||
};
|
||||
|
||||
const mapRawPropTo = (attrName) => (style, value) => {
|
||||
if (typeof value === 'number' || typeof value === 'string') {
|
||||
style[attrName] = value;
|
||||
}
|
||||
};
|
||||
|
||||
const mapUnitPropTo = (attrName, unit) => (style, value) => {
|
||||
if (typeof value === 'number' || typeof value === 'string') {
|
||||
style[attrName] = unit(value);
|
||||
}
|
||||
};
|
||||
|
||||
const mapBooleanPropTo = (attrName, attrValue) => (style, value) => {
|
||||
if (value) {
|
||||
style[attrName] = attrValue;
|
||||
}
|
||||
};
|
||||
|
||||
const mapDirectionalUnitPropTo = (attrName, unit, dirs) => (style, value) => {
|
||||
if (typeof value === 'number' || typeof value === 'string') {
|
||||
for (let i = 0; i < dirs.length; i++) {
|
||||
style[attrName + '-' + dirs[i]] = unit(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const mapColorPropTo = (attrName) => (style, value) => {
|
||||
if (isColorCode(value)) {
|
||||
style[attrName] = value;
|
||||
}
|
||||
};
|
||||
|
||||
const styleMapperByPropName = {
|
||||
// Direct mapping
|
||||
position: mapRawPropTo('position'),
|
||||
overflow: mapRawPropTo('overflow'),
|
||||
overflowX: mapRawPropTo('overflow-x'),
|
||||
overflowY: mapRawPropTo('overflow-y'),
|
||||
top: mapUnitPropTo('top', unit),
|
||||
bottom: mapUnitPropTo('bottom', unit),
|
||||
left: mapUnitPropTo('left', unit),
|
||||
right: mapUnitPropTo('right', unit),
|
||||
width: mapUnitPropTo('width', unit),
|
||||
minWidth: mapUnitPropTo('min-width', unit),
|
||||
maxWidth: mapUnitPropTo('max-width', unit),
|
||||
height: mapUnitPropTo('height', unit),
|
||||
minHeight: mapUnitPropTo('min-height', unit),
|
||||
maxHeight: mapUnitPropTo('max-height', unit),
|
||||
fontSize: mapUnitPropTo('font-size', unit),
|
||||
fontFamily: mapRawPropTo('font-family'),
|
||||
lineHeight: (style, value) => {
|
||||
if (typeof value === 'number') {
|
||||
style['line-height'] = value;
|
||||
} else if (typeof value === 'string') {
|
||||
style['line-height'] = unit(value);
|
||||
}
|
||||
},
|
||||
opacity: mapRawPropTo('opacity'),
|
||||
textAlign: mapRawPropTo('text-align'),
|
||||
verticalAlign: mapRawPropTo('vertical-align'),
|
||||
textTransform: mapRawPropTo('text-transform'), // VOREStation Addition
|
||||
unselectable: mapRawPropTo('unselectable'), // VOREStation Addition
|
||||
// Boolean props
|
||||
inline: mapBooleanPropTo('display', 'inline-block'),
|
||||
bold: mapBooleanPropTo('font-weight', 'bold'),
|
||||
italic: mapBooleanPropTo('font-style', 'italic'),
|
||||
nowrap: mapBooleanPropTo('white-space', 'nowrap'),
|
||||
preserveWhitespace: mapBooleanPropTo('white-space', 'pre-wrap'),
|
||||
// Margins
|
||||
m: mapDirectionalUnitPropTo('margin', halfUnit, ['top', 'bottom', 'left', 'right']),
|
||||
mx: mapDirectionalUnitPropTo('margin', halfUnit, ['left', 'right']),
|
||||
my: mapDirectionalUnitPropTo('margin', halfUnit, ['top', 'bottom']),
|
||||
mt: mapUnitPropTo('margin-top', halfUnit),
|
||||
mb: mapUnitPropTo('margin-bottom', halfUnit),
|
||||
ml: mapUnitPropTo('margin-left', halfUnit),
|
||||
mr: mapUnitPropTo('margin-right', halfUnit),
|
||||
// Margins
|
||||
p: mapDirectionalUnitPropTo('padding', halfUnit, ['top', 'bottom', 'left', 'right']),
|
||||
px: mapDirectionalUnitPropTo('padding', halfUnit, ['left', 'right']),
|
||||
py: mapDirectionalUnitPropTo('padding', halfUnit, ['top', 'bottom']),
|
||||
pt: mapUnitPropTo('padding-top', halfUnit),
|
||||
pb: mapUnitPropTo('padding-bottom', halfUnit),
|
||||
pl: mapUnitPropTo('padding-left', halfUnit),
|
||||
pr: mapUnitPropTo('padding-right', halfUnit),
|
||||
// Color props
|
||||
color: mapColorPropTo('color'),
|
||||
textColor: mapColorPropTo('color'),
|
||||
backgroundColor: mapColorPropTo('background-color'),
|
||||
// VOREStation Addition Start
|
||||
// Flex props
|
||||
order: mapRawPropTo('order'),
|
||||
flexDirection: mapRawPropTo('flex-direction'),
|
||||
flexGrow: mapRawPropTo('flex-grow'),
|
||||
flexShrink: mapRawPropTo('flex-shrink'),
|
||||
flexWrap: mapRawPropTo('flex-wrap'),
|
||||
flexFlow: mapRawPropTo('flex-flow'),
|
||||
flexBasis: mapRawPropTo('flex-basis'),
|
||||
flex: mapRawPropTo('flex'),
|
||||
alignItems: mapRawPropTo('align-items'),
|
||||
justifyContent: mapRawPropTo('justify-content'),
|
||||
alignSelf: mapRawPropTo('align-self'),
|
||||
// VOREStation Addition End
|
||||
// Utility props
|
||||
fillPositionedParent: (style, value) => {
|
||||
if (value) {
|
||||
style['position'] = 'absolute';
|
||||
style['top'] = 0;
|
||||
style['bottom'] = 0;
|
||||
style['left'] = 0;
|
||||
style['right'] = 0;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export const computeBoxProps = (props: BoxProps) => {
|
||||
const computedProps: HTMLAttributes<any> = {};
|
||||
const computedStyles = {};
|
||||
// Compute props
|
||||
for (let propName of Object.keys(props)) {
|
||||
if (propName === 'style') {
|
||||
continue;
|
||||
}
|
||||
// IE8: onclick workaround
|
||||
if (Byond.IS_LTE_IE8 && propName === 'onClick') {
|
||||
computedProps.onclick = props[propName];
|
||||
continue;
|
||||
}
|
||||
const propValue = props[propName];
|
||||
const mapPropToStyle = styleMapperByPropName[propName];
|
||||
if (mapPropToStyle) {
|
||||
mapPropToStyle(computedStyles, propValue);
|
||||
} else {
|
||||
computedProps[propName] = propValue;
|
||||
}
|
||||
}
|
||||
// Concatenate styles
|
||||
let style = '';
|
||||
for (let attrName of Object.keys(computedStyles)) {
|
||||
const attrValue = computedStyles[attrName];
|
||||
style += attrName + ':' + attrValue + ';';
|
||||
}
|
||||
if (props.style) {
|
||||
for (let attrName of Object.keys(props.style)) {
|
||||
const attrValue = props.style[attrName];
|
||||
style += attrName + ':' + attrValue + ';';
|
||||
}
|
||||
}
|
||||
if (style.length > 0) {
|
||||
computedProps.style = style;
|
||||
}
|
||||
return computedProps;
|
||||
};
|
||||
|
||||
export const computeBoxClassName = (props: BoxProps) => {
|
||||
const color = props.textColor || props.color;
|
||||
const backgroundColor = props.backgroundColor;
|
||||
return classes([
|
||||
isColorClass(color) && 'color-' + color,
|
||||
isColorClass(backgroundColor) && 'color-bg-' + backgroundColor,
|
||||
]);
|
||||
};
|
||||
|
||||
export const Box: SFC<BoxProps> = (props: BoxProps) => {
|
||||
const { as = 'div', className, children, ...rest } = props;
|
||||
// Render props
|
||||
if (typeof children === 'function') {
|
||||
return children(computeBoxProps(props));
|
||||
}
|
||||
const computedClassName =
|
||||
typeof className === 'string' ? className + ' ' + computeBoxClassName(rest) : computeBoxClassName(rest);
|
||||
const computedProps = computeBoxProps(rest);
|
||||
// Render a wrapper element
|
||||
return createVNode(
|
||||
VNodeFlags.HtmlElement,
|
||||
as,
|
||||
computedClassName,
|
||||
children,
|
||||
ChildFlags.UnknownChildren,
|
||||
computedProps,
|
||||
undefined
|
||||
);
|
||||
};
|
||||
|
||||
Box.defaultHooks = pureComponentHooks;
|
||||
Reference in New Issue
Block a user