@deltarobotics/uhd-viewer 0.0.0-stage → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +74 -0
- package/LICENSE +202 -0
- package/NOTICE +22 -0
- package/README.md +168 -2
- package/bin/serve.d.mts +62 -0
- package/bin/serve.mjs +257 -0
- package/bin/uhd-viewer.mjs +75 -0
- package/dist/app/assets/KodeMono-Bold-DdIivhPN.woff2 +0 -0
- package/dist/app/assets/KodeMono-Medium-CVnTuv5A.ttf +0 -0
- package/dist/app/assets/KodeMono-Regular-Bdr_-rJX.woff2 +0 -0
- package/dist/app/assets/KodeMono-SemiBold-JAfn5Dpm.ttf +0 -0
- package/dist/app/assets/index-CEJyT8hF.css +2 -0
- package/dist/app/assets/index-DWZ-48wc.js +3853 -0
- package/dist/app/index.html +16 -0
- package/dist/components/components.css +6372 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +26609 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/types/uhd-viewer/src/api.d.ts +286 -0
- package/dist/components/types/uhd-viewer/src/cad/CadView.d.ts +52 -0
- package/dist/components/types/uhd-viewer/src/cad/ModelView.d.ts +30 -0
- package/dist/components/types/uhd-viewer/src/cad/explode.d.ts +110 -0
- package/dist/components/types/uhd-viewer/src/cad/explodeSample.d.ts +25 -0
- package/dist/components/types/uhd-viewer/src/cad/findings.d.ts +41 -0
- package/dist/components/types/uhd-viewer/src/cad/labels.d.ts +76 -0
- package/dist/components/types/uhd-viewer/src/cad/model.d.ts +132 -0
- package/dist/components/types/uhd-viewer/src/cad/row.d.ts +15 -0
- package/dist/components/types/uhd-viewer/src/cad/scene.d.ts +95 -0
- package/dist/components/types/uhd-viewer/src/cad/scope.d.ts +89 -0
- package/dist/components/types/uhd-viewer/src/canvas/Canvas.d.ts +90 -0
- package/dist/components/types/uhd-viewer/src/canvas/Icon.d.ts +5 -0
- package/dist/components/types/uhd-viewer/src/canvas/LinkEdge.d.ts +40 -0
- package/dist/components/types/uhd-viewer/src/canvas/Port.d.ts +18 -0
- package/dist/components/types/uhd-viewer/src/canvas/actions.d.ts +5 -0
- package/dist/components/types/uhd-viewer/src/canvas/geometry.d.ts +72 -0
- package/dist/components/types/uhd-viewer/src/canvas/interaction.d.ts +162 -0
- package/dist/components/types/uhd-viewer/src/canvas/nodes.d.ts +43 -0
- package/dist/components/types/uhd-viewer/src/canvas/reveal.d.ts +55 -0
- package/dist/components/types/uhd-viewer/src/canvas/rightDrag.d.ts +51 -0
- package/dist/components/types/uhd-viewer/src/canvas/routing.d.ts +28 -0
- package/dist/components/types/uhd-viewer/src/chrome/ArtifactCards.d.ts +30 -0
- package/dist/components/types/uhd-viewer/src/chrome/Artifacts.d.ts +44 -0
- package/dist/components/types/uhd-viewer/src/chrome/BoardInspector.d.ts +53 -0
- package/dist/components/types/uhd-viewer/src/chrome/Chrome.d.ts +126 -0
- package/dist/components/types/uhd-viewer/src/chrome/Evidence.d.ts +20 -0
- package/dist/components/types/uhd-viewer/src/chrome/InterfaceCards.d.ts +66 -0
- package/dist/components/types/uhd-viewer/src/chrome/PairView.d.ts +37 -0
- package/dist/components/types/uhd-viewer/src/chrome/Sections.d.ts +128 -0
- package/dist/components/types/uhd-viewer/src/components.d.ts +60 -0
- package/dist/components/types/uhd-viewer/src/host/channel.d.ts +49 -0
- package/dist/components/types/uhd-viewer/src/host/context.d.ts +29 -0
- package/dist/components/types/uhd-viewer/src/host/protocol.d.ts +22 -0
- package/dist/components/types/uhd-viewer/src/host/targets.d.ts +101 -0
- package/dist/components/types/uhd-viewer/src/layout/board-layout.d.ts +69 -0
- package/dist/components/types/uhd-viewer/src/layout/card-body.d.ts +64 -0
- package/dist/components/types/uhd-viewer/src/layout/layout.d.ts +94 -0
- package/dist/components/types/uhd-viewer/src/layout/module-layout.d.ts +32 -0
- package/dist/components/types/uhd-viewer/src/layout/router.d.ts +55 -0
- package/dist/components/types/uhd-viewer/src/layout/taps.d.ts +20 -0
- package/dist/components/types/uhd-viewer/src/model/artifacts.d.ts +129 -0
- package/dist/components/types/uhd-viewer/src/model/classification.d.ts +41 -0
- package/dist/components/types/uhd-viewer/src/model/diagnostics.d.ts +27 -0
- package/dist/components/types/uhd-viewer/src/model/evidence.d.ts +63 -0
- package/dist/components/types/uhd-viewer/src/model/from-uhd.d.ts +58 -0
- package/dist/components/types/uhd-viewer/src/model/hierarchy.d.ts +173 -0
- package/dist/components/types/uhd-viewer/src/model/isolate.d.ts +33 -0
- package/dist/components/types/uhd-viewer/src/model/level.d.ts +7 -0
- package/dist/components/types/uhd-viewer/src/model/nets.d.ts +53 -0
- package/dist/components/types/uhd-viewer/src/model/outputs.d.ts +79 -0
- package/dist/components/types/uhd-viewer/src/model/slots.d.ts +184 -0
- package/dist/components/types/uhd-viewer/src/model/types.d.ts +213 -0
- package/dist/components/types/uhd-viewer/src/options.d.ts +27 -0
- package/dist/components/types/uhd-viewer/src/source/source.d.ts +109 -0
- package/dist/components/types/uhd-viewer/src/source/tolerant.d.ts +45 -0
- package/dist/components/types/uhd-viewer/src/theme/ThemeProvider.d.ts +33 -0
- package/dist/components/types/uhd-viewer/src/theme/adapters.d.ts +28 -0
- package/dist/components/types/uhd-viewer/src/theme/resolve.d.ts +19 -0
- package/dist/components/types/uhd-viewer/src/theme/themes.d.ts +67 -0
- package/dist/components/types/uhd-viewer/src/theme/tokens.d.ts +175 -0
- package/dist/components/types/uhd-viewer/src/ui/Inspector.d.ts +45 -0
- package/dist/components/types/uhd-viewer/src/ui/Legend.d.ts +59 -0
- package/dist/components/types/uhd-viewer/src/ui/ScrollArea.d.ts +16 -0
- package/dist/components/types/uhd-viewer/src/ui/Toolbar.d.ts +49 -0
- package/dist/components/types/uhd-viewer/src/ui/Tooltips.d.ts +3 -0
- package/dist/components/types/uhd-viewer/src/ui/cx.d.ts +2 -0
- package/dist/components/types/uhd-viewer/src/ui/legendFit.d.ts +55 -0
- package/dist/components/types/uhd-viewer/src/viewer/controller.d.ts +219 -0
- package/dist/components/types/uhd-viewer/src/viewer/details.d.ts +81 -0
- package/dist/components/types/uhd-viewer/src/viewer/hierarchy.d.ts +82 -0
- package/dist/components/types/uhd-viewer/src/viewer/mount.d.ts +12 -0
- package/dist/components/types/uhd-viewer/src/viewer/views.d.ts +187 -0
- package/dist/headless/index.d.ts +71 -0
- package/dist/headless/index.js +7425 -0
- package/dist/headless/index.js.map +1 -0
- package/dist/lib/api.d.ts +252 -0
- package/dist/lib/uhd-viewer.css +3 -0
- package/dist/lib/uhd-viewer.d.ts +4 -0
- package/dist/lib/uhd-viewer.js +97787 -0
- package/package.json +110 -4
- package/src/styles/fonts/OFL.txt +93 -0
- package/src/styles/tailwind-theme.css +48 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { InterfaceSlot, SlotKind } from "../model/slots";
|
|
2
|
+
/** The card's look, in one place. */
|
|
3
|
+
export declare const CARD_LOOK: {
|
|
4
|
+
readonly list: "flex flex-col gap-1.5";
|
|
5
|
+
readonly card: "uhd-slot-card rounded-[6px] border border-line bg-[color-mix(in_oklab,var(--uhd-text)_3%,transparent)] px-2.5 py-[7px] has-[[data-card-toggle]:focus-visible]:outline has-[[data-card-toggle]:focus-visible]:outline-1 has-[[data-card-toggle]:focus-visible]:-outline-offset-1 has-[[data-card-toggle]:focus-visible]:outline-focus hover:border-line-strong";
|
|
6
|
+
readonly cardOpen: "border-line-strong";
|
|
7
|
+
readonly cardOpenSlot: "bg-transparent";
|
|
8
|
+
readonly head: "flex min-w-0 items-center gap-2";
|
|
9
|
+
/** The toggle covers the whole summary (a stretched button): a click anywhere opens the card. */
|
|
10
|
+
readonly toggle: "min-w-0 truncate text-left text-[12px] leading-[18px] text-fg outline-none after:absolute after:inset-0 after:content-[''] cursor-pointer";
|
|
11
|
+
readonly chip: "inline-flex h-[18px] shrink-0 items-center rounded-[4px] bg-[color-mix(in_oklab,var(--uhd-text)_8%,transparent)] px-1.5 text-[10px] leading-none text-fg-muted";
|
|
12
|
+
readonly pin: "inline-flex h-4 shrink-0 items-center rounded-[4px] border border-line px-1 text-[10px] leading-none text-fg-muted";
|
|
13
|
+
/**
|
|
14
|
+
* The pin mapping's columns, shared by its rows: the pin as wide as the widest (at least 44 px, its cell's
|
|
15
|
+
* minimum; at most 40 % of the card), the leaf (when any pin binds one) at most 30 %, and what it meets in the rest.
|
|
16
|
+
*/
|
|
17
|
+
readonly pinMap: "grid gap-x-2 gap-y-[3px] text-[11px] leading-none";
|
|
18
|
+
readonly pinMapPins: "grid-cols-[fit-content(40%)_minmax(0,1fr)]";
|
|
19
|
+
readonly pinMapLeaves: "grid-cols-[fit-content(40%)_fit-content(30%)_minmax(0,1fr)]";
|
|
20
|
+
readonly pinRow: "col-span-full grid min-h-5 grid-cols-subgrid items-center";
|
|
21
|
+
/** A pin in the mapping: a chip that ends in an ellipsis when the column is narrower than its name. */
|
|
22
|
+
readonly pinName: "inline-block h-4 max-w-full truncate rounded-[4px] border border-line px-1 align-middle text-[10px] leading-[14px] text-fg-muted";
|
|
23
|
+
readonly meta: "mt-[5px] flex min-w-0 items-center gap-1";
|
|
24
|
+
readonly role: "ml-auto shrink-0 text-[10px] leading-none text-fg-faint";
|
|
25
|
+
readonly linked: "mt-[5px] flex min-w-0 items-center gap-1.5 text-[11px] leading-[16px]";
|
|
26
|
+
readonly more: "flex h-6 w-full cursor-pointer items-center gap-1.5 rounded-[3px] px-1 text-left text-[11px] text-fg-muted hover:text-fg focus-visible:outline focus-visible:outline-1 focus-visible:outline-focus";
|
|
27
|
+
readonly detail: "mt-2 flex flex-col gap-2.5 border-t border-line-subtle pt-2";
|
|
28
|
+
readonly group: "flex flex-col gap-[3px]";
|
|
29
|
+
readonly button: "relative z-10 inline-flex h-6 min-w-0 cursor-pointer items-center gap-1.5 rounded-[4px] border border-line px-2 text-[10.5px] leading-none text-fg hover:bg-hover focus-visible:outline focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-focus";
|
|
30
|
+
readonly textAction: "relative z-10 inline-flex shrink-0 cursor-pointer items-center gap-1 text-[10.5px] leading-none text-link hover:underline focus-visible:outline focus-visible:outline-1 focus-visible:outline-focus";
|
|
31
|
+
};
|
|
32
|
+
/** The pin glyph's colour by kind: power red, signal blue, mechanical grey (theme tokens; swap here). */
|
|
33
|
+
export declare const SLOT_COLOR: Record<SlotKind, string>;
|
|
34
|
+
export interface InterfaceCardActions {
|
|
35
|
+
/** Show the interface (or its first link) on the canvas. */
|
|
36
|
+
locate?: (slot: InterfaceSlot) => void;
|
|
37
|
+
/** Select one of its links (or a derived one) by its id on the level. */
|
|
38
|
+
selectLink?: (id: string) => void;
|
|
39
|
+
/** Open the source that declares it (its link's line, else the interface's). */
|
|
40
|
+
openSource?: (slot: InterfaceSlot) => void;
|
|
41
|
+
/** An open slot: start a link from it. */
|
|
42
|
+
connect?: (slot: InterfaceSlot) => void;
|
|
43
|
+
/** A finding's Locate (the host's key), else the slot's own Locate. */
|
|
44
|
+
finding?: (key: string) => void;
|
|
45
|
+
/** A source the interface cites. */
|
|
46
|
+
openLink?: (url: string) => void;
|
|
47
|
+
}
|
|
48
|
+
/** The pin glyph: one bar per pin (up to four), in the kind's colour; an open slot's are outlined. */
|
|
49
|
+
export declare function SlotGlyph({ kind, pins, open }: {
|
|
50
|
+
kind: SlotKind;
|
|
51
|
+
pins: number;
|
|
52
|
+
open?: boolean;
|
|
53
|
+
}): import("react").JSX.Element;
|
|
54
|
+
/** One interface as a slot card; it expands in place. */
|
|
55
|
+
export declare function InterfaceCard({ slot, open, onToggle, actions }: {
|
|
56
|
+
slot: InterfaceSlot;
|
|
57
|
+
open: boolean;
|
|
58
|
+
onToggle: () => void;
|
|
59
|
+
actions: InterfaceCardActions;
|
|
60
|
+
}): import("react").JSX.Element;
|
|
61
|
+
/** The cards, ten at a time (PB-1088): "Show 10 more" adds the next ten, "Show fewer" goes back to the first ten. */
|
|
62
|
+
export declare function InterfaceCards({ slots, actions, first }: {
|
|
63
|
+
slots: InterfaceSlot[];
|
|
64
|
+
actions: InterfaceCardActions;
|
|
65
|
+
first?: number;
|
|
66
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ViewLink, ViewModel } from "../model/types";
|
|
2
|
+
import { type Classification } from "../model/classification";
|
|
3
|
+
/**
|
|
4
|
+
* Pair view (design board 08): every stored link between two modules, left
|
|
5
|
+
* to right, with each link's child links as conductors. Crossovers (TX→RX)
|
|
6
|
+
* draw as crossing lines. Unlinked interfaces are listed below.
|
|
7
|
+
*/
|
|
8
|
+
interface Endpoints {
|
|
9
|
+
a: {
|
|
10
|
+
node: string;
|
|
11
|
+
port: string;
|
|
12
|
+
};
|
|
13
|
+
b: {
|
|
14
|
+
node: string;
|
|
15
|
+
port: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** True endpoints of a link, joining harness segments back together. */
|
|
19
|
+
export declare function pairEnds(vm: ViewModel, link: ViewLink): Endpoints;
|
|
20
|
+
export declare function PairView({ vm, link, mode, onClose }: {
|
|
21
|
+
vm: ViewModel;
|
|
22
|
+
link: ViewLink;
|
|
23
|
+
mode: Classification;
|
|
24
|
+
onClose: () => void;
|
|
25
|
+
}): import("react").JSX.Element | null;
|
|
26
|
+
/**
|
|
27
|
+
* The pair a link joins, small, for the inspector: the two modules and the
|
|
28
|
+
* link's conductors from one to the other (a crossover crosses). `onOpen`
|
|
29
|
+
* opens the full pair view.
|
|
30
|
+
*/
|
|
31
|
+
export declare function PairPreview({ vm, link, mode, onOpen }: {
|
|
32
|
+
vm: ViewModel;
|
|
33
|
+
link: ViewLink;
|
|
34
|
+
mode: Classification;
|
|
35
|
+
onOpen: () => void;
|
|
36
|
+
}): import("react").JSX.Element | null;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The inspector's sections (PB-1042, design A "Linear-tight", 2026-10-21):
|
|
3
|
+
* one column, no boxes. Each section is a 28 px header row (chevron, title,
|
|
4
|
+
* count, and a summary on the right) over its body, separated from the next
|
|
5
|
+
* by a 1 px divider. Secondary sections start collapsed and say what they
|
|
6
|
+
* hold in the header. The look is in one place (`SECTION_LOOK`), from the
|
|
7
|
+
* viewer's tokens only, so a host's theme decides the colours.
|
|
8
|
+
*
|
|
9
|
+
* Keyboard: a section header and an interface card are stops of one list
|
|
10
|
+
* (`data-nav`); Arrow Up and Down move between them, Home and End go to the
|
|
11
|
+
* first and the last, Enter and Space open and close (they are buttons).
|
|
12
|
+
*/
|
|
13
|
+
import { type KeyboardEvent, type ReactNode } from "react";
|
|
14
|
+
/** The sections' look, in one place: swap these to restyle them. */
|
|
15
|
+
export declare const SECTION_LOOK: {
|
|
16
|
+
readonly root: "uhd-sections font-ui text-fg";
|
|
17
|
+
readonly section: "uhd-section border-b border-line-subtle";
|
|
18
|
+
readonly header: "flex h-7 min-w-0 items-center gap-1.5 pr-3 pl-2.5";
|
|
19
|
+
readonly toggle: "group/sec -my-px flex h-7 min-w-0 flex-1 cursor-pointer items-center gap-1.5 rounded-[3px] text-left outline-none focus-visible:outline focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-focus";
|
|
20
|
+
readonly chevron: "shrink-0 text-fg-muted transition-transform duration-100";
|
|
21
|
+
readonly title: "shrink-0 text-[11px] leading-none font-bold text-fg";
|
|
22
|
+
readonly count: "shrink-0 text-[11px] leading-none text-fg-faint tabular-nums";
|
|
23
|
+
readonly summary: "ml-auto min-w-0 shrink truncate text-right text-[11px] leading-none text-fg-muted";
|
|
24
|
+
readonly body: "px-3 pt-0.5 pb-2.5";
|
|
25
|
+
/** A key and its value, as the Parameters rows. */
|
|
26
|
+
readonly kv: "flex min-h-[22px] items-baseline gap-2 py-[3px] text-[11px] leading-[1.35]";
|
|
27
|
+
readonly key: "w-[92px] shrink-0 truncate text-fg-faint";
|
|
28
|
+
readonly value: "min-w-0 flex-1 text-fg [overflow-wrap:anywhere]";
|
|
29
|
+
/** A small heading inside a section (an expanded card's groups). */
|
|
30
|
+
readonly label: "text-[10px] leading-none text-fg-faint";
|
|
31
|
+
/** A quiet text action at the right of a header ("Show all 21"). */
|
|
32
|
+
readonly aside: "ml-auto shrink-0 cursor-pointer text-[11px] leading-none text-fg-muted hover:text-fg focus-visible:outline focus-visible:outline-1 focus-visible:outline-focus";
|
|
33
|
+
};
|
|
34
|
+
type Listener = () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Which sections are open and which interface cards are expanded, kept for
|
|
37
|
+
* as long as the page lives (a tab's webview, the viewer's page): sections by
|
|
38
|
+
* their id, cards per selection, so going back to a module shows it as it was.
|
|
39
|
+
*/
|
|
40
|
+
declare class KeptState {
|
|
41
|
+
private sections;
|
|
42
|
+
private cards;
|
|
43
|
+
private listeners;
|
|
44
|
+
private version;
|
|
45
|
+
subscribe: (l: Listener) => () => undefined;
|
|
46
|
+
snapshot: () => number;
|
|
47
|
+
private changed;
|
|
48
|
+
section(id: string, fallback: boolean): boolean;
|
|
49
|
+
setSection(id: string, open: boolean): void;
|
|
50
|
+
expanded(selection: string): ReadonlySet<string>;
|
|
51
|
+
setExpanded(selection: string, ids: ReadonlySet<string>): void;
|
|
52
|
+
/** For tests and a host that resets its page. */
|
|
53
|
+
clear(): void;
|
|
54
|
+
}
|
|
55
|
+
/** The page's kept state (one per page). */
|
|
56
|
+
export declare const keptInspectorState: KeptState;
|
|
57
|
+
/** The selection the cards below belong to: their expanded set is kept under it. */
|
|
58
|
+
export declare const SelectionKey: import("react").Context<string>;
|
|
59
|
+
/** Whether a section is open (kept while the page lives), and its setter. */
|
|
60
|
+
export declare function useSectionOpen(id: string, defaultOpen: boolean): [boolean, (open: boolean) => void];
|
|
61
|
+
/** The interface cards expanded for the current selection, and a toggle. Several may be open at once. */
|
|
62
|
+
export declare function useExpandedCards(): [ReadonlySet<string>, (id: string) => void];
|
|
63
|
+
/** Where a key moves focus in a list of `count` stops from `index`; undefined: the key is not a move. */
|
|
64
|
+
export declare function navTarget(key: string, index: number, count: number): number | undefined;
|
|
65
|
+
/** Arrow keys on a stop (`data-nav`) move to the next one within the sections (`data-nav-root`). */
|
|
66
|
+
export declare function onNavKey(e: KeyboardEvent<HTMLElement>): void;
|
|
67
|
+
/**
|
|
68
|
+
* The column the sections are in: its stops are one keyboard list. Inside
|
|
69
|
+
* another (a host's inspector around the viewer's details) it is part of the
|
|
70
|
+
* outer one, so the arrows go through both.
|
|
71
|
+
*/
|
|
72
|
+
export declare function Sections({ children, className, label }: {
|
|
73
|
+
children?: ReactNode;
|
|
74
|
+
className?: string;
|
|
75
|
+
label?: string;
|
|
76
|
+
}): import("react").JSX.Element;
|
|
77
|
+
export interface DetailsSectionProps {
|
|
78
|
+
/** Kept open or closed by this id while the page lives. */
|
|
79
|
+
id: string;
|
|
80
|
+
title: string;
|
|
81
|
+
count?: number;
|
|
82
|
+
/** What it holds, said in the header (shown open or closed): "6 linked · 1 open", "DolphinRC · $69.99". */
|
|
83
|
+
summary?: ReactNode;
|
|
84
|
+
/** A text action at the header's right instead of the summary ("Show all 21"). */
|
|
85
|
+
aside?: ReactNode;
|
|
86
|
+
/** Open at first (secondary sections start closed). */
|
|
87
|
+
defaultOpen?: boolean;
|
|
88
|
+
children?: ReactNode;
|
|
89
|
+
className?: string;
|
|
90
|
+
}
|
|
91
|
+
/** A section: its header row (a disclosure button) and its body. */
|
|
92
|
+
export declare function DetailsSection({ id, title, count, summary, aside, defaultOpen, children, className }: DetailsSectionProps): import("react").JSX.Element;
|
|
93
|
+
/** Rows of keys and values; past `limit` the rest wait behind "Show all N" (the header's aside, `ShowAll`). */
|
|
94
|
+
export declare function KeyValues({ rows, limit }: {
|
|
95
|
+
rows: {
|
|
96
|
+
key: string;
|
|
97
|
+
value: ReactNode;
|
|
98
|
+
title?: string;
|
|
99
|
+
}[];
|
|
100
|
+
limit?: number;
|
|
101
|
+
}): import("react").JSX.Element;
|
|
102
|
+
/** How many rows of a long list are shown at first, and how many more each "Show more" adds (PB-1088). */
|
|
103
|
+
export declare const LIST_STEP = 10;
|
|
104
|
+
/**
|
|
105
|
+
* A long list shown `step` rows at a time (PB-1088): "Show 10 more" under the
|
|
106
|
+
* rows adds the next ones, "Show fewer" goes back to the first `step`.
|
|
107
|
+
* `keep`: rows that must stay shown (an expanded card), counted from the top.
|
|
108
|
+
*/
|
|
109
|
+
export declare function useLoadMore(total: number, step?: number, keep?: number): {
|
|
110
|
+
limit: number;
|
|
111
|
+
footer: ReactNode;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* A long free text (a module's description) cut to `lines` lines, with "More"
|
|
115
|
+
* to read it all and "Less" to cut it again (PB-1088). The toggle shows only
|
|
116
|
+
* when the text is cut.
|
|
117
|
+
*/
|
|
118
|
+
export declare function ClampedText({ text, lines, className }: {
|
|
119
|
+
text: string;
|
|
120
|
+
lines?: number;
|
|
121
|
+
className?: string;
|
|
122
|
+
}): import("react").JSX.Element;
|
|
123
|
+
/** A section's rows shown in part, and the header action that shows them all. Lists use `useLoadMore` (PB-1088). */
|
|
124
|
+
export declare function useShowAll(total: number, limit: number): {
|
|
125
|
+
limit: number | undefined;
|
|
126
|
+
aside: ReactNode;
|
|
127
|
+
};
|
|
128
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The component library (`@deltarobotics/uhd-viewer/components`): the
|
|
3
|
+
* viewer's views of a UHD bundle as React components, for hosts that build
|
|
4
|
+
* their own shell. No app chrome: the shell places the views, its own header,
|
|
5
|
+
* tabs and panels.
|
|
6
|
+
*
|
|
7
|
+
* <ThemeProvider adapter={vscodeThemeAdapter()}>
|
|
8
|
+
* <UhdViewer bundleUrl="/uhd-bundle.json" host={host}>
|
|
9
|
+
* <DiagramCanvas />
|
|
10
|
+
* <ViewerInspector />
|
|
11
|
+
* </UhdViewer>
|
|
12
|
+
* </ThemeProvider>
|
|
13
|
+
*
|
|
14
|
+
* React, React DOM, Three, React Flow and Radix are peer dependencies here
|
|
15
|
+
* (one copy each in the host's bundle). The stylesheet is
|
|
16
|
+
* `@deltarobotics/uhd-viewer/components.css`; a host's own Tailwind build
|
|
17
|
+
* gets the token utilities from `@deltarobotics/uhd-viewer/tailwind-theme.css`.
|
|
18
|
+
* Nothing here names a host product.
|
|
19
|
+
*/
|
|
20
|
+
export type * from "./api";
|
|
21
|
+
export { renderViewer } from "./viewer/mount";
|
|
22
|
+
export { parseHostMessage, isViewerEvent, originAllowed, PREFIX as HOST_MESSAGE_PREFIX } from "./host/protocol";
|
|
23
|
+
export { UhdViewer, ViewerBoundary, ViewerProvider, useViewer, useViewerSource, useViewerController, type AppProps as UhdViewerOptions, type UhdViewerProps, type HostLink, type ViewerController } from "./viewer/controller";
|
|
24
|
+
export type { LoadedSource } from "./source/source";
|
|
25
|
+
export { tolerantSystem, isPlaceholder, type MissingDefinition, type LeftOut, type TolerantSystem } from "./source/tolerant";
|
|
26
|
+
export type { Classification } from "./model/classification";
|
|
27
|
+
export { CLASSIFICATIONS, colorFor, legendFor, classKey, type LegendEntry } from "./model/classification";
|
|
28
|
+
export { isolate, presentKeys, linkKeys, toggleIsolated, type Isolation } from "./model/isolate";
|
|
29
|
+
export type { ViewModel, ViewNode, ViewLink } from "./model/types";
|
|
30
|
+
export type { Selection } from "./canvas/Canvas";
|
|
31
|
+
export type { Panel, Goto } from "./chrome/Chrome";
|
|
32
|
+
export { initialInteraction, interactionReducer, interactionProps, canvasCommand, applySelectChanges, firstView, TOOL_OPTIONS, type CanvasTool, type InteractionState, type InteractionAction, type CanvasCommand, type Viewport } from "./canvas/interaction";
|
|
33
|
+
export { openAction } from "./viewer/controller";
|
|
34
|
+
export { cardWidth, labelIsCut, CARD_W, CARD_W_MAX } from "./layout/card-body";
|
|
35
|
+
export { DiagramCanvas, DiagramToolbar, ToolToggle, ViewButtons, DiagramLegend, DiagramLegendBody, DiagramLegendItems, FittedLegend, LegendFold, LegendToolbarButton, IsolationClear, MissingNotice, ScenarioBanner, Scene3D, ViewerInspector, ViewerNodeMenu, CLASSIFICATION_OPTIONS, DETAIL_OPTIONS, type DiagramCanvasProps, type FittedLegendProps, type Scene3DProps } from "./viewer/views";
|
|
36
|
+
export { ModelView, type ModelViewProps, type ModelInfo } from "./cad/ModelView";
|
|
37
|
+
export { ViewerHierarchy, HierarchyToggle, RAIL_WIDTH, HIERARCHY_LOOK, type ViewerHierarchyProps, type HierarchyCommand } from "./viewer/hierarchy";
|
|
38
|
+
export { buildHierarchy, filterHierarchy, visibleRows, treeKey, selectedPath, rowTarget, drillInto, revealPaths, ancestorsOf, hierarchyIndex, walkHierarchy, panelState, groupWiring, markLegend, WIRING_PATH, kindOf, KIND_ICON, KIND_LABEL as HIERARCHY_KIND_LABEL, HIERARCHY_WIDTH, type HierarchyNode, type HierarchyKind, type HierarchyRow, type HierarchyPanelState, type HierarchyOptions, type TreeKeyResult, } from "./model/hierarchy";
|
|
39
|
+
export { SelectionDetails, type SelectionDetailsProps, type DetailsTarget, type InterfaceRequest } from "./viewer/details";
|
|
40
|
+
export { Sections, DetailsSection, KeyValues, useShowAll, useLoadMore, ClampedText, LIST_STEP, useSectionOpen, useExpandedCards, SelectionKey, keptInspectorState, navTarget, onNavKey, SECTION_LOOK, type DetailsSectionProps } from "./chrome/Sections";
|
|
41
|
+
export { InterfaceCards, InterfaceCard, SlotGlyph, CARD_LOOK, SLOT_COLOR, type InterfaceCardActions } from "./chrome/InterfaceCards";
|
|
42
|
+
export { interfaceSlots, slotSummary, groupSlots, checkFindings, levelNames, humanize, sentence, paramValue, type InterfaceSlot, type SlotKind, type SlotState, type SlotPin, type SlotLink, type SlotFinding, type SlotNote, type HostFinding, type SlotOptions } from "./model/slots";
|
|
43
|
+
export { ArtifactCard, ArtifactCards, ArtifactGrid, type ArtifactCardProps } from "./chrome/ArtifactCards";
|
|
44
|
+
export { EvidenceSection } from "./chrome/Evidence";
|
|
45
|
+
export { artifactCard, artifactCards, mergeFormats, isInternalArtifact, classifyArtifact, evidenceSourceCards, groupArtifactCards, ARTIFACT_GROUPS, type ArtifactCardModel, type ArtifactCardOptions, type ArtifactGroup, type ArtifactKind, type ArtifactPreview, type ArtifactSourceRow } from "./model/artifacts";
|
|
46
|
+
export type { EvidenceFiles, SourceRow, Verification } from "./model/evidence";
|
|
47
|
+
export { HostContext, type HostActions } from "./host/context";
|
|
48
|
+
export { ScrollArea, type ScrollAreaProps } from "./ui/ScrollArea";
|
|
49
|
+
export { Toolbar, ToolbarSeparator, IconButton, ToggleGroup, type ToolbarProps, type IconButtonProps, type ToggleGroupProps } from "./ui/Toolbar";
|
|
50
|
+
export { Legend, LegendItem, LegendSwatches, LegendTab, type LegendItemProps, type LegendProps, type LegendTabProps } from "./ui/Legend";
|
|
51
|
+
export { legendStage, legendRoom, legendFolded, LEGEND_SHORT, type LegendStage } from "./ui/legendFit";
|
|
52
|
+
export { InspectorPanel, Section, PropertyRow, Badge, StatusDot, EmptyState, type InspectorPanelProps, type Tone } from "./ui/Inspector";
|
|
53
|
+
export { Tooltips } from "./ui/Tooltips";
|
|
54
|
+
export { Icon } from "./canvas/Icon";
|
|
55
|
+
export { cx } from "./ui/cx";
|
|
56
|
+
export { TOKEN_NAMES, tokenVar, token, mix, defineTheme, applyTheme, readToken, themeCss, themeDeclarations, DERIVED, type Theme, type ThemeTokens, type ThemeToken, type ThemeScheme, } from "./theme/tokens";
|
|
57
|
+
export { defaultDark, defaultLight, defaultTheme, DRC_TOKENS, DARK_DATA_TOKENS, LIGHT_DATA_TOKENS } from "./theme/themes";
|
|
58
|
+
export { staticTheme, defaultThemeAdapter, vscodeThemeAdapter, vscodeTheme, vscodeScheme, pickTheme, type ThemeAdapter } from "./theme/adapters";
|
|
59
|
+
export { ThemeProvider, useTheme, tokenColor, type ThemeProviderProps, type ThemeState } from "./theme/ThemeProvider";
|
|
60
|
+
export { resolveTheme, completeTheme } from "./theme/resolve";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The viewer's side of the host channel: commands from the handle or the
|
|
3
|
+
* parent window reach the mounted viewer (queued until it has a model on
|
|
4
|
+
* screen), and its events go to the host's callbacks and, in a frame, to the
|
|
5
|
+
* parent window.
|
|
6
|
+
*/
|
|
7
|
+
import type { ViewerEvent, ViewerHostMessage, ViewerOptions } from "../api";
|
|
8
|
+
/** Host messages on their way to the viewer component (App.tsx subscribes once it shows a model). */
|
|
9
|
+
export interface CommandBus {
|
|
10
|
+
send(message: ViewerHostMessage): void;
|
|
11
|
+
/** Receive messages, first the ones that waited; returns the unsubscribe. */
|
|
12
|
+
subscribe(handler: (message: ViewerHostMessage) => void): () => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function commandBus(): CommandBus;
|
|
15
|
+
/** Calls the option callback that matches an event. */
|
|
16
|
+
export declare function deliver(options: ViewerOptions, event: ViewerEvent): void;
|
|
17
|
+
/** The part of `window` the parent channel uses (a test passes its own). */
|
|
18
|
+
export interface ChannelWindow {
|
|
19
|
+
/** The frame's parent (the window itself when not in a frame). */
|
|
20
|
+
parent: {
|
|
21
|
+
postMessage(message: unknown, targetOrigin: string): void;
|
|
22
|
+
};
|
|
23
|
+
location: {
|
|
24
|
+
origin: string;
|
|
25
|
+
ancestorOrigins?: ArrayLike<string>;
|
|
26
|
+
};
|
|
27
|
+
document?: {
|
|
28
|
+
referrer?: string;
|
|
29
|
+
};
|
|
30
|
+
addEventListener(type: "message", listener: (e: MessageEvent) => void): void;
|
|
31
|
+
removeEventListener(type: "message", listener: (e: MessageEvent) => void): void;
|
|
32
|
+
}
|
|
33
|
+
export interface ParentChannel {
|
|
34
|
+
/** Post an event to the parent (held until the parent's origin is known). */
|
|
35
|
+
post(event: ViewerEvent): void;
|
|
36
|
+
close(): void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The postMessage channel with the parent window. Accepts host messages from
|
|
40
|
+
* `win.parent` only, from an allowed origin (default: `win`'s own). Events
|
|
41
|
+
* go to the parent's origin: the frame's ancestor origin or referrer when it
|
|
42
|
+
* is allowed, the only allowed origin when exactly one is listed, else the
|
|
43
|
+
* origin of the parent's first accepted message (events wait until then).
|
|
44
|
+
* Returns undefined when `win` is not in a frame.
|
|
45
|
+
*/
|
|
46
|
+
export declare function connectParent(win: ChannelWindow, options: {
|
|
47
|
+
origins?: string[];
|
|
48
|
+
onMessage: (message: ViewerHostMessage) => void;
|
|
49
|
+
}): ParentChannel | undefined;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ArtifactDef, ModuleDef } from "@deltarobotics/uhd";
|
|
2
|
+
import type { ArtifactPreview } from "../model/artifacts";
|
|
3
|
+
import type { EvidenceFiles } from "../model/evidence";
|
|
4
|
+
export interface HostActions {
|
|
5
|
+
openSource?: (defId: string, instancePath?: string) => void;
|
|
6
|
+
openArtifact?: (defId: string, artifactId: string) => void;
|
|
7
|
+
/** Open a module on its own (the host's new tab); given only when the host takes it. */
|
|
8
|
+
openModule?: (path: string) => void;
|
|
9
|
+
/** Show a module in the host's own inspector (a node's INSPECT); given only when the host has one. */
|
|
10
|
+
inspect?: (path: string, defId?: string) => void;
|
|
11
|
+
/** Open a web address (an evidence source); not given: a link in a new tab. */
|
|
12
|
+
openLink?: (url: string) => void;
|
|
13
|
+
/**
|
|
14
|
+
* `"live"` (default): a module's body model turns in a small 3D preview
|
|
15
|
+
* above its cards. `"cards"`: no model is loaded for the inspector; the
|
|
16
|
+
* model is a card like the others, with the picture `artifactPreview` gives.
|
|
17
|
+
*/
|
|
18
|
+
artifactModels?: "live" | "cards";
|
|
19
|
+
/** A picture for an artifact that is not an image itself (a model's exported preview, or the model to draw small). */
|
|
20
|
+
artifactPreview?: (def: ModuleDef, artifact: ArtifactDef) => ArtifactPreview | undefined;
|
|
21
|
+
/** Draws a model small, as a picture's URL, for a card whose preview is a model. Not given: such cards show their icon. */
|
|
22
|
+
drawModel?: (src: string) => Promise<string>;
|
|
23
|
+
/** Load pictures from web addresses (default true). */
|
|
24
|
+
remoteImages?: boolean;
|
|
25
|
+
/** A definition's evidence files (sources.json, verification.json), when the host has them. */
|
|
26
|
+
evidence?: (defId: string) => EvidenceFiles | undefined;
|
|
27
|
+
}
|
|
28
|
+
export declare const HostContext: import("react").Context<HostActions>;
|
|
29
|
+
export declare const useHost: () => HostActions;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host message protocol (README, "Host messages"): checking what arrives
|
|
3
|
+
* over `postMessage`, and which origins a frame's parent may have. Nothing
|
|
4
|
+
* here names a host.
|
|
5
|
+
*/
|
|
6
|
+
import type { ViewerEvent, ViewerHostMessage } from "../api";
|
|
7
|
+
/** Every protocol message's type starts with this. */
|
|
8
|
+
export declare const PREFIX = "uhd-viewer:";
|
|
9
|
+
/**
|
|
10
|
+
* A host → viewer message, checked and normalised (a path given as a list of
|
|
11
|
+
* child ids is joined); undefined for anything else.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseHostMessage(data: unknown): ViewerHostMessage | undefined;
|
|
14
|
+
/** A viewer → host event (for a host or a relay telling them from other messages). */
|
|
15
|
+
export declare const isViewerEvent: (data: unknown) => data is ViewerEvent;
|
|
16
|
+
/**
|
|
17
|
+
* `origin` is one of `allowed`: an exact origin, `scheme://*` (any origin
|
|
18
|
+
* with that scheme), or `*` (any). An opaque origin ("null") matches only `*`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function originAllowed(origin: string, allowed: readonly string[]): boolean;
|
|
21
|
+
/** Origins from a comma-separated list (`a,b`), blanks dropped. */
|
|
22
|
+
export declare const originList: (value: string | null | undefined) => string[];
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host messages against the model: what a focus or a select names on which
|
|
3
|
+
* drill level, and the viewer's selection as the host sees it (canonical
|
|
4
|
+
* paths from the root). Pure functions, so they test without a page.
|
|
5
|
+
*/
|
|
6
|
+
import type { ModuleDef } from "@deltarobotics/uhd";
|
|
7
|
+
import type { ModuleLookup } from "@deltarobotics/uhd";
|
|
8
|
+
import type { ViewerSelection } from "../api";
|
|
9
|
+
import type { ViewModel } from "../model/types";
|
|
10
|
+
/** A selection on the level being viewed (ids relative to it), as the canvas and inspector hold it. */
|
|
11
|
+
export type LevelSelection = {
|
|
12
|
+
kind: "node" | "link";
|
|
13
|
+
id: string;
|
|
14
|
+
} | null;
|
|
15
|
+
/** The longest prefix of `path` that names instances, child by child, from `root`. */
|
|
16
|
+
export declare function instancePrefix(root: ModuleDef, lookup: ModuleLookup, path: string[]): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Where to show a focused module: the current level when it is drawn there
|
|
19
|
+
* (a child, or a child of a module expanded in place), else the level of its
|
|
20
|
+
* parent. A path that stops naming instances is followed as far as it does;
|
|
21
|
+
* the root (or nothing valid) shows the top level with nothing selected.
|
|
22
|
+
*/
|
|
23
|
+
export declare function focusTarget(root: ModuleDef, lookup: ModuleLookup, path: string, current: {
|
|
24
|
+
drill: string[];
|
|
25
|
+
expanded: ReadonlySet<string>;
|
|
26
|
+
}): {
|
|
27
|
+
drill: string[];
|
|
28
|
+
selection: LevelSelection;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The drill path for `path`: as far as it names instances, and only through
|
|
32
|
+
* modules with children of their own (a level shows a module's children).
|
|
33
|
+
*/
|
|
34
|
+
export declare function drillTarget(root: ModuleDef, lookup: ModuleLookup, path: string): string[];
|
|
35
|
+
/** A selection in the 3D view (by instance path), as the host sees it. */
|
|
36
|
+
export declare function cadHostSelection(sel: {
|
|
37
|
+
body?: string;
|
|
38
|
+
component?: string;
|
|
39
|
+
harness?: string;
|
|
40
|
+
mate?: string;
|
|
41
|
+
}, defAt: (path: string[]) => ModuleDef | undefined): ViewerSelection | null;
|
|
42
|
+
/**
|
|
43
|
+
* What a host's select picks in the 3D view, by path from the root: the
|
|
44
|
+
* selection it made on the diagram's level (a module or a link; nets are not
|
|
45
|
+
* drawn in 3D), else the first id naming a module instance in full. `none`
|
|
46
|
+
* for no ids; undefined when nothing applies.
|
|
47
|
+
*/
|
|
48
|
+
export declare function cadSelectTarget(root: ModuleDef, lookup: ModuleLookup, drill: string[], onLevel: LevelSelection | undefined, ids: string[]): {
|
|
49
|
+
kind: "node" | "link" | "none";
|
|
50
|
+
path: string;
|
|
51
|
+
} | undefined;
|
|
52
|
+
/** A stored or derived link id as the view selects it: the line that draws it, or the derived link itself. */
|
|
53
|
+
export declare function selectableLink(vm: ViewModel, id: string): LevelSelection;
|
|
54
|
+
/**
|
|
55
|
+
* The lines a harness is drawn along on this level, when it has no card of
|
|
56
|
+
* its own: a cable between two parts is one line with the harness as a region
|
|
57
|
+
* along it, and the links that name a harness carry its region too. Empty for
|
|
58
|
+
* a harness drawn as a card (and for anything else).
|
|
59
|
+
*/
|
|
60
|
+
export declare function harnessLines(vm: ViewModel, id: string): ViewModel["links"];
|
|
61
|
+
/**
|
|
62
|
+
* A module selection as the diagram can show it: a harness drawn along its
|
|
63
|
+
* lines (no card of its own) is selected as the line that carries its name
|
|
64
|
+
* tab, so a row of the hierarchy or a host's focus on it selects and frames
|
|
65
|
+
* something drawn. Anything else as it is.
|
|
66
|
+
*/
|
|
67
|
+
export declare function drawnSelection(vm: ViewModel, selection: LevelSelection): LevelSelection;
|
|
68
|
+
/** The harness a selected line runs through (its path on the level), if any: its row in the hierarchy. */
|
|
69
|
+
export declare function selectedHarness(vm: ViewModel, selection: LevelSelection): string | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* The first of `ids` drawn on this level: a node (module instance path, net,
|
|
72
|
+
* boundary port) or a link. `node:` and `link:` prefixes pick the kind. Ids
|
|
73
|
+
* are canonical paths from the root (as `selectionChanged` reports them) or
|
|
74
|
+
* relative to the level. Undefined when none is there; null for no ids.
|
|
75
|
+
*/
|
|
76
|
+
export declare function selectTarget(vm: ViewModel, drill: string[], ids: string[]): LevelSelection | undefined;
|
|
77
|
+
/** A level id as a canonical path from the root. */
|
|
78
|
+
export declare function fullId(drill: string[], id: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* The selection as the host sees it: canonical ids, and the definition of
|
|
81
|
+
* the module selected (for a link, the module that declares it).
|
|
82
|
+
*/
|
|
83
|
+
export declare function hostSelection(vm: ViewModel, drill: string[], selection: LevelSelection, levelDefId?: string): ViewerSelection | null;
|
|
84
|
+
/** The definition that declares a level link: the module expanded in place that holds it, or the level's. */
|
|
85
|
+
export declare function linkOwner(vm: ViewModel, linkId: string, levelDefId?: string): string | undefined;
|
|
86
|
+
/** Selections compare by content (the host hears each change once). */
|
|
87
|
+
export declare const selectionKey: (s: ViewerSelection | null) => string;
|
|
88
|
+
/**
|
|
89
|
+
* Whether the host hears the selection now: when it changed, and when a module or link was picked again while it
|
|
90
|
+
* was selected (a click on it, a row of the hierarchy, a host's focus). A pick is a new `pick` (the controller's
|
|
91
|
+
* state object, made anew by each pick, kept when nothing was picked); a rebuild or a view change makes none.
|
|
92
|
+
* The host then knows the user chose it (D6: the Inspector comes back every time, also for the module already
|
|
93
|
+
* selected), and two picks that arrive together (nothing, then the same module again) are still said.
|
|
94
|
+
*/
|
|
95
|
+
export declare function saySelection(sent: {
|
|
96
|
+
key: string;
|
|
97
|
+
pick: unknown;
|
|
98
|
+
}, now: {
|
|
99
|
+
selection: ViewerSelection | null;
|
|
100
|
+
pick: unknown;
|
|
101
|
+
}): boolean;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface BoardNode {
|
|
2
|
+
id: string;
|
|
3
|
+
w: number;
|
|
4
|
+
h: number;
|
|
5
|
+
/** A net junction (placed after the components). */
|
|
6
|
+
net?: boolean;
|
|
7
|
+
/** Taxonomy category ("power.regulator", "component.passive.capacitor"). */
|
|
8
|
+
category?: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
/** A junction that is one tap of a rail drawn in several places: the rail's id (taps.ts). */
|
|
11
|
+
tapOf?: string;
|
|
12
|
+
/** A card's height once one side holds this many ports (cards grow to fit their ports). */
|
|
13
|
+
heightFor?: (perSide: number) => number;
|
|
14
|
+
/** Ports on lines that do not go to a junction (a sheet port's, a direct link's): either side. */
|
|
15
|
+
otherPorts?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface Rect {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
w: number;
|
|
21
|
+
h: number;
|
|
22
|
+
}
|
|
23
|
+
export type FunctionGroup = "io" | "power" | "mcu" | "sensor" | "output" | "other";
|
|
24
|
+
/** A passive or discrete part: placed with the part it serves rather than in a group of its own. */
|
|
25
|
+
export declare function isSatellite(category?: string): boolean;
|
|
26
|
+
/** The function group of a component, from its category. */
|
|
27
|
+
export declare function functionGroup(category?: string): FunctionGroup;
|
|
28
|
+
/** Whether `boxes` overlap once each is grown by its own padding. */
|
|
29
|
+
export declare function hits(a: Rect, b: Rect, padA?: number, padB?: number): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The free top-left position nearest `ideal` (a centre) for a box of size w×h,
|
|
32
|
+
* clear of every obstacle by the paddings. Falls back to below everything.
|
|
33
|
+
*/
|
|
34
|
+
export declare function freeSpot(ideal: [number, number], w: number, h: number, obstacles: Rect[], pad?: {
|
|
35
|
+
x: number;
|
|
36
|
+
y: number;
|
|
37
|
+
}): {
|
|
38
|
+
x: number;
|
|
39
|
+
y: number;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Isotonic placement: tops for boxes in a fixed order, each at least `gap`
|
|
43
|
+
* below the one before, as close to its ideal top as that allows (least
|
|
44
|
+
* squares, pool-adjacent-violators).
|
|
45
|
+
*/
|
|
46
|
+
export declare function pack(ideal: number[], heights: number[], gap: number): number[];
|
|
47
|
+
/** What the layout and the rail taps share: the clusters of a board level. */
|
|
48
|
+
export interface BoardClusters {
|
|
49
|
+
/** Cluster (its anchor's id) of each component. */
|
|
50
|
+
clusterOf: Map<string, string>;
|
|
51
|
+
/** Members of each cluster: the anchor first, then its satellites in reading order. */
|
|
52
|
+
clusters: Map<string, string[]>;
|
|
53
|
+
/** Function group of each cluster. */
|
|
54
|
+
group: Map<string, FunctionGroup>;
|
|
55
|
+
/** Component members of each junction. */
|
|
56
|
+
members: Map<string, string[]>;
|
|
57
|
+
/** Component ↔ component lines (two-member nets of their own). */
|
|
58
|
+
direct: [string, string][];
|
|
59
|
+
}
|
|
60
|
+
/** Cluster a board level's components: each passive with the part it serves, a dedicated connector with its part. */
|
|
61
|
+
export declare function boardClusters(nodes: BoardNode[], edges: [string, string][]): BoardClusters;
|
|
62
|
+
/**
|
|
63
|
+
* Top-left positions by node id for a board level. `edges` are the lines
|
|
64
|
+
* drawn between nodes (component ↔ junction, or component ↔ component).
|
|
65
|
+
*/
|
|
66
|
+
export declare function boardLayout(nodes: BoardNode[], edges: [string, string][]): Record<string, {
|
|
67
|
+
x: number;
|
|
68
|
+
y: number;
|
|
69
|
+
}>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a module card's body holds (its icon, its title and the chips that
|
|
3
|
+
* count its unlinked interfaces by protocol) and how much height that needs.
|
|
4
|
+
*
|
|
5
|
+
* The layout grows a card to fit its body between the labels of the ports
|
|
6
|
+
* on its top and bottom edges; the card then draws only the chips that fit
|
|
7
|
+
* and folds the rest into "+N". Sizes follow `.module-body`, `.module-title`
|
|
8
|
+
* and `.port-group` in styles/app.css.
|
|
9
|
+
*/
|
|
10
|
+
import type { PortGroup } from "./layout";
|
|
11
|
+
import type { Side } from "../canvas/routing";
|
|
12
|
+
/** Chips shown before the rest fold into "+N". */
|
|
13
|
+
export declare const MAX_CHIPS = 4;
|
|
14
|
+
/** Chip rows a card grows for; more chips fold into "+N". */
|
|
15
|
+
export declare const MAX_CHIP_ROWS = 3;
|
|
16
|
+
export interface CardInsets {
|
|
17
|
+
top: number;
|
|
18
|
+
bottom: number;
|
|
19
|
+
left: number;
|
|
20
|
+
right: number;
|
|
21
|
+
}
|
|
22
|
+
/** A port's label as the card draws it: the name without its parenthesised or dashed qualifier. */
|
|
23
|
+
export declare function portLabelText(name: string): string;
|
|
24
|
+
/** How wide a label on a card's left or right edge may run before it is cut with an ellipsis. */
|
|
25
|
+
export declare function sideLabelWidth(cardWidth: number): number;
|
|
26
|
+
/** A card's width with nothing to fit, and the widest it grows to for its labels. */
|
|
27
|
+
export declare const CARD_W = 170;
|
|
28
|
+
export declare const CARD_W_MAX = 272;
|
|
29
|
+
/** The widest a label on a card's top or bottom edge runs (its share of the edge, when that is less). */
|
|
30
|
+
export declare const TOP_LABEL_MAX = 160;
|
|
31
|
+
/** A label's width as drawn (8 px type). */
|
|
32
|
+
export declare const labelWidth: (name: string) => number;
|
|
33
|
+
/**
|
|
34
|
+
* The width a card takes so the labels of its linked interfaces fit beside
|
|
35
|
+
* its body: as wide as the longest needs (two may face each other across the
|
|
36
|
+
* card), from the plain width up to `CARD_W_MAX`. A longer label is cut with
|
|
37
|
+
* an ellipsis and says its whole name on hover.
|
|
38
|
+
*/
|
|
39
|
+
export declare function cardWidth(labels: readonly string[]): number;
|
|
40
|
+
/** A label is drawn short: it does not fit `width`, or the card leaves out the name's qualifier. */
|
|
41
|
+
export declare function labelIsCut(name: string, width: number): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Room the body keeps clear of the port labels: a label row on the top and
|
|
44
|
+
* bottom edges that have labelled ports, and on the left and right as wide
|
|
45
|
+
* as that edge's longest label.
|
|
46
|
+
*/
|
|
47
|
+
export declare function cardInsets(labels: {
|
|
48
|
+
side: Side;
|
|
49
|
+
name: string;
|
|
50
|
+
}[], cardWidth: number): CardInsets;
|
|
51
|
+
export declare function chipText(g: PortGroup): string;
|
|
52
|
+
/** The height a card needs for its body, with up to MAX_CHIP_ROWS rows of chips. */
|
|
53
|
+
export declare function cardHeight(title: string, width: number, groups: PortGroup[], insets: CardInsets): number;
|
|
54
|
+
/**
|
|
55
|
+
* The chips a card of this size draws: as many groups as fit its free rows,
|
|
56
|
+
* the rest counted in "+N". A card with no room for a row draws none.
|
|
57
|
+
*/
|
|
58
|
+
export declare function fitChips(title: string, box: {
|
|
59
|
+
w: number;
|
|
60
|
+
h: number;
|
|
61
|
+
}, groups: PortGroup[], insets: CardInsets): {
|
|
62
|
+
shown: PortGroup[];
|
|
63
|
+
rest: number;
|
|
64
|
+
};
|