@deltarobotics/uhd-viewer 0.0.0-stage → 0.2.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +22 -0
  4. package/README.md +168 -2
  5. package/bin/serve.d.mts +62 -0
  6. package/bin/serve.mjs +257 -0
  7. package/bin/uhd-viewer.mjs +75 -0
  8. package/dist/app/assets/KodeMono-Bold-DdIivhPN.woff2 +0 -0
  9. package/dist/app/assets/KodeMono-Medium-CVnTuv5A.ttf +0 -0
  10. package/dist/app/assets/KodeMono-Regular-Bdr_-rJX.woff2 +0 -0
  11. package/dist/app/assets/KodeMono-SemiBold-JAfn5Dpm.ttf +0 -0
  12. package/dist/app/assets/index-Boi2erhd.css +2 -0
  13. package/dist/app/assets/index-CkpIRYgM.js +3853 -0
  14. package/dist/app/index.html +16 -0
  15. package/dist/components/components.css +6108 -0
  16. package/dist/components/index.d.ts +1 -0
  17. package/dist/components/index.js +26048 -0
  18. package/dist/components/index.js.map +1 -0
  19. package/dist/components/types/uhd-viewer/src/api.d.ts +286 -0
  20. package/dist/components/types/uhd-viewer/src/cad/CadView.d.ts +52 -0
  21. package/dist/components/types/uhd-viewer/src/cad/ModelView.d.ts +28 -0
  22. package/dist/components/types/uhd-viewer/src/cad/explode.d.ts +110 -0
  23. package/dist/components/types/uhd-viewer/src/cad/explodeSample.d.ts +25 -0
  24. package/dist/components/types/uhd-viewer/src/cad/findings.d.ts +41 -0
  25. package/dist/components/types/uhd-viewer/src/cad/labels.d.ts +76 -0
  26. package/dist/components/types/uhd-viewer/src/cad/model.d.ts +132 -0
  27. package/dist/components/types/uhd-viewer/src/cad/row.d.ts +15 -0
  28. package/dist/components/types/uhd-viewer/src/cad/scene.d.ts +95 -0
  29. package/dist/components/types/uhd-viewer/src/cad/scope.d.ts +89 -0
  30. package/dist/components/types/uhd-viewer/src/canvas/Canvas.d.ts +86 -0
  31. package/dist/components/types/uhd-viewer/src/canvas/Icon.d.ts +5 -0
  32. package/dist/components/types/uhd-viewer/src/canvas/LinkEdge.d.ts +40 -0
  33. package/dist/components/types/uhd-viewer/src/canvas/Port.d.ts +18 -0
  34. package/dist/components/types/uhd-viewer/src/canvas/actions.d.ts +5 -0
  35. package/dist/components/types/uhd-viewer/src/canvas/geometry.d.ts +72 -0
  36. package/dist/components/types/uhd-viewer/src/canvas/interaction.d.ts +162 -0
  37. package/dist/components/types/uhd-viewer/src/canvas/nodes.d.ts +43 -0
  38. package/dist/components/types/uhd-viewer/src/canvas/reveal.d.ts +37 -0
  39. package/dist/components/types/uhd-viewer/src/canvas/rightDrag.d.ts +51 -0
  40. package/dist/components/types/uhd-viewer/src/canvas/routing.d.ts +28 -0
  41. package/dist/components/types/uhd-viewer/src/chrome/ArtifactCards.d.ts +30 -0
  42. package/dist/components/types/uhd-viewer/src/chrome/Artifacts.d.ts +44 -0
  43. package/dist/components/types/uhd-viewer/src/chrome/BoardInspector.d.ts +53 -0
  44. package/dist/components/types/uhd-viewer/src/chrome/Chrome.d.ts +116 -0
  45. package/dist/components/types/uhd-viewer/src/chrome/Evidence.d.ts +20 -0
  46. package/dist/components/types/uhd-viewer/src/chrome/InterfaceCards.d.ts +56 -0
  47. package/dist/components/types/uhd-viewer/src/chrome/PairView.d.ts +37 -0
  48. package/dist/components/types/uhd-viewer/src/chrome/Sections.d.ts +107 -0
  49. package/dist/components/types/uhd-viewer/src/components.d.ts +60 -0
  50. package/dist/components/types/uhd-viewer/src/host/channel.d.ts +49 -0
  51. package/dist/components/types/uhd-viewer/src/host/context.d.ts +29 -0
  52. package/dist/components/types/uhd-viewer/src/host/protocol.d.ts +22 -0
  53. package/dist/components/types/uhd-viewer/src/host/targets.d.ts +85 -0
  54. package/dist/components/types/uhd-viewer/src/layout/board-layout.d.ts +69 -0
  55. package/dist/components/types/uhd-viewer/src/layout/card-body.d.ts +64 -0
  56. package/dist/components/types/uhd-viewer/src/layout/layout.d.ts +94 -0
  57. package/dist/components/types/uhd-viewer/src/layout/module-layout.d.ts +32 -0
  58. package/dist/components/types/uhd-viewer/src/layout/router.d.ts +55 -0
  59. package/dist/components/types/uhd-viewer/src/layout/taps.d.ts +20 -0
  60. package/dist/components/types/uhd-viewer/src/model/artifacts.d.ts +129 -0
  61. package/dist/components/types/uhd-viewer/src/model/classification.d.ts +38 -0
  62. package/dist/components/types/uhd-viewer/src/model/diagnostics.d.ts +27 -0
  63. package/dist/components/types/uhd-viewer/src/model/evidence.d.ts +63 -0
  64. package/dist/components/types/uhd-viewer/src/model/from-uhd.d.ts +57 -0
  65. package/dist/components/types/uhd-viewer/src/model/hierarchy.d.ts +169 -0
  66. package/dist/components/types/uhd-viewer/src/model/isolate.d.ts +33 -0
  67. package/dist/components/types/uhd-viewer/src/model/nets.d.ts +53 -0
  68. package/dist/components/types/uhd-viewer/src/model/outputs.d.ts +79 -0
  69. package/dist/components/types/uhd-viewer/src/model/slots.d.ts +182 -0
  70. package/dist/components/types/uhd-viewer/src/model/types.d.ts +213 -0
  71. package/dist/components/types/uhd-viewer/src/options.d.ts +27 -0
  72. package/dist/components/types/uhd-viewer/src/source/source.d.ts +109 -0
  73. package/dist/components/types/uhd-viewer/src/source/tolerant.d.ts +45 -0
  74. package/dist/components/types/uhd-viewer/src/theme/ThemeProvider.d.ts +33 -0
  75. package/dist/components/types/uhd-viewer/src/theme/adapters.d.ts +28 -0
  76. package/dist/components/types/uhd-viewer/src/theme/resolve.d.ts +19 -0
  77. package/dist/components/types/uhd-viewer/src/theme/themes.d.ts +67 -0
  78. package/dist/components/types/uhd-viewer/src/theme/tokens.d.ts +175 -0
  79. package/dist/components/types/uhd-viewer/src/ui/Inspector.d.ts +45 -0
  80. package/dist/components/types/uhd-viewer/src/ui/Legend.d.ts +40 -0
  81. package/dist/components/types/uhd-viewer/src/ui/ScrollArea.d.ts +16 -0
  82. package/dist/components/types/uhd-viewer/src/ui/Toolbar.d.ts +49 -0
  83. package/dist/components/types/uhd-viewer/src/ui/Tooltips.d.ts +3 -0
  84. package/dist/components/types/uhd-viewer/src/ui/cx.d.ts +2 -0
  85. package/dist/components/types/uhd-viewer/src/ui/legendFit.d.ts +42 -0
  86. package/dist/components/types/uhd-viewer/src/viewer/controller.d.ts +218 -0
  87. package/dist/components/types/uhd-viewer/src/viewer/details.d.ts +81 -0
  88. package/dist/components/types/uhd-viewer/src/viewer/hierarchy.d.ts +60 -0
  89. package/dist/components/types/uhd-viewer/src/viewer/mount.d.ts +12 -0
  90. package/dist/components/types/uhd-viewer/src/viewer/views.d.ts +156 -0
  91. package/dist/headless/index.d.ts +71 -0
  92. package/dist/headless/index.js +7425 -0
  93. package/dist/headless/index.js.map +1 -0
  94. package/dist/lib/api.d.ts +252 -0
  95. package/dist/lib/uhd-viewer.css +3 -0
  96. package/dist/lib/uhd-viewer.d.ts +4 -0
  97. package/dist/lib/uhd-viewer.js +97469 -0
  98. package/package.json +110 -4
  99. package/src/styles/fonts/OFL.txt +93 -0
  100. package/src/styles/tailwind-theme.css +48 -0
