@trading-game/design-intelligence-layer 0.16.0 → 0.16.1

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/README.md CHANGED
@@ -98,10 +98,11 @@ npm install react react-dom tailwindcss
98
98
  | Component | Import |
99
99
  |---|---|
100
100
  | Accordion | `Accordion, AccordionItem, AccordionTrigger, AccordionContent` |
101
- | Alert | `Alert` — dismissible in-page notification. Variants: `default`, `brand`, `info`, `warning`, `danger`, `success`. Layouts: `inline`, `card`. Slots: `title`, `description`, `icon`, `action`, `actions`, `onDismiss`. |
101
+ | Alert | `Alert` — dismissible status notification. Variants: `info`, `warning`, `danger`, `success`. Layouts: `inline`, `card`. Slots: `title`, `description`, `icon`, `action`, `actions`, `onDismiss`. |
102
102
  | Alert Dialog | `AlertDialog, AlertDialogTrigger, AlertDialogContent, ...` |
103
103
  | Avatar | `Avatar, AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup` |
104
104
  | Badge | `Badge, badgeVariants` |
105
+ | Banner | `Banner` — dismissible promotional surface. Single visual treatment (light-blue diagonal gradient). Layouts: `inline`, `card`. Slots: `title`, `description`, `icon`, `action`, `actions`, `onDismiss`, `onClick` (whole-banner clickable). |
105
106
  | Breadcrumb | `Breadcrumb, BreadcrumbList, BreadcrumbItem, ...` |
106
107
  | Button | `Button, buttonVariants` |
107
108
  | Calendar | `Calendar, CalendarDayButton` |
