@declarion/react 0.12.4 → 0.19.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/dist-lib/ActionRunner-F1HBBKyQ.js +8344 -0
- package/dist-lib/{DraggableChildrenTable-CcogMLSZ.js → DraggableChildrenTable-D7kzLdIg.js} +55 -54
- package/dist-lib/{Grid-Cwxca9aO.js → Grid-Cz_2olTR.js} +120 -120
- package/dist-lib/{MarkdownRenderer-Dbl3AFDQ.js → MarkdownRenderer-Cm-nbv6g.js} +1 -1
- package/dist-lib/api/data.d.ts +28 -0
- package/dist-lib/api/entities.d.ts +13 -7
- package/dist-lib/dataTableStyles-vwD1mVOP.js +22 -0
- package/dist-lib/declarion-react.css +1 -1
- package/dist-lib/hooks/useCursorEntityData.d.ts +57 -0
- package/dist-lib/hooks/useEntityData.d.ts +2 -2
- package/dist-lib/hooks/useSSE.d.ts +1 -0
- package/dist-lib/index.js +5285 -7322
- package/dist-lib/lib/actions.d.ts +23 -18
- package/dist-lib/testing.d.ts +66 -0
- package/dist-lib/testing.js +147 -0
- package/dist-lib/types/api.d.ts +24 -0
- package/dist-lib/types/schema.d.ts +20 -0
- package/package.json +14 -3
- package/dist-lib/dataTableStyles-EMyLDQRB.js +0 -5342
- package/dist-lib/rich-text-CJpzFOG5.js +0 -46
- package/dist-lib/value-CrpaObP_.js +0 -774
|
@@ -141,29 +141,34 @@ export declare function filterLayoutForSlot(layout: ResolvedActionLayoutNode[],
|
|
|
141
141
|
excludeIf?: (action: Action) => boolean;
|
|
142
142
|
}): ResolvedActionLayoutNode[];
|
|
143
143
|
/**
|
|
144
|
-
* True when an action
|
|
144
|
+
* True when an action needs at least one selected row to be meaningful, so a
|
|
145
|
+
* surface (the list toolbar) greys it while nothing is selected and enables it
|
|
146
|
+
* once a selection exists.
|
|
145
147
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
* value, and two of the five modes (`ui_steps`, `widget`) have no
|
|
151
|
-
* derivation at all. So the SDK stands in slot membership: an action is
|
|
152
|
-
* selection-mode iff its `visibility` includes `list_floatbar`.
|
|
148
|
+
* The server derives this from the handler's id-arity contract (a handler that
|
|
149
|
+
* cannot run without object IDs - not allow_no_objects, not invoke=unbound),
|
|
150
|
+
* association mode, or an href `${id}` row-link, and emits it as
|
|
151
|
+
* `requires_selection`. When the field is PRESENT it is authoritative.
|
|
153
152
|
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* (a mis-declared schema can diverge). Full rationale, the divergence
|
|
159
|
-
* case, and the planned hybrid replacement: docs/architecture.md
|
|
160
|
-
* "List Toolbar Selection Model".
|
|
153
|
+
* When ABSENT (an older server, or the `widget`/`ui_steps` modes the server
|
|
154
|
+
* does not derive) we fall back to the historical proxy: slot membership in
|
|
155
|
+
* `list_floatbar`. Absent MUST NOT be read as false, or every handler action
|
|
156
|
+
* would silently read as page-level against an older server.
|
|
161
157
|
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* toolbar) once a selection exists.
|
|
158
|
+
* See docs/architecture.md "List Toolbar Selection Model" and plan
|
|
159
|
+
* 2026-06-22-toolbar-action-slots-and-id-arity.md.
|
|
165
160
|
*/
|
|
166
161
|
export declare function actionRequiresSelection(action: Action): boolean;
|
|
162
|
+
/**
|
|
163
|
+
* True when the action declares the `list_floatbar` (selection bar) slot.
|
|
164
|
+
*
|
|
165
|
+
* This is the OLD body of actionRequiresSelection, kept ONLY to decide
|
|
166
|
+
* toolbar/floatbar de-duplication: an action that opts into the floatbar is
|
|
167
|
+
* rendered there on selection, so the static toolbar drops it to avoid a
|
|
168
|
+
* double-render. It is NOT the selection predicate - greying is driven by
|
|
169
|
+
* actionRequiresSelection (the accurate server signal).
|
|
170
|
+
*/
|
|
171
|
+
export declare function actionInFloatbarSlot(action: Action): boolean;
|
|
167
172
|
/**
|
|
168
173
|
* Walks a ResolvedActionLayoutNode[] and sets `enabled: false` plus the
|
|
169
174
|
* given `reason` on every leaf whose action satisfies `predicate`. Groups
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
2
|
+
import { type RenderResult } from "@testing-library/react";
|
|
3
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
4
|
+
import { type ActionExecuteRequest, type ActionExecuteResponse } from "./api/data";
|
|
5
|
+
import type { Schema } from "./types/schema";
|
|
6
|
+
import type { ListMeta, ListResponse, Refs } from "./types/api";
|
|
7
|
+
/** A single action's stubbed outcome: the action's RESULT payload (what
|
|
8
|
+
* executeDeclarionAction unwraps from response.result), or a function of the
|
|
9
|
+
* dispatched body returning it. The harness always wraps it in a success
|
|
10
|
+
* envelope - it does NOT sniff for an envelope shape, so a domain result like
|
|
11
|
+
* { status: "closed" } keeps its result intact. Simulate a failure by throwing
|
|
12
|
+
* from a function result. The union avoids `unknown` so the function form keeps
|
|
13
|
+
* its typed `body` parameter at consumer call sites. */
|
|
14
|
+
export type ActionResult = ((body: ActionExecuteRequest) => unknown) | Record<string, unknown> | unknown[] | string | number | boolean | null;
|
|
15
|
+
/** Rows plus optional meta + response-level `$refs` (ref/expanded-column data)
|
|
16
|
+
* for one entity's list/count fixture. */
|
|
17
|
+
export interface EntityDataFixture {
|
|
18
|
+
rows: Record<string, unknown>[];
|
|
19
|
+
meta?: Partial<ListMeta>;
|
|
20
|
+
refs?: Refs;
|
|
21
|
+
}
|
|
22
|
+
export interface RenderWithDeclarionOptions {
|
|
23
|
+
/** Seeded into the schema query cache so useSchema resolves warm. Build with schemaFixture. */
|
|
24
|
+
schema?: Schema;
|
|
25
|
+
/** entity -> rows, { rows, meta }, or an entityDataFixture() ListResponse; resolves useEntityData / useEntityCount. */
|
|
26
|
+
entityData?: Record<string, Record<string, unknown>[] | EntityDataFixture | ListResponse>;
|
|
27
|
+
/** entity -> { [id]: row }; resolves useEntityItem. */
|
|
28
|
+
entityItems?: Record<string, Record<string, Record<string, unknown>>>;
|
|
29
|
+
/** action code -> result | (body) => result; resolves executeAction (and create/update/delete/restore). */
|
|
30
|
+
actionResults?: Record<string, ActionResult>;
|
|
31
|
+
/** Initial path for the memory router (e.g. "/replay/abc/compare"). Default "/". */
|
|
32
|
+
route?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface RenderWithDeclarionResult extends RenderResult {
|
|
35
|
+
/** The live QueryClient, for advanced cache assertions or manual refetch. */
|
|
36
|
+
queryClient: QueryClient;
|
|
37
|
+
}
|
|
38
|
+
/** Build a valid Schema from a partial - fills the required empty maps so a
|
|
39
|
+
* consumer only declares the entities/screens its test needs. */
|
|
40
|
+
export declare function schemaFixture(partial?: Partial<Schema>): Schema;
|
|
41
|
+
/** Build the ListResponse envelope the real list hooks consume, from rows +
|
|
42
|
+
* optional meta overrides. Defaults meta to an exact count of the row set. */
|
|
43
|
+
export declare function entityDataFixture(rows: Record<string, unknown>[], meta?: Partial<ListMeta>, refs?: Refs): ListResponse;
|
|
44
|
+
/** Typed pass-through for an action-result map (ergonomic + future-proof seam). */
|
|
45
|
+
export declare function actionResults(map: Record<string, ActionResult>): Record<string, ActionResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Build a FULL action-dispatch envelope for a stub - so a render test can drive
|
|
48
|
+
* ActionRunner's NON-success toasts (status "partial" / "skipped" / "accepted"
|
|
49
|
+
* with success / errors / skipped arrays), which a plain result payload cannot
|
|
50
|
+
* express. A plain actionResults value stays the result payload (wrapped as
|
|
51
|
+
* success); only an actionEnvelope() value is forwarded verbatim, so a domain
|
|
52
|
+
* result with a `status` field is never mistaken for an envelope.
|
|
53
|
+
*/
|
|
54
|
+
export declare function actionEnvelope(env: Partial<ActionExecuteResponse> & {
|
|
55
|
+
status: string;
|
|
56
|
+
}): ActionResult;
|
|
57
|
+
/** Clear every harness seam + the seeded auth state. Auto-registered as an
|
|
58
|
+
* afterEach when the test runner exposes one (vitest/jest globals); exported
|
|
59
|
+
* so a runner without globals can call it explicitly. */
|
|
60
|
+
export declare function cleanupDeclarion(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Render a consumer screen under the SDK's real providers with fixtures seeded
|
|
63
|
+
* through the read/action seams. Returns the testing-library result plus the
|
|
64
|
+
* live queryClient.
|
|
65
|
+
*/
|
|
66
|
+
export declare function renderWithDeclarion(ui: ReactElement, opts?: RenderWithDeclarionOptions): RenderWithDeclarionResult;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Pt as e, ct as t, lt as n, t as r, tt as i, ut as a } from "./ActionRunner-F1HBBKyQ.js";
|
|
2
|
+
import { MemoryRouter as o } from "react-router-dom";
|
|
3
|
+
import { QueryClient as s, QueryClientProvider as c } from "@tanstack/react-query";
|
|
4
|
+
import { Toaster as l } from "sonner";
|
|
5
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
6
|
+
import { render as f } from "@testing-library/react";
|
|
7
|
+
//#region src/testing.tsx
|
|
8
|
+
function p(e = {}) {
|
|
9
|
+
return {
|
|
10
|
+
languages: [],
|
|
11
|
+
structures: {},
|
|
12
|
+
entities: {},
|
|
13
|
+
screens: {},
|
|
14
|
+
navigation: [],
|
|
15
|
+
actions: {},
|
|
16
|
+
enums: {},
|
|
17
|
+
parameters: {},
|
|
18
|
+
...e
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function m(e, t = {}, n) {
|
|
22
|
+
return {
|
|
23
|
+
data: e,
|
|
24
|
+
meta: {
|
|
25
|
+
total: t.total ?? e.length,
|
|
26
|
+
page: t.page ?? 1,
|
|
27
|
+
per_page: t.per_page ?? 50,
|
|
28
|
+
total_pages: t.total_pages ?? 1,
|
|
29
|
+
has_more: t.has_more ?? !1,
|
|
30
|
+
count_mode: t.count_mode ?? "exact"
|
|
31
|
+
},
|
|
32
|
+
...n === void 0 ? {} : { $refs: n }
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function h(e) {
|
|
36
|
+
return e;
|
|
37
|
+
}
|
|
38
|
+
var g = Symbol("declarion.testing.actionEnvelope");
|
|
39
|
+
function _(e) {
|
|
40
|
+
return {
|
|
41
|
+
...e,
|
|
42
|
+
[g]: !0
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function v(e) {
|
|
46
|
+
if (e && typeof e == "object" && e[g]) {
|
|
47
|
+
let t = { ...e };
|
|
48
|
+
return delete t[g], t;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
status: "success",
|
|
52
|
+
result: e
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function y() {
|
|
56
|
+
let t = {
|
|
57
|
+
id: "test-tenant",
|
|
58
|
+
code: "test",
|
|
59
|
+
name: "Test",
|
|
60
|
+
role: "admin"
|
|
61
|
+
}, n = {
|
|
62
|
+
id: "test-user",
|
|
63
|
+
email: "test@example.com",
|
|
64
|
+
display_name: "Test User",
|
|
65
|
+
is_active: !0,
|
|
66
|
+
roles: ["admin"],
|
|
67
|
+
permissions: ["*"],
|
|
68
|
+
tenant: t,
|
|
69
|
+
created_at: "2026-01-01T00:00:00Z",
|
|
70
|
+
updated_at: "2026-01-01T00:00:00Z"
|
|
71
|
+
};
|
|
72
|
+
e.getState().setUser(n, t);
|
|
73
|
+
}
|
|
74
|
+
function b(e) {
|
|
75
|
+
if (e === void 0) return { rows: [] };
|
|
76
|
+
if (Array.isArray(e)) return { rows: e };
|
|
77
|
+
if (Array.isArray(e.data)) {
|
|
78
|
+
let t = e;
|
|
79
|
+
return {
|
|
80
|
+
rows: t.data,
|
|
81
|
+
meta: t.meta,
|
|
82
|
+
refs: t.$refs
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return e;
|
|
86
|
+
}
|
|
87
|
+
function x(e) {
|
|
88
|
+
let r = e.entityData ?? {};
|
|
89
|
+
a((e, t) => {
|
|
90
|
+
let n = r[e], i = b(n), a = i.meta?.per_page ?? 50, o = i.meta?.total ?? i.rows.length;
|
|
91
|
+
return t.count === "only" ? {
|
|
92
|
+
data: [],
|
|
93
|
+
meta: {
|
|
94
|
+
page: 1,
|
|
95
|
+
per_page: a,
|
|
96
|
+
total: o,
|
|
97
|
+
total_pages: i.meta?.total_pages ?? Math.max(1, Math.ceil(o / a)),
|
|
98
|
+
count_mode: i.meta?.count_mode ?? "exact"
|
|
99
|
+
}
|
|
100
|
+
} : {
|
|
101
|
+
data: i.rows,
|
|
102
|
+
meta: {
|
|
103
|
+
page: i.meta?.page ?? 1,
|
|
104
|
+
per_page: a,
|
|
105
|
+
has_more: i.meta?.has_more ?? !1
|
|
106
|
+
},
|
|
107
|
+
...i.refs === void 0 ? {} : { $refs: i.refs }
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
let o = e.entityItems ?? {};
|
|
111
|
+
n((e, t) => {
|
|
112
|
+
let n = typeof t == "string" ? t : i(t);
|
|
113
|
+
return { data: o[e]?.[n] };
|
|
114
|
+
});
|
|
115
|
+
let s = e.actionResults ?? {};
|
|
116
|
+
t(async (e, t) => {
|
|
117
|
+
if (!(e in s)) throw Error(`renderWithDeclarion: no action result registered for "${e}" (seed it via actionResults)`);
|
|
118
|
+
let n = s[e];
|
|
119
|
+
return v(typeof n == "function" ? await n(t) : n);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function S() {
|
|
123
|
+
a(null), n(null), t(null), e.setState({
|
|
124
|
+
user: null,
|
|
125
|
+
isAuthenticated: !1,
|
|
126
|
+
activeTenant: null,
|
|
127
|
+
tenants: []
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function C(e, t = {}) {
|
|
131
|
+
let n = new s({ defaultOptions: { queries: {
|
|
132
|
+
retry: !1,
|
|
133
|
+
gcTime: Infinity
|
|
134
|
+
} } });
|
|
135
|
+
y(), n.setQueryData(["schema", !0], t.schema ?? p()), x(t);
|
|
136
|
+
let i = f(/* @__PURE__ */ d(c, {
|
|
137
|
+
client: n,
|
|
138
|
+
children: [/* @__PURE__ */ u(o, {
|
|
139
|
+
initialEntries: [t.route ?? "/"],
|
|
140
|
+
children: /* @__PURE__ */ u(r, { children: e })
|
|
141
|
+
}), /* @__PURE__ */ u(l, {})]
|
|
142
|
+
}));
|
|
143
|
+
return Object.assign(i, { queryClient: n });
|
|
144
|
+
}
|
|
145
|
+
typeof afterEach == "function" && afterEach(() => S());
|
|
146
|
+
//#endregion
|
|
147
|
+
export { _ as actionEnvelope, h as actionResults, S as cleanupDeclarion, m as entityDataFixture, C as renderWithDeclarion, p as schemaFixture };
|
package/dist-lib/types/api.d.ts
CHANGED
|
@@ -68,6 +68,13 @@ export declare class ApiError extends Error {
|
|
|
68
68
|
*/
|
|
69
69
|
export declare const CURSOR_SEMANTICS_MISMATCH = "cursor_semantics_mismatch";
|
|
70
70
|
export declare const CURSOR_LOCALE_CHANGED = "cursor_locale_changed";
|
|
71
|
+
/**
|
|
72
|
+
* A cross-store (Postgres-hot / ClickHouse-cold) archive cursor that the server
|
|
73
|
+
* could not decode for this read - a malformed token, a tenant/entity mismatch,
|
|
74
|
+
* or a retired bespoke-archive cursor minted before the native-cursor release.
|
|
75
|
+
* Same recovery contract as the other two: drop `after`, refetch window 1.
|
|
76
|
+
*/
|
|
77
|
+
export declare const ARCHIVE_CURSOR_INVALID = "archive_cursor_invalid";
|
|
71
78
|
/** True if the error is a recoverable cursor-stale signal that warrants
|
|
72
79
|
* refetching page 1 instead of surfacing to the user. */
|
|
73
80
|
export declare function isCursorStaleError(err: unknown): boolean;
|
|
@@ -271,6 +278,13 @@ export interface V2Meta {
|
|
|
271
278
|
limit: number;
|
|
272
279
|
has_more: boolean;
|
|
273
280
|
cursor?: string;
|
|
281
|
+
/** How `total` was produced: "exact" or "estimated". Absent when no count
|
|
282
|
+
* was requested. A cross-store cursor total is always "estimated". */
|
|
283
|
+
count_mode?: string;
|
|
284
|
+
/** True when a count WAS requested but abandoned because the cold-tier count
|
|
285
|
+
* would exceed the interactive scan bound (BC4b). The data window still
|
|
286
|
+
* loaded; render NO total ("~N") - distinct from a real `total: 0`. */
|
|
287
|
+
count_unknown?: boolean;
|
|
274
288
|
}
|
|
275
289
|
/**
|
|
276
290
|
* Refs map: keyed by entity code (or $-prefixed virtual entity code),
|
|
@@ -316,6 +330,16 @@ export interface V2ListParams {
|
|
|
316
330
|
limit?: number;
|
|
317
331
|
after?: string;
|
|
318
332
|
include_deleted?: boolean;
|
|
333
|
+
/** Request the (estimated) total alongside the window (`?count=with`). The
|
|
334
|
+
* cursor UI sends this on the FIRST window only; later windows omit it. */
|
|
335
|
+
count?: boolean;
|
|
336
|
+
/** Screen code, so the server applies that screen's `fixed_filters` (a
|
|
337
|
+
* cursor list of a `fixed_filters` view, e.g. the audit auth-log, needs
|
|
338
|
+
* the same server-side prefilter the offset list gets). */
|
|
339
|
+
screen?: string;
|
|
340
|
+
/** Return display-bounded (truncated) values for list cells, matching the
|
|
341
|
+
* offset list's `preview: true`. */
|
|
342
|
+
preview?: boolean;
|
|
319
343
|
}
|
|
320
344
|
/** Per-field resolved display unit codes. */
|
|
321
345
|
export type Units = Record<string, string>;
|
|
@@ -363,6 +363,16 @@ export interface Entity {
|
|
|
363
363
|
* docs/plans/2026-05-18-declarative-row-count.md.
|
|
364
364
|
*/
|
|
365
365
|
count?: "exact" | "estimated";
|
|
366
|
+
/**
|
|
367
|
+
* Computed (server-side, never author-set) pagination mode the generated
|
|
368
|
+
* admin list MUST use: "offset" (numbered pages) or "cursor" (keyset /
|
|
369
|
+
* infinite scroll). "cursor" iff the entity declares `persistence.archive`
|
|
370
|
+
* AND the deployment has ClickHouse wired at boot - a cross-store hot+cold
|
|
371
|
+
* read cannot offset-paginate. Absent means "offset" (every plain Postgres /
|
|
372
|
+
* ClickHouse-only / ClickHouse-disabled-archive entity). The SDK branches the
|
|
373
|
+
* list UI on this. See docs/plans/2026-06-20-cross-store-list-cursor-pagination.md.
|
|
374
|
+
*/
|
|
375
|
+
list_pagination?: "offset" | "cursor";
|
|
366
376
|
}
|
|
367
377
|
export interface ExportConfig {
|
|
368
378
|
enabled?: boolean;
|
|
@@ -808,6 +818,16 @@ export interface Action {
|
|
|
808
818
|
*/
|
|
809
819
|
resolved_hidden_defaults?: Record<string, unknown>;
|
|
810
820
|
ui_steps?: UIStep[];
|
|
821
|
+
/**
|
|
822
|
+
* Server-derived: the action needs at least one selected row to be
|
|
823
|
+
* meaningful (the list toolbar greys it while nothing is selected). Derived
|
|
824
|
+
* from the handler's id-arity contract (cannot run without object IDs),
|
|
825
|
+
* association mode, or an href `${id}` row-link. ABSENT means the server did
|
|
826
|
+
* not derive it (older server, or widget/ui_steps modes) - consumers MUST
|
|
827
|
+
* fall back to the list_floatbar slot proxy, NOT treat absent as false. See
|
|
828
|
+
* actionRequiresSelection in lib/actions.ts.
|
|
829
|
+
*/
|
|
830
|
+
requires_selection?: boolean;
|
|
811
831
|
}
|
|
812
832
|
export interface LanguageDef {
|
|
813
833
|
code: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@declarion/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "React SDK for Declarion, the schema-driven business apps platform.",
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"import": "./dist-lib/vite/index.js",
|
|
26
26
|
"default": "./dist-lib/vite/index.js"
|
|
27
27
|
},
|
|
28
|
+
"./testing": {
|
|
29
|
+
"types": "./dist-lib/testing.d.ts",
|
|
30
|
+
"import": "./dist-lib/testing.js",
|
|
31
|
+
"default": "./dist-lib/testing.js"
|
|
32
|
+
},
|
|
28
33
|
"./styles.css": "./dist-lib/declarion-react.css"
|
|
29
34
|
},
|
|
30
35
|
"files": [
|
|
@@ -37,7 +42,13 @@
|
|
|
37
42
|
},
|
|
38
43
|
"peerDependencies": {
|
|
39
44
|
"react": "^19.0.0",
|
|
40
|
-
"react-dom": "^19.0.0"
|
|
45
|
+
"react-dom": "^19.0.0",
|
|
46
|
+
"@testing-library/react": "^16.3.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"@testing-library/react": {
|
|
50
|
+
"optional": true
|
|
51
|
+
}
|
|
41
52
|
},
|
|
42
53
|
"dependencies": {
|
|
43
54
|
"@dnd-kit/core": "^6.3.1",
|
|
@@ -108,7 +119,7 @@
|
|
|
108
119
|
"check:pkg": "publint run",
|
|
109
120
|
"lint": "tsc --noEmit && eslint src --max-warnings=0",
|
|
110
121
|
"test": "vitest run",
|
|
111
|
-
"test:coverage": "vitest run --coverage
|
|
122
|
+
"test:coverage": "vitest run --coverage",
|
|
112
123
|
"preview": "vite preview"
|
|
113
124
|
}
|
|
114
125
|
}
|