@effindomv2/fui-rs 0.1.19 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "fui-rs"
3
- version = "0.1.19"
3
+ version = "0.1.21"
4
4
  edition = "2021"
5
5
  license = "AGPL-3.0-only OR LicenseRef-EffinDom-Commercial"
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effindomv2/fui-rs",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "private": false,
5
5
  "license": "AGPL-3.0-only OR LicenseRef-EffinDom-Commercial",
6
6
  "description": "EffinDom v2 Rust frontend framework SDK and host generators",
@@ -33,11 +33,12 @@
33
33
  "generate:host": "npm run generate:host-services && npm run generate:host-events:home && npm run generate:host-events:workbench && npm run generate:host-events:stage4 && npm run generate:host-events:stage5 && npm run generate:host-events:immediate-drawing && npm run generate:worker-host-services && npm run generate:framework-host-services",
34
34
  "guard:runtime-dependency": "bash scripts/check-runtime-dependency.sh",
35
35
  "lint": "cd ../.. && npm run lint:v2",
36
+ "lint:rust": "bash -lc 'source \"$HOME/.cargo/env\" && cargo clippy --manifest-path Cargo.toml --all-targets -- -D warnings'",
36
37
  "build": "npm run guard:runtime-dependency && npm run check:abi && bash scripts/build.sh",
37
38
  "test:unit": "npm run guard:runtime-dependency && npm run check:abi && npm run generate:host && bash -lc 'source \"$HOME/.cargo/env\" && cargo test --manifest-path Cargo.toml'",
38
39
  "test:integration": "npm --prefix ../.. run build:v2:browser-bridge && npm run build && playwright test -c playwright.config.ts",
39
40
  "typecheck": "npm run guard:runtime-dependency && npm run check:abi && tsc -p tsconfig.json --noEmit",
40
- "prepublishOnly": "npm run check:abi && npm run lint && npm run typecheck"
41
+ "prepublishOnly": "npm run check:abi && npm run lint && npm run lint:rust && npm run typecheck"
41
42
  },
