- name
- component-mapping-matrix
- description
- Comprehensive cross-platform UI component mapping matrix showing how every common
UI pattern maps across Crystal UI::View, SwiftUI, UIKit, AppKit, Jetpack Compose,
Android Views, and Web HTML/CSS. Implementation priority guide for expanding the
asset_pipeline cross-platform component system.
- user-invocable
- true
- allowed-tools
- Read, Write, Edit, Glob, Grep, Bash
- version
- 2.0.0
# Component Mapping Matrix
This is the master reference for expanding the asset_pipeline cross-platform UI component system. Every row represents one component and shows its exact native equivalent on every supported platform.
### See also: Apple Platform Guide
For each `UI::View` below, the **`apple-platform-guide` skill** contains a developer-facing usage doc at `components/<slug>.md` covering: feel-of-the-flow, Quickstart code, Customization table (all knobs + theme tokens), feel recipes, platform behavior, and HIG citations. The slug is the HIG page slug (e.g. `UI::Button` → `components/buttons.md`; `UI::MenuButton` → `components/pop-up-buttons.md`). When this matrix tells you *what to map*, the platform guide tells you *how to use it and why*.
Raw HIG markdown for every component lives in the **`apple-hig` skill** at `pages/<slug>.md`.
---
## 1. How to Read This Matrix
### Columns
| Column | Meaning |
|--------|---------|
| **Crystal UI::View** | The abstract class name in `src/ui/views/`. This is what app developers write. |
| **Priority** | P0 = done/implemented, P3 = specialized stubs being upgraded. See Section 3. |
| **SwiftUI** | Apple's declarative framework equivalent. Useful for cross-referencing SwiftUI docs when designing the Crystal API. |
| **UIKit** | The imperative iOS class our ObjC bridge instantiates on `flag?(:ios)`. Exact class names for `objc_getClass()`. |
| **AppKit** | The imperative macOS class our ObjC bridge instantiates on `flag?(:macos)`. Exact class names for `objc_getClass()`. |
| **Compose** | Android Jetpack Compose function equivalent. Reference for the future declarative Android renderer. |
| **Android View** | The imperative Android class our JNI bridge instantiates on `flag?(:android)`. Exact class names for JNI `FindClass()`. |
| **Web HTML/CSS** | The HTML element and CSS our `Web::Renderer` emits. |
### Priority Tiers
- **P0** — Fully implemented. Working and tested across all 4 platform renderers.
- **Implemented** — Class exists with full API; P3 stubs being upgraded to full renderer support in parallel.
### Using This Matrix for Implementation
When adding a new component, use this matrix to:
1. Confirm all 4 platform equivalents before writing any Crystal code.
2. Note any platform divergences in the "Notes" column before designing the abstract API.
3. Track implementation status by updating the priority to P0 once all renderers are complete.
4. Identify which renderer visit methods to add (`abstract def visit(view : NewView)` in `PlatformVisitor`).
---
## 2. Complete Mapping Matrix
### Text Display
| Crystal UI::View | Priority | SwiftUI | UIKit | AppKit | Compose | Android View | Web HTML/CSS | Notes |
|-----------------|----------|---------|-------|--------|---------|--------------|--------------|-------|
| `UI::Label` | **P0** | `Text` | `UILabel` | `NSTextField` (non-editable, no bezel, no background) | `Text()` | `TextView` | `<span>` with inline font/color styles | Done. AppKit uses NSTextField configured as a label, not NSText. |
| `UI::RichText` | **P0** | `Text` with `.attributedString` | `UITextView` (non-editable) | `NSTextView` (non-editable) | `AnnotatedString` in `Text()` | `TextView` with `SpannableString` | `<p>` or `<div>` with inner HTML | `Span` records with bold/italic/underline/strikethrough/link. `add_span()` builder. `plain_text` helper. |
| `UI::TextEditor` | **P0** | `TextEditor` | `UITextView` (editable) | `NSTextView` (editable) | `TextField(minLines=3)` or `BasicTextField` | `EditText` (multiline) | `<textarea>` | Multiline editor with optional line numbers and syntax highlighting hint. |
### Text Input
| Crystal UI::View | Priority | SwiftUI | UIKit | AppKit | Compose | Android View | Web HTML/CSS | Notes |
|-----------------|----------|---------|-------|--------|---------|--------------|--------------|-------|
| `UI::TextField` | **P0** | `TextField` | `UITextField` | `NSTextField` (editable) / `NSSecureTextField` for `secure_entry` | `TextField()` / `OutlinedTextField()` | `EditText` | `<input type="text">` or `<input type="password">` | Done. `secure_entry` property switches to NSSecureTextField / UITextField secureTextEntry / EditText inputType=textPassword. |
| `UI::SecureField` | **P0** | `SecureField` | `UITextField` (secureTextEntry=true) | `NSSecureTextField` | `TextField(visualTransformation=PasswordVisualTransformation)` | `EditText` (inputType=textPassword) | `<input type="password">` | Dedicated type for type-safe visitor dispatch. Always secure. |
| `UI::SearchField` | **P0** | `searchable()` modifier + `TextField` | `UISearchBar` or `UISearchTextField` (iOS 13+) | `NSSearchField` | `SearchBar()` or `DockedSearchBar()` | `SearchView` | `<input type="search">` | Has `on_submit` and `on_cancel` callbacks in addition to `on_change`. |
| `UI::TextArea` | **P0** | `TextEditor` | `UITextView` (editable) | `NSTextView` (editable) | `TextField(minLines=N)` | `EditText` (multiline, scrollbars) | `<textarea rows="N">` | Multiline text input with `line_limit`, `is_editable`, `is_scrollable`. |
### Buttons and Actions
| Crystal UI::View | Priority | SwiftUI | UIKit | AppKit | Compose | Android View | Web HTML/CSS | Notes |
|-----------------|----------|---------|-------|--------|---------|--------------|--------------|-------|
| `UI::Button` | **P0** | `Button` | `UIButton` (system style) | `NSButton` (bezelStyle=rounded) | `Button()` / `ElevatedButton()` | `MaterialButton` / `Button` | `<button type="button">` | Done. Foreground color, disabled state, on_tap callback. |
| `UI::IconButton` | **P0** | `Button { Image(...) }` | `UIButton` with `setImage:forState:` | `NSButton` with image + no title | `IconButton()` | `ImageButton` | `<button><img src=...></button>` or `<button class="icon-btn">` | SF Symbol / material icon / CSS icon class by platform. `icon_size`, `tint_color`, `disabled`. |
| `UI::LinkButton` | **P0** | `Link` | `UIButton` with URL action | `NSButton` + `NSWorkspace.openURL:` | `TextButton()` styled as link, or `ClickableText` | `Button` with URL intent | `<a href="...">` | `url` property. `opens_in_browser` flag. Optional `on_tap` override. |
| `UI::MenuButton` | **P0** | `Menu` | `UIMenu` + `UIButton` (iOS 14+ `menu` property) | `NSPopUpButton` | `DropdownMenu { ... }` | `PopupMenu` or `DropdownMenu` | `<select>` or custom `<div>` dropdown | `MenuItem` records with `is_destructive` flag. `add_item()` builder methods. |
| `UI::ToggleButton` | **P0** | `Toggle` (button style) | `UIButton` (checkboxConfiguration / selected state) | `NSButton` (buttonType=switch or toggle) | `FilledTonalButton()` with toggle state | `ToggleButton` | `<button aria-pressed="true/false">` | `is_selected`, `icon`, `on_toggle : Proc(Bool, Nil)`. `toggle()` convenience method. |
### Layout Containers
| Crystal UI::View | Priority | SwiftUI | UIKit | AppKit | Compose | Android View | Web HTML/CSS | Notes |
|-----------------|----------|---------|-------|--------|---------|--------------|--------------|-------|
| `UI::VStack` | **P0** | `VStack` | `UIStackView` (axis=.vertical) | `NSStackView` (orientation=vertical, 1) | `Column()` | `LinearLayout` (orientation=VERTICAL) | `<div style="display:flex;flex-direction:column">` | Done. Spacing and alignment supported. |
| `UI::HStack` | **P0** | `HStack` | `UIStackView` (axis=.horizontal) | `NSStackView` (orientation=horizontal, 0) | `Row()` | `LinearLayout` (orientation=HORIZONTAL) | `<div style="display:flex;flex-direction:row">` | Done. |
| `UI::ZStack` | **P0** | `ZStack` | `UIView` + Auto Layout constraints (or manual frames) | `NSView` + addSubview + autoresizing mask | `Box()` | `FrameLayout` | `<div style="position:relative">` with children `position:absolute` | Done. Children stack back-to-front in document order. |
| `UI::ScrollView` | **P0** | `ScrollView` | `UIScrollView` | `NSScrollView` | `LazyColumn()` / `LazyRow()` / `ScrollableColumn()` | `ScrollView` (vertical only) / `HorizontalScrollView` | `<div style="overflow:auto">` | Done. scroll_horizontal + scroll_vertical properties. Android ScrollView only scrolls one axis; HorizontalScrollView for horizontal. |
| `UI::Spacer` | **P0** | `Spacer` | `UILayoutGuide` (flexible space) or `UIView` with low compression | NSView with low hugging priority inside NSStackView | `Spacer()` | `Space` with `layout_weight=1` | `<div style="flex:1 1 0%">` | Done. min_length property sets minimum size. |
| `UI::Grid` | **P0** | `LazyVGrid` / `LazyHGrid` | `UICollectionView` with `UICollectionViewFlowLayout` | `NSCollectionView` with `NSCollectionViewGridLayout` | `LazyVerticalGrid()` / `LazyHorizontalGrid()` | `RecyclerView` with `GridLayoutManager` | CSS Grid: `<div style="display:grid;grid-template-columns:...">` | `Column` records with alignment + minimum_width. `add_row()` builder. `row_count`/`column_count` helpers. |
| `UI::ListView` | **P0** | `List` | `UITableView` or `UICollectionView` (iOS 14+ list) | `NSTableView` or `NSOutlineView` | `LazyColumn { items(...) }` | `RecyclerView` with `LinearLayoutManager` | `<ul>` or `<div>` with repeated child elements | `Section` records with header/footer. `ListView.flat()` convenience constructor. `on_item_tap : Proc(Int32, Int32, Nil)`. |
Auf GitHub ansehen