@rahdar/plugin-sdk 0.0.0 → 2026.10.51

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.
Files changed (154) hide show
  1. package/README.md +38 -0
  2. package/index.js +52 -0
  3. package/package.json +46 -1
  4. package/peers.json +8 -0
  5. package/shared.d.ts +3 -0
  6. package/shared.js +24 -0
  7. package/types/branding.d.ts +14 -0
  8. package/types/kernel/actions/ActionHost.d.ts +16 -0
  9. package/types/kernel/actions/hostContext.d.ts +4 -0
  10. package/types/kernel/actions/types.d.ts +130 -0
  11. package/types/kernel/api/paging.d.ts +39 -0
  12. package/types/kernel/api/polling.d.ts +37 -0
  13. package/types/kernel/api/request.d.ts +84 -0
  14. package/types/kernel/api/schema.d.ts +24077 -0
  15. package/types/kernel/approvals/ApprovalView.d.ts +6 -0
  16. package/types/kernel/approvals/ApprovalsView.d.ts +7 -0
  17. package/types/kernel/approvals/ApproverQuorumNotice.d.ts +8 -0
  18. package/types/kernel/approvals/BreakGlassBanner.d.ts +5 -0
  19. package/types/kernel/approvals/CancelRequest.d.ts +13 -0
  20. package/types/kernel/approvals/DecisionPanel.d.ts +11 -0
  21. package/types/kernel/approvals/ExpiresIn.d.ts +10 -0
  22. package/types/kernel/approvals/MyRequests.d.ts +5 -0
  23. package/types/kernel/approvals/Recap.d.ts +9 -0
  24. package/types/kernel/approvals/api.d.ts +130 -0
  25. package/types/kernel/approvals/columns.d.ts +22 -0
  26. package/types/kernel/approvals/words.d.ts +31 -0
  27. package/types/kernel/auth/Can.d.ts +9 -0
  28. package/types/kernel/auth/LoginView.d.ts +9 -0
  29. package/types/kernel/auth/SecondFactorForm.d.ts +25 -0
  30. package/types/kernel/auth/StepUp.d.ts +17 -0
  31. package/types/kernel/auth/api.d.ts +115 -0
  32. package/types/kernel/auth/freshSignIn.d.ts +2 -0
  33. package/types/kernel/auth/useCan.d.ts +49 -0
  34. package/types/kernel/auth/webauthn.d.ts +19 -0
  35. package/types/kernel/feature.d.ts +90 -0
  36. package/types/kernel/features.d.ts +5 -0
  37. package/types/kernel/inbox/InboxBell.d.ts +6 -0
  38. package/types/kernel/inbox/InboxView.d.ts +6 -0
  39. package/types/kernel/inbox/NoticeRow.d.ts +17 -0
  40. package/types/kernel/inbox/api.d.ts +53 -0
  41. package/types/kernel/keyboard/ShortcutsHelp.d.ts +6 -0
  42. package/types/kernel/keyboard/filterShortcut.d.ts +5 -0
  43. package/types/kernel/keyboard/keys.d.ts +14 -0
  44. package/types/kernel/keyboard/shortcuts.d.ts +5 -0
  45. package/types/kernel/keyboard/useKeySequences.d.ts +16 -0
  46. package/types/kernel/manifest.d.ts +21 -0
  47. package/types/kernel/metrics/ChartPanel.d.ts +28 -0
  48. package/types/kernel/metrics/MetricChart.d.ts +13 -0
  49. package/types/kernel/metrics/axis.d.ts +71 -0
  50. package/types/kernel/metrics/pluginSeries.d.ts +17 -0
  51. package/types/kernel/nav/currentView.d.ts +21 -0
  52. package/types/kernel/nav/groups.d.ts +22 -0
  53. package/types/kernel/plugins/PluginBoundary.d.ts +25 -0
  54. package/types/kernel/plugins/PluginUnavailable.d.ts +6 -0
  55. package/types/kernel/plugins/boot.d.ts +33 -0
  56. package/types/kernel/plugins/guarded.d.ts +3 -0
  57. package/types/kernel/plugins/usePluginsChanged.d.ts +6 -0
  58. package/types/kernel/plugins/validate.d.ts +19 -0
  59. package/types/kernel/registry.d.ts +12 -0
  60. package/types/kernel/routing/roots.d.ts +24 -0
  61. package/types/kernel/shell/AccountView.d.ts +11 -0
  62. package/types/kernel/shell/AdminView.d.ts +7 -0
  63. package/types/kernel/shell/Breadcrumb.d.ts +6 -0
  64. package/types/kernel/shell/ClusterLayout.d.ts +14 -0
  65. package/types/kernel/shell/ClusterViewNav.d.ts +13 -0
  66. package/types/kernel/shell/CommandPalette.d.ts +15 -0
  67. package/types/kernel/shell/FeatureDisabled.d.ts +13 -0
  68. package/types/kernel/shell/FeatureGate.d.ts +12 -0
  69. package/types/kernel/shell/FreshnessBar.d.ts +11 -0
  70. package/types/kernel/shell/GlobalContext.d.ts +7 -0
  71. package/types/kernel/shell/HomeView.d.ts +6 -0
  72. package/types/kernel/shell/NavGroup.d.ts +13 -0
  73. package/types/kernel/shell/NavItem.d.ts +33 -0
  74. package/types/kernel/shell/NavToggle.d.ts +13 -0
  75. package/types/kernel/shell/RootLayout.d.ts +15 -0
  76. package/types/kernel/shell/SectionNav.d.ts +41 -0
  77. package/types/kernel/shell/UserMenu.d.ts +10 -0
  78. package/types/kernel/shell/lastPlace.d.ts +17 -0
  79. package/types/kernel/shell/pageTitle.d.ts +13 -0
  80. package/types/kernel/shell/recents.d.ts +16 -0
  81. package/types/kernel/shell/useColorSchemeToggle.d.ts +10 -0
  82. package/types/kernel/shell/useFreshness.d.ts +25 -0
  83. package/types/kernel/shell/useNavCollapsed.d.ts +14 -0
  84. package/types/kernel/slots.d.ts +206 -0
  85. package/types/kernel/stream/sse.d.ts +22 -0
  86. package/types/kernel/stream/useClusterStream.d.ts +27 -0
  87. package/types/kernel/stream/useUserStream.d.ts +11 -0
  88. package/types/kernel/time/Ago.d.ts +9 -0
  89. package/types/kernel/time/ranges.d.ts +32 -0
  90. package/types/kernel/time/time.d.ts +89 -0
  91. package/types/kernel/time/timezone.d.ts +44 -0
  92. package/types/kernel/useDismissedNotice.d.ts +3 -0
  93. package/types/sdk/index.d.ts +92 -0
  94. package/types/ui/ActionMenuItem.d.ts +27 -0
  95. package/types/ui/AnchoredMenu.d.ts +20 -0
  96. package/types/ui/CapabilityGate.d.ts +23 -0
  97. package/types/ui/CapabilityReason.d.ts +11 -0
  98. package/types/ui/CodeEditor.d.ts +31 -0
  99. package/types/ui/ConfirmDialog.d.ts +51 -0
  100. package/types/ui/DescriptionList.d.ts +26 -0
  101. package/types/ui/DiagramView.d.ts +35 -0
  102. package/types/ui/DialogActions.d.ts +26 -0
  103. package/types/ui/EmptyState.d.ts +42 -0
  104. package/types/ui/ErrorState.d.ts +36 -0
  105. package/types/ui/FieldRow.d.ts +9 -0
  106. package/types/ui/HeldRequestLink.d.ts +4 -0
  107. package/types/ui/HoldToConfirm.d.ts +22 -0
  108. package/types/ui/LoadingState.d.ts +16 -0
  109. package/types/ui/NodeOutcomeSummary.d.ts +59 -0
  110. package/types/ui/Notice.d.ts +18 -0
  111. package/types/ui/Page.d.ts +13 -0
  112. package/types/ui/PageHeader.d.ts +18 -0
  113. package/types/ui/Pager.d.ts +21 -0
  114. package/types/ui/Section.d.ts +22 -0
  115. package/types/ui/Stat.d.ts +20 -0
  116. package/types/ui/StatusBadge.d.ts +11 -0
  117. package/types/ui/Toolbar.d.ts +19 -0
  118. package/types/ui/capabilityGate.d.ts +43 -0
  119. package/types/ui/codeDiagnostics.d.ts +11 -0
  120. package/types/ui/codeMirrorTheme.d.ts +11 -0
  121. package/types/ui/diagram.d.ts +49 -0
  122. package/types/ui/errorReading.d.ts +30 -0
  123. package/types/ui/formErrors.d.ts +10 -0
  124. package/types/ui/graph/ViewControls.d.ts +19 -0
  125. package/types/ui/graph/elk.d.ts +3 -0
  126. package/types/ui/held.d.ts +12 -0
  127. package/types/ui/inAppNavigation.d.ts +5 -0
  128. package/types/ui/nodeOutcome.d.ts +13 -0
  129. package/types/ui/notify.d.ts +77 -0
  130. package/types/ui/safeHref.d.ts +8 -0
  131. package/types/ui/table/ColumnsMenu.d.ts +26 -0
  132. package/types/ui/table/DataTable.d.ts +109 -0
  133. package/types/ui/table/GridFind.d.ts +16 -0
  134. package/types/ui/table/GridTable.d.ts +49 -0
  135. package/types/ui/table/HeaderCell.d.ts +25 -0
  136. package/types/ui/table/MiddleTruncate.d.ts +21 -0
  137. package/types/ui/table/StaticTable.d.ts +14 -0
  138. package/types/ui/table/TableStates.d.ts +35 -0
  139. package/types/ui/table/columns.d.ts +49 -0
  140. package/types/ui/table/density.d.ts +13 -0
  141. package/types/ui/table/gridFind.d.ts +7 -0
  142. package/types/ui/table/index.d.ts +5 -0
  143. package/types/ui/table/layout.d.ts +48 -0
  144. package/types/ui/table/measure.d.ts +16 -0
  145. package/types/ui/table/measurement.d.ts +92 -0
  146. package/types/ui/table/menuAnchor.d.ts +12 -0
  147. package/types/ui/table/rovingGrid.d.ts +37 -0
  148. package/types/ui/table/sort.d.ts +14 -0
  149. package/types/ui/table/tableState.d.ts +51 -0
  150. package/types/ui/table/useGridFind.d.ts +18 -0
  151. package/types/ui/trustedTypes.d.ts +16 -0
  152. package/types/ui/useTruncated.d.ts +8 -0
  153. package/vite.d.ts +14 -0
  154. package/vite.js +62 -0
