@shoppexio/builder-runtime 0.1.1 → 0.1.2

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.
Files changed (44) hide show
  1. package/dist/index.d.ts +4 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +4 -0
  4. package/dist/layout.d.ts +3 -8
  5. package/dist/layout.d.ts.map +1 -1
  6. package/dist/layout.js +2 -10
  7. package/dist/preview-fixtures.d.ts +16 -0
  8. package/dist/preview-fixtures.d.ts.map +1 -0
  9. package/dist/preview-fixtures.js +40 -0
  10. package/dist/product-page.d.ts +13 -0
  11. package/dist/product-page.d.ts.map +1 -0
  12. package/dist/product-page.js +18 -0
  13. package/dist/react.d.ts +31 -2
  14. package/dist/react.d.ts.map +1 -1
  15. package/dist/react.js +122 -42
  16. package/dist/search-bar-settings.d.ts +33 -0
  17. package/dist/search-bar-settings.d.ts.map +1 -0
  18. package/dist/search-bar-settings.js +99 -0
  19. package/dist/standard-product-blocks.d.ts +48 -0
  20. package/dist/standard-product-blocks.d.ts.map +1 -0
  21. package/dist/standard-product-blocks.js +45 -0
  22. package/dist/standard-product-page.d.ts +69 -0
  23. package/dist/standard-product-page.d.ts.map +1 -0
  24. package/dist/standard-product-page.js +89 -0
  25. package/dist/storefront-google-fonts.d.ts +2 -0
  26. package/dist/storefront-google-fonts.d.ts.map +1 -0
  27. package/dist/storefront-google-fonts.js +28 -0
  28. package/package.json +3 -3
  29. package/src/builder-runtime.test.ts +33 -0
  30. package/src/index.ts +4 -0
  31. package/src/layout.ts +11 -21
  32. package/src/preview-fixtures.ts +56 -0
  33. package/src/product-page.test.ts +37 -0
  34. package/src/product-page.ts +32 -0
  35. package/src/react-runtime.test.tsx +42 -0
  36. package/src/react.tsx +214 -45
  37. package/src/search-bar-settings.test.ts +72 -0
  38. package/src/search-bar-settings.ts +176 -0
  39. package/src/standard-product-blocks.test.tsx +93 -0
  40. package/src/standard-product-blocks.tsx +121 -0
  41. package/src/standard-product-page.test.ts +171 -0
  42. package/src/standard-product-page.ts +169 -0
  43. package/src/storefront-google-fonts.test.ts +31 -0
  44. package/src/storefront-google-fonts.ts +43 -0
package/dist/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
+ export * from './preview-fixtures.js';
2
+ export * from './product-page.js';
3
+ export * from './standard-product-page.js';
1
4
  export * from './attributes.js';
2
5
  export * from './content.js';
3
6
  export * from './css-vars.js';
4
7
  export * from './layout.js';
5
8
  export * from './react.js';
9
+ export * from './storefront-google-fonts.js';
6
10
  export * from './style-slots.js';
7
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
+ export * from './preview-fixtures.js';
2
+ export * from './product-page.js';
3
+ export * from './standard-product-page.js';
1
4
  export * from './attributes.js';
2
5
  export * from './content.js';
3
6
  export * from './css-vars.js';
4
7
  export * from './layout.js';
5
8
  export * from './react.js';
9
+ export * from './storefront-google-fonts.js';
6
10
  export * from './style-slots.js';
package/dist/layout.d.ts CHANGED
@@ -1,18 +1,13 @@
1
- import type { BlockInstance, BuilderSettings, PageLayout, ThemeManifest } from '@shoppex/builder-contracts';
1
+ import { getThemePageBlockOrderFromManifest as resolveThemePageBlockOrder, type BlockInstance, type BuilderSettings, type PageLayout, type ThemeManifest, type ThemePageBlockOrderPage } from '@shoppex/builder-contracts';
2
2
  export type ThemePageBlockOrderManifest = {
3
- pages?: Record<string, {
4
- allowedBlocks?: string[];
5
- defaultBlocks?: Array<{
6
- type?: string;
7
- }>;
8
- }>;
3
+ pages?: Record<string, ThemePageBlockOrderPage>;
9
4
  };
5
+ export { resolveThemePageBlockOrder as getThemePageBlockOrderFromManifest };
10
6
  export declare function getPageLayout(settings: BuilderSettings, pageId: string): PageLayout;
11
7
  export declare function getPageBlocks(settings: BuilderSettings, pageId: string): BlockInstance[];
12
8
  export declare function getVisiblePageBlocks(settings: BuilderSettings, pageId: string): BlockInstance[];
