@wix/web5-core 1.56.1 → 1.57.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/client/wixAuthFetch.js +2 -2
- package/dist/cjs/client/wixAuthFetch.js.map +1 -1
- package/dist/cjs/component/componentDefinitions/HeroEntitySectionDefinition.js +20 -15
- package/dist/cjs/component/componentDefinitions/HeroEntitySectionDefinition.js.map +1 -1
- package/dist/cjs/component/componentDefinitions/HeroSectionDefinition.js +12 -4
- package/dist/cjs/component/componentDefinitions/HeroSectionDefinition.js.map +1 -1
- package/dist/cjs/component/componentDefinitions/listItemsSectionDefinition.js +24 -29
- package/dist/cjs/component/componentDefinitions/listItemsSectionDefinition.js.map +1 -1
- package/dist/cjs/component/componentParser.js +8 -1
- package/dist/cjs/component/componentParser.js.map +1 -1
- package/dist/cjs/component/types.js.map +1 -1
- package/dist/cjs/components/placement/PlacementResponseRenderer.css +0 -4
- package/dist/cjs/components/placement/PlacementResponseRenderer.js +11 -33
- package/dist/cjs/components/placement/PlacementResponseRenderer.js.map +1 -1
- package/dist/cjs/components/placement/buildPlacementDependencies.js.map +1 -1
- package/dist/cjs/components/ui/OptimizedImage.js +59 -14
- package/dist/cjs/components/ui/OptimizedImage.js.map +1 -1
- package/dist/cjs/components/ui/SectionSkeleton.css +19 -0
- package/dist/cjs/components/ui/SectionSkeleton.js +8 -4
- package/dist/cjs/components/ui/SectionSkeleton.js.map +1 -1
- package/dist/cjs/components/ui/UserQuery.css +72 -0
- package/dist/cjs/components/ui/UserQuery.js +131 -37
- package/dist/cjs/components/ui/UserQuery.js.map +1 -1
- package/dist/cjs/context/UserQueryContext.js +34 -0
- package/dist/cjs/context/UserQueryContext.js.map +1 -0
- package/dist/cjs/entity/defaultExtractor.js +9 -2
- package/dist/cjs/entity/defaultExtractor.js.map +1 -1
- package/dist/cjs/entity/fetchEntityListData.js +13 -26
- package/dist/cjs/entity/fetchEntityListData.js.map +1 -1
- package/dist/cjs/entity/index.js +5 -1
- package/dist/cjs/entity/index.js.map +1 -1
- package/dist/cjs/entity/listEntityItems.js +90 -0
- package/dist/cjs/entity/listEntityItems.js.map +1 -0
- package/dist/cjs/hostScope.js +63 -0
- package/dist/cjs/hostScope.js.map +1 -0
- package/dist/cjs/index.js +38 -13
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/patternValidator/validator.test.js +61 -61
- package/dist/cjs/patternValidator/validator.test.js.map +1 -1
- package/dist/cjs/registry/ComponentRegistry.js +22 -2
- package/dist/cjs/registry/ComponentRegistry.js.map +1 -1
- package/dist/cjs/registry/index.js +1 -3
- package/dist/cjs/registry/index.js.map +1 -1
- package/dist/cjs/registry/types.js.map +1 -1
- package/dist/cjs/styles/base-utilities.css +35 -0
- package/dist/cjs/styles/components.css +1 -0
- package/dist/cjs/styles/host-reset.css +100 -0
- package/dist/cjs/styles/tailwind-theme.css +6 -6
- package/dist/cjs/utils/backendEnvironment.js +78 -0
- package/dist/cjs/utils/backendEnvironment.js.map +1 -0
- package/dist/cjs/utils/entityLinkParser.js +3 -1
- package/dist/cjs/utils/entityLinkParser.js.map +1 -1
- package/dist/cjs/utils/imageBackdrop.js +269 -0
- package/dist/cjs/utils/imageBackdrop.js.map +1 -0
- package/dist/cjs/utils/intentExtractor.js +20 -9
- package/dist/cjs/utils/intentExtractor.js.map +1 -1
- package/dist/cjs/utils/productBackHandoff.js +106 -0
- package/dist/cjs/utils/productBackHandoff.js.map +1 -0
- package/dist/cjs/utils/refreshPrompts.js +72 -0
- package/dist/cjs/utils/refreshPrompts.js.map +1 -0
- package/dist/esm/client/wixAuthFetch.js +2 -2
- package/dist/esm/client/wixAuthFetch.js.map +1 -1
- package/dist/esm/component/componentDefinitions/HeroEntitySectionDefinition.js +20 -15
- package/dist/esm/component/componentDefinitions/HeroEntitySectionDefinition.js.map +1 -1
- package/dist/esm/component/componentDefinitions/HeroSectionDefinition.js +12 -4
- package/dist/esm/component/componentDefinitions/HeroSectionDefinition.js.map +1 -1
- package/dist/esm/component/componentDefinitions/listItemsSectionDefinition.js +25 -30
- package/dist/esm/component/componentDefinitions/listItemsSectionDefinition.js.map +1 -1
- package/dist/esm/component/componentParser.js +8 -1
- package/dist/esm/component/componentParser.js.map +1 -1
- package/dist/esm/component/types.js.map +1 -1
- package/dist/esm/components/placement/PlacementResponseRenderer.css +0 -4
- package/dist/esm/components/placement/PlacementResponseRenderer.js +1 -16
- package/dist/esm/components/placement/PlacementResponseRenderer.js.map +1 -1
- package/dist/esm/components/placement/buildPlacementDependencies.js.map +1 -1
- package/dist/esm/components/ui/OptimizedImage.js +50 -5
- package/dist/esm/components/ui/OptimizedImage.js.map +1 -1
- package/dist/esm/components/ui/SectionSkeleton.css +19 -0
- package/dist/esm/components/ui/SectionSkeleton.js +5 -1
- package/dist/esm/components/ui/SectionSkeleton.js.map +1 -1
- package/dist/esm/components/ui/UserQuery.css +72 -0
- package/dist/esm/components/ui/UserQuery.js +52 -6
- package/dist/esm/components/ui/UserQuery.js.map +1 -1
- package/dist/esm/context/UserQueryContext.js +21 -0
- package/dist/esm/context/UserQueryContext.js.map +1 -0
- package/dist/esm/entity/defaultExtractor.js +9 -2
- package/dist/esm/entity/defaultExtractor.js.map +1 -1
- package/dist/esm/entity/fetchEntityListData.js +14 -26
- package/dist/esm/entity/fetchEntityListData.js.map +1 -1
- package/dist/esm/entity/index.js +1 -0
- package/dist/esm/entity/index.js.map +1 -1
- package/dist/esm/entity/listEntityItems.js +85 -0
- package/dist/esm/entity/listEntityItems.js.map +1 -0
- package/dist/esm/hostScope.js +59 -0
- package/dist/esm/hostScope.js.map +1 -0
- package/dist/esm/index.js +13 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/patternValidator/validator.test.js +61 -61
- package/dist/esm/patternValidator/validator.test.js.map +1 -1
- package/dist/esm/registry/ComponentRegistry.js +22 -2
- package/dist/esm/registry/ComponentRegistry.js.map +1 -1
- package/dist/esm/registry/index.js +0 -1
- package/dist/esm/registry/index.js.map +1 -1
- package/dist/esm/registry/types.js.map +1 -1
- package/dist/esm/styles/base-utilities.css +35 -0
- package/dist/esm/styles/components.css +1 -0
- package/dist/esm/styles/host-reset.css +100 -0
- package/dist/esm/styles/tailwind-theme.css +6 -6
- package/dist/esm/utils/backendEnvironment.js +71 -0
- package/dist/esm/utils/backendEnvironment.js.map +1 -0
- package/dist/esm/utils/entityLinkParser.js +3 -1
- package/dist/esm/utils/entityLinkParser.js.map +1 -1
- package/dist/esm/utils/imageBackdrop.js +262 -0
- package/dist/esm/utils/imageBackdrop.js.map +1 -0
- package/dist/esm/utils/intentExtractor.js +21 -12
- package/dist/esm/utils/intentExtractor.js.map +1 -1
- package/dist/esm/utils/productBackHandoff.js +100 -0
- package/dist/esm/utils/productBackHandoff.js.map +1 -0
- package/dist/esm/utils/refreshPrompts.js +67 -0
- package/dist/esm/utils/refreshPrompts.js.map +1 -0
- package/dist/types/component/componentDefinitions/HeroEntitySectionDefinition.d.ts.map +1 -1
- package/dist/types/component/componentDefinitions/HeroSectionDefinition.d.ts.map +1 -1
- package/dist/types/component/componentDefinitions/listItemsSectionDefinition.d.ts +2 -2
- package/dist/types/component/componentDefinitions/listItemsSectionDefinition.d.ts.map +1 -1
- package/dist/types/component/componentParser.d.ts.map +1 -1
- package/dist/types/component/types.d.ts +1 -5
- package/dist/types/component/types.d.ts.map +1 -1
- package/dist/types/components/placement/PlacementResponseRenderer.d.ts +1 -1
- package/dist/types/components/placement/PlacementResponseRenderer.d.ts.map +1 -1
- package/dist/types/components/placement/buildPlacementDependencies.d.ts +1 -2
- package/dist/types/components/placement/buildPlacementDependencies.d.ts.map +1 -1
- package/dist/types/components/ui/OptimizedImage.d.ts +9 -0
- package/dist/types/components/ui/OptimizedImage.d.ts.map +1 -1
- package/dist/types/components/ui/SectionSkeleton.d.ts.map +1 -1
- package/dist/types/components/ui/UserQuery.d.ts +21 -0
- package/dist/types/components/ui/UserQuery.d.ts.map +1 -1
- package/dist/types/context/UserQueryContext.d.ts +12 -0
- package/dist/types/context/UserQueryContext.d.ts.map +1 -0
- package/dist/types/entity/defaultExtractor.d.ts.map +1 -1
- package/dist/types/entity/fetchEntityListData.d.ts +0 -2
- package/dist/types/entity/fetchEntityListData.d.ts.map +1 -1
- package/dist/types/entity/index.d.ts +1 -0
- package/dist/types/entity/index.d.ts.map +1 -1
- package/dist/types/entity/listEntityItems.d.ts +40 -0
- package/dist/types/entity/listEntityItems.d.ts.map +1 -0
- package/dist/types/hostScope.d.ts +83 -0
- package/dist/types/hostScope.d.ts.map +1 -0
- package/dist/types/index.d.ts +11 -7
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/registry/ComponentRegistry.d.ts +8 -0
- package/dist/types/registry/ComponentRegistry.d.ts.map +1 -1
- package/dist/types/registry/index.d.ts +0 -1
- package/dist/types/registry/index.d.ts.map +1 -1
- package/dist/types/registry/types.d.ts +5 -6
- package/dist/types/registry/types.d.ts.map +1 -1
- package/dist/types/utils/backendEnvironment.d.ts +30 -0
- package/dist/types/utils/backendEnvironment.d.ts.map +1 -0
- package/dist/types/utils/entityLinkParser.d.ts.map +1 -1
- package/dist/types/utils/imageBackdrop.d.ts +102 -0
- package/dist/types/utils/imageBackdrop.d.ts.map +1 -0
- package/dist/types/utils/intentExtractor.d.ts +21 -4
- package/dist/types/utils/intentExtractor.d.ts.map +1 -1
- package/dist/types/utils/productBackHandoff.d.ts +43 -0
- package/dist/types/utils/productBackHandoff.d.ts.map +1 -0
- package/dist/types/utils/refreshPrompts.d.ts +32 -0
- package/dist/types/utils/refreshPrompts.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/components/placement/PlacementResponseRenderer.css +0 -4
- package/src/components/ui/SectionSkeleton.css +19 -0
- package/src/components/ui/UserQuery.css +72 -0
- package/src/styles/base-utilities.css +35 -0
- package/src/styles/components.css +1 -0
- package/src/styles/host-reset.css +100 -0
- package/src/styles/tailwind-theme.css +6 -6
- package/dist/cjs/registry/Intent.js +0 -19
- package/dist/cjs/registry/Intent.js.map +0 -1
- package/dist/cjs/utils/conversationApi.js +0 -52
- package/dist/cjs/utils/conversationApi.js.map +0 -1
- package/dist/cjs/utils/conversationMode.js +0 -23
- package/dist/cjs/utils/conversationMode.js.map +0 -1
- package/dist/esm/registry/Intent.js +0 -15
- package/dist/esm/registry/Intent.js.map +0 -1
- package/dist/esm/utils/conversationApi.js +0 -45
- package/dist/esm/utils/conversationApi.js.map +0 -1
- package/dist/esm/utils/conversationMode.js +0 -18
- package/dist/esm/utils/conversationMode.js.map +0 -1
- package/dist/types/registry/Intent.d.ts +0 -12
- package/dist/types/registry/Intent.d.ts.map +0 -1
- package/dist/types/utils/conversationApi.d.ts +0 -26
- package/dist/types/utils/conversationApi.d.ts.map +0 -1
- package/dist/types/utils/conversationMode.d.ts +0 -16
- package/dist/types/utils/conversationMode.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["../../../src/component/types.ts"],"sourcesContent":["import type { FC } from 'react';\nimport type { Callout } from '../types/callout';\n\n/** Props extracted from markdown (base layer). */\nexport interface BaseCompProps {}\nexport interface SlotCompProps extends BaseCompProps {\n callout?: Callout;\n}\n\nexport interface SectionCompProps extends BaseCompProps {\n callout?: Callout;\n}\n\n/** Section props with a slot. TSlot enforces which slot component this section accepts. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface SectionCompPropsWithSlot<TSlot extends FC<any> = FC<any>>\n extends SectionCompProps {\n slot?: TSlot;\n}\n\n// ----------------------\n// Base Components\n// ----------------------\n\nexport interface TextCompProps extends BaseCompProps {\n content: string;\n variant?: 'h1' | 'h2' | 'body' | 'caption';\n}\n\nexport interface ButtonCompProps extends BaseCompProps {\n label: string;\n variant?: 'primary' | 'secondary' | 'ghost';\n onClick?: string;\n}\n\nexport interface ImageCompProps extends BaseCompProps {\n src: string;\n alt: string;\n ratio?: '16:9' | '4:3' | '1:1' | '9:16' | '3:4';\n}\n\nexport interface BadgeCompProps extends BaseCompProps {\n label: string;\n color?: 'primary' | 'secondary' | 'success' | 'warning' | 'error';\n}\n\n// ----------------------\n// Hero Button (aligned to HeroSection1Button)\n// ----------------------\n\nexport interface HeroButton {\n id: string;\n text: string;\n variant?: 'primary' | 'secondary';\n onClick?: string;\n}\n\n// ----------------------\n// Slot Components\n// ----------------------\n\nexport interface KpiItemCompProps extends SlotCompProps {\n title: string;\n description: string;\n icon?: string;\n}\n\n/** Feature item — aligned to web50-server-ui Feature interface */\nexport interface FeatureItemCompProps extends SlotCompProps {\n title?: string;\n description?: string;\n icon?: string;\n}\n\n/** Feature card — aligned to web50-server-ui FeatureCard */\nexport interface FeatureCardCompProps extends SlotCompProps {\n title: string;\n description: string;\n imageUrl?: string;\n imageFromText?: boolean;\n linkText?: string;\n linkHref?: string;\n callout?: Callout;\n}\n\n/** Resolved entity data (populated at runtime via useResolveGenericEntityData) */\nexport interface EntityItemData {\n url: string;\n title: string;\n type: string;\n description?: string;\n excerpt?: string;\n imageUrl?: string;\n date?: string;\n publishDate?: string;\n author?: string;\n cmsItemId?: string;\n usage?: number;\n tags?: string[];\n /** Product vendor / brand name (e.g. \"HOKA\") */\n vendor?: string;\n /** Formatted price string (e.g. \"542.00 NIS\") */\n price?: string;\n /** Secondary product image URL — shown on hover */\n secondaryImageUrl?: string;\n /** Available sizes for the product */\n sizes?: string[];\n /** Original price before discount (formatted, e.g. \"494.00 NIS\") — shown with strikethrough */\n compareAtPrice?: string;\n /** Discount percentage (e.g. \"30% OFF\") */\n discountPercent?: string;\n /** Product variants with IDs and availability — used for add-to-cart and size display */\n variants?: {\n label: string;\n variantId: string;\n available: boolean;\n selectedOptions?: { name: string; value: string }[];\n price?: string;\n compareAtPrice?: string;\n }[];\n /** All product image URLs (not just featured + secondary) */\n allImages?: string[];\n /** Product option groups (e.g. Size, Color) with their available values */\n options?: { name: string; values: string[] }[];\n}\n\n/** Single entity item within an entity section */\nexport interface EntityItem {\n entityId: string;\n linkText?: string;\n entityType: string;\n entityUrl: string;\n description?: string;\n imageUrl?: string;\n /** Per-item callout from a blockquote inside the list item */\n callout?: Callout;\n /** Resolved at runtime via useResolveGenericEntityData hook; not produced by parse() */\n data?: EntityItemData;\n}\n\n// ---------------------------------------------------------------------------\n// Deprecated aliases — kept for seed-components compilation\n// ---------------------------------------------------------------------------\n/** @deprecated Use EntityItemData */\nexport type GenericEntityData = EntityItemData;\n/** @deprecated Use EntityItemData */\nexport type SolutionEntityData = EntityItemData;\n/** @deprecated Use EntityItemData */\nexport type BlogEntityData = EntityItemData;\n/** @deprecated Use EntityItem */\nexport type GenericEntityCompProps = EntityItem;\n\n/** Comparison row — aligned to web50-server-ui ComparisonRow */\nexport interface ComparisonRow {\n feature: string;\n iconHint?: string;\n values: (boolean | string)[];\n}\n\nexport interface ComparisonColumn {\n label: string;\n href?: string;\n entityId?: string;\n entityType?: string;\n}\n\n/** @deprecated Use Callout from types/callout instead */\nexport interface AiNarrativeCompProps extends SlotCompProps {\n content: string;\n}\n\n// ----------------------\n// Section Components\n// ----------------------\n\n/** Hero — aligned to HeroSection1Props */\nexport interface HeroCompProps extends SectionCompProps {\n headline: string;\n badge?: string | { text: string; showIndicator?: boolean };\n content?: string;\n buttons?: HeroButton[];\n image?: string;\n trailingList?: string;\n leadingQuote?: string;\n}\n\n/**\n * Entity hero — a hero section whose body carries one or more web5 entity\n * links (`web5://entity/...`). Shares the hero framing fields with\n * {@link HeroCompProps} but, instead of CTA buttons, surfaces the entities as\n * resolvable {@link EntityItem}s for rich rendering.\n */\nexport interface HeroEntityCompProps extends SectionCompProps {\n headline: string;\n badge?: string | { text: string; showIndicator?: boolean };\n content?: string;\n image?: string;\n leadingQuote?: string;\n items: EntityItem[];\n}\n\n/** KPI — aligned to KpiSectionProps */\nexport interface KpiCompProps\n extends SectionCompPropsWithSlot<KpiItemComponent> {\n title: string;\n items: KpiItemCompProps[];\n}\n\n/** Feature cards — aligned to FeatureCardsSectionProps */\nexport interface FeatureCardsCompProps extends SectionCompProps {\n cards: FeatureCardCompProps[];\n}\n\n/** Unified entity section — replaces EntityCompProps, SolutionEntityCompProps, BlogEntityCompProps */\nexport interface EntityCompProps extends SectionCompProps {\n title: string;\n description?: string;\n items: EntityItem[];\n}\n\n/** Comparison — aligned to ComparisonSection1Props */\nexport interface ComparisonCompProps extends SectionCompProps {\n title: string;\n description?: string;\n columnLabels: string[];\n columns?: ComparisonColumn[];\n rows: ComparisonRow[];\n featureColumnLabel?: string;\n ctaText?: string;\n ctaHref?: string;\n}\n\n/** General text — aligned to GeneralTextSectionProps (used by Fallback) */\nexport interface GeneralTextCompProps extends SectionCompProps {\n markdown: string;\n}\n\n/** Callout — aligned to CalloutSectionProps */\nexport interface CalloutCompProps extends SectionCompProps {\n callouts: Callout[];\n title?: string;\n relatedLinks?: { text: string; url: string }[];\n}\n\n/** Next steps — aligned to NextStepsSectionProps */\nexport interface NextStepsCompProps extends SectionCompProps {\n title: string;\n body?: string;\n backgroundImage?: string;\n steps: { content: string; iconHint?: string }[];\n}\n\n/** Feature section 9+ — aligned to FeatureSection9PlusProps */\nexport interface FeatureSection9PlusCompProps extends SectionCompProps {\n title: string;\n description?: string;\n features: { title?: string; description: string; iconHint?: string }[];\n}\n\n/** List items section — aligned to ListItemsSectionProps */\nexport interface ListItemsSectionCompProps extends SectionCompProps {\n title: string;\n description?: string;\n features: { title?: string; description: string }[];\n imageUrl?: string;\n imageFromText?: boolean;\n variant: 'list' | 'cards';\n}\n\nexport type ListItemsSectionComponent = FC<ListItemsSectionCompProps>;\n\n/** Error — aligned to ErrorSection */\nexport interface ErrorCompProps extends SectionCompProps {\n type: import('../errors/conversationErrorTypes').ConversationErrorType;\n}\n\n/** Skip/HTML/Search — null-component parsers */\nexport interface NullCompProps extends SectionCompProps {}\n\n/** @deprecated Use EntityCompProps */\nexport type SolutionEntityCompProps = EntityCompProps;\n/** @deprecated Use EntityCompProps */\nexport type BlogEntityCompProps = EntityCompProps;\n\n/** CTA Banner — dark purple gradient card with headline, description, and pill link buttons */\nexport interface CtaBannerCompProps extends SectionCompProps {\n headline: string;\n description?: string;\n links: { text: string; href: string }[];\n /** Contextual background image — resolved from allowed keywords during parse() */\n imageUrl?: string;\n imageFromText?: boolean;\n}\n\nexport type CtaBannerSectionComponent = FC<CtaBannerCompProps>;\n\n/** Text block — heading + body with an optional pullquote callout on the side */\nexport interface TextBlockCompProps extends SectionCompProps {\n title: string;\n description: string;\n}\n\n/** Personalized narrative — standalone section with no parse() definition */\nexport interface PersonalizedNarrativeCompProps extends SectionCompProps {\n title: string;\n content?: string;\n}\n\n// --------------------------------\n// Types of component - all components\n// --------------------------------\n\nexport type Component = BaseComponent | SlotComponent | SectionComponent;\n\nexport type BaseComponent = FC<BaseCompProps>;\nexport type SlotComponent = FC<SlotCompProps>;\nexport type SectionComponent = FC<SectionCompProps>;\n\n// Base Components\nexport type TextComponent = FC<TextCompProps>;\nexport type ButtonComponent = FC<ButtonCompProps>;\nexport type ImageComponent = FC<ImageCompProps>;\nexport type BadgeComponent = FC<BadgeCompProps>;\n\n// Slot Components\nexport type KpiItemComponent = FC<KpiItemCompProps>;\nexport type FeatureItemComponent = FC<FeatureItemCompProps>;\nexport type FeatureCardComponent = FC<FeatureCardCompProps>;\n/** @deprecated Use FC<EntityItem> */\nexport type GenericEntityComponent = FC<EntityItem>;\nexport type AiNarrativeComponent = FC<AiNarrativeCompProps>;\n\n// Section Components\nexport type ComparisonSectionComponent = FC<ComparisonCompProps>;\nexport type GeneralTextSectionComponent = FC<GeneralTextCompProps>;\nexport type TextBlockSectionComponent = FC<TextBlockCompProps>;\nexport type HeroSectionComponent = FC<HeroCompProps>;\nexport type HeroEntitySectionComponent = FC<HeroEntityCompProps>;\n\n// section components with slots\nexport type KpiSectionComponent = FC<KpiCompProps>;\nexport type FeatureCardsSectionComponent = FC<FeatureCardsCompProps>;\nexport type EntitySectionComponent = FC<EntityCompProps>;\n\n// New section component types for Phase 4\nexport type CalloutSectionComponent = FC<CalloutCompProps>;\nexport type NextStepsSectionComponent = FC<NextStepsCompProps>;\nexport type FeatureSection9PlusSectionComponent =\n FC<FeatureSection9PlusCompProps>;\nexport type NullSectionComponent = FC<NullCompProps>;\nexport type ErrorSectionComponent = FC<ErrorCompProps>;\nexport type SolutionEntitySectionComponent = FC<SolutionEntityCompProps>;\nexport type BlogEntitySectionComponent = FC<BlogEntityCompProps>;\nexport type PersonalizedNarrativeSectionComponent =\n FC<PersonalizedNarrativeCompProps>;\n\nexport type PropsOf<T> = T extends (props: infer P) => unknown ? P : never;\n\nexport interface SectionFixture<TProps> {\n markdown: string;\n expected: Partial<TProps>;\n}\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["../../../src/component/types.ts"],"sourcesContent":["import type { FC } from 'react';\nimport type { Callout } from '../types/callout';\n\n/** Props extracted from markdown (base layer). */\nexport interface BaseCompProps {}\nexport interface SlotCompProps extends BaseCompProps {\n callout?: Callout;\n}\n\nexport interface SectionCompProps extends BaseCompProps {\n callout?: Callout;\n}\n\n/** Section props with a slot. TSlot enforces which slot component this section accepts. */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport interface SectionCompPropsWithSlot<TSlot extends FC<any> = FC<any>>\n extends SectionCompProps {\n slot?: TSlot;\n}\n\n// ----------------------\n// Base Components\n// ----------------------\n\nexport interface TextCompProps extends BaseCompProps {\n content: string;\n variant?: 'h1' | 'h2' | 'body' | 'caption';\n}\n\nexport interface ButtonCompProps extends BaseCompProps {\n label: string;\n variant?: 'primary' | 'secondary' | 'ghost';\n onClick?: string;\n}\n\nexport interface ImageCompProps extends BaseCompProps {\n src: string;\n alt: string;\n ratio?: '16:9' | '4:3' | '1:1' | '9:16' | '3:4';\n}\n\nexport interface BadgeCompProps extends BaseCompProps {\n label: string;\n color?: 'primary' | 'secondary' | 'success' | 'warning' | 'error';\n}\n\n// ----------------------\n// Hero Button (aligned to HeroSection1Button)\n// ----------------------\n\nexport interface HeroButton {\n id: string;\n text: string;\n variant?: 'primary' | 'secondary';\n onClick?: string;\n}\n\n// ----------------------\n// Slot Components\n// ----------------------\n\nexport interface KpiItemCompProps extends SlotCompProps {\n title: string;\n description: string;\n icon?: string;\n}\n\n/** Feature item — aligned to web50-server-ui Feature interface */\nexport interface FeatureItemCompProps extends SlotCompProps {\n title?: string;\n description?: string;\n icon?: string;\n}\n\n/** Feature card — aligned to web50-server-ui FeatureCard */\nexport interface FeatureCardCompProps extends SlotCompProps {\n title: string;\n description: string;\n imageUrl?: string;\n imageFromText?: boolean;\n linkText?: string;\n linkHref?: string;\n callout?: Callout;\n}\n\n/** Resolved entity data (populated at runtime via useResolveGenericEntityData) */\nexport interface EntityItemData {\n url: string;\n title: string;\n type: string;\n description?: string;\n excerpt?: string;\n imageUrl?: string;\n date?: string;\n publishDate?: string;\n author?: string;\n cmsItemId?: string;\n usage?: number;\n tags?: string[];\n /** Product vendor / brand name (e.g. \"HOKA\") */\n vendor?: string;\n /** Formatted price string (e.g. \"542.00 NIS\") */\n price?: string;\n /** Secondary product image URL — shown on hover */\n secondaryImageUrl?: string;\n /** Available sizes for the product */\n sizes?: string[];\n /** Original price before discount (formatted, e.g. \"494.00 NIS\") — shown with strikethrough */\n compareAtPrice?: string;\n /** Discount percentage (e.g. \"30% OFF\") */\n discountPercent?: string;\n /** Product variants with IDs and availability — used for add-to-cart and size display */\n variants?: {\n label: string;\n variantId: string;\n available: boolean;\n selectedOptions?: { name: string; value: string }[];\n price?: string;\n compareAtPrice?: string;\n }[];\n /** All product image URLs (not just featured + secondary) */\n allImages?: string[];\n /** Product option groups (e.g. Size, Color) with their available values */\n options?: { name: string; values: string[] }[];\n}\n\n/** Single entity item within an entity section */\nexport interface EntityItem {\n entityId: string;\n linkText?: string;\n entityType: string;\n entityUrl: string;\n description?: string;\n imageUrl?: string;\n /** Per-item callout from a blockquote inside the list item */\n callout?: Callout;\n /** Resolved at runtime via useResolveGenericEntityData hook; not produced by parse() */\n data?: EntityItemData;\n}\n\n// ---------------------------------------------------------------------------\n// Deprecated aliases — kept for seed-components compilation\n// ---------------------------------------------------------------------------\n/** @deprecated Use EntityItemData */\nexport type GenericEntityData = EntityItemData;\n/** @deprecated Use EntityItemData */\nexport type SolutionEntityData = EntityItemData;\n/** @deprecated Use EntityItemData */\nexport type BlogEntityData = EntityItemData;\n/** @deprecated Use EntityItem */\nexport type GenericEntityCompProps = EntityItem;\n\n/** Comparison row — aligned to web50-server-ui ComparisonRow */\nexport interface ComparisonRow {\n feature: string;\n iconHint?: string;\n values: (boolean | string)[];\n}\n\nexport interface ComparisonColumn {\n label: string;\n href?: string;\n entityId?: string;\n entityType?: string;\n}\n\n/** @deprecated Use Callout from types/callout instead */\nexport interface AiNarrativeCompProps extends SlotCompProps {\n content: string;\n}\n\n// ----------------------\n// Section Components\n// ----------------------\n\n/** Hero — aligned to HeroSection1Props */\nexport interface HeroCompProps extends SectionCompProps {\n headline: string;\n badge?: string | { text: string; showIndicator?: boolean };\n content?: string;\n buttons?: HeroButton[];\n image?: string;\n trailingList?: string;\n leadingQuote?: string;\n}\n\n/**\n * Entity hero — a hero section whose body carries one or more web5 entity\n * links (`web5://entity/...`). Shares the hero framing fields with\n * {@link HeroCompProps} but, instead of CTA buttons, surfaces the entities as\n * resolvable {@link EntityItem}s for rich rendering.\n */\nexport interface HeroEntityCompProps extends SectionCompProps {\n headline: string;\n badge?: string | { text: string; showIndicator?: boolean };\n content?: string;\n image?: string;\n leadingQuote?: string;\n items: EntityItem[];\n}\n\n/** KPI — aligned to KpiSectionProps */\nexport interface KpiCompProps\n extends SectionCompPropsWithSlot<KpiItemComponent> {\n title: string;\n items: KpiItemCompProps[];\n}\n\n/** Feature cards — aligned to FeatureCardsSectionProps */\nexport interface FeatureCardsCompProps extends SectionCompProps {\n cards: FeatureCardCompProps[];\n}\n\n/** Unified entity section — replaces EntityCompProps, SolutionEntityCompProps, BlogEntityCompProps */\nexport interface EntityCompProps extends SectionCompProps {\n title: string;\n description?: string;\n items: EntityItem[];\n}\n\n/** Comparison — aligned to ComparisonSection1Props */\nexport interface ComparisonCompProps extends SectionCompProps {\n title: string;\n description?: string;\n columnLabels: string[];\n columns?: ComparisonColumn[];\n rows: ComparisonRow[];\n featureColumnLabel?: string;\n ctaText?: string;\n ctaHref?: string;\n}\n\n/** General text — aligned to GeneralTextSectionProps (used by Fallback) */\nexport interface GeneralTextCompProps extends SectionCompProps {\n markdown: string;\n}\n\n/** Callout — aligned to CalloutSectionProps */\nexport interface CalloutCompProps extends SectionCompProps {\n callouts: Callout[];\n title?: string;\n relatedLinks?: { text: string; url: string }[];\n}\n\n/** Next steps — aligned to NextStepsSectionProps */\nexport interface NextStepsCompProps extends SectionCompProps {\n title: string;\n body?: string;\n backgroundImage?: string;\n steps: { content: string; iconHint?: string }[];\n}\n\n/** Feature section 9+ — aligned to FeatureSection9PlusProps */\nexport interface FeatureSection9PlusCompProps extends SectionCompProps {\n title: string;\n description?: string;\n features: { title?: string; description: string; iconHint?: string }[];\n}\n\n/** List items section — title + a list of feature items. */\nexport interface ListItemsSectionCompProps extends SectionCompProps {\n title: string;\n features: { title?: string; description: string }[];\n}\n\nexport type ListItemsSectionComponent = FC<ListItemsSectionCompProps>;\n\n/** Error — aligned to ErrorSection */\nexport interface ErrorCompProps extends SectionCompProps {\n type: import('../errors/conversationErrorTypes').ConversationErrorType;\n}\n\n/** Skip/HTML/Search — null-component parsers */\nexport interface NullCompProps extends SectionCompProps {}\n\n/** @deprecated Use EntityCompProps */\nexport type SolutionEntityCompProps = EntityCompProps;\n/** @deprecated Use EntityCompProps */\nexport type BlogEntityCompProps = EntityCompProps;\n\n/** CTA Banner — dark purple gradient card with headline, description, and pill link buttons */\nexport interface CtaBannerCompProps extends SectionCompProps {\n headline: string;\n description?: string;\n links: { text: string; href: string }[];\n /** Contextual background image — resolved from allowed keywords during parse() */\n imageUrl?: string;\n imageFromText?: boolean;\n}\n\nexport type CtaBannerSectionComponent = FC<CtaBannerCompProps>;\n\n/** Text block — heading + body with an optional pullquote callout on the side */\nexport interface TextBlockCompProps extends SectionCompProps {\n title: string;\n description: string;\n}\n\n/** Personalized narrative — standalone section with no parse() definition */\nexport interface PersonalizedNarrativeCompProps extends SectionCompProps {\n title: string;\n content?: string;\n}\n\n// --------------------------------\n// Types of component - all components\n// --------------------------------\n\nexport type Component = BaseComponent | SlotComponent | SectionComponent;\n\nexport type BaseComponent = FC<BaseCompProps>;\nexport type SlotComponent = FC<SlotCompProps>;\nexport type SectionComponent = FC<SectionCompProps>;\n\n// Base Components\nexport type TextComponent = FC<TextCompProps>;\nexport type ButtonComponent = FC<ButtonCompProps>;\nexport type ImageComponent = FC<ImageCompProps>;\nexport type BadgeComponent = FC<BadgeCompProps>;\n\n// Slot Components\nexport type KpiItemComponent = FC<KpiItemCompProps>;\nexport type FeatureItemComponent = FC<FeatureItemCompProps>;\nexport type FeatureCardComponent = FC<FeatureCardCompProps>;\n/** @deprecated Use FC<EntityItem> */\nexport type GenericEntityComponent = FC<EntityItem>;\nexport type AiNarrativeComponent = FC<AiNarrativeCompProps>;\n\n// Section Components\nexport type ComparisonSectionComponent = FC<ComparisonCompProps>;\nexport type GeneralTextSectionComponent = FC<GeneralTextCompProps>;\nexport type TextBlockSectionComponent = FC<TextBlockCompProps>;\nexport type HeroSectionComponent = FC<HeroCompProps>;\nexport type HeroEntitySectionComponent = FC<HeroEntityCompProps>;\n\n// section components with slots\nexport type KpiSectionComponent = FC<KpiCompProps>;\nexport type FeatureCardsSectionComponent = FC<FeatureCardsCompProps>;\nexport type EntitySectionComponent = FC<EntityCompProps>;\n\n// New section component types for Phase 4\nexport type CalloutSectionComponent = FC<CalloutCompProps>;\nexport type NextStepsSectionComponent = FC<NextStepsCompProps>;\nexport type FeatureSection9PlusSectionComponent =\n FC<FeatureSection9PlusCompProps>;\nexport type NullSectionComponent = FC<NullCompProps>;\nexport type ErrorSectionComponent = FC<ErrorCompProps>;\nexport type SolutionEntitySectionComponent = FC<SolutionEntityCompProps>;\nexport type BlogEntitySectionComponent = FC<BlogEntityCompProps>;\nexport type PersonalizedNarrativeSectionComponent =\n FC<PersonalizedNarrativeCompProps>;\n\nexport type PropsOf<T> = T extends (props: infer P) => unknown ? P : never;\n\nexport interface SectionFixture<TProps> {\n markdown: string;\n expected: Partial<TProps>;\n}\n"],"mappings":"","ignoreList":[]}
|
|
@@ -101,21 +101,6 @@ const StarIcon = () => /*#__PURE__*/_react.default.createElement('svg', {
|
|
|
101
101
|
d: 'M8 0 L9.6 6.4 L16 8 L9.6 9.6 L8 16 L6.4 9.6 L0 8 L6.4 6.4 Z',
|
|
102
102
|
fill: 'currentColor'
|
|
103
103
|
}));
|
|
104
|
-
const ChevronIcon = () => /*#__PURE__*/_react.default.createElement('svg', {
|
|
105
|
-
className: 'w5-placement__show-more-icon',
|
|
106
|
-
viewBox: '0 0 16 16',
|
|
107
|
-
width: 14,
|
|
108
|
-
height: 14,
|
|
109
|
-
'aria-hidden': true,
|
|
110
|
-
focusable: false
|
|
111
|
-
}, /*#__PURE__*/_react.default.createElement('path', {
|
|
112
|
-
d: 'M4 6 L8 10 L12 6',
|
|
113
|
-
fill: 'none',
|
|
114
|
-
stroke: 'currentColor',
|
|
115
|
-
strokeWidth: 1.6,
|
|
116
|
-
strokeLinecap: 'round',
|
|
117
|
-
strokeLinejoin: 'round'
|
|
118
|
-
}));
|
|
119
104
|
const PlacementResponseRenderer = ({
|
|
120
105
|
sections,
|
|
121
106
|
prompt,
|
|
@@ -160,7 +145,7 @@ const PlacementResponseRenderer = ({
|
|
|
160
145
|
__self: void 0,
|
|
161
146
|
__source: {
|
|
162
147
|
fileName: _jsxFileName,
|
|
163
|
-
lineNumber:
|
|
148
|
+
lineNumber: 204,
|
|
164
149
|
columnNumber: 5
|
|
165
150
|
}
|
|
166
151
|
}, section.component));
|
|
@@ -178,7 +163,7 @@ const PlacementResponseRenderer = ({
|
|
|
178
163
|
__self: void 0,
|
|
179
164
|
__source: {
|
|
180
165
|
fileName: _jsxFileName,
|
|
181
|
-
lineNumber:
|
|
166
|
+
lineNumber: 214,
|
|
182
167
|
columnNumber: 5
|
|
183
168
|
}
|
|
184
169
|
}, eyebrow && /*#__PURE__*/_react.default.createElement("div", {
|
|
@@ -186,14 +171,14 @@ const PlacementResponseRenderer = ({
|
|
|
186
171
|
__self: void 0,
|
|
187
172
|
__source: {
|
|
188
173
|
fileName: _jsxFileName,
|
|
189
|
-
lineNumber:
|
|
174
|
+
lineNumber: 225,
|
|
190
175
|
columnNumber: 9
|
|
191
176
|
}
|
|
192
177
|
}, /*#__PURE__*/_react.default.createElement(StarIcon, {
|
|
193
178
|
__self: void 0,
|
|
194
179
|
__source: {
|
|
195
180
|
fileName: _jsxFileName,
|
|
196
|
-
lineNumber:
|
|
181
|
+
lineNumber: 226,
|
|
197
182
|
columnNumber: 11
|
|
198
183
|
}
|
|
199
184
|
}), /*#__PURE__*/_react.default.createElement("span", {
|
|
@@ -201,7 +186,7 @@ const PlacementResponseRenderer = ({
|
|
|
201
186
|
__self: void 0,
|
|
202
187
|
__source: {
|
|
203
188
|
fileName: _jsxFileName,
|
|
204
|
-
lineNumber:
|
|
189
|
+
lineNumber: 227,
|
|
205
190
|
columnNumber: 11
|
|
206
191
|
}
|
|
207
192
|
}, eyebrow)), query && /*#__PURE__*/_react.default.createElement("p", {
|
|
@@ -209,7 +194,7 @@ const PlacementResponseRenderer = ({
|
|
|
209
194
|
__self: void 0,
|
|
210
195
|
__source: {
|
|
211
196
|
fileName: _jsxFileName,
|
|
212
|
-
lineNumber:
|
|
197
|
+
lineNumber: 230,
|
|
213
198
|
columnNumber: 17
|
|
214
199
|
}
|
|
215
200
|
}, query), prompt && /*#__PURE__*/_react.default.createElement("header", {
|
|
@@ -217,7 +202,7 @@ const PlacementResponseRenderer = ({
|
|
|
217
202
|
__self: void 0,
|
|
218
203
|
__source: {
|
|
219
204
|
fileName: _jsxFileName,
|
|
220
|
-
lineNumber:
|
|
205
|
+
lineNumber: 231,
|
|
221
206
|
columnNumber: 18
|
|
222
207
|
}
|
|
223
208
|
}, prompt), sectionNodes, showMore && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", {
|
|
@@ -226,7 +211,7 @@ const PlacementResponseRenderer = ({
|
|
|
226
211
|
__self: void 0,
|
|
227
212
|
__source: {
|
|
228
213
|
fileName: _jsxFileName,
|
|
229
|
-
lineNumber:
|
|
214
|
+
lineNumber: 239,
|
|
230
215
|
columnNumber: 11
|
|
231
216
|
}
|
|
232
217
|
}), /*#__PURE__*/_react.default.createElement("a", {
|
|
@@ -236,24 +221,17 @@ const PlacementResponseRenderer = ({
|
|
|
236
221
|
__self: void 0,
|
|
237
222
|
__source: {
|
|
238
223
|
fileName: _jsxFileName,
|
|
239
|
-
lineNumber:
|
|
224
|
+
lineNumber: 240,
|
|
240
225
|
columnNumber: 11
|
|
241
226
|
}
|
|
242
227
|
}, /*#__PURE__*/_react.default.createElement("span", {
|
|
243
228
|
__self: void 0,
|
|
244
229
|
__source: {
|
|
245
230
|
fileName: _jsxFileName,
|
|
246
|
-
lineNumber:
|
|
247
|
-
columnNumber: 13
|
|
248
|
-
}
|
|
249
|
-
}, showMoreLabel ?? 'Show more'), /*#__PURE__*/_react.default.createElement(ChevronIcon, {
|
|
250
|
-
__self: void 0,
|
|
251
|
-
__source: {
|
|
252
|
-
fileName: _jsxFileName,
|
|
253
|
-
lineNumber: 267,
|
|
231
|
+
lineNumber: 245,
|
|
254
232
|
columnNumber: 13
|
|
255
233
|
}
|
|
256
|
-
}))));
|
|
234
|
+
}, showMoreLabel ?? 'Continue in Form AI'))));
|
|
257
235
|
};
|
|
258
236
|
exports.PlacementResponseRenderer = PlacementResponseRenderer;
|
|
259
237
|
//# sourceMappingURL=PlacementResponseRenderer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_jsxFileName","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","PlacementSmoothHeight","children","innerRef","React","useRef","height","setHeight","useState","useEffect","el","current","ResizeObserver","observer","offsetHeight","observe","disconnect","createElement","className","style","undefined","__self","__source","fileName","lineNumber","columnNumber","ref","exports","StarIcon","viewBox","width","focusable","d","fill","ChevronIcon","stroke","strokeWidth","strokeLinecap","strokeLinejoin","PlacementResponseRenderer","sections","prompt","eyebrow","query","variant","streaming","clamp","clampHeight","showMoreHref","showMoreLabel","rootRef","overflowing","setOverflowing","measure","scrollHeight","clientHeight","rootClass","filter","Boolean","join","sectionNodes","map","section","Fragment","key","id","sectionType","component","showMore","maxHeight","href"],"sources":["../../../../src/components/placement/PlacementResponseRenderer.tsx"],"sourcesContent":["/**\n * PlacementResponseRenderer (DL #088 D3.2, DL #097 visual pass).\n *\n * Renders the AI response inside a placement slot. Takes already-parsed\n * sections from the caller's parser and renders the placement chrome\n * (FormAI eyebrow + optional user-query chip) above them.\n *\n * The renderer deliberately does NOT call the parser itself — that's the\n * caller's job (the placement bundle wires the parser of its choice).\n *\n * No post-parse filtering: hero / next-steps exclusion is the **prompt's**\n * job (the LLM is instructed not to emit them), and there's no\n * `maxComponents` cap. Placement-specific designs for a section type (e.g. a\n * tailored rich-text fallback) belong as `{ placement: true }` registry\n * variants in the client package — `resolveSection(type, { placement: true })`\n * picks them automatically.\n *\n * Visual chrome (Figma 128:5251 framing / 128:5258 conversation):\n * - `variant` drives the card; both variants show the highlight border.\n * - `eyebrow` renders the FormAI star + label (chrome, opt-in).\n * - `query` renders the user's question as a chip (conversation only).\n * Styles live in `./PlacementResponseRenderer.css` (injected with the client UMD).\n */\nimport React, { Fragment, type FC, type ReactNode } from 'react';\nimport type { PlacementVariant } from '../../types/placement';\n\n/**\n * Minimal section shape the renderer needs. Designed to match\n * `web50-server-ui`'s `PageSection` shape (with a pre-instantiated `component`)\n * so the renderer works against today's parser output without modification.\n */\nexport interface PlacementSection {\n /** Stable id for React key. Falls back to `sectionType + index` if absent. */\n id?: string;\n /** Section type key (e.g., 'narrative', 'list-items', 'pros-cons'). */\n sectionType: string;\n /** Pre-instantiated React element from the parser. */\n component: ReactNode;\n}\n\n/**\n * Placement visual variant → `w5-placement--<variant>` class. Defined in\n * `../../types/placement` (DL #106 D1: free-form string, no longer a closed\n * `'informational' | 'conversation'` union) and re-exported here for back-compat\n * with existing `from '.../PlacementResponseRenderer'` imports.\n */\nexport type { PlacementVariant };\n\nexport interface PlacementResponseRendererProps {\n /** Already-parsed sections from `parseMarkdownToComponents`. */\n sections: readonly PlacementSection[];\n /** Deprecated plain-text prompt header (kept for back-compat). */\n prompt?: string;\n /**\n * Eyebrow label shown with the accent star at the top (e.g. \"FormAI\").\n * Chrome — opt-in; omit to render no eyebrow.\n */\n eyebrow?: string;\n /**\n * The user's question, rendered as a chip above the answer (conversation\n * variant, DL #097). Omit for the informational variant.\n */\n query?: string;\n /** Visual variant — both add the persistent gradient highlight border. */\n variant?: PlacementVariant;\n /**\n * Clamp the answer body to a max height with a fade-out and a \"Show more\"\n * affordance (DL #113) — Google-AI-Overview style. Opt-in; used by the\n * `searchResults` placement. The body is capped at `clampHeight` (or the\n * `--w5-placement-clamp-height` token); the fade + button appear only once\n * the content overflows and a `showMoreHref` is supplied.\n */\n clamp?: boolean;\n /** Clamp height in px (DL #113). Overrides `--w5-placement-clamp-height`. */\n clampHeight?: number;\n /**\n * Destination for \"Show more\" (DL #113) — the main Web5 page seeded with the\n * visitor's search terms (`<mainPage>?initialQuestion=<q>`). When absent the\n * button is not rendered (clamp + fade still apply).\n */\n showMoreHref?: string;\n /** Label for the \"Show more\" button (DL #113). Default `'Show more'`. */\n showMoreLabel?: string;\n /**\n * True while the answer is still streaming in. The highlight border stays\n * solid for the whole render and only starts its spin once this flips to\n * false (answer settled); it remains visible afterwards.\n */\n streaming?: boolean;\n /** Optional extra className for the placement root. */\n className?: string;\n}\n\n/**\n * Smooths out step-wise height changes in the placement slot: the\n * loader→content swap and each streamed section appending. `height: auto`\n * changes aren't CSS-animatable, so we measure the content's natural height\n * with a ResizeObserver and transition an explicit `height` on the wrapper\n * (see `.w5-placement__body` in the CSS). Falls back to natural auto-height\n * when ResizeObserver is unavailable (SSR, old jsdom).\n *\n * Mounted by the placement stream app (embed-placement) AROUND the\n * loader/content swap — not inside this renderer — so the swap itself\n * animates too.\n */\nexport const PlacementSmoothHeight: FC<{ children: ReactNode }> = ({\n children,\n}) => {\n const innerRef = React.useRef<HTMLDivElement | null>(null);\n const [height, setHeight] = React.useState<number | null>(null);\n\n React.useEffect(() => {\n const el = innerRef.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => {\n setHeight(el.offsetHeight);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n return (\n <div\n className=\"w5-placement__body\"\n style={height != null ? { height } : undefined}\n >\n {/* flow-root (in CSS) keeps child margins inside the measured box. */}\n <div ref={innerRef} className=\"w5-placement__body-inner\">\n {children}\n </div>\n </div>\n );\n};\n\nconst StarIcon: FC = () =>\n React.createElement(\n 'svg',\n {\n className: 'w5-placement__eyebrow-icon',\n viewBox: '0 0 16 16',\n width: 13,\n height: 13,\n 'aria-hidden': true,\n focusable: false,\n },\n React.createElement('path', {\n d: 'M8 0 L9.6 6.4 L16 8 L9.6 9.6 L8 16 L6.4 9.6 L0 8 L6.4 6.4 Z',\n fill: 'currentColor',\n }),\n );\n\nconst ChevronIcon: FC = () =>\n React.createElement(\n 'svg',\n {\n className: 'w5-placement__show-more-icon',\n viewBox: '0 0 16 16',\n width: 14,\n height: 14,\n 'aria-hidden': true,\n focusable: false,\n },\n React.createElement('path', {\n d: 'M4 6 L8 10 L12 6',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.6,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n }),\n );\n\nexport const PlacementResponseRenderer: FC<PlacementResponseRendererProps> = ({\n sections,\n prompt,\n eyebrow,\n query,\n variant,\n streaming,\n className,\n clamp,\n clampHeight,\n showMoreHref,\n showMoreLabel,\n}) => {\n // Overflow detection for the clamp (DL #113). The clamp caps the *root* card\n // (not a wrapper) so the answer sections stay direct children of the\n // placement root — clients lay them out with `:has(> …)` direct-child grids\n // (e.g. feature-com's search-overview two-column layout), which a wrapper\n // would break. With `max-height` + `overflow: hidden` the root's scrollHeight\n // is the full content and clientHeight is the capped box; the fade + \"Show\n // more\" only appear when the content actually overflows (a fade under a short\n // answer reads as broken). Re-measure on every section change (streaming) and\n // on container resize.\n const rootRef = React.useRef<HTMLElement | null>(null);\n const [overflowing, setOverflowing] = React.useState(false);\n\n React.useEffect(() => {\n if (!clamp) {\n setOverflowing(false);\n return;\n }\n const el = rootRef.current;\n if (!el) return;\n const measure = (): void =>\n setOverflowing(el.scrollHeight > el.clientHeight + 1);\n measure();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(measure);\n observer.observe(el);\n return () => observer.disconnect();\n }, [clamp, clampHeight, sections]);\n\n const rootClass = [\n 'w5-placement',\n variant ? `w5-placement--${variant}` : '',\n streaming ? 'w5-placement--streaming' : '',\n clamp ? 'w5-placement--clamped' : '',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ');\n\n const sectionNodes = sections.map((section, i) => (\n <Fragment key={section.id ?? `${section.sectionType}-${i}`}>\n {section.component}\n </Fragment>\n ));\n\n // The fade + button overlay the bottom of the clamped card. The button only\n // appears once the content actually overflows and a destination is supplied.\n const showMore = !!clamp && overflowing && !!showMoreHref;\n\n return (\n <section\n ref={rootRef}\n className={rootClass}\n data-w5-placement-renderer=\"\"\n style={\n clamp && clampHeight != null\n ? { maxHeight: `${clampHeight}px` }\n : undefined\n }\n >\n {eyebrow && (\n <div className=\"w5-placement__eyebrow\">\n <StarIcon />\n <span className=\"w5-placement__eyebrow-label\">{eyebrow}</span>\n </div>\n )}\n {query && <p className=\"w5-placement__query\">{query}</p>}\n {prompt && <header className=\"w5-placement__prompt\">{prompt}</header>}\n {sectionNodes}\n {/* Fade + \"Show more\" overlay the bottom of the clamped card. Both are\n absolutely positioned (out of flow), so they don't disturb the\n client's grid placement of the sections, and are clipped by the\n root's `overflow: hidden`. */}\n {showMore && (\n <>\n <div className=\"w5-placement__fade\" aria-hidden=\"true\" />\n <a\n className=\"w5-placement__show-more\"\n href={showMoreHref}\n aria-label=\"See the full answer on the AI page\"\n >\n <span>{showMoreLabel ?? 'Show more'}</span>\n <ChevronIcon />\n </a>\n </>\n )}\n </section>\n );\n};\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_jsxFileName","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","PlacementSmoothHeight","children","innerRef","React","useRef","height","setHeight","useState","useEffect","el","current","ResizeObserver","observer","offsetHeight","observe","disconnect","createElement","className","style","undefined","__self","__source","fileName","lineNumber","columnNumber","ref","exports","StarIcon","viewBox","width","focusable","d","fill","PlacementResponseRenderer","sections","prompt","eyebrow","query","variant","streaming","clamp","clampHeight","showMoreHref","showMoreLabel","rootRef","overflowing","setOverflowing","measure","scrollHeight","clientHeight","rootClass","filter","Boolean","join","sectionNodes","map","section","Fragment","key","id","sectionType","component","showMore","maxHeight","href"],"sources":["../../../../src/components/placement/PlacementResponseRenderer.tsx"],"sourcesContent":["/**\n * PlacementResponseRenderer (DL #088 D3.2, DL #097 visual pass).\n *\n * Renders the AI response inside a placement slot. Takes already-parsed\n * sections from the caller's parser and renders the placement chrome\n * (FormAI eyebrow + optional user-query chip) above them.\n *\n * The renderer deliberately does NOT call the parser itself — that's the\n * caller's job (the placement bundle wires the parser of its choice).\n *\n * No post-parse filtering: hero / next-steps exclusion is the **prompt's**\n * job (the LLM is instructed not to emit them), and there's no\n * `maxComponents` cap. Placement-specific designs for a section type (e.g. a\n * tailored rich-text fallback) belong as `{ placement: true }` registry\n * variants in the client package — `resolveSection(type, { placement: true })`\n * picks them automatically.\n *\n * Visual chrome (Figma 128:5251 framing / 128:5258 conversation):\n * - `variant` drives the card; both variants show the highlight border.\n * - `eyebrow` renders the FormAI star + label (chrome, opt-in).\n * - `query` renders the user's question as a chip (conversation only).\n * Styles live in `./PlacementResponseRenderer.css` (injected with the client UMD).\n */\nimport React, { Fragment, type FC, type ReactNode } from 'react';\nimport type { PlacementVariant } from '../../types/placement';\n\n/**\n * Minimal section shape the renderer needs. Designed to match\n * `web50-server-ui`'s `PageSection` shape (with a pre-instantiated `component`)\n * so the renderer works against today's parser output without modification.\n */\nexport interface PlacementSection {\n /** Stable id for React key. Falls back to `sectionType + index` if absent. */\n id?: string;\n /** Section type key (e.g., 'narrative', 'list-items', 'pros-cons'). */\n sectionType: string;\n /** Pre-instantiated React element from the parser. */\n component: ReactNode;\n}\n\n/**\n * Placement visual variant → `w5-placement--<variant>` class. Defined in\n * `../../types/placement` (DL #106 D1: free-form string, no longer a closed\n * `'informational' | 'conversation'` union) and re-exported here for back-compat\n * with existing `from '.../PlacementResponseRenderer'` imports.\n */\nexport type { PlacementVariant };\n\nexport interface PlacementResponseRendererProps {\n /** Already-parsed sections from `parseMarkdownToComponents`. */\n sections: readonly PlacementSection[];\n /** Deprecated plain-text prompt header (kept for back-compat). */\n prompt?: string;\n /**\n * Eyebrow label shown with the accent star at the top (e.g. \"FormAI\").\n * Chrome — opt-in; omit to render no eyebrow.\n */\n eyebrow?: string;\n /**\n * The user's question, rendered as a chip above the answer (conversation\n * variant, DL #097). Omit for the informational variant.\n */\n query?: string;\n /** Visual variant — both add the persistent gradient highlight border. */\n variant?: PlacementVariant;\n /**\n * Clamp the answer body to a max height with a fade-out and a \"Show more\"\n * affordance (DL #113) — Google-AI-Overview style. Opt-in; used by the\n * `searchResults` placement. The body is capped at `clampHeight` (or the\n * `--w5-placement-clamp-height` token); the fade + button appear only once\n * the content overflows and a `showMoreHref` is supplied.\n */\n clamp?: boolean;\n /** Clamp height in px (DL #113). Overrides `--w5-placement-clamp-height`. */\n clampHeight?: number;\n /**\n * Destination for \"Show more\" (DL #113) — the main Web5 page seeded with the\n * visitor's search terms (`<mainPage>?initialQuestion=<q>`). When absent the\n * button is not rendered (clamp + fade still apply).\n */\n showMoreHref?: string;\n /** Label for the \"Show more\" button (DL #113). Default `'Continue in Form AI'`. */\n showMoreLabel?: string;\n /**\n * True while the answer is still streaming in. The highlight border stays\n * solid for the whole render and only starts its spin once this flips to\n * false (answer settled); it remains visible afterwards.\n */\n streaming?: boolean;\n /** Optional extra className for the placement root. */\n className?: string;\n}\n\n/**\n * Smooths out step-wise height changes in the placement slot: the\n * loader→content swap and each streamed section appending. `height: auto`\n * changes aren't CSS-animatable, so we measure the content's natural height\n * with a ResizeObserver and transition an explicit `height` on the wrapper\n * (see `.w5-placement__body` in the CSS). Falls back to natural auto-height\n * when ResizeObserver is unavailable (SSR, old jsdom).\n *\n * Mounted by the placement stream app (embed-placement) AROUND the\n * loader/content swap — not inside this renderer — so the swap itself\n * animates too.\n */\nexport const PlacementSmoothHeight: FC<{ children: ReactNode }> = ({\n children,\n}) => {\n const innerRef = React.useRef<HTMLDivElement | null>(null);\n const [height, setHeight] = React.useState<number | null>(null);\n\n React.useEffect(() => {\n const el = innerRef.current;\n if (!el || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => {\n setHeight(el.offsetHeight);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n return (\n <div\n className=\"w5-placement__body\"\n style={height != null ? { height } : undefined}\n >\n {/* flow-root (in CSS) keeps child margins inside the measured box. */}\n <div ref={innerRef} className=\"w5-placement__body-inner\">\n {children}\n </div>\n </div>\n );\n};\n\nconst StarIcon: FC = () =>\n React.createElement(\n 'svg',\n {\n className: 'w5-placement__eyebrow-icon',\n viewBox: '0 0 16 16',\n width: 13,\n height: 13,\n 'aria-hidden': true,\n focusable: false,\n },\n React.createElement('path', {\n d: 'M8 0 L9.6 6.4 L16 8 L9.6 9.6 L8 16 L6.4 9.6 L0 8 L6.4 6.4 Z',\n fill: 'currentColor',\n }),\n );\n\nexport const PlacementResponseRenderer: FC<PlacementResponseRendererProps> = ({\n sections,\n prompt,\n eyebrow,\n query,\n variant,\n streaming,\n className,\n clamp,\n clampHeight,\n showMoreHref,\n showMoreLabel,\n}) => {\n // Overflow detection for the clamp (DL #113). The clamp caps the *root* card\n // (not a wrapper) so the answer sections stay direct children of the\n // placement root — clients lay them out with `:has(> …)` direct-child grids\n // (e.g. feature-com's search-overview two-column layout), which a wrapper\n // would break. With `max-height` + `overflow: hidden` the root's scrollHeight\n // is the full content and clientHeight is the capped box; the fade + \"Show\n // more\" only appear when the content actually overflows (a fade under a short\n // answer reads as broken). Re-measure on every section change (streaming) and\n // on container resize.\n const rootRef = React.useRef<HTMLElement | null>(null);\n const [overflowing, setOverflowing] = React.useState(false);\n\n React.useEffect(() => {\n if (!clamp) {\n setOverflowing(false);\n return;\n }\n const el = rootRef.current;\n if (!el) return;\n const measure = (): void =>\n setOverflowing(el.scrollHeight > el.clientHeight + 1);\n measure();\n if (typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(measure);\n observer.observe(el);\n return () => observer.disconnect();\n }, [clamp, clampHeight, sections]);\n\n const rootClass = [\n 'w5-placement',\n variant ? `w5-placement--${variant}` : '',\n streaming ? 'w5-placement--streaming' : '',\n clamp ? 'w5-placement--clamped' : '',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ');\n\n const sectionNodes = sections.map((section, i) => (\n <Fragment key={section.id ?? `${section.sectionType}-${i}`}>\n {section.component}\n </Fragment>\n ));\n\n // The fade + button overlay the bottom of the clamped card. The button only\n // appears once the content actually overflows and a destination is supplied.\n const showMore = !!clamp && overflowing && !!showMoreHref;\n\n return (\n <section\n ref={rootRef}\n className={rootClass}\n data-w5-placement-renderer=\"\"\n style={\n clamp && clampHeight != null\n ? { maxHeight: `${clampHeight}px` }\n : undefined\n }\n >\n {eyebrow && (\n <div className=\"w5-placement__eyebrow\">\n <StarIcon />\n <span className=\"w5-placement__eyebrow-label\">{eyebrow}</span>\n </div>\n )}\n {query && <p className=\"w5-placement__query\">{query}</p>}\n {prompt && <header className=\"w5-placement__prompt\">{prompt}</header>}\n {sectionNodes}\n {/* Fade + \"Show more\" overlay the bottom of the clamped card. Both are\n absolutely positioned (out of flow), so they don't disturb the\n client's grid placement of the sections, and are clipped by the\n root's `overflow: hidden`. */}\n {showMore && (\n <>\n <div className=\"w5-placement__fade\" aria-hidden=\"true\" />\n <a\n className=\"w5-placement__show-more\"\n href={showMoreHref}\n aria-label=\"See the full answer on the AI page\"\n >\n <span>{showMoreLabel ?? 'Continue in Form AI'}</span>\n </a>\n </>\n )}\n </section>\n );\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","require","_defaultExtractor","_fetchEntityListData","_PlacementPayloadContext","FROM_PARAM","WEB5_ID_PARAM","forwardWeb5Id","url","web5Id","window","startsWith","target","URL","location","href","origin","searchParams","get","set","isAbsolute","test","toString","pathname","search","hash","makeWeb5LinkApi","opts","fullAppUrl","decorate","getForwardWeb5Id","navigateFull","originalUrl","encodeURIComponent","assign","handleLinkClick","e","preventDefault","sendWeb5Message","navigateToUrl","transformUrl","resolveUrl","isExternalUrl","isActionRegistered","executeAction","undefined","makeConversationApi","sendMessage","message","trackingOptions","onSubmit","loadConversationByTriggerId","STUB_MARKDOWN_UTILS","parseMarkdownToAst","extractLinks","extractText","REAL_ENTITY_TRANSFORMS","transformToSolutionEntityData","transformToBlogPostEntityData","transformToGenericEntityData","buildPlacementDependencies","web5LinkApi","conversationApi","entityFetcher","built","useWeb5Link","useConversation","useDebugImageContext","useResolveGenericEntityData","entities","options","entityConfig","usePlacementPayload","idsToFetch","useMemo","filter","data","map","entityId","idsKey","join","apiData","setApiData","useState","Map","apiSettled","setApiSettled","useEffect","length","cancelled","fetchEntityListData","fetchImpl","then","prev","size","next","k","v","catch","enrichedEntities","entity","raw","typeConfig","entityTypes","entityType","payloadType","urlMatchProperty","transform","loading","entityTransforms","markdownUtils","overrides"],"sources":["../../../../src/components/placement/buildPlacementDependencies.ts"],"sourcesContent":["/**\n * buildPlacementDependencies (DL #088 D3.4).\n *\n * Produces a `ComponentDependencies` value tailored to the placement surface.\n * The placement-bundled section components consume the same DI hooks the full\n * app does (`useWeb5Link`, `useConversation`, `useMarkdownUtils`, …) but\n * placement needs **different impls** for some of them:\n *\n * - `useWeb5Link` — `web5://` links always redirect to full Web5 (D12).\n * - `useConversation.sendMessage` — calls into the placement bundle's submit\n * pathway (D11/D13) via the `onSubmit` callback.\n * - Everything else — safe defaults (no-ops, passthroughs, or stubs that\n * throw with a clear message if accidentally called by a section that\n * isn't placement-ready).\n *\n * Per OQ10, the exact set of fields that need real impls vs no-ops depends on\n * which section components the loaded client UMD actually registers in\n * placement. v1 ships safe stubs; we tighten them per-section as integration\n * surfaces gaps.\n *\n * The caller can override any field via `opts.overrides`.\n */\nimport { useEffect, useMemo, useState } from 'react';\nimport type {\n ComponentDependencies,\n Web5LinkApi,\n ConversationApi,\n MarkdownUtils,\n EntityTransforms,\n SendMessageOptions,\n} from '../../types/dependencies';\nimport {\n transformToSolutionEntityData,\n transformToBlogPostEntityData,\n transformToGenericEntityData,\n} from '../../entity/defaultExtractor';\nimport { fetchEntityListData } from '../../entity/fetchEntityListData';\nimport { usePlacementPayload } from './PlacementPayloadContext';\nimport type { ApiPayloadItem, EntityTypeConfig } from '../../types/entity';\n\nexport interface BuildPlacementDependenciesOptions {\n /**\n * URL the placement navigates to when a `web5://` link is clicked or\n * `sendWeb5Message` is called. Defaults to `/web5`. The original URL is\n * passed as a query param so the full app can pick up where placement left off.\n */\n fullAppUrl?: string;\n /**\n * Called when a section component invokes `useConversation().sendMessage(...)`.\n * Wired by the placement bundle to its D10 submit pathway.\n */\n onSubmit?: (\n message: string,\n options?: SendMessageOptions,\n ) => Promise<void> | void;\n /**\n * Auth-aware `fetch` for the items API\n * (`/wix-assistant-web5/v1/items?id=…`). Same Wix-OAuth strategy the\n * placement's conversation fetcher uses — the host page can't make\n * anonymous cross-origin calls to wixapis.com (no\n * Access-Control-Allow-Credentials on the response), so the placement\n * bundle creates a Wix-auth fetcher in `main.ts` and supplies it here.\n * When omitted, the resolver skips the API step and only enriches\n * from the streaming `answer.payload` (DL #099 PR 4).\n */\n entityFetcher?: typeof fetch;\n /**\n * Returns the `web5_id` value to forward onto same-origin navigable URLs the\n * placement's section components resolve (entity cards, links) — the\n * placement's own response trigger id (optionally `<triggerId>;<threadId>`,\n * DL #110), falling back to the page's `?web5_id=`. Read at resolve/navigate\n * time so a value captured mid-stream is used. Mirrors the main app, which\n * forwards its current conversation's trigger id (see web50-server-ui\n * `useWeb5Link.appendWeb5Id`). Carrying it forward keeps the destination\n * page's placement (e.g. `pdpFraming`) warm so it renders. Omit to forward\n * nothing.\n */\n getForwardWeb5Id?: () => string | undefined;\n /**\n * Optional overrides for any of the auto-built deps. Merged shallowly on top\n * of the defaults — pass `useWeb5Link: customHook` to take full control.\n */\n overrides?: Partial<ComponentDependencies>;\n}\n\nconst FROM_PARAM = 'from';\nconst WEB5_ID_PARAM = 'web5_id';\n\n/**\n * Append `web5Id` as `?web5_id=` onto an outbound navigable URL so the\n * destination page's placement renders warm too. Skips `web5://` / `mailto:` /\n * hash- or query-only / cross-origin URLs, preserves the original\n * relative/absolute shape, and is idempotent.\n */\nfunction forwardWeb5Id(url: string, web5Id: string): string {\n if (typeof window === 'undefined' || !url || !web5Id) return url;\n if (\n url.startsWith('web5://') ||\n url.startsWith('mailto:') ||\n url.startsWith('#') ||\n url.startsWith('?')\n ) {\n return url;\n }\n let target: URL;\n try {\n target = new URL(url, window.location.href);\n } catch {\n return url;\n }\n // Never leak the id cross-site — only decorate same-origin destinations.\n if (target.origin !== window.location.origin) return url;\n if (target.searchParams.get(WEB5_ID_PARAM) === web5Id) return url;\n target.searchParams.set(WEB5_ID_PARAM, web5Id);\n const isAbsolute =\n /^[a-zA-Z][a-zA-Z\\d+\\-.]*:/.test(url) || url.startsWith('//');\n return isAbsolute\n ? target.toString()\n : target.pathname + target.search + target.hash;\n}\n\nfunction makeWeb5LinkApi(opts: BuildPlacementDependenciesOptions): Web5LinkApi {\n const fullAppUrl = opts.fullAppUrl ?? '/web5';\n const decorate = <T extends string | undefined>(url: T): T => {\n const web5Id = opts.getForwardWeb5Id?.();\n return web5Id && url ? (forwardWeb5Id(url, web5Id) as T) : url;\n };\n\n const navigateFull = (originalUrl: string): void => {\n if (typeof window === 'undefined') return;\n const target = `${fullAppUrl}?${FROM_PARAM}=${encodeURIComponent(originalUrl)}`;\n window.location.assign(target);\n };\n\n return {\n handleLinkClick: (e, url) => {\n if (!url) return;\n if (url.startsWith('web5://')) {\n // D12: web5:// links from placement always redirect to full Web5.\n e.preventDefault();\n navigateFull(url);\n }\n // Other URLs use normal browser navigation (the <a href> default). The\n // href the section already rendered came through `resolveUrl`, so it\n // already carries `?web5_id=` when forwarding is enabled.\n },\n sendWeb5Message: (url) => navigateFull(url),\n navigateToUrl: (url) => {\n if (typeof window !== 'undefined') {\n window.location.assign(decorate(url));\n }\n },\n transformUrl: () => null,\n resolveUrl: (url) => decorate(url),\n isExternalUrl: () => false,\n isActionRegistered: () => false,\n executeAction: async () => undefined,\n };\n}\n\nfunction makeConversationApi(\n opts: BuildPlacementDependenciesOptions,\n): ConversationApi {\n return {\n sendMessage: async (message, trackingOptions) => {\n await opts.onSubmit?.(message, trackingOptions);\n },\n loadConversationByTriggerId: async () => {\n // No-op for v1 — placement is bound to a single trigger (its own).\n // Browsing other triggers means leaving placement; see D6 history.\n },\n };\n}\n\nconst STUB_MARKDOWN_UTILS: MarkdownUtils = {\n parseMarkdownToAst: () => ({}),\n extractLinks: () => [],\n extractText: () => '',\n};\n\n/**\n * Real entity transforms (DL #099 PR 4). Pure payload-row → entity-data\n * mappers — no React, no host environment — so the placement can wire\n * them in directly. Section components in placement-ready client UMDs\n * pull these via `useEntityTransforms()` and pass them as the\n * `options.transform` to `useResolveGenericEntityData`.\n *\n * Before DL #099 these were throwing stubs because the placement had\n * no payload to feed them. Now the BE's `answer.payload` rides through\n * `PlacementPayloadProvider` and the resolver actually runs.\n */\nconst REAL_ENTITY_TRANSFORMS: EntityTransforms = {\n transformToSolutionEntityData,\n transformToBlogPostEntityData,\n transformToGenericEntityData,\n};\n\nexport function buildPlacementDependencies(\n opts: BuildPlacementDependenciesOptions = {},\n): ComponentDependencies {\n const web5LinkApi = makeWeb5LinkApi(opts);\n const conversationApi = makeConversationApi(opts);\n const entityFetcher = opts.entityFetcher;\n\n const built: ComponentDependencies = {\n useWeb5Link: () => web5LinkApi,\n useConversation: () => conversationApi,\n useDebugImageContext: () => false,\n // Real payload-lookup resolver (DL #099 PR 4). Reads the accumulated\n // streaming `answer.payload` and the client UMD's `entityConfig` from\n // `PlacementPayloadProvider`; if either is missing we pass entities\n // through unchanged. No async fallback — the placement has no\n // entity-list API; sections render what the payload provided or nothing.\n useResolveGenericEntityData: (entities, options) => {\n const { entityConfig } = usePlacementPayload();\n\n // The placement resolves entity data exclusively via the items API\n // — mirroring the main app's `useEntityListData`\n // (web50-server-ui/src/hooks/useEntityListData.ts). The streaming\n // `answer.payload` is intentionally ignored (DL #099 PR 4 follow-up):\n // its shape varies per query and partial coverage caused empty cards.\n const idsToFetch = useMemo(\n () => entities.filter((e) => !e.data).map((e) => e.entityId),\n [entities],\n );\n const idsKey = idsToFetch.join(',');\n\n const [apiData, setApiData] = useState<\n Map<string, ApiPayloadItem>\n >(() => new Map());\n const [apiSettled, setApiSettled] = useState(false);\n\n useEffect(() => {\n if (!entityFetcher || idsToFetch.length === 0) {\n setApiSettled(true);\n return;\n }\n let cancelled = false;\n setApiSettled(false);\n fetchEntityListData(idsToFetch, { fetchImpl: entityFetcher })\n .then((map) => {\n if (cancelled) return;\n setApiData((prev) => {\n if (map.size === 0) return prev;\n const next = new Map(prev);\n for (const [k, v] of map) next.set(k, v);\n return next;\n });\n setApiSettled(true);\n })\n .catch(() => {\n if (!cancelled) setApiSettled(true);\n });\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [idsKey]);\n\n // Merge API rows. Per-type config looked up via entityConfig; falls\n // back to a synthetic config if the client UMD didn't register a row\n // for this entityType (rare).\n const enrichedEntities = useMemo(() => {\n if (apiData.size === 0) return entities;\n return entities.map((entity) => {\n if (entity.data) return entity;\n const raw = apiData.get(entity.entityId);\n if (!raw) return entity;\n const typeConfig: EntityTypeConfig =\n entityConfig?.entityTypes[entity.entityType] ?? {\n payloadType: entity.entityType,\n urlMatchProperty: 'url',\n };\n return { ...entity, data: options.transform(raw, typeConfig) };\n });\n }, [entities, apiData, entityConfig]);\n\n return { enrichedEntities, loading: !apiSettled };\n },\n entityTransforms: REAL_ENTITY_TRANSFORMS,\n markdownUtils: STUB_MARKDOWN_UTILS,\n };\n\n return { ...built, ...(opts.overrides ?? {}) };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_react","require","_defaultExtractor","_fetchEntityListData","_PlacementPayloadContext","FROM_PARAM","WEB5_ID_PARAM","forwardWeb5Id","url","web5Id","window","startsWith","target","URL","location","href","origin","searchParams","get","set","isAbsolute","test","toString","pathname","search","hash","makeWeb5LinkApi","opts","fullAppUrl","decorate","getForwardWeb5Id","navigateFull","originalUrl","encodeURIComponent","assign","handleLinkClick","e","preventDefault","sendWeb5Message","navigateToUrl","transformUrl","resolveUrl","isExternalUrl","isActionRegistered","executeAction","undefined","makeConversationApi","sendMessage","message","trackingOptions","onSubmit","loadConversationByTriggerId","STUB_MARKDOWN_UTILS","parseMarkdownToAst","extractLinks","extractText","REAL_ENTITY_TRANSFORMS","transformToSolutionEntityData","transformToBlogPostEntityData","transformToGenericEntityData","buildPlacementDependencies","web5LinkApi","conversationApi","entityFetcher","built","useWeb5Link","useConversation","useDebugImageContext","useResolveGenericEntityData","entities","options","entityConfig","usePlacementPayload","idsToFetch","useMemo","filter","data","map","entityId","idsKey","join","apiData","setApiData","useState","Map","apiSettled","setApiSettled","useEffect","length","cancelled","fetchEntityListData","fetchImpl","then","prev","size","next","k","v","catch","enrichedEntities","entity","raw","typeConfig","entityTypes","entityType","payloadType","urlMatchProperty","transform","loading","entityTransforms","markdownUtils","overrides"],"sources":["../../../../src/components/placement/buildPlacementDependencies.ts"],"sourcesContent":["/**\n * buildPlacementDependencies (DL #088 D3.4).\n *\n * Produces a `ComponentDependencies` value tailored to the placement surface.\n * The placement-bundled section components consume the same DI hooks the full\n * app does (`useWeb5Link`, `useConversation`, `useMarkdownUtils`, …) but\n * placement needs **different impls** for some of them:\n *\n * - `useWeb5Link` — `web5://` links always redirect to full Web5 (D12).\n * - `useConversation.sendMessage` — calls into the placement bundle's submit\n * pathway (D11/D13) via the `onSubmit` callback.\n * - Everything else — safe defaults (no-ops, passthroughs, or stubs that\n * throw with a clear message if accidentally called by a section that\n * isn't placement-ready).\n *\n * Per OQ10, the exact set of fields that need real impls vs no-ops depends on\n * which section components the loaded client UMD actually registers in\n * placement. v1 ships safe stubs; we tighten them per-section as integration\n * surfaces gaps.\n *\n * The caller can override any field via `opts.overrides`.\n */\nimport { useEffect, useMemo, useState } from 'react';\nimport type {\n ComponentDependencies,\n Web5LinkApi,\n ConversationApi,\n MarkdownUtils,\n EntityTransforms,\n SendMessageOptions,\n} from '../../types/dependencies';\nimport {\n transformToSolutionEntityData,\n transformToBlogPostEntityData,\n transformToGenericEntityData,\n} from '../../entity/defaultExtractor';\nimport { fetchEntityListData } from '../../entity/fetchEntityListData';\nimport { usePlacementPayload } from './PlacementPayloadContext';\nimport type { ApiPayloadItem, EntityTypeConfig } from '../../types/entity';\n\nexport interface BuildPlacementDependenciesOptions {\n /**\n * URL the placement navigates to when a `web5://` link is clicked or\n * `sendWeb5Message` is called. Defaults to `/web5`. The original URL is\n * passed as a query param so the full app can pick up where placement left off.\n */\n fullAppUrl?: string;\n /**\n * Called when a section component invokes `useConversation().sendMessage(...)`.\n * Wired by the placement bundle to its D10 submit pathway.\n */\n onSubmit?: (\n message: string,\n options?: SendMessageOptions,\n ) => Promise<void> | void;\n /**\n * Auth-aware `fetch` for the entity `list-items` API. Same Wix-OAuth strategy the\n * placement's conversation fetcher uses — the host page can't make\n * anonymous cross-origin calls to wixapis.com (no\n * Access-Control-Allow-Credentials on the response), so the placement\n * bundle creates a Wix-auth fetcher in `main.ts` and supplies it here.\n * When omitted, the resolver skips the API step and only enriches\n * from the streaming `answer.payload` (DL #099 PR 4).\n */\n entityFetcher?: typeof fetch;\n /**\n * Returns the `web5_id` value to forward onto same-origin navigable URLs the\n * placement's section components resolve (entity cards, links) — the\n * placement's own response trigger id (optionally `<triggerId>;<threadId>`,\n * DL #110), falling back to the page's `?web5_id=`. Read at resolve/navigate\n * time so a value captured mid-stream is used. Mirrors the main app, which\n * forwards its current conversation's trigger id (see web50-server-ui\n * `useWeb5Link.appendWeb5Id`). Carrying it forward keeps the destination\n * page's placement (e.g. `pdpFraming`) warm so it renders. Omit to forward\n * nothing.\n */\n getForwardWeb5Id?: () => string | undefined;\n /**\n * Optional overrides for any of the auto-built deps. Merged shallowly on top\n * of the defaults — pass `useWeb5Link: customHook` to take full control.\n */\n overrides?: Partial<ComponentDependencies>;\n}\n\nconst FROM_PARAM = 'from';\nconst WEB5_ID_PARAM = 'web5_id';\n\n/**\n * Append `web5Id` as `?web5_id=` onto an outbound navigable URL so the\n * destination page's placement renders warm too. Skips `web5://` / `mailto:` /\n * hash- or query-only / cross-origin URLs, preserves the original\n * relative/absolute shape, and is idempotent.\n */\nfunction forwardWeb5Id(url: string, web5Id: string): string {\n if (typeof window === 'undefined' || !url || !web5Id) return url;\n if (\n url.startsWith('web5://') ||\n url.startsWith('mailto:') ||\n url.startsWith('#') ||\n url.startsWith('?')\n ) {\n return url;\n }\n let target: URL;\n try {\n target = new URL(url, window.location.href);\n } catch {\n return url;\n }\n // Never leak the id cross-site — only decorate same-origin destinations.\n if (target.origin !== window.location.origin) return url;\n if (target.searchParams.get(WEB5_ID_PARAM) === web5Id) return url;\n target.searchParams.set(WEB5_ID_PARAM, web5Id);\n const isAbsolute =\n /^[a-zA-Z][a-zA-Z\\d+\\-.]*:/.test(url) || url.startsWith('//');\n return isAbsolute\n ? target.toString()\n : target.pathname + target.search + target.hash;\n}\n\nfunction makeWeb5LinkApi(opts: BuildPlacementDependenciesOptions): Web5LinkApi {\n const fullAppUrl = opts.fullAppUrl ?? '/web5';\n const decorate = <T extends string | undefined>(url: T): T => {\n const web5Id = opts.getForwardWeb5Id?.();\n return web5Id && url ? (forwardWeb5Id(url, web5Id) as T) : url;\n };\n\n const navigateFull = (originalUrl: string): void => {\n if (typeof window === 'undefined') return;\n const target = `${fullAppUrl}?${FROM_PARAM}=${encodeURIComponent(originalUrl)}`;\n window.location.assign(target);\n };\n\n return {\n handleLinkClick: (e, url) => {\n if (!url) return;\n if (url.startsWith('web5://')) {\n // D12: web5:// links from placement always redirect to full Web5.\n e.preventDefault();\n navigateFull(url);\n }\n // Other URLs use normal browser navigation (the <a href> default). The\n // href the section already rendered came through `resolveUrl`, so it\n // already carries `?web5_id=` when forwarding is enabled.\n },\n sendWeb5Message: (url) => navigateFull(url),\n navigateToUrl: (url) => {\n if (typeof window !== 'undefined') {\n window.location.assign(decorate(url));\n }\n },\n transformUrl: () => null,\n resolveUrl: (url) => decorate(url),\n isExternalUrl: () => false,\n isActionRegistered: () => false,\n executeAction: async () => undefined,\n };\n}\n\nfunction makeConversationApi(\n opts: BuildPlacementDependenciesOptions,\n): ConversationApi {\n return {\n sendMessage: async (message, trackingOptions) => {\n await opts.onSubmit?.(message, trackingOptions);\n },\n loadConversationByTriggerId: async () => {\n // No-op for v1 — placement is bound to a single trigger (its own).\n // Browsing other triggers means leaving placement; see D6 history.\n },\n };\n}\n\nconst STUB_MARKDOWN_UTILS: MarkdownUtils = {\n parseMarkdownToAst: () => ({}),\n extractLinks: () => [],\n extractText: () => '',\n};\n\n/**\n * Real entity transforms (DL #099 PR 4). Pure payload-row → entity-data\n * mappers — no React, no host environment — so the placement can wire\n * them in directly. Section components in placement-ready client UMDs\n * pull these via `useEntityTransforms()` and pass them as the\n * `options.transform` to `useResolveGenericEntityData`.\n *\n * Before DL #099 these were throwing stubs because the placement had\n * no payload to feed them. Now the BE's `answer.payload` rides through\n * `PlacementPayloadProvider` and the resolver actually runs.\n */\nconst REAL_ENTITY_TRANSFORMS: EntityTransforms = {\n transformToSolutionEntityData,\n transformToBlogPostEntityData,\n transformToGenericEntityData,\n};\n\nexport function buildPlacementDependencies(\n opts: BuildPlacementDependenciesOptions = {},\n): ComponentDependencies {\n const web5LinkApi = makeWeb5LinkApi(opts);\n const conversationApi = makeConversationApi(opts);\n const entityFetcher = opts.entityFetcher;\n\n const built: ComponentDependencies = {\n useWeb5Link: () => web5LinkApi,\n useConversation: () => conversationApi,\n useDebugImageContext: () => false,\n // Real payload-lookup resolver (DL #099 PR 4). Reads the accumulated\n // streaming `answer.payload` and the client UMD's `entityConfig` from\n // `PlacementPayloadProvider`; if either is missing we pass entities\n // through unchanged. No async fallback — the placement has no\n // entity-list API; sections render what the payload provided or nothing.\n useResolveGenericEntityData: (entities, options) => {\n const { entityConfig } = usePlacementPayload();\n\n // The placement resolves entity data exclusively via the items API\n // — mirroring the main app's `useEntityListData`\n // (web50-server-ui/src/hooks/useEntityListData.ts). The streaming\n // `answer.payload` is intentionally ignored (DL #099 PR 4 follow-up):\n // its shape varies per query and partial coverage caused empty cards.\n const idsToFetch = useMemo(\n () => entities.filter((e) => !e.data).map((e) => e.entityId),\n [entities],\n );\n const idsKey = idsToFetch.join(',');\n\n const [apiData, setApiData] = useState<\n Map<string, ApiPayloadItem>\n >(() => new Map());\n const [apiSettled, setApiSettled] = useState(false);\n\n useEffect(() => {\n if (!entityFetcher || idsToFetch.length === 0) {\n setApiSettled(true);\n return;\n }\n let cancelled = false;\n setApiSettled(false);\n fetchEntityListData(idsToFetch, { fetchImpl: entityFetcher })\n .then((map) => {\n if (cancelled) return;\n setApiData((prev) => {\n if (map.size === 0) return prev;\n const next = new Map(prev);\n for (const [k, v] of map) next.set(k, v);\n return next;\n });\n setApiSettled(true);\n })\n .catch(() => {\n if (!cancelled) setApiSettled(true);\n });\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [idsKey]);\n\n // Merge API rows. Per-type config looked up via entityConfig; falls\n // back to a synthetic config if the client UMD didn't register a row\n // for this entityType (rare).\n const enrichedEntities = useMemo(() => {\n if (apiData.size === 0) return entities;\n return entities.map((entity) => {\n if (entity.data) return entity;\n const raw = apiData.get(entity.entityId);\n if (!raw) return entity;\n const typeConfig: EntityTypeConfig =\n entityConfig?.entityTypes[entity.entityType] ?? {\n payloadType: entity.entityType,\n urlMatchProperty: 'url',\n };\n return { ...entity, data: options.transform(raw, typeConfig) };\n });\n }, [entities, apiData, entityConfig]);\n\n return { enrichedEntities, loading: !apiSettled };\n },\n entityTransforms: REAL_ENTITY_TRANSFORMS,\n markdownUtils: STUB_MARKDOWN_UTILS,\n };\n\n return { ...built, ...(opts.overrides ?? {}) };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -4,6 +4,7 @@ exports.__esModule = true;
|
|
|
4
4
|
exports.OptimizedImage = void 0;
|
|
5
5
|
var _react = _interopRequireWildcard(require("react"));
|
|
6
6
|
var _imageUtils = require("../../utils/image-utils");
|
|
7
|
+
var _imageBackdrop = require("../../utils/imageBackdrop");
|
|
7
8
|
var _linkTypes = require("../../types/link-types");
|
|
8
9
|
var _ComponentDependenciesContext = require("../../context/ComponentDependenciesContext");
|
|
9
10
|
var _useResolvedImageSources = require("../../hooks/useResolvedImageSources");
|
|
@@ -27,6 +28,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
27
28
|
imageFromText = false,
|
|
28
29
|
disableResize = false,
|
|
29
30
|
imageMode = 'fit',
|
|
31
|
+
adaptiveBackdrop = false,
|
|
30
32
|
fallbackOnLowRes,
|
|
31
33
|
lowResThreshold = 550
|
|
32
34
|
} = props;
|
|
@@ -42,6 +44,8 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
42
44
|
const [isError, setIsError] = (0, _react.useState)(false);
|
|
43
45
|
const [imageUrl, setImageUrl] = (0, _react.useState)('');
|
|
44
46
|
const [isFallback, setIsFallback] = (0, _react.useState)(false);
|
|
47
|
+
// null = adaptive analysis pending (only meaningful when adaptiveBackdrop).
|
|
48
|
+
const [backdrop, setBackdrop] = (0, _react.useState)(null);
|
|
45
49
|
const isDebugImageEnabled = deps.useDebugImageContext();
|
|
46
50
|
const [dimensions, setDimensions] = (0, _react.useState)(null);
|
|
47
51
|
const containerRef = (0, _react.useRef)(null);
|
|
@@ -112,6 +116,41 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
112
116
|
const isLowResResolvedAsset = hasResolvedSourceDimensions && (resolvedSource.width < lowResThreshold || resolvedSource.height < lowResThreshold);
|
|
113
117
|
const cachedFallbackUrl = (0, _react.useMemo)(() => sourceCacheKey ? lowResFallbackCache.get(sourceCacheKey) ?? '' : '', [sourceCacheKey]);
|
|
114
118
|
const showDynamicBadge = isContextualImage && isDebugImageEnabled;
|
|
119
|
+
|
|
120
|
+
// Adaptive fit: probe the resolved image's edges, then map to fit/object-fit.
|
|
121
|
+
// Until analysis resolves (`backdrop === null`) the displayed URL is held back
|
|
122
|
+
// so we never fetch with the wrong mode and flash a re-crop. On a backdrop we
|
|
123
|
+
// render `contain` (whole subject visible) and paint the slot its colour; on a
|
|
124
|
+
// busy scene we `cover`. Failures resolve to `hasBackdrop: false` → `cover`.
|
|
125
|
+
const adaptiveActive = adaptiveBackdrop && layout !== 'intrinsic';
|
|
126
|
+
const adaptiveResolved = !adaptiveActive || backdrop !== null;
|
|
127
|
+
const effectiveObjectFit = adaptiveActive ? backdrop != null && backdrop.hasBackdrop ? 'contain' : 'cover' : objectFit;
|
|
128
|
+
const effectiveImageMode = adaptiveActive ? backdrop != null && backdrop.hasBackdrop ? 'fit' : 'fill' : imageMode;
|
|
129
|
+
const adaptiveBackgroundColor = adaptiveActive && backdrop != null && backdrop.hasBackdrop ? backdrop.backgroundColor : undefined;
|
|
130
|
+
(0, _react.useEffect)(() => {
|
|
131
|
+
if (!adaptiveActive) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
setBackdrop(null);
|
|
135
|
+
if (!effectiveFilename || isFallback || cachedFallbackUrl || isLowResResolvedAsset && fallbackOnLowRes) {
|
|
136
|
+
// No analyzable primary source → behave like a busy scene (cover).
|
|
137
|
+
setBackdrop({
|
|
138
|
+
hasBackdrop: false
|
|
139
|
+
});
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const token = {
|
|
143
|
+
aborted: false
|
|
144
|
+
};
|
|
145
|
+
(0, _imageBackdrop.loadBackdropAnalysis)(effectiveFilename, token).then(result => {
|
|
146
|
+
if (!token.aborted) {
|
|
147
|
+
setBackdrop(result);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return () => {
|
|
151
|
+
token.aborted = true;
|
|
152
|
+
};
|
|
153
|
+
}, [adaptiveActive, effectiveFilename, isFallback, cachedFallbackUrl, isLowResResolvedAsset, fallbackOnLowRes]);
|
|
115
154
|
(0, _react.useEffect)(() => {
|
|
116
155
|
setIsLoaded(false);
|
|
117
156
|
setIsError(false);
|
|
@@ -216,6 +255,11 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
216
255
|
if (disableResize) {
|
|
217
256
|
return;
|
|
218
257
|
}
|
|
258
|
+
// Hold the fetch until adaptive analysis picks fit vs fill, so we request
|
|
259
|
+
// the right CDN mode once instead of fetching twice and re-cropping.
|
|
260
|
+
if (!adaptiveResolved) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
219
263
|
if (!dimensions || !effectiveFilename || isFallback || cachedFallbackUrl || isLowResResolvedAsset && fallbackOnLowRes) {
|
|
220
264
|
return;
|
|
221
265
|
}
|
|
@@ -239,10 +283,10 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
239
283
|
const dpr = window.devicePixelRatio ?? 1;
|
|
240
284
|
const optimizedUrl = (0, _imageUtils.getResizedImageUrl)(imageFilename, dimensions.width * dpr, dimensions.height * dpr, {
|
|
241
285
|
quality,
|
|
242
|
-
imageMode
|
|
286
|
+
imageMode: effectiveImageMode
|
|
243
287
|
});
|
|
244
288
|
setImageUrl(optimizedUrl);
|
|
245
|
-
}, [dimensions, cachedFallbackUrl, effectiveFilename, isFallback, isLowResResolvedAsset, layout, disableResize, quality,
|
|
289
|
+
}, [dimensions, cachedFallbackUrl, effectiveFilename, isFallback, isLowResResolvedAsset, layout, disableResize, quality, effectiveImageMode, adaptiveResolved]);
|
|
246
290
|
const handleImageLoad = e => {
|
|
247
291
|
const img = e.currentTarget;
|
|
248
292
|
if (fallbackOnLowRes && !isFallback && !hasResolvedSourceDimensions && (img.naturalWidth < lowResThreshold || img.naturalHeight < lowResThreshold)) {
|
|
@@ -300,7 +344,8 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
300
344
|
ref: containerRef,
|
|
301
345
|
className: ['block', layout === 'intrinsic' ? '' : 'relative overflow-hidden', showDynamicBadge ? 'relative' : '', className].filter(Boolean).join(' '),
|
|
302
346
|
style: layout === 'intrinsic' ? undefined : {
|
|
303
|
-
minHeight: '1px'
|
|
347
|
+
minHeight: '1px',
|
|
348
|
+
backgroundColor: adaptiveBackgroundColor
|
|
304
349
|
},
|
|
305
350
|
onClick: clickable ? onClick : undefined,
|
|
306
351
|
onKeyDown: clickable ? handleKeyDown : undefined,
|
|
@@ -310,7 +355,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
310
355
|
__self: void 0,
|
|
311
356
|
__source: {
|
|
312
357
|
fileName: _jsxFileName,
|
|
313
|
-
lineNumber:
|
|
358
|
+
lineNumber: 609,
|
|
314
359
|
columnNumber: 7
|
|
315
360
|
}
|
|
316
361
|
}, showDynamicBadge && /*#__PURE__*/_react.default.createElement("span", {
|
|
@@ -318,7 +363,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
318
363
|
__self: void 0,
|
|
319
364
|
__source: {
|
|
320
365
|
fileName: _jsxFileName,
|
|
321
|
-
lineNumber:
|
|
366
|
+
lineNumber: 631,
|
|
322
367
|
columnNumber: 11
|
|
323
368
|
}
|
|
324
369
|
}, contextualImageKey), !isLoaded && !isError && sourceIdentifier && /*#__PURE__*/_react.default.createElement("span", {
|
|
@@ -329,7 +374,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
329
374
|
__self: void 0,
|
|
330
375
|
__source: {
|
|
331
376
|
fileName: _jsxFileName,
|
|
332
|
-
lineNumber:
|
|
377
|
+
lineNumber: 636,
|
|
333
378
|
columnNumber: 11
|
|
334
379
|
}
|
|
335
380
|
}), isError && /*#__PURE__*/_react.default.createElement("span", {
|
|
@@ -339,7 +384,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
339
384
|
__self: void 0,
|
|
340
385
|
__source: {
|
|
341
386
|
fileName: _jsxFileName,
|
|
342
|
-
lineNumber:
|
|
387
|
+
lineNumber: 645,
|
|
343
388
|
columnNumber: 11
|
|
344
389
|
}
|
|
345
390
|
}, /*#__PURE__*/_react.default.createElement("span", {
|
|
@@ -347,7 +392,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
347
392
|
__self: void 0,
|
|
348
393
|
__source: {
|
|
349
394
|
fileName: _jsxFileName,
|
|
350
|
-
lineNumber:
|
|
395
|
+
lineNumber: 650,
|
|
351
396
|
columnNumber: 13
|
|
352
397
|
}
|
|
353
398
|
}, /*#__PURE__*/_react.default.createElement("svg", {
|
|
@@ -360,7 +405,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
360
405
|
__self: void 0,
|
|
361
406
|
__source: {
|
|
362
407
|
fileName: _jsxFileName,
|
|
363
|
-
lineNumber:
|
|
408
|
+
lineNumber: 651,
|
|
364
409
|
columnNumber: 15
|
|
365
410
|
}
|
|
366
411
|
}, /*#__PURE__*/_react.default.createElement("path", {
|
|
@@ -371,7 +416,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
371
416
|
__self: void 0,
|
|
372
417
|
__source: {
|
|
373
418
|
fileName: _jsxFileName,
|
|
374
|
-
lineNumber:
|
|
419
|
+
lineNumber: 659,
|
|
375
420
|
columnNumber: 17
|
|
376
421
|
}
|
|
377
422
|
})), /*#__PURE__*/_react.default.createElement("span", {
|
|
@@ -379,13 +424,13 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
379
424
|
__self: void 0,
|
|
380
425
|
__source: {
|
|
381
426
|
fileName: _jsxFileName,
|
|
382
|
-
lineNumber:
|
|
427
|
+
lineNumber: 666,
|
|
383
428
|
columnNumber: 15
|
|
384
429
|
}
|
|
385
430
|
}, "Failed to load image"))), imageUrl && !isError && /*#__PURE__*/_react.default.createElement("img", {
|
|
386
431
|
src: imageUrl,
|
|
387
432
|
alt: alt,
|
|
388
|
-
className: `${layout === 'intrinsic' ? 'w-full h-auto' : 'absolute inset-0 w-full h-full'} transition-opacity duration-300 ${isLoaded ? 'opacity-100' : 'opacity-0'} ${
|
|
433
|
+
className: `${layout === 'intrinsic' ? 'w-full h-auto' : 'absolute inset-0 w-full h-full'} transition-opacity duration-300 ${isLoaded ? 'opacity-100' : 'opacity-0'} ${effectiveObjectFit === 'contain' ? 'object-contain' : effectiveObjectFit === 'cover' ? 'object-cover' : effectiveObjectFit === 'fill' ? 'object-fill' : effectiveObjectFit === 'none' ? 'object-none' : effectiveObjectFit === 'scale-down' ? 'object-scale-down' : ''}`,
|
|
389
434
|
style: layout === 'intrinsic' ? {
|
|
390
435
|
width: '100%',
|
|
391
436
|
height: 'auto',
|
|
@@ -396,7 +441,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
396
441
|
inset: 0,
|
|
397
442
|
width: '100%',
|
|
398
443
|
height: '100%',
|
|
399
|
-
objectFit,
|
|
444
|
+
objectFit: effectiveObjectFit,
|
|
400
445
|
maxWidth: '100%',
|
|
401
446
|
display: 'block'
|
|
402
447
|
},
|
|
@@ -406,7 +451,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
|
|
|
406
451
|
__self: void 0,
|
|
407
452
|
__source: {
|
|
408
453
|
fileName: _jsxFileName,
|
|
409
|
-
lineNumber:
|
|
454
|
+
lineNumber: 672,
|
|
410
455
|
columnNumber: 11
|
|
411
456
|
}
|
|
412
457
|
})));
|