Skip to content

fix(egress-composite): adjust PaginatedGrid sizing#1966

Merged
jdimovska merged 16 commits intomainfrom
fix/egress-composite/paginated-grid-sizing-and-refactors
Apr 24, 2026
Merged

fix(egress-composite): adjust PaginatedGrid sizing#1966
jdimovska merged 16 commits intomainfrom
fix/egress-composite/paginated-grid-sizing-and-refactors

Conversation

@arnautov-anton
Copy link
Copy Markdown
Contributor

@arnautov-anton arnautov-anton commented Oct 18, 2025

💡 Overview

Ref: https://getstream.slack.com/archives/C090P1YS3U6/p1760375157855869

📝 Implementation notes

As a side-quest this PR refactors styling overrides and adds layers for easier CSS adjustments, removes clsx (in favour of cx from @emotion/css) and replaces decode from js-base64 with atob.

🎫 Ticket: https://linear.app/stream/issue/XYZ-123

📑 Docs: https://github.com/GetStream/docs-content/pull/1204

Summary by CodeRabbit

  • New Features

    • Grid layout size constraints: responsive participant sizing with improved two-up behavior and enforced 16:9 aspect ratio when enabled.
  • Chores

    • Removed unused dependencies and migrated classname composition to Emotion.
    • Consolidated styles into CSS layers and added local stylesheet to app entry.
    • Added a configurable size-constraints option and corresponding test updates.

@arnautov-anton arnautov-anton force-pushed the fix/egress-composite/paginated-grid-sizing-and-refactors branch 2 times, most recently from 08e2701 to a3f8662 Compare October 18, 2025 08:21
@arnautov-anton arnautov-anton marked this pull request as ready for review October 22, 2025 08:39
@arnautov-anton arnautov-anton force-pushed the fix/egress-composite/paginated-grid-sizing-and-refactors branch from a4d02bd to 1d46205 Compare November 3, 2025 09:07
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 15, 2026

⚠️ No Changeset found

Latest commit: 07ad427

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Added a data-group-size attribute to paginated grid groups; removed clsx/js-base64 deps and replaced clsx with Emotion cx; consolidated Emotion CSS into layered blocks and added layout.grid.size_constraints option with corresponding styles; switched JWT decode to atob; added global window typings; updated entry imports and tests.

Changes

