@neatico/visual-core 0.14.2 → 0.14.26
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/cjs/composition.js +62 -36
- package/dist/cjs/compositionScenes.js +91 -38
- package/dist/cjs/content.js +538 -120
- package/dist/cjs/designBlueprint.js +94 -19
- package/dist/cjs/designSystem.js +464 -77
- package/dist/cjs/editorial.js +76 -20
- package/dist/cjs/fontCatalog.js +75 -23
- package/dist/cjs/layoutContracts.js +57 -11
- package/dist/cjs/layouts.js +5 -92
- package/dist/cjs/pagination.js +16 -5
- package/dist/cjs/socialLayouts.js +127 -387
- package/dist/cjs/text.js +12 -2
- package/dist/composition.d.ts +4 -4
- package/dist/composition.js +62 -36
- package/dist/compositionScenes.d.ts +2 -2
- package/dist/compositionScenes.js +91 -38
- package/dist/content.d.ts +55 -20
- package/dist/content.js +539 -121
- package/dist/designBlueprint.d.ts +4 -4
- package/dist/designBlueprint.js +95 -20
- package/dist/designSystem.d.ts +11 -7
- package/dist/designSystem.js +465 -79
- package/dist/editorial.d.ts +1 -1
- package/dist/editorial.js +77 -21
- package/dist/fontCatalog.d.ts +1 -1
- package/dist/fontCatalog.js +75 -23
- package/dist/layoutContracts.d.ts +3 -3
- package/dist/layoutContracts.js +58 -12
- package/dist/layouts.d.ts +2 -2
- package/dist/layouts.js +5 -92
- package/dist/pagination.js +16 -5
- package/dist/socialLayouts.d.ts +40 -232
- package/dist/socialLayouts.js +127 -387
- package/dist/text.js +12 -2
- package/package.json +2 -2
package/dist/cjs/composition.js
CHANGED
|
@@ -6,18 +6,29 @@ exports.validateComposition = validateComposition;
|
|
|
6
6
|
exports.COMPOSITION_PROMPT = `Also return composition:{version:1,root:node}. Design a hierarchy from the content, not a fixed template. A node is {type,weight?,tone?,role?,bind?,icon?,children?}. row and column contain 2-4 children; nest up to 5 levels, at most 40 nodes. Weight is relative space 0.5-4. Tone plain/card/contrast applies to groups. Text binds exactly one existing nonempty content field (title or headline, body, eyebrow, cta, value, attribution, items.0.title, items.0.description, etc); never bind notes. Include EVERY nonempty content field exactly once. Text role hero/heading/body/caption controls typography. Image is an optional original conceptual illustration, not invented evidence or a photo. Icon optionally uses idea/check/chart/people/shield/arrow. Divider separates related content. No coordinates, CSS, HTML, URLs or text in the tree. Use one strong hero, purposeful contrast, asymmetric columns, grouped evidence, and breathing room. Rows reflow for narrow formats. Different stories should have different trees, not just different colors.`;
|
|
7
7
|
function compositionFields(value) {
|
|
8
8
|
const fields = {};
|
|
9
|
-
for (const key of [
|
|
10
|
-
|
|
9
|
+
for (const key of [
|
|
10
|
+
"title",
|
|
11
|
+
"headline",
|
|
12
|
+
"body",
|
|
13
|
+
"eyebrow",
|
|
14
|
+
"cta",
|
|
15
|
+
"value",
|
|
16
|
+
"attribution",
|
|
17
|
+
])
|
|
18
|
+
if (typeof value[key] === "string" && value[key].trim())
|
|
11
19
|
fields[key] = value[key];
|
|
12
20
|
if (Array.isArray(value.items))
|
|
13
|
-
value.items.forEach((item, i) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
value.items.forEach((item, i) => {
|
|
22
|
+
if (!item || typeof item !== "object")
|
|
23
|
+
return;
|
|
24
|
+
for (const key of ["title", "description"]) {
|
|
25
|
+
if (!Object.prototype.hasOwnProperty.call(item, key))
|
|
26
|
+
continue;
|
|
27
|
+
const v = item[key];
|
|
28
|
+
if (typeof v === "string" && v.trim())
|
|
29
|
+
fields[`items.${i}.${key}`] = v;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
21
32
|
return fields;
|
|
22
33
|
}
|
|
23
34
|
function validateComposition(raw, fields) {
|
|
@@ -25,44 +36,59 @@ function validateComposition(raw, fields) {
|
|
|
25
36
|
let count = 0, images = 0;
|
|
26
37
|
const seen = new Set();
|
|
27
38
|
if (!value || value.version !== 1)
|
|
28
|
-
throw new Error(
|
|
39
|
+
throw new Error("Unsupported composition");
|
|
29
40
|
function visit(n, depth) {
|
|
30
|
-
if (!n ||
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
throw new Error(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
if (!n ||
|
|
42
|
+
typeof n !== "object" ||
|
|
43
|
+
++count > 40 ||
|
|
44
|
+
depth > 5 ||
|
|
45
|
+
!["row", "column", "text", "image", "divider", "icon"].includes(n.type))
|
|
46
|
+
throw new Error("Invalid composition node");
|
|
47
|
+
if (n.weight !== undefined &&
|
|
48
|
+
(!Number.isFinite(n.weight) || n.weight < 0.5 || n.weight > 4))
|
|
49
|
+
throw new Error("Invalid composition weight");
|
|
50
|
+
if (n.tone !== undefined && !["plain", "card", "contrast"].includes(n.tone))
|
|
51
|
+
throw new Error("Invalid composition tone");
|
|
52
|
+
const out = {
|
|
53
|
+
type: n.type,
|
|
54
|
+
weight: n.weight,
|
|
55
|
+
tone: n.tone,
|
|
56
|
+
};
|
|
57
|
+
if (n.type === "row" || n.type === "column") {
|
|
58
|
+
if (!Array.isArray(n.children) ||
|
|
59
|
+
n.children.length < 2 ||
|
|
60
|
+
n.children.length > 4)
|
|
61
|
+
throw new Error("Invalid composition group");
|
|
62
|
+
out.children = n.children.map((c) => visit(c, depth + 1));
|
|
41
63
|
}
|
|
42
64
|
else {
|
|
43
65
|
if (n.children !== undefined)
|
|
44
|
-
throw new Error(
|
|
45
|
-
if (n.type ===
|
|
46
|
-
if (!n.bind ||
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
throw new Error(
|
|
66
|
+
throw new Error("Leaf cannot have children");
|
|
67
|
+
if (n.type === "text") {
|
|
68
|
+
if (!n.bind ||
|
|
69
|
+
!Object.prototype.hasOwnProperty.call(fields, n.bind) ||
|
|
70
|
+
seen.has(n.bind))
|
|
71
|
+
throw new Error("Invalid or duplicated binding");
|
|
72
|
+
if (n.role !== undefined &&
|
|
73
|
+
!["hero", "heading", "body", "caption"].includes(n.role))
|
|
74
|
+
throw new Error("Invalid text role");
|
|
50
75
|
seen.add(n.bind);
|
|
51
76
|
out.bind = n.bind;
|
|
52
|
-
out.role = n.role ||
|
|
77
|
+
out.role = n.role || "body";
|
|
53
78
|
}
|
|
54
|
-
if (n.type ===
|
|
55
|
-
throw new Error(
|
|
56
|
-
if (n.type ===
|
|
57
|
-
if (!n.icon ||
|
|
58
|
-
|
|
79
|
+
if (n.type === "image" && ++images > 1)
|
|
80
|
+
throw new Error("Only one illustration per composition");
|
|
81
|
+
if (n.type === "icon") {
|
|
82
|
+
if (!n.icon ||
|
|
83
|
+
!["idea", "check", "chart", "people", "shield", "arrow"].includes(n.icon))
|
|
84
|
+
throw new Error("Invalid icon");
|
|
59
85
|
out.icon = n.icon;
|
|
60
86
|
}
|
|
61
87
|
}
|
|
62
88
|
return out;
|
|
63
89
|
}
|
|
64
90
|
const root = visit(value.root, 0);
|
|
65
|
-
if (Object.keys(fields).some(key => !seen.has(key)))
|
|
66
|
-
throw new Error(
|
|
91
|
+
if (Object.keys(fields).some((key) => !seen.has(key)))
|
|
92
|
+
throw new Error("Composition omits content");
|
|
67
93
|
return { version: 1, root };
|
|
68
94
|
}
|
|
@@ -2,50 +2,103 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AUTHORED_COMPOSITIONS = exports.COMPOSITION_SCENES = void 0;
|
|
4
4
|
exports.sceneRecipePreference = sceneRecipePreference;
|
|
5
|
-
const both = [
|
|
5
|
+
const both = ["presentation", "social"];
|
|
6
6
|
exports.COMPOSITION_SCENES = [
|
|
7
|
-
{ id:
|
|
8
|
-
{ id:
|
|
9
|
-
{ id:
|
|
10
|
-
{ id:
|
|
11
|
-
{ id:
|
|
12
|
-
{ id:
|
|
13
|
-
{ id:
|
|
14
|
-
{ id:
|
|
15
|
-
{ id:
|
|
16
|
-
{ id:
|
|
17
|
-
{ id:
|
|
18
|
-
{ id:
|
|
19
|
-
{ id:
|
|
20
|
-
{ id:
|
|
21
|
-
{ id:
|
|
22
|
-
{ id:
|
|
23
|
-
|
|
7
|
+
{ id: "menu-details", kinds: ["parameters"], outputs: both },
|
|
8
|
+
{ id: "travel-details", kinds: ["parameters"], outputs: both },
|
|
9
|
+
{ id: "offer-details", kinds: ["parameters"], outputs: both },
|
|
10
|
+
{ id: "questions", kinds: ["features"], outputs: both },
|
|
11
|
+
{ id: "case-study", kinds: ["features"], outputs: both },
|
|
12
|
+
{ id: "brand-collection", kinds: ["features"], outputs: both },
|
|
13
|
+
{ id: "hero", kinds: ["paragraph"], outputs: both },
|
|
14
|
+
{ id: "chapter", kinds: ["paragraph"], outputs: ["presentation"] },
|
|
15
|
+
{ id: "statement", kinds: ["paragraph"], outputs: both },
|
|
16
|
+
{ id: "closing", kinds: ["paragraph"], outputs: both },
|
|
17
|
+
{ id: "product-launch", kinds: ["features"], outputs: both },
|
|
18
|
+
{ id: "feature-spotlight", kinds: ["features"], outputs: both },
|
|
19
|
+
{ id: "feature-overview", kinds: ["features"], outputs: both },
|
|
20
|
+
{ id: "benefits", kinds: ["features"], outputs: both },
|
|
21
|
+
{ id: "comparison", kinds: ["comparison"], outputs: both },
|
|
22
|
+
{ id: "before-after", kinds: ["comparison"], outputs: both },
|
|
23
|
+
{ id: "plan-options", kinds: ["comparison"], outputs: both },
|
|
24
|
+
{ id: "process", kinds: ["steps"], outputs: both },
|
|
25
|
+
{ id: "roadmap", kinds: ["steps"], outputs: both },
|
|
26
|
+
{ id: "tutorial", kinds: ["steps"], outputs: both },
|
|
27
|
+
{ id: "checklist", kinds: ["features"], outputs: both },
|
|
28
|
+
{ id: "metrics", kinds: ["chart"], outputs: both },
|
|
29
|
+
{ id: "trend", kinds: ["chart"], outputs: both },
|
|
30
|
+
{ id: "results", kinds: ["chart"], outputs: both },
|
|
31
|
+
{ id: "quotation", kinds: ["quote"], outputs: both },
|
|
32
|
+
{ id: "testimonial", kinds: ["quote"], outputs: both },
|
|
33
|
+
{ id: "code-example", kinds: ["code"], outputs: both },
|
|
34
|
+
{ id: "specifications", kinds: ["parameters"], outputs: both },
|
|
35
|
+
{ id: "pricing-details", kinds: ["parameters"], outputs: both },
|
|
36
|
+
{ id: "event-details", kinds: ["parameters"], outputs: both },
|
|
37
|
+
{ id: "recruitment-details", kinds: ["parameters"], outputs: both },
|
|
38
|
+
{
|
|
39
|
+
id: "product-demonstration",
|
|
40
|
+
kinds: ["image"],
|
|
41
|
+
outputs: both,
|
|
42
|
+
requiresAsset: true,
|
|
43
|
+
},
|
|
44
|
+
{ id: "photograph", kinds: ["image"], outputs: both, requiresAsset: true },
|
|
45
|
+
...[
|
|
46
|
+
"banner-hero",
|
|
47
|
+
"product-showcase",
|
|
48
|
+
"editorial-cover",
|
|
49
|
+
"image-campaign",
|
|
50
|
+
].map((id) => ({
|
|
51
|
+
id,
|
|
52
|
+
kinds: ["image"],
|
|
53
|
+
outputs: both,
|
|
54
|
+
requiresAsset: true,
|
|
55
|
+
})),
|
|
24
56
|
];
|
|
25
57
|
exports.AUTHORED_COMPOSITIONS = [
|
|
26
|
-
{ id:
|
|
27
|
-
{ id:
|
|
28
|
-
{ id:
|
|
29
|
-
{ id:
|
|
30
|
-
{ id:
|
|
31
|
-
{ id:
|
|
32
|
-
{ id:
|
|
33
|
-
{ id:
|
|
34
|
-
{ id:
|
|
35
|
-
{ id:
|
|
36
|
-
{ id:
|
|
58
|
+
{ id: "feature-focus", kind: "features", min: 1, max: 1 },
|
|
59
|
+
{ id: "feature-bento", kind: "features", min: 2, max: 6 },
|
|
60
|
+
{ id: "feature-index", kind: "features", min: 2, max: 6 },
|
|
61
|
+
{ id: "steps-journey", kind: "steps", min: 2, max: 6 },
|
|
62
|
+
{ id: "steps-ribbon", kind: "steps", min: 2, max: 4 },
|
|
63
|
+
{ id: "comparison-panels", kind: "comparison", min: 2, max: 3 },
|
|
64
|
+
{ id: "quote-editorial", kind: "quote", min: 0, max: 0 },
|
|
65
|
+
{ id: "quote-poster", kind: "quote", min: 0, max: 0 },
|
|
66
|
+
{ id: "code-editorial", kind: "code", min: 0, max: 0 },
|
|
67
|
+
{ id: "parameter-ledger", kind: "parameters", min: 1, max: 8 },
|
|
68
|
+
{ id: "parameter-cards", kind: "parameters", min: 1, max: 4 },
|
|
37
69
|
];
|
|
38
70
|
/** Soft art-direction preferences; capacity and measured quality always remain mandatory. */
|
|
39
71
|
function sceneRecipePreference(scene, recipeId) {
|
|
40
72
|
const preferred = {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
73
|
+
"banner-hero": ["authored-image-banner"],
|
|
74
|
+
"product-showcase": ["authored-image-split"],
|
|
75
|
+
"editorial-cover": ["authored-image-editorial"],
|
|
76
|
+
"image-campaign": ["authored-image-campaign"],
|
|
77
|
+
hero: ["cover", "semantic-hero-split"],
|
|
78
|
+
chapter: ["section", "semantic-hero-editorial"],
|
|
79
|
+
statement: ["statement", "semantic-hero-stack"],
|
|
80
|
+
closing: ["closing"],
|
|
81
|
+
"product-launch": ["authored-feature-bento"],
|
|
82
|
+
"feature-spotlight": ["authored-feature-focus"],
|
|
83
|
+
"feature-overview": ["authored-feature-bento", "three-column"],
|
|
84
|
+
benefits: ["authored-feature-index"],
|
|
85
|
+
comparison: ["authored-comparison-panels"],
|
|
86
|
+
"before-after": ["before-after", "semantic-comparison-split"],
|
|
87
|
+
"plan-options": ["authored-comparison-panels"],
|
|
88
|
+
process: ["authored-steps-ribbon"],
|
|
89
|
+
roadmap: ["authored-steps-ribbon", "roadmap"],
|
|
90
|
+
tutorial: ["authored-steps-journey"],
|
|
91
|
+
checklist: ["authored-feature-index", "checklist"],
|
|
92
|
+
quotation: ["authored-quote-editorial"],
|
|
93
|
+
testimonial: ["authored-quote-poster"],
|
|
94
|
+
"code-example": ["authored-code-editorial"],
|
|
95
|
+
specifications: ["authored-parameter-ledger"],
|
|
96
|
+
"pricing-details": ["authored-parameter-cards"],
|
|
97
|
+
"event-details": ["authored-parameter-cards"],
|
|
98
|
+
"recruitment-details": ["authored-parameter-ledger"],
|
|
49
99
|
};
|
|
50
|
-
return scene &&
|
|
100
|
+
return scene &&
|
|
101
|
+
preferred[scene]?.some((id) => recipeId === id || recipeId.startsWith(`${id}--`))
|
|
102
|
+
? 6
|
|
103
|
+
: 0;
|
|
51
104
|
}
|