42
43
  "dependencies": {
43
44
  "@effindomv2/runtime": "0.1.26"
package/src/color.rs CHANGED
@@ -106,7 +106,10 @@ mod tests {
106
106
  #[test]
107
107
  fn color_helpers_mask_channels_and_interpolate() {
108
108
  assert_eq!(rgba(0x112, 0x134, 0x156, 0x178), 0x12345678);
109
- assert_eq!(mix_color(rgb(0, 0, 0), rgb(255, 255, 255), 0.5), rgba(128, 128, 128, 255));
109
+ assert_eq!(
110
+ mix_color(rgb(0, 0, 0), rgb(255, 255, 255), 0.5),
111
+ rgba(128, 128, 128, 255)
112
+ );
110
113
  assert_eq!(hsl_to_color(0.0, 1.0, 0.5), rgb(255, 0, 0));
111
114
  }
112
115
  }
@@ -1,6 +1,6 @@
1
1
  use super::ContextMenuAppearance;
2
2
  use crate::bindings::ui;
3
- use crate::event::{self, PointerEventArgs, PointerType};
3
+ use crate::event::{self, PointerButton, PointerEventArgs, PointerType};
4
4
  use crate::ffi::{
5
5
  BorderStyle, CursorStyle, HandleValue, KeyEventType, SemanticRole, TextAlign, TextOverflow,
6
6
  Unit,
@@ -29,7 +29,7 @@ thread_local! {
29
29
  }
30
30
 
31
31
  fn is_primary_activation_pointer(event: &PointerEventArgs) -> bool {
32
- event.button == 0
32
+ event.button == PointerButton::Primary
33
33
  || event.pointer_type == PointerType::Touch
34
34
  || event.pointer_type == PointerType::Pen
35
35
  }
@@ -1,6 +1,6 @@
1
1
  use super::*;
2
2
  use crate::bindings::ui;
3
- use crate::event::PointerType;
3
+ use crate::event::{PointerButton, PointerType};
4
4
  use crate::ffi::{CursorStyle, HandleValue, SemanticRole};
5
5
  use crate::navigation;
6
6
  use crate::node::{text, NodeHandle, NodeRef, WeakFlexBox};
@@ -14,8 +14,13 @@ thread_local! {
14
14
  static ACTIVE_PREVIEW_OWNER: Cell<u64> = const { Cell::new(HandleValue::Invalid as u64) };
15
15
  }
16
16
 
17
- fn is_primary_activation_pointer(event: &PointerEventArgs) -> bool {
18
- event.button == 0
17
+ fn is_middle_mouse_button(event: &PointerEventArgs) -> bool {
18
+ event.pointer_type == PointerType::Mouse && event.button == PointerButton::Auxiliary
19
+ }
20
+
21
+ fn is_activation_pointer(event: &PointerEventArgs) -> bool {
22
+ event.button == PointerButton::Primary
23
+ || is_middle_mouse_button(event)
19
24
  || event.pointer_type == PointerType::Touch
20
25
  || event.pointer_type == PointerType::Pen
21
26
  }
@@ -59,6 +64,8 @@ impl NavLink {
59
64
  label_node
60
65
  .font_family(theme.fonts.body_family.clone())
61
66
  .font_size(15.0)
67
+ .text_color(theme.colors.accent)
68
+ .selectable(false)
62
69
  .cursor(CursorStyle::Pointer);
63
70
  root.justify_content(JustifyContent::Start)
64
71
  .align_items(AlignItems::Center)
@@ -124,21 +131,22 @@ impl NavLink {
124
131
  });
125
132
  let target = self.event_target();
126
133
  self.root.on_pointer_down(move |event| {
127
- if !is_primary_activation_pointer(event) {
134
+ if !is_activation_pointer(event) {
128
135
  target.pointer_pressed.set(false);
129
136
  target.pointer_pressed_open_in_new_tab.set(false);
130
137
  return;
131
138
  }
132
139
  target.pointer_pressed.set(true);
133
- target
134
- .pointer_pressed_open_in_new_tab
135
- .set(target.should_open_in_new_tab(event.modifiers));
140
+ target.pointer_pressed_open_in_new_tab.set(
141
+ is_middle_mouse_button(event) || target.should_open_in_new_tab(event.modifiers),
142
+ );
136
143
  event.handled = true;
137
144
  });
138
145
  let target = self.event_target();
139
146
  self.root.on_pointer_up(move |event| {
140
- if target.pointer_pressed.replace(false) && is_primary_activation_pointer(event) {
147
+ if target.pointer_pressed.replace(false) && is_activation_pointer(event) {
141
148
  let open_in_new_tab = target.pointer_pressed_open_in_new_tab.get()
149
+ || is_middle_mouse_button(event)
142
150
  || target.should_open_in_new_tab(event.modifiers);
143
151
  target.activate(open_in_new_tab);
144
152
  event.handled = true;
@@ -442,7 +450,6 @@ impl NavLinkEventTarget {
442
450
  } else {
443
451
  self.text_color_override
444
452
  .get()
445
- .or_else(|| self.label.configured_text_color())
446
453
  .unwrap_or(theme.colors.accent)
447
454
  };
448
455
  if self.label.handle() != NodeHandle::INVALID {
@@ -528,7 +528,7 @@ impl SliderEventTarget {
528
528
  }
529
529
 
530
530
  fn handle_pointer_move(&self, event: &mut PointerEventArgs) {
531
- if !self.is_enabled() || !self.dragging_state.get() || event.buttons == 0 {
531
+ if !self.is_enabled() || !self.dragging_state.get() || event.buttons.is_empty() {
532
532
  return;
533
533
  }
534
534
  self.update_value_from_pointer(event.scene_x, event.scene_y, true, true);
package/src/event.rs CHANGED
@@ -43,6 +43,58 @@ impl PointerType {
43
43
  }
44
44
  }
45
45
 
46
+ #[repr(i32)]
47
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
48
+ pub enum PointerButton {
49
+ None = -1,
50
+ Primary = 0,
51
+ Auxiliary = 1,
52
+ Secondary = 2,
53
+ Back = 3,
54
+ Forward = 4,
55
+ }
56
+
57
+ impl PointerButton {
58
+ pub fn from_raw(value: i32) -> Self {
59
+ match value {
60
+ 0 => Self::Primary,
61
+ 1 => Self::Auxiliary,
62
+ 2 => Self::Secondary,
63
+ 3 => Self::Back,
64
+ 4 => Self::Forward,
65
+ _ => Self::None,
66
+ }
67
+ }
68
+ }
69
+
70
+ #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
71
+ pub struct PointerButtons(u32);
72
+
73
+ impl PointerButtons {
74
+ pub const NONE: Self = Self(0);
75
+ pub const PRIMARY: Self = Self(1 << 0);
76
+ pub const SECONDARY: Self = Self(1 << 1);
77
+ pub const AUXILIARY: Self = Self(1 << 2);
78
+ pub const BACK: Self = Self(1 << 3);
79
+ pub const FORWARD: Self = Self(1 << 4);
80
+
81
+ pub const fn from_raw(value: u32) -> Self {
82
+ Self(value)
83
+ }
84
+
85
+ pub const fn bits(self) -> u32 {
86
+ self.0
87
+ }
88
+
89
+ pub const fn is_empty(self) -> bool {
90
+ self.0 == 0
91
+ }
92
+
93
+ pub const fn contains(self, buttons: Self) -> bool {
94
+ self.0 & buttons.0 == buttons.0
95
+ }
96
+ }
97
+
46
98
  #[derive(Clone, Copy, Debug, PartialEq, Eq)]
47
99
  pub enum GestureIntent {
48
100
  None = 0,
@@ -109,8 +161,8 @@ pub struct PointerEventArgs {
109
161
  pub modifiers: u32,
110
162
  pub pointer_id: i32,
111
163
  pub pointer_type: PointerType,
112
- pub button: i32,
113
- pub buttons: u32,
164
+ pub button: PointerButton,
165
+ pub buttons: PointerButtons,
114
166
  pub pressure: f32,
115
167
  pub width: f32,
116
168
  pub height: f32,
@@ -145,8 +197,8 @@ impl PointerEventArgs {
145
197
  modifiers,
146
198
  pointer_id,
147
199
  pointer_type,
148
- button,
149
- buttons,
200
+ button: PointerButton::from_raw(button),
201
+ buttons: PointerButtons::from_raw(buttons),
150
202
  pressure,
151
203
  width,
152
204
  height,
package/src/lib.rs CHANGED
@@ -4,9 +4,9 @@ pub mod assets;
4
4
  #[doc(hidden)]
5
5
  pub mod bindings;
6
6
  pub mod bitmap;
7
- pub mod color;
8
7
  #[doc(hidden)]
9
8
  pub mod bridge_callbacks;
9
+ pub mod color;
10
10
  pub(crate) mod context_menu_manager;
11
11
  pub mod controls;
12
12
  pub mod debug;
@@ -456,8 +456,9 @@ pub mod prelude {
456
456
  pub use crate::drawing::{DrawContext, Paint, Path};
457
457
  pub use crate::event::{
458
458
  FocusChangedEventArgs, GestureEventArgs, GestureEventKind, GestureEventPhase,
459
- GestureIntent, KeyEventArgs, LongPressEventArgs, PointerEventArgs, PointerType,
460
- SelectionChangedEventArgs, TextChangedEventArgs, WheelEventArgs,
459
+ GestureIntent, KeyEventArgs, LongPressEventArgs, PointerButton, PointerButtons,
460
+ PointerEventArgs, PointerType, SelectionChangedEventArgs, TextChangedEventArgs,
461
+ WheelEventArgs,
461
462
  };
462
463
  pub use crate::external_drop::{
463
464
  ExternalDropEventArgs, ExternalDropItemInfo, ExternalDropItemKind,
@@ -488,10 +489,10 @@ pub mod prelude {
488
489
  auto, column, custom_drawable, fill, flex_box, grid, image, pct, portal, px, row,
489
490
  scroll_box, scroll_view, svg, text, viewport_height, viewport_width, virtual_list, Border,
490
491
  Child, ContextMenuEventArgs, Corners, CustomDrawable, DrawableInvalidator, EdgeInsets,
491
- FlexBox, FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, Image, ImageNode,
492
- Length, Node, PresenterHostStyle, ScrollBar, ScrollBarStyle, ScrollBarVisibility,
493
- ScrollBox, ScrollState, ScrollView, Shadow, Svg, SvgNode, Text, TextCore, TextNode,
494
- ThemeBindable, VirtualList,
492
+ FlexBox, FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, HasTextNode, Image,
493
+ ImageNode, Length, Node, PresenterHostStyle, ScrollBar, ScrollBarStyle,
494
+ ScrollBarVisibility, ScrollBox, ScrollState, ScrollView, Shadow, Svg, SvgNode, Text,
495
+ TextCore, TextLayoutSurface, TextNode, ThemeBindable, VirtualList,
495
496
  };
496
497
  pub use crate::persisted;
497
498
  pub use crate::platform;
@@ -581,8 +582,8 @@ pub use drag_drop::{
581
582
  pub use drawing::{DrawContext, Paint, Path};
582
583
  pub use event::{
583
584
  FocusChangedEventArgs, GestureEventArgs, GestureEventKind, GestureEventPhase, GestureIntent,
584
- KeyEventArgs, LongPressEventArgs, PointerEventArgs, PointerType, SelectionChangedEventArgs,
585
- TextChangedEventArgs, WheelEventArgs,
585
+ KeyEventArgs, LongPressEventArgs, PointerButton, PointerButtons, PointerEventArgs, PointerType,
586
+ SelectionChangedEventArgs, TextChangedEventArgs, WheelEventArgs,
586
587
  };
587
588
  pub use external_drop::{ExternalDropEventArgs, ExternalDropItemInfo, ExternalDropItemKind};
588
589
  pub use fetch::{Fetch, FetchErrorEventArgs, FetchRequest, FetchResponse};
@@ -609,9 +610,10 @@ pub use node::{
609
610
  auto, column, custom_drawable, fill, flex_box, grid, image, pct, portal, px, row, scroll_box,
610
611
  scroll_view, svg, text, viewport_height, viewport_width, virtual_list, Border, Child,
611
612
  ContextMenuEventArgs, Corners, CustomDrawable, DrawableInvalidator, EdgeInsets, FlexBox,
612
- FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, Image, ImageNode, Length, Node,
613
- PresenterHostStyle, ScrollBar, ScrollBarStyle, ScrollBarVisibility, ScrollBox, ScrollState,
614
- ScrollView, Shadow, Svg, SvgNode, Text, TextCore, TextNode, ThemeBindable, VirtualList,
613
+ FlexBoxSurface, GradientStop, Grid, GridTrack, HasFlexBoxRoot, HasTextNode, Image, ImageNode,
614
+ Length, Node, PresenterHostStyle, ScrollBar, ScrollBarStyle, ScrollBarVisibility, ScrollBox,
615
+ ScrollState, ScrollView, Shadow, Svg, SvgNode, Text, TextCore, TextLayoutSurface, TextNode,
616
+ ThemeBindable, VirtualList,
615
617
  };
616
618
  pub use persisted::*;
617
619
  pub use platform::*;
package/src/node/core.rs CHANGED
@@ -3,7 +3,7 @@ use crate::drag_drop::{
3
3
  DragCompletedEventArgs, DragDataObject, DragDropEffects, DragEventArgs, DropProposal,
4
4
  };
5
5
  use crate::drag_gesture::{DragCompletedEvent, DragGesture, DragStartedEvent};
6
- use crate::event::{SelectionChangedEventArgs, TextChangedEventArgs};
6
+ use crate::event::{PointerButton, SelectionChangedEventArgs, TextChangedEventArgs};
7
7
  use crate::external_drop::ExternalDropEventArgs;
8
8
  use crate::persisted::PersistedStateAdapter;
9
9
  use crate::tool_tip::ToolTip;
@@ -31,7 +31,7 @@ pub(crate) type ExternalDragEventCallback = Rc<dyn Fn(ExternalDropEventArgs)>;
31
31
  pub(crate) type EffectiveEnabledChangedCallback = Rc<dyn Fn(bool)>;
32
32
 
33
33
  pub(crate) fn is_primary_activation_pointer(event: &PointerEventArgs) -> bool {
34
- event.button == 0
34
+ event.button == PointerButton::Primary
35
35
  || event.pointer_type == PointerType::Touch
36
36
  || event.pointer_type == PointerType::Pen
37
37
  }
@@ -513,11 +513,7 @@ impl NodeRef {
513
513
  self.inner.borrow().handle
514
514
  }
515
515
 
516
- pub(crate) fn set_semantic_checked(
517
- &self,
518
- state: SemanticCheckedState,
519
- announce: bool,
520
- ) {
516
+ pub(crate) fn set_semantic_checked(&self, state: SemanticCheckedState, announce: bool) {
521
517
  let handle = {
522
518
  let mut core = self.inner.borrow_mut();
523
519
  core.behavior.semantic_checked = Some(state);
package/src/node/mod.rs CHANGED
@@ -100,6 +100,85 @@ impl ThemeBindable for FlexBox {
100
100
  }
101
101
  }
102
102
 
103
+ pub trait HasTextNode {
104
+ fn text_node(&self) -> &TextNode;
105
+ }
106
+
107
+ pub trait TextLayoutSurface: HasTextNode {
108
+ fn width(&self, width: f32, unit: Unit) -> &Self {
109
+ self.text_node().width(width, unit);
110
+ self
111
+ }
112
+
113
+ fn height(&self, height: f32, unit: Unit) -> &Self {
114
+ self.text_node().height(height, unit);
115
+ self
116
+ }
117
+
118
+ fn fill_width(&self) -> &Self {
119
+ self.text_node().fill_width();
120
+ self
121
+ }
122
+
123
+ fn fill_height(&self) -> &Self {
124
+ self.text_node().fill_height();
125
+ self
126
+ }
127
+
128
+ fn fill_size(&self) -> &Self {
129
+ self.text_node().fill_size();
130
+ self
131
+ }
132
+
133
+ fn line_height(&self, line_height: f32) -> &Self {
134
+ self.text_node().line_height(line_height);
135
+ self
136
+ }
137
+
138
+ fn text_align(&self, align: TextAlign) -> &Self {
139
+ self.text_node().text_align(align);
140
+ self
141
+ }
142
+
143
+ fn text_vertical_align(&self, align: TextVerticalAlign) -> &Self {
144
+ self.text_node().text_vertical_align(align);
145
+ self
146
+ }
147
+
148
+ fn text_limits(&self, max_chars: i32, max_lines: i32) -> &Self {
149
+ self.text_node().text_limits(max_chars, max_lines);
150
+ self
151
+ }
152
+
153
+ fn max_lines(&self, max_lines: i32) -> &Self {
154
+ self.text_node().max_lines(max_lines);
155
+ self
156
+ }
157
+
158
+ fn wrapping(&self, wrap: bool) -> &Self {
159
+ self.text_node().wrapping(wrap);
160
+ self
161
+ }
162
+
163
+ fn text_overflow(&self, overflow: TextOverflow) -> &Self {
164
+ self.text_node().text_overflow(overflow);
165
+ self
166
+ }
167
+
168
+ fn text_overflow_fade(&self, horizontal: bool, vertical: bool) -> &Self {
169
+ self.text_node().text_overflow_fade(horizontal, vertical);
170
+ self
171
+ }
172
+ }
173
+
174
+ impl<T: HasTextNode> TextLayoutSurface for T {}
175
+
176
+ impl HasTextNode for TextNode {
177
+ fn text_node(&self) -> &TextNode {
178
+ self
179
+ }
180
+ }
181
+
103
182
  pub trait FlexBoxSurface: HasFlexBoxRoot {
104
183
  fn width(&self, width: f32, unit: Unit) -> &Self {
105
184
  self.flex_box_root().width(width, unit);
@@ -164,10 +164,6 @@ impl TextNode {
164
164
  self
165
165
  }
166
166
 
167
- pub(crate) fn configured_text_color(&self) -> Option<u32> {
168
- self.props.borrow().text_color
169
- }
170
-
171
167
  pub fn style_runs(&self, words: Vec<u32>) -> &Self {
172
168
  {
173
169
  let mut props = self.props.borrow_mut();
package/src/text.rs CHANGED
@@ -3,7 +3,7 @@ use crate::bindings::ui;
3
3
  use crate::ffi::{TextAlign, TextOverflow, TextVerticalAlign, Unit};
4
4
  use crate::frame_scheduler::on_loaded;
5
5
  use crate::logger::error;
6
- use crate::node::{Node, TextNode};
6
+ use crate::node::{HasTextNode, Node, TextNode, ThemeBindable};
7
7
  use crate::theme;
8
8
  use crate::typography::{FontFamily, FontStack, FontStyle, FontWeight};
9
9
  use std::cell::RefCell;
@@ -247,6 +247,29 @@ impl Deref for RichText {
247
247
  }
248
248
  }
249
249
 
250
+ impl HasTextNode for RichText {
251
+ fn text_node(&self) -> &TextNode {
252
+ &self.node
253
+ }
254
+ }
255
+
256
+ impl ThemeBindable for RichText {
257
+ fn theme_binding_node(&self) -> crate::node::NodeRef {
258
+ self.node.retained_node_ref()
259
+ }
260
+
261
+ fn weak_theme_target(&self) -> Box<dyn Fn() -> Option<Self>> {
262
+ let weak_node = self.node.weak_theme_target();
263
+ let weak_state = Rc::downgrade(&self.state);
264
+ Box::new(move || {
265
+ Some(Self {
266
+ node: weak_node()?,
267
+ state: weak_state.upgrade()?,
268
+ })
269
+ })
270
+ }
271
+ }
272
+
250
273
  impl Node for RichText {
251
274
  fn retained_node_ref(&self) -> crate::node::NodeRef {
252
275
  self.node.retained_node_ref()
package/src/theme.rs CHANGED
@@ -1,7 +1,7 @@
1
- use crate::generated::framework_host_services;
2
1
  use crate::color::{
3
2
  color_alpha, color_blue, color_green, color_red, mix_color, rgb, rgba, with_alpha,
4
3
  };
4
+ use crate::generated::framework_host_services;
5
5
  use crate::signal::{Callback, Signal, SubscriptionGuard};
6
6
  use crate::typography::{FontFamily, FontStack};
7
7
  use std::cell::RefCell;