Skip to content

docs(native-list): add the shared style spec and drop dead web CSS - #107

Open
huhuanming wants to merge 1 commit into
codex/ok-50498-android-theme-iconsfrom
codex/native-list-style-spec
Open

huhuanming wants to merge 1 commit into
codex/ok-50498-android-theme-iconsfrom
codex/native-list-style-spec

Conversation

@huhuanming

Copy link
Copy Markdown
Contributor

What

P0 of the row-style work: establish the shared style vocabulary as a document, and clear the dead style overrides that would otherwise be copied forward.

No rendering values change in this PR.

Why

NativeList serves 13 row templates from one shared view pool per platform, and each template hard-codes its own typography and geometry in three separate renderers. Only market accepts a style object today; every other template is tuned by adding a presentation variant plus a branch in each renderer.

Two vocabularies have drifted far enough to be a problem on their own:

  • The package's theme keys and the application's design tokens are different names for the same colors — textprimaryText, textSubduedsecondaryText, borderSubduedseparator — and the application's iconActive maps onto the key named accent. Every consumer writes the mapping by hand.
  • The application has a named type scale ($bodyMd is used 2,418 times across the app, $bodySm 1,735, $bodyLg 791) while the list uses ten-plus bare font sizes and references the scale nowhere. "One step smaller" has no shared meaning between design and this component.

What is in docs/STYLE_SPEC.md

Section Contents
§2 How the spec is enforced: tokens resolve to numbers in validation.ts, so the native renderers never learn the vocabulary and cannot drift from it. Everything else is review.
§3 Color tokens aliased to the application's names; the type scale; spacing and radius bounds.
§4 The per-template style surface — 13 templates, keyed by model field rather than by view, with each platform's current value side by side.
§5 List chrome: separators, group radius, section index rail, pull to refresh, reorder preview.
§6 Registered divergences — recorded, not fixed.
§7 Four template isolation rules.
§8 Where the style pass belongs in each renderer.
§9 Review checklist.

Why keys are named after model fields

All three platforms share one view pool and the mapping is not one-to-one: metricCard renders its value through the title label and its title through the subtitle label; the status label carries rail.status, activity.status, message.time, and metricCard.trend. Naming style keys after views would mis-target. market already follows this rule with style.price / style.change.

Divergences registered, not changed

The row-height tables are deliberately left alone — the values may have been tuned per platform on real devices, and changing them without device verification would be guesswork:

Template iOS Android Web
rail 40 28 40
activity + footer actions 100 104 100
dataRow + secondary text 60 64 60
sectionHeader summary 68 80 68
sectionHeader value + checkbox 56 40 56

Also registered in §6:

  • Android draws sticky headers through a second renderer. StickySectionHeaderDecoration uses canvas.drawText with its own Paint, font sizes, hard-coded semibold typeface, height, inset, manual letter spacing and baseline math. iOS pins the real cell and Web reuses renderElement, so both inherit row styling for free.
  • Section headers carrying a value or a checkbox silently lose stickiness on Android only (isSimpleStickySectionHeader). Needs a product decision.
  • Source scale is list-wide on Android. usesSelectorSourceScale is computed with items.any { … }, so one selector row switches the sub-400dp metric system for the entire list.

Cleanup

Removed dead duplicated rules from WEB_LIST_CSS: four blocks were emitted twice and a prefers-reduced-motion block three times, and every property of the earlier copies was redeclared by the later ones, so removing them changes no rendering.

Deliberately not removed, documented in §6.4 instead — both look like duplication but are load-bearing:

  • .ok-native-list-account-action-row .ok-native-list-visual{border-radius:8px!important} — the !important overrides an inline radius written by createVisual. Removing it regresses the account action row to 10px.
  • .ok-native-list-market-change{color:#fff;background:#8d8d8d} — literals rather than tokens because --nl-inverse-text defaults to #fcfcfc and --nl-secondary to #6b7280. Swapping them changes untinted rendering.

Drive-by: src/__tests__/NativeList.web.test.ts was left unformatted by d91262e and failed eslint; prettier applied.

Base branch

Targets codex/ok-50498-android-theme-icons, not main — the react-native-native-list package does not exist on main.

Verification

  • jest — 5 suites, 68 tests, all pass
  • tsc -b — clean
  • eslint — clean (9 errors before the prettier fix, all pre-existing)

Next

P1 (contract plus Web implementation), P2 (iOS and Android), P3 (list chrome and an example page) follow as separate PRs. This spec is the input to all three.

🤖 Generated with Claude Code

Add docs/STYLE_SPEC.md as the style vocabulary for rows, section headers,
fixed footers, and empty states. The three renderers cannot constrain each
other, so the spec is authoritative by review plus the one boundary they
share: the serialized snapshot.

It records the design tokens aliased to the application's own token names,
the per-template style surface keyed by model field rather than by view
(metricCard renders its value through the title label, so view names
mis-target), list chrome, the template isolation rules, and a review
checklist.

Cross-platform divergences are registered, not changed: the three row-height
tables disagree (rail 40/28/40, sectionHeader summary 68/80/68), Android
draws sticky headers through a second renderer with its own typography,
section headers carrying a value or a checkbox silently lose stickiness on
Android, and source scale is computed list-wide.

Remove dead duplicated rules from WEB_LIST_CSS: four blocks were emitted
twice and a prefers-reduced-motion block three times, and every property of
the earlier copies was redeclared by the later ones, so removing them
changes no rendering. The two oddities that look like duplication are
load-bearing and are documented instead - the !important on the account
action row overrides an inline radius, and the market change chip's literal
colors do not equal their nearest tokens.

Also apply prettier to NativeList.web.test.ts, which was left unformatted by
d91262e and failed lint before this change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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