Skip to content

Conversation

@benlife5
Copy link
Contributor

@benlife5 benlife5 commented Dec 9, 2025

When a new card was added to a card section (either via adding in the constant value or via a new list item on the entity), the shared card styles were being reset to the defaults. This was because the new card was being created with default props, triggering it to update the shared context, triggering the existing cards to dispatch updates. This change makes it so that new cards are initialized with the shared styling props of the already existing cards.

@benlife5 benlife5 marked this pull request as ready for review December 9, 2025 18:05
@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

Warning: Component files have been updated but no migrations have been added. See https://github.com/yext/visual-editor/blob/main/packages/visual-editor/src/components/migrations/README.md for more information.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

Walkthrough

The PR introduces a shared card-styling flow across multiple page sections. A new exported helper gatherSlotStyles extracts styles from CardSlot props; wrapper components (Event/Insight/Product/Team/Testimonial) call it to derive sharedCardProps and pass backgroundColor and sharedSlotStyles into default

CardSlotData factory functions. Many default card factories’ signatures were extended to accept these styling parameters and apply them to generated slot data. DirectoryWrapper’s updatedCards generation was changed to read slot props from the first CardSlot, causing newly produced/updated cards to use that first-slot styling.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Wrapper as SectionCardsWrapper
    participant Hook as useGetCardSlots.gatherSlotStyles
    participant Factory as default<X>CardSlotData
    participant Slots as CardSlot[] (data.props.slots)

    Wrapper->>Slots: read CardSlot (first element)
    Wrapper->>Hook: gatherSlotStyles(first CardSlot.props)
    Hook-->>Wrapper: slotStyles map
    Wrapper->>Factory: create new card (id,index, backgroundColor, slotStyles)
    Factory-->>Wrapper: cardData with applied sharedSlotStyles
    Wrapper->>Slots: insert/replace cardData into CardSlot array
    note right of Slots: Result: generated cards inherit shared styles\nsourced from first CardSlot
Loading

Possibly related PRs

Suggested labels

create-dev-release

