diff --git a/crates/op-editor-ui/src/font_catalog.rs b/crates/op-editor-ui/src/font_catalog.rs new file mode 100644 index 000000000..8638fe80d --- /dev/null +++ b/crates/op-editor-ui/src/font_catalog.rs @@ -0,0 +1,31 @@ +//! Shared font-family catalog used by typography widgets and hosts. + +/// TS `BUNDLED_FAMILIES` (use-system-fonts.ts:9-21). +pub const BUNDLED_FONT_FAMILIES: [&str; 11] = [ + "Inter", + "Poppins", + "Roboto", + "Montserrat", + "Open Sans", + "Lato", + "Raleway", + "DM Sans", + "Playfair Display", + "Nunito", + "Source Sans 3", +]; + +/// TS `FALLBACK_SYSTEM_FONTS` (use-system-fonts.ts:24-36). +pub const FALLBACK_SYSTEM_FONTS: [&str; 11] = [ + "Arial", + "Helvetica", + "Helvetica Neue", + "Georgia", + "Times New Roman", + "Courier New", + "Verdana", + "Trebuchet MS", + "Tahoma", + "Impact", + "Comic Sans MS", +]; diff --git a/crates/op-editor-ui/src/lib.rs b/crates/op-editor-ui/src/lib.rs index 4d2610494..0c47be685 100644 --- a/crates/op-editor-ui/src/lib.rs +++ b/crates/op-editor-ui/src/lib.rs @@ -31,6 +31,7 @@ pub use op_i18n as i18n; pub use op_editor_core::render_backend; pub mod accessibility; +pub mod font_catalog; pub mod layout_scene; pub mod layout_scene_hit; pub mod scene_vars; diff --git a/crates/op-editor-ui/src/widgets/mod.rs b/crates/op-editor-ui/src/widgets/mod.rs index f296d772f..8e7256998 100644 --- a/crates/op-editor-ui/src/widgets/mod.rs +++ b/crates/op-editor-ui/src/widgets/mod.rs @@ -89,6 +89,7 @@ pub mod property_panel_visibility; pub mod property_panel_widget; #[cfg(test)] mod property_panel_widget_tests; +pub mod text_input; mod text_selection; pub mod toolbar; @@ -223,6 +224,7 @@ pub mod variables_panel; mod variables_preset_menu; pub use prop_row::PropertyRow; +pub use text_input::TextInputWidget; pub use tree::{TreeItem, TreeWidget}; pub use layer_panel::{LayerItem, LayerPanel}; diff --git a/crates/op-editor-ui/src/widgets/property_panel_typography.rs b/crates/op-editor-ui/src/widgets/property_panel_typography.rs index 2748892d8..31d84201a 100644 --- a/crates/op-editor-ui/src/widgets/property_panel_typography.rs +++ b/crates/op-editor-ui/src/widgets/property_panel_typography.rs @@ -28,36 +28,7 @@ use crate::widgets::PaintCx; use crate::{Point2D, Rect, TextLayout}; use jian_widgets::components::select::{SelectHit, SelectState}; -/// TS `BUNDLED_FAMILIES` (use-system-fonts.ts:9-21). -pub const BUNDLED_FONT_FAMILIES: [&str; 11] = [ - "Inter", - "Poppins", - "Roboto", - "Montserrat", - "Open Sans", - "Lato", - "Raleway", - "DM Sans", - "Playfair Display", - "Nunito", - "Source Sans 3", -]; - -/// TS `FALLBACK_SYSTEM_FONTS` (use-system-fonts.ts:24-36) — shown -/// when no host enumeration is available (wasm host). -pub const FALLBACK_SYSTEM_FONTS: [&str; 11] = [ - "Arial", - "Helvetica", - "Helvetica Neue", - "Georgia", - "Times New Roman", - "Courier New", - "Verdana", - "Trebuchet MS", - "Tahoma", - "Impact", - "Comic Sans MS", -]; +pub use crate::font_catalog::{BUNDLED_FONT_FAMILIES, FALLBACK_SYSTEM_FONTS}; /// One selectable row (TS `FontInfo`). #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/crates/op-editor-ui/src/widgets/text_input.rs b/crates/op-editor-ui/src/widgets/text_input.rs new file mode 100644 index 000000000..1da8f1338 --- /dev/null +++ b/crates/op-editor-ui/src/widgets/text_input.rs @@ -0,0 +1,93 @@ +//! OP widget facade for Jian's reusable single-line text input view. + +use super::{LayoutBox, LayoutCx, PaintCx, Widget, WidgetId}; +use crate::{Point2D, Rect}; +use jian_core::text_input::TextInputState; +use jian_widgets::components::text_input::TextInputView; +use jian_widgets::Tokens; + +const DEFAULT_WIDTH: f32 = 160.0; +const DEFAULT_HEIGHT: f32 = 30.0; + +pub struct TextInputWidget { + pub id: WidgetId, + pub state: TextInputState, + pub placeholder: String, + pub focused: bool, + pub font_size: f32, + pub now_ms: u64, + pub pad_x: f32, + pub tokens: Tokens, +} + +impl TextInputWidget { + pub fn new(id: u64, state: TextInputState) -> Self { + Self { + id: WidgetId::new(id), + state, + placeholder: String::new(), + focused: false, + font_size: 13.0, + now_ms: 0, + pad_x: 8.0, + tokens: Tokens::dark(), + } + } + + pub fn with_placeholder(mut self, placeholder: impl Into) -> Self { + self.placeholder = placeholder.into(); + self + } +} + +impl Widget for TextInputWidget { + fn id(&self) -> WidgetId { + self.id + } + + fn layout(&self, cx: &LayoutCx) -> LayoutBox { + LayoutBox { + rect: Rect { + origin: Point2D::new(0.0, 0.0), + size: Point2D::new(cx.available_width.max(DEFAULT_WIDTH), DEFAULT_HEIGHT), + }, + } + } + + fn paint(&self, cx: &mut PaintCx<'_>, rect: Rect) { + let view = TextInputView { + state: &self.state, + placeholder: &self.placeholder, + focused: self.focused, + font_size: self.font_size, + now_ms: self.now_ms, + pad_x: self.pad_x, + }; + view.paint(cx.backend, rect, &self.tokens); + } + + fn access_node(&self) -> accesskit::Node { + let mut node = accesskit::Node::new(accesskit::Role::TextInput); + let label = if self.placeholder.is_empty() { + self.state.text() + } else { + &self.placeholder + }; + node.set_label(label); + node + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn exposes_text_input_access_role() { + let widget = TextInputWidget::new(401, TextInputState::with_text("hello")); + + let node = widget.access_node(); + + assert_eq!(node.role(), accesskit::Role::TextInput); + } +} diff --git a/crates/op-host-native/src/widget_host/font_picker_dispatch.rs b/crates/op-host-native/src/widget_host/font_picker_dispatch.rs index 0945e76ae..99104a9bf 100644 --- a/crates/op-host-native/src/widget_host/font_picker_dispatch.rs +++ b/crates/op-host-native/src/widget_host/font_picker_dispatch.rs @@ -4,9 +4,8 @@ //! (`op_editor_ui::widgets::property_panel_typography`). use super::WidgetHostNative; -use op_editor_ui::widgets::property_panel_typography::{ - font_picker_entries, BUNDLED_FONT_FAMILIES, -}; +use op_editor_ui::font_catalog::BUNDLED_FONT_FAMILIES; +use op_editor_ui::widgets::property_panel_typography::font_picker_entries; use op_editor_ui::widgets::{PropertyPanel, TOP_BAR_HEIGHT}; use op_editor_ui::{Point2D, Rect}; diff --git a/crates/op-host-web/src/web_fonts.rs b/crates/op-host-web/src/web_fonts.rs index 88dcf1708..df1c675e1 100644 --- a/crates/op-host-web/src/web_fonts.rs +++ b/crates/op-host-web/src/web_fonts.rs @@ -15,7 +15,7 @@ use crate::repaint_ctx::RepaintContext; use jian_ops_schema::node::{PenNode, TextContent}; use js_sys::{Array, Function, Promise, Reflect, Uint8Array}; use op_editor_core::pen_node_ext::PenNodeExt; -use op_editor_ui::widgets::property_panel_typography::BUNDLED_FONT_FAMILIES; +use op_editor_ui::font_catalog::BUNDLED_FONT_FAMILIES; use wasm_bindgen::closure::Closure; use wasm_bindgen::{JsCast, JsValue}; diff --git a/crates/op-host-web/src/widget_host/web_fonts.rs b/crates/op-host-web/src/widget_host/web_fonts.rs index 3dd021293..04728ff83 100644 --- a/crates/op-host-web/src/widget_host/web_fonts.rs +++ b/crates/op-host-web/src/widget_host/web_fonts.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use op_editor_ui::widgets::property_panel_typography::BUNDLED_FONT_FAMILIES; +use op_editor_ui::font_catalog::BUNDLED_FONT_FAMILIES; use super::WidgetHost;