One label-and-value row inside a transaction receipt. Two layouts: stacked when the value runs long, inline when it is short.
⤷ TransactionSlot, which is the test a primitive has to pass. The inline layout is built the way it should be — #label fills the slack and #value hugs — so a long label pushes the value rather than clipping it. Nothing is outstanding on the component itself; Code Connect stays open because the native library does not exist yet.Contexts are illustrative. Final screens will reference actual GCash patterns.
Layout = Stacked | Inline matches Countdown - Unit, which uses the same property name for the same idea. #label and #value come from the design system's form vocabulary rather than being invented here.⤷ TransactionSlot, and the renames made during this assessment propagated straight through to all three.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Layout=Stacked | N/A | N/A | 272 × 34 | Label above value, both left-aligned and full width. The value's 16px line-height gives it room to wrap onto a second line. |
| Layout=Inline | N/A | N/A | 272 × 24 | Label left, value right, one line each at 14/14. The value truncates rather than wraps — this is the default the receipt uses. |
| Long label | N/A | N/A | fill / hug | Inline only. #label takes the slack at 164 and #value hugs at 108, so a longer label pushes the value instead of overlapping it. |
- The layout setting is named the way the rest of the system names it. It was
Orientation = Inline | Stacked, which collided twice over: Countdown - Unit already usedLayoutfor these exact values, and Voucher already usedOrientationto mean Vertical or Horizontal. NowLayout = Stacked | Inline. The property name becomes the native parameter, so this was worth settling before Code Connect. C2 · Variant & Property Naming - The text layers say what they hold.
#nameand#textbecame#labeland#value, matching the form vocabulary used elsewhere in the design system. The rename propagated to all three instances inside the receipt's slot. C2 · Variant & Property Naming - The line-height difference between layouts is deliberate.
#valueis 14/16 stacked but 14/14 inline, while#labelstays 14/14 in both. Confirmed as intended rather than drift: the stacked layout exists for values that wrap onto a second line and needs the extra leading, and the inline value is a single truncating line that does not. C1 · Layer Structure & Naming - Having no container is deliberate. Both layouts are bare text layers directly under the component, where most components in the system wrap in a
Container. Confirmed as intended:⤷ TransactionSlotowns the gap between rows, so a container here would only add a level and a second place to set spacing. C1 · Layer Structure & Naming
- Write down what the inline value does when it overflows. Inline gives the value 108px and one line. Whether a long reference number truncates at the tail, truncates in the middle, or forces the row to stacked is a decision the native implementation has to make, and it is not visible from the component. Middle truncation is usually right for identifiers, tail truncation for everything else. Docs
- Publish the token names once Dev Mode is read. Both fills resolve to library variables — verified on the component's own text nodes — but the read-only tools return variable IDs rather than names, so the spec tables carry hex values only. A single Dev Mode pass would let the token paths be printed alongside them. Token
- Read the pair as one thing for assistive tech. A screen reader stepping through the receipt should hear "Reference number, 165A25912345" as a single utterance rather than two disconnected fragments. Group the label and value and expose the label as the accessibility label of the value. A11y
- See siblings: Modal - Transaction Receipt is the only consumer today, holding three of these in
⤷ TransactionSlot. Modal is the third component in the family and does not use this row. Family
Two text colours and nothing else — the entry paints no surface of its own, so the receipt behind it shows through. Both layouts use the same pair; what changes between them is the arrangement and the value's text style, not the palette.
| Role | Token | Value |
|---|---|---|
| #label | text/color-text-weaker | #6780A9 |
| #value | text/color-text | #0A2757 |
| Background | none — inherits the receipt surface | — |
iOS — Swift Package Manager
.package(url: "https://github.com/AY-Org/eb-ds-ios", from: "1.0.0")
Android — Gradle (Kotlin DSL)
implementation("com.eastblue.ds:modal:1.0.0")
Import
import EastBlueDS import com.eastblue.ds.modal.*
Planned API — the native library does not exist yet. The artifact is the Modal family: Modal, Modal - Transaction Receipt and this entry all ship in <code>com.eastblue.ds:modal</code> and import <code>com.eastblue.ds.modal.*</code>.
One property. label and value are the two native parameters with no row here, because #label and #value are text layers rather than component properties — Figma exposes no way to set them but overriding the layer, which is also why Code Connect will have nothing to bind them to. layout is a parameter in both languages rather than a SwiftUI modifier: it decides the arrangement of the two children, not the component's appearance, and the modifier form would have read differently from the Compose signature for no gain.
| Figma Property | SwiftUI | Compose |
|---|---|---|
| Layout — Stacked, Inline | layout: EBEntryLayout = .stacked | layout: EBEntryLayout = Stacked |
EBTransactionReceiptEntry( label: "Recipient", value: "Juan dela Cruz · 0917 123 4567", layout: .stacked )
EBTransactionReceiptEntry( label = "Recipient", value = "Juan dela Cruz · 0917 123 4567", layout = EBEntryLayout.Stacked )
EBTransactionReceiptEntry( label: "Reference no.", value: "0091 2345 6789", layout: .inline )
EBTransactionReceiptEntry( label = "Reference no.", value = "0091 2345 6789", layout = EBEntryLayout.Inline )
| Requirement | iOS | Android |
|---|---|---|
| Label and value read as one unit | .accessibilityElement(children: .combine) | Modifier.semantics(mergeDescendants = true) |
| Label is not announced as a separate control | No traits added — it is static text | No role assigned |
| Truncated inline values stay reachable | Full value in accessibilityValue, not the truncated string | Full value in contentDescription |
| Layout follows the text size setting | Switch to stacked when Dynamic Type would truncate the inline value | Switch to stacked at large font scales |
Do
Use inline for short, scannable values — amounts, dates, reference numbers.
Don't
Don't use inline for names or addresses that will truncate at 108px.
Do
Let the label take the slack so a longer label pushes the value.
Don't
Don't set a fixed width on the label to force a column — it clips the moment the copy changes.
Do
Keep spacing between rows on the slot that holds them.
Don't
Don't add padding inside the row; it will double up with the slot's gap.
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | Two text layers, no wrapper. Both differences between the layouts are confirmed intentional: the missing container, and the fact that #value carries a different text style in each — Primary/Multi-line Label/Light/Small stacked so it can wrap, Primary/Label/Light/Small inline so it stays on one line. |
| C2 | Variant & Property Naming | Ready | Layout = Stacked | Inline matches Countdown - Unit. #label and #value come from the form vocabulary. |
| C3 | Token Coverage | Ready | Both fills are bound and named: #label on text/color-text-weaker at #6780A9, #value on text/color-text at #0A2757. All four text layers resolve to shared library styles. The entry paints no surface, so the receipt behind it shows through. |
| C4 | Native Mappability | Ready | A label and a value in a row or a column. Maps to an HStack with a Spacer or a VStack, with no web-only pattern in the way. layout is a parameter rather than a SwiftUI modifier because it arranges the children rather than styling them. The one gap is that neither piece of content is a Figma property — see C7. |
| C5 | Interaction State Coverage | Not Applicable | Display only — the row is not tappable. In the receipt, the tap target belongs to the copy control on the reference row. |
| C6 | Asset & Icon Quality | Not Applicable | No icons or assets — text only. |
1 component set × 2 Layout values = 2 variants. Content is set by overriding the two text layers, not through a variant, so nothing multiplies the set.
| Layout | Size | #value text style | Node |
|---|---|---|---|
| Stacked | 272 × 34 | Primary/Multi-line Label/Light/Small | 5947:181502 |
| Inline | 272 × 24 | Primary/Label/Light/Small | 5947:181503 |
.eb-preview-mtre-shell declared font-family: inherit, which resolves to the site’s --font-body — BarkAda. Both text layers carry Primary/* styles and are Proxima Soft in Figma, so every label and value on the page was rendered in the wrong face. The root now names Proxima Soft; no per-layer override is needed, because nothing in this component is Secondary.Layout is the driving property, so Stacked and Inline each get a card, in the panel’s order. The single card was titled with the component’s own name and specified Stacked only.Gap 4, Padding 0, which can only ever have described Stacked. Read off both auto-layout panels: Stacked is 34 tall, gap 4, no padding, top left; Inline is 24 tall, gap 0, 5px above and below, left and centred. The old rows also used #label width and #value width in place of the seven canonical keys.#value uses a different text style in each layout. Primary/Multi-line Label/Light/Small stacked, so long content wraps; Primary/Label/Light/Small inline, so it stays on one line. The page recorded this only as a line-height difference of 16 against 14, which is the consequence rather than the cause. #label is Primary/Label/Light/Small in both.Proxima Soft SemiBold · 14 / 14 · +0.25, "shared library style · name pending Dev Mode read", and an Alignment row that is a Layout key. All four text layers now resolve.#label on text/color-text-weaker at #6780A9, #value on text/color-text at #0A2757, both matching the node fills exactly. A Colors by Layout table carries them, and states that the entry paints no surface of its own.Layout was a control; it is the driving property, so it becomes the cards. Nothing else in the panel is switchable, which leaves the explicit empty array.gcash/east-blue-ios and com.gcash.eastblue:components:1.0.0, with no Import line. It now cites the Modal family artifact com.eastblue.ds:modal:1.0.0 and imports com.eastblue.ds.modal.*.#label and #value are text layers; the Figma panel exposes only Layout. One row now, with both strings named in the description instead.#label and #value are layers rather than component properties, Code Connect will have nothing to attach the entry’s two strings to when the native library lands. Recorded against C7, which was already open on registration..ebLayout(.stacked / .inline) — a SwiftUI modifier — against its own Compose column’s layout: EBEntryLayout parameter, while the Style tab used a parameter in both. Settled on the parameter: layout arranges the two children rather than styling the component, so the modifier form would have diverged from Compose for no gain.#value line-height column read "16 — wraps" and "14 — truncates". The line-heights follow from the text styles, and the truncation is preview CSS rather than anything Figma states. The column now carries the two resolved style names.layout being a parameter rather than a modifier.getSnippet, so both language tabs were frozen on a static string.Orientation renamed to Layout, matching Countdown - Unit, which already used that name for the same Stacked and Inline values.#name and #text renamed to #label and #value; the rename propagated to all three instances in the receipt's slot.Container confirmed intentional — ⤷ TransactionSlot owns the spacing between rows.Transaction Entry to Modal - Transaction Receipt Entry to place it in the Modal family.