@opensite/ui 3.5.6 → 3.5.8

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.
@@ -1132,16 +1132,22 @@ var FeaturedCardsGridDropdown = ({
1132
1132
  optixFlowConfig
1133
1133
  }) => {
1134
1134
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1135
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-4 pb-8", children: featuredLinks?.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx(
1135
+ featuredLinks && featuredLinks?.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-4 pb-8", children: featuredLinks?.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx(
1136
1136
  FeaturedLink,
1137
1137
  {
1138
1138
  link,
1139
1139
  optixFlowConfig
1140
1140
  },
1141
1141
  `desktop-featured-link-${index}`
1142
- )) }),
1143
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
1144
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-4 pt-8", children: links?.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx(NavLink, { link }, `default-nav-link-${index}`)) })
1142
+ )) }) : null,
1143
+ featuredLinks && featuredLinks?.length > 0 && links && links?.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Separator, {}) : null,
1144
+ links && links?.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
1145
+ "div",
1146
+ {
1147
+ className: `grid grid-cols-4 pt-${featuredLinks && featuredLinks?.length > 0 ? 8 : 0} gap-4`,
1148
+ children: links?.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx(NavLink, { link }, `default-nav-link-${index}`))
1149
+ }
1150
+ ) : null
1145
1151
  ] });
1146
1152
  };
1147
1153
  var GroupedLinksImageDropdown = ({
@@ -39,16 +39,16 @@ interface IMenuLink {
39
39
  */
40
40
  interface NavbarAnimatedPreviewProps {
41
41
  /**
42
- * Logo configuration
43
- */
42
+ * Logo configuration
43
+ */
44
44
  logo?: LogoConfig;
45
45
  /**
46
- * Navigation menu links with optional dropdown groups
47
- */
46
+ * Navigation menu links with optional dropdown groups
47
+ */
48
48
  menuLinks?: IMenuLink[];
49
49
  /**
50
- * Action configurations (e.g., Sign In, Get Started buttons)
51
- */
50
+ * Action configurations (e.g., Sign In, Get Started buttons)
51
+ */
52
52
  actions?: ActionConfig[];
53
53
  }
54
54
  interface NavbarAnimatedPreviewRuntimeProps {
@@ -39,16 +39,16 @@ interface IMenuLink {
39
39
  */
40
40
  interface NavbarAnimatedPreviewProps {
41
41
  /**
42
- * Logo configuration
43
- */
42
+ * Logo configuration
43
+ */
44
44
  logo?: LogoConfig;
45
45
  /**
46
- * Navigation menu links with optional dropdown groups
47
- */
46
+ * Navigation menu links with optional dropdown groups
47
+ */
48
48
  menuLinks?: IMenuLink[];
49
49
  /**
50
- * Action configurations (e.g., Sign In, Get Started buttons)
51
- */
50
+ * Action configurations (e.g., Sign In, Get Started buttons)
51
+ */
52
52
  actions?: ActionConfig[];
53
53
  }
54
54
  interface NavbarAnimatedPreviewRuntimeProps {
@@ -1107,16 +1107,22 @@ var FeaturedCardsGridDropdown = ({
1107
1107
  optixFlowConfig
1108
1108
  }) => {
1109
1109
  return /* @__PURE__ */ jsxs("div", { children: [
1110
- /* @__PURE__ */ jsx("div", { className: "flex gap-4 pb-8", children: featuredLinks?.map((link, index) => /* @__PURE__ */ jsx(
1110
+ featuredLinks && featuredLinks?.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex gap-4 pb-8", children: featuredLinks?.map((link, index) => /* @__PURE__ */ jsx(
1111
1111
  FeaturedLink,
1112
1112
  {
1113
1113
  link,
1114
1114
  optixFlowConfig
1115
1115
  },
1116
1116
  `desktop-featured-link-${index}`
1117
- )) }),
1118
- /* @__PURE__ */ jsx(Separator, {}),
1119
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 pt-8", children: links?.map((link, index) => /* @__PURE__ */ jsx(NavLink, { link }, `default-nav-link-${index}`)) })
1117
+ )) }) : null,
1118
+ featuredLinks && featuredLinks?.length > 0 && links && links?.length > 0 ? /* @__PURE__ */ jsx(Separator, {}) : null,
1119
+ links && links?.length > 0 ? /* @__PURE__ */ jsx(
1120
+ "div",
1121
+ {
1122
+ className: `grid grid-cols-4 pt-${featuredLinks && featuredLinks?.length > 0 ? 8 : 0} gap-4`,
1123
+ children: links?.map((link, index) => /* @__PURE__ */ jsx(NavLink, { link }, `default-nav-link-${index}`))
1124
+ }
1125
+ ) : null
1120
1126
  ] });
1121
1127
  };
1122
1128
  var GroupedLinksImageDropdown = ({
package/dist/registry.cjs CHANGED
@@ -66975,16 +66975,22 @@ var FeaturedCardsGridDropdown = ({
66975
66975
  optixFlowConfig
66976
66976
  }) => {
66977
66977
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
66978
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-4 pb-8", children: featuredLinks?.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx(
66978
+ featuredLinks && featuredLinks?.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-4 pb-8", children: featuredLinks?.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx(
66979
66979
  FeaturedLink,
66980
66980
  {
66981
66981
  link,
66982
66982
  optixFlowConfig
66983
66983
  },
66984
66984
  `desktop-featured-link-${index}`
66985
- )) }),
66986
- /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
66987
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-4 pt-8", children: links?.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx(NavLink, { link }, `default-nav-link-${index}`)) })
66985
+ )) }) : null,
66986
+ featuredLinks && featuredLinks?.length > 0 && links && links?.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Separator, {}) : null,
66987
+ links && links?.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
66988
+ "div",
66989
+ {
66990
+ className: `grid grid-cols-4 pt-${featuredLinks && featuredLinks?.length > 0 ? 8 : 0} gap-4`,
66991
+ children: links?.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx(NavLink, { link }, `default-nav-link-${index}`))
66992
+ }
66993
+ ) : null
66988
66994
  ] });
66989
66995
  };
