Skip to content

feat: ListItem, the read-only row of the List family — implements nuri-com/nuri-design-system#240 - #241

Merged
darioaschero merged 2 commits into
mainfrom
claude/list-item-c25ec6
Nov 10, 2026
Merged

darioaschero merged 2 commits into
mainfrom
claude/list-item-c25ec6

Conversation

@darioaschero

Copy link
Copy Markdown
Collaborator

Implements #240: ListItem / nuri-list-item, the read-only row of the List family, as admitted in the decision record. The admission used the sole-architect exception, with an independent review. This PR does not close the issue: Done needs independent verification and the native residue below.

The contract as built

  • Slots. Each slot is singular and renders in the order the author writes it, through the shared classifier:
    • textMuted: sm, muted, one line, truncated;
    • text: md emphasis, one line, truncated, stack.fill: 'shrink', required: true;
    • textSuffix: md, muted, one line, stack.fill: 'hug'.
  • Anatomy. text and textSuffix sit in an internal line row (gap xs). The line sits inside a content column (gap xs, grow-shrink) with textMuted.
  • Root. A view row with paddingX: 'md', paddingY: 'sm' and minHeight: 'xl' (60).
  • Nothing else. No axes, no behaviour, no themeScope. ListItemProps is { children?: React.ReactNode }. The frozen schema and the Guard F pin are unchanged.

What changed

Spec

  • packages/spec/components/list-item.ts (new). The header records the 60 exception, the separator dependency, the screen's 6 above and below, no mixing, and the rule on identifiers.
  • The list.ts, list-action.ts and list-switch.ts headers name the rows of the family. The "every list row" floor comments now say "every pressable list row" and name the list-item exception. These are comments only.
  • @nuri/spec exports ./descriptors/list-item.

Codegen and guards

  • scripts/parsers/descriptors.js roster.
  • docs-drift.test.js EXPECTED_DESCRIPTORS gains list-item (parts content · textMuted · line · text · textSuffix, no interactive). The Guard F pin does not move.
  • naming, component-api, no-unused-exports, spec-agnosticism and recipes needed no edit: they derive from the roster and pass.
  • Regenerated: rn/generated/components/list-item.ts (new) and index.ts, rn/generated/data/recipes.ts (+ list-item), and the prototype/generated/descriptors/list-item.js twin (new).
  • The list-action.js and list-switch.js twins change in comments only, because the twin carries the descriptor body.
  • Only the descriptor twins, recipes.ts and the RN adapters walk the roster (scripts/tokens-parser.js). Palette, tokens, icons and CSS are untouched.

RN

  • The barrel exports ListItem, ListItemTextMuted, ListItemText, ListItemTextSuffix and their Props, and public-surface.test.ts lists them.
  • Type tests:
    • keyof ListItemProps is exactly 'children', and each slot's props are exactly 'children';
    • @ts-expect-error on onPress, disabled, accessibilityLabel, accent, a scalar text, and ListItemText without children.
  • render-smoke:
    • the 60 row, the content column and the line row are asserted by geometry on host nodes;
    • there is no pressable host, role, accessible or onPress inside the rows;
    • type and truncation per text;
    • value-first and suffix-first order (a reversed group, and a reversed line);
    • requires Text, and a repeated slot fails as singular;
    • one new snapshot. The existing snapshots (List, ListAction, ListSwitch, ListSeparator) are unchanged: the .snap diff is +242 / −0.

Web

  • prototype/recipes/list-item.js (new), imported by recipes/list.js and the playground bundle.
  • factory.test.js C13–C13d mirror the RN block on the web factory path:
    • no button, role, tabindex, wash or aria-label;
    • the row, content and line attributes;
    • value-first and suffix-first order;
    • required and singular.
  • Legacy: packages/prototype/legacy/components/list-item/ is pruned, as icon-button and tab-bar were before it. legacy/README.md (the table and the "Pruned" note) is updated. <nuri-list-item> is now defined once, by defineNuriComponent in the active recipe. The frozen legacy pages that mention the old tag stay as read-only specs.

