Skip to content

refactor: remove YextField#1201

Open
briantstephan wants to merge 5 commits intomainfrom
remove-yext-field
Open

refactor: remove YextField#1201
briantstephan wants to merge 5 commits intomainfrom
remove-yext-field

Conversation

@briantstephan
Copy link
Copy Markdown
Contributor

@briantstephan briantstephan commented May 4, 2026

This removes the YextField helper, which was no more than a basic wrapper after our recent field type refactors.

Tested on the site linked below and didn't notice any issues. Feel free to play around with it.
https://dev.yext.com/s/1000167375/yextsites/67153/pagesets

@briantstephan briantstephan self-assigned this May 4, 2026
@briantstephan briantstephan added the create-dev-release Triggers dev release workflow label May 4, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

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.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 4, 2026

commit: 86b3bf9

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 03c050bc-17f7-445e-8294-17c9714c0da0

📥 Commits

Reviewing files that changed from the base of the PR and between 686976b and 35f7d69.

📒 Files selected for processing (5)
  • packages/visual-editor/src/components/contentBlocks/Address.tsx
  • packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx
  • packages/visual-editor/src/components/pageSections/InsightSection/InsightCardsWrapper.tsx
  • packages/visual-editor/src/editor/README.md
  • packages/visual-editor/src/index.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/visual-editor/src/index.ts
  • packages/visual-editor/src/editor/README.md

Walkthrough

This pull request removes the YextField helper and its test module, migrates the Yext field/type definitions into packages/visual-editor/src/fields/fields.ts, and updates ~60+ visual-editor component files to declare editor field schemas as direct object-literal YextFields rather than wrapping them with YextField(...). Imports and type references were adjusted to use the new fields.ts exports. The editor README was updated to document direct YextFields usage. The i18next config was changed to stop ignoring the deleted test file.

Sequence Diagram(s)

(omitted)

Possibly related PRs

  • yext/visual-editor#1184: Related migration/removal of the YextField helper and conversion of field schemas to inline definitions.
  • yext/visual-editor#1186: Related changes to the editor field system and video field definitions overlapping this refactor.
  • yext/visual-editor#1170: Related refactor touching CTA/field selector logic and fields.ts type surface.

Suggested reviewers

  • benlife5
  • jwartofsky-yext
  • asanehisa
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor: remove YextField' clearly and concisely describes the main change: removing the YextField helper across the codebase.
Description check ✅ Passed The description is directly related to the changeset, explaining that YextField was a wrapper that became redundant after type refactors, and noting manual testing on a development site.
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 remove-yext-field

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/visual-editor/src/components/contentBlocks/Address.tsx (1)

201-223: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pre-existing: setDeep return values are discarded in resolveAddressFields.

setDeep returns a new object rather than mutating in place. The two setDeep calls inside resolveAddressFields (lines 209 and 216) discard their return values, so ctaVariant.visible and color.visible are never applied to the returned updatedFields. This is a pre-existing bug surfaced here alongside the addressFields refactor.

🐛 Proposed fix
  const updatedFields = resolveDataFromParent(addressFields, data);
  const showGetDirectionsLink = data.props.styles.showGetDirectionsLink;
