Text, input, and controls
Text editing, selection, cursor movement, keyboard interaction and press feedback stay in native controls. PHP receives semantic events instead of driving each platform frame.
use Pam\Native\TextEllipsizeMode;use Pam\Native\UI\Text;
$title = Text::make('A long native title') ->numberOfLines(2) ->ellipsize(TextEllipsizeMode::Tail) ->allowFontScaling() ->maxFontSizeMultiplier(1.6) ->selectable();Text also supports automatic fit, platform break strategy, hyphenation and
data detection. Keep font scaling enabled unless a tightly constrained
decorative label has an accessible alternative.
Packaged fonts on Android
Section titled “Packaged fonts on Android”Place TTF or OTF files in the application source, for example
assets/fonts/Brand-Bold.ttf, and declare the application type system once:
@font-face { font-family: "Brand"; src: url("asset://assets/fonts/Brand-Bold.ttf"); font-weight: 700; }
.brand-title { font-weight: 700; font-size: 20px; }<template> <Text class="brand-title">Brand title</Text></template>PAM Native resolves @font-face aliases before the typed tree crosses into
native code and loads the selected file below the packaged pam/ asset root.
Add one face per numeric weight and optional italic variant; ordinary
font-family, font-weight, and font-style declarations select the closest
match. Since 0.5.71, the logical family inherits through layout containers, so
a descendant may change only its weight and still select the correct face.
Paths with traversal, empty segments, or unsupported extensions are rejected.
A normal family name such as sans-serif continues to resolve through
Android.
Since 0.5.84, the Rust layout engine reads each selected TTF/OTF once and caches normalized glyph advances shared by every text node using that face. Intrinsic width, wrapping, accessibility font scaling, and flex centering use the same packaged font the platform renders before the first mount. This avoids clipped labels and font-specific centering drift without a UI-thread measure or post-render correction.
An inline fontFamily="asset://…" attribute remains valid for a one-off
element. A scoped @font-face and semantic class are preferable when a family
is reused because paths stay out of the template structure. The alias compiles
to a typed native property and adds no font registry or runtime selector work.
PAM Native 0.5.54 prepends src/app.css while compiling every component.
Local <style scoped> rules may override it, and either sheet may split files
with relative @import. Nothing creates a runtime CSS cascade, selector pass,
or WebView.
letterSpacing uses logical points, matching the rest of the text contract.
PAM Native 0.5.43 converts that value to Android’s font-relative em unit
using the authored fontSize, so letterSpacing="0.6" remains a subtle
tracking adjustment rather than 60% of a glyph width.
Packaged fonts use their cached face metrics; installed and missing families
fall back to PAM’s allocation-free estimator. A centered Row containing
Text, gap, and an icon therefore centers the visible control content,
including when the Android font scale changes.
PAM Native 0.5.85 also rounds the absolute start and end edges of Android
frames before deriving pixel extents. Text and icon children that share a
logical center therefore retain the same physical center even on fractional
density screens.
use Pam\Native\KeyboardType;use Pam\Native\ReturnKeyType;use Pam\Native\UI\Input;
$email = Input::make($this->state->email) ->placeholder('you@example.com') ->keyboard(KeyboardType::Email) ->returnKey(ReturnKeyType::Done) ->maxLength(254) ->onChange(fn (string $value) => $this->state->email = $value) ->onSubmit(fn () => $this->submit());<Input bind:value="$email" keyboardType="email" returnKeyType="done" sync="debounced" placeholder="you@example.com" on:submit="submit"/>TextInput is the compatibility entry point for Input. Inputs additionally
support multiline and secure entry, autofill hints, capitalization,
autocorrect, selection, content-size/key events and native-owned immediate or
debounced state.
keyboardType accepts PAM’s concise text, email, number, phone,
decimal, and url values. PAM Native 0.5.79 also accepts the familiar React
Native aliases default, email-address, number-pad, numeric,
phone-pad, decimal-pad, ascii-capable, numbers-and-punctuation,
ascii-capable-number-pad, name-phone-pad, twitter, web-search, and
visible-password.
Buttons, pressables, and toggles
Section titled “Buttons, pressables, and toggles”$save = Button::make('Save') ->loading($this->state->saving) ->onPress(fn () => $this->save());
$card = Pressable::make(Text::make('Open project')) ->hitSlop(12) ->pressRetentionOffset(20) ->delayLongPress(450) ->pressedOpacity(0.72) ->onPress($open) ->onLongPress($showMenu);
$enabled = Toggle::make($this->state->enabled) ->trackColors(0xFFCBD5E1, 0xFF2563EB) ->thumbColor(0xFFFFFFFF) ->onToggle(fn (bool $value) => $this->state->enabled = $value);NativeSwitch exposes the same native switch family. TouchableOpacity,
TouchableHighlight, TouchableWithoutFeedback, and
TouchableNativeFeedback exist for authoring compatibility; new code should
prefer Pressable when it needs the complete press lifecycle.