13
9
  export declare function getBlockById(settings: BuilderSettings, pageId: string, blockId: string): BlockInstance | null;
14
10
  export declare function getAllowedBlockTypes(manifest: ThemeManifest, pageId: string): string[];
15
- export declare function getThemePageBlockOrderFromManifest(manifest: ThemePageBlockOrderManifest, pageId: string): string[];
16
11
  export declare function canAddBlock(settings: BuilderSettings, manifest: ThemeManifest, pageId: string, blockType: string): boolean;
17
12
  export declare function resolveBlockSettings(block: BlockInstance, manifest: ThemeManifest): Record<string, unknown>;
18
13
  //# sourceMappingURL=layout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE5G,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QACrB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,aAAa,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC1C,CAAC,CAAC;CACJ,CAAC;AAEF,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAEnF;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAExF;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAE/F;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAE7G;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAEtF;AAED,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,2BAA2B,EACrC,MAAM,EAAE,MAAM,GACb,MAAM,EAAE,CAWV;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAc1H;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgB3G"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kCAAkC,IAAI,0BAA0B,EAChE,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAC7B,MAAM,4BAA4B,CAAC;AAEpC,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;CACjD,CAAC;AAEF,OAAO,EAAE,0BAA0B,IAAI,kCAAkC,EAAE,CAAC;AAE5E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAEnF;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAExF;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAE/F;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAE7G;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAEtF;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAc1H;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgB3G"}
package/dist/layout.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { getThemePageBlockOrderFromManifest as resolveThemePageBlockOrder, } from '@shoppex/builder-contracts';
2
+ export { resolveThemePageBlockOrder as getThemePageBlockOrderFromManifest };
1
3
  export function getPageLayout(settings, pageId) {
2
4
  return settings.theme.layout[pageId] ?? { blocks: [] };
3
5
  }