Suggested reviewers

  • mkilpatrick
  • asanehisa
  • briantstephan

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: preventing shared styles from being lost when new cards are added to card sections.
Description check ✅ Passed The description clearly explains the problem (shared styles reset to defaults when new cards added) and the solution (initialize new cards with existing cards' shared styling props).
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch shared-styles-fix

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
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: 1

🧹 Nitpick comments (5)
packages/visual-editor/src/components/pageSections/InsightSection/InsightCardsWrapper.tsx (1)

65-74: Potential null access on props.styles.

If CardSlot[0].props.styles is undefined, accessing .backgroundColor at line 70 will throw. Consider adding optional chaining for defensive access:

     const sharedCardProps =
       data.props.slots.CardSlot.length === 0
         ? undefined
         : {
             backgroundColor:
-              data.props.slots.CardSlot[0].props.styles.backgroundColor,
+              data.props.slots.CardSlot[0].props.styles?.backgroundColor,
             slotStyles: gatherSlotStyles(
               data.props.slots.CardSlot[0].props.slots
             ),
           };
packages/visual-editor/src/components/pageSections/EventSection/EventCardsWrapper.tsx (1)

59-70: Same optional chaining improvement as InsightCardsWrapper.

For consistency and defensive coding, consider adding optional chaining on props.styles:

     const sharedCardProps =
       data.props.slots.CardSlot.length === 0
         ? undefined
         : {
             backgroundColor:
-              data.props.slots.CardSlot[0].props.styles.backgroundColor,
+              data.props.slots.CardSlot[0].props.styles?.backgroundColor,
             truncateDescription:
               data.props.slots.CardSlot[0].props.truncateDescription,
             slotStyles: gatherSlotStyles(
               data.props.slots.CardSlot[0].props.slots
             ),
           };
packages/visual-editor/src/components/pageSections/TeamSection/TeamCardsWrapper.tsx (1)

62-71: Consider defensive access for styles property.

If CardSlot[0].props.styles is undefined, accessing .backgroundColor will throw. While TypeScript types may guarantee this structure, a defensive check would be safer.

     const sharedCardProps =
       data.props.slots.CardSlot.length === 0
         ? undefined
         : {
             backgroundColor:
-              data.props.slots.CardSlot[0].props.styles.backgroundColor,
+              data.props.slots.CardSlot[0].props.styles?.backgroundColor,
             slotStyles: gatherSlotStyles(
               data.props.slots.CardSlot[0].props.slots
             ),
           };
packages/visual-editor/src/components/pageSections/ProductSection/ProductCardsWrapper.tsx (1)

65-74: Same defensive access suggestion applies here.

As noted in TeamCardsWrapper.tsx, consider using data.props.slots.CardSlot[0].props.styles?.backgroundColor for safety.

packages/visual-editor/src/components/pageSections/TestimonialSection/TestimonialCardsWrapper.tsx (1)

67-76: Consistent implementation across wrappers.

Same pattern as other wrappers. Consider styles?.backgroundColor for defensive access.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 811d9ee and 04aaecc.

📒 Files selected for processing (12)
  • packages/visual-editor/src/components/directory/DirectoryWrapper.tsx (1 hunks)
  • packages/visual-editor/src/components/pageSections/EventSection/EventCard.tsx (1 hunks)
  • packages/visual-editor/src/components/pageSections/EventSection/EventCardsWrapper.tsx (4 hunks)
  • packages/visual-editor/src/components/pageSections/InsightSection/InsightCard.tsx (2 hunks)
  • packages/visual-editor/src/components/pageSections/InsightSection/InsightCardsWrapper.tsx (4 hunks)
  • packages/visual-editor/src/components/pageSections/ProductSection/ProductCard.tsx (2 hunks)
  • packages/visual-editor/src/components/pageSections/ProductSection/ProductCardsWrapper.tsx (4 hunks)
  • packages/visual-editor/src/components/pageSections/TeamSection/TeamCard.tsx (1 hunks)
  • packages/visual-editor/src/components/pageSections/TeamSection/TeamCardsWrapper.tsx (4 hunks)
  • packages/visual-editor/src/components/pageSections/TestimonialSection/TestimonialCard.tsx (1 hunks)
  • packages/visual-editor/src/components/pageSections/TestimonialSection/TestimonialCardsWrapper.tsx (4 hunks)
  • packages/visual-editor/src/hooks/useGetCardSlots.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
packages/visual-editor/src/components/pageSections/ProductSection/ProductCardsWrapper.tsx (2)
packages/visual-editor/src/hooks/useGetCardSlots.tsx (1)
  • gatherSlotStyles (35-42)
packages/visual-editor/src/components/pageSections/ProductSection/ProductCard.tsx (1)
  • defaultProductCardSlotData (54-180)
packages/visual-editor/src/components/pageSections/TeamSection/TeamCardsWrapper.tsx (2)
packages/visual-editor/src/hooks/useGetCardSlots.tsx (1)
  • gatherSlotStyles (35-42)
packages/visual-editor/src/components/pageSections/TeamSection/TeamCard.tsx (1)
  • defaultTeamCardSlotData (51-208)
packages/visual-editor/src/components/pageSections/InsightSection/InsightCardsWrapper.tsx (2)
packages/visual-editor/src/hooks/useGetCardSlots.tsx (1)
  • gatherSlotStyles (35-42)
packages/visual-editor/src/components/pageSections/InsightSection/InsightCard.tsx (1)
  • defaultInsightCardSlotData (50-208)
packages/visual-editor/src/components/pageSections/TeamSection/TeamCard.tsx (1)
packages/visual-editor/src/components/contentBlocks/index.ts (1)
  • PhoneListProps (13-13)
packages/visual-editor/src/components/pageSections/EventSection/EventCard.tsx (1)
packages/visual-editor/src/components/contentBlocks/index.ts (1)
  • TimestampProps (15-15)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: call_unit_test / unit_tests (18.x)
  • GitHub Check: call_unit_test / unit_tests (20.x)
  • GitHub Check: semgrep/ci
🔇 Additional comments (17)
packages/visual-editor/src/components/pageSections/InsightSection/InsightCardsWrapper.tsx (1)

99-104: Correctly propagates shared styles to new cards.

The implementation properly passes backgroundColor and slotStyles from existing cards to newly created placeholder cards, which addresses the root cause described in the PR objectives.

packages/visual-editor/src/components/pageSections/TestimonialSection/TestimonialCard.tsx (1)

39-126: Implementation correctly applies shared styles to new cards.

The function signature extension and the post-processing loop at lines 119-123 properly inherit styles from existing cards, fixing the shared styles reset issue.

packages/visual-editor/src/components/pageSections/InsightSection/InsightCard.tsx (2)

50-55: Function signature correctly extended for shared style propagation.

The additional backgroundColor and sharedSlotStyles parameters enable inheriting styles from existing cards, which is the core fix for the shared styles reset issue.


201-207: Post-processing correctly applies shared slot styles.

The iteration over cardData.props.slots and conditional style assignment ensures new cards inherit the styling configuration from existing cards.

packages/visual-editor/src/components/pageSections/EventSection/EventCardsWrapper.tsx (1)

98-104: Shared style propagation correctly implemented.

The implementation properly passes all shared props (backgroundColor, truncateDescription, slotStyles) to newly created cards, maintaining consistency with the fix pattern.

packages/visual-editor/src/components/pageSections/TeamSection/TeamCardsWrapper.tsx (1)

100-105: Shared styles propagation looks correct.

Both code paths (entity values and static values) correctly pass sharedCardProps?.backgroundColor and sharedCardProps?.slotStyles to defaultTeamCardSlotData, ensuring new cards inherit styling from existing cards.

Also applies to: 159-164

packages/visual-editor/src/components/pageSections/ProductSection/ProductCard.tsx (2)

54-59: Function signature extension looks appropriate.

The new optional parameters backgroundColor and sharedSlotStyles enable style inheritance without breaking existing call sites that don't pass these arguments.


173-177: Style application replaces rather than merges.

This completely overwrites slotArray[0].props.styles with sharedSlotStyles[slotKey]. This is likely intentional for full style synchronization, but note that any slot-specific defaults defined above (e.g., aspectRatio: 1.78 on ImageSlot) will be lost if sharedSlotStyles contains that key.

packages/visual-editor/src/components/pageSections/ProductSection/ProductCardsWrapper.tsx (1)

102-107: Implementation is consistent with the pattern.

Both entity-driven and static value paths correctly pass shared styling to new cards, matching the fix described in the PR.

Also applies to: 161-166

packages/visual-editor/src/components/pageSections/TestimonialSection/TestimonialCardsWrapper.tsx (1)

105-110: LGTM!

Both code paths correctly propagate shared styles to newly created testimonial cards.

Also applies to: 165-170

packages/visual-editor/src/components/pageSections/EventSection/EventCard.tsx (3)

55-61: EventCard includes additional truncateDescription parameter.

Unlike other card factories, this one includes a card-specific style property (truncateDescription). This is appropriate given EventCard's unique truncation feature.


62-70: Defaults are appropriate.

Using nullish coalescing for backgroundColor and truncateDescription (defaulting to true) maintains backward compatibility while enabling style inheritance.


187-191: Same style replacement behavior as other cards.

This completely replaces slot styles when sharedSlotStyles[slotKey] is present. This is consistent with ProductCard.tsx and other card implementations.

packages/visual-editor/src/components/pageSections/TeamSection/TeamCard.tsx (3)

51-56: Function signature correctly supports shared styling propagation.

The new optional parameters backgroundColor and sharedSlotStyles allow newly created cards to inherit styling from existing cards, addressing the root cause described in the PR objectives.


57-199: Comprehensive card data construction with proper type annotations.

The factory now builds a fully structured cardData object with all slot definitions, using satisfies annotations for type safety. The conditional spreading of id and index properties and the fallback for backgroundColor are well-implemented.


201-205: This suggestion is not applicable. The current implementation is correct. gatherSlotStyles extracts complete style objects from an existing card (value[0].props.styles || {}), not partial styles. When sharedSlotStyles is applied to new cards, direct assignment is the intended behavior—it replaces the default styles with styles from the first card. Using deepMerge or spread operators would prevent style updates from taking effect properly and is unnecessary here.

Likely an incorrect or invalid review comment.

packages/visual-editor/src/components/directory/DirectoryWrapper.tsx (1)

146-147: No changes needed—the implementation correctly applies shared card styles and handles undefined gracefully.

The code uses CardSlot[0]'s styles and slots for all newly created cards, which is the correct approach for the shared styling feature. The defaultDirectoryCardSlotData factory function safely handles undefined values through optional chaining and null coalescing operators (e.g., existingCardStyle?.backgroundColor ?? backgroundColors.background1.value), ensuring defaults are applied when styles are not provided. When CardSlot is empty, undefined is passed and the factory correctly falls back to default values.

Copy link
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: 0

🧹 Nitpick comments (1)
packages/visual-editor/src/hooks/useGetCardSlots.tsx (1)

35-42: Good defensive access with optional chaining.

The optional chaining (value?.[0]?.props?.styles) correctly addresses the concern from the previous review about potential runtime errors when slot arrays are empty. The fallback to {} ensures consistent behavior.

Consider adding an explicit return type annotation.

For improved type safety and documentation, consider adding a return type:

-export const gatherSlotStyles = (slotProps: Record<string, Slot>) => {
+export const gatherSlotStyles = (slotProps: Record<string, Slot>): Record<string, any> => {
   return Object.fromEntries(
     Object.entries(slotProps).map(([key, value]) => [
       key,
       value?.[0]?.props?.styles || {},
     ])
   );
 };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 04aaecc and 8b3ba42.

📒 Files selected for processing (1)
  • packages/visual-editor/src/hooks/useGetCardSlots.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: call_unit_test / unit_tests (20.x)
  • GitHub Check: call_unit_test / unit_tests (18.x)
  • GitHub Check: semgrep/ci
🔇 Additional comments (1)
packages/visual-editor/src/hooks/useGetCardSlots.tsx (1)

29-29: LGTM! Clean refactoring for code reuse.

Extracting the slot styles logic into gatherSlotStyles improves maintainability and aligns well with the PR objective of sharing card styling across multiple wrapper components.

Copy link
Contributor

@asanehisa asanehisa left a comment

Choose a reason for hiding this comment

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

lgtm, was FAQ / adding a "card" to faq ok?

@benlife5
Copy link
Contributor Author

benlife5 commented Dec 9, 2025

Interestingly, the styles aren't shared at all between each item in FAQ Section... will add a note to the FAQ revamp item

@benlife5 benlife5 merged commit d119696 into main Dec 10, 2025
15 checks passed
@benlife5 benlife5 deleted the shared-styles-fix branch December 10, 2025 14:14
@coderabbitai coderabbitai bot mentioned this pull request Dec 19, 2025
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