@declarion/react 0.19.0 → 0.23.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.
@@ -1,4 +1,17 @@
1
- import type { Action, ActionCondition, LocalizedString, Schema } from "../types/schema";
1
+ import type { Action, ActionCondition, Entity, LocalizedString, Schema } from "../types/schema";
2
+ /**
3
+ * rowDetailId builds the detail-route id for a row - the value an href's
4
+ * `${id}` placeholder and a detail screen's `:id` segment receive - addressing
5
+ * it by the entity's REAL primary key (any single field or a composite key), so
6
+ * an entity whose PK is not named `id` (e.g. `schedule.code`) resolves correctly
7
+ * instead of emitting an empty `${id}`. Falls back to a raw `id` lookup only
8
+ * when no entity is in scope (defensive; an href dispatch always has one) or the
9
+ * row has no resolvable PK yet (an optimistic placeholder).
10
+ *
11
+ * Single source of truth for row -> detail-id, shared by ResponsiveActionBar
12
+ * (action_layout dispatch) and ActionButton (flat href dispatch).
13
+ */
14
+ export declare function rowDetailId(row: Record<string, unknown> | undefined, entity: Entity | undefined): string;
2
15
  /**
3
16
  * Evaluates action conditions against row data.
4
17
  * Returns true if the action is available (all conditions pass).
@@ -1,4 +1,4 @@
1
- import { type ReactElement } from "react";
1
+ import { type ReactElement, type ReactNode } from "react";
2
2
  import { type RenderResult } from "@testing-library/react";
3
3
  import { QueryClient } from "@tanstack/react-query";
4
4
  import { type ActionExecuteRequest, type ActionExecuteResponse } from "./api/data";
@@ -64,3 +64,21 @@ export declare function cleanupDeclarion(): void;
64
64
  * live queryClient.
65
65
  */
66
66
  export declare function renderWithDeclarion(ui: ReactElement, opts?: RenderWithDeclarionOptions): RenderWithDeclarionResult;
67
+ export interface PreviewHarnessProps extends RenderWithDeclarionOptions {
68
+ children: ReactNode;
69
+ /** Default true: seeds an admin user so useSchema's auth gate opens and the
70
+ * screen renders authenticated. Set false to render a pre-login screen
71
+ * (SignIn / SignUp / Forgot / Reset / TwoFA / AuthShell) in its logged-out
72
+ * state, where useSchema stays disabled (no fetch) as in production. */
73
+ authenticated?: boolean;
74
+ }
75
+ /**
76
+ * Component form of {@link renderWithDeclarion} for live previews / stories /
77
+ * Storybook: wraps `children` in the SDK's real providers (QueryClient +
78
+ * MemoryRouter + ActionRunnerProvider + the Sonner outlet) and seeds the same
79
+ * read/action seams from props, so an SDK screen renders against fixtures with
80
+ * no network. Unlike renderWithDeclarion (which calls testing-library's render),
81
+ * this returns an element you compose directly. Providers + seeds are created
82
+ * once per mount (useState initializer) so a static snapshot is deterministic.
83
+ */
84
+ export declare function PreviewHarness({ children, authenticated, ...opts }: PreviewHarnessProps): ReactElement;
@@ -1,11 +1,12 @@
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";
1
+ import { Pt as e, ct as t, lt as n, t as r, tt as i, ut as a } from "./ActionRunner-C2A73D9b.js";
2
+ import { useState as o } from "react";
3
+ import { MemoryRouter as s } from "react-router-dom";
4
+ import { QueryClient as c, QueryClientProvider as l } from "@tanstack/react-query";
5
+ import { Toaster as u } from "sonner";
6
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
7
+ import { render as p } from "@testing-library/react";
7
8
  //#region src/testing.tsx