@@ -13,16 +15,6 @@ export function getBlockById(settings, pageId, blockId) {
13
15
  export function getAllowedBlockTypes(manifest, pageId) {
14
16
  return manifest.pages[pageId]?.allowedBlocks ?? [];
15
17
  }
16
- export function getThemePageBlockOrderFromManifest(manifest, pageId) {
17
- const page = manifest.pages?.[pageId];
18
- if (!page) {
19
- return [];
20
- }
21
- const defaultBlockTypes = (page.defaultBlocks ?? [])
22
- .map((block) => block.type)
23
- .filter((blockType) => typeof blockType === 'string' && blockType.length > 0);
24
- return defaultBlockTypes.length > 0 ? defaultBlockTypes : page.allowedBlocks ?? [];
25
- }
26
18
  export function canAddBlock(settings, manifest, pageId, blockType) {
27
19
  const page = manifest.pages[pageId];
28
20
  const blockDefinition = manifest.blocks[blockType];
@@ -0,0 +1,16 @@
1
+ export type BuilderPreviewReview = {
2
+ id: string;
3
+ author: string | null;
4
+ comment: string | null;
5
+ rating: number | null;
6
+ created_at: string;
7
+ is_automated?: boolean;
8
+ };
9
+ export type BuilderPreviewFaqItem = {
10
+ question: string;
11
+ answer: string;
12
+ };
13
+ export declare const BUILDER_PREVIEW_REVIEWS: BuilderPreviewReview[];
14
+ export declare function getBuilderPreviewReviewFixtures<T = BuilderPreviewReview>(): T[];
15
+ export declare const BUILDER_PREVIEW_FAQ_ITEMS: BuilderPreviewFaqItem[];
16
+ //# sourceMappingURL=preview-fixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview-fixtures.d.ts","sourceRoot":"","sources":["../src/preview-fixtures.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,oBAAoB,EAsBzD,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,CAAC,GAAG,oBAAoB,KAAK,CAAC,EAAE,CAE/E;AAED,eAAO,MAAM,yBAAyB,EAAE,qBAAqB,EAa5D,CAAC"}
@@ -0,0 +1,40 @@
1
+ export const BUILDER_PREVIEW_REVIEWS = [
2
+ {
3
+ id: 'preview-review-1',
4
+ author: 'Alex M.',
5
+ comment: 'Instant delivery and clear instructions. Would buy again.',
6
+ rating: 5,
7
+ created_at: '2026-04-12T10:00:00.000Z',
8
+ },
9
+ {
10
+ id: 'preview-review-2',
11
+ author: 'Jamie R.',
12
+ comment: 'Support answered quickly when I had a setup question.',
13
+ rating: 5,
14
+ created_at: '2026-04-03T14:30:00.000Z',
15
+ },
16
+ {
17
+ id: 'preview-review-3',
18
+ author: 'Taylor S.',
19
+ comment: 'Smooth checkout experience and exactly what was advertised.',
20
+ rating: 4,
21
+ created_at: '2026-03-22T09:15:00.000Z',
22
+ },
23
+ ];
24
+ export function getBuilderPreviewReviewFixtures() {
25
+ return BUILDER_PREVIEW_REVIEWS;
26
+ }
27
+ export const BUILDER_PREVIEW_FAQ_ITEMS = [
28
+ {
29
+ question: 'How fast is delivery?',
30
+ answer: 'Most digital products are delivered instantly after payment confirmation.',
31
+ },
32
+ {
33
+ question: 'Which payment methods do you accept?',
34
+ answer: 'Available payment methods depend on your shop configuration and region.',
35
+ },
36
+ {
37
+ question: 'How do I get support?',
38
+ answer: 'Use the contact page or your customer portal for order-related help.',
39
+ },
40
+ ];
@@ -0,0 +1,13 @@
1
+ import type { BlockInstance } from '@shoppex/builder-contracts';
2
+ export declare function getBuilderBlockSettingText(block: Pick<BlockInstance, 'settings'>, key: string): string | null;
3
+ export declare function getLayoutPageBlockAttributes(pageId: string, block: Pick<BlockInstance, 'id' | 'type'>): {
4
+ 'data-page-id': string;
5
+ };
6
+ export declare function getProductPageBlockAttributes(block: Pick<BlockInstance, 'id' | 'type'>): {
7
+ 'data-page-id': string;
8
+ };
9
+ /** @deprecated Use getBuilderBlockSettingText */
10
+ export declare const getProductBlockText: typeof getBuilderBlockSettingText;
11
+ /** @deprecated Use getProductPageBlockAttributes */
12
+ export declare const getBuilderProductBlockAttributes: typeof getProductPageBlockAttributes;
13
+ //# sourceMappingURL=product-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-page.d.ts","sourceRoot":"","sources":["../src/product-page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGhE,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,EACtC,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,IAAI,CAGf;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,MAAM,CAAC;;EAM1C;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,MAAM,CAAC;;EAG1C;AAED,iDAAiD;AACjD,eAAO,MAAM,mBAAmB,mCAA6B,CAAC;AAE9D,oDAAoD;AACpD,eAAO,MAAM,gCAAgC,sCAAgC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { builderBlock } from './attributes.js';
2
+ export function getBuilderBlockSettingText(block, key) {
3
+ const value = block.settings[key];
4
+ return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
5
+ }
6
+ export function getLayoutPageBlockAttributes(pageId, block) {
7
+ return {
8
+ 'data-page-id': pageId,
9
+ ...builderBlock(block.id, block.type),
10
+ };
11
+ }
12
+ export function getProductPageBlockAttributes(block) {
13
+ return getLayoutPageBlockAttributes('product', block);
14
+ }
15
+ /** @deprecated Use getBuilderBlockSettingText */
16
+ export const getProductBlockText = getBuilderBlockSettingText;
17
+ /** @deprecated Use getProductPageBlockAttributes */
18
+ export const getBuilderProductBlockAttributes = getProductPageBlockAttributes;
package/dist/react.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { BlockInstance, BuilderSettings, Breakpoint, StyleSlotId } from '@shoppex/builder-contracts';
2
- import { type ComponentType, type ElementType, type ReactNode } from 'react';
2
+ import { type ComponentPropsWithoutRef, type ComponentType, type ElementType, type ReactNode } from 'react';
3
+ import { type BuilderAttributeMap } from './attributes.js';
3
4
  type BuilderRuntimeContextValue = {
4
5
  settings: BuilderSettings;
5
6
  };
@@ -75,11 +76,39 @@ export declare function useVisibleBuilderPageBlocks(pageId: string): {
75
76
  style_overrides?: Partial<Record<StyleSlotId, import("@shoppex/builder-contracts").StyleSlotValue>> | undefined;
76
77
  }[];
77
78
  export declare function useThemePageBlocks(pageId: string, defaultOrder: string[]): BlockInstance[];
79
+ export declare function useThemePageBlockAttributes(pageId: string, defaultOrder: string[]): BuilderAttributeMap;
80
+ type DedicatedBuilderPageProps<T extends ElementType> = {
81
+ pageId: string;
82
+ defaultBlockOrder: string[];
83
+ as?: T;
84
+ children: ReactNode;
85
+ } & Omit<ComponentPropsWithoutRef<T>, 'as' | 'children'>;
86
+ export declare function DedicatedBuilderPage<T extends ElementType = 'section'>({ pageId, defaultBlockOrder, as, children, ...rest }: DedicatedBuilderPageProps<T>): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
87
+ export declare function useBuilderPreviewReviews<T>(input: {
88
+ reviews: T[];
89
+ isLoading: boolean;
90
+ error: unknown;
91
+ fixtures?: T[];
92
+ }): {
93
+ reviews: T[];
94
+ isLoading: boolean;
95
+ error: unknown;
96
+ isUsingFixtures: boolean;
97
+ };
78
98
  export declare function useBuilderStyleSlot(slotId: StyleSlotId, input?: {
79
99
  breakpoint?: Breakpoint;
80
100
  fallback?: unknown;
81
101
  }): unknown;
82
102
  export declare function useBuilderCss(selector?: string): string;
103
+ export declare function useSearchBarSettings(input: {
104
+ variant: 'hero' | 'navigation';
105
+ headerSettings?: Record<string, unknown>;
106
+ }): import("./search-bar-settings.js").ResolvedSearchBarSettings;
107
+ export { buildSearchShellStyle, getNavigationHeaderSettings, resolveSearchBarSettings, } from './search-bar-settings.js';
108
+ export declare function isBuilderPreviewRuntime(): boolean;
83
109
  export declare function resolvePreviewReloadTarget(location: Pick<Location, 'search' | 'hash'>, sessionPath: unknown): string | null;
84
- export {};
110
+ export { getBuilderBlockSettingText, getBuilderProductBlockAttributes, getLayoutPageBlockAttributes, getProductBlockText, getProductPageBlockAttributes, } from './product-page.js';
111
+ export { createStandardProductBlockRegistry, splitStandardProductPageBlocks, buildStandardProductInfoTabs, resolveStandardBuyBoxLabels, resolveStandardDetailsLabels, resolveStandardRelatedProductsTitle, resolveScopedBlockSettingText, STANDARD_PRODUCT_BLOCK_TYPES, STANDARD_PRODUCT_PRIMARY_BLOCK_TYPES, STANDARD_PRODUCT_SECONDARY_BLOCK_TYPES, } from './standard-product-blocks.js';
112
+ export type { StandardBuyBoxLabels, StandardDetailsLabels, StandardProductBlockRegistryData, StandardProductBlockRegistryOptions, StandardProductBlockRegistrySlots, StandardProductBlockType, StandardProductSettingScope, StandardProductTabSpec, } from './standard-product-blocks.js';
113
+ export { getBuilderPreviewReviewFixtures } from './preview-fixtures.js';
85
114
  //# sourceMappingURL=react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"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"}
package/dist/react.js CHANGED
@@ -1,9 +1,12 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { BuilderSettingsSchema, PreviewMessageSchema, createEmptyBuilderSettings, migrateLegacyBuilderSettings, } from '@shoppex/builder-contracts';
2
+ import { BuilderSettingsSchema, PreviewMessageSchema, createEmptyBuilderSettings, isTrustedPreviewParentOrigin, migrateLegacyBuilderSettings, normalizeDedicatedPageId, } from '@shoppex/builder-contracts';
3
3
  import { createElement, createContext, useContext, useEffect, useMemo, useRef, useState, } from 'react';
4
4
  import { getBlockSettingValue, getBuilderContentList, getBuilderContentRecord, getBuilderContentString, getBuilderContentValue, } from './content.js';
5
+ import { BUILDER_PREVIEW_REVIEWS } from './preview-fixtures.js';
5
6
  import { createBuilderCss } from './css-vars.js';
7
+ import { builderBlock } from './attributes.js';
6
8
  import { getPageBlocks, getPageLayout, getVisiblePageBlocks } from './layout.js';
9
+ import { getNavigationHeaderSettings, resolveSearchBarSettings, } from './search-bar-settings.js';
7
10
  import { resolveStyleSlotValue } from './style-slots.js';
8
11
  const BUILDER_SETTINGS_WINDOW_KEY = '__SHOPPEX_BUILDER_SETTINGS__';
9
12
  const BUILDER_STATE_EVENT_NAME = 'shoppex:builder-state';
@@ -155,6 +158,7 @@ export function BuilderRuntimePreviewProvider({ initialSettings, children, }) {
155
158
  message: normalized.message,
156
159
  ...(normalized.stack ? { stack: normalized.stack } : {}),
157
160
  source,
161
+ phase: 'runtime',
158
162
  diagnostics: {
159
163
  name: normalized.name,
160
164
  href: window.location.href,
@@ -295,13 +299,48 @@ export function useVisibleBuilderPageBlocks(pageId) {
295
299
  }
296
300
  export function useThemePageBlocks(pageId, defaultOrder) {
297
301
  const { settings } = useBuilderRuntime();
302
+ const canonicalPageId = normalizeDedicatedPageId(pageId);
298
303
  return useMemo(() => {
299
- const page = settings.theme.layout[pageId];
304
+ const page = settings.theme.layout[canonicalPageId];
300
305
  if (page) {
301
306
  return page.blocks.filter((block) => block.visible);
302
307
  }
303
308
  return defaultOrder.map((type) => ({ id: type, type, visible: true, settings: {} }));
304
- }, [defaultOrder, pageId, settings.theme.layout]);
309
+ }, [canonicalPageId, defaultOrder, settings.theme.layout]);
310
+ }
311
+ export function useThemePageBlockAttributes(pageId, defaultOrder) {
312
+ const canonicalPageId = normalizeDedicatedPageId(pageId);
313
+ const blocks = useThemePageBlocks(pageId, defaultOrder);
314
+ const block = blocks[0];
315
+ return useMemo(() => ({
316
+ 'data-page-id': canonicalPageId,
317
+ ...(block ? builderBlock(block.id, block.type) : {}),
318
+ }), [block, canonicalPageId]);
319
+ }
320
+ export function DedicatedBuilderPage({ pageId, defaultBlockOrder, as, children, ...rest }) {
321
+ const attrs = useThemePageBlockAttributes(pageId, defaultBlockOrder);
322
+ const Component = (as ?? 'section');
323
+ return createElement(Component, { ...attrs, ...rest }, children);
324
+ }
325
+ export function useBuilderPreviewReviews(input) {
326
+ const fixtures = input.fixtures ?? BUILDER_PREVIEW_REVIEWS;
327
+ const shouldUseFixtures = isBuilderPreviewRuntime() && Boolean(input.error);
328
+ return useMemo(() => {
329
+ if (!shouldUseFixtures) {
330
+ return {
331
+ reviews: input.reviews,
332
+ isLoading: input.isLoading,
333
+ error: input.error,
334
+ isUsingFixtures: false,
335
+ };
336
+ }
337
+ return {
338
+ reviews: fixtures,
339
+ isLoading: false,
340
+ error: null,
341
+ isUsingFixtures: true,
342
+ };
343
+ }, [fixtures, input.error, input.isLoading, input.reviews, shouldUseFixtures]);
305
344
  }
306
345
  export function useBuilderStyleSlot(slotId, input = {}) {
307
346
  return resolveStyleSlotValue(useBuilderRuntime().settings, slotId, input);
@@ -333,7 +372,42 @@ function getNestedBuilderSetting(record, path) {
333
372
  }
334
373
  return current;
335
374
  }
336
- function isBuilderPreviewRuntime() {
375
+ export function useSearchBarSettings(input) {
376
+ const runtime = useBuilderRuntime();
377
+ const headerSettings = useMemo(() => input.headerSettings ?? getNavigationHeaderSettings(runtime.settings), [input.headerSettings, runtime.settings]);
378
+ const heroPlaceholder = useBuilderContentValue('hero.search.placeholder');
379
+ const heroBackground = useBuilderContentValue('hero.search.background');
380
+ const heroBorderColor = useBuilderContentValue('hero.search.borderColor');
381
+ const heroBorderRadius = useBuilderContentValue('hero.search.borderRadius');
382
+ const heroMaxWidth = useBuilderContentValue('hero.search.maxWidth');
383
+ const heroShowShortcut = useBuilderContentValue('hero.search.showShortcut');
384
+ const heroShow = useBuilderContentValue('hero.search.show');
385
+ return useMemo(() => resolveSearchBarSettings({
386
+ variant: input.variant,
387
+ headerSettings,
388
+ heroValues: {
389
+ 'hero.search.placeholder': heroPlaceholder,
390
+ 'hero.search.background': heroBackground,
391
+ 'hero.search.borderColor': heroBorderColor,
392
+ 'hero.search.borderRadius': heroBorderRadius,
393
+ 'hero.search.maxWidth': heroMaxWidth,
394
+ 'hero.search.showShortcut': heroShowShortcut,
395
+ 'hero.search.show': heroShow,
396
+ },
397
+ }), [
398
+ headerSettings,
399
+ heroBackground,
400
+ heroBorderColor,
401
+ heroBorderRadius,
402
+ heroMaxWidth,
403
+ heroPlaceholder,
404
+ heroShow,
405
+ heroShowShortcut,
406
+ input.variant,
407
+ ]);
408
+ }
409
+ export { buildSearchShellStyle, getNavigationHeaderSettings, resolveSearchBarSettings, } from './search-bar-settings.js';
410
+ export function isBuilderPreviewRuntime() {
337
411
  if (typeof window === 'undefined') {
338
412
  return false;
339
413
  }
@@ -423,7 +497,7 @@ function isTrustedBuilderPreviewEmbed(location, parentOrigin) {
423
497
  return false;
424
498
  if (!hasBuilderPreviewMode(location))
425
499
  return false;
426
- return isTrustedBuilderPreviewParentOrigin(parentOrigin);
500
+ return isTrustedPreviewParentOrigin(parentOrigin);
427
501
  }
428
502
  function hasBuilderPreviewMode(location) {
429
503
  const searchParams = new URLSearchParams(location.search);
@@ -431,23 +505,6 @@ function hasBuilderPreviewMode(location) {
431
505
  || searchParams.get('shoppex-preview-mode') === 'builder'
432
506
  || searchParams.get('shoppex-preview') === 'builder');
433
507
  }
434
- function isTrustedBuilderPreviewParentOrigin(origin) {
435
- try {
436
- const parsed = new URL(origin);
437
- const hostname = parsed.hostname.toLowerCase();
438
- return (hostname === 'dashboard.shoppex.io'
439
- || hostname === 'dashboard.shoppex.test'
440
- || hostname === 'localhost'
441
- || hostname === '127.0.0.1'
442
- || hostname === '::1'
443
- || hostname.endsWith('.localhost')
444
- || hostname.endsWith('.vercel.app')
445
- || hostname.endsWith('.vercel.run'));
446
- }
447
- catch {
448
- return false;
449
- }
450
- }
451
508
  function selectBuilderElement(blockId) {
452
509
  document
453
510
  .querySelectorAll(BUILDER_SELECTED_SELECTOR)
@@ -458,7 +515,9 @@ function selectBuilderElement(blockId) {
458
515
  if (!target)
459
516
  return;
460
517
  target.setAttribute('data-builder-selected', 'true');
461
- target.scrollIntoView({ behavior: 'smooth', block: 'center' });
518
+ const pageId = target.getAttribute('data-page-id');
519
+ const scrollBlock = pageId === 'footer' ? 'end' : pageId === 'navigation' ? 'start' : 'nearest';
520
+ target.scrollIntoView({ behavior: 'smooth', block: scrollBlock });
462
521
  }
463
522
  function createBuilderSelection(blockElement, target) {
464
523
  const contentElement = target.closest(BUILDER_CONTENT_SELECTOR);
@@ -641,7 +700,8 @@ function installBuilderPreviewHoverInspector() {
641
700
  window.removeEventListener('mouseout', handleMouseOut, true);
642
701
  };
643
702
  }
644
- const INSERTER_HOVER_BAND_PX = 16;
703
+ const INSERTER_HOVER_BAND_PX = 28;
704
+ const INSERTER_CLEAR_DELAY_MS = 150;
645
705
  /**
646
706
  * Direct-manipulation bridge: tracks the bounding rect of the selected
647
707
  * block (for the floating toolbar), the inter-block gap currently
@@ -731,26 +791,43 @@ function installBuilderDirectManipulation(postMessage, getRevision) {
731
791
  // a tracked block stack. We don't try to be clever about which gap;
732
792
  // every direct ancestor with a list of `[data-builder-block]` children
733
793
  // contributes one gap per pair.
794
+ let inserterClearTimer = null;
734
795
  const postInserter = (index, rect) => {
735
- const key = index === null || !rect
736
- ? '__none__'
737
- : `${index}|${rect.top}|${rect.left}|${rect.width}|${rect.height}`;
738
- if (key === lastInserterKey)
796
+ const emitInserter = () => {
797
+ const key = index === null || !rect
798
+ ? '__none__'
799
+ : `${index}|${rect.top}|${rect.left}|${rect.width}|${rect.height}`;
800
+ if (key === lastInserterKey)
801
+ return;
802
+ lastInserterKey = key;
803
+ postMessage({
804
+ type: 'INSERTER_HOVER',
805
+ revision: getRevision(),
806
+ index,
807
+ rect: rect === null
808
+ ? null
809
+ : {
810
+ top: rect.top,
811
+ left: rect.left,
812
+ width: rect.width,
813
+ height: rect.height,
814
+ },
815
+ });
816
+ };
817
+ if (index !== null && rect !== null) {
818
+ if (inserterClearTimer !== null) {
819
+ window.clearTimeout(inserterClearTimer);
820
+ inserterClearTimer = null;
821
+ }
822
+ emitInserter();
739
823
  return;
740
- lastInserterKey = key;
741
- postMessage({
742
- type: 'INSERTER_HOVER',
743
- revision: getRevision(),
744
- index,
745
- rect: rect === null
746
- ? null
747
- : {
748
- top: rect.top,
749
- left: rect.left,
750
- width: rect.width,
751
- height: rect.height,
752
- },
753
- });
824
+ }
825
+ if (inserterClearTimer !== null)
826
+ return;
827
+ inserterClearTimer = window.setTimeout(() => {
828
+ inserterClearTimer = null;
829
+ emitInserter();
830
+ }, INSERTER_CLEAR_DELAY_MS);
754
831
  };
755
832
  const handleMouseMove = (event) => {
756
833
  const blocks = Array.from(document.querySelectorAll(BUILDER_BLOCK_SELECTOR)).filter((el) => {
@@ -885,3 +962,6 @@ function installBuilderDirectManipulation(postMessage, getRevision) {
885
962
  window.removeEventListener('mousedown', handleMouseDown, true);
886
963
  };
887
964
  }
965
+ export { getBuilderBlockSettingText, getBuilderProductBlockAttributes, getLayoutPageBlockAttributes, getProductBlockText, getProductPageBlockAttributes, } from './product-page.js';
966
+ export { createStandardProductBlockRegistry, splitStandardProductPageBlocks, buildStandardProductInfoTabs, resolveStandardBuyBoxLabels, resolveStandardDetailsLabels, resolveStandardRelatedProductsTitle, resolveScopedBlockSettingText, STANDARD_PRODUCT_BLOCK_TYPES, STANDARD_PRODUCT_PRIMARY_BLOCK_TYPES, STANDARD_PRODUCT_SECONDARY_BLOCK_TYPES, } from './standard-product-blocks.js';
967
+ export { getBuilderPreviewReviewFixtures } from './preview-fixtures.js';
@@ -0,0 +1,33 @@
1
+ import type { BuilderSettings } from '@shoppex/builder-contracts';
2
+ export declare const SEARCH_BAR_MAX_WIDTH: Record<string, string>;
3
+ export type ResolvedSearchBarSettings = {
4
+ placeholder: string;
5
+ backgroundColor?: string;
6
+ borderColor?: string;
7
+ borderRadiusPx?: number;
8
+ maxWidth: string;
9
+ showShortcut: boolean;
10
+ showInHero: boolean;
11
+ };
12
+ export declare function getNavigationHeaderSettings(settings: BuilderSettings): Record<string, unknown>;
13
+ export declare function readSetting(sources: Array<Record<string, unknown> | undefined>, path: string): unknown;
14
+ export declare function isValidHexColor(value: unknown): value is string;
15
+ export declare function normalizeHexColor(value: string): string;
16
+ export declare function resolveSearchColor(value: unknown): string | undefined;
17
+ export declare function resolveSearchBorderRadius(value: unknown): number | undefined;
18
+ export declare function resolveSearchMaxWidth(value: unknown, fallback?: string): string;
19
+ export declare function resolveSearchBoolean(value: unknown, fallback: boolean): boolean;
20
+ export declare function resolveSearchPlaceholder(value: unknown, fallback: string): string;
21
+ export declare function resolveSearchBarSettings(input: {
22
+ variant: 'hero' | 'navigation';
23
+ heroValues: Record<string, unknown>;
24
+ headerSettings: Record<string, unknown>;
25
+ }): ResolvedSearchBarSettings;
26
+ export declare function buildSearchShellStyle(settings: Pick<ResolvedSearchBarSettings, 'backgroundColor' | 'borderColor' | 'borderRadiusPx'>): {
27
+ backgroundColor?: string;
28
+ borderColor?: string;
29
+ borderWidth?: string;
30
+ borderStyle?: 'solid';
31
+ borderRadius?: string;
32
+ } | undefined;
33
+ //# sourceMappingURL=search-bar-settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-bar-settings.d.ts","sourceRoot":"","sources":["../src/search-bar-settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKvD,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,eAAe,GACxB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAED,wBAAgB,WAAW,CACzB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EACnD,IAAI,EAAE,MAAM,GACX,OAAO,CAUT;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAG/D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGrE;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAG5E;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAO,GAAG,MAAM,CAK7E;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAG/E;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GACf,MAAM,CAER;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,OAAO,EAAE,MAAM,GAAG,YAAY,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC,GAAG,yBAAyB,CAwD5B;AAED,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,IAAI,CACZ,yBAAyB,EACzB,iBAAiB,GAAG,aAAa,GAAG,gBAAgB,CACrD,GACA;IACD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,SAAS,CAoBZ"}
@@ -0,0 +1,99 @@
1
+ export const SEARCH_BAR_MAX_WIDTH = {
2
+ sm: '20rem',
3
+ md: '28rem',
4
+ lg: '36rem',
5
+ full: '100%',
6
+ };
7
+ export function getNavigationHeaderSettings(settings) {
8
+ const block = settings.theme.layout.navigation?.blocks.find((candidate) => candidate.type === 'header');
9
+ return block?.settings ?? {};
10
+ }
11
+ export function readSetting(sources, path) {
12
+ for (const source of sources) {
13
+ if (!source)
14
+ continue;
15
+ if (!Object.prototype.hasOwnProperty.call(source, path))
16
+ continue;
17
+ const value = source[path];
18
+ if (value !== undefined && value !== null && value !== '') {
19
+ return value;
20
+ }
21
+ }
22
+ return undefined;
23
+ }
24
+ export function isValidHexColor(value) {
25
+ if (typeof value !== 'string' || !value.trim())
26
+ return false;
27
+ return /^#?[a-f\d]{3}(?:[a-f\d]{3})?(?:[a-f\d]{2})?$/i.test(value.trim());
28
+ }
29
+ export function normalizeHexColor(value) {
30
+ const trimmed = value.trim();
31
+ return trimmed.startsWith('#') ? trimmed : `#${trimmed}`;
32
+ }
33
+ export function resolveSearchColor(value) {
34
+ if (!isValidHexColor(value))
35
+ return undefined;
36
+ return normalizeHexColor(value);
37
+ }
38
+ export function resolveSearchBorderRadius(value) {
39
+ if (typeof value !== 'number' || !Number.isFinite(value))
40
+ return undefined;
41
+ return Math.max(0, Math.round(value));
42
+ }
43
+ export function resolveSearchMaxWidth(value, fallback = 'md') {
44
+ if (typeof value === 'string' && value in SEARCH_BAR_MAX_WIDTH) {
45
+ return SEARCH_BAR_MAX_WIDTH[value];
46
+ }
47
+ return SEARCH_BAR_MAX_WIDTH[fallback] ?? SEARCH_BAR_MAX_WIDTH.md;
48
+ }
49
+ export function resolveSearchBoolean(value, fallback) {
50
+ if (typeof value === 'boolean')
51
+ return value;
52
+ return fallback;
53
+ }
54
+ export function resolveSearchPlaceholder(value, fallback) {
55
+ return typeof value === 'string' && value.trim() ? value : fallback;
56
+ }
57
+ export function resolveSearchBarSettings(input) {
58
+ const navSources = [input.headerSettings];
59
+ const heroSources = [input.heroValues, input.headerSettings];
60
+ if (input.variant === 'hero') {
61
+ return {
62
+ placeholder: resolveSearchPlaceholder(readSetting(heroSources, 'hero.search.placeholder') ??
63
+ readSetting(navSources, 'navigation.search.placeholder'), 'Search products…'),
64
+ backgroundColor: resolveSearchColor(readSetting(heroSources, 'hero.search.background') ??
65
+ readSetting(navSources, 'navigation.search.background')),
66
+ borderColor: resolveSearchColor(readSetting(heroSources, 'hero.search.borderColor') ??
67
+ readSetting(navSources, 'navigation.search.borderColor')),
68
+ borderRadiusPx: resolveSearchBorderRadius(readSetting(heroSources, 'hero.search.borderRadius') ??
69
+ readSetting(navSources, 'navigation.search.borderRadius')),
70
+ maxWidth: resolveSearchMaxWidth(readSetting(heroSources, 'hero.search.maxWidth'), 'md'),
71
+ showShortcut: resolveSearchBoolean(readSetting(heroSources, 'hero.search.showShortcut'), true),
72
+ showInHero: resolveSearchBoolean(readSetting(heroSources, 'hero.search.show'), true),
73
+ };
74
+ }
75
+ return {
76
+ placeholder: resolveSearchPlaceholder(readSetting(navSources, 'navigation.search.placeholder'), 'Search products…'),
77
+ backgroundColor: resolveSearchColor(readSetting(navSources, 'navigation.search.background')),
78
+ borderColor: resolveSearchColor(readSetting(navSources, 'navigation.search.borderColor')),
79
+ borderRadiusPx: resolveSearchBorderRadius(readSetting(navSources, 'navigation.search.borderRadius')),
80
+ maxWidth: SEARCH_BAR_MAX_WIDTH.md,
81
+ showShortcut: true,
82
+ showInHero: true,
83
+ };
84
+ }
85
+ export function buildSearchShellStyle(settings) {
86
+ const style = {};
87
+ if (settings.backgroundColor) {
88
+ style.backgroundColor = settings.backgroundColor;
89
+ }
90
+ if (settings.borderColor) {
91
+ style.borderColor = settings.borderColor;
92
+ style.borderWidth = '1px';
93
+ style.borderStyle = 'solid';
94
+ }
95
+ if (settings.borderRadiusPx !== undefined) {
96
+ style.borderRadius = `${settings.borderRadiusPx}px`;
97
+ }
98
+ return Object.keys(style).length > 0 ? style : undefined;
99
+ }