@nuvio/shared 1.0.0 → 1.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/index.js CHANGED
@@ -1,40 +1,1544 @@
1
+ import {
2
+ PCC_BRANDABLE_CATEGORIES,
3
+ PCC_REJECTED_CATEGORIES,
4
+ PCC_SUPPORTED_CATEGORIES,
5
+ defaultPccManifestPath,
6
+ isPccBrandableCategory,
7
+ isPccRejectedCategory,
8
+ isPccSupportedCategory,
9
+ parsePccManifest,
10
+ pccCategoryLabel,
11
+ pccHostsForCategory
12
+ } from "./chunk-3R2WM7JQ.js";
13
+
1
14
  // src/constants.ts
2
15
  var NUVIO_WS_PATH = "/__nuvio/ws";
16
+ var NUVIO_BRAND_PATH = "/__nuvio/brand";
17
+ var NUVIO_PCC_PATH = "/__nuvio/pcc";
3
18
 
4
- // src/protocol.ts
19
+ // src/brand-kit.ts
5
20
  import { z } from "zod";
21
+ var BRAND_ACCENT_COLORS = ["blue", "purple", "green", "slate", "rose"];
22
+ var BRAND_COLORS = ["none", "neutral", ...BRAND_ACCENT_COLORS];
23
+ var BRAND_RADIUS = ["sharp", "soft", "rounded", "pill"];
24
+ var BRAND_DENSITY = ["compact", "balanced", "spacious"];
25
+ var BRAND_TYPOGRAPHY = ["clean", "bold", "soft"];
26
+ var BRAND_SURFACES = ["white", "muted"];
27
+ var BRAND_BUTTON_VARIANTS = ["solid", "outline"];
28
+ var BRAND_BUTTON_HOVERS = ["none", "darken"];
29
+ var BRAND_CARD_SHADOWS = ["none", "sm", "md"];
30
+ var BRAND_CARD_HOVERS = ["none", "border"];
31
+ var BRAND_APPLY_ACTIONS = [
32
+ "button",
33
+ "card",
34
+ "heading",
35
+ "text",
36
+ "table",
37
+ "form",
38
+ "badge"
39
+ ];
40
+ var BRAND_PRESET_DIMENSIONS_BY_ACTION = {
41
+ button: ["color", "buttonVariant", "radius", "density", "buttonHover"],
42
+ card: ["surface", "color", "radius", "density", "cardShadow", "cardHover"],
43
+ heading: ["color", "typography"],
44
+ text: ["color"],
45
+ table: ["color", "radius"],
46
+ form: ["color", "radius", "density", "surface"],
47
+ badge: ["color"]
48
+ };
49
+ function brandPresetDimensionsForAction(action) {
50
+ return BRAND_PRESET_DIMENSIONS_BY_ACTION[action];
51
+ }
52
+ var BRAND_ACCENT_SLOT_BY_ACTION = {
53
+ button: "fill",
54
+ card: "border",
55
+ heading: "text",
56
+ text: "text",
57
+ table: "border",
58
+ form: "border",
59
+ badge: "tint"
60
+ };
61
+ function getBrandColorSlotLabel(action) {
62
+ const labels = {
63
+ button: "Fill",
64
+ card: "Border color",
65
+ heading: "Text color",
66
+ text: "Text color",
67
+ table: "Border color",
68
+ form: "Field border",
69
+ badge: "Tint"
70
+ };
71
+ return labels[action];
72
+ }
73
+ function brandColorsForAction(action) {
74
+ const slot = BRAND_ACCENT_SLOT_BY_ACTION[action];
75
+ if (slot === "border") {
76
+ return BRAND_COLORS;
77
+ }
78
+ if (slot === "text") {
79
+ return ["neutral", ...BRAND_ACCENT_COLORS];
80
+ }
81
+ if (slot === "tint") {
82
+ return ["neutral", ...BRAND_ACCENT_COLORS];
83
+ }
84
+ return BRAND_ACCENT_COLORS;
85
+ }
86
+ function isBrandAccentColor(color) {
87
+ return BRAND_ACCENT_COLORS.includes(color);
88
+ }
89
+ var BRAND_RADIUS_FIELD_LABEL = "Corners";
90
+ var BRAND_DENSITY_FIELD_LABEL = "Spacing";
91
+ function getBrandTypographyFieldLabel(action) {
92
+ return action === "heading" ? "Heading style" : "Typography";
93
+ }
94
+ var BRAND_SURFACE_FIELD_LABEL = "Surface";
95
+ var BRAND_BUTTON_VARIANT_FIELD_LABEL = "Style";
96
+ var BRAND_BUTTON_HOVER_FIELD_LABEL = "Hover";
97
+ var BRAND_CARD_SHADOW_FIELD_LABEL = "Shadow";
98
+ var BRAND_CARD_HOVER_FIELD_LABEL = "Hover";
99
+ function formatAccentForSummary(action, config) {
100
+ if (config.color === "none" && (action === "card" || action === "table" || action === "form")) {
101
+ return "No border";
102
+ }
103
+ const label = COLOR_LABELS[config.color];
104
+ switch (action) {
105
+ case "button":
106
+ return config.buttonVariant === "outline" ? `${label} outline` : `${label} fill`;
107
+ case "card":
108
+ case "table":
109
+ return `${label} border`;
110
+ case "form":
111
+ return `${label} field border`;
112
+ case "badge":
113
+ return `${label} tint`;
114
+ case "heading":
115
+ case "text":
116
+ return `${label} text`;
117
+ default:
118
+ return label;
119
+ }
120
+ }
121
+ var DEFAULT_BRAND_CONFIG = {
122
+ color: "blue",
123
+ surface: "white",
124
+ buttonVariant: "solid",
125
+ buttonHover: "darken",
126
+ cardShadow: "none",
127
+ cardHover: "none",
128
+ radius: "soft",
129
+ density: "balanced",
130
+ typography: "clean"
131
+ };
132
+ var brandConfigSchema = z.object({
133
+ color: z.enum(BRAND_COLORS),
134
+ surface: z.enum(BRAND_SURFACES),
135
+ buttonVariant: z.enum(BRAND_BUTTON_VARIANTS),
136
+ buttonHover: z.enum(BRAND_BUTTON_HOVERS),
137
+ cardShadow: z.enum(BRAND_CARD_SHADOWS),
138
+ cardHover: z.enum(BRAND_CARD_HOVERS),
139
+ radius: z.enum(BRAND_RADIUS),
140
+ density: z.enum(BRAND_DENSITY),
141
+ typography: z.enum(BRAND_TYPOGRAPHY)
142
+ });
143
+ var brandTokensSchema = z.object({
144
+ accent: z.enum(BRAND_COLORS),
145
+ surface: z.enum(BRAND_SURFACES),
146
+ radius: z.enum(BRAND_RADIUS),
147
+ density: z.enum(BRAND_DENSITY),
148
+ typography: z.enum(BRAND_TYPOGRAPHY),
149
+ buttonVariant: z.enum(BRAND_BUTTON_VARIANTS),
150
+ buttonHover: z.enum(BRAND_BUTTON_HOVERS),
151
+ cardShadow: z.enum(BRAND_CARD_SHADOWS),
152
+ cardHover: z.enum(BRAND_CARD_HOVERS)
153
+ });
154
+ var brandConfigFileV2Schema = z.object({
155
+ version: z.literal(2),
156
+ tokens: brandTokensSchema
157
+ });
158
+ var COLOR_LABELS = {
159
+ none: "None",
160
+ neutral: "Neutral",
161
+ blue: "Blue",
162
+ purple: "Purple",
163
+ green: "Green",
164
+ slate: "Slate",
165
+ rose: "Rose"
166
+ };
167
+ var RADIUS_LABELS = {
168
+ sharp: "Sharp",
169
+ soft: "Soft",
170
+ rounded: "Rounded",
171
+ pill: "Pill"
172
+ };
173
+ var DENSITY_LABELS = {
174
+ compact: "Compact",
175
+ balanced: "Balanced",
176
+ spacious: "Spacious"
177
+ };
178
+ var SURFACE_LABELS = {
179
+ white: "White",
180
+ muted: "Muted"
181
+ };
182
+ var BUTTON_VARIANT_LABELS = {
183
+ solid: "Solid",
184
+ outline: "Outline"
185
+ };
186
+ var BUTTON_HOVER_LABELS = {
187
+ none: "None",
188
+ darken: "Darken"
189
+ };
190
+ var CARD_SHADOW_LABELS = {
191
+ none: "None",
192
+ sm: "Subtle",
193
+ md: "Medium"
194
+ };
195
+ var CARD_HOVER_LABELS = {
196
+ none: "None",
197
+ border: "Border"
198
+ };
199
+ var TYPOGRAPHY_LABELS = {
200
+ clean: "Clean",
201
+ bold: "Bold",
202
+ soft: "Soft"
203
+ };
204
+ var ACTION_LABELS = {
205
+ button: "Button",
206
+ card: "Card",
207
+ heading: "Heading",
208
+ text: "Text",
209
+ table: "Table",
210
+ form: "Form",
211
+ badge: "Badge"
212
+ };
213
+ function colorBgClass(color) {
214
+ if (color === "neutral") {
215
+ return "bg-gray-600";
216
+ }
217
+ return color === "slate" ? "bg-slate-700" : `bg-${color}-600`;
218
+ }
219
+ function colorTextClass(color) {
220
+ if (color === "neutral") {
221
+ return "text-gray-700";
222
+ }
223
+ return color === "slate" ? "text-slate-700" : `text-${color}-600`;
224
+ }
225
+ function colorBorderClass(color) {
226
+ if (color === "none") {
227
+ return null;
228
+ }
229
+ if (color === "neutral") {
230
+ return "border-gray-200";
231
+ }
232
+ return color === "slate" ? "border-slate-300" : `border-${color}-300`;
233
+ }
234
+ function colorAccentBorderClass(color) {
235
+ if (color === "neutral") {
236
+ return "border-gray-600";
237
+ }
238
+ return color === "slate" ? "border-slate-700" : `border-${color}-600`;
239
+ }
240
+ function accentBorderRecipeParts(color) {
241
+ if (color === "none") {
242
+ return ["border-0"];
243
+ }
244
+ const borderColor = colorBorderClass(color);
245
+ if (!borderColor) {
246
+ return [];
247
+ }
248
+ return ["border", borderColor];
249
+ }
250
+ function surfaceBgClass(surface) {
251
+ return surface === "muted" ? "bg-slate-50" : "bg-white";
252
+ }
253
+ function colorBadgeBgClass(color) {
254
+ if (color === "neutral") {
255
+ return "bg-gray-100";
256
+ }
257
+ return color === "slate" ? "bg-slate-100" : `bg-${color}-100`;
258
+ }
259
+ function colorBadgeTextClass(color) {
260
+ if (color === "neutral") {
261
+ return "text-gray-700";
262
+ }
263
+ return color === "slate" ? "text-slate-700" : `text-${color}-700`;
264
+ }
265
+ function radiusClass(radius) {
266
+ const map = {
267
+ sharp: "rounded-none",
268
+ soft: "rounded-md",
269
+ rounded: "rounded-xl",
270
+ pill: "rounded-full"
271
+ };
272
+ return map[radius];
273
+ }
274
+ function densityButtonPadding(density) {
275
+ const map = {
276
+ compact: "px-3 py-1.5",
277
+ balanced: "px-4 py-2",
278
+ spacious: "px-6 py-3"
279
+ };
280
+ return map[density];
281
+ }
282
+ function densityCardPadding(density) {
283
+ const map = {
284
+ compact: "p-4",
285
+ balanced: "p-6",
286
+ spacious: "p-8"
287
+ };
288
+ return map[density];
289
+ }
290
+ function typographyClasses(typography) {
291
+ const map = {
292
+ clean: "text-base font-medium",
293
+ bold: "text-lg font-semibold",
294
+ soft: "text-sm font-normal"
295
+ };
296
+ return map[typography];
297
+ }
298
+ function buttonHoverClass(color, buttonHover, buttonVariant) {
299
+ if (buttonHover === "none" || color === "none" || color === "neutral") {
300
+ return null;
301
+ }
302
+ if (buttonVariant === "outline") {
303
+ return color === "slate" ? "hover:bg-slate-100" : `hover:bg-${color}-50`;
304
+ }
305
+ return color === "slate" ? "hover:bg-slate-800" : `hover:bg-${color}-700`;
306
+ }
307
+ function cardShadowClass(cardShadow) {
308
+ if (cardShadow === "none") {
309
+ return null;
310
+ }
311
+ return cardShadow === "sm" ? "shadow-sm" : "shadow-md";
312
+ }
313
+ function cardHoverBorderClass(color, cardHover) {
314
+ if (cardHover === "none" || color === "none" || color === "neutral") {
315
+ return null;
316
+ }
317
+ return color === "slate" ? "hover:border-slate-400" : `hover:border-${color}-400`;
318
+ }
319
+ function joinRecipeClasses(parts) {
320
+ return parts.filter(Boolean).join(" ").trim();
321
+ }
322
+ function isFormLabelHost(hint) {
323
+ const tag = hint?.tagName?.toLowerCase() ?? "";
324
+ const hostId = hint?.hostId?.toLowerCase() ?? "";
325
+ return tag === "label" || hostId.endsWith(".label");
326
+ }
327
+ function brandFragmentHostHint(entry) {
328
+ return {
329
+ tagName: entry.tagName,
330
+ hierarchyRole: entry.hierarchyRole,
331
+ hostId: entry.id
332
+ };
333
+ }
334
+ function normalizeBrandConfig(input) {
335
+ const parsed = brandConfigSchema.safeParse(input);
336
+ if (parsed.success) {
337
+ return parsed.data;
338
+ }
339
+ const v2 = brandConfigFileV2Schema.safeParse(input);
340
+ if (v2.success) {
341
+ const { tokens } = v2.data;
342
+ return {
343
+ color: tokens.accent,
344
+ surface: tokens.surface,
345
+ buttonVariant: tokens.buttonVariant,
346
+ buttonHover: tokens.buttonHover ?? DEFAULT_BRAND_CONFIG.buttonHover,
347
+ cardShadow: tokens.cardShadow ?? DEFAULT_BRAND_CONFIG.cardShadow,
348
+ cardHover: tokens.cardHover ?? DEFAULT_BRAND_CONFIG.cardHover,
349
+ radius: tokens.radius,
350
+ density: tokens.density,
351
+ typography: tokens.typography
352
+ };
353
+ }
354
+ if (input && typeof input === "object") {
355
+ const partial = input;
356
+ const tokens = partial.version === 2 && partial.tokens && typeof partial.tokens === "object" ? partial.tokens : null;
357
+ const source = tokens ?? partial;
358
+ return {
359
+ color: brandConfigSchema.shape.color.safeParse(source.accent ?? source.color).success ? source.accent ?? source.color : DEFAULT_BRAND_CONFIG.color,
360
+ surface: brandConfigSchema.shape.surface.safeParse(source.surface).success ? source.surface : DEFAULT_BRAND_CONFIG.surface,
361
+ buttonVariant: brandConfigSchema.shape.buttonVariant.safeParse(source.buttonVariant).success ? source.buttonVariant : DEFAULT_BRAND_CONFIG.buttonVariant,
362
+ buttonHover: brandConfigSchema.shape.buttonHover.safeParse(source.buttonHover).success ? source.buttonHover : DEFAULT_BRAND_CONFIG.buttonHover,
363
+ cardShadow: brandConfigSchema.shape.cardShadow.safeParse(source.cardShadow).success ? source.cardShadow : DEFAULT_BRAND_CONFIG.cardShadow,
364
+ cardHover: brandConfigSchema.shape.cardHover.safeParse(source.cardHover).success ? source.cardHover : DEFAULT_BRAND_CONFIG.cardHover,
365
+ radius: brandConfigSchema.shape.radius.safeParse(source.radius).success ? source.radius : DEFAULT_BRAND_CONFIG.radius,
366
+ density: brandConfigSchema.shape.density.safeParse(source.density).success ? source.density : DEFAULT_BRAND_CONFIG.density,
367
+ typography: brandConfigSchema.shape.typography.safeParse(source.typography).success ? source.typography : DEFAULT_BRAND_CONFIG.typography
368
+ };
369
+ }
370
+ return { ...DEFAULT_BRAND_CONFIG };
371
+ }
372
+ function serializeBrandConfig(config) {
373
+ return {
374
+ version: 2,
375
+ tokens: {
376
+ accent: config.color,
377
+ surface: config.surface,
378
+ radius: config.radius,
379
+ density: config.density,
380
+ typography: config.typography,
381
+ buttonVariant: config.buttonVariant,
382
+ buttonHover: config.buttonHover,
383
+ cardShadow: config.cardShadow,
384
+ cardHover: config.cardHover
385
+ }
386
+ };
387
+ }
388
+ function brandConfigsEqual(a, b) {
389
+ return a.color === b.color && a.surface === b.surface && a.buttonVariant === b.buttonVariant && a.buttonHover === b.buttonHover && a.cardShadow === b.cardShadow && a.cardHover === b.cardHover && a.radius === b.radius && a.density === b.density && a.typography === b.typography;
390
+ }
391
+ function buildBrandClassFragment(action, config, hint) {
392
+ switch (action) {
393
+ case "button":
394
+ if (config.buttonVariant === "outline") {
395
+ return joinRecipeClasses([
396
+ "border",
397
+ colorAccentBorderClass(config.color),
398
+ colorTextClass(config.color),
399
+ "bg-transparent",
400
+ radiusClass(config.radius),
401
+ densityButtonPadding(config.density),
402
+ buttonHoverClass(config.color, config.buttonHover, config.buttonVariant)
403
+ ]);
404
+ }
405
+ return joinRecipeClasses([
406
+ colorBgClass(config.color),
407
+ "text-white",
408
+ radiusClass(config.radius),
409
+ densityButtonPadding(config.density),
410
+ buttonHoverClass(config.color, config.buttonHover, config.buttonVariant)
411
+ ]);
412
+ case "card":
413
+ return joinRecipeClasses([
414
+ surfaceBgClass(config.surface),
415
+ ...accentBorderRecipeParts(config.color),
416
+ radiusClass(config.radius),
417
+ densityCardPadding(config.density),
418
+ cardShadowClass(config.cardShadow),
419
+ cardHoverBorderClass(config.color, config.cardHover)
420
+ ]);
421
+ case "heading":
422
+ return [typographyClasses(config.typography), colorTextClass(config.color)].join(" ").trim();
423
+ case "text":
424
+ return joinRecipeClasses(["text-sm font-normal", colorTextClass(config.color)]);
425
+ case "table":
426
+ return joinRecipeClasses([
427
+ "max-w-full",
428
+ ...accentBorderRecipeParts(config.color),
429
+ radiusClass(config.radius)
430
+ ]);
431
+ case "form":
432
+ if (isFormLabelHost(hint)) {
433
+ return "text-sm font-medium text-gray-700";
434
+ }
435
+ return joinRecipeClasses([
436
+ surfaceBgClass(config.surface),
437
+ ...accentBorderRecipeParts(config.color),
438
+ radiusClass(config.radius),
439
+ densityButtonPadding(config.density)
440
+ ]);
441
+ case "badge":
442
+ return [
443
+ "inline-flex",
444
+ "items-center",
445
+ "px-2",
446
+ "py-0.5",
447
+ "text-xs",
448
+ "font-medium",
449
+ "rounded-full",
450
+ colorBadgeBgClass(config.color),
451
+ colorBadgeTextClass(config.color)
452
+ ].join(" ").trim();
453
+ default: {
454
+ const _exhaustive = action;
455
+ return _exhaustive;
456
+ }
457
+ }
458
+ }
459
+ function buildBrandPatchOps(action, config, hint) {
460
+ return [
461
+ {
462
+ kind: "mergeTailwindClassName",
463
+ classNameFragment: buildBrandClassFragment(action, config, hint)
464
+ }
465
+ ];
466
+ }
467
+ function buildBrandPreviewSummary(action, config) {
468
+ if (action === "text") {
469
+ return `${ACTION_LABELS.text} \xB7 ${formatAccentForSummary(action, config)} \xB7 Body size`;
470
+ }
471
+ if (action === "heading") {
472
+ return [
473
+ ACTION_LABELS.heading,
474
+ formatAccentForSummary(action, config),
475
+ TYPOGRAPHY_LABELS[config.typography]
476
+ ].join(" \xB7 ");
477
+ }
478
+ if (action === "card") {
479
+ const parts = [
480
+ ACTION_LABELS.card,
481
+ SURFACE_LABELS[config.surface],
482
+ formatAccentForSummary(action, config),
483
+ RADIUS_LABELS[config.radius],
484
+ DENSITY_LABELS[config.density]
485
+ ];
486
+ if ((config.cardShadow ?? DEFAULT_BRAND_CONFIG.cardShadow) !== "none") {
487
+ parts.push(
488
+ `${CARD_SHADOW_LABELS[config.cardShadow ?? DEFAULT_BRAND_CONFIG.cardShadow]} shadow`
489
+ );
490
+ }
491
+ if ((config.cardHover ?? DEFAULT_BRAND_CONFIG.cardHover) !== "none") {
492
+ parts.push(`${CARD_HOVER_LABELS[config.cardHover ?? DEFAULT_BRAND_CONFIG.cardHover]} hover`);
493
+ }
494
+ return parts.join(" \xB7 ");
495
+ }
496
+ if (action === "table") {
497
+ return [
498
+ ACTION_LABELS.table,
499
+ formatAccentForSummary(action, config),
500
+ RADIUS_LABELS[config.radius]
501
+ ].join(" \xB7 ");
502
+ }
503
+ if (action === "form") {
504
+ return [
505
+ ACTION_LABELS.form,
506
+ formatAccentForSummary(action, config),
507
+ RADIUS_LABELS[config.radius],
508
+ DENSITY_LABELS[config.density]
509
+ ].join(" \xB7 ");
510
+ }
511
+ if (action === "badge") {
512
+ return [
513
+ ACTION_LABELS.badge,
514
+ formatAccentForSummary(action, config),
515
+ RADIUS_LABELS.pill
516
+ ].join(" \xB7 ");
517
+ }
518
+ return [
519
+ ACTION_LABELS.button,
520
+ formatAccentForSummary(action, config),
521
+ BUTTON_VARIANT_LABELS[config.buttonVariant],
522
+ RADIUS_LABELS[config.radius],
523
+ DENSITY_LABELS[config.density],
524
+ (config.buttonHover ?? DEFAULT_BRAND_CONFIG.buttonHover) !== "none" ? `${BUTTON_HOVER_LABELS[config.buttonHover ?? DEFAULT_BRAND_CONFIG.buttonHover]} hover` : null
525
+ ].filter(Boolean).join(" \xB7 ");
526
+ }
527
+ function getBrandColorLabel(color) {
528
+ return COLOR_LABELS[color];
529
+ }
530
+ function getBrandRadiusLabel(radius) {
531
+ return RADIUS_LABELS[radius];
532
+ }
533
+ function getBrandDensityLabel(density) {
534
+ return DENSITY_LABELS[density];
535
+ }
536
+ function getBrandTypographyLabel(typography) {
537
+ return TYPOGRAPHY_LABELS[typography];
538
+ }
539
+ function getBrandSurfaceLabel(surface) {
540
+ return SURFACE_LABELS[surface];
541
+ }
542
+ function getBrandButtonVariantLabel(variant) {
543
+ return BUTTON_VARIANT_LABELS[variant];
544
+ }
545
+ function getBrandButtonHoverLabel(hover) {
546
+ return BUTTON_HOVER_LABELS[hover];
547
+ }
548
+ function getBrandCardShadowLabel(shadow) {
549
+ return CARD_SHADOW_LABELS[shadow];
550
+ }
551
+ function getBrandCardHoverLabel(hover) {
552
+ return CARD_HOVER_LABELS[hover];
553
+ }
554
+
555
+ // src/brand-page-discovery.ts
556
+ var BRAND_PAGE_DISCOVERY_PLURALS = {
557
+ button: "buttons",
558
+ card: "cards",
559
+ heading: "headings",
560
+ text: "text blocks",
561
+ table: "tables",
562
+ form: "forms",
563
+ badge: "badges"
564
+ };
565
+ var BRAND_PAGE_DISCOVERY_SINGULARS = {
566
+ button: "button",
567
+ card: "card",
568
+ heading: "heading",
569
+ text: "text block",
570
+ table: "table",
571
+ form: "form",
572
+ badge: "badge"
573
+ };
574
+ function formatDiscoveryCount(action, count) {
575
+ const label = count === 1 ? BRAND_PAGE_DISCOVERY_SINGULARS[action] : BRAND_PAGE_DISCOVERY_PLURALS[action];
576
+ return `${count} ${label}`;
577
+ }
578
+ function buildBrandPageDiscoveryLine(counts) {
579
+ const parts = [];
580
+ for (const action of BRAND_APPLY_ACTIONS) {
581
+ const count = counts[action] ?? 0;
582
+ if (count > 0) {
583
+ parts.push(formatDiscoveryCount(action, count));
584
+ }
585
+ }
586
+ if (parts.length === 0) {
587
+ return null;
588
+ }
589
+ return `On this page: ${parts.join(" \xB7 ")}`;
590
+ }
591
+
592
+ // src/brand-bulk.ts
593
+ function buildBrandValidateSummary(action, config, count) {
594
+ const base = buildBrandPreviewSummary(action, config);
595
+ const noun = count === 1 ? "element" : "elements";
596
+ return `${base} \xB7 ${count} ${noun}`;
597
+ }
598
+ function buildBrandBulkPreviewSummary(action, config, count) {
599
+ return buildBrandValidateSummary(action, config, count);
600
+ }
601
+ function buildBrandBulkPatchOps(action, config) {
602
+ return buildBrandPatchOps(action, config);
603
+ }
604
+ var PATCHABLE_CLASSNAME_MODES = /* @__PURE__ */ new Set([
605
+ "literal-only",
606
+ "cn-basic",
607
+ "cn-conditional",
608
+ "classnames-static"
609
+ ]);
610
+ function isDuplicateId(id, duplicateIds) {
611
+ return duplicateIds.has(id);
612
+ }
613
+ function isStylePatchableEntry(entry, duplicateIds) {
614
+ if (isDuplicateId(entry.id, duplicateIds)) {
615
+ return false;
616
+ }
617
+ if (entry.hasLiteralClassName === false) {
618
+ return false;
619
+ }
620
+ const mode = entry.classNameMode ?? "literal-only";
621
+ if (mode === "unsupported") {
622
+ return false;
623
+ }
624
+ if (!PATCHABLE_CLASSNAME_MODES.has(mode)) {
625
+ return false;
626
+ }
627
+ if (entry.riskLevel === "unsupported" && entry.hasLiteralClassName !== true) {
628
+ return false;
629
+ }
630
+ return resolveBrandBulkPatchHostId(entry) !== null;
631
+ }
632
+ function resolveBrandBulkPatchHostId(entry) {
633
+ if (entry.patchHostId) {
634
+ return entry.patchHostId;
635
+ }
636
+ if (entry.hasLiteralClassName === true) {
637
+ return entry.id;
638
+ }
639
+ const styleTarget = entry.styleTargets?.find((t) => t.classNamePatchable);
640
+ return styleTarget?.patchHostId ?? null;
641
+ }
642
+ function entryMatchesBrandBulkAction(entry, action) {
643
+ const id = entry.id.toLowerCase();
644
+ const tag = entry.tagName?.toLowerCase() ?? "";
645
+ const role = entry.hierarchyRole;
646
+ switch (action) {
647
+ case "button":
648
+ return role === "button" || tag === "button" || id.endsWith(".button") || id.includes(".cta") || id.includes(".filter") || id.includes(".seeall");
649
+ case "card":
650
+ return role === "card" || id.endsWith(".card") || tag === "card" || tag.startsWith("card");
651
+ case "heading":
652
+ if (id.endsWith(".value")) {
653
+ return false;
654
+ }
655
+ return /^h[1-6]$/.test(tag) || id.endsWith(".title") || id.endsWith(".heading") || id.endsWith(".header") || id.includes(".title");
656
+ case "text":
657
+ if (role === "button" || role === "card") {
658
+ return false;
659
+ }
660
+ if (/^h[1-6]$/.test(tag)) {
661
+ return id.endsWith(".value");
662
+ }
663
+ return role === "text" || tag === "p" || tag === "span" && (id.endsWith(".label") || id.endsWith(".subtitle") || id.includes(".nametext")) || tag === "label" && !id.startsWith("form.") || id.endsWith(".subtitle") || id.includes(".nametext") || entry.textEditable === true && (tag === "span" || tag === "label" || tag === "div");
664
+ case "table":
665
+ return role === "table" || id.endsWith(".table") || id.includes(".header.") || /\.row\./.test(id);
666
+ case "form":
667
+ return role === "form" || role === "input" || tag === "input" || tag === "textarea" || tag === "select" || tag === "label" || id.endsWith(".input") || id.endsWith(".label");
668
+ case "badge":
669
+ return id.endsWith(".badge") || id.includes(".badge.") || tag === "span" && (id.includes("badge") || id.includes("status") || id.includes("chip"));
670
+ default: {
671
+ const _exhaustive = action;
672
+ return _exhaustive;
673
+ }
674
+ }
675
+ }
676
+ function filterBrandBulkCandidates(entries, action, knownIds, duplicateIds, options) {
677
+ const pccHosts = options?.pccHosts;
678
+ if (pccHosts && pccHosts.length > 0) {
679
+ return filterBrandBulkCandidatesFromPccHosts(
680
+ entries,
681
+ pccHosts,
682
+ knownIds,
683
+ duplicateIds
684
+ );
685
+ }
686
+ const seenHostIds = /* @__PURE__ */ new Set();
687
+ const targets = [];
688
+ for (const entry of entries) {
689
+ if (!knownIds.has(entry.id)) {
690
+ continue;
691
+ }
692
+ if (!isStylePatchableEntry(entry, duplicateIds)) {
693
+ continue;
694
+ }
695
+ if (!entryMatchesBrandBulkAction(entry, action)) {
696
+ continue;
697
+ }
698
+ const hostId = resolveBrandBulkPatchHostId(entry);
699
+ if (!hostId || !knownIds.has(hostId)) {
700
+ continue;
701
+ }
702
+ if (seenHostIds.has(hostId)) {
703
+ continue;
704
+ }
705
+ seenHostIds.add(hostId);
706
+ targets.push({
707
+ hostId,
708
+ entryId: entry.id,
709
+ label: entry.id
710
+ });
711
+ }
712
+ return targets;
713
+ }
714
+ function filterBrandBulkCandidatesFromPccHosts(entries, pccHosts, knownIds, duplicateIds) {
715
+ const byId = new Map(entries.map((entry) => [entry.id, entry]));
716
+ const seenHostIds = /* @__PURE__ */ new Set();
717
+ const targets = [];
718
+ for (const hostId of pccHosts) {
719
+ const entry = byId.get(hostId);
720
+ if (!entry || !knownIds.has(hostId)) {
721
+ continue;
722
+ }
723
+ if (!isStylePatchableEntry(entry, duplicateIds)) {
724
+ continue;
725
+ }
726
+ const patchHostId = resolveBrandBulkPatchHostId(entry);
727
+ if (!patchHostId || !knownIds.has(patchHostId)) {
728
+ continue;
729
+ }
730
+ if (seenHostIds.has(patchHostId)) {
731
+ continue;
732
+ }
733
+ seenHostIds.add(patchHostId);
734
+ targets.push({
735
+ hostId: patchHostId,
736
+ entryId: entry.id,
737
+ label: entry.id
738
+ });
739
+ }
740
+ return targets;
741
+ }
742
+ function buildBrandBulkTargetOps(action, config, targets, entries) {
743
+ const byId = entries ? new Map(entries.map((entry) => [entry.id, entry])) : null;
744
+ return targets.map((target) => {
745
+ const entry = byId?.get(target.entryId);
746
+ const hint = entry ? brandFragmentHostHint(entry) : void 0;
747
+ return {
748
+ hostId: target.hostId,
749
+ ops: buildBrandPatchOps(action, config, hint)
750
+ };
751
+ });
752
+ }
753
+
754
+ // src/brand-inspector.ts
755
+ var DIMENSION_LABELS = {
756
+ color: "Color",
757
+ radius: "Radius",
758
+ density: "Density",
759
+ typography: "Typography",
760
+ surface: "Surface",
761
+ buttonVariant: "Style"
762
+ };
763
+ function stripVariantPrefixes(token) {
764
+ let t = token;
765
+ while (t.includes(":")) {
766
+ const idx = t.indexOf(":");
767
+ t = t.slice(idx + 1);
768
+ }
769
+ return t;
770
+ }
771
+ function tokenizeClassName(className) {
772
+ return className.trim().split(/\s+/).filter(Boolean).map(stripVariantPrefixes);
773
+ }
774
+ function colorBgToken(color) {
775
+ if (color === "neutral") {
776
+ return "bg-gray-600";
777
+ }
778
+ return color === "slate" ? "bg-slate-700" : `bg-${color}-600`;
779
+ }
780
+ function colorTextToken(color) {
781
+ if (color === "neutral") {
782
+ return "text-gray-700";
783
+ }
784
+ return color === "slate" ? "text-slate-700" : `text-${color}-600`;
785
+ }
786
+ function colorBorderToken(color) {
787
+ if (color === "none") {
788
+ return null;
789
+ }
790
+ if (color === "neutral") {
791
+ return "border-gray-200";
792
+ }
793
+ return color === "slate" ? "border-slate-300" : `border-${color}-300`;
794
+ }
795
+ var RADIUS_TOKENS = {
796
+ sharp: "rounded-none",
797
+ soft: "rounded-md",
798
+ rounded: "rounded-xl",
799
+ pill: "rounded-full"
800
+ };
801
+ var BUTTON_DENSITY_TOKENS = {
802
+ compact: { px: "px-3", py: "py-1.5" },
803
+ balanced: { px: "px-4", py: "py-2" },
804
+ spacious: { px: "px-6", py: "py-3" }
805
+ };
806
+ var CARD_DENSITY_TOKENS = {
807
+ compact: "p-4",
808
+ balanced: "p-6",
809
+ spacious: "p-8"
810
+ };
811
+ var TYPOGRAPHY_TOKENS = {
812
+ clean: { size: "text-base", weight: "font-medium" },
813
+ bold: { size: "text-lg", weight: "font-semibold" },
814
+ soft: { size: "text-sm", weight: "font-normal" }
815
+ };
816
+ function colorBadgeBgToken(color) {
817
+ if (color === "neutral") {
818
+ return "bg-gray-100";
819
+ }
820
+ return color === "slate" ? "bg-slate-100" : `bg-${color}-100`;
821
+ }
822
+ function colorBadgeTextToken(color) {
823
+ if (color === "neutral") {
824
+ return "text-gray-700";
825
+ }
826
+ return color === "slate" ? "text-slate-700" : `text-${color}-700`;
827
+ }
828
+ function tokenMatchesBrandColor(token, color, prefix) {
829
+ if (color === "none") {
830
+ return false;
831
+ }
832
+ const exact = prefix === "bg-" ? [colorBgToken(color), colorBadgeBgToken(color)] : prefix === "text-" ? [colorTextToken(color), colorBadgeTextToken(color)] : [colorBorderToken(color)].filter((value) => value != null);
833
+ if (exact.includes(token)) {
834
+ return true;
835
+ }
836
+ if (!isBrandAccentColor(color)) {
837
+ return false;
838
+ }
839
+ return token.startsWith(prefix) && token.includes(`-${color}-`);
840
+ }
841
+ function detectCardBorderSlotColor(tokens) {
842
+ let last = { color: null, token: null };
843
+ for (const token of tokens) {
844
+ if (token === "border-gray-200") {
845
+ last = { color: "neutral", token };
846
+ continue;
847
+ }
848
+ if (token === "border-0" || token === "border-transparent") {
849
+ last = { color: "none", token };
850
+ continue;
851
+ }
852
+ for (const color of BRAND_COLORS) {
853
+ if (tokenMatchesBrandColor(token, color, "border-")) {
854
+ last = { color, token };
855
+ }
856
+ }
857
+ }
858
+ return last;
859
+ }
860
+ function detectBorderSlotColor(tokens) {
861
+ let last = { color: null, token: null };
862
+ let lastAccent = { color: null, token: null };
863
+ for (const token of tokens) {
864
+ if (token === "border-gray-200") {
865
+ last = { color: "neutral", token };
866
+ continue;
867
+ }
868
+ if (token === "border-0" || token === "border-transparent") {
869
+ last = { color: "none", token };
870
+ continue;
871
+ }
872
+ for (const color of BRAND_COLORS) {
873
+ if (!tokenMatchesBrandColor(token, color, "border-")) {
874
+ continue;
875
+ }
876
+ last = { color, token };
877
+ if (isBrandAccentColor(color)) {
878
+ lastAccent = { color, token };
879
+ }
880
+ }
881
+ }
882
+ if (lastAccent.color) {
883
+ return lastAccent;
884
+ }
885
+ return last;
886
+ }
887
+ function detectBrandColorForSlot(tokens, slot) {
888
+ if (slot === "border") {
889
+ return detectBorderSlotColor(tokens);
890
+ }
891
+ let result = { color: null, token: null };
892
+ for (const token of tokens) {
893
+ if (slot === "text" && token === "text-gray-700") {
894
+ result = { color: "neutral", token };
895
+ }
896
+ if (slot === "tint" && (token === "bg-gray-100" || token === "text-gray-700")) {
897
+ result = { color: "neutral", token };
898
+ }
899
+ for (const color of BRAND_COLORS) {
900
+ if (slot === "fill" && tokenMatchesBrandColor(token, color, "bg-")) {
901
+ result = { color, token };
902
+ } else if (slot === "text" && tokenMatchesBrandColor(token, color, "text-")) {
903
+ result = { color, token };
904
+ } else if (slot === "tint") {
905
+ if (tokenMatchesBrandColor(token, color, "bg-") || tokenMatchesBrandColor(token, color, "text-")) {
906
+ result = { color, token };
907
+ }
908
+ }
909
+ }
910
+ }
911
+ return result;
912
+ }
913
+ function detectBrandColorForAction(tokens, action) {
914
+ if (action === "card") {
915
+ return detectCardBorderSlotColor(tokens);
916
+ }
917
+ const slot = BRAND_ACCENT_SLOT_BY_ACTION[action];
918
+ if (!slot) {
919
+ return { color: null, token: null };
920
+ }
921
+ return detectBrandColorForSlot(tokens, slot);
922
+ }
923
+ function detectBrandColor(tokens) {
924
+ let result = { color: null, token: null };
925
+ for (const token of tokens) {
926
+ for (const color of BRAND_COLORS) {
927
+ const candidates = [colorBgToken(color), colorTextToken(color), colorBorderToken(color)].filter(
928
+ (value) => value != null
929
+ );
930
+ if (candidates.includes(token)) {
931
+ result = { color, token };
932
+ }
933
+ }
934
+ if (!token.startsWith("bg-") && !token.startsWith("text-") && !token.startsWith("border-")) {
935
+ continue;
936
+ }
937
+ for (const color of BRAND_COLORS) {
938
+ if (!isBrandAccentColor(color)) {
939
+ continue;
940
+ }
941
+ if (token.includes(`-${color}-`)) {
942
+ result = { color, token };
943
+ }
944
+ }
945
+ }
946
+ return result;
947
+ }
948
+ function detectBrandRadius(tokens) {
949
+ let result = { radius: null, token: null };
950
+ let lastRoundedToken = null;
951
+ for (const token of tokens) {
952
+ if (!token.startsWith("rounded")) {
953
+ continue;
954
+ }
955
+ lastRoundedToken = token;
956
+ for (const radius of BRAND_RADIUS) {
957
+ if (token === RADIUS_TOKENS[radius]) {
958
+ result = { radius, token };
959
+ }
960
+ }
961
+ }
962
+ if (result.radius || !lastRoundedToken) {
963
+ return result;
964
+ }
965
+ return { radius: null, token: lastRoundedToken };
966
+ }
967
+ function detectBrandDensityForAction(tokens, action) {
968
+ if (action === "card") {
969
+ let result = { density: null, token: null };
970
+ for (const density of BRAND_DENSITY) {
971
+ const cardToken = CARD_DENSITY_TOKENS[density];
972
+ if (tokens.includes(cardToken)) {
973
+ result = { density, token: cardToken };
974
+ }
975
+ }
976
+ return result;
977
+ }
978
+ if (action === "button" || action === "form") {
979
+ let result = { density: null, token: null };
980
+ for (const density of BRAND_DENSITY) {
981
+ const button = BUTTON_DENSITY_TOKENS[density];
982
+ if (tokens.includes(button.px) && tokens.includes(button.py)) {
983
+ result = { density, token: `${button.px} ${button.py}` };
984
+ }
985
+ }
986
+ return result;
987
+ }
988
+ return { density: null, token: null };
989
+ }
990
+ function detectBrandDensity(tokens) {
991
+ let result = { density: null, token: null };
992
+ for (const density of BRAND_DENSITY) {
993
+ const button = BUTTON_DENSITY_TOKENS[density];
994
+ if (tokens.includes(button.px) && tokens.includes(button.py)) {
995
+ result = { density, token: `${button.px} ${button.py}` };
996
+ }
997
+ }
998
+ for (const density of BRAND_DENSITY) {
999
+ const cardToken = CARD_DENSITY_TOKENS[density];
1000
+ if (tokens.includes(cardToken)) {
1001
+ result = { density, token: cardToken };
1002
+ }
1003
+ }
1004
+ return result;
1005
+ }
1006
+ var BRAND_SIZE_TOKENS = /* @__PURE__ */ new Set(["text-sm", "text-base", "text-lg"]);
1007
+ function detectBrandTypography(tokens) {
1008
+ const size = tokens.filter((token2) => BRAND_SIZE_TOKENS.has(token2)).at(-1) ?? null;
1009
+ const weight = tokens.filter((token2) => token2.startsWith("font-")).at(-1) ?? null;
1010
+ if (!size && !weight) {
1011
+ return { typography: null, token: null };
1012
+ }
1013
+ for (const typography of BRAND_TYPOGRAPHY) {
1014
+ const expected = TYPOGRAPHY_TOKENS[typography];
1015
+ const sizeMatch = !size || size === expected.size;
1016
+ const weightMatch = !weight || weight === expected.weight;
1017
+ if (size && weight) {
1018
+ if (size === expected.size && weight === expected.weight) {
1019
+ return { typography, token: `${expected.size} ${expected.weight}` };
1020
+ }
1021
+ continue;
1022
+ }
1023
+ if (sizeMatch && weightMatch && (size || weight)) {
1024
+ return {
1025
+ typography,
1026
+ token: [size ?? expected.size, weight ?? expected.weight].join(" ")
1027
+ };
1028
+ }
1029
+ }
1030
+ const token = [size, weight].filter(Boolean).join(" ");
1031
+ return { typography: null, token: token || null };
1032
+ }
1033
+ function radiusLabelFromToken(token) {
1034
+ if (!token) {
1035
+ return "Not set";
1036
+ }
1037
+ for (const radius of BRAND_RADIUS) {
1038
+ if (token === RADIUS_TOKENS[radius]) {
1039
+ return getBrandRadiusLabel(radius);
1040
+ }
1041
+ }
1042
+ const suffix = token.replace("rounded-", "");
1043
+ return suffix ? `Custom (${suffix})` : "Custom radius";
1044
+ }
1045
+ function densityLabelFromToken(token) {
1046
+ if (!token) {
1047
+ return "Not set";
1048
+ }
1049
+ for (const density of BRAND_DENSITY) {
1050
+ const button = BUTTON_DENSITY_TOKENS[density];
1051
+ if (token === `${button.px} ${button.py}` || token === CARD_DENSITY_TOKENS[density]) {
1052
+ return getBrandDensityLabel(density);
1053
+ }
1054
+ }
1055
+ return "Custom spacing";
1056
+ }
1057
+ function typographyLabelFromToken(token) {
1058
+ if (!token) {
1059
+ return "Not set";
1060
+ }
1061
+ for (const typography of BRAND_TYPOGRAPHY) {
1062
+ const expected = TYPOGRAPHY_TOKENS[typography];
1063
+ if (token === `${expected.size} ${expected.weight}`) {
1064
+ return getBrandTypographyLabel(typography);
1065
+ }
1066
+ }
1067
+ return "Custom typography";
1068
+ }
1069
+ function colorLabelFromDetection(color, token) {
1070
+ if (color) {
1071
+ return getBrandColorLabel(color);
1072
+ }
1073
+ if (!token) {
1074
+ return "Not set";
1075
+ }
1076
+ return "Custom color";
1077
+ }
1078
+ function buildRow(dimension, status, currentLabel, brandLabel, currentToken, expectedToken) {
1079
+ return {
1080
+ dimension,
1081
+ dimensionLabel: DIMENSION_LABELS[dimension],
1082
+ status,
1083
+ currentLabel,
1084
+ brandLabel,
1085
+ currentToken,
1086
+ expectedToken
1087
+ };
1088
+ }
1089
+ function buildHeadline(matchCount, checkedCount) {
1090
+ if (checkedCount === 0) {
1091
+ return "No brand styles detected on this element.";
1092
+ }
1093
+ if (matchCount === checkedCount) {
1094
+ return "Matches your saved brand.";
1095
+ }
1096
+ if (matchCount === 0) {
1097
+ return "This element does not match your saved brand.";
1098
+ }
1099
+ return `${matchCount} of ${checkedCount} brand traits match your saved brand.`;
1100
+ }
1101
+ var INSPECT_DIMENSIONS_BY_ACTION = {
1102
+ button: ["color", "buttonVariant", "radius", "density"],
1103
+ card: ["surface", "color", "radius", "density"],
1104
+ heading: ["color", "typography"],
1105
+ text: ["color"],
1106
+ table: ["color", "radius"],
1107
+ form: ["color", "radius", "density", "surface"],
1108
+ badge: ["color"]
1109
+ };
1110
+ function detectBrandSurface(tokens) {
1111
+ let result = { surface: null, token: null };
1112
+ if (tokens.includes("bg-slate-50")) {
1113
+ result = { surface: "muted", token: "bg-slate-50" };
1114
+ }
1115
+ if (tokens.includes("bg-white")) {
1116
+ result = { surface: "white", token: "bg-white" };
1117
+ }
1118
+ return result;
1119
+ }
1120
+ function detectBrandButtonVariant(tokens) {
1121
+ if (tokens.includes("bg-transparent")) {
1122
+ return { buttonVariant: "outline", token: "bg-transparent" };
1123
+ }
1124
+ for (const color of BRAND_COLORS) {
1125
+ if (tokens.includes(colorBgToken(color))) {
1126
+ return { buttonVariant: "solid", token: colorBgToken(color) };
1127
+ }
1128
+ }
1129
+ return { buttonVariant: null, token: null };
1130
+ }
1131
+ function inspectRecipeFragmentMatch(className, expectedFragment) {
1132
+ const expectedTokens = tokenizeClassName(expectedFragment);
1133
+ const actualTokens = tokenizeClassName(className);
1134
+ const matchCount = expectedTokens.filter((token) => actualTokens.includes(token)).length;
1135
+ const checkedCount = expectedTokens.length;
1136
+ return {
1137
+ rows: [],
1138
+ matchCount,
1139
+ checkedCount,
1140
+ headline: buildHeadline(matchCount, checkedCount)
1141
+ };
1142
+ }
1143
+ function inferBrandPresetsFromTokens(tokens, action) {
1144
+ const buttonVariantDetection = detectBrandButtonVariant([...tokens]);
1145
+ const colorDetection = action === "button" && buttonVariantDetection.buttonVariant === "outline" ? detectBrandColorForSlot([...tokens], "text") : action ? detectBrandColorForAction([...tokens], action) : detectBrandColor([...tokens]);
1146
+ const radiusDetection = detectBrandRadius([...tokens]);
1147
+ const densityDetection = action ? detectBrandDensityForAction([...tokens], action) : detectBrandDensity([...tokens]);
1148
+ const typographyDetection = detectBrandTypography([...tokens]);
1149
+ const surfaceDetection = detectBrandSurface([...tokens]);
1150
+ const dimensions = action ? new Set(INSPECT_DIMENSIONS_BY_ACTION[action]) : null;
1151
+ const patch = {};
1152
+ if (colorDetection.color && (!dimensions || dimensions.has("color"))) {
1153
+ patch.color = colorDetection.color;
1154
+ }
1155
+ if (surfaceDetection.surface && (!dimensions || dimensions.has("surface"))) {
1156
+ patch.surface = surfaceDetection.surface;
1157
+ }
1158
+ if (buttonVariantDetection.buttonVariant && (!dimensions || dimensions.has("buttonVariant"))) {
1159
+ patch.buttonVariant = buttonVariantDetection.buttonVariant;
1160
+ }
1161
+ if (radiusDetection.radius && (!dimensions || dimensions.has("radius"))) {
1162
+ patch.radius = radiusDetection.radius;
1163
+ }
1164
+ if (densityDetection.density && (!dimensions || dimensions.has("density"))) {
1165
+ patch.density = densityDetection.density;
1166
+ }
1167
+ if (typographyDetection.typography && (!dimensions || dimensions.has("typography"))) {
1168
+ patch.typography = typographyDetection.typography;
1169
+ }
1170
+ return patch;
1171
+ }
1172
+ function inferBrandPresetsFromClassName(className, action) {
1173
+ return inferBrandPresetsFromTokens(tokenizeClassName(className), action);
1174
+ }
1175
+ function inspectBrandMatchForAction(action, className, brand, hint) {
1176
+ if (action === "text") {
1177
+ return inspectRecipeFragmentMatch(className, buildBrandClassFragment("text", brand));
1178
+ }
1179
+ if (action === "form" || action === "badge") {
1180
+ return inspectRecipeFragmentMatch(className, buildBrandClassFragment(action, brand, hint));
1181
+ }
1182
+ const full = inspectBrandMatch(className, brand);
1183
+ const dimensions = new Set(INSPECT_DIMENSIONS_BY_ACTION[action]);
1184
+ const rows = full.rows.filter((row) => dimensions.has(row.dimension));
1185
+ const checkedRows = rows.filter((row) => row.status !== "not_set");
1186
+ const matchCount = checkedRows.filter((row) => row.status === "match").length;
1187
+ return {
1188
+ rows,
1189
+ matchCount,
1190
+ checkedCount: checkedRows.length,
1191
+ headline: buildHeadline(matchCount, checkedRows.length)
1192
+ };
1193
+ }
1194
+ function inspectBrandMatch(className, brand) {
1195
+ const tokens = tokenizeClassName(className);
1196
+ const colorDetection = detectBrandColor(tokens);
1197
+ const radiusDetection = detectBrandRadius(tokens);
1198
+ const densityDetection = detectBrandDensity(tokens);
1199
+ const typographyDetection = detectBrandTypography(tokens);
1200
+ const rows = [
1201
+ buildRow(
1202
+ "color",
1203
+ colorDetection.token == null ? "not_set" : colorDetection.color === brand.color ? "match" : "mismatch",
1204
+ colorLabelFromDetection(colorDetection.color, colorDetection.token),
1205
+ getBrandColorLabel(brand.color),
1206
+ colorDetection.token ?? void 0,
1207
+ colorTextToken(brand.color)
1208
+ ),
1209
+ buildRow(
1210
+ "radius",
1211
+ radiusDetection.token == null ? "not_set" : radiusDetection.radius === brand.radius ? "match" : "mismatch",
1212
+ radiusDetection.radius ? getBrandRadiusLabel(radiusDetection.radius) : radiusLabelFromToken(radiusDetection.token),
1213
+ getBrandRadiusLabel(brand.radius),
1214
+ radiusDetection.token ?? void 0,
1215
+ RADIUS_TOKENS[brand.radius]
1216
+ ),
1217
+ buildRow(
1218
+ "density",
1219
+ densityDetection.token == null ? "not_set" : densityDetection.density === brand.density ? "match" : "mismatch",
1220
+ densityDetection.density ? getBrandDensityLabel(densityDetection.density) : densityLabelFromToken(densityDetection.token),
1221
+ getBrandDensityLabel(brand.density),
1222
+ densityDetection.token ?? void 0,
1223
+ `${BUTTON_DENSITY_TOKENS[brand.density].px} ${BUTTON_DENSITY_TOKENS[brand.density].py}`
1224
+ ),
1225
+ buildRow(
1226
+ "typography",
1227
+ typographyDetection.token == null ? "not_set" : typographyDetection.typography === brand.typography ? "match" : "mismatch",
1228
+ typographyDetection.typography ? getBrandTypographyLabel(typographyDetection.typography) : typographyLabelFromToken(typographyDetection.token),
1229
+ getBrandTypographyLabel(brand.typography),
1230
+ typographyDetection.token ?? void 0,
1231
+ `${TYPOGRAPHY_TOKENS[brand.typography].size} ${TYPOGRAPHY_TOKENS[brand.typography].weight}`
1232
+ )
1233
+ ];
1234
+ const checkedRows = rows.filter((row) => row.status !== "not_set");
1235
+ const matchCount = checkedRows.filter((row) => row.status === "match").length;
1236
+ return {
1237
+ rows,
1238
+ matchCount,
1239
+ checkedCount: checkedRows.length,
1240
+ headline: buildHeadline(matchCount, checkedRows.length)
1241
+ };
1242
+ }
1243
+
1244
+ // src/brand-selection.ts
1245
+ function isNonBrandableNavEntry(entry) {
1246
+ const id = entry.id.toLowerCase();
1247
+ return id.startsWith("nav.") || id.includes(".nav.");
1248
+ }
1249
+ function resolveBrandCategoryForEntry(entry) {
1250
+ if (isNonBrandableNavEntry(entry)) {
1251
+ return null;
1252
+ }
1253
+ for (const action of BRAND_APPLY_ACTIONS) {
1254
+ if (entryMatchesBrandBulkAction(entry, action)) {
1255
+ return action;
1256
+ }
1257
+ }
1258
+ return null;
1259
+ }
1260
+ function isBrandableEntry(entry) {
1261
+ return resolveBrandCategoryForEntry(entry) !== null;
1262
+ }
1263
+
1264
+ // src/evaluate-brand-scan.ts
1265
+ function classifyHostBrandStatus(entry, brand, action) {
1266
+ if (!entry) {
1267
+ return { status: "missing", inspect: null };
1268
+ }
1269
+ const className = entry.classNameValue ?? "";
1270
+ const hint = brandFragmentHostHint(entry);
1271
+ const inspect = inspectBrandMatchForAction(action, className, brand, hint);
1272
+ if (inspect.checkedCount === 0) {
1273
+ return { status: "no_traits", inspect };
1274
+ }
1275
+ if (inspect.matchCount === inspect.checkedCount) {
1276
+ return { status: "on_brand", inspect };
1277
+ }
1278
+ return { status: "off_brand", inspect };
1279
+ }
1280
+ function evaluateBrandPageScan(manifest, entries, brandInput) {
1281
+ const brand = normalizeBrandConfig(brandInput ?? DEFAULT_BRAND_CONFIG);
1282
+ const byId = new Map(entries.map((entry) => [entry.id, entry]));
1283
+ const hosts = [];
1284
+ const categories = [];
1285
+ let onBrandCount = 0;
1286
+ let offBrandCount = 0;
1287
+ let noTraitsCount = 0;
1288
+ let missingCount = 0;
1289
+ const categoryKeys = Object.keys(manifest.categories);
1290
+ for (const category of categoryKeys) {
1291
+ if (!isPccBrandableCategory(category)) {
1292
+ continue;
1293
+ }
1294
+ const config = manifest.categories[category];
1295
+ if (!config) {
1296
+ continue;
1297
+ }
1298
+ let onBrand = 0;
1299
+ let offBrand = 0;
1300
+ let noTraits = 0;
1301
+ let missing = 0;
1302
+ for (const hostId of config.hosts) {
1303
+ const { status, inspect } = classifyHostBrandStatus(
1304
+ byId.get(hostId),
1305
+ brand,
1306
+ category
1307
+ );
1308
+ hosts.push({ hostId, category, status, inspect });
1309
+ if (status === "on_brand") {
1310
+ onBrand += 1;
1311
+ onBrandCount += 1;
1312
+ } else if (status === "off_brand") {
1313
+ offBrand += 1;
1314
+ offBrandCount += 1;
1315
+ } else if (status === "no_traits") {
1316
+ noTraits += 1;
1317
+ noTraitsCount += 1;
1318
+ } else {
1319
+ missing += 1;
1320
+ missingCount += 1;
1321
+ }
1322
+ }
1323
+ categories.push({
1324
+ category,
1325
+ expected: config.hosts.length,
1326
+ onBrand,
1327
+ offBrand,
1328
+ noTraits,
1329
+ missing,
1330
+ pass: offBrand === 0 && missing === 0
1331
+ });
1332
+ }
1333
+ return {
1334
+ page: manifest.page,
1335
+ route: manifest.route,
1336
+ brand,
1337
+ categories,
1338
+ hosts,
1339
+ onBrandCount,
1340
+ offBrandCount,
1341
+ noTraitsCount,
1342
+ missingCount,
1343
+ pass: offBrandCount === 0 && missingCount === 0
1344
+ };
1345
+ }
1346
+ function pccBrandableHostIds(manifest) {
1347
+ const hosts = [];
1348
+ for (const category of Object.keys(manifest.categories)) {
1349
+ if (!isPccBrandableCategory(category)) {
1350
+ continue;
1351
+ }
1352
+ const config = manifest.categories[category];
1353
+ if (config) {
1354
+ hosts.push(...config.hosts);
1355
+ }
1356
+ }
1357
+ return hosts;
1358
+ }
1359
+
1360
+ // src/evaluate-coverage.ts
1361
+ var PATCHABLE_CLASSNAME_MODES2 = /* @__PURE__ */ new Set([
1362
+ "literal-only",
1363
+ "cn-basic",
1364
+ "cn-conditional",
1365
+ "classnames-static"
1366
+ ]);
1367
+ function duplicateIdSet(errors) {
1368
+ return new Set(errors.map((e) => e.id));
1369
+ }
1370
+ function isHostPatchable(entry, duplicateIds) {
1371
+ if (duplicateIds.has(entry.id)) {
1372
+ return { patchable: false, reason: "duplicate_id" };
1373
+ }
1374
+ if (entry.hasLiteralClassName === false) {
1375
+ return { patchable: false, reason: "no_literal_classname" };
1376
+ }
1377
+ const mode = entry.classNameMode ?? "literal-only";
1378
+ if (mode === "unsupported") {
1379
+ return { patchable: false, reason: `classNameMode:${mode}` };
1380
+ }
1381
+ if (!PATCHABLE_CLASSNAME_MODES2.has(mode)) {
1382
+ return { patchable: false, reason: `classNameMode:${mode}` };
1383
+ }
1384
+ if (entry.riskLevel === "unsupported" && entry.hasLiteralClassName !== true) {
1385
+ return { patchable: false, reason: "risk_unsupported" };
1386
+ }
1387
+ const patchHostId = resolveBrandBulkPatchHostId(entry);
1388
+ if (!patchHostId) {
1389
+ return { patchable: false, reason: "no_patch_host" };
1390
+ }
1391
+ return { patchable: true };
1392
+ }
1393
+ function evaluatePageCoverage(manifest, entries, duplicateErrors = []) {
1394
+ const byId = new Map(entries.map((e) => [e.id, e]));
1395
+ const duplicateIds = duplicateIdSet(duplicateErrors);
1396
+ const issues = [];
1397
+ const categories = [];
1398
+ let gateIndexed = 0;
1399
+ let gatePatchable = 0;
1400
+ let gateCategorized = 0;
1401
+ let gateEditable = 0;
1402
+ let gateBrandable = 0;
1403
+ let gateExpected = 0;
1404
+ let brandableCount = 0;
1405
+ let editableOnlyCount = 0;
1406
+ const categoryKeys = Object.keys(manifest.categories);
1407
+ for (const category of categoryKeys) {
1408
+ const config = manifest.categories[category];
1409
+ if (!config) {
1410
+ continue;
1411
+ }
1412
+ let indexed = 0;
1413
+ let patchable = 0;
1414
+ let categorized = 0;
1415
+ let editable = 0;
1416
+ let brandable = 0;
1417
+ for (const hostId of config.hosts) {
1418
+ gateExpected += 1;
1419
+ const entry = byId.get(hostId);
1420
+ if (!entry) {
1421
+ issues.push({ kind: "missing", hostId, category });
1422
+ continue;
1423
+ }
1424
+ if (duplicateIds.has(hostId)) {
1425
+ issues.push({ kind: "duplicate_id", hostId, category, reason: "duplicate_id" });
1426
+ continue;
1427
+ }
1428
+ indexed += 1;
1429
+ gateIndexed += 1;
1430
+ categorized += 1;
1431
+ gateCategorized += 1;
1432
+ const patch = isHostPatchable(entry, duplicateIds);
1433
+ if (!patch.patchable) {
1434
+ issues.push({
1435
+ kind: "unpatchable",
1436
+ hostId,
1437
+ category,
1438
+ reason: patch.reason
1439
+ });
1440
+ continue;
1441
+ }
1442
+ patchable += 1;
1443
+ gatePatchable += 1;
1444
+ editable += 1;
1445
+ gateEditable += 1;
1446
+ if (isPccBrandableCategory(category)) {
1447
+ brandable += 1;
1448
+ gateBrandable += 1;
1449
+ brandableCount += 1;
1450
+ } else {
1451
+ editableOnlyCount += 1;
1452
+ }
1453
+ }
1454
+ const expected = config.hosts.length;
1455
+ const pass2 = (!config.required || expected > 0) && issues.filter((i) => i.category === category).length === 0 && indexed === expected && patchable === expected && editable === expected;
1456
+ categories.push({
1457
+ category,
1458
+ required: config.required,
1459
+ expected,
1460
+ indexed,
1461
+ patchable,
1462
+ categorized,
1463
+ editable,
1464
+ brandable,
1465
+ pass: pass2
1466
+ });
1467
+ }
1468
+ const pass = categories.every((c) => c.pass) && issues.length === 0;
1469
+ return {
1470
+ page: manifest.page,
1471
+ route: manifest.route,
1472
+ categories,
1473
+ gates: {
1474
+ expected: gateExpected,
1475
+ indexed: gateIndexed,
1476
+ patchable: gatePatchable,
1477
+ categorized: gateCategorized,
1478
+ editable: gateEditable,
1479
+ brandable: gateBrandable
1480
+ },
1481
+ issues,
1482
+ brandableCount,
1483
+ editableOnlyCount,
1484
+ pass
1485
+ };
1486
+ }
1487
+
1488
+ // src/pcc-brand-bulk.ts
1489
+ function normalizeAppRoute(route) {
1490
+ const pathOnly = route.split("?")[0]?.split("#")[0] ?? "/";
1491
+ const trimmed = pathOnly.trim() || "/";
1492
+ if (trimmed.length > 1 && trimmed.endsWith("/")) {
1493
+ return trimmed.slice(0, -1);
1494
+ }
1495
+ return trimmed;
1496
+ }
1497
+ function pccHostsForBrandAction(manifest, action) {
1498
+ if (!manifest) {
1499
+ return null;
1500
+ }
1501
+ const hosts = pccHostsForCategory(manifest, action);
1502
+ return hosts.length > 0 ? hosts : null;
1503
+ }
1504
+ function pccManifestMatchesRoute(manifest, route) {
1505
+ return normalizeAppRoute(manifest.route) === normalizeAppRoute(route);
1506
+ }
1507
+
1508
+ // src/protocol.ts
1509
+ import { z as z2 } from "zod";
6
1510
  var PROTOCOL_VERSION = 8;
