@cosmicdrift/kumiko-renderer-web 0.220.0 → 0.220.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer-web",
3
- "version": "0.220.0",
3
+ "version": "0.220.1",
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.220.0",
20
- "@cosmicdrift/kumiko-headless": "0.220.0",
21
- "@cosmicdrift/kumiko-renderer": "0.220.0",
19
+ "@cosmicdrift/kumiko-dispatcher-live": "0.220.1",
20
+ "@cosmicdrift/kumiko-headless": "0.220.1",
21
+ "@cosmicdrift/kumiko-renderer": "0.220.1",
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.220.0"
67
+ "@cosmicdrift/kumiko-locale-de": "0.220.1"
68
68
  },
69
69
  "repository": {
70
70
  "type": "git",
@@ -673,8 +673,8 @@ function DefaultDataTable({
673
673
  // scrollen typischerweise mit dem Page-Container, nicht intern.
674
674
  // Sticky würde mit der Topbar konkurrieren.
675
675
  const hasTableActions = rowActions !== undefined && rowActions.length > 0;
676
- const tableContent =
677
- rows.length === 0 ? (
676
+ function tableInner(): ReactNode {
677
+ return rows.length === 0 ? (
678
678
  <div
679
679
  data-testid={testId !== undefined ? `${testId}-empty` : "render-list-empty"}
680
680
  className="flex flex-col items-center justify-center rounded-md border border-dashed p-12 text-sm text-muted-foreground gap-3"
@@ -777,6 +777,8 @@ function DefaultDataTable({
777
777
  </Table>
778
778
  </div>
779
779
  );
780
+ }
781
+ const tableContent = tableInner();
780
782
 
781
783
  // Pager wird IMMER unter der Tabelle gerendert (auch bei rows=[]),
782
784
  // damit der User bei einem Filter-Hit-of-Zero zurückblättern kann
@@ -1701,7 +1703,6 @@ function DefaultForm({
1701
1703
  export type FormScreenShellWidth = FormWidth;
1702
1704
 
1703
1705
  const formScreenShellWidth: Record<FormScreenShellWidth, string> = {
1704
- sm: "max-w-sm mx-auto",
1705
1706
  "3xl": "max-w-3xl mx-auto",
1706
1707
  "4xl": "max-w-4xl mx-auto",
1707
1708
  full: "max-w-full",
@@ -20,12 +20,6 @@ export type InfinityListProps<TData = unknown, TRow = Readonly<Record<string, un
20
20
  /** Must derive from row content (e.g. `row.id`), not from `index` — a
21
21
  * live refresh reorders rows (new/changed rows move to the front). */
22
22
  readonly rowId: (row: TRow, index: number) => string;
23
- /** Pass this when `rowId` depends on list position — the live-merge path
24
- * needs a position-independent identity. Without it, an index-based
25
- * `rowId` (legitimate when live-merge isn't used) can collide between
26
- * the freshly-fetched first page's local indices and the accumulated
27
- * list's indices, silently dropping an unrelated mid-list row on merge. */
28
- readonly rowKey?: (row: TRow) => string;
29
23
  readonly renderRow: (row: TRow) => ReactNode;
30
24
  readonly emptyState?: ReactNode;
31
25
  readonly className?: string;
@@ -55,7 +49,6 @@ export function InfinityList<TData = unknown, TRow = Readonly<Record<string, unk
55
49
  rows,
56
50
  nextCursor,
57
51
  rowId,
58
- rowKey,
59
52
  renderRow,
60
53
  emptyState,
61
54
  className,
@@ -80,16 +73,6 @@ export function InfinityList<TData = unknown, TRow = Readonly<Record<string, unk
80
73
  nextCursorRef.current = nextCursor;
81
74
  const rowIdRef = useRef(rowId);
82
75
  rowIdRef.current = rowId;
83
- const rowKeyRef = useRef(rowKey);
84
- rowKeyRef.current = rowKey;
85
- // Position-independent when rowKey is supplied, otherwise falls back to
86
- // the (possibly position-dependent) rowId — same identity function used
87
- // for both sides of the live-merge diff below so a position-based rowId
88
- // can no longer collide across the fresh page's local indices and the
89
- // accumulated list's indices (fw#1829).
90
- const identifyRef = useRef((row: TRow, index: number): string =>
91
- rowKeyRef.current !== undefined ? rowKeyRef.current(row) : rowIdRef.current(row, index),
92
- );
93
76
 
94
77
  // Discards a response whose request was superseded by a newer one before
95
78
  // it resolved (e.g. two searches fired in quick succession) — without
@@ -121,9 +104,8 @@ export function InfinityList<TData = unknown, TRow = Readonly<Record<string, unk
121
104
  if (cursor === null) {
122
105
  // Same identity as refreshFirstPage's freshIds/staleRows diff below
123
106
  // — this ref is what that diff's previousFirstPageIds reads, so it
124
- // must agree on rowKey vs rowId or the two id spaces never overlap.
125
107
  firstPageIdsRef.current = new Set(
126
- nextRows.map((row, index) => identifyRef.current(row, index)),
108
+ nextRows.map((row, index) => rowIdRef.current(row, index)),
127
109
  );
128
110
  }
129
111
  setState((prev) => {
@@ -174,7 +156,7 @@ export function InfinityList<TData = unknown, TRow = Readonly<Record<string, unk
174
156
  // skip: background live refresh failed, keep showing the current rows
175
157
  if (!res.isSuccess) return;
176
158
  const freshRows = rowsRef.current(res.data);
177
- const freshIds = new Set(freshRows.map((row, index) => identifyRef.current(row, index)));
159
+ const freshIds = new Set(freshRows.map((row, index) => rowIdRef.current(row, index)));
178
160
  // A row absent from freshIds is stale for one of two reasons: it was
179
161
  // dropped from page 1 (deleted, or filtered out elsewhere) and must be
180
162
  // pruned, or it belongs to an already-accumulated later page and must
@@ -194,7 +176,7 @@ export function InfinityList<TData = unknown, TRow = Readonly<Record<string, unk
194
176
  return { kind: "ready", rows: freshRows, cursor: nextCursorRef.current(res.data) };
195
177
  }
196
178
  const staleRows = prev.rows.filter((row, index) => {
197
- const id = identifyRef.current(row, index);
179
+ const id = rowIdRef.current(row, index);
198
180
  return !freshIds.has(id) && !previousFirstPageIds.has(id);
199
181
  });
200
182
  return { kind: "ready", rows: [...freshRows, ...staleRows], cursor: prev.cursor };