Valdi UI Framework

repository·main·Indexed 12 days ago

https://github.com/snapchat/valdi

A cross-platform UI framework for writing declarative TypeScript components that compile directly to native views on iOS, Android, and macOS without using web views or JavaScript bridges.

Tokens
275.3K
Snippets
829
Records
1.1K
Agent score
96%

What's inside Valdi

  1. Overview of Valdi native template elements

    main

    Valdi provides a set of native template elements for building high-performance interfaces. These elements include layout containers, media views, text components, and interactive inputs. Layout and positioning for these elements are powered by the Yoga layout engine, which implements Flexbox behavior.

    Available element categories include:

    • Layout & Containers: Layout, View, ScrollView, Slot
    • Media: ImageView, VideoView, AnimatedImage
    • Text & Input: Label, TextField, TextView
    • Web & Specialized: WebView, BlurView, SpinnerView, ShapeView
  2. What is Valdi?

    main

    Valdi is a framework for building performant, cross-platform, declarative UIs using TypeScript.

    Key features include:

    • Native Rendering: Unlike WebView-based solutions, the Valdi compiler transforms TypeScript source into valdimodule files. These files are consumed by the Valdi runtime to render UI natively on each platform.
    • Hotreloader: Enables rapid iteration by live-updating the UI on a connected device or emulator during development.
    • Native Integration: Provides mechanisms to hook into native code easily.
    • Cross-Platform: Write UI and business logic once to target multiple platforms.
  3. Use RxJS for Valdi components

    main

    The rxjs-valdi module provides a specialized version of RxJS tailored for Valdi components. It is a mirror of the npm rxjs package, specifically containing files from rx/src/internal, but with certain web-specific and problematic code paths removed to ensure stability in Valdi environments.

    Key Differences from Standard RxJS

    Removed Web-Specific Modules: To maintain compatibility with the Valdi runtime, the following modules have been stripped out:

    • rx/src/internal/ajax
    • rx/src/internal/observable/dom
    • rx/src/internal/observable/bindNodeCallback.ts

    Stability Optimizations: To prevent stack overflow issues on Android, the following changes were made to Observable.ts and Subject.ts:

    • The useDeprecatedSynchronousErrorHandling code path has been removed.
    • errorContext wrapping has been removed.

    Check the package.json file in the module directory to determine the exact version of RxJS being used.

  4. Explore Valdi example applications

    main

    The apps/ directory in the repository contains several runnable examples demonstrating different Valdi capabilities:

    • helloworld: A minimal component for the fastest way to get something on screen.
    • navigation_example: Demonstrates screen navigation patterns.
    • managed_context_example: Shows how to share state across components using managed context.
    • valdi_gpt: An AI-driven dynamic UI example where Valdi renders UI described at runtime.
    • cli_example: Demonstrates building a Valdi CLI application.
    • benchmark: Provides performance benchmarks.
  5. Use core text components for rendering and editing

    main

    Valdi provides three primary components for handling text:

    • <label />: The default component for displaying text. It supports single or multiple lines and offers styling for font, color, alignment, and autoscaling. Note that dimensions are calculated by the native platform (iOS/Android) for accurate layout.
    • <textfield />: The default for single-line text editing. Supports placeholders, text editing configurations, and keyboard/selection settings.
    • <textview />: The component used for multi-line text editing.

    All these components use the value property to set the displayed text, which accepts a string or an AttributedText object.

    // Example of component usage
    <label value="Hello World" />
    <textfield value="Single line input" />
    <textview value="Multi-line input" />
  6. What is a Valdi module

    main

    In Valdi, features are organized into modules. A module is a self-contained unit consisting of TypeScript classes, components, and functions. It may also include image assets, localized strings, and TypeScript tests.

    Modules are compiled into .valdimodule files, which are then consumed by the Valdi Runtime to render natively on each platform. Modules are capable of depending on other modules.

  7. Compare Valdi with other frameworks

    main

    Valdi is a cross-platform native UI framework built around TypeScript and Bazel. Use the following comparison to determine if Valdi meets your technical requirements compared to React Native, Flutter, or pure Native development:

    FeatureValdiReact NativeFlutterNative iOS/Android
    LanguageTypeScriptJavaScript / TypeScriptDartSwift / Kotlin
    Renders toTrue native views (no WebView, no JS bridge)True native views (new arch: JSI, no bridge)Native views via Skia/ImpellerPlatform native
    UI modelClass-based components, side-effect JSXFunction/class components, virtual DOMWidget treeUIKit / Jetpack Compose
    Hot reloadvaldi hotreload — sub-second on-deviceMetro bundler — fastFlutter hot reload — fastPreviews / simulators
    Build systemBazel (BUILD.bazel)npm / Metropubspec.yaml + flutter CLIXcode / Gradle
    TypingStrong (TypeScript, no any in generated APIs)Optional (TypeScript overlay)Strong (Dart)Strong
    Dev platformmacOS Apple Silicon (iOS + Android); Linux (Android only)macOS, Windows, LinuxmacOS, Windows, LinuxmacOS (iOS); macOS/Windows/Linux (Android)
    Target platformsiOS, Android, macOS desktop, Web (alpha)iOS, Android, WebiOS, Android, Web, DesktopiOS or Android only
    Open sourceYes (MIT)Yes (MIT)Yes (BSD)Yes
    Bazel integrationFirst-classThird-party rules onlyNot supportedVia rules_apple / rules_android
  8. Understand Valdi's Component Model vs React

    main

    Valdi components are inspired by Functional Reactive Programming, similar to React, but they use a different class structure. While React uses function components and class React.Component, Valdi uses Component (stateless) and StatefulComponent (stateful) classes.

    Key Mapping

    • Props $\rightarrow$ ViewModel: In Valdi, what React calls Props are called ViewModel. They are provided by the parent via JSX attributes and are ReadOnly.
    • State $\rightarrow$ State: Both use State for internal properties that trigger re-renders when changed via this.setState().
    • Context $\rightarrow$ Context: Valdi's Context is a third generic parameter used for native API integration, distinct from React's Context API.

    Rendering Trigger

    Just like React, a render pass is triggered when:

    1. The ViewModel (props) changes from a parent.
    2. this.setState() is called with new values.
    import { StatefulComponent } from "valdi_core/src/Component";
    
    interface ViewModel {
      label: string;
      onDoThing: (count: number) => void;
    }
    
    interface State {
      counter: number;
    }
    
    class MyComponent extends StatefulComponent<ViewModel, State> {
      state = {
        counter: 0,
      };
    
      handleTap = () => {
        const counter = this.state.counter + 1;
        this.setState({ counter });
        this.viewModel.onDoThing(counter);
      };
    
      onRender(): void {
        <view onTap={this.handleTap}>
          <label
            value={`$${this.viewModel.label} (click count ${this.state.counter})`}
          />
        </view>;
      }
    }
  9. Use higher-order functions for general-purpose logic reuse

    main
    The valdi/foundation/src/functional module provides a collection of higher-order functions designed for general-purpose logic reuse across different features. These functions follow the pattern of returning new functions based on input, similar to RxJS operators like map or switchMap, but are decoupled from Observables and can be used in any context requiring functional composition.
  10. Understand FlexBox layout in Valdi

    main

    Valdi implements FlexBox layout using Yoga, Facebook's cross-platform layout engine. The behavior follows the CSS Flexible Box Layout specification.

    Key concepts include:

    • main axis: The primary axis for layout. In row mode, this is horizontal; in column mode, it is vertical.
    • cross axis: The axis perpendicular to the main axis.

    Use FlexBox to efficiently layout children within a parent container, even when child sizes are dynamic or unknown.

  11. How Native and JS Value References work

    main

    Valdi enables cross-platform communication by maintaining a mapping between TypeScript and platform (iOS/Android) code.

    • Native Reference: A C++, Objective-C, or Kotlin object or function exposed to TypeScript.
    • JS Value Reference: A TypeScript function exposed to C++, Objective-C, or Kotlin.

    The runtime automatically manages these references during the lifetime of your TypeScript component. When you call a TypeScript function backed by an Objective-C method, the runtime handles the bridge, and vice versa.

    // @ViewModel
    // @ExportModel
    interface ViewModel {
      fetchUserIds(cb: (userIds: string[]) => void): void;
    }
    
    // @ExportModel
    export class MyComponent extends Component<ViewModel> {
      onCreate() {
        // fetchUserIds is a Native Reference (from platform)
        const fetchUserIds = this.viewModel.fetchUserIds;
    
        // Passing an arrow function creates a JS Value Reference
        fetchUserIds((userIds) => {
          // logic
        });
      }
    }