@burojs/ui-shadcn 0.4.0 → 0.5.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/README.md +22 -5
- package/dist/bulk-summary-CwSd6Yjb.cjs +108 -0
- package/dist/bulk-summary-CwSd6Yjb.cjs.map +1 -0
- package/dist/bulk-summary-GxMDP4bw.js +108 -0
- package/dist/bulk-summary-GxMDP4bw.js.map +1 -0
- package/dist/button-BxnnE28H.cjs +55 -0
- package/dist/button-BxnnE28H.cjs.map +1 -0
- package/dist/button-MWVeZaqj.js +44 -0
- package/dist/button-MWVeZaqj.js.map +1 -0
- package/dist/candidates-gate-CX2PBu6l.js +63 -0
- package/dist/candidates-gate-CX2PBu6l.js.map +1 -0
- package/dist/candidates-gate-DiFI52r7.cjs +70 -0
- package/dist/candidates-gate-DiFI52r7.cjs.map +1 -0
- package/dist/candidates-relation-picker-CBsVcnPR.js +82 -0
- package/dist/candidates-relation-picker-CBsVcnPR.js.map +1 -0
- package/dist/candidates-relation-picker-Dd_GVLlu.cjs +84 -0
- package/dist/candidates-relation-picker-Dd_GVLlu.cjs.map +1 -0
- package/dist/check-confirm-dialog-BRByTFpg.cjs +1534 -0
- package/dist/check-confirm-dialog-BRByTFpg.cjs.map +1 -0
- package/dist/check-confirm-dialog-CkaVTPT9.js +1232 -0
- package/dist/check-confirm-dialog-CkaVTPT9.js.map +1 -0
- package/dist/dialog-B_rt9S1c.js +63 -0
- package/dist/dialog-B_rt9S1c.js.map +1 -0
- package/dist/dialog-DRNUq9EA.cjs +112 -0
- package/dist/dialog-DRNUq9EA.cjs.map +1 -0
- package/dist/filter-builder-B3mZFL-K.cjs +1761 -0
- package/dist/filter-builder-B3mZFL-K.cjs.map +1 -0
- package/dist/filter-builder-DOnaXNfP.js +1605 -0
- package/dist/filter-builder-DOnaXNfP.js.map +1 -0
- package/dist/flow-runtime-B6zOHYqI.cjs +255 -0
- package/dist/flow-runtime-B6zOHYqI.cjs.map +1 -0
- package/dist/flow-runtime-D8h99FSg.js +252 -0
- package/dist/flow-runtime-D8h99FSg.js.map +1 -0
- package/dist/flow-screen-CX05b3G9.cjs +705 -0
- package/dist/flow-screen-CX05b3G9.cjs.map +1 -0
- package/dist/flow-screen-CmbARSqg.js +701 -0
- package/dist/flow-screen-CmbARSqg.js.map +1 -0
- package/dist/index.cjs +2825 -11912
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1612 -1862
- package/dist/index.d.ts +1700 -1950
- package/dist/index.js +2498 -11605
- package/dist/index.js.map +1 -1
- package/dist/inline-flow-host-B7U1OJUe.cjs +112 -0
- package/dist/inline-flow-host-B7U1OJUe.cjs.map +1 -0
- package/dist/inline-flow-host-C3H2UpSA.js +112 -0
- package/dist/inline-flow-host-C3H2UpSA.js.map +1 -0
- package/dist/input-BI0czGyI.cjs +23 -0
- package/dist/input-BI0czGyI.cjs.map +1 -0
- package/dist/input-CUPStzZO.js +17 -0
- package/dist/input-CUPStzZO.js.map +1 -0
- package/dist/label-66W1qbke.js +29 -0
- package/dist/label-66W1qbke.js.map +1 -0
- package/dist/label-w6JYf2cF.cjs +36 -0
- package/dist/label-w6JYf2cF.cjs.map +1 -0
- package/dist/lazy-relation-picker-dialog-2oxnA6IR.js +14 -0
- package/dist/lazy-relation-picker-dialog-2oxnA6IR.js.map +1 -0
- package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs +19 -0
- package/dist/lazy-relation-picker-dialog-BfAGKzUG.cjs.map +1 -0
- package/dist/markdown/index.cjs +1 -1
- package/dist/markdown/index.js +1 -1
- package/dist/page-flow-route-CQ7HsbBm.cjs +277 -0
- package/dist/page-flow-route-CQ7HsbBm.cjs.map +1 -0
- package/dist/page-flow-route-CyXSvXSE.js +277 -0
- package/dist/page-flow-route-CyXSvXSE.js.map +1 -0
- package/dist/peek-filter-CnqHwTMU.cjs +51 -0
- package/dist/peek-filter-CnqHwTMU.cjs.map +1 -0
- package/dist/peek-filter-ErLfO153.js +28 -0
- package/dist/peek-filter-ErLfO153.js.map +1 -0
- package/dist/place-node--GdsP688.js +7315 -0
- package/dist/place-node--GdsP688.js.map +1 -0
- package/dist/place-node-SIp4XYQH.cjs +7833 -0
- package/dist/place-node-SIp4XYQH.cjs.map +1 -0
- package/dist/related-list-cards-B6x9HQQp.js +42 -0
- package/dist/related-list-cards-B6x9HQQp.js.map +1 -0
- package/dist/related-list-cards-nxuODlIA.cjs +42 -0
- package/dist/related-list-cards-nxuODlIA.cjs.map +1 -0
- package/dist/related-list-timeline-BYJKEbmA.cjs +142 -0
- package/dist/related-list-timeline-BYJKEbmA.cjs.map +1 -0
- package/dist/related-list-timeline-DEdfd-rr.js +142 -0
- package/dist/related-list-timeline-DEdfd-rr.js.map +1 -0
- package/dist/related-rows-B4levHcR.js +186 -0
- package/dist/related-rows-B4levHcR.js.map +1 -0
- package/dist/related-rows-zh5f_4QR.cjs +209 -0
- package/dist/related-rows-zh5f_4QR.cjs.map +1 -0
- package/dist/relation-create-BOaUe12G.cjs +362 -0
- package/dist/relation-create-BOaUe12G.cjs.map +1 -0
- package/dist/relation-create-Bg-eEJLs.js +337 -0
- package/dist/relation-create-Bg-eEJLs.js.map +1 -0
- package/dist/relation-many-picker-B-NCEUgX.cjs +465 -0
- package/dist/relation-many-picker-B-NCEUgX.cjs.map +1 -0
- package/dist/relation-many-picker-gdAOD-qK.js +464 -0
- package/dist/relation-many-picker-gdAOD-qK.js.map +1 -0
- package/dist/relation-picker-BAY77ivO.js +462 -0
- package/dist/relation-picker-BAY77ivO.js.map +1 -0
- package/dist/relation-picker-Da_uhFvA.cjs +479 -0
- package/dist/relation-picker-Da_uhFvA.cjs.map +1 -0
- package/dist/relation-picker-dialog-M0pQaWlp.cjs +300 -0
- package/dist/relation-picker-dialog-M0pQaWlp.cjs.map +1 -0
- package/dist/relation-picker-dialog-hA9rYrZB.js +299 -0
- package/dist/relation-picker-dialog-hA9rYrZB.js.map +1 -0
- package/dist/resource-page-router-OSQyRA5b.cjs +1779 -0
- package/dist/resource-page-router-OSQyRA5b.cjs.map +1 -0
- package/dist/resource-page-router-T4vS5gbJ.js +1582 -0
- package/dist/resource-page-router-T4vS5gbJ.js.map +1 -0
- package/dist/{rich-text-IDFvyvRE.js → rich-text-DFerywgz.js} +7 -4
- package/dist/{rich-text-IDFvyvRE.js.map → rich-text-DFerywgz.js.map} +1 -1
- package/dist/{rich-text-lndbYqzR.cjs → rich-text-vTyVjDoa.cjs} +25 -22
- package/dist/{rich-text-lndbYqzR.cjs.map → rich-text-vTyVjDoa.cjs.map} +1 -1
- package/dist/search-access-B7G5oR8n.cjs +812 -0
- package/dist/search-access-B7G5oR8n.cjs.map +1 -0
- package/dist/search-access-CURsWn-U.js +669 -0
- package/dist/search-access-CURsWn-U.js.map +1 -0
- package/dist/shell-BPlk8hEa.js +205 -0
- package/dist/shell-BPlk8hEa.js.map +1 -0
- package/dist/shell-DxhlsPwm.cjs +271 -0
- package/dist/shell-DxhlsPwm.cjs.map +1 -0
- package/dist/skeleton-U2noefj5.js +13 -0
- package/dist/skeleton-U2noefj5.js.map +1 -0
- package/dist/skeleton-_1gP7wan.cjs +18 -0
- package/dist/skeleton-_1gP7wan.cjs.map +1 -0
- package/dist/styles.css +241 -9
- package/dist/toaster-C7CiYA4Z.cjs +248 -0
- package/dist/toaster-C7CiYA4Z.cjs.map +1 -0
- package/dist/toaster-CfCRLgR-.js +164 -0
- package/dist/toaster-CfCRLgR-.js.map +1 -0
- package/dist/use-dialog-filter-state-BBCC0OEK.cjs +92 -0
- package/dist/use-dialog-filter-state-BBCC0OEK.cjs.map +1 -0
- package/dist/use-dialog-filter-state-BDcgS5Oz.js +87 -0
- package/dist/use-dialog-filter-state-BDcgS5Oz.js.map +1 -0
- package/dist/{use-theme-BwPWinB2.cjs → use-theme-DFlpXils.cjs} +12 -1
- package/dist/use-theme-DFlpXils.cjs.map +1 -0
- package/dist/{use-theme-IHmtrhEt.js → use-theme-dnE3Od3I.js} +7 -2
- package/dist/use-theme-dnE3Od3I.js.map +1 -0
- package/package.json +16 -14
- package/dist/use-theme-BwPWinB2.cjs.map +0 -1
- package/dist/use-theme-IHmtrhEt.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { t as THEME_STORAGE_KEY } from "./theme-storage-key-pYlp4aDS.cjs";
|
|
2
2
|
import * as React$1 from "react";
|
|
3
|
-
import { AnchorHTMLAttributes,
|
|
4
|
-
import { ActionDensity, AppRuntime, Check, CheckSurface, CustomPageDef,
|
|
5
|
-
import {
|
|
6
|
-
import { CheckGateState, FieldBinding, FieldImplementation, FieldPresentation, FilterFieldSpec, FilterKind, FormValues, RecentRecord, RowRecord, SavedViewEntry, UIPresentationHostProps, UIPresentationHosts, UseDeclarativeFormOptions, modeForSurface } from "@burojs/react";
|
|
3
|
+
import { AnchorHTMLAttributes, ComponentProps, ComponentType, JSX, ReactElement, ReactNode, SVGProps } from "react";
|
|
4
|
+
import { ActionDensity, AnyFrameHandle, AppRuntime, AuthResult, Check, CheckSurface, CustomPageDef, DraftOption, EntityRef, ErasedResourceHandle, ExportArtifact, ExportTarget, FieldDeclaration, FilterExpression, FilterGroup, FilterOperator, FixedFilterInput, FormBody, FrameHandle, HrefOpts, I18nCaps, NavGroupDef, NavNode, PortableValue, RelationOpen, ResolvedFixedFilter, ResourceDef, ResourceFieldMap, ResourceHandle, RouteMatch, SavedViewDef, ScreenMode, ScreenSources, SearchDecl, SectionDef, SortExpression, StandardSchemaV1, TaskRunReport, UiSettingsIssue, ValidationIssues, ValueCodec, i18nPrefixToRef } from "@burojs/core";
|
|
5
|
+
import { BlockImplementationCatalog, CheckGateState, CollectionDisplayProps, CollectionInputProps, DEFAULT_LANGUAGE_STORAGE_KEY, FieldBinding, FieldImplementation, FieldImplementationLayout, FieldPresentation, FilterFieldSpec, FilterKind, FormValues, QuickSettledRow, RowRecord, SavedViewEntry, ScalarDisplayProps, ScalarInputProps, UIPresentationHostProps, UIPresentationHosts, UseFormControllerFormOptions, modeForSurface } from "@burojs/react";
|
|
7
6
|
import { ToasterProps as ToasterProps$1, toast } from "sonner";
|
|
8
7
|
import { z } from "zod";
|
|
9
8
|
import { isImage } from "@burojs/file-storage";
|
|
@@ -13,7 +12,7 @@ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
|
13
12
|
import { Command as Command$1 } from "cmdk";
|
|
14
13
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
15
14
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
16
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
15
|
+
import { Slot as Slot$1 } from "@radix-ui/react-slot";
|
|
17
16
|
import { ControllerProps, FieldPath, FieldValues } from "react-hook-form";
|
|
18
17
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
19
18
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
@@ -188,7 +187,11 @@ declare function CommandPaletteDocsGroup({ locale, onSelect, heading }: CommandP
|
|
|
188
187
|
//#region src/layout/app-layout.d.ts
|
|
189
188
|
interface AppLayoutProps {
|
|
190
189
|
children: ReactNode;
|
|
191
|
-
/**
|
|
190
|
+
/**
|
|
191
|
+
* The sidebar tree — typically <AppSidebar .../>. `null` (or `undefined`/`false`) means no
|
|
192
|
+
* sidebar at all: the layout then mounts no `SidebarProvider`, so `useOptionalSidebar()` is
|
|
193
|
+
* null below it and `AppHeader` drops its trigger.
|
|
194
|
+
*/
|
|
192
195
|
sidebar: ReactNode;
|
|
193
196
|
/** The header tree — typically <AppHeader .../>. */
|
|
194
197
|
header?: ReactNode;
|
|
@@ -212,56 +215,31 @@ interface AppLayoutProps {
|
|
|
212
215
|
*/
|
|
213
216
|
declare function AppLayout({ children, sidebar, header, docPanel }: AppLayoutProps): React.ReactElement;
|
|
214
217
|
//#endregion
|
|
218
|
+
//#region src/shell/slot.d.ts
|
|
219
|
+
/**
|
|
220
|
+
* A shell component's slot. Omit it (or pass `undefined`, which is the same
|
|
221
|
+
* thing) to get the component's default; pass `false` to leave the slot
|
|
222
|
+
* empty; pass anything else to replace the default with it. `null` is an
|
|
223
|
+
* element like any other: it replaces the default and renders nothing.
|
|
224
|
+
*/
|
|
225
|
+
type Slot = ReactNode | false;
|
|
226
|
+
//#endregion
|
|
215
227
|
//#region src/layout/app-sidebar.d.ts
|
|
228
|
+
/** Every slot follows {@link Slot}: omit for the default, `false` for nothing, an element to replace. */
|
|
216
229
|
interface AppSidebarProps {
|
|
217
|
-
/** Top of the sidebar
|
|
218
|
-
|
|
219
|
-
/** Scope filters rendered under the
|
|
220
|
-
filters?:
|
|
221
|
-
/** Main navigation
|
|
222
|
-
nav
|
|
223
|
-
/** Footer
|
|
224
|
-
footer?:
|
|
225
|
-
}
|
|
226
|
-
declare function AppSidebar({ switcher, filters, nav, footer }: AppSidebarProps): React.ReactElement;
|
|
227
|
-
//#endregion
|
|
228
|
-
//#region src/layout/sidebar.d.ts
|
|
229
|
-
interface SidebarProps {
|
|
230
|
-
className?: string;
|
|
231
|
-
/** Current pathname for active-link highlight + aria-current. */
|
|
232
|
-
currentPath?: string;
|
|
233
|
-
/**
|
|
234
|
-
* Slot for context pickers (company switcher, product-group, location, etc.)
|
|
235
|
-
* Rendered between the app name and the resource nav links.
|
|
236
|
-
*/
|
|
237
|
-
pickers?: ReactNode;
|
|
238
|
-
/** Slot for content rendered below the resource nav links (footer, version, etc.) */
|
|
239
|
-
footer?: ReactNode;
|
|
240
|
-
/**
|
|
241
|
-
* Optional static nav links rendered ABOVE the resource list (e.g. external
|
|
242
|
-
* URLs, conditional links). Consumer provides the JSX. For declarative
|
|
243
|
-
* registered pages, prefer `defineCustomPage` + `app.use(...)` — those are
|
|
244
|
-
* auto-rendered between this slot and the Resources header. The two
|
|
245
|
-
* coexist so adopters can migrate incrementally.
|
|
246
|
-
*/
|
|
247
|
-
topNav?: ReactNode;
|
|
248
|
-
/**
|
|
249
|
-
* Optional icon resolver invoked for each resource link. Returns a
|
|
250
|
-
* ReactNode (typically a Tabler icon at `h-4 w-4`) rendered to
|
|
251
|
-
* the LEFT of the resource label, mirroring the iar-ui sidebar
|
|
252
|
-
* pattern. Returning `undefined` for a particular resource is fine —
|
|
253
|
-
* that link renders without an icon. The whole prop is optional;
|
|
254
|
-
* adopters who don't supply it get the legacy text-only sidebar.
|
|
255
|
-
*/
|
|
256
|
-
iconForResource?: (def: ResourceDef) => ReactNode;
|
|
257
|
-
/** Same as `iconForResource` but for custom pages (top-level + sectioned). */
|
|
258
|
-
iconForCustomPage?: (def: CustomPageDef) => ReactNode;
|
|
230
|
+
/** Top of the sidebar. Default `<SidebarBrand />` (the `ShellProvider` brand). */
|
|
231
|
+
header?: Slot;
|
|
232
|
+
/** Scope filters rendered under the header. No default. */
|
|
233
|
+
filters?: Slot;
|
|
234
|
+
/** Main navigation. Default `<NavMain />`. */
|
|
235
|
+
nav?: Slot;
|
|
236
|
+
/** Footer. Default `<UserMenu />`, which renders nothing without an auth provider. */
|
|
237
|
+
footer?: Slot;
|
|
259
238
|
}
|
|
260
|
-
declare function
|
|
239
|
+
declare function AppSidebar({ header, filters, nav, footer }: AppSidebarProps): React.ReactElement;
|
|
261
240
|
//#endregion
|
|
262
241
|
//#region src/layout/nav-main.d.ts
|
|
263
242
|
interface NavMainProps {
|
|
264
|
-
currentPath?: string;
|
|
265
243
|
iconForResource?: (def: ResourceDef) => ReactNode;
|
|
266
244
|
iconForCustomPage?: (def: CustomPageDef) => ReactNode;
|
|
267
245
|
/** Icon for a collapsible section's trigger row (#16). */
|
|
@@ -287,7 +265,67 @@ interface NavMainProps {
|
|
|
287
265
|
*/
|
|
288
266
|
topLabel?: string | null;
|
|
289
267
|
}
|
|
290
|
-
declare function NavMain({ topLabel,
|
|
268
|
+
declare function NavMain({ topLabel, iconForResource, iconForCustomPage, iconForSection, entryFilter }: NavMainProps): React.ReactElement;
|
|
269
|
+
//#endregion
|
|
270
|
+
//#region src/layout/use-nav-tree.d.ts
|
|
271
|
+
/**
|
|
272
|
+
* How a group presents its children. `flat` and `collapsible` expand inline in
|
|
273
|
+
* the sidebar; any other value is the key of a registered content layout
|
|
274
|
+
* (`tabs`, `secondary-sidebar`, or an app's own), and the sidebar shows the
|
|
275
|
+
* group as ONE link into its area.
|
|
276
|
+
*/
|
|
277
|
+
type NavTreeLayout = 'flat' | 'collapsible' | 'tabs' | 'secondary-sidebar' | (string & {});
|
|
278
|
+
/** One navigable entry. `icon` is the declared icon NAME; the renderer resolves it. */
|
|
279
|
+
type NavTreeEntry = {
|
|
280
|
+
kind: 'resource' | 'page';
|
|
281
|
+
key: string;
|
|
282
|
+
label: string;
|
|
283
|
+
href: string;
|
|
284
|
+
icon?: string;
|
|
285
|
+
active: boolean;
|
|
286
|
+
} | {
|
|
287
|
+
kind: 'group';
|
|
288
|
+
key: string;
|
|
289
|
+
label: string;
|
|
290
|
+
href?: string;
|
|
291
|
+
icon?: string;
|
|
292
|
+
/** For a content group: its link is the current location. Otherwise: an ancestor of it. */
|
|
293
|
+
active: boolean;
|
|
294
|
+
layout: NavTreeLayout;
|
|
295
|
+
/** Declared `defaultOpen`, or the active page lives inside. */
|
|
296
|
+
defaultOpen: boolean;
|
|
297
|
+
children: NavTreeEntry[];
|
|
298
|
+
};
|
|
299
|
+
/**
|
|
300
|
+
* One block of the sidebar. The first block is the ungrouped top level, with
|
|
301
|
+
* `key: null` and `label: null`: the renderer decides its heading. A block with
|
|
302
|
+
* a key and `label: null` is a content group's own link and has no heading.
|
|
303
|
+
*/
|
|
304
|
+
interface NavTreeSection {
|
|
305
|
+
key: string | null;
|
|
306
|
+
label: string | null;
|
|
307
|
+
icon?: string;
|
|
308
|
+
collapsible: boolean;
|
|
309
|
+
/** Open on first render: declared `defaultOpen`, or `active`. */
|
|
310
|
+
defaultOpen: boolean;
|
|
311
|
+
/** One of the entries is the page currently shown. Drives re-opening a collapsed block. */
|
|
312
|
+
active: boolean;
|
|
313
|
+
entries: NavTreeEntry[];
|
|
314
|
+
}
|
|
315
|
+
interface UseNavTreeOptions {
|
|
316
|
+
/**
|
|
317
|
+
* Extra allow-filter applied to every nav entry (resources, custom pages and
|
|
318
|
+
* groups) on top of the built-in visibility rules. Return false to hide an
|
|
319
|
+
* entry. Defaults to always-true.
|
|
320
|
+
*/
|
|
321
|
+
entryFilter?: (entry: NavNode) => boolean;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* The sidebar's navigation as plain data: what `<NavMain>` draws, with every
|
|
325
|
+
* visibility rule, permission gate, sort, label and active flag already
|
|
326
|
+
* applied. Build a custom nav on it and it shows the same entries.
|
|
327
|
+
*/
|
|
328
|
+
declare function useNavTree(opts?: UseNavTreeOptions): NavTreeSection[];
|
|
291
329
|
//#endregion
|
|
292
330
|
//#region src/layout/nav-slots.d.ts
|
|
293
331
|
/** A resolved child entry a layout renderer draws (spec §8.2). */
|
|
@@ -308,33 +346,10 @@ interface NavLayoutProps {
|
|
|
308
346
|
children: ReactNode;
|
|
309
347
|
}
|
|
310
348
|
type NavLayout = ComponentType<NavLayoutProps>;
|
|
311
|
-
/** Components-registry slot key for a layout renderer
|
|
349
|
+
/** Components-registry slot key for a layout renderer: `layout.<key>`. */
|
|
312
350
|
declare function layoutSlot(key: string): string;
|
|
313
|
-
/** Components-registry slot key for a custom page's component. */
|
|
314
|
-
declare function pageSlot(name: string): string;
|
|
315
|
-
/**
|
|
316
|
-
* Components-registry slot key for a `kind: 'component'` tab's body.
|
|
317
|
-
*
|
|
318
|
-
* The declaration and the registration have to name the SAME slot, and until
|
|
319
|
-
* this existed both sides hand-wrote the `'tab.'` prefix — which is how two
|
|
320
|
-
* conventions ended up in the wild (a bare component name, and a full
|
|
321
|
-
* `'tab.…'` key) and why `DetailTabsShell` normalises them. Passing this
|
|
322
|
-
* function's result on both sides makes the two agree by construction:
|
|
323
|
-
*
|
|
324
|
-
* ```ts
|
|
325
|
-
* tabs: [{ kind: 'component', key: 'history', component: tabSlot('document-history') }]
|
|
326
|
-
* components: { [tabSlot('document-history')]: DocumentHistoryTab }
|
|
327
|
-
* ```
|
|
328
|
-
*
|
|
329
|
-
* Idempotent, so `tabSlot(tabSlot('x'))` is `tabSlot('x')` — the shell accepts
|
|
330
|
-
* an already-prefixed key and so does this, rather than producing `tab.tab.x`
|
|
331
|
-
* for an adopter migrating a hand-written literal.
|
|
332
|
-
*/
|
|
333
|
-
declare function tabSlot(name: string): string;
|
|
334
351
|
/** Resolve the registered layout renderer for a `layout` slot key, or undefined. */
|
|
335
352
|
declare function useLayout(key: string): NavLayout | undefined;
|
|
336
|
-
/** Resolve the registered component for a custom page, or undefined. */
|
|
337
|
-
declare function usePageComponent(name: string): ComponentType<Record<string, never>> | undefined;
|
|
338
353
|
/**
|
|
339
354
|
* Non-hook-in-loop layout lookup: read the Components registry once, return a
|
|
340
355
|
* resolver `(key) => NavLayout | undefined`. Lets `NavChrome` resolve a
|
|
@@ -446,59 +461,166 @@ interface ResourcePageRouterProps {
|
|
|
446
461
|
}
|
|
447
462
|
/**
|
|
448
463
|
* Dispatch a resolved `RouteMatch` (from `matchPath`/`useMatch`) to the
|
|
449
|
-
* framework component that renders it.
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
* `
|
|
460
|
-
*
|
|
461
|
-
* - `
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
* the
|
|
468
|
-
* the half that "worked" rendered the stub `<ResourceEdit>` below against a
|
|
469
|
-
* constant record id. Both it and `ResourceConfig.singleton` are gone — read
|
|
470
|
-
* that type for what a one-row screen is expressed with instead.
|
|
471
|
-
*
|
|
472
|
-
* STILL STUBS — framework GLUE, not data-connected:
|
|
473
|
-
* - `show`, `edit`, `create`/`create-wizard`.
|
|
474
|
-
* `ResourceShow`/`ResourceEdit`/`ResourceCreate` are prop-driven: they
|
|
475
|
-
* take an already-loaded `record` and `onSave`/`onCreate` callbacks
|
|
476
|
-
* rather than fetching anything themselves (data fetching is the HOST's
|
|
477
|
-
* job — see the demo app's Next.js app-router pages for the
|
|
478
|
-
* connected pattern). This router has no data provider to draw on for
|
|
479
|
-
* these matches, so it renders the MINIMAL props derivable from the
|
|
480
|
-
* match alone: a stub `record={{ id }}` and no-op save/create callbacks.
|
|
481
|
-
* A host that wants live data for these routes should render its own
|
|
482
|
-
* connected page instead of (or on top of) `<ResourcePageRouter>` — see
|
|
483
|
-
* the playground's `_nav-area-page.tsx`, written for exactly that reason
|
|
484
|
-
* (predating `<ResourceListPage>`, and — per its own dispatcher — still
|
|
485
|
-
* necessary: it feeds the list page an app-level query `meta` and a
|
|
486
|
-
* `renderCell` this generic router has no way to know about).
|
|
487
|
-
*
|
|
488
|
-
* `custom-page`, and `group-index` when a page IS registered, render
|
|
489
|
-
* whatever the adopter registered for that slot — they own their own data
|
|
490
|
-
* by construction, so "real vs. stub" does not apply to them.
|
|
464
|
+
* framework component that renders it. Every branch is data-connected:
|
|
465
|
+
*
|
|
466
|
+
* - `{ kind: 'resource', action: 'list' }` → `<ResourceListPage>`, which
|
|
467
|
+
* self-fetches through `useResourceList`;
|
|
468
|
+
* - `show`, `edit` and `create` → `<RecordRoute>` (the
|
|
469
|
+
* component `<RecordPage>` renders), which reads with `useOne`, writes with
|
|
470
|
+
* `useUpdateOne`/`useCreateOne`, navigates after a write and renders the
|
|
471
|
+
* record states, breadcrumbs and `?tab=`. A record route whose operation
|
|
472
|
+
* the resource turned off (`operations.show: false`, …) renders the
|
|
473
|
+
* not-found panel;
|
|
474
|
+
* - `{ kind: 'group-index' }` → the group's index page when it has a
|
|
475
|
+
* `body`, else that target's list when it is a resource;
|
|
476
|
+
* - `custom-page` → the page's `body` behind the nav gate (`<PageHost>`: a
|
|
477
|
+
* page whose `visible` or whose group's `visible` rejects it renders
|
|
478
|
+
* not-found and mounts nothing); a page without `body` renders not-found,
|
|
479
|
+
* because the host owns that route.
|
|
480
|
+
*
|
|
481
|
+
* A record route always renders the framework's record page: a different layout is a frame on
|
|
482
|
+
* the screen (`views.<mode>.frame`), never a replaced route (P6-56).
|
|
491
483
|
*/
|
|
492
484
|
declare function ResourcePageRouter({ match }: ResourcePageRouterProps): ReactElement;
|
|
493
485
|
/**
|
|
494
|
-
* Resolves the active route (`useMatch
|
|
495
|
-
* chain chrome (`NavChrome`), dispatching to the right
|
|
496
|
-
* via `ResourcePageRouter`. No match → a not-found panel
|
|
497
|
-
*
|
|
498
|
-
*
|
|
486
|
+
* Resolves the active route (`useMatch`, from the router adapter) and renders
|
|
487
|
+
* it inside the group-chain chrome (`NavChrome`), dispatching to the right
|
|
488
|
+
* framework component via `ResourcePageRouter`. No match → a not-found panel;
|
|
489
|
+
* no router adapter at all → the same panel, and in development one
|
|
490
|
+
* `console.error` naming `RouterAdapterProvider` (once per app), because
|
|
491
|
+
* then EVERY route is not-found. Wrapped in a `Suspense` boundary so a
|
|
492
|
+
* lazily-loaded custom page (`React.lazy`) degrades to a skeleton inside the
|
|
493
|
+
* chrome.
|
|
499
494
|
*/
|
|
500
495
|
declare function NavAreaPage(): ReactElement;
|
|
501
496
|
//#endregion
|
|
497
|
+
//#region src/layout/record-page.d.ts
|
|
498
|
+
/**
|
|
499
|
+
* A record page's resource and action. Inside a record slot both default to
|
|
500
|
+
* the route (`<RecordPage defaults={{ type }} />`); outside one both are
|
|
501
|
+
* required, and a missing one renders not-found with a development error.
|
|
502
|
+
* `defaults` exists on `create` only: show and edit render the record as it
|
|
503
|
+
* is, so the type refuses it there rather than ignoring it.
|
|
504
|
+
*/
|
|
505
|
+
type RecordPageProps = {
|
|
506
|
+
readonly resource?: string;
|
|
507
|
+
readonly action: Exclude<ScreenMode, 'create'>;
|
|
508
|
+
readonly defaults?: never;
|
|
509
|
+
} | {
|
|
510
|
+
readonly resource?: string;
|
|
511
|
+
readonly action?: Extract<ScreenMode, 'create'>;
|
|
512
|
+
/**
|
|
513
|
+
* The caller's tier of starting values, above each field's declared
|
|
514
|
+
* default, the matched type's `defaults` and URL prefill.
|
|
515
|
+
*/
|
|
516
|
+
readonly defaults?: Record<string, unknown>;
|
|
517
|
+
};
|
|
518
|
+
/**
|
|
519
|
+
* The record page — show, edit or create — wired to data. It reads the id
|
|
520
|
+
* and the group chain from the current route match, reads with `useOne`,
|
|
521
|
+
* renders the record through `<RecordScreen>` (which writes with the
|
|
522
|
+
* resource's update or create), navigates after a write (show when the
|
|
523
|
+
* resource has one, else the list), and renders translated loading,
|
|
524
|
+
* not-found, session-expired and error states. It draws no breadcrumb trail:
|
|
525
|
+
* the header's `<HeaderBreadcrumbs>` does, and shows the record's title once
|
|
526
|
+
* this page has loaded it (the id until then). The open panel of a keyed tabs node lives in the URL as `?<tabsKey>=<panelKey>`.
|
|
527
|
+
*
|
|
528
|
+
* `<ResourcePageRouter>` renders the record route itself; a different layout is a frame on the
|
|
529
|
+
* screen (`views.<mode>.frame`), never a replaced route (P6-56).
|
|
530
|
+
*/
|
|
531
|
+
declare function RecordPage(props: RecordPageProps): ReactElement;
|
|
532
|
+
//#endregion
|
|
533
|
+
//#region src/layout/record-breadcrumbs.d.ts
|
|
534
|
+
/**
|
|
535
|
+
* The record trail of the current route, the one `<HeaderBreadcrumbs>` draws
|
|
536
|
+
* there; record and flow pages draw none of their own.
|
|
537
|
+
*
|
|
538
|
+
* On a record route whose operation is available: the group chain, the
|
|
539
|
+
* resource, then the record (show), the record linking to show when show is
|
|
540
|
+
* available plus "Edit" (edit), or "Create" (create). The record crumb is the
|
|
541
|
+
* record's title once `<RecordPage>` has loaded it, and the id while it loads,
|
|
542
|
+
* has failed, or is not mounted at all.
|
|
543
|
+
*
|
|
544
|
+
* On a page-hosted flow's route: the record's edit-shaped trail ending with the
|
|
545
|
+
* flow's label, once the flow page shows its form or its "not available"
|
|
546
|
+
* notice; until then, and on every not-found it answers with, the record's
|
|
547
|
+
* show trail with the id, so a flow the user may not run is never named. A
|
|
548
|
+
* name no flow answers to is the framework 404, with no trail.
|
|
549
|
+
*
|
|
550
|
+
* Nothing on any other route.
|
|
551
|
+
*/
|
|
552
|
+
declare function RecordBreadcrumbs(): ReactElement | null;
|
|
553
|
+
//#endregion
|
|
554
|
+
//#region src/record/record-screen.d.ts
|
|
555
|
+
type AnyResourceHandle = ResourceHandle<any, any, any, any>;
|
|
556
|
+
interface RecordScreenProps {
|
|
557
|
+
/** A canonical resource name, or its handle. */
|
|
558
|
+
readonly resource: string | AnyResourceHandle;
|
|
559
|
+
readonly mode: 'show' | 'edit' | 'create';
|
|
560
|
+
/** The record to read (show, edit); not needed when `record` is given. */
|
|
561
|
+
readonly recordId?: string;
|
|
562
|
+
/**
|
|
563
|
+
* The accepted type of a typed create. Without a router, changing it remounts the form for the
|
|
564
|
+
* new type and discards unsaved input without asking for confirmation.
|
|
565
|
+
*/
|
|
566
|
+
readonly type?: string;
|
|
567
|
+
/** A row the caller already holds: nothing is read. */
|
|
568
|
+
readonly record?: Readonly<Record<string, unknown>>;
|
|
569
|
+
/** The caller's starting values of a create, above the field defaults. */
|
|
570
|
+
readonly defaults?: Readonly<Record<string, unknown>>;
|
|
571
|
+
/**
|
|
572
|
+
* User input for a create (a search text typed into a relation select): after the first settled
|
|
573
|
+
* plan each key whose field the plan holds `active` is set once, as the user typing it would
|
|
574
|
+
* (the form is dirty); any other key is dropped. Not a default, never trusted.
|
|
575
|
+
*/
|
|
576
|
+
readonly input?: Readonly<Record<string, unknown>>;
|
|
577
|
+
/** Replaces the built-in update or create; receives the payload. */
|
|
578
|
+
readonly onSubmit?: (payload: Record<string, unknown>) => Promise<unknown>;
|
|
579
|
+
/** Called after a successful submit with what the write returned. */
|
|
580
|
+
readonly onSuccess?: (result: unknown) => void;
|
|
581
|
+
/** Replaces Cancel's default back navigation. */
|
|
582
|
+
readonly onCancel?: () => void;
|
|
583
|
+
/** The submit button's label. */
|
|
584
|
+
readonly submitLabel?: string;
|
|
585
|
+
/** Rendered after the record's actions in show. */
|
|
586
|
+
readonly extraActions?: ReactNode;
|
|
587
|
+
/**
|
|
588
|
+
* This instance's record frame (code only): used when its slots cover every slot the screen
|
|
589
|
+
* fills, else a development error and the screen's own frame (spec 3.3).
|
|
590
|
+
*/
|
|
591
|
+
readonly frame?: FrameHandle<'record'> | AnyFrameHandle;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* A record's show, edit or create screen outside a route (P1b+P1c decision
|
|
595
|
+
* 20): the planned screen in its frame (the screen's, the app's, the built-in
|
|
596
|
+
* one, or this instance's `frame`). Reads the record by `recordId` unless
|
|
597
|
+
* `record` is given; writes with the resource's update or create unless
|
|
598
|
+
* `onSubmit` is given. A resource the app does not know renders not-found.
|
|
599
|
+
*/
|
|
600
|
+
declare function RecordScreen(props: RecordScreenProps): ReactElement;
|
|
601
|
+
//#endregion
|
|
602
|
+
//#region src/record/frame-pieces.d.ts
|
|
603
|
+
/**
|
|
604
|
+
* The record's title: its `recordTitle` / display field (show, edit), or
|
|
605
|
+
* "Create <label>" in create. Inside `<RecordScreen>` only; no props.
|
|
606
|
+
*/
|
|
607
|
+
declare const RecordTitle: () => ReactElement | null;
|
|
608
|
+
/**
|
|
609
|
+
* The record's item actions: the resolved `<ActionOverflow>` of the mode's
|
|
610
|
+
* surface, then `<RecordScreen extraActions>`. Nothing in create or before
|
|
611
|
+
* the record is read.
|
|
612
|
+
*/
|
|
613
|
+
declare const RecordActions: () => ReactElement | null;
|
|
614
|
+
/** Copies the record's id to the clipboard. Nothing without an id (create). */
|
|
615
|
+
declare const CopyId: () => ReactElement | null;
|
|
616
|
+
/**
|
|
617
|
+
* Submit and Cancel (edit, create): Submit runs the controller's submit and
|
|
618
|
+
* then `onSuccess`; Cancel calls `onCancel`, else navigates back through the
|
|
619
|
+
* navigation guard. Above them, the form-level messages and a failed write.
|
|
620
|
+
* Nothing in show.
|
|
621
|
+
*/
|
|
622
|
+
declare const FormActions: () => ReactElement | null;
|
|
623
|
+
//#endregion
|
|
502
624
|
//#region src/layout/default-nav-layouts.d.ts
|
|
503
625
|
/** The built-in content-wrapping layouts. Merge into the app's Components registry. */
|
|
504
626
|
declare const defaultNavLayouts: Record<string, NavLayout>;
|
|
@@ -545,6 +667,8 @@ declare function ContextPicker({ sliceName, label, options, value, onChange, pla
|
|
|
545
667
|
/** What the user picked. `'system'` means "no explicit choice" — nothing is
|
|
546
668
|
* persisted for it; its absence from storage IS the `system` state. */
|
|
547
669
|
type ThemeChoice = 'light' | 'dark' | 'system';
|
|
670
|
+
/** Every theme choice, in the order a control offers them. */
|
|
671
|
+
declare const THEME_CHOICES: readonly ThemeChoice[];
|
|
548
672
|
/** What is actually painted. Never `'system'` — every reader (Toaster,
|
|
549
673
|
* CodeMirror, Mermaid) only ever needs to know light or dark. */
|
|
550
674
|
type ResolvedTheme = 'light' | 'dark';
|
|
@@ -590,14 +714,28 @@ interface UseThemeResult {
|
|
|
590
714
|
declare function useTheme(): UseThemeResult;
|
|
591
715
|
//#endregion
|
|
592
716
|
//#region src/layout/language-switch.d.ts
|
|
717
|
+
interface LanguageSwitchProps {
|
|
718
|
+
/**
|
|
719
|
+
* Called with the picked locale code AFTER the live locale has switched and
|
|
720
|
+
* the choice has been persisted.
|
|
721
|
+
*/
|
|
722
|
+
onChange?: (code: string) => void;
|
|
723
|
+
className?: string;
|
|
724
|
+
}
|
|
593
725
|
/**
|
|
594
|
-
*
|
|
595
|
-
*
|
|
596
|
-
*
|
|
597
|
-
*
|
|
598
|
-
*
|
|
726
|
+
* Segmented locale switcher: one button per locale the i18n facade lists
|
|
727
|
+
* (`I18nFacade.locales`, which `createI18nFromRegistry` fills from the
|
|
728
|
+
* registry), each labelled with the locale's own name (`Intl.DisplayNames`).
|
|
729
|
+
* A view over {@link useLanguageSwitch}: picking a locale switches the LIVE
|
|
730
|
+
* locale (no reload) and persists it under `<BuroProvider languageStorageKey>`.
|
|
731
|
+
*
|
|
732
|
+
* Reactivity: the active locale is read live, so the switcher always reflects
|
|
733
|
+
* the CURRENT locale, including a change made elsewhere. `tests/language-switch.test.tsx`
|
|
734
|
+
* guards that nothing here reloads the page.
|
|
599
735
|
*/
|
|
600
|
-
declare
|
|
736
|
+
declare function LanguageSwitch({ onChange, className }: LanguageSwitchProps): React.ReactElement;
|
|
737
|
+
//#endregion
|
|
738
|
+
//#region src/layout/language-storage.d.ts
|
|
601
739
|
/**
|
|
602
740
|
* Legacy RU/EN-only pair. `<LanguageSwitch>` itself no longer uses these —
|
|
603
741
|
* see its own docblock. New code that needs an arbitrary (not just 'en'/'ru')
|
|
@@ -669,142 +807,81 @@ declare function saveLanguage(code: LanguageCode, storageKey?: string): void;
|
|
|
669
807
|
declare function loadLocale(storageKey?: string): string | undefined;
|
|
670
808
|
/** Persist an arbitrary locale code. Generic counterpart to {@link saveLanguage}. */
|
|
671
809
|
declare function saveLocale(code: string, storageKey?: string): void;
|
|
672
|
-
interface LanguageSwitchProps {
|
|
673
|
-
/**
|
|
674
|
-
* The locale registry to build the switcher from. `registry.locales()`
|
|
675
|
-
* is the ENTIRE set of buttons rendered — there is no separate list to
|
|
676
|
-
* keep in sync, and no literal locale code anywhere in this component.
|
|
677
|
-
* Adding a locale to the registry (a new contribution — see
|
|
678
|
-
* `@burojs/i18n-core`'s `LocaleRegistry`) is the whole mechanism for it to
|
|
679
|
-
* appear here.
|
|
680
|
-
*/
|
|
681
|
-
registry: LocaleRegistry;
|
|
682
|
-
/**
|
|
683
|
-
* Namespace to read each locale's `nav.languageName` display name from
|
|
684
|
-
* (see {@link localeDisplayName}). Defaults to `'common'` — the same
|
|
685
|
-
* default namespace `LocaleRegistry` itself uses.
|
|
686
|
-
*/
|
|
687
|
-
namespace?: string;
|
|
688
|
-
className?: string;
|
|
689
|
-
/**
|
|
690
|
-
* localStorage key to persist the chosen locale under via
|
|
691
|
-
* {@link saveLocale}. Defaults to `buro:language`.
|
|
692
|
-
*/
|
|
693
|
-
storageKey?: string;
|
|
694
|
-
/**
|
|
695
|
-
* Called AFTER the locale is persisted to localStorage, INSTEAD of the
|
|
696
|
-
* default live-switch behavior. Pass this if your app needs to do
|
|
697
|
-
* something else on a language change (re-key a provider tree, push a
|
|
698
|
-
* route); omit it to get the default: switch the live locale via
|
|
699
|
-
* `useChangeLocale()`, no reload.
|
|
700
|
-
*/
|
|
701
|
-
onChange?: (code: string) => void;
|
|
702
|
-
}
|
|
703
|
-
/**
|
|
704
|
-
* Locale switcher built entirely from a {@link LocaleRegistry} — any number
|
|
705
|
-
* of locales, not a fixed pair. A segmented control with one button per
|
|
706
|
-
* `registry.locales()` entry.
|
|
707
|
-
*
|
|
708
|
-
* Reactivity: the active locale is read live via `useLocale()`
|
|
709
|
-
* (`useSyncExternalStore` under the i18n facade's `onLocaleChange`), so this
|
|
710
|
-
* component always reflects the CURRENT locale, including a change made
|
|
711
|
-
* elsewhere (another switcher instance, a deep link, etc.) — there is no
|
|
712
|
-
* local "current" state to fall out of sync. Picking a locale persists the
|
|
713
|
-
* choice via `saveLocale` and switches the LIVE locale via
|
|
714
|
-
* `useChangeLocale()` — no reload. Adopters who need to do something else
|
|
715
|
-
* pass `onChange`, which takes over entirely.
|
|
716
|
-
*
|
|
717
|
-
* ⚠️ The two-button predecessor of this component used to reload the page on
|
|
718
|
-
* every pick, and its docblock used to justify that as necessary because
|
|
719
|
-
* "resource labels and the framework's built-in strings are consumed at
|
|
720
|
-
* provider-boot registration time." That was true at v0.1 and is not true
|
|
721
|
-
* now — the i18n content model made every label render-time. Nothing here
|
|
722
|
-
* should reintroduce a reload; `tests/language-switch.test.tsx` guards it.
|
|
723
|
-
*/
|
|
724
|
-
declare function LanguageSwitch({ registry, namespace, className, storageKey, onChange }: LanguageSwitchProps): React.ReactElement;
|
|
725
810
|
//#endregion
|
|
726
811
|
//#region src/layout/breadcrumbs.d.ts
|
|
727
|
-
|
|
812
|
+
type Segment = {
|
|
813
|
+
label: string;
|
|
814
|
+
href?: string;
|
|
815
|
+
};
|
|
816
|
+
interface BreadcrumbsBaseProps {
|
|
817
|
+
className?: string;
|
|
728
818
|
/**
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
* resolves when a `ResourceContext.Provider` wraps the tree
|
|
732
|
-
* (currently set in tests only). Pass `resource` explicitly from
|
|
733
|
-
* resource-aware renderers like `<ResourceShow>` so the breadcrumb
|
|
734
|
-
* works in production code paths that don't (yet) provide the
|
|
735
|
-
* context.
|
|
819
|
+
* Scopes the trail offers help for, outermost first. Defaults to the resource
|
|
820
|
+
* this breadcrumb is rooted at (none for a trail without a resource).
|
|
736
821
|
*/
|
|
737
|
-
|
|
822
|
+
docScopes?: string[];
|
|
738
823
|
/**
|
|
739
|
-
*
|
|
740
|
-
*
|
|
741
|
-
*
|
|
824
|
+
* Segments rendered before the resource segment (or before the page label in
|
|
825
|
+
* a trail without one), each followed by a chevron — the group chain. A
|
|
826
|
+
* segment with an `href` renders as a link; without one, as muted text.
|
|
742
827
|
*/
|
|
828
|
+
leadingSegments?: Segment[];
|
|
829
|
+
/** Optional testid forwarded to the root nav. */
|
|
830
|
+
'data-testid'?: string;
|
|
831
|
+
}
|
|
832
|
+
/** A trail that ends at, or passes through, a resource: its list link, then the record. */
|
|
833
|
+
interface ResourceBreadcrumbsProps extends BreadcrumbsBaseProps {
|
|
834
|
+
/** Resource name (the registry key). */
|
|
835
|
+
resource: string;
|
|
836
|
+
name?: never;
|
|
837
|
+
/** Identifier for the current page (testid only); a record id on show/edit pages. */
|
|
743
838
|
recordId?: string;
|
|
744
839
|
/**
|
|
745
|
-
* Display label for the trailing
|
|
746
|
-
*
|
|
747
|
-
* useful when the breadcrumb sits next to a page title that
|
|
748
|
-
* already names the record.
|
|
840
|
+
* Display label for the trailing segment (the current page). When omitted
|
|
841
|
+
* the resource segment itself is the current crumb (a list page).
|
|
749
842
|
*/
|
|
750
843
|
pageLabel?: string;
|
|
751
|
-
className?: string;
|
|
752
|
-
/**
|
|
753
|
-
* Scopes the trail offers help for, outermost first. Defaults to the resource
|
|
754
|
-
* this breadcrumb is rooted at. Pass a longer list when the trail crosses
|
|
755
|
-
* several documented resources — the control then offers all of them, which
|
|
756
|
-
* is the thing a per-entity icon structurally cannot do.
|
|
757
|
-
*/
|
|
758
|
-
docScopes?: string[];
|
|
759
844
|
/**
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
*
|
|
763
|
-
* `Документы по типу › Заказы на производство › #id`. A segment with an `href`
|
|
764
|
-
* renders as a link; without one it renders as muted static text. Undefined
|
|
765
|
-
* (the default) → the breadcrumb starts at the resource segment, unchanged.
|
|
845
|
+
* Segments rendered between the resource link and the trailing page label —
|
|
846
|
+
* the record on an edit page («Documents › live-one › Edit»). A segment
|
|
847
|
+
* without `href` renders as plain text.
|
|
766
848
|
*/
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
* resource. A segment without `href` renders as plain text, for records whose
|
|
779
|
-
* resource has no standalone show page.
|
|
780
|
-
*/
|
|
781
|
-
middleSegments?: Array<{
|
|
782
|
-
label: string;
|
|
783
|
-
href?: string;
|
|
784
|
-
}>;
|
|
785
|
-
/** Optional testid forwarded to the root nav. */
|
|
786
|
-
'data-testid'?: string;
|
|
849
|
+
middleSegments?: Segment[];
|
|
850
|
+
}
|
|
851
|
+
/** A trail with no resource segment: a custom page or a group index. */
|
|
852
|
+
interface PageBreadcrumbsProps extends BreadcrumbsBaseProps {
|
|
853
|
+
resource?: never;
|
|
854
|
+
/** The test-id name of the current crumb: the custom page's or the group's key. */
|
|
855
|
+
name: string;
|
|
856
|
+
/** The current page's label, the trail's last crumb. */
|
|
857
|
+
pageLabel: string;
|
|
858
|
+
recordId?: never;
|
|
859
|
+
middleSegments?: never;
|
|
787
860
|
}
|
|
861
|
+
type BreadcrumbsProps = ResourceBreadcrumbsProps | PageBreadcrumbsProps;
|
|
788
862
|
/**
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
*
|
|
792
|
-
*
|
|
793
|
-
*
|
|
794
|
-
*
|
|
795
|
-
*
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
*
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
|
|
807
|
-
|
|
863
|
+
* The navigation breadcrumb, in two shapes. With `resource`: the leading
|
|
864
|
+
* segments, the resource (a link to its canonical, nesting-aware list href,
|
|
865
|
+
* or the current crumb on a bare list), the middle segments and the page
|
|
866
|
+
* label. Without: the leading segments and the page label only, test ids
|
|
867
|
+
* named by `name`. The last crumb is always the "you are here" marker — an
|
|
868
|
+
* emphasised, non-linked span with `aria-current="page"`. Every crumb carries
|
|
869
|
+
* its label as a `title` tooltip, so a truncated one can still be read.
|
|
870
|
+
*/
|
|
871
|
+
declare function Breadcrumbs(props: BreadcrumbsProps): ReactElement | null;
|
|
872
|
+
//#endregion
|
|
873
|
+
//#region src/layout/header-breadcrumbs.d.ts
|
|
874
|
+
/**
|
|
875
|
+
* The page's one breadcrumb trail, and `<AppHeader>`'s default `breadcrumbs`:
|
|
876
|
+
* the group chain and the resource, custom page or group — and on a record
|
|
877
|
+
* route or a page-hosted flow's route the record trail (`<RecordBreadcrumbs>`,
|
|
878
|
+
* `data-testid="record-breadcrumbs"`), which ends with the record's title once
|
|
879
|
+
* the page has loaded it. Record and flow pages draw no trail of their own, so
|
|
880
|
+
* a page never shows two. Nothing — silently — without a match: a sidebar or
|
|
881
|
+
* header rendered in a story with no router is not a misconfiguration, and
|
|
882
|
+
* `<NavAreaPage>`'s own message is the one that names the fix.
|
|
883
|
+
*/
|
|
884
|
+
declare function HeaderBreadcrumbs(): ReactElement | null;
|
|
808
885
|
//#endregion
|
|
809
886
|
//#region src/layout/command-palette.d.ts
|
|
810
887
|
/**
|
|
@@ -860,11 +937,14 @@ declare function CommandPalette({ open, onOpenChange, children, placeholder, emp
|
|
|
860
937
|
//#endregion
|
|
861
938
|
//#region src/layout/command-palette-trigger.d.ts
|
|
862
939
|
interface CommandPaletteTriggerProps {
|
|
863
|
-
/**
|
|
864
|
-
|
|
940
|
+
/**
|
|
941
|
+
* Opens the palette. Defaults to the `ShellProvider`'s `openPalette`; with
|
|
942
|
+
* neither, the trigger renders nothing.
|
|
943
|
+
*/
|
|
944
|
+
onOpen?: () => void;
|
|
865
945
|
/** Shortcut hint rendered in the `<kbd>` chip. Defaults to `⌘K`. */
|
|
866
946
|
shortcut?: string;
|
|
867
|
-
/** `data-testid` for the trigger button. */
|
|
947
|
+
/** `data-testid` for the trigger button. Default `'open-palette'`. */
|
|
868
948
|
testid?: string;
|
|
869
949
|
className?: string;
|
|
870
950
|
}
|
|
@@ -877,7 +957,7 @@ interface CommandPaletteTriggerProps {
|
|
|
877
957
|
* (`commandPalette.trigger` / `.triggerHint`) instead of hardcoded English.
|
|
878
958
|
* Falls back to English when rendered outside a `BuroProvider`.
|
|
879
959
|
*/
|
|
880
|
-
declare function CommandPaletteTrigger({ onOpen, shortcut, testid, className }: CommandPaletteTriggerProps): React.ReactElement;
|
|
960
|
+
declare function CommandPaletteTrigger({ onOpen, shortcut, testid, className }: CommandPaletteTriggerProps): React.ReactElement | null;
|
|
881
961
|
//#endregion
|
|
882
962
|
//#region src/layout/command-palette-navigation-groups.d.ts
|
|
883
963
|
/**
|
|
@@ -902,24 +982,14 @@ type CommandPaletteNavigationTestIdRole = 'resource' | 'page' | 'section' | 'gro
|
|
|
902
982
|
* `useVisibilityCtx()` (mirrors the sidebar's filter logic so an entry
|
|
903
983
|
* hidden in the sidebar stays hidden in the palette).
|
|
904
984
|
*
|
|
905
|
-
* Navigation
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
* `window.location.assign(href)` so it remains usable outside Next /
|
|
909
|
-
* react-router shells; SPA shells should always supply `navigate` to
|
|
910
|
-
* keep client-side routing intact.
|
|
985
|
+
* Navigation goes through `useRouteNavigate` — the `RouterAdapter` the host
|
|
986
|
+
* mounts above `<BuroProvider>` — so picks stay client-side with nothing to
|
|
987
|
+
* wire.
|
|
911
988
|
*/
|
|
912
989
|
interface CommandPaletteNavigationGroupsProps {
|
|
913
990
|
/**
|
|
914
|
-
* Called
|
|
915
|
-
*
|
|
916
|
-
* react-router, etc.). Optional — when omitted the component falls
|
|
917
|
-
* back to `window.location.assign(href)` (full reload).
|
|
918
|
-
*/
|
|
919
|
-
navigate?: (href: string) => void;
|
|
920
|
-
/**
|
|
921
|
-
* Called after the user picks a navigation entry, BEFORE `navigate`
|
|
922
|
-
* fires. Adopters typically wire this to `setOpen(false)` to close
|
|
991
|
+
* Called after the user picks a navigation entry, BEFORE the
|
|
992
|
+
* navigation. Adopters typically wire this to `setOpen(false)` to close
|
|
923
993
|
* the palette before the route change. Optional.
|
|
924
994
|
*/
|
|
925
995
|
onSelect?: () => void;
|
|
@@ -939,7 +1009,7 @@ interface CommandPaletteNavigationGroupsProps {
|
|
|
939
1009
|
*
|
|
940
1010
|
* Visibility filtering mirrors `<Sidebar>` (visible predicates evaluated
|
|
941
1011
|
* against `useVisibilityCtx()`, fail-closed for throwing predicates,
|
|
942
|
-
*
|
|
1012
|
+
* resources with no list page hidden from navigation entirely). An entry hidden
|
|
943
1013
|
* in the sidebar is also hidden in the palette — that parity is the
|
|
944
1014
|
* primary contract of this component.
|
|
945
1015
|
*
|
|
@@ -967,7 +1037,6 @@ interface CommandPaletteNavigationGroupsProps {
|
|
|
967
1037
|
*
|
|
968
1038
|
* ```tsx
|
|
969
1039
|
* 'use client';
|
|
970
|
-
* import { useRouter } from 'next/navigation';
|
|
971
1040
|
* import { useCommandPalette } from '@burojs/react';
|
|
972
1041
|
* import {
|
|
973
1042
|
* CommandPalette,
|
|
@@ -975,12 +1044,10 @@ interface CommandPaletteNavigationGroupsProps {
|
|
|
975
1044
|
* } from '@burojs/ui-shadcn';
|
|
976
1045
|
*
|
|
977
1046
|
* function Shell() {
|
|
978
|
-
* const router = useRouter();
|
|
979
1047
|
* const { open, setOpen } = useCommandPalette();
|
|
980
1048
|
* return (
|
|
981
1049
|
* <CommandPalette open={open} onOpenChange={setOpen}>
|
|
982
1050
|
* <CommandPaletteNavigationGroups
|
|
983
|
-
* navigate={(href) => router.push(href)}
|
|
984
1051
|
* onSelect={() => setOpen(false)}
|
|
985
1052
|
* />
|
|
986
1053
|
* </CommandPalette>
|
|
@@ -988,7 +1055,7 @@ interface CommandPaletteNavigationGroupsProps {
|
|
|
988
1055
|
* }
|
|
989
1056
|
* ```
|
|
990
1057
|
*/
|
|
991
|
-
declare function CommandPaletteNavigationGroups({
|
|
1058
|
+
declare function CommandPaletteNavigationGroups({ onSelect, getTestId }: CommandPaletteNavigationGroupsProps): React.ReactElement | null;
|
|
992
1059
|
//#endregion
|
|
993
1060
|
//#region src/layout/command-palette-recent-group.d.ts
|
|
994
1061
|
/**
|
|
@@ -996,35 +1063,21 @@ declare function CommandPaletteNavigationGroups({ navigate, onSelect, getTestId
|
|
|
996
1063
|
* `useTestIds` pattern used by `<CommandPaletteNavigationGroups>`.
|
|
997
1064
|
*
|
|
998
1065
|
* - `recent` — a recently-visited record entry. `id` passed to the
|
|
999
|
-
* builder is `<resource>:<record-id>`.
|
|
1066
|
+
* builder is `<canonical resource>:<record-id>`.
|
|
1000
1067
|
*/
|
|
1001
1068
|
type CommandPaletteRecentTestIdRole = 'recent';
|
|
1002
1069
|
/**
|
|
1003
1070
|
* Props for `<CommandPaletteRecentGroup>`.
|
|
1004
1071
|
*
|
|
1005
|
-
* The component reads the recent list
|
|
1006
|
-
*
|
|
1007
|
-
* re-reads on every mount
|
|
1008
|
-
* single-tab consistency is preserved because the
|
|
1009
|
-
* tears down + remounts each time it opens.
|
|
1072
|
+
* The component reads the signed-in user's recent list (the records
|
|
1073
|
+
* `<RecordPage>` recorded as it read them) and renders one `<CommandItem>`
|
|
1074
|
+
* per entry. It re-reads on every mount, when the user changes and when
|
|
1075
|
+
* `refreshKey` changes — single-tab consistency is preserved because the
|
|
1076
|
+
* palette dialog tears down + remounts each time it opens.
|
|
1010
1077
|
*/
|
|
1011
1078
|
interface CommandPaletteRecentGroupProps {
|
|
1012
1079
|
/**
|
|
1013
|
-
*
|
|
1014
|
-
* single-user / unauthenticated adopters omit and share a `'singleton'`
|
|
1015
|
-
* bucket. The list is keyed by user so signing out + back in as a
|
|
1016
|
-
* different user doesn't leak the previous user's history.
|
|
1017
|
-
*/
|
|
1018
|
-
userId?: string | null;
|
|
1019
|
-
/**
|
|
1020
|
-
* Called to navigate to the picked record's URL. Wire this to your
|
|
1021
|
-
* app router (`router.push` for Next App Router, `navigate(to)` for
|
|
1022
|
-
* react-router, etc.). Optional — when omitted the component falls
|
|
1023
|
-
* back to `window.location.assign(href)` (full reload).
|
|
1024
|
-
*/
|
|
1025
|
-
navigate?: (href: string) => void;
|
|
1026
|
-
/**
|
|
1027
|
-
* Called BEFORE `navigate` fires. Adopters typically wire this to
|
|
1080
|
+
* Called BEFORE the navigation. Adopters typically wire this to
|
|
1028
1081
|
* `setOpen(false)` to close the palette during the route change.
|
|
1029
1082
|
*/
|
|
1030
1083
|
onSelect?: () => void;
|
|
@@ -1039,17 +1092,11 @@ interface CommandPaletteRecentGroupProps {
|
|
|
1039
1092
|
* explicit string to override.
|
|
1040
1093
|
*/
|
|
1041
1094
|
heading?: string;
|
|
1042
|
-
/**
|
|
1043
|
-
* Override the path generator. By default the component navigates
|
|
1044
|
-
* to `/<resource>/<id>` — adopters with custom routes (e.g. nested
|
|
1045
|
-
* subresources) can override.
|
|
1046
|
-
*/
|
|
1047
|
-
recordHref?: (entry: RecentRecord) => string;
|
|
1048
1095
|
/**
|
|
1049
1096
|
* Re-read trigger. When this prop changes the component re-reads
|
|
1050
1097
|
* `localStorage` (e.g. flip from `false` → `true` on palette open).
|
|
1051
|
-
* Optional — when omitted the component reads only on mount
|
|
1052
|
-
*
|
|
1098
|
+
* Optional — when omitted the component reads only on mount and when
|
|
1099
|
+
* the user changes, which is sufficient for the typical "palette
|
|
1053
1100
|
* dialog re-mounts on each open" use case.
|
|
1054
1101
|
*/
|
|
1055
1102
|
refreshKey?: unknown;
|
|
@@ -1063,10 +1110,10 @@ interface CommandPaletteRecentGroupProps {
|
|
|
1063
1110
|
withSeparator?: boolean;
|
|
1064
1111
|
}
|
|
1065
1112
|
/**
|
|
1066
|
-
* Render the "Recent" group inside a command palette: the last
|
|
1067
|
-
*
|
|
1068
|
-
*
|
|
1069
|
-
*
|
|
1113
|
+
* Render the "Recent" group inside a command palette: the last records the
|
|
1114
|
+
* signed-in user opened. `<RecordPage>` records each show or edit visit
|
|
1115
|
+
* from the record it read — there is nothing to wire, and nothing is
|
|
1116
|
+
* recorded or shown without a signed-in user.
|
|
1070
1117
|
*
|
|
1071
1118
|
* Visibility:
|
|
1072
1119
|
*
|
|
@@ -1074,18 +1121,18 @@ interface CommandPaletteRecentGroupProps {
|
|
|
1074
1121
|
* "Recent" heading on a fresh user). Adopters that want a permanent
|
|
1075
1122
|
* slot (with an empty-state row) can fork this component — the
|
|
1076
1123
|
* surface is small.
|
|
1077
|
-
* -
|
|
1078
|
-
*
|
|
1079
|
-
* resource
|
|
1080
|
-
*
|
|
1081
|
-
* record / resource is gone.
|
|
1124
|
+
* - An entry opens the record's show route, else its edit route, built
|
|
1125
|
+
* from the registry. An entry whose resource the registry no longer
|
|
1126
|
+
* has, whose resource's `visible` now hides it from the user, or which
|
|
1127
|
+
* has neither route, is not rendered.
|
|
1082
1128
|
*
|
|
1083
|
-
* Example (router-independent —
|
|
1084
|
-
* `useResourceUrlState` uses; wrap the app in
|
|
1129
|
+
* Example (router-independent — picks navigate through `useRouteNavigate`,
|
|
1130
|
+
* the `RouterAdapter` seam `useResourceUrlState` also uses; wrap the app in
|
|
1131
|
+
* `RouterAdapterProvider` once):
|
|
1085
1132
|
*
|
|
1086
1133
|
* ```tsx
|
|
1087
1134
|
* 'use client';
|
|
1088
|
-
* import {
|
|
1135
|
+
* import { useCommandPalette } from '@burojs/react';
|
|
1089
1136
|
* import {
|
|
1090
1137
|
* CommandPalette,
|
|
1091
1138
|
* CommandPaletteRecentGroup,
|
|
@@ -1094,18 +1141,15 @@ interface CommandPaletteRecentGroupProps {
|
|
|
1094
1141
|
* } from '@burojs/ui-shadcn';
|
|
1095
1142
|
*
|
|
1096
1143
|
* function Shell() {
|
|
1097
|
-
* const router = useRouterAdapter();
|
|
1098
1144
|
* const { open, setOpen } = useCommandPalette();
|
|
1099
1145
|
* return (
|
|
1100
1146
|
* <CommandPalette open={open} onOpenChange={setOpen}>
|
|
1101
1147
|
* <CommandPaletteRecentGroup
|
|
1102
|
-
* navigate={(href) => router.push(href)}
|
|
1103
1148
|
* onSelect={() => setOpen(false)}
|
|
1104
1149
|
* refreshKey={open}
|
|
1105
1150
|
* />
|
|
1106
1151
|
* <CommandSeparator />
|
|
1107
1152
|
* <CommandPaletteNavigationGroups
|
|
1108
|
-
* navigate={(href) => router.push(href)}
|
|
1109
1153
|
* onSelect={() => setOpen(false)}
|
|
1110
1154
|
* />
|
|
1111
1155
|
* </CommandPalette>
|
|
@@ -1113,7 +1157,7 @@ interface CommandPaletteRecentGroupProps {
|
|
|
1113
1157
|
* }
|
|
1114
1158
|
* ```
|
|
1115
1159
|
*/
|
|
1116
|
-
declare function CommandPaletteRecentGroup({
|
|
1160
|
+
declare function CommandPaletteRecentGroup({ onSelect, getTestId, heading, refreshKey, withSeparator }: CommandPaletteRecentGroupProps): React.ReactElement | null;
|
|
1117
1161
|
//#endregion
|
|
1118
1162
|
//#region src/layout/command-palette-records-group.d.ts
|
|
1119
1163
|
/**
|
|
@@ -1162,14 +1206,7 @@ interface CommandPaletteRecordsGroupProps {
|
|
|
1162
1206
|
*/
|
|
1163
1207
|
debounceMs?: number;
|
|
1164
1208
|
/**
|
|
1165
|
-
* Called
|
|
1166
|
-
* app router (`router.push` for Next App Router, `navigate(to)` for
|
|
1167
|
-
* react-router, etc.). Optional — when omitted the component falls
|
|
1168
|
-
* back to `window.location.assign(href)` (full reload).
|
|
1169
|
-
*/
|
|
1170
|
-
navigate?: (href: string) => void;
|
|
1171
|
-
/**
|
|
1172
|
-
* Called BEFORE `navigate` fires. Adopters typically wire this to
|
|
1209
|
+
* Called BEFORE the navigation. Adopters typically wire this to
|
|
1173
1210
|
* `setOpen(false)` to close the palette during the route change.
|
|
1174
1211
|
*/
|
|
1175
1212
|
onSelect?: () => void;
|
|
@@ -1207,7 +1244,7 @@ interface CommandPaletteRecordsGroupProps {
|
|
|
1207
1244
|
* - Each resource hit is prefixed with the resource's label so an
|
|
1208
1245
|
* ambiguous query (matching multiple resources) stays disambiguated.
|
|
1209
1246
|
* - On pick: calls `onSelect` (typical: close the palette) THEN
|
|
1210
|
-
*
|
|
1247
|
+
* navigates to the record.
|
|
1211
1248
|
*
|
|
1212
1249
|
* Cancellation:
|
|
1213
1250
|
*
|
|
@@ -1224,12 +1261,13 @@ interface CommandPaletteRecordsGroupProps {
|
|
|
1224
1261
|
* that calls `useList` exactly once per render. The sub-component count
|
|
1225
1262
|
* is stable, so no conditional/loop hook is created.
|
|
1226
1263
|
*
|
|
1227
|
-
* Example (router-independent —
|
|
1228
|
-
* `useResourceUrlState` uses; wrap the app in
|
|
1264
|
+
* Example (router-independent — picks navigate through `useRouteNavigate`,
|
|
1265
|
+
* the `RouterAdapter` seam `useResourceUrlState` also uses; wrap the app in
|
|
1266
|
+
* `RouterAdapterProvider` once):
|
|
1229
1267
|
*
|
|
1230
1268
|
* ```tsx
|
|
1231
1269
|
* 'use client';
|
|
1232
|
-
* import {
|
|
1270
|
+
* import { useCommandPalette } from '@burojs/react';
|
|
1233
1271
|
* import {
|
|
1234
1272
|
* CommandPalette,
|
|
1235
1273
|
* CommandPaletteRecordsGroup,
|
|
@@ -1237,17 +1275,14 @@ interface CommandPaletteRecordsGroupProps {
|
|
|
1237
1275
|
* } from '@burojs/ui-shadcn';
|
|
1238
1276
|
*
|
|
1239
1277
|
* function Shell() {
|
|
1240
|
-
* const router = useRouterAdapter();
|
|
1241
1278
|
* const { open, setOpen } = useCommandPalette();
|
|
1242
1279
|
* return (
|
|
1243
1280
|
* <CommandPalette open={open} onOpenChange={setOpen}>
|
|
1244
1281
|
* <CommandPaletteRecordsGroup
|
|
1245
1282
|
* enabled={open}
|
|
1246
|
-
* navigate={(href) => router.push(href)}
|
|
1247
1283
|
* onSelect={() => setOpen(false)}
|
|
1248
1284
|
* />
|
|
1249
1285
|
* <CommandPaletteNavigationGroups
|
|
1250
|
-
* navigate={(href) => router.push(href)}
|
|
1251
1286
|
* onSelect={() => setOpen(false)}
|
|
1252
1287
|
* />
|
|
1253
1288
|
* </CommandPalette>
|
|
@@ -1255,7 +1290,7 @@ interface CommandPaletteRecordsGroupProps {
|
|
|
1255
1290
|
* }
|
|
1256
1291
|
* ```
|
|
1257
1292
|
*/
|
|
1258
|
-
declare function CommandPaletteRecordsGroup({ enabled, pageSize, minQueryLength, debounceMs,
|
|
1293
|
+
declare function CommandPaletteRecordsGroup({ enabled, pageSize, minQueryLength, debounceMs, onSelect, getTestId, heading, recordHref }: CommandPaletteRecordsGroupProps): React.ReactElement | null;
|
|
1259
1294
|
//#endregion
|
|
1260
1295
|
//#region src/layout/command-palette-actions-group.d.ts
|
|
1261
1296
|
/**
|
|
@@ -1279,8 +1314,8 @@ type CommandPaletteActionsTestIdRole = 'action';
|
|
|
1279
1314
|
* about WHICH actions appear: it also reads `useAppActions()` and renders
|
|
1280
1315
|
* those alongside the prop list — see the component's own docblock for the
|
|
1281
1316
|
* merge order. Each action has a single activation path: either `href`
|
|
1282
|
-
* (
|
|
1283
|
-
* are provided `href` wins.
|
|
1317
|
+
* (navigates through `useRouteNavigate`) OR `onRun` (custom handler). When
|
|
1318
|
+
* both are provided `href` wins.
|
|
1284
1319
|
*/
|
|
1285
1320
|
interface ActionItem {
|
|
1286
1321
|
/** Stable id used for the cmdk `value` and the optional `getTestId` callback. */
|
|
@@ -1304,11 +1339,12 @@ interface ActionItem {
|
|
|
1304
1339
|
*/
|
|
1305
1340
|
onRun?: () => void | Promise<void>;
|
|
1306
1341
|
/**
|
|
1307
|
-
* Optional href shortcut: when set, the component
|
|
1308
|
-
* `
|
|
1309
|
-
*
|
|
1310
|
-
*
|
|
1311
|
-
*
|
|
1342
|
+
* Optional href shortcut: when set, the component navigates to it
|
|
1343
|
+
* through `useRouteNavigate` (the same navigate → `onSelect` → close
|
|
1344
|
+
* flow used elsewhere in the palette) and `onRun` is not called. An
|
|
1345
|
+
* external href (`https:`, `mailto:`) opens in a new window instead.
|
|
1346
|
+
* Use this for actions that are really just navigation shortcuts
|
|
1347
|
+
* (e.g. `"Create new <resource>"`).
|
|
1312
1348
|
*/
|
|
1313
1349
|
href?: string;
|
|
1314
1350
|
/**
|
|
@@ -1356,14 +1392,7 @@ interface CommandPaletteActionsGroupProps {
|
|
|
1356
1392
|
*/
|
|
1357
1393
|
actions?: ActionItem[];
|
|
1358
1394
|
/**
|
|
1359
|
-
* Called
|
|
1360
|
-
* your app router (`router.push` for Next App Router, etc.). When
|
|
1361
|
-
* omitted the component falls back to `window.location.assign(href)`
|
|
1362
|
-
* (full reload). SPAs should always supply `navigate`.
|
|
1363
|
-
*/
|
|
1364
|
-
navigate?: (href: string) => void;
|
|
1365
|
-
/**
|
|
1366
|
-
* Called AFTER the action's handler resolves (or `navigate(href)`
|
|
1395
|
+
* Called AFTER the action's handler resolves (or the navigation
|
|
1367
1396
|
* fires). Adopters typically wire this to `setOpen(false)` so the
|
|
1368
1397
|
* palette closes once the user has picked an action.
|
|
1369
1398
|
*/
|
|
@@ -1408,8 +1437,8 @@ interface CommandPaletteActionsGroupProps {
|
|
|
1408
1437
|
* - Errors thrown / rejected from `onRun` are caught + logged via
|
|
1409
1438
|
* `console.error` and the palette still closes — the user is never
|
|
1410
1439
|
* stuck on an overlay after a misbehaving handler.
|
|
1411
|
-
* - Actions with `href` set bypass `onRun` and
|
|
1412
|
-
* `
|
|
1440
|
+
* - Actions with `href` set bypass `onRun` and navigate through
|
|
1441
|
+
* `useRouteNavigate`; an external href opens in a new window.
|
|
1413
1442
|
* - A registry entry the rule engine allowed-but-disabled (`disabled: true`)
|
|
1414
1443
|
* stays keyboard-reachable and dimmed (`opacity-60`), and selecting it
|
|
1415
1444
|
* shows its `disabledReason` via `toast` instead of running the action —
|
|
@@ -1436,12 +1465,11 @@ interface CommandPaletteActionsGroupProps {
|
|
|
1436
1465
|
* keywords: 'logout sign out',
|
|
1437
1466
|
* },
|
|
1438
1467
|
* ]}
|
|
1439
|
-
* navigate={(href) => router.push(href)}
|
|
1440
1468
|
* onSelect={() => setOpen(false)}
|
|
1441
1469
|
* />
|
|
1442
1470
|
* ```
|
|
1443
1471
|
*/
|
|
1444
|
-
declare function CommandPaletteActionsGroup({ actions,
|
|
1472
|
+
declare function CommandPaletteActionsGroup({ actions, onSelect, getTestId, heading }: CommandPaletteActionsGroupProps): React.ReactElement | null;
|
|
1445
1473
|
//#endregion
|
|
1446
1474
|
//#region src/layout/command-palette-create-group.d.ts
|
|
1447
1475
|
/**
|
|
@@ -1458,19 +1486,12 @@ type CommandPaletteCreateTestIdRole = 'create';
|
|
|
1458
1486
|
interface CommandPaletteCreateGroupProps {
|
|
1459
1487
|
/**
|
|
1460
1488
|
* Override which resources expose a Create entry. Default: every
|
|
1461
|
-
*
|
|
1489
|
+
* resource with a list page that passes its `visible(ctx)` predicate.
|
|
1462
1490
|
* Adopters who want to hide a specific resource's Create action
|
|
1463
1491
|
* (e.g. read-only views, demo-only resources) supply a predicate
|
|
1464
1492
|
* that returns `false` for that resource.
|
|
1465
1493
|
*/
|
|
1466
1494
|
resourceFilter?: (def: ResourceDef) => boolean;
|
|
1467
|
-
/**
|
|
1468
|
-
* Called to navigate to `/${resource}/create`. Wire this to your
|
|
1469
|
-
* app router (`router.push` for Next App Router, etc.). When omitted
|
|
1470
|
-
* the component falls back to `window.location.assign(href)` (full
|
|
1471
|
-
* reload). SPAs should always supply `navigate`.
|
|
1472
|
-
*/
|
|
1473
|
-
navigate?: (href: string) => void;
|
|
1474
1495
|
/**
|
|
1475
1496
|
* Called AFTER the navigation fires. Adopters typically wire this
|
|
1476
1497
|
* to `setOpen(false)` so the palette closes once the user has
|
|
@@ -1491,7 +1512,7 @@ interface CommandPaletteCreateGroupProps {
|
|
|
1491
1512
|
/**
|
|
1492
1513
|
* Override the path generator. By default each item navigates to
|
|
1493
1514
|
* `/<resource>/create`. Adopters with custom create routes
|
|
1494
|
-
* (e.g.
|
|
1515
|
+
* (e.g. a dedicated flow, a modal) override per-resource.
|
|
1495
1516
|
*/
|
|
1496
1517
|
createHref?: (def: ResourceDef) => string;
|
|
1497
1518
|
/**
|
|
@@ -1504,14 +1525,12 @@ interface CommandPaletteCreateGroupProps {
|
|
|
1504
1525
|
/**
|
|
1505
1526
|
* Render the per-resource quick-action group inside a command
|
|
1506
1527
|
* palette: one `"Create new <resource>"` item per registered
|
|
1507
|
-
*
|
|
1528
|
+
* visible resource with a list page.
|
|
1508
1529
|
*
|
|
1509
1530
|
* Filters applied (in order):
|
|
1510
1531
|
*
|
|
1511
|
-
* 1.
|
|
1512
|
-
*
|
|
1513
|
-
* convention; their create flow lives inside the parent's show
|
|
1514
|
-
* page tab.
|
|
1532
|
+
* 1. Resources with no list page (`views.list.page: false`) are
|
|
1533
|
+
* excluded — they are reached through a parent's placement.
|
|
1515
1534
|
* 2. `evaluateVisible(def.visible, visibilityCtx)` must return true.
|
|
1516
1535
|
* Same predicate the sidebar + navigation group use, fail-closed
|
|
1517
1536
|
* on throwing predicates. Hidden in sidebar → hidden here.
|
|
@@ -1525,13 +1544,12 @@ interface CommandPaletteCreateGroupProps {
|
|
|
1525
1544
|
*
|
|
1526
1545
|
* ```tsx
|
|
1527
1546
|
* <CommandPaletteCreateGroup
|
|
1528
|
-
* navigate={(href) => router.push(href)}
|
|
1529
1547
|
* onSelect={() => setOpen(false)}
|
|
1530
1548
|
* getTestId={(role, name) => `command-palette-${role}:${name}`}
|
|
1531
1549
|
* />
|
|
1532
1550
|
* ```
|
|
1533
1551
|
*/
|
|
1534
|
-
declare function CommandPaletteCreateGroup({ resourceFilter,
|
|
1552
|
+
declare function CommandPaletteCreateGroup({ resourceFilter, onSelect, getTestId, heading, createHref, prefix }: CommandPaletteCreateGroupProps): React.ReactElement | null;
|
|
1535
1553
|
//#endregion
|
|
1536
1554
|
//#region src/layout/link-component.d.ts
|
|
1537
1555
|
/**
|
|
@@ -1551,67 +1569,31 @@ type LinkComponentProps = Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>
|
|
|
1551
1569
|
children?: ReactNode;
|
|
1552
1570
|
};
|
|
1553
1571
|
type LinkComponent = ComponentType<LinkComponentProps>;
|
|
1554
|
-
/**
|
|
1555
|
-
* Imperative client-side navigation. Mirrors the `<Link>` mechanism for the
|
|
1556
|
-
* cases a component must navigate from an event handler (e.g. a whole-row click
|
|
1557
|
-
* on a list, #4) rather than render an anchor. The default performs a full-page
|
|
1558
|
-
* `window.location.assign`; adopters install their router's push
|
|
1559
|
-
* (`next/router`'s `router.push`, react-router's `navigate`) via
|
|
1560
|
-
* `<LinkComponentProvider navigate={...}>` so it stays client-side.
|
|
1561
|
-
*/
|
|
1562
|
-
type NavigateFn = (href: string) => void;
|
|
1563
|
-
/**
|
|
1564
|
-
* Read the imperative navigate function. Use for programmatic navigation from an
|
|
1565
|
-
* event handler; prefer `useLinkComponent()` (a real anchor) whenever the target
|
|
1566
|
-
* can be rendered as a link, since anchors give Cmd/Ctrl-click, middle-click and
|
|
1567
|
-
* right-click "open in new tab" for free.
|
|
1568
|
-
*/
|
|
1569
|
-
declare function useNavigate(): NavigateFn;
|
|
1570
|
-
/**
|
|
1571
|
-
* Read the app's current pathname. Supplied by `LinkComponentProvider`
|
|
1572
|
-
* (`currentPath` prop, e.g. Next's `usePathname()` or react-router's
|
|
1573
|
-
* `useLocation().pathname`). Defaults to '' when no provider is present
|
|
1574
|
-
* (SSR-safe). This is the read side of the router seam — `useMatch` uses it
|
|
1575
|
-
* to resolve the active route via `matchPath`.
|
|
1576
|
-
*/
|
|
1577
|
-
declare function useCurrentPath(): string;
|
|
1578
1572
|
interface LinkComponentProviderProps {
|
|
1579
1573
|
/**
|
|
1580
|
-
* The router-aware Link component to use throughout
|
|
1581
|
-
*
|
|
1582
|
-
*
|
|
1583
|
-
* primitive once for react-router / TanStack Router.
|
|
1574
|
+
* The router-aware Link component to use throughout `@burojs/ui-shadcn` for
|
|
1575
|
+
* internal navigation. Pass `Link` from `next/link` for Next.js App Router;
|
|
1576
|
+
* wrap your router's link primitive once for react-router / TanStack Router.
|
|
1584
1577
|
*/
|
|
1585
1578
|
linkComponent: LinkComponent;
|
|
1586
|
-
/**
|
|
1587
|
-
* Optional imperative navigate (client-side) for handler-driven navigation
|
|
1588
|
-
* such as whole-row clicks. Defaults to a full-page `window.location.assign`.
|
|
1589
|
-
*/
|
|
1590
|
-
navigate?: NavigateFn;
|
|
1591
|
-
/**
|
|
1592
|
-
* The app's current pathname; feed `usePathname()` (Next) or
|
|
1593
|
-
* `useLocation().pathname` (react-router).
|
|
1594
|
-
*/
|
|
1595
|
-
currentPath?: string;
|
|
1596
1579
|
children: ReactNode;
|
|
1597
1580
|
}
|
|
1598
1581
|
/**
|
|
1599
|
-
* Install a router-aware `LinkComponent` for every framework component
|
|
1600
|
-
*
|
|
1601
|
-
*
|
|
1602
|
-
*
|
|
1603
|
-
* but causes a full document reload on every click, which defeats the
|
|
1604
|
-
* SPA experience a client-side router (Next.js, react-router) is meant
|
|
1605
|
-
* to provide.
|
|
1582
|
+
* Install a router-aware `LinkComponent` for every framework component that
|
|
1583
|
+
* renders an internal navigation link (sidebar entries, action links, relation
|
|
1584
|
+
* cells, the list-empty Create CTA, …). Without it the framework falls back to
|
|
1585
|
+
* a raw `<a>` — correct, but a full document reload on every click.
|
|
1606
1586
|
*
|
|
1607
|
-
*
|
|
1587
|
+
* This is a link component and nothing else: the location and imperative
|
|
1588
|
+
* navigation are the `RouterAdapter`'s (`RouterAdapterProvider` and
|
|
1589
|
+
* `useRouteNavigate` from `@burojs/react`), the one router seam.
|
|
1608
1590
|
*
|
|
1609
1591
|
* import Link from 'next/link';
|
|
1610
1592
|
* <LinkComponentProvider linkComponent={Link}>
|
|
1611
1593
|
* <App />
|
|
1612
1594
|
* </LinkComponentProvider>
|
|
1613
1595
|
*/
|
|
1614
|
-
declare function LinkComponentProvider({ linkComponent,
|
|
1596
|
+
declare function LinkComponentProvider({ linkComponent, children }: LinkComponentProviderProps): ReactElement;
|
|
1615
1597
|
/**
|
|
1616
1598
|
* Read the current `LinkComponent`. Call this from any framework
|
|
1617
1599
|
* component that needs to render an internal-navigation link, then
|
|
@@ -1629,52 +1611,87 @@ declare function useLinkComponent(): LinkComponent;
|
|
|
1629
1611
|
/**
|
|
1630
1612
|
* The app-scoped visibility predicate passed to the pure core resolvers so
|
|
1631
1613
|
* that group-index → first-visible-child resolution and (later) chrome item
|
|
1632
|
-
* lists honor `visible(ctx)`. Resources and
|
|
1633
|
-
* against the current visibility context;
|
|
1634
|
-
*
|
|
1614
|
+
* lists honor `visible(ctx)`. Resources, groups and custom pages consult
|
|
1615
|
+
* `evaluateVisible` against the current visibility context; a node without a
|
|
1616
|
+
* predicate is visible. The custom-page route gates on it too (`<PageHost>`).
|
|
1635
1617
|
*/
|
|
1636
1618
|
declare function useNavVisible(): (node: NavNode) => boolean;
|
|
1637
1619
|
/** Canonical href for a resource / custom page / group. Nesting-independent. */
|
|
1638
1620
|
declare function useHref(name: string, opts?: Omit<HrefOpts, 'isVisible'>): string;
|
|
1639
|
-
/**
|
|
1621
|
+
/**
|
|
1622
|
+
* Resolve the active route from the router adapter's pathname, or null. The
|
|
1623
|
+
* router adapter is the framework's only source of the location; without one
|
|
1624
|
+
* there is no location, so there is no match.
|
|
1625
|
+
*/
|
|
1640
1626
|
declare function useMatch(): RouteMatch | null;
|
|
1641
1627
|
//#endregion
|
|
1642
|
-
//#region src/layout/navigation-guard.d.ts
|
|
1628
|
+
//#region src/layout/navigation-guard-dialog.d.ts
|
|
1643
1629
|
/**
|
|
1644
|
-
*
|
|
1645
|
-
*
|
|
1646
|
-
*
|
|
1630
|
+
* The unsaved-changes guard's "leave?" dialog. The guard itself — which clicks
|
|
1631
|
+
* it holds, `beforeunload`, the back-button sentinel — is `@burojs/react`'s and
|
|
1632
|
+
* mounted by `<BuroProvider>`; this component registers itself as the guard's
|
|
1633
|
+
* dialog while mounted and answers the navigation the guard is holding.
|
|
1634
|
+
* `<AppLayout>` renders one, so an app on the layout mounts nothing; an app
|
|
1635
|
+
* without it renders this once inside `<BuroProvider>`. With no dialog
|
|
1636
|
+
* registered the guard asks through `window.confirm`.
|
|
1637
|
+
*
|
|
1638
|
+
* A second mounted dialog stays closed: the guard hands a held navigation to
|
|
1639
|
+
* the most recently registered dialog only, and back to the previous one when
|
|
1640
|
+
* that one unmounts.
|
|
1647
1641
|
*/
|
|
1648
|
-
declare function
|
|
1649
|
-
declare function NavigationGuardProvider({ children }: {
|
|
1650
|
-
children: ReactNode;
|
|
1651
|
-
}): React.ReactElement;
|
|
1642
|
+
declare function NavigationGuardDialog(): ReactElement;
|
|
1652
1643
|
//#endregion
|
|
1653
|
-
//#region src/
|
|
1654
|
-
interface
|
|
1655
|
-
|
|
1656
|
-
email: string;
|
|
1657
|
-
/** 1–2 char fallback shown in the avatar circle. */
|
|
1658
|
-
avatarFallback: string;
|
|
1659
|
-
/** Extra dropdown rows rendered above the logout item (theme/language/role, etc.). */
|
|
1660
|
-
menu?: ReactNode;
|
|
1661
|
-
onLogout: () => void;
|
|
1662
|
-
logoutLabel?: string;
|
|
1644
|
+
//#region src/shell/refresh-button.d.ts
|
|
1645
|
+
interface RefreshButtonProps {
|
|
1646
|
+
readonly className?: string;
|
|
1663
1647
|
}
|
|
1664
|
-
|
|
1648
|
+
/** Ghost icon button that refetches the app's data; spins and disables while it runs. */
|
|
1649
|
+
declare function RefreshButton({ className }: RefreshButtonProps): ReactElement | null;
|
|
1650
|
+
//#endregion
|
|
1651
|
+
//#region src/shell/app-actions.d.ts
|
|
1652
|
+
/**
|
|
1653
|
+
* The app-level action strip: every `defineAppAction` entry that belongs to no resource, already
|
|
1654
|
+
* filtered by the rule engine (`useAppActions`). Only entries that resolve to a route render: a
|
|
1655
|
+
* `link`, or a flow hosted on a page (`hostHref`). A `modal` entry needs a presentation host and is
|
|
1656
|
+
* skipped. `disabledReason` keeps the action visible but inert, with the reason as its tooltip.
|
|
1657
|
+
*/
|
|
1658
|
+
declare function AppActions(): ReactElement | null;
|
|
1659
|
+
//#endregion
|
|
1660
|
+
//#region src/shell/help-button.d.ts
|
|
1661
|
+
type HelpButtonProps = {
|
|
1662
|
+
readonly className?: string;
|
|
1663
|
+
} & ({
|
|
1664
|
+
readonly href: string;
|
|
1665
|
+
readonly onClick?: never;
|
|
1666
|
+
} | {
|
|
1667
|
+
readonly onClick: () => void;
|
|
1668
|
+
readonly href?: never;
|
|
1669
|
+
});
|
|
1670
|
+
/** Ghost icon button that opens help: a link when given `href`, a button when given `onClick`. */
|
|
1671
|
+
declare function HelpButton({ href, onClick, className }: HelpButtonProps): ReactElement;
|
|
1665
1672
|
//#endregion
|
|
1666
1673
|
//#region src/layout/app-header.d.ts
|
|
1674
|
+
/** Every slot follows {@link Slot}: omit for the default, `false` for nothing, an element to replace. */
|
|
1667
1675
|
interface AppHeaderProps {
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1676
|
+
/** The breadcrumb trail. Default `<HeaderBreadcrumbs />`, the current route's trail. */
|
|
1677
|
+
breadcrumbs?: Slot;
|
|
1678
|
+
/**
|
|
1679
|
+
* The search chip. Default `<CommandPaletteTrigger />`, which renders only
|
|
1680
|
+
* when the `ShellProvider` has an `openPalette`.
|
|
1681
|
+
*/
|
|
1682
|
+
search?: Slot;
|
|
1683
|
+
/**
|
|
1684
|
+
* The right-hand controls. Default `<AppActions />` and `<RefreshButton />`;
|
|
1685
|
+
* each renders nothing when it has nothing to show.
|
|
1686
|
+
*/
|
|
1687
|
+
actions?: Slot;
|
|
1671
1688
|
className?: string;
|
|
1672
1689
|
}
|
|
1673
1690
|
declare function AppHeader({ breadcrumbs, search, actions, className }: AppHeaderProps): React.ReactElement;
|
|
1674
1691
|
//#endregion
|
|
1675
1692
|
//#region src/layout/document-title.d.ts
|
|
1676
1693
|
/**
|
|
1677
|
-
* Register the desired `document.title` for the current page. Under a
|
|
1694
|
+
* Register the desired `document.title` for the current page (suffixed with ` · <brand name>` under a `ShellProvider` brand). Under a
|
|
1678
1695
|
* `DocumentTitleProvider` the title is applied AND DEFENDED against Next's
|
|
1679
1696
|
* metadata writes (Next re-applies the root `metadata.title` to `<title>` on
|
|
1680
1697
|
* soft navigations — same-URL clicks, `?query` changes, post-hydration ticks —
|
|
@@ -1714,62 +1731,19 @@ declare function DocumentTitleProvider({ routeKey, children }: {
|
|
|
1714
1731
|
//#region src/notification/toaster.d.ts
|
|
1715
1732
|
interface ToasterProps extends ToasterProps$1 {}
|
|
1716
1733
|
/**
|
|
1717
|
-
* Shadcn-canonical Sonner setup
|
|
1718
|
-
*
|
|
1719
|
-
*
|
|
1734
|
+
* Shadcn-canonical Sonner setup, and — inside a `<BuroProvider>` — the app's
|
|
1735
|
+
* notification sink: the dispatcher's default `notify` (every handler's
|
|
1736
|
+
* `notify`, and a thrown handler's error) is delivered here. Outside a
|
|
1737
|
+
* provider it registers nothing and still renders anything sent with `toast()`.
|
|
1720
1738
|
*
|
|
1721
|
-
*
|
|
1722
|
-
*
|
|
1723
|
-
*
|
|
1724
|
-
*
|
|
1725
|
-
*
|
|
1726
|
-
* submenu — flips the toast theme without a remount.
|
|
1727
|
-
* - Toast surface, border, shadow, and description text are pinned
|
|
1728
|
-
* to `bg-background` / `text-foreground` / `border-border` / etc.,
|
|
1729
|
-
* matching Card and AlertDialog primitives.
|
|
1739
|
+
* Bound to design tokens via `toastOptions.classNames`, so toasts inherit the
|
|
1740
|
+
* app's light/dark theme through the same CSS-variable cascade as the rest of
|
|
1741
|
+
* the UI; `theme` is reactive via `useTheme()`. The error catalogue follows the
|
|
1742
|
+
* ACTIVE i18n locale, read per toast so a language switch is honoured; with no
|
|
1743
|
+
* i18n provider it falls back to the locale `<LanguageSwitch>` persisted.
|
|
1730
1744
|
*/
|
|
1731
1745
|
declare function Toaster(props: ToasterProps): React.ReactElement;
|
|
1732
1746
|
//#endregion
|
|
1733
|
-
//#region src/notification/notification-provider.d.ts
|
|
1734
|
-
interface NotificationSink {
|
|
1735
|
-
open(args: {
|
|
1736
|
-
readonly type: 'success' | 'error' | 'progress';
|
|
1737
|
-
readonly message: string;
|
|
1738
|
-
readonly description?: string;
|
|
1739
|
-
}): void;
|
|
1740
|
-
close(key: string): void;
|
|
1741
|
-
}
|
|
1742
|
-
/**
|
|
1743
|
-
* A legacy query adapter can build its default query-error notification outside
|
|
1744
|
-
* our i18n bundle: in a Russian-primary app the user
|
|
1745
|
-
* saw «Error (status code: undefined)» / «Failed to fetch», plus it duplicated
|
|
1746
|
-
* the inline error state a list already renders. We can't localize a string we
|
|
1747
|
-
* don't own, so `toFriendlyError` recognises it and substitutes plain language.
|
|
1748
|
-
* The SAME helper backs the list's inline panel — see friendly-error.ts for why
|
|
1749
|
-
* that matters.
|
|
1750
|
-
*/
|
|
1751
|
-
interface NotificationProviderOptions {
|
|
1752
|
-
/**
|
|
1753
|
-
* How to find the ACTIVE locale when an error toast needs its catalogue.
|
|
1754
|
-
* Defaults to the locale persisted by `<LanguageSwitch>` under
|
|
1755
|
-
* {@link DEFAULT_LANGUAGE_STORAGE_KEY}.
|
|
1756
|
-
*
|
|
1757
|
-
* The escape hatch exists because the default is only right for an app that
|
|
1758
|
-
* left `storageKey` alone: `<LanguageSwitch storageKey="acme:lang">` writes
|
|
1759
|
-
* somewhere this factory does not look, and the toast would silently take the
|
|
1760
|
-
* fallback catalogue forever. Such an app passes
|
|
1761
|
-
* `{ resolveLocale: () => loadLocale('acme:lang') }` — or reads its own i18n
|
|
1762
|
-
* facade directly, which is strictly better still.
|
|
1763
|
-
*
|
|
1764
|
-
* ⚠️ It is a FUNCTION, not a value, and that is load-bearing: both examples
|
|
1765
|
-
* build this sink once (`React.useMemo(…, [])`) and it has no React context
|
|
1766
|
-
* to subscribe to, so a locale captured at construction would freeze at
|
|
1767
|
-
* whatever was active on the first render. Called per toast instead.
|
|
1768
|
-
*/
|
|
1769
|
-
readonly resolveLocale?: () => string | undefined;
|
|
1770
|
-
}
|
|
1771
|
-
declare function createNotificationProvider(options?: NotificationProviderOptions): NotificationSink;
|
|
1772
|
-
//#endregion
|
|
1773
1747
|
//#region src/auth/login-form.d.ts
|
|
1774
1748
|
declare const schema: z.ZodObject<{
|
|
1775
1749
|
email: z.ZodString;
|
|
@@ -1793,7 +1767,10 @@ declare function LoginForm({ onSubmit, title, description, className }: LoginFor
|
|
|
1793
1767
|
//#region src/auth/auth-page.d.ts
|
|
1794
1768
|
interface AuthPageProps {
|
|
1795
1769
|
children: ReactNode;
|
|
1796
|
-
/**
|
|
1770
|
+
/**
|
|
1771
|
+
* The brand above the auth card. Omit it for `<BrandMark />` (the `ShellProvider` brand, if
|
|
1772
|
+
* any); pass `false` for none; pass an element to replace it.
|
|
1773
|
+
*/
|
|
1797
1774
|
brand?: ReactNode;
|
|
1798
1775
|
/** Optional footer text under the auth card (e.g. legal). */
|
|
1799
1776
|
footer?: ReactNode;
|
|
@@ -1830,13 +1807,28 @@ declare const shadcnFieldImplementations: Readonly<{
|
|
|
1830
1807
|
'default:date-time': FieldImplementation<unknown, Readonly<Record<string, unknown>>>;
|
|
1831
1808
|
enum: FieldImplementation<unknown, Readonly<Record<string, unknown>>>;
|
|
1832
1809
|
json: FieldImplementation<unknown, Readonly<Record<string, unknown>>>;
|
|
1833
|
-
relation:
|
|
1810
|
+
relation: Readonly<{
|
|
1811
|
+
Input?: import("react").ComponentType<ScalarInputProps<unknown, Readonly<Record<string, unknown>>>> | undefined;
|
|
1812
|
+
Display?: import("react").ComponentType<ScalarDisplayProps<unknown, Readonly<Record<string, unknown>>>> | undefined;
|
|
1813
|
+
CollectionInput?: import("react").ComponentType<CollectionInputProps<unknown, Readonly<Record<string, unknown>>>> | undefined;
|
|
1814
|
+
CollectionDisplay?: import("react").ComponentType<CollectionDisplayProps<unknown, Readonly<Record<string, unknown>>>> | undefined;
|
|
1815
|
+
layout?: FieldImplementationLayout;
|
|
1816
|
+
meta: import("@burojs/core").StandardSchemaV1<unknown, Readonly<Record<string, unknown>>>;
|
|
1817
|
+
}>;
|
|
1834
1818
|
richText: FieldImplementation<unknown, Readonly<Record<string, unknown>>>;
|
|
1835
1819
|
'rich-text': FieldImplementation<unknown, Readonly<Record<string, unknown>>>;
|
|
1836
1820
|
'default:rich-text': FieldImplementation<unknown, Readonly<Record<string, unknown>>>;
|
|
1837
1821
|
file: FieldImplementation<unknown, Readonly<Record<string, unknown>>>;
|
|
1838
1822
|
}>;
|
|
1839
1823
|
//#endregion
|
|
1824
|
+
//#region src/blocks/builtins.d.ts
|
|
1825
|
+
/**
|
|
1826
|
+
* The built-in block views (`buro:*`), keyed by block id. The renderer composes them first and
|
|
1827
|
+
* the app's `blockImplementations` over them: an app entry with a built-in id replaces that view
|
|
1828
|
+
* (with a development notice); a built-in cannot be dropped.
|
|
1829
|
+
*/
|
|
1830
|
+
declare const shadcnBlockImplementations: BlockImplementationCatalog;
|
|
1831
|
+
//#endregion
|
|
1840
1832
|
//#region src/fields/registry.d.ts
|
|
1841
1833
|
interface FieldRendererProps {
|
|
1842
1834
|
value: unknown;
|
|
@@ -1850,7 +1842,7 @@ interface FieldRendererProps {
|
|
|
1850
1842
|
};
|
|
1851
1843
|
options?: Array<{
|
|
1852
1844
|
value: string;
|
|
1853
|
-
label:
|
|
1845
|
+
label: string;
|
|
1854
1846
|
icon?: string;
|
|
1855
1847
|
}>;
|
|
1856
1848
|
/**
|
|
@@ -1878,6 +1870,15 @@ interface FieldRendererProps {
|
|
|
1878
1870
|
}
|
|
1879
1871
|
interface FieldInputProps {
|
|
1880
1872
|
name: string;
|
|
1873
|
+
/** A relation select's create seeds (P6-31): the registry's `candidates` literals. */
|
|
1874
|
+
relationSeeds?: Readonly<Record<string, unknown>>;
|
|
1875
|
+
/** A relation select's extra filters from the form's `filter` function (P7 3.4). */
|
|
1876
|
+
fixedFilters?: readonly FixedFilterInput[];
|
|
1877
|
+
/**
|
|
1878
|
+
* The field owner's source states, projected by what the user may view: what a relation's
|
|
1879
|
+
* `candidates` refs are read from (P7 3.4).
|
|
1880
|
+
*/
|
|
1881
|
+
metaSources?: ScreenSources;
|
|
1881
1882
|
id?: string;
|
|
1882
1883
|
value: unknown;
|
|
1883
1884
|
/** True when this renderer is reached through a collection implementation. */
|
|
@@ -1886,7 +1887,7 @@ interface FieldInputProps {
|
|
|
1886
1887
|
testid?: string;
|
|
1887
1888
|
options?: Array<{
|
|
1888
1889
|
value: string;
|
|
1889
|
-
label:
|
|
1890
|
+
label: string;
|
|
1890
1891
|
icon?: string;
|
|
1891
1892
|
}>;
|
|
1892
1893
|
placeholder?: string;
|
|
@@ -1900,7 +1901,7 @@ interface FieldInputProps {
|
|
|
1900
1901
|
pattern?: string;
|
|
1901
1902
|
/**
|
|
1902
1903
|
* When true, renders `aria-invalid="true"` on the underlying input
|
|
1903
|
-
* control. Forwarded by `<
|
|
1904
|
+
* control. Forwarded by `<RecordScreen>` for fields that have a
|
|
1904
1905
|
* non-null validation error AND have been touched (blurred or
|
|
1905
1906
|
* post-submit). Renderers should pass this through to their root
|
|
1906
1907
|
* input element so screen-readers can announce the invalid state.
|
|
@@ -1919,18 +1920,18 @@ interface FieldInputProps {
|
|
|
1919
1920
|
* `aria-errormessage` on their root input element so screen-readers
|
|
1920
1921
|
* with WAI-ARIA 1.2 support associate the error specifically.
|
|
1921
1922
|
* `aria-invalid="true"` must also be set for `aria-errormessage` to
|
|
1922
|
-
* be honored — `<
|
|
1923
|
+
* be honored — `<RecordScreen>` already wires both together.
|
|
1923
1924
|
*/
|
|
1924
1925
|
ariaErrorMessage?: string;
|
|
1925
1926
|
/**
|
|
1926
1927
|
* Field metadata, mirroring `FieldRendererProps.field`. Forwarded by
|
|
1927
|
-
* `<
|
|
1928
|
+
* `<RecordScreen>` so renderers that depend on per-field meta (e.g.
|
|
1928
1929
|
* the relation picker reading `meta.to` for the target resource) can
|
|
1929
1930
|
* read it. Renderers that don't care simply ignore the prop.
|
|
1930
1931
|
*
|
|
1931
1932
|
* The `ui` block carries the field-type-specific renderer config
|
|
1932
1933
|
* (e.g. `<FileInput>` reads `ui.accept` / `ui.maxSize` /
|
|
1933
|
-
* `ui.fileStorage`). Forwarded by `<
|
|
1934
|
+
* `ui.fileStorage`). Forwarded by `<RecordScreen>` from the field
|
|
1934
1935
|
* definition's `def.ui` block.
|
|
1935
1936
|
*
|
|
1936
1937
|
* Optional for backward compatibility — every existing renderer was
|
|
@@ -1975,8 +1976,8 @@ declare function DateDisplay({ value }: FieldRendererProps): React$1.ReactElemen
|
|
|
1975
1976
|
declare function DateInput({ name, id, value, onChange, testid, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage }: FieldInputProps): React$1.ReactElement;
|
|
1976
1977
|
//#endregion
|
|
1977
1978
|
//#region src/fields/enum.d.ts
|
|
1978
|
-
declare function EnumDisplay({ value, options, field }: FieldRendererProps): React$1.ReactElement;
|
|
1979
|
-
declare function EnumInput({ name, id, value, onChange, testid, options, field, placeholder, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage }: FieldInputProps): React$1.ReactElement;
|
|
1979
|
+
declare function EnumDisplay({ value, options, field, resource }: FieldRendererProps): React$1.ReactElement;
|
|
1980
|
+
declare function EnumInput({ name, id, value, onChange, testid, options, field, placeholder, disabled, required, ariaInvalid, ariaDescribedBy, ariaErrorMessage, resource }: FieldInputProps): React$1.ReactElement;
|
|
1980
1981
|
//#endregion
|
|
1981
1982
|
//#region src/fields/textarea.d.ts
|
|
1982
1983
|
declare function TextareaDisplay({ value }: FieldRendererProps): React$1.ReactElement;
|
|
@@ -2042,6 +2043,25 @@ declare function RelationField({ to, value }: {
|
|
|
2042
2043
|
/** FK value to resolve, or null/undefined/'' when empty. */
|
|
2043
2044
|
value: unknown;
|
|
2044
2045
|
}): React$1.ReactElement;
|
|
2046
|
+
/**
|
|
2047
|
+
* A to-many relation (`f.relationMany`): each key rendered as {@link RelationDisplay} renders
|
|
2048
|
+
* one — eager keys share the aggregator's batched read, lazy keys read nothing.
|
|
2049
|
+
*/
|
|
2050
|
+
declare function RelationManyDisplay({ value, field }: FieldRendererProps): React$1.ReactElement;
|
|
2051
|
+
//#endregion
|
|
2052
|
+
//#region src/fields/candidates-gate.d.ts
|
|
2053
|
+
/** A select that must not read its target now (P7 3.4): why, and what it tells the user. */
|
|
2054
|
+
type CandidatesGate = {
|
|
2055
|
+
readonly kind: 'pending';
|
|
2056
|
+
} | {
|
|
2057
|
+
readonly kind: 'empty';
|
|
2058
|
+
readonly message: string;
|
|
2059
|
+
readonly testId: string;
|
|
2060
|
+
} | {
|
|
2061
|
+
readonly kind: 'forbidden';
|
|
2062
|
+
readonly message: string;
|
|
2063
|
+
readonly testId: string;
|
|
2064
|
+
};
|
|
2045
2065
|
//#endregion
|
|
2046
2066
|
//#region src/fields/relation-picker.d.ts
|
|
2047
2067
|
/**
|
|
@@ -2074,8 +2094,13 @@ interface RelationPickerProps {
|
|
|
2074
2094
|
to: string;
|
|
2075
2095
|
/** Currently-selected FK value, or null/undefined when empty. */
|
|
2076
2096
|
value: string | number | null | undefined;
|
|
2077
|
-
/** Called with the new selected id, or null when cleared. */
|
|
2097
|
+
/** Called with the new selected id (or `by` value), or null when cleared. */
|
|
2078
2098
|
onChange: (next: string | number | null) => void;
|
|
2099
|
+
/**
|
|
2100
|
+
* The target field the value holds (`meta.by`, spec 4.2): options write `row[by]` and the
|
|
2101
|
+
* selected value is resolved by it. Absent: the target's id field.
|
|
2102
|
+
*/
|
|
2103
|
+
by?: string;
|
|
2079
2104
|
/**
|
|
2080
2105
|
* Field whose value is matched against the search text. Defaults to
|
|
2081
2106
|
* the target's `displayField` (which is what the trigger label
|
|
@@ -2106,6 +2131,27 @@ interface RelationPickerProps {
|
|
|
2106
2131
|
* user, and add `label` to render it as an undeletable badge instead.
|
|
2107
2132
|
*/
|
|
2108
2133
|
fixedFilters?: readonly FixedFilterInput[];
|
|
2134
|
+
/**
|
|
2135
|
+
* The trusted `defaults` of a create opened from this select (P6-31): the registry field's
|
|
2136
|
+
* static `eq` literals, handed down by the form controller. Never read from `fixedFilters` or
|
|
2137
|
+
* `field.meta`.
|
|
2138
|
+
*/
|
|
2139
|
+
createSeeds?: Readonly<Record<string, unknown>>;
|
|
2140
|
+
/**
|
|
2141
|
+
* What the field's `candidates` say about reading the target right now (P7 3.4): `pending`
|
|
2142
|
+
* draws a disabled trigger, `empty` a popover that says what to choose first, `forbidden` a
|
|
2143
|
+
* disabled trigger and why. While set, nothing is read for the options. Absent: read normally.
|
|
2144
|
+
*/
|
|
2145
|
+
candidatesGate?: CandidatesGate;
|
|
2146
|
+
/**
|
|
2147
|
+
* Whether a loaded row fits the resolved candidate filters (already in `fixedFilters`):
|
|
2148
|
+
* `false` makes the field say the chosen row "does not match the current filter" (P7 3.4).
|
|
2149
|
+
*/
|
|
2150
|
+
rowFits?: (row: Record<string, unknown>) => boolean | undefined;
|
|
2151
|
+
/** The form field holding the key (the "view" and "+ create" test ids); defaults to `name`. */
|
|
2152
|
+
fieldName?: string;
|
|
2153
|
+
/** The field's `ui.open` (P7 3.6): what the "view" button opens, or no button for `none`. */
|
|
2154
|
+
open?: RelationOpen;
|
|
2109
2155
|
disabled?: boolean;
|
|
2110
2156
|
required?: boolean;
|
|
2111
2157
|
className?: string;
|
|
@@ -2116,7 +2162,7 @@ interface RelationPickerProps {
|
|
|
2116
2162
|
/** Forwarded to the trigger button as `aria-errormessage` (WAI-ARIA 1.2). */
|
|
2117
2163
|
ariaErrorMessage?: string;
|
|
2118
2164
|
}
|
|
2119
|
-
declare function RelationPicker({ to, value, onChange, searchField, pageSize, clearable, placeholder, name, id, testid, fixedFilters, disabled, required, className, ariaInvalid, ariaDescribedBy, ariaErrorMessage }: RelationPickerProps): React$1.ReactElement;
|
|
2165
|
+
declare function RelationPicker({ to, value, onChange, by, searchField, pageSize, clearable, placeholder, name, id, testid, fixedFilters, createSeeds, candidatesGate, rowFits, fieldName, open: openMode, disabled, required, className, ariaInvalid, ariaDescribedBy, ariaErrorMessage }: RelationPickerProps): React$1.ReactElement;
|
|
2120
2166
|
/**
|
|
2121
2167
|
* Form-field adapter wrapping `<RelationPicker>` for use as a default
|
|
2122
2168
|
* Input renderer in the field registry. Reads `field.meta.to` for the
|
|
@@ -2126,6 +2172,20 @@ declare function RelationPicker({ to, value, onChange, searchField, pageSize, cl
|
|
|
2126
2172
|
*/
|
|
2127
2173
|
declare function RelationPickerInput(props: FieldInputProps): React$1.ReactElement;
|
|
2128
2174
|
//#endregion
|
|
2175
|
+
//#region src/fields/relation-create.d.ts
|
|
2176
|
+
/** What the picker and its dialog share: one pending create per select (P6-34). */
|
|
2177
|
+
interface SelectCreate {
|
|
2178
|
+
readonly pending: boolean;
|
|
2179
|
+
/**
|
|
2180
|
+
* The hand-back read is forbidden: its filter names a field P5 hides from the user (the same
|
|
2181
|
+
* rule that stops the picker's own option read), or the access map is not ready. A blocked
|
|
2182
|
+
* select offers no "+ Create" and starts none, so no predicate on a hidden field is ever sent.
|
|
2183
|
+
*/
|
|
2184
|
+
readonly blocked: boolean;
|
|
2185
|
+
/** Runs `open` unless a create of this select is already pending or the select is gone. */
|
|
2186
|
+
start(open: () => Promise<QuickSettledRow>): void;
|
|
2187
|
+
}
|
|
2188
|
+
//#endregion
|
|
2129
2189
|
//#region src/fields/relation-picker-dialog.d.ts
|
|
2130
2190
|
/**
|
|
2131
2191
|
* Advanced-search modal for the relation picker (#11 / #9). The inline popover
|
|
@@ -2176,11 +2236,34 @@ interface RelationPickerDialogProps {
|
|
|
2176
2236
|
* renders it as an undeletable badge.
|
|
2177
2237
|
*/
|
|
2178
2238
|
fixedFilters?: readonly FixedFilterInput[];
|
|
2179
|
-
/**
|
|
2180
|
-
|
|
2239
|
+
/**
|
|
2240
|
+
* The select's one pending create (P6-34), shared with its popover. With it the footer offers
|
|
2241
|
+
* "+ Create" (the target's `quick.create`, handed back through the select's own query); without
|
|
2242
|
+
* it the dialog offers none. The dialog is not a dismiss scope and holds no form: the sheet a
|
|
2243
|
+
* create opens stacks above it.
|
|
2244
|
+
*/
|
|
2245
|
+
create?: SelectCreate;
|
|
2246
|
+
/** The trusted `defaults` of that create: the registry field's static `eq` literals (P6-31). */
|
|
2247
|
+
createSeeds?: Readonly<Record<string, unknown>>;
|
|
2248
|
+
/** The form field holding the key (the create button's test id). */
|
|
2249
|
+
fieldName?: string;
|
|
2250
|
+
/** Runs before a create opens: the select returns focus to its trigger. */
|
|
2251
|
+
onBeforeCreate?: () => void;
|
|
2181
2252
|
pageSize?: number;
|
|
2253
|
+
/**
|
|
2254
|
+
* A to-many select's choice (P7 3.5): a click toggles the row in `selected` through `onToggle`
|
|
2255
|
+
* and the dialog stays open until the user is done. Without it, a click picks one row and closes.
|
|
2256
|
+
*/
|
|
2257
|
+
multiple?: boolean;
|
|
2258
|
+
/** The keys already chosen (`multiple` only): their rows are marked. */
|
|
2259
|
+
selected?: readonly (string | number)[];
|
|
2260
|
+
onToggle?: (value: string | number) => void;
|
|
2182
2261
|
}
|
|
2183
|
-
declare function RelationPickerDialog({ to, open, onOpenChange, onSelect, onSelectRow, searchField, valueField, fixedFilters,
|
|
2262
|
+
declare function RelationPickerDialog({ to, open, onOpenChange, onSelect, onSelectRow, searchField, valueField, fixedFilters, create, createSeeds, fieldName, onBeforeCreate, pageSize, multiple, selected, onToggle }: RelationPickerDialogProps): React$1.ReactElement;
|
|
2263
|
+
//#endregion
|
|
2264
|
+
//#region src/fields/lazy-relation-picker-dialog.d.ts
|
|
2265
|
+
/** The "Advanced search" dialog, loaded on the first open: nothing is drawn until it arrives. */
|
|
2266
|
+
declare function LazyRelationPickerDialog(props: ComponentProps<typeof RelationPickerDialog>): ReactElement;
|
|
2184
2267
|
//#endregion
|
|
2185
2268
|
//#region src/fields/use-dialog-filter-state.d.ts
|
|
2186
2269
|
/** The portable erased AST — the only shape this module deals in. */
|
|
@@ -2222,6 +2305,10 @@ interface DialogFilterState {
|
|
|
2222
2305
|
readonly fixed: readonly ResolvedFixedFilter[];
|
|
2223
2306
|
/** The single expression to hand the data provider. */
|
|
2224
2307
|
readonly filter: ErasedExpression | undefined;
|
|
2308
|
+
/** Whether the target has a search for this user (no field left means no search box). */
|
|
2309
|
+
readonly searchEnabled: boolean;
|
|
2310
|
+
/** The read must not be sent: undecided access, or a filter naming a field the user may not view. */
|
|
2311
|
+
readonly blocked: boolean;
|
|
2225
2312
|
readonly reset: () => void;
|
|
2226
2313
|
}
|
|
2227
2314
|
/**
|
|
@@ -2322,6 +2409,12 @@ interface ResolvedFieldDisplayProps {
|
|
|
2322
2409
|
readonly testId?: string;
|
|
2323
2410
|
readonly fallback: ReactNode;
|
|
2324
2411
|
readonly presentation?: FieldPresentation;
|
|
2412
|
+
/**
|
|
2413
|
+
* The owner's own source states, by name (P7 3.2): a form controller's projected `record` and
|
|
2414
|
+
* `values`, a flow's `with` and `args`. They replace the sources built from `record` and
|
|
2415
|
+
* `form`, so a field P5 withholds stays pending in a `meta` ref as it does everywhere else.
|
|
2416
|
+
*/
|
|
2417
|
+
readonly metaSources?: ScreenSources;
|
|
2325
2418
|
}
|
|
2326
2419
|
interface ResolvedFieldInputProps extends Omit<ResolvedFieldDisplayProps, 'fallback'> {
|
|
2327
2420
|
readonly inputId?: string;
|
|
@@ -2340,6 +2433,18 @@ interface ResolvedFieldInputProps extends Omit<ResolvedFieldDisplayProps, 'fallb
|
|
|
2340
2433
|
readonly touched?: boolean;
|
|
2341
2434
|
/** Optional canonical issues; localized errorMessage remains the fallback. */
|
|
2342
2435
|
readonly issues?: ValidationIssues;
|
|
2436
|
+
/**
|
|
2437
|
+
* A relation select's create seeds (P6-31), from the form controller's binding. A separate
|
|
2438
|
+
* channel from `field.meta`: the seeds' provenance is the code registry, and `meta` can be
|
|
2439
|
+
* written by a layer.
|
|
2440
|
+
*/
|
|
2441
|
+
readonly relationSeeds?: Readonly<Record<string, unknown>>;
|
|
2442
|
+
/**
|
|
2443
|
+
* A relation select's extra filters from the form's `filter` function (P7 3.4): code, handed
|
|
2444
|
+
* down by the form controller on its own channel, applied on top of the field's `candidates`.
|
|
2445
|
+
* Never read from `field.meta`, which a layer can write.
|
|
2446
|
+
*/
|
|
2447
|
+
readonly fixedFilters?: readonly FixedFilterInput[];
|
|
2343
2448
|
readonly fallback: ReactNode;
|
|
2344
2449
|
}
|
|
2345
2450
|
//#endregion
|
|
@@ -2349,15 +2454,12 @@ type FieldProps = Omit<ResolvedFieldInputProps, 'resource' | 'fallback'> & {
|
|
|
2349
2454
|
readonly i18nPrefix?: string;
|
|
2350
2455
|
readonly fallback?: ReactNode;
|
|
2351
2456
|
/**
|
|
2352
|
-
* A relation field's RESOLVED
|
|
2353
|
-
* `FieldBinding.fixedFilters`)
|
|
2354
|
-
*
|
|
2355
|
-
*
|
|
2356
|
-
* (`
|
|
2357
|
-
*
|
|
2358
|
-
* resolved per-render scope wins. `<DeclarativeForm>` never sets this
|
|
2359
|
-
* explicitly: it spreads the whole `FieldBinding` (`{...binding}`), which
|
|
2360
|
-
* already carries `fixedFilters` when the field declared a `filter` opt.
|
|
2457
|
+
* A relation field's `filter` function RESOLVED against the form's values (design doc §5,
|
|
2458
|
+
* `@burojs/react`'s `FieldBinding.fixedFilters`). It reaches the select on its own channel (a
|
|
2459
|
+
* prop of the input, never `field.meta`, which a layer can write) and applies on top of the
|
|
2460
|
+
* field's `candidates`. `<DeclarativeForm>` never sets this explicitly: it spreads the whole
|
|
2461
|
+
* `FieldBinding` (`{...binding}`), which already carries `fixedFilters` when the field
|
|
2462
|
+
* declared a `filter` function.
|
|
2361
2463
|
*
|
|
2362
2464
|
* `FixedFilterInput`, not the bare AST — matches `FieldBinding.fixedFilters`
|
|
2363
2465
|
* (`@burojs/react`) and `RelationPickerProps`/`RelationPickerDialogProps`
|
|
@@ -2399,9 +2501,15 @@ type FieldDisplayProps = Omit<ResolvedFieldDisplayProps, 'resource' | 'fallback'
|
|
|
2399
2501
|
declare function FieldDisplay({ resource, i18nPrefix, fallback, value, ...rest }: FieldDisplayProps): ReactElement;
|
|
2400
2502
|
//#endregion
|
|
2401
2503
|
//#region src/forms/declarative-form.d.ts
|
|
2402
|
-
/**
|
|
2504
|
+
/**
|
|
2505
|
+
* A footer slot may need the controller's submit-gate to build its own submit
|
|
2506
|
+
* control — see {@link DeclarativeFormSlots.footer}.
|
|
2507
|
+
*/
|
|
2403
2508
|
interface DeclarativeFormFooterCtx {
|
|
2404
|
-
/**
|
|
2509
|
+
/**
|
|
2510
|
+
* `form.canSubmit` already ANDed with the whole-form `disabled` lock — a
|
|
2511
|
+
* footer never has to re-derive that combination itself.
|
|
2512
|
+
*/
|
|
2405
2513
|
readonly canSubmit: boolean;
|
|
2406
2514
|
}
|
|
2407
2515
|
/**
|
|
@@ -2417,152 +2525,118 @@ interface DeclarativeFormSlots {
|
|
|
2417
2525
|
* function form exists for the common case a plain node cannot serve: a
|
|
2418
2526
|
* CUSTOM footer (e.g. Cancel + Submit side by side) that still needs the
|
|
2419
2527
|
* framework's own disabled-while-invalid gate — `slots` is built by the
|
|
2420
|
-
* CALLER before
|
|
2528
|
+
* CALLER before the form controller has run, so a plain node has no way
|
|
2421
2529
|
* to read `form.canSubmit`. Called once per render with `{ canSubmit }`
|
|
2422
2530
|
* (already ANDed with the whole-form `disabled` lock) instead of forcing
|
|
2423
2531
|
* every such caller to either reimplement the gate or stand up a second,
|
|
2424
|
-
* parallel
|
|
2425
|
-
* two independent async-validation instances observably disagreeing for
|
|
2426
|
-
* a tick — the first caller this was added for was `EntityDialog` in the
|
|
2427
|
-
* since-deleted `apps/l2-web-ui`).
|
|
2532
|
+
* parallel controller just to read it.
|
|
2428
2533
|
*/
|
|
2429
2534
|
readonly footer?: ReactNode | ((ctx: DeclarativeFormFooterCtx) => ReactNode);
|
|
2430
2535
|
readonly [slot: string]: ReactNode | ((ctx: DeclarativeFormFooterCtx) => ReactNode) | undefined;
|
|
2431
2536
|
}
|
|
2432
|
-
interface DeclarativeFormProps {
|
|
2537
|
+
interface DeclarativeFormProps<F extends ResourceFieldMap = ResourceFieldMap> {
|
|
2433
2538
|
/** The same field-def map shape `defineResource`'s `f` builder produces. */
|
|
2434
|
-
readonly fields:
|
|
2435
|
-
/**
|
|
2539
|
+
readonly fields: F;
|
|
2540
|
+
/**
|
|
2541
|
+
* The form's tree (`(l) => [...]`, the same builder a resource's
|
|
2542
|
+
* `views.<mode>.body` uses); absent, every field in one column, in
|
|
2543
|
+
* declaration order. A field under a `when` that does not hold is inactive:
|
|
2544
|
+
* it is not drawn and not submitted.
|
|
2545
|
+
*/
|
|
2546
|
+
readonly body?: FormBody<F>;
|
|
2547
|
+
/** The draft identity; `draft` without it is a development error. */
|
|
2548
|
+
readonly formId?: string;
|
|
2549
|
+
readonly draft?: DraftOption;
|
|
2550
|
+
/** Controlled values: presence (not truthiness) selects controlled mode. */
|
|
2436
2551
|
readonly value?: FormValues;
|
|
2437
2552
|
/** Uncontrolled seed. Ignored once `value` is supplied. */
|
|
2438
|
-
readonly
|
|
2553
|
+
readonly defaults?: FormValues;
|
|
2439
2554
|
readonly onChange?: (values: FormValues) => void;
|
|
2440
|
-
/** Drives label i18n, the doc address, and the `<Field>` EntityRef — see `<Field>`'s own docblock. */
|
|
2441
|
-
readonly i18nPrefix?: string;
|
|
2442
2555
|
readonly schema?: StandardSchemaV1;
|
|
2556
|
+
/** Cross-field validation; may return warnings as well as errors. */
|
|
2557
|
+
readonly validate?: UseFormControllerFormOptions['validate'];
|
|
2443
2558
|
/**
|
|
2444
|
-
*
|
|
2445
|
-
* `
|
|
2446
|
-
*
|
|
2447
|
-
* internal.
|
|
2559
|
+
* Conditional checks for this form, as a plain list (a resource-less form has
|
|
2560
|
+
* no `app.checkSource` entry); a confirmable warning asks through the
|
|
2561
|
+
* mounted `<CheckConfirmDialog>`.
|
|
2448
2562
|
*/
|
|
2449
|
-
readonly
|
|
2563
|
+
readonly checks?: readonly Check[];
|
|
2564
|
+
/** The check surface; default `'create'`. */
|
|
2565
|
+
readonly surface?: CheckSurface;
|
|
2566
|
+
/** Receives the payload: the active declared fields only. */
|
|
2450
2567
|
readonly onSubmit?: (values: FormValues) => unknown | Promise<unknown>;
|
|
2451
2568
|
/**
|
|
2452
|
-
*
|
|
2453
|
-
*
|
|
2454
|
-
* display components instead of disabled inputs (`<DeclarativeDisplay>`,
|
|
2455
|
-
* Task 7).
|
|
2456
|
-
*/
|
|
2457
|
-
readonly disabled?: boolean;
|
|
2458
|
-
/** Simple column-count switch. Defaults to a single column. */
|
|
2459
|
-
readonly layout?: 'single' | 'two-column';
|
|
2460
|
-
/**
|
|
2461
|
-
* Class applied to the `<form>` element itself.
|
|
2462
|
-
*
|
|
2463
|
-
* Exists so a host can make the form a layout container rather than a
|
|
2464
|
-
* plain block — the case that motivated it is a dialog taller than the
|
|
2465
|
-
* viewport, where the form must become `flex flex-col` so its body can
|
|
2466
|
-
* scroll between a fixed header and a fixed footer. Without it the host
|
|
2467
|
-
* can only scroll the whole dialog, which drags the submit button out of
|
|
2468
|
-
* reach.
|
|
2569
|
+
* Text slots and the doc address key as `resources.<i18nPrefix>.…`; the
|
|
2570
|
+
* leaf ids are `<i18nPrefix>:field:<name>:hint` / `:info`. Default `'form'`.
|
|
2469
2571
|
*/
|
|
2470
|
-
readonly
|
|
2572
|
+
readonly i18nPrefix?: string;
|
|
2471
2573
|
/**
|
|
2472
|
-
*
|
|
2473
|
-
*
|
|
2474
|
-
*
|
|
2475
|
-
* This is the scroll region for a form too tall to fit: pair it with
|
|
2476
|
-
* `className` (`flex flex-col`) and give this `flex-1 overflow-y-auto
|
|
2477
|
-
* min-h-0`. Kept separate from `className` because scrolling the whole
|
|
2478
|
-
* form would scroll its footer away too, which is the bug rather than the
|
|
2479
|
-
* fix.
|
|
2574
|
+
* Whole-form lock: every field renders disabled, OR-ed with that field's
|
|
2575
|
+
* own resolved `disabled`. Distinct from a read-only VIEW
|
|
2576
|
+
* (`<DeclarativeDisplay>`), which renders displays instead of inputs.
|
|
2480
2577
|
*/
|
|
2481
|
-
readonly
|
|
2482
|
-
readonly slots?: DeclarativeFormSlots;
|
|
2578
|
+
readonly disabled?: boolean;
|
|
2483
2579
|
/**
|
|
2484
2580
|
* Per-field render override — swap ONE field's node without abandoning
|
|
2485
|
-
* the managed
|
|
2486
|
-
*
|
|
2487
|
-
* `<Field/>` node this renderer would have used, so an override can
|
|
2488
|
-
* wrap/decorate rather than reimplement.
|
|
2581
|
+
* the managed leaf (label, message slot, hint): receives the binding and
|
|
2582
|
+
* the default input node, so an override can wrap rather than reimplement.
|
|
2489
2583
|
*/
|
|
2490
2584
|
readonly renderField?: Record<string, (binding: FieldBinding, defaultNode: ReactNode) => ReactNode>;
|
|
2585
|
+
readonly slots?: DeclarativeFormSlots;
|
|
2586
|
+
/** The submit caption; defaults to the framework bundle's `actions.save` ("Save"). */
|
|
2491
2587
|
readonly submitLabel?: string;
|
|
2492
2588
|
/**
|
|
2493
|
-
*
|
|
2494
|
-
*
|
|
2495
|
-
*
|
|
2496
|
-
* the resource def via `app.checkSource` — these are a plain prop, merged
|
|
2497
|
-
* into `form.errors`/`form.warnings` on submit and gated behind
|
|
2498
|
-
* `<CheckConfirmDialog>` (mounted below) when a confirmable warning fires.
|
|
2589
|
+
* Class applied to the `<form>` element itself — e.g. `flex flex-col` for a
|
|
2590
|
+
* dialog taller than the viewport, so the body can scroll between a fixed
|
|
2591
|
+
* header and footer.
|
|
2499
2592
|
*/
|
|
2500
|
-
readonly
|
|
2593
|
+
readonly className?: string;
|
|
2501
2594
|
/**
|
|
2502
|
-
*
|
|
2503
|
-
*
|
|
2504
|
-
* create/edit inference off `value`/`defaultValue` presence; supply this
|
|
2505
|
-
* whenever that heuristic is wrong for this form — most commonly, a create
|
|
2506
|
-
* form that ALSO seeds `defaultValue` (e.g. `defaultValue={{ status:
|
|
2507
|
-
* 'draft' }}`), which the inference alone would misread as `'edit'`. See
|
|
2508
|
-
* `UseDeclarativeFormOptions.surface`'s own doc comment (`@burojs/react`)
|
|
2509
|
-
* for the full rationale.
|
|
2595
|
+
* Class applied to the fields region (`[data-buro-region="form-body"]`), the
|
|
2596
|
+
* scroll region of a form too tall to fit (`flex-1 overflow-y-auto min-h-0`).
|
|
2510
2597
|
*/
|
|
2511
|
-
readonly
|
|
2598
|
+
readonly bodyClassName?: string;
|
|
2512
2599
|
}
|
|
2513
2600
|
/**
|
|
2514
|
-
* Batteries-included form
|
|
2515
|
-
*
|
|
2516
|
-
*
|
|
2517
|
-
*
|
|
2518
|
-
*
|
|
2519
|
-
*
|
|
2520
|
-
*
|
|
2521
|
-
*
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
* the slot in `text-destructive`, else the first warning renders in
|
|
2525
|
-
* `text-warning-emphasis`, else nothing renders at all — mirroring
|
|
2526
|
-
* `resource-form.tsx`'s single-slot rule so no field can silently double its
|
|
2527
|
-
* layout's space, without reserving height for a message that may never
|
|
2528
|
-
* appear. Form-level (`field === '_form'`) errors/warnings render in their
|
|
2529
|
-
* own non-destructive/destructive summary above the fields. Submit is
|
|
2530
|
-
* disabled on `!form.canSubmit` (errors only — warnings never block) or
|
|
2531
|
-
* `props.disabled`.
|
|
2532
|
-
*/
|
|
2533
|
-
declare function DeclarativeForm(props: DeclarativeFormProps): ReactElement;
|
|
2601
|
+
* Batteries-included resource-less form (P1b+P1c decision 21) over
|
|
2602
|
+
* `useFormController` and the screen renderer: the form's `body` tree (or one
|
|
2603
|
+
* column of every field), each leaf with its label, input, one message slot
|
|
2604
|
+
* (error over warning) and hint; a form-level error / warning summary above;
|
|
2605
|
+
* the submit footer below. Uncontrolled by default (`defaults` seeds,
|
|
2606
|
+
* `onSubmit(payload)` delivers the active declared values); controlled
|
|
2607
|
+
* `value` / `onChange` remain available. Submit is disabled on
|
|
2608
|
+
* `!form.canSubmit` (errors only — warnings never block) or `disabled`.
|
|
2609
|
+
*/
|
|
2610
|
+
declare function DeclarativeForm<F extends ResourceFieldMap = ResourceFieldMap>(props: DeclarativeFormProps<F>): ReactElement;
|
|
2534
2611
|
//#endregion
|
|
2535
2612
|
//#region src/forms/declarative-display.d.ts
|
|
2536
|
-
interface DeclarativeDisplayProps {
|
|
2613
|
+
interface DeclarativeDisplayProps<F extends ResourceFieldMap = ResourceFieldMap> {
|
|
2537
2614
|
/** The same field-def map shape `defineResource`'s `f` builder produces. */
|
|
2538
|
-
readonly fields:
|
|
2615
|
+
readonly fields: F;
|
|
2539
2616
|
/** The values to display — this renderer owns no state of its own. */
|
|
2540
2617
|
readonly values: FormValues;
|
|
2541
|
-
/**
|
|
2618
|
+
/**
|
|
2619
|
+
* Drives label i18n, the doc address and the leaf ids
|
|
2620
|
+
* (`<i18nPrefix>:field:<name>:hint` / `:info`). Default `'form'`.
|
|
2621
|
+
*/
|
|
2542
2622
|
readonly i18nPrefix?: string;
|
|
2543
|
-
/**
|
|
2544
|
-
|
|
2623
|
+
/**
|
|
2624
|
+
* The display's tree, as `<DeclarativeForm body>`; absent, every field in
|
|
2625
|
+
* one column, in declaration order. A field under a `when` that does not
|
|
2626
|
+
* hold over `values` is not shown.
|
|
2627
|
+
*/
|
|
2628
|
+
readonly body?: FormBody<F>;
|
|
2545
2629
|
}
|
|
2546
2630
|
/**
|
|
2547
|
-
* Read-only VIEW
|
|
2548
|
-
*
|
|
2549
|
-
*
|
|
2550
|
-
*
|
|
2551
|
-
*
|
|
2552
|
-
*
|
|
2553
|
-
*
|
|
2554
|
-
* instance to own here. It IS, however, a thin map over the exact same
|
|
2555
|
-
* conditional-visibility resolution the controller runs internally
|
|
2556
|
-
* (`resolveFieldFlags` + `useOptionalVisibilityCtx`, `@burojs/react`,
|
|
2557
|
-
* Task 4) — reused as-is, not reimplemented, so a field hidden in
|
|
2558
|
-
* `<DeclarativeForm>` is hidden here too for the same values snapshot.
|
|
2559
|
-
*
|
|
2560
|
-
* Renders every visible field, in `fields` declaration order, as a label
|
|
2561
|
-
* plus `<FieldDisplay/>` — mirroring `<DeclarativeForm>`'s own per-field
|
|
2562
|
-
* layout (label above the field's node) minus the parts a view has no use
|
|
2563
|
-
* for (required marker, error/warning slot, submit).
|
|
2631
|
+
* Read-only VIEW of a resource-less field map (P1b+P1c S3e): the
|
|
2632
|
+
* read/edit/locked distinction's "view" corner — **edit** is
|
|
2633
|
+
* `<DeclarativeForm>`, **locked** `<DeclarativeForm disabled>` (inputs,
|
|
2634
|
+
* disabled), **view** this (displays, never inputs). Driven by the form
|
|
2635
|
+
* controller in `show` mode over `values`, rendered through the same screen
|
|
2636
|
+
* renderer, so a field hidden by a `when` in `<DeclarativeForm>` is hidden here
|
|
2637
|
+
* too for the same values.
|
|
2564
2638
|
*/
|
|
2565
|
-
declare function DeclarativeDisplay(props: DeclarativeDisplayProps): ReactElement;
|
|
2639
|
+
declare function DeclarativeDisplay<F extends ResourceFieldMap = ResourceFieldMap>(props: DeclarativeDisplayProps<F>): ReactElement;
|
|
2566
2640
|
//#endregion
|
|
2567
2641
|
//#region src/export/export-dialog.d.ts
|
|
2568
2642
|
interface ExportDialogProps {
|
|
@@ -2570,7 +2644,11 @@ interface ExportDialogProps {
|
|
|
2570
2644
|
readonly onOpenChange: (open: boolean) => void;
|
|
2571
2645
|
readonly resource: string;
|
|
2572
2646
|
readonly target: ExportTarget;
|
|
2573
|
-
/**
|
|
2647
|
+
/**
|
|
2648
|
+
* The list's currently visible columns — what "as in table" (the default) sends as `request.columns`.
|
|
2649
|
+
* Empty means "unknown": the dialog then sends the same set as "All columns" (the resource's list
|
|
2650
|
+
* fields, minus any a `column` rule hides). `request.columns` is never omitted.
|
|
2651
|
+
*/
|
|
2574
2652
|
readonly visibleColumns: readonly string[];
|
|
2575
2653
|
/** Known row estimate, shown in the filter-scope title and handed to the exporter as a progress total hint. */
|
|
2576
2654
|
readonly estimatedCount?: number;
|
|
@@ -2580,14 +2658,15 @@ interface ExportDialogProps {
|
|
|
2580
2658
|
* unregistered `UIPresentRequest.component` registry key silently renders
|
|
2581
2659
|
* `null`, so a framework-owned dialog would do nothing until every adopter
|
|
2582
2660
|
* registered it (see `packages/react/src/ui/ui-presentations.tsx:74,138`).
|
|
2583
|
-
*
|
|
2584
|
-
*
|
|
2661
|
+
* The flow host draws the opposite line (it IS presented, as `buro:flow`, and
|
|
2662
|
+
* `shadcnPresentationHosts` registers it); this dialog stays self-hosted, built
|
|
2663
|
+
* on the local `<Dialog>` primitives, no registry involved.
|
|
2585
2664
|
*
|
|
2586
2665
|
* A `mode` state (`'form' | 'progress' | 'confirm-close'`) swaps content
|
|
2587
2666
|
* inside ONE `<DialogContent>`/one Radix focus scope. A second, nested
|
|
2588
2667
|
* Radix root for the close-while-running confirm was tried elsewhere in this
|
|
2589
|
-
* codebase and deadlocked the jsdom test runner
|
|
2590
|
-
*
|
|
2668
|
+
* codebase and deadlocked the jsdom test runner (the old form-modal action's
|
|
2669
|
+
* menu-held dialog, deleted in P4) — this dialog
|
|
2591
2670
|
* never repeats that shape.
|
|
2592
2671
|
*/
|
|
2593
2672
|
declare function ExportDialog({ open, onOpenChange, resource, target, visibleColumns, estimatedCount }: ExportDialogProps): React$1.ReactElement;
|
|
@@ -2808,7 +2887,7 @@ declare function EnumPicker({ enumName, value, onChange, renderAs, name, id, tes
|
|
|
2808
2887
|
//#region src/primitives/button.d.ts
|
|
2809
2888
|
declare const buttonVariants: (props?: ({
|
|
2810
2889
|
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
2811
|
-
size?: "
|
|
2890
|
+
size?: "sm" | "lg" | "default" | "icon" | null | undefined;
|
|
2812
2891
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
2813
2892
|
interface ButtonProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
2814
2893
|
asChild?: boolean;
|
|
@@ -2860,40 +2939,12 @@ interface ActionButtonProps {
|
|
|
2860
2939
|
children?: React.ReactNode;
|
|
2861
2940
|
/**
|
|
2862
2941
|
* Render the action as a `<DropdownMenuItem>` (icon + label) instead of a
|
|
2863
|
-
* standalone `<Button>`, for use inside an overflow `…` menu.
|
|
2864
|
-
*
|
|
2865
|
-
* (
|
|
2866
|
-
* open through the framework's `UIPresentationRuntime` (`useUIPresent`).
|
|
2942
|
+
* standalone `<Button>`, for use inside an overflow `…` menu. Links navigate,
|
|
2943
|
+
* modal actions open through the framework's `UIPresentationRuntime`
|
|
2944
|
+
* (`useUIPresent`), and a flow hands its run to a runner outside the menu.
|
|
2867
2945
|
* Destructive actions get destructive item styling.
|
|
2868
2946
|
*/
|
|
2869
2947
|
asMenuItem?: boolean;
|
|
2870
|
-
/**
|
|
2871
|
-
* Menu-mode only. Called instead of running the action directly, so the
|
|
2872
|
-
* OWNER of the menu (`ActionOverflow`) can run the check gate and mount its
|
|
2873
|
-
* dialog outside the dropdown (see {@link ActionConfirmRunner}). Called
|
|
2874
|
-
* unconditionally — not only when the action carries a `confirm` — because
|
|
2875
|
-
* a conditional check (Task 10) can fire with no `confirm` at all and still
|
|
2876
|
-
* needs the dialog; `ActionConfirmRunner` is where that gate actually runs.
|
|
2877
|
-
* Without it, a confirming or check-gated action rendered as a menu item
|
|
2878
|
-
* cannot prompt (see {@link ActionConfirmDialog} for why the dialog must
|
|
2879
|
-
* not live inside the menu).
|
|
2880
|
-
*/
|
|
2881
|
-
onRequestConfirm?: () => void;
|
|
2882
|
-
/**
|
|
2883
|
-
* Menu-mode only, and the exact analogue of {@link onRequestConfirm} for
|
|
2884
|
-
* `formModal` actions: called instead of opening the form, so the OWNER of
|
|
2885
|
-
* the menu (`ActionOverflow`) mounts the Dialog OUTSIDE the dropdown.
|
|
2886
|
-
*
|
|
2887
|
-
* Without it, a formModal item had to render its own `<Dialog>` inside
|
|
2888
|
-
* `DropdownMenuContent` and hold the menu open with `onSelect`'s
|
|
2889
|
-
* `preventDefault()` so the dialog's own subtree wasn't torn down. That nests
|
|
2890
|
-
* two Radix focus scopes (menu + dialog) inside one another: in a browser
|
|
2891
|
-
* focus ping-pongs between them and typing into the form is unreliable; under
|
|
2892
|
-
* jsdom the same construction deadlocked the test runner. The confirm dialog
|
|
2893
|
-
* had this identical bug and was fixed the identical way — see
|
|
2894
|
-
* {@link ActionConfirmRunner}.
|
|
2895
|
-
*/
|
|
2896
|
-
onRequestForm?: () => void;
|
|
2897
2948
|
}
|
|
2898
2949
|
/**
|
|
2899
2950
|
* A denial the rule asked to SHOW.
|
|
@@ -2905,9 +2956,8 @@ interface ActionButtonProps {
|
|
|
2905
2956
|
* a tooltip: the click is already intercepted, so one path serves mouse,
|
|
2906
2957
|
* keyboard and assistive tech alike.
|
|
2907
2958
|
*
|
|
2908
|
-
* Shared by every leaf renderer (`LinkActionButton` / `
|
|
2909
|
-
*
|
|
2910
|
-
* each — one component, both shapes (`asMenuItem` switches between a standalone
|
|
2959
|
+
* Shared by every leaf renderer (`LinkActionButton` / `ModalActionButton` /
|
|
2960
|
+
* the flow button) rather than reimplemented in each — one component, both shapes (`asMenuItem` switches between a standalone
|
|
2911
2961
|
* `<Button>` and a `<DropdownMenuItem>`).
|
|
2912
2962
|
*
|
|
2913
2963
|
* Exported (not a package-private leaf) because a `disabled` `Availability` is
|
|
@@ -2929,7 +2979,7 @@ interface DisabledActionProps {
|
|
|
2929
2979
|
asMenuItem?: boolean;
|
|
2930
2980
|
/**
|
|
2931
2981
|
* Resource the denial belongs to — scopes the reason/fallback key lookup the
|
|
2932
|
-
* same way
|
|
2982
|
+
* same way the record form's field-lock reason is scoped, so a resource can
|
|
2933
2983
|
* override the generic wording via `resources.<res>.<key>`.
|
|
2934
2984
|
*/
|
|
2935
2985
|
resource?: string;
|
|
@@ -2952,41 +3002,6 @@ interface DisabledActionProps {
|
|
|
2952
3002
|
surface?: string;
|
|
2953
3003
|
}
|
|
2954
3004
|
declare function DisabledAction({ reason, label, icon, testid, size, variant, className, asMenuItem, resource, density, actionName, surface }: DisabledActionProps): React.ReactElement;
|
|
2955
|
-
interface ActionConfirmDialogProps {
|
|
2956
|
-
open: boolean;
|
|
2957
|
-
onOpenChange: (open: boolean) => void;
|
|
2958
|
-
title: React.ReactNode;
|
|
2959
|
-
message: string;
|
|
2960
|
-
isDestructive?: boolean;
|
|
2961
|
-
busy?: boolean;
|
|
2962
|
-
onConfirm: () => void;
|
|
2963
|
-
/** Base testid; the dialog and its two buttons suffix `:confirm[-ok|-cancel]`. */
|
|
2964
|
-
testid: string;
|
|
2965
|
-
/**
|
|
2966
|
-
* Label for the confirming button. Prefer the action's own VERB («Выполнить»)
|
|
2967
|
-
* over a neutral «ОК»: a button that repeats what is about to happen is
|
|
2968
|
-
* readable at a glance and matches the delete dialog, which already confirms
|
|
2969
|
-
* with «Удалить». Falls back to the generic wording when absent.
|
|
2970
|
-
*/
|
|
2971
|
-
confirmLabel?: React.ReactNode;
|
|
2972
|
-
}
|
|
2973
|
-
/**
|
|
2974
|
-
* The confirm prompt shown before a confirming action runs.
|
|
2975
|
-
*
|
|
2976
|
-
* @deprecated Nothing in `@burojs/ui-shadcn` mounts this any more — both
|
|
2977
|
-
* action call sites went through `useCheckGate` + `<CheckConfirmDialog>`,
|
|
2978
|
-
* which carries the same affordances (`title`, `proceedLabel`, `tone`) and
|
|
2979
|
-
* merges `action.confirm` with any firing check into ONE dialog. Still
|
|
2980
|
-
* exported for a host that already depends on it directly.
|
|
2981
|
-
*
|
|
2982
|
-
* Deliberately a standalone component so it can be mounted OUTSIDE a
|
|
2983
|
-
* `<DropdownMenuContent>`. Rendering a Radix Dialog inside an open Radix menu
|
|
2984
|
-
* mounts two focus scopes / dismissable layers at once, which fight over focus
|
|
2985
|
-
* (a hard deadlock under jsdom, broken dismiss behavior in a real browser) and
|
|
2986
|
-
* risks the dialog being torn down with the menu. `ActionOverflow` therefore
|
|
2987
|
-
* owns one of these as a SIBLING of the menu; see {@link ActionConfirmRunner}.
|
|
2988
|
-
*/
|
|
2989
|
-
declare function ActionConfirmDialog({ open, onOpenChange, title, message, isDestructive, busy, onConfirm, testid, confirmLabel }: ActionConfirmDialogProps): React.ReactElement;
|
|
2990
3005
|
declare function ActionButton(props: ActionButtonProps): React.ReactElement | null;
|
|
2991
3006
|
//#endregion
|
|
2992
3007
|
//#region src/actions/action-overflow.d.ts
|
|
@@ -3002,6 +3017,16 @@ interface ActionOverflowProps {
|
|
|
3002
3017
|
*/
|
|
3003
3018
|
surface: string;
|
|
3004
3019
|
className?: string;
|
|
3020
|
+
/**
|
|
3021
|
+
* Flows this screen presents inline (P6 3.12): their own button is not drawn here, the
|
|
3022
|
+
* placement is their control on this screen.
|
|
3023
|
+
*/
|
|
3024
|
+
hideFlows?: (name: string) => boolean;
|
|
3025
|
+
/**
|
|
3026
|
+
* A row in a narrow list: every action goes into the one menu, so the actions column is a single
|
|
3027
|
+
* control wide. Default: {@link RowActionsCollapseContext}.
|
|
3028
|
+
*/
|
|
3029
|
+
collapse?: boolean;
|
|
3005
3030
|
}
|
|
3006
3031
|
/**
|
|
3007
3032
|
* Collapses an entity's actions into an overflow menu so tables and detail
|
|
@@ -3013,14 +3038,14 @@ interface ActionOverflowProps {
|
|
|
3013
3038
|
* own control (at their resolved density — icon-only on a row, icon+label on
|
|
3014
3039
|
* a toolbar); everything else collapses into one menu after them, with the
|
|
3015
3040
|
* destructive tail set off by a separator. Menu items reuse
|
|
3016
|
-
* `<ActionButton asMenuItem>`
|
|
3017
|
-
*
|
|
3041
|
+
* `<ActionButton asMenuItem>` for a link or a modal and `<FlowMenuItem>` for a
|
|
3042
|
+
* flow, whose run continues outside the dropdown. Tone is NOT
|
|
3018
3043
|
* hardcoded here (no more `variant="ghost"`): it comes from each action's own
|
|
3019
3044
|
* `variant`, exactly like the menu items already respected it — a hardcoded
|
|
3020
3045
|
* `ghost` used to strip a destructive standalone action of its destructive
|
|
3021
3046
|
* look.
|
|
3022
3047
|
*/
|
|
3023
|
-
declare function ActionOverflow({ resource, record, surface, className }: ActionOverflowProps): React.ReactElement | null;
|
|
3048
|
+
declare function ActionOverflow({ resource, record, surface, className, hideFlows, collapse }: ActionOverflowProps): React.ReactElement | null;
|
|
3024
3049
|
//#endregion
|
|
3025
3050
|
//#region src/actions/action-surface.d.ts
|
|
3026
3051
|
/**
|
|
@@ -3063,6 +3088,12 @@ interface BulkActionToolbarProps<TRecord extends BulkRecord = BulkRecord> {
|
|
|
3063
3088
|
* itself via `table.resetRowSelection()`.
|
|
3064
3089
|
*/
|
|
3065
3090
|
onClearSelection?: () => void;
|
|
3091
|
+
/**
|
|
3092
|
+
* Replaces the selection. A bulk flow calls it after its run: the ids that succeeded leave the
|
|
3093
|
+
* selection and the others stay (P4 spec 4.16). Without it, a run that succeeded for every id
|
|
3094
|
+
* clears the selection through `onClearSelection`.
|
|
3095
|
+
*/
|
|
3096
|
+
onSelectionChange?: (ids: string[]) => void;
|
|
3066
3097
|
className?: string;
|
|
3067
3098
|
/**
|
|
3068
3099
|
* The list's currently visible columns (Task 8) — forwarded to the
|
|
@@ -3070,33 +3101,81 @@ interface BulkActionToolbarProps<TRecord extends BulkRecord = BulkRecord> {
|
|
|
3070
3101
|
* what "as shown in the table" (the dialog's default) sends as
|
|
3071
3102
|
* `request.columns`. Optional: this toolbar is usable standalone, with no
|
|
3072
3103
|
* `<ResourceListPage>`/list controller in reach — a caller that omits it
|
|
3073
|
-
* gets
|
|
3074
|
-
*
|
|
3104
|
+
* gets the dialog's "All columns" set for that default: the resource's list
|
|
3105
|
+
* fields, minus any a `column` rule hides.
|
|
3075
3106
|
*/
|
|
3076
3107
|
visibleColumns?: readonly string[];
|
|
3077
3108
|
}
|
|
3078
|
-
declare function BulkActionToolbar<TRecord extends BulkRecord = BulkRecord>({ resource, table, selectedRecords, selectedIds, onClearSelection, className, visibleColumns }: BulkActionToolbarProps<TRecord>): React.ReactElement | null;
|
|
3109
|
+
declare function BulkActionToolbar<TRecord extends BulkRecord = BulkRecord>({ resource, table, selectedRecords, selectedIds, onClearSelection, onSelectionChange, className, visibleColumns }: BulkActionToolbarProps<TRecord>): React.ReactElement | null;
|
|
3079
3110
|
//#endregion
|
|
3080
|
-
//#region src/
|
|
3081
|
-
interface
|
|
3082
|
-
|
|
3083
|
-
|
|
3111
|
+
//#region src/flows/flow-action-button.d.ts
|
|
3112
|
+
interface FlowActionButtonProps {
|
|
3113
|
+
readonly resource: string;
|
|
3114
|
+
/** The flow's name in the resource's `actions`. */
|
|
3115
|
+
readonly actionName: string;
|
|
3116
|
+
readonly record?: {
|
|
3117
|
+
id: string;
|
|
3118
|
+
} & Record<string, unknown>;
|
|
3119
|
+
/** The surface (`'row'`, `'show'`, …): the test id's namespace, as `ActionButton`'s. */
|
|
3120
|
+
readonly scope?: string;
|
|
3121
|
+
readonly asMenuItem?: boolean;
|
|
3122
|
+
readonly density?: ActionDensity;
|
|
3123
|
+
readonly variant?: ButtonProps['variant'];
|
|
3124
|
+
readonly size?: ButtonProps['size'];
|
|
3125
|
+
readonly className?: string;
|
|
3126
|
+
readonly children?: ReactNode;
|
|
3084
3127
|
}
|
|
3085
|
-
|
|
3086
|
-
|
|
3128
|
+
/**
|
|
3129
|
+
* A flow's button or menu item (P4 spec 4.15, 4.17). The control is decided without a run — the
|
|
3130
|
+
* flow's gate (undecided while permissions load), the page's one batched read on a row (I8), its
|
|
3131
|
+
* `when` and pre-click checks — so the flow machine is not in the first screen. A hover or a
|
|
3132
|
+
* focus starts loading the flow runtime; the click (at the latest) starts the run, whose `with`
|
|
3133
|
+
* sources load then: until it has decided, the control is busy and a second click does nothing,
|
|
3134
|
+
* so one click sends at most once.
|
|
3135
|
+
*/
|
|
3136
|
+
declare function FlowActionButton(props: FlowActionButtonProps): ReactElement | null;
|
|
3137
|
+
//#endregion
|
|
3138
|
+
//#region src/flows/app-flow-button.d.ts
|
|
3139
|
+
interface AppFlowButtonProps {
|
|
3140
|
+
/** The entry `useAppActions()` returned for a `kind: 'flow'` app action. */
|
|
3141
|
+
readonly action: {
|
|
3142
|
+
readonly name: string;
|
|
3143
|
+
readonly label: string;
|
|
3144
|
+
readonly icon?: string;
|
|
3145
|
+
readonly disabledReason?: string;
|
|
3146
|
+
/** A flow hosted on a custom page (P7 3.15): the control is a link to it, not a runner. */
|
|
3147
|
+
readonly hostHref?: string;
|
|
3148
|
+
};
|
|
3149
|
+
readonly variant?: ButtonProps['variant'];
|
|
3150
|
+
readonly size?: ButtonProps['size'];
|
|
3151
|
+
readonly className?: string;
|
|
3152
|
+
}
|
|
3153
|
+
/**
|
|
3154
|
+
* An app flow's control (P4-D: app flows are drawn). `useAppActions()` decides whether the
|
|
3155
|
+
* entry exists and whether it is disabled (the flow's gate); this button draws it, loads the
|
|
3156
|
+
* flow runtime on intent (a hover, a focus, at the latest the click) and runs the flow — its
|
|
3157
|
+
* host when it has a form or a review, else the send behind the confirm dialog. Busy from the
|
|
3158
|
+
* click until the interaction ends. Test id: `app-action:<name>`.
|
|
3159
|
+
*/
|
|
3160
|
+
declare function AppFlowButton({ action, variant, size, className }: AppFlowButtonProps): ReactElement;
|
|
3087
3161
|
//#endregion
|
|
3088
3162
|
//#region src/checks/check-confirm-dialog.d.ts
|
|
3089
3163
|
interface CheckConfirmDialogProps {
|
|
3090
3164
|
readonly state: CheckGateState;
|
|
3091
|
-
/**
|
|
3165
|
+
/**
|
|
3166
|
+
* Base testid; the dialog and its rows suffix `:dialog`, `:proceed`,
|
|
3167
|
+
* `:cancel`, `:item:<checkId>`.
|
|
3168
|
+
*/
|
|
3092
3169
|
readonly testid: string;
|
|
3093
|
-
/**
|
|
3170
|
+
/**
|
|
3171
|
+
* Fired (before `state.cancel()`) when an anchored row — `path[0]` is a
|
|
3172
|
+
* field name — is clicked.
|
|
3173
|
+
*/
|
|
3094
3174
|
readonly onAnchorFocus?: (field: string) => void;
|
|
3095
3175
|
/**
|
|
3096
3176
|
* Overrides the neutral `checks.dialogTitle` heading. The ACTION call sites
|
|
3097
|
-
* pass the action's own label here
|
|
3098
|
-
*
|
|
3099
|
-
* heads an archive prompt instead of a generic "please review".
|
|
3177
|
+
* pass the action's own label here, so «Архивировать» heads an archive
|
|
3178
|
+
* prompt instead of a generic "please review".
|
|
3100
3179
|
*/
|
|
3101
3180
|
readonly title?: ReactNode;
|
|
3102
3181
|
/**
|
|
@@ -3115,12 +3194,10 @@ interface CheckConfirmDialogProps {
|
|
|
3115
3194
|
}
|
|
3116
3195
|
/**
|
|
3117
3196
|
* Renders `useCheckGate`'s `state` — one dialog for `action.confirm`
|
|
3118
|
-
* headers, blocking checks and confirmable warnings alike
|
|
3119
|
-
*
|
|
3120
|
-
*
|
|
3121
|
-
*
|
|
3122
|
-
* content and both buttons — Task 10 folds the two into one dialog, and
|
|
3123
|
-
* staying close in shape/behaviour here is what keeps that merge cheap.
|
|
3197
|
+
* headers, blocking checks and confirmable warnings alike — since P4 the
|
|
3198
|
+
* only confirm dialog an action has (a flow's `confirm` lowers to a check):
|
|
3199
|
+
* a controlled `<Dialog>` with a focus-restore-on-close effect and a
|
|
3200
|
+
* `data-testid` on the content and both buttons.
|
|
3124
3201
|
*
|
|
3125
3202
|
* Blockers ('error' severity) are shown first, under `checks.blocked`, and
|
|
3126
3203
|
* NEVER get a proceed button — `state.proceed()` already no-ops while
|
|
@@ -3295,10 +3372,17 @@ interface DataTableProps<TRow> {
|
|
|
3295
3372
|
* (except an interactive element — link, button, checkbox, kebab — or while
|
|
3296
3373
|
* selecting text) navigates to `rowHref(row)`. Cmd/Ctrl-click and middle-click
|
|
3297
3374
|
* open it in a NEW TAB, matching native link behaviour. Client-side nav uses
|
|
3298
|
-
* the
|
|
3299
|
-
* keyboard / copy-link, so this is a mouse-affordance layer on
|
|
3375
|
+
* `useRouteNavigate()` (the `RouterAdapter`). The row's own ID cell stays a
|
|
3376
|
+
* real anchor for keyboard / copy-link, so this is a mouse-affordance layer on
|
|
3377
|
+
* top.
|
|
3300
3378
|
*/
|
|
3301
3379
|
rowHref?: (row: TRow) => string | undefined;
|
|
3380
|
+
/**
|
|
3381
|
+
* A row opener asked before `rowHref` on a plain click (P3-17): `true` means it handled the
|
|
3382
|
+
* row (a quick entry opened) and the row does not navigate. A modified click (Cmd/Ctrl,
|
|
3383
|
+
* middle) still opens `rowHref` in a new tab.
|
|
3384
|
+
*/
|
|
3385
|
+
onRowOpen?: (row: TRow) => boolean;
|
|
3302
3386
|
/**
|
|
3303
3387
|
* Enable drag-to-reorder on column headers (#17). When set, headers become
|
|
3304
3388
|
* draggable and dropping one onto another calls `onColumnReorder(from, to)`.
|
|
@@ -3317,7 +3401,7 @@ interface DataTableProps<TRow> {
|
|
|
3317
3401
|
selectionColumnId?: string;
|
|
3318
3402
|
className?: string;
|
|
3319
3403
|
}
|
|
3320
|
-
declare function DataTable<TRow>({ table, tableTestId, getRowTestId, getCellTestId, isLoading, loadingRowCount, emptyState, errorState, rowClassName, ariaLabel, onColumnReorder, rowHref, selectionColumnId, className }: DataTableProps<TRow>): React.ReactElement;
|
|
3404
|
+
declare function DataTable<TRow>({ table, tableTestId, getRowTestId, getCellTestId, isLoading, loadingRowCount, emptyState, errorState, rowClassName, ariaLabel, onColumnReorder, rowHref, onRowOpen, selectionColumnId, className }: DataTableProps<TRow>): React.ReactElement;
|
|
3321
3405
|
//#endregion
|
|
3322
3406
|
//#region src/data-table/data-table-faceted-filter.d.ts
|
|
3323
3407
|
/**
|
|
@@ -3769,9 +3853,7 @@ declare function ListSearchInput({ resource, label, value, onCommit, placeholder
|
|
|
3769
3853
|
* default: `<ResourceListPage>` distinguishes a declarative
|
|
3770
3854
|
* `views.list.search` (names its first field) from a resolver (generic
|
|
3771
3855
|
* `list.search` label, since the framework cannot know what a resolver
|
|
3772
|
-
* matches
|
|
3773
|
-
* branch), and the embedded sub-resource tab always names its one
|
|
3774
|
-
* `contains` field.
|
|
3856
|
+
* matches), and a `related-list` placement names its own search field.
|
|
3775
3857
|
*/
|
|
3776
3858
|
placeholder?: string;
|
|
3777
3859
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -3818,145 +3900,396 @@ declare function ColumnsToggle({ resource, def, allAvailable, required, visibleC
|
|
|
3818
3900
|
onRestoreDefaults?: () => void;
|
|
3819
3901
|
}): import("react/jsx-runtime").JSX.Element;
|
|
3820
3902
|
//#endregion
|
|
3821
|
-
//#region src/list-kit/
|
|
3822
|
-
|
|
3823
|
-
* Props of {@link CursorLoadMore}.
|
|
3824
|
-
*
|
|
3825
|
-
* Deliberately shaped as three scalars rather than taking the controller's
|
|
3826
|
-
* `cursor` group whole: the group's `next` is an opaque TOKEN (useful to a
|
|
3827
|
-
* consumer that wants to log or deep-link it) while this control only ever
|
|
3828
|
-
* needs to know whether there IS one. Spreading `cursor` in would also make
|
|
3829
|
-
* the component unusable by a surface that paginates a nested/embedded list
|
|
3830
|
-
* outside `useResourceList` — the workflows page does exactly that.
|
|
3831
|
-
*/
|
|
3832
|
-
interface CursorLoadMoreProps {
|
|
3833
|
-
/** Render the button at all. `false` renders nothing (see the docblock). */
|
|
3834
|
-
hasMore: boolean;
|
|
3835
|
-
/** A load-more fetch is in flight — disables the button and swaps the label. */
|
|
3836
|
-
loading?: boolean;
|
|
3837
|
-
/** Fetch the next page. Wire to `cursor.loadMore()`. */
|
|
3838
|
-
onMore: () => void;
|
|
3839
|
-
}
|
|
3840
|
-
/**
|
|
3841
|
-
* The "load more" footer for a **cursor (opaque-token) paginated** list —
|
|
3842
|
-
* the counterpart of the numbered pager `<ResourceList>` renders for offset
|
|
3843
|
-
* providers.
|
|
3844
|
-
*
|
|
3845
|
-
* ```tsx
|
|
3846
|
-
* const { rows, cursor } = useResourceListContext();
|
|
3847
|
-
* // …the table…
|
|
3848
|
-
* {cursor && (
|
|
3849
|
-
* <CursorLoadMore
|
|
3850
|
-
* hasMore={cursor.next !== null}
|
|
3851
|
-
* loading={cursor.isLoadingMore}
|
|
3852
|
-
* onMore={cursor.loadMore}
|
|
3853
|
-
* />
|
|
3854
|
-
* )}
|
|
3855
|
-
* ```
|
|
3856
|
-
*
|
|
3857
|
-
* ⚠️ **Renders `null` when `hasMore` is false**, so an exhausted cursor
|
|
3858
|
-
* leaves no dead control behind — the caller does not need its own guard.
|
|
3859
|
-
* That is also what makes "the button is gone" a usable end-of-list
|
|
3860
|
-
* assertion in tests.
|
|
3861
|
-
*
|
|
3862
|
-
* Why it lives in the framework rather than in the app that first needed it
|
|
3863
|
-
* (core flexibility program, Task B5.3): it has **zero coupling to any
|
|
3864
|
-
* provider**. It knows nothing about Temporal, tokens, or where the next
|
|
3865
|
-
* page comes from — only "is there more" / "is it coming" / "go get it". A
|
|
3866
|
-
* cursor list is now a first-class declared mode
|
|
3867
|
-
* (`views.list.pagination: 'cursor'`), so the control that drives one
|
|
3868
|
-
* belongs beside the pager it replaces.
|
|
3869
|
-
*
|
|
3870
|
-
* @see ResourceListController.cursor in `@burojs/react`
|
|
3871
|
-
*/
|
|
3872
|
-
declare function CursorLoadMore({ hasMore, loading, onMore }: CursorLoadMoreProps): React.ReactElement | null;
|
|
3903
|
+
//#region src/list-kit/pieces/list-body.d.ts
|
|
3904
|
+
declare const ListBody: () => ReactElement | null;
|
|
3873
3905
|
//#endregion
|
|
3874
|
-
//#region src/list-kit/
|
|
3906
|
+
//#region src/list-kit/pieces/list-bulk-bar.d.ts
|
|
3907
|
+
declare const ListBulkBar: () => ReactElement | null;
|
|
3908
|
+
//#endregion
|
|
3909
|
+
//#region src/list-kit/pieces/list-columns.d.ts
|
|
3910
|
+
declare const ListColumns: () => ReactElement | null;
|
|
3911
|
+
//#endregion
|
|
3912
|
+
//#region src/list-kit/pieces/list-controls.d.ts
|
|
3875
3913
|
/**
|
|
3876
|
-
*
|
|
3914
|
+
* The toolbar as a frame places it (`<ListControls/>`): under `checkFrame` it draws the pieces it
|
|
3915
|
+
* is made of, so a frame that also places one of them is counted twice.
|
|
3877
3916
|
*/
|
|
3878
|
-
|
|
3917
|
+
declare function ListControls(): ReactElement | null;
|
|
3918
|
+
//#endregion
|
|
3919
|
+
//#region src/list-kit/pieces/list-create.d.ts
|
|
3920
|
+
declare const ListCreate: () => ReactElement | null;
|
|
3921
|
+
//#endregion
|
|
3922
|
+
//#region src/list-kit/pieces/list-export.d.ts
|
|
3923
|
+
declare const ListExport: () => ReactElement | null;
|
|
3924
|
+
//#endregion
|
|
3925
|
+
//#region src/list-kit/pieces/list-filters.d.ts
|
|
3926
|
+
declare const ListFilters: () => ReactElement | null;
|
|
3927
|
+
//#endregion
|
|
3928
|
+
//#region src/list-kit/pieces/list-flows.d.ts
|
|
3929
|
+
declare const ListFlows: () => ReactElement | null;
|
|
3930
|
+
//#endregion
|
|
3931
|
+
//#region src/list-kit/pieces/list-live.d.ts
|
|
3932
|
+
declare const ListLive: () => ReactElement | null;
|
|
3933
|
+
//#endregion
|
|
3934
|
+
//#region src/list-kit/pieces/list-saved-views.d.ts
|
|
3935
|
+
declare const ListSavedViews: () => ReactElement | null;
|
|
3936
|
+
//#endregion
|
|
3937
|
+
//#region src/resource/resource-list.d.ts
|
|
3938
|
+
type RowRecord$1 = {
|
|
3939
|
+
id: string;
|
|
3940
|
+
} & Record<string, unknown>;
|
|
3941
|
+
interface ResourceListProps {
|
|
3942
|
+
resource: string;
|
|
3943
|
+
data?: RowRecord$1[];
|
|
3944
|
+
total?: number;
|
|
3945
|
+
page?: number;
|
|
3946
|
+
pageSize?: number;
|
|
3879
3947
|
/**
|
|
3880
|
-
*
|
|
3881
|
-
*
|
|
3882
|
-
*
|
|
3883
|
-
* `routing.createHref` through `hrefFor`, which throws `unknown node
|
|
3884
|
-
* '<resource>'` for a name the registry doesn't know. Route-level code
|
|
3885
|
-
* should 404 before mounting this component (the playground's
|
|
3886
|
-
* `app/(admin)/[resource]/page.tsx` does exactly that).
|
|
3948
|
+
* Called when the user picks a different page size. The size selector is
|
|
3949
|
+
* rendered ONLY when this is supplied — a list whose host does not persist
|
|
3950
|
+
* page size should not offer a control that silently resets on navigation.
|
|
3887
3951
|
*/
|
|
3888
|
-
|
|
3952
|
+
onPageSize?: (size: number) => void;
|
|
3889
3953
|
/**
|
|
3890
|
-
*
|
|
3891
|
-
*
|
|
3892
|
-
*
|
|
3893
|
-
* location picker, a tenant id, anything a data provider turns into a
|
|
3894
|
-
* server-side `where`.
|
|
3954
|
+
* Ask the host for the row count of the CURRENTLY described set (Task
|
|
3955
|
+
* B4.3). Rendered ONLY when this is supplied and `total` is unknown — the
|
|
3956
|
+
* same "no control the host cannot honour" gate `onPageSize` above uses.
|
|
3895
3957
|
*
|
|
3896
|
-
*
|
|
3897
|
-
*
|
|
3898
|
-
*
|
|
3899
|
-
*
|
|
3900
|
-
* `
|
|
3958
|
+
* This component is presentational by contract, so the trigger arrives as
|
|
3959
|
+
* a prop rather than being read from `useResourceListContext()`:
|
|
3960
|
+
* `useResourceListContext()` THROWS outside a provider
|
|
3961
|
+
* (`list-kit/context.tsx`), and `<ResourceList>` must stay usable
|
|
3962
|
+
* standalone — a `related-list` placement mounts one with a hand-rolled count and
|
|
3963
|
+
* no controller at all.
|
|
3901
3964
|
*
|
|
3902
|
-
*
|
|
3903
|
-
*
|
|
3904
|
-
*
|
|
3905
|
-
*
|
|
3906
|
-
*
|
|
3907
|
-
*
|
|
3908
|
-
*
|
|
3909
|
-
*
|
|
3965
|
+
* ⚠️ Answering moves the user, on purpose. The host writes the answer into
|
|
3966
|
+
* `total`, which flips `knownTotal` and with it four behaviours that are
|
|
3967
|
+
* dead on an unknown-total list: `pagination.showing` replaces the
|
|
3968
|
+
* range-only readout, the first/last jump buttons appear, `hasNextPage`
|
|
3969
|
+
* switches from "this page is full" to `page < totalPages`, and the
|
|
3970
|
+
* out-of-range clamp navigates a stale `?page=20` to the last real page.
|
|
3971
|
+
* That last one is the point of offering the trigger on a wrong page at
|
|
3972
|
+
* all.
|
|
3910
3973
|
*/
|
|
3911
|
-
|
|
3974
|
+
onRequestCount?: () => void;
|
|
3912
3975
|
/**
|
|
3913
|
-
*
|
|
3914
|
-
*
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
*
|
|
3976
|
+
* A count request is in flight. The trigger keeps its place and its width;
|
|
3977
|
+
* only its label is swapped for a spinner, and it stops accepting clicks.
|
|
3978
|
+
*/
|
|
3979
|
+
isCountingRows?: boolean;
|
|
3980
|
+
/** Page-size choices. Defaults to a standard admin ladder. */
|
|
3981
|
+
pageSizeOptions?: number[];
|
|
3982
|
+
onPage?: (n: number) => void;
|
|
3983
|
+
/**
|
|
3984
|
+
* Opaque-token pagination. When supplied, the numbered pager is replaced by
|
|
3985
|
+
* a load-more control: a token list has no page index to jump to. Absent →
|
|
3986
|
+
* the offset pager renders exactly as before.
|
|
3987
|
+
*/
|
|
3988
|
+
loadMore?: {
|
|
3989
|
+
hasMore: boolean;
|
|
3990
|
+
loading: boolean;
|
|
3991
|
+
onMore: () => void;
|
|
3992
|
+
};
|
|
3993
|
+
selectable?: boolean;
|
|
3994
|
+
/**
|
|
3995
|
+
* Accumulating selection owned by the caller. When provided the component
|
|
3996
|
+
* is CONTROLLED: this is the WHOLE selected set (ids that are not on the
|
|
3997
|
+
* current page included), the component keeps no selection state of its
|
|
3998
|
+
* own, and every change — including the page-scoped header checkbox — is
|
|
3999
|
+
* reported through `onSelectionChange` as the new whole set.
|
|
3922
4000
|
*
|
|
3923
|
-
*
|
|
3924
|
-
*
|
|
3925
|
-
* page by hand and passed its own `renderCell` knows more than the
|
|
3926
|
-
* registry does; the slot exists for the standard router, which mounts
|
|
3927
|
-
* `<ResourceListPage resource={...}>` with no props at all.
|
|
4001
|
+
* Omit it for the uncontrolled behaviour: the component owns the selection
|
|
4002
|
+
* and drops it whenever `data` changes identity.
|
|
3928
4003
|
*
|
|
3929
|
-
* ⚠️
|
|
3930
|
-
*
|
|
3931
|
-
*
|
|
3932
|
-
*
|
|
4004
|
+
* ⚠️ A controlled caller MUST commit every emission it receives through
|
|
4005
|
+
* `onSelectionChange` back into this prop: skip one and the `emittedRef`
|
|
4006
|
+
* bridge (below) stays armed against a base the DOM never reflected, so
|
|
4007
|
+
* the next toggle composes against a phantom selection instead of what's
|
|
4008
|
+
* actually checked.
|
|
3933
4009
|
*/
|
|
3934
|
-
|
|
4010
|
+
selectedIds?: string[];
|
|
4011
|
+
onSelectionChange?: (ids: string[]) => void;
|
|
4012
|
+
className?: string;
|
|
4013
|
+
/** When true, show skeleton rows instead of the table. */
|
|
4014
|
+
isLoading?: boolean;
|
|
4015
|
+
/** When non-null, show an error state. */
|
|
4016
|
+
error?: {
|
|
4017
|
+
message: string;
|
|
4018
|
+
} | Error | null;
|
|
3935
4019
|
/**
|
|
3936
|
-
*
|
|
3937
|
-
*
|
|
3938
|
-
*
|
|
3939
|
-
*
|
|
3940
|
-
*
|
|
3941
|
-
* (dashed border, icon, heading, and a "Clear filter" / "+ Create" /
|
|
3942
|
-
* "back to page 1" CTA), whereas a supplied node renders inside the
|
|
3943
|
-
* table body, so the header row survives and the CTAs do not. Pass one
|
|
3944
|
-
* when a slot wants the table chrome to stay put; omit it for the
|
|
3945
|
-
* standard panel.
|
|
4020
|
+
* Optional retry callback. When provided AND `error` is set, the
|
|
4021
|
+
* error-state panel renders a "Retry" button that invokes this
|
|
4022
|
+
* callback. The typical wiring is `onRetry={() => query.refetch()}`
|
|
4023
|
+
* when the parent uses the framework's `useList` (or an equivalent
|
|
4024
|
+
* `refetch()` method on the data source).
|
|
3946
4025
|
*/
|
|
3947
|
-
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
4026
|
+
onRetry?: () => void;
|
|
4027
|
+
/** Render an inline "+ Create" button in the empty state. */
|
|
4028
|
+
createHref?: string;
|
|
4029
|
+
/** Whether the list is currently filtered (changes empty-state copy). */
|
|
4030
|
+
isFiltered?: boolean;
|
|
4031
|
+
/** Called when the user clicks the "Clear filter" link in the filtered-empty state. */
|
|
4032
|
+
onClearFilter?: () => void;
|
|
4033
|
+
/**
|
|
4034
|
+
* Replacement for the "no rows" rendering, forwarded to
|
|
4035
|
+
* `<DataTable emptyState>`.
|
|
4036
|
+
*
|
|
4037
|
+
* ⚠️ This changes the SHAPE of the empty list, not just its copy. Left
|
|
4038
|
+
* undefined (the default, and what every caller did before the slot work)
|
|
4039
|
+
* this component early-returns a standalone panel INSTEAD of the table —
|
|
4040
|
+
* dashed border, icon, heading, and one of three CTAs ("Clear filter" when
|
|
4041
|
+
* filtered / "+ Create" when genuinely empty / "back to page 1" on an
|
|
4042
|
+
* out-of-range page). Supplying a node skips that panel entirely: the
|
|
4043
|
+
* table renders with its header row and the node fills a single body cell
|
|
4044
|
+
* spanning every column, so the column headers survive but none of the
|
|
4045
|
+
* CTAs do — the caller owns whatever recovery affordance the state needs.
|
|
4046
|
+
*
|
|
4047
|
+
* The footer/pagination is still hidden while there are no rows.
|
|
4048
|
+
*/
|
|
4049
|
+
emptyState?: React.ReactNode;
|
|
4050
|
+
/**
|
|
4051
|
+
* Another drawing of the same rows in place of the table (a `related-list` with `view: 'cards'`
|
|
4052
|
+
* or `'timeline'`, P6 3.13). Everything around the rows stays this component's: the loading,
|
|
4053
|
+
* error and empty states, the numbered pager or load-more footer, the on-demand count. The
|
|
4054
|
+
* table's own affordances (selection, column menu, sort headers) do not exist on it.
|
|
4055
|
+
*/
|
|
4056
|
+
rowsView?: {
|
|
4057
|
+
readonly render: (rows: RowRecord$1[]) => React.ReactNode;
|
|
4058
|
+
/** Drawn while the first page loads, in place of the table skeleton. */
|
|
4059
|
+
readonly skeleton: React.ReactNode;
|
|
4060
|
+
};
|
|
4061
|
+
/**
|
|
4062
|
+
* If provided, each row becomes a clickable link to this href.
|
|
4063
|
+
* Receives the row record; returns the navigation target.
|
|
4064
|
+
* Default behavior: rows are not clickable. Set to `(row) => '/{resource}/{row.id}'`
|
|
4065
|
+
* for typical show-page navigation.
|
|
4066
|
+
*/
|
|
4067
|
+
rowHref?: (row: RowRecord$1) => string | undefined;
|
|
4068
|
+
/**
|
|
4069
|
+
* A row's quick opener (P3-17): when it returns a function, a plain click on the row or its
|
|
4070
|
+
* first cell calls it instead of navigating; the first cell keeps the `rowHref` anchor (marked
|
|
4071
|
+
* for the opener) when there is one, and is a button when there is none. `null`: the row
|
|
4072
|
+
* follows `rowHref`.
|
|
4073
|
+
*/
|
|
4074
|
+
rowQuick?: (row: RowRecord$1) => (() => void) | null;
|
|
4075
|
+
/**
|
|
4076
|
+
* Changes whenever `rowHref` or `rowQuick` would answer differently for the same row (an
|
|
4077
|
+
* access answer arrived): the memoized rows and cells re-render.
|
|
4078
|
+
*/
|
|
4079
|
+
rowLinkKey?: unknown;
|
|
4080
|
+
/**
|
|
4081
|
+
* Per-cell custom renderer override. Returns `undefined` to fall back to
|
|
4082
|
+
* the default field-type-based display. Use for badges, links, or any
|
|
4083
|
+
* custom visual treatment that depends on column + value + row.
|
|
4084
|
+
*
|
|
4085
|
+
* MUST be a pure function of `(col, value, row)` — the cell it renders runs
|
|
4086
|
+
* inside `<DataTable>`'s memoized row/cell (`MemoRow`/`MemoCell` in
|
|
4087
|
+
* data-table.tsx), which intentionally skips re-rendering when a row's own
|
|
4088
|
+
* data and selection state haven't changed. If the returned output depends
|
|
4089
|
+
* on EXTERNAL reactive state (locale, a feature flag, anything read outside
|
|
4090
|
+
* `col`/`value`/`row`), it will go stale under that memo the same way the
|
|
4091
|
+
* built-in `DateDisplay`/`NumberDisplay` renderers did before they were
|
|
4092
|
+
* fixed to self-subscribe to locale. Delegate any such state-dependent
|
|
4093
|
+
* text to a component that subscribes to it itself (`useLocale()` /
|
|
4094
|
+
* `useOptionalT()` — see `EnumDisplay`/`BooleanDisplay`/`DateDisplay` for
|
|
4095
|
+
* the pattern) rather than resolving it inline in this callback.
|
|
4096
|
+
*/
|
|
4097
|
+
renderCell?: (col: string, value: unknown, row: RowRecord$1) => React.ReactNode | undefined;
|
|
4098
|
+
/** Current native sort expression. The header exposes the first sort key. */
|
|
4099
|
+
sort?: readonly {
|
|
4100
|
+
field: string;
|
|
4101
|
+
direction: 'asc' | 'desc';
|
|
4102
|
+
}[];
|
|
4103
|
+
/**
|
|
4104
|
+
* Sort request from a column header. `direction` is EXPLICIT when the header
|
|
4105
|
+
* menu picks «по возрастанию/убыванию/сбросить» (`'asc'`/`'desc'`/`null`); it
|
|
4106
|
+
* is omitted when a caller wants the legacy 3-click toggle. Consumers should
|
|
4107
|
+
* honour an explicit direction and fall back to toggling when it's undefined.
|
|
4108
|
+
*/
|
|
4109
|
+
onSort?: (field: string, direction?: 'asc' | 'desc' | null) => void;
|
|
4110
|
+
/**
|
|
4111
|
+
* Hide a column from a column-header menu. Receives the column name; the
|
|
4112
|
+
* parent removes it from the visible-columns list. When omitted, the header
|
|
4113
|
+
* menu shows no «hide» item.
|
|
4114
|
+
*/
|
|
4115
|
+
onHideColumn?: (field: string) => void;
|
|
4116
|
+
/**
|
|
4117
|
+
* Columns that may NOT be hidden — the header menu omits «hide» for these.
|
|
4118
|
+
* Without it every column is treated as hideable (when `onHideColumn` is set).
|
|
4119
|
+
*/
|
|
4120
|
+
requiredColumns?: string[];
|
|
4121
|
+
/**
|
|
4122
|
+
* Bump to reset the persisted column layout (#17). `resetLayout.mode`:
|
|
4123
|
+
* - `'sizes'` — clear user-resized widths only.
|
|
4124
|
+
* - `'all'` — clear widths AND pinning AND order back to defaults.
|
|
4125
|
+
* The token is what triggers it; increment it on each reset click.
|
|
4126
|
+
*/
|
|
4127
|
+
resetLayout?: {
|
|
4128
|
+
token: number;
|
|
4129
|
+
mode: 'sizes' | 'all';
|
|
4130
|
+
};
|
|
4131
|
+
/**
|
|
4132
|
+
* Override for the column list rendered in the table. When omitted,
|
|
4133
|
+
* the table falls back to `def.views.list.columns` (or all field
|
|
4134
|
+
* keys). When provided, the table renders EXACTLY this set in the
|
|
4135
|
+
* given order — useful for the user-toggleable Columns menu (see
|
|
4136
|
+
* `views.list.optionalColumns` / `requiredColumns`).
|
|
4137
|
+
*/
|
|
4138
|
+
columns?: string[];
|
|
4139
|
+
/**
|
|
4140
|
+
* Optional callback that hands the parent the underlying TanStack
|
|
4141
|
+
* `Table` instance. Fires once after the table is mounted (and
|
|
4142
|
+
* again with `null` on unmount). Use this when the parent needs to
|
|
4143
|
+
* read selection state for components that live OUTSIDE the table
|
|
4144
|
+
* (e.g. `<BulkActionToolbar>` which calls
|
|
4145
|
+
* `table.getFilteredSelectedRowModel().rows`). The id-array
|
|
4146
|
+
* `onSelectionChange` callback remains the recommended way to
|
|
4147
|
+
* trigger a parent re-render on selection changes — `tableRef`
|
|
4148
|
+
* gives access to the rows, not a re-render signal.
|
|
4149
|
+
*/
|
|
4150
|
+
tableRef?: (table: Table$1<RowRecord$1> | null) => void;
|
|
4151
|
+
}
|
|
4152
|
+
declare function ResourceList({ resource, data, total, page, pageSize, onPageSize, onRequestCount, isCountingRows, pageSizeOptions, onPage, loadMore, selectable, selectedIds, onSelectionChange, className, isLoading, error, onRetry, createHref, isFiltered, onClearFilter, emptyState, rowsView, rowHref, rowQuick, rowLinkKey, renderCell, sort, onSort, onHideColumn, requiredColumns, resetLayout, columns: columnsOverride, tableRef }: ResourceListProps): React.ReactElement;
|
|
4153
|
+
//#endregion
|
|
4154
|
+
//#region src/list-kit/cursor-load-more.d.ts
|
|
4155
|
+
/**
|
|
4156
|
+
* Props of {@link CursorLoadMore}.
|
|
4157
|
+
*
|
|
4158
|
+
* Deliberately shaped as three scalars rather than taking the controller's
|
|
4159
|
+
* `cursor` group whole: the group's `next` is an opaque TOKEN (useful to a
|
|
4160
|
+
* consumer that wants to log or deep-link it) while this control only ever
|
|
4161
|
+
* needs to know whether there IS one. Spreading `cursor` in would also make
|
|
4162
|
+
* the component unusable by a surface that paginates a nested/embedded list
|
|
4163
|
+
* outside `useResourceList` — the workflows page does exactly that.
|
|
4164
|
+
*/
|
|
4165
|
+
interface CursorLoadMoreProps {
|
|
4166
|
+
/** Render the button at all. `false` renders nothing (see the docblock). */
|
|
4167
|
+
hasMore: boolean;
|
|
4168
|
+
/** A load-more fetch is in flight — disables the button and swaps the label. */
|
|
4169
|
+
loading?: boolean;
|
|
4170
|
+
/** Fetch the next page. Wire to `cursor.loadMore()`. */
|
|
4171
|
+
onMore: () => void;
|
|
4172
|
+
}
|
|
4173
|
+
/**
|
|
4174
|
+
* The "load more" footer for a **cursor (opaque-token) paginated** list —
|
|
4175
|
+
* the counterpart of the numbered pager `<ResourceList>` renders for offset
|
|
4176
|
+
* providers.
|
|
4177
|
+
*
|
|
4178
|
+
* ```tsx
|
|
4179
|
+
* const { rows, cursor } = useResourceListContext();
|
|
4180
|
+
* // …the table…
|
|
4181
|
+
* {cursor && (
|
|
4182
|
+
* <CursorLoadMore
|
|
4183
|
+
* hasMore={cursor.next !== null}
|
|
4184
|
+
* loading={cursor.isLoadingMore}
|
|
4185
|
+
* onMore={cursor.loadMore}
|
|
4186
|
+
* />
|
|
4187
|
+
* )}
|
|
4188
|
+
* ```
|
|
4189
|
+
*
|
|
4190
|
+
* ⚠️ **Renders `null` when `hasMore` is false**, so an exhausted cursor
|
|
4191
|
+
* leaves no dead control behind — the caller does not need its own guard.
|
|
4192
|
+
* That is also what makes "the button is gone" a usable end-of-list
|
|
4193
|
+
* assertion in tests.
|
|
4194
|
+
*
|
|
4195
|
+
* Why it lives in the framework rather than in the app that first needed it
|
|
4196
|
+
* (core flexibility program, Task B5.3): it has **zero coupling to any
|
|
4197
|
+
* provider**. It knows nothing about Temporal, tokens, or where the next
|
|
4198
|
+
* page comes from — only "is there more" / "is it coming" / "go get it". A
|
|
4199
|
+
* cursor list is now a first-class declared mode
|
|
4200
|
+
* (`views.list.pagination: 'cursor'`), so the control that drives one
|
|
4201
|
+
* belongs beside the pager it replaces.
|
|
4202
|
+
*
|
|
4203
|
+
* @see ResourceListController.cursor in `@burojs/react`
|
|
4204
|
+
*/
|
|
4205
|
+
declare function CursorLoadMore({ hasMore, loading, onMore }: CursorLoadMoreProps): React.ReactElement | null;
|
|
4206
|
+
//#endregion
|
|
4207
|
+
//#region src/list-kit/resource-list-page.d.ts
|
|
4208
|
+
/**
|
|
4209
|
+
* Props of {@link ResourceListPage}.
|
|
4210
|
+
*/
|
|
4211
|
+
interface ResourceListPageProps {
|
|
4212
|
+
/**
|
|
4213
|
+
* Registry name of the resource to list.
|
|
4214
|
+
*
|
|
4215
|
+
* ⚠️ **Precondition: it MUST be registered.** `useResourceList` resolves
|
|
4216
|
+
* `routing.createHref` through `hrefFor`, which throws `unknown node
|
|
4217
|
+
* '<resource>'` for a name the registry doesn't know. Route-level code
|
|
4218
|
+
* should 404 before mounting this component (the playground's
|
|
4219
|
+
* `app/(admin)/[resource]/page.tsx` does exactly that).
|
|
4220
|
+
*/
|
|
4221
|
+
resource: string;
|
|
4222
|
+
/**
|
|
4223
|
+
* Extra `meta` merged into the underlying `useList` call — and therefore
|
|
4224
|
+
* into the react-query cache key. This is the seam for app-level query
|
|
4225
|
+
* scope the framework cannot know about: a sidebar product-group /
|
|
4226
|
+
* location picker, a tenant id, anything a data provider turns into a
|
|
4227
|
+
* server-side `where`.
|
|
4228
|
+
*
|
|
4229
|
+
* ⚠️ **The caller MUST memoize this object.** It flows into the query key
|
|
4230
|
+
* AND into the controller's own memo chain; an inline object literal
|
|
4231
|
+
* mints a fresh key on every render, which busts that chain and can
|
|
4232
|
+
* produce a refetch loop. The playground memoizes on
|
|
4233
|
+
* `[scope.productGroup, scope.locationId]`:
|
|
4234
|
+
*
|
|
4235
|
+
* ```tsx
|
|
4236
|
+
* const scope = useScope();
|
|
4237
|
+
* const listMeta = useMemo(
|
|
4238
|
+
* () => ({ scope: { pg: scope.productGroup, location_id: scope.locationId } }),
|
|
4239
|
+
* [scope.productGroup, scope.locationId],
|
|
4240
|
+
* );
|
|
4241
|
+
* return <ResourceListPage resource={resource} meta={listMeta} />;
|
|
4242
|
+
* ```
|
|
4243
|
+
*/
|
|
4244
|
+
meta?: Record<string, unknown>;
|
|
4245
|
+
/**
|
|
4246
|
+
* App-level per-cell renderer, consulted AFTER this component's own
|
|
4247
|
+
* built-in branches (typed discriminator → declared `enum` field) and
|
|
4248
|
+
* BEFORE `<ResourceList>`'s default field-type display. Return
|
|
4249
|
+
* `undefined` to fall through, exactly like `<ResourceList renderCell>`.
|
|
4250
|
+
*
|
|
4251
|
+
* The built-ins cover what the registry can describe on its own; this
|
|
4252
|
+
* prop is for the rest — the playground uses it for a legacy hardcoded
|
|
4253
|
+
* `status` badge and a `is_active` Yes/No badge, neither of which the
|
|
4254
|
+
* framework can derive from a field def.
|
|
4255
|
+
*
|
|
4256
|
+
* ⚠️ Wins over a registered `list.cell.<resource>` slot (level 1 —
|
|
4257
|
+
* {@link ../list-kit/list-slots.js | listSlot}). A host that mounted this
|
|
4258
|
+
* page by hand and passed its own `renderCell` knows more than the
|
|
4259
|
+
* registry does; the slot exists for the standard router, which mounts
|
|
4260
|
+
* `<ResourceListPage resource={...}>` with no props at all.
|
|
4261
|
+
*
|
|
4262
|
+
* ⚠️ Same purity requirement as `<ResourceList renderCell>`: it runs
|
|
4263
|
+
* inside a memoized cell, so anything depending on external reactive
|
|
4264
|
+
* state (locale, flags) must be delegated to a component that
|
|
4265
|
+
* subscribes to that state itself.
|
|
4266
|
+
*/
|
|
4267
|
+
renderCell?: (col: string, value: unknown, row: RowRecord) => ReactNode | undefined;
|
|
4268
|
+
/**
|
|
4269
|
+
* Replacement for the table's empty state, forwarded to
|
|
4270
|
+
* `<ResourceList emptyState>` and from there to `<DataTable emptyState>`.
|
|
4271
|
+
*
|
|
4272
|
+
* ⚠️ Supplying this changes the SHAPE of the empty list, not just its
|
|
4273
|
+
* copy: the default is a standalone panel rendered INSTEAD of the table
|
|
4274
|
+
* (dashed border, icon, heading, and a "Clear filter" / "+ Create" /
|
|
4275
|
+
* "back to page 1" CTA), whereas a supplied node renders inside the
|
|
4276
|
+
* table body, so the header row survives and the CTAs do not. Pass one
|
|
4277
|
+
* when a slot wants the table chrome to stay put; omit it for the
|
|
4278
|
+
* standard panel.
|
|
4279
|
+
*/
|
|
4280
|
+
emptyState?: ReactNode;
|
|
4281
|
+
}
|
|
4282
|
+
/**
|
|
4283
|
+
* The assembled, data-connected list page (core flexibility program, Task
|
|
4284
|
+
* B3.1) — the piece that makes `<ResourceList>` actually useful. Given a
|
|
4285
|
+
* resource name it renders the whole standard list surface:
|
|
4286
|
+
*
|
|
4287
|
+
* - page header,
|
|
4288
|
+
* - the filter region — search box + pinned controls + the filter-builder
|
|
4289
|
+
* popover + applied-filter badges + "Clear all" (via {@link FilterRegion}),
|
|
4290
|
+
* - saved-views dropdown and its two dialogs (save-current / manage),
|
|
4291
|
+
* - the columns toggle and the create button,
|
|
4292
|
+
* - `<ResourceList>` itself (table, empty/error/loading states,
|
|
3960
4293
|
* pagination),
|
|
3961
4294
|
* - the floating bulk-action bar.
|
|
3962
4295
|
*
|
|
@@ -3969,6 +4302,11 @@ interface ResourceListPageProps {
|
|
|
3969
4302
|
* — the filter region's OWN testids moved to the builder's `list-filter:*`
|
|
3970
4303
|
* convention; everything else is unchanged).
|
|
3971
4304
|
*
|
|
4305
|
+
* It renders through the built-in `related-list` block (spec 8.4, decision 63): the view is
|
|
4306
|
+
* `buro:related-list`'s, inside a `[data-buro-node="place"]` wrapper, and an app that registers
|
|
4307
|
+
* its own `buro:related-list` view (`<BuroProvider blockImplementations>`) replaces this list
|
|
4308
|
+
* everywhere, a development notice saying so. The body itself lives in `ResourceListSurface`.
|
|
4309
|
+
*
|
|
3972
4310
|
* The whole subtree is wrapped in `<ResourceListProvider>`, so any nested
|
|
3973
4311
|
* component can read the live controller with `useResourceListContext()`
|
|
3974
4312
|
* instead of receiving a hand-threaded prop chain. That is the seam the
|
|
@@ -3982,7 +4320,7 @@ interface ResourceListPageProps {
|
|
|
3982
4320
|
* covers:
|
|
3983
4321
|
*
|
|
3984
4322
|
* - **`list.cell.<resource>`** (level 1) is consulted for every cell, AFTER
|
|
3985
|
-
* this component's own built-in branches (
|
|
4323
|
+
* this component's own built-in branches (typed discriminator →
|
|
3986
4324
|
* declared `enum` field) and BEFORE `<ResourceList>`'s default field-type
|
|
3987
4325
|
* display — the same position the `renderCell` prop occupies, and the
|
|
3988
4326
|
* explicit prop wins when both are present. Everything else — filters,
|
|
@@ -3991,17 +4329,13 @@ interface ResourceListPageProps {
|
|
|
3991
4329
|
* the search box, the pinned controls, the filter-builder popover and its
|
|
3992
4330
|
* applied-filter badges. Saved views, the columns toggle, the create
|
|
3993
4331
|
* button, the table, the footer and pagination all stay standard.
|
|
3994
|
-
* -
|
|
3995
|
-
* page header
|
|
3996
|
-
*
|
|
3997
|
-
*
|
|
3998
|
-
* ⚠️
|
|
3999
|
-
* `
|
|
4000
|
-
*
|
|
4001
|
-
* and its breadcrumb slot — and the spec's level-3 guarantee is that
|
|
4002
|
-
* routing, data loading, redirects and BREADCRUMBS stay framework-owned:
|
|
4003
|
-
* "you lose only the default assembled markup". A slot that wants a
|
|
4004
|
-
* visible heading of its own renders one; the header's `h1` is `sr-only`.
|
|
4332
|
+
* - A whole-body override is a list frame (`views.list.frame`, P7-34), which arranges the
|
|
4333
|
+
* framework's pieces and keeps the page header, the controller, the URL state, the saved-view
|
|
4334
|
+
* dialogs, the export watcher and the bulk bar. `list.body.<resource>` is gone (P7-37).
|
|
4335
|
+
*
|
|
4336
|
+
* ⚠️ The `<PageHeader>` stays framework-owned. It is what writes `document.title` (via
|
|
4337
|
+
* `useDocumentTitle`, defended against Next's metadata re-application) and what renders the
|
|
4338
|
+
* page's accessible `<h1>` and its breadcrumb slot; the header's `h1` is `sr-only`.
|
|
4005
4339
|
*
|
|
4006
4340
|
* Both slots take no props and read the controller from
|
|
4007
4341
|
* `useResourceListContext()`, so each is unit-testable against a
|
|
@@ -4035,7 +4369,13 @@ declare function ResourceListPage({ resource, meta, renderCell, emptyState }: Re
|
|
|
4035
4369
|
* no `list.filters.<resource>` slot is registered, so this component itself
|
|
4036
4370
|
* never has to know about the override ladder.
|
|
4037
4371
|
*/
|
|
4038
|
-
declare function FilterRegion(
|
|
4372
|
+
declare function FilterRegion({ search }?: {
|
|
4373
|
+
/**
|
|
4374
|
+
* The search a placement declares (`related-list`'s `search` prop), `null` for none; the route
|
|
4375
|
+
* list omits it and reads the resource's `views.list.search`.
|
|
4376
|
+
*/
|
|
4377
|
+
readonly search?: SearchDecl | null;
|
|
4378
|
+
}): React.ReactElement;
|
|
4039
4379
|
//#endregion
|
|
4040
4380
|
//#region src/list-kit/filter-builder/filter-builder.d.ts
|
|
4041
4381
|
type Expression$2 = FilterExpression<ErasedResourceHandle>;
|
|
@@ -4311,9 +4651,17 @@ interface FilterValueControlProps {
|
|
|
4311
4651
|
* gets the plain generic label every existing test asserts on.
|
|
4312
4652
|
*/
|
|
4313
4653
|
readonly fieldLabel?: string;
|
|
4314
|
-
readonly autoFocus?: boolean;
|
|
4315
4654
|
/**
|
|
4316
|
-
*
|
|
4655
|
+
* Visible hint inside a text/number box (`ScalarValueInput`). Only a caller
|
|
4656
|
+
* that shows the control with nothing naming its field beside it passes one:
|
|
4657
|
+
* the pinned toolbar (`PinnedFilterControls`) gives the field's label, so a
|
|
4658
|
+
* pinned text filter is not an unlabelled empty box (REF-44). A builder row
|
|
4659
|
+
* names its field in its own field picker and passes none.
|
|
4660
|
+
*/
|
|
4661
|
+
readonly placeholder?: string;
|
|
4662
|
+
readonly autoFocus?: boolean;
|
|
4663
|
+
/**
|
|
4664
|
+
* Delay (ms) before a scalar single-value edit (`ScalarValueInput`'s
|
|
4317
4665
|
* text/number/date box) commits upward. Only that control debounces —
|
|
4318
4666
|
* enum/relation/boolean commit on selection already, so they ignore this.
|
|
4319
4667
|
* Defaults to 300 (the legacy chip UX: don't spam the URL/provider on
|
|
@@ -4373,227 +4721,38 @@ interface FilterValueControlProps {
|
|
|
4373
4721
|
*/
|
|
4374
4722
|
declare function FilterValueControl(props: FilterValueControlProps): React.ReactElement | null;
|
|
4375
4723
|
//#endregion
|
|
4376
|
-
//#region src/resource/resource-list.d.ts
|
|
4377
|
-
type RowRecord$1 = {
|
|
4378
|
-
id: string;
|
|
4379
|
-
} & Record<string, unknown>;
|
|
4380
|
-
interface ResourceListProps {
|
|
4381
|
-
resource: string;
|
|
4382
|
-
data?: RowRecord$1[];
|
|
4383
|
-
total?: number;
|
|
4384
|
-
page?: number;
|
|
4385
|
-
pageSize?: number;
|
|
4386
|
-
/**
|
|
4387
|
-
* Called when the user picks a different page size. The size selector is
|
|
4388
|
-
* rendered ONLY when this is supplied — a list whose host does not persist
|
|
4389
|
-
* page size should not offer a control that silently resets on navigation.
|
|
4390
|
-
*/
|
|
4391
|
-
onPageSize?: (size: number) => void;
|
|
4392
|
-
/**
|
|
4393
|
-
* Ask the host for the row count of the CURRENTLY described set (Task
|
|
4394
|
-
* B4.3). Rendered ONLY when this is supplied and `total` is unknown — the
|
|
4395
|
-
* same "no control the host cannot honour" gate `onPageSize` above uses.
|
|
4396
|
-
*
|
|
4397
|
-
* This component is presentational by contract, so the trigger arrives as
|
|
4398
|
-
* a prop rather than being read from `useResourceListContext()`:
|
|
4399
|
-
* `useResourceListContext()` THROWS outside a provider
|
|
4400
|
-
* (`list-kit/context.tsx`), and `<ResourceList>` must stay usable
|
|
4401
|
-
* standalone — `SubresourceTabBody` mounts one with a hand-rolled count and
|
|
4402
|
-
* no controller at all.
|
|
4403
|
-
*
|
|
4404
|
-
* ⚠️ Answering moves the user, on purpose. The host writes the answer into
|
|
4405
|
-
* `total`, which flips `knownTotal` and with it four behaviours that are
|
|
4406
|
-
* dead on an unknown-total list: `pagination.showing` replaces the
|
|
4407
|
-
* range-only readout, the first/last jump buttons appear, `hasNextPage`
|
|
4408
|
-
* switches from "this page is full" to `page < totalPages`, and the
|
|
4409
|
-
* out-of-range clamp navigates a stale `?page=20` to the last real page.
|
|
4410
|
-
* That last one is the point of offering the trigger on a wrong page at
|
|
4411
|
-
* all.
|
|
4412
|
-
*/
|
|
4413
|
-
onRequestCount?: () => void;
|
|
4414
|
-
/**
|
|
4415
|
-
* A count request is in flight. The trigger keeps its place and its width;
|
|
4416
|
-
* only its label is swapped for a spinner, and it stops accepting clicks.
|
|
4417
|
-
*/
|
|
4418
|
-
isCountingRows?: boolean;
|
|
4419
|
-
/** Page-size choices. Defaults to a standard admin ladder. */
|
|
4420
|
-
pageSizeOptions?: number[];
|
|
4421
|
-
onPage?: (n: number) => void;
|
|
4422
|
-
/**
|
|
4423
|
-
* Opaque-token pagination. When supplied, the numbered pager is replaced by
|
|
4424
|
-
* a load-more control: a token list has no page index to jump to. Absent →
|
|
4425
|
-
* the offset pager renders exactly as before.
|
|
4426
|
-
*/
|
|
4427
|
-
loadMore?: {
|
|
4428
|
-
hasMore: boolean;
|
|
4429
|
-
loading: boolean;
|
|
4430
|
-
onMore: () => void;
|
|
4431
|
-
};
|
|
4432
|
-
selectable?: boolean;
|
|
4433
|
-
/**
|
|
4434
|
-
* Accumulating selection owned by the caller. When provided the component
|
|
4435
|
-
* is CONTROLLED: this is the WHOLE selected set (ids that are not on the
|
|
4436
|
-
* current page included), the component keeps no selection state of its
|
|
4437
|
-
* own, and every change — including the page-scoped header checkbox — is
|
|
4438
|
-
* reported through `onSelectionChange` as the new whole set.
|
|
4439
|
-
*
|
|
4440
|
-
* Omit it for the uncontrolled behaviour: the component owns the selection
|
|
4441
|
-
* and drops it whenever `data` changes identity.
|
|
4442
|
-
*
|
|
4443
|
-
* ⚠️ A controlled caller MUST commit every emission it receives through
|
|
4444
|
-
* `onSelectionChange` back into this prop: skip one and the `emittedRef`
|
|
4445
|
-
* bridge (below) stays armed against a base the DOM never reflected, so
|
|
4446
|
-
* the next toggle composes against a phantom selection instead of what's
|
|
4447
|
-
* actually checked.
|
|
4448
|
-
*/
|
|
4449
|
-
selectedIds?: string[];
|
|
4450
|
-
onSelectionChange?: (ids: string[]) => void;
|
|
4451
|
-
className?: string;
|
|
4452
|
-
/** When true, show skeleton rows instead of the table. */
|
|
4453
|
-
isLoading?: boolean;
|
|
4454
|
-
/** When non-null, show an error state. */
|
|
4455
|
-
error?: {
|
|
4456
|
-
message: string;
|
|
4457
|
-
} | Error | null;
|
|
4458
|
-
/**
|
|
4459
|
-
* Optional retry callback. When provided AND `error` is set, the
|
|
4460
|
-
* error-state panel renders a "Retry" button that invokes this
|
|
4461
|
-
* callback. The typical wiring is `onRetry={() => query.refetch()}`
|
|
4462
|
-
* when the parent uses the framework's `useList` (or an equivalent
|
|
4463
|
-
* `refetch()` method on the data source).
|
|
4464
|
-
*/
|
|
4465
|
-
onRetry?: () => void;
|
|
4466
|
-
/** Render an inline "+ Create" button in the empty state. */
|
|
4467
|
-
createHref?: string;
|
|
4468
|
-
/** Whether the list is currently filtered (changes empty-state copy). */
|
|
4469
|
-
isFiltered?: boolean;
|
|
4470
|
-
/** Called when the user clicks the "Clear filter" link in the filtered-empty state. */
|
|
4471
|
-
onClearFilter?: () => void;
|
|
4472
|
-
/**
|
|
4473
|
-
* Replacement for the "no rows" rendering, forwarded to
|
|
4474
|
-
* `<DataTable emptyState>`.
|
|
4475
|
-
*
|
|
4476
|
-
* ⚠️ This changes the SHAPE of the empty list, not just its copy. Left
|
|
4477
|
-
* undefined (the default, and what every caller did before the slot work)
|
|
4478
|
-
* this component early-returns a standalone panel INSTEAD of the table —
|
|
4479
|
-
* dashed border, icon, heading, and one of three CTAs ("Clear filter" when
|
|
4480
|
-
* filtered / "+ Create" when genuinely empty / "back to page 1" on an
|
|
4481
|
-
* out-of-range page). Supplying a node skips that panel entirely: the
|
|
4482
|
-
* table renders with its header row and the node fills a single body cell
|
|
4483
|
-
* spanning every column, so the column headers survive but none of the
|
|
4484
|
-
* CTAs do — the caller owns whatever recovery affordance the state needs.
|
|
4485
|
-
*
|
|
4486
|
-
* The footer/pagination is still hidden while there are no rows.
|
|
4487
|
-
*/
|
|
4488
|
-
emptyState?: React.ReactNode;
|
|
4489
|
-
/**
|
|
4490
|
-
* If provided, each row becomes a clickable link to this href.
|
|
4491
|
-
* Receives the row record; returns the navigation target.
|
|
4492
|
-
* Default behavior: rows are not clickable. Set to `(row) => '/{resource}/{row.id}'`
|
|
4493
|
-
* for typical show-page navigation.
|
|
4494
|
-
*/
|
|
4495
|
-
rowHref?: (row: RowRecord$1) => string | undefined;
|
|
4496
|
-
/**
|
|
4497
|
-
* Per-cell custom renderer override. Returns `undefined` to fall back to
|
|
4498
|
-
* the default field-type-based display. Use for badges, links, or any
|
|
4499
|
-
* custom visual treatment that depends on column + value + row.
|
|
4500
|
-
*
|
|
4501
|
-
* MUST be a pure function of `(col, value, row)` — the cell it renders runs
|
|
4502
|
-
* inside `<DataTable>`'s memoized row/cell (`MemoRow`/`MemoCell` in
|
|
4503
|
-
* data-table.tsx), which intentionally skips re-rendering when a row's own
|
|
4504
|
-
* data and selection state haven't changed. If the returned output depends
|
|
4505
|
-
* on EXTERNAL reactive state (locale, a feature flag, anything read outside
|
|
4506
|
-
* `col`/`value`/`row`), it will go stale under that memo the same way the
|
|
4507
|
-
* built-in `DateDisplay`/`NumberDisplay` renderers did before they were
|
|
4508
|
-
* fixed to self-subscribe to locale. Delegate any such state-dependent
|
|
4509
|
-
* text to a component that subscribes to it itself (`useLocale()` /
|
|
4510
|
-
* `useOptionalT()` — see `EnumDisplay`/`BooleanDisplay`/`DateDisplay` for
|
|
4511
|
-
* the pattern) rather than resolving it inline in this callback.
|
|
4512
|
-
*/
|
|
4513
|
-
renderCell?: (col: string, value: unknown, row: RowRecord$1) => React.ReactNode | undefined;
|
|
4514
|
-
/** Current native sort expression. The header exposes the first sort key. */
|
|
4515
|
-
sort?: readonly {
|
|
4516
|
-
field: string;
|
|
4517
|
-
direction: 'asc' | 'desc';
|
|
4518
|
-
}[];
|
|
4519
|
-
/**
|
|
4520
|
-
* Sort request from a column header. `direction` is EXPLICIT when the header
|
|
4521
|
-
* menu picks «по возрастанию/убыванию/сбросить» (`'asc'`/`'desc'`/`null`); it
|
|
4522
|
-
* is omitted when a caller wants the legacy 3-click toggle. Consumers should
|
|
4523
|
-
* honour an explicit direction and fall back to toggling when it's undefined.
|
|
4524
|
-
*/
|
|
4525
|
-
onSort?: (field: string, direction?: 'asc' | 'desc' | null) => void;
|
|
4526
|
-
/**
|
|
4527
|
-
* Hide a column from a column-header menu. Receives the column name; the
|
|
4528
|
-
* parent removes it from the visible-columns list. When omitted, the header
|
|
4529
|
-
* menu shows no «hide» item.
|
|
4530
|
-
*/
|
|
4531
|
-
onHideColumn?: (field: string) => void;
|
|
4532
|
-
/**
|
|
4533
|
-
* Columns that may NOT be hidden — the header menu omits «hide» for these.
|
|
4534
|
-
* Without it every column is treated as hideable (when `onHideColumn` is set).
|
|
4535
|
-
*/
|
|
4536
|
-
requiredColumns?: string[];
|
|
4537
|
-
/**
|
|
4538
|
-
* Bump to reset the persisted column layout (#17). `resetLayout.mode`:
|
|
4539
|
-
* - `'sizes'` — clear user-resized widths only.
|
|
4540
|
-
* - `'all'` — clear widths AND pinning AND order back to defaults.
|
|
4541
|
-
* The token is what triggers it; increment it on each reset click.
|
|
4542
|
-
*/
|
|
4543
|
-
resetLayout?: {
|
|
4544
|
-
token: number;
|
|
4545
|
-
mode: 'sizes' | 'all';
|
|
4546
|
-
};
|
|
4547
|
-
/**
|
|
4548
|
-
* Override for the column list rendered in the table. When omitted,
|
|
4549
|
-
* the table falls back to `def.views.list.columns` (or all field
|
|
4550
|
-
* keys). When provided, the table renders EXACTLY this set in the
|
|
4551
|
-
* given order — useful for the user-toggleable Columns menu (see
|
|
4552
|
-
* `views.list.optionalColumns` / `requiredColumns`).
|
|
4553
|
-
*/
|
|
4554
|
-
columns?: string[];
|
|
4555
|
-
/**
|
|
4556
|
-
* Optional callback that hands the parent the underlying TanStack
|
|
4557
|
-
* `Table` instance. Fires once after the table is mounted (and
|
|
4558
|
-
* again with `null` on unmount). Use this when the parent needs to
|
|
4559
|
-
* read selection state for components that live OUTSIDE the table
|
|
4560
|
-
* (e.g. `<BulkActionToolbar>` which calls
|
|
4561
|
-
* `table.getFilteredSelectedRowModel().rows`). The id-array
|
|
4562
|
-
* `onSelectionChange` callback remains the recommended way to
|
|
4563
|
-
* trigger a parent re-render on selection changes — `tableRef`
|
|
4564
|
-
* gives access to the rows, not a re-render signal.
|
|
4565
|
-
*/
|
|
4566
|
-
tableRef?: (table: Table$1<RowRecord$1> | null) => void;
|
|
4567
|
-
}
|
|
4568
|
-
declare function ResourceList({ resource, data, total, page, pageSize, onPageSize, onRequestCount, isCountingRows, pageSizeOptions, onPage, loadMore, selectable, selectedIds, onSelectionChange, className, isLoading, error, onRetry, createHref, isFiltered, onClearFilter, emptyState, rowHref, renderCell, sort, onSort, onHideColumn, requiredColumns, resetLayout, columns: columnsOverride, tableRef }: ResourceListProps): React.ReactElement;
|
|
4569
|
-
//#endregion
|
|
4570
4724
|
//#region src/list-kit/list-slots.d.ts
|
|
4571
4725
|
/**
|
|
4572
|
-
* The
|
|
4573
|
-
*
|
|
4574
|
-
*
|
|
4726
|
+
* The two override seams `<ResourceListPage>` opens on the standard list (core flexibility
|
|
4727
|
+
* program, Task B3.2; level 1 added by SP0 Task 5) — the "level 1" and "level 2" rungs of the
|
|
4728
|
+
* spec's override ladder:
|
|
4575
4729
|
*
|
|
4576
4730
|
* ```
|
|
4577
4731
|
* level 0 nothing registered → the standard assembled list
|
|
4578
4732
|
* level 1 list.cell.<r> → one column's renderer; everything else stays standard
|
|
4579
4733
|
* level 2 list.filters.<r> → custom filter region; table/footer stay standard
|
|
4580
|
-
* level 3 list.body.<r> → the whole body is yours
|
|
4581
4734
|
* ```
|
|
4582
4735
|
*
|
|
4736
|
+
* ⚠️ **The old level 3, `list.body.<r>`, is gone (P7-37).** A whole-body override is a list frame
|
|
4737
|
+
* (`views.list.frame`, `defineFrame(id, { for: 'list' })`): it places the framework's pieces
|
|
4738
|
+
* (`<ListControls/>`, `<ListBody/>`, …) instead of replacing them, so it keeps the filters, the
|
|
4739
|
+
* saved views, the columns menu, URL state, selection and the bulk bar. A component still
|
|
4740
|
+
* registered under `list.body.<r>` is a development error at mount and a `checkApp` error
|
|
4741
|
+
* (`list.body-removed`), never a silent no-op.
|
|
4742
|
+
*
|
|
4583
4743
|
* ⚠️ **Level 1 is reachable through the registry now, not only through a
|
|
4584
4744
|
* prop.** `<ResourceList renderCell>` / `<ResourceListPage renderCell>` still
|
|
4585
4745
|
* work — an explicit prop wins over the registered slot — but neither is
|
|
4586
4746
|
* reachable through the standard `NavAreaPage` router, which mounts
|
|
4587
4747
|
* `<ResourceListPage resource={...} />` with no props at all. Before this,
|
|
4588
4748
|
* an adopter who wanted one column rendered as a badge had no way to reach
|
|
4589
|
-
* that router and had to
|
|
4749
|
+
* that router and had to replace the whole list body instead, trading away
|
|
4590
4750
|
* filters, the columns menu, saved views and URL state to repaint a single
|
|
4591
|
-
* cell. `list.cell.<r>` closes that gap the same way `list.filters.<r>`
|
|
4592
|
-
* `list.body.<r>` already do.
|
|
4751
|
+
* cell. `list.cell.<r>` closes that gap the same way `list.filters.<r>` does.
|
|
4593
4752
|
*
|
|
4594
4753
|
* ⚠️ **`list.cell.<r>` never sees a column `<ResourceListPage>`'s OWN
|
|
4595
4754
|
* built-in branches already claimed.** A column with a declared `enum`
|
|
4596
|
-
* gets the framework's `<EnumBadge>`, and a
|
|
4755
|
+
* gets the framework's `<EnumBadge>`, and a typed resource's discriminator column
|
|
4597
4756
|
* gets its label/badge, BEFORE either the `renderCell` prop or the
|
|
4598
4757
|
* `list.cell.<r>` slot is consulted — same as the pre-Task-5 behaviour for
|
|
4599
4758
|
* the prop. The registered renderer's function is simply never called for
|
|
@@ -4601,20 +4760,20 @@ declare function ResourceList({ resource, data, total, page, pageSize, onPageSiz
|
|
|
4601
4760
|
* This is the genuinely surprising half of the contract, so it is
|
|
4602
4761
|
* exercised explicitly in `tests/list-cell-slot.test.tsx`.
|
|
4603
4762
|
*
|
|
4604
|
-
* ⚠️ **Polling is no longer a reason to
|
|
4763
|
+
* ⚠️ **Polling is no longer a reason to write a list frame.** A list that needs
|
|
4605
4764
|
* fresh data declares `views.list.refetchInterval` (`@burojs/core`); the
|
|
4606
4765
|
* controller resolves it into a `live` slice and `<ResourceListPage>` renders
|
|
4607
|
-
* the pause toggle. Every adopter surface that
|
|
4608
|
-
*
|
|
4609
|
-
*
|
|
4766
|
+
* the pause toggle. Every adopter surface that replaced the body *only* to get a
|
|
4767
|
+
* `refetchInterval` gave up filters, the columns menu, saved views and URL state to buy one
|
|
4768
|
+
* option it can now declare.
|
|
4610
4769
|
*
|
|
4611
4770
|
* ⚠️ **Slots are registered through the Components registry, NOT on
|
|
4612
4771
|
* `ResourceConfig`.** `packages/core` declares `dependencies: {}` and
|
|
4613
4772
|
* imports React nowhere, and `ResourceViews` is non-generic — an inline
|
|
4614
4773
|
* `ComponentType` on the config would both drag React into core and lose
|
|
4615
|
-
* `TRecord` inference. The registry
|
|
4616
|
-
* (`
|
|
4617
|
-
* and
|
|
4774
|
+
* `TRecord` inference. The registry's keys are dotted with the canonical
|
|
4775
|
+
* resource last (`list.<region>.<resource>`, `record.<action>.<resource>`,
|
|
4776
|
+
* `layout.<key>`), and they need zero core changes.
|
|
4618
4777
|
*
|
|
4619
4778
|
* @see docs/specs/core-flexibility-overview.md §3
|
|
4620
4779
|
* @see docs/superpowers/plans/2026-07-26-cfb3-assembled-page-slots.md — Task B3.2
|
|
@@ -4628,10 +4787,8 @@ declare function ResourceList({ resource, data, total, page, pageSize, onPageSiz
|
|
|
4628
4787
|
* - `'filters'` — the filter region only (search box + dynamic filter chips
|
|
4629
4788
|
* + "+ Add filter"). Saved views, the columns toggle, the create button,
|
|
4630
4789
|
* the table, the footer and pagination all stay standard.
|
|
4631
|
-
* - `'body'` — everything below the page header: the whole toolbar row, the
|
|
4632
|
-
* saved-view dialogs, the table, the footer and the bulk bar.
|
|
4633
4790
|
*/
|
|
4634
|
-
type ListSlotRegion = 'filters' | '
|
|
4791
|
+
type ListSlotRegion = 'filters' | 'cell';
|
|
4635
4792
|
/**
|
|
4636
4793
|
* A list slot component. It takes **no props**: everything it needs — rows,
|
|
4637
4794
|
* query state, filters, sorting, columns, selection, saved views, hrefs —
|
|
@@ -4666,12 +4823,12 @@ type ListCellRenderer = NonNullable<ResourceListProps['renderCell']>;
|
|
|
4666
4823
|
* <BuroProvider components={{ [listSlot('filters', 'code_code')]: CodeFilterRegion }}>
|
|
4667
4824
|
* ```
|
|
4668
4825
|
*
|
|
4669
|
-
*
|
|
4670
|
-
* `
|
|
4671
|
-
* `
|
|
4672
|
-
*
|
|
4673
|
-
*
|
|
4674
|
-
*
|
|
4826
|
+
* The key is `list.<region>.<resource>` with the resource canonicalised, as
|
|
4827
|
+
* `canonicalResourceName` does: the bare id in the default namespace (`order` and
|
|
4828
|
+
* `default:order` name the same slot), `namespace:id` otherwise
|
|
4829
|
+
* (`list.cell.crm:deals`). Typing `region` as a union rather than a free
|
|
4830
|
+
* string is the point of the helper — a typo'd slot key is otherwise a
|
|
4831
|
+
* silent no-op, which is precisely how registry slots fail.
|
|
4675
4832
|
*/
|
|
4676
4833
|
declare function listSlot(region: ListSlotRegion, resource: string): string;
|
|
4677
4834
|
/**
|
|
@@ -4686,11 +4843,11 @@ declare function listSlot(region: ListSlotRegion, resource: string): string;
|
|
|
4686
4843
|
* call directly. A single widened return type would let `useListSlot('cell',
|
|
4687
4844
|
* r)`'s result typecheck as `<Slot />`, which compiles and then explodes at
|
|
4688
4845
|
* render (a component invoked as a 3-arg function, or vice versa). The
|
|
4689
|
-
* `'filters'
|
|
4846
|
+
* `'filters'` overload's contract is byte-identical to before this
|
|
4690
4847
|
* region existed.
|
|
4691
4848
|
*/
|
|
4692
4849
|
declare function useListSlot(region: 'cell', resource: string): ListCellRenderer | undefined;
|
|
4693
|
-
declare function useListSlot(region: 'filters'
|
|
4850
|
+
declare function useListSlot(region: 'filters', resource: string): ListSlot | undefined;
|
|
4694
4851
|
//#endregion
|
|
4695
4852
|
//#region src/saved-views/saved-views-dropdown.d.ts
|
|
4696
4853
|
/**
|
|
@@ -4781,378 +4938,67 @@ interface SavedViewsDropdownProps {
|
|
|
4781
4938
|
* 'fork-entry' → an entry's inline Fork button (viewId passed)
|
|
4782
4939
|
* 'issues-notice' → the adapter-issues banner (no viewId)
|
|
4783
4940
|
*/
|
|
4784
|
-
getTestId?: (role: 'trigger' | 'menu' | 'view-item' | 'save-current' | 'manage' | 'separator' | 'section-header' | 'rename-entry' | 'delete-entry' | 'fork-entry' | 'issues-notice', viewId?: string) => string | undefined;
|
|
4785
|
-
/** Trigger label override. Default: "Views". */
|
|
4786
|
-
triggerLabel?: string;
|
|
4787
|
-
/**
|
|
4788
|
-
* Render the trigger as a compact icon-only square button (no visible label).
|
|
4789
|
-
* `triggerLabel` becomes the `aria-label` + tooltip. The bookmark icon (the
|
|
4790
|
-
* saved-views affordance) stays.
|
|
4791
|
-
*/
|
|
4792
|
-
iconOnly?: boolean;
|
|
4793
|
-
/** className applied to the trigger button. */
|
|
4794
|
-
triggerClassName?: string;
|
|
4795
|
-
/** className applied to the popover content. */
|
|
4796
|
-
popoverContentClassName?: string;
|
|
4797
|
-
/** Popover content alignment. Default: 'start'. */
|
|
4798
|
-
popoverAlign?: 'start' | 'center' | 'end';
|
|
4799
|
-
}
|
|
4800
|
-
declare function SavedViewsDropdown({ adopterViews, entries, issues, onApply, onSaveCurrent, canSaveCurrent, onManage, onRenameEntry, onDeleteEntry, onForkEntry, canFork, getTestId, triggerLabel, iconOnly, triggerClassName, popoverContentClassName, popoverAlign }: SavedViewsDropdownProps): React.ReactElement;
|
|
4801
|
-
//#endregion
|
|
4802
|
-
//#region src/resource/list-error-state.d.ts
|
|
4803
|
-
interface ListErrorStateProps {
|
|
4804
|
-
/** Whatever the query threw. */
|
|
4805
|
-
error: {
|
|
4806
|
-
message?: string;
|
|
4807
|
-
} | Error;
|
|
4808
|
-
/** When provided, a Retry button is rendered and calls this. */
|
|
4809
|
-
onRetry?: () => void;
|
|
4810
|
-
/** Resource name, used to build the retry button's test id. */
|
|
4811
|
-
resource?: string;
|
|
4812
|
-
/** Overrides the default «Не удалось загрузить данные» heading. */
|
|
4813
|
-
title?: string;
|
|
4814
|
-
className?: string;
|
|
4815
|
-
}
|
|
4816
|
-
/**
|
|
4817
|
-
* The canonical "this list failed to load" panel: icon, heading, an
|
|
4818
|
-
* actionable sentence, and a Retry button.
|
|
4819
|
-
*
|
|
4820
|
-
* ⚠️ Extracted from `<ResourceList>` because it was trapped inside it. The
|
|
4821
|
-
* `schedules` list is rendered by a level-3 body slot, which is the whole
|
|
4822
|
-
* point of slots — but the slot then had to hand-roll its own error branch,
|
|
4823
|
-
* and hand-rolled it worse: a bare red card printing
|
|
4824
|
-
*
|
|
4825
|
-
* «Не удалось загрузить расписания. Temporal GET
|
|
4826
|
-
* /namespaces/default/schedules?maximumPageSize=10 -> 502»
|
|
4827
|
-
*
|
|
4828
|
-
* — a raw internal HTTP trace under a Russian sentence, with NO way to retry.
|
|
4829
|
-
* When Temporal was briefly down, the only recovery was reloading the page.
|
|
4830
|
-
*
|
|
4831
|
-
* A slot author should not have to re-derive an error state the framework
|
|
4832
|
-
* already knows how to render, so this is now shared by both. `toFriendlyError`
|
|
4833
|
-
* keeps the technical string out of the operator's face while leaving
|
|
4834
|
-
* adopter-written messages verbatim; the raw text stays reachable under
|
|
4835
|
-
* «Подробности» for whoever has to file the bug.
|
|
4836
|
-
*/
|
|
4837
|
-
declare function ListErrorState({ error, onRetry, resource, title, className }: ListErrorStateProps): React.ReactElement;
|
|
4838
|
-
//#endregion
|
|
4839
|
-
//#region src/resource/resource-show.d.ts
|
|
4840
|
-
interface ResourceShowProps {
|
|
4841
|
-
resource: string;
|
|
4842
|
-
record: {
|
|
4843
|
-
id: string;
|
|
4844
|
-
} & Record<string, unknown>;
|
|
4845
|
-
className?: string;
|
|
4846
|
-
/**
|
|
4847
|
-
* Slot for adopter-supplied UI rendered to the RIGHT of the resolved
|
|
4848
|
-
* `<ActionOverflow surface="show">` — NOT an action itself, just arbitrary
|
|
4849
|
-
* chrome the host wants next to the toolbar (a status badge, a link out to
|
|
4850
|
-
* another system, anything that isn't dispatched through the action
|
|
4851
|
-
* registry). Every entity already carries the built-in Edit and Delete
|
|
4852
|
-
* (plus any registry-declared actions whose surface includes `'show'`)
|
|
4853
|
-
* through `<ActionOverflow>`, so this slot no longer needs to (and must
|
|
4854
|
-
* not try to) supply page-local Edit/Delete of its own — there is nothing
|
|
4855
|
-
* left for it to fill in there. It renders directly alongside the
|
|
4856
|
-
* registry actions with no separator between them; the two are one visual
|
|
4857
|
-
* group, not two.
|
|
4858
|
-
*/
|
|
4859
|
-
extraActions?: ReactNode;
|
|
4860
|
-
/**
|
|
4861
|
-
* When true, ResourceShow renders WITHOUT its own `<PageHeader>` (no
|
|
4862
|
-
* breadcrumb / title / toolbar actions) — only the banner + field card,
|
|
4863
|
-
* still wrapped in the `page-show` testid root.
|
|
4864
|
-
*
|
|
4865
|
-
* Used by the tabbed detail shell (`ResourceShowTabs`), which hoists a
|
|
4866
|
-
* SINGLE header above the tab strip so item actions stay visible on every
|
|
4867
|
-
* tab. The non-tabbed page leaves this false and renders its own header.
|
|
4868
|
-
*/
|
|
4869
|
-
hideHeader?: boolean;
|
|
4870
|
-
/**
|
|
4871
|
-
* Optional breadcrumb override rendered in the page header IN PLACE OF the
|
|
4872
|
-
* default `<Breadcrumbs resource pageLabel>`. Pass a custom `<Breadcrumbs>`
|
|
4873
|
-
* (e.g. with `leadingSegments` + a different root `resource`) to root the
|
|
4874
|
-
* detail page at a different list — the sub-project-5 "sticky nav" uses this
|
|
4875
|
-
* so a document opened from a per-type list breadcrumbs back to that list +
|
|
4876
|
-
* section instead of the generic Documents list. Undefined → default.
|
|
4877
|
-
*/
|
|
4878
|
-
breadcrumbs?: ReactNode;
|
|
4879
|
-
/**
|
|
4880
|
-
* Optional per-context field map MERGED over the resource-level `def.fields`
|
|
4881
|
-
* — same contract as `ResourceForm`'s prop of the same name (override keys
|
|
4882
|
-
* win on collision, resource-only keys still render). Omitted → the details
|
|
4883
|
-
* panel renders `def.fields`, or the matched document type's field set when
|
|
4884
|
-
* this resource declares `templates`.
|
|
4885
|
-
*
|
|
4886
|
-
* ⚠️ Not the document-type mechanism: a templated resource resolves its own
|
|
4887
|
-
* projection from `record[templates.discriminatorField]`, replacing rather
|
|
4888
|
-
* than merging. Passing this prop turns that resolution OFF for this render.
|
|
4889
|
-
*/
|
|
4890
|
-
fieldsOverride?: ResourceFieldMap;
|
|
4891
|
-
/**
|
|
4892
|
-
* Optional layout override — same contract as `ResourceForm`'s prop of the
|
|
4893
|
-
* same name: when set, it REPLACES `views.show.fields ?? views.fields`
|
|
4894
|
-
* outright for this render.
|
|
4895
|
-
*
|
|
4896
|
-
* Precedence: this prop → the matched template's `views.fields` → the
|
|
4897
|
-
* resource's own.
|
|
4898
|
-
*/
|
|
4899
|
-
fieldsLayoutOverride?: FieldLayoutSpec;
|
|
4900
|
-
}
|
|
4901
|
-
/**
|
|
4902
|
-
* Resolve a record's display name using the resource's `displayField`,
|
|
4903
|
-
* falling back to `id`.
|
|
4904
|
-
*/
|
|
4905
|
-
declare function recordDisplayName(record: Record<string, unknown>, displayField?: string): string;
|
|
4906
|
-
/**
|
|
4907
|
-
* Per-resource banner slot. Rendered above the field card when the adopter
|
|
4908
|
-
* registers a component under `show.banner.<resource>` in the global components
|
|
4909
|
-
* map (see `mergeComponents` + `<BuroProvider components={...}>`).
|
|
4910
|
-
*
|
|
4911
|
-
* Resources that do NOT register an override get the default render — the
|
|
4912
|
-
* 22 prior e2e specs verify this backward-compat path.
|
|
4913
|
-
*/
|
|
4914
|
-
interface ResourceShowBannerProps {
|
|
4915
|
-
resource: string;
|
|
4916
|
-
record: {
|
|
4917
|
-
id: string;
|
|
4918
|
-
} & Record<string, unknown>;
|
|
4919
|
-
}
|
|
4920
|
-
/**
|
|
4921
|
-
* The show-page `<PageHeader>` (breadcrumb + title + the resolved
|
|
4922
|
-
* `<ActionOverflow surface="show">` item-action list, then any adopter
|
|
4923
|
-
* `extraActions`).
|
|
4924
|
-
*
|
|
4925
|
-
* Extracted so BOTH the non-tabbed `<ResourceShow>` (which renders it inline)
|
|
4926
|
-
* and the tabbed shell (`ResourceShowTabs`, which hoists it above the tab
|
|
4927
|
-
* strip so it stays visible on every tab) render the identical header from one
|
|
4928
|
-
* source of truth.
|
|
4929
|
-
*/
|
|
4930
|
-
declare function ShowPageHeader({ resource, record, extraActions, breadcrumbs }: {
|
|
4931
|
-
resource: string;
|
|
4932
|
-
record: {
|
|
4933
|
-
id: string;
|
|
4934
|
-
} & Record<string, unknown>;
|
|
4935
|
-
extraActions?: ReactNode;
|
|
4936
|
-
breadcrumbs?: ReactNode;
|
|
4937
|
-
}): React.ReactElement | null;
|
|
4938
|
-
declare function ResourceShow({ resource, record, className, extraActions, hideHeader, fieldsOverride, fieldsLayoutOverride, breadcrumbs }: ResourceShowProps): React.ReactElement | null;
|
|
4939
|
-
//#endregion
|
|
4940
|
-
//#region src/resource/detail-tabs-shell.d.ts
|
|
4941
|
-
interface DetailTabsShellProps {
|
|
4942
|
-
resource: string;
|
|
4943
|
-
record: {
|
|
4944
|
-
id: string;
|
|
4945
|
-
} & Record<string, unknown>;
|
|
4946
|
-
/** Which detail surface this shell serves — drives `resolveTabs(view)`. */
|
|
4947
|
-
view: TabView;
|
|
4948
|
-
/**
|
|
4949
|
-
* The currently active tab key. Resolved against the VISIBLE tab set (see
|
|
4950
|
-
* `resolveTabs`): an unknown / hidden value falls back to the `details` tab
|
|
4951
|
-
* when present, else the first visible tab. Pass `undefined` to default to
|
|
4952
|
-
* `details`.
|
|
4953
|
-
*/
|
|
4954
|
-
activeTab?: string;
|
|
4955
|
-
/**
|
|
4956
|
-
* Called when the user clicks a tab trigger. Receives the new tab key
|
|
4957
|
-
* (`details` for the field/form panel, otherwise the tab's `key`).
|
|
4958
|
-
* Consumers typically wire this to a URL search-param so deep-links /
|
|
4959
|
-
* back-forward navigation work. When omitted, the shell falls back to
|
|
4960
|
-
* internal state (uncontrolled).
|
|
4961
|
-
*/
|
|
4962
|
-
onTabChange?: (tab: string) => void;
|
|
4963
|
-
/**
|
|
4964
|
-
* Optional renderer for relation-tab list rows. Forwarded to the embedded
|
|
4965
|
-
* `<ResourceList>`'s `rowHref`. Default behaviour produces
|
|
4966
|
-
* `/{childResource}/{row.id}` so a row click navigates to the standalone
|
|
4967
|
-
* show page.
|
|
4968
|
-
*/
|
|
4969
|
-
subresourceRowHref?: (childResource: string, row: {
|
|
4970
|
-
id: string;
|
|
4971
|
-
}) => string;
|
|
4972
|
-
/**
|
|
4973
|
-
* The SINGLE page header, rendered ABOVE the tab strip and therefore always
|
|
4974
|
-
* visible regardless of the active tab. Item toolbar actions live here so
|
|
4975
|
-
* they never vanish when a non-details tab is active. Only mounted on the
|
|
4976
|
-
* tabbed path (the fast path uses `renderStandalone`'s own header).
|
|
4977
|
-
*/
|
|
4978
|
-
header: ReactNode;
|
|
4979
|
-
/**
|
|
4980
|
-
* Renders the `details` tab body WITHOUT its own header (chromeless): the
|
|
4981
|
-
* Show field card for `view: 'show'`, or the Edit form for `view: 'edit'`.
|
|
4982
|
-
*/
|
|
4983
|
-
renderDetails: () => ReactNode;
|
|
4984
|
-
/**
|
|
4985
|
-
* Renders the standalone page (WITH its own header) used on the fast path —
|
|
4986
|
-
* when the resource resolves to only the synthesized `details` tab. Keeps
|
|
4987
|
-
* the no-tabs page byte-identical to the pre-tabs component.
|
|
4988
|
-
*/
|
|
4989
|
-
renderStandalone: () => ReactNode;
|
|
4990
|
-
}
|
|
4991
|
-
/**
|
|
4992
|
-
* Shared detail-page tab shell for Show AND Edit.
|
|
4993
|
-
*
|
|
4994
|
-
* Fast path: when `resolveTabs` yields only the synthesized `details` tab (the
|
|
4995
|
-
* resource declares no tabs for this view and has no subresources), the shell
|
|
4996
|
-
* is a transparent passthrough to `renderStandalone()` — no Tabs primitive in
|
|
4997
|
-
* the tree, no visual change, and the standalone component renders its own
|
|
4998
|
-
* header exactly as before.
|
|
4999
|
-
*
|
|
5000
|
-
* Tabbed path: a single hoisted `header` renders above the `TabsList` (always
|
|
5001
|
-
* visible), the `details` tab hosts the chromeless content from
|
|
5002
|
-
* `renderDetails()`, and component / relation tabs render lazily (Radix
|
|
5003
|
-
* unmounts inactive `Tabs.Content`, so an inactive tab's `useList` / fetch
|
|
5004
|
-
* never fires until it is activated).
|
|
5005
|
-
*/
|
|
5006
|
-
declare function DetailTabsShell(props: DetailTabsShellProps): React.ReactElement | null;
|
|
5007
|
-
interface SubresourceTabBodyProps {
|
|
5008
|
-
childResource: string;
|
|
5009
|
-
foreignKey: string;
|
|
5010
|
-
parentId: string;
|
|
5011
|
-
rowHref: (row: {
|
|
5012
|
-
id: string;
|
|
5013
|
-
} & Record<string, unknown>) => string;
|
|
5014
|
-
/**
|
|
5015
|
-
* Rows per page. Default `10` — the value this component hardcoded before
|
|
5016
|
-
* the knob existed, so omitting it changes nothing.
|
|
5017
|
-
*
|
|
5018
|
-
* Excluded from the count key on purpose: see the `countKey` note below.
|
|
5019
|
-
*/
|
|
5020
|
-
pageSize?: number;
|
|
5021
|
-
/**
|
|
5022
|
-
* Extra filters **ANDed with** the parent FK filter.
|
|
5023
|
-
*
|
|
5024
|
-
* ⚠️ They never REPLACE it. The FK is what makes this list a sub-resource of
|
|
5025
|
-
* the open record; a filter array that supplanted it would silently turn a
|
|
5026
|
-
* tab that reads as "this document's codes" into a listing of every row in
|
|
5027
|
-
* the child table.
|
|
5028
|
-
*/
|
|
5029
|
-
filters?: readonly FilterExpression<ErasedResourceHandle>[];
|
|
5030
|
-
/**
|
|
5031
|
-
* Field a free-text search box targets. **Absent → no box is rendered**, the
|
|
5032
|
-
* same rule `views.list.search` follows on the standalone list page. A bare
|
|
5033
|
-
* field name, NOT a `SearchDecl` — this is TAB level, one field, no
|
|
5034
|
-
* resolver escape hatch. The term is composed via `searchToFilter` as
|
|
5035
|
-
* `{ field: search, op: 'contains' }` and ANDed onto the filters above.
|
|
5036
|
-
*/
|
|
5037
|
-
search?: string;
|
|
5038
|
-
}
|
|
5039
|
-
/**
|
|
5040
|
-
* Mounts a paginated `<ResourceList>` of `childResource` filtered to
|
|
5041
|
-
* `foreignKey === parentId`. Same internals as the standalone list page; the
|
|
5042
|
-
* FK filter is non-clearable from inside the tab (the user is in the parent's
|
|
5043
|
-
* context — clearing it would surface unrelated rows).
|
|
5044
|
-
*
|
|
5045
|
-
* Three optional knobs tune the surface — `pageSize`, `filters`, `search`
|
|
5046
|
-
* (Task B6.1, closing this component's own `TODO(v2)`). Every one of them is
|
|
5047
|
-
* absent by default, and absent means the pre-B6 behaviour to the byte: ten
|
|
5048
|
-
* rows a page, no search box, the FK as the only filter. Adopters normally
|
|
5049
|
-
* declare them on the tab (`RelationTab`) rather than here; they exist as
|
|
5050
|
-
* props because this component is exported for bespoke tab layouts.
|
|
5051
|
-
*
|
|
5052
|
-
* `sort` is deliberately NOT among them. The embedded list renders a fixed
|
|
5053
|
-
* column set with no sort affordance, so a declaration site with no reader
|
|
5054
|
-
* would be exactly the dead `views.list.filters` key the program is deleting.
|
|
5055
|
-
*
|
|
5056
|
-
* Exported so adopters composing bespoke tab layouts can reuse the embedded
|
|
5057
|
-
* filtered list without re-implementing the `useList` + FK-filter wiring.
|
|
5058
|
-
*/
|
|
5059
|
-
declare function SubresourceTabBody({ childResource, foreignKey, parentId, rowHref, pageSize, filters: extraFilters, search: searchField }: SubresourceTabBodyProps): ReactNode;
|
|
5060
|
-
//#endregion
|
|
5061
|
-
//#region src/resource/resource-show-tabs.d.ts
|
|
5062
|
-
interface ResourceShowTabsProps extends ResourceShowProps {
|
|
5063
|
-
/**
|
|
5064
|
-
* The currently active tab key. Resolved against the VISIBLE tab set (see
|
|
5065
|
-
* `resolveTabs`): an unknown / hidden value falls back to the `details` tab
|
|
5066
|
-
* when present, else the first visible tab. Pass `undefined` to default to
|
|
5067
|
-
* `details`.
|
|
5068
|
-
*/
|
|
5069
|
-
activeTab?: string;
|
|
5070
|
-
/**
|
|
5071
|
-
* Called when the user clicks a tab trigger. Receives the new tab key
|
|
5072
|
-
* (`details` for the field panel, otherwise the tab's `key` — a subresource
|
|
5073
|
-
* name for auto-relation tabs). Consumers typically wire this to a URL
|
|
5074
|
-
* search-param via the router so deep-links / back-forward navigation work.
|
|
5075
|
-
* When omitted, the component falls back to internal state (uncontrolled).
|
|
5076
|
-
*/
|
|
5077
|
-
onTabChange?: (tab: string) => void;
|
|
4941
|
+
getTestId?: (role: 'trigger' | 'menu' | 'view-item' | 'save-current' | 'manage' | 'separator' | 'section-header' | 'rename-entry' | 'delete-entry' | 'fork-entry' | 'issues-notice', viewId?: string) => string | undefined;
|
|
4942
|
+
/** Trigger label override. Default: "Views". */
|
|
4943
|
+
triggerLabel?: string;
|
|
5078
4944
|
/**
|
|
5079
|
-
*
|
|
5080
|
-
*
|
|
5081
|
-
*
|
|
5082
|
-
* show page (the "shows in tab AND has standalone pages" contract).
|
|
4945
|
+
* Render the trigger as a compact icon-only square button (no visible label).
|
|
4946
|
+
* `triggerLabel` becomes the `aria-label` + tooltip. The bookmark icon (the
|
|
4947
|
+
* saved-views affordance) stays.
|
|
5083
4948
|
*/
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
4949
|
+
iconOnly?: boolean;
|
|
4950
|
+
/** className applied to the trigger button. */
|
|
4951
|
+
triggerClassName?: string;
|
|
4952
|
+
/** className applied to the popover content. */
|
|
4953
|
+
popoverContentClassName?: string;
|
|
4954
|
+
/** Popover content alignment. Default: 'start'. */
|
|
4955
|
+
popoverAlign?: 'start' | 'center' | 'end';
|
|
5087
4956
|
}
|
|
5088
|
-
|
|
5089
|
-
* Renders `<ResourceShow>` with a declarative tab strip resolved by the core
|
|
5090
|
-
* `resolveTabs` helper — Details (the field panel) + any `component` /
|
|
5091
|
-
* `relation` tabs declared on the resource / template, plus auto-generated
|
|
5092
|
-
* relation tabs for every registered subresource.
|
|
5093
|
-
*
|
|
5094
|
-
* The page header (breadcrumb + the resolved `<ActionOverflow surface="show">`
|
|
5095
|
-
* item-action list, then adopter `extraActions`) is hoisted ABOVE the tab strip by the
|
|
5096
|
-
* shared `DetailTabsShell`, so item actions stay visible on every tab. The
|
|
5097
|
-
* `details` tab therefore renders `<ResourceShow>` chromeless (`hideHeader`).
|
|
5098
|
-
*
|
|
5099
|
-
* Fast path: when the resource declares no `tabs`, has no subresources, and
|
|
5100
|
-
* `resolveTabs` yields only the synthesized `details` tab, this is a
|
|
5101
|
-
* transparent passthrough to a plain `<ResourceShow>` (own header, no Tabs
|
|
5102
|
-
* primitive in the tree, no visual change).
|
|
5103
|
-
*/
|
|
5104
|
-
declare function ResourceShowTabs(props: ResourceShowTabsProps): React.ReactElement | null;
|
|
4957
|
+
declare function SavedViewsDropdown({ adopterViews, entries, issues, onApply, onSaveCurrent, canSaveCurrent, onManage, onRenameEntry, onDeleteEntry, onForkEntry, canFork, getTestId, triggerLabel, iconOnly, triggerClassName, popoverContentClassName, popoverAlign }: SavedViewsDropdownProps): React.ReactElement;
|
|
5105
4958
|
//#endregion
|
|
5106
|
-
//#region src/resource/
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
/**
|
|
5120
|
-
* Resolved component for this tab's slot — looked up via
|
|
5121
|
-
* `useComponent('tab.<key>')` by the caller. `undefined` when the slot is
|
|
5122
|
-
* unregistered; `<TabBody>` then renders a graceful empty state instead of
|
|
5123
|
-
* crashing the page.
|
|
5124
|
-
*/
|
|
5125
|
-
component?: ComponentType<TabComponentProps>;
|
|
5126
|
-
resource: string;
|
|
5127
|
-
record: {
|
|
5128
|
-
id: string;
|
|
5129
|
-
} & Record<string, unknown>;
|
|
5130
|
-
}
|
|
5131
|
-
interface TabBodyState {
|
|
5132
|
-
error: Error | null;
|
|
4959
|
+
//#region src/resource/list-error-state.d.ts
|
|
4960
|
+
interface ListErrorStateProps {
|
|
4961
|
+
/** Whatever the query threw. */
|
|
4962
|
+
error: {
|
|
4963
|
+
message?: string;
|
|
4964
|
+
} | Error;
|
|
4965
|
+
/** When provided, a Retry button is rendered and calls this. */
|
|
4966
|
+
onRetry?: () => void;
|
|
4967
|
+
/** Resource name, used to build the retry button's test id. */
|
|
4968
|
+
resource?: string;
|
|
4969
|
+
/** Overrides the default «Не удалось загрузить данные» heading. */
|
|
4970
|
+
title?: string;
|
|
4971
|
+
className?: string;
|
|
5133
4972
|
}
|
|
5134
4973
|
/**
|
|
5135
|
-
*
|
|
4974
|
+
* The canonical "this list failed to load" panel: icon, heading, an
|
|
4975
|
+
* actionable sentence, and a Retry button.
|
|
5136
4976
|
*
|
|
5137
|
-
*
|
|
4977
|
+
* ⚠️ Extracted from `<ResourceList>` because it was trapped inside it. The
|
|
4978
|
+
* `schedules` list is rendered by a level-3 body slot, which is the whole
|
|
4979
|
+
* point of slots — but the slot then had to hand-roll its own error branch,
|
|
4980
|
+
* and hand-rolled it worse: a bare red card printing
|
|
5138
4981
|
*
|
|
5139
|
-
*
|
|
5140
|
-
*
|
|
5141
|
-
*
|
|
5142
|
-
*
|
|
5143
|
-
*
|
|
5144
|
-
* shows until it resolves. Radix `Tabs.Content` unmounts inactive tabs, so a
|
|
5145
|
-
* lazy body's `useList` / fetch never fires until its tab is activated.
|
|
5146
|
-
* - **Empty state**: when the slot is unregistered (`component` is undefined)
|
|
5147
|
-
* the wrapper renders a muted placeholder rather than throwing.
|
|
4982
|
+
* «Не удалось загрузить расписания. Temporal GET
|
|
4983
|
+
* /namespaces/default/schedules?maximumPageSize=10 -> 502»
|
|
4984
|
+
*
|
|
4985
|
+
* — a raw internal HTTP trace under a Russian sentence, with NO way to retry.
|
|
4986
|
+
* When Temporal was briefly down, the only recovery was reloading the page.
|
|
5148
4987
|
*
|
|
5149
|
-
*
|
|
4988
|
+
* A slot author should not have to re-derive an error state the framework
|
|
4989
|
+
* already knows how to render, so this is now shared by both. `toFriendlyError`
|
|
4990
|
+
* keeps the technical string out of the operator's face while leaving
|
|
4991
|
+
* adopter-written messages verbatim; the raw text stays reachable under
|
|
4992
|
+
* «Подробности» for whoever has to file the bug.
|
|
5150
4993
|
*/
|
|
5151
|
-
declare
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
4994
|
+
declare function ListErrorState({ error, onRetry, resource, title, className }: ListErrorStateProps): React.ReactElement;
|
|
4995
|
+
//#endregion
|
|
4996
|
+
//#region src/resource/record-display-name.d.ts
|
|
4997
|
+
/**
|
|
4998
|
+
* A record's display name: its `displayField` value when present and non-empty, else its `id`.
|
|
4999
|
+
* Exported for consumers building delete dialogs, breadcrumbs and relation labels.
|
|
5000
|
+
*/
|
|
5001
|
+
declare function recordDisplayName(record: Record<string, unknown>, displayField?: string): string;
|
|
5156
5002
|
//#endregion
|
|
5157
5003
|
//#region src/resource/page-header.d.ts
|
|
5158
5004
|
interface PageHeaderProps {
|
|
@@ -5160,10 +5006,10 @@ interface PageHeaderProps {
|
|
|
5160
5006
|
resource: string;
|
|
5161
5007
|
/**
|
|
5162
5008
|
* Page mode. Drives default title:
|
|
5163
|
-
* - 'list' →
|
|
5164
|
-
* - 'show' → label
|
|
5165
|
-
* - 'edit' → 'Edit ' + label
|
|
5166
|
-
* - 'create' → 'Create ' + label
|
|
5009
|
+
* - 'list' → labelPlural
|
|
5010
|
+
* - 'show' → label + ': ' + recordName
|
|
5011
|
+
* - 'edit' → 'Edit ' + label + ': ' + recordName
|
|
5012
|
+
* - 'create' → 'Create ' + label
|
|
5167
5013
|
*/
|
|
5168
5014
|
mode: 'list' | 'show' | 'edit' | 'create';
|
|
5169
5015
|
/** Display name of the current record (for show/edit). */
|
|
@@ -5173,7 +5019,7 @@ interface PageHeaderProps {
|
|
|
5173
5019
|
* (or `/{resource}` fallback) for show/edit/create.
|
|
5174
5020
|
*/
|
|
5175
5021
|
backHref?: string;
|
|
5176
|
-
/** Override the back-link label. Defaults to
|
|
5022
|
+
/** Override the back-link label. Defaults to labelPlural. */
|
|
5177
5023
|
backLabel?: string;
|
|
5178
5024
|
/** Slot for action buttons (Edit/Delete/+Create) on the right. */
|
|
5179
5025
|
actions?: ReactNode;
|
|
@@ -5184,7 +5030,7 @@ interface PageHeaderProps {
|
|
|
5184
5030
|
* the back-link is suppressed in favour of the breadcrumb (the two
|
|
5185
5031
|
* are functionally redundant — a breadcrumb's leading link points
|
|
5186
5032
|
* at the same URL as the back-link, with more spatial context).
|
|
5187
|
-
* Pass `<Breadcrumbs pageLabel={recordName} />` from
|
|
5033
|
+
* Pass `<Breadcrumbs resource={resource} pageLabel={recordName} />` from
|
|
5188
5034
|
* `@burojs/ui-shadcn` for the canonical resource-rooted layout.
|
|
5189
5035
|
*/
|
|
5190
5036
|
breadcrumbs?: ReactNode;
|
|
@@ -5223,239 +5069,43 @@ interface PageHeaderProps {
|
|
|
5223
5069
|
className?: string;
|
|
5224
5070
|
}
|
|
5225
5071
|
declare function PageHeader({ resource, mode, recordName, backHref, backLabel, actions, title, breadcrumbs, backLink, visibleTitle, labelOverride, className }: PageHeaderProps): React.ReactElement | null;
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5072
|
+
/**
|
|
5073
|
+
* The show-page `<PageHeader>`: the breadcrumb, the record's title and the resolved
|
|
5074
|
+
* `<ActionOverflow surface="show">` item-action list, then any `extraActions`.
|
|
5075
|
+
*/
|
|
5076
|
+
declare function ShowPageHeader({ resource, record, extraActions, breadcrumbs }: {
|
|
5229
5077
|
resource: string;
|
|
5230
5078
|
record: {
|
|
5231
5079
|
id: string;
|
|
5232
5080
|
} & Record<string, unknown>;
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
/** Override the back-link href (defaults to the show page for this record). */
|
|
5237
|
-
backHref?: string;
|
|
5238
|
-
/**
|
|
5239
|
-
* Optional per-template field map. Forwarded to ResourceForm; keys override
|
|
5240
|
-
* the resource-level `def.fields` on collision. Used by the document-
|
|
5241
|
-
* templates v1 wiring on the playground edit page.
|
|
5242
|
-
*/
|
|
5243
|
-
fieldsOverride?: ResourceFieldMap;
|
|
5244
|
-
/**
|
|
5245
|
-
* Optional per-template layout override forwarded to ResourceForm. See
|
|
5246
|
-
* `ResourceFormProps.fieldsLayoutOverride` — pass the matched template's
|
|
5247
|
-
* `views?.fields` alongside `fieldsOverride`.
|
|
5248
|
-
*/
|
|
5249
|
-
fieldsLayoutOverride?: FieldLayoutSpec;
|
|
5250
|
-
/**
|
|
5251
|
-
* Optional derived-value map forwarded to ResourceForm. See
|
|
5252
|
-
* `ResourceFormProps.derive`. On edit, a target that already holds a saved
|
|
5253
|
-
* value is never auto-overwritten.
|
|
5254
|
-
*/
|
|
5255
|
-
derive?: Record<string, (values: Record<string, unknown>) => unknown>;
|
|
5256
|
-
/**
|
|
5257
|
-
* When true, ResourceEdit renders WITHOUT its own `<PageHeader>` — only the
|
|
5258
|
-
* form, still wrapped in the `page-edit` testid root.
|
|
5259
|
-
*
|
|
5260
|
-
* Used by the tabbed detail shell (`ResourceEditTabs`), which hoists a
|
|
5261
|
-
* SINGLE header above the tab strip so edit-surface item actions stay
|
|
5262
|
-
* visible on every tab. The non-tabbed page leaves this false.
|
|
5263
|
-
*/
|
|
5264
|
-
hideHeader?: boolean;
|
|
5265
|
-
}
|
|
5081
|
+
extraActions?: ReactNode;
|
|
5082
|
+
breadcrumbs?: ReactNode;
|
|
5083
|
+
}): React.ReactElement | null;
|
|
5266
5084
|
/**
|
|
5267
|
-
* The edit-page `<PageHeader
|
|
5268
|
-
* `<ActionOverflow surface="edit">` item-action list
|
|
5269
|
-
*
|
|
5270
|
-
* Extracted so BOTH the non-tabbed `<ResourceEdit>` (which renders it inline)
|
|
5271
|
-
* and the tabbed shell (`ResourceEditTabs`, which hoists it above the tab
|
|
5272
|
-
* strip) render the identical header from one source of truth.
|
|
5085
|
+
* The edit-page `<PageHeader>`: the back-link, the record's title and the resolved
|
|
5086
|
+
* `<ActionOverflow surface="edit">` item-action list.
|
|
5273
5087
|
*/
|
|
5274
|
-
declare function EditPageHeader({ resource, record, backHref }: {
|
|
5088
|
+
declare function EditPageHeader({ resource, record, backHref, breadcrumbs }: {
|
|
5275
5089
|
resource: string;
|
|
5276
5090
|
record: {
|
|
5277
5091
|
id: string;
|
|
5278
5092
|
} & Record<string, unknown>;
|
|
5279
5093
|
backHref?: string;
|
|
5094
|
+
breadcrumbs?: ReactNode;
|
|
5280
5095
|
}): React.ReactElement;
|
|
5281
|
-
declare function ResourceEdit({ resource, record, onSave, onCancel, className, backHref, fieldsOverride, fieldsLayoutOverride, derive, hideHeader }: ResourceEditProps): React.ReactElement;
|
|
5282
|
-
//#endregion
|
|
5283
|
-
//#region src/resource/resource-edit-tabs.d.ts
|
|
5284
|
-
interface ResourceEditTabsProps extends ResourceEditProps {
|
|
5285
|
-
/**
|
|
5286
|
-
* The currently active tab key. Resolved against the VISIBLE tab set (see
|
|
5287
|
-
* `resolveTabs`): an unknown / hidden value falls back to the `details` tab
|
|
5288
|
-
* (the form) when present, else the first visible tab. Pass `undefined` to
|
|
5289
|
-
* default to `details`.
|
|
5290
|
-
*/
|
|
5291
|
-
activeTab?: string;
|
|
5292
|
-
/**
|
|
5293
|
-
* Called when the user clicks a tab trigger. Receives the new tab key
|
|
5294
|
-
* (`details` for the form panel, otherwise the tab's `key`). Consumers
|
|
5295
|
-
* typically wire this to a URL search-param so deep-links / back-forward
|
|
5296
|
-
* navigation work. When omitted, falls back to internal state.
|
|
5297
|
-
*/
|
|
5298
|
-
onTabChange?: (tab: string) => void;
|
|
5299
|
-
/**
|
|
5300
|
-
* Optional renderer for relation-tab list rows. Forwarded to the embedded
|
|
5301
|
-
* `<ResourceList>`'s `rowHref`. Default behaviour produces
|
|
5302
|
-
* `/{childResource}/{row.id}`.
|
|
5303
|
-
*/
|
|
5304
|
-
subresourceRowHref?: (childResource: string, row: {
|
|
5305
|
-
id: string;
|
|
5306
|
-
}) => string;
|
|
5307
|
-
}
|
|
5308
|
-
/**
|
|
5309
|
-
* Renders `<ResourceEdit>` with a declarative tab strip resolved by the core
|
|
5310
|
-
* `resolveTabs` helper for the `'edit'` surface — the `details` tab hosts the
|
|
5311
|
-
* FORM, alongside any `component` / `relation` tabs declared on the resource /
|
|
5312
|
-
* template (and auto-generated relation tabs for every registered
|
|
5313
|
-
* subresource).
|
|
5314
|
-
*
|
|
5315
|
-
* The page header (back-link + the resolved `<ActionOverflow surface="edit">`
|
|
5316
|
-
* item-action list) is hoisted ABOVE the tab strip by the shared `DetailTabsShell`, so
|
|
5317
|
-
* edit-surface item actions stay visible on every tab. The `details` tab
|
|
5318
|
-
* therefore renders `<ResourceEdit>` chromeless (`hideHeader`).
|
|
5319
|
-
*
|
|
5320
|
-
* Fast path: when the resource declares no edit tabs and has no subresources,
|
|
5321
|
-
* this is a transparent passthrough to a plain `<ResourceEdit>` (own header,
|
|
5322
|
-
* no Tabs primitive in the tree).
|
|
5323
|
-
*/
|
|
5324
|
-
declare function ResourceEditTabs(props: ResourceEditTabsProps): React.ReactElement | null;
|
|
5325
|
-
//#endregion
|
|
5326
|
-
//#region src/resource/resource-create.d.ts
|
|
5327
|
-
interface ResourceCreateProps {
|
|
5328
|
-
resource: string;
|
|
5329
|
-
defaults?: Record<string, unknown>;
|
|
5330
|
-
onCreate: (values: Record<string, unknown>) => Promise<void>;
|
|
5331
|
-
onCancel?: () => void;
|
|
5332
|
-
className?: string;
|
|
5333
|
-
/** Override the back-link href (defaults to the resource list page). */
|
|
5334
|
-
backHref?: string;
|
|
5335
|
-
/**
|
|
5336
|
-
* Optional per-template field map. Forwarded to ResourceForm; keys override
|
|
5337
|
-
* the resource-level `def.fields` on collision. Used by the document-
|
|
5338
|
-
* templates v1 wiring on the playground create page.
|
|
5339
|
-
*/
|
|
5340
|
-
fieldsOverride?: ResourceFieldMap;
|
|
5341
|
-
/**
|
|
5342
|
-
* Optional per-template layout override forwarded to ResourceForm. See
|
|
5343
|
-
* `ResourceFormProps.fieldsLayoutOverride` — pass the matched template's
|
|
5344
|
-
* `views?.fields` alongside `fieldsOverride`.
|
|
5345
|
-
*/
|
|
5346
|
-
fieldsLayoutOverride?: FieldLayoutSpec;
|
|
5347
|
-
/**
|
|
5348
|
-
* Optional derived-value map forwarded to ResourceForm. See
|
|
5349
|
-
* `ResourceFormProps.derive` — powers e.g. the preprint auto-name.
|
|
5350
|
-
*/
|
|
5351
|
-
derive?: Record<string, (values: Record<string, unknown>) => unknown>;
|
|
5352
|
-
/**
|
|
5353
|
-
* Names what is being created, when the page knows something more specific
|
|
5354
|
-
* than the resource label. A document create launched as `?type=order_code`
|
|
5355
|
-
* should read «Создать: Заказ кодов», not the generic «Создать: Документ» —
|
|
5356
|
-
* the user picked a type one screen ago and the title should confirm it.
|
|
5357
|
-
* Omitted → the resource label is used, exactly as before.
|
|
5358
|
-
*/
|
|
5359
|
-
typeLabel?: string;
|
|
5360
|
-
}
|
|
5361
|
-
declare function ResourceCreate({ resource, defaults, onCreate, onCancel, className, backHref, fieldsOverride, fieldsLayoutOverride, derive, typeLabel }: ResourceCreateProps): React.ReactElement;
|
|
5362
|
-
//#endregion
|
|
5363
|
-
//#region src/resource/document-type-picker.d.ts
|
|
5364
|
-
/** Text a host may substitute for a type's frozen declaration literals. */
|
|
5365
|
-
interface DocumentTypeText {
|
|
5366
|
-
label?: string;
|
|
5367
|
-
description?: string;
|
|
5368
|
-
}
|
|
5369
|
-
interface DocumentTypePickerProps {
|
|
5370
|
-
/** The templated resource whose types are on offer. */
|
|
5371
|
-
resource: string;
|
|
5372
|
-
/**
|
|
5373
|
-
* Called with the chosen type. Each card is a `<button>` when this is the
|
|
5374
|
-
* only handler given.
|
|
5375
|
-
*/
|
|
5376
|
-
onSelect?: (template: DocumentTemplate) => void;
|
|
5377
|
-
/**
|
|
5378
|
-
* Per-type href. Given this, each card is an anchor rendered through the
|
|
5379
|
-
* installed `LinkComponent`, so it keeps SPA routing, middle-click and
|
|
5380
|
-
* "open in new tab" — which a button cannot. Both may be passed: the
|
|
5381
|
-
* anchor navigates and `onSelect` still fires.
|
|
5382
|
-
*/
|
|
5383
|
-
hrefFor?: (template: DocumentTemplate) => string;
|
|
5384
|
-
/**
|
|
5385
|
-
* Substitute the declared `label` / `description` for one type — the seam
|
|
5386
|
-
* for translated text. A resource declaration's literals are frozen at boot,
|
|
5387
|
-
* so this is where a host hands back what it resolved from its i18n bundle.
|
|
5388
|
-
* Anything omitted falls back to the declaration.
|
|
5389
|
-
*/
|
|
5390
|
-
localize?: (template: DocumentTemplate) => DocumentTypeText;
|
|
5391
|
-
/** Rendered when no type is on offer. Defaults to nothing at all. */
|
|
5392
|
-
emptyState?: React$1.ReactNode;
|
|
5393
|
-
className?: string;
|
|
5394
|
-
}
|
|
5395
|
-
/**
|
|
5396
|
-
* The create-page type picker: one card per document type a user may be
|
|
5397
|
-
* offered right now.
|
|
5398
|
-
*
|
|
5399
|
-
* **This is where four of `DocumentTemplate`'s keys are read.** `visible`
|
|
5400
|
-
* decides which types appear (through `useVisibleTemplates`, so the set
|
|
5401
|
-
* narrows the moment scope moves — a type declared
|
|
5402
|
-
* `visible: (ctx) => ctx.scope?.market !== 'EU'` leaves the offer when the
|
|
5403
|
-
* market becomes EU, with no code here that knows what a market is). `icon`
|
|
5404
|
-
* and `color` render the chip. `description` renders under the title. Until
|
|
5405
|
-
* SP6 task 3 the framework shipped a `DocumentTemplate` type describing this
|
|
5406
|
-
* component's card and no component: every adopter declaring types had to
|
|
5407
|
-
* write the picker themselves, and the three presentational keys did nothing
|
|
5408
|
-
* whatsoever in anyone's app.
|
|
5409
|
-
*
|
|
5410
|
-
* **It offers, it does not navigate and it does not authorize.** The host
|
|
5411
|
-
* decides what choosing a type means — usually pushing `?type=<type>` at its
|
|
5412
|
-
* own create route — because the URL contract belongs to the application's
|
|
5413
|
-
* router, not to a library component. And `visible` gates the OFFER only: a
|
|
5414
|
-
* hand-typed URL naming a hidden type still renders that type's form, exactly
|
|
5415
|
-
* as `ResourceConfig.visible` gates navigation rather than routes. Where the
|
|
5416
|
-
* boundary has to hold, declare a capability rule.
|
|
5417
|
-
*/
|
|
5418
|
-
declare function DocumentTypePicker({ resource, onSelect, hrefFor, localize, emptyState, className }: DocumentTypePickerProps): React$1.ReactElement | null;
|
|
5419
|
-
//#endregion
|
|
5420
|
-
//#region src/resource/unsupported-document-type.d.ts
|
|
5421
|
-
interface UnsupportedDocumentTypeProps {
|
|
5422
|
-
/** The templated resource whose declaration refused this value. */
|
|
5423
|
-
resource: string;
|
|
5424
|
-
/** The unrecognised discriminator value, or `null` when the record had none. */
|
|
5425
|
-
typeValue: string | null;
|
|
5426
|
-
className?: string;
|
|
5427
|
-
}
|
|
5428
|
-
/**
|
|
5429
|
-
* What `ResourceConfig.templates.fallback: 'unsupported'` renders.
|
|
5430
|
-
*
|
|
5431
|
-
* **This panel is a refusal, not an error.** The resource has declared that a
|
|
5432
|
-
* record whose document type it does not know must be named rather than
|
|
5433
|
-
* guessed at: rendering the host resource's whole field map instead would show
|
|
5434
|
-
* a person the union of every type's columns and let them believe that is what
|
|
5435
|
-
* the record is. A resource that would rather show that union simply omits
|
|
5436
|
-
* `fallback`, which is the default and changes nothing.
|
|
5437
|
-
*
|
|
5438
|
-
* The strings are the framework's own `create.unsupportedType` /
|
|
5439
|
-
* `create.unsupportedTypeHint`, in both shipped locales. They were added for
|
|
5440
|
-
* the one application that hand-wrote this panel, and until now that
|
|
5441
|
-
* application was their only reader — the same "the wiring works and its only
|
|
5442
|
-
* caller leaves" shape this component exists to close. The `create.` namespace
|
|
5443
|
-
* is now a misnomer (the show surface renders them too) and is kept anyway:
|
|
5444
|
-
* renaming would silently drop any adopter bundle that already shadows those
|
|
5445
|
-
* keys.
|
|
5446
|
-
*
|
|
5447
|
-
* `typeValue === null` — the record carries no discriminator at all — still
|
|
5448
|
-
* lands here, with the hint naming an empty type. See
|
|
5449
|
-
* `resolveTemplateProjection` for why the two are one outcome.
|
|
5450
|
-
*/
|
|
5451
|
-
declare function UnsupportedDocumentType({ resource, typeValue, className }: UnsupportedDocumentTypeProps): React$1.ReactElement;
|
|
5452
5096
|
//#endregion
|
|
5453
5097
|
//#region src/resource/create-button.d.ts
|
|
5454
5098
|
interface CreateButtonProps {
|
|
5455
5099
|
/** Resource this creates. Required — the button gates itself. */
|
|
5456
5100
|
resource: string;
|
|
5457
|
-
/** Target create route, e.g. `resourceCreateHref(def, resource)`. */
|
|
5101
|
+
/** Target create route, e.g. `resourceCreateHref(def, resource)`. Ignored with `onOpen`. */
|
|
5458
5102
|
href: string;
|
|
5103
|
+
/**
|
|
5104
|
+
* Opens the create somewhere other than a route — a resource without a create page opens its
|
|
5105
|
+
* `quick.create` (P3-19). The control is then a button, drawn when the entry gate answers
|
|
5106
|
+
* `open` (inert with its reason when `disabled`, absent otherwise, and while access loads).
|
|
5107
|
+
*/
|
|
5108
|
+
onOpen?: () => void;
|
|
5459
5109
|
/** `data-testid` for the button. */
|
|
5460
5110
|
testid?: string;
|
|
5461
5111
|
size?: ButtonProps['size'];
|
|
@@ -5476,119 +5126,14 @@ interface CreateButtonProps {
|
|
|
5476
5126
|
* nothing for `absent`/`hidden`, a focusable `aria-disabled` control with a
|
|
5477
5127
|
* toast reason for `disabled`, and the normal link for `available`.
|
|
5478
5128
|
*/
|
|
5479
|
-
declare function CreateButton({ resource, href, testid, size, variant, label, className }: CreateButtonProps): React.ReactElement | null;
|
|
5480
|
-
//#endregion
|
|
5481
|
-
//#region src/resource/resource-form.d.ts
|
|
5482
|
-
interface ResourceFormProps {
|
|
5483
|
-
resource: string;
|
|
5484
|
-
view: 'edit' | 'create';
|
|
5485
|
-
recordId?: string;
|
|
5486
|
-
initialValues: Record<string, unknown>;
|
|
5487
|
-
onSubmit: (values: Record<string, unknown>) => Promise<void>;
|
|
5488
|
-
onCancel?: () => void;
|
|
5489
|
-
className?: string;
|
|
5490
|
-
submitLabel?: string;
|
|
5491
|
-
/**
|
|
5492
|
-
* Optional per-context field map MERGED over the resource-level
|
|
5493
|
-
* `def.fields`. Keys present here win over keys of the same name on the
|
|
5494
|
-
* resource; keys only on the resource still render. It means "specialize or
|
|
5495
|
-
* add these keys for this render".
|
|
5496
|
-
*
|
|
5497
|
-
* ⚠️ **This is not how a document type projects its field set.** A templated
|
|
5498
|
-
* resource resolves that itself — the form reads
|
|
5499
|
-
* `initialValues[templates.discriminatorField]`, matches the template and
|
|
5500
|
-
* renders the template's OWN field map (a replacement, not a merge). Passing
|
|
5501
|
-
* `fieldsOverride` turns that resolution OFF for this render, because an
|
|
5502
|
-
* explicit map outranks an inferred one. Adopters wiring a template by hand
|
|
5503
|
-
* (as the since-deleted `apps/playground` did before the resolution was
|
|
5504
|
-
* promoted) therefore
|
|
5505
|
-
* keep exactly the behaviour they had.
|
|
5506
|
-
*/
|
|
5507
|
-
fieldsOverride?: ResourceFieldMap;
|
|
5508
|
-
/**
|
|
5509
|
-
* Optional layout override for the shared `views.fields` declaration — the
|
|
5510
|
-
* same idea as `fieldsOverride`, one tier up: when set, it REPLACES
|
|
5511
|
-
* `views.form.fields ?? views.fields` outright for this render.
|
|
5512
|
-
*
|
|
5513
|
-
* Precedence: this prop → the matched template's `views.fields` → the
|
|
5514
|
-
* resource's own. A template's declared order wins over the resource's
|
|
5515
|
-
* because merging two orders has no meaning anyone could predict.
|
|
5516
|
-
*
|
|
5517
|
-
* Ignored when `fieldsFilter` is set — a wizard step's hand-picked order
|
|
5518
|
-
* already wins outright over any shared layout declaration.
|
|
5519
|
-
*/
|
|
5520
|
-
fieldsLayoutOverride?: FieldLayoutSpec;
|
|
5521
|
-
/**
|
|
5522
|
-
* Optional whitelist of field names to render. When set, only the listed
|
|
5523
|
-
* fields are visible inside the form (in array order); every other field
|
|
5524
|
-
* declared on the resource is hidden. Used by `<ResourceWizard>` to
|
|
5525
|
-
* project a slice of the resource's field set into a single step.
|
|
5526
|
-
*
|
|
5527
|
-
* Differs from `fieldsOverride` (which adds / replaces fields). Permission
|
|
5528
|
-
* (`visible`) gates and the create-view "system field" rule still apply
|
|
5529
|
-
* on top of this filter — a field listed here that fails `visible(ctx)`
|
|
5530
|
-
* still does not render.
|
|
5531
|
-
*
|
|
5532
|
-
* Empty array (`[]`) renders zero inputs (the canonical
|
|
5533
|
-
* "summary / confirm" wizard step shape). Field names not present on
|
|
5534
|
-
* the resource def are silently ignored at render time.
|
|
5535
|
-
*/
|
|
5536
|
-
fieldsFilter?: string[];
|
|
5537
|
-
/**
|
|
5538
|
-
* Optional override of the form-level cross-field validator. When
|
|
5539
|
-
* provided, this validator runs in place of the resource's own
|
|
5540
|
-
* `def.validate`. Used by `<ResourceWizard>` to attach step-level
|
|
5541
|
-
* validation that wraps the form's normal lifecycle. Adopters who
|
|
5542
|
-
* just want the resource-level validate should leave this undefined.
|
|
5543
|
-
*/
|
|
5544
|
-
validateOverride?: ResourceValidator;
|
|
5545
|
-
/**
|
|
5546
|
-
* Optional override of the submit button's label. When omitted the
|
|
5547
|
-
* form falls back to `submitLabel` (existing prop) and then to the
|
|
5548
|
-
* default ('Save' / 'Create' depending on view).
|
|
5549
|
-
*/
|
|
5550
|
-
hideCancelButton?: boolean;
|
|
5551
|
-
/**
|
|
5552
|
-
* @internal
|
|
5553
|
-
* Optional callback that mirrors in-progress field values to a parent.
|
|
5554
|
-
* The form invokes this AFTER each setFieldValue, but deferred to a
|
|
5555
|
-
* microtask via queueMicrotask() so the parent's setState (if any) does
|
|
5556
|
-
* not interleave with the form's own state updates.
|
|
5557
|
-
*
|
|
5558
|
-
* Used by ResourceWizard to mirror typed-but-not-yet-Next-ed values
|
|
5559
|
-
* across step boundaries. Adopters generally should not need this; if
|
|
5560
|
-
* they do, they MUST tolerate the microtask deferral and any throw
|
|
5561
|
-
* inside the callback (errors are caught + console.error'd, but the
|
|
5562
|
-
* form continues).
|
|
5563
|
-
*
|
|
5564
|
-
* Stable reference is NOT required — ResourceForm reads via the
|
|
5565
|
-
* latest render's prop, not a memoized closure.
|
|
5566
|
-
*/
|
|
5567
|
-
onValuesChange?: (values: Record<string, unknown>) => void;
|
|
5568
|
-
/**
|
|
5569
|
-
* Optional derived-value map: `targetField → (values) => computed`. Each
|
|
5570
|
-
* target is auto-filled from the other live form values UNTIL the user edits
|
|
5571
|
-
* it directly — or it already carried a value on mount (an edit form with a
|
|
5572
|
-
* saved value is never auto-overwritten). A nullish/empty computed value
|
|
5573
|
-
* never overwrites. This is the framework mechanism behind the preprint
|
|
5574
|
-
* auto-name («<gtin> x <quantity> (<name>)»), replacing a bespoke per-form
|
|
5575
|
-
* effect — same spirit as the `visible(ctx, values)` predicates, but writing
|
|
5576
|
-
* a value instead of gating render.
|
|
5577
|
-
*
|
|
5578
|
-
* ⚠️ A templated resource resolves this itself: the matched document type's
|
|
5579
|
-
* own `derive` map applies with no prop passed at all. This prop OVERRIDES
|
|
5580
|
-
* that map wholesale for the render — it does not merge with it.
|
|
5581
|
-
*/
|
|
5582
|
-
derive?: Record<string, (values: Record<string, unknown>) => unknown>;
|
|
5583
|
-
}
|
|
5584
|
-
declare function ResourceForm(props: ResourceFormProps): React.ReactElement | null;
|
|
5129
|
+
declare function CreateButton({ resource, href, testid, size, variant, label, className, onOpen }: CreateButtonProps): React.ReactElement | null;
|
|
5585
5130
|
//#endregion
|
|
5586
5131
|
//#region src/resource/form-context.d.ts
|
|
5587
5132
|
/**
|
|
5588
5133
|
* Minimal form-control handle exposed to field renderers so a field can update
|
|
5589
5134
|
* SIBLING fields (a field renderer otherwise only sees its own value). Used for
|
|
5590
5135
|
* reactive prefills — e.g. picking a product on a GTIN field also fills the
|
|
5591
|
-
* «Название товара» / «Тип кода» fields (#2). `<
|
|
5136
|
+
* «Название товара» / «Тип кода» fields (#2). `<RecordScreen>` provides it.
|
|
5592
5137
|
*/
|
|
5593
5138
|
interface FormControl {
|
|
5594
5139
|
/** Merge a patch of `{ fieldName: value }` into the form's live values. */
|
|
@@ -5597,74 +5142,6 @@ interface FormControl {
|
|
|
5597
5142
|
/** Read the surrounding form's control handle, or `null` outside a form. */
|
|
5598
5143
|
declare function useFormControl(): FormControl | null;
|
|
5599
5144
|
//#endregion
|
|
5600
|
-
//#region src/resource/resource-wizard.d.ts
|
|
5601
|
-
interface ResourceWizardProps<TValues = Record<string, unknown>> {
|
|
5602
|
-
/** Wizard definition produced by `defineResourceWizard`. */
|
|
5603
|
-
def: ResourceWizardDef<TValues>;
|
|
5604
|
-
/** Optional initial form values (seeded into step 1). */
|
|
5605
|
-
initialValues?: Partial<TValues>;
|
|
5606
|
-
/**
|
|
5607
|
-
* Called once when the user clicks Submit on the LAST step AND every
|
|
5608
|
-
* step's validators (per-field + step-level + form-level) pass. Receives
|
|
5609
|
-
* the full accumulated values across every step.
|
|
5610
|
-
*/
|
|
5611
|
-
onSubmit: (values: TValues) => Promise<void>;
|
|
5612
|
-
/**
|
|
5613
|
-
* Called when the user clicks the Cancel button on any step. Adopters
|
|
5614
|
-
* typically wire this to `router.back()` or `router.push(listUrl)`.
|
|
5615
|
-
* Values are discarded — there is no draft persistence in v0.2.
|
|
5616
|
-
*/
|
|
5617
|
-
onCancel?: () => void;
|
|
5618
|
-
/**
|
|
5619
|
-
* Optional view label (defaults to 'create'). Forwarded to the
|
|
5620
|
-
* underlying `<ResourceForm>` instance for testid + system-field
|
|
5621
|
-
* gating semantics.
|
|
5622
|
-
*/
|
|
5623
|
-
view?: 'create' | 'edit';
|
|
5624
|
-
/** Optional record id when editing an existing record. */
|
|
5625
|
-
recordId?: string;
|
|
5626
|
-
/**
|
|
5627
|
-
* Per-template field map override (forwarded to ResourceForm). Used
|
|
5628
|
-
* when the wizard renders a templated resource and the adopter wants
|
|
5629
|
-
* the matched template's field set on each step.
|
|
5630
|
-
*/
|
|
5631
|
-
fieldsOverride?: ResourceFieldMap;
|
|
5632
|
-
className?: string;
|
|
5633
|
-
}
|
|
5634
|
-
/**
|
|
5635
|
-
* Multi-step form built on top of `<ResourceForm>`. Each step renders
|
|
5636
|
-
* one `<ResourceForm>` configured with a slice of the resource's
|
|
5637
|
-
* fields (`fieldsFilter`) plus an optional step-level validator
|
|
5638
|
-
* (`validateOverride`). The wizard owns the step index, the
|
|
5639
|
-
* accumulated values across steps, and the Next / Back / Submit /
|
|
5640
|
-
* Cancel button rail.
|
|
5641
|
-
*
|
|
5642
|
-
* Behavior:
|
|
5643
|
-
* - Step 0 renders on mount.
|
|
5644
|
-
* - Next: runs the step's validators (per-field + step.validate);
|
|
5645
|
-
* if all pass, advances to step + 1.
|
|
5646
|
-
* - Back: decrements the step (no validation) and preserves values.
|
|
5647
|
-
* - Submit (last step): runs validators; on pass calls
|
|
5648
|
-
* `onSubmit(values)` with the FULL accumulated values map.
|
|
5649
|
-
* - Cancel: calls `onCancel?.()`.
|
|
5650
|
-
*
|
|
5651
|
-
* The progress indicator above the body shows every step with the
|
|
5652
|
-
* current step highlighted. Completed steps (anything left of the
|
|
5653
|
-
* current step) are clickable — clicking jumps back without
|
|
5654
|
-
* re-validation. Future steps are disabled until reached.
|
|
5655
|
-
*
|
|
5656
|
-
* Edge cases:
|
|
5657
|
-
* - Empty `fields[]` step → renders no inputs (summary / confirm
|
|
5658
|
-
* pattern). Submit on a single-step wizard skips Next/Back entirely.
|
|
5659
|
-
* - Step values persist across Back navigation — the wizard owns the
|
|
5660
|
-
* values map directly; ResourceForm receives a fresh `initialValues`
|
|
5661
|
-
* prop each render keyed off step id so its internal state resets
|
|
5662
|
-
* to the wizard's snapshot.
|
|
5663
|
-
* - Hidden / conditional fields per step are honored by ResourceForm
|
|
5664
|
-
* (B3) via the values context the wizard threads through.
|
|
5665
|
-
*/
|
|
5666
|
-
declare function ResourceWizard<TValues = Record<string, unknown>>(props: ResourceWizardProps<TValues>): React.ReactElement | null;
|
|
5667
|
-
//#endregion
|
|
5668
5145
|
//#region src/ui-presentations/dialog-host.d.ts
|
|
5669
5146
|
/**
|
|
5670
5147
|
* Concrete `dialog` host for `BuroProvider`'s `presentationHosts` prop:
|
|
@@ -5679,6 +5156,24 @@ declare namespace DialogPresentationHost {
|
|
|
5679
5156
|
title: "string";
|
|
5680
5157
|
description: "string";
|
|
5681
5158
|
wrapper: "boolean";
|
|
5159
|
+
ownTitle: "boolean";
|
|
5160
|
+
}>;
|
|
5161
|
+
}
|
|
5162
|
+
//#endregion
|
|
5163
|
+
//#region src/ui-presentations/popover-host.d.ts
|
|
5164
|
+
/**
|
|
5165
|
+
* Concrete `popover` host for `BuroProvider`'s `presentationHosts` prop (spec 4.1, 4.12): a
|
|
5166
|
+
* non-modal Radix popover positioned against the request's `anchor.element`. Focus stays on the
|
|
5167
|
+
* anchor (nothing is focused on open, nothing is restored on close); the content is a
|
|
5168
|
+
* `role="dialog"` named by the presented screen. It closes through the guarded `dismiss()` on
|
|
5169
|
+
* Escape, on a pointer down outside it, when focus moves elsewhere, when the pointer has been off
|
|
5170
|
+
* both the anchor and the popover for {@link POPOVER_LEAVE_GRACE_MS}, and when the anchor leaves
|
|
5171
|
+
* the document.
|
|
5172
|
+
*/
|
|
5173
|
+
declare function PopoverPresentationHost({ component: Component, props, options, anchor }: UIPresentationHostProps): ReactElement | null;
|
|
5174
|
+
declare namespace PopoverPresentationHost {
|
|
5175
|
+
var optionsSchema: Readonly<{
|
|
5176
|
+
title: "string";
|
|
5682
5177
|
}>;
|
|
5683
5178
|
}
|
|
5684
5179
|
//#endregion
|
|
@@ -5690,6 +5185,7 @@ declare namespace SheetPresentationHost {
|
|
|
5690
5185
|
title: "string";
|
|
5691
5186
|
description: "string";
|
|
5692
5187
|
wrapper: "boolean";
|
|
5188
|
+
ownTitle: "boolean";
|
|
5693
5189
|
}>;
|
|
5694
5190
|
}
|
|
5695
5191
|
//#endregion
|
|
@@ -5702,12 +5198,18 @@ interface PresentationShellProps {
|
|
|
5702
5198
|
readonly dismiss: () => void;
|
|
5703
5199
|
readonly wrapper: boolean;
|
|
5704
5200
|
readonly copy: PresentationCopy;
|
|
5201
|
+
/**
|
|
5202
|
+
* The presented component renders the overlay's title itself, as the Radix `Title` (a quick
|
|
5203
|
+
* entry's record title, plan ruling 2): the shell renders no title and no description, and
|
|
5204
|
+
* focus moves to the element marked `data-buro-overlay-heading` on open.
|
|
5205
|
+
*/
|
|
5206
|
+
readonly ownTitle?: boolean;
|
|
5705
5207
|
readonly children: ReactNode;
|
|
5706
5208
|
}
|
|
5707
5209
|
/** Shared Radix lifecycle shell for a centered temporary presentation. */
|
|
5708
|
-
declare function DialogPresentationShell({ dismiss, wrapper, copy, children }: PresentationShellProps): import("react/jsx-runtime").JSX.Element;
|
|
5210
|
+
declare function DialogPresentationShell({ dismiss, wrapper, copy, ownTitle, children }: PresentationShellProps): import("react/jsx-runtime").JSX.Element;
|
|
5709
5211
|
/** Shared Radix lifecycle shell for a right-hand temporary presentation. */
|
|
5710
|
-
declare function SheetPresentationShell({ dismiss, wrapper, copy, children }: PresentationShellProps): import("react/jsx-runtime").JSX.Element;
|
|
5212
|
+
declare function SheetPresentationShell({ dismiss, wrapper, copy, ownTitle, children }: PresentationShellProps): import("react/jsx-runtime").JSX.Element;
|
|
5711
5213
|
//#endregion
|
|
5712
5214
|
//#region src/ui-presentations/copy.d.ts
|
|
5713
5215
|
/**
|
|
@@ -5723,9 +5225,14 @@ declare function wrapperEnabled(options: Readonly<Record<string, unknown>>): boo
|
|
|
5723
5225
|
//#endregion
|
|
5724
5226
|
//#region src/ui-presentations/index.d.ts
|
|
5725
5227
|
/**
|
|
5726
|
-
* Concrete dialog/sheet hosts for `BuroProvider`'s `presentationHosts`
|
|
5727
|
-
* prop, keyed by `UIPresentationDescriptor['host']
|
|
5728
|
-
*
|
|
5228
|
+
* Concrete dialog/sheet/popover hosts for `BuroProvider`'s `presentationHosts`
|
|
5229
|
+
* prop, keyed by `UIPresentationDescriptor['host']`, and the kit's overlay
|
|
5230
|
+
* screens (`screens.quick`: a record's quick entry; `screens.peek`: the hover
|
|
5231
|
+
* preview of a relation display's record; `screens.flow`: a flow's host,
|
|
5232
|
+
* loaded on first use). Pass this straight through:
|
|
5233
|
+
* `<BuroProvider presentationHosts={shadcnPresentationHosts} .../>`; an app
|
|
5234
|
+
* with hosts of its own keeps quick entries and flows by spreading
|
|
5235
|
+
* `shadcnPresentationHosts.screens` into them.
|
|
5729
5236
|
*/
|
|
5730
5237
|
declare const shadcnPresentationHosts: UIPresentationHosts;
|
|
5731
5238
|
//#endregion
|
|
@@ -5747,6 +5254,8 @@ type IconComponent = ComponentType<SVGProps<SVGSVGElement>>;
|
|
|
5747
5254
|
* ```
|
|
5748
5255
|
*/
|
|
5749
5256
|
declare function registerIcons(map: Record<string, IconComponent>): void;
|
|
5257
|
+
/** Whether `name` is a registered icon (built-in or via {@link registerIcons}). */
|
|
5258
|
+
declare function hasIcon(name: string): boolean;
|
|
5750
5259
|
interface IconProps {
|
|
5751
5260
|
/** Semantic registry key (e.g. `'Hash'`). See REGISTRY above. */
|
|
5752
5261
|
name?: string;
|
|
@@ -6048,7 +5557,7 @@ type FormItemProps = React$1.HTMLAttributes<HTMLDivElement>;
|
|
|
6048
5557
|
declare const FormItem: React$1.ForwardRefExoticComponent<FormItemProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
6049
5558
|
type FormLabelProps = React$1.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>;
|
|
6050
5559
|
declare const FormLabel: React$1.ForwardRefExoticComponent<Omit<LabelPrimitive.LabelProps & React$1.RefAttributes<HTMLLabelElement>, "ref"> & React$1.RefAttributes<HTMLLabelElement>>;
|
|
6051
|
-
type FormControlProps = React$1.ComponentPropsWithoutRef<typeof Slot>;
|
|
5560
|
+
type FormControlProps = React$1.ComponentPropsWithoutRef<typeof Slot$1>;
|
|
6052
5561
|
type FormDescriptionProps = React$1.HTMLAttributes<HTMLParagraphElement>;
|
|
6053
5562
|
declare const FormDescription: React$1.ForwardRefExoticComponent<FormDescriptionProps & React$1.RefAttributes<HTMLParagraphElement>>;
|
|
6054
5563
|
type FormMessageProps = React$1.HTMLAttributes<HTMLParagraphElement>;
|
|
@@ -6163,7 +5672,7 @@ declare const Label: React$1.ForwardRefExoticComponent<Omit<LabelPrimitive.Label
|
|
|
6163
5672
|
//#region src/primitives/tabs.d.ts
|
|
6164
5673
|
/**
|
|
6165
5674
|
* Thin shadcn-ui-style wrapper around `@radix-ui/react-tabs`. Exposed as
|
|
6166
|
-
* a primitive so feature components (e.g.
|
|
5675
|
+
* a primitive so feature components (e.g. the screen tree's tabs node) can compose
|
|
6167
5676
|
* the standard accessible Tabs pattern without re-implementing radix
|
|
6168
5677
|
* boilerplate.
|
|
6169
5678
|
*
|
|
@@ -6238,18 +5747,20 @@ type SidebarContextValue = {
|
|
|
6238
5747
|
toggleSidebar: () => void;
|
|
6239
5748
|
};
|
|
6240
5749
|
declare function useSidebar(): SidebarContextValue;
|
|
5750
|
+
/** The sidebar context, or `null` outside a `SidebarProvider`. Never throws. */
|
|
5751
|
+
declare function useOptionalSidebar(): SidebarContextValue | null;
|
|
6241
5752
|
interface SidebarProviderProps extends React$1.ComponentPropsWithoutRef<'div'> {
|
|
6242
5753
|
defaultOpen?: boolean;
|
|
6243
5754
|
open?: boolean;
|
|
6244
5755
|
onOpenChange?: (open: boolean) => void;
|
|
6245
5756
|
}
|
|
6246
5757
|
declare const SidebarProvider: React$1.ForwardRefExoticComponent<SidebarProviderProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
6247
|
-
interface SidebarProps
|
|
5758
|
+
interface SidebarProps extends React$1.ComponentPropsWithoutRef<'div'> {
|
|
6248
5759
|
side?: 'left' | 'right';
|
|
6249
5760
|
variant?: 'sidebar' | 'floating' | 'inset';
|
|
6250
5761
|
collapsible?: 'offcanvas' | 'icon' | 'none';
|
|
6251
5762
|
}
|
|
6252
|
-
declare const Sidebar
|
|
5763
|
+
declare const Sidebar: React$1.ForwardRefExoticComponent<SidebarProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
6253
5764
|
declare const SidebarTrigger: React$1.ForwardRefExoticComponent<Omit<ButtonProps & React$1.RefAttributes<HTMLButtonElement>, "ref"> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
6254
5765
|
declare const SidebarRail: React$1.ForwardRefExoticComponent<Omit<React$1.DetailedHTMLProps<React$1.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
6255
5766
|
declare const SidebarInset: React$1.ForwardRefExoticComponent<Omit<React$1.DetailedHTMLProps<React$1.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & React$1.RefAttributes<HTMLElement>>;
|
|
@@ -6270,7 +5781,7 @@ declare const SidebarMenu: React$1.ForwardRefExoticComponent<Omit<React$1.Detail
|
|
|
6270
5781
|
declare const SidebarMenuItem: React$1.ForwardRefExoticComponent<Omit<React$1.DetailedHTMLProps<React$1.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "ref"> & React$1.RefAttributes<HTMLLIElement>>;
|
|
6271
5782
|
declare const sidebarMenuButtonVariants: (props?: ({
|
|
6272
5783
|
variant?: "default" | "outline" | null | undefined;
|
|
6273
|
-
size?: "
|
|
5784
|
+
size?: "sm" | "lg" | "default" | null | undefined;
|
|
6274
5785
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6275
5786
|
interface SidebarMenuButtonProps extends React$1.ComponentPropsWithoutRef<'button'>, VariantProps<typeof sidebarMenuButtonVariants> {
|
|
6276
5787
|
asChild?: boolean;
|
|
@@ -6466,9 +5977,248 @@ declare const typography: {
|
|
|
6466
5977
|
};
|
|
6467
5978
|
type TypographyKey = keyof typeof typography;
|
|
6468
5979
|
//#endregion
|
|
5980
|
+
//#region src/shell/shell-context.d.ts
|
|
5981
|
+
interface ShellBrand {
|
|
5982
|
+
readonly name: string;
|
|
5983
|
+
readonly subtitle?: string;
|
|
5984
|
+
readonly logo?: ReactNode;
|
|
5985
|
+
/** Where the brand links to. Default `'/'`. */
|
|
5986
|
+
readonly homePath?: string;
|
|
5987
|
+
}
|
|
5988
|
+
interface ShellUser {
|
|
5989
|
+
readonly name: string;
|
|
5990
|
+
readonly email?: string;
|
|
5991
|
+
readonly avatarUrl?: string;
|
|
5992
|
+
readonly initials: string;
|
|
5993
|
+
}
|
|
5994
|
+
/** Maps the auth provider's identity to what the shell shows. `initials` is derived from `name`. */
|
|
5995
|
+
type ShellUserMapper = (identity: unknown) => Omit<ShellUser, 'initials'>;
|
|
5996
|
+
interface ShellContextValue {
|
|
5997
|
+
readonly brand?: ShellBrand;
|
|
5998
|
+
readonly mapUser: ShellUserMapper;
|
|
5999
|
+
/** Where sign-out and "Sign in" go. Default `'/login'`. */
|
|
6000
|
+
readonly loginPath: string;
|
|
6001
|
+
/** Set only when a command palette is mounted. */
|
|
6002
|
+
readonly openPalette?: () => void;
|
|
6003
|
+
/** The mounted palette's open state; `AppShell` sets it unless `palette={false}`. Read it with {@link usePaletteState}. */
|
|
6004
|
+
readonly palette?: PaletteState;
|
|
6005
|
+
}
|
|
6006
|
+
interface PaletteState {
|
|
6007
|
+
readonly open: boolean;
|
|
6008
|
+
readonly setOpen: (open: boolean) => void;
|
|
6009
|
+
}
|
|
6010
|
+
/** `name`, else `email`, else `id` for the name; `email`; `avatarUrl` else `avatar`. */
|
|
6011
|
+
declare function defaultUserMapper(identity: unknown): Omit<ShellUser, 'initials'>;
|
|
6012
|
+
type ShellProviderProps = Partial<ShellContextValue> & {
|
|
6013
|
+
readonly children: ReactNode;
|
|
6014
|
+
};
|
|
6015
|
+
declare function ShellProvider({ brand, mapUser, loginPath, openPalette, palette, children }: ShellProviderProps): ReactElement;
|
|
6016
|
+
/** Outside a `ShellProvider`: no brand, the default mapper, `/login`. */
|
|
6017
|
+
declare function useShell(): ShellContextValue;
|
|
6018
|
+
/**
|
|
6019
|
+
* The palette's `open` and `setOpen`, for a custom `AppShell palette={<MyPalette/>}`, which
|
|
6020
|
+
* receives no props. Throws outside an `AppShell` (or a `ShellProvider` given `palette`).
|
|
6021
|
+
*/
|
|
6022
|
+
declare function usePaletteState(): PaletteState;
|
|
6023
|
+
//#endregion
|
|
6024
|
+
//#region src/shell/use-current-user.d.ts
|
|
6025
|
+
interface CurrentUser {
|
|
6026
|
+
readonly user: ShellUser | null;
|
|
6027
|
+
/** The identity is being fetched. `false` for a query that is idle (session not ready) or absent. */
|
|
6028
|
+
readonly isLoading: boolean;
|
|
6029
|
+
/** `false` when the app has no `authProvider`: there is no identity to show and no logout to run. */
|
|
6030
|
+
readonly available: boolean;
|
|
6031
|
+
/**
|
|
6032
|
+
* Logs out, then goes to the shell's `loginPath`; stays put on `{ success: false }`. Returns the
|
|
6033
|
+
* result. Rejects when the auth provider's `logout` throws instead of returning a result.
|
|
6034
|
+
*/
|
|
6035
|
+
readonly signOut: () => Promise<AuthResult>;
|
|
6036
|
+
}
|
|
6037
|
+
/**
|
|
6038
|
+
* The signed-in user as the shell shows it. Never throws: without an `authProvider` it reports
|
|
6039
|
+
* `available: false` and no user.
|
|
6040
|
+
*/
|
|
6041
|
+
declare function useCurrentUser(): CurrentUser;
|
|
6042
|
+
//#endregion
|
|
6043
|
+
//#region src/shell/sidebar-brand.d.ts
|
|
6044
|
+
/** The brand tile, name and subtitle at the top of the sidebar; reads `AppShell brand` / `ShellProvider brand`. */
|
|
6045
|
+
declare function SidebarBrand(): ReactElement | null;
|
|
6046
|
+
//#endregion
|
|
6047
|
+
//#region src/shell/brand-mark.d.ts
|
|
6048
|
+
/**
|
|
6049
|
+
* The `ShellProvider` brand as a standalone mark — `SidebarBrand` without the sidebar button.
|
|
6050
|
+
* `AuthPage` shows it when given no `brand`. Renders nothing without a brand.
|
|
6051
|
+
*/
|
|
6052
|
+
declare function BrandMark(): ReactElement | null;
|
|
6053
|
+
//#endregion
|
|
6054
|
+
//#region src/shell/use-nav-icon.d.ts
|
|
6055
|
+
/**
|
|
6056
|
+
* Resolve a nav icon NAME to a node: a Components-registry slot of that key
|
|
6057
|
+
* first, then the `registerIcons` registry. An unknown name yields `undefined`
|
|
6058
|
+
* (no placeholder circle) and, outside production, warns once per name.
|
|
6059
|
+
*/
|
|
6060
|
+
declare function resolveNavIcon(name: string | undefined, components: (key: string) => unknown): ReactNode | undefined;
|
|
6061
|
+
/** `resolveNavIcon` bound to the Components registry in context. */
|
|
6062
|
+
declare function useNavIcon(): (name: string | undefined) => ReactNode | undefined;
|
|
6063
|
+
//#endregion
|
|
6064
|
+
//#region src/shell/app-shell.d.ts
|
|
6065
|
+
/** Every slot follows {@link Slot}: omit for the default, `false` for nothing, an element to replace. */
|
|
6066
|
+
interface AppShellProps {
|
|
6067
|
+
/** Read by `SidebarBrand`, `AuthPage` and the document title. */
|
|
6068
|
+
brand: ShellBrand;
|
|
6069
|
+
/** Maps the auth provider's identity to what the user menu shows. Default: `defaultUserMapper`. */
|
|
6070
|
+
user?: ShellUserMapper;
|
|
6071
|
+
/** Where sign-out and "Sign in" go. Default `'/login'`. */
|
|
6072
|
+
loginPath?: string;
|
|
6073
|
+
/** Default `<AppSidebar />`. `false` gives a header-only layout with no sidebar trigger. */
|
|
6074
|
+
sidebar?: Slot;
|
|
6075
|
+
/** Default `<AppHeader />`. */
|
|
6076
|
+
header?: Slot;
|
|
6077
|
+
/**
|
|
6078
|
+
* Default `<DefaultCommandPalette />`. `false` removes the palette, the ⌘K / Ctrl+K shortcut
|
|
6079
|
+
* and the header's search chip. A custom element receives no props: it reads `open` and
|
|
6080
|
+
* `setOpen` from `usePaletteState()`.
|
|
6081
|
+
*/
|
|
6082
|
+
palette?: Slot;
|
|
6083
|
+
/** Passed to `AppLayout`, typically `<DocPanel />`. */
|
|
6084
|
+
docPanel?: ReactNode;
|
|
6085
|
+
children: ReactNode;
|
|
6086
|
+
}
|
|
6087
|
+
/**
|
|
6088
|
+
* `AppLayout` with the default sidebar, header and command palette, and the brand and user
|
|
6089
|
+
* context they read. Renders inside `BuroProvider`, a `RouterAdapter` and a
|
|
6090
|
+
* `LinkComponentProvider`; it does not boot the runtime, own routes or guard auth.
|
|
6091
|
+
*/
|
|
6092
|
+
declare function AppShell({ brand, user, loginPath, sidebar, header, palette, docPanel, children }: AppShellProps): ReactElement;
|
|
6093
|
+
//#endregion
|
|
6094
|
+
//#region src/shell/default-command-palette.d.ts
|
|
6095
|
+
interface DefaultCommandPaletteProps {
|
|
6096
|
+
open: boolean;
|
|
6097
|
+
onOpenChange: (open: boolean) => void;
|
|
6098
|
+
/** Appended to the Actions group after theme, language and sign out. */
|
|
6099
|
+
actions?: ActionItem[];
|
|
6100
|
+
/** Replaces every group. The dialog, input, empty state and footer stay. */
|
|
6101
|
+
children?: ReactNode;
|
|
6102
|
+
}
|
|
6103
|
+
/**
|
|
6104
|
+
* The palette `AppShell` mounts by default: Docs, Recent, Records, Navigation, Create and
|
|
6105
|
+
* Actions, in that order. Records needs a data runtime and is left out without one. Actions are the theme choices, the languages (only with more than
|
|
6106
|
+
* one locale), "Sign out" (only when someone is signed in) and then `actions`.
|
|
6107
|
+
*/
|
|
6108
|
+
declare function DefaultCommandPalette({ open, onOpenChange, actions, children }: DefaultCommandPaletteProps): ReactElement;
|
|
6109
|
+
//#endregion
|
|
6110
|
+
//#region src/shell/scope-switcher.d.ts
|
|
6111
|
+
interface ScopeOption {
|
|
6112
|
+
value: string;
|
|
6113
|
+
label: string;
|
|
6114
|
+
description?: string;
|
|
6115
|
+
icon?: ReactNode;
|
|
6116
|
+
}
|
|
6117
|
+
interface ScopeSwitcherProps {
|
|
6118
|
+
options: readonly ScopeOption[];
|
|
6119
|
+
value: string | null;
|
|
6120
|
+
/** A rejection is swallowed here and leaves the value unchanged; the caller reports the error. */
|
|
6121
|
+
onChange: (value: string) => void | Promise<void>;
|
|
6122
|
+
/** Dropdown heading, e.g. "Tenant". */
|
|
6123
|
+
label?: string;
|
|
6124
|
+
/** Rows rendered after a separator, e.g. an "Administration" item. */
|
|
6125
|
+
extra?: ReactNode;
|
|
6126
|
+
/** Shown when `value` is null. */
|
|
6127
|
+
placeholder?: string;
|
|
6128
|
+
}
|
|
6129
|
+
/** A sidebar-header picker for the current tenant, workspace or other scope. */
|
|
6130
|
+
declare function ScopeSwitcher({ options, value, onChange, label, extra, placeholder }: ScopeSwitcherProps): ReactElement;
|
|
6131
|
+
//#endregion
|
|
6132
|
+
//#region src/shell/user-menu.d.ts
|
|
6133
|
+
interface UserMenuProps {
|
|
6134
|
+
/** `'sidebar'`: the sidebar-footer row (avatar, name, email). `'avatar'`: a round avatar button for a header. Default `'sidebar'`. */
|
|
6135
|
+
variant?: 'sidebar' | 'avatar';
|
|
6136
|
+
/**
|
|
6137
|
+
* The menu's parts, in the order given. Omit to get the default set: Profile, Theme, Language
|
|
6138
|
+
* (only with more than one locale) and Sign out. Passed parts always render. Signed out, the
|
|
6139
|
+
* menu shows the passed parts except `Profile` and `SignOut`, then "Sign in"; the default set
|
|
6140
|
+
* signed out is Theme, Language and "Sign in".
|
|
6141
|
+
*/
|
|
6142
|
+
children?: ReactNode;
|
|
6143
|
+
}
|
|
6144
|
+
declare function Profile(): ReactElement;
|
|
6145
|
+
declare function Theme(): ReactElement;
|
|
6146
|
+
declare function Language(): ReactElement | null;
|
|
6147
|
+
declare function Separator$1(): ReactElement;
|
|
6148
|
+
type ItemProps = {
|
|
6149
|
+
id: string;
|
|
6150
|
+
label: ReactNode;
|
|
6151
|
+
icon?: ReactNode;
|
|
6152
|
+
} & ({
|
|
6153
|
+
href: string;
|
|
6154
|
+
onSelect?: never;
|
|
6155
|
+
} | {
|
|
6156
|
+
onSelect: () => void;
|
|
6157
|
+
href?: never;
|
|
6158
|
+
});
|
|
6159
|
+
declare function Item(props: ItemProps): ReactElement;
|
|
6160
|
+
declare function SignOut(): ReactElement;
|
|
6161
|
+
declare function UserMenuRoot({ variant, children }: UserMenuProps): ReactElement | null;
|
|
6162
|
+
/**
|
|
6163
|
+
* The user's menu. Fills each part you do not pass with its default; passed children replace
|
|
6164
|
+
* the default set. `UserMenu.Profile`, `.Theme`, `.Language`, `.Separator`, `.Item` and
|
|
6165
|
+
* `.SignOut` are the parts. Signed out it is still a menu — the parts that need no identity,
|
|
6166
|
+
* then "Sign in" (`user-menu:sign-in`) — so theme and language stay reachable. Renders nothing
|
|
6167
|
+
* without an auth provider.
|
|
6168
|
+
*/
|
|
6169
|
+
declare const UserMenu: typeof UserMenuRoot & {
|
|
6170
|
+
Profile: typeof Profile;
|
|
6171
|
+
Theme: typeof Theme;
|
|
6172
|
+
Language: typeof Language;
|
|
6173
|
+
Separator: typeof Separator$1;
|
|
6174
|
+
Item: typeof Item;
|
|
6175
|
+
SignOut: typeof SignOut;
|
|
6176
|
+
};
|
|
6177
|
+
//#endregion
|
|
6178
|
+
//#region src/shell/use-language-switch.d.ts
|
|
6179
|
+
interface LanguageSwitchApi {
|
|
6180
|
+
/** The active locale code. */
|
|
6181
|
+
readonly locale: string;
|
|
6182
|
+
/** Every locale the app can switch to; just the active one when the i18n facade does not list them. */
|
|
6183
|
+
readonly locales: readonly string[];
|
|
6184
|
+
/** Switch the live locale (no reload) and persist the choice under the provider's `languageStorageKey`. */
|
|
6185
|
+
readonly change: (code: string) => void;
|
|
6186
|
+
}
|
|
6187
|
+
/**
|
|
6188
|
+
* The headless model behind every language control: the active locale, the
|
|
6189
|
+
* locales on offer, and a `change` that switches live and remembers the pick.
|
|
6190
|
+
* `<LanguageSwitch>`, `<LanguageSubmenu>` and the palette actions are views
|
|
6191
|
+
* over it; an app's own control can be one too.
|
|
6192
|
+
*/
|
|
6193
|
+
declare function useLanguageSwitch(): LanguageSwitchApi;
|
|
6194
|
+
//#endregion
|
|
6195
|
+
//#region src/shell/theme-controls.d.ts
|
|
6196
|
+
/** Radio submenu over {@link THEME_CHOICES}, bound to the stored choice (not the resolved theme). */
|
|
6197
|
+
declare function ThemeSubmenu(): ReactElement;
|
|
6198
|
+
/** Icon button cycling light, dark, system. The icon shows the current choice. */
|
|
6199
|
+
declare function ThemeToggle(): ReactElement;
|
|
6200
|
+
/** One command-palette action per theme choice. */
|
|
6201
|
+
declare function useThemePaletteActions(): ActionItem[];
|
|
6202
|
+
//#endregion
|
|
6203
|
+
//#region src/shell/language-submenu.d.ts
|
|
6204
|
+
/**
|
|
6205
|
+
* A locale's name in its own language ("English", "Русский", "Français"),
|
|
6206
|
+
* capitalised. Falls back to the bare code when `Intl.DisplayNames` does not
|
|
6207
|
+
* know it (or the code is not a valid BCP-47 tag).
|
|
6208
|
+
*/
|
|
6209
|
+
declare function localeLabel(code: string): string;
|
|
6210
|
+
/**
|
|
6211
|
+
* Radio submenu over the app's locales. Renders nothing only when there is no
|
|
6212
|
+
* i18n facade; with one locale it still renders that one choice (hiding a
|
|
6213
|
+
* single-locale row is the default menu's decision, not this part's).
|
|
6214
|
+
*/
|
|
6215
|
+
declare function LanguageSubmenu(): ReactElement | null;
|
|
6216
|
+
/** One command-palette action per locale; empty unless the app has more than one. */
|
|
6217
|
+
declare function useLanguagePaletteActions(): ActionItem[];
|
|
6218
|
+
//#endregion
|
|
6469
6219
|
//#region src/index.d.ts
|
|
6470
6220
|
declare const PACKAGE_NAME: "@burojs/ui-shadcn";
|
|
6471
6221
|
declare const PACKAGE_VERSION: "0.0.0";
|
|
6472
6222
|
//#endregion
|
|
6473
|
-
export { ActionButton, type ActionButtonProps,
|
|
6223
|
+
export { ActionButton, type ActionButtonProps, type ActionItem, ActionOverflow, type ActionOverflowProps, type ActionSurface, AlertDialog, AlertDialogAction, AlertDialogActionProps, AlertDialogCancel, AlertDialogCancelProps, AlertDialogContent, AlertDialogContentProps, AlertDialogDescription, AlertDialogDescriptionProps, AlertDialogFooter, AlertDialogFooterProps, AlertDialogHeader, AlertDialogHeaderProps, AlertDialogOverlay, AlertDialogOverlayProps, AlertDialogPortal, AlertDialogTitle, AlertDialogTitleProps, AlertDialogTrigger, AppActions, AppFlowButton, type AppFlowButtonProps, AppHeader, type AppHeaderProps, AppLayout, type AppLayoutProps, AppShell, type AppShellProps, AppSidebar, type AppSidebarProps, AuthPage, type AuthPageProps, Avatar, AvatarFallback, AvatarImage, Badge, BadgeProps, BooleanDisplay, BooleanInput, BrandMark, Breadcrumbs, type BreadcrumbsProps, type BuildNavItemsArgs, BulkActionToolbar, type BulkActionToolbarProps, Button, ButtonProps, Card, CardContent, CardContentProps, CardDescription, CardDescriptionProps, CardFooter, CardFooterProps, CardHeader, CardHeaderProps, CardProps, CardTitle, CardTitleProps, CheckConfirmDialog, type CheckConfirmDialogProps, Checkbox, CheckboxProps, Collapsible, CollapsibleContent, CollapsibleTrigger, ColumnsToggle, Command, CommandDialog, CommandDialogProps, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandLoadingProps, CommandPalette, CommandPaletteActionsGroup, type CommandPaletteActionsGroupProps, type CommandPaletteActionsTestIdRole, CommandPaletteCreateGroup, type CommandPaletteCreateGroupProps, type CommandPaletteCreateTestIdRole, CommandPaletteDocsGroup, type CommandPaletteDocsGroupProps, CommandPaletteNavigationGroups, type CommandPaletteNavigationGroupsProps, type CommandPaletteNavigationTestIdRole, type CommandPaletteProps, CommandPaletteRecentGroup, type CommandPaletteRecentGroupProps, type CommandPaletteRecentTestIdRole, CommandPaletteRecordsGroup, type CommandPaletteRecordsGroupProps, type CommandPaletteRecordsTestIdRole, type CommandPaletteTestIdRole, CommandPaletteTrigger, type CommandPaletteTriggerProps, CommandSeparator, ContextPicker, type ContextPickerProps, CopyId, CreateButton, type CreateButtonProps, CursorLoadMore, type CursorLoadMoreProps, DEFAULT_LANGUAGE, DEFAULT_LANGUAGE_STORAGE_KEY, DataTable, DataTableDateRangeFilter, type DataTableDateRangeFilterProps, DataTableEnumFilter, type DataTableEnumFilterProps, DataTableFacetedFilter, type DataTableFacetedFilterProps, DataTableNumRangeFilter, type DataTableNumRangeFilterProps, DataTableOperatorFilter, type DataTableOperatorFilterProps, type DataTableProps, DataTableRowActions, type DataTableRowActionsProps, DataTableTextFilter, type DataTableTextFilterProps, DataTableToolbar, type DataTableToolbarProps, DataTableViewOptions, type DataTableViewOptionsProps, DateDisplay, DateInput, DeclarativeDisplay, type DeclarativeDisplayProps, DeclarativeForm, type DeclarativeFormProps, type DeclarativeFormSlots, DefaultCommandPalette, type DefaultCommandPaletteProps, Dialog, DialogClose, DialogContent, DialogContentProps, DialogDescription, DialogDescriptionProps, type DialogFilterState, DialogFooter, DialogFooterProps, DialogHeader, DialogHeaderProps, DialogOverlayProps, DialogPresentationHost, DialogPresentationShell, DialogTitle, DialogTitleProps, DialogTrigger, DisabledAction, type DisabledActionProps, DocBrowser, type DocBrowserProps, DocInfo, type DocInfoProps, DocPanel, type DocPanelProps, DocTrailHelp, type DocTrailHelpProps, DocumentTitleProvider, type DraftRemovalSignal, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, ENUM_PICKER_CLEAR_SENTINEL, EditPageHeader, EnumBadge, type EnumBadgeProps, EnumDisplay, EnumInput, EnumPicker, type EnumPickerProps, type EnumPickerRenderAs, EnumDisplay$1 as EnumValueDisplay, type EnumDisplayProps as EnumValueDisplayProps, type EnumDisplayVariant as EnumValueDisplayVariant, ExportButton, type ExportButtonProps, ExportDialog, type ExportDialogProps, type FacetedFilterOption, Field, FieldDisplay, type FieldDisplayProps, type FieldProps, FileDisplay, FileField, type FileFieldProps, FileInput, type FileInputProps, FilterBadges, type FilterBadgesProps, FilterBuilder, type FilterBuilderProps, type FilterOperator, FilterPanel, type FilterPanelProps, FilterRegion, FilterValueControl, type FilterValueControlProps, FlowActionButton, type FlowActionButtonProps, Form, FormActions, FormControl, FormControlProps, FormDescription, FormDescriptionProps, FormField, FormItem, FormItemProps, FormLabel, FormLabelProps, FormMessage, FormMessageProps, HeaderBreadcrumbs, HelpButton, type HelpButtonProps, Icon, IconComponent, IconProps, Input, InputProps, Label, LabelProps, type LanguageCode, LanguageSubmenu, LanguageSwitch, type LanguageSwitchApi, type LanguageSwitchProps, type LinkComponent, type LinkComponentProps, LinkComponentProvider, type LinkComponentProviderProps, ListBody, ListBulkBar, type ListCellRenderer, ListColumns, ListControls, ListCreate, ListErrorState, type ListErrorStateProps, ListExport, ListFilters, ListFlows, ListLive, ListSavedViews, ListSearchInput, type ListSlot, type ListSlotRegion, type LoginCredentials, LoginForm, type LoginFormProps, NavAreaLayout, type NavAreaLayoutProps, NavAreaPage, NavChrome, NavChromeBoundaryProvider, type NavChromeProps, type NavItem, type NavLayout, type NavLayoutProps, NavMain, type NavMainProps, type NavTreeEntry, type NavTreeLayout, type NavTreeSection, NavigationGuardDialog, NumberDisplay, NumberInput, PACKAGE_NAME, PACKAGE_VERSION, type PageBreadcrumbsProps, PageHeader, type PageHeaderProps, type PaletteState, PinnedFilterControls, type PinnedFilterControlsProps, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverContentProps, PopoverPresentationHost, PopoverTrigger, type PresentationCopy, Progress, ProgressProps, RecordActions, RecordBreadcrumbs, RecordPage, type RecordPageProps, RecordScreen, type RecordScreenProps, RecordTitle, RefreshButton, type RefreshButtonProps, RelationDisplay, RelationField, RelationManyDisplay, RelationPicker, LazyRelationPickerDialog as RelationPickerDialog, type RelationPickerDialogProps, RelationPickerInput, type RelationPickerProps, type ResolvedTheme, type ResourceBreadcrumbsProps, ResourceList, ResourceListPage, type ResourceListPageProps, type ResourceListProps, ResourcePageRouter, type ResourcePageRouterProps, type RowActionDescriptor, SavedViewsDropdown, type SavedViewsDropdownProps, type ScopeOption, ScopeSwitcher, type ScopeSwitcherProps, SecondarySidebarLayout, Select, SelectContent, SelectContentProps, SelectGroup, SelectItem, SelectItemProps, SelectLabel, SelectLabelProps, SelectScrollDownButton, SelectScrollDownButtonProps, SelectScrollUpButton, SelectScrollUpButtonProps, SelectSeparator, SelectSeparatorProps, SelectTrigger, SelectTriggerProps, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetContentProps, SheetDescription, SheetDescriptionProps, SheetFooter, SheetFooterProps, SheetHeader, SheetHeaderProps, SheetOverlayProps, SheetPresentationHost, SheetPresentationShell, SheetTitle, SheetTitleProps, SheetTrigger, type ShellBrand, type ShellContextValue, ShellProvider, type ShellProviderProps, type ShellUser, type ShellUserMapper, ShowPageHeader, Sidebar, SidebarBrand, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuButtonProps, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubButtonProps, SidebarMenuSubItem, SidebarProps, SidebarProvider, SidebarProviderProps, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, type Slot, type SpacingKey, THEME_CHOICES, THEME_STORAGE_KEY, Table, TableBody, TableBodyProps, TableCaption, TableCaptionProps, TableCell, TableCellProps, TableHead, TableHeadProps, TableHeader, TableHeaderProps, TableProps, TableRow, TableRowProps, Tabs, TabsContent, TabsContentProps, TabsLayout, TabsList, TabsListProps, TabsTrigger, TabsTriggerProps, TaskRunPanel, TaskRunPanelProps, TextDisplay, TextInput, Textarea, TextareaDisplay, TextareaInput, TextareaProps, type ThemeChoice, ThemeSubmenu, ThemeToggle, Toaster, type ToasterProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type TypographyKey, type UseBuroDataTableOptions, type UseDialogFilterStateOptions, type UseNavTreeOptions, type UseThemeResult, UserMenu, type UserMenuProps, badgeVariants, buildNavItems, buroSortingToTanStack, buttonVariants, cn, defaultNavLayouts, defaultUserMapper, downloadArtifact, formatOperatorLabel, hasIcon, i18nPrefixToRef, isImage, layoutSlot, listSlot, loadLanguage, loadLocale, localeLabel, modeForSurface, recordDisplayName, registerIcons, relationLinkClassName, resolveNavIcon, resolveUpdater, saveLanguage, saveLocale, shadcnBlockImplementations, shadcnFieldImplementations, shadcnPresentationHosts, spacing, tanStackSortingToBuro, toast, typography, useBuroDataTable, useCurrentUser, useDialogFilterState, useDocumentTitle, useExportRunWatcher, useFormControl, useFormField, useHref, useIsMobile, useLanguagePaletteActions, useLanguageSwitch, useLayout, useLayoutResolver, useLinkComponent, useListSlot, useMatch, useNavChromeBoundary, useNavIcon, useNavTree, useNavVisible, useOptionalSidebar, usePaletteState, usePresentationCopy, useShell, useSidebar, useTheme, useThemePaletteActions, wrapperEnabled };
|
|
6474
6224
|
//# sourceMappingURL=index.d.cts.map
|