@@ -0,0 +1,25 @@
1
+ import type { PointerEvent } from 'react';
2
+ import type { Column } from './columns.ts';
3
+ import type { HeaderSorting } from './sort.ts';
4
+ interface HeaderCellProps<T> {
5
+ /** A `div` with the `columnheader` role in the grid, a native `th` in the static table. */
6
+ as: 'div' | 'th';
7
+ column: Column<T>;
8
+ /** Null when the column cannot sort here. */
9
+ sorting: HeaderSorting | null;
10
+ onSort: () => void;
11
+ /** The grid's resize handle and its fit-to-content double-click; the static table has neither. */
12
+ resize?: {
13
+ onStart: (e: PointerEvent<HTMLElement>) => void;
14
+ onFit: () => void;
15
+ };
16
+ /** Where the cell is in the grid's focus model, and its 1-based `aria-colindex`. */
17
+ grid?: {
18
+ col: number;
19
+ index: number;
20
+ };
21
+ className?: string;
22
+ }
23
+ /** A column's header cell, shared by both renderers: its name or sort button, and the border handle that resizes it. */
24
+ export declare function HeaderCell<T>({ as: Tag, column, sorting, onSort, resize, grid, className, }: Readonly<HeaderCellProps<T>>): import("react").JSX.Element;
25
+ export {};
@@ -0,0 +1,21 @@
1
+ /**
2
+ * An identifier shortened in the middle: the start shrinks and the last characters stay, so names that
3
+ * share a prefix (`DLQ.orders.a1b2…`, `DLQ.orders.c3d4…`) stay distinguishable. The full value is the
4
+ * cell's `title` and its reveal panel, and the clipped start stays in the DOM, so it can still be
5
+ * selected and read.
6
+ *
7
+ * The two parts are hidden from assistive technology and from `getByText`, which read the whole value from
8
+ * one visually hidden span instead: read in pieces, the parts come out as two words with a space between.
9
+ *
10
+ * Outside a table, where no cell offers the full value, `tooltip` names it on hover and on keyboard focus:
11
+ * the shortened name takes a tab stop only while it is actually shortened.
12
+ *
13
+ * The ellipsis is the tail's own leading mark, shown only while the start is clipped. `text-overflow`
14
+ * would put it right after the last whole character of the start and leave the rest of the start's box
15
+ * empty between it and the tail: a gap of up to one character. Here the start's box ends exactly where
16
+ * the ellipsis begins, so the start, the ellipsis and the tail abut.
17
+ */
18
+ export declare function MiddleTruncate({ text, tooltip }: Readonly<{
19
+ text: string;
20
+ tooltip?: boolean;
21
+ }>): import("react").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { TableModel } from './DataTable.tsx';
3
+ /**
4
+ * The small, read-only renderer of `DataTable` (ADR-0160): a native `<table>` through Mantine's
5
+ * `Table`, with tabular figures, a header that sticks to the page, and the same column model and
6
+ * solver as the grid. The layout is fixed, so the solved widths hold and an identifier or code value
7
+ * is shortened by its kind (middle or end) instead of widening its column. Not virtualised, so cells
8
+ * hold natively focusable controls and the keyboard needs no grid model. `DataTable` switches to the
9
+ * grid above 200 rows.
10
+ */
11
+ export declare function StaticTable<T>({ model, caption }: Readonly<{
12
+ model: TableModel<T>;
13
+ caption?: ReactNode;
14
+ }>): import("react").JSX.Element;
@@ -0,0 +1,35 @@
1
+ import type { ReactNode } from 'react';
2
+ /** How many placeholder rows a table that is loading shows. */
3
+ export declare const SKELETON_ROWS = 8;
4
+ /**
5
+ * The grid's loading rows: placeholders under the header, in the same tracks and at the density's
6
+ * row height, so the page does not move when the rows arrive. Hidden from assistive technology and
7
+ * outside `role="grid"`; `LoadingLabel` says what is loading.
8
+ */
9
+ export declare function SkeletonRows({ tracks }: Readonly<{
10
+ tracks: number;
11
+ }>): import("react").JSX.Element;
12
+ /** The static table's loading rows. */
13
+ export declare function SkeletonTableRows({ columns }: Readonly<{
14
+ columns: number;
15
+ }>): import("react").JSX.Element;
16
+ /** What a screen reader hears while the placeholders show. */
17
+ export declare function LoadingLabel({ label }: Readonly<{
18
+ label: string;
19
+ }>): import("react").JSX.Element;
20
+ /**
21
+ * The thin bar over a table whose rows stay visible while they are fetched again. Its track is
22
+ * always there, so the table does not move when a refetch starts.
23
+ */
24
+ export declare function RefetchBar({ active }: Readonly<{
25
+ active: boolean;
26
+ }>): import("react").JSX.Element;
27
+ /**
28
+ * The empty or error content, a sibling of the grid and never a child of it. `reserveRows` keeps it at
29
+ * least that many rows tall, less the gap the frame puts above it: the height the loading rows had, so
30
+ * a failure in place of them moves nothing below.
31
+ */
32
+ export declare function StateSlot({ children, reserveRows }: Readonly<{
33
+ children: ReactNode;
34
+ reserveRows?: number;
35
+ }>): import("react").JSX.Element;
@@ -0,0 +1,49 @@
1
+ import type { ReactNode } from 'react';
2
+ /** What a column holds. It sets the column's bounds, font and how an overlong value is shortened. */
3
+ export type ColumnKind = 'text' | 'identifier' | 'code' | 'number' | 'time' | 'status';
4
+ /**
5
+ * How much a column matters when the table is too narrow for all of them. `essential` is never hidden;
6
+ * `low` goes before `high`. The first data column and any column that names the node a row came from
7
+ * are `essential`.
8
+ */
9
+ export type ColumnPriority = 'essential' | 'high' | 'low';
10
+ export interface Column<T> {
11
+ id: string;
12
+ header: string;
13
+ /**
14
+ * What the header cell draws when `header` is too long for the column, which is then as wide as its
15
+ * figures. `header` stays the column's name: the Columns menu, the announcements and assistive
16
+ * technology use it, and `description` says what the short label stands for.
17
+ */
18
+ short?: string;
19
+ /** The plain value of the cell: what is measured, copied, revealed and put in its `title`. */
20
+ accessor: (row: T) => unknown;
21
+ cell?: (row: T) => ReactNode;
22
+ kind: ColumnKind;
23
+ priority: ColumnPriority;
24
+ /** Bounds in `ch`, overriding the kind's. */
25
+ min?: number;
26
+ max?: number;
27
+ /** Whether the column shares spare width, overriding the kind's. */
28
+ grow?: boolean;
29
+ /**
30
+ * The cell is drawn as a `StatusBadge`, whose padding and border widen it beyond its text, so the
31
+ * Measurer sizes it with them. Plain-word `status` columns (a type, "yes"/"no") are not badges.
32
+ */
33
+ badge?: boolean;
34
+ /** Static table only: wrap the value instead of shortening it. */
35
+ wrap?: boolean;
36
+ /** The `sort` query value this column sorts by, if sortable. */
37
+ sortKey?: string;
38
+ description?: string;
39
+ }
40
+ interface KindPreset {
41
+ /** Bounds in `ch`; a kind without them is as wide as its content. */
42
+ min?: number;
43
+ max?: number;
44
+ grow: boolean;
45
+ truncate: 'end' | 'middle' | 'none';
46
+ mono: boolean;
47
+ }
48
+ export declare const KIND_PRESETS: Record<ColumnKind, KindPreset>;
49
+ export {};
@@ -0,0 +1,13 @@
1
+ export type Density = 'compact' | 'comfortable';
2
+ /** The browser-storage key `public/boot-prefs.js` reads before the first paint (ADR-0162). */
3
+ export declare const DENSITY_KEY = "as:density";
4
+ /** The density a control would switch to, named for what it does, shared by the user menu and the palette. */
5
+ export declare function densityToggleLabel(density: Density): string;
6
+ /**
7
+ * The viewer's table density, for every table (ADR-0162): a per-browser preference, not part of the URL.
8
+ *
9
+ * Storage is read synchronously, so the first render already uses it; `boot-prefs.js` has put the same
10
+ * value on `<html data-density>` before React ran, and the hook keeps that attribute in step afterwards.
11
+ * A consumer that sizes rows in JavaScript reads the height from the theme's `other.density[density]`.
12
+ */
13
+ export declare function useDensity(): [Density, (density: Density) => void];
@@ -0,0 +1,7 @@
1
+ import type { Column } from './columns.ts';
2
+ /** The zero-based positions of the rows with a shown cell that contains the query, ignoring case. */
3
+ export declare function findRows<T>(columns: readonly Column<T>[], data: readonly T[], query: string): number[];
4
+ /** The match after or before the current one, wrapping at both ends; -1 where there are none. */
5
+ export declare function stepMatch(current: number, count: number, by: 1 | -1): number;
6
+ /** What the find says about its result, for the eye and for a screen reader. */
7
+ export declare function findSummary(query: string, count: number, current: number): string;
@@ -0,0 +1,5 @@
1
+ export { DataTable, STATIC_ROW_LIMIT, type DataTableProps, type TableToolbar } from './DataTable.tsx';
2
+ export { KIND_PRESETS, type Column, type ColumnKind, type ColumnPriority } from './columns.ts';
3
+ export { DENSITY_KEY, densityToggleLabel, useDensity, type Density } from './density.ts';
4
+ export type { RowMenu, RowMenuContext } from './GridTable.tsx';
5
+ export { MiddleTruncate } from './MiddleTruncate.tsx';
@@ -0,0 +1,48 @@
1
+ import type { ColumnPriority } from './columns.ts';
2
+ /** A column as the solver sees it: every width in px. */
3
+ export interface SolverColumn {
4
+ id: string;
5
+ /** The measured width of the column's content. */
6
+ intrinsic: number;
7
+ min: number;
8
+ max: number;
9
+ grow: boolean;
10
+ /** Whether its values can be shortened, so the column may go down to `min`. */
11
+ truncates: boolean;
12
+ priority: ColumnPriority;
13
+ /** A width the operator set. It is kept exactly: never clamped and never shrunk. */
14
+ userWidth?: number;
15
+ /** The operator chose to show this column, so it is never hidden. */
16
+ userShown?: boolean;
17
+ /** Never hidden, whatever its priority (a node-attribution column). */
18
+ essential?: boolean;
19
+ }
20
+ export interface SolveResult {
21
+ /** `grid-template-columns` for the visible data columns, in order. The select and actions columns are the renderer's. */
22
+ template: string;
23
+ /** The px width each visible column gets once the grid is laid out, keyed by column id. */
24
+ widths: Record<string, number>;
25
+ /** The ids of the hidden columns, in column order. */
26
+ hidden: string[];
27
+ /** Even the shortest widths do not fit: the table scrolls sideways. */
28
+ overflow: boolean;
29
+ }
30
+ /**
31
+ * Lays the columns out in `W` px, the grid's inline size; `fixed` is the px of the select and actions
32
+ * columns the renderer adds beside them. Pure, and the only place the table decides what fits.
33
+ *
34
+ * 1. A width the operator set is a hard track.
35
+ * 2. When everything fits, grow columns get `minmax(base, 1fr)` and the rest their base.
36
+ * 3. Otherwise truncatable columns shrink toward their minimum.
37
+ * 4. Otherwise `low`, then `high`, columns are hidden, inline end first. `prev` supplies the
38
+ * hysteresis. Essential columns, the first data column and columns the operator chose to show stay.
39
+ * 5. Otherwise the minimums are used and the table overflows.
40
+ *
41
+ * `W === 0` (no layout yet, as in jsdom) shows every column at its base.
42
+ */
43
+ export declare function solveColumns(input: {
44
+ W: number;
45
+ cols: SolverColumn[];
46
+ prev?: SolveResult;
47
+ fixed?: number;
48
+ }): SolveResult;
@@ -0,0 +1,16 @@
1
+ import { type RefObject } from 'react';
2
+ import type { MeasureColumn } from './measurement.ts';
3
+ interface MeasurerProps {
4
+ fields: MeasureColumn[];
5
+ sample: string[][];
6
+ rootRef: RefObject<HTMLDivElement | null>;
7
+ }
8
+ /**
9
+ * Where column widths come from (ADR-0161): an `inert`, `aria-hidden`, zero-size box, clipped so it
10
+ * can never widen the page, holding a `max-content` grid of the header and a sample of the values.
11
+ * Each cell is in its kind's font and bounded in `ch`, so a track's width is already clamped, and
12
+ * because the grid does not depend on the table's own width, what it reports cannot lock a column at
13
+ * the width it was stretched to.
14
+ */
15
+ export declare const Measurer: import("react").NamedExoticComponent<Readonly<MeasurerProps>>;
16
+ export {};
@@ -0,0 +1,92 @@
1
+ import { type RefObject } from 'react';
2
+ import { type Column } from './columns.ts';
3
+ /** What a column is, once its kind's preset and its own overrides are resolved. */
4
+ export interface ColumnSpec {
5
+ /** Bounds in `ch`; a column without them is as wide as its content. */
6
+ min?: number;
7
+ max?: number;
8
+ grow: boolean;
9
+ /** Whether the solver may take it below its content width, by shortening or wrapping the value. */
10
+ truncates: boolean;
11
+ truncate: 'end' | 'middle' | 'none';
12
+ mono: boolean;
13
+ /** Text-like kinds are the ones whose longest values are sampled. */
14
+ textLike: boolean;
15
+ /** Figures and times: tabular digits. */
16
+ tabular: boolean;
17
+ alignEnd: boolean;
18
+ /** Drawn as a `StatusBadge`: its padding and border are measured with the text. */
19
+ badge: boolean;
20
+ }
21
+ export declare function columnSpec<T>(column: Column<T>): ColumnSpec;
22
+ /** The text of a cell whose column draws nothing of its own: the value, or nothing for none. */
23
+ export declare function cellText(value: unknown): string;
24
+ /**
25
+ * What the Measurer renders: the text of the first rows of the page, then the longest values of each
26
+ * text-like column beyond them, one row each with the other cells empty. One string per column.
27
+ */
28
+ export declare function sampleRows<T>(columns: Column<T>[], data: readonly T[]): string[][];
29
+ /** The px of the things a `ch` or a `rem` stands for, which the solver needs and only layout knows. */
30
+ export interface Metrics {
31
+ /** One `ch` of the UI typeface and of the monospace one. */
32
+ ch: number;
33
+ mono: number;
34
+ /** A cell's padding on both sides. */
35
+ pad: number;
36
+ /** The select and actions columns. */
37
+ select: number;
38
+ actions: number;
39
+ }
40
+ interface Measurement {
41
+ metrics: Metrics;
42
+ /** The px each column's content needs, padding included and already clamped to its bounds. */
43
+ intrinsic: Record<string, number>;
44
+ }
45
+ /** Reads the Measurer's layout: the probes, then the header row, which is where each track's width shows. */
46
+ export declare function readMeasurement(root: HTMLElement | null, ids: readonly string[]): Measurement | null;
47
+ /** What the Measurer draws for one column. */
48
+ export interface MeasureColumn {
49
+ id: string;
50
+ header: string;
51
+ sortable: boolean;
52
+ spec: ColumnSpec;
53
+ }
54
+ interface MeasurementInput<T> {
55
+ columns: Column<T>[];
56
+ data: readonly T[];
57
+ density: string;
58
+ /** Whether the viewer is in the table, so live growth must wait. */
59
+ isBusy: () => boolean;
60
+ /**
61
+ * Whether the table has a width, so its Measurer has a layout to read. A table inside a hidden tab
62
+ * has none; it is measured when it is first shown, never from a read that saw nothing.
63
+ */
64
+ shown: boolean;
65
+ }
66
+ interface MeasurementResult {
67
+ measurement: Measurement;
68
+ /** The props of the Measurer, which the table renders inside its frame so it inherits the table's type. */
69
+ measurerProps: {
70
+ fields: MeasureColumn[];
71
+ sample: string[][];
72
+ rootRef: RefObject<HTMLDivElement | null>;
73
+ };
74
+ /** Measures again, at once and from scratch (a double-click on a column border). */
75
+ refit: () => void;
76
+ /** Applies growth that was held back, once the viewer has left the table. */
77
+ resume: () => void;
78
+ }
79
+ /**
80
+ * Measures the columns when, and only when, ADR-0161 says to, in a layout effect so it is before
81
+ * paint: the first non-empty data, a change to the column set, fonts finishing loading, a density
82
+ * change, and an explicit refit. Rows that arrive later can only widen columns, at most every
83
+ * 2 seconds, and never while the viewer is reading the table.
84
+ */
85
+ export declare function useMeasurement<T>({ columns, data, density, isBusy, shown, }: Readonly<MeasurementInput<T>>): MeasurementResult;
86
+ /**
87
+ * Reports the inline size of an element now and whenever it changes, from one ResizeObserver that
88
+ * is throttled to a frame. Never from scroll. Reads `clientWidth`, so where there is no layout
89
+ * (jsdom) it is 0, which the solver takes as "show every column at its base".
90
+ */
91
+ export declare function useInlineSize(ref: RefObject<HTMLElement | null>, onSize: (px: number) => void): void;
92
+ export {};
@@ -0,0 +1,12 @@
1
+ /** A viewport point the menu opens from: the pointer, or just under the control that opened it. */
2
+ export interface MenuAnchor {
3
+ x: number;
4
+ y: number;
5
+ }
6
+ /** The anchor just under an element, at its inline start, for a menu opened from the keyboard. */
7
+ export declare function anchorBelow(element: Element): MenuAnchor;
8
+ /**
9
+ * Keeps an anchor inside the viewport. A point outside it counts as a hidden reference, and the
10
+ * positioning engine then hides the menu outright rather than showing it at the edge.
11
+ */
12
+ export declare function clampToViewport(anchor: MenuAnchor): MenuAnchor;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The keyboard model of a data grid (ADR-0108): one tab stop, and the WAI-ARIA APG grid keys to
3
+ * move between cells. Pure, so the moves are tested apart from any rendering.
4
+ *
5
+ * <p>Row 0 is the header row; body rows are 1…`rows`. Columns are 0…`cols - 1` in visual order.
6
+ */
7
+ export interface GridPos {
8
+ row: number;
9
+ col: number;
10
+ }
11
+ interface GridShape {
12
+ /** Body rows; the header row is added on top as row 0. */
13
+ rows: number;
14
+ cols: number;
15
+ /** Rows a Page Up / Page Down moves by. */
16
+ page: number;
17
+ /** In a right-to-left page, ArrowLeft moves toward the end of the row. */
18
+ rtl?: boolean;
19
+ }
20
+ interface GridKey {
21
+ key: string;
22
+ ctrlKey?: boolean;
23
+ metaKey?: boolean;
24
+ }
25
+ /**
26
+ * Where a key moves focus from `pos`, or null when the key is not a movement key. A move past an
27
+ * edge stays at the edge rather than wrapping: a grid is not a ring, and wrapping from the last
28
+ * row to the header would read as the view having jumped.
29
+ */
30
+ export declare function nextCell(pos: GridPos, input: GridKey, shape: GridShape): GridPos | null;
31
+ /**
32
+ * The row index a remembered row key resolves to after the data changed: its new index when it is
33
+ * still there, otherwise the nearest surviving neighbour of where it was, so that removing the
34
+ * focused row hands focus to the row that took its place.
35
+ */
36
+ export declare function resolveRow(keys: readonly string[], key: string | null, lastIndex: number): number;
37
+ export {};
@@ -0,0 +1,14 @@
1
+ /** How a sortable column stands: whether the table is sorted by it, and which way. */
2
+ export interface HeaderSorting {
3
+ active: boolean;
4
+ desc: boolean;
5
+ }
6
+ /** A `sort` query value as the column key it names and whether it descends (a leading `-`). */
7
+ export declare function parseSort(sort: string | undefined): {
8
+ field: string | undefined;
9
+ desc: boolean;
10
+ };
11
+ /** The sort a click on `key`'s header asks for: ascending, then descending, then none. */
12
+ export declare function nextSort(sort: string | undefined, key: string): string | undefined;
13
+ /** How a column with `sortKey` stands under `sort`, or null when it cannot sort here. */
14
+ export declare function sortingOf(sort: string | undefined, sortKey: string | undefined, enabled: boolean): HeaderSorting | null;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * What a viewer has done to one table (ADR-0161): the widths they set, the columns they hid or chose
3
+ * to show, and their order. Stored per browser, never in the URL. It is the shape a saved view would
4
+ * persist.
5
+ */
6
+ export interface TableState {
7
+ v: 1;
8
+ /** Widths in px a viewer set. Each is a hard track: fitting never shrinks it. */
9
+ widths: Record<string, number>;
10
+ /** Columns the viewer hid. */
11
+ hidden: string[];
12
+ /** Columns the viewer chose to show, which the solver never hides for lack of room. */
13
+ shown: string[];
14
+ /** Column ids in the order the viewer wants; ids it does not list follow in their own order. */
15
+ order: string[];
16
+ }
17
+ export declare const EMPTY_TABLE_STATE: TableState;
18
+ /** The narrowest a viewer can make a column. */
19
+ export declare const MIN_COLUMN_WIDTH = 48;
20
+ /** The state a stored string holds, or the empty one when it is missing, not JSON, or from another shape. */
21
+ export declare function parseTableState(raw: string | null): TableState;
22
+ /** The stored state for a table, or the empty one when it has no key or storage is unavailable. */
23
+ export declare function readTableState(storageKey: string | undefined): TableState;
24
+ /** The state with `id` set to `width` px, within what a column can be. */
25
+ export declare function withWidth(state: TableState, id: string, width: number): TableState;
26
+ /** The state with `id` back to fitting. */
27
+ export declare function withoutWidth(state: TableState, id: string): TableState;
28
+ /** The state with every width back to fitting. */
29
+ export declare function withoutWidths(state: TableState): TableState;
30
+ /** The state with `id` shown (and kept shown) or hidden. */
31
+ export declare function withVisibility(state: TableState, id: string, visible: boolean): TableState;
32
+ /**
33
+ * The columns in the order a viewer chose: those it lists first, in its order, then the rest as
34
+ * declared. An id the table no longer has is ignored. The first declared column identifies a row and
35
+ * stays first, whatever the stored order says.
36
+ */
37
+ export declare function orderColumns<C extends {
38
+ id: string;
39
+ }>(columns: C[], order: string[]): C[];
40
+ /**
41
+ * The state with `id` moved one place earlier (`-1`) or later (`1`) among `ids`, which are every
42
+ * column's id in the order now shown. The first column stays first, so nothing moves before it, and a
43
+ * move past either end leaves the state as it was.
44
+ */
45
+ export declare function withMovedColumn(state: TableState, ids: string[], id: string, by: -1 | 1): TableState;
46
+ /**
47
+ * A table's state, read from `as.table.<storageKey>` and read again whenever the key changes (a view
48
+ * that serves several resource kinds keeps each kind's widths apart). Without a key the state lasts
49
+ * as long as the table is shown. `update` writes through to storage.
50
+ */
51
+ export declare function useTableState(storageKey: string | undefined): [TableState, (change: (state: TableState) => TableState) => void];
@@ -0,0 +1,18 @@
1
+ import type { Column } from './columns.ts';
2
+ /** The find bar's state; `epoch` changes each time it is opened, so its input is focused anew. */
3
+ export interface FindState {
4
+ query: string;
5
+ cursor: number;
6
+ epoch: number;
7
+ }
8
+ /**
9
+ * The grid's own find (the browser's cannot see rows the virtualizer has not rendered): the bar's state,
10
+ * the matching rows, and the row the find stands on, which `scrollTo` brings into view.
11
+ */
12
+ export declare function useGridFind<T>(columns: readonly Column<T>[], data: readonly T[], scrollTo: (row: number) => void): {
13
+ find: FindState | null;
14
+ setFind: import("react").Dispatch<import("react").SetStateAction<FindState | null>>;
15
+ matches: number[];
16
+ cursor: number;
17
+ foundRow: number;
18
+ };
@@ -0,0 +1,16 @@
1
+ /** Installed once, before anything renders. Where Trusted Types is not enforced it changes nothing. */
2
+ export declare function installDefaultPolicy(): void;
3
+ /**
4
+ * A script URL for `new Worker(...)`: refused unless it is on this page's origin. Without Trusted
5
+ * Types (tests, older browsers) it is the string itself.
6
+ */
7
+ export declare function workerScriptUrl(url: string): string;
8
+ /**
9
+ * The markup the code highlighter produced, cleaned. Syntax-highlighted code is the one place Rahdar
10
+ * renders HTML (Mantine sets it with `dangerouslySetInnerHTML`), and its text comes from broker data:
11
+ * message bodies, headers, configuration. The highlighter escapes it, and this is the second line: only
12
+ * `<span>` elements with a class and a style survive, whatever the input, and where Trusted Types is
13
+ * available the result is a `TrustedHTML` the sink accepts. Typed as a string because that is what
14
+ * Mantine's adapter contract says; React hands it to the sink untouched.
15
+ */
16
+ export declare function highlightedMarkup(html: string): string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Whether the element's text is cut off by an ellipsis right now, so a `title` is added only when it
3
+ * tells the reader something the row does not already show. `text` re-measures when the words change.
4
+ */
5
+ export declare function useTruncated<T extends HTMLElement>(text: string): {
6
+ ref: import("react").RefObject<T | null>;
7
+ truncated: boolean;
8
+ };
package/vite.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { PluginOption } from 'vite';
2
+
3
+ /** Options for {@link rahdarPlugin}. */
4
+ export interface RahdarPluginOptions {
5
+ /** The plugin's id, exactly as its `plugin.json` declares it. */
6
+ id: string;
7
+ /** The module whose default export is the plugin (`definePlugin(...)`). Default `./src/feature.tsx`. */
8
+ entry?: string;
9
+ /** Where the bundle goes. Default `target/classes/META-INF/rahdar/ui`, inside the plugin jar. */
10
+ outDir?: string;
11
+ }
12
+
13
+ /** Vite configuration for a plugin's UI: a Module Federation remote that shares Rahdar's libraries. */
14
+ export function rahdarPlugin(options: RahdarPluginOptions): PluginOption[];
package/vite.js ADDED
@@ -0,0 +1,62 @@
1
+ import { federation } from '@module-federation/vite';
2
+
3
+ import { SDK, SHARED_LIBRARIES, packageOf } from './shared.js';
4
+ import peers from './peers.json' with { type: 'json' };
5
+
6
+ /**
7
+ * Vite configuration for a plugin's UI (ADR-0100): a Module Federation remote named after the
8
+ * plugin, exposing `./feature`, that takes React, Mantine, TanStack and this SDK from the running
9
+ * Rahdar (`import: false`), with a relative base so it is served from wherever Rahdar mounts it,
10
+ * built into the jar's `META-INF/rahdar/ui/`.
11
+ *
12
+ * The build fails on an import Rahdar does not share — `@mantine/notifications`, say, or
13
+ * Mantine's CSS — since a plugin's own copy would load beside Rahdar's and silently misbehave.
14
+ *
15
+ * @param {{ id: string, entry?: string, outDir?: string }} options
16
+ * @returns {import('vite').PluginOption[]}
17
+ */
18
+ export function rahdarPlugin({ id, entry = './src/feature.tsx', outDir = 'target/classes/META-INF/rahdar/ui' }) {
19
+ if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(id)) {
20
+ throw new Error(
21
+ `rahdarPlugin: "${id}" is not a plugin id (lowercase kebab-case, at least two segments, as in plugin.json)`,
22
+ );
23
+ }
24
+ const shared = Object.fromEntries([
25
+ ...SHARED_LIBRARIES.map((name) => [
26
+ name,
27
+ { singleton: true, import: false, requiredVersion: peers[packageOf(name)] },
28
+ ]),
29
+ [SDK, { singleton: true, import: false, requiredVersion: false }],
30
+ ]);
31
+ const allowed = new Set([...SHARED_LIBRARIES.map(packageOf), SDK]);
32
+
33
+ return [
34
+ {
35
+ name: 'rahdar-plugin',
36
+ // A remote has no index.html: the exposed module is the build's input, remoteEntry.js its entry.
37
+ config: () => ({
38
+ base: './',
39
+ build: { outDir, emptyOutDir: true, target: 'esnext', rolldownOptions: { input: entry } },
40
+ }),
41
+ resolveId(source, importer) {
42
+ if (!importer || !source.startsWith('@mantine/')) return null;
43
+ if (allowed.has(packageOf(source)) && !source.endsWith('.css')) return null;
44
+ this.error(
45
+ `${source} is not shared by Rahdar, so a plugin would load its own copy beside Rahdar's. ` +
46
+ (source.startsWith('@mantine/notifications')
47
+ ? 'Use notify from @rahdar/plugin-sdk instead.'
48
+ : source.endsWith('.css')
49
+ ? "Rahdar already loads Mantine's styles; remove this import."
50
+ : 'Use @mantine/core and @mantine/hooks only.'),
51
+ );
52
+ },
53
+ },
54
+ federation({
55
+ name: `plugin_${id.replace(/-/g, '_')}`,
56
+ filename: 'remoteEntry.js',
57
+ exposes: { './feature': entry },
58
+ shared,
59
+ dts: false,
60
+ }),
61
+ ];
62
+ }