@declarion/react 0.27.0 → 0.28.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.
@@ -1,5 +1,5 @@
1
1
  import { s as e } from "./DynamicIcon-DCRdxxZ7.js";
2
- import { Fn as t, In as n, m as r, mn as i, p as a, tn as o } from "./ActionRunner-D9fJRkNV.js";
2
+ import { Ln as t, Rn as n, gn as r, m as i, p as a, rn as o } from "./ActionRunner-DtUDeH4F.js";
3
3
  import { n as s, r as c, t as l } from "./dataTableStyles-vwD1mVOP.js";
4
4
  import { useCallback as u, useMemo as d, useRef as f } from "react";
5
5
  import { jsx as p, jsxs as m } from "react/jsx-runtime";
@@ -207,7 +207,7 @@ function T({ row: n, columns: o, editableColumns: s, displayOnlyColumns: c, chil
207
207
  ...A,
208
208
  textDecoration: y ? "line-through" : "none"
209
209
  },
210
- children: t ? r({
210
+ children: t ? i({
211
211
  field: t,
212
212
  fieldName: e,
213
213
  value: n[e],
@@ -215,7 +215,7 @@ function T({ row: n, columns: o, editableColumns: s, displayOnlyColumns: c, chil
215
215
  record: n,
216
216
  refs: f,
217
217
  locale: v
218
- }) : i(n[e])
218
+ }) : r(n[e])
219
219
  }, e) : /* @__PURE__ */ p("td", {
220
220
  style: {
221
221
  ...j,
@@ -224,7 +224,7 @@ function T({ row: n, columns: o, editableColumns: s, displayOnlyColumns: c, chil
224
224
  borderRadius: a ? 4 : 0
225
225
  },
226
226
  title: a ? `${e} is required` : void 0,
227
- children: t ? r({
227
+ children: t ? i({
228
228
  field: t,
229
229
  fieldName: e,
230
230
  value: n[e],
@@ -233,7 +233,7 @@ function T({ row: n, columns: o, editableColumns: s, displayOnlyColumns: c, chil
233
233
  record: n,
234
234
  refs: f,
235
235
  locale: v
236
- }) : i(n[e])
236
+ }) : r(n[e])
237
237
  }, e);
238
238
  }),
239
239
  /* @__PURE__ */ p("td", {
@@ -1,5 +1,5 @@
1
- import { C as e, S as t, _ as n, b as r, x as i, y as a } from "./ActionRunner-D9fJRkNV.js";
2
- import { c as o, i as s, l as c, t as l } from "./value-BQWyqKHC.js";
1
+ import { C as e, S as t, _ as n, b as r, x as i, y as a } from "./ActionRunner-DtUDeH4F.js";
2
+ import { c as o, i as s, l as c, t as l } from "./value-CNUbJNK-.js";
3
3
  import { useCallback as u, useEffect as d, useMemo as f, useRef as p, useState as m } from "react";
4
4
  import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
5
5
  import { DndContext as v, PointerSensor as y, closestCenter as b, useSensor as x, useSensors as ee } from "@dnd-kit/core";
@@ -1,4 +1,4 @@
1
- import { T as e } from "./ActionRunner-D9fJRkNV.js";
1
+ import { T as e } from "./ActionRunner-DtUDeH4F.js";
2
2
  import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
3
  import r, { defaultUrlTransform as i } from "react-markdown";
4
4
  import a from "remark-breaks";
@@ -0,0 +1 @@
1
+ export declare function EmbedHistoryTracker(): null;
@@ -0,0 +1,19 @@
1
+ /** The React Router navigation action, as returned by `useNavigationType()`. */
2
+ export type EmbedNavAction = "PUSH" | "POP" | "REPLACE";
3
+ interface EmbedHistoryState {
4
+ /** In-frame history depth: 0 at the entry screen, +1 per in-frame drill. */
5
+ readonly depth: number;
6
+ /** When true, the NEXT applied navigation is treated as a fresh root (depth
7
+ * resets to 0) regardless of its action. Set by a host-driven `navigate`. */
8
+ readonly nextIsRoot: boolean;
9
+ /** Apply one navigation's action to the depth. PUSH +1, POP -1 (floored at
10
+ * 0), REPLACE unchanged; a pending root marker forces 0 and clears itself.
11
+ * Called once per navigation by the tracker. */
12
+ applyNavigation: (action: EmbedNavAction) => void;
13
+ /** Mark the next applied navigation as a fresh root (host-driven `navigate`). */
14
+ markRoot: () => void;
15
+ /** Reset to the entry screen (embed re-bootstrap). */
16
+ reset: () => void;
17
+ }
18
+ export declare const useEmbedHistoryStore: import("zustand").UseBoundStore<import("zustand").StoreApi<EmbedHistoryState>>;
19
+ export {};
@@ -10,7 +10,9 @@ export { EmbedDirtyReporter } from "./EmbedDirtyReporter";
10
10
  export { EMBED_MESSAGE_SOURCE, EMBED_PROTOCOL_VERSION, EMBED_MESSAGE_TYPES, postToParent, type EmbedMessageType, type EmbedMessage, type EmbedMessagePayloadMap, type EmbedReadyPayload, type EmbedSetTokenPayload, type EmbedTokenExpiredPayload, type EmbedReloadRequiredPayload, type EmbedResizedPayload, type EmbedNavigationPayload, type EmbedDirtyChangedPayload, type EmbedNavigationFailedPayload, type EmbedNavigatePayload, type EmbedSetThemePayload, } from "./protocol";
11
11
  export { resolveEmbedNavigation, resolveEmbedNavigationPayload, } from "./screen-location";
12
12
  export type { EmbedNavigationResolution } from "./screen-location";
13
- export { useEmbedNavigate, useEmbedScreenNavigate, useEmbedNavigationFailed, } from "./useEmbedNavigate";
13
+ export { useEmbedNavigate, useEmbedScreenNavigate, useEmbedScreenBack, useEmbedNavigationFailed, } from "./useEmbedNavigate";
14
+ export { useEmbedHistoryStore, type EmbedNavAction } from "./embed-history";
15
+ export { EmbedHistoryTracker } from "./EmbedHistoryTracker";
14
16
  export { useGlobalLinkInterceptor, interceptedNavigationTarget, interceptedProgrammaticTarget, NATIVE_LINK_ATTR, } from "./useGlobalLinkInterceptor";
15
17
  export { EmbedLocationReporter } from "./EmbedLocationReporter";
16
18
  export { useEmbedDirtyStore, useReportEmbedDirty } from "./embed-dirty";
@@ -26,6 +26,18 @@ export declare function useEmbedScreenNavigate(): (to: string, opts?: NavigateOp
26
26
  * them.
27
27
  */
28
28
  export declare function useEmbedNavigate(): (to: string, opts?: NavigateOptions) => void;
29
+ /**
30
+ * Embed-mode Back: pop the iframe's own browser history (`navigate(-1)`) to the
31
+ * exact prior URL, so the URL-keyed retained page + cache restore the prior
32
+ * screen's full state - "the same as a normal app", just without tab chrome.
33
+ *
34
+ * Routed through the SAME deferred unsaved-changes guard the rest of embed
35
+ * navigation uses: a raw `navigate(-1)` would bypass the dirty guard and
36
+ * silently discard an in-progress edit (Codex finding). The CALLER
37
+ * (`useScreenBack`) decides WHEN to use this (only when in-frame history depth
38
+ * > 0); this hook only performs the guarded pop.
39
+ */
40
+ export declare function useEmbedScreenBack(): () => void;
29
41
  /**
30
42
  * Emit a `navigation-failed` event to the host. Used where an in-frame
31
43
  * navigation cannot be handled OUTSIDE the chokepoint - chiefly the embedded
@@ -0,0 +1,61 @@
1
+ import { type QueryKey } from "@tanstack/react-query";
2
+ /** The canonical list-page envelope a paginated action returns in its `result` -
3
+ * the same shape `data.list` (ListResponse) produces. */
4
+ export interface ActionListPage<T> {
5
+ data: T[];
6
+ meta?: {
7
+ cursor?: string;
8
+ has_more?: boolean;
9
+ };
10
+ }
11
+ /** Query-key root for a one-shot action read. Mirrors the entity root
12
+ * `entity-data`. */
13
+ export declare const ACTION_DATA_KEY = "action-data";
14
+ /** Query-key root for a cursor (infinite) action read. Mirrors the entity cursor
15
+ * root `entity-data-cursor`; distinct from the one-shot read so it is
16
+ * reaped/registered independently. */
17
+ export declare const ACTION_DATA_CURSOR_KEY = "action-data-cursor";
18
+ /**
19
+ * The React Query key for a one-shot action read. Single source of truth for
20
+ * both `useActionData` and a screen registering it as its PRIMARY read with its
21
+ * retained page (`useRegisterRetainedQuery`). `params` is embedded directly;
22
+ * React Query hashes it stably (sorted keys).
23
+ */
24
+ export declare function actionDataQueryKey(actionCode: string | undefined, params: Record<string, unknown>): QueryKey;
25
+ /**
26
+ * Read an arbitrary action ONCE and cache its `result` - the action mirror of
27
+ * `useEntityData`. `T` is whatever the action returns (a summary object, or a
28
+ * plain array that is not cursor-paginated). Returns the raw React Query result;
29
+ * the caller registers the key via `actionDataQueryKey` +
30
+ * `useRegisterRetainedQuery` for retention.
31
+ */
32
+ export declare function useActionData<T>(actionCode: string | undefined, params: Record<string, unknown>, enabled?: boolean): import("@tanstack/react-query").UseQueryResult<NoInfer<T>, Error>;
33
+ /**
34
+ * The React Query key for a cursor (infinite) action read. Single source of
35
+ * truth for both `useCursorActionData` and its retained-page registration. The
36
+ * key excludes the cursor (the cursor is the page param, not part of identity).
37
+ */
38
+ export declare function cursorActionDataQueryKey(actionCode: string | undefined, params: Record<string, unknown>): QueryKey;
39
+ /** The accumulated, table-ready result of a cursor action read - mirrors the
40
+ * shape `useCursorEntityData` feeds a list. */
41
+ export interface CursorActionDataResult<T> {
42
+ rows: T[];
43
+ hasMore: boolean;
44
+ fetchNextPage: () => void;
45
+ isFetchingNextPage: boolean;
46
+ isLoading: boolean;
47
+ isError: boolean;
48
+ error: Error | null;
49
+ refetch: () => void;
50
+ queryKey: QueryKey;
51
+ }
52
+ /**
53
+ * Drive a cursor-paginated table from an action that returns an `ActionListPage`
54
+ * in its `result`. The mirror of `useCursorEntityData`, differing only in the
55
+ * source (an action via `executeAction`, not `EntityClient.list`): it
56
+ * accumulates windows with `useInfiniteQuery`, advancing `meta.cursor` while
57
+ * `meta.has_more`, and exposes the flattened rows. Register the returned
58
+ * `queryKey` with `useRegisterRetainedQuery` so the pages survive a tab switch /
59
+ * Back within the retention window and die with the retained page.
60
+ */
61
+ export declare function useCursorActionData<T>(actionCode: string | undefined, params: Record<string, unknown>, enabled?: boolean): CursorActionDataResult<T>;
@@ -1,3 +1,4 @@
1
+ import { type QueryKey } from "@tanstack/react-query";
1
2
  import type { FilterNodeParam, Refs, V2Meta } from "../types/api";
2
3
  /**
3
4
  * Query-key root for the cursor (infinite) entity list. Distinct from the
@@ -7,6 +8,18 @@ import type { FilterNodeParam, Refs, V2Meta } from "../types/api";
7
8
  * list. See useSSE.ts.
8
9
  */
9
10
  export declare const CURSOR_ENTITY_DATA_KEY = "entity-data-cursor";
11
+ /**
12
+ * The stable JSON segment of the cursor list's query key (the view-defining
13
+ * params, order-independent). Extracted so both the hook and the key builder
14
+ * compute it identically.
15
+ */
16
+ export declare function cursorEntityStableKey(params: CursorEntityDataParams): string;
17
+ /**
18
+ * The React Query key for the cursor (infinite) entity list. Single source of
19
+ * truth for both `useCursorEntityData` and a screen registering its PRIMARY
20
+ * cursor read with its retained page (`useRegisterRetainedQuery`).
21
+ */
22
+ export declare function cursorEntityDataQueryKey(entity: string | undefined, params: CursorEntityDataParams): QueryKey;
10
23
  export interface CursorEntityDataParams {
11
24
  sort?: string;
12
25
  filters?: FilterNodeParam[];
@@ -1,4 +1,12 @@
1
+ import { type QueryKey } from "@tanstack/react-query";
1
2
  import type { ListParams, ListResponse } from "../types/api";
3
+ /**
4
+ * The React Query key for an entity list-window read. The single source of
5
+ * truth for both `useEntityData` and a screen registering its PRIMARY read with
6
+ * its retained page (`useRegisterRetainedQuery`), so the registered key matches
7
+ * the live query exactly. See hooks/usePageStateRuntime.ts.
8
+ */
9
+ export declare function entityDataQueryKey(entity: string | undefined, params: ListParams): QueryKey;
2
10
  /**
3
11
  * useEntityData fetches one page-window of entity rows.
4
12
  *
@@ -1,2 +1,10 @@
1
+ import { type QueryKey } from "@tanstack/react-query";
1
2
  import type { PkValues } from "../types/schema";
3
+ /**
4
+ * The React Query key for a single-record read. Single source of truth for both
5
+ * `useEntityItem` and a detail screen registering its PRIMARY read with its
6
+ * retained page (`useRegisterRetainedQuery`). For a string PK uses it directly;
7
+ * for a composite PK sorts the parts so key order does not fork the cache.
8
+ */
9
+ export declare function entityItemQueryKey(entity: string | undefined, pkValues: PkValues | string | undefined): QueryKey;
2
10
  export declare function useEntityItem(entity: string | undefined, pkValues: PkValues | string | undefined): import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").DataResponse<Record<string, unknown>>>, Error>;
@@ -0,0 +1,32 @@
1
+ /** A `useState`-style setter accepting a value or an updater. */
2
+ export type PageStateSetter<T> = (next: T | ((prev: T) => T)) => void;
3
+ /**
4
+ * How coarsely a value is keyed.
5
+ * - `"url"` (default): keyed by the full canonical URL, so it FORKS when
6
+ * filters/sort/sub-view change (per-view memory - e.g. scroll position,
7
+ * expanded rows). A filter change is a new view with its own value.
8
+ * - `"path"`: keyed by the screen pathname only, so it PERSISTS across
9
+ * in-screen query changes (e.g. row selection, which survives a filter or
10
+ * column change and is pruned to the visible rows, not reset).
11
+ */
12
+ export type PageStateScope = "url" | "path";
13
+ export interface PageStateOptions {
14
+ scope?: PageStateScope;
15
+ }
16
+ /**
17
+ * Bind a deep value to the current screen's retained page.
18
+ *
19
+ * Returns `[value, setValue]`:
20
+ * - `value` is the stored value for the live canonical URL, or `defaultValue`
21
+ * when absent / reaped / retention disabled. Re-renders only when THIS
22
+ * pageKey's value for THIS key changes.
23
+ * - `setValue` writes through to the store under the LIVE canonical URL
24
+ * (tracked via a per-render ref, so the stable setter always targets the
25
+ * currently-mounted view - never a key captured at mount, never the
26
+ * destination's after a navigation). Accepts a value or an updater.
27
+ *
28
+ * Writes are immediate (write-through), so there is no deferred unmount flush to
29
+ * lose: a value set while mounted at a URL is already stored under that URL when
30
+ * the screen unmounts. The retained page is created lazily on first write.
31
+ */
32
+ export declare function usePageState<T>(key: string, defaultValue: T, opts?: PageStateOptions): [T, PageStateSetter<T>];
@@ -0,0 +1,27 @@
1
+ import { type QueryClient, type QueryKey } from "@tanstack/react-query";
2
+ /**
3
+ * Apply `gcTime` to every retained-read query-key prefix. Exported so app.tsx
4
+ * can seed the DEFAULT floor on the QueryClient at module load - BEFORE the
5
+ * first screen renders and creates its reads - so even that first screen's data
6
+ * is not GC'd at React Query's 5-min default within the retention window. The
7
+ * runtime then overrides with the resolved per-tenant value for later reads.
8
+ */
9
+ export declare function applyRetainedReadGcTime(client: QueryClient, gcTime: number): void;
10
+ /**
11
+ * Mount once (Layout) to drive the retained-page lifecycle from the resolved
12
+ * `ui_page_state_ttl_ms`. Idempotent and inert beyond its three effects.
13
+ */
14
+ export declare function usePageStateRuntime(): void;
15
+ /**
16
+ * Register a screen's PRIMARY heavy read (its list or detail query key) with the
17
+ * current retained page, so a kill/sweep `removeQueries` releases the cached
18
+ * data alongside the deep state. Call from the standard pages (and custom
19
+ * screens) with the key from the matching key-builder (`entityDataQueryKey` /
20
+ * `cursorEntityDataQueryKey` / `entityItemQueryKey`).
21
+ *
22
+ * Pass ONLY primary heavy reads - never a shared ref/lookup query, or a
23
+ * sibling screen that shares its key would lose it on this page's eviction.
24
+ * `enabled` (default true) lets the cursor/offset pages register exactly the
25
+ * read they actually use.
26
+ */
27
+ export declare function useRegisterRetainedQuery(queryKey: QueryKey | undefined, enabled?: boolean): void;
@@ -0,0 +1,11 @@
1
+ /** The platform parameter governing retained-page retention. Declared in
2
+ * modules/_platform/schema/core_parameters.yaml (int, category `ui`,
3
+ * `[tenant]`, env `DECLARION_UI_PAGE_STATE_TTL_MS`). */
4
+ export declare const PAGE_STATE_TTL_PARAM = "ui_page_state_ttl_ms";
5
+ /**
6
+ * Resolve the retention window in milliseconds. Returns the per-tenant value
7
+ * once the parameter loads, the YAML-mirrored default before then, and clamps a
8
+ * malformed value to the default (never NaN/negative). `0` is honored as
9
+ * "retention disabled".
10
+ */
11
+ export declare function usePageStateTtl(): number;
@@ -1,2 +1,11 @@
1
1
  import { type Entity, type Screen } from "../types/schema";
2
+ /**
3
+ * The embed-guarded tab registration shared by the schema-driven Smart pages
4
+ * (`useRegisterScreenTab`) and the public custom-screen hook (`useScreenTab`),
5
+ * so the "open a tab for this screen" logic - and its embed guard - lives in one
6
+ * place. Registers `route` as a tab once; `search` is captured at first
7
+ * registration (the mirror syncs later changes), so it is excluded from the
8
+ * effect deps. No-op when `route` is absent or embed mode is on (Invariant 8).
9
+ */
10
+ export declare function useScreenTabRegistration(route: string | undefined, title: string, icon: string | undefined, search: string): void;
2
11
  export declare function useRegisterScreenTab(screen: Screen | undefined, entity: Entity | undefined, search: string): void;
@@ -0,0 +1,10 @@
1
+ export interface UseScreenTabOptions {
2
+ /** The tab's route. Defaults to the live `location.pathname` - the right value
3
+ * for a param-less custom screen, which is the common case. */
4
+ route?: string;
5
+ /** Tab title. Defaults to the route when omitted. */
6
+ title?: string;
7
+ /** Tab icon name (resolved by the icon registry). */
8
+ icon?: string;
9
+ }
10
+ export declare function useScreenTab(opts?: UseScreenTabOptions): void;
@@ -16,11 +16,13 @@ export { useSchema } from "./hooks/useSchema";
16
16
  export { useEntity } from "./hooks/useEntity";
17
17
  export { useScreen } from "./hooks/useScreen";
18
18
  export { useAuth } from "./hooks/useAuth";
19
- export { useEntityData, useEntityCount } from "./hooks/useEntityData";
20
- export { useCursorEntityData } from "./hooks/useCursorEntityData";
19
+ export { useEntityData, useEntityCount, entityDataQueryKey } from "./hooks/useEntityData";
20
+ export { useCursorEntityData, cursorEntityDataQueryKey, cursorEntityStableKey, } from "./hooks/useCursorEntityData";
21
21
  export type { CursorEntityDataParams, CursorEntityDataResult, } from "./hooks/useCursorEntityData";
22
22
  export { useAllEntityData } from "./hooks/useAllEntityData";
23
- export { useEntityItem } from "./hooks/useEntityItem";
23
+ export { useEntityItem, entityItemQueryKey } from "./hooks/useEntityItem";
24
+ export { useActionData, useCursorActionData, actionDataQueryKey, cursorActionDataQueryKey, ACTION_DATA_KEY, ACTION_DATA_CURSOR_KEY, } from "./hooks/useActionData";
25
+ export type { ActionListPage, CursorActionDataResult } from "./hooks/useActionData";
24
26
  export { useCreateEntity, useUpdateEntity, useDeleteEntity } from "./hooks/useMutations";
25
27
  export { useDebounce } from "./hooks/useDebounce";
26
28
  export { usePublicParams, useResolvedParam, useParam } from "./hooks/useParams";
@@ -38,6 +40,17 @@ export { useTabStore, type TabItem, type ReturnTarget } from "./stores/tabs";
38
40
  export { useTabNavigate } from "./hooks/useTabNavigate";
39
41
  export { useScreenBack } from "./hooks/useScreenBack";
40
42
  export type { UseScreenBackOptions, ScreenBack } from "./hooks/useScreenBack";
43
+ export { usePageState } from "./hooks/usePageState";
44
+ export type { PageStateSetter } from "./hooks/usePageState";
45
+ export { canonicalUrl } from "./lib/canonical-url";
46
+ export type { CanonicalLocation } from "./lib/canonical-url";
47
+ export { useRegisterRetainedQuery } from "./hooks/usePageStateRuntime";
48
+ export { usePageStateTtl, PAGE_STATE_TTL_PARAM } from "./hooks/usePageStateTtl";
49
+ export { useScreenTab } from "./hooks/useScreenTab";
50
+ export type { UseScreenTabOptions } from "./hooks/useScreenTab";
51
+ export { useTabSearchMirror } from "./hooks/useTabSearchMirror";
52
+ export { useVirtualScrollRestoration, usePlainScrollRestoration, useSavedScrollOffset, SCROLL_STATE_KEY, } from "./lib/scroll-restoration";
53
+ export type { ScrollAnchor, ScrollableVirtualizer } from "./lib/scroll-restoration";
41
54
  export { SmartListPage } from "./components/pages/SmartListPage";
42
55
  export { SmartDetailPage } from "./components/pages/SmartDetailPage";
43
56
  export { SmartRecordListPage } from "./components/pages/SmartRecordListPage";