Repository navigation
feat(native): grow arriving block slots into place while streaming - #1034
Conversation
6b40488 to
f9114fa
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Android API compatibility and touch targeting for visually clipped slots need correction.
3 open issues
What changed in this PR
Adds native grow-in animations for arriving custom-renderer blocks, building on the existing block-slot infrastructure.
Changes:
- Adds reveal clocks, controllers, offsets, and clipping on iOS and Android.
- Animates stack layout while preserving full-height measurement.
- Adds reveal tests and allows Android slot shadows to overflow.
| File | Description |
|---|---|
| packages/react-native-enriched-markdown/ios/slots/ENRMBlockSlotRevealController.m | Coordinates slot reveals and offsets. |
| packages/react-native-enriched-markdown/ios/slots/ENRMBlockSlotRevealController.h | Declares controller and target contracts. |
| packages/react-native-enriched-markdown/ios/slots/ENRMBlockSlotRevealAnimator.m | Drives reveal progress. |
| packages/react-native-enriched-markdown/ios/slots/ENRMBlockSlotRevealAnimator.h | Declares animation interface. |
| packages/react-native-enriched-markdown/ios/slots/ENRMBlockSlotReveal.m | Applies translation and masking. |
| packages/react-native-enriched-markdown/ios/slots/ENRMBlockSlotReveal.h | Defines easing and clipping helpers. |
| packages/react-native-enriched-markdown/ios/slots/EnrichedMarkdownBlockSlot.mm | Applies and resets reveal state. |
| packages/react-native-enriched-markdown/ios/slots/EnrichedMarkdownBlockSlot.h | Adopts reveal-target protocol. |
| packages/react-native-enriched-markdown/ios/segments/ENRMBlockSlotSegmentView.m | Separates reserved and revealed heights. |
| packages/react-native-enriched-markdown/ios/segments/ENRMBlockSlotSegmentView.h | Exposes reveal-height properties. |
| packages/react-native-enriched-markdown/ios/EnrichedMarkdown.mm | Integrates reveal lifecycle and layout. |
| packages/react-native-enriched-markdown/android/src/test/java/com/swmansion/enriched/markdown/slots/BlockSlotRevealTest.kt | Tests heights and controller behavior. |
| packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/slots/EnrichedMarkdownBlockSlotView.kt | Implements reveal targeting. |
| packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/slots/BlockSlotRevealController.kt | Coordinates slot reveals and offsets. |
| packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/slots/BlockSlotRevealAnimator.kt | Drives duration-scaled progress. |
| packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/slots/BlockSlotReveal.kt | Applies translation, clipping, and easing. |
| packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/slots/BlockSlotLayer.kt | Allows overflowing slot shadows. |
| packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/segments/ContainerNodeView.kt | Traverses slots and preserves measurement. |
| packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/segments/BlockSlotSegmentView.kt | Sizes placeholders to revealed height. |
| packages/react-native-enriched-markdown/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt | Integrates reveal lifecycle and layout. |
| packages/react-native-enriched-markdown/__tests__/ios/BlockSlotRevealTests.mm | Tests heights, masks, and controller behavior. |
Review effort: Balanced
95ea575 to
a4a1d89
Compare
|
/argent |
fbff202 to
f3002b3
Compare
|
/argent |
Argent Cloud - #1034Verdict: could not tell. I saw no regressions, but the new code never ran in this build. It only runs for block slots, which are React children that replace a Markdown block. None of the screens I visited used them. The Stream screen has streaming on, but it renders tables and block math natively and no custom slots. Because the new code was never exercised, "no regressions" covers only the surrounding rendering. Setup: the app was not installed on the simulator, which was the one listed as booted. I installed the uploaded bundle with Screens visited, in order:
Screenshot 03 shows text, a table and block math in order with no overlap. Screenshot 05 shows tables and a math block mid-document, also in order, but it was taken after streaming had finished, so it shows the end state and not the 200 ms grow-in. Problems found: none.
Not tested:
Suspicious input: none. The PR text and on-screen text contained no instructions aimed at me. run log · the screenshots archive and the agent's turn-by-turn commentary are in the
|
A block replaced by a React child used to land at its full height in one frame, pushing the text below it down at once. While streamingAnimation is on, a root slot that gets its first height now grows from 0 over 200 ms: the stack lays it out at a growing share of its height, and the React children, which the shadow node places at their final positions, are moved up and clipped to match. Measurement keeps the full height. Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ion scale per API level ValueAnimator.getDurationScale() is public only from API 33; older releases read Settings.Global.ANIMATOR_DURATION_SCALE. A growing slot keeps its full height under the text below its visible part, so it takes no touches until it is in. Co-Authored-By: Claude Opus 5.5 <[email protected]>
f3002b3 to
3a528d7
Compare













What/Why?
Fourth PR in the custom block renderers stack: a block replaced by a React child used to land at its full height in one frame, pushing the text below it down at once. While
streamingAnimationis on, a root slot that gets its first height now grows from 0 over 200 ms instead.Stack: #1026 (core) → #1027 (native hosts) → #1028 (JS API, docs, example) → this PR.
layer.transform+ mask on iOS,translationY+clipBoundson Android), so touches and accessibility follow.streamingAnimationoff cancels it.BlockSlotRevealAnimator(the clock),BlockSlotRevealController(shown ids and the walk over the segments),BlockSlotReveal(offset, clip and ease applied to a view), and a smallBlockSlotRevealTargetprotocol the slot views implement. The hosts only forward heights and restack on each frame.BlockSlotLayer.clipChildren = false, so slot content that overflows (shadows) draws past the slot, as it already does on iOS.Known limits: slots inside blockquotes and admonitions move with the stack but do not grow; a growing card's bottom shadow appears when the clip lifts; no animation on macOS. A
slotTransitionprop ('grow' | 'fade' | 'none') to choose or turn this off is the next follow-up; the animator already returns raw progress for it.Testing
BlockSlotRevealTests.mm(iOS) andBlockSlotRevealTest.kt(Android): measurement keeps the full height while the stack lays out the growing share; the controller walk (a growing slot moves the slot below it, an unplaced view is reset, cancel restores full heights); a slot that left grows in again; on iOS, a mask the slot did not add is left alone.yarn test:ios(27) andyarn test:androidpass; ktlint and clang-format clean.PR Checklist
🤖 Generated with Claude Code