@cosmicdrift/kumiko-renderer-web 0.213.0 → 0.215.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.215.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.215.0",
|
|
20
|
+
"@cosmicdrift/kumiko-headless": "0.215.0",
|
|
21
|
+
"@cosmicdrift/kumiko-renderer": "0.215.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",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"@types/react-dom": "^19.2.3",
|
|
65
65
|
"jsdom": "^29.1.1",
|
|
66
66
|
"tailwindcss": "^4.3.0",
|
|
67
|
-
"@cosmicdrift/kumiko-locale-de": "0.
|
|
67
|
+
"@cosmicdrift/kumiko-locale-de": "0.215.0"
|
|
68
68
|
},
|
|
69
69
|
"repository": {
|
|
70
70
|
"type": "git",
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// fw#2315: a list column with `renderer: { format: "enumOption", keyPrefix }`
|
|
2
|
+
// must resolve the raw enum value through useTranslation() in DataTableCell.
|
|
3
|
+
// Exercises the SAME synthesized-entity/pass-through-columns shape that
|
|
4
|
+
// ProjectionListBody (projection-list-shim.ts) and RelatedListSection
|
|
5
|
+
// (related-list-section.tsx) build for `projectionList`- and `relatedList`-
|
|
6
|
+
// screens — both delegate straight to RenderList with `columns` passed 1:1,
|
|
7
|
+
// so this proxies the real projectionList/relatedList render path without
|
|
8
|
+
// standing up a full query/dispatcher stack.
|
|
9
|
+
//
|
|
10
|
+
// DoD-Test: rendering the SAME column under two locales must produce two
|
|
11
|
+
// DIFFERENT cell labels — not just prove the format key exists.
|
|
12
|
+
|
|
13
|
+
import { describe, expect, test } from "bun:test";
|
|
14
|
+
import type {
|
|
15
|
+
EntityDefinition,
|
|
16
|
+
EntityListScreenDefinition,
|
|
17
|
+
} from "@cosmicdrift/kumiko-framework/ui-types";
|
|
18
|
+
import {
|
|
19
|
+
createStaticLocaleResolver,
|
|
20
|
+
type LiveEventSubscriber,
|
|
21
|
+
LiveEventsProvider,
|
|
22
|
+
LocaleProvider,
|
|
23
|
+
type NavApi,
|
|
24
|
+
NavProvider,
|
|
25
|
+
PrimitivesProvider,
|
|
26
|
+
RenderList,
|
|
27
|
+
TokensProvider,
|
|
28
|
+
type TranslationsByLocale,
|
|
29
|
+
} from "@cosmicdrift/kumiko-renderer";
|
|
30
|
+
import { cleanup, render } from "@testing-library/react";
|
|
31
|
+
import type { ReactElement, ReactNode } from "react";
|
|
32
|
+
import { defaultPrimitives } from "../primitives";
|
|
33
|
+
import { defaultTokens } from "../tokens";
|
|
34
|
+
|
|
35
|
+
const stubNav: NavApi = {
|
|
36
|
+
route: undefined,
|
|
37
|
+
navigate: () => {},
|
|
38
|
+
replace: () => {},
|
|
39
|
+
hrefFor: () => "",
|
|
40
|
+
searchParams: {},
|
|
41
|
+
setSearchParams: () => {},
|
|
42
|
+
};
|
|
43
|
+
const stubLiveEvents: LiveEventSubscriber = () => () => {};
|
|
44
|
+
const stubTokens = {
|
|
45
|
+
tokens: defaultTokens,
|
|
46
|
+
mode: "dark" as const,
|
|
47
|
+
setMode: () => {},
|
|
48
|
+
toggleMode: () => {},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Same all-text synthesized entity shape as projection-list-shim.ts'
|
|
52
|
+
// synthesizeProjectionEntity / related-list-section.tsx's
|
|
53
|
+
// synthesizeRelatedListEntity — a projectionList/relatedList column has no
|
|
54
|
+
// real EntityDefinition, only a text-typed pseudo-field per column.
|
|
55
|
+
const statusColumnEntity = {
|
|
56
|
+
fields: { status: { type: "text" } },
|
|
57
|
+
} as unknown as EntityDefinition;
|
|
58
|
+
|
|
59
|
+
const STATUS_KEY_PREFIX = "contact:entity:contact:field:status:option:";
|
|
60
|
+
|
|
61
|
+
const STATUS_BUNDLES: TranslationsByLocale = {
|
|
62
|
+
de: { [`${STATUS_KEY_PREFIX}active`]: "Aktiv" },
|
|
63
|
+
en: { [`${STATUS_KEY_PREFIX}active`]: "Active" },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const statusScreen: EntityListScreenDefinition = {
|
|
67
|
+
id: "",
|
|
68
|
+
type: "entityList",
|
|
69
|
+
entity: "__projection__",
|
|
70
|
+
columns: [{ field: "status", renderer: { format: "enumOption", keyPrefix: STATUS_KEY_PREFIX } }],
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Explicit cleanup() before each render — two renders happen inside a single
|
|
74
|
+
// test to prove the locale-switch, and RTL's auto-cleanup only fires between
|
|
75
|
+
// `test()` blocks, not within one.
|
|
76
|
+
function renderStatusListUnderLocale(locale: string, statusValue: string): string | null {
|
|
77
|
+
cleanup();
|
|
78
|
+
function Wrapper({ children }: { readonly children: ReactNode }): ReactElement {
|
|
79
|
+
return (
|
|
80
|
+
<TokensProvider value={stubTokens}>
|
|
81
|
+
<LocaleProvider
|
|
82
|
+
resolver={createStaticLocaleResolver({ locale })}
|
|
83
|
+
fallbackBundles={[STATUS_BUNDLES]}
|
|
84
|
+
>
|
|
85
|
+
<PrimitivesProvider value={defaultPrimitives}>
|
|
86
|
+
<NavProvider value={stubNav}>
|
|
87
|
+
<LiveEventsProvider value={stubLiveEvents}>{children}</LiveEventsProvider>
|
|
88
|
+
</NavProvider>
|
|
89
|
+
</PrimitivesProvider>
|
|
90
|
+
</LocaleProvider>
|
|
91
|
+
</TokensProvider>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
const result = render(
|
|
95
|
+
<RenderList
|
|
96
|
+
screen={statusScreen}
|
|
97
|
+
entity={statusColumnEntity}
|
|
98
|
+
rows={[{ id: "r1", status: statusValue }]}
|
|
99
|
+
featureName="contact"
|
|
100
|
+
/>,
|
|
101
|
+
{ wrapper: Wrapper },
|
|
102
|
+
);
|
|
103
|
+
return result.getByTestId("cell-r1-status").textContent;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
describe("RenderList — enumOption-FormatSpec auf projectionList/relatedList-Spalten (fw#2315)", () => {
|
|
107
|
+
test("dieselbe Spalte unter zwei Locales rendert zwei verschiedene Beschriftungen", () => {
|
|
108
|
+
expect(renderStatusListUnderLocale("de", "active")).toBe("Aktiv");
|
|
109
|
+
expect(renderStatusListUnderLocale("en", "active")).toBe("Active");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("unbekannter Options-Key fällt auf den Rohwert zurück", () => {
|
|
113
|
+
expect(renderStatusListUnderLocale("de", "archived")).toBe("archived");
|
|
114
|
+
});
|
|
115
|
+
});
|
package/src/primitives/index.tsx
CHANGED
|
@@ -1528,8 +1528,9 @@ function DataTableCell({
|
|
|
1528
1528
|
}: DataTableCellProps): ReactNode {
|
|
1529
1529
|
const componentRef = isComponentRendererRef(renderer);
|
|
1530
1530
|
const ResolvedComponent = useColumnRenderer(componentRef?.name);
|
|
1531
|
+
const t = useTranslation();
|
|
1531
1532
|
if (typeof renderer === "object" && renderer !== null && "format" in renderer) {
|
|
1532
|
-
return applyFormatSpec(renderer as { format: string } & Record<string, unknown>, value);
|
|
1533
|
+
return applyFormatSpec(renderer as { format: string } & Record<string, unknown>, value, t);
|
|
1533
1534
|
}
|
|
1534
1535
|
if (typeof renderer === "function") {
|
|
1535
1536
|
const fn = renderer as (v: unknown, r?: Readonly<Record<string, unknown>>) => string;
|