8
- function p(e = {}) {
9
+ function m(e = {}) {
9
10
  return {
10
11
  languages: [],
11
12
  structures: {},
@@ -18,7 +19,7 @@ function p(e = {}) {
18
19
  ...e
19
20
  };
20
21
  }
21
- function m(e, t = {}, n) {
22
+ function h(e, t = {}, n) {
22
23
  return {
23
24
  data: e,
24
25
  meta: {
@@ -32,27 +33,27 @@ function m(e, t = {}, n) {
32
33
  ...n === void 0 ? {} : { $refs: n }
33
34
  };
34
35
  }
35
- function h(e) {
36
+ function g(e) {
36
37
  return e;
37
38
  }
38
- var g = Symbol("declarion.testing.actionEnvelope");
39
- function _(e) {
39
+ var _ = Symbol("declarion.testing.actionEnvelope");
40
+ function v(e) {
40
41
  return {
41
42
  ...e,
42
- [g]: !0
43
+ [_]: !0
43
44
  };
44
45
  }
45
- function v(e) {
46
- if (e && typeof e == "object" && e[g]) {
46
+ function y(e) {
47
+ if (e && typeof e == "object" && e[_]) {
47
48
  let t = { ...e };
48
- return delete t[g], t;
49
+ return delete t[_], t;
49
50
  }
50
51
  return {
51
52
  status: "success",
52
53
  result: e
53
54
  };
54
55
  }
55
- function y() {
56
+ function b() {
56
57
  let t = {
57
58
  id: "test-tenant",
58
59
  code: "test",
@@ -71,7 +72,7 @@ function y() {
71
72
  };
72
73
  e.getState().setUser(n, t);
73
74
  }
74
- function b(e) {
75
+ function x(e) {
75
76
  if (e === void 0) return { rows: [] };
76
77
  if (Array.isArray(e)) return { rows: e };
77
78
  if (Array.isArray(e.data)) {
@@ -84,10 +85,10 @@ function b(e) {
84
85
  }
85
86
  return e;
86
87
  }
87
- function x(e) {
88
+ function S(e) {
88
89
  let r = e.entityData ?? {};
89
90
  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
+ let n = r[e], i = x(n), a = i.meta?.per_page ?? 50, o = i.meta?.total ?? i.rows.length;
91
92
  return t.count === "only" ? {
92
93
  data: [],
93
94
  meta: {
@@ -116,10 +117,10 @@ function x(e) {
116
117
  t(async (e, t) => {
117
118
  if (!(e in s)) throw Error(`renderWithDeclarion: no action result registered for "${e}" (seed it via actionResults)`);
118
119
  let n = s[e];
119
- return v(typeof n == "function" ? await n(t) : n);
120
+ return y(typeof n == "function" ? await n(t) : n);
120
121
  });
121
122
  }
122
- function S() {
123
+ function C() {
123
124
  a(null), n(null), t(null), e.setState({
124
125
  user: null,
125
126
  isAuthenticated: !1,
@@ -127,21 +128,42 @@ function S() {
127
128
  tenants: []
128
129
  });
129
130
  }
130
- function C(e, t = {}) {
131
- let n = new s({ defaultOptions: { queries: {
131
+ function w(e, t = {}) {
132
+ let n = new c({ defaultOptions: { queries: {
132
133
  retry: !1,
133
134
  gcTime: Infinity
134
135
  } } });
135
- y(), n.setQueryData(["schema", !0], t.schema ?? p()), x(t);
136
- let i = f(/* @__PURE__ */ d(c, {
136
+ b(), n.setQueryData(["schema", !0], t.schema ?? m()), S(t);
137
+ let i = p(/* @__PURE__ */ f(l, {
137
138
  client: n,
138
- children: [/* @__PURE__ */ u(o, {
139
+ children: [/* @__PURE__ */ d(s, {
139
140
  initialEntries: [t.route ?? "/"],
140
- children: /* @__PURE__ */ u(r, { children: e })
141
- }), /* @__PURE__ */ u(l, {})]
141
+ children: /* @__PURE__ */ d(r, { children: e })
142
+ }), /* @__PURE__ */ d(u, {})]
142
143
  }));
143
144
  return Object.assign(i, { queryClient: n });
144
145
  }
145
- typeof afterEach == "function" && afterEach(() => S());
146
+ function T({ children: t, authenticated: n = !0, ...i }) {
147
+ let [a] = o(() => {
148
+ let t = new c({ defaultOptions: { queries: {
149
+ retry: !1,
150
+ gcTime: Infinity
151
+ } } });
152
+ return n ? (b(), t.setQueryData(["schema", !0], i.schema ?? m())) : e.setState({
153
+ user: null,
154
+ isAuthenticated: !1,
155
+ activeTenant: null,
156
+ tenants: []
157
+ }), S(i), t;
158
+ });
159
+ return /* @__PURE__ */ f(l, {
160
+ client: a,
161
+ children: [/* @__PURE__ */ d(s, {
162
+ initialEntries: [i.route ?? "/"],
163
+ children: /* @__PURE__ */ d(r, { children: t })
164
+ }), /* @__PURE__ */ d(u, {})]
165
+ });
166
+ }
167
+ typeof afterEach == "function" && afterEach(() => C());
146
168
  //#endregion
147
- export { _ as actionEnvelope, h as actionResults, S as cleanupDeclarion, m as entityDataFixture, C as renderWithDeclarion, p as schemaFixture };
169
+ export { T as PreviewHarness, v as actionEnvelope, g as actionResults, C as cleanupDeclarion, h as entityDataFixture, w as renderWithDeclarion, m as schemaFixture };
@@ -384,6 +384,7 @@ export declare function extractPkValues(entity: Entity, record: Record<string, u
384
384
  export declare function pkValuePartsToId(values: string[]): string;
385
385
  export declare function pkValuesToId(pkValues: PkValues): string;
386
386
  export declare function pkValuesToDetailId(entity: Entity, pkValues: PkValues): string;
387
+ export declare function singlePkValues(entity: Entity, value: string): PkValues | undefined;
387
388
  export declare function pkValuesFromId(id: string, expectedCount: number): string[] | null;
388
389
  export declare function resolveDetailRoute(list: Pick<Screen, "detail_screen"> | undefined, entity: Pick<Entity, "detail_screen"> | undefined, allScreens: Record<string, {
389
390
  route?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@declarion/react",
3
- "version": "0.19.0",
3
+ "version": "0.23.0",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "description": "React SDK for Declarion, the schema-driven business apps platform.",
@@ -41,9 +41,9 @@
41
41
  "access": "public"
42
42
  },
43
43
  "peerDependencies": {
44
+ "@testing-library/react": "^16.3.0",
44
45
  "react": "^19.0.0",
45
- "react-dom": "^19.0.0",
46
- "@testing-library/react": "^16.3.0"
46
+ "react-dom": "^19.0.0"
47
47
  },
48
48
  "peerDependenciesMeta": {
49
49
  "@testing-library/react": {
@@ -68,11 +68,11 @@
68
68
  "class-variance-authority": "^0.7.1",
69
69
  "clsx": "^2.1.1",
70
70
  "date-fns": "^4.4.0",
71
- "lucide-react": "^1.18.0",
71
+ "lucide-react": "^1.21.0",
72
72
  "mdast-util-to-string": "^4.0.0",
73
73
  "monaco-editor": "^0.55.1",
74
74
  "react-markdown": "^10.1.0",
75
- "react-router-dom": "^7.17.0",
75
+ "react-router-dom": "^7.18.0",
76
76
  "react-textarea-autosize": "^8.5.9",
77
77
  "recharts": "^3.8.1",
78
78
  "remark-breaks": "^4.0.0",
@@ -107,7 +107,7 @@
107
107
  "tailwindcss": "^4.3.1",
108
108
  "tsc-alias": "^1.8.17",
109
109
  "typescript": "^6.0.3",
110
- "typescript-eslint": "^8.61.1",
110
+ "typescript-eslint": "^8.62.0",
111
111
  "vite": "^8.0.16",
112
112
  "vitest": "^4.1.9"
113
113
  },