Archived
f4abfe6fdc
Belated rename commit for foundation/el-ui — was missed in the workspace-wide crates→vessels pass earlier today. Same structural intent as the rename in the other repos: 'crates' is the Rust word, 'vessel' is El's, and the directory rename is the marker that this slot holds an El buildable unit even if its current contents are still Rust pending port. Plus the El ports themselves — manifest.el + src/main.el per sub- vessel (el-aop, el-auth, el-config, el-i18n, el-identity, el-layout, el-platform, el-publish, el-secrets, el-services, el-style, el-ui- compiler). The ui-compiler is a stub: elc only emits C right now; generating browser-target JS/Wasm is the biggest open language gap and gets its own project. Until then, el-ui-compiler emits a JS module that throws elc.backend_missing so callers fail loudly. Cross-repo path dependencies in Cargo.toml updated to vessels/.
142 lines
3.5 KiB
Rust
142 lines
3.5 KiB
Rust
/// ScrollView — scrollable container.
|
|
///
|
|
/// Wraps content that may exceed the available space. Scrolling axis can be
|
|
/// vertical (default), horizontal, or both. On platforms with native scroll
|
|
/// behaviors (iOS, Android), the backend translates this to a native scroll
|
|
/// container — you get momentum, overscroll, pull-to-refresh for free.
|
|
|
|
use el_style::modifier::{StyleModifier, StyleSet};
|
|
|
|
/// Which axis (or axes) can scroll.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum ScrollAxis {
|
|
/// Vertical scrolling only (default). Most content views.
|
|
Vertical,
|
|
/// Horizontal scrolling only. Carousels, horizontal lists.
|
|
Horizontal,
|
|
/// Free scrolling in both directions. Maps, canvases.
|
|
Both,
|
|
}
|
|
|
|
/// Scroll indicator visibility.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum ScrollIndicator {
|
|
/// Show when scrolling, hide otherwise (platform default).
|
|
Automatic,
|
|
/// Always show.
|
|
Always,
|
|
/// Never show.
|
|
Never,
|
|
}
|
|
|
|
/// A scrollable container.
|
|
#[derive(Debug, Clone)]
|
|
pub struct ScrollView {
|
|
pub axis: ScrollAxis,
|
|
pub indicator: ScrollIndicator,
|
|
/// Whether the user can zoom (pinch-to-zoom). Default: false.
|
|
pub zoomable: bool,
|
|
/// Minimum zoom scale (only relevant when zoomable = true).
|
|
pub min_zoom: f32,
|
|
/// Maximum zoom scale (only relevant when zoomable = true).
|
|
pub max_zoom: f32,
|
|
/// Whether to clip content to the scroll view bounds. Default: true.
|
|
pub clips_to_bounds: bool,
|
|
pub style: StyleSet,
|
|
}
|
|
|
|
impl Default for ScrollView {
|
|
fn default() -> Self {
|
|
Self {
|
|
axis: ScrollAxis::Vertical,
|
|
indicator: ScrollIndicator::Automatic,
|
|
zoomable: false,
|
|
min_zoom: 1.0,
|
|
max_zoom: 3.0,
|
|
clips_to_bounds: true,
|
|
style: StyleSet::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ScrollView {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
pub fn horizontal() -> Self {
|
|
Self {
|
|
axis: ScrollAxis::Horizontal,
|
|
..Self::default()
|
|
}
|
|
}
|
|
|
|
pub fn both_axes() -> Self {
|
|
Self {
|
|
axis: ScrollAxis::Both,
|
|
..Self::default()
|
|
}
|
|
}
|
|
|
|
pub fn indicator(mut self, indicator: ScrollIndicator) -> Self {
|
|
self.indicator = indicator;
|
|
self
|
|
}
|
|
|
|
pub fn zoomable(mut self, min: f32, max: f32) -> Self {
|
|
self.zoomable = true;
|
|
self.min_zoom = min;
|
|
self.max_zoom = max;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl StyleModifier for ScrollView {
|
|
fn style_mut(&mut self) -> &mut StyleSet {
|
|
&mut self.style
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn scroll_default_is_vertical() {
|
|
let sv = ScrollView::new();
|
|
assert_eq!(sv.axis, ScrollAxis::Vertical);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_horizontal_constructor() {
|
|
let sv = ScrollView::horizontal();
|
|
assert_eq!(sv.axis, ScrollAxis::Horizontal);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_both_axes() {
|
|
let sv = ScrollView::both_axes();
|
|
assert_eq!(sv.axis, ScrollAxis::Both);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_zoomable() {
|
|
let sv = ScrollView::new().zoomable(0.5, 4.0);
|
|
assert!(sv.zoomable);
|
|
assert_eq!(sv.min_zoom, 0.5);
|
|
assert_eq!(sv.max_zoom, 4.0);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_clips_by_default() {
|
|
let sv = ScrollView::new();
|
|
assert!(sv.clips_to_bounds);
|
|
}
|
|
|
|
#[test]
|
|
fn scroll_indicator_setting() {
|
|
let sv = ScrollView::new().indicator(ScrollIndicator::Never);
|
|
assert_eq!(sv.indicator, ScrollIndicator::Never);
|
|
}
|
|
}
|