Cohort / File(s) Summary
Core SDK
packages/react-sdk/src/core/components/CallLayout/PaginatedGridLayout.tsx
Add data-group-size attribute on each paginated-grid group container (data-group-size={group.length}).
App dependencies
sample-apps/react/egress-composite/package.json
Removed clsx and js-base64 from dependencies.
SCSS layering & imports
sample-apps/react/egress-composite/src/main.scss, .../CompositeApp.scss, .../components/LogoAndTitle.scss, .../layouts/.../*.scss, .../PaginatedGrid/PaginatedGrid.scss
Wrapped many styles in @layer blocks, imported SDK stylesheet into a named layer, and added size-constrained PaginatedGrid rules that reference data-group-size.
Class utility & styling hooks
sample-apps/react/egress-composite/src/CompositeApp.tsx, .../hooks/options/useGenericLayoutStyles.ts, useLogoAndTitleStyles.ts, useParticipantLabelStyles.ts, useParticipantStyles.ts, useVideoStyles.ts
Replaced clsx with cx from @emotion/css; consolidated multiple conditional css fragments into single @layer-wrapped css blocks and updated composed class usage.
Paginated grid & config
sample-apps/react/egress-composite/src/components/layouts/PaginatedGrid/PaginatedGrid.tsx, sample-apps/react/egress-composite/src/ConfigurationContext.tsx
Added optional layout.grid.size_constraints configuration (boolean); conditionally apply paginated-grid--size-constrained class; switched JWT payload decoding from decode (js-base64) to native atob.
Global types
sample-apps/react/egress-composite/src/global.d.ts
Added global Window augmentations: setupLayout(configuration: ConfigurationValue): void, call: Call, and client: StreamVideoClient.
Entry changes
sample-apps/react/egress-composite/src/main.tsx
Import local main.scss, removed SDK CSS import, and removed // @ts-expect-error`` suppression for window.setupLayout assignment.
Tests
sample-apps/react/egress-composite/tests/layouts.spec.ts
Switched tests to use cx; extended TestCase with optional options and added a test case enabling layout.grid.size_constraints.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hopped through layers, stitched classes with cx,
atob unwrapped tokens tucked in my trex,
grids learned to count groups—one, two, then more,
styles tucked in layers, neat like my store,
nibble the changes, a crunchy little fix 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(egress-composite): adjust PaginatedGrid sizing' accurately summarizes the main change—adjusting PaginatedGrid sizing—and is specific to the primary objective.
Description check ✅ Passed The description includes the required sections: Overview (with Slack reference), and Implementation notes covering refactoring details. However, it's missing explicit implementation details about what 'adjust sizing' means and how size constraints work.
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 fix/egress-composite/paginated-grid-sizing-and-refactors

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
packages/react-sdk/src/core/components/CallLayout/PaginatedGridLayout.tsx (1)

35-66: Consider memoizing PaginatedGridLayoutGroup for large participant lists.

This component renders within PaginatedGridLayout and iterates over participants. Wrapping it with React.memo could prevent unnecessary re-renders when parent state changes but props remain the same.

♻️ Optional: Add React.memo
-const PaginatedGridLayoutGroup = ({
+const PaginatedGridLayoutGroup = React.memo(function PaginatedGridLayoutGroup({
   group,
   mirror,
   VideoPlaceholder,
   PictureInPicturePlaceholder,
   ParticipantViewUI,
-}: PaginatedGridLayoutGroupProps) => {
+}: PaginatedGridLayoutGroupProps) {
   return (
     // ... component body unchanged
   );
-};
+});

As per coding guidelines: "Use React.memo for components rendered in large participant lists to optimize re-render performance"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-sdk/src/core/components/CallLayout/PaginatedGridLayout.tsx`
around lines 35 - 66, Wrap the PaginatedGridLayoutGroup component with
React.memo to avoid unnecessary re-renders when its props (group, mirror,
VideoPlaceholder, PictureInPicturePlaceholder, ParticipantViewUI) haven't
changed; locate the PaginatedGridLayoutGroup function and export (or assign) a
memoized version using React.memo(PaginatedGridLayoutGroup) so the component
only re-renders on prop changes while continuing to render ParticipantView for
each participant.sessionId as before.
sample-apps/react/egress-composite/src/hooks/options/useVideoStyles.ts (1)

17-37: Avoid emitting optional overrides with empty values.

This block is always generated, so unset options still serialize background-color / object-fit declarations with no value. Browsers will ignore them, but it makes the generated CSS harder to inspect and diverges from the conditional cx([...]) pattern already used in the sibling option hooks.

♻️ Possible cleanup
   const styles = [
-    css`
-      `@layer` overrides-layer {
-        & .str-video__video {
-          background-color: ${videoBackgroundColor};
-        }
-
-        & .str-video__video {
-          object-fit: ${typeof videoScaleMode === 'undefined'
-            ? undefined
-            : objectFitMap[videoScaleMode]};
-        }
-
-        & .str-video__video.str-video__video--screen-share {
-          object-fit: ${objectFitMap[videoScreenshareScaleMode]};
-        }
-      }
-    `,
+    videoBackgroundColor &&
+      css`
+        `@layer` overrides-layer {
+          & .str-video__video {
+            background-color: ${videoBackgroundColor};
+          }
+        }
+      `,
+    typeof videoScaleMode !== 'undefined' &&
+      css`
+        `@layer` overrides-layer {
+          & .str-video__video {
+            object-fit: ${objectFitMap[videoScaleMode]};
+          }
+        }
+      `,
+    css`
+      `@layer` overrides-layer {
+        & .str-video__video.str-video__video--screen-share {
+          object-fit: ${objectFitMap[videoScreenshareScaleMode]};
+        }
+      }
+    `,
   ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sample-apps/react/egress-composite/src/hooks/options/useVideoStyles.ts`
around lines 17 - 37, The generated CSS always emits empty
background-color/object-fit declarations; update useVideoStyles to only add the
corresponding css fragments when values are present: check videoBackgroundColor
before adding the block that sets background-color, check typeof videoScaleMode
!== 'undefined' (or presence) before adding the object-fit block that uses
objectFitMap[videoScaleMode], and check videoScreenshareScaleMode before adding
the screenshare object-fit block. Modify the styles array construction (where
css and cx are used) to push these conditional css snippets (or build separate
css calls) so undefined values are never serialized; keep using css, cx,
objectFitMap, videoScaleMode, videoScreenshareScaleMode, and
videoBackgroundColor to locate and change the code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@sample-apps/react/egress-composite/src/components/layouts/Spotlight/Spotlight.scss`:
- Line 12: Insert a blank line immediately above the single-line SCSS comment
"// max-width: unset;" in Spotlight.scss so there is an empty line before that
comment, which will satisfy the stylelint comment-spacing rule; locate the
comment text "// max-width: unset;" and add one empty line above it.

In `@sample-apps/react/egress-composite/src/components/LogoAndTitle.scss`:
- Around line 7-10: Remove the unexpected empty lines before the declarations in
LogoAndTitle.scss: open the selector/block that contains the width and height
properties (the lines with "width" and "height") and delete the blank lines
immediately preceding those declarations so the properties appear directly under
the selector with no empty lines between the selector and "width" and between
"width" and "height".

In `@sample-apps/react/egress-composite/src/CompositeApp.scss`:
- Around line 8-9: The typography block currently violates stylelint rules: add
a blank line before the declarations to satisfy declaration-empty-line-before
and normalize keyword casing for values to satisfy value-keyword-case;
specifically, in CompositeApp.scss update the block containing the
font-synthesis and text-rendering properties so there is an empty line before
those declarations and change the text-rendering value to the linter-expected
case (use lowercase keyword form) while keeping font-synthesis: none as-is.

In `@sample-apps/react/egress-composite/src/global.d.ts`:
- Line 5: The declaration for setupLayout references the type ConfigurationValue
but it isn't imported; update global.d.ts to import ConfigurationValue from
./ConfigurationContext.tsx and then use that imported type in the setupLayout
signature (the symbol names to edit are ConfigurationValue and setupLayout in
global.d.ts, and the source is ConfigurationContext.tsx).

---

Nitpick comments:
In `@packages/react-sdk/src/core/components/CallLayout/PaginatedGridLayout.tsx`:
- Around line 35-66: Wrap the PaginatedGridLayoutGroup component with React.memo
to avoid unnecessary re-renders when its props (group, mirror, VideoPlaceholder,
PictureInPicturePlaceholder, ParticipantViewUI) haven't changed; locate the
PaginatedGridLayoutGroup function and export (or assign) a memoized version
using React.memo(PaginatedGridLayoutGroup) so the component only re-renders on
prop changes while continuing to render ParticipantView for each
participant.sessionId as before.

In `@sample-apps/react/egress-composite/src/hooks/options/useVideoStyles.ts`:
- Around line 17-37: The generated CSS always emits empty
background-color/object-fit declarations; update useVideoStyles to only add the
corresponding css fragments when values are present: check videoBackgroundColor
before adding the block that sets background-color, check typeof videoScaleMode
!== 'undefined' (or presence) before adding the object-fit block that uses
objectFitMap[videoScaleMode], and check videoScreenshareScaleMode before adding
the screenshare object-fit block. Modify the styles array construction (where
css and cx are used) to push these conditional css snippets (or build separate
css calls) so undefined values are never serialized; keep using css, cx,
objectFitMap, videoScaleMode, videoScreenshareScaleMode, and
videoBackgroundColor to locate and change the code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8a1170ea-ab79-41b1-a266-c51228159a95

📥 Commits

Reviewing files that changed from the base of the PR and between 7d8a50d and 6a03494.

⛔ Files ignored due to path filters (8)
  • packages/audio-filters-web/src/krispai/dist/krispsdk.es5.js is excluded by !**/dist/**
  • packages/audio-filters-web/src/krispai/dist/krispsdk.js is excluded by !**/dist/**
  • packages/audio-filters-web/src/krispai/dist/krispsdk.mjs is excluded by !**/dist/**
  • packages/audio-filters-web/src/krispai/dist/usermedia.js is excluded by !**/dist/**
  • packages/audio-filters-web/src/krispai/dist/usermedia.mjs is excluded by !**/dist/**
  • sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---grid-1.png is excluded by !**/*.png
  • sample-apps/react/egress-composite/tests/__screenshots__/layouts.spec.ts/Layouts-Should-render-layout---grid-with-size-constraints-1.png is excluded by !**/*.png
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (20)
  • packages/react-sdk/src/core/components/CallLayout/PaginatedGridLayout.tsx
  • sample-apps/react/egress-composite/package.json
  • sample-apps/react/egress-composite/src/CompositeApp.scss
  • sample-apps/react/egress-composite/src/CompositeApp.tsx
  • sample-apps/react/egress-composite/src/ConfigurationContext.tsx
  • sample-apps/react/egress-composite/src/components/LogoAndTitle.scss
  • sample-apps/react/egress-composite/src/components/layouts/DominantSpeaker/DominantSpeaker.scss
  • sample-apps/react/egress-composite/src/components/layouts/DominantSpeaker/DominantSpeakerScreenShare.scss
  • sample-apps/react/egress-composite/src/components/layouts/PaginatedGrid/PaginatedGrid.scss
  • sample-apps/react/egress-composite/src/components/layouts/PaginatedGrid/PaginatedGrid.tsx
  • sample-apps/react/egress-composite/src/components/layouts/Spotlight/Spotlight.scss
  • sample-apps/react/egress-composite/src/global.d.ts
  • sample-apps/react/egress-composite/src/hooks/options/useGenericLayoutStyles.ts
  • sample-apps/react/egress-composite/src/hooks/options/useLogoAndTitleStyles.ts
  • sample-apps/react/egress-composite/src/hooks/options/useParticipantLabelStyles.ts
  • sample-apps/react/egress-composite/src/hooks/options/useParticipantStyles.ts
  • sample-apps/react/egress-composite/src/hooks/options/useVideoStyles.ts
  • sample-apps/react/egress-composite/src/main.scss
  • sample-apps/react/egress-composite/src/main.tsx
  • sample-apps/react/egress-composite/tests/layouts.spec.ts
💤 Files with no reviewable changes (1)
  • sample-apps/react/egress-composite/package.json

Comment thread sample-apps/react/egress-composite/src/components/LogoAndTitle.scss
Comment thread sample-apps/react/egress-composite/src/CompositeApp.scss
Comment thread sample-apps/react/egress-composite/src/global.d.ts
@jdimovska jdimovska merged commit 9c7009f into main Apr 24, 2026
14 checks passed
@jdimovska jdimovska deleted the fix/egress-composite/paginated-grid-sizing-and-refactors branch April 24, 2026 13:10
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.

3 participants