@shoppexio/builder-runtime 0.1.0
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/attributes.d.ts +8 -0
- package/dist/attributes.d.ts.map +1 -0
- package/dist/attributes.js +17 -0
- package/dist/builder-runtime.test.d.ts +2 -0
- package/dist/builder-runtime.test.d.ts.map +1 -0
- package/dist/builder-runtime.test.js +115 -0
- package/dist/content.d.ts +13 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +39 -0
- package/dist/css-vars.d.ts +6 -0
- package/dist/css-vars.d.ts.map +1 -0
- package/dist/css-vars.js +97 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/layout.d.ts +9 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +40 -0
- package/dist/react-runtime.test.d.ts +2 -0
- package/dist/react-runtime.test.d.ts.map +1 -0
- package/dist/react-runtime.test.js +292 -0
- package/dist/react.d.ts +302 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +408 -0
- package/dist/style-slots.d.ts +12 -0
- package/dist/style-slots.d.ts.map +1 -0
- package/dist/style-slots.js +31 -0
- package/package.json +91 -0
- package/src/attributes.ts +23 -0
- package/src/builder-runtime.test.ts +143 -0
- package/src/content.ts +58 -0
- package/src/css-vars.ts +124 -0
- package/src/index.ts +6 -0
- package/src/jsdom.d.ts +6 -0
- package/src/layout.ts +55 -0
- package/src/react-runtime.test.tsx +430 -0
- package/src/react.tsx +550 -0
- package/src/style-slots.ts +46 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { StyleSlotId } from '@shoppex/builder-contracts';
|
|
2
|
+
export type BuilderAttributeMap = Record<string, string>;
|
|
3
|
+
export declare function builderContent(path: string): BuilderAttributeMap;
|
|
4
|
+
export declare function builderSlot(slotId: StyleSlotId, input?: {
|
|
5
|
+
blockId?: string;
|
|
6
|
+
}): BuilderAttributeMap;
|
|
7
|
+
export declare function builderBlock(blockId: string, blockType: string): BuilderAttributeMap;
|
|
8
|
+
//# sourceMappingURL=attributes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEzD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,CAIhE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,mBAAmB,CAKtG;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,mBAAmB,CAKpF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function builderContent(path) {
|
|
2
|
+
return {
|
|
3
|
+
'data-builder-content': path,
|
|
4
|
+
};
|
|
5
|
+
}
|
|
6
|
+
export function builderSlot(slotId, input = {}) {
|
|
7
|
+
return {
|
|
8
|
+
'data-builder-slot': slotId,
|
|
9
|
+
...(input.blockId ? { 'data-builder-block': input.blockId } : {}),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function builderBlock(blockId, blockType) {
|
|
13
|
+
return {
|
|
14
|
+
'data-builder-block': blockId,
|
|
15
|
+
'data-builder-block-type': blockType,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder-runtime.test.d.ts","sourceRoot":"","sources":["../src/builder-runtime.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { createBlockInstance, createEmptyBuilderSettings } from '@shoppex/builder-contracts';
|
|
3
|
+
import { builderBlock, builderContent, builderSlot, canAddBlock, createBuilderCss, getBuilderContentList, getBuilderContentString, getPageBlocks, resolveBlockSettings, resolveStyleSlotValue, } from './index.js';
|
|
4
|
+
function createSettings() {
|
|
5
|
+
return {
|
|
6
|
+
...createEmptyBuilderSettings(1),
|
|
7
|
+
theme: {
|
|
8
|
+
content: {
|
|
9
|
+
'hero.title': 'Launch sale',
|
|
10
|
+
faq: {
|
|
11
|
+
items: [{ question: 'Can I edit sections?', answer: 'Yes' }],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
layout: {
|
|
15
|
+
home: {
|
|
16
|
+
blocks: [
|
|
17
|
+
createBlockInstance({
|
|
18
|
+
id: 'hero-1',
|
|
19
|
+
type: 'hero',
|
|
20
|
+
settings: { title: 'Hero block' },
|
|
21
|
+
style_overrides: {
|
|
22
|
+
'button.radius': { base: 14 },
|
|
23
|
+
},
|
|
24
|
+
}),
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
style_slots: {
|
|
29
|
+
'button.radius': { base: 8, md: 12 },
|
|
30
|
+
'color.primary': '#ff5500',
|
|
31
|
+
},
|
|
32
|
+
pages: [],
|
|
33
|
+
terms: {},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const manifest = {
|
|
38
|
+
id: 'default',
|
|
39
|
+
name: 'Default',
|
|
40
|
+
version: '2.0.0',
|
|
41
|
+
pages: {
|
|
42
|
+
home: {
|
|
43
|
+
label: 'Home',
|
|
44
|
+
allowedBlocks: ['hero'],
|
|
45
|
+
defaultBlocks: [],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
blocks: {
|
|
49
|
+
hero: {
|
|
50
|
+
label: 'Hero',
|
|
51
|
+
variants: [],
|
|
52
|
+
settings: {
|
|
53
|
+
title: { type: 'text', label: 'Headline', defaultValue: 'Default hero' },
|
|
54
|
+
},
|
|
55
|
+
exposedStyleSlots: ['button.radius'],
|
|
56
|
+
presets: [],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
styleSlots: {},
|
|
60
|
+
presets: {},
|
|
61
|
+
};
|
|
62
|
+
describe('@shoppex/builder-runtime', () => {
|
|
63
|
+
test('reads direct and nested content values', () => {
|
|
64
|
+
const settings = createSettings();
|
|
65
|
+
expect(getBuilderContentString(settings, 'hero.title')).toBe('Launch sale');
|
|
66
|
+
expect(getBuilderContentList(settings, 'faq.items')).toEqual([{ question: 'Can I edit sections?', answer: 'Yes' }]);
|
|
67
|
+
});
|
|
68
|
+
test('preserves intentionally empty content strings', () => {
|
|
69
|
+
const settings = createSettings();
|
|
70
|
+
settings.theme.content['hero.subtitle'] = '';
|
|
71
|
+
expect(getBuilderContentString(settings, 'hero.subtitle', 'Default subtitle')).toBe('');
|
|
72
|
+
});
|
|
73
|
+
test('resolves page blocks', () => {
|
|
74
|
+
const settings = createSettings();
|
|
75
|
+
expect(getPageBlocks(settings, 'home')).toHaveLength(1);
|
|
76
|
+
expect(getPageBlocks(settings, 'missing')).toEqual([]);
|
|
77
|
+
});
|
|
78
|
+
test('resolves style slots with breakpoint fallback and block override', () => {
|
|
79
|
+
const settings = createSettings();
|
|
80
|
+
const block = settings.theme.layout.home.blocks[0];
|
|
81
|
+
expect(resolveStyleSlotValue(settings, 'button.radius', { breakpoint: 'lg' })).toBe(12);
|
|
82
|
+
expect(resolveStyleSlotValue(settings, 'button.radius', { block, breakpoint: 'md' })).toBe(14);
|
|
83
|
+
});
|
|
84
|
+
test('emits CSS variables with responsive media blocks', () => {
|
|
85
|
+
const css = createBuilderCss(createSettings());
|
|
86
|
+
expect(css).toContain('--builder-button-radius: 8px;');
|
|
87
|
+
expect(css).toContain('--builder-color-primary: #ff5500;');
|
|
88
|
+
expect(css).toContain('@media (min-width: 768px)');
|
|
89
|
+
expect(css).toContain('--builder-button-radius: 12px;');
|
|
90
|
+
});
|
|
91
|
+
test('checks block limits against the manifest', () => {
|
|
92
|
+
const settings = createSettings();
|
|
93
|
+
expect(canAddBlock(settings, manifest, 'home', 'hero')).toBe(true);
|
|
94
|
+
expect(canAddBlock(settings, manifest, 'home', 'faq')).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
test('merges block defaults from the manifest', () => {
|
|
97
|
+
const block = createBlockInstance({
|
|
98
|
+
id: 'hero-2',
|
|
99
|
+
type: 'hero',
|
|
100
|
+
settings: {},
|
|
101
|
+
});
|
|
102
|
+
expect(resolveBlockSettings(block, manifest)).toEqual({ title: 'Default hero' });
|
|
103
|
+
});
|
|
104
|
+
test('creates the three supported builder attributes', () => {
|
|
105
|
+
expect(builderContent('hero.title')).toEqual({ 'data-builder-content': 'hero.title' });
|
|
106
|
+
expect(builderSlot('button.radius', { blockId: 'hero-1' })).toEqual({
|
|
107
|
+
'data-builder-slot': 'button.radius',
|
|
108
|
+
'data-builder-block': 'hero-1',
|
|
109
|
+
});
|
|
110
|
+
expect(builderBlock('hero-1', 'hero')).toEqual({
|
|
111
|
+
'data-builder-block': 'hero-1',
|
|
112
|
+
'data-builder-block-type': 'hero',
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BuilderSettings } from '@shoppex/builder-contracts';
|
|
2
|
+
export type JsonRecord = Record<string, unknown>;
|
|
3
|
+
export declare function getBuilderContentValue(settings: BuilderSettings, path: string): unknown;
|
|
4
|
+
export declare function getBuilderContentString(settings: BuilderSettings, path: string, fallback?: string): string | undefined;
|
|
5
|
+
export declare function getBuilderContentList<T = unknown>(settings: BuilderSettings, path: string, fallback?: T[]): T[];
|
|
6
|
+
export declare function getBuilderContentRecord(settings: BuilderSettings): JsonRecord;
|
|
7
|
+
export declare function getBlockSettingValue<T = unknown>(settings: BuilderSettings, input: {
|
|
8
|
+
pageId: string;
|
|
9
|
+
blockId: string;
|
|
10
|
+
path: string;
|
|
11
|
+
fallback: T;
|
|
12
|
+
}): T;
|
|
13
|
+
//# sourceMappingURL=content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAQvF;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGtH;AAED,wBAAgB,qBAAqB,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,CAAC,EAAO,GAAG,CAAC,EAAE,CAGnH;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,UAAU,CAE7E;AAED,wBAAgB,oBAAoB,CAAC,CAAC,GAAG,OAAO,EAC9C,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,CAAC,CAAA;CAAE,GACpE,CAAC,CAYH"}
|
package/dist/content.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function getBuilderContentValue(settings, path) {
|
|
2
|
+
const content = settings.theme.content;
|
|
3
|
+
if (Object.prototype.hasOwnProperty.call(content, path)) {
|
|
4
|
+
return content[path];
|
|
5
|
+
}
|
|
6
|
+
return getByDottedPath(content, path);
|
|
7
|
+
}
|
|
8
|
+
export function getBuilderContentString(settings, path, fallback) {
|
|
9
|
+
const value = getBuilderContentValue(settings, path);
|
|
10
|
+
return typeof value === 'string' ? value : fallback;
|
|
11
|
+
}
|
|
12
|
+
export function getBuilderContentList(settings, path, fallback = []) {
|
|
13
|
+
const value = getBuilderContentValue(settings, path);
|
|
14
|
+
return Array.isArray(value) ? value : fallback;
|
|
15
|
+
}
|
|
16
|
+
export function getBuilderContentRecord(settings) {
|
|
17
|
+
return settings.theme.content;
|
|
18
|
+
}
|
|
19
|
+
export function getBlockSettingValue(settings, input) {
|
|
20
|
+
const block = settings.theme.layout[input.pageId]?.blocks.find((candidate) => candidate.id === input.blockId);
|
|
21
|
+
if (!block) {
|
|
22
|
+
return input.fallback;
|
|
23
|
+
}
|
|
24
|
+
if (Object.prototype.hasOwnProperty.call(block.settings, input.path)) {
|
|
25
|
+
return block.settings[input.path];
|
|
26
|
+
}
|
|
27
|
+
const nested = getByDottedPath(block.settings, input.path);
|
|
28
|
+
return nested === undefined ? input.fallback : nested;
|
|
29
|
+
}
|
|
30
|
+
function getByDottedPath(record, path) {
|
|
31
|
+
let current = record;
|
|
32
|
+
for (const segment of path.split('.')) {
|
|
33
|
+
if (!current || typeof current !== 'object') {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
current = current[segment];
|
|
37
|
+
}
|
|
38
|
+
return current;
|
|
39
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { BuilderSettings, StyleSlotId, StyleSlots } from '@shoppex/builder-contracts';
|
|
2
|
+
export declare function getStyleSlotCssVariable(slotId: StyleSlotId): string;
|
|
3
|
+
export declare function createStyleSlotCssVariables(slots: StyleSlots): Record<string, string>;
|
|
4
|
+
export declare function createBuilderCss(settings: BuilderSettings, selector?: string): string;
|
|
5
|
+
export declare function createStyleSlotsCss(slots: StyleSlots, selector?: string): string;
|
|
6
|
+
//# sourceMappingURL=css-vars.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-vars.d.ts","sourceRoot":"","sources":["../src/css-vars.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAc,WAAW,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAsCvG,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEnE;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAarF;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,SAAU,GAAG,MAAM,CAEtF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,SAAU,GAAG,MAAM,CAoDjF"}
|
package/dist/css-vars.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { CORE_STYLE_SLOT_IDS } from '@shoppex/builder-contracts';
|
|
2
|
+
import { isResponsiveRecord } from './style-slots.js';
|
|
3
|
+
const BREAKPOINT_MEDIA = {
|
|
4
|
+
sm: '(min-width: 640px)',
|
|
5
|
+
md: '(min-width: 768px)',
|
|
6
|
+
lg: '(min-width: 1024px)',
|
|
7
|
+
xl: '(min-width: 1280px)',
|
|
8
|
+
};
|
|
9
|
+
const STYLE_SLOT_CSS_VARIABLES = {
|
|
10
|
+
'button.radius': { name: '--builder-button-radius', unit: 'px' },
|
|
11
|
+
'button.background': { name: '--builder-button-background' },
|
|
12
|
+
'button.foreground': { name: '--builder-button-foreground' },
|
|
13
|
+
'button.border': { name: '--builder-button-border' },
|
|
14
|
+
'button.font.weight': { name: '--builder-button-font-weight' },
|
|
15
|
+
'input.radius': { name: '--builder-input-radius', unit: 'px' },
|
|
16
|
+
'input.height': { name: '--builder-input-height', unit: 'px' },
|
|
17
|
+
'input.border': { name: '--builder-input-border' },
|
|
18
|
+
'input.background': { name: '--builder-input-background' },
|
|
19
|
+
'input.foreground': { name: '--builder-input-foreground' },
|
|
20
|
+
'card.radius': { name: '--builder-card-radius', unit: 'px' },
|
|
21
|
+
'card.background': { name: '--builder-card-background' },
|
|
22
|
+
'card.border': { name: '--builder-card-border' },
|
|
23
|
+
'section.padding.y': { name: '--builder-section-padding-y', unit: 'px' },
|
|
24
|
+
'section.padding.x': { name: '--builder-section-padding-x', unit: 'px' },
|
|
25
|
+
'container.width': { name: '--builder-container-width', unit: 'px' },
|
|
26
|
+
'color.primary': { name: '--builder-color-primary' },
|
|
27
|
+
'color.accent': { name: '--builder-color-accent' },
|
|
28
|
+
'color.background': { name: '--builder-color-background' },
|
|
29
|
+
'color.foreground': { name: '--builder-color-foreground' },
|
|
30
|
+
'color.muted': { name: '--builder-color-muted' },
|
|
31
|
+
'link.color': { name: '--builder-link-color' },
|
|
32
|
+
'typography.heading.weight': { name: '--builder-typography-heading-weight' },
|
|
33
|
+
'typography.body.size': { name: '--builder-typography-body-size', unit: 'px' },
|
|
34
|
+
};
|
|
35
|
+
export function getStyleSlotCssVariable(slotId) {
|
|
36
|
+
return STYLE_SLOT_CSS_VARIABLES[slotId].name;
|
|
37
|
+
}
|
|
38
|
+
export function createStyleSlotCssVariables(slots) {
|
|
39
|
+
const variables = {};
|
|
40
|
+
for (const slotId of CORE_STYLE_SLOT_IDS) {
|
|
41
|
+
const value = slots[slotId];
|
|
42
|
+
if (value === undefined || isResponsiveRecord(value)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
variables[STYLE_SLOT_CSS_VARIABLES[slotId].name] = formatStyleSlotValue(slotId, value);
|
|
46
|
+
}
|
|
47
|
+
return variables;
|
|
48
|
+
}
|
|
49
|
+
export function createBuilderCss(settings, selector = ':root') {
|
|
50
|
+
return createStyleSlotsCss(settings.theme.style_slots, selector);
|
|
51
|
+
}
|
|
52
|
+
export function createStyleSlotsCss(slots, selector = ':root') {
|
|
53
|
+
const baseDeclarations = [];
|
|
54
|
+
const responsiveDeclarations = {
|
|
55
|
+
sm: [],
|
|
56
|
+
md: [],
|
|
57
|
+
lg: [],
|
|
58
|
+
xl: [],
|
|
59
|
+
};
|
|
60
|
+
for (const slotId of CORE_STYLE_SLOT_IDS) {
|
|
61
|
+
const value = slots[slotId];
|
|
62
|
+
if (value === undefined) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const cssVariable = STYLE_SLOT_CSS_VARIABLES[slotId].name;
|
|
66
|
+
if (!isResponsiveRecord(value)) {
|
|
67
|
+
baseDeclarations.push(`${cssVariable}: ${formatStyleSlotValue(slotId, value)};`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (value.base !== undefined) {
|
|
71
|
+
baseDeclarations.push(`${cssVariable}: ${formatStyleSlotValue(slotId, value.base)};`);
|
|
72
|
+
}
|
|
73
|
+
for (const breakpoint of ['sm', 'md', 'lg', 'xl']) {
|
|
74
|
+
if (value[breakpoint] !== undefined) {
|
|
75
|
+
responsiveDeclarations[breakpoint].push(`${cssVariable}: ${formatStyleSlotValue(slotId, value[breakpoint])};`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const chunks = [];
|
|
80
|
+
if (baseDeclarations.length > 0) {
|
|
81
|
+
chunks.push(`${selector} {\n ${baseDeclarations.join('\n ')}\n}`);
|
|
82
|
+
}
|
|
83
|
+
for (const breakpoint of ['sm', 'md', 'lg', 'xl']) {
|
|
84
|
+
if (responsiveDeclarations[breakpoint].length === 0) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
chunks.push(`@media ${BREAKPOINT_MEDIA[breakpoint]} {\n ${selector} {\n ${responsiveDeclarations[breakpoint].join('\n ')}\n }\n}`);
|
|
88
|
+
}
|
|
89
|
+
return chunks.join('\n\n');
|
|
90
|
+
}
|
|
91
|
+
function formatStyleSlotValue(slotId, value) {
|
|
92
|
+
const unit = STYLE_SLOT_CSS_VARIABLES[slotId].unit;
|
|
93
|
+
if (typeof value === 'number') {
|
|
94
|
+
return unit ? `${value}${unit}` : `${value}`;
|
|
95
|
+
}
|
|
96
|
+
return String(value);
|
|
97
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +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"}
|
package/dist/index.js
ADDED
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BlockInstance, BuilderSettings, PageLayout, ThemeManifest } from '@shoppex/builder-contracts';
|
|
2
|
+
export declare function getPageLayout(settings: BuilderSettings, pageId: string): PageLayout;
|
|
3
|
+
export declare function getPageBlocks(settings: BuilderSettings, pageId: string): BlockInstance[];
|
|
4
|
+
export declare function getVisiblePageBlocks(settings: BuilderSettings, pageId: string): BlockInstance[];
|
|
5
|
+
export declare function getBlockById(settings: BuilderSettings, pageId: string, blockId: string): BlockInstance | null;
|
|
6
|
+
export declare function getAllowedBlockTypes(manifest: ThemeManifest, pageId: string): string[];
|
|
7
|
+
export declare function canAddBlock(settings: BuilderSettings, manifest: ThemeManifest, pageId: string, blockType: string): boolean;
|
|
8
|
+
export declare function resolveBlockSettings(block: BlockInstance, manifest: ThemeManifest): Record<string, unknown>;
|
|
9
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +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,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
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export function getPageLayout(settings, pageId) {
|
|
2
|
+
return settings.theme.layout[pageId] ?? { blocks: [] };
|
|
3
|
+
}
|
|
4
|
+
export function getPageBlocks(settings, pageId) {
|
|
5
|
+
return getPageLayout(settings, pageId).blocks;
|
|
6
|
+
}
|
|
7
|
+
export function getVisiblePageBlocks(settings, pageId) {
|
|
8
|
+
return getPageBlocks(settings, pageId).filter((block) => block.visible);
|
|
9
|
+
}
|
|
10
|
+
export function getBlockById(settings, pageId, blockId) {
|
|
11
|
+
return getPageBlocks(settings, pageId).find((block) => block.id === blockId) ?? null;
|
|
12
|
+
}
|
|
13
|
+
export function getAllowedBlockTypes(manifest, pageId) {
|
|
14
|
+
return manifest.pages[pageId]?.allowedBlocks ?? [];
|
|
15
|
+
}
|
|
16
|
+
export function canAddBlock(settings, manifest, pageId, blockType) {
|
|
17
|
+
const page = manifest.pages[pageId];
|
|
18
|
+
const blockDefinition = manifest.blocks[blockType];
|
|
19
|
+
if (!page || !blockDefinition || !page.allowedBlocks.includes(blockType)) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (!blockDefinition.maxInstances) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
const currentCount = getPageBlocks(settings, pageId).filter((block) => block.type === blockType).length;
|
|
26
|
+
return currentCount < blockDefinition.maxInstances;
|
|
27
|
+
}
|
|
28
|
+
export function resolveBlockSettings(block, manifest) {
|
|
29
|
+
const blockDefinition = manifest.blocks[block.type];
|
|
30
|
+
if (!blockDefinition) {
|
|
31
|
+
return block.settings;
|
|
32
|
+
}
|
|
33
|
+
const defaults = Object.fromEntries(Object.entries(blockDefinition.settings)
|
|
34
|
+
.filter(([, field]) => Object.prototype.hasOwnProperty.call(field, 'defaultValue'))
|
|
35
|
+
.map(([key, field]) => [key, field.defaultValue]));
|
|
36
|
+
return {
|
|
37
|
+
...defaults,
|
|
38
|
+
...block.settings,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-runtime.test.d.ts","sourceRoot":"","sources":["../src/react-runtime.test.tsx"],"names":[],"mappings":""}
|