@cosmicdrift/kumiko-renderer-web 0.131.0 → 0.133.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer-web",
3
- "version": "0.131.0",
3
+ "version": "0.133.0",
4
4
  "description": "Web-platform bindings for @cosmicdrift/kumiko-renderer. HTML default-primitives, browser history-based navigation, EventSource-backed live events, and a one-call createKumikoApp that mounts the whole stack via react-dom.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -16,9 +16,9 @@
16
16
  "./styles.css": "./src/styles.css"
17
17
  },
18
18
  "dependencies": {
19
- "@cosmicdrift/kumiko-dispatcher-live": "0.131.0",
20
- "@cosmicdrift/kumiko-headless": "0.131.0",
21
- "@cosmicdrift/kumiko-renderer": "0.131.0",
19
+ "@cosmicdrift/kumiko-dispatcher-live": "0.133.0",
20
+ "@cosmicdrift/kumiko-headless": "0.133.0",
21
+ "@cosmicdrift/kumiko-renderer": "0.133.0",
22
22
  "@radix-ui/react-dialog": "^1.1.15",
23
23
  "@radix-ui/react-dropdown-menu": "^2.1.16",
24
24
  "@radix-ui/react-label": "^2.1.8",
@@ -1,9 +1,9 @@
1
1
  //
2
2
  // ToastProvider + useToast pinnt: toast() rendert Title+Description in
3
- // einem Radix-Toast; mehrere toasts stapeln; Variant=destructive setzt
4
- // die destructive-Klasse; useToast außerhalb des Providers ist no-op
5
- // (kein crash); IDs sind kollisionsfrei auch bei zwei Calls im selben
6
- // Tick (Counter-Race-Bug).
3
+ // einem Radix-Toast; mehrere toasts stapeln; Variant=bad setzt die
4
+ // StatusTone-Klasse; useToast außerhalb des Providers ist no-op (kein
5
+ // crash); IDs sind kollisionsfrei auch bei zwei Calls im selben Tick
6
+ // (Counter-Race-Bug).
7
7
 
8
8
  import { describe, expect, test } from "bun:test";
9
9
  import { act, fireEvent, screen } from "@testing-library/react";
@@ -49,7 +49,7 @@ describe("ToastProvider + useToast", () => {
49
49
  options={[
50
50
  {
51
51
  title: "Konflikt",
52
- variant: "destructive",
52
+ variant: "bad",
53
53
  docsUrl: "https://docs.kumiko.rocks/errors/stale_state",
54
54
  },
55
55
  ]}
@@ -88,18 +88,18 @@ describe("ToastProvider + useToast", () => {
88
88
  expect(screen.queryByRole("link")).toBeNull();
89
89
  });
90
90
 
91
- test("variant=destructive: setzt die destructive-Klasse auf den Root", () => {
91
+ test("variant=bad: setzt die status-bad StatusTone-Klasse auf den Root", () => {
92
92
  render(
93
93
  <ToastProvider>
94
- <ToastTrigger options={[{ title: "Failed", variant: "destructive" }]} />
94
+ <ToastTrigger options={[{ title: "Failed", variant: "bad" }]} />
95
95
  </ToastProvider>,
96
96
  );
97
97
  // Class-Mapping ist der Public-Vertrag mit Tailwind-Tokens. Wir
98
98
  // suchen den nearest Ancestor des Title-Knotens dessen Klassen-
99
- // String "destructive" enthält — Radix-Toast.Root rendert in einem
99
+ // String "status-bad" enthält — Radix-Toast.Root rendert in einem
100
100
  // <li>, aber die genaue Role wechselt je nach priority/type.
101
101
  let node: HTMLElement | null = screen.getByText("Failed");
102
- while (node !== null && !node.className.includes("destructive")) {
102
+ while (node !== null && !node.className.includes("status-bad")) {
103
103
  node = node.parentElement;
104
104
  }
105
105
  expect(node).not.toBeNull();
@@ -778,7 +778,7 @@ function useRowActionTrigger(row: ListRowViewModel) {
778
778
  toast({
779
779
  title: t("kumiko.rowAction.failed"),
780
780
  description: e instanceof Error ? e.message : String(e),
781
- variant: "destructive",
781
+ variant: "bad",
782
782
  ...(docsUrl !== undefined && { docsUrl }),
783
783
  });
784
784
  } finally {
@@ -3,9 +3,9 @@
3
3
  // kann. Kein Context-Boilerplate für Konsumenten — der Hook returned
4
4
  // einen `toast()`-Trigger, mehr Public-API gibt's nicht.
5
5
  //
6
- // Variants: "default" (neutral) und "destructive" (Fehler-Akzent).
7
- // Auto-dismiss nach 5s, manuell schließbar via X-Button. Der ARIA-
8
- // Live-Region-Setup kommt komplett aus Radix.
6
+ // Variant = StatusTone (dieselbe Farb-Familie wie StatusBadge), Default
7
+ // "muted" (neutral). Auto-dismiss nach 5s, manuell schließbar via X-Button.
8
+ // Der ARIA-Live-Region-Setup kommt komplett aus Radix.
9
9
 
10
10
  import { useTranslation } from "@cosmicdrift/kumiko-renderer";
11
11
  import * as Primitive from "@radix-ui/react-toast";
@@ -21,8 +21,9 @@ import {
21
21
  useState,
22
22
  } from "react";
23
23
  import { cn } from "../lib/cn";
24
+ import type { StatusTone } from "../widgets/status-badge";
24
25
 
25
- export type ToastVariant = "default" | "destructive";
26
+ export type ToastVariant = StatusTone;
26
27
 
27
28
  export type ToastOptions = {
28
29
  readonly title: string;
@@ -111,6 +112,14 @@ const rootClass =
111
112
  "data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full " +
112
113
  "data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full";
113
114
 
115
+ const TONE_CLASS: Record<StatusTone, string> = {
116
+ ok: "border-status-ok/30 bg-status-ok/10 text-status-ok",
117
+ warn: "border-status-warn/30 bg-status-warn/10 text-status-warn",
118
+ bad: "border-status-bad/30 bg-status-bad/10 text-status-bad",
119
+ critical: "border-status-critical/40 bg-status-critical/15 text-status-critical",
120
+ muted: "border bg-background text-foreground",
121
+ };
122
+
114
123
  function ToastItem({
115
124
  entry,
116
125
  onClose,
@@ -120,10 +129,7 @@ function ToastItem({
120
129
  }): ReactNode {
121
130
  const t = useTranslation();
122
131
  const learnMore = entry.docsLinkLabel ?? t("kumiko.toast.learn-more");
123
- const variantClass =
124
- entry.variant === "destructive"
125
- ? "destructive group border-destructive bg-destructive text-destructive-foreground"
126
- : "border bg-background text-foreground";
132
+ const variantClass = TONE_CLASS[entry.variant ?? "muted"];
127
133
  return (
128
134
  <Primitive.Root
129
135
  className={cn(rootClass, variantClass)}
@@ -159,7 +165,6 @@ function ToastItem({
159
165
  "absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity",
160
166
  "hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1",
161
167
  "group-hover:opacity-100",
162
- "group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50",
163
168
  )}
164
169
  aria-label={t("kumiko.dialog.close")}
165
170
  >