brand-intent 0.3.2 → 0.4.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/package.json +1 -1
- package/parser/compositionParser.ts +41 -1
- package/parser/index.ts +2 -0
package/package.json
CHANGED
|
@@ -22,6 +22,26 @@ export interface ParsedImageRegion {
|
|
|
22
22
|
colEnd?: number; // 0-based column (undefined = full width)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/** Anchor keywords for illustration placement. */
|
|
26
|
+
export type IllustrationAnchor =
|
|
27
|
+
| 'top-left' | 'top-center' | 'top-right'
|
|
28
|
+
| 'center-left' | 'center' | 'center-right'
|
|
29
|
+
| 'bottom-left' | 'bottom-center' | 'bottom-right';
|
|
30
|
+
|
|
31
|
+
/** Parsed illustration placement from `illustration:` line. */
|
|
32
|
+
export interface ParsedIllustration {
|
|
33
|
+
anchor: IllustrationAnchor;
|
|
34
|
+
fit: 'width' | 'height';
|
|
35
|
+
/** Scale as fraction 0–1 (e.g. 0.9 = 90% of canvas dimension). */
|
|
36
|
+
scale: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const ILLUSTRATION_ANCHORS = new Set<string>([
|
|
40
|
+
'top-left', 'top-center', 'top-right',
|
|
41
|
+
'center-left', 'center', 'center-right',
|
|
42
|
+
'bottom-left', 'bottom-center', 'bottom-right',
|
|
43
|
+
]);
|
|
44
|
+
|
|
25
45
|
export interface ParsedComposition {
|
|
26
46
|
/** Programmatic ID (from `id:` line, or fallback from first `#` line). */
|
|
27
47
|
id: string;
|
|
@@ -44,6 +64,8 @@ export interface ParsedComposition {
|
|
|
44
64
|
sticky: ParsedStickyRegion[];
|
|
45
65
|
/** Flow regions — content-driven flow areas. */
|
|
46
66
|
flow: ParsedFlowRegion | null;
|
|
67
|
+
/** Illustration placement (grid mode only for now). */
|
|
68
|
+
illustration?: ParsedIllustration;
|
|
47
69
|
}
|
|
48
70
|
|
|
49
71
|
/** A sticky (repetition) region — composed elements that don't participate in flow. */
|
|
@@ -179,6 +201,7 @@ export function parseCompositionFile(content: string, fileName: string): ParsedC
|
|
|
179
201
|
const slots: ParsedSlot[] = [];
|
|
180
202
|
const sticky: ParsedStickyRegion[] = [];
|
|
181
203
|
let flow: ParsedFlowRegion | null = null;
|
|
204
|
+
let illustration: ParsedIllustration | undefined = undefined;
|
|
182
205
|
|
|
183
206
|
/** Parse a fraction string like "2/3" → 0.667. */
|
|
184
207
|
function parseFraction(s: string, ctx: string): number {
|
|
@@ -260,6 +283,23 @@ export function parseCompositionFile(content: string, fileName: string): ParsedC
|
|
|
260
283
|
continue;
|
|
261
284
|
}
|
|
262
285
|
|
|
286
|
+
// Illustration placement: "illustration: bottom-center fit-width 90%"
|
|
287
|
+
if (line.startsWith('illustration:')) {
|
|
288
|
+
const parts = line.slice(13).trim().split(/\s+/);
|
|
289
|
+
if (parts.length < 3) throw new Error(`${fileName}:${lineNum}: invalid illustration line — expected "illustration: <anchor> <fit-width|fit-height> <N%>"`);
|
|
290
|
+
const anchor = parts[0];
|
|
291
|
+
if (!ILLUSTRATION_ANCHORS.has(anchor)) throw new Error(`${fileName}:${lineNum}: invalid illustration anchor "${anchor}" (expected ${[...ILLUSTRATION_ANCHORS].join(', ')})`);
|
|
292
|
+
const fitStr = parts[1];
|
|
293
|
+
if (fitStr !== 'fit-width' && fitStr !== 'fit-height') throw new Error(`${fileName}:${lineNum}: invalid illustration fit "${fitStr}" (expected fit-width or fit-height)`);
|
|
294
|
+
const scaleStr = parts[2];
|
|
295
|
+
const scaleMatch = scaleStr.match(/^(\d+(?:\.\d+)?)%$/);
|
|
296
|
+
if (!scaleMatch) throw new Error(`${fileName}:${lineNum}: invalid illustration scale "${scaleStr}" (expected e.g. "90%")`);
|
|
297
|
+
const scale = parseFloat(scaleMatch[1]) / 100;
|
|
298
|
+
if (scale <= 0 || scale > 2) throw new Error(`${fileName}:${lineNum}: illustration scale out of range (expected 1%–200%)`);
|
|
299
|
+
illustration = { anchor: anchor as IllustrationAnchor, fit: fitStr === 'fit-width' ? 'width' : 'height', scale };
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
|
|
263
303
|
// grid: is no longer used in layout files (format owns the grid). Silently skip.
|
|
264
304
|
if (line.startsWith('grid:')) {
|
|
265
305
|
console.warn(`${fileName}:${lineNum}: "grid:" in layout files is no longer needed — format defines the grid`);
|
|
@@ -512,5 +552,5 @@ export function parseCompositionFile(content: string, fileName: string): ParsedC
|
|
|
512
552
|
// Validate required fields
|
|
513
553
|
if (!image) image = 'full'; // default to full-bleed image
|
|
514
554
|
if (!logo && !logoNone && !sticky.length) throw new Error(`${fileName}: missing "logo:" line (or use sticky: block)`);
|
|
515
|
-
return { id, name, description, mode, image, imageExplicit, logo, logoNone: logoNone || undefined, icon, slots, sticky, flow };
|
|
555
|
+
return { id, name, description, mode, image, imageExplicit, logo, logoNone: logoNone || undefined, icon, slots, sticky, flow, illustration };
|
|
516
556
|
}
|