Skip to content

Make layout tokens customisable via Appearance.tokens#4114

Open
laevandus wants to merge 3 commits into
developfrom
add/layout-token-customisation
Open

Make layout tokens customisable via Appearance.tokens#4114
laevandus wants to merge 3 commits into
developfrom
add/layout-token-customisation

Conversation

@laevandus
Copy link
Copy Markdown
Contributor

@laevandus laevandus commented May 27, 2026

🔗 Issue Links

IOS-1728

🎯 Goal

Let integrators customise the SDK's layout tokens (radii, padding, sizing, elevation) by overriding values on Appearance.tokens.

📝 Summary

  • Convert the public layout tokens on Appearance.DesignSystemTokens from read-only computed properties to settable public lazy var, so individual values can be overridden.
  • Group the tokens with // MARK: - section headers (Button, Composer, Dark, Device, Icon, Light, Message, Radius, Spacing), matching Appearance.ColorPalette.

🛠 Implementation

  • DesignSystemTokens is already a @MainActor public final class. Switching the layout tokens from computed var { … } to lazy var = … keeps each default (which references foundation constants or other tokens) while making them assignable — e.g. Appearance.default.tokens.messageBubbleRadiusAttachment = 20. lazy is required because the defaults reference other instance members.
  • Reads are unchanged, so the change is additive and source-compatible; the grouping is comment-only.
  • These tokens are generated upstream in the design-system-tokens repo; the generator was updated with the same lazy var + grouping change so future regenerations stay in sync.

🎨 Showcase

N/A — no visual change; this exposes customisation points.

🧪 Manual Testing Notes

Override a token before first use and confirm the UI reflects it, e.g. set Appearance.default.tokens.messageBubbleRadiusAttachment = 0 and observe attachment bubble corners become square.

☑️ Contributor Checklist

  • I have signed the Stream CLA (required)
  • This change should be manually QAed
  • Changelog is updated with client-facing changes
  • Changelog is updated with new localization keys
  • New code is covered by unit tests
  • Documentation has been updated in the docs-content repo

Summary by CodeRabbit

  • New Features
    • Layout tokens (radii, padding, sizing, elevation, icons, spacing, and related UI measurements) are now customizable via Appearance.tokens, enabling easier visual theming and layout adjustments.
  • Documentation
    • CHANGELOG updated with an “Upcoming” entry noting the new customizable layout tokens.

Review Change Stack

laevandus added 2 commits May 27, 2026 15:57
Convert the public Chat layout tokens in DesignSystemTokens from read-only computed properties to settable public lazy var, matching the customisation pattern of colorPalette/fonts/images on Appearance. Consumers can now override individual tokens, e.g. Appearance.default.tokens.messageBubbleRadiusAttachment = 20.

Refs IOS-1728
@laevandus laevandus requested a review from a team as a code owner May 27, 2026 13:11
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 71989e78-df05-4f8d-90b8-5f155ccaf755

📥 Commits

Reviewing files that changed from the base of the PR and between 2deaff6 and f4ab229.

📒 Files selected for processing (1)
  • CHANGELOG.md
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

📝 Walkthrough

Walkthrough

This PR converts design token properties in Appearance.DesignSystemTokens from computed properties to lazy-initialized stored properties, reorganizes them under themed MARK sections, and updates the changelog to state layout tokens are customizable via Appearance.tokens.

Changes

Design Token Properties Refactoring

Layer / File(s) Summary
Token property conversion and customization documentation
Sources/StreamChatCommonUI/Appearance+DesignTokens.swift, CHANGELOG.md
Token properties change from public var <name>: <Type> { <constant> } computed getters to public lazy var <name>: <Type> = <constant> stored initializers, reorganized under themed MARK sections (Button, Composer, Dark/Light elevations, Device, Icon, Message bubble radii, Radius, Spacing). Changelog entry documents that custom layout tokens are now exposed via Appearance.tokens.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • martinmitrevski

Poem

🐰 I nibble tokens, snug and neat,
From computed hops to lazy seat,
Sections reordered, values stay,
Appearance.tokens paves the way.
A tiny change, a happier beat.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title directly describes the main change: converting layout tokens to customizable properties via Appearance.tokens.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch add/layout-token-customisation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@laevandus laevandus force-pushed the add/layout-token-customisation branch from 2deaff6 to f4ab229 Compare May 27, 2026 13:21
@Stream-SDK-Bot
Copy link
Copy Markdown
Collaborator