7
- var riskLevelSchema = z.enum(["safe", "caution", "unsupported"]);
8
- var textTargetSchema = z.object({
1511
+ var riskLevelSchema = z2.enum(["safe", "caution", "unsupported"]);
1512
+ var textTargetSchema = z2.object({
9
1513
  /** Stable within host: `data-nuvio-id` or `loc:line:column`. */
10
- key: z.string(),
11
- label: z.string(),
12
- file: z.string(),
13
- line: z.number().int(),
14
- column: z.number().int(),
15
- tagName: z.string(),
16
- textEditable: z.boolean(),
17
- textPreview: z.string().optional(),
1514
+ key: z2.string(),
1515
+ label: z2.string(),
1516
+ file: z2.string(),
1517
+ line: z2.number().int(),
1518
+ column: z2.number().int(),
1519
+ tagName: z2.string(),
1520
+ textEditable: z2.boolean(),
1521
+ textPreview: z2.string().optional(),
18
1522
  /** Present when the text node has its own `data-nuvio-id`. */
19
- nuvioId: z.string().optional(),
1523
+ nuvioId: z2.string().optional(),
20
1524
  /** Host id used for `mergeTailwindClassName` when patching styles for this target. */
21
- patchHostId: z.string(),
22
- insideMap: z.boolean().optional()
1525
+ patchHostId: z2.string(),
1526
+ insideMap: z2.boolean().optional()
23
1527
  });
24
- var styleTargetSchema = z.object({
1528
+ var styleTargetSchema = z2.object({
25
1529
  /** Stable key within host: `data-nuvio-id` or `host` for selected container. */
26
- key: z.string(),
27
- label: z.string(),
28
- file: z.string(),
29
- line: z.number().int(),
30
- column: z.number().int(),
31
- tagName: z.string(),
32
- nuvioId: z.string(),
33
- patchHostId: z.string(),
34
- classNamePatchable: z.boolean(),
1530
+ key: z2.string(),
1531
+ label: z2.string(),
1532
+ file: z2.string(),
1533
+ line: z2.number().int(),
1534
+ column: z2.number().int(),
1535
+ tagName: z2.string(),
1536
+ nuvioId: z2.string(),
1537
+ patchHostId: z2.string(),
1538
+ classNamePatchable: z2.boolean(),
35
1539
  riskLevel: riskLevelSchema.optional()
36
1540
  });
37
- var hierarchyRoleSchema = z.enum([
1541
+ var hierarchyRoleSchema = z2.enum([
38
1542
  "section",
39
1543
  "card",
40
1544
  "table",
@@ -47,63 +1551,63 @@ var hierarchyRoleSchema = z.enum([
47
1551
  "media",
48
1552
  "unknown"
49
1553
  ]);
50
- var rowTargetSchema = z.object({
51
- rowKey: z.string(),
52
- nuvioId: z.string(),
53
- label: z.string(),
54
- file: z.string(),
55
- line: z.number().int()
1554
+ var rowTargetSchema = z2.object({
1555
+ rowKey: z2.string(),
1556
+ nuvioId: z2.string(),
1557
+ label: z2.string(),
1558
+ file: z2.string(),
1559
+ line: z2.number().int()
56
1560
  });
57
- var tableMetaSchema = z.object({
58
- dataBinding: z.string(),
59
- file: z.string(),
60
- line: z.number().int(),
61
- columns: z.array(z.string()).optional()
1561
+ var tableMetaSchema = z2.object({
1562
+ dataBinding: z2.string(),
1563
+ file: z2.string(),
1564
+ line: z2.number().int(),
1565
+ columns: z2.array(z2.string()).optional()
62
1566
  });
63
- var tableDataFieldSchema = z.object({
64
- arrayName: z.string(),
65
- rowKey: z.string(),
66
- field: z.string()
1567
+ var tableDataFieldSchema = z2.object({
1568
+ arrayName: z2.string(),
1569
+ rowKey: z2.string(),
1570
+ field: z2.string()
67
1571
  });
68
- var classNameModeSchema = z.enum([
1572
+ var classNameModeSchema = z2.enum([
69
1573
  "literal-only",
70
1574
  "cn-basic",
71
1575
  "cn-conditional",
72
1576
  "classnames-static",
73
1577
  "unsupported"
74
1578
  ]);
75
- var libraryIdSchema = z.enum(["shadcn", "tailadmin", "daisyui"]);
76
- var indexEntrySchema = z.object({
77
- id: z.string(),
78
- file: z.string(),
79
- line: z.number().int(),
80
- column: z.number().int(),
1579
+ var libraryIdSchema = z2.enum(["shadcn", "tailadmin", "daisyui"]);
1580
+ var indexEntrySchema = z2.object({
1581
+ id: z2.string(),
1582
+ file: z2.string(),
1583
+ line: z2.number().int(),
1584
+ column: z2.number().int(),
81
1585
  /** Source index v2 metadata */
82
- tagName: z.string().optional(),
83
- componentName: z.string().optional(),
84
- hasLiteralClassName: z.boolean().optional(),
85
- classNameValue: z.string().optional(),
86
- textEditable: z.boolean().optional(),
87
- structuralEditable: z.boolean().optional(),
1586
+ tagName: z2.string().optional(),
1587
+ componentName: z2.string().optional(),
1588
+ hasLiteralClassName: z2.boolean().optional(),
1589
+ classNameValue: z2.string().optional(),
1590
+ textEditable: z2.boolean().optional(),
1591
+ structuralEditable: z2.boolean().optional(),
88
1592
  riskLevel: riskLevelSchema.optional(),
89
- unsupportedReasons: z.array(z.string()).optional(),
90
- insideMap: z.boolean().optional(),
1593
+ unsupportedReasons: z2.array(z2.string()).optional(),
1594
+ insideMap: z2.boolean().optional(),
91
1595
  /** Index v3: default id for className patches on this host. */
92
- patchHostId: z.string().optional(),
1596
+ patchHostId: z2.string().optional(),
93
1597
  /** Index v3: preferred text target key in `textTargets`. */
94
- primaryTextTargetKey: z.string().optional(),
1598
+ primaryTextTargetKey: z2.string().optional(),
95
1599
  /** Index v3: descendant (and host) text edit targets. */
96
- textTargets: z.array(textTargetSchema).optional(),
1600
+ textTargets: z2.array(textTargetSchema).optional(),
97
1601
  /** Index v3: explicit style patch targets for this selected host. */
98
- styleTargets: z.array(styleTargetSchema).optional(),
1602
+ styleTargets: z2.array(styleTargetSchema).optional(),
99
1603
  /** Index v3: coarse host role, used for defaults/hints only. */
100
1604
  hierarchyRole: hierarchyRoleSchema.optional(),
101
1605
  /** Index v3: nearest ancestor host id in JSX ownership hierarchy. */
102
- parentHostId: z.string().optional(),
1606
+ parentHostId: z2.string().optional(),
103
1607
  /** Index v3: descendant host ids under this host (if any). */
104
- childTargetIds: z.array(z.string()).optional(),
1608
+ childTargetIds: z2.array(z2.string()).optional(),
105
1609
  /** Index v4: row hosts when this entry is a table section. */
106
- rowTargets: z.array(rowTargetSchema).optional(),
1610
+ rowTargets: z2.array(rowTargetSchema).optional(),
107
1611
  /** Index v4: static table data binding for Tier C. */
108
1612
  tableMeta: tableMetaSchema.optional(),
109
1613
  /** Index v4: when this host maps to a `tableData` field edit. */
@@ -113,65 +1617,65 @@ var indexEntrySchema = z.object({
113
1617
  /** Index v6: shadcn / TailAdmin / DaisyUI hint for this host. */
114
1618
  libraryHint: libraryIdSchema.optional()
115
1619
  });
116
- var runtimeDiagnosticsSchema = z.object({
117
- viteVersion: z.string().optional(),
118
- reactVersion: z.string().optional(),
119
- tailwindVersion: z.string().optional(),
120
- overlayCssMode: z.literal("self-contained").optional(),
1620
+ var runtimeDiagnosticsSchema = z2.object({
1621
+ viteVersion: z2.string().optional(),
1622
+ reactVersion: z2.string().optional(),
1623
+ tailwindVersion: z2.string().optional(),
1624
+ overlayCssMode: z2.literal("self-contained").optional(),
121
1625
  /** Project-level library detection (v0.8). */
122
- detectedLibraries: z.array(libraryIdSchema).optional()
1626
+ detectedLibraries: z2.array(libraryIdSchema).optional()
123
1627
  });
124
- var duplicateIdOccurrenceSchema = z.object({
125
- file: z.string(),
126
- line: z.number().int(),
127
- column: z.number().int()
1628
+ var duplicateIdOccurrenceSchema = z2.object({
1629
+ file: z2.string(),
1630
+ line: z2.number().int(),
1631
+ column: z2.number().int()
128
1632
  });
129
- var duplicateIdErrorSchema = z.object({
130
- id: z.string(),
131
- occurrences: z.array(duplicateIdOccurrenceSchema)
1633
+ var duplicateIdErrorSchema = z2.object({
1634
+ id: z2.string(),
1635
+ occurrences: z2.array(duplicateIdOccurrenceSchema)
132
1636
  });
133
- var clientPingSchema = z.object({
134
- type: z.literal("ping"),
135
- protocolVersion: z.number().int(),
136
- requestId: z.string().min(1)
1637
+ var clientPingSchema = z2.object({
1638
+ type: z2.literal("ping"),
1639
+ protocolVersion: z2.number().int(),
1640
+ requestId: z2.string().min(1)
137
1641
  });
138
- var clientSelectSchema = z.object({
139
- type: z.literal("select"),
140
- protocolVersion: z.number().int(),
141
- requestId: z.string().min(1),
142
- id: z.string().min(1)
1642
+ var clientSelectSchema = z2.object({
1643
+ type: z2.literal("select"),
1644
+ protocolVersion: z2.number().int(),
1645
+ requestId: z2.string().min(1),
1646
+ id: z2.string().min(1)
143
1647
  });
144
- var patchOpSetTextSchema = z.object({
145
- kind: z.literal("setText"),
146
- text: z.string()
1648
+ var patchOpSetTextSchema = z2.object({
1649
+ kind: z2.literal("setText"),
1650
+ text: z2.string()
147
1651
  });
148
- var patchOpMergeTailwindSchema = z.object({
149
- kind: z.literal("mergeTailwindClassName"),
150
- classNameFragment: z.string()
1652
+ var patchOpMergeTailwindSchema = z2.object({
1653
+ kind: z2.literal("mergeTailwindClassName"),
1654
+ classNameFragment: z2.string()
151
1655
  });
152
- var patchOpRemoveTailwindSchema = z.object({
153
- kind: z.literal("removeTailwindClassName"),
154
- classNameFragment: z.string()
1656
+ var patchOpRemoveTailwindSchema = z2.object({
1657
+ kind: z2.literal("removeTailwindClassName"),
1658
+ classNameFragment: z2.string()
155
1659
  });
156
- var patchOpMoveSiblingSchema = z.object({
157
- kind: z.literal("moveSibling"),
158
- direction: z.enum(["up", "down"])
1660
+ var patchOpMoveSiblingSchema = z2.object({
1661
+ kind: z2.literal("moveSibling"),
1662
+ direction: z2.enum(["up", "down"])
159
1663
  });
160
- var patchOpSetHiddenSchema = z.object({
161
- kind: z.literal("setHidden"),
162
- hidden: z.boolean()
1664
+ var patchOpSetHiddenSchema = z2.object({
1665
+ kind: z2.literal("setHidden"),
1666
+ hidden: z2.boolean()
163
1667
  });
164
- var patchOpDuplicateHostSchema = z.object({
165
- kind: z.literal("duplicateHost")
1668
+ var patchOpDuplicateHostSchema = z2.object({
1669
+ kind: z2.literal("duplicateHost")
166
1670
  });
167
- var patchOpSetTableDataFieldSchema = z.object({
168
- kind: z.literal("setTableDataField"),
169
- arrayName: z.string(),
170
- rowKey: z.string(),
171
- field: z.string(),
172
- value: z.string()
1671
+ var patchOpSetTableDataFieldSchema = z2.object({
1672
+ kind: z2.literal("setTableDataField"),
1673
+ arrayName: z2.string(),
1674
+ rowKey: z2.string(),
1675
+ field: z2.string(),
1676
+ value: z2.string()
173
1677
  });
174
- var patchOpSchema = z.discriminatedUnion("kind", [
1678
+ var patchOpSchema = z2.discriminatedUnion("kind", [
175
1679
  patchOpSetTextSchema,
176
1680
  patchOpMergeTailwindSchema,
177
1681
  patchOpRemoveTailwindSchema,
@@ -180,119 +1684,119 @@ var patchOpSchema = z.discriminatedUnion("kind", [
180
1684
  patchOpDuplicateHostSchema,
181
1685
  patchOpSetTableDataFieldSchema
182
1686
  ]);
183
- var breakpointSchema = z.enum(["base", "sm", "md", "lg", "xl"]);
184
- var clientPatchApplySchema = z.object({
185
- type: z.literal("patchApply"),
186
- protocolVersion: z.number().int(),
187
- requestId: z.string().min(1),
188
- id: z.string().min(1),
189
- ops: z.array(patchOpSchema).min(1),
1687
+ var breakpointSchema = z2.enum(["base", "sm", "md", "lg", "xl"]);
1688
+ var clientPatchApplySchema = z2.object({
1689
+ type: z2.literal("patchApply"),
1690
+ protocolVersion: z2.number().int(),
1691
+ requestId: z2.string().min(1),
1692
+ id: z2.string().min(1),
1693
+ ops: z2.array(patchOpSchema).min(1),
190
1694
  /** Optional responsive context for className merges. */
191
1695
  activeBreakpoint: breakpointSchema.optional(),
192
1696
  /** When true, server validates and returns `patchAck` with `diffSummary` but does not write disk or push undo. */
193
- dryRun: z.boolean().optional()
1697
+ dryRun: z2.boolean().optional()
194
1698
  });
195
- var clientPatchUndoSchema = z.object({
196
- type: z.literal("patchUndo"),
197
- protocolVersion: z.number().int(),
198
- requestId: z.string().min(1)
1699
+ var clientPatchUndoSchema = z2.object({
1700
+ type: z2.literal("patchUndo"),
1701
+ protocolVersion: z2.number().int(),
1702
+ requestId: z2.string().min(1)
199
1703
  });
200
- var clientTagElementSchema = z.object({
201
- type: z.literal("tagElement"),
202
- protocolVersion: z.number().int(),
203
- requestId: z.string().min(1),
204
- file: z.string().min(1),
205
- line: z.number().int().positive(),
206
- column: z.number().int().nonnegative(),
207
- nuvioId: z.string().min(1)
1704
+ var clientTagElementSchema = z2.object({
1705
+ type: z2.literal("tagElement"),
1706
+ protocolVersion: z2.number().int(),
1707
+ requestId: z2.string().min(1),
1708
+ file: z2.string().min(1),
1709
+ line: z2.number().int().positive(),
1710
+ column: z2.number().int().nonnegative(),
1711
+ nuvioId: z2.string().min(1)
208
1712
  });
209
- var clientMessageSchema = z.discriminatedUnion("type", [
1713
+ var clientMessageSchema = z2.discriminatedUnion("type", [
210
1714
  clientPingSchema,
211
1715
  clientSelectSchema,
212
1716
  clientPatchApplySchema,
213
1717
  clientPatchUndoSchema,
214
1718
  clientTagElementSchema
215
1719
  ]);
216
- var serverPongSchema = z.object({
217
- type: z.literal("pong"),
218
- protocolVersion: z.number().int(),
219
- requestId: z.string(),
1720
+ var serverPongSchema = z2.object({
1721
+ type: z2.literal("pong"),
1722
+ protocolVersion: z2.number().int(),
1723
+ requestId: z2.string(),
220
1724
  diagnostics: runtimeDiagnosticsSchema.optional()
221
1725
  });
222
- var serverErrorSchema = z.object({
223
- type: z.literal("error"),
224
- code: z.string(),
225
- message: z.string(),
226
- requestId: z.string().optional()
1726
+ var serverErrorSchema = z2.object({
1727
+ type: z2.literal("error"),
1728
+ code: z2.string(),
1729
+ message: z2.string(),
1730
+ requestId: z2.string().optional()
227
1731
  });
228
- var serverIndexReadySchema = z.object({
229
- type: z.literal("indexReady"),
230
- protocolVersion: z.number().int(),
231
- indexVersion: z.number().int(),
232
- entries: z.array(indexEntrySchema),
233
- duplicateErrors: z.array(duplicateIdErrorSchema),
1732
+ var serverIndexReadySchema = z2.object({
1733
+ type: z2.literal("indexReady"),
1734
+ protocolVersion: z2.number().int(),
1735
+ indexVersion: z2.number().int(),
1736
+ entries: z2.array(indexEntrySchema),
1737
+ duplicateErrors: z2.array(duplicateIdErrorSchema),
234
1738
  diagnostics: runtimeDiagnosticsSchema.optional()
235
1739
  });
236
- var serverSelectAckSchema = z.object({
237
- type: z.literal("selectAck"),
238
- protocolVersion: z.number().int(),
239
- requestId: z.string(),
240
- id: z.string(),
241
- ok: z.boolean(),
242
- file: z.string().optional(),
243
- line: z.number().int().optional(),
244
- column: z.number().int().optional(),
1740
+ var serverSelectAckSchema = z2.object({
1741
+ type: z2.literal("selectAck"),
1742
+ protocolVersion: z2.number().int(),
1743
+ requestId: z2.string(),
1744
+ id: z2.string(),
1745
+ ok: z2.boolean(),
1746
+ file: z2.string().optional(),
1747
+ line: z2.number().int().optional(),
1748
+ column: z2.number().int().optional(),
245
1749
  /** Index v3 snapshot for the selected host (also on `indexReady` entries). */
246
- patchHostId: z.string().optional(),
247
- primaryTextTargetKey: z.string().optional(),
248
- textTargets: z.array(textTargetSchema).optional(),
249
- styleTargets: z.array(styleTargetSchema).optional(),
1750
+ patchHostId: z2.string().optional(),
1751
+ primaryTextTargetKey: z2.string().optional(),
1752
+ textTargets: z2.array(textTargetSchema).optional(),
1753
+ styleTargets: z2.array(styleTargetSchema).optional(),
250
1754
  hierarchyRole: hierarchyRoleSchema.optional(),
251
- parentHostId: z.string().optional(),
252
- childTargetIds: z.array(z.string()).optional(),
253
- rowTargets: z.array(rowTargetSchema).optional(),
1755
+ parentHostId: z2.string().optional(),
1756
+ childTargetIds: z2.array(z2.string()).optional(),
1757
+ rowTargets: z2.array(rowTargetSchema).optional(),
254
1758
  tableMeta: tableMetaSchema.optional(),
255
1759
  tableDataField: tableDataFieldSchema.optional(),
256
- errorCode: z.string().optional(),
257
- errorMessage: z.string().optional()
1760
+ errorCode: z2.string().optional(),
1761
+ errorMessage: z2.string().optional()
258
1762
  });
259
- var serverPatchAckSchema = z.object({
260
- type: z.literal("patchAck"),
261
- protocolVersion: z.number().int(),
262
- requestId: z.string(),
263
- id: z.string(),
264
- ok: z.boolean(),
265
- diffSummary: z.string().optional(),
1763
+ var serverPatchAckSchema = z2.object({
1764
+ type: z2.literal("patchAck"),
1765
+ protocolVersion: z2.number().int(),
1766
+ requestId: z2.string(),
1767
+ id: z2.string(),
1768
+ ok: z2.boolean(),
1769
+ diffSummary: z2.string().optional(),
266
1770
  /** Present when this ack is for a `patchApply` with `dryRun: true`. */
267
- dryRun: z.boolean().optional(),
1771
+ dryRun: z2.boolean().optional(),
268
1772
  /** Absolute path written on successful non-dry apply (for touched-file log). */
269
- writtenFile: z.string().optional(),
1773
+ writtenFile: z2.string().optional(),
270
1774
  /** Server undo stack size after this apply (non-dry success only). */
271
- undoStackDepth: z.number().int().optional(),
272
- errorCode: z.string().optional(),
273
- errorMessage: z.string().optional()
1775
+ undoStackDepth: z2.number().int().optional(),
1776
+ errorCode: z2.string().optional(),
1777
+ errorMessage: z2.string().optional()
274
1778
  });
275
- var serverPatchUndoAckSchema = z.object({
276
- type: z.literal("patchUndoAck"),
277
- protocolVersion: z.number().int(),
278
- requestId: z.string(),
279
- ok: z.boolean(),
280
- file: z.string().optional(),
1779
+ var serverPatchUndoAckSchema = z2.object({
1780
+ type: z2.literal("patchUndoAck"),
1781
+ protocolVersion: z2.number().int(),
1782
+ requestId: z2.string(),
1783
+ ok: z2.boolean(),
1784
+ file: z2.string().optional(),
281
1785
  /** Remaining in-memory undo snapshots after this undo (success only). */
282
- undoStackDepth: z.number().int().optional(),
283
- errorCode: z.string().optional(),
284
- errorMessage: z.string().optional()
1786
+ undoStackDepth: z2.number().int().optional(),
1787
+ errorCode: z2.string().optional(),
1788
+ errorMessage: z2.string().optional()
285
1789
  });
286
- var serverTagElementAckSchema = z.object({
287
- type: z.literal("tagElementAck"),
288
- protocolVersion: z.number().int(),
289
- requestId: z.string(),
290
- ok: z.boolean(),
291
- id: z.string().optional(),
292
- errorCode: z.string().optional(),
293
- errorMessage: z.string().optional()
1790
+ var serverTagElementAckSchema = z2.object({
1791
+ type: z2.literal("tagElementAck"),
1792
+ protocolVersion: z2.number().int(),
1793
+ requestId: z2.string(),
1794
+ ok: z2.boolean(),
1795
+ id: z2.string().optional(),
1796
+ errorCode: z2.string().optional(),
1797
+ errorMessage: z2.string().optional()
294
1798
  });
295
- var serverMessageSchema = z.discriminatedUnion("type", [
1799
+ var serverMessageSchema = z2.discriminatedUnion("type", [
296
1800
  serverPongSchema,
297
1801
  serverErrorSchema,
298
1802
  serverIndexReadySchema,
@@ -506,11 +2010,51 @@ function suggestNuvioId(options) {
506
2010
  return uniqueId(base, options.existingIds);
507
2011
  }
508
2012
  export {
2013
+ BRAND_ACCENT_COLORS,
2014
+ BRAND_ACCENT_SLOT_BY_ACTION,
2015
+ BRAND_APPLY_ACTIONS,
2016
+ BRAND_BUTTON_HOVERS,
2017
+ BRAND_BUTTON_HOVER_FIELD_LABEL,
2018
+ BRAND_BUTTON_VARIANTS,
2019
+ BRAND_BUTTON_VARIANT_FIELD_LABEL,
2020
+ BRAND_CARD_HOVERS,
2021
+ BRAND_CARD_HOVER_FIELD_LABEL,
2022
+ BRAND_CARD_SHADOWS,
2023
+ BRAND_CARD_SHADOW_FIELD_LABEL,
2024
+ BRAND_COLORS,
2025
+ BRAND_DENSITY,
2026
+ BRAND_DENSITY_FIELD_LABEL,
2027
+ BRAND_PAGE_DISCOVERY_PLURALS,
2028
+ BRAND_PRESET_DIMENSIONS_BY_ACTION,
2029
+ BRAND_RADIUS,
2030
+ BRAND_RADIUS_FIELD_LABEL,
2031
+ BRAND_SURFACES,
2032
+ BRAND_SURFACE_FIELD_LABEL,
2033
+ BRAND_TYPOGRAPHY,
2034
+ DEFAULT_BRAND_CONFIG,
509
2035
  LIBRARY_IDS,
2036
+ NUVIO_BRAND_PATH,
510
2037
  NUVIO_ID_PATTERN,
2038
+ NUVIO_PCC_PATH,
511
2039
  NUVIO_WS_PATH,
2040
+ PCC_BRANDABLE_CATEGORIES,
2041
+ PCC_REJECTED_CATEGORIES,
2042
+ PCC_SUPPORTED_CATEGORIES,
512
2043
  PROTOCOL_VERSION,
2044
+ brandColorsForAction,
2045
+ brandConfigSchema,
2046
+ brandConfigsEqual,
2047
+ brandFragmentHostHint,
2048
+ brandPresetDimensionsForAction,
513
2049
  breakpointSchema,
2050
+ buildBrandBulkPatchOps,
2051
+ buildBrandBulkPreviewSummary,
2052
+ buildBrandBulkTargetOps,
2053
+ buildBrandClassFragment,
2054
+ buildBrandPageDiscoveryLine,
2055
+ buildBrandPatchOps,
2056
+ buildBrandPreviewSummary,
2057
+ buildBrandValidateSummary,
514
2058
  classNameModeSchema,
515
2059
  clientMessageSchema,
516
2060
  clientPatchApplySchema,
@@ -518,19 +2062,49 @@ export {
518
2062
  clientPingSchema,
519
2063
  clientSelectSchema,
520
2064
  clientTagElementSchema,
2065
+ defaultPccManifestPath,
521
2066
  detectShadcnComponentMode,
522
2067
  duplicateIdErrorSchema,
523
2068
  duplicateIdOccurrenceSchema,
2069
+ entryMatchesBrandBulkAction,
2070
+ evaluateBrandPageScan,
2071
+ evaluatePageCoverage,
2072
+ filterBrandBulkCandidates,
524
2073
  formatLibraryList,
2074
+ getBrandButtonHoverLabel,
2075
+ getBrandButtonVariantLabel,
2076
+ getBrandCardHoverLabel,
2077
+ getBrandCardShadowLabel,
2078
+ getBrandColorLabel,
2079
+ getBrandColorSlotLabel,
2080
+ getBrandDensityLabel,
2081
+ getBrandRadiusLabel,
2082
+ getBrandSurfaceLabel,
2083
+ getBrandTypographyFieldLabel,
2084
+ getBrandTypographyLabel,
525
2085
  hierarchyRoleSchema,
526
2086
  indexEntrySchema,
2087
+ inferBrandPresetsFromClassName,
2088
+ inferBrandPresetsFromTokens,
527
2089
  inferLibraryFromFilePath,
2090
+ inspectBrandMatch,
2091
+ inspectBrandMatchForAction,
2092
+ isBrandAccentColor,
2093
+ isBrandableEntry,
2094
+ isHostPatchable,
2095
+ isNonBrandableNavEntry,
2096
+ isPccBrandableCategory,
2097
+ isPccRejectedCategory,
2098
+ isPccSupportedCategory,
528
2099
  isShadcnCompoundTag,
529
2100
  isValidNuvioId,
530
2101
  libraryGuidanceForEntry,
531
2102
  libraryIdSchema,
532
2103
  librarySegmentForTag,
2104
+ normalizeAppRoute,
2105
+ normalizeBrandConfig,
533
2106
  parseClientMessage,
2107
+ parsePccManifest,
534
2108
  parseServerMessage,
535
2109
  patchOpDuplicateHostSchema,
536
2110
  patchOpMergeTailwindSchema,
@@ -539,10 +2113,18 @@ export {
539
2113
  patchOpSetHiddenSchema,
540
2114
  patchOpSetTableDataFieldSchema,
541
2115
  patchOpSetTextSchema,
2116
+ pccBrandableHostIds,
2117
+ pccCategoryLabel,
2118
+ pccHostsForBrandAction,
2119
+ pccHostsForCategory,
2120
+ pccManifestMatchesRoute,
2121
+ resolveBrandBulkPatchHostId,
2122
+ resolveBrandCategoryForEntry,
542
2123
  resolveEntryLibraryHint,
543
2124
  riskLevelSchema,
544
2125
  rowTargetSchema,
545
2126
  runtimeDiagnosticsSchema,
2127
+ serializeBrandConfig,
546
2128
  serializeServerMessage,
547
2129
  serverErrorSchema,
548
2130
  serverIndexReadySchema,