Move dioxus-specifc code into dioxus-tui crate and rename core crate to Rink

This commit is contained in:
Evan Almloff 2023-03-13 12:04:51 -05:00
parent 8e8c89c99e
commit f34fa5d974
55 changed files with 241 additions and 55 deletions

View file

@ -15,7 +15,8 @@ members = [
"packages/liveview",
"packages/autofmt",
"packages/rsx",
"packages/tui",
"packages/dioxus-tui",
"packages/rink",
"packages/native-core",
"packages/native-core-macro",
"packages/rsx-rosetta",

View file

@ -13,7 +13,7 @@ dioxus-web = { path = "../../packages/web" }
dioxus-ssr = { path = "../../packages/ssr" }
dioxus-router = { path = "../../packages/router" }
dioxus-liveview = { path = "../../packages/liveview", features = ["axum"] }
dioxus-tui = { path = "../../packages/tui" }
dioxus-tui = { path = "../../packages/dioxus-tui" }
fermi = { path = "../../packages/fermi" }

View file

@ -13,25 +13,18 @@ license = "MIT/Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dioxus = { path = "../dioxus", version = "^0.3.0", optional = true }
dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"], optional = true }
dioxus = { path = "../dioxus", version = "^0.3.0" }
dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"] }
dioxus-html = { path = "../html", version = "^0.3.0" }
dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
dioxus-native-core = { path = "../native-core", version = "^0.2.0", features = ["dioxus"] }
dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.3.0" }
dioxus-hot-reload = { path = "../hot-reload", optional = true }
rink = { path = "../rink" }
tui = "0.17.0"
crossterm = "0.23.0"
anyhow = "1.0.42"
tokio = { version = "1.15.0", features = ["full"] }
futures = "0.3.19"
taffy = "0.2.1"
smallvec = "1.6"
rustc-hash = "1.1.0"
anymap = "1.0.0-beta.2"
futures-channel = "0.3.25"
shipyard = { version = "0.6.2", features = ["proc", "std"], default-features = false }
once_cell = "1.17.1"
[dev-dependencies]
dioxus = { path = "../dioxus" }
@ -43,6 +36,5 @@ name = "update"
harness = false
[features]
default = ["hot-reload", "dioxus-bindings"]
default = ["hot-reload"]
hot-reload = ["dioxus-hot-reload"]
dioxus-bindings = ["dioxus", "dioxus-core", "dioxus-native-core/dioxus"]

View file

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

View file

@ -1,7 +1,6 @@
use dioxus::prelude::*;
use dioxus_html::FormData;
use dioxus_tui::prelude::*;
use dioxus_tui::Config;
fn main() {
dioxus_tui::launch_cfg(app, Config::new());

View file

@ -1,3 +1,6 @@
pub mod prelude;
pub mod widgets;
use std::{
ops::Deref,
rc::Rc,
@ -11,7 +14,8 @@ use dioxus_native_core::{
NodeId, RealDom,
};
use crate::{query::Query, render, Config, Renderer, TuiContext};
pub use rink::Config;
use rink::{query::Query, render, Renderer, TuiContext};
pub fn launch(app: Component<()>) {
launch_cfg(app, Config::default())
@ -29,11 +33,8 @@ pub fn launch_cfg_with_props<Props: 'static>(app: Component<Props>, props: Props
};
let dioxus_state = Rc::new(RwLock::new(dioxus_state));
let mut vdom = VirtualDom::new_with_props(app, props)
.with_root_context(TuiContext { tx: event_tx })
.with_root_context(Query {
rdom: rdom.clone(),
stretch: taffy.clone(),
})
.with_root_context(TuiContext::new(event_tx))
.with_root_context(Query::new(rdom.clone(), taffy.clone()))
.with_root_context(DioxusElementToNodeId {
mapping: dioxus_state.clone(),
});

View file

@ -0,0 +1,2 @@
pub use crate::widgets::*;
pub use rink::Config;

View file

@ -1,11 +1,11 @@
use crate::widgets::get_root_id;
use crate::Query;
use crossterm::{cursor::MoveTo, execute};
use dioxus::prelude::*;
use dioxus_elements::input_data::keyboard_types::Key;
use dioxus_html as dioxus_elements;
use dioxus_html::FormData;
use dioxus_native_core::utils::cursor::{Cursor, Pos};
use rink::Query;
use std::{collections::HashMap, io::stdout};
use taffy::geometry::Point;

View file

@ -1,11 +1,11 @@
use crate::widgets::get_root_id;
use crate::Query;
use crossterm::{cursor::*, execute};
use dioxus::prelude::*;
use dioxus_elements::input_data::keyboard_types::Key;
use dioxus_html as dioxus_elements;
use dioxus_html::FormData;
use dioxus_native_core::utils::cursor::{Cursor, Pos};
use rink::Query;
use std::{collections::HashMap, io::stdout};
use taffy::geometry::Point;

View file

@ -1,11 +1,11 @@
use std::collections::HashMap;
use crate::widgets::get_root_id;
use crate::Query;
use dioxus::prelude::*;
use dioxus_elements::input_data::keyboard_types::Key;
use dioxus_html as dioxus_elements;
use dioxus_html::FormData;
use rink::Query;
#[derive(Props)]
pub(crate) struct SliderProps<'a> {

View file

@ -1,11 +1,11 @@
use crate::widgets::get_root_id;
use crate::Query;
use crossterm::{cursor::*, execute};
use dioxus::prelude::*;
use dioxus_elements::input_data::keyboard_types::Key;
use dioxus_html as dioxus_elements;
use dioxus_html::FormData;
use dioxus_native_core::utils::cursor::{Cursor, Pos};
use rink::Query;
use std::{collections::HashMap, io::stdout};
use taffy::geometry::Point;

2
packages/rink/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
Cargo.lock

2
packages/rink/.vscode/spellright.dict vendored Normal file
View file

@ -0,0 +1,2 @@
esque
Tui

39
packages/rink/Cargo.toml Normal file
View file

@ -0,0 +1,39 @@
[package]
name = "rink"
version = "0.2.2"
authors = ["Jonathan Kelley, @dementhos"]
edition = "2021"
description = "TUI-based renderer for Dioxus"
repository = "https://github.com/DioxusLabs/dioxus/"
homepage = "https://dioxuslabs.com"
documentation = "https://dioxuslabs.com"
keywords = ["dom", "ui", "gui", "react", "terminal"]
license = "MIT/Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dioxus-html = { path = "../html", version = "^0.3.0" }
dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.3.0" }
tui = "0.17.0"
crossterm = "0.23.0"
anyhow = "1.0.42"
tokio = { version = "1.15.0", features = ["full"] }
futures = "0.3.19"
taffy = "0.2.1"
smallvec = "1.6"
rustc-hash = "1.1.0"
anymap = "1.0.0-beta.2"
futures-channel = "0.3.25"
shipyard = { version = "0.6.2", features = ["proc", "std"], default-features = false }
once_cell = "1.17.1"
[dev-dependencies]
tokio = { version = "1" }
criterion = "0.3.5"
[features]
default = []
parallel = ["shipyard/parallel"]

90
packages/rink/README.md Normal file
View file

@ -0,0 +1,90 @@
<div align="center">
<h1>Rink</h1>
<p>
<strong>A beautiful terminal user interfaces library in Rust.</strong>
</p>
</div>
<div align="center">
<!-- Crates version -->
<a href="https://crates.io/crates/rink">
<img src="https://img.shields.io/crates/v/rink.svg?style=flat-square"
alt="Crates.io version" />
</a>
<!-- Downloads -->
<a href="https://crates.io/crates/rink">
<img src="https://img.shields.io/crates/d/rink.svg?style=flat-square"
alt="Download" />
</a>
<!-- docs -->
<a href="https://docs.rs/rink">
<img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square"
alt="docs.rs docs" />
</a>
<!-- CI -->
<a href="https://github.com/jkelleyrtp/rink/actions">
<img src="https://github.com/dioxuslabs/rink/actions/workflows/main.yml/badge.svg"
alt="CI status" />
</a>
<!-- Discord -->
<a href="https://discord.gg/XgGxMSkvUM">
<img src="https://img.shields.io/discord/899851952891002890.svg?logo=discord&style=flat-square" alt="Discord Link" />
</a>
</div>
<br/>
Leverage CSS, HTML, and Rust to build beautiful, portable, terminal user interfaces.
```rust
fn app(cx: Scope) -> Element {
cx.render(rsx!{
div {
width: "100%",
height: "10px",
background_color: "red",
justify_content: "center",
align_items: "center",
"Hello world!"
}
})
}
```
![demo app](examples/example.png)
## Background
You can use Html-like semantics with inline styles, tree hierarchy, components, and more in your [`text-based user interface (TUI)`](https://en.wikipedia.org/wiki/Text-based_user_interface) application.
Rink is essentially a port of [Ink](https://github.com/vadimdemedes/ink) but for [`Rust`](https://www.rust-lang.org/) and [`Dioxus`](https://dioxuslabs.com/). Rink doesn't depend on Node.js or any other JavaScript runtime, so your binaries are portable and beautiful.
## Limitations
- **Subset of Html**
Terminals can only render a subset of HTML. We support as much as we can.
- **Particular frontend design**
Terminals and browsers are and look different. Therefore, the same design might not be the best to cover both renderers.
## Status
**WARNING: Rink is currently under construction!**
Rendering a VirtualDom works fine, but the ecosystem of hooks is not yet ready. Additionally, some bugs in the flexbox implementation might be quirky at times.
## Features
Rink features:
- [x] Flexbox-based layout system
- [ ] CSS selectors
- [x] inline CSS support
- [x] Built-in focusing system
* [x] Widgets<sup>1</sup>
* [ ] Support for events, hooks, and callbacks<sup>2</sup>
* [ ] Html tags<sup>3</sup>
<sup>1</sup> Currently only a subset of the input element is implemented as a component (not an element). The `Input` component supports sliders, text, numbers, passwords, buttons, and checkboxes.
<sup>2</sup> Basic keyboard, mouse, and focus events are implemented.
<sup>3</sup> Currently, most HTML tags don't translate into any meaning inside of Dioxus TUI. So an `input` _element_ won't mean anything nor does it have any additional functionality.

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View file

@ -46,18 +46,13 @@ impl Default for Config {
}
}
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default)]
pub enum RenderingMode {
/// only 16 colors by accessed by name, no alpha support
BaseColors,
/// 8 bit colors, will be downsampled from rgb colors
Ansi,
/// 24 bit colors, most terminals support this
#[default]
Rgb,
}
impl Default for RenderingMode {
fn default() -> Self {
RenderingMode::Rgb
}
}

View file

@ -19,8 +19,9 @@ use dioxus_native_core::node_ref::NodeView;
#[derive(Component)]
pub struct Focused(pub bool);
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub(crate) enum FocusLevel {
#[default]
Unfocusable,
Focusable,
Ordered(std::num::NonZeroU16),
@ -58,12 +59,6 @@ impl Ord for FocusLevel {
}
}
impl Default for FocusLevel {
fn default() -> Self {
FocusLevel::Unfocusable
}
}
#[derive(Clone, PartialEq, Debug, Default, Component)]
pub(crate) struct Focus {
pub level: FocusLevel,

View file

@ -27,8 +27,6 @@ use tokio::select;
use tui::{backend::CrosstermBackend, layout::Rect, Terminal};
mod config;
#[cfg(feature = "dioxus-bindings")]
pub mod dioxus;
mod focus;
mod hooks;
mod layout;
@ -39,16 +37,10 @@ mod render;
mod style;
mod style_attributes;
mod widget;
#[cfg(feature = "dioxus-bindings")]
mod widgets;
#[cfg(feature = "dioxus-bindings")]
pub use crate::dioxus::*;
pub use config::*;
pub use hooks::*;
pub use query::Query;
#[cfg(feature = "dioxus-bindings")]
pub use widgets::*;
// the layout space has a multiplier of 10 to minimize rounding errors
pub(crate) fn screen_to_layout_space(screen: u16) -> f32 {
@ -69,6 +61,10 @@ pub struct TuiContext {
}
impl TuiContext {
pub fn new(tx: UnboundedSender<InputEvent>) -> Self {
Self { tx }
}
pub fn quit(&self) {
self.tx.unbounded_send(InputEvent::Close).unwrap();
}

View file

@ -2,7 +2,7 @@ use dioxus_native_core::{node_ref::NodeView, Dependancy, SendAnyMap, State};
use dioxus_native_core_macro::partial_derive_state;
use shipyard::Component;
#[derive(PartialEq, Debug, Clone, Copy, Component)]
#[derive(PartialEq, Debug, Clone, Copy, Component, Default)]
pub(crate) enum PreventDefault {
Focus,
KeyPress,
@ -14,6 +14,7 @@ pub(crate) enum PreventDefault {
MouseEnter,
MouseLeave,
MouseOut,
#[default]
Unknown,
MouseOver,
ContextMenu,
@ -21,12 +22,6 @@ pub(crate) enum PreventDefault {
MouseUp,
}
impl Default for PreventDefault {
fn default() -> Self {
PreventDefault::Unknown
}
}
#[partial_derive_state]
impl State for PreventDefault {
type ParentDependencies = ();

View file

@ -47,6 +47,10 @@ pub struct Query {
}
impl Query {
pub fn new(rdom: Arc<RwLock<RealDom>>, stretch: Arc<Mutex<Taffy>>) -> Self {
Self { rdom, stretch }
}
pub fn get(&self, id: NodeId) -> ElementRef {
let rdom = self.rdom.read();
let stretch = self.stretch.lock();

73
packages/rink/test.html Normal file
View file

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<style>
html,
body {
height: 100%;
}
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: black;
/* justify-content: center;
align-items: center; */
/* margin: auto; */
}
.smaller {
height: 70%;
width: 70%;
background-color: green;
/* justify-content: center; */
/* align-items: center; */
}
.superinner {
height: 100%;
width: 100%;
/* display: flex; */
/* */
margin-top: 20px;
margin-bottom: 20px;
margin-left: 20px;
margin-right: 20px;
/* */
background-color: red;
justify-content: center;
align-items: center;
flex-direction: column;
/* margin: 20px; */
/* margin: 20px; */
}
</style>
</head>
<body>
<div class="container">
<div class="smaller">
<div class="superinner">
<h1>Hello World</h1>
<p>This is a test</p>
</div>
</div>
</div>
<!-- <div class="container">
<div class="smaller">
hello world
<div style="color: green; margin: 40px;">
goodbye
<div style="color:red;">
asdasdasd
</div>
</div>
</div>
</div> -->
</body>
</html>