#![allow(non_snake_case)]
use crate::composable;
use crate::layout::policies::EmptyMeasurePolicy;
use crate::modifier::Modifier;
use crate::text::TextStyle; use crate::text_field_modifier_node::TextFieldElement;
use crate::widgets::Layout;
use cranpose_core::NodeId;
use cranpose_foundation::modifier_element;
use cranpose_foundation::text::{TextFieldLineLimits, TextFieldState};
use cranpose_ui_graphics::Color;
#[composable]
pub fn BasicTextField(state: TextFieldState, modifier: Modifier, style: TextStyle) -> NodeId {
BasicTextFieldWithOptions(
state,
modifier,
BasicTextFieldOptions {
text_style: style,
..BasicTextFieldOptions::default()
},
)
}
#[derive(Debug, Clone, PartialEq)]
pub struct BasicTextFieldOptions {
pub text_style: TextStyle,
pub cursor_color: Color,
pub line_limits: TextFieldLineLimits,
}
impl Default for BasicTextFieldOptions {
fn default() -> Self {
Self {
text_style: TextStyle::default(),
cursor_color: Color(0.0, 0.0, 0.0, 1.0), line_limits: TextFieldLineLimits::default(),
}
}
}
#[composable]
pub fn BasicTextFieldWithOptions(
state: TextFieldState,
modifier: Modifier,
options: BasicTextFieldOptions,
) -> NodeId {
let _text = state.text();
let text_field_element = TextFieldElement::new(state, options.text_style)
.with_cursor_color(options.cursor_color)
.with_line_limits(options.line_limits);
let text_field_modifier = modifier_element(text_field_element);
let final_modifier = Modifier::from_parts(vec![text_field_modifier]);
let combined_modifier = modifier.then(final_modifier);
Layout(
combined_modifier,
EmptyMeasurePolicy,
|| {}, )
}
#[cfg(test)]
mod tests {
use super::*;
use cranpose_core::{location_key, Composition, DefaultScheduler, MemoryApplier, Runtime};
use std::sync::Arc;
fn with_test_runtime<T>(f: impl FnOnce() -> T) -> T {
let _runtime = Runtime::new(Arc::new(DefaultScheduler));
f()
}
#[test]
fn basic_text_field_creates_node() {
let mut composition = Composition::new(MemoryApplier::new());
let state = TextFieldState::new("Test content");
let result = composition.render(location_key(file!(), line!(), column!()), {
let state = state.clone();
move || {
BasicTextField(state.clone(), Modifier::empty(), TextStyle::default());
}
});
assert!(result.is_ok());
assert!(composition.root().is_some());
}
#[test]
fn basic_text_field_state_updates() {
with_test_runtime(|| {
let state = TextFieldState::new("Hello");
assert_eq!(state.text(), "Hello");
state.edit(|buffer| {
buffer.place_cursor_at_end();
buffer.insert("!");
});
assert_eq!(state.text(), "Hello!");
});
}
}