LeCodesdocs

UI content elements

The leaf elements that display something: UIText, UIImage, UIVideo. Each has one mutable content property (.text, .src, .player) that lives on the element — content is never a style. For editable text see UIInput in interactive.md.

At a glance

TypeScript
import photo from './photo.jpg'

const caption = UIText("Loading…").style({ color: "white", fontSize: 16 })

const screen = UIScreen([
  UIImage(photo).style({ width: "100%", height: 220, borderRadius: 16, objectFit: "cover" }),
  caption,
]).style({ bgColor: "black", p: 16, pt: "safe-top", gap: 12 })

screen.open()
caption.text = "Sunset over the harbor"     // re-renders immediately

UIText

TypeScript
UIText(text: string): UIText

text.text = "Updated"       // get/set the displayed string

Text-specific styles (on top of the common element styles):

TypeScript
textAlign:      "start" | "center" | "end" | "left" | "right"   // default left
fontFamily:     string            // system: "serif", "sans-serif", "monospaced"; custom via registerFont
fontSize:       UIValue           // default 14
lineHeight:     UIValue | "normal"
fontWeight:     number | "normal" | "bold"     // 400, 700, …
fontStyle:      "normal" | "italic"
color:          Color
textDecoration: "underline" | "line-through" | "none"
letterSpacing:  UIValue
Note

lineHeight: 1.5 means 1.5 px — a bare number is px everywhere. A multiplier is "1.5em" (resolved against this element's own fontSize; there is no inheritance).

Note

the default screen background is black — always set color explicitly.

UIText's .style() takes no border/background-image props — bgColor, padding, and margins work, but a decorated text chip is a UIRow/UIColumn around a UIText. Custom fonts must be registered before the screen opens — see fonts.md.

UIImage

TypeScript
UIImage(src: ImageSource): UIImage

// ImageSource:
//   string          — remote URL, or an asset() / imported project file
//   FetchResponse   — a downloaded body used directly as pixels
//   File            — from openFilePicker()
//   SvgSource       — wrapped raw SVG XML
//   Canvas          — a 2D Canvas, baked to a texture on assign

img.src            // get the (resolved) source / set a new one — updates the displayed image

Image-specific styles:

TypeScript
objectFit:    "cover" | "contain" | "fill"   // how the source maps into the box
tintColor:    Color                          // SVG sources only
borderRadius: number                         // px (number only on UIImage)
Note

tintColor applies only to SVG sources, and it replaces all fill and stroke colors in the SVG — it's for monochrome icons, not multicolored artwork.

Note

a bare relative path string (UIImage("./photo.png")) does not resolve to a bundled asset — plain strings work only for https://… URLs. Import the file or use asset('./photo.png').

Cropping an atlas: setSourceRect

TypeScript
img.setSourceRect(x: number, y: number, w: number, h: number): this   // texture pixels

Renders only a sub-rectangle of the source — the spritesheet primitive. The rect's w/h become the element's intrinsic size (one frame, not the whole atlas), and the cropped frame always fills the box, overriding objectFit. Chainable and safe to call before the element is on screen (the initial crop is applied at mount). Sprite-style animation is swapping the rect per frame:

TypeScript
const icon = UIImage(atlasUrl).style({ width: 64, height: 64 }).setSourceRect(0, 0, 128, 128)
let frame = 0
setInterval(() => { icon.setSourceRect((++frame % 8) * 128, 0, 128, 128) }, 100)

Pitfall: bgImage is not image content

TypeScript
const img = UIImage("")            // ✗ empty source as a placeholder
img.style.bgImage = url            // ✗ bgImage is container decoration, not content
const img = UIImage(url)           // ✓ the source goes in the constructor…
img.src = newUrl                   // ✓ …and swaps via .src

UIVideo

TypeScript
UIVideo(player: VideoPlayer): UIVideo

video.player       // read-only — the VideoPlayer passed at construction

The element is just the on-screen surface; playback lives entirely on the VideoPlayer — create it first, control it directly:

TypeScript
const player = new VideoPlayer(asset('./intro.mp4'))
const video = UIVideo(player).style({ width: "100%", height: 220, borderRadius: 12, objectFit: "cover" })
player.play()

Video-specific style:

TypeScript
objectFit: "cover" | "contain" | "fill"

UIVideo also accepts the drawable styles (border*, bgColor, …) for framing. The player is a native resource — dispose() it when the video is gone for good, and stop playback in the screen's onClose (see Conventions — Lifecycle).

See also