@cosmicdrift/kumiko-renderer-web 0.64.0 → 0.65.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.
|
|
3
|
+
"version": "0.65.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.
|
|
20
|
-
"@cosmicdrift/kumiko-headless": "0.
|
|
21
|
-
"@cosmicdrift/kumiko-renderer": "0.
|
|
19
|
+
"@cosmicdrift/kumiko-dispatcher-live": "0.65.0",
|
|
20
|
+
"@cosmicdrift/kumiko-headless": "0.65.0",
|
|
21
|
+
"@cosmicdrift/kumiko-renderer": "0.65.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",
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
// nach Timezone den Vortag.
|
|
7
7
|
|
|
8
8
|
import { describe, expect, mock, test } from "bun:test";
|
|
9
|
-
import { fireEvent,
|
|
9
|
+
import { fireEvent, screen } from "@testing-library/react";
|
|
10
10
|
import userEvent from "@testing-library/user-event";
|
|
11
11
|
import { DateInput } from "../primitives/date-input";
|
|
12
|
+
import { render } from "./test-utils";
|
|
12
13
|
|
|
13
14
|
describe("DateInput", () => {
|
|
14
15
|
test("Eingabefeld zeigt locale-numerisches Datum (de-DE)", () => {
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
// Tick (Counter-Race-Bug).
|
|
7
7
|
|
|
8
8
|
import { describe, expect, test } from "bun:test";
|
|
9
|
-
import { act, fireEvent,
|
|
9
|
+
import { act, fireEvent, screen } from "@testing-library/react";
|
|
10
10
|
import { type ReactNode, useEffect } from "react";
|
|
11
11
|
import { type ToastOptions, ToastProvider, useToast } from "../primitives/toast";
|
|
12
|
+
import { render } from "./test-utils";
|
|
12
13
|
|
|
13
14
|
// Trigger-Component die im Mount toast() aufruft. So testen wir den
|
|
14
15
|
// Hook ohne userEvent-Klick-Pfad und ohne fragile timer.
|
|
@@ -41,7 +42,7 @@ describe("ToastProvider + useToast", () => {
|
|
|
41
42
|
expect(screen.getByText("Copied")).toBeTruthy();
|
|
42
43
|
});
|
|
43
44
|
|
|
44
|
-
test("docsUrl: rendert
|
|
45
|
+
test("docsUrl: rendert Learn-more-Link (i18n-Default) mit target=_blank", () => {
|
|
45
46
|
render(
|
|
46
47
|
<ToastProvider>
|
|
47
48
|
<ToastTrigger
|
|
@@ -55,7 +56,7 @@ describe("ToastProvider + useToast", () => {
|
|
|
55
56
|
/>
|
|
56
57
|
</ToastProvider>,
|
|
57
58
|
);
|
|
58
|
-
const link = screen.getByRole("link", { name: /
|
|
59
|
+
const link = screen.getByRole("link", { name: /Learn more/i });
|
|
59
60
|
expect(link.getAttribute("href")).toBe("https://docs.kumiko.rocks/errors/stale_state");
|
|
60
61
|
expect(link.getAttribute("target")).toBe("_blank");
|
|
61
62
|
expect(link.getAttribute("rel")).toBe("noopener noreferrer");
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// Datums-Teil neben dem Uhrzeit-Input. So teilen `date` und `timestamp`
|
|
8
8
|
// dieselbe Tipp-/Navigations-UX statt zweier divergenter Primitives (#369).
|
|
9
9
|
|
|
10
|
+
import { useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
10
11
|
import { type ReactNode, useState } from "react";
|
|
11
12
|
import { cn } from "../lib/cn";
|
|
12
13
|
import { CalendarPopover } from "./calendar-popover";
|
|
@@ -47,6 +48,7 @@ export function DateField({
|
|
|
47
48
|
min,
|
|
48
49
|
max,
|
|
49
50
|
}: DateFieldProps): ReactNode {
|
|
51
|
+
const t = useTranslation();
|
|
50
52
|
const resolvedLocale = locale ?? guessLocale();
|
|
51
53
|
const selected = parseIso(value);
|
|
52
54
|
|
|
@@ -101,7 +103,7 @@ export function DateField({
|
|
|
101
103
|
{...(maxDate !== undefined && { max: maxDate })}
|
|
102
104
|
{...(disabled !== undefined && { disabled })}
|
|
103
105
|
{...(hasError !== undefined && { hasError })}
|
|
104
|
-
triggerLabel="
|
|
106
|
+
triggerLabel={t("kumiko.field.open-calendar")}
|
|
105
107
|
/>
|
|
106
108
|
</div>
|
|
107
109
|
);
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// inputValueToTimestamp kapseln die UTC↔Wall-Clock-Umrechnung (Bug-Bash-2,
|
|
11
11
|
// 2026-06-08) und sind separat getestet.
|
|
12
12
|
|
|
13
|
+
import { useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
13
14
|
import { type ReactNode, useState } from "react";
|
|
14
15
|
import { cn } from "../lib/cn";
|
|
15
16
|
import { DateField } from "./date-field";
|
|
@@ -89,6 +90,7 @@ export function TimestampInput({
|
|
|
89
90
|
min,
|
|
90
91
|
max,
|
|
91
92
|
}: TimestampInputProps): ReactNode {
|
|
93
|
+
const t = useTranslation();
|
|
92
94
|
const local = timestampToInputValue(value);
|
|
93
95
|
const isoDate = local !== "" ? local.slice(0, 10) : "";
|
|
94
96
|
// Uhrzeit ohne gesetztes Datum würde im Wire-Wert verschwinden — lokal
|
|
@@ -125,7 +127,7 @@ export function TimestampInput({
|
|
|
125
127
|
/>
|
|
126
128
|
<input
|
|
127
129
|
type="time"
|
|
128
|
-
aria-label="
|
|
130
|
+
aria-label={t("kumiko.field.time")}
|
|
129
131
|
disabled={disabled}
|
|
130
132
|
aria-invalid={hasError === true ? true : undefined}
|
|
131
133
|
value={effectiveTime}
|
package/src/primitives/toast.tsx
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// Auto-dismiss nach 5s, manuell schließbar via X-Button. Der ARIA-
|
|
8
8
|
// Live-Region-Setup kommt komplett aus Radix.
|
|
9
9
|
|
|
10
|
+
import { useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
10
11
|
import * as Primitive from "@radix-ui/react-toast";
|
|
11
12
|
import { X } from "lucide-react";
|
|
12
13
|
import {
|
|
@@ -29,7 +30,8 @@ export type ToastOptions = {
|
|
|
29
30
|
readonly variant?: ToastVariant;
|
|
30
31
|
// Self-service deep-link (z.B. KumikoError.docsUrl). Wenn gesetzt
|
|
31
32
|
// rendert der Toast einen "Mehr erfahren →" Link der in neuem Tab
|
|
32
|
-
// öffnet. Label override via `docsLinkLabel` (Default:
|
|
33
|
+
// öffnet. Label override via `docsLinkLabel` (Default: i18n
|
|
34
|
+
// kumiko.toast.learn-more).
|
|
33
35
|
readonly docsUrl?: string;
|
|
34
36
|
readonly docsLinkLabel?: string;
|
|
35
37
|
};
|
|
@@ -116,6 +118,8 @@ function ToastItem({
|
|
|
116
118
|
readonly entry: ToastEntry;
|
|
117
119
|
readonly onClose: () => void;
|
|
118
120
|
}): ReactNode {
|
|
121
|
+
const t = useTranslation();
|
|
122
|
+
const learnMore = entry.docsLinkLabel ?? t("kumiko.toast.learn-more");
|
|
119
123
|
const variantClass =
|
|
120
124
|
entry.variant === "destructive"
|
|
121
125
|
? "destructive group border-destructive bg-destructive text-destructive-foreground"
|
|
@@ -135,7 +139,7 @@ function ToastItem({
|
|
|
135
139
|
</Primitive.Description>
|
|
136
140
|
)}
|
|
137
141
|
{entry.docsUrl !== undefined && (
|
|
138
|
-
<Primitive.Action altText={
|
|
142
|
+
<Primitive.Action altText={learnMore} asChild>
|
|
139
143
|
<a
|
|
140
144
|
href={entry.docsUrl}
|
|
141
145
|
target="_blank"
|
|
@@ -145,7 +149,7 @@ function ToastItem({
|
|
|
145
149
|
"focus:outline-none focus:ring-1 focus:ring-current rounded",
|
|
146
150
|
)}
|
|
147
151
|
>
|
|
148
|
-
{
|
|
152
|
+
{learnMore} →
|
|
149
153
|
</a>
|
|
150
154
|
</Primitive.Action>
|
|
151
155
|
)}
|
|
@@ -157,7 +161,7 @@ function ToastItem({
|
|
|
157
161
|
"group-hover:opacity-100",
|
|
158
162
|
"group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50",
|
|
159
163
|
)}
|
|
160
|
-
aria-label="
|
|
164
|
+
aria-label={t("kumiko.dialog.close")}
|
|
161
165
|
>
|
|
162
166
|
<X className="h-4 w-4" />
|
|
163
167
|
</Primitive.Close>
|