- setDeep(
+ const withCtaVariant = setDeep(
    updatedFields,
    "styles.objectFields.ctaVariant.visible",
    showGetDirectionsLink
  );
  const ctaVariant = data.props.styles.ctaVariant;
  const showColor = isCtaVariantWithColor(ctaVariant);
- setDeep(
-   updatedFields,
+  return setDeep(
+   withCtaVariant,
    "styles.objectFields.color.visible",
    showGetDirectionsLink && showColor
  );
-
- return updatedFields;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/visual-editor/src/components/contentBlocks/Address.tsx` around lines
201 - 223, resolveAddressFields currently calls setDeep twice but discards its
return value, so the updates to "styles.objectFields.ctaVariant.visible" and
"styles.objectFields.color.visible" are never applied; update the function to
capture and reassign the returned object from setDeep (e.g., updatedFields =
setDeep(updatedFields, "styles.objectFields.ctaVariant.visible",
showGetDirectionsLink) and then updatedFields = setDeep(updatedFields,
"styles.objectFields.color.visible", showGetDirectionsLink && showColor)) so the
modifications persist before returning updatedFields; keep references to
resolveAddressFields, setDeep, updatedFields, addressFields, and
isCtaVariantWithColor when locating the code to change.
🧹 Nitpick comments (3)
packages/visual-editor/src/components/pageSections/InsightSection/InsightCardsWrapper.tsx (1)

30-66: ⚡ Quick win

LGTM — styles field correctly inlined.

The five showImage/showCategory/showPublishTime/showDescription/showCTA radio options are preserved verbatim; only the YextField() wrapper is removed and label is made explicit.

One pre-existing nit (not introduced here): insightCardsWrapperFields lacks an explicit YextFields<InsightCardsWrapperProps> type annotation, unlike insightCardFields and insightSectionFields. Adding it here would catch schema-shape mismatches at compile time, consistent with the other two files.

🔧 Optional: add type annotation for consistency
-const insightCardsWrapperFields = {
+const insightCardsWrapperFields: YextFields<InsightCardsWrapperProps> = {

Also add the import if not already present (it may already be covered by the existing YextComponentConfig import path):

-import { YextComponentConfig } from "../../../fields/fields.ts";
+import { YextComponentConfig, YextFields } from "../../../fields/fields.ts";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/visual-editor/src/components/pageSections/InsightSection/InsightCardsWrapper.tsx`
around lines 30 - 66, Add an explicit YextFields<InsightCardsWrapperProps> type
annotation to the insightCardsWrapperFields constant to match the pattern used
by insightCardFields and insightSectionFields; ensure the YextFields type is
imported if not already (check existing imports alongside YextComponentConfig).
This will enforce the schema shape at compile time and keep consistency with the
other component field definitions.
packages/visual-editor/src/index.ts (1)

7-7: ⚡ Quick win

Route this type re-export through fields/index.ts.

Exporting YextFieldDefinition from ./fields/fields.ts makes that deep module part of the public API. Re-export it from packages/visual-editor/src/fields/index.ts and keep the root index pointed at the fields entrypoint instead.

♻️ Suggested change
- export { type YextFieldDefinition } from "./fields/fields.ts";
+ export { type YextFieldDefinition } from "./fields/index.ts";
// packages/visual-editor/src/fields/index.ts
export { type YextFieldDefinition } from "./fields.ts";

As per coding guidelines, "Public exports should go through package entrypoints such as packages/visual-editor/src/index.ts and related package index.ts files."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/visual-editor/src/index.ts` at line 7, The root export currently
exposes YextFieldDefinition directly from ./fields/fields.ts; instead create a
re-export in the fields entrypoint by adding export { type YextFieldDefinition }
from "./fields.ts" to fields/index.ts, then update
packages/visual-editor/src/index.ts to re-export from the fields entrypoint
(e.g. export * from "./fields") so the public type YextFieldDefinition flows
through the package entrypoint rather than the deep ./fields/fields.ts module.
packages/visual-editor/src/components/LocatorResultCard.tsx (1)

340-358: Pre-existing hooks violation tracked by the updated TODO.

getDisplayFieldOptions calls useTemplateMetadata() (a hook) inside a plain function invoked from an options: () => ... callback — this violates the Rules of Hooks. The updated TODO correctly names the fix path ("refactor the custom render path"), likely converting DisplayFieldSelector into a proper custom-render field so the hook call lives inside a component.

Would you like me to draft the refactored implementation (e.g., wrapping getDisplayFieldOptions in a React.FC that is used as the field's render: callback instead of options:) and open a tracking issue? Based on learnings, hooks must only be called at the top level of React function components or custom hooks — this applies to all TSX files in the repo.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/visual-editor/src/components/LocatorResultCard.tsx` around lines 340
- 358, getDisplayFieldOptions currently calls the hook useTemplateMetadata
inside a plain function (used in an options: () => ...) which violates the Rules
of Hooks; refactor by moving the hook call into a React component and use that
component as the field's custom render instead of options. Concretely, create a
functional component (e.g., DisplayFieldSelector) that calls useTemplateMetadata
at the top level, derives locatorDisplayFields and maps to
EmbeddedStringOption[] (using FieldTypeData and field_type_id/field_name) and
expose the options via props or directly render the select; then replace the
options: getDisplayFieldOptions usage with render: <DisplayFieldSelector .../>
(or a render function that returns that component) so hooks are only invoked
inside the component. Ensure the filtering logic over fieldTypeId (handle string
| string[]) and the mapping to {label, value} remains identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx`:
- Line 27: Add the missing type annotation and use toPuckFields: annotate the
footerExpandedLinksWrapperFields constant with
YextFields<FooterExpandedLinksWrapperProps>, and update the resolveFields
implementation to wrap its return with toPuckFields(...) instead of using an
unsafe "as any" cast so it matches the pattern used by FooterLinksSlot,
FooterExpandedLinkSectionSlot, PhotoGalleryWrapper, etc.; keep the same field
shape but replace the cast with toPuckFields for correct typing and consistency.

In `@packages/visual-editor/src/editor/README.md`:
- Around line 380-383: The code examples for object properties (e.g., the
spacing property and the two other similar examples) mistakenly close each
property with "};" which will cause TypeScript parse errors inside a YextFields
object literal; edit the examples to replace the trailing semicolons with commas
(change "};" to "},") so each property uses a comma separator consistent with
the other examples (look for the spacing property and the two analogous property
blocks in the README examples).

---

Outside diff comments:
In `@packages/visual-editor/src/components/contentBlocks/Address.tsx`:
- Around line 201-223: resolveAddressFields currently calls setDeep twice but
discards its return value, so the updates to
"styles.objectFields.ctaVariant.visible" and "styles.objectFields.color.visible"
are never applied; update the function to capture and reassign the returned
object from setDeep (e.g., updatedFields = setDeep(updatedFields,
"styles.objectFields.ctaVariant.visible", showGetDirectionsLink) and then
updatedFields = setDeep(updatedFields, "styles.objectFields.color.visible",
showGetDirectionsLink && showColor)) so the modifications persist before
returning updatedFields; keep references to resolveAddressFields, setDeep,
updatedFields, addressFields, and isCtaVariantWithColor when locating the code
to change.

---

Nitpick comments:
In `@packages/visual-editor/src/components/LocatorResultCard.tsx`:
- Around line 340-358: getDisplayFieldOptions currently calls the hook
useTemplateMetadata inside a plain function (used in an options: () => ...)
which violates the Rules of Hooks; refactor by moving the hook call into a React
component and use that component as the field's custom render instead of
options. Concretely, create a functional component (e.g., DisplayFieldSelector)
that calls useTemplateMetadata at the top level, derives locatorDisplayFields
and maps to EmbeddedStringOption[] (using FieldTypeData and
field_type_id/field_name) and expose the options via props or directly render
the select; then replace the options: getDisplayFieldOptions usage with render:
<DisplayFieldSelector .../> (or a render function that returns that component)
so hooks are only invoked inside the component. Ensure the filtering logic over
fieldTypeId (handle string | string[]) and the mapping to {label, value} remains
identical.

In
`@packages/visual-editor/src/components/pageSections/InsightSection/InsightCardsWrapper.tsx`:
- Around line 30-66: Add an explicit YextFields<InsightCardsWrapperProps> type
annotation to the insightCardsWrapperFields constant to match the pattern used
by insightCardFields and insightSectionFields; ensure the YextFields type is
imported if not already (check existing imports alongside YextComponentConfig).
This will enforce the schema shape at compile time and keep consistency with the
other component field definitions.

In `@packages/visual-editor/src/index.ts`:
- Line 7: The root export currently exposes YextFieldDefinition directly from
./fields/fields.ts; instead create a re-export in the fields entrypoint by
adding export { type YextFieldDefinition } from "./fields.ts" to
fields/index.ts, then update packages/visual-editor/src/index.ts to re-export
from the fields entrypoint (e.g. export * from "./fields") so the public type
YextFieldDefinition flows through the package entrypoint rather than the deep
./fields/fields.ts module.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a05c90f5-9237-4be1-a26c-b3567dcad401

📥 Commits

Reviewing files that changed from the base of the PR and between cd5c81d and 686976b.

⛔ Files ignored due to path filters (1)
  • packages/visual-editor/src/components/testing/screenshots/Locator/[tablet] latest version multi-pageset default props.png is excluded by !**/*.png, !packages/visual-editor/src/components/testing/screenshots/**
📒 Files selected for processing (79)
  • packages/visual-editor/i18next-cli.platform.config.ts
  • packages/visual-editor/src/components/Locator.tsx
  • packages/visual-editor/src/components/LocatorResultCard.tsx
  • packages/visual-editor/src/components/contentBlocks/Address.tsx
  • packages/visual-editor/src/components/contentBlocks/BodyText.tsx
  • packages/visual-editor/src/components/contentBlocks/CTAGroup.tsx
  • packages/visual-editor/src/components/contentBlocks/Emails.tsx
  • packages/visual-editor/src/components/contentBlocks/HoursStatus.tsx
  • packages/visual-editor/src/components/contentBlocks/HoursTable.tsx
  • packages/visual-editor/src/components/contentBlocks/Phone.tsx
  • packages/visual-editor/src/components/contentBlocks/PhoneList.tsx
  • packages/visual-editor/src/components/contentBlocks/Text.tsx
  • packages/visual-editor/src/components/contentBlocks/Video.tsx
  • packages/visual-editor/src/components/contentBlocks/image/Image.tsx
  • packages/visual-editor/src/components/contentBlocks/image/styling.ts
  • packages/visual-editor/src/components/customCode/CustomCodeSection.tsx
  • packages/visual-editor/src/components/directory/Directory.tsx
  • packages/visual-editor/src/components/directory/DirectoryCard.tsx
  • packages/visual-editor/src/components/directory/DirectoryWrapper.tsx
  • packages/visual-editor/src/components/footer/CopyrightMessageSlot.tsx
  • packages/visual-editor/src/components/footer/ExpandedFooter.tsx
  • packages/visual-editor/src/components/footer/Footer.tsx
  • packages/visual-editor/src/components/footer/FooterExpandedLinkSectionSlot.tsx
  • packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx
  • packages/visual-editor/src/components/footer/FooterLinksSlot.tsx
  • packages/visual-editor/src/components/footer/FooterLogoSlot.tsx
  • packages/visual-editor/src/components/footer/FooterSocialLinksSlot.tsx
  • packages/visual-editor/src/components/footer/FooterUtilityImagesSlot.tsx
  • packages/visual-editor/src/components/footer/SecondaryFooterSlot.tsx
  • packages/visual-editor/src/components/header/ExpandedHeader.tsx
  • packages/visual-editor/src/components/header/Header.tsx
  • packages/visual-editor/src/components/header/HeaderLinks.tsx
  • packages/visual-editor/src/components/header/PrimaryHeaderSlot.tsx
  • packages/visual-editor/src/components/header/SecondaryHeaderSlot.tsx
  • packages/visual-editor/src/components/layoutBlocks/Grid.tsx
  • packages/visual-editor/src/components/pageSections/AboutSection/AboutSection.tsx
  • packages/visual-editor/src/components/pageSections/AboutSection/AboutSectionDetailsColumn.tsx
  • packages/visual-editor/src/components/pageSections/Banner.tsx
  • packages/visual-editor/src/components/pageSections/Breadcrumbs.tsx
  • packages/visual-editor/src/components/pageSections/CoreInfoSection.tsx
  • packages/visual-editor/src/components/pageSections/EventSection/EventCard.tsx
  • packages/visual-editor/src/components/pageSections/EventSection/EventCardsWrapper.tsx
  • packages/visual-editor/src/components/pageSections/EventSection/EventSection.tsx
  • packages/visual-editor/src/components/pageSections/FAQsSection/FAQCard.tsx
  • packages/visual-editor/src/components/pageSections/FAQsSection/FAQsSection.tsx
  • packages/visual-editor/src/components/pageSections/HeroSection.tsx
  • packages/visual-editor/src/components/pageSections/InsightSection/InsightCard.tsx
  • packages/visual-editor/src/components/pageSections/InsightSection/InsightCardsWrapper.tsx
  • packages/visual-editor/src/components/pageSections/InsightSection/InsightSection.tsx
  • packages/visual-editor/src/components/pageSections/NearbyLocations/NearbyLocations.tsx
  • packages/visual-editor/src/components/pageSections/NearbyLocations/NearbyLocationsCardsWrapper.tsx
  • packages/visual-editor/src/components/pageSections/PhotoGallerySection/PhotoGallerySection.tsx
  • packages/visual-editor/src/components/pageSections/PhotoGallerySection/PhotoGalleryWrapper.tsx
  • packages/visual-editor/src/components/pageSections/ProductSection/ProductCard.tsx
  • packages/visual-editor/src/components/pageSections/ProductSection/ProductCardsWrapper.tsx
  • packages/visual-editor/src/components/pageSections/ProductSection/ProductSection.tsx
  • packages/visual-editor/src/components/pageSections/ProfessionalHeroSection.tsx
  • packages/visual-editor/src/components/pageSections/PromoSection/PromoSection.tsx
  • packages/visual-editor/src/components/pageSections/ReviewsSection/ReviewsSection.tsx
  • packages/visual-editor/src/components/pageSections/SectionContainer.tsx
  • packages/visual-editor/src/components/pageSections/StaticMapSection.tsx
  • packages/visual-editor/src/components/pageSections/TeamSection/TeamCard.tsx
  • packages/visual-editor/src/components/pageSections/TeamSection/TeamCardsWrapper.tsx
  • packages/visual-editor/src/components/pageSections/TeamSection/TeamSection.tsx
  • packages/visual-editor/src/components/pageSections/TestimonialSection/TestimonialCard.tsx
  • packages/visual-editor/src/components/pageSections/TestimonialSection/TestimonialCardsWrapper.tsx
  • packages/visual-editor/src/components/pageSections/TestimonialSection/TestimonialSection.tsx
  • packages/visual-editor/src/components/pageSections/VideoSection.tsx
  • packages/visual-editor/src/editor/README.md
  • packages/visual-editor/src/editor/YextField.test.tsx
  • packages/visual-editor/src/editor/YextField.tsx
  • packages/visual-editor/src/editor/index.ts
  • packages/visual-editor/src/fields/EntityFieldSelectorField.tsx
  • packages/visual-editor/src/fields/MultiSelectorField.tsx
  • packages/visual-editor/src/fields/YextAutoField.tsx
  • packages/visual-editor/src/fields/fields.ts
  • packages/visual-editor/src/fields/index.ts
  • packages/visual-editor/src/index.ts
  • packages/visual-editor/src/internal/puck/components/meta-title/MetaTitleField.tsx
💤 Files with no reviewable changes (3)
  • packages/visual-editor/src/editor/YextField.test.tsx
  • packages/visual-editor/src/editor/YextField.tsx
  • packages/visual-editor/src/editor/index.ts

Comment thread packages/visual-editor/src/components/footer/FooterExpandedLinksWrapper.tsx Outdated
Comment thread packages/visual-editor/src/editor/README.md Outdated
@briantstephan briantstephan marked this pull request as ready for review May 4, 2026 21:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

create-dev-release Triggers dev release workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant