@mandolop97/constructor-nexora 1.5.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * ════════════════════════════════════════════════════════════════════════════
3
- * NEXORA VISUAL BUILDER — OFFICIAL CONTRACT
3
+ * NEXORA VISUAL BUILDER — OFFICIAL CONTRACT v1.7.0
4
4
  * ════════════════════════════════════════════════════════════════════════════
5
5
  *
6
6
  * This file defines the **shared contract** between the Nexora Visual Builder
@@ -9,9 +9,27 @@
9
9
  * Both systems MUST use these exact types, names, and structures to ensure
10
10
  * full compatibility and seamless data flow.
11
11
  *
12
- * VERSION: 1.5.0
12
+ * VERSION: 1.7.0
13
+ *
14
+ * ── DATA OWNERSHIP POLICY ──
15
+ *
16
+ * ┌─────────────┬────────────────────────────┬───────────────────────────┐
17
+ * │ Layer │ Responsibility │ Prohibitions │
18
+ * ├─────────────┼────────────────────────────┼───────────────────────────┤
19
+ * │ Host/Template│ Fetch + adapt data. │ Cannot modify schema │
20
+ * │ (consumer) │ Build RenderContext. │ nodes directly. │
21
+ * │ │ Provide hostData. │ │
22
+ * ├─────────────┼────────────────────────────┼───────────────────────────┤
23
+ * │ Builder │ Schema CRUD. │ NO fetch to external APIs │
24
+ * │ (editor) │ Adapt hostData for preview. │ NO direct DB calls for │
25
+ * │ │ Validate before publish. │ business data. │
26
+ * ├─────────────┼────────────────────────────┼───────────────────────────┤
27
+ * │ Renderer │ Render nodes from schema + │ NO fetch. NO state │
28
+ * │ (PageRender)│ resolved context. Pure. │ mutation. Read-only. │
29
+ * └─────────────┴────────────────────────────┴───────────────────────────┘
13
30
  */
14
31
  import { NodeStyle, ThemeTokens, AnimationPreset, SchemaNode, Schema } from './schema';
32
+ import { PageType, PageMetadata } from './page-types';
15
33
  /** All built-in node types supported by the builder */
16
34
  export type BuiltInNodeType = 'Section' | 'Container' | 'Grid' | 'Stack' | 'Text' | 'Image' | 'Divider' | 'Badge' | 'Spacer' | 'Icon' | 'SocialIcons' | 'Button' | 'Card' | 'Input' | 'Accordion' | 'TabsBlock' | 'VideoEmbed' | 'FormBlock' | 'ProductCard' | 'ProductGrid' | 'CollectionGrid' | 'Navbar' | 'Footer' | 'AnnouncementBar' | 'HeroSection' | 'FeatureBar' | 'TestimonialCard' | 'NewsletterSection' | 'ImageBanner' | 'RichTextSection' | 'CTASection' | 'TestimonialSection' | 'FAQSection';
17
35
  /** Extensible node type — accepts built-in types plus any custom string */
@@ -229,25 +247,110 @@ export interface BoundSchemaNode extends SchemaNode {
229
247
  };
230
248
  }
231
249
  export type RenderMode = 'public' | 'preview' | 'edit';
250
+ /** Runtime context for the current page */
251
+ export interface PageContext {
252
+ /** Type of the current page */
253
+ pageType: PageType;
254
+ /** Current page slug */
255
+ slug: string;
256
+ /** URL parameters (e.g., product handle, collection handle) */
257
+ params?: Record<string, string>;
258
+ /** Query string parameters */
259
+ query?: Record<string, string>;
260
+ /** Render mode — replaces the old `isPreview` boolean */
261
+ mode: RenderMode;
262
+ /** The page metadata (SEO, OG, etc.) */
263
+ metadata?: PageMetadata;
264
+ }
265
+ /**
266
+ * RenderContext v1.7.0 — The single source of truth for all rendering data.
267
+ *
268
+ * Built by the Host/Template layer and consumed read-only by Builder and Renderer.
269
+ */
232
270
  export interface RenderContext {
271
+ /** Current render mode */
233
272
  mode: RenderMode;
234
- /** Data available for binding */
273
+ /** Page-level context (optional auto-built from mode if not provided) */
274
+ page?: PageContext;
275
+ /** All data available for binding resolution */
235
276
  data?: {
236
- products?: any[];
237
- collections?: any[];
238
- pages?: any[];
239
- settings?: Record<string, any>;
240
- custom?: Record<string, any>;
277
+ /** E-commerce product data */
278
+ products: any[];
279
+ /** Product collections / categories */
280
+ collections: any[];
281
+ /** CMS / content pages */
282
+ pages: any[];
283
+ /** Global site settings (store name, currency, language, etc.) */
284
+ settings: Record<string, any>;
285
+ /** Card template schema for hydration (used by ProductGrid) */
286
+ cardTemplate?: {
287
+ nodes: Record<string, SchemaNode>;
288
+ rootNodeId: string;
289
+ themeTokens?: ThemeTokens;
290
+ };
291
+ /** Host-defined custom data sources */
292
+ custom: Record<string, any>;
241
293
  };
242
- /** Current item when rendering inside a collection */
294
+ /** Iteration context set by collection renderers (e.g., ProductGrid) */
243
295
  currentItem?: any;
244
- /** Item index when rendering inside a collection */
296
+ /** Current item index in iteration */
245
297
  currentIndex?: number;
246
- /** Theme tokens */
298
+ /** Theme tokens snapshot */
247
299
  theme?: ThemeTokens;
248
- /** Resolve asset URLs */
300
+ /** Resolve asset paths to full URLs */
249
301
  resolveAssetUrl?: (path: string) => string;
250
302
  }
303
+ /**
304
+ * Slot behavior determines what can be done with a slot's content:
305
+ * - locked: Render as-is. Inspector disabled. Cannot delete/move.
306
+ * - editable: Full inspector access. Can reorder children.
307
+ * - dynamic: Data-driven. Bindings resolved at render. Children generated from data.
308
+ */
309
+ export type SlotBehavior = 'locked' | 'editable' | 'dynamic';
310
+ /**
311
+ * Slot assignment for template integration.
312
+ *
313
+ * Fallback rules:
314
+ * - If slot has no children AND fallbackNodeId is set → render fallback node.
315
+ * - If slot has no children AND no fallback → render empty placeholder (edit mode only).
316
+ */
317
+ export interface SlotAssignment {
318
+ /** Slot identifier (e.g. 'header', 'footer', 'main', 'sidebar') */
319
+ __slot: string;
320
+ /** Slot behavior */
321
+ behavior: SlotBehavior;
322
+ /** Fallback node ID if slot is empty */
323
+ fallbackNodeId?: string;
324
+ }
325
+ export type PublishStage = 'draft' | 'validated' | 'preview' | 'published';
326
+ /** Options for the validation step */
327
+ export interface ValidatorOptions {
328
+ /** Treat warnings as errors */
329
+ strict?: boolean;
330
+ /** Page type for context-aware validation */
331
+ pageType?: PageType;
332
+ }
333
+ /**
334
+ * Publication pipeline contract.
335
+ *
336
+ * Rules:
337
+ * - `validate().errors.length > 0` blocks publish.
338
+ * - Warnings are displayed but do NOT block.
339
+ * - Preview is optional.
340
+ */
341
+ export interface PublishPipeline {
342
+ /** 1. Save work-in-progress */
343
+ saveDraft: (schema: Schema) => Promise<void>;
344
+ /** 2. Run validation — must pass with 0 errors to proceed */
345
+ validate: (schema: Schema, opts?: ValidatorOptions) => {
346
+ errors: string[];
347
+ warnings: string[];
348
+ };
349
+ /** 3. Generate preview (optional) — returns preview URL */
350
+ preview?: (schema: Schema) => Promise<string>;
351
+ /** 4. Publish to production */
352
+ publish: (payload: any) => Promise<void>;
353
+ }
251
354
  export type TemplateType = 'page' | 'header' | 'footer' | 'component' | 'single';
252
355
  export interface PageDefinition {
253
356
  slug: string;
@@ -261,7 +364,13 @@ export interface PageDefinition {
261
364
  width: number;
262
365
  height: number;
263
366
  };
367
+ /**
368
+ * Host-provided data for edit/preview binding resolution.
369
+ * @deprecated Use `hostData` instead. This alias is kept for backward compatibility.
370
+ */
264
371
  mockData?: Record<string, any>;
372
+ /** Host-provided data for edit/preview binding resolution */
373
+ hostData?: Record<string, any>;
265
374
  }
