UI widgets
Current EMWaver UI scripts import components from emw-ui, import JSX and render from emw-jsx, then render JSX. The JSX is converted to the same serializable UI tree used by the native renderers.
Imports and render
import { JSX, render } from "emw-jsx";
import {
Button,
Card,
Column,
Divider,
Grid,
LogViewer,
Modal,
Picker,
Plot,
Progress,
Row,
Scroll,
Slider,
Spacer,
Text,
TextEditor,
TextField,
Tile,
Toggle,
} from "emw-ui";
function App() {
return <Text>Hello from EMWaver</Text>;
}
render(<App />);Layout
<Column padding={16} spacing={12}>
<Text>Stacked vertically</Text>
<Row spacing={8}>
<Button>Left</Button>
<Button>Right</Button>
</Row>
<Grid columns={3} spacing={8}>
<Tile title="A" value="1" />
<Tile title="B" value="2" />
<Tile title="C" value="3" />
</Grid>
<Divider />
<Spacer minLength={20} />
</Column>
<Scroll padding={16} spacing={14}>
<Text>Scrollable page content</Text>
</Scroll>Card
<Card title="GPIO Control" subtitle="Pin A0">
<Button onTap={toggle}>Toggle</Button>
</Card>Text
<Text>Hello</Text>
<Text font="title2" fontWeight="semibold">Sampler</Text>
<Text font="caption" foregroundColor="#6B7280">
Last reading: {String(reading)}
</Text>Button
<Button id="capture.start" onTap={startCapture}>Start capture</Button>
<Button buttonStyle="borderedProminent" controlSize="large" onTap={save}>
Save
</Button>Tile
<Tile
title="Temperature"
value={temperatureText}
monospaceValue={true}
subtitle="Last reading"
onTap={refresh}
/>Slider
<Slider
id="pwm.duty"
value={duty}
min={0}
max={4095}
step={1}
label="Duty cycle"
onChange={(value) => { duty = Number(value); rerender(); }}
onSubmit={(value) => { writeDuty(Number(value)); }}
/>TextField
<TextField
value={command}
placeholder="Enter command..."
onChange={(value) => { command = String(value || ""); }}
onSubmit={(value) => { sendCommand(String(value || "")); }}
/>
<TextField value={apiKey} secure={true} placeholder="API key" />TextEditor
<TextEditor
value={hexData}
placeholder="Data bytes..."
minHeight={120}
onChange={(value) => { hexData = String(value || ""); rerender(); }}
/>Picker
<Picker
id="gpio.pin"
selected={selectedPin}
options={[
{ label: "A0", value: "0" },
{ label: "A1", value: "1" },
{ label: "GPIO4", value: "4" },
]}
style="menu"
onChange={(value) => { selectedPin = String(value); rerender(); }}
/>
<Picker
style="segmented"
selected={mode}
options={[{ label: "RX", value: "rx" }, { label: "TX", value: "tx" }]}
/>Toggle
<Toggle
label="Enable output"
value={enabled}
onChange={(value) => { enabled = Boolean(value); rerender(); }}
/>Plot
Plot can render inline data or a named/buffer-backed source. The sampler UI uses source="samplerBits" with viewport callbacks for pan/zoom.
<Plot
height={240}
dataX={[0, 1, 2, 3, 4]}
dataY={[0, 1, 0, 1, 0]}
/>
<Plot
height={240}
source="samplerBits"
bins={400}
xMin={xMin}
xMax={xMax}
yMin={-10}
yMax={265}
errorText={chartErr}
onViewportChange={(rangeValue) => {
const range = parseViewportRange(rangeValue);
if (range) scheduleViewport(range.min, range.max);
}}
/>
const bufId = buffer(capturedBytes);
<Plot height={240} source={{ kind: "buffer", id: bufId }} />LogViewer
<LogViewer text={logLines.join("
")} minHeight={220} />Progress
<Progress value={42} total={100} label="Flashing..." />
<Progress label="Scanning..." />Modal
<Modal
open={showModal}
title="Confirm"
subtitle="Are you sure?"
onClose={() => { showModal = false; rerender(); }}
>
<Button onTap={confirm}>OK</Button>
</Modal>Dynamic children and nulls
Components ignore null, undefined, and false children, so conditional UI can be written naturally.
<Column spacing={10}>
<Text font="title2">Radio</Text>
{statusText ? <Text font="caption">{statusText}</Text> : null}
{items.map((item) => <Tile title={item.name} value={item.value} />)}
</Column>Common style props
| Prop | Type | Notes |
|---|---|---|
padding | number or edge object | Use 16 or { top, bottom, leading, trailing }. |
spacing | number | Gap between children for layout nodes. |
width, height | number | Fixed size. |
minWidth, maxWidth, minHeight, maxHeight | number | Size constraints. |
cornerRadius | number | Rounded corners. |
backgroundColor, foregroundColor | string | Native/platform color string. |
fillsWidth | boolean | Stretch to available width. |
alignment | string | Common values: leading, center, trailing. |
Event handlers
| Prop | Used by | Payload |
|---|---|---|
onTap | Button, Tile | No payload. |
onChange | Picker, Slider, Toggle, TextField, TextEditor | New value. |
onSubmit | TextField, Slider | Committed value. |
onViewportChange | Plot | Viewport range with min and max. |
onSelectRange | Plot | Selected range. |
onClose | Modal | No payload. |