@@ -232,8 +233,9 @@ States: hover (`bg-secondary-hover`), focus (3px `ring-ring/50`), active (`opaci
232
233
  <Badge variant="fill" /> // Blue tint
233
234
  <Badge variant="fill-success" /> // Green tint
234
235
  <Badge variant="fill-fail" /> // Red tint
235
- <Badge variant="fill-warning" /> // Orange tint
236
- <Badge variant="fill-credit" /> // Amber-orange tint — credit/bonus labels
236
+ <Badge variant="fill-warning" /> // Yellow tint — status/warning
237
+ <Badge variant="fill-credit" /> // Light peach — credit/bonus labels
238
+ <Badge variant="fill-demo" /> // Red-orange tint — demo/test-mode flags
237
239
 
238
240
  // Outline (black border, secondary-hover on hover)
239
241
  <Badge variant="outline" />
@@ -251,12 +253,10 @@ States: hover (`bg-secondary-hover`), focus (3px `ring-ring/50`), active (`opaci
251
253
 
252
254
  ## Alert variants
253
255
 
254
- Dismissible, in-page notification surface. Six variants × two layouts × optional title / description / icon / action / dismiss slots.
256
+ Dismissible **status** notification (info / warning / danger / success). For promotional / marketing surfaces, use **Banner** instead.
255
257
 
256
258
  ```tsx
257
259
  // Variant — controls the surface tint and icon accent
258
- <Alert variant="default" /> // white surface + subtle border (neutral)
259
- <Alert variant="brand" /> // solid brand-blue surface, white text
260
260
  <Alert variant="info" /> // sky-blue tint
261
261
  <Alert variant="warning" /> // yellow tint
262
262
  <Alert variant="danger" /> // red tint
@@ -290,9 +290,55 @@ Dismissible, in-page notification surface. Six variants × two layouts × option
290
290
 
291
291
  **Behaviour:**
292
292
  - Dismissal is **controlled** — clicking the close X calls `onDismiss`; the parent owns visibility.
293
- - Brand variant's buttons use `Button variant="primary-inverse"`; every other variant's buttons use `Button variant="secondary"`. Pass a fully-styled `<Button>` to `action` / `actions` to override.
293
+ - All variants' buttons default to `Button variant="secondary"`. Pass a fully-styled `<Button>` to `action` / `actions` to override.
294
294
  - Inline + single-line content (only title OR only description) renders at a fixed 48px height with everything vertically centered. Inline + multi-line and card layouts grow to fit.
295
- - `role="alert"` + `aria-live="assertive"` for `danger` / `warning`; `role="status"` + `aria-live="polite"` for the rest.
295
+ - `role="alert"` + `aria-live="assertive"` for `danger` / `warning`; `role="status"` + `aria-live="polite"` for `info` / `success`.
296
+
297
+ ## Banner
298
+
299
+ Dismissible **promotional / marketing** surface — for feature launches, offers, onboarding nudges, cross-promo. Single visual treatment (no severity variants); for status messages use **Alert** instead.
300
+
301
+ ```tsx
302
+ // Layout — controls the shape
303
+ <Banner layout="inline" /> // single row: icon · body · optional action · close X (default)
304
+ <Banner layout="card" /> // body on row 1, up to 2 action buttons on row 2 bottom-left
305
+
306
+ // Slots — all optional (at least one of title or description is required)
307
+ <Banner
308
+ layout="inline"
309
+ title={<>Spring release <b>is here.</b></>} // wrap emphasis in <b> for brand-blue accent
310
+ description="New features just landed — take a look at what's changed."
311
+ icon={<MyIcon />} // omit to use the default 40px brand-blue gift badge
312
+ action="Get started" // string wrapped in Button variant="primary"
313
+ onDismiss={() => setOpen(false)} // when provided, close X is rendered
314
+ dismissLabel="Dismiss" // aria-label for the close X
315
+ />
316
+
317
+ <Banner
318
+ layout="card"
319
+ title="..."
320
+ description="..."
321
+ actions={["Learn more", "Get started"]} // first = Secondary, second = Primary
322
+ onDismiss={() => setOpen(false)}
323
+ />
324
+
325
+ // Whole-banner clickable — the surface itself is the CTA.
326
+ // Mutually exclusive with action / actions (buttons dropped, dev warning).
327
+ <Banner
328
+ layout="inline"
329
+ title="Tap anywhere on this banner"
330
+ description="Whole surface is the click target."
331
+ onClick={() => navigate("/promo")}
332
+ onDismiss={() => setOpen(false)} // close X still works independently
333
+ />
334
+ ```
335
+
336
+ **Visual:**
337
+ - Surface: 135° diagonal gradient `#EBEBFF → #FFFFFF` with `border-primary/20` light-blue edge.
338
+ - Default icon: 40px brand-blue circle with a white `Gift` glyph. Override via `icon` (pass any `ReactNode`) or `icon={null}` to omit.
339
+ - Default action button: `Button variant="primary"` (single inline action) or `[Secondary, Primary]` pair (card actions). Pass `<Button>` elements explicitly to override variant/size.
340
+ - Title supports `<b>` children styled with `text-primary` for in-line brand-blue accent.
341
+ - Close X (32px) hovers to `bg-secondary-hover`.
296
342
 
297
343
  ## Component behaviour notes
298
344
 
package/dist/index.cjs CHANGED
@@ -606,8 +606,6 @@ var alertVariants = (0, import_class_variance_authority2.cva)(
606
606
  {
607
607
  variants: {
608
608
  variant: {
609
- default: "bg-prominent border border-border-subtle",
610
- brand: "bg-primary",
611
609
  info: "bg-semantic-info/10",
612
610
  warning: "bg-semantic-warning/10",
613
611
  danger: "bg-semantic-error/10",
@@ -629,32 +627,24 @@ var alertVariants = (0, import_class_variance_authority2.cva)(
629
627
  );
630
628
  var SINGLE_LINE_CLASSES = "items-center min-h-12 py-2 gap-y-0";
631
629
  var TITLE_CLASSES = {
632
- default: "text-on-prominent",
633
- brand: "text-on-primary",
634
630
  info: "text-on-prominent",
635
631
  warning: "text-on-prominent",
636
632
  danger: "text-on-prominent",
637
633
  success: "text-on-prominent"
638
634
  };
639
635
  var ICON_CLASSES = {
640
- default: "text-on-prominent",
641
- brand: "text-on-primary",
642
636
  info: "text-semantic-info",
643
637
  warning: "text-semantic-warning",
644
638
  danger: "text-semantic-error",
645
639
  success: "text-semantic-win"
646
640
  };
647
641
  var DESC_CLASSES = {
648
- default: "text-on-subtle",
649
- brand: "text-on-primary opacity-80",
650
642
  info: "text-on-subtle",
651
643
  warning: "text-on-subtle",
652
644
  danger: "text-on-subtle",
653
645
  success: "text-on-subtle"
654
646
  };
655
647
  var CLOSE_CLASSES = {
656
- default: "text-on-subtle opacity-70",
657
- brand: "text-on-primary opacity-70",
658
648
  info: "text-on-subtle opacity-70",
659
649
  warning: "text-on-subtle opacity-70",
660
650
  danger: "text-on-subtle opacity-70",
@@ -662,10 +652,6 @@ var CLOSE_CLASSES = {
662
652
  };
663
653
  function defaultIconForVariant(variant) {
664
654
  switch (variant) {
665
- case "default":
666
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Info, {});
667
- case "brand":
668
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Sparkles, {});
669
655
  case "info":
670
656
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Info, {});
671
657
  case "warning":
@@ -676,9 +662,6 @@ function defaultIconForVariant(variant) {
676
662
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.CheckCircle2, {});
677
663
  }
678
664
  }
679
- function actionButtonVariantFor(variant) {
680
- return variant === "brand" ? "primary-inverse" : "secondary";
681
- }
682
665
  function Alert(_a) {
683
666
  var _b = _a, {
684
667
  variant = "info",
@@ -716,7 +699,7 @@ function Alert(_a) {
716
699
  const showIcon = icon !== null;
717
700
  const resolvedIcon = icon === void 0 ? defaultIconForVariant(variant) : icon;
718
701
  const showCloseButton = typeof onDismiss === "function";
719
- const buttonVariant = actionButtonVariantFor(variant);
702
+ const buttonVariant = "secondary";
720
703
  const isAssertive = variant === "danger" || variant === "warning";
721
704
  const role = isAssertive ? "alert" : "status";
722
705
  const ariaLive = isAssertive ? "assertive" : "polite";
@@ -778,9 +761,10 @@ function Alert(_a) {
778
761
  "aria-hidden": true,
779
762
  className: cn(
780
763
  "inline-flex shrink-0 size-4 [&_svg]:size-full",
781
- // 2px nudge (mt-0.5) aligns the 16px icon with the title cap-height
782
- // in multi-line / card layouts. This is the one exception to the
783
- // 8-point grid — required for optical typography alignment.
764
+ // Single-line: grid is items-center so the icon centers automatically.
765
+ // Multi-line / card: top-aligned with the title cap-height via a 2px
766
+ // (mt-0.5) optical nudge so the icon reads as introducing the message
767
+ // header, not floating between title and description.
784
768
  isSingleLine ? "" : "mt-0.5",
785
769
  ICON_CLASSES[variant]
786
770
  ),
@@ -1142,6 +1126,10 @@ var badgeVariants = (0, import_class_variance_authority3.cva)(
1142
1126
  "fill-fail": "bg-semantic-loss/10 border-transparent text-semantic-loss",
1143
1127
  "fill-warning": "bg-semantic-warning/10 border-transparent text-semantic-warning",
1144
1128
  "fill-credit": "bg-semantic-boost-surface border-transparent text-on-semantic-boost !text-xs !font-semibold",
1129
+ // Demo / test-mode flag — opaque light-peach surface + red-orange text.
1130
+ // Uses --semantic-demo-surface (a solid color-mix of demo @ 10% with white)
1131
+ // so the badge looks identical on any background.
1132
+ "fill-demo": "bg-semantic-demo-surface border-transparent text-semantic-demo",
1145
1133
  // Ghost (transparent)
1146
1134
  ghost: "bg-transparent border-transparent text-primary [a&]:hover:bg-secondary-hover [a&]:hover:text-primary",
1147
1135
  "ghost-success": "bg-transparent border-transparent text-semantic-win [a&]:hover:bg-semantic-win/10 [a&]:hover:text-semantic-win",
@@ -7255,7 +7243,7 @@ function HeaderNavigationBlock({
7255
7243
  actions
7256
7244
  }) {
7257
7245
  var _a;
7258
- return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "w-full min-w-80 max-w-layout-diagram-small border border-border-subtle rounded-md overflow-hidden bg-prominent", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("header", { className: "flex items-center gap-2 border-b border-border-subtle bg-prominent px-layout-margin-inline py-3", children: [
7246
+ return /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { className: "w-full min-w-80 max-w-layout-diagram-small rounded-md overflow-hidden bg-prominent", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("header", { className: "flex items-center gap-2 border-b border-border-subtle bg-prominent px-layout-margin-inline py-3", children: [
7259
7247
  onBack && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(NavigationButton, { type: "button", size: "md", "aria-label": "Back", onClick: onBack, children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(import_lucide_react25.ArrowLeft, { className: "size-5" }) }),
7260
7248
  /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("div", { className: "flex min-w-0 flex-1 items-center justify-center gap-2", children: [
7261
7249
  badge && /* @__PURE__ */ (0, import_jsx_runtime61.jsx)(Badge, { variant: (_a = badge.variant) != null ? _a : "fill-warning", size: "sm", children: badge.label }),