diff --git a/CHANGELOG.md b/CHANGELOG.md index 020c0cb..6ee466a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.0.1] - 2025-11-24 + +### Documentation +- Enhanced README with comprehensive explanations of `data-hygraph-component-chain` attribute +- Added detailed examples for single-level and deeply nested components +- Clarified the relationship between `data-hygraph-entry-id` and component chains +- Added examples for union/modular components with multiple component types +- Included GraphQL query examples showing how to extract `instanceId` values +- Improved component chain documentation with helper function usage examples + ## [1.0.0] - 2024-11-13 ### Added diff --git a/README.md b/README.md index 239a460..dde5195 100644 --- a/README.md +++ b/README.md @@ -108,54 +108,312 @@ Common optional attributes: ### Tagging Component Fields -Use the optional `data-hygraph-component-chain` attribute when a field lives inside a modular component, repeatable component list, or union component. The attribute accepts a JSON string array describing the path from the entry to the nested field. +Use the `data-hygraph-component-chain` attribute when a field lives inside a modular component, repeatable component list, or union component. The component chain tells Studio how to navigate from the root entry to the specific nested field. + +#### Key Concepts + +| Attribute | Value | Purpose | +|-----------|-------|---------| +| `data-hygraph-entry-id` | Always the **root page/entry ID** | Identifies which Hygraph entry contains this content | +| `data-hygraph-field-api-id` | The component field name in your schema | Identifies which field to open in the editor | +| `data-hygraph-component-chain` | JSON array of `{fieldApiId, instanceId}` | Describes the path from root entry to the nested field | + +**Important:** `data-hygraph-entry-id` is always the root entry ID (e.g., page or article), even for deeply nested components. The component chain handles the navigation to nested fields—you never use the component's ID as the entry ID. + +#### What is `instanceId`? + +The `instanceId` is the unique identifier for each component instance, returned by Hygraph in your GraphQL response: + +```graphql +query { + page(where: { id: "page_123" }) { + id # Root entry ID → use for data-hygraph-entry-id + title + contentSections { # Modular component field + ... on HeroSection { + id # ← This is the instanceId for the component chain + headline + subheadline + } + ... on FeatureGrid { + id # ← instanceId + features { + id # ← instanceId for nested components + title + description + } + } + } + } +} +``` -Each element in the array must contain: -- `fieldApiId`: the API ID of the component field in your schema -- `instanceId`: the ID returned by Hygraph for that component entry +#### Single-Level Components + +For a field inside a component list (e.g., `Page.contentSections[]`): + +```tsx +{page.contentSections.map((section) => { + const chain = [ + createComponentChainLink('contentSections', section.id) + ]; + + return ( +

+ {section.headline} +

+ ); +})} +``` +The resulting HTML: ```html - - - 2 - + Welcome to Our Site + +``` - -
+#### Deeply Nested Components + +For components inside other components (e.g., `Page.contentSections[].features[]`): + +```tsx +{page.contentSections.map((section, sectionIndex) => ( +
+ {section.features?.map((feature, featureIndex) => { + // Build the chain: page → contentSections → features + const chain = [ + createComponentChainLink('contentSections', section.id), + createComponentChainLink('features', feature.id) + ]; + + return ( +
+

+ {feature.title} +

+

+ {feature.description} +

+
+ ); + })} +
+))} +``` + +#### Union/Modular Components (Multiple Component Types) + +When a field accepts different component types, handle each type in a switch statement: + +```tsx +{page.contentSections.map((section) => { + const chain = [createComponentChainLink('contentSections', section.id)]; + + switch (section.__typename) { + case 'HeroSection': + return ( +
+

+ {section.headline} +

+
+ ); + + case 'FeatureGrid': + return ( +
+

+ {section.gridTitle} +

+ {/* Render nested features with extended chain */} +
+ ); + + default: + return null; + } +})} ``` -Union components work the same way—the chain lists each component hop down to the field you want to tag. Always serialize the array with double quotes so the HTML attribute remains valid. +#### Complete Example: Page with Modular Content -> Tip: Instead of hand-writing JSON strings, use the helpers exported from `@hygraph/preview-sdk/core`: -> ```tsx -> import { -> createPreviewAttributes, -> createComponentChainLink, -> } from '@hygraph/preview-sdk/core'; +Here's a full example showing a page template with multiple component types and nesting: + +```tsx +import { + createPreviewAttributes, + createComponentChainLink, +} from '@hygraph/preview-sdk/core'; + +interface Page { + id: string; + title: string; + contentSections: Array; +} + +export function PageTemplate({ page }: { page: Page }) { + return ( +
+ {/* Simple field - no component chain needed */} +

+ {page.title} +

+ + {/* Modular content sections */} + {page.contentSections.map((section, index) => { + const sectionChain = [ + createComponentChainLink('contentSections', section.id) + ]; + + switch (section.__typename) { + case 'HeroSection': + return ( +
+

+ {section.headline} +

+
+
+ ); + + case 'FeatureGrid': + return ( +
+ {section.features.map((feature, featureIndex) => { + // Extend the chain for nested components + const featureChain = [ + ...sectionChain, + createComponentChainLink('features', feature.id) + ]; + + return ( +
+

+ {feature.title} +

+

+ {feature.description} +

+
+ ); + })} +
+ ); + + case 'Testimonial': + return ( +
+ {section.quote} +
+ ); + + default: + return null; + } + })} +
+ ); +} +``` + +#### Using Raw HTML Attributes (Without Helpers) + +If you prefer not to use the helper functions, you can write the attributes directly: + +```html + + -> const attributes = createPreviewAttributes({ -> entryId: recipe.id, -> fieldApiId: 'notes', -> componentChain: [ -> createComponentChainLink('recipeSteps', step.id), -> createComponentChainLink('tips', tip.id), -> ], -> }); -> ``` -> Apply the returned attributes to your element with the JSX spread operator. + Welcome + + + +

+ Feature description here +

+``` + +> **Note:** Always use double quotes inside the JSON string and single quotes for the HTML attribute value to ensure valid HTML. ## Framework Guides diff --git a/package.json b/package.json index 4e253a0..c3d6d47 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hygraph/preview-sdk", - "version": "1.0.0", + "version": "1.0.1", "description": "Content preview SDK for seamless real-time content editing in Hygraph CMS", "publishConfig": { "access": "public"