LF it all!! - And actual tgui3

This commit is contained in:
Letter N
2020-07-21 17:45:03 +08:00
parent 775d84370f
commit 9fa060de9e
10 changed files with 1243 additions and 1263 deletions

View File

@@ -8,6 +8,8 @@ env:
es6: true
browser: true
node: true
globals:
Byond: readonly
plugins:
- react
settings:
@@ -388,7 +390,7 @@ rules:
## Enforce a particular style for multiline comments
# multiline-comment-style: error
## Enforce newlines between operands of ternary expressions
multiline-ternary: [error, always-multiline]
# multiline-ternary: [error, always-multiline]
## Require constructor names to begin with a capital letter
# new-cap: error
## Enforce or disallow parentheses when invoking a constructor with no

9
tgui/.gitattributes vendored
View File

@@ -2,9 +2,18 @@
## Enforce text mode and LF line breaks
*.js text eol=lf
*.jsx text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.css text eol=lf
*.scss text eol=lf
*.html text eol=lf
*.json text eol=lf
*.yml text eol=lf
*.md text eol=lf
*.bat text eol=lf
yarn.lock text eol=lf
bin/tgui text eol=lf
## Treat bundles as binary and ignore them during conflicts
*.bundle.* binary merge=tgui-merge-bundle

View File

