@opensite/ui 3.5.5 → 3.5.7

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/registry.cjs CHANGED
@@ -97927,8 +97927,8 @@ function StatsGrowthTimeline({
97927
97927
  }
97928
97928
  ),
97929
97929
  milestone.title && (typeof milestone.title === "string" ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-2 text-xl font-bold", children: milestone.title }) : milestone.title),
97930
- milestone.description && (typeof milestone.description === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-4 text-muted-foreground", children: milestone.description }) : milestone.description),
97931
- milestone.metric && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 rounded-lg border bg-background p-4 shadow-sm", children: [
97930
+ milestone.description && (typeof milestone.description === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-4 opacity-70 text-balance", children: milestone.description }) : milestone.description),
97931
+ milestone.metric && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 rounded-lg border bg-card text-card-foreground p-4 shadow-sm", children: [
97932
97932
  renderMilestoneIcon(milestone),
97933
97933
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
97934
97934
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-semibold", children: milestone.metric.value }),
@@ -97989,8 +97989,8 @@ function StatsGrowthTimeline({
97989
97989
  futureClassName
97990
97990
  ),
97991
97991
  children: [
97992
- futureHeading && (typeof futureHeading === "string" ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-4 text-2xl font-bold", children: futureHeading }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4", children: futureHeading })),
97993
- futureDescription && (typeof futureDescription === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mx-auto mb-8 max-w-full md:max-w-lg text-balance", children: futureDescription }) : futureDescription),
97992
+ futureHeading && (typeof futureHeading === "string" ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-2xl font-bold", children: futureHeading }) : futureHeading),
97993
+ futureDescription && (typeof futureDescription === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-full md:max-w-md text-balance", children: futureDescription }) : futureDescription),
97994
97994
  /* @__PURE__ */ jsxRuntime.jsx(
97995
97995
  BlockActions,
97996
97996
  {
@@ -98035,12 +98035,12 @@ function StatsGrowthTimeline({
98035
98035
  ),
98036
98036
  children: heading
98037
98037
  }
98038
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mb-4", headingClassName), children: heading })),
98038
+ ) : heading),
98039
98039
  description && (typeof description === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
98040
98040
  "p",
98041
98041
  {
98042
98042
  className: cn(
98043
- "mx-auto max-w-3xl text-lg text-muted-foreground",
98043
+ "max-w-full md:max-w-md text-base md:text-lg text-balance",
98044
98044
  descriptionClassName
98045
98045
  ),
98046
98046
  children: description
@@ -112060,7 +112060,97 @@ var BLOCK_REGISTRY = {
112060
112060
  category: "hero",
112061
112061
  component: HeroMentalHealthTeam,
112062
112062
  props: "HeroMentalHealthTeamProps",
112063
- exampleUsage: `<HeroMentalHealthTeam />`.trim()
112063
+ exampleUsage: `
112064
+ <HeroMentalHealthTeam
112065
+ heading="Compassionate care for your mental wellbeing"
112066
+ description="Our team of experienced mental health professionals is dedicated to providing compassionate care and support to individuals in need."
112067
+ smallImages={[
112068
+ { src: "/images/team-1.jpg", alt: "Dr. Smith" },
112069
+ { src: "/images/team-2.jpg", alt: "Dr. Johnson" },
112070
+ ]}
112071
+ testimonial={{
112072
+ quote:
112073
+ "The support I received changed my life. I'm so grateful for the compassionate care.",
112074
+ author: "Sarah M.",
112075
+ role: "Client",
112076
+ avatarSrc: "/images/avatar.jpg",
112077
+ }}
112078
+ featureImage={{ src: "/images/feature.jpg", alt: "Mental health support" }}
112079
+ actions={[
112080
+ { label: "Get Started", href: "#", variant: "default" },
112081
+ { label: "Talk to Sales", href: "#", variant: "outline" },
112082
+ ]}
112083
+ background="gray"
112084
+ />
112085
+ `.trim(),
112086
+ 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.",
112087
+ usageRequirements: {
112088
+ requiredProps: ["heading", "smallImages", "featureImage", "testimonial"],
112089
+ propConstraints: {
112090
+ heading: { required: true, maxLength: 40 },
112091
+ description: { maxLength: 130 },
112092
+ smallImages: { required: true, count: 2, minItems: 2, maxItems: 2 },
112093
+ featureImage: { required: true },
112094
+ testimonial: {
112095
+ required: true,
112096
+ note: "Must be a real, sourced testimonial. Do not fabricate."
112097
+ },
112098
+ actions: {
112099
+ maxItems: 2,
112100
+ pinnedValues: {
112101
+ "0.variant": "default",
112102
+ "1.variant": "outline"
112103
+ }
112104
+ }
112105
+ },
112106
+ mediaSlots: {
112107
+ featureImage: {
112108
+ path: "featureImage",
112109
+ roles: ["feature", "hero"],
112110
+ disallowedRoles: ["logo", "favicon"],
112111
+ minPixelClass: "large",
112112
+ required: true,
112113
+ note: "Large feature image. Must not be a logo or favicon."
112114
+ },
112115
+ "smallImages[]": {
112116
+ path: "smallImages[]",
112117
+ roles: ["thumbnail", "profile", "feature"],
112118
+ disallowedRoles: ["logo", "favicon"],
112119
+ minPixelClass: "small",
112120
+ required: true,
112121
+ note: "Two team / supporting images. Must not be logos."
112122
+ },
112123
+ "testimonial.avatarSrc": {
112124
+ path: "testimonial.avatarSrc",
112125
+ roles: ["profile", "avatar"],
112126
+ disallowedRoles: ["logo", "favicon"],
112127
+ minPixelClass: "small",
112128
+ preferredAspect: "1:1",
112129
+ note: "Headshot/avatar for the testimonial author."
112130
+ }
112131
+ },
112132
+ requiresSiteCapabilities: ["reviews_or_testimonials", "media_library"]
112133
+ },
112134
+ defaultProps: {
112135
+ heading: "Compassionate care for your mental wellbeing",
112136
+ description: "Our team of experienced mental health professionals is dedicated to providing compassionate care and support to individuals in need.",
112137
+ smallImages: [
112138
+ { src: "/images/team-1.jpg", alt: "Dr. Smith" },
112139
+ { src: "/images/team-2.jpg", alt: "Dr. Johnson" }
112140
+ ],
112141
+ testimonial: {
112142
+ quote: "The support I received changed my life. I'm so grateful for the compassionate care.",
112143
+ author: "Sarah M.",
112144
+ role: "Client",
112145
+ avatarSrc: "/images/avatar.jpg"
112146
+ },
112147
+ featureImage: { src: "/images/feature.jpg", alt: "Mental health support" },
112148
+ actions: [
112149
+ { label: "Get Started", href: "#", variant: "default" },
112150
+ { label: "Talk to Sales", href: "#", variant: "outline" }
112151
+ ],
112152
+ background: "gray"
112153
+ }
112064
112154
  },
112065
112155
  "hero-mentorship-video-split": {
112066
112156
  id: "hero-mentorship-video-split",
@@ -120360,9 +120450,11 @@ function normalizeBlock(block, source) {
120360
120450
  },
120361
120451
  examples: {
120362
120452
  exampleUsage: block.exampleUsage || null,
120363
- defaultData: null
120453
+ defaultData: block.defaultProps ? JSON.parse(JSON.stringify(block.defaultProps)) : null
120364
120454
  },
120365
- source: source ?? null
120455
+ source: source ?? null,
120456
+ importantUsageNotes: block.importantUsageNotes ?? null,
120457
+ usageRequirements: block.usageRequirements ? JSON.parse(JSON.stringify(block.usageRequirements)) : null
120366
120458
  };
120367
120459
  }
120368
120460
  function createBuilderContractBundle({
@@ -1,68 +1,124 @@
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 default / example payload for the block, matching the prop
112
+ * shape. Optional. When supplied, consumers should prefer this over
113
+ * parsing `exampleUsage` JSX.
114
+ */
115
+ defaultProps?: Record<string, unknown>;
116
+ }
61
117
  /**
62
118
  * Metadata-only block registry entry (no component import)
63
119
  * Used for AI-driven component discovery without bundling all components
64
120
  */
65
- interface BlockMetadata {
121
+ interface BlockMetadata extends BlockContractFields {
66
122
  id: string;
67
123
  name: string;
68
124
  description: string;
@@ -81,7 +137,7 @@ interface BlockMetadata {
81
137
  * Full block registry entry with component reference
82
138
  * @deprecated Use BlockMetadata for new code - this type causes all components to be bundled
83
139
  */
84
- interface BlockRegistryEntry<T = any> {
140
+ interface BlockRegistryEntry<T = any> extends BlockContractFields {
85
141
  id: string;
86
142
  name: string;
87
143
  description: string;
@@ -107,7 +163,13 @@ interface BuilderContractPropsContract {
107
163
  }
108
164
  interface BuilderContractExamples {
109
165
  exampleUsage: string | null;
110
- defaultData: null;
166
+ /**
167
+ * Canonical default / example props payload. Populated from
168
+ * BlockRegistryEntry.defaultProps when declared, otherwise null.
169
+ * Older consumers that expected this to always be null should treat
170
+ * an object value as advisory example data, not as a schema.
171
+ */
172
+ defaultData: Record<string, unknown> | null;
111
173
  }
112
174
  interface BuilderContractBlock {
113
175
  componentId: string;
@@ -121,6 +183,16 @@ interface BuilderContractBlock {
121
183
  propsContract: BuilderContractPropsContract;
122
184
  examples: BuilderContractExamples;
123
185
  source: BuilderContractBlockSource | null;
186
+ /**
187
+ * Human-readable usage guidance for AI prompts. Mirrors
188
+ * BlockRegistryEntry.importantUsageNotes when declared, otherwise null.
189
+ */
190
+ importantUsageNotes: string | null;
191
+ /**
192
+ * Structured, machine-readable usage requirements. Null when the
193
+ * registry entry does not declare any.
194
+ */
195
+ usageRequirements: BlockUsageRequirements | null;
124
196
  }
125
197
  interface BuilderContractMetadata {
126
198
  contractVersion: string;
@@ -195,6 +267,50 @@ interface BuilderContractBundle {
195
267
  pageRules: BuilderContractPageRules;
196
268
  }
197
269
 
270
+ /**
271
+ * Semantic Block Registry
272
+ *
273
+ * This registry maps semantic concepts to available UI blocks for AI-driven
274
+ * site generation. Each block entry contains:
275
+ * - id: Unique identifier for the block
276
+ * - name: Human-readable name
277
+ * - description: What the block does and when to use it
278
+ * - semanticTags: Array of semantic concepts this block represents
279
+ * - category: Block category (about, features, cta, testimonials, etc.)
280
+ * - component: Reference to the actual component
281
+ * - props: TypeScript type for the component's props
282
+ * - exampleUsage: Code example showing how to use the block
283
+ */
284
+
285
+ /**
286
+ * Block Registry - Central registry of all available UI blocks
287
+ */
288
+ declare const BLOCK_REGISTRY: Record<string, BlockRegistryEntry>;
289
+ /**
290
+ * Get blocks by semantic tag
291
+ */
292
+ declare function getBlocksBySemanticTag(tag: string): BlockRegistryEntry[];
293
+ /**
294
+ * Get blocks by category
295
+ */
296
+ declare function getBlocksByCategory(category: BlockCategory): BlockRegistryEntry[];
297
+ /**
298
+ * Get block by ID
299
+ */
300
+ declare function getBlockById(id: string): BlockRegistryEntry | undefined;
301
+ /**
302
+ * Get all available blocks
303
+ */
304
+ declare function getAllBlocks(): BlockRegistryEntry[];
305
+ /**
306
+ * Get all categories
307
+ */
308
+ declare function getAllCategories(): BlockCategory[];
309
+ /**
310
+ * Search blocks by query (searches name, description, and semantic tags)
311
+ */
312
+ declare function searchBlocks(query: string): BlockRegistryEntry[];
313
+
198
314
  declare const BUILDER_CONTRACT_VERSION = "v1";
199
315
  interface CreateBuilderContractBundleOptions {
200
316
  blocks: BlockRegistryEntry[];
@@ -205,4 +321,4 @@ interface CreateBuilderContractBundleOptions {
205
321
  }
206
322
  declare function createBuilderContractBundle({ blocks, uiVersion, exportedAt, source, blockSources, }: CreateBuilderContractBundleOptions): BuilderContractBundle;
207
323
 
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 };
324
+ 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,124 @@
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 default / example payload for the block, matching the prop
112
+ * shape. Optional. When supplied, consumers should prefer this over
113
+ * parsing `exampleUsage` JSX.
114
+ */
115
+ defaultProps?: Record<string, unknown>;
116
+ }
61
117
  /**
62
118
  * Metadata-only block registry entry (no component import)
63
119
  * Used for AI-driven component discovery without bundling all components
64
120
  */
65
- interface BlockMetadata {
121
+ interface BlockMetadata extends BlockContractFields {
66
122
  id: string;
67
123
  name: string;
68
124
  description: string;
@@ -81,7 +137,7 @@ interface BlockMetadata {
81
137
  * Full block registry entry with component reference
82
138
  * @deprecated Use BlockMetadata for new code - this type causes all components to be bundled
83
139
  */
84
- interface BlockRegistryEntry<T = any> {
140
+ interface BlockRegistryEntry<T = any> extends BlockContractFields {
85
141
  id: string;
86
142
  name: string;
87
143
  description: string;
@@ -107,7 +163,13 @@ interface BuilderContractPropsContract {
107
163
  }
108
164
  interface BuilderContractExamples {
109
165
  exampleUsage: string | null;
110
- defaultData: null;
166
+ /**
167
+ * Canonical default / example props payload. Populated from
168
+ * BlockRegistryEntry.defaultProps when declared, otherwise null.
169
+ * Older consumers that expected this to always be null should treat
170
+ * an object value as advisory example data, not as a schema.
171
+ */
172
+ defaultData: Record<string, unknown> | null;
111
173
  }
112
174
  interface BuilderContractBlock {
113
175
  componentId: string;
@@ -121,6 +183,16 @@ interface BuilderContractBlock {
121
183
  propsContract: BuilderContractPropsContract;
122
184
  examples: BuilderContractExamples;
123
185
  source: BuilderContractBlockSource | null;
186
+ /**
187
+ * Human-readable usage guidance for AI prompts. Mirrors
188
+ * BlockRegistryEntry.importantUsageNotes when declared, otherwise null.
189
+ */
190
+ importantUsageNotes: string | null;
191
+ /**
192
+ * Structured, machine-readable usage requirements. Null when the
193
+ * registry entry does not declare any.
194
+ */
195
+ usageRequirements: BlockUsageRequirements | null;
124
196
  }
125
197
  interface BuilderContractMetadata {
126
198
  contractVersion: string;
@@ -195,6 +267,50 @@ interface BuilderContractBundle {
195
267
  pageRules: BuilderContractPageRules;
196
268
  }
197
269
 
270
+ /**
271
+ * Semantic Block Registry
272
+ *
273
+ * This registry maps semantic concepts to available UI blocks for AI-driven
274
+ * site generation. Each block entry contains:
275
+ * - id: Unique identifier for the block
276
+ * - name: Human-readable name
277
+ * - description: What the block does and when to use it
278
+ * - semanticTags: Array of semantic concepts this block represents
279
+ * - category: Block category (about, features, cta, testimonials, etc.)
280
+ * - component: Reference to the actual component
281
+ * - props: TypeScript type for the component's props
282
+ * - exampleUsage: Code example showing how to use the block
283
+ */
284
+
285
+ /**
286
+ * Block Registry - Central registry of all available UI blocks
287
+ */
288
+ declare const BLOCK_REGISTRY: Record<string, BlockRegistryEntry>;
289
+ /**
290
+ * Get blocks by semantic tag
291
+ */
292
+ declare function getBlocksBySemanticTag(tag: string): BlockRegistryEntry[];
293
+ /**
294
+ * Get blocks by category
295
+ */
296
+ declare function getBlocksByCategory(category: BlockCategory): BlockRegistryEntry[];
297
+ /**
298
+ * Get block by ID
299
+ */
300
+ declare function getBlockById(id: string): BlockRegistryEntry | undefined;
301
+ /**
302
+ * Get all available blocks
303
+ */
304
+ declare function getAllBlocks(): BlockRegistryEntry[];
305
+ /**
306
+ * Get all categories
307
+ */
308
+ declare function getAllCategories(): BlockCategory[];
309
+ /**
310
+ * Search blocks by query (searches name, description, and semantic tags)
311
+ */
312
+ declare function searchBlocks(query: string): BlockRegistryEntry[];
313
+
198
314
  declare const BUILDER_CONTRACT_VERSION = "v1";
199
315
  interface CreateBuilderContractBundleOptions {
200
316
  blocks: BlockRegistryEntry[];
@@ -205,4 +321,4 @@ interface CreateBuilderContractBundleOptions {
205
321
  }
206
322
  declare function createBuilderContractBundle({ blocks, uiVersion, exportedAt, source, blockSources, }: CreateBuilderContractBundleOptions): BuilderContractBundle;
207
323
 
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 };
324
+ 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
@@ -97887,8 +97887,8 @@ function StatsGrowthTimeline({
97887
97887
  }
97888
97888
  ),
97889
97889
  milestone.title && (typeof milestone.title === "string" ? /* @__PURE__ */ jsx("h3", { className: "mb-2 text-xl font-bold", children: milestone.title }) : milestone.title),
97890
- milestone.description && (typeof milestone.description === "string" ? /* @__PURE__ */ jsx("p", { className: "mb-4 text-muted-foreground", children: milestone.description }) : milestone.description),
97891
- milestone.metric && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 rounded-lg border bg-background p-4 shadow-sm", children: [
97890
+ milestone.description && (typeof milestone.description === "string" ? /* @__PURE__ */ jsx("p", { className: "mb-4 opacity-70 text-balance", children: milestone.description }) : milestone.description),
97891
+ milestone.metric && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 rounded-lg border bg-card text-card-foreground p-4 shadow-sm", children: [
97892
97892
  renderMilestoneIcon(milestone),
97893
97893
  /* @__PURE__ */ jsxs("div", { children: [
97894
97894
  /* @__PURE__ */ jsx("div", { className: "text-2xl font-semibold", children: milestone.metric.value }),
@@ -97949,8 +97949,8 @@ function StatsGrowthTimeline({
97949
97949
  futureClassName
97950
97950
  ),
97951
97951
  children: [
97952
- futureHeading && (typeof futureHeading === "string" ? /* @__PURE__ */ jsx("h3", { className: "mb-4 text-2xl font-bold", children: futureHeading }) : /* @__PURE__ */ jsx("div", { className: "mb-4", children: futureHeading })),
97953
- futureDescription && (typeof futureDescription === "string" ? /* @__PURE__ */ jsx("p", { className: "mx-auto mb-8 max-w-full md:max-w-lg text-balance", children: futureDescription }) : futureDescription),
97952
+ futureHeading && (typeof futureHeading === "string" ? /* @__PURE__ */ jsx("h3", { className: "text-2xl font-bold", children: futureHeading }) : futureHeading),
97953
+ futureDescription && (typeof futureDescription === "string" ? /* @__PURE__ */ jsx("p", { className: "max-w-full md:max-w-md text-balance", children: futureDescription }) : futureDescription),
97954
97954
  /* @__PURE__ */ jsx(
97955
97955
  BlockActions,
97956
97956
  {
@@ -97995,12 +97995,12 @@ function StatsGrowthTimeline({
97995
97995
  ),
97996
97996
  children: heading
97997
97997
  }
97998
- ) : /* @__PURE__ */ jsx("div", { className: cn("mb-4", headingClassName), children: heading })),
97998
+ ) : heading),
97999
97999
  description && (typeof description === "string" ? /* @__PURE__ */ jsx(
98000
98000
  "p",
98001
98001
  {
98002
98002
  className: cn(
98003
- "mx-auto max-w-3xl text-lg text-muted-foreground",
98003
+ "max-w-full md:max-w-md text-base md:text-lg text-balance",
98004
98004
  descriptionClassName
98005
98005
  ),
98006
98006
  children: description
@@ -112020,7 +112020,97 @@ var BLOCK_REGISTRY = {
112020
112020
  category: "hero",
112021
112021
  component: HeroMentalHealthTeam,
112022
112022
  props: "HeroMentalHealthTeamProps",
112023
- exampleUsage: `<HeroMentalHealthTeam />`.trim()
112023
+ exampleUsage: `
112024
+ <HeroMentalHealthTeam
112025
+ heading="Compassionate care for your mental wellbeing"
112026
+ description="Our team of experienced mental health professionals is dedicated to providing compassionate care and support to individuals in need."
112027
+ smallImages={[
112028
+ { src: "/images/team-1.jpg", alt: "Dr. Smith" },
112029
+ { src: "/images/team-2.jpg", alt: "Dr. Johnson" },
112030
+ ]}
112031
+ testimonial={{
112032
+ quote:
112033
+ "The support I received changed my life. I'm so grateful for the compassionate care.",
112034
+ author: "Sarah M.",
112035
+ role: "Client",
112036
+ avatarSrc: "/images/avatar.jpg",
112037
+ }}
112038
+ featureImage={{ src: "/images/feature.jpg", alt: "Mental health support" }}
112039
+ actions={[
112040
+ { label: "Get Started", href: "#", variant: "default" },
112041
+ { label: "Talk to Sales", href: "#", variant: "outline" },
112042
+ ]}
112043
+ background="gray"
112044
+ />
112045
+ `.trim(),
112046
+ 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.",
112047
+ usageRequirements: {
112048
+ requiredProps: ["heading", "smallImages", "featureImage", "testimonial"],
112049
+ propConstraints: {
112050
+ heading: { required: true, maxLength: 40 },
112051
+ description: { maxLength: 130 },
112052
+ smallImages: { required: true, count: 2, minItems: 2, maxItems: 2 },
112053
+ featureImage: { required: true },
112054
+ testimonial: {
112055
+ required: true,
112056
+ note: "Must be a real, sourced testimonial. Do not fabricate."
112057
+ },
112058
+ actions: {
112059
+ maxItems: 2,
112060
+ pinnedValues: {
112061
+ "0.variant": "default",
112062
+ "1.variant": "outline"
112063
+ }
112064
+ }
112065
+ },
112066
+ mediaSlots: {
112067
+ featureImage: {
112068
+ path: "featureImage",
112069
+ roles: ["feature", "hero"],
112070
+ disallowedRoles: ["logo", "favicon"],
112071
+ minPixelClass: "large",
112072
+ required: true,
112073
+ note: "Large feature image. Must not be a logo or favicon."
112074
+ },
112075
+ "smallImages[]": {
112076
+ path: "smallImages[]",
112077
+ roles: ["thumbnail", "profile", "feature"],
112078
+ disallowedRoles: ["logo", "favicon"],
112079
+ minPixelClass: "small",
112080
+ required: true,
112081
+ note: "Two team / supporting images. Must not be logos."
112082
+ },
112083
+ "testimonial.avatarSrc": {
112084
+ path: "testimonial.avatarSrc",
112085
+ roles: ["profile", "avatar"],
112086
+ disallowedRoles: ["logo", "favicon"],
112087
+ minPixelClass: "small",
112088
+ preferredAspect: "1:1",
112089
+ note: "Headshot/avatar for the testimonial author."
112090
+ }
112091
+ },
112092
+ requiresSiteCapabilities: ["reviews_or_testimonials", "media_library"]
112093
+ },
112094
+ defaultProps: {
112095
+ heading: "Compassionate care for your mental wellbeing",
112096
+ description: "Our team of experienced mental health professionals is dedicated to providing compassionate care and support to individuals in need.",
112097
+ smallImages: [
112098
+ { src: "/images/team-1.jpg", alt: "Dr. Smith" },
112099
+ { src: "/images/team-2.jpg", alt: "Dr. Johnson" }
112100
+ ],
112101
+ testimonial: {
112102
+ quote: "The support I received changed my life. I'm so grateful for the compassionate care.",
112103
+ author: "Sarah M.",
112104
+ role: "Client",
112105
+ avatarSrc: "/images/avatar.jpg"
112106
+ },
112107
+ featureImage: { src: "/images/feature.jpg", alt: "Mental health support" },
112108
+ actions: [
112109
+ { label: "Get Started", href: "#", variant: "default" },
112110
+ { label: "Talk to Sales", href: "#", variant: "outline" }
112111
+ ],
112112
+ background: "gray"
112113
+ }
112024
112114
  },
112025
112115
  "hero-mentorship-video-split": {
112026
112116
  id: "hero-mentorship-video-split",
@@ -120320,9 +120410,11 @@ function normalizeBlock(block, source) {
120320
120410
  },
120321
120411
  examples: {
120322
120412
  exampleUsage: block.exampleUsage || null,
120323
- defaultData: null
120413
+ defaultData: block.defaultProps ? JSON.parse(JSON.stringify(block.defaultProps)) : null
120324
120414
  },
120325
- source: source ?? null
120415
+ source: source ?? null,
120416
+ importantUsageNotes: block.importantUsageNotes ?? null,
120417
+ usageRequirements: block.usageRequirements ? JSON.parse(JSON.stringify(block.usageRequirements)) : null
120326
120418
  };
120327
120419
  }
120328
120420
  function createBuilderContractBundle({
@@ -603,8 +603,8 @@ function StatsGrowthTimeline({
603
603
  }
604
604
  ),
605
605
  milestone.title && (typeof milestone.title === "string" ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-2 text-xl font-bold", children: milestone.title }) : milestone.title),
606
- milestone.description && (typeof milestone.description === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-4 text-muted-foreground", children: milestone.description }) : milestone.description),
607
- milestone.metric && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 rounded-lg border bg-background p-4 shadow-sm", children: [
606
+ milestone.description && (typeof milestone.description === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-4 opacity-70 text-balance", children: milestone.description }) : milestone.description),
607
+ milestone.metric && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 rounded-lg border bg-card text-card-foreground p-4 shadow-sm", children: [
608
608
  renderMilestoneIcon(milestone),
609
609
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
610
610
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-semibold", children: milestone.metric.value }),
@@ -665,8 +665,8 @@ function StatsGrowthTimeline({
665
665
  futureClassName
666
666
  ),
667
667
  children: [
668
- futureHeading && (typeof futureHeading === "string" ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-4 text-2xl font-bold", children: futureHeading }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4", children: futureHeading })),
669
- futureDescription && (typeof futureDescription === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mx-auto mb-8 max-w-full md:max-w-lg text-balance", children: futureDescription }) : futureDescription),
668
+ futureHeading && (typeof futureHeading === "string" ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-2xl font-bold", children: futureHeading }) : futureHeading),
669
+ futureDescription && (typeof futureDescription === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-full md:max-w-md text-balance", children: futureDescription }) : futureDescription),
670
670
  /* @__PURE__ */ jsxRuntime.jsx(
671
671
  BlockActions,
672
672
  {
@@ -711,12 +711,12 @@ function StatsGrowthTimeline({
711
711
  ),
712
712
  children: heading
713
713
  }
714
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mb-4", headingClassName), children: heading })),
714
+ ) : heading),
715
715
  description && (typeof description === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
716
716
  "p",
717
717
  {
718
718
  className: cn(
719
- "mx-auto max-w-3xl text-lg text-muted-foreground",
719
+ "max-w-full md:max-w-md text-base md:text-lg text-balance",
720
720
  descriptionClassName
721
721
  ),
722
722
  children: description
@@ -582,8 +582,8 @@ function StatsGrowthTimeline({
582
582
  }
583
583
  ),
584
584
  milestone.title && (typeof milestone.title === "string" ? /* @__PURE__ */ jsx("h3", { className: "mb-2 text-xl font-bold", children: milestone.title }) : milestone.title),
585
- milestone.description && (typeof milestone.description === "string" ? /* @__PURE__ */ jsx("p", { className: "mb-4 text-muted-foreground", children: milestone.description }) : milestone.description),
586
- milestone.metric && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 rounded-lg border bg-background p-4 shadow-sm", children: [
585
+ milestone.description && (typeof milestone.description === "string" ? /* @__PURE__ */ jsx("p", { className: "mb-4 opacity-70 text-balance", children: milestone.description }) : milestone.description),
586
+ milestone.metric && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 rounded-lg border bg-card text-card-foreground p-4 shadow-sm", children: [
587
587
  renderMilestoneIcon(milestone),
588
588
  /* @__PURE__ */ jsxs("div", { children: [
589
589
  /* @__PURE__ */ jsx("div", { className: "text-2xl font-semibold", children: milestone.metric.value }),
@@ -644,8 +644,8 @@ function StatsGrowthTimeline({
644
644
  futureClassName
645
645
  ),
646
646
  children: [
647
- futureHeading && (typeof futureHeading === "string" ? /* @__PURE__ */ jsx("h3", { className: "mb-4 text-2xl font-bold", children: futureHeading }) : /* @__PURE__ */ jsx("div", { className: "mb-4", children: futureHeading })),
648
- futureDescription && (typeof futureDescription === "string" ? /* @__PURE__ */ jsx("p", { className: "mx-auto mb-8 max-w-full md:max-w-lg text-balance", children: futureDescription }) : futureDescription),
647
+ futureHeading && (typeof futureHeading === "string" ? /* @__PURE__ */ jsx("h3", { className: "text-2xl font-bold", children: futureHeading }) : futureHeading),
648
+ futureDescription && (typeof futureDescription === "string" ? /* @__PURE__ */ jsx("p", { className: "max-w-full md:max-w-md text-balance", children: futureDescription }) : futureDescription),
649
649
  /* @__PURE__ */ jsx(
650
650
  BlockActions,
651
651
  {
@@ -690,12 +690,12 @@ function StatsGrowthTimeline({
690
690
  ),
691
691
  children: heading
692
692
  }
693
- ) : /* @__PURE__ */ jsx("div", { className: cn("mb-4", headingClassName), children: heading })),
693
+ ) : heading),
694
694
  description && (typeof description === "string" ? /* @__PURE__ */ jsx(
695
695
  "p",
696
696
  {
697
697
  className: cn(
698
- "mx-auto max-w-3xl text-lg text-muted-foreground",
698
+ "max-w-full md:max-w-md text-base md:text-lg text-balance",
699
699
  descriptionClassName
700
700
  ),
701
701
  children: description
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensite/ui",
3
- "version": "3.5.5",
3
+ "version": "3.5.7",
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",