tgui: Fix Crafting, Tweak Box Units (#50577)

* Fix PersonalCrafting

* Half em units for margin/padding, full em unit for everything else.

* Update docs

* Opsie

* Rebuild tgui

* Let's pretend that IE10 is IE8

Closes #50588

* Assert dominance
This commit is contained in:
Aleksej Komarov
2020-04-21 09:24:19 +03:00
committed by GitHub
parent e5b6114fa1
commit d86c667901
17 changed files with 151 additions and 122 deletions

View File

@@ -140,3 +140,4 @@ Fikou = Game Master
Skoglol = Game Master
4dplanner = Game Master
Time-Green = Game Master
StyleMistake = Game Master

View File

@@ -54,32 +54,25 @@ Make sure to add new items to this list if you document new components.
These are the components which you can use for interface construction.
If you have trouble finding the exact prop you need on a component,
please note, that most of these components inherit from other basic
components, such as `Box`. This component in particular provides a lot
components, such as [Box](#box). This component in particular provides a lot
of styling options for all components, e.g. `color` and `opacity`, thus
it is used a lot in this framework.
There are a few important semantics you need to know about:
**Event handlers.**
Event handlers are callbacks that you can attack to various element to
listen for browser events. Inferno supports camelcase (`onClick`) and
lowercase (`onclick`) event names.
- Some elements support a `content` prop, which is a synonym to a
`children` prop.
- `content` is better used when your element is a self-closing tag
(like `<Button content="Hello" />`), and when content is small and simple
enough to fit in a prop. Keep in mind, that this prop is **not** native
to React, and is only available on these components: `Button`, `Tooltip`.
- You should never use `children` explicitly as a prop on an element.
Instead open a full tag, and place children or text inside the tag.
- Inferno supports both camelcase (`onClick`) and lowercase (`onclick`)
event names.
- Camel case names are what's called "synthetic" events, and are the
*preferred way* of handling events in React, for efficiency and
performance reasons. Please read
[Inferno Event Handling](https://infernojs.org/docs/guides/event-handling)
to understand what this is about.
- Lower case names are native browser events and should be used sparingly,
for example when you need an explicit IE8 support. **DO NOT** use
lowercase event handlers unless you really know what you are doing.
- [Button](#button) component does not support lowercase `onclick` event.
Use the camel case `onClick` instead.
- Camel case names are what's called *synthetic* events, and are the
**preferred way** of handling events in React, for efficiency and
performance reasons. Please read
[Inferno Event Handling](https://infernojs.org/docs/guides/event-handling)
to understand what this is about.
- Lower case names are native browser events and should be used sparingly,
for example when you need an explicit IE8 support. **DO NOT** use
lowercase event handlers unless you really know what you are doing.
- [Button](#button) component does not support the lowercase `onclick` event.
Use the camel case `onClick` instead.
## `tgui/components`
@@ -87,7 +80,7 @@ event names.
This component provides animations for numeric values.
Props:
**Props:**
- `value: number` - Value to animate.
- `initial: number` - Initial value to use in animation when element
@@ -106,7 +99,7 @@ Just a block quote, just like this example in markdown:
> Here's an example of a block quote.
Props:
**Props:**
- See inherited props: [Box](#box)
@@ -138,15 +131,21 @@ This way, `Button` can pull out the `className` generated by the `Box`.
</Box>
```
`Box` units, like width, height and margins can be defined in two ways:
- By plain numbers (1 unit equals `0.5em`);
- In absolute measures, by providing a full unit string (e.g. `100px`).
**Box Units**
`Box` units, like width, height and margins can be defined in two ways:
- By plain numbers
- 1 unit equals `1rem` for width, height and positioning properties.
- 1 unit equals `0.5rem` for margins and paddings.
- By strings with proper CSS units
- For example: `100px`, `2em`, `1rem`, `100%`, etc.
Units which are used in `Box` are `0.5em`, which are half font-size.
Default font size is `12px`, so each unit is effectively `6px` in size.
If you need more precision, you can always use fractional numbers.
Props:
Default font size (`1rem`) is equal to `12px`.
**Props:**
- `as: string` - The component used for the root node.
- `color: string` - Applies an atomic `color-<name>` class to the element.
@@ -204,7 +203,7 @@ all available horizontal space.
Buttons allow users to take actions, and make choices, with a single click.
Props:
**Props:**
- See inherited props: [Box](#box)
- `fluid: boolean` - Fill all available horizontal space.
@@ -233,7 +232,7 @@ over the button.
A ghetto checkbox, made entirely using existing Button API.
Props:
**Props:**
- See inherited props: [Button](#button)
- `checked: boolean` - Boolean value, which marks the checkbox as checked.
@@ -242,7 +241,7 @@ Props:
A button with a an extra confirmation step, using native button component.
Props:
**Props:**
- See inherited props: [Button](#button)
- `confirmMessage: string` - Text to display after first click; defaults to "Confirm?"
@@ -254,7 +253,7 @@ A button that turns into an input box after the first click. Turns back into a
button after the user hits enter, defocuses, or hits escape. Enter and defocus
commit, while escape cancels.
Props:
**Props:**
- See inherited props: [Box](#box)
- `fluid`: fill availible horizontal space
@@ -297,7 +296,7 @@ Example (map):
It supports a full set of `Box` properties for layout purposes.
Props:
**Props:**
- See inherited props: [Box](#box)
- `params: any` - An object with parameters, which are directly passed to
@@ -309,7 +308,7 @@ in [BYOND controls and parameters guide](https://secure.byond.com/docs/ref/skinp
Displays contents when open, acts as a fluid button when closed. Click to
toggle, closed by default.
Props:
**Props:**
- See inherited props: [Box](#box)
- `children: any` - What is collapsed when closed
@@ -325,7 +324,7 @@ or for visually representing a color.
If you want to set a background color on an element, use a plain
[Box](#box) instead.
Props:
**Props:**
- See inherited props: [Box](#box)
- `color: string` - Color of the box.
@@ -336,7 +335,7 @@ Dims surrounding area to emphasize content placed inside.
Content is automatically centered inside the dimmer.
Props:
**Props:**
- See inherited props: [Box](#box)
@@ -345,7 +344,7 @@ Props:
Draws a horizontal or vertical line, dividing a section into groups.
Works like the good old `<hr>` element, but it's fancier.
Props:
**Props:**
- `vertical: boolean` - Divide content vertically.
- `hidden: boolean` - Divider can divide content without creating a dividing
@@ -356,7 +355,7 @@ line.
A simple dropdown box component. Lets the user select from a list of options
and displays selected entry.
Props:
**Props:**
- See inherited props: [Box](#box)
- `options: string[]` - An array of strings which will be displayed in the
@@ -397,7 +396,7 @@ to the left, and certain elements to the right:
Flex item with `grow` property serves as a "filler", to separate the other
two flex items as far as possible from each other.
Props:
**Props:**
- See inherited props: [Box](#box)
- `spacing: number` - Spacing between flex items, in integer units
@@ -444,7 +443,7 @@ when they overflow the line.
### `Flex.Item`
Props:
**Props:**
- See inherited props: [Box](#box)
- `order: number` - By default, flex items are laid out in the source order.
@@ -493,13 +492,13 @@ Example:
</Grid>
```
Props:
**Props:**
- See inherited props: [Table](#table)
### `Grid.Column`
Props:
**Props:**
- See inherited props: [Table.Cell](#tablecell)
- `size: number` (default: 1) - Size of the column relative to other columns.
@@ -517,7 +516,7 @@ transform names with `-o` suffixes to FA Regular icons. For example:
- `square` will get transformed to `fas square`
- `square-o` will get transformed to `far square`
Props:
**Props:**
- See inherited props: [Box](#box)
- `name: string` - Icon name.
@@ -534,7 +533,7 @@ A basic text input, which allow users to enter text into a UI.
> Input does not support custom font size and height due to the way
> it's implemented in CSS. Eventually, this needs to be fixed.
Props:
**Props:**
- See inherited props: [Box](#box)
- `value: string` - Value of an input.
@@ -554,7 +553,7 @@ up and down.
Single click opens an input box to manually type in a number.
Props:
**Props:**
- See inherited props: [Box](#box)
- `animated: boolean` - Animates the value if it was changed externally.
@@ -614,13 +613,13 @@ to perform some sort of action), there is a way to do that:
</LabeledList>
```
Props:
**Props:**
- `children: LabeledList.Item` - Items to render.
### `LabeledList.Item`
Props:
**Props:**
- `label: string` - Item label.
- `color: string` - Sets the color of the text.
@@ -642,7 +641,7 @@ Example:
</LabeledList>
```
Props:
**Props:**
- `size: number` - Size of the divider.
@@ -653,7 +652,7 @@ adjusts its own size to fit the content you're trying to display.
Must be a direct child of a layout component (e.g. [Window](#window)).
Props:
**Props:**
- See inherited props: [Box](#box)
@@ -661,7 +660,7 @@ Props:
A notice box, which warns you about something very important.
Props:
**Props:**
- See inherited props: [Box](#box)
- `info: boolean` - Info box
@@ -674,7 +673,7 @@ Props:
A fancy, interactive number input, which you can either drag up and down
to fine tune the value, or single click it to manually type a number.
Props:
**Props:**
- `animated: boolean` - Animates the value if it was changed externally.
- `fluid: boolean` - Fill all available horizontal space.
@@ -720,7 +719,7 @@ Usage of `ranges` prop:
value={0.6} />
```
Props:
**Props:**
- `value: number` - Current progress as a floating point number between
`minValue` (default: 0) and `maxValue` (default: 1). Determines the
@@ -775,7 +774,7 @@ in precise values by dragging it left and right.
Single click opens an input box to manually type in a number.
Props:
**Props:**
- See inherited props: [Box](#box)
- `animated: boolean` - Animates the value if it was changed externally.
@@ -824,7 +823,7 @@ Example:
</Table>
```
Props:
**Props:**
- See inherited props: [Box](#box)
- `collapsing: boolean` - Collapses table to the smallest possible size.
@@ -833,7 +832,7 @@ Props:
A straight forward mapping to `<tr>` element.
Props:
**Props:**
- See inherited props: [Box](#box)
@@ -841,7 +840,7 @@ Props:
A straight forward mapping to `<td>` element.
Props:
**Props:**
- See inherited props: [Box](#box)
- `collapsing: boolean` - Collapses table cell to the smallest possible size,
@@ -891,7 +890,7 @@ Tabs also support a vertical configuration. This is usually paired with a
</Flex>
```
Props:
**Props:**
- See inherited props: [Box](#box)
- `vertical: boolean` - Use a vertical configuration, where tabs will be
@@ -903,7 +902,7 @@ stacked vertically.
An individual tab element. Tabs function like buttons, so they inherit
a lot of `Button` props.
Props:
**Props:**
- See inherited props: [Button](#button)
- `altSelection` - Whether the tab buttons select via standard select (color
@@ -932,7 +931,7 @@ Usage:
</Box>
```
Props:
**Props:**
- `position: string` - Tooltip position.
- `content/children: string` - Content of the tooltip. Must be a plain string.
@@ -958,7 +957,7 @@ Example:
</Window>
```
Props:
**Props:**
- `className: string` - Applies a CSS class to the element.
- `theme: string` - A name of the theme.
@@ -974,7 +973,7 @@ putting your content into [Window.Content](#windowcontent).
Canonical window content, which is usually the main target of window focus.
Can be scrollable.
Props:
**Props:**
- `className: string` - Applies a CSS class to the element.
- `scrollable: boolean` - Shows or hides the scrollbar.

View File

@@ -22,9 +22,11 @@ const tridentVersion = (() => {
/**
* True if browser is an Internet Explorer 8 or lower.
*
* (Actually, no, it also includes IE9 and IE10).
*/
export const IS_IE8 = tridentVersion !== null
&& tridentVersion <= 4;
&& tridentVersion <= 6;
/**
* Makes a BYOND call.

View File

@@ -3,7 +3,7 @@ import { createVNode } from 'inferno';
import { ChildFlags, VNodeFlags } from 'inferno-vnode-flags';
import { CSS_COLORS } from '../constants';
const UNIT_PX = 6;
const UNIT_PX = 12;
/**
* Coverts our rem-like spacing unit into a CSS unit.
@@ -17,6 +17,18 @@ export const unit = value => {
}
};
/**
* Same as `unit`, but half the size for integers numbers.
*/
export const halfUnit = value => {
if (typeof value === 'string') {
return value;
}
if (typeof value === 'number') {
return (value * UNIT_PX * 0.5) + 'px';
}
};
const isColorCode = str => !isColorClass(str);
const isColorClass = str => typeof str === 'string'
@@ -28,7 +40,7 @@ const mapRawPropTo = attrName => (style, value) => {
}
};
const mapUnitPropTo = attrName => (style, value) => {
const mapUnitPropTo = (attrName, unit) => (style, value) => {
if (!isFalsy(value)) {
style[attrName] = unit(value);
}
@@ -40,7 +52,7 @@ const mapBooleanPropTo = (attrName, attrValue) => (style, value) => {
}
};
const mapDirectionalUnitPropTo = (attrName, dirs) => (style, value) => {
const mapDirectionalUnitPropTo = (attrName, unit, dirs) => (style, value) => {
if (!isFalsy(value)) {
for (let i = 0; i < dirs.length; i++) {
style[attrName + '-' + dirs[i]] = unit(value);
@@ -60,17 +72,17 @@ const styleMapperByPropName = {
overflow: mapRawPropTo('overflow'),
overflowX: mapRawPropTo('overflow-x'),
overflowY: mapRawPropTo('overflow-y'),
top: mapUnitPropTo('top'),
bottom: mapUnitPropTo('bottom'),
left: mapUnitPropTo('left'),
right: mapUnitPropTo('right'),
width: mapUnitPropTo('width'),
minWidth: mapUnitPropTo('min-width'),
maxWidth: mapUnitPropTo('max-width'),
height: mapUnitPropTo('height'),
minHeight: mapUnitPropTo('min-height'),
maxHeight: mapUnitPropTo('max-height'),
fontSize: mapUnitPropTo('font-size'),
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: mapRawPropTo('line-height'),
opacity: mapRawPropTo('opacity'),
@@ -82,33 +94,33 @@ const styleMapperByPropName = {
italic: mapBooleanPropTo('font-style', 'italic'),
nowrap: mapBooleanPropTo('white-space', 'nowrap'),
// Margins
m: mapDirectionalUnitPropTo('margin', [
m: mapDirectionalUnitPropTo('margin', halfUnit, [
'top', 'bottom', 'left', 'right',
]),
mx: mapDirectionalUnitPropTo('margin', [
mx: mapDirectionalUnitPropTo('margin', halfUnit, [
'left', 'right',
]),
my: mapDirectionalUnitPropTo('margin', [
my: mapDirectionalUnitPropTo('margin', halfUnit, [
'top', 'bottom',
]),
mt: mapUnitPropTo('margin-top'),
mb: mapUnitPropTo('margin-bottom'),
ml: mapUnitPropTo('margin-left'),
mr: mapUnitPropTo('margin-right'),
mt: mapUnitPropTo('margin-top', halfUnit),
mb: mapUnitPropTo('margin-bottom', halfUnit),
ml: mapUnitPropTo('margin-left', halfUnit),
mr: mapUnitPropTo('margin-right', halfUnit),
// Margins
p: mapDirectionalUnitPropTo('padding', [
p: mapDirectionalUnitPropTo('padding', halfUnit, [
'top', 'bottom', 'left', 'right',
]),
px: mapDirectionalUnitPropTo('padding', [
px: mapDirectionalUnitPropTo('padding', halfUnit, [
'left', 'right',
]),
py: mapDirectionalUnitPropTo('padding', [
py: mapDirectionalUnitPropTo('padding', halfUnit, [
'top', 'bottom',
]),
pt: mapUnitPropTo('padding-top'),
pb: mapUnitPropTo('padding-bottom'),
pl: mapUnitPropTo('padding-left'),
pr: mapUnitPropTo('padding-right'),
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'),

View File

@@ -46,7 +46,6 @@ export const BlackMarketUplink = (props, context) => {
{categories.map(category => (
<Tabs.Tab
key={category}
height={4}
mt={0.5}
selected={viewing_category === category}
onClick={() => act('set_category', {

View File

@@ -10,7 +10,7 @@ export const ChemFilterPane = (props, context) => {
return (
<Section
title={title}
minHeight={40}
minHeight="240px"
buttons={(
<Fragment>
<Input
@@ -18,6 +18,7 @@ export const ChemFilterPane = (props, context) => {
width="140px"
onInput={(e, value) => onReagentInput(value)} />
<Button
ml={1}
icon="plus"
onClick={() => act('add', {
which: titleKey,

View File

@@ -196,7 +196,7 @@ const PackagingControlsItem = props => {
return (
<LabeledList.Item label={label}>
<NumberInput
width={14}
width="84px"
unit={amountUnit}
step={1}
stepPixelSize={15}
@@ -245,7 +245,7 @@ const PackagingControls = (props, context) => {
{pillStyles.map(pill => (
<Button
key={pill.id}
width={5}
width="30px"
selected={pill.id === chosenPillStyle}
textAlign="center"
color="transparent"

View File

@@ -39,7 +39,7 @@ export const ChemPress = (props, context) => {
{pill_styles.map(pill => (
<Button
key={pill.id}
width={5}
width="30px"
selected={pill.id === pill_style}
textAlign="center"
color="transparent"

View File

@@ -44,7 +44,7 @@ const CfStep1 = (props, context) => {
return (
<Section
title="Step 1"
minHeight={51}>
minHeight="306px">
<Box
mt={5}
bold
@@ -89,7 +89,7 @@ const CfStep2 = (props, context) => {
return (
<Section
title="Step 2: Customize your device"
minHeight={47}
minHeight="282px"
buttons={(
<Box bold color="good">
{data.totalprice} cr
@@ -346,7 +346,7 @@ const CfStep3 = (props, context) => {
return (
<Section
title="Step 3: Payment"
minHeight={47}>
minHeight="282px">
<Box
italic
textAlign="center"
@@ -398,7 +398,7 @@ const CfStep3 = (props, context) => {
const CfStep4 = (props, context) => {
return (
<Section
minHeight={47}>
minHeight="282px">
<Box
bold
textAlign="center"

View File

@@ -50,7 +50,7 @@ const HealthStat = props => {
return (
<Box
inline
width={4}
width={2}
color={COLORS.damageType[type]}
textAlign="center">
{value}
@@ -62,7 +62,7 @@ export const CrewConsole = () => {
return (
<Window resizable>
<Window.Content scrollable>
<Section minHeight={90}>
<Section minHeight="540px">
<CrewTable />
</Section>
</Window.Content>

View File

@@ -43,7 +43,7 @@ export const Electropack = (props, context) => {
maxValue={maxFrequency / 10}
value={frequency / 10}
format={value => toFixed(value, 1)}
width={13}
width="80px"
onDrag={(e, value) => act('freq', {
freq: value,
})} />
@@ -65,7 +65,7 @@ export const Electropack = (props, context) => {
minValue={1}
maxValue={100}
value={code}
width={13}
width="80px"
onDrag={(e, value) => act('code', {
code: value,
})} />

View File

@@ -69,7 +69,7 @@ export const NtosArcade = (props, context) => {
<Box m={1} />
<Section
inline
width={26}
width="156px"
textAlign="center">
<img src={data.BossID} />
</Section>

View File

@@ -64,7 +64,7 @@ export const NtosMain = (props, context) => {
name: program.name,
})} />
</Table.Cell>
<Table.Cell collapsing width={3}>
<Table.Cell collapsing width="18px">
{!!program.running && (
<Button
lineHeight="24px"

View File

@@ -22,7 +22,11 @@ export const PersonalCrafting = (props, context) => {
continue;
}
// Push category
categories.push(subcategory);
categories.push({
name: subcategory,
category,
subcategory,
});
// Push recipes
const _recipes = subcategories[subcategory];
for (let recipe of _recipes) {
@@ -35,7 +39,10 @@ export const PersonalCrafting = (props, context) => {
continue;
}
// Push category
categories.push(category);
categories.push({
name: category,
category,
});
// Push recipes
const _recipes = crafting_recipes[category];
for (let recipe of _recipes) {
@@ -46,7 +53,8 @@ export const PersonalCrafting = (props, context) => {
}
}
// Sort out the tab state
const [tab, setTab] = useLocalState(context, 'tab', categories[0]);
const [tab, setTab] = useLocalState(
context, 'tab', categories[0]?.name);
const shownRecipes = recipes
.filter(recipe => recipe.category === tab);
return (
@@ -77,10 +85,17 @@ export const PersonalCrafting = (props, context) => {
<Tabs vertical>
{categories.map(category => (
<Tabs.Tab
key={category}
selected={category === tab}
onClick={() => setTab(category)}>
{category}
key={category.name}
selected={category.name === tab}
onClick={() => {
setTab(category.name);
// Backend expects `0` or '' to indicate no subcategory
act('set_category', {
category: category.category,
subcategory: category.subcategory,
});
}}>
{category.name}
</Tabs.Tab>
))}
</Tabs>

View File

@@ -30,7 +30,7 @@ export const Signaler = (props, context) => {
maxValue={maxFrequency / 10}
value={frequency / 10}
format={value => toFixed(value, 1)}
width={13}
width="80px"
onDrag={(e, value) => act('freq', {
freq: value,
})} />
@@ -57,7 +57,7 @@ export const Signaler = (props, context) => {
minValue={1}
maxValue={100}
value={code}
width={13}
width="80px"
onDrag={(e, value) => act('code', {
code: value,
})} />

View File

@@ -117,8 +117,8 @@ const KitchenSinkButton = props => {
<Button fluid content="Fluid" />
<Button
my={1}
lineHeight={2}
minWidth={30}
lineHeight={1}
minWidth={15}
textAlign="center"
content="With Box props" />
</Box>
@@ -320,7 +320,7 @@ class KitchenSinkInput extends Component {
<LabeledList.Item label="NumberInput (onChange)">
<NumberInput
animated
width={10}
width="30px"
step={1}
stepPixelSize={5}
value={number}
@@ -333,7 +333,7 @@ class KitchenSinkInput extends Component {
<LabeledList.Item label="NumberInput (onDrag)">
<NumberInput
animated
width={10}
width="30px"
step={1}
stepPixelSize={5}
value={number}

File diff suppressed because one or more lines are too long