266
375
  export interface InspectorFieldDef {
267
376
  key: string;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * ════════════════════════════════════════════════════════════════════════════
3
+ * NEXORA — PAGE TYPES, METADATA, VISIBILITY & CONSTRAINTS
4
+ * ════════════════════════════════════════════════════════════════════════════
5
+ */
6
+ import { NodeType } from './schema';
7
+ /** Supported page types for the e-commerce builder */
8
+ export type PageType = 'home' | 'collection' | 'product' | 'cart' | 'checkout' | 'static' | 'landing' | 'blog' | 'blog-post' | 'account' | 'search' | 'custom';
9
+ /** Mapping of page types to human-readable labels */
10
+ export declare const PAGE_TYPE_LABELS: Record<PageType, string>;
11
+ export interface PageMetadata {
12
+ /** Page title for <title> tag and og:title */
13
+ title?: string;
14
+ /** Meta description for SEO and og:description */
15
+ description?: string;
16
+ /** Open Graph image URL */
17
+ ogImage?: string;
18
+ /** Canonical URL */
19
+ canonical?: string;
20
+ /** Additional meta tags */
21
+ meta?: Array<{
22
+ name: string;
23
+ content: string;
24
+ }>;
25
+ /** Whether search engines should index this page */
26
+ noIndex?: boolean;
27
+ /** JSON-LD structured data */
28
+ jsonLd?: Record<string, any>;
29
+ }
30
+ /**
31
+ * @deprecated Import PageContext from '@/types/contract' instead.
32
+ * This re-export is kept for backward compatibility.
33
+ */
34
+ export type { PageContext } from './contract';
35
+ export type DeviceVisibility = 'all' | 'desktop' | 'tablet' | 'mobile' | 'desktop+tablet' | 'tablet+mobile';
36
+ export interface VisibilityRule {
37
+ /** Show/hide on specific devices */
38
+ device?: DeviceVisibility;
39
+ /** Show only on specific page types */
40
+ pageTypes?: PageType[];
41
+ /** Show only when user is authenticated */
42
+ requireAuth?: boolean;
43
+ /** Custom condition expression (future) */
44
+ condition?: string;
45
+ /** Schedule visibility */
46
+ schedule?: {
47
+ startDate?: string;
48
+ endDate?: string;
49
+ };
50
+ }
51
+ /** Configuration for locking specific props on a node */
52
+ export interface LockedPropsConfig {
53
+ /** List of prop keys that are locked (cannot be edited) */
54
+ lockedProps?: string[];
55
+ /** List of style keys that are locked */
56
+ lockedStyles?: string[];
57
+ /** Whether the entire node is locked from deletion */
58
+ preventDelete?: boolean;
59
+ /** Whether the node can be moved/reordered */
60
+ preventMove?: boolean;
61
+ }
62
+ /** Default block-to-page-type compatibility map */
63
+ export declare const BLOCK_PAGE_TYPE_DEFAULTS: Partial<Record<NodeType, PageType[]>>;
64
+ /** Check if a block type is compatible with a page type */
65
+ export declare function isBlockCompatibleWithPage(blockType: NodeType, pageType: PageType, allowedPageTypes?: PageType[]): boolean;
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import type { SlotAssignment } from './contract';
2
3
  export type BuiltInNodeType = 'Section' | 'Container' | 'Grid' | 'Stack' | 'Text' | 'Image' | 'Divider' | 'Badge' | 'Button' | 'Card' | 'Input' | 'ProductCard' | 'ProductGrid' | 'CollectionGrid' | 'Navbar' | 'Footer' | 'AnnouncementBar' | 'FeatureBar' | 'TestimonialCard' | 'NewsletterSection' | 'HeroSection' | 'ImageBanner' | 'RichTextSection' | 'CTASection' | 'TestimonialSection' | 'FAQSection' | 'Accordion' | 'TabsBlock' | 'VideoEmbed' | 'Spacer' | 'Icon' | 'SocialIcons' | 'FormBlock';
3
4
  /** Extensible node type — accepts all built-in types plus any custom string. */
4
5
  export type NodeType = BuiltInNodeType | (string & {});
@@ -180,6 +181,8 @@ export interface SchemaNode {
180
181
  customCSS?: string;
181
182
  /** IDs of global styles applied to this node */
182
183
  appliedGlobalStyles?: string[];
184
+ /** Slot assignment for template integration */
185
+ slot?: SlotAssignment;
183
186
  }
184
187
  export interface ThemeTokens {
185
188
  colors: {
@@ -244,7 +247,10 @@ export interface PageDefinition {
244
247
  width: number;
245
248
  height: number;
246
249
  };
250
+ /** @deprecated Use hostData */
247
251
  mockData?: Record<string, any>;
252
+ /** Host-provided data for edit/preview binding resolution */
253
+ hostData?: Record<string, any>;
248
254
  }
249
255
  export type RenderMode = 'public' | 'preview' | 'edit';
250
256
  export type TemplateType = 'page' | 'header' | 'footer' | 'component' | 'single';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mandolop97/constructor-nexora",
3
3
  "private": false,
4
- "version": "1.5.0",
4
+ "version": "1.7.1",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -18,7 +18,9 @@
18
18
  "react-dom": "^18.0.0"
19
19
  },
20
20
  "files": [
21
- "dist"
21
+ "dist",
22
+ "NEXORA.md",
23
+ "CHANGELOG.md"
22
24
  ],
23
25
  "scripts": {
24
26
  "dev": "vite",