@@ -0,0 +1,218 @@
1
+ import { Component, type ErrorInfo, type ReactNode } from "react";
2
+ import type { ChildLink } from "@deltarobotics/uhd";
3
+ import type { UhdBundleDiagnostic } from "@deltarobotics/uhd";
4
+ import type { Classification } from "../model/classification";
5
+ import type { ViewLink } from "../model/types";
6
+ import { type ComputedLayout, type LevelLayout, type LinkLayout } from "../layout/layout";
7
+ import type { Pt } from "../canvas/routing";
8
+ import { type LoadedSource } from "../source/source";
9
+ import type { ViewerEvent, ViewerOptions, ViewerSelection } from "../api";
10
+ import type { Selection, ViewCommand } from "../canvas/Canvas";
11
+ import { type CanvasTool, type Viewport } from "../canvas/interaction";
12
+ import type { Goto, NodeMenuItem, Panel } from "../chrome/Chrome";
13
+ import type { CadSelection } from "../cad/CadView";
14
+ import type { LegendStage } from "../ui/legendFit";
15
+ import type { CommandBus } from "../host/channel";
16
+ import { type HostActions } from "../host/context";
17
+ type Overrides = Record<string, ChildLink[]>;
18
+ /** What is being dragged right now (see LiveLayout). */
19
+ export interface Live {
20
+ nodes?: Set<string>;
21
+ links?: Set<string>;
22
+ }
23
+ export interface AppProps extends ViewerOptions {
24
+ /** Development only: absolute artifact bases are served through Vite's /@fs route. */
25
+ fsRoute?: boolean;
26
+ /** The host channel (mount.tsx): its messages, where events go, and which open actions the host takes. */
27
+ host?: HostLink;
28
+ }
29
+ export interface HostLink {
30
+ bus: CommandBus;
31
+ emit: (event: ViewerEvent) => void;
32
+ /** The host opens sources (the viewer offers OPEN SOURCE). */
33
+ source: boolean;
34
+ /** The host opens artifact files (instead of a new tab). */
35
+ artifact: boolean;
36
+ /** The host opens modules on their own (double-click), `onOpenModule`. */
37
+ module?: boolean;
38
+ /** The host shows the pair view (instead of the viewer's own over the diagram). */
39
+ pair?: boolean;
40
+ /** The host has an inspector of its own and shows a module there when asked (`onInspect`). */
41
+ inspect?: boolean;
42
+ }
43
+ /** Loads the UHD bundle (the viewer's only input): the source once loaded, or why not. */
44
+ export declare function useViewerSource(props: Pick<AppProps, "bundle" | "bundleUrl" | "resolveArtifact" | "fsRoute">): {
45
+ source: LoadedSource | null;
46
+ error: string | null;
47
+ empty: boolean;
48
+ };
49
+ /**
50
+ * The viewer's state and behaviour for one loaded bundle: what is drawn, what
51
+ * is selected, the drill level, the classification, layout edits, the host
52
+ * channel. Shells read it through `useViewer()` inside `UhdViewer`; the
53
+ * canvases, inspector panels, toolbar and legend are views of it.
54
+ */
55
+ export declare function useViewerController(source: LoadedSource, options: ViewerOptions, host?: HostLink): {
56
+ source: LoadedSource;
57
+ options: ViewerOptions;
58
+ scenario: import("../source/source").ViewerScenario;
59
+ scenarios: {
60
+ id: string;
61
+ label: string;
62
+ }[];
63
+ onScenario: (id: string) => void;
64
+ system: import("@deltarobotics/uhd").ModuleDef;
65
+ vm: import("../components").ViewModel;
66
+ drawn: import("../components").ViewModel;
67
+ layout: ComputedLayout;
68
+ hand: LevelLayout;
69
+ levelKey: string;
70
+ levelDef: import("@deltarobotics/uhd").ModuleDef;
71
+ drill: string[];
72
+ topLevel: boolean;
73
+ diagnostics: import("../model/diagnostics").ScopedDiagnostic[];
74
+ hostDiagnostics: UhdBundleDiagnostic[];
75
+ errors: number;
76
+ defFor: (id?: string) => import("@deltarobotics/uhd").ModuleDef | undefined;
77
+ bSlotsFor: (link: ViewLink) => string[];
78
+ view: "3d" | "diagram";
79
+ setView: import("react").Dispatch<import("react").SetStateAction<"3d" | "diagram">>;
80
+ mode: Classification;
81
+ setMode: (m: Classification) => void;
82
+ conductors: boolean;
83
+ setConductors: import("react").Dispatch<import("react").SetStateAction<boolean>>;
84
+ showGrounds: boolean;
85
+ setShowGrounds: import("react").Dispatch<import("react").SetStateAction<boolean>>;
86
+ isolated: ReadonlySet<string>;
87
+ isolation: import("../components").Isolation | null;
88
+ present: Set<string>;
89
+ onIsolate: (key: string, add?: boolean) => void;
90
+ clearIsolated: () => void;
91
+ legendStage: LegendStage;
92
+ setLegendStage: import("react").Dispatch<import("react").SetStateAction<LegendStage>>;
93
+ panel: Panel | null;
94
+ setPanel: import("react").Dispatch<import("react").SetStateAction<Panel | null>>;
95
+ selection: Selection;
96
+ setSelection: (s: Selection) => void;
97
+ group: readonly string[];
98
+ onSelectChanges: (changes: readonly {
99
+ id: string;
100
+ selected: boolean;
101
+ }[]) => void;
102
+ onSelectAll: () => void;
103
+ onEscape: () => void;
104
+ interaction: import("../components").InteractionState;
105
+ onInteraction: import("react").ActionDispatch<[action: import("../components").InteractionAction]>;
106
+ tool: CanvasTool;
107
+ setTool: (tool: CanvasTool) => void;
108
+ viewCommand: ViewCommand | undefined;
109
+ fitView: () => void;
110
+ zoomIn: () => void;
111
+ zoomOut: () => void;
112
+ viewport: Viewport | undefined;
113
+ /** Counts the times a host replaced the viewports: the canvas opens again on them. */
114
+ viewportsSeq: number;
115
+ onViewport: (v: Viewport | null) => void;
116
+ openLinks: Set<string>;
117
+ overrides: Overrides;
118
+ pair: ViewLink | undefined;
119
+ setPairLink: import("react").Dispatch<import("react").SetStateAction<string | null>>;
120
+ onNavigate: (depth: number) => void;
121
+ onDrill: (id: string) => void;
122
+ onGoto: (g: Goto) => void;
123
+ onPair: (l: ViewLink) => void;
124
+ onReset: () => void;
125
+ onToggleLink: (id: string) => void;
126
+ onToggleExpand: (id: string) => void;
127
+ onMove: (id: string, x: number, y: number) => void;
128
+ onOverride: (linkId: string, childLinks: ChildLink[] | null) => void;
129
+ editLink: (linkId: string, patch: LinkLayout) => void;
130
+ onPins: (linkId: string, pins: Pt[]) => void;
131
+ setLive: import("react").Dispatch<import("react").SetStateAction<Live | null>>;
132
+ centre: {
133
+ id: string;
134
+ seq: number;
135
+ } | undefined;
136
+ reveal: {
137
+ selection: NonNullable<Selection>;
138
+ seq: number;
139
+ } | undefined;
140
+ cadFocus: {
141
+ path: string;
142
+ seq: number;
143
+ kind?: "node" | "link" | "none";
144
+ look?: boolean;
145
+ } | undefined;
146
+ onCadSelect: (s: CadSelection) => void;
147
+ cadSelection: ViewerSelection | null;
148
+ focusPath: (path: string) => void;
149
+ hostActions: HostActions;
150
+ onOpenNode: (id: string) => void;
151
+ onNodeContext: (id: string, x: number, y: number) => void;
152
+ onPaneContext: (x: number, y: number) => void;
153
+ menu: {
154
+ id?: string;
155
+ x: number;
156
+ y: number;
157
+ } | null;
158
+ menuItems: NodeMenuItem[];
159
+ closeMenu: () => void;
160
+ };
161
+ /**
162
+ * What a double-click on a node does: `open` it on its own (the host's new
163
+ * tab), `expand` it in place, or `none`. Only a module that holds modules
164
+ * has a level to open or to expand; a part with nothing inside, a net's
165
+ * junction, a rail's tap and a boundary port have none.
166
+ */
167
+ export declare function openAction(node: {
168
+ defId?: string;
169
+ childCount?: number;
170
+ net?: unknown;
171
+ tapOf?: string;
172
+ sheetPort?: unknown;
173
+ } | undefined, hostOpens: boolean): "open" | "expand" | "none";
174
+ /** Everything a view of the loaded model reads (see useViewerController). */
175
+ export type ViewerController = ReturnType<typeof useViewerController>;
176
+ /** The viewer's state, inside `UhdViewer` (or `ViewerProvider`). */
177
+ export declare function useViewer(): ViewerController;
178
+ /** The viewer's state for a loaded source, for the components inside. */
179
+ export declare function ViewerProvider({ source, options, host, children }: {
180
+ source: LoadedSource;
181
+ options: ViewerOptions;
182
+ host?: HostLink;
183
+ children?: ReactNode;
184
+ }): import("react").JSX.Element;
185
+ export interface UhdViewerProps extends AppProps {
186
+ /** The views of the model: canvases, panels, the shell's own chrome. */
187
+ children?: ReactNode;
188
+ }
189
+ /**
190
+ * Loads the bundle, then provides the viewer's state to `children`. While
191
+ * loading, or when the bundle cannot be read, it says so in place.
192
+ */
193
+ export declare function UhdViewer({ children, ...props }: UhdViewerProps): import("react").JSX.Element;
194
+ /**
195
+ * A bundle the viewer cannot draw says so in place, instead of leaving an
196
+ * empty page: what failed, and that the next bundle is tried again (a
197
+ * producer that rebuilds on a source edit sends one).
198
+ */
199
+ export declare class ViewerBoundary extends Component<{
200
+ source: LoadedSource;
201
+ children?: ReactNode;
202
+ }, {
203
+ failed?: {
204
+ source: LoadedSource;
205
+ message: string;
206
+ };
207
+ }> {
208
+ state: {
209
+ failed?: {
210
+ source: LoadedSource;
211
+ message: string;
212
+ };
213
+ };
214
+ componentDidCatch(error: Error, info: ErrorInfo): void;
215
+ static getDerivedStateFromError(): null;
216
+ render(): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
217
+ }
218
+ export {};
@@ -0,0 +1,81 @@
1
+ /**
2
+ * The inspector's details for one thing of a bundle, without a viewer around
3
+ * it: what `ViewerInspector` shows for a selected module, link or net, for a
4
+ * host that has an inspector of its own (a native side view) and selects by
5
+ * path. The same components draw both, so a host's inspector and the
6
+ * viewer's show a module the same way.
7
+ *
8
+ * <ThemeProvider adapter={vscodeThemeAdapter()}>
9
+ * <SelectionDetails bundle={bundle} target={{ kind: "module", path: "stack/esc" }} host={{ openArtifact }} />
10
+ * </ThemeProvider>
11
+ *
12
+ * The level that holds the target is modelled as the viewer models it (its
13
+ * links, nets and checks), but nothing is laid out or drawn.
14
+ */
15
+ import { type ReactNode } from "react";
16
+ import type { ModuleDef } from "@deltarobotics/uhd";
17
+ import type { UhdBundle } from "@deltarobotics/uhd";
18
+ import type { ArtifactResolver } from "../api";
19
+ import { type HostActions } from "../host/context";
20
+ import type { Classification } from "../model/classification";
21
+ import { type HostFinding } from "../model/slots";
22
+ /** An interface card's request to its host: the module's path, the interface, and the links that end on it as their module declares them. */
23
+ export interface InterfaceRequest {
24
+ /** The module's instance path from the root. */
25
+ path: string;
26
+ interfaceId: string;
27
+ /** The module that declares the links (the level's), from the root. */
28
+ owner: string;
29
+ /** Its stored links by their local ids ("rx_fc_pads"). */
30
+ links: string[];
31
+ }
32
+ /** What to show: a module instance by its path from the root (`""`: the root), a link on the level of its owner, or a definition on its own. */
33
+ export type DetailsTarget = {
34
+ kind: "module";
35
+ path: string;
36
+ } | {
37
+ kind: "link";
38
+ owner: string;
39
+ ids: string[];
40
+ } | {
41
+ kind: "definition";
42
+ id: string;
43
+ };
44
+ export interface SelectionDetailsProps {
45
+ /** The bundle the target is in. Not given: only `definition` targets among `definitions` can be shown. */
46
+ bundle?: UhdBundle;
47
+ /** Definitions outside the bundle (a library part shown on its own), by their ids. */
48
+ definitions?: ModuleDef[];
49
+ target: DetailsTarget;
50
+ /** URL of a definition's artifact file; not given, files do not resolve (their cards show icons). */
51
+ resolveArtifact?: ArtifactResolver;
52
+ /** What the host takes over, and how artifacts are shown (host/context.ts). */
53
+ host?: HostActions;
54
+ /** How interface swatches are coloured (default: by domain). */
55
+ mode?: Classification;
56
+ /** A board's drawings with pan and zoom, as in the viewer (default false: the drawings are cards, nothing is fetched). */
57
+ boardDrawings?: boolean;
58
+ /** The user picked something else in the details (an end of a link, a net's member, a functional link): canonical ids from the root. */
59
+ onSelect?: (selection: {
60
+ kind: "node" | "link";
61
+ id: string;
62
+ }) => void;
63
+ /** The user asked for the pair view of the link shown. */
64
+ onPair?: (request: {
65
+ linkId: string;
66
+ a: string;
67
+ b: string;
68
+ }) => void;
69
+ /** Shown when the target is not in the bundle. */
70
+ missing?: ReactNode;
71
+ /** The host's findings for the interface cards (with the keys its Locate takes); not given, the viewer's own checks. */
72
+ findings?: HostFinding[];
73
+ /** A finding's Locate on an interface card. */
74
+ onFinding?: (key: string) => void;
75
+ /** An interface card's Open in source: the line of its link, else of the interface. */
76
+ onInterfaceSource?: (request: InterfaceRequest) => void;
77
+ /** An open slot's Connect…. */
78
+ onConnect?: (request: InterfaceRequest) => void;
79
+ className?: string;
80
+ }
81
+ export declare function SelectionDetails({ bundle, definitions, target, resolveArtifact, host, mode, boardDrawings, onSelect, onPair, missing, className, findings, onFinding, onInterfaceSource, onConnect }: SelectionDetailsProps): import("react").JSX.Element;
@@ -0,0 +1,60 @@
1
+ import { type HierarchyNode, type HierarchyPanelState } from "../model/hierarchy";
2
+ /** What a host asks of the panel: show a module's row, put the keyboard in the filter, open or fold it. */
3
+ export interface HierarchyCommand {
4
+ type: "reveal" | "filter" | "open" | "close" | "toggle";
5
+ /** For `reveal`: the module's instance path. */
6
+ path?: string;
7
+ /** A new number for every command (the same command twice is two). */
8
+ seq: number;
9
+ }
10
+ export interface ViewerHierarchyProps {
11
+ /** What the host kept for this tab (`onStateChange` gave it); anything malformed is ignored. */
12
+ state?: unknown;
13
+ /** The panel's state changed (open, width, open rows): a host keeps it per tab. */
14
+ onStateChange?: (state: HierarchyPanelState) => void;
15
+ /** The panel opened or folded (at once; a host's toggle button shows it). */
16
+ onOpenChange?: (open: boolean) => void;
17
+ command?: HierarchyCommand;
18
+ /** Attributes a host puts on every row (`data-*`), e.g. for its own context menu. */
19
+ rowAttributes?: (node: HierarchyNode) => Record<`data-${string}`, string>;
20
+ /** Show the panel's own context menu (default). A host with a menu of its own passes false: a right-click then only selects the row. */
21
+ ownMenu?: boolean;
22
+ /** Below this width of the window the panel starts folded when nothing was kept (default 640). */
23
+ narrow?: number;
24
+ className?: string;
25
+ }
26
+ /** The folded panel's width. */
27
+ export declare const RAIL_WIDTH = 36;
28
+ /**
29
+ * The panel's look, in one place (PB-1042; the Pencil iterations, 2026-10-21):
30
+ * docked flush at the left of the canvas, below the floating header, with a
31
+ * border at its edge; rows highlighted in the theme's selection colour. Only
32
+ * the viewer's tokens, so a host's theme decides the colours (orange only
33
+ * under the Protoboard theme). Swap these to restyle it.
34
+ */
35
+ export declare const HIERARCHY_LOOK: {
36
+ readonly dock: "uhd-hierarchy-dock absolute inset-y-0 left-0 z-30 flex flex-col pt-[var(--uhd-inset-top,0px)]";
37
+ readonly panel: "relative flex min-h-0 flex-1 flex-col overflow-hidden border-t border-r border-line bg-surface font-ui text-fg";
38
+ readonly rail: "flex min-h-0 flex-1 flex-col items-center gap-1 border-t border-r border-line bg-surface py-1";
39
+ readonly header: "flex h-8 shrink-0 items-center gap-0.5 pr-1 pl-3";
40
+ readonly title: "min-w-0 flex-1 truncate font-label text-[11px] tracking-[0.08em] text-fg-muted uppercase";
41
+ readonly filterBox: "mx-2 mb-1.5 flex h-7 shrink-0 items-center gap-1.5 rounded-md border border-line bg-sunken px-2 focus-within:outline focus-within:outline-1 focus-within:-outline-offset-1 focus-within:outline-focus";
42
+ readonly row: "uhd-tree-row group relative flex h-[26px] cursor-pointer items-center gap-1.5 pr-3 text-[12.5px] leading-none outline-none select-none";
43
+ readonly rowSelected: "bg-selection text-selection-fg outline outline-1 -outline-offset-1 outline-focus";
44
+ readonly rowIdle: "text-fg hover:bg-hover";
45
+ /** Filtering: a row that only leads to what matches. */
46
+ readonly rowDim: "text-fg-faint hover:bg-hover hover:text-fg";
47
+ readonly rowFocus: "focus-visible:outline focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-focus";
48
+ readonly groupRow: "mt-1 border-t border-line-subtle text-fg-muted";
49
+ readonly badge: "shrink-0 rounded border border-line px-1.5 font-code text-[10px] leading-[16px] text-fg-muted";
50
+ readonly legend: "flex shrink-0 flex-wrap items-center gap-x-3 gap-y-1 border-t border-line-subtle px-3 py-1.5 text-[10.5px] text-fg-muted";
51
+ };
52
+ /** The panel, docked at the left of the view: render it beside the shell's `.workspace` (its sibling, before it), which then starts after it. */
53
+ export declare function ViewerHierarchy({ state: given, onStateChange, onOpenChange, command, rowAttributes, ownMenu, narrow, className }: ViewerHierarchyProps): import("react").JSX.Element;
54
+ /** The toolbar's Hierarchy button (left of a shell's view tabs): it opens and folds the panel. */
55
+ export declare function HierarchyToggle({ open, onClick, disabled, className }: {
56
+ open: boolean;
57
+ onClick: () => void;
58
+ disabled?: boolean;
59
+ className?: string;
60
+ }): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Renders a viewer shell into an element: the standalone app (app/main.tsx,
3
+ * lib.tsx's mountViewer) or a host's own shell built from the library's views
4
+ * (`renderViewer(el, options, Shell)`). The handle carries the host channel:
5
+ * its methods send host messages, events go to the options' callbacks and,
6
+ * with `parentWindow`, to the parent window. The shell receives the options
7
+ * and the channel (`host`) as props and passes them to `UhdViewer`.
8
+ */
9
+ import { type ComponentType } from "react";
10
+ import type { AppProps } from "./controller";
11
+ import type { ViewerHandle } from "../api";
12
+ export declare function renderViewer<P extends AppProps>(element: HTMLElement, props: P, Shell: ComponentType<P>): ViewerHandle;
@@ -0,0 +1,156 @@
1
+ /**
2
+ * The library's views of a loaded model, each reading the viewer's state
3
+ * (`useViewer`): the diagram canvas with its toolbar and legend, the 3D
4
+ * scene, the inspector panels and a module's context menu. Shells place them;
5
+ * none of them is app chrome.
6
+ */
7
+ import { type ReactNode } from "react";
8
+ export interface DiagramCanvasProps {
9
+ /** Draw the floating toolbar (fit, zoom, reset layout). Default true. */
10
+ toolbar?: boolean;
11
+ /** Draw the classification's legend. Default true. */
12
+ legend?: boolean;
13
+ /** A panel floats over the canvas's right side: fitting leaves room for it. Default: the inspector panel is open. */
14
+ coveredRight?: boolean;
15
+ /** What the shell adds to the notice about definitions the bundle does not hold (how its producer gets them). */
16
+ missingHint?: ReactNode;
17
+ className?: string;
18
+ }
19
+ /** The diagram of the current level: modules, interfaces, links and harnesses. */
20
+ export declare function DiagramCanvas({ toolbar, legend, coveredRight, missingHint, className }: DiagramCanvasProps): import("react").JSX.Element;
21
+ /** The scenario being shown, when it is not the nominal build. */
22
+ export declare function ScenarioBanner(): import("react").JSX.Element | null;
23
+ /**
24
+ * Definitions the bundle names and does not hold (source/tolerant.ts): they are
25
+ * drawn as placeholders, and this says which. It can be put away; a bundle
26
+ * that lacks something else brings it back.
27
+ */
28
+ export declare function MissingNotice({ hint, className }: {
29
+ hint?: ReactNode;
30
+ className?: string;
31
+ }): import("react").JSX.Element | null;
32
+ /** The diagram's view controls as icon toggles (each with a tooltip). */
33
+ export declare const CLASSIFICATION_OPTIONS: readonly [{
34
+ readonly id: "domain";
35
+ readonly icon: "layers";
36
+ readonly label: "Colour by domain";
37
+ }, {
38
+ readonly id: "drc";
39
+ readonly icon: "shield-check";
40
+ readonly label: "Colour by DRC health";
41
+ }, {
42
+ readonly id: "signal";
43
+ readonly icon: "activity";
44
+ readonly label: "Colour by signal type";
45
+ }];
46
+ export declare const DETAIL_OPTIONS: readonly [{
47
+ readonly id: "bundled";
48
+ readonly icon: "minus";
49
+ readonly label: "Basic: one line per link";
50
+ }, {
51
+ readonly id: "conductors";
52
+ readonly icon: "rows-3";
53
+ readonly label: "Ribbon: every conductor";
54
+ }];
55
+ /**
56
+ * The pointer's tool: select (a drag on the empty canvas draws a selection
57
+ * box) or pan (a drag moves the view). For a shell's own toolbar.
58
+ */
59
+ export declare function ToolToggle({ tooltipSide, size }: {
60
+ tooltipSide?: "top" | "bottom" | "left" | "right";
61
+ size?: "sm" | "md";
62
+ }): import("react").JSX.Element;
63
+ /** Fit and zoom, as the canvas does them (a fit asked for here is also what the level opens on next time). */
64
+ export declare function ViewButtons({ tooltipSide }: {
65
+ tooltipSide?: "top" | "bottom" | "left" | "right";
66
+ }): import("react").JSX.Element;
67
+ /**
68
+ * The diagram's controls (classification, detail, grounds; `controls={false}` leaves them out), then fit, zoom and reset.
69
+ * When the legend has no room beside it, it starts with the legend's button (`legend`: what that opens; default the
70
+ * viewer's legend).
71
+ */
72
+ export declare function DiagramToolbar({ coveredRight, className, controls, legend }: {
73
+ coveredRight?: boolean;
74
+ className?: string;
75
+ controls?: boolean;
76
+ legend?: ReactNode;
77
+ }): import("react").JSX.Element;
78
+ /**
79
+ * The entries of the current classification's legend, as buttons: a click
80
+ * isolates one (its links stay, with the interfaces and modules they touch;
81
+ * the rest of the level fades), a click on it again shows everything, a
82
+ * click on another switches, and Shift, Ctrl or Cmd holds several. For a
83
+ * shell that draws its own legend card.
84
+ */
85
+ export declare function DiagramLegendItems({ compact, columns }?: {
86
+ compact?: boolean;
87
+ columns?: number;
88
+ }): import("react").JSX.Element;
89
+ /** The way back from an isolated legend entry to everything (shown only while something is isolated). */
90
+ export declare function IsolationClear({ className }: {
91
+ className?: string;
92
+ }): import("react").JSX.Element | null;
93
+ /**
94
+ * What the legend shows in a form: `full` the title and the entries with their
95
+ * labels; `compact` the classification's icon and the swatches alone (each
96
+ * named by its label).
97
+ */
98
+ export declare function DiagramLegendBody({ form }: {
99
+ form: "full" | "compact";
100
+ }): import("react").JSX.Element;
101
+ /** What the link colours mean in the current classification; a click on an entry isolates it. It gives way to the toolbar as the canvas narrows (`FittedLegend`). */
102
+ export declare function DiagramLegend({ className }: {
103
+ className?: string;
104
+ }): import("react").JSX.Element;
105
+ /**
106
+ * A legend card at the canvas's bottom left that stays there and gives way
107
+ * to the bottom toolbar (ui/legendFit.ts): the full form while it fits beside
108
+ * the toolbar, then the compact one, and at its smallest none, the toolbar
109
+ * then offering it behind a button (`LegendToolbarButton`). It measures the
110
+ * room it has (a `ResizeObserver` on the canvas, the toolbar and both forms)
111
+ * from hidden copies of the two forms, so it never overlaps the toolbar.
112
+ * `render` draws a form; the card is a sibling of the toolbar (`.toolbar`).
113
+ */
114
+ export declare function FittedLegend({ label, render, className }: {
115
+ label: string;
116
+ render: (form: "full" | "compact") => ReactNode;
117
+ className?: string;
118
+ }): import("react").JSX.Element;
119
+ /**
120
+ * The legend's button in the toolbar, shown only when the legend has no room
121
+ * beside it (`FittedLegend`): it opens the legend (`children`) as a popover
122
+ * above the toolbar. Escape, a click elsewhere or the button closes it, and
123
+ * the keyboard goes back to the button.
124
+ */
125
+ export declare function LegendToolbarButton({ children, label }: {
126
+ children: ReactNode;
127
+ label?: string;
128
+ }): import("react").JSX.Element | null;
129
+ export interface Scene3DProps {
130
+ /** Show the 3D view's own inspector card. Default: the inspector panel is open. */
131
+ inspector?: boolean;
132
+ /**
133
+ * The module to show, by instance path from the root. Default: the level
134
+ * the viewer is on (`drill`), so the root shows the whole assembly and a
135
+ * module shows that module alone. A shell whose tab is on a module with no
136
+ * level of its own (a part) passes that module's path.
137
+ */
138
+ scope?: string[];
139
+ /** What the shell adds where a module has nothing to draw (how its 3D model is made). */
140
+ emptyHint?: ReactNode;
141
+ }
142
+ /**
143
+ * The 3D model of what is being viewed: the whole assembly at the root, one
144
+ * module alone (in its own coordinates) on that module's level. With its own
145
+ * toolbar and (optionally) its inspector.
146
+ */
147
+ export declare function Scene3D({ inspector, scope, emptyHint }: Scene3DProps): import("react").JSX.Element;
148
+ /**
149
+ * The inspector of the current level: the selected module or link, else the
150
+ * hierarchy or the system checks (`panel`). Hidden while no panel is open.
151
+ */
152
+ export declare function ViewerInspector({ className }: {
153
+ className?: string;
154
+ }): import("react").JSX.Element | null;
155
+ /** A module's context menu, where the pointer opened it. */
156
+ export declare function ViewerNodeMenu(): import("react").JSX.Element | null;
@@ -0,0 +1,71 @@
1
+ import type { UhdBundle } from "@deltarobotics/uhd";
2
+ import type { LinkLayout } from "../lib/api.js";
3
+
4
+ export interface Box { x: number; y: number; w: number; h: number }
5
+ /** One level of `diagram.layouts` in the display file. */
6
+ export interface LevelLayout {
7
+ nodes: Record<string, { x?: number; y?: number; w?: number; h?: number }>;
8
+ ports?: Record<string, "left" | "right" | "top" | "bottom">;
9
+ links?: Record<string, LinkLayout>;
10
+ }
11
+ /** A level layout with the nodes the layout step must not move (the viewer ignores the list). */
12
+ export type PinnedLevelLayout = LevelLayout & { pinned?: string[] };
13
+ export interface LayoutMetrics {
14
+ cards: number;
15
+ boundary: number;
16
+ links: number;
17
+ crossings: number;
18
+ overlaps: number;
19
+ aspect: number;
20
+ width: number;
21
+ height: number;
22
+ strip: number;
23
+ stripAxis: "row" | "column";
24
+ stripCards: string[];
25
+ underCards: number;
26
+ length: number;
27
+ detail: { overlaps: [string, string][]; underCards: { link: string; card: string }[] };
28
+ }
29
+ export interface LayoutFinding {
30
+ severity: "warning" | "info";
31
+ code: "strip" | "crossings" | "overlaps" | "under-cards" | "aspect";
32
+ message: string;
33
+ }
34
+ export interface LayoutLimits {
35
+ strip: (cards: number) => number;
36
+ crossings: (links: number) => number;
37
+ aspect: [number, number];
38
+ }
39
+ export declare const LAYOUT_LIMITS: LayoutLimits;
40
+ export declare function layoutFindings(m: LayoutMetrics, limits?: LayoutLimits): LayoutFinding[];
41
+ export interface DiagramLevel { level: string; label: string; board: boolean }
42
+ export declare function diagramLevels(bundle: UhdBundle, maxDepth?: number): DiagramLevel[];
43
+ export interface LevelOptions {
44
+ layout?: LevelLayout | null;
45
+ expanded?: string[];
46
+ legacy?: boolean;
47
+ }
48
+ export interface MeasuredLevel {
49
+ level: string;
50
+ saved: boolean;
51
+ metrics: LayoutMetrics;
52
+ findings: LayoutFinding[];
53
+ /** What the viewer draws (internal shapes: read `layout.boxes` and `layout.routes` only). */
54
+ view: { nodes: { id: string; label: string; parent?: string; kind: string }[] };
55
+ layout: { boxes: Record<string, Box>; routes: Record<string, [number, number][]> };
56
+ }
57
+ export declare function measureLevel(bundle: UhdBundle, level: string, opts?: LevelOptions): MeasuredLevel;
58
+ export interface ProposeOptions extends LevelOptions {
59
+ mode?: "default" | "tidy";
60
+ pinned?: string[];
61
+ }
62
+ export interface Proposal {
63
+ level: string;
64
+ before: MeasuredLevel;
65
+ after: MeasuredLevel;
66
+ layout: PinnedLevelLayout;
67
+ better: boolean;
68
+ }
69
+ export declare function proposeLevel(bundle: UhdBundle, level: string, opts?: ProposeOptions): Proposal;
70
+ export declare function reads(m: LayoutMetrics): number;
71
+ export declare function readsBetter(a: LayoutMetrics, b: LayoutMetrics): boolean;