mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-26 22:20:19 +00:00
Merge branch 'upstream' into add-fuzzing-to-native-core
This commit is contained in:
commit
7294edcd89
9 changed files with 332 additions and 147 deletions
37
.github/workflows/docs stable.yml
vendored
Normal file
37
.github/workflows/docs stable.yml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
name: docs stable
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment: docs
|
||||
steps:
|
||||
|
||||
# NOTE: Comment out when https://github.com/rust-lang/mdBook/pull/1306 is merged and released
|
||||
# - name: Setup mdBook
|
||||
# uses: peaceiris/actions-mdbook@v1
|
||||
# with:
|
||||
# mdbook-version: "0.4.10"
|
||||
|
||||
# NOTE: Delete when the previous one is enabled
|
||||
- name: Setup mdBook
|
||||
run: |
|
||||
cargo install mdbook --git https://github.com/Demonthos/mdBook.git --branch master
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Build
|
||||
run: cd docs &&
|
||||
cd guide && mdbook build -d ../nightly/guide && cd .. &&
|
||||
cd router && mdbook build -d ../nightly/router && cd ..
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
with:
|
||||
branch: gh-pages # The branch the action should deploy to.
|
||||
folder: docs/nightly # The folder the action should deploy.
|
||||
target-folder: docs
|
||||
repository-name: dioxuslabs/docsite
|
||||
clean: false
|
||||
token: ${{ secrets.DEPLOY_KEY }} # let's pretend I don't need it for now
|
|
@ -18,8 +18,6 @@ cargo run --example hello_world
|
|||
|
||||
[custom_assets](./custom_assets.rs) - Include images
|
||||
|
||||
[custom_element](./custom_element.rs) - Render webcomponents
|
||||
|
||||
[custom_html](./custom_html.rs) - Customize wrapper HTML
|
||||
|
||||
[eval](./eval.rs) - Evaluate JS expressions
|
||||
|
@ -132,36 +130,6 @@ cargo run --example hello_world
|
|||
|
||||
[todomvc](./todomvc.rs) - Todo task list example
|
||||
|
||||
## Terminal UI
|
||||
|
||||
[tui_all_events](../packages/tui/examples/tui_all_events.rs) - All of the terminal events
|
||||
|
||||
[tui_border](../packages/tui/examples/tui_border.rs) - Different styles of borders and corners
|
||||
|
||||
[tui_buttons](../packages/tui/examples/tui_buttons.rs) - A grid of buttons that work demonstrate the focus system
|
||||
|
||||
[tui_color_test](../packages/tui/examples/tui_color_test.rs) - Grid of colors to demonstrate compatablility with different terminal color rendering modes
|
||||
|
||||
[tui_colorpicker](../packages/tui/examples/tui_colorpicker.rs) - A colorpicker
|
||||
|
||||
[tui_components](../packages/tui/examples/tui_components.rs) - Simple component example
|
||||
|
||||
[tui_flex](../packages/tui/examples/tui_flex.rs) - Flexbox support
|
||||
|
||||
[tui_hover](../packages/tui/examples/tui_hover.rs) - Detect hover and mouse events
|
||||
|
||||
[tui_list](../packages/tui/examples/tui_list.rs) - Renders a list of items
|
||||
|
||||
[tui_margin](../packages/tui/examples/tui_margin.rs) - Margins around flexboxes
|
||||
|
||||
[tui_quadrants](../packages/tui/examples/tui_quadrants.rs) - Four quadrants
|
||||
|
||||
[tui_readme](../packages/tui/examples/tui_readme.rs) - The readme example
|
||||
|
||||
[tui_task](../packages/tui/examples/tui_task.rs) - Background tasks
|
||||
|
||||
[tui_text](../packages/tui/examples/tui_text.rs) - Simple text example
|
||||
|
||||
# TODO
|
||||
Missing Features
|
||||
- Fine-grained reactivity
|
||||
|
@ -175,4 +143,4 @@ Missing examples
|
|||
- Custom elements
|
||||
- Component Children: Pass children into child components
|
||||
- Render To string: Render a mounted virtualdom to a string
|
||||
- Testing and Debugging
|
||||
- Testing and Debugging
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
- [ ] pub aspect_ratio: Number, ----> parsing is done, but taffy doesnt support it
|
||||
*/
|
||||
|
||||
use lightningcss::properties::border::LineStyle;
|
||||
use lightningcss::properties::{align, display, flex, position, size};
|
||||
use lightningcss::{
|
||||
properties::{align::GapValue, border::BorderSideWidth, Property, PropertyId},
|
||||
|
@ -45,8 +46,43 @@ use taffy::{
|
|||
style::{FlexDirection, PositionType},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LayoutConfigeration {
|
||||
/// the default border widths to use
|
||||
pub border_widths: BorderWidths,
|
||||
}
|
||||
|
||||
pub struct BorderWidths {
|
||||
/// the default border width to use for thin borders
|
||||
pub thin: f32,
|
||||
/// the default border width to use for medium borders
|
||||
pub medium: f32,
|
||||
/// the default border width to use for thick borders
|
||||
pub thick: f32,
|
||||
}
|
||||
|
||||
impl Default for BorderWidths {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
thin: 1.0,
|
||||
medium: 3.0,
|
||||
thick: 5.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// applies the entire html namespace defined in dioxus-html
|
||||
pub fn apply_layout_attributes(name: &str, value: &str, style: &mut Style) {
|
||||
apply_layout_attributes_cfg(name, value, style, &LayoutConfigeration::default())
|
||||
}
|
||||
|
||||
/// applies the entire html namespace defined in dioxus-html with the specified configeration
|
||||
pub fn apply_layout_attributes_cfg(
|
||||
name: &str,
|
||||
value: &str,
|
||||
style: &mut Style,
|
||||
config: &LayoutConfigeration,
|
||||
) {
|
||||
if let Ok(property) =
|
||||
Property::parse_string(PropertyId::from(name), value, ParserOptions::default())
|
||||
{
|
||||
|
@ -84,41 +120,85 @@ pub fn apply_layout_attributes(name: &str, value: &str, style: &mut Style) {
|
|||
style.position.right = convert_length_percentage_or_auto(inset.right);
|
||||
}
|
||||
Property::BorderTopWidth(width) => {
|
||||
style.border.top = convert_border_side_width(width);
|
||||
style.border.top = convert_border_side_width(width, &config.border_widths);
|
||||
}
|
||||
Property::BorderBottomWidth(width) => {
|
||||
style.border.bottom = convert_border_side_width(width);
|
||||
style.border.bottom = convert_border_side_width(width, &config.border_widths);
|
||||
}
|
||||
Property::BorderLeftWidth(width) => {
|
||||
style.border.left = convert_border_side_width(width);
|
||||
style.border.left = convert_border_side_width(width, &config.border_widths);
|
||||
}
|
||||
Property::BorderRightWidth(width) => {
|
||||
style.border.right = convert_border_side_width(width);
|
||||
style.border.right = convert_border_side_width(width, &config.border_widths);
|
||||
}
|
||||
Property::BorderWidth(width) => {
|
||||
style.border.top = convert_border_side_width(width.top);
|
||||
style.border.bottom = convert_border_side_width(width.bottom);
|
||||
style.border.left = convert_border_side_width(width.left);
|
||||
style.border.right = convert_border_side_width(width.right);
|
||||
style.border.top = convert_border_side_width(width.top, &config.border_widths);
|
||||
style.border.bottom =
|
||||
convert_border_side_width(width.bottom, &config.border_widths);
|
||||
style.border.left = convert_border_side_width(width.left, &config.border_widths);
|
||||
style.border.right = convert_border_side_width(width.right, &config.border_widths);
|
||||
}
|
||||
Property::Border(border) => {
|
||||
let width = convert_border_side_width(border.width);
|
||||
let width = convert_border_side_width(border.width, &config.border_widths);
|
||||
style.border.top = width;
|
||||
style.border.bottom = width;
|
||||
style.border.left = width;
|
||||
style.border.right = width;
|
||||
}
|
||||
Property::BorderTop(top) => {
|
||||
style.border.top = convert_border_side_width(top.width);
|
||||
style.border.top = convert_border_side_width(top.width, &config.border_widths);
|
||||
}
|
||||
Property::BorderBottom(bottom) => {
|
||||
style.border.bottom = convert_border_side_width(bottom.width);
|
||||
style.border.bottom =
|
||||
convert_border_side_width(bottom.width, &config.border_widths);
|
||||
}
|
||||
Property::BorderLeft(left) => {
|
||||
style.border.left = convert_border_side_width(left.width);
|
||||
style.border.left = convert_border_side_width(left.width, &config.border_widths);
|
||||
}
|
||||
Property::BorderRight(right) => {
|
||||
style.border.right = convert_border_side_width(right.width);
|
||||
style.border.right = convert_border_side_width(right.width, &config.border_widths);
|
||||
}
|
||||
Property::BorderTopStyle(line_style) => {
|
||||
if line_style != LineStyle::None {
|
||||
style.border.top =
|
||||
convert_border_side_width(BorderSideWidth::Medium, &config.border_widths);
|
||||
}
|
||||
}
|
||||
Property::BorderBottomStyle(line_style) => {
|
||||
if line_style != LineStyle::None {
|
||||
style.border.bottom =
|
||||
convert_border_side_width(BorderSideWidth::Medium, &config.border_widths);
|
||||
}
|
||||
}
|
||||
Property::BorderLeftStyle(line_style) => {
|
||||
if line_style != LineStyle::None {
|
||||
style.border.left =
|
||||
convert_border_side_width(BorderSideWidth::Medium, &config.border_widths);
|
||||
}
|
||||
}
|
||||
Property::BorderRightStyle(line_style) => {
|
||||
if line_style != LineStyle::None {
|
||||
style.border.right =
|
||||
convert_border_side_width(BorderSideWidth::Medium, &config.border_widths);
|
||||
}
|
||||
}
|
||||
Property::BorderStyle(styles) => {
|
||||
if styles.top != LineStyle::None {
|
||||
style.border.top =
|
||||
convert_border_side_width(BorderSideWidth::Medium, &config.border_widths);
|
||||
}
|
||||
if styles.bottom != LineStyle::None {
|
||||
style.border.bottom =
|
||||
convert_border_side_width(BorderSideWidth::Medium, &config.border_widths);
|
||||
}
|
||||
if styles.left != LineStyle::None {
|
||||
style.border.left =
|
||||
convert_border_side_width(BorderSideWidth::Medium, &config.border_widths);
|
||||
}
|
||||
if styles.right != LineStyle::None {
|
||||
style.border.right =
|
||||
convert_border_side_width(BorderSideWidth::Medium, &config.border_widths);
|
||||
}
|
||||
}
|
||||
Property::FlexDirection(flex_direction, _) => {
|
||||
use FlexDirection::*;
|
||||
|
@ -330,12 +410,15 @@ fn convert_length_percentage_or_auto(
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_border_side_width(border_side_width: BorderSideWidth) -> Dimension {
|
||||
fn convert_border_side_width(
|
||||
border_side_width: BorderSideWidth,
|
||||
border_width_config: &BorderWidths,
|
||||
) -> Dimension {
|
||||
match border_side_width {
|
||||
BorderSideWidth::Length(Length::Value(value)) => convert_length_value(value),
|
||||
BorderSideWidth::Thick => Dimension::Points(5.0),
|
||||
BorderSideWidth::Medium => Dimension::Points(3.0),
|
||||
BorderSideWidth::Thin => Dimension::Points(1.0),
|
||||
BorderSideWidth::Thick => Dimension::Points(border_width_config.thick),
|
||||
BorderSideWidth::Medium => Dimension::Points(border_width_config.medium),
|
||||
BorderSideWidth::Thin => Dimension::Points(border_width_config.thin),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,8 +195,7 @@ impl<S: State<V>, V: FromAnyValue> RealDom<S, V> {
|
|||
text: value.to_string(),
|
||||
});
|
||||
let node_id = self.create_node(node);
|
||||
let node = self.tree.get_mut(node_id).unwrap();
|
||||
node.node_data.element_id = Some(id);
|
||||
self.set_element_id(node_id, id);
|
||||
self.stack.push(node_id);
|
||||
mark_dirty(node_id, NodeMask::new().with_text(), &mut nodes_updated);
|
||||
}
|
||||
|
|
|
@ -1,87 +1,160 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::{cmp::Ordering, ops::Range};
|
||||
|
||||
use dioxus_html::input_data::keyboard_types::{Code, Key, Modifiers};
|
||||
|
||||
/// This contains the information about the text that is used by the cursor to handle navigation.
|
||||
pub trait Text {
|
||||
/// Returns the line at the given index.
|
||||
fn line(&self, number: usize) -> Option<&Self>;
|
||||
/// Returns the length of the text in characters.
|
||||
fn length(&self) -> usize;
|
||||
/// Returns the number of lines in the text.
|
||||
fn line_count(&self) -> usize;
|
||||
/// Returns the character at the given character index.
|
||||
fn character(&self, idx: usize) -> Option<char>;
|
||||
/// Returns the length of the text before the given line in characters.
|
||||
fn len_before_line(&self, line: usize) -> usize;
|
||||
}
|
||||
|
||||
impl Text for str {
|
||||
fn line(&self, number: usize) -> Option<&str> {
|
||||
self.lines().nth(number)
|
||||
}
|
||||
|
||||
fn length(&self) -> usize {
|
||||
self.chars().count()
|
||||
}
|
||||
|
||||
fn line_count(&self) -> usize {
|
||||
self.lines().count()
|
||||
}
|
||||
|
||||
fn character(&self, idx: usize) -> Option<char> {
|
||||
self.chars().nth(idx)
|
||||
}
|
||||
|
||||
fn len_before_line(&self, line: usize) -> usize {
|
||||
self.lines()
|
||||
.take(line)
|
||||
.map(|l| l.chars().count())
|
||||
.sum::<usize>()
|
||||
}
|
||||
}
|
||||
|
||||
/// This contains the information about the text that is used by the cursor to handle editing text.
|
||||
pub trait TextEditable<T: Text + ?Sized>: AsRef<T> {
|
||||
/// Inserts a character at the given character index.
|
||||
fn insert_character(&mut self, idx: usize, text: char);
|
||||
/// Deletes the given character range.
|
||||
fn delete_range(&mut self, range: Range<usize>);
|
||||
}
|
||||
|
||||
impl TextEditable<str> for String {
|
||||
fn insert_character(&mut self, idx: usize, text: char) {
|
||||
self.insert(idx, text);
|
||||
}
|
||||
|
||||
fn delete_range(&mut self, range: Range<usize>) {
|
||||
self.replace_range(range, "");
|
||||
}
|
||||
}
|
||||
|
||||
/// A cursor position
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Pos {
|
||||
/// The virtual column of the cursor. This can be more than the line length. To get the realized column, use [`Pos::col()`].
|
||||
pub col: usize,
|
||||
/// The row of the cursor.
|
||||
pub row: usize,
|
||||
}
|
||||
|
||||
impl Pos {
|
||||
/// Creates a new cursor position.
|
||||
pub fn new(col: usize, row: usize) -> Self {
|
||||
Self { row, col }
|
||||
}
|
||||
|
||||
pub fn up(&mut self, rope: &str) {
|
||||
self.move_row(-1, rope);
|
||||
/// Moves the position up by one line.
|
||||
pub fn up(&mut self, text: &(impl Text + ?Sized)) {
|
||||
self.move_row(-1, text);
|
||||
}
|
||||
|
||||
pub fn down(&mut self, rope: &str) {
|
||||
self.move_row(1, rope);
|
||||
/// Moves the position down by one line.
|
||||
pub fn down(&mut self, text: &(impl Text + ?Sized)) {
|
||||
self.move_row(1, text);
|
||||
}
|
||||
|
||||
pub fn right(&mut self, rope: &str) {
|
||||
self.move_col(1, rope);
|
||||
/// Moves the position right by one character.
|
||||
pub fn right(&mut self, text: &(impl Text + ?Sized)) {
|
||||
self.move_col(1, text);
|
||||
}
|
||||
|
||||
pub fn left(&mut self, rope: &str) {
|
||||
self.move_col(-1, rope);
|
||||
/// Moves the position left by one character.
|
||||
pub fn left(&mut self, text: &(impl Text + ?Sized)) {
|
||||
self.move_col(-1, text);
|
||||
}
|
||||
|
||||
pub fn move_row(&mut self, change: i32, rope: &str) {
|
||||
/// Move the position's row by the given amount. (positive is down, negative is up)
|
||||
pub fn move_row(&mut self, change: i32, text: &(impl Text + ?Sized)) {
|
||||
let new = self.row as i32 + change;
|
||||
if new >= 0 && new < rope.lines().count() as i32 {
|
||||
if new >= 0 && new < text.line_count() as i32 {
|
||||
self.row = new as usize;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn move_col(&mut self, change: i32, rope: &str) {
|
||||
self.realize_col(rope);
|
||||
let idx = self.idx(rope) as i32;
|
||||
if idx + change >= 0 && idx + change <= rope.len() as i32 {
|
||||
let len_line = self.len_line(rope) as i32;
|
||||
/// Move the position's column by the given amount. (positive is right, negative is left)
|
||||
pub fn move_col(&mut self, change: i32, text: &(impl Text + ?Sized)) {
|
||||
self.realize_col(text);
|
||||
let idx = self.idx(text) as i32;
|
||||
if idx + change >= 0 && idx + change <= text.length() as i32 {
|
||||
let len_line = self.len_line(text) as i32;
|
||||
let new_col = self.col as i32 + change;
|
||||
let diff = new_col - len_line;
|
||||
if diff > 0 {
|
||||
self.down(rope);
|
||||
self.down(text);
|
||||
self.col = 0;
|
||||
self.move_col(diff - 1, rope);
|
||||
self.move_col(diff - 1, text);
|
||||
} else if new_col < 0 {
|
||||
self.up(rope);
|
||||
self.col = self.len_line(rope);
|
||||
self.move_col(new_col + 1, rope);
|
||||
self.up(text);
|
||||
self.col = self.len_line(text);
|
||||
self.move_col(new_col + 1, text);
|
||||
} else {
|
||||
self.col = new_col as usize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn col(&self, rope: &str) -> usize {
|
||||
self.col.min(self.len_line(rope))
|
||||
/// Get the realized column of the position. This is the column, but capped at the line length.
|
||||
pub fn col(&self, text: &(impl Text + ?Sized)) -> usize {
|
||||
self.col.min(self.len_line(text))
|
||||
}
|
||||
|
||||
/// Get the row of the position.
|
||||
pub fn row(&self) -> usize {
|
||||
self.row
|
||||
}
|
||||
|
||||
fn len_line(&self, rope: &str) -> usize {
|
||||
let line = rope.lines().nth(self.row).unwrap_or_default();
|
||||
let len = line.len();
|
||||
if len > 0 && line.chars().nth(len - 1) == Some('\n') {
|
||||
len - 1
|
||||
fn len_line(&self, text: &(impl Text + ?Sized)) -> usize {
|
||||
if let Some(line) = text.line(self.row) {
|
||||
let len = line.length();
|
||||
if len > 0 && line.character(len - 1) == Some('\n') {
|
||||
len - 1
|
||||
} else {
|
||||
len
|
||||
}
|
||||
} else {
|
||||
len
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn idx(&self, rope: &str) -> usize {
|
||||
rope.lines().take(self.row).map(|l| l.len()).sum::<usize>() + self.col(rope)
|
||||
/// Get the character index of the position.
|
||||
pub fn idx(&self, text: &(impl Text + ?Sized)) -> usize {
|
||||
text.len_before_line(self.row) + self.col(text)
|
||||
}
|
||||
|
||||
// the column can be more than the line length, cap it
|
||||
pub fn realize_col(&mut self, rope: &str) {
|
||||
self.col = self.col(rope);
|
||||
/// If the column is more than the line length, cap it to the line length.
|
||||
pub fn realize_col(&mut self, text: &(impl Text + ?Sized)) {
|
||||
self.col = self.col(text);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,13 +170,17 @@ impl PartialOrd for Pos {
|
|||
}
|
||||
}
|
||||
|
||||
/// A cursor is a selection of text. It has a start and end position of the selection.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Cursor {
|
||||
/// The start position of the selection. The start position is the origin of the selection, not necessarily the first position.
|
||||
pub start: Pos,
|
||||
/// The end position of the selection. If the end position is None, the cursor is a caret.
|
||||
pub end: Option<Pos>,
|
||||
}
|
||||
|
||||
impl Cursor {
|
||||
/// Create a new cursor with the given start position.
|
||||
pub fn from_start(pos: Pos) -> Self {
|
||||
Self {
|
||||
start: pos,
|
||||
|
@ -111,6 +188,7 @@ impl Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a new cursor with the given start and end position.
|
||||
pub fn new(start: Pos, end: Pos) -> Self {
|
||||
Self {
|
||||
start,
|
||||
|
@ -118,7 +196,8 @@ impl Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
fn move_cursor(&mut self, f: impl FnOnce(&mut Pos), shift: bool) {
|
||||
/// Move the cursor position. If shift is true, the end position will be moved instead of the start position.
|
||||
pub fn move_cursor(&mut self, f: impl FnOnce(&mut Pos), shift: bool) {
|
||||
if shift {
|
||||
self.with_end(f);
|
||||
} else {
|
||||
|
@ -127,38 +206,36 @@ impl Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
fn delete_selection(&mut self, text: &mut String) -> [i32; 2] {
|
||||
/// Delete the currently selected text and update the cursor position.
|
||||
pub fn delete_selection<T: Text + ?Sized>(&mut self, text: &mut impl TextEditable<T>) {
|
||||
let first = self.first();
|
||||
let last = self.last();
|
||||
let dr = first.row as i32 - last.row as i32;
|
||||
let dc = if dr != 0 {
|
||||
-(last.col as i32)
|
||||
} else {
|
||||
first.col as i32 - last.col as i32
|
||||
};
|
||||
text.replace_range(first.idx(text)..last.idx(text), "");
|
||||
text.delete_range(first.idx(text.as_ref())..last.idx(text.as_ref()));
|
||||
if let Some(end) = self.end.take() {
|
||||
if self.start > end {
|
||||
self.start = end;
|
||||
}
|
||||
}
|
||||
[dc, dr]
|
||||
}
|
||||
|
||||
pub fn handle_input(
|
||||
/// Handle moving the cursor with the given key.
|
||||
pub fn handle_input<T: Text + ?Sized>(
|
||||
&mut self,
|
||||
data: &dioxus_html::KeyboardData,
|
||||
text: &mut String,
|
||||
max_width: usize,
|
||||
text: &mut impl TextEditable<T>,
|
||||
max_text_length: usize,
|
||||
) {
|
||||
use Code::*;
|
||||
match data.code() {
|
||||
ArrowUp => {
|
||||
self.move_cursor(|c| c.up(text), data.modifiers().contains(Modifiers::SHIFT));
|
||||
self.move_cursor(
|
||||
|c| c.up(text.as_ref()),
|
||||
data.modifiers().contains(Modifiers::SHIFT),
|
||||
);
|
||||
}
|
||||
ArrowDown => {
|
||||
self.move_cursor(
|
||||
|c| c.down(text),
|
||||
|c| c.down(text.as_ref()),
|
||||
data.modifiers().contains(Modifiers::SHIFT),
|
||||
);
|
||||
}
|
||||
|
@ -167,22 +244,22 @@ impl Cursor {
|
|||
self.move_cursor(
|
||||
|c| {
|
||||
let mut change = 1;
|
||||
let idx = c.idx(text);
|
||||
let length = text.len();
|
||||
let idx = c.idx(text.as_ref());
|
||||
let length = text.as_ref().length();
|
||||
while idx + change < length {
|
||||
let chr = text.chars().nth(idx + change).unwrap();
|
||||
let chr = text.as_ref().character(idx + change).unwrap();
|
||||
if chr.is_whitespace() {
|
||||
break;
|
||||
}
|
||||
change += 1;
|
||||
}
|
||||
c.move_col(change as i32, text);
|
||||
c.move_col(change as i32, text.as_ref());
|
||||
},
|
||||
data.modifiers().contains(Modifiers::SHIFT),
|
||||
);
|
||||
} else {
|
||||
self.move_cursor(
|
||||
|c| c.right(text),
|
||||
|c| c.right(text.as_ref()),
|
||||
data.modifiers().contains(Modifiers::SHIFT),
|
||||
);
|
||||
}
|
||||
|
@ -192,28 +269,28 @@ impl Cursor {
|
|||
self.move_cursor(
|
||||
|c| {
|
||||
let mut change = -1;
|
||||
let idx = c.idx(text) as i32;
|
||||
let idx = c.idx(text.as_ref()) as i32;
|
||||
while idx + change > 0 {
|
||||
let chr = text.chars().nth((idx + change) as usize).unwrap();
|
||||
let chr = text.as_ref().character((idx + change) as usize).unwrap();
|
||||
if chr == ' ' {
|
||||
break;
|
||||
}
|
||||
change -= 1;
|
||||
}
|
||||
c.move_col(change, text);
|
||||
c.move_col(change, text.as_ref());
|
||||
},
|
||||
data.modifiers().contains(Modifiers::SHIFT),
|
||||
);
|
||||
} else {
|
||||
self.move_cursor(
|
||||
|c| c.left(text),
|
||||
|c| c.left(text.as_ref()),
|
||||
data.modifiers().contains(Modifiers::SHIFT),
|
||||
);
|
||||
}
|
||||
}
|
||||
End => {
|
||||
self.move_cursor(
|
||||
|c| c.col = c.len_line(text),
|
||||
|c| c.col = c.len_line(text.as_ref()),
|
||||
data.modifiers().contains(Modifiers::SHIFT),
|
||||
);
|
||||
}
|
||||
|
@ -221,64 +298,70 @@ impl Cursor {
|
|||
self.move_cursor(|c| c.col = 0, data.modifiers().contains(Modifiers::SHIFT));
|
||||
}
|
||||
Backspace => {
|
||||
self.start.realize_col(text);
|
||||
let mut start_idx = self.start.idx(text);
|
||||
self.start.realize_col(text.as_ref());
|
||||
let mut start_idx = self.start.idx(text.as_ref());
|
||||
if self.end.is_some() {
|
||||
self.delete_selection(text);
|
||||
} else if start_idx > 0 {
|
||||
self.start.left(text);
|
||||
text.replace_range(start_idx - 1..start_idx, "");
|
||||
self.start.left(text.as_ref());
|
||||
text.delete_range(start_idx - 1..start_idx);
|
||||
if data.modifiers().contains(Modifiers::CONTROL) {
|
||||
start_idx = self.start.idx(text);
|
||||
start_idx = self.start.idx(text.as_ref());
|
||||
while start_idx > 0
|
||||
&& text
|
||||
.chars()
|
||||
.nth(start_idx - 1)
|
||||
.as_ref()
|
||||
.character(start_idx - 1)
|
||||
.filter(|c| *c != ' ')
|
||||
.is_some()
|
||||
{
|
||||
self.start.left(text);
|
||||
text.replace_range(start_idx - 1..start_idx, "");
|
||||
start_idx = self.start.idx(text);
|
||||
self.start.left(text.as_ref());
|
||||
text.delete_range(start_idx - 1..start_idx);
|
||||
start_idx = self.start.idx(text.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Enter => {
|
||||
if text.len() + 1 - self.selection_len(text) <= max_width {
|
||||
text.insert(self.start.idx(text), '\n');
|
||||
if text.as_ref().length() + 1 - self.selection_len(text.as_ref()) <= max_text_length
|
||||
{
|
||||
text.insert_character(self.start.idx(text.as_ref()), '\n');
|
||||
self.start.col = 0;
|
||||
self.start.down(text);
|
||||
self.start.down(text.as_ref());
|
||||
}
|
||||
}
|
||||
Tab => {
|
||||
if text.len() + 1 - self.selection_len(text) <= max_width {
|
||||
self.start.realize_col(text);
|
||||
if text.as_ref().length() + 1 - self.selection_len(text.as_ref()) <= max_text_length
|
||||
{
|
||||
self.start.realize_col(text.as_ref());
|
||||
self.delete_selection(text);
|
||||
text.insert(self.start.idx(text), '\t');
|
||||
self.start.right(text);
|
||||
text.insert_character(self.start.idx(text.as_ref()), '\t');
|
||||
self.start.right(text.as_ref());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.start.realize_col(text);
|
||||
self.start.realize_col(text.as_ref());
|
||||
if let Key::Character(character) = data.key() {
|
||||
if text.len() + 1 - self.selection_len(text) <= max_width {
|
||||
if text.as_ref().length() + 1 - self.selection_len(text.as_ref())
|
||||
<= max_text_length
|
||||
{
|
||||
self.delete_selection(text);
|
||||
let character = character.chars().next().unwrap();
|
||||
text.insert(self.start.idx(text), character);
|
||||
self.start.right(text);
|
||||
text.insert_character(self.start.idx(text.as_ref()), character);
|
||||
self.start.right(text.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Modify the end selection position
|
||||
pub fn with_end(&mut self, f: impl FnOnce(&mut Pos)) {
|
||||
let mut new = self.end.take().unwrap_or_else(|| self.start.clone());
|
||||
f(&mut new);
|
||||
self.end.replace(new);
|
||||
}
|
||||
|
||||
/// Returns first position of the selection (this could be the start or the end depending on the position)
|
||||
pub fn first(&self) -> &Pos {
|
||||
if let Some(e) = &self.end {
|
||||
e.min(&self.start)
|
||||
|
@ -287,6 +370,7 @@ impl Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns last position of the selection (this could be the start or the end depending on the position)
|
||||
pub fn last(&self) -> &Pos {
|
||||
if let Some(e) = &self.end {
|
||||
e.max(&self.start)
|
||||
|
@ -295,7 +379,8 @@ impl Cursor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn selection_len(&self, text: &str) -> usize {
|
||||
/// Returns the length of the selection
|
||||
pub fn selection_len(&self, text: &(impl Text + ?Sized)) -> usize {
|
||||
self.last().idx(text) - self.first().idx(text)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use dioxus_native_core::layout_attributes::apply_layout_attributes;
|
||||
use dioxus_native_core::layout_attributes::{
|
||||
apply_layout_attributes_cfg, BorderWidths, LayoutConfigeration,
|
||||
};
|
||||
use dioxus_native_core::node::OwnedAttributeView;
|
||||
use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView};
|
||||
use dioxus_native_core::state::ChildDepState;
|
||||
|
@ -94,7 +96,18 @@ impl ChildDepState for TaffyLayout {
|
|||
.binary_search(&attribute.name.as_ref())
|
||||
.is_ok());
|
||||
if let Some(text) = value.as_text() {
|
||||
apply_layout_attributes(&attribute.name, text, &mut style);
|
||||
apply_layout_attributes_cfg(
|
||||
&attribute.name,
|
||||
text,
|
||||
&mut style,
|
||||
&LayoutConfigeration {
|
||||
border_widths: BorderWidths {
|
||||
thin: 1.0,
|
||||
medium: 1.0,
|
||||
thick: 1.0,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,8 +40,8 @@ pub(crate) fn NumbericInput<'a>(cx: Scope<'a, NumbericInputProps>) -> Element<'a
|
|||
let dragging = use_state(cx, || false);
|
||||
|
||||
let text = text_ref.read().clone();
|
||||
let start_highlight = cursor.read().first().idx(&text);
|
||||
let end_highlight = cursor.read().last().idx(&text);
|
||||
let start_highlight = cursor.read().first().idx(&*text);
|
||||
let end_highlight = cursor.read().last().idx(&*text);
|
||||
let (text_before_first_cursor, text_after_first_cursor) = text.split_at(start_highlight);
|
||||
let (text_highlighted, text_after_second_cursor) =
|
||||
text_after_first_cursor.split_at(end_highlight - start_highlight);
|
||||
|
@ -113,7 +113,7 @@ pub(crate) fn NumbericInput<'a>(cx: Scope<'a, NumbericInputProps>) -> Element<'a
|
|||
};
|
||||
if is_text{
|
||||
let mut text = text_ref.write();
|
||||
cursor.write().handle_input(&k, &mut text, max_len);
|
||||
cursor.write().handle_input(&k, &mut *text, max_len);
|
||||
update(text.clone());
|
||||
|
||||
let node = tui_query.get(get_root_id(cx).unwrap());
|
||||
|
@ -165,7 +165,7 @@ pub(crate) fn NumbericInput<'a>(cx: Scope<'a, NumbericInputProps>) -> Element<'a
|
|||
}
|
||||
new.row = 0;
|
||||
|
||||
new.realize_col(&text_ref.read());
|
||||
new.realize_col(text_ref.read().as_str());
|
||||
cursor.set(Cursor::from_start(new));
|
||||
dragging.set(true);
|
||||
let node = tui_query_clone.get(get_root_id(cx).unwrap());
|
||||
|
|
|
@ -40,8 +40,8 @@ pub(crate) fn Password<'a>(cx: Scope<'a, PasswordProps>) -> Element<'a> {
|
|||
let dragging = use_state(cx, || false);
|
||||
|
||||
let text = text_ref.read().clone();
|
||||
let start_highlight = cursor.read().first().idx(&text);
|
||||
let end_highlight = cursor.read().last().idx(&text);
|
||||
let start_highlight = cursor.read().first().idx(&*text);
|
||||
let end_highlight = cursor.read().last().idx(&*text);
|
||||
let (text_before_first_cursor, text_after_first_cursor) = text.split_at(start_highlight);
|
||||
let (text_highlighted, text_after_second_cursor) =
|
||||
text_after_first_cursor.split_at(end_highlight - start_highlight);
|
||||
|
@ -88,7 +88,7 @@ pub(crate) fn Password<'a>(cx: Scope<'a, PasswordProps>) -> Element<'a> {
|
|||
return;
|
||||
}
|
||||
let mut text = text_ref.write();
|
||||
cursor.write().handle_input(&k, &mut text, max_len);
|
||||
cursor.write().handle_input(&k, &mut *text, max_len);
|
||||
if let Some(input_handler) = &cx.props.raw_oninput {
|
||||
input_handler.call(FormData {
|
||||
value: text.clone(),
|
||||
|
@ -147,7 +147,7 @@ pub(crate) fn Password<'a>(cx: Scope<'a, PasswordProps>) -> Element<'a> {
|
|||
// textboxs are only one line tall
|
||||
new.row = 0;
|
||||
|
||||
new.realize_col(&text_ref.read());
|
||||
new.realize_col(text_ref.read().as_str());
|
||||
cursor.set(Cursor::from_start(new));
|
||||
dragging.set(true);
|
||||
let node = tui_query_clone.get(get_root_id(cx).unwrap());
|
||||
|
|
|
@ -40,8 +40,8 @@ pub(crate) fn TextBox<'a>(cx: Scope<'a, TextBoxProps>) -> Element<'a> {
|
|||
let dragging = use_state(cx, || false);
|
||||
|
||||
let text = text_ref.read().clone();
|
||||
let start_highlight = cursor.read().first().idx(&text);
|
||||
let end_highlight = cursor.read().last().idx(&text);
|
||||
let start_highlight = cursor.read().first().idx(&*text);
|
||||
let end_highlight = cursor.read().last().idx(&*text);
|
||||
let (text_before_first_cursor, text_after_first_cursor) = text.split_at(start_highlight);
|
||||
let (text_highlighted, text_after_second_cursor) =
|
||||
text_after_first_cursor.split_at(end_highlight - start_highlight);
|
||||
|
@ -90,7 +90,7 @@ pub(crate) fn TextBox<'a>(cx: Scope<'a, TextBoxProps>) -> Element<'a> {
|
|||
return;
|
||||
}
|
||||
let mut text = text_ref.write();
|
||||
cursor.write().handle_input(&k, &mut text, max_len);
|
||||
cursor.write().handle_input(&k, &mut *text, max_len);
|
||||
if let Some(input_handler) = &cx.props.raw_oninput{
|
||||
input_handler.call(FormData{
|
||||
value: text.clone(),
|
||||
|
@ -138,7 +138,7 @@ pub(crate) fn TextBox<'a>(cx: Scope<'a, TextBoxProps>) -> Element<'a> {
|
|||
// textboxs are only one line tall
|
||||
new.row = 0;
|
||||
|
||||
new.realize_col(&text_ref.read());
|
||||
new.realize_col(text_ref.read().as_str());
|
||||
cursor.set(Cursor::from_start(new));
|
||||
dragging.set(true);
|
||||
let node = tui_query_clone.get(get_root_id(cx).unwrap());
|
||||
|
|
Loading…
Reference in a new issue