use crate::{
AnyElement, ComponentTheme, Hooks, Palette, UseTheme, components::theme::resolve_style,
element, prelude::Fragment,
};
use ratatui::{
buffer::Buffer,
layout::{Position, Rect},
style::Style,
text::{Line, Text as RataText},
widgets::{Paragraph, Widget},
};
use ratatui_kit_macros::{Props, component};
use std::ops::{Deref, DerefMut};
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TextTheme {
pub style: Style,
}
impl ComponentTheme for TextTheme {
fn from_palette(palette: &Palette) -> Self {
Self {
style: Style::new().fg(palette.fg),
}
}
}
impl Default for TextTheme {
fn default() -> Self {
Self::from_palette(&Palette::default())
}
}
#[derive(Clone, Default)]
pub struct TextParagraph<'a> {
inner: Paragraph<'a>,
}
impl<'a> Deref for TextParagraph<'a> {
type Target = Paragraph<'a>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for TextParagraph<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl Widget for TextParagraph<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
self.inner.render(area, buf);
}
}
impl From<String> for TextParagraph<'_> {
fn from(value: String) -> Self {
Self {
inner: Paragraph::new(value),
}
}
}
impl<'a> From<Paragraph<'a>> for TextParagraph<'a> {
fn from(value: Paragraph<'a>) -> Self {
Self { inner: value }
}
}
impl<'a> From<&'a str> for TextParagraph<'a> {
fn from(value: &'a str) -> Self {
Self {
inner: Paragraph::new(value),
}
}
}
impl<'a> From<Line<'a>> for TextParagraph<'a> {
fn from(value: Line<'a>) -> Self {
Self {
inner: Paragraph::new(value),
}
}
}
impl<'a> From<RataText<'a>> for TextParagraph<'a> {
fn from(value: RataText<'a>) -> Self {
Self {
inner: Paragraph::new(value),
}
}
}
#[derive(Default, Props)]
pub struct TextProps {
pub text: TextParagraph<'static>,
pub style: Option<Style>,
pub alignment: ratatui::layout::Alignment,
pub scroll: Position,
pub wrap: Option<bool>,
}
#[component]
pub fn Text(props: &TextProps, hooks: Hooks) -> impl Into<AnyElement<'static>> {
let theme = hooks.use_component_theme::<TextTheme>();
let style = resolve_style(theme.style, props.style);
let paragraph = props
.text
.inner
.clone()
.style(style)
.scroll((props.scroll.x, props.scroll.y))
.alignment(props.alignment);
let paragraph = if let Some(wrap) = props.wrap {
paragraph.wrap(ratatui::widgets::Wrap { trim: wrap })
} else {
paragraph
};
let paragraph = TextParagraph::from(paragraph);
element! {
Fragment{
widget(paragraph)
}
}
}