@@ -67,8 +67,9 @@ Run one of the following:
game as you code it. Very useful, highly recommended.
- In order to use it, you should start the game server first, connect to it
and wait until the world has been properly loaded and you are no longer
in the lobby. Start tgui dev server. You'll know that it's hooked correctly
if data gets dumped to the log when tgui windows are opened.
in the lobby. Start tgui dev server, and once it has finished building,
press F5 on any tgui window. You'll know that it's hooked correctly if
you see a green bug icon in titlebar and data gets dumped to the console.
- `bin/tgui --dev --reload` - reload byond cache once.
- `bin/tgui --dev --debug` - run server with debug logging enabled.
- `bin/tgui --dev --no-hot` - disable hot module replacement (helps when
@@ -134,11 +135,11 @@ logs and time spent on rendering. Use this information to optimize your
code, and try to keep re-renders below 16ms.
**Kitchen Sink.**
Press `Ctrl+Alt+=` to open the KitchenSink interface. This interface is a
Press `F12` to open the KitchenSink interface. This interface is a
playground to test various tgui components.
**Layout Debugger.**
Press `Ctrl+Alt+-` to toggle the *layout debugger*. It will show outlines of
Press `F11` to toggle the *layout debugger*. It will show outlines of
all tgui elements, which makes it easy to understand how everything comes
together, and can reveal certain layout bugs which are not normally visible.

View File

@@ -52,6 +52,7 @@ task-dev-server() {
task-eslint() {
cd "${base_dir}"
eslint ./packages "${@}"
echo "tgui: eslint check passed"
}
## Mr. Proper
@@ -153,6 +154,13 @@ if [[ ${1} == '--lint-harder' ]]; then
exit 0
fi
if [[ ${1} == '--fix' ]]; then
shift 1
task-install
task-eslint --fix "${@}"
exit 0
fi
## Analyze the bundle
if [[ ${1} == '--analyze' ]]; then
task-install

View File

@@ -275,11 +275,11 @@ interface.
Example (button):
```
```jsx
<ByondUi
params={{
id: 'test_button', // optional, can be auto-generated
parent: config.window,
parent: 'some_container', // optional, defaults to the current window
type: 'button',
text: 'Hello, world!',
}} />
@@ -287,11 +287,10 @@ Example (button):
Example (map):
```
```jsx
<ByondUi
params={{
id: 'test_map',
parent: config.window,
type: 'map',
}} />
```
@@ -982,6 +981,7 @@ Example:
- `className: string` - Applies a CSS class to the element.
- `theme: string` - A name of the theme.
- For a list of themes, see `packages/tgui/styles/themes`.
- `title: string` - Window title.
- `resizable: boolean` - Controls resizability of the window.
- `children: any` - Child elements, which are rendered directly inside the
window. If you use a [Dimmer](#dimmer) or [Modal](#modal) in your UI,

View File

@@ -73,6 +73,7 @@ This might look a bit intimidating compared to the reactive part but it's not as
You don't really need to know all this to understand how to use it, but I find it helps with understanding when things go wrong.
Ractive conditionals can have an `else` as well
```ractive
{{#if data.condition}}
value
@@ -116,7 +117,7 @@ and you can mix string literals, values, and tags as well.
Ractive has loops for iterating over data and inserting something for each
member of an array or object
```
```ractive
{{#each data.list_of_foo}}
foo {{number}} is here.
{{/each}}
@@ -135,6 +136,7 @@ Objects are represented by `{}`, arrays by `[]`
`list("bla", "blo")` would become `["bla", "blo"]` and `list("foo" = 1, "bar" = 2)` would become `{"foo": 1, "bar": 2}`
First things first, above the `return` of the function you're making the interface in, you're going to want to add something like this
```jsx
const things = data.things || [];
```
@@ -142,6 +144,7 @@ const things = data.things || [];
This ensures that you'll never be reading a null entry by mistake. Substitute `{}` for objects as appropriate.
If it's an array, you'll want to do this in the template
```jsx
{things.map(thing => (
<Fragment>
@@ -187,7 +190,7 @@ const fooArray = toArray(fooObject);
Also occasionally you'd see an else:
```
```ractive
{{#each data.potentially_empty_list}}
Thing "{{name}}" is in this list!
{{else}}
@@ -220,7 +223,7 @@ This will be a reference of tgui components and the tgui-next equivalent.
Equivalent of `<ui-display>` is `<Section>`
```
```ractive
<ui-display title="Status">
Contents
</ui-display>
@@ -236,7 +239,7 @@ becomes
A feature sometimes used is if `ui-display` has the `button` property, it will contain a `partial` command. This becomes the `buttons` property on `Section`:
```
```ractive
<ui-display title="Status" button>
{{#partial button}}
<ui-button /> // lots more button bullshit here
@@ -263,7 +266,7 @@ Very important to note `ui-section` is NOT the equivalent of `Section`
`<ui-section>` does not have a direct equivalent, but the closest equivalent is `<LabeledList>`
```
```ractive
<ui-section label="power">
No Power
</ui-section>
@@ -293,7 +296,7 @@ Also good to know that if you need the contents of a `LabeledList.Item` to be co
`<ui-notice>` has a direct equivalent in `<NoticeBox>`
```
```ractive
<ui-notice>
Notice stuff!
</ui-notice>
@@ -311,7 +314,7 @@ becomes
The equivalent of `ui-button` is `Button` but it works quite a bit differently.
```
```ractive
<ui-button
state='{{data.condition ? "disabled" : null}}'
action="ui_action"

View File

@@ -0,0 +1,91 @@
# tgui Migration Guide to v4 from v3
## The Easy Part
- Copy and replace the following files in bulk:
- `code/__DEFINES/tgui.dm`
- `code/controllers/subsystem/tgui.dm`
- `code/modules/tgui/**`
- `tgui/**`
- Except: `tgui/packages/tgui/interfaces`
- Manually resolve conflicts for files that were touched outside the
`interfaces` folder.
- Copy the updated `log_tgui` proc from:
- `code/__HELPERS/_logging.dm`
If you have a dual nano/tgui setup, then make sure to rename all ui procs
on `/datum`, such as `ui_interact` to `tgui_interact`, to avoid namespace
clashing. Usual stuff.
## Update `ui_interact` proc signatures
First of all, tgui states need to move from `ui_interact` to `ui_state`.
One way of doing it, is to just cherry pick those procs from upstream.
If you want to search and replace manually, search for `state = GLOB`, and
extract those things into `ui_state` procs like so:
```dm
.../ui_state(mob/user)
return GLOB.default_state
```
Then reduce `ui_interact` until you finish with something like this:
```dm
.../ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "FooBar", "Foo Bar UI", 600, 400)
ui.open()
```
## Update asset delivery code
Remove all asset code that injects stylesheets by modifying tgui's `basehtml`.
You no longer need to do that.
Find all occurences of `asset.send(user)` in `ui_interact`, and refactor those
snippets to the following proc:
```dm
.../ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/simple/foobar),
)
```
## Check `ui_act` for new bugs
Code behind `ui_act` was recently refactored to use JSON-encoded payloads
instead of just strings. Since it can now carry numbers and other complex
types, you should check that the code is type agnostic and does not break
due to an assumption that every parameter is a string.
One of such offenders is the personal crafting interface, where it needlessly
compares parameters to `""` and `"0"`. You can now replace this code with
simple assignments, because an empty category will now be properly `null`
instead of an empty string.
## Backend data changes
Interfaces that relied on `config.window.id`, must now use
`window.__windowId__`, which is a global constant unique for the page
the script is running on (so you can be sure it never changes).
In case of `ByondUi`, this parameter can be completely omitted, because
parent will always default to the current window id.
Affected interfaces:
- `CameraConsole`
- Any interface that uses the `ByondUi` component
---
That's all folks!
There is a lot of stuff that was refactored under the hood, but normal UI
stuff wouldn't and shouldn't touch it, so you should be good with just
going through the checklist above.

View File

@@ -4,11 +4,11 @@
Basic tgui backend code consists of the following vars and procs:
```
ui_interact(mob/user, ui_key, datum/tgui/ui, force_open,
datum/tgui/master_ui, datum/ui_state/state)
```dm
ui_interact(mob/user, datum/tgui/ui)
ui_data(mob/user)
ui_act(action, params)
ui_state()
```
- `src_object` - The atom, which UI corresponds to in the game world.
@@ -19,9 +19,9 @@ or set up a new instance of UI by calling the `SStgui` subsystem.
has into an associative list, which will then be sent to UI as a JSON string.
- `ui_act` - This proc receives user actions and reacts to them by changing
the state of the game.
- `ui_state` (set in `ui_interact`) - This var dictates under what conditions
a UI may be interacted with. This may be the standard checks that check if
you are in range and conscious, or more.
- `ui_state` - This proc dictates under what conditions a UI may be interacted
with. This may be the standard checks that check if you are in range and
conscious, or more.
Once backend is complete, you create an new interface component on the
frontend, which will receive this JSON data and render it on screen.
@@ -37,10 +37,10 @@ powerful interactions for embedded objects or remote access.
Let's start with a very basic hello world.
```dm
/obj/machinery/my_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/my_machine/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "my_machine", name, 300, 300, master_ui, state)
ui = new(user, src, "MyMachine")
ui.open()
```
@@ -48,9 +48,7 @@ This is the proc that defines our interface. There's a bit going on here, so
let's break it down. First, we override the ui_interact proc on our object. This
will be called by `interact` for you, which is in turn called by `attack_hand`
(or `attack_self` for items). `ui_interact` is also called to update a UI (hence
the `try_update_ui`), so we accept an existing UI to update. The `state` is a
default argument so that a caller can overload it with named arguments
(`ui_interact(state = overloaded_state)`) if needed.
the `try_update_ui`), so we accept an existing UI to update.
Inside the `if(!ui)` block (which means we are creating a new UI), we choose our
template, title, and size; we can also set various options like `style` (for
@@ -294,10 +292,10 @@ here's what you need (note that you'll probably be forced to clean your shit up
upon code review):
```dm
/obj/copypasta/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state) // Remember to use the appropriate state.
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/copypasta/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "copypasta", name, 300, 300, master_ui, state)
ui = new(user, src, "copypasta")
ui.open()
/obj/copypasta/ui_data(mob/user)

View File

@@ -13,7 +13,7 @@
},
"dependencies": {
"babel-eslint": "^10.0.3",
"eslint": "^6.7.2",
"eslint": "^7.4.0",
"eslint-plugin-react": "^7.17.0"
}
}

File diff suppressed because it is too large Load Diff