Playground

  • pages/component/list-item.html (new), with its card in component/index.html. Three boards: the review rows, identifiers and expiry, and a long value with a long label.
  • pages/operation.html, the six review sheets (boards 2, 5, 7, 9, 12, 14):
    • 16 rows, 10 suffixes and 10 separators move to nuri-list-item inside nuri-list, with a nuri-list-separator between rows;
    • the column drops padding-x="lg", adds padding-top="sm", and moves padding-bottom from lg to xl;
    • the misfit-log line is closed ("resolved: … · none", the feat: six icon glyphs + nuri mark at 22/32 — implements nuri-com/nuri-design-system#230 #236 convention).
    • Nothing else on the page changes. The board comments still say "rows 72", because they describe send-wip.html round 21 (history).

Expo demo

  • src/sheets/ActivitySheet.tsx gains a read-only "Processing" list: three ListItems with suffixes, in their own List, inside View paddingY="sm". It is not mixed with the ListAction lists.

Doc

  • harness/shell.js nav and pipeline/component-api-ir.js:
    • the new list-item page (nav 28) carries the doc rules from the decision record: read-only, never an action; authored order, value first then suffix; a short suffix; identifiers abbreviated with the ellipsis in the middle; 60 and 3 against ListAction's 72 and 0; separators and the screen's 6; no mixing; singular slots against ListAction's repeatable ones;
    • the List page gains a lead naming the three rows.
  • pipeline/docs-drift.test.js pins both pages. Regenerated generated/components/list.md and list-item.md.
  • pipeline/docs.js NAV_ORDER is not touched: the IR's nav wins, as for list-switch.

Admission ledger

Verification

The 5 gates, run locally as in gates.yml, on the committed tree:

Gate Commands Result
spec node --test scripts/*.test.js · node scripts/tokens-parser.js · git diff --exit-code packages/rn/generated packages/prototype/generated 128 pass · 0 fail · re-emit clean
prototype npm test -w @nuri/prototype · npm run build -w @nuri/prototype · git diff --exit-code packages/prototype/styles/ · npm run build -w @nuri/playground · git diff --exit-code packages/playground/generated/ 134 pass · 0 fail · clean · clean
doc npm test -w @nuri/doc · npm run build -w @nuri/doc · git diff --exit-code packages/doc/generated/ 3 pass · clean
rn npm test -w @nuri/rn · npm run typecheck -w @nuri/rn 21 suites · 312 tests · 27 snapshots pass · tsc exit 0
expo-demo npm run typecheck -w @nuri/expo-demo tsc exit 0
  • Determinism. Root npm run build twice. The 90 files under rn/, prototype/, playground/ and doc/generated are hash-identical (sha256 of all files 47bc4a8f…). git status is clean afterwards.
  • Mutation check. Setting content's gap to sm in the descriptor fails one RN test (render-smoke) and one web test (C13). The change was reverted.

Geometry on web, measured by probe in the iPhone SE frame (375×667), on all six operation.html review boards:

  • rows are 60, split 7.9 / 3 / 7.9;
  • hairlines are at y 425 and 498 (one at 498 on the two-row boards) and span x 18–357;
  • text is 13.9 from each hairline, above and below;
  • the label's x is 18, the same as the hairline's;
  • the suffix sits 3 after the value;
  • sheet tops are 281 (boards 2, 5, 7, 9) and 354 (boards 12, 14);
  • the button is at 589–649 and nothing scrolls.

Against main. The same probe on main@0cbb776's page gives the same tops, hairlines, gaps and button. All 48 measured items (texts, separators, buttons) keep position, colour, weight and size. The only difference is that label boxes now stretch to the content width (339) instead of hugging, the same as list-action's align: stretch, and the glyphs don't move. Board 7's screenshot is byte-identical to main's. A guarded capture confirmed that the baseline page had the 16 hand rows and the new page has the 16 nuri-list-items.

Long values, web.

  • On the component page, the value box is narrower than its natural width and ends with an ellipsis. The suffix keeps its natural width (flex: 0 0 auto), sits 3 after the value, and ends at the line's end.
  • The long label truncates on its own line.

RN-web (Expo web preview, ActivitySheet, 375×667):

  • rows are 60 at 7.9 / 3 / 7.9, with tops 73 apart and hairlines at x 18–357 every 73;
  • text x is 18 and the suffix sits 3 after the value;
  • the content column (gap 3, grow and shrink) and the line row (gap 3) are present in the DOM;
  • no role and no tabindex on the row, content, line or texts;
  • with a long value, the value truncates (245.5 of 378.2, with an ellipsis) and the suffix keeps its text width (90.5) and its 3 gap;
  • no console errors.

Evidence in docs/evidence/list-item/:

  • web-operation-review-boards-{light,dark}.png: the six sheets;
  • web-operation-board7-pixel-identical-to-main.png;
  • web-component-list-item-{light,dark}.png;
  • rn-web-activity-sheet-{light,dark}.jpg;
  • rn-web-long-value-probe.jpg.

Native-only residue, for the operator

These can't be proven in-session (on a device or simulator):

  1. VoiceOver (iOS) and TalkBack (Android) read the row's texts one by one, in screen order, with no stop on the row itself, as in today's composition. The suffix-first case reads suffix, then value.
  2. Android truncation. With a long value, the value ellipsizes and the suffix stays whole and 3 after it (the hug → alignSelf: flex-start / maxWidth: 100% path). Also check a short value: no flexGrow inflation.
  3. Large text (Dynamic Type / font scale): the row grows past 60 without clipping, and both lines stay one line each and truncate.
  4. Optional: the ActivitySheet rows on device, light and dark.

Not done here

  • The real-consumer nuri-com/nuri-expo PR is attached during Verification/Done.
  • The independent verification is a separate session.
  • The merge is the operator's.

🤖 Generated with Claude Code

darioaschero and others added 2 commits November 9, 2026 22:23
Implements the contract admitted in
#240 (comment)
(sole-architect exception, independent review at #issuecomment-6744184207).

Spec
- components/list-item.ts: three singular text slots in authored order —
  textMuted (sm muted), text (md emphasis, required, fill shrink),
  textSuffix (md muted, fill hug) — inside an internal `content` column
  (gap xs) and `line` row (gap xs); root row paddingX md, paddingY sm,
  minHeight xl (60). No axes, no behaviour, no props beyond children.
  The frozen schema and the Guard F pin are unchanged.
- list.ts / list-action.ts / list-switch.ts: header comments name the
  three rows; "every list row" reworded for the recorded 60 exception.

Codegen and guards
- descriptors.js roster + spec exports; regenerated the RN adapter,
  recipes.ts, the components index and the web twin (list-action and
  list-switch twins change in comments only).
- docs-drift EXPECTED_DESCRIPTORS pins list-item's shape.

RN
- barrel exports ListItem, ListItemTextMuted, ListItemText,
  ListItemTextSuffix (+ Props); public-surface roster; exact-type
  fixtures (keyof ListItemProps = 'children'; no onPress, disabled,
  accessibilityLabel or accent).
- render-smoke: structure by geometry on host nodes (60 row, content
  column, line row), no pressable/role/accessible host, value-first and
  suffix-first order, required Text and singular slots.

Web
- recipes/list-item.js (+ list.js import, playground bundle).
- factory tests C13–C13d mirror the RN block on the web factory path.
- legacy components/list-item/ pruned; legacy/README.md updated, so
  <nuri-list-item> is defined once.

Playground
- pages/component/list-item.html (+ index card).
- operation.html: the six review sheets (boards 2, 5, 7, 9, 12, 14) use
  nuri-list-item inside nuri-list with nuri-list-separator between rows;
  the column drops padding-x lg, adds padding-top sm, padding-bottom
  lg → xl; the misfit-log line is closed. Nothing else on the page moves.

Expo demo
- ActivitySheet gains a read-only "Processing" list.

Doc
- shell nav, component-api-ir (List lead names the three rows; the
  list-item lead carries the admitted doc rules), doc drift pins,
  generated list.md and list-item.md.

Evidence under docs/evidence/list-item/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
prompts/admission-list-item.md is the amended #240 record (it matches the
issue body), with its title and a status paragraph set to: Admitted
(sole-architect exception) · Ready · implemented in
#241, independent verification pending.
The #232 precedent: the admission ledger flips in the implementing PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@darioaschero

Copy link
Copy Markdown
Collaborator Author

Independent verification · #241 against the #240 decision record

This is the independent verification that docs/design-system-admission.md requires after implementation. It ran in a fresh session that had no part in drafting the request, the review or the implementation. It approves nothing, requests no changes and records no outcome: the operator merges.

Inputs. I used only these:

I did not read the implementer's notes or use the PR body as proof. I read only the status line of prompts/admission-list-item.md.

Head verified: 77478c1 (detached checkout of pull/241/head, based on main@0cbb776). Every check below was re-run on it.

Result.

  • Every acceptance criterion that can be checked in-session is met.
  • No anti-scope item is breached.
  • The mutation test kills the order tests on both render paths.
  • Nothing failed in the PR's own scope. Two environment problems that predate this PR are listed under "Could not check / caveats".

Acceptance criteria

# Criterion Result Evidence
1 <ListItem> / <nuri-list-item> render from the descriptor on both targets; no hand-authored platform strings; mechanical names Met RN adapter: renderDescriptorInstance({ descriptor: listItemDescriptor, recipe: recipes["list-item"] }), names from nuriNames('list-item').rn. Web: defineNuriComponent(listItemDescriptor, nuriNames('list-item').web). Rendered from nuri-list-item / -text-muted / -text / -text-suffix in the browser, and as ListItem / ListItemTextMuted / ListItemText / ListItemTextSuffix on RN-web and in the RN test renderer.
2a 60 floor, md sides, sm above and below, 3 between the lines Met (web, RN-web, RN tests) Descriptor: minHeight: 'xl', paddingX: 'md', paddingY: 'sm'; content has gap: 'xs'. Baked RN recipe: minHeight 60, paddingHorizontal 12, paddingVertical 6, gap 3. Measured: 60 tall, split 7.9 / 3 / 7.9, on all 16 web rows and 3 RN-web rows (tables below).
2b Label sm muted, value md emphasis, in authored order Met Label 14.5px, weight 400, rgb(102,100,85); value 17px, weight 600, rgb(34,32,19); suffix 17px, weight 400, muted. Same on web and RN-web. Order: see "Composition".
2c Suffix next to the value; it stays whole while the value truncates Met on web and RN-web · Android not checkable here Gap value→suffix is 3 everywhere. Long-value probes (below): the value is clipped with an ellipsis, and the suffix keeps exactly its natural width.
3 Not focusable, no wash, no tap response; screen readers read the texts in screen order Met structurally (web, RN-web, RN tests) · reading not checkable here Web: 0 of the page's 10 focusables sit inside a row; no role, tabindex or aria-label; background unchanged on pointerdown; DOM unchanged after click; cursor: auto. RN-web: rows have no role, tabindex or focusable. RN tests: no function style, accessibilityRole, accessible or onPress in a row. VoiceOver/TalkBack and Android focus are left for the operator.
4 Legacy recipe pruned, legacy/README.md updated, tag defined once Met legacy/components/list-item/ is gone (6 dirs left). README table and "Pruned" note updated. git grep finds one definition, packages/prototype/recipes/list-item.js:16. The remaining mentions are frozen legacy pages and comments, which the scope keeps as read-only specs.
5 Six operation.html sheets use nuri-list-item; misfit line closed; sheets measure as before Met 7 hunks: one in each of boards 2, 5, 7, 9, 12, 14, and the misfit line (L1932). 16 rows, 10 suffixes and 10 separators, with the texts carried over verbatim. Measurements equal main (table below).
6 list, list-action, list-switch, list-separator snapshots unchanged Met Snapshot file is +242 / −0: only the new ListItem snapshot is added. The 4 existing List / ListAction / ListSwitch snapshots are byte-identical and pass (27/27).
7 Full gate suite green incl. @nuri/doc; commands and output in the PR Met Re-run below. My counts match the PR's table. CI on the head: 5/5 SUCCESS.
8 Status line flipped in the same PR Met (see note) Line 1 of prompts/admission-list-item.md (commit 77478c1, this PR): "ADMITTED … · Ready · IMPLEMENTED in PR #241, independent verification pending". The file is new here, in the prompts/admission-*.md pattern. The issue body itself carries no status line.

Anti-scope

Item Result Evidence
No change to list, list-action, list-switch, list-separator beyond header comments; no schema change Held The spec diffs of list.ts, list-action.ts and list-switch.ts are header comments only. I imported the generated twins from main and from the head and ran deepStrictEqual on every export: the data is identical. The RN baked recipes keep their 15 keys identical, and list-item is added. The ListSeparator sources in rn/primitives, prototype/primitives and prototype/styles are untouched. schema.ts is byte-identical to main.
Guard F pin unchanged Held The only hunk in scripts/docs-drift.test.js is at L308 (the EXPECTED_DESCRIPTORS roster). The Guard F block (L505 on) is untouched.
No press, focus, wash, chevron, selection, copy or reveal Held The descriptor has no behaviour, no interactive and no palette.variant. The type-tests reject onPress, disabled, accessibilityLabel, accent and a scalar text (@ts-expect-error, tsc green). Probes: see AC 3.
No single-element reading; no textEnd; no avatar or trailing column Held Three text slots only (textMuted, text, textSuffix). No accessible, role or label on the row on either target.
No interactive descendants; no mono, weight option or wrapping Held All slots are kind: 'text', with axes: [] and lines: 1, flow: 'truncate' on every text.
text required; slots singular Held No slot is multiple, and text is required: true. RN throws "requires Text" and "… is singular"; web throws "requires text" and "is singular — it appears 2 times". It is the same mechanism as select-field and select-trigger.
fill: 'shrink' on text, 'hug' on textSuffix Held RN text: flexGrow 0, flexShrink 1, minWidth 0. RN textSuffix: flexShrink 0, alignSelf flex-start, maxWidth 100%. Web: data-fill="shrink" and "hug"; the suffix's computed flex is 0 0 auto.
No token, palette row or accent; no grouping container; no auto-inserted separators Held git diff --stat origin/main HEAD -- packages/spec/axes packages/spec/tokens is empty. list is data-identical, and separators are author-placed.
operation.html confined to the six sheets and their misfit line Held See AC 5.

Gates (re-run on the head after npm ci; the lockfile is unchanged against main)

Gate Commands Result
root npm run build · npm test build exit 0, tree clean. npm test exit 1: the only failure is packages/gen-ui/live.test.js (see caveats). Every other suite passes.
spec node --test scripts/*.test.js · node scripts/tokens-parser.js · git diff --exit-code packages/rn/generated packages/prototype/generated 128/128 · clean
prototype npm test -w @nuri/prototype · npm run build -w @nuri/prototype · git diff --exit-code packages/prototype/styles/ · npm run build -w @nuri/playground · git diff --exit-code packages/playground/generated/ 134/134 · clean · clean
doc npm test -w @nuri/doc · npm run build -w @nuri/doc · git diff --exit-code packages/doc/generated/ 3/3 · clean
rn npm test -w @nuri/rn · npm run typecheck -w @nuri/rn 21 suites, 312 tests, 27 snapshots · tsc exit 0
expo-demo npm run typecheck -w @nuri/expo-demo tsc exit 0
determinism (npm run build && npm run build -w @nuri/doc) twice sha256 of the 97 files under rn/generated, prototype/generated, prototype/styles, playground/generated and doc/generated is identical across the two builds (manifest 253e9e44…). git diff --exit-code is clean, so generated ≡ committed.

Composition and the mutation test

  • Tests on both render paths. RN render-smoke has ListItem — value-first and ListItem — suffix-first. The web factory/factory.test.js has C13b (value-first) and C13c (suffix-first). They assert the host children of content and line in order.
  • Mutation. In packages/spec/composition/classify.js I sorted the ordered plan by anatomy index before the singular check, so anatomy order beat authored order. I then regenerated, which copies the file to prototype/generated/composition-classify.js for web.
    • RN: value-first and suffix-first fail; the base and the required/singular tests pass.
    • Web: C13b and C13c are not ok; C13 and C13d are ok.
    • After the revert, all 4 pass on both paths and the tree is clean. The tests catch a broken order.

Rendered proof · web (iPhone SE, 375 × 667)

The PR head and git archive origin/main were each served statically. operation.html renders every board at data-device="iphone-se". Positions are relative to each device screen.

main (hand composition) #241
Rows 72, split 13.9 / 3 / 13.9 60, split 7.9 / 3 / 7.9 (all 16)
Row tops 353 · 426 · 499 359 · 432 · 505 (every 73)
Hairlines y 425, 498 (3-row sheets), 498 (2-row), x 18–357 identical
Text to hairline 13.9 above and below 13.9 above and below
Text x / hairline x 18 / 18 18 / 18
Suffix gap 3 3
Sheet top 281 (boards 2, 5, 7, 9) · 354 (12, 14) identical
Button 589–649 on all six identical
Sheet scrolls no no
  • Text rects. All 54 text nodes in the six sheets have the same x, y, height, colour, weight and font size on main and on the PR.
    • The only difference is the label box width: 339 in the PR, because content is align: 'stretch', against the text's own width on main. The glyphs start at the same x.
    • Board 7's From chip is at 239.4–275.4, so the sheet top at 281 is clear of it.
  • Structural parts. In every row, nuri-list-item > nuri-view (363 × 60) holds exactly one content column (339 × 44.2, data-gap="xs", data-fill="grow-shrink"). The column holds the label and the line row (339 × 21.9), and the line holds the value and the suffix.
  • Long value. In the DOM only, I appended a row to board 7's list with the value "₿ 22 450 000 … 000" and the suffix "€ 21.17". Then I removed it.
    • The value box is 286.1 wide and one line high (21.9; scrollHeight 44, -webkit-line-clamp: 1), and the ellipsis is drawn.
    • The suffix is 49.9 wide, the same as on the unmodified row, with scrollWidth = clientWidth.
    • The gap stays 3, the line ends at 357, and the row stays 60.
  • component/list-item.html. It renders 7 rows, all 60, each with content and line, including the long-value and long-label cases. The console has no errors.
  • Dark. With one board toggled, the label and suffix are rgb(183,180,164), the value rgb(240,238,227) and the hairline rgb(61,59,46), on rgb(18,17,11). The rows are still 60.

Rendered proof · RN-web (Expo web preview, iPhone SE, Menu → Activity Sheet, the new "Processing" list)

  • Rows are 60 at y 117.9, 190.9 and 263.9 (every 73), split 7.9 / 3 / 7.9, at x 6 and 363 wide.
  • Hairlines are at y 183.9 and 256.9, x 18–357. The text is at x 18, with 13.9 between the text and the hairline on both sides, and the suffix 3 after the value.
  • content (2 children, 44.2 tall) and line (a View, 21.9 tall) render.
  • There is no role, tabindex or focusable inside the rows.
  • Long value. I replaced the text of the "€ 12.00" Text in the DOM.
    • The value is 260.1 wide, with scrollWidth 482 > clientWidth 260, nowrap and an ellipsis.
    • The suffix "3433 Sats" stays at its natural 75.9, with flexShrink 0.
    • The gap stays 3, the line ends at 357, and the row stays 60.

Could not check / caveats

  • The Expo web bundle does not build at this head.
    • Metro fails on packages/rn/runtime/native-text-input-command.ts, which has a static require of react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent ("Importing react-native internals is not supported on web").
    • The PR does not touch that file; it was last changed in Codex/textfield native authoritative reconciler #196.
    • For the RN-web probe I added a local, uncommitted native-text-input-command.web.ts stub with the same exports as no-ops. The original already returns null when Platform.OS === 'web', so web behaviour is unchanged. I removed the stub afterwards.
    • This needs its own fix outside this PR.
  • packages/gen-ui/live.test.js fails in the root npm test. It is a live test that calls an external MCP endpoint. It is not in gates.yml, and the PR touches nothing in packages/gen-ui.
  • RN-web dark was not checked. The demo does not follow the system colour scheme, and its theme toggle sits behind the sheet. Web dark was checked.
  • Device rendering (iOS, Android) and screen-reader speech cannot be checked in-session.
  • The real-consumer proof (a nuri-com/nuri-expo PR that implements the Send review sheet from the playground link) is still open. It belongs to Verification/Done.
  • Not contract changes, recorded for completeness:
    • doc/generated/components/list.md gains one sentence naming ListItem and the no-mixing rule;
    • packages/spec/package.json gains the ./descriptors/list-item export that the generated RN adapter imports;
    • docs/evidence/list-item/ holds 8 screenshots, which I did not use as proof.

Native-only residue for the operator (device or simulator)

  • VoiceOver (iOS) and TalkBack (Android): each row's texts are read one by one in screen order (label, value, suffix), with no stop on the row itself, as in today's composition.
  • Android focus: a hardware keyboard or D-pad never lands on a ListItem row.
  • Android truncation: with a long value, the value ellipsizes and the suffix stays whole and is not pushed out. Check this on the textSuffix hug path (flexShrink 0) and the value's flexShrink 1 with minWidth 0.
  • Large text (Dynamic Type and Android font scale): the row grows past 60 without clipping, and the 3 gap and the hairline spacing hold.
  • Dark mode on the native build of the expo-demo Activity sheet.

@darioaschero
darioaschero merged commit c69488b into main Nov 10, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant