@declarion/react 0.48.2 → 0.50.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/Check-DAfMbQIw.js +38 -0
- package/dist-lib/{DraggableChildrenTable-p2ZSdwzj.js → DraggableChildrenTable-Dar8C-Z9.js} +31 -31
- package/dist-lib/DynamicIcon-DW5krHuX.js +280 -0
- package/dist-lib/{Grid-CjLFAKMZ.js → Grid-BkHtfsty.js} +2 -2
- package/dist-lib/{LayoutRenderer-DCscqXsv.js → LayoutRenderer-Cic7IAop.js} +601 -598
- package/dist-lib/ListCardsBody-Dko91bLv.js +287 -0
- package/dist-lib/{MarkdownRenderer-Sb7zcvj0.js → MarkdownRenderer-CJrVG5HZ.js} +1 -1
- package/dist-lib/RefreshControl-BS8WWL8i.js +430 -0
- package/dist-lib/{SmartDetailPage.impl-BAW-Tx_H.js → SmartDetailPage.impl-DxRDo0p2.js} +521 -516
- package/dist-lib/SmartListPage.impl-CNdq5Vts.js +2849 -0
- package/dist-lib/{SmartRecordListPage.impl-DtSSlGrI.js → SmartRecordListPage.impl-3ct7f4rT.js} +244 -241
- package/dist-lib/SortHeaderMenu-NgjkW8QZ.js +106 -0
- package/dist-lib/action-dispatch-hVrm3Hrg.js +1984 -0
- package/dist-lib/api/batch.d.ts +5 -2
- package/dist-lib/api/data.d.ts +35 -4
- package/dist-lib/api/entities.d.ts +3 -3
- package/dist-lib/cardProjection-BR-fXPvJ.js +757 -0
- package/dist-lib/components/{shared → actions}/ObjectActionBar.d.ts +1 -1
- package/dist-lib/components/{shared → actions}/ResponsiveActionBar.d.ts +1 -1
- package/dist-lib/components/fields/cells/factories/date.d.ts +2 -0
- package/dist-lib/components/file-widgets/upload.d.ts +6 -1
- package/dist-lib/components/layout/Layout.d.ts +1 -1
- package/dist-lib/components/layout/TopBar.d.ts +1 -1
- package/dist-lib/components/pages/SmartListPage.d.ts +2 -12
- package/dist-lib/components/pages/SmartListPage.impl.d.ts +4 -0
- package/dist-lib/components/pages/list/ListCardRow.d.ts +40 -0
- package/dist-lib/components/pages/list/ListCardsBody.d.ts +34 -0
- package/dist-lib/components/pages/list/ListFloatbar.d.ts +1 -1
- package/dist-lib/components/pages/list/ListFooter.d.ts +26 -0
- package/dist-lib/components/pages/list/ListHeader.d.ts +1 -1
- package/dist-lib/components/pages/list/ListNoRows.d.ts +32 -0
- package/dist-lib/components/pages/list/ListTable.d.ts +34 -0
- package/dist-lib/components/pages/list/ListTableRow.d.ts +18 -0
- package/dist-lib/components/pages/list/ListToolbar.d.ts +43 -0
- package/dist-lib/components/pages/list/SortHeaderMenu.d.ts +14 -0
- package/dist-lib/components/pages/list/page-size.d.ts +3 -0
- package/dist-lib/components/pages/list/sortable-header.d.ts +2 -0
- package/dist-lib/components/pages/list/useListColumnLayout.d.ts +37 -0
- package/dist-lib/components/pages/list/useListQuery.d.ts +66 -0
- package/dist-lib/components/pages/list/useListRowInteraction.d.ts +61 -0
- package/dist-lib/components/pages/list/useListSelection.d.ts +31 -0
- package/dist-lib/components/pages/list/useListSort.d.ts +45 -0
- package/dist-lib/components/pages/list/useListViews.d.ts +46 -0
- package/dist-lib/components/pages/list/useRowMenu.d.ts +1 -1
- package/dist-lib/components/primitives/Icons.d.ts +5 -0
- package/dist-lib/components/shared/RefreshControl.d.ts +17 -4
- package/dist-lib/field-classification-Bm0mgbwA.js +1134 -0
- package/dist-lib/format-count-BfRGwx2v.js +1551 -0
- package/dist-lib/hooks/useBrandingChrome.d.ts +17 -1
- package/dist-lib/hooks/useText.d.ts +3 -0
- package/dist-lib/hooks/useViews.d.ts +1 -1
- package/dist-lib/icons.js +1 -1
- package/dist-lib/index.d.ts +17 -15
- package/dist-lib/index.js +1784 -6288
- package/dist-lib/lib/messages.d.ts +7 -1
- package/dist-lib/lib/rowClickGesture.d.ts +12 -0
- package/dist-lib/lib/timestamp.d.ts +8 -3
- package/dist-lib/peekDraftStore-bb4WroTA.js +194 -0
- package/dist-lib/record-documents-key-8fdm7C10.js +27 -0
- package/dist-lib/registry-CgeGoWpW.js +1768 -0
- package/dist-lib/testing.d.ts +17 -2
- package/dist-lib/testing.js +72 -58
- package/dist-lib/types/api.d.ts +54 -12
- package/dist-lib/types/schema.d.ts +22 -6
- package/dist-lib/{useCurrentScreen-BshVTPVq.js → useCurrentScreen-D3XH5ptA.js} +1127 -1070
- package/dist-lib/useListQuery-CfuINl-0.js +87 -0
- package/dist-lib/useProperties-DNocaxBX.js +81 -0
- package/dist-lib/{useProperties-DrHFr0A1.js → useTabSearchMirror-d0BAUIcQ.js} +116 -194
- package/dist-lib/{value-B1O6QikE.js → value-D71J0sJq.js} +69 -69
- package/package.json +1 -1
- package/dist-lib/DynamicIcon-Dc2j-rg_.js +0 -275
- package/dist-lib/RefreshControl-Cnl9nE0x.js +0 -945
- package/dist-lib/registry-CCxnZW2b.js +0 -5281
- /package/dist-lib/components/{shared → actions}/ActionButton.d.ts +0 -0
- /package/dist-lib/components/{shared → actions}/ActionDialog.d.ts +0 -0
- /package/dist-lib/components/{shared → actions}/ActionResultDialog.d.ts +0 -0
- /package/dist-lib/components/{shared → actions}/ActionRunner.d.ts +0 -0
- /package/dist-lib/components/{mass-edit → actions}/PropertyGridEditor.d.ts +0 -0
- /package/dist-lib/components/{shared → actions}/RowActionsKebab.d.ts +0 -0
- /package/dist-lib/components/{shared → chrome}/AssociationTabs.d.ts +0 -0
- /package/dist-lib/components/{shared → chrome}/AuditMetaStrip.d.ts +0 -0
- /package/dist-lib/components/{shared → chrome}/Breadcrumbs.d.ts +0 -0
- /package/dist-lib/components/{shared → chrome}/HighlightsStrip.d.ts +0 -0
- /package/dist-lib/components/{shared → chrome}/PageHeader.d.ts +0 -0
- /package/dist-lib/components/{shared → chrome}/RecordHeader.d.ts +0 -0
- /package/dist-lib/components/{shell → layout}/CommandPalette.d.ts +0 -0
- /package/dist-lib/components/{columns → list}/ColumnPicker.d.ts +0 -0
- /package/dist-lib/components/{views → list}/ViewSwitcher.d.ts +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import { type ResolvedActionLayoutNode } from "../../lib/actions";
|
|
3
3
|
import { type Action } from "../../types/schema";
|
|
4
|
-
import { type WidgetContext } from "../../components/
|
|
4
|
+
import { type WidgetContext } from "../../components/actions/ResponsiveActionBar";
|
|
5
5
|
export type ObjectActionBarSlot = "detail" | "detail_toolbar" | "list_row" | "quick_peek";
|
|
6
6
|
export type ObjectActionSelection = {
|
|
7
7
|
include: string[];
|
|
@@ -232,7 +232,7 @@ interface LayoutDecision {
|
|
|
232
232
|
*/
|
|
233
233
|
iconOnly: ReadonlySet<string>;
|
|
234
234
|
}
|
|
235
|
-
export declare function computeLayout(nodes: ResolvedActionLayoutNode[], containerWidth: number, reservedRightWidth: number, measuredWidths: Map<string, number>, entityActions: Record<string, Action> | undefined, globalActions: Record<string, Action> | undefined, measurementOverride?: (node: ResolvedActionLayoutNode) => boolean, prevInline?: ReadonlySet<string>,
|
|
235
|
+
export declare function computeLayout(nodes: ResolvedActionLayoutNode[], containerWidth: number, reservedRightWidth: number, measuredWidths: Map<string, number>, entityActions: Record<string, Action> | undefined, globalActions: Record<string, Action> | undefined, measurementOverride?: (node: ResolvedActionLayoutNode) => boolean, prevInline?: ReadonlySet<string>, prevIconOnly?: ReadonlySet<string>): LayoutDecision;
|
|
236
236
|
/**
|
|
237
237
|
* slotIsContentSized answers the only question the contract check may act on:
|
|
238
238
|
* is the box holding this bar sized BY the bar?
|
|
@@ -8,9 +8,14 @@ export interface UploadOptions {
|
|
|
8
8
|
signal?: AbortSignal;
|
|
9
9
|
}
|
|
10
10
|
export declare class UploadError extends Error {
|
|
11
|
+
/** The declared type's identifier, e.g. `file.too_large`. */
|
|
11
12
|
code: string;
|
|
12
13
|
status: number;
|
|
13
|
-
|
|
14
|
+
/** The untouched body, so a declared member reaches a caller through ext(). */
|
|
15
|
+
raw?: unknown;
|
|
16
|
+
constructor(status: number, code: string, message: string, raw?: unknown);
|
|
17
|
+
/** A declared member of this error's type, read the one way. */
|
|
18
|
+
ext<T = unknown>(member: string): T | undefined;
|
|
14
19
|
}
|
|
15
20
|
export interface UploadEnvelope {
|
|
16
21
|
status: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useTabStore } from "../../stores/tabs";
|
|
2
2
|
import { type NavNode, type Screen } from "../../types/schema";
|
|
3
|
-
import type { Crumb } from "../../components/
|
|
3
|
+
import type { Crumb } from "../../components/chrome/Breadcrumbs";
|
|
4
4
|
export declare function Layout(): import("react").JSX.Element | null;
|
|
5
5
|
export declare function buildCrumbs(nodes: NavNode[], screens: Record<string, Screen>, pathname: string, tabs: ReturnType<typeof useTabStore.getState>["tabs"], activeTabId: string | null, topLevelNavigate: (to: string) => void): Crumb[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type RefObject } from "react";
|
|
2
|
-
import { type Crumb } from "../../components/
|
|
2
|
+
import { type Crumb } from "../../components/chrome/Breadcrumbs";
|
|
3
3
|
export interface TopBarProps {
|
|
4
4
|
breadcrumbs?: Crumb[];
|
|
5
5
|
onCrumbClick?: (c: Crumb) => void;
|
|
@@ -1,12 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
interface SmartListPageProps {
|
|
4
|
-
screenCode: string;
|
|
5
|
-
}
|
|
6
|
-
export declare const PER_PAGE_MAX = 1000;
|
|
7
|
-
export declare const PER_PAGE_DEFAULT = 200;
|
|
8
|
-
export declare const PER_PAGE_OPTIONS: readonly [25, 50, 100, 200, 500, 1000];
|
|
9
|
-
export declare function rowSelectionKey(entity: Entity, row: RowData): string;
|
|
10
|
-
export declare function selectedRowPkValues(entity: Entity | undefined, rows: RowData[], selectedKeys: string[]): PkValues[];
|
|
11
|
-
export declare function SmartListPage({ screenCode }: SmartListPageProps): import("react").JSX.Element;
|
|
12
|
-
export {};
|
|
1
|
+
import type { SmartListPageProps } from "./SmartListPage.impl";
|
|
2
|
+
export declare function SmartListPage(props: SmartListPageProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Row } from "@tanstack/react-table";
|
|
2
|
+
import type { ListResponse, RowData } from "../../../types/api";
|
|
3
|
+
import { type Action, type Entity, type Screen } from "../../../types/schema";
|
|
4
|
+
import type { resolveCellRenderer } from "../../../components/fields/cells/registry";
|
|
5
|
+
import type { RowInteraction } from "./useListRowInteraction";
|
|
6
|
+
type CellRenderer = ReturnType<typeof resolveCellRenderer>;
|
|
7
|
+
interface ListCardRowProps {
|
|
8
|
+
row: Row<RowData>;
|
|
9
|
+
/** The ABSOLUTE index, which is what decides striping - the list is
|
|
10
|
+
* virtualized, so `nth-child` would count the render window. */
|
|
11
|
+
rowIndex: number;
|
|
12
|
+
entity: Entity;
|
|
13
|
+
screen: Screen;
|
|
14
|
+
entityCode: string | undefined;
|
|
15
|
+
entities: Record<string, Entity> | undefined;
|
|
16
|
+
/** The active saved view's columns, which the card projection may follow. */
|
|
17
|
+
savedViewColumns: string[] | undefined;
|
|
18
|
+
refs: ListResponse<RowData>["$refs"];
|
|
19
|
+
locale: string;
|
|
20
|
+
renderers: Map<string, CellRenderer>;
|
|
21
|
+
rowActions: {
|
|
22
|
+
code: string;
|
|
23
|
+
action: Action;
|
|
24
|
+
}[];
|
|
25
|
+
tabNavigate: (href: string, meta?: {
|
|
26
|
+
title?: string;
|
|
27
|
+
icon?: string;
|
|
28
|
+
}) => void;
|
|
29
|
+
interaction: RowInteraction;
|
|
30
|
+
hasSoftDelete: boolean;
|
|
31
|
+
zebra: boolean;
|
|
32
|
+
hasBatchActions: boolean;
|
|
33
|
+
hasDetailTarget: boolean;
|
|
34
|
+
/** The row's stable id, which is also TanStack's. */
|
|
35
|
+
rowKey: (row: Record<string, unknown>) => string;
|
|
36
|
+
/** TanStack Virtual's measure ref, so a card sizes itself. */
|
|
37
|
+
measureElement: (node: Element | null) => void;
|
|
38
|
+
}
|
|
39
|
+
export declare function ListCardRow({ row, rowIndex, entity, screen, entityCode, entities, savedViewColumns, refs, locale, renderers, rowActions, tabNavigate, interaction, hasSoftDelete, zebra, hasBatchActions, hasDetailTarget, rowKey, measureElement, }: ListCardRowProps): import("react").JSX.Element;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Row } from "@tanstack/react-table";
|
|
2
|
+
import type { Virtualizer } from "@tanstack/react-virtual";
|
|
3
|
+
import type { ListResponse, RowData } from "../../../types/api";
|
|
4
|
+
import type { resolveCellRenderer } from "../../../components/fields/cells/registry";
|
|
5
|
+
import type { Action, Entity, Screen } from "../../../types/schema";
|
|
6
|
+
import type { RowInteraction } from "./useListRowInteraction";
|
|
7
|
+
interface ListCardsBodyProps {
|
|
8
|
+
rows: Row<RowData>[];
|
|
9
|
+
virtualizer: Virtualizer<HTMLDivElement, Element>;
|
|
10
|
+
entity: Entity;
|
|
11
|
+
screen: Screen;
|
|
12
|
+
entityCode: string | undefined;
|
|
13
|
+
entities: Record<string, Entity> | undefined;
|
|
14
|
+
savedViewColumns: string[] | undefined;
|
|
15
|
+
refs: ListResponse<RowData>["$refs"];
|
|
16
|
+
locale: string;
|
|
17
|
+
renderers: Map<string, ReturnType<typeof resolveCellRenderer>>;
|
|
18
|
+
rowActions: {
|
|
19
|
+
code: string;
|
|
20
|
+
action: Action;
|
|
21
|
+
}[];
|
|
22
|
+
tabNavigate: (href: string, meta?: {
|
|
23
|
+
title?: string;
|
|
24
|
+
icon?: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
interaction: RowInteraction;
|
|
27
|
+
hasSoftDelete: boolean;
|
|
28
|
+
zebra: boolean;
|
|
29
|
+
hasBatchActions: boolean;
|
|
30
|
+
hasDetailTarget: boolean;
|
|
31
|
+
rowKey: (row: Record<string, unknown>) => string;
|
|
32
|
+
}
|
|
33
|
+
export declare function ListCardsBody({ rows, virtualizer, ...card }: ListCardsBodyProps): import("react").JSX.Element;
|
|
34
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ResolvedActionLayoutNode } from "../../../lib/actions";
|
|
2
|
-
import { type WidgetContext } from "../../../components/
|
|
2
|
+
import { type WidgetContext } from "../../../components/actions/ResponsiveActionBar";
|
|
3
3
|
import type { Action, Entity, Screen } from "../../../types/schema";
|
|
4
4
|
export interface ListFloatbarProps {
|
|
5
5
|
selectedIds: string[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface ListFooterProps {
|
|
2
|
+
/** An offset list's window shape. Absent on a cursor list. */
|
|
3
|
+
meta: {
|
|
4
|
+
has_more?: boolean;
|
|
5
|
+
} | undefined;
|
|
6
|
+
isCursor: boolean;
|
|
7
|
+
isPhone: boolean;
|
|
8
|
+
rowsLoaded: number;
|
|
9
|
+
selectedCount: number;
|
|
10
|
+
/** The total, and how it was produced. Undefined while the count is in
|
|
11
|
+
* flight or after it failed - the footer degrades to the loaded count. */
|
|
12
|
+
countTotal: number | undefined;
|
|
13
|
+
countStrategy: "exact" | "estimated" | undefined;
|
|
14
|
+
countLoading: boolean;
|
|
15
|
+
countError: boolean;
|
|
16
|
+
page: number;
|
|
17
|
+
totalPages: number | undefined;
|
|
18
|
+
goToPage: (page: number) => void;
|
|
19
|
+
perPage: number;
|
|
20
|
+
setPerPage: (n: number) => void;
|
|
21
|
+
hasMorePages: boolean;
|
|
22
|
+
fetchNextPage: () => void;
|
|
23
|
+
isFetchingNextPage: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function ListFooter({ meta, isCursor, isPhone, rowsLoaded, selectedCount, countTotal, countStrategy, countLoading, countError, page, totalPages, goToPage, perPage, setPerPage, hasMorePages, fetchNextPage, isFetchingNextPage, }: ListFooterProps): import("react").JSX.Element | null;
|
|
26
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ResolvedActionLayoutNode } from "../../../lib/actions";
|
|
2
|
-
import { type WidgetContext } from "../../../components/
|
|
2
|
+
import { type WidgetContext } from "../../../components/actions/ResponsiveActionBar";
|
|
3
3
|
import type { Action } from "../../../types/schema";
|
|
4
4
|
export interface ListHeaderProps {
|
|
5
5
|
title: string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type Action, type Entity, type Screen } from "../../../types/schema";
|
|
3
|
+
/** The sentence a failed load shows: the server's own, then the two members
|
|
4
|
+
* saying WHICH value it is about - without them the reader is told something
|
|
5
|
+
* went wrong and not what to change. Never the machine code, which is already
|
|
6
|
+
* in the console and the audit. */
|
|
7
|
+
export declare function listLoadErrorDescription(error: unknown): string;
|
|
8
|
+
interface ListNoRowsProps {
|
|
9
|
+
isLoading: boolean;
|
|
10
|
+
/** The load has been running long enough to be worth saying so. */
|
|
11
|
+
tableLoadingStale: boolean;
|
|
12
|
+
isError: boolean;
|
|
13
|
+
error: unknown;
|
|
14
|
+
rowCount: number;
|
|
15
|
+
entity: Entity;
|
|
16
|
+
screen: Screen;
|
|
17
|
+
screenName: string;
|
|
18
|
+
screenIcon: string;
|
|
19
|
+
/** A search or a filter is active, so "no results" is the honest title
|
|
20
|
+
* rather than "none yet". */
|
|
21
|
+
isFiltered: boolean;
|
|
22
|
+
/** The empty state invites a create only where the toolbar actually serves
|
|
23
|
+
* one, so `disable_defaults: [__new]` is honoured. */
|
|
24
|
+
canCreate: boolean;
|
|
25
|
+
toolbarActions: {
|
|
26
|
+
code: string;
|
|
27
|
+
action: Action;
|
|
28
|
+
}[];
|
|
29
|
+
onRetry: () => void;
|
|
30
|
+
}
|
|
31
|
+
export declare function ListNoRows({ isLoading, tableLoadingStale, isError, error, rowCount, entity, screen, screenName, screenIcon, isFiltered, canCreate, toolbarActions, onRetry, }: ListNoRowsProps): ReactNode;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type ColumnDef, type Row, type Table } from "@tanstack/react-table";
|
|
3
|
+
import type { Virtualizer } from "@tanstack/react-virtual";
|
|
4
|
+
import { type SortCol, type SortNulls } from "../../../lib/sort";
|
|
5
|
+
import type { RowData } from "../../../types/api";
|
|
6
|
+
import type { Entity } from "../../../types/schema";
|
|
7
|
+
import type { useHeaderReorder } from "./useHeaderReorder";
|
|
8
|
+
interface ListTableProps {
|
|
9
|
+
table: Table<RowData>;
|
|
10
|
+
columns: ColumnDef<RowData>[];
|
|
11
|
+
rows: Row<RowData>[];
|
|
12
|
+
entity: Entity;
|
|
13
|
+
/** Published as CSS variables on the <table> so a resize drag reflows without
|
|
14
|
+
* re-rendering the memoized body. */
|
|
15
|
+
columnSizeVars: Record<string, number>;
|
|
16
|
+
/** The real columns' summed width, which forces the horizontal scroll. */
|
|
17
|
+
totalColumnsWidth: number;
|
|
18
|
+
theadRef: React.RefObject<HTMLTableSectionElement | null>;
|
|
19
|
+
virtualizer: Virtualizer<HTMLDivElement, Element>;
|
|
20
|
+
/** The ordered visible set, which decides a header's drop slot. */
|
|
21
|
+
visibleCols: string[];
|
|
22
|
+
headerReorder: ReturnType<typeof useHeaderReorder>;
|
|
23
|
+
sortCols: SortCol[];
|
|
24
|
+
sortNullsMap: Map<string, SortNulls>;
|
|
25
|
+
shiftClickColumn: (field: string) => void;
|
|
26
|
+
applyColumnSort: (field: string, dir: "asc" | "desc", nulls: SortNulls | undefined) => void;
|
|
27
|
+
appendColumnSort: (field: string, dir: "asc" | "desc", nulls: SortNulls | undefined) => void;
|
|
28
|
+
clearColumnSort: (field: string) => void;
|
|
29
|
+
clearAllSorts: () => void;
|
|
30
|
+
renderRow: (row: Row<RowData>, index: number) => ReactNode;
|
|
31
|
+
isResizingColumn: string | false;
|
|
32
|
+
}
|
|
33
|
+
export declare function ListTable({ table, columns, rows, entity, columnSizeVars, totalColumnsWidth, theadRef, virtualizer: rowVirtualizer, visibleCols, headerReorder, sortCols, sortNullsMap, shiftClickColumn, applyColumnSort, appendColumnSort, clearColumnSort, clearAllSorts, renderRow, isResizingColumn, }: ListTableProps): import("react").JSX.Element;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Row } from "@tanstack/react-table";
|
|
2
|
+
import type { RowData } from "../../../types/api";
|
|
3
|
+
import type { Entity } from "../../../types/schema";
|
|
4
|
+
import type { RowInteraction } from "./useListRowInteraction";
|
|
5
|
+
interface ListTableRowProps {
|
|
6
|
+
row: Row<RowData>;
|
|
7
|
+
rowIndex: number;
|
|
8
|
+
entity: Entity;
|
|
9
|
+
hasSoftDelete: boolean;
|
|
10
|
+
zebra: boolean;
|
|
11
|
+
/** The entity has a detail route. A composite-PK entity has none, so without
|
|
12
|
+
* the peek branch its rows looked dead. */
|
|
13
|
+
hasDetailTarget: boolean;
|
|
14
|
+
interaction: RowInteraction;
|
|
15
|
+
measureElement: (node: Element | null) => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function ListTableRow({ row, rowIndex, entity, hasSoftDelete, zebra, hasDetailTarget, interaction, measureElement, }: ListTableRowProps): import("react").JSX.Element;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { FilterNode } from "../../../lib/filters";
|
|
2
|
+
import { type Entity, type Schema, type Screen } from "../../../types/schema";
|
|
3
|
+
import type { ListColumnLayout } from "./useListColumnLayout";
|
|
4
|
+
import type { ListQueryResult } from "./useListQuery";
|
|
5
|
+
import type { ListSelection } from "./useListSelection";
|
|
6
|
+
import type { ListSortState } from "./useListSort";
|
|
7
|
+
import type { ListViews } from "./useListViews";
|
|
8
|
+
interface ListToolbarProps {
|
|
9
|
+
screen: Screen;
|
|
10
|
+
entity: Entity;
|
|
11
|
+
entityCode: string | undefined;
|
|
12
|
+
schema: Schema | undefined;
|
|
13
|
+
screenCode: string;
|
|
14
|
+
screenName: string;
|
|
15
|
+
locale: string;
|
|
16
|
+
isPhone: boolean;
|
|
17
|
+
/** Cards mode has no column headers, so sorting moves into a menu here. */
|
|
18
|
+
isCardsPresentation: boolean;
|
|
19
|
+
sort: ListSortState;
|
|
20
|
+
columns: ListColumnLayout;
|
|
21
|
+
views: ListViews;
|
|
22
|
+
query: ListQueryResult;
|
|
23
|
+
selection: ListSelection;
|
|
24
|
+
filters: {
|
|
25
|
+
json: FilterNode[];
|
|
26
|
+
debouncedSearch: string;
|
|
27
|
+
count: number;
|
|
28
|
+
onOpen: () => void;
|
|
29
|
+
};
|
|
30
|
+
searchValue: string;
|
|
31
|
+
onSearchChange: (value: string) => void;
|
|
32
|
+
onSaveView: () => void;
|
|
33
|
+
page: number;
|
|
34
|
+
perPage: number;
|
|
35
|
+
includeDeleted: boolean;
|
|
36
|
+
canViewDeleted: boolean;
|
|
37
|
+
onToggleDeleted: () => void;
|
|
38
|
+
/** The entity auto-updates from the CDC relay, so the refresh control shows
|
|
39
|
+
* the Live indicator instead of the button alone. */
|
|
40
|
+
isLive: boolean;
|
|
41
|
+
}
|
|
42
|
+
export declare function ListToolbar({ screen, entity, entityCode, schema, screenCode, screenName, locale, isPhone, isCardsPresentation, sort, columns, views, query, selection, filters, searchValue, onSearchChange, onSaveView, page, perPage, includeDeleted, canViewDeleted, onToggleDeleted, isLive, }: ListToolbarProps): import("react").JSX.Element;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SortNulls } from "../../../lib/sort";
|
|
2
|
+
export declare function SortHeaderMenu({ field, activeDir, activeNulls, inMultiSort, canAppend, onApply, onAppend, onClearColumn, onClearAll, }: {
|
|
3
|
+
field: string;
|
|
4
|
+
activeDir: "asc" | "desc" | false;
|
|
5
|
+
activeNulls: SortNulls | undefined;
|
|
6
|
+
/** True if this column is already part of the current sort list. */
|
|
7
|
+
inMultiSort: boolean;
|
|
8
|
+
/** True if the sort has room to add another column (length < cap). */
|
|
9
|
+
canAppend: boolean;
|
|
10
|
+
onApply: (dir: "asc" | "desc", nulls: SortNulls | undefined) => void;
|
|
11
|
+
onAppend: (dir: "asc" | "desc", nulls: SortNulls | undefined) => void;
|
|
12
|
+
onClearColumn: () => void;
|
|
13
|
+
onClearAll: () => void;
|
|
14
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ColumnSizingState } from "@tanstack/react-table";
|
|
2
|
+
import type { Screen } from "../../../types/schema";
|
|
3
|
+
interface ListColumnLayoutInput {
|
|
4
|
+
screenCode: string;
|
|
5
|
+
screen: Screen | undefined;
|
|
6
|
+
searchParams: URLSearchParams;
|
|
7
|
+
setSearchParams: (next: URLSearchParams) => void;
|
|
8
|
+
}
|
|
9
|
+
/** Which columns a list shows, in what order, and how wide. */
|
|
10
|
+
export interface ListColumnLayout {
|
|
11
|
+
/** The ordered visible set, from `?columns` or the screen/view default. */
|
|
12
|
+
visible: string[];
|
|
13
|
+
/** Live widths during a drag; the device store is the durable backing. */
|
|
14
|
+
sizing: ColumnSizingState;
|
|
15
|
+
setSizing: (updater: ColumnSizingState | ((prev: ColumnSizingState) => ColumnSizingState)) => void;
|
|
16
|
+
/** Apply a new ordered visible set - the one path for toggle, reorder and
|
|
17
|
+
* show-all. */
|
|
18
|
+
apply: (next: string[]) => void;
|
|
19
|
+
/** Back to the screen or view default: drop `?columns`. Widths untouched. */
|
|
20
|
+
clear: () => void;
|
|
21
|
+
/** Drag-free reorder: swap one column a slot up or down. */
|
|
22
|
+
move: (col: string, dir: "up" | "down") => void;
|
|
23
|
+
/** Commit a finished resize to the device store, and say once that widths are
|
|
24
|
+
* personal. */
|
|
25
|
+
commitResize: (sizing: ColumnSizingState) => void;
|
|
26
|
+
resetWidths: () => void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Which columns a list shows, in what order, and how wide.
|
|
30
|
+
*
|
|
31
|
+
* Order, visibility, sort and filters ride the URL, so they are shareable and
|
|
32
|
+
* can be saved into a view. Widths are per DEVICE (localStorage), never sent to
|
|
33
|
+
* the server and never part of a saved view - which is why the two live in
|
|
34
|
+
* different places and why a resize says so the first time.
|
|
35
|
+
*/
|
|
36
|
+
export declare function useListColumnLayout({ screenCode, screen, searchParams, setSearchParams, }: ListColumnLayoutInput): ListColumnLayout;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { FilterNode } from "../../../lib/filters";
|
|
2
|
+
import type { RowData, ListResponse } from "../../../types/api";
|
|
3
|
+
import type { Entity, Screen } from "../../../types/schema";
|
|
4
|
+
interface ListQueryInput {
|
|
5
|
+
entity: Entity | undefined;
|
|
6
|
+
entityCode: string | undefined;
|
|
7
|
+
screen: Screen | undefined;
|
|
8
|
+
screenCode: string;
|
|
9
|
+
page: number;
|
|
10
|
+
perPage: number;
|
|
11
|
+
/** The sort grammar the request carries, already stripped of the segments
|
|
12
|
+
* the backend's strict parser would reject. Undefined when the URL carries
|
|
13
|
+
* no sort and the screen declares no default. */
|
|
14
|
+
sortForRequest: string | undefined;
|
|
15
|
+
debouncedSearch: string;
|
|
16
|
+
filters: FilterNode[];
|
|
17
|
+
/** A malformed `?filters=` bookmark: the list loads unfiltered and the screen
|
|
18
|
+
* shows the error rather than sending something the backend refuses. */
|
|
19
|
+
filterError: boolean;
|
|
20
|
+
includeDeleted: boolean;
|
|
21
|
+
expand: string[] | undefined;
|
|
22
|
+
select: string[] | undefined;
|
|
23
|
+
/** Whether to run the separate count query. A paginated list needs the total
|
|
24
|
+
* to size its pager; a screen that loads one window and shows what it loaded
|
|
25
|
+
* would pay a request per load for a number nothing renders. */
|
|
26
|
+
runCountQuery: boolean;
|
|
27
|
+
/** The canonical form of the URL, so a change resets the stale-loading clock. */
|
|
28
|
+
urlKey: string;
|
|
29
|
+
}
|
|
30
|
+
/** One view over the rows a list screen shows, whichever source produced them. */
|
|
31
|
+
export interface ListQueryResult {
|
|
32
|
+
rows: RowData[];
|
|
33
|
+
meta: ListResponse<RowData>["meta"] | undefined;
|
|
34
|
+
/** Join-expansion data for the loaded window, keyed by entity then id. */
|
|
35
|
+
refs: ListResponse<RowData>["$refs"];
|
|
36
|
+
isLoading: boolean;
|
|
37
|
+
isFetching: boolean;
|
|
38
|
+
isError: boolean;
|
|
39
|
+
error: unknown;
|
|
40
|
+
/** True while a load has been running long enough to be worth saying so. */
|
|
41
|
+
isLoadingStale: boolean;
|
|
42
|
+
retry: () => void;
|
|
43
|
+
/** The total, and how it was produced. Undefined while the count is in flight
|
|
44
|
+
* or after it failed - a caller degrades to the loaded row count. */
|
|
45
|
+
countTotal: number | undefined;
|
|
46
|
+
countStrategy: "exact" | "estimated" | undefined;
|
|
47
|
+
countLoading: boolean;
|
|
48
|
+
countError: boolean;
|
|
49
|
+
totalPages: number | undefined;
|
|
50
|
+
hasMorePages: boolean;
|
|
51
|
+
/** Cursor mode: an archive entity on a ClickHouse deployment, whose
|
|
52
|
+
* cross-store hot+cold read cannot offset-paginate. */
|
|
53
|
+
isCursor: boolean;
|
|
54
|
+
fetchNextPage: () => void;
|
|
55
|
+
isFetchingNextPage: boolean;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The rows a list screen shows: the window query, the separate count query, and
|
|
59
|
+
* one view over whichever of the two sources is live.
|
|
60
|
+
*
|
|
61
|
+
* The window and the count are SEPARATE requests on purpose - the table renders
|
|
62
|
+
* the moment the window resolves and never blocks on a count that may take
|
|
63
|
+
* seconds on a firehose table.
|
|
64
|
+
*/
|
|
65
|
+
export declare function useListQuery(input: ListQueryInput): ListQueryResult;
|
|
66
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { MouseEvent as ReactMouseEvent } from "react";
|
|
2
|
+
import type { QuickPeekFieldSpec } from "../../../components/list/QuickPeek";
|
|
3
|
+
import { useLongPress } from "../../../hooks/useLongPress";
|
|
4
|
+
import type { RowData } from "../../../types/api";
|
|
5
|
+
import { type Action, type Entity, type Screen } from "../../../types/schema";
|
|
6
|
+
interface RowInteractionInput {
|
|
7
|
+
entity: Entity | undefined;
|
|
8
|
+
screen: Screen | undefined;
|
|
9
|
+
screens: Record<string, Screen> | undefined;
|
|
10
|
+
entities: Record<string, Entity> | undefined;
|
|
11
|
+
searchParams: URLSearchParams;
|
|
12
|
+
tabNavigate: (href: string, meta: {
|
|
13
|
+
title?: string;
|
|
14
|
+
icon?: string;
|
|
15
|
+
}) => void;
|
|
16
|
+
/** Commits interaction-owned URL state before navigation, so a click that
|
|
17
|
+
* lands before the passive tab effect runs does not lose it. */
|
|
18
|
+
commitScreenTabSearch: (search: string) => void;
|
|
19
|
+
/** A phone never peeks: the drawer would cover the list it came from. */
|
|
20
|
+
isPhone: boolean;
|
|
21
|
+
canUpdate: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** What a click, a long press or a right-click on a row does. */
|
|
24
|
+
export interface RowInteraction {
|
|
25
|
+
/** Open in the right drawer instead of navigating, when the screen asks for
|
|
26
|
+
* it and the viewport has room. */
|
|
27
|
+
peekAllowed: boolean;
|
|
28
|
+
peekRow: RowData | null;
|
|
29
|
+
setPeekRow: (row: RowData | null) => void;
|
|
30
|
+
peekFields: QuickPeekFieldSpec[];
|
|
31
|
+
peekActions: Record<string, Action>;
|
|
32
|
+
peekExecute: (code: string, action: Action, params: Record<string, unknown>) => Promise<unknown>;
|
|
33
|
+
/** Where the kebab, the right-click and the long press all land. */
|
|
34
|
+
contextMenu: {
|
|
35
|
+
x: number;
|
|
36
|
+
y: number;
|
|
37
|
+
row: RowData;
|
|
38
|
+
} | null;
|
|
39
|
+
setContextMenu: (menu: {
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
row: RowData;
|
|
43
|
+
} | null) => void;
|
|
44
|
+
/** The row a press started on. A ref, not state: it changes on every touch
|
|
45
|
+
* and must not re-render a virtualized list mid-gesture. */
|
|
46
|
+
pressedRow: React.MutableRefObject<RowData | null>;
|
|
47
|
+
longPress: ReturnType<typeof useLongPress>;
|
|
48
|
+
onRowClick: (e: ReactMouseEvent, row: RowData) => void;
|
|
49
|
+
navigateToDetail: (row: RowData, options?: {
|
|
50
|
+
draft?: RowData | null;
|
|
51
|
+
}) => void;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Everything a row responds to.
|
|
55
|
+
*
|
|
56
|
+
* Peek and drill share one gesture, so the peek is DEFERRED by the double-click
|
|
57
|
+
* window: a second click on the same row cancels it and drills into detail
|
|
58
|
+
* instead. An immediately-opened drawer eats that second click.
|
|
59
|
+
*/
|
|
60
|
+
export declare function useListRowInteraction({ entity, screen, screens, entities, searchParams, tabNavigate, commitScreenTabSearch, isPhone, canUpdate, }: RowInteractionInput): RowInteraction;
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RowSelectionState } from "@tanstack/react-table";
|
|
2
|
+
import type { RowData } from "../../../types/api";
|
|
3
|
+
import { type Entity, type PkValues } from "../../../types/schema";
|
|
4
|
+
/** The id a selection is keyed by: the entity's primary key values in the
|
|
5
|
+
* platform's own detail-id encoding, so a composite key selects as stably as a
|
|
6
|
+
* single one and the key round-trips to a detail route. */
|
|
7
|
+
export declare function rowSelectionKey(entity: Entity, row: RowData): string;
|
|
8
|
+
export declare function selectedRowPkValues(entity: Entity | undefined, rows: RowData[], selectedKeys: string[]): PkValues[];
|
|
9
|
+
/** Which rows are selected, and the shapes an action needs them in. */
|
|
10
|
+
export interface ListSelection {
|
|
11
|
+
state: RowSelectionState;
|
|
12
|
+
setState: (updater: RowSelectionState | ((prev: RowSelectionState) => RowSelectionState)) => void;
|
|
13
|
+
/** The selection's row ids, which are also TanStack's row ids. */
|
|
14
|
+
ids: string[];
|
|
15
|
+
/** The same rows as primary key values. */
|
|
16
|
+
pkValues: PkValues[];
|
|
17
|
+
/** The full row objects, resolved from the loaded window. */
|
|
18
|
+
rows: Record<string, unknown>[];
|
|
19
|
+
/** TanStack's `getRowId`, and the key everything else here agrees on. */
|
|
20
|
+
keyOf: (row: Record<string, unknown>) => string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Which rows are selected.
|
|
24
|
+
*
|
|
25
|
+
* The state is DEEP retained-page state rather than URL state, and SCREEN-scoped
|
|
26
|
+
* (`scope: "path"`): it survives a tab switch, Back, and an in-screen filter
|
|
27
|
+
* change. Rows that a change filtered away are PRUNED rather than the selection
|
|
28
|
+
* being blanket-cleared, so a filter that still contains the selected rows keeps
|
|
29
|
+
* them.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useListSelection(entity: Entity | undefined, rows: RowData[], isFetching: boolean): ListSelection;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SortingState } from "@tanstack/react-table";
|
|
2
|
+
import { type SortCol, type SortNulls } from "../../../lib/sort";
|
|
3
|
+
interface ListSortInput {
|
|
4
|
+
searchParams: URLSearchParams;
|
|
5
|
+
setSearchParams: (next: URLSearchParams) => void;
|
|
6
|
+
/** The screen's declared `sort_default`, used when the URL carries none. */
|
|
7
|
+
screenSortDefault: string | undefined;
|
|
8
|
+
/** Commits the URL to the tab store in the same interaction, before React
|
|
9
|
+
* Router schedules the navigation. */
|
|
10
|
+
commitScreenTabSearch: (search: string) => void;
|
|
11
|
+
}
|
|
12
|
+
/** How a list is ordered, and every gesture that changes it. */
|
|
13
|
+
export interface ListSortState {
|
|
14
|
+
/** The parser-filtered columns, which the header and the saved-view path read. */
|
|
15
|
+
cols: SortCol[];
|
|
16
|
+
/** Per-column NULLs placement, which TanStack's `{id, desc}` cannot model. */
|
|
17
|
+
nullsByField: Map<string, SortNulls>;
|
|
18
|
+
/** The raw URL grammar minus the documented `$property.*` deferral, so
|
|
19
|
+
* malformed input still reaches the backend's strict-parse 400 rather than
|
|
20
|
+
* being silently rewritten. */
|
|
21
|
+
forRequest: string | undefined;
|
|
22
|
+
/** The same order in TanStack's own shape. */
|
|
23
|
+
tableSorting: SortingState;
|
|
24
|
+
/** The one writer of the URL `sort` param. */
|
|
25
|
+
write: (cols: SortCol[]) => void;
|
|
26
|
+
/** Replace the whole sort with one column, as a plain header click does. */
|
|
27
|
+
applyColumn: (field: string, dir: "asc" | "desc", nulls: SortNulls | undefined) => void;
|
|
28
|
+
/** Shift-click: toggle this column in or out of the multi-sort tail. */
|
|
29
|
+
shiftClickColumn: (field: string) => void;
|
|
30
|
+
/** Append a column to the tail with a chosen direction and NULLs placement. */
|
|
31
|
+
appendColumn: (field: string, dir: "asc" | "desc", nulls: SortNulls | undefined) => void;
|
|
32
|
+
/** Splice one column out, preserving the rest of the multi-sort. */
|
|
33
|
+
clearColumn: (field: string) => void;
|
|
34
|
+
clearAll: () => void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The list's ordering: parsed from the URL, written back to it through one
|
|
38
|
+
* writer, and offered to the header in the shapes it needs.
|
|
39
|
+
*
|
|
40
|
+
* Every gesture goes through `write`, which commits the tab store before React
|
|
41
|
+
* Router schedules the navigation - that is what closes the mount-effect race
|
|
42
|
+
* for the header, the menu and the mobile sort sheet alike.
|
|
43
|
+
*/
|
|
44
|
+
export declare function useListSort({ searchParams, setSearchParams, screenSortDefault, commitScreenTabSearch, }: ListSortInput): ListSortState;
|
|
45
|
+
export {};
|