66990
66996
  var GroupedLinksImageDropdown = ({
@@ -112060,7 +112066,106 @@ var BLOCK_REGISTRY = {
112060
112066
  category: "hero",
112061
112067
  component: HeroMentalHealthTeam,
112062
112068
  props: "HeroMentalHealthTeamProps",
112063
- exampleUsage: `<HeroMentalHealthTeam />`.trim()
112069
+ exampleUsage: `
112070
+ <HeroMentalHealthTeam
112071
+ heading="Compassionate care for your mental wellbeing"
112072
+ description="Our team of experienced mental health professionals is dedicated to providing compassionate care and support to individuals in need."
112073
+ smallImages={[
112074
+ { src: "/images/team-1.jpg", alt: "Dr. Smith" },
112075
+ { src: "/images/team-2.jpg", alt: "Dr. Johnson" },
112076
+ ]}
112077
+ testimonial={{
112078
+ quote:
112079
+ "The support I received changed my life. I'm so grateful for the compassionate care.",
112080
+ author: "Sarah M.",
112081
+ role: "Client",
112082
+ avatarSrc: "/images/avatar.jpg",
112083
+ }}
112084
+ featureImage={{ src: "/images/feature.jpg", alt: "Mental health support" }}
112085
+ actions={[
112086
+ { label: "Get Started", href: "#", variant: "default" },
112087
+ { label: "Talk to Sales", href: "#", variant: "outline" },
112088
+ ]}
112089
+ background="gray"
112090
+ />
112091
+ `.trim(),
112092
+ importantUsageNotes: "Only use if you have a valid testimonial - DO NOT MAKE UP A TESTIMONIAL/REVIEW. Supply exactly 2 images to the 'smallImages' prop and ensure you supply a 'featureImage' prop object. Do not exceed 40 characters for the 'heading' prop. Do not exceed 130 characters for the 'description' prop. If you supply multiple 'actions', ensure to use a variant of 'default' for the first action, and 'outline' for the second action to ensure proper visual distinction between the two CTAs. Follow the example props closely for this block.",
112093
+ usageRequirements: {
112094
+ requiredProps: ["heading", "smallImages", "featureImage", "testimonial"],
112095
+ propConstraints: {
112096
+ heading: { required: true, maxLength: 40 },
112097
+ description: { maxLength: 130 },
112098
+ smallImages: { required: true, count: 2, minItems: 2, maxItems: 2 },
112099
+ featureImage: { required: true },
112100
+ testimonial: {
112101
+ required: true,
112102
+ note: "Must be a real, sourced testimonial. Do not fabricate."
112103
+ },
112104
+ actions: {
112105
+ maxItems: 2,
112106
+ pinnedValues: {
112107
+ "0.variant": "default",
112108
+ "1.variant": "outline"
112109
+ }
112110
+ }
112111
+ },
112112
+ mediaSlots: {
112113
+ featureImage: {
112114
+ path: "featureImage",
112115
+ roles: ["feature", "hero"],
112116
+ disallowedRoles: ["logo", "favicon"],
112117
+ minPixelClass: "large",
112118
+ required: true,
112119
+ note: "Large feature image. Must not be a logo or favicon."
112120
+ },
112121
+ "smallImages[]": {
112122
+ path: "smallImages[]",
112123
+ roles: ["thumbnail", "profile", "feature"],
112124
+ disallowedRoles: ["logo", "favicon"],
112125
+ minPixelClass: "small",
112126
+ required: true,
112127
+ note: "Two team / supporting images. Must not be logos."
112128
+ },
112129
+ "testimonial.avatarSrc": {
112130
+ path: "testimonial.avatarSrc",
112131
+ roles: ["profile", "avatar"],
112132
+ disallowedRoles: ["logo", "favicon"],
112133
+ minPixelClass: "small",
112134
+ preferredAspect: "1:1",
112135
+ note: "Headshot/avatar for the testimonial author."
112136
+ }
112137
+ },
112138
+ requiresSiteCapabilities: ["reviews_or_testimonials", "media_library"]
112139
+ },
112140
+ exampleProps: {
112141
+ heading: "Compassionate care for your mental wellbeing",
112142
+ description: "Our team of experienced mental health professionals is dedicated to providing compassionate care and support to individuals in need.",
112143
+ smallImages: [
112144
+ {
112145
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112146
+ alt: "Dr. Smith"
112147
+ },
112148
+ {
112149
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112150
+ alt: "Dr. Johnson"
112151
+ }
112152
+ ],
112153
+ testimonial: {
112154
+ quote: "The support I received changed my life. I'm so grateful for the compassionate care.",
112155
+ author: "Sarah M.",
112156
+ role: "Client",
112157
+ avatarSrc: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp"
112158
+ },
112159
+ featureImage: {
112160
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112161
+ alt: "Mental health support"
112162
+ },
112163
+ actions: [
112164
+ { label: "Get Started", href: "#", variant: "default" },
112165
+ { label: "Talk to Sales", href: "#", variant: "outline" }
112166
+ ],
112167
+ background: "gray"
112168
+ }
112064
112169
  },
112065
112170
  "hero-mentorship-video-split": {
112066
112171
  id: "hero-mentorship-video-split",
@@ -112079,7 +112184,101 @@ var BLOCK_REGISTRY = {
112079
112184
  category: "hero",
112080
112185
  component: HeroMentorshipVideoSplit,
112081
112186
  props: "HeroMentorshipVideoSplitProps",
112082
- exampleUsage: `<HeroMentorshipVideoSplit />`.trim()
112187
+ exampleUsage: `
112188
+ <HeroMentorshipVideoSplit
112189
+ heading="Reclaim Your Peace. Scale Sustainably."
112190
+ description="Somatic mindset coaching for high-achieving entrepreneurs ready to lead from strength \u2014 not survival mode."
112191
+ action={{ label: "Book Your Discovery Call", href: "/contact", variant: "default", size: "lg" }}
112192
+ videoLabel="Watch the Overview"
112193
+ videoTitle="Coaching Overview"
112194
+ modalVideo={{
112195
+ image: {
112196
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112197
+ alt: "Coaching overview poster",
112198
+ },
112199
+ video: {
112200
+ src: "https://toastability-production.s3.amazonaws.com/4kox2ux0ye1wlqkdwg03s08a67i1",
112201
+ },
112202
+ }}
112203
+ image={{
112204
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112205
+ alt: "Coach portrait",
112206
+ }}
112207
+ background="dark"
112208
+ />
112209
+ `.trim(),
112210
+ importantUsageNotes: "The 'image' prop is the main hero image and MUST be an image asset (poster/photo). The 'modalVideo' prop's nested 'video.src' MUST be a video asset (HLS playlist or MP4) and 'modalVideo.image.src' MUST be an image asset (video poster). NEVER swap these: do not put a video URL into the 'image' prop and do not put an image URL into 'modalVideo.video.src'. All media src values must be absolute URLs to real CDN assets \u2014 never relative paths or placeholder strings. Keep 'heading' concise (under 60 characters) for visual balance.",
112211
+ usageRequirements: {
112212
+ requiredProps: ["heading", "image"],
112213
+ propConstraints: {
112214
+ heading: { required: true, maxLength: 60 },
112215
+ description: { maxLength: 220 },
112216
+ image: {
112217
+ required: true,
112218
+ note: "Main hero image. Must be an image asset (jpg/png/webp), NOT a video URL."
112219
+ },
112220
+ "modalVideo.video.src": {
112221
+ note: "Must be a video asset URL (HLS .m3u8 master playlist or .mp4). Must NOT be an image URL."
112222
+ },
112223
+ "modalVideo.image.src": {
112224
+ note: "Video poster image. Must be an image asset, NOT a video URL."
112225
+ }
112226
+ },
112227
+ mediaSlots: {
112228
+ image: {
112229
+ path: "image",
112230
+ roles: ["hero", "feature", "profile"],
112231
+ disallowedRoles: ["logo", "favicon", "video-thumbnail"],
112232
+ minPixelClass: "large",
112233
+ required: true,
112234
+ note: "Main hero image slot. IMAGE MEDIA ONLY. Do not assign a video URL here."
112235
+ },
112236
+ "modalVideo.video.src": {
112237
+ path: "modalVideo.video.src",
112238
+ roles: [],
112239
+ disallowedRoles: ["logo", "favicon", "hero", "feature", "profile"],
112240
+ note: "VIDEO MEDIA ONLY (HLS master playlist or MP4). Do not assign an image URL here."
112241
+ },
112242
+ "modalVideo.image.src": {
112243
+ path: "modalVideo.image.src",
112244
+ roles: ["video-thumbnail", "hero", "feature"],
112245
+ disallowedRoles: ["logo", "favicon"],
112246
+ minPixelClass: "medium",
112247
+ note: "Poster image shown before the video plays. IMAGE MEDIA ONLY."
112248
+ }
112249
+ },
112250
+ requiresSiteCapabilities: ["media_library"],
112251
+ notes: [
112252
+ "Image and video media must never be swapped between the 'image' prop and the 'modalVideo' prop.",
112253
+ "All media src values must be absolute URLs to real assets; relative paths are not allowed."
112254
+ ]
112255
+ },
112256
+ exampleProps: {
112257
+ heading: "Reclaim Your Peace. Scale Sustainably.",
112258
+ description: "Somatic mindset coaching for high-achieving entrepreneurs ready to lead from strength \u2014 not survival mode.",
112259
+ action: {
112260
+ label: "Book Your Discovery Call",
112261
+ href: "/contact",
112262
+ variant: "default",
112263
+ size: "lg"
112264
+ },
112265
+ videoLabel: "Watch the Overview",
112266
+ videoTitle: "Coaching Overview",
112267
+ modalVideo: {
112268
+ image: {
112269
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112270
+ alt: "Coaching overview poster"
112271
+ },
112272
+ video: {
112273
+ src: "https://toastability-production.s3.amazonaws.com/4kox2ux0ye1wlqkdwg03s08a67i1"
112274
+ }
112275
+ },
112276
+ image: {
112277
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112278
+ alt: "Coach portrait"
112279
+ },
112280
+ background: "dark"
112281
+ }
112083
112282
  },
112084
112283
  "hero-business-operations-mosaic": {
112085
112284
  id: "hero-business-operations-mosaic",
@@ -120360,9 +120559,11 @@ function normalizeBlock(block, source) {
120360
120559
  },
120361
120560
  examples: {
120362
120561
  exampleUsage: block.exampleUsage || null,
120363
- defaultData: null
120562
+ exampleProps: block.exampleProps ? JSON.parse(JSON.stringify(block.exampleProps)) : null
120364
120563
  },
120365
- source: source ?? null
120564
+ source: source ?? null,
120565
+ importantUsageNotes: block.importantUsageNotes ?? null,
120566
+ usageRequirements: block.usageRequirements ? JSON.parse(JSON.stringify(block.usageRequirements)) : null
120366
120567
  };
120367
120568
  }
120368
120569
  function createBuilderContractBundle({
@@ -1,68 +1,131 @@
1
1
  /**
2
- * Semantic Block Registry
2
+ * Block Registry Types
3
3
  *
4
- * This registry maps semantic concepts to available UI blocks for AI-driven
5
- * site generation. Each block entry contains:
6
- * - id: Unique identifier for the block
7
- * - name: Human-readable name
8
- * - description: What the block does and when to use it
9
- * - semanticTags: Array of semantic concepts this block represents
10
- * - category: Block category (about, features, cta, testimonials, etc.)
11
- * - component: Reference to the actual component
12
- * - props: TypeScript type for the component's props
13
- * - exampleUsage: Code example showing how to use the block
14
- */
15
- interface BlockRegistryEntry$1<T = any> {
16
- id: string;
17
- name: string;
18
- description: string;
19
- semanticTags: string[];
20
- category: BlockCategory$1;
21
- component: React.ComponentType<T>;
22
- props: string;
23
- exampleUsage: string;
24
- }
25
- type BlockCategory$1 = "about" | "features" | "cta" | "testimonials" | "services" | "hero" | "footer" | "header" | "pricing" | "team" | "stats" | "faq" | "contact" | "carousel" | "gallery" | "timeline" | "process" | "benefits" | "comparison" | "background-pattern-hero" | "blog" | "article" | "case-studies-list" | "case-study-detail" | "navbar" | "logos" | "project-list" | "project-detail" | "list" | "offer-modal" | "banner" | "industries" | "resource-detail" | "service-detail" | "services-list" | "resource-list" | "link-page";
26
- /**
27
- * Block Registry - Central registry of all available UI blocks
28
- */
29
- declare const BLOCK_REGISTRY: Record<string, BlockRegistryEntry$1>;
30
- /**
31
- * Get blocks by semantic tag
4
+ * Shared type definitions for the block registry system.
32
5
  */
33
- declare function getBlocksBySemanticTag(tag: string): BlockRegistryEntry$1[];
6
+ type BlockCategory = "about" | "features" | "cta" | "testimonials" | "services" | "hero" | "footer" | "header" | "pricing" | "team" | "stats" | "faq" | "contact" | "carousel" | "gallery" | "timeline" | "process" | "benefits" | "comparison" | "background-pattern-hero" | "blog" | "article" | "case-studies-list" | "case-study-detail" | "navbar" | "logos" | "project-list" | "project-detail" | "list" | "offer-modal" | "banner" | "industries" | "resource-detail" | "service-detail" | "services-list" | "resource-list" | "link-page";
34
7
  /**
35
- * Get blocks by category
8
+ * Semantic role hints for a media slot. Consumers (semantic site builders,
9
+ * media classifiers) use these to scope which assets are eligible for a slot.
10
+ *
11
+ * - `logo`: brand logos / wordmarks (small, transparent backgrounds).
12
+ * - `favicon`: tiny brand icon.
13
+ * - `hero`: large hero/banner imagery.
14
+ * - `feature`: large feature/marketing imagery (non-logo).
15
+ * - `thumbnail`: small supporting imagery (e.g. card images, team thumbs).
16
+ * - `profile`: portrait/headshot of a person.
17
+ * - `avatar`: small profile / testimonial avatar.
18
+ * - `gallery`: imagery suited for galleries / grids.
19
+ * - `background`: large background imagery, often photographic.
20
+ * - `screenshot`: product screenshots / UI captures.
21
+ * - `illustration`: vector / illustrative art.
22
+ * - `video-thumbnail`: poster image for a video slot.
36
23
  */
37
- declare function getBlocksByCategory(category: BlockCategory$1): BlockRegistryEntry$1[];
24
+ type MediaRole = "logo" | "favicon" | "hero" | "feature" | "thumbnail" | "profile" | "avatar" | "gallery" | "background" | "screenshot" | "illustration" | "video-thumbnail";
25
+ /** Minimum pixel class expected for a media asset. */
26
+ type MediaPixelClass = "tiny" | "small" | "medium" | "large" | "xlarge";
38
27
  /**
39
- * Get block by ID
28
+ * Structured description of a single media slot inside a block's prop tree.
29
+ * The `path` is dot/bracket notation, e.g. `featureImage`, `smallImages[]`,
30
+ * `testimonial.avatarSrc`.
40
31
  */
41
- declare function getBlockById(id: string): BlockRegistryEntry$1 | undefined;
32
+ interface BlockMediaSlot {
33
+ path: string;
34
+ /** Allowed/expected semantic roles for this slot, in priority order. */
35
+ roles: MediaRole[];
36
+ /** Roles that must NOT be assigned to this slot. */
37
+ disallowedRoles?: MediaRole[];
38
+ /** Minimum acceptable pixel class for this slot. */
39
+ minPixelClass?: MediaPixelClass;
40
+ /** Preferred aspect ratio, e.g. "16:9", "1:1", "4:5". */
41
+ preferredAspect?: string;
42
+ /** Whether the block visually requires this slot to render correctly. */
43
+ required?: boolean;
44
+ /** Short note explaining the slot's intent (consumed by AI prompts). */
45
+ note?: string;
46
+ }
42
47
  /**
43
- * Get all available blocks
48
+ * Per-prop content constraints. Additive – consumers should treat missing
49
+ * fields as "no constraint declared" rather than rejecting payloads.
44
50
  */
45
- declare function getAllBlocks(): BlockRegistryEntry$1[];
51
+ interface BlockPropConstraint {
52
+ /** Whether the block requires this prop to render correctly. */
53
+ required?: boolean;
54
+ /** Maximum string length for text-shaped props. */
55
+ maxLength?: number;
56
+ /** Exact item count for array props (shorthand for minItems = maxItems). */
57
+ count?: number;
58
+ /** Minimum array length. */
59
+ minItems?: number;
60
+ /** Maximum array length. */
61
+ maxItems?: number;
62
+ /**
63
+ * Pinned values, by index for array props or as a single value for scalars.
64
+ * Used for the `actions[0].variant = "default"` / `actions[1].variant = "outline"` pattern.
65
+ */
66
+ pinnedValues?: Record<string, string | number | boolean>;
67
+ /** Free-form note about this prop (for AI prompts). */
68
+ note?: string;
69
+ }
46
70
  /**
47
- * Get all categories
71
+ * Capabilities the host site / data source must satisfy for the block to be
72
+ * suitable. Consumers (e.g. Octane) gate block selection on these BEFORE the
73
+ * block is offered to the model, so it cannot fabricate the missing input.
48
74
  */
49
- declare function getAllCategories(): BlockCategory$1[];
75
+ type SiteCapability = "reviews_or_testimonials" | "pricing_data" | "team_members" | "blog_posts" | "case_studies" | "metrics_or_stats" | "product_catalog" | "media_library" | "contact_info";
50
76
  /**
51
- * Search blocks by query (searches name, description, and semantic tags)
77
+ * Structured usage requirements for a block. This is the executable
78
+ * complement to `importantUsageNotes` (which remains for human-readable
79
+ * prompt context). When present, downstream consumers SHOULD enforce these
80
+ * at selection time and during post-generation validation.
52
81
  */
53
- declare function searchBlocks(query: string): BlockRegistryEntry$1[];
54
-
82
+ interface BlockUsageRequirements {
83
+ /** Names of props that are required for the block to render correctly. */
84
+ requiredProps?: string[];
85
+ /** Per-prop content/cardinality constraints, keyed by prop name/path. */
86
+ propConstraints?: Record<string, BlockPropConstraint>;
87
+ /** Media slot metadata, keyed by slot path. */
88
+ mediaSlots?: Record<string, BlockMediaSlot>;
89
+ /** Site capabilities required to safely select this block. */
90
+ requiresSiteCapabilities?: SiteCapability[];
91
+ /**
92
+ * Free-form structured rules that don't fit other fields. Consumers should
93
+ * treat unknown keys as advisory.
94
+ */
95
+ notes?: string[];
96
+ }
55
97
  /**
56
- * Block Registry Types
57
- *
58
- * Shared type definitions for the block registry system.
98
+ * Shared metadata fields that describe a block's contract. Used both by
99
+ * {@link BlockMetadata} (no component) and {@link BlockRegistryEntry}
100
+ * (with component).
59
101
  */
60
- type BlockCategory = "about" | "features" | "cta" | "testimonials" | "services" | "hero" | "footer" | "header" | "pricing" | "team" | "stats" | "faq" | "contact" | "carousel" | "gallery" | "timeline" | "process" | "benefits" | "comparison" | "background-pattern-hero" | "blog" | "article" | "case-studies-list" | "case-study-detail" | "navbar" | "logos" | "project-list" | "project-detail" | "list" | "offer-modal" | "banner" | "industries" | "resource-detail" | "service-detail" | "services-list" | "resource-list" | "link-page";
102
+ interface BlockContractFields {
103
+ /**
104
+ * Human-readable usage guidance for AI prompts. This remains advisory.
105
+ * For executable rules use {@link BlockContractFields.usageRequirements}.
106
+ */
107
+ importantUsageNotes?: string;
108
+ /** Structured, machine-readable usage requirements. */
109
+ usageRequirements?: BlockUsageRequirements;
110
+ /**
111
+ * Canonical example payload for the block, matching the prop shape.
112
+ * Optional. When supplied, consumers should prefer this over parsing
113
+ * `exampleUsage` JSX.
114
+ *
115
+ * IMPORTANT: These are reference examples for AI prompting / preview
116
+ * tooling only. They are NOT runtime defaults — consumers MUST NOT
117
+ * substitute these values as fallback content on a real client site.
118
+ * The previous name (`defaultProps`) was renamed to make this explicit:
119
+ * AI agents had begun treating "default" values as safe runtime
120
+ * fallbacks for missing client data, which is incorrect.
121
+ */
122
+ exampleProps?: Record<string, unknown>;
123
+ }
61
124
  /**
62
125
  * Metadata-only block registry entry (no component import)
63
126
  * Used for AI-driven component discovery without bundling all components
64
127
  */
65
- interface BlockMetadata {
128
+ interface BlockMetadata extends BlockContractFields {
66
129
  id: string;
67
130
  name: string;
68
131
  description: string;
@@ -81,7 +144,7 @@ interface BlockMetadata {
81
144
  * Full block registry entry with component reference
82
145
  * @deprecated Use BlockMetadata for new code - this type causes all components to be bundled
83
146
  */
84
- interface BlockRegistryEntry<T = any> {
147
+ interface BlockRegistryEntry<T = any> extends BlockContractFields {
85
148
  id: string;
86
149
  name: string;
87
150
  description: string;
@@ -107,7 +170,17 @@ interface BuilderContractPropsContract {
107
170
  }
108
171
  interface BuilderContractExamples {
109
172
  exampleUsage: string | null;
110
- defaultData: null;
173
+ /**
174
+ * Canonical example props payload. Populated from
175
+ * BlockRegistryEntry.exampleProps when declared, otherwise null.
176
+ *
177
+ * IMPORTANT: This is reference example data only, not a runtime
178
+ * fallback. Consumers MUST NOT substitute these values for missing
179
+ * client content. The previous name (`defaultData`) was renamed
180
+ * because downstream AI agents were treating it as safe runtime
181
+ * default content.
182
+ */
183
+ exampleProps: Record<string, unknown> | null;
111
184
  }
112
185
  interface BuilderContractBlock {
113
186
  componentId: string;
@@ -121,6 +194,16 @@ interface BuilderContractBlock {
121
194
  propsContract: BuilderContractPropsContract;
122
195
  examples: BuilderContractExamples;
123
196
  source: BuilderContractBlockSource | null;
197
+ /**
198
+ * Human-readable usage guidance for AI prompts. Mirrors
199
+ * BlockRegistryEntry.importantUsageNotes when declared, otherwise null.
200
+ */
201
+ importantUsageNotes: string | null;
202
+ /**
203
+ * Structured, machine-readable usage requirements. Null when the
204
+ * registry entry does not declare any.
205
+ */
206
+ usageRequirements: BlockUsageRequirements | null;
124
207
  }
125
208
  interface BuilderContractMetadata {
126
209
  contractVersion: string;
@@ -195,6 +278,50 @@ interface BuilderContractBundle {
195
278
  pageRules: BuilderContractPageRules;
196
279
  }
197
280
 
281
+ /**
282
+ * Semantic Block Registry
283
+ *
284
+ * This registry maps semantic concepts to available UI blocks for AI-driven
285
+ * site generation. Each block entry contains:
286
+ * - id: Unique identifier for the block
287
+ * - name: Human-readable name
288
+ * - description: What the block does and when to use it
289
+ * - semanticTags: Array of semantic concepts this block represents
290
+ * - category: Block category (about, features, cta, testimonials, etc.)
291
+ * - component: Reference to the actual component
292
+ * - props: TypeScript type for the component's props
293
+ * - exampleUsage: Code example showing how to use the block
294
+ */
295
+
296
+ /**
297
+ * Block Registry - Central registry of all available UI blocks
298
+ */
299
+ declare const BLOCK_REGISTRY: Record<string, BlockRegistryEntry>;
300
+ /**
301
+ * Get blocks by semantic tag
302
+ */
303
+ declare function getBlocksBySemanticTag(tag: string): BlockRegistryEntry[];
304
+ /**
305
+ * Get blocks by category
306
+ */
307
+ declare function getBlocksByCategory(category: BlockCategory): BlockRegistryEntry[];
308
+ /**
309
+ * Get block by ID
310
+ */
311
+ declare function getBlockById(id: string): BlockRegistryEntry | undefined;
312
+ /**
313
+ * Get all available blocks
314
+ */
315
+ declare function getAllBlocks(): BlockRegistryEntry[];
316
+ /**
317
+ * Get all categories
318
+ */
319
+ declare function getAllCategories(): BlockCategory[];
320
+ /**
321
+ * Search blocks by query (searches name, description, and semantic tags)
322
+ */
323
+ declare function searchBlocks(query: string): BlockRegistryEntry[];
324
+
198
325
  declare const BUILDER_CONTRACT_VERSION = "v1";
199
326
  interface CreateBuilderContractBundleOptions {
200
327
  blocks: BlockRegistryEntry[];
@@ -205,4 +332,4 @@ interface CreateBuilderContractBundleOptions {
205
332
  }
206
333
  declare function createBuilderContractBundle({ blocks, uiVersion, exportedAt, source, blockSources, }: CreateBuilderContractBundleOptions): BuilderContractBundle;
207
334
 
208
- export { BLOCK_REGISTRY, BUILDER_CONTRACT_VERSION, type BlockCategory, type BlockMetadata, type BlockRegistryEntry, type BuilderContractBlock, type BuilderContractBlockSource, type BuilderContractBundle, type BuilderContractDesignTokens, type BuilderContractDynamicSourceDefinition, type BuilderContractDynamicSources, type BuilderContractExamples, type BuilderContractLayoutRole, type BuilderContractMetadata, type BuilderContractPageRules, type BuilderContractPropsContract, type BuilderContractSharedLayout, type BuilderContractSharedLayoutSection, createBuilderContractBundle, getAllBlocks, getAllCategories, getBlockById, getBlocksByCategory, getBlocksBySemanticTag, searchBlocks };
335
+ export { BLOCK_REGISTRY, BUILDER_CONTRACT_VERSION, type BlockCategory, type BlockContractFields, type BlockMediaSlot, type BlockMetadata, type BlockPropConstraint, type BlockRegistryEntry, type BlockUsageRequirements, type BuilderContractBlock, type BuilderContractBlockSource, type BuilderContractBundle, type BuilderContractDesignTokens, type BuilderContractDynamicSourceDefinition, type BuilderContractDynamicSources, type BuilderContractExamples, type BuilderContractLayoutRole, type BuilderContractMetadata, type BuilderContractPageRules, type BuilderContractPropsContract, type BuilderContractSharedLayout, type BuilderContractSharedLayoutSection, type MediaPixelClass, type MediaRole, type SiteCapability, createBuilderContractBundle, getAllBlocks, getAllCategories, getBlockById, getBlocksByCategory, getBlocksBySemanticTag, searchBlocks };
@@ -1,68 +1,131 @@
1
1
  /**
2
- * Semantic Block Registry
2
+ * Block Registry Types
3
3
  *
4
- * This registry maps semantic concepts to available UI blocks for AI-driven
5
- * site generation. Each block entry contains:
6
- * - id: Unique identifier for the block
7
- * - name: Human-readable name
8
- * - description: What the block does and when to use it
9
- * - semanticTags: Array of semantic concepts this block represents
10
- * - category: Block category (about, features, cta, testimonials, etc.)
11
- * - component: Reference to the actual component
12
- * - props: TypeScript type for the component's props
13
- * - exampleUsage: Code example showing how to use the block
14
- */
15
- interface BlockRegistryEntry$1<T = any> {
16
- id: string;
17
- name: string;
18
- description: string;
19
- semanticTags: string[];
20
- category: BlockCategory$1;
21
- component: React.ComponentType<T>;
22
- props: string;
23
- exampleUsage: string;
24
- }
25
- type BlockCategory$1 = "about" | "features" | "cta" | "testimonials" | "services" | "hero" | "footer" | "header" | "pricing" | "team" | "stats" | "faq" | "contact" | "carousel" | "gallery" | "timeline" | "process" | "benefits" | "comparison" | "background-pattern-hero" | "blog" | "article" | "case-studies-list" | "case-study-detail" | "navbar" | "logos" | "project-list" | "project-detail" | "list" | "offer-modal" | "banner" | "industries" | "resource-detail" | "service-detail" | "services-list" | "resource-list" | "link-page";
26
- /**
27
- * Block Registry - Central registry of all available UI blocks
28
- */
29
- declare const BLOCK_REGISTRY: Record<string, BlockRegistryEntry$1>;
30
- /**
31
- * Get blocks by semantic tag
4
+ * Shared type definitions for the block registry system.
32
5
  */
33
- declare function getBlocksBySemanticTag(tag: string): BlockRegistryEntry$1[];
6
+ type BlockCategory = "about" | "features" | "cta" | "testimonials" | "services" | "hero" | "footer" | "header" | "pricing" | "team" | "stats" | "faq" | "contact" | "carousel" | "gallery" | "timeline" | "process" | "benefits" | "comparison" | "background-pattern-hero" | "blog" | "article" | "case-studies-list" | "case-study-detail" | "navbar" | "logos" | "project-list" | "project-detail" | "list" | "offer-modal" | "banner" | "industries" | "resource-detail" | "service-detail" | "services-list" | "resource-list" | "link-page";
34
7
  /**
35
- * Get blocks by category
8
+ * Semantic role hints for a media slot. Consumers (semantic site builders,
9
+ * media classifiers) use these to scope which assets are eligible for a slot.
10
+ *
11
+ * - `logo`: brand logos / wordmarks (small, transparent backgrounds).
12
+ * - `favicon`: tiny brand icon.
13
+ * - `hero`: large hero/banner imagery.
14
+ * - `feature`: large feature/marketing imagery (non-logo).
15
+ * - `thumbnail`: small supporting imagery (e.g. card images, team thumbs).
16
+ * - `profile`: portrait/headshot of a person.
17
+ * - `avatar`: small profile / testimonial avatar.
18
+ * - `gallery`: imagery suited for galleries / grids.
19
+ * - `background`: large background imagery, often photographic.
20
+ * - `screenshot`: product screenshots / UI captures.
21
+ * - `illustration`: vector / illustrative art.
22
+ * - `video-thumbnail`: poster image for a video slot.
36
23
  */
37
- declare function getBlocksByCategory(category: BlockCategory$1): BlockRegistryEntry$1[];
24
+ type MediaRole = "logo" | "favicon" | "hero" | "feature" | "thumbnail" | "profile" | "avatar" | "gallery" | "background" | "screenshot" | "illustration" | "video-thumbnail";
25
+ /** Minimum pixel class expected for a media asset. */
26
+ type MediaPixelClass = "tiny" | "small" | "medium" | "large" | "xlarge";
38
27
  /**
39
- * Get block by ID
28
+ * Structured description of a single media slot inside a block's prop tree.
29
+ * The `path` is dot/bracket notation, e.g. `featureImage`, `smallImages[]`,
30
+ * `testimonial.avatarSrc`.
40
31
  */
41
- declare function getBlockById(id: string): BlockRegistryEntry$1 | undefined;
32
+ interface BlockMediaSlot {
33
+ path: string;
34
+ /** Allowed/expected semantic roles for this slot, in priority order. */
35
+ roles: MediaRole[];
36
+ /** Roles that must NOT be assigned to this slot. */
37
+ disallowedRoles?: MediaRole[];
38
+ /** Minimum acceptable pixel class for this slot. */
39
+ minPixelClass?: MediaPixelClass;
40
+ /** Preferred aspect ratio, e.g. "16:9", "1:1", "4:5". */
41
+ preferredAspect?: string;
42
+ /** Whether the block visually requires this slot to render correctly. */
43
+ required?: boolean;
44
+ /** Short note explaining the slot's intent (consumed by AI prompts). */
45
+ note?: string;
46
+ }
42
47
  /**
43
- * Get all available blocks
48
+ * Per-prop content constraints. Additive – consumers should treat missing
49
+ * fields as "no constraint declared" rather than rejecting payloads.
44
50
  */
45
- declare function getAllBlocks(): BlockRegistryEntry$1[];
51
+ interface BlockPropConstraint {
52
+ /** Whether the block requires this prop to render correctly. */
53
+ required?: boolean;
54
+ /** Maximum string length for text-shaped props. */
55
+ maxLength?: number;
56
+ /** Exact item count for array props (shorthand for minItems = maxItems). */
57
+ count?: number;
58
+ /** Minimum array length. */
59
+ minItems?: number;
60
+ /** Maximum array length. */
61
+ maxItems?: number;
62
+ /**
63
+ * Pinned values, by index for array props or as a single value for scalars.
64
+ * Used for the `actions[0].variant = "default"` / `actions[1].variant = "outline"` pattern.
65
+ */
66
+ pinnedValues?: Record<string, string | number | boolean>;
67
+ /** Free-form note about this prop (for AI prompts). */
68
+ note?: string;
69
+ }
46
70
  /**
47
- * Get all categories
71
+ * Capabilities the host site / data source must satisfy for the block to be
72
+ * suitable. Consumers (e.g. Octane) gate block selection on these BEFORE the
73
+ * block is offered to the model, so it cannot fabricate the missing input.
48
74
  */
49
- declare function getAllCategories(): BlockCategory$1[];
75
+ type SiteCapability = "reviews_or_testimonials" | "pricing_data" | "team_members" | "blog_posts" | "case_studies" | "metrics_or_stats" | "product_catalog" | "media_library" | "contact_info";
50
76
  /**
51
- * Search blocks by query (searches name, description, and semantic tags)
77
+ * Structured usage requirements for a block. This is the executable
78
+ * complement to `importantUsageNotes` (which remains for human-readable
79
+ * prompt context). When present, downstream consumers SHOULD enforce these
80
+ * at selection time and during post-generation validation.
52
81
  */
53
- declare function searchBlocks(query: string): BlockRegistryEntry$1[];
54
-
82
+ interface BlockUsageRequirements {
83
+ /** Names of props that are required for the block to render correctly. */
84
+ requiredProps?: string[];
85
+ /** Per-prop content/cardinality constraints, keyed by prop name/path. */
86
+ propConstraints?: Record<string, BlockPropConstraint>;
87
+ /** Media slot metadata, keyed by slot path. */
88
+ mediaSlots?: Record<string, BlockMediaSlot>;
89
+ /** Site capabilities required to safely select this block. */
90
+ requiresSiteCapabilities?: SiteCapability[];
91
+ /**
92
+ * Free-form structured rules that don't fit other fields. Consumers should
93
+ * treat unknown keys as advisory.
94
+ */
95
+ notes?: string[];
96
+ }
55
97
  /**
56
- * Block Registry Types
57
- *
58
- * Shared type definitions for the block registry system.
98
+ * Shared metadata fields that describe a block's contract. Used both by
99
+ * {@link BlockMetadata} (no component) and {@link BlockRegistryEntry}
100
+ * (with component).
59
101
  */
60
- type BlockCategory = "about" | "features" | "cta" | "testimonials" | "services" | "hero" | "footer" | "header" | "pricing" | "team" | "stats" | "faq" | "contact" | "carousel" | "gallery" | "timeline" | "process" | "benefits" | "comparison" | "background-pattern-hero" | "blog" | "article" | "case-studies-list" | "case-study-detail" | "navbar" | "logos" | "project-list" | "project-detail" | "list" | "offer-modal" | "banner" | "industries" | "resource-detail" | "service-detail" | "services-list" | "resource-list" | "link-page";
102
+ interface BlockContractFields {
103
+ /**
104
+ * Human-readable usage guidance for AI prompts. This remains advisory.
105
+ * For executable rules use {@link BlockContractFields.usageRequirements}.
106
+ */
107
+ importantUsageNotes?: string;
108
+ /** Structured, machine-readable usage requirements. */
109
+ usageRequirements?: BlockUsageRequirements;
110
+ /**
111
+ * Canonical example payload for the block, matching the prop shape.
112
+ * Optional. When supplied, consumers should prefer this over parsing
113
+ * `exampleUsage` JSX.
114
+ *
115
+ * IMPORTANT: These are reference examples for AI prompting / preview
116
+ * tooling only. They are NOT runtime defaults — consumers MUST NOT
117
+ * substitute these values as fallback content on a real client site.
118
+ * The previous name (`defaultProps`) was renamed to make this explicit:
119
+ * AI agents had begun treating "default" values as safe runtime
120
+ * fallbacks for missing client data, which is incorrect.
121
+ */
122
+ exampleProps?: Record<string, unknown>;
123
+ }
61
124
  /**
62
125
  * Metadata-only block registry entry (no component import)
63
126
  * Used for AI-driven component discovery without bundling all components
64
127
  */
65
- interface BlockMetadata {
128
+ interface BlockMetadata extends BlockContractFields {
66
129
  id: string;
67
130
  name: string;
68
131
  description: string;
@@ -81,7 +144,7 @@ interface BlockMetadata {
81
144
  * Full block registry entry with component reference
82
145
  * @deprecated Use BlockMetadata for new code - this type causes all components to be bundled
83
146
  */
84
- interface BlockRegistryEntry<T = any> {
147
+ interface BlockRegistryEntry<T = any> extends BlockContractFields {
85
148
  id: string;
86
149
  name: string;
87
150
  description: string;
@@ -107,7 +170,17 @@ interface BuilderContractPropsContract {
107
170
  }
108
171
  interface BuilderContractExamples {
109
172
  exampleUsage: string | null;
110
- defaultData: null;
173
+ /**
174
+ * Canonical example props payload. Populated from
175
+ * BlockRegistryEntry.exampleProps when declared, otherwise null.
176
+ *
177
+ * IMPORTANT: This is reference example data only, not a runtime
178
+ * fallback. Consumers MUST NOT substitute these values for missing
179
+ * client content. The previous name (`defaultData`) was renamed
180
+ * because downstream AI agents were treating it as safe runtime
181
+ * default content.
182
+ */
183
+ exampleProps: Record<string, unknown> | null;
111
184
  }
112
185
  interface BuilderContractBlock {
113
186
  componentId: string;
@@ -121,6 +194,16 @@ interface BuilderContractBlock {
121
194
  propsContract: BuilderContractPropsContract;
122
195
  examples: BuilderContractExamples;
123
196
  source: BuilderContractBlockSource | null;
197
+ /**
198
+ * Human-readable usage guidance for AI prompts. Mirrors
199
+ * BlockRegistryEntry.importantUsageNotes when declared, otherwise null.
200
+ */
201
+ importantUsageNotes: string | null;
202
+ /**
203
+ * Structured, machine-readable usage requirements. Null when the
204
+ * registry entry does not declare any.
205
+ */
206
+ usageRequirements: BlockUsageRequirements | null;
124
207
  }
125
208
  interface BuilderContractMetadata {
126
209
  contractVersion: string;
@@ -195,6 +278,50 @@ interface BuilderContractBundle {
195
278
  pageRules: BuilderContractPageRules;
196
279
  }
197
280
 
281
+ /**
282
+ * Semantic Block Registry
283
+ *
284
+ * This registry maps semantic concepts to available UI blocks for AI-driven
285
+ * site generation. Each block entry contains:
286
+ * - id: Unique identifier for the block
287
+ * - name: Human-readable name
288
+ * - description: What the block does and when to use it
289
+ * - semanticTags: Array of semantic concepts this block represents
290
+ * - category: Block category (about, features, cta, testimonials, etc.)
291
+ * - component: Reference to the actual component
292
+ * - props: TypeScript type for the component's props
293
+ * - exampleUsage: Code example showing how to use the block
294
+ */
295
+
296
+ /**
297
+ * Block Registry - Central registry of all available UI blocks
298
+ */
299
+ declare const BLOCK_REGISTRY: Record<string, BlockRegistryEntry>;
300
+ /**
301
+ * Get blocks by semantic tag
302
+ */
303
+ declare function getBlocksBySemanticTag(tag: string): BlockRegistryEntry[];
304
+ /**
305
+ * Get blocks by category
306
+ */
307
+ declare function getBlocksByCategory(category: BlockCategory): BlockRegistryEntry[];
308
+ /**
309
+ * Get block by ID
310
+ */
311
+ declare function getBlockById(id: string): BlockRegistryEntry | undefined;
312
+ /**
313
+ * Get all available blocks
314
+ */
315
+ declare function getAllBlocks(): BlockRegistryEntry[];
316
+ /**
317
+ * Get all categories
318
+ */
319
+ declare function getAllCategories(): BlockCategory[];
320
+ /**
321
+ * Search blocks by query (searches name, description, and semantic tags)
322
+ */
323
+ declare function searchBlocks(query: string): BlockRegistryEntry[];
324
+
198
325
  declare const BUILDER_CONTRACT_VERSION = "v1";
199
326
  interface CreateBuilderContractBundleOptions {
200
327
  blocks: BlockRegistryEntry[];
@@ -205,4 +332,4 @@ interface CreateBuilderContractBundleOptions {
205
332
  }
206
333
  declare function createBuilderContractBundle({ blocks, uiVersion, exportedAt, source, blockSources, }: CreateBuilderContractBundleOptions): BuilderContractBundle;
207
334
 
208
- export { BLOCK_REGISTRY, BUILDER_CONTRACT_VERSION, type BlockCategory, type BlockMetadata, type BlockRegistryEntry, type BuilderContractBlock, type BuilderContractBlockSource, type BuilderContractBundle, type BuilderContractDesignTokens, type BuilderContractDynamicSourceDefinition, type BuilderContractDynamicSources, type BuilderContractExamples, type BuilderContractLayoutRole, type BuilderContractMetadata, type BuilderContractPageRules, type BuilderContractPropsContract, type BuilderContractSharedLayout, type BuilderContractSharedLayoutSection, createBuilderContractBundle, getAllBlocks, getAllCategories, getBlockById, getBlocksByCategory, getBlocksBySemanticTag, searchBlocks };
335
+ export { BLOCK_REGISTRY, BUILDER_CONTRACT_VERSION, type BlockCategory, type BlockContractFields, type BlockMediaSlot, type BlockMetadata, type BlockPropConstraint, type BlockRegistryEntry, type BlockUsageRequirements, type BuilderContractBlock, type BuilderContractBlockSource, type BuilderContractBundle, type BuilderContractDesignTokens, type BuilderContractDynamicSourceDefinition, type BuilderContractDynamicSources, type BuilderContractExamples, type BuilderContractLayoutRole, type BuilderContractMetadata, type BuilderContractPageRules, type BuilderContractPropsContract, type BuilderContractSharedLayout, type BuilderContractSharedLayoutSection, type MediaPixelClass, type MediaRole, type SiteCapability, createBuilderContractBundle, getAllBlocks, getAllCategories, getBlockById, getBlocksByCategory, getBlocksBySemanticTag, searchBlocks };
package/dist/registry.js CHANGED
@@ -66935,16 +66935,22 @@ var FeaturedCardsGridDropdown = ({
66935
66935
  optixFlowConfig
66936
66936
  }) => {
66937
66937
  return /* @__PURE__ */ jsxs("div", { children: [
66938
- /* @__PURE__ */ jsx("div", { className: "flex gap-4 pb-8", children: featuredLinks?.map((link, index) => /* @__PURE__ */ jsx(
66938
+ featuredLinks && featuredLinks?.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex gap-4 pb-8", children: featuredLinks?.map((link, index) => /* @__PURE__ */ jsx(
66939
66939
  FeaturedLink,
66940
66940
  {
66941
66941
  link,
66942
66942
  optixFlowConfig
66943
66943
  },
66944
66944
  `desktop-featured-link-${index}`
66945
- )) }),
66946
- /* @__PURE__ */ jsx(Separator, {}),
66947
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 pt-8", children: links?.map((link, index) => /* @__PURE__ */ jsx(NavLink, { link }, `default-nav-link-${index}`)) })
66945
+ )) }) : null,
66946
+ featuredLinks && featuredLinks?.length > 0 && links && links?.length > 0 ? /* @__PURE__ */ jsx(Separator, {}) : null,
66947
+ links && links?.length > 0 ? /* @__PURE__ */ jsx(
66948
+ "div",
66949
+ {
66950
+ className: `grid grid-cols-4 pt-${featuredLinks && featuredLinks?.length > 0 ? 8 : 0} gap-4`,
66951
+ children: links?.map((link, index) => /* @__PURE__ */ jsx(NavLink, { link }, `default-nav-link-${index}`))
66952
+ }
66953
+ ) : null
66948
66954
  ] });
66949
66955
  };
66950
66956
  var GroupedLinksImageDropdown = ({
@@ -112020,7 +112026,106 @@ var BLOCK_REGISTRY = {
112020
112026
  category: "hero",
112021
112027
  component: HeroMentalHealthTeam,
112022
112028
  props: "HeroMentalHealthTeamProps",
112023
- exampleUsage: `<HeroMentalHealthTeam />`.trim()
112029
+ exampleUsage: `
112030
+ <HeroMentalHealthTeam
112031
+ heading="Compassionate care for your mental wellbeing"
112032
+ description="Our team of experienced mental health professionals is dedicated to providing compassionate care and support to individuals in need."
112033
+ smallImages={[
112034
+ { src: "/images/team-1.jpg", alt: "Dr. Smith" },
112035
+ { src: "/images/team-2.jpg", alt: "Dr. Johnson" },
112036
+ ]}
112037
+ testimonial={{
112038
+ quote:
112039
+ "The support I received changed my life. I'm so grateful for the compassionate care.",
112040
+ author: "Sarah M.",
112041
+ role: "Client",
112042
+ avatarSrc: "/images/avatar.jpg",
112043
+ }}
112044
+ featureImage={{ src: "/images/feature.jpg", alt: "Mental health support" }}
112045
+ actions={[
112046
+ { label: "Get Started", href: "#", variant: "default" },
112047
+ { label: "Talk to Sales", href: "#", variant: "outline" },
112048
+ ]}
112049
+ background="gray"
112050
+ />
112051
+ `.trim(),
112052
+ importantUsageNotes: "Only use if you have a valid testimonial - DO NOT MAKE UP A TESTIMONIAL/REVIEW. Supply exactly 2 images to the 'smallImages' prop and ensure you supply a 'featureImage' prop object. Do not exceed 40 characters for the 'heading' prop. Do not exceed 130 characters for the 'description' prop. If you supply multiple 'actions', ensure to use a variant of 'default' for the first action, and 'outline' for the second action to ensure proper visual distinction between the two CTAs. Follow the example props closely for this block.",
112053
+ usageRequirements: {
112054
+ requiredProps: ["heading", "smallImages", "featureImage", "testimonial"],
112055
+ propConstraints: {
112056
+ heading: { required: true, maxLength: 40 },
112057
+ description: { maxLength: 130 },
112058
+ smallImages: { required: true, count: 2, minItems: 2, maxItems: 2 },
112059
+ featureImage: { required: true },
112060
+ testimonial: {
112061
+ required: true,
112062
+ note: "Must be a real, sourced testimonial. Do not fabricate."
112063
+ },
112064
+ actions: {
112065
+ maxItems: 2,
112066
+ pinnedValues: {
112067
+ "0.variant": "default",
112068
+ "1.variant": "outline"
112069
+ }
112070
+ }
112071
+ },
112072
+ mediaSlots: {
112073
+ featureImage: {
112074
+ path: "featureImage",
112075
+ roles: ["feature", "hero"],
112076
+ disallowedRoles: ["logo", "favicon"],
112077
+ minPixelClass: "large",
112078
+ required: true,
112079
+ note: "Large feature image. Must not be a logo or favicon."
112080
+ },
112081
+ "smallImages[]": {
112082
+ path: "smallImages[]",
112083
+ roles: ["thumbnail", "profile", "feature"],
112084
+ disallowedRoles: ["logo", "favicon"],
112085
+ minPixelClass: "small",
112086
+ required: true,
112087
+ note: "Two team / supporting images. Must not be logos."
112088
+ },
112089
+ "testimonial.avatarSrc": {
112090
+ path: "testimonial.avatarSrc",
112091
+ roles: ["profile", "avatar"],
112092
+ disallowedRoles: ["logo", "favicon"],
112093
+ minPixelClass: "small",
112094
+ preferredAspect: "1:1",
112095
+ note: "Headshot/avatar for the testimonial author."
112096
+ }
112097
+ },
112098
+ requiresSiteCapabilities: ["reviews_or_testimonials", "media_library"]
112099
+ },
112100
+ exampleProps: {
112101
+ heading: "Compassionate care for your mental wellbeing",
112102
+ description: "Our team of experienced mental health professionals is dedicated to providing compassionate care and support to individuals in need.",
112103
+ smallImages: [
112104
+ {
112105
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112106
+ alt: "Dr. Smith"
112107
+ },
112108
+ {
112109
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112110
+ alt: "Dr. Johnson"
112111
+ }
112112
+ ],
112113
+ testimonial: {
112114
+ quote: "The support I received changed my life. I'm so grateful for the compassionate care.",
112115
+ author: "Sarah M.",
112116
+ role: "Client",
112117
+ avatarSrc: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp"
112118
+ },
112119
+ featureImage: {
112120
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112121
+ alt: "Mental health support"
112122
+ },
112123
+ actions: [
112124
+ { label: "Get Started", href: "#", variant: "default" },
112125
+ { label: "Talk to Sales", href: "#", variant: "outline" }
112126
+ ],
112127
+ background: "gray"
112128
+ }
112024
112129
  },
112025
112130
  "hero-mentorship-video-split": {
112026
112131
  id: "hero-mentorship-video-split",
@@ -112039,7 +112144,101 @@ var BLOCK_REGISTRY = {
112039
112144
  category: "hero",
112040
112145
  component: HeroMentorshipVideoSplit,
112041
112146
  props: "HeroMentorshipVideoSplitProps",
112042
- exampleUsage: `<HeroMentorshipVideoSplit />`.trim()
112147
+ exampleUsage: `
112148
+ <HeroMentorshipVideoSplit
112149
+ heading="Reclaim Your Peace. Scale Sustainably."
112150
+ description="Somatic mindset coaching for high-achieving entrepreneurs ready to lead from strength \u2014 not survival mode."
112151
+ action={{ label: "Book Your Discovery Call", href: "/contact", variant: "default", size: "lg" }}
112152
+ videoLabel="Watch the Overview"
112153
+ videoTitle="Coaching Overview"
112154
+ modalVideo={{
112155
+ image: {
112156
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112157
+ alt: "Coaching overview poster",
112158
+ },
112159
+ video: {
112160
+ src: "https://toastability-production.s3.amazonaws.com/4kox2ux0ye1wlqkdwg03s08a67i1",
112161
+ },
112162
+ }}
112163
+ image={{
112164
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112165
+ alt: "Coach portrait",
112166
+ }}
112167
+ background="dark"
112168
+ />
112169
+ `.trim(),
112170
+ importantUsageNotes: "The 'image' prop is the main hero image and MUST be an image asset (poster/photo). The 'modalVideo' prop's nested 'video.src' MUST be a video asset (HLS playlist or MP4) and 'modalVideo.image.src' MUST be an image asset (video poster). NEVER swap these: do not put a video URL into the 'image' prop and do not put an image URL into 'modalVideo.video.src'. All media src values must be absolute URLs to real CDN assets \u2014 never relative paths or placeholder strings. Keep 'heading' concise (under 60 characters) for visual balance.",
112171
+ usageRequirements: {
112172
+ requiredProps: ["heading", "image"],
112173
+ propConstraints: {
112174
+ heading: { required: true, maxLength: 60 },
112175
+ description: { maxLength: 220 },
112176
+ image: {
112177
+ required: true,
112178
+ note: "Main hero image. Must be an image asset (jpg/png/webp), NOT a video URL."
112179
+ },
112180
+ "modalVideo.video.src": {
112181
+ note: "Must be a video asset URL (HLS .m3u8 master playlist or .mp4). Must NOT be an image URL."
112182
+ },
112183
+ "modalVideo.image.src": {
112184
+ note: "Video poster image. Must be an image asset, NOT a video URL."
112185
+ }
112186
+ },
112187
+ mediaSlots: {
112188
+ image: {
112189
+ path: "image",
112190
+ roles: ["hero", "feature", "profile"],
112191
+ disallowedRoles: ["logo", "favicon", "video-thumbnail"],
112192
+ minPixelClass: "large",
112193
+ required: true,
112194
+ note: "Main hero image slot. IMAGE MEDIA ONLY. Do not assign a video URL here."
112195
+ },
112196
+ "modalVideo.video.src": {
112197
+ path: "modalVideo.video.src",
112198
+ roles: [],
112199
+ disallowedRoles: ["logo", "favicon", "hero", "feature", "profile"],
112200
+ note: "VIDEO MEDIA ONLY (HLS master playlist or MP4). Do not assign an image URL here."
112201
+ },
112202
+ "modalVideo.image.src": {
112203
+ path: "modalVideo.image.src",
112204
+ roles: ["video-thumbnail", "hero", "feature"],
112205
+ disallowedRoles: ["logo", "favicon"],
112206
+ minPixelClass: "medium",
112207
+ note: "Poster image shown before the video plays. IMAGE MEDIA ONLY."
112208
+ }
112209
+ },
112210
+ requiresSiteCapabilities: ["media_library"],
112211
+ notes: [
112212
+ "Image and video media must never be swapped between the 'image' prop and the 'modalVideo' prop.",
112213
+ "All media src values must be absolute URLs to real assets; relative paths are not allowed."
112214
+ ]
112215
+ },
112216
+ exampleProps: {
112217
+ heading: "Reclaim Your Peace. Scale Sustainably.",
112218
+ description: "Somatic mindset coaching for high-achieving entrepreneurs ready to lead from strength \u2014 not survival mode.",
112219
+ action: {
112220
+ label: "Book Your Discovery Call",
112221
+ href: "/contact",
112222
+ variant: "default",
112223
+ size: "lg"
112224
+ },
112225
+ videoLabel: "Watch the Overview",
112226
+ videoTitle: "Coaching Overview",
112227
+ modalVideo: {
112228
+ image: {
112229
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112230
+ alt: "Coaching overview poster"
112231
+ },
112232
+ video: {
112233
+ src: "https://toastability-production.s3.amazonaws.com/4kox2ux0ye1wlqkdwg03s08a67i1"
112234
+ }
112235
+ },
112236
+ image: {
112237
+ src: "https://cdn.ing/assets/i/r/308196/g6bbn73f7gxal82uu49m9prfd0u8/workplace-in-cafe.webp",
112238
+ alt: "Coach portrait"
112239
+ },
112240
+ background: "dark"
112241
+ }
112043
112242
  },
112044
112243
  "hero-business-operations-mosaic": {
112045
112244
  id: "hero-business-operations-mosaic",
@@ -120320,9 +120519,11 @@ function normalizeBlock(block, source) {
120320
120519
  },
120321
120520
  examples: {
120322
120521
  exampleUsage: block.exampleUsage || null,
120323
- defaultData: null
120522
+ exampleProps: block.exampleProps ? JSON.parse(JSON.stringify(block.exampleProps)) : null
120324
120523
  },
120325
- source: source ?? null
120524
+ source: source ?? null,
120525
+ importantUsageNotes: block.importantUsageNotes ?? null,
120526
+ usageRequirements: block.usageRequirements ? JSON.parse(JSON.stringify(block.usageRequirements)) : null
120326
120527
  };
120327
120528
  }
120328
120529
  function createBuilderContractBundle({
@@ -77,6 +77,6 @@ interface SocialLinkIconProps extends Omit<PressableProps, "children">, SocialLi
77
77
  * />
78
78
  * ```
79
79
  */
80
- declare const SocialLinkIcon: React.ForwardRefExoticComponent<SocialLinkIconProps & React.RefAttributes<HTMLAnchorElement | HTMLButtonElement | HTMLSpanElement>>;
80
+ declare const SocialLinkIcon: React.ForwardRefExoticComponent<SocialLinkIconProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement | HTMLSpanElement>>;
81
81
 
82
82
  export { SocialLinkIcon, type SocialLinkIconDynamicIconProps, type SocialLinkIconProps };
@@ -77,6 +77,6 @@ interface SocialLinkIconProps extends Omit<PressableProps, "children">, SocialLi
77
77
  * />
78
78
  * ```
79
79
  */
80
- declare const SocialLinkIcon: React.ForwardRefExoticComponent<SocialLinkIconProps & React.RefAttributes<HTMLAnchorElement | HTMLButtonElement | HTMLSpanElement>>;
80
+ declare const SocialLinkIcon: React.ForwardRefExoticComponent<SocialLinkIconProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement | HTMLSpanElement>>;
81
81
 
82
82
  export { SocialLinkIcon, type SocialLinkIconDynamicIconProps, type SocialLinkIconProps };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensite/ui",
3
- "version": "3.5.6",
3
+ "version": "3.5.8",
4
4
  "description": "Foundational UI component library for OpenSite Semantic Site Builder with tree-shakable exports and abstract styling",
5
5
  "keywords": [
6
6
  "react",