SDK Performance

target metric benchmark branch performance status
MessageList Hitches total duration 10 ms 51.74 ms -417.4% 🔽 🔴
Duration 2.6 s 2.55 s 1.92% 🔼 🟢
Hitch time ratio 4 ms per s 20.28 ms per s -407.0% 🔽 🔴
Frame rate 75 fps 77.49 fps 3.32% 🔼 🟢
Number of hitches 1 5.0 -400.0% 🔽 🔴

@github-actions
Copy link
Copy Markdown

Public Interface

 @MainActor public final class DesignSystemTokens  
-   public var buttonHitTargetMinHeight: CGFloat
+   public lazy var buttonHitTargetMinHeight: CGFloat
-   public var buttonHitTargetMinWidth: CGFloat
+   public lazy var buttonHitTargetMinWidth: CGFloat
-   public var buttonPaddingXIconOnlyLg: CGFloat
+   public lazy var buttonPaddingXIconOnlyLg: CGFloat
-   public var buttonPaddingXIconOnlyMd: CGFloat
+   public lazy var buttonPaddingXIconOnlyMd: CGFloat
-   public var buttonPaddingXIconOnlySm: CGFloat
+   public lazy var buttonPaddingXIconOnlySm: CGFloat
-   public var buttonPaddingXIconOnlyXs: CGFloat
+   public lazy var buttonPaddingXIconOnlyXs: CGFloat
-   public var buttonPaddingXWithLabelLg: CGFloat
+   public lazy var buttonPaddingXWithLabelLg: CGFloat
-   public var buttonPaddingXWithLabelMd: CGFloat
+   public lazy var buttonPaddingXWithLabelMd: CGFloat
-   public var buttonPaddingXWithLabelSm: CGFloat
+   public lazy var buttonPaddingXWithLabelSm: CGFloat
-   public var buttonPaddingXWithLabelXs: CGFloat
+   public lazy var buttonPaddingXWithLabelXs: CGFloat
-   public var buttonPaddingYLg: CGFloat
+   public lazy var buttonPaddingYLg: CGFloat
-   public var buttonPaddingYMd: CGFloat
+   public lazy var buttonPaddingYMd: CGFloat
-   public var buttonPaddingYSm: CGFloat
+   public lazy var buttonPaddingYSm: CGFloat
-   public var buttonPaddingYXs: CGFloat
+   public lazy var buttonPaddingYXs: CGFloat
-   public var buttonRadiusFull: CGFloat
+   public lazy var buttonRadiusFull: CGFloat
-   public var buttonRadiusLg: CGFloat
+   public lazy var buttonRadiusLg: CGFloat
-   public var buttonRadiusMd: CGFloat
+   public lazy var buttonRadiusMd: CGFloat
-   public var buttonRadiusSm: CGFloat
+   public lazy var buttonRadiusSm: CGFloat
-   public var buttonVisualHeightLg: CGFloat
+   public lazy var buttonVisualHeightLg: CGFloat
-   public var buttonVisualHeightMd: CGFloat
+   public lazy var buttonVisualHeightMd: CGFloat
-   public var buttonVisualHeightSm: CGFloat
+   public lazy var buttonVisualHeightSm: CGFloat
-   public var buttonVisualHeightXs: CGFloat
+   public lazy var buttonVisualHeightXs: CGFloat
-   public var composerRadiusFixed: CGFloat
+   public lazy var composerRadiusFixed: CGFloat
-   public var composerRadiusFloating: CGFloat
+   public lazy var composerRadiusFloating: CGFloat
-   public var darkElevation1: BoxShadow
+   public lazy var darkElevation1: BoxShadow
-   public var darkElevation2: BoxShadow
+   public lazy var darkElevation2: BoxShadow
-   public var darkElevation3: BoxShadow
+   public lazy var darkElevation3: BoxShadow
-   public var darkElevation4: BoxShadow
+   public lazy var darkElevation4: BoxShadow
-   public var deviceRadius: CGFloat
+   public lazy var deviceRadius: CGFloat
-   public var deviceSafeAreaBottom: CGFloat
+   public lazy var deviceSafeAreaBottom: CGFloat
-   public var deviceSafeAreaTop: CGFloat
+   public lazy var deviceSafeAreaTop: CGFloat
-   public var iconSizeLg: CGFloat
+   public lazy var iconSizeLg: CGFloat
-   public var iconSizeMd: CGFloat
+   public lazy var iconSizeMd: CGFloat
-   public var iconSizeSm: CGFloat
+   public lazy var iconSizeSm: CGFloat
-   public var iconSizeXs: CGFloat
+   public lazy var iconSizeXs: CGFloat
-   public var iconStrokeDefault: CGFloat
+   public lazy var iconStrokeDefault: CGFloat
-   public var iconStrokeEmphasis: CGFloat
+   public lazy var iconStrokeEmphasis: CGFloat
-   public var iconStrokeSubtle: CGFloat
+   public lazy var iconStrokeSubtle: CGFloat
-   public var lightElevation1: BoxShadow
+   public lazy var lightElevation1: BoxShadow
-   public var lightElevation2: BoxShadow
+   public lazy var lightElevation2: BoxShadow
-   public var lightElevation3: BoxShadow
+   public lazy var lightElevation3: BoxShadow
-   public var lightElevation4: BoxShadow
+   public lazy var lightElevation4: BoxShadow
-   public var messageBubbleRadiusAttachment: CGFloat
+   public lazy var messageBubbleRadiusAttachment: CGFloat
-   public var messageBubbleRadiusAttachmentInline: CGFloat
+   public lazy var messageBubbleRadiusAttachmentInline: CGFloat
-   public var messageBubbleRadiusGroupBottom: CGFloat
+   public lazy var messageBubbleRadiusGroupBottom: CGFloat
-   public var messageBubbleRadiusGroupMiddle: CGFloat
+   public lazy var messageBubbleRadiusGroupMiddle: CGFloat
-   public var messageBubbleRadiusGroupTop: CGFloat
+   public lazy var messageBubbleRadiusGroupTop: CGFloat
-   public var messageBubbleRadiusTail: CGFloat
+   public lazy var messageBubbleRadiusTail: CGFloat
-   public var radius2xl: CGFloat
+   public lazy var radius2xl: CGFloat
-   public var radius3xl: CGFloat
+   public lazy var radius3xl: CGFloat
-   public var radius4xl: CGFloat
+   public lazy var radius4xl: CGFloat
-   public var radiusLg: CGFloat
+   public lazy var radiusLg: CGFloat
-   public var radiusMax: CGFloat
+   public lazy var radiusMax: CGFloat
-   public var radiusMd: CGFloat
+   public lazy var radiusMd: CGFloat
-   public var radiusNone: CGFloat
+   public lazy var radiusNone: CGFloat
-   public var radiusSm: CGFloat
+   public lazy var radiusSm: CGFloat
-   public var radiusXl: CGFloat
+   public lazy var radiusXl: CGFloat
-   public var radiusXs: CGFloat
+   public lazy var radiusXs: CGFloat
-   public var radiusXxs: CGFloat
+   public lazy var radiusXxs: CGFloat
-   public var spacing2xl: CGFloat
+   public lazy var spacing2xl: CGFloat
-   public var spacing3xl: CGFloat
+   public lazy var spacing3xl: CGFloat
-   public var spacingLg: CGFloat
+   public lazy var spacingLg: CGFloat
-   public var spacingMd: CGFloat
+   public lazy var spacingMd: CGFloat
-   public var spacingNone: CGFloat
+   public lazy var spacingNone: CGFloat
-   public var spacingSm: CGFloat
+   public lazy var spacingSm: CGFloat
-   public var spacingXl: CGFloat
+   public lazy var spacingXl: CGFloat
-   public var spacingXs: CGFloat
+   public lazy var spacingXs: CGFloat
-   public var spacingXxs: CGFloat
+   public lazy var spacingXxs: CGFloat
-   public var spacingXxxs: CGFloat
+   public lazy var spacingXxxs: CGFloat

@Stream-SDK-Bot
Copy link
Copy Markdown
Collaborator

SDK Size

title develop branch diff status
StreamChat 6.85 MB 6.85 MB 0 KB 🟢
StreamChatUI 4.25 MB 4.25 MB 0 KB 🟢
StreamChatCommonUI 0.8 MB 0.84 MB +41 KB 🟢

@Stream-SDK-Bot
Copy link
Copy Markdown
Collaborator

StreamChatCommonUI XCSize

Object Diff (bytes)
Appearance+DesignTokens.o +20091

@sonarqubecloud
Copy link
Copy Markdown

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.

4 participants