@loomweaver/plugin-sdk 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/package.json +45 -0
- package/src/index.d.ts +22 -0
- package/src/index.js +23 -0
- package/src/index.js.map +1 -0
- package/src/lib/auth.d.ts +60 -0
- package/src/lib/auth.js +35 -0
- package/src/lib/auth.js.map +1 -0
- package/src/lib/bar-item.d.ts +67 -0
- package/src/lib/bar-item.js +2 -0
- package/src/lib/bar-item.js.map +1 -0
- package/src/lib/button.d.ts +4 -0
- package/src/lib/button.js +2 -0
- package/src/lib/button.js.map +1 -0
- package/src/lib/capability.d.ts +38 -0
- package/src/lib/capability.js +32 -0
- package/src/lib/capability.js.map +1 -0
- package/src/lib/command.d.ts +199 -0
- package/src/lib/command.js +2 -0
- package/src/lib/command.js.map +1 -0
- package/src/lib/container-handle.d.ts +36 -0
- package/src/lib/container-handle.js +4 -0
- package/src/lib/container-handle.js.map +1 -0
- package/src/lib/content-route.d.ts +254 -0
- package/src/lib/content-route.js +2 -0
- package/src/lib/content-route.js.map +1 -0
- package/src/lib/contribution.d.ts +4 -0
- package/src/lib/contribution.js +2 -0
- package/src/lib/contribution.js.map +1 -0
- package/src/lib/dialog-ref.d.ts +25 -0
- package/src/lib/dialog-ref.js +37 -0
- package/src/lib/dialog-ref.js.map +1 -0
- package/src/lib/dialog.d.ts +105 -0
- package/src/lib/dialog.js +2 -0
- package/src/lib/dialog.js.map +1 -0
- package/src/lib/dirty-surface.d.ts +48 -0
- package/src/lib/dirty-surface.js +2 -0
- package/src/lib/dirty-surface.js.map +1 -0
- package/src/lib/menu.d.ts +48 -0
- package/src/lib/menu.js +2 -0
- package/src/lib/menu.js.map +1 -0
- package/src/lib/notification.d.ts +28 -0
- package/src/lib/notification.js +2 -0
- package/src/lib/notification.js.map +1 -0
- package/src/lib/pane-area.d.ts +29 -0
- package/src/lib/pane-area.js +2 -0
- package/src/lib/pane-area.js.map +1 -0
- package/src/lib/plugin-state.d.ts +52 -0
- package/src/lib/plugin-state.js +2 -0
- package/src/lib/plugin-state.js.map +1 -0
- package/src/lib/plugin.d.ts +259 -0
- package/src/lib/plugin.js +2 -0
- package/src/lib/plugin.js.map +1 -0
- package/src/lib/product-identity.d.ts +25 -0
- package/src/lib/product-identity.js +17 -0
- package/src/lib/product-identity.js.map +1 -0
- package/src/lib/rail-item.d.ts +61 -0
- package/src/lib/rail-item.js +2 -0
- package/src/lib/rail-item.js.map +1 -0
- package/src/lib/settings-model.d.ts +164 -0
- package/src/lib/settings-model.js +2 -0
- package/src/lib/settings-model.js.map +1 -0
- package/src/lib/surface.d.ts +220 -0
- package/src/lib/surface.js +2 -0
- package/src/lib/surface.js.map +1 -0
- package/src/lib/view-state.d.ts +38 -0
- package/src/lib/view-state.js +9 -0
- package/src/lib/view-state.js.map +1 -0
- package/src/lib/view.d.ts +103 -0
- package/src/lib/view.js +2 -0
- package/src/lib/view.js.map +1 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { Type } from '@angular/core';
|
|
2
|
+
import { AccessRequirement } from './auth.js';
|
|
3
|
+
import { ContainerSpec } from './content-route.js';
|
|
4
|
+
import { ViewAction } from './view.js';
|
|
5
|
+
/**
|
|
6
|
+
* How a surface is presented (the UI-boundary form). Exactly one is set:
|
|
7
|
+
*
|
|
8
|
+
* - `component` — an Angular class rendered in-process (trusted rung; the default today). Cannot
|
|
9
|
+
* cross an RPC boundary, so a **sandboxed** plugin never uses this form.
|
|
10
|
+
* - `loadComponent` — the same thing, **deferred**: a loader the host calls the first time the surface is
|
|
11
|
+
* actually shown, mirroring Angular's `Route.loadComponent`. Use it when a surface drags a heavy
|
|
12
|
+
* dependency tree behind it (a chart engine, a graph layout), so that code lands in its own chunk and a
|
|
13
|
+
* user who never opens the surface never downloads it. Routable surfaces hand it straight to the router;
|
|
14
|
+
* host-mounted ones render nothing until it resolves.
|
|
15
|
+
* - `iframe` — a URL the host mounts as an **isolated** `<iframe sandbox>` surface. A plain string, so it
|
|
16
|
+
* serialises over the `ctx`-RPC boundary — which is why it is the form a **sandboxed** plugin uses
|
|
17
|
+
* (the first untrusted rung). A **trusted** plugin may use it too, to embed a foreign origin on purpose
|
|
18
|
+
* (a dashboard, a docs site, a video): a sandboxed plugin is confined to same-origin URLs at the RPC
|
|
19
|
+
* seam, whereas for a trusted one the distribution's CSP `frame-src` decides what may be framed.
|
|
20
|
+
* - `container` — the surface hosts a **nested pane tree** of child surfaces
|
|
21
|
+
* ("workspace-in-a-tab"): the host draws the inner drag/split/tab mechanics, the surface only declares
|
|
22
|
+
* which children it offers. Must be combined with `routable` (the container tab holds its own `:id`).
|
|
23
|
+
*
|
|
24
|
+
* Mirrors the {@link ContentSurface} union so a {@link Surface} and a {@link ContentRoute}
|
|
25
|
+
* present identically, deliberately: `ContentRoute`
|
|
26
|
+
* remains the host's internal storage shape, `Surface` the one authoring contract.
|
|
27
|
+
*/
|
|
28
|
+
export type SurfacePresentation = {
|
|
29
|
+
readonly component: Type<unknown>;
|
|
30
|
+
readonly loadComponent?: never;
|
|
31
|
+
readonly iframe?: never;
|
|
32
|
+
readonly container?: never;
|
|
33
|
+
} | {
|
|
34
|
+
readonly loadComponent: () => Promise<Type<unknown>>;
|
|
35
|
+
readonly component?: never;
|
|
36
|
+
readonly iframe?: never;
|
|
37
|
+
readonly container?: never;
|
|
38
|
+
} | {
|
|
39
|
+
readonly iframe: string;
|
|
40
|
+
readonly component?: never;
|
|
41
|
+
readonly loadComponent?: never;
|
|
42
|
+
readonly container?: never;
|
|
43
|
+
} | {
|
|
44
|
+
readonly container: ContainerSpec;
|
|
45
|
+
readonly component?: never;
|
|
46
|
+
readonly loadComponent?: never;
|
|
47
|
+
readonly iframe?: never;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* The **routable** capability of a {@link Surface}: the surface is URL-addressable, so it
|
|
51
|
+
* can hold the one URL pane (deep-link, browser back/forward, `RouteReuseStrategy`). Carries the former
|
|
52
|
+
* {@link ContentRoute} route fields. Omit for a surface that only ever lives as host-rendered workspace
|
|
53
|
+
* state (a classic sidebar view).
|
|
54
|
+
*/
|
|
55
|
+
export interface SurfaceRoutable {
|
|
56
|
+
/** Route path (Angular syntax), e.g. `'reports'`, `'doc/:id'`, `'dashboard'`. */
|
|
57
|
+
readonly path: string;
|
|
58
|
+
/**
|
|
59
|
+
* A **chromeless** surface owns the whole content area while active: no tab strip, never a tab,
|
|
60
|
+
* excluded from splits, drags and the new-tab picker — the full-area screen that login and
|
|
61
|
+
* onboarding need. Every other routable surface lives in the tab area: navigating to it opens (or
|
|
62
|
+
* re-uses) a tab, in whatever workspace the user is standing in. (This flag replaces the retired
|
|
63
|
+
* `group` concept, whose only remaining meaning had been "lives in the tab area".)
|
|
64
|
+
*/
|
|
65
|
+
readonly chromeless?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Default title for the tab the host opens when navigation lands on this route (a deep link,
|
|
68
|
+
* browser history, `navigateContent`). Falls back to {@link Surface.title} when omitted.
|
|
69
|
+
*/
|
|
70
|
+
readonly title?: string;
|
|
71
|
+
/** Default icon for that dynamic tab; falls back to {@link Surface.icon}. */
|
|
72
|
+
readonly icon?: string;
|
|
73
|
+
/** Whether the routable {@link title} is a literal rather than a Transloco key. */
|
|
74
|
+
readonly titleIsLiteral?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Nested sub-route segments — the surface's own level-2 tabs, reflected in the URL.
|
|
77
|
+
* Angular syntax, so a segment may carry a value (`'structure/:structureId'`); the bare tab root is a
|
|
78
|
+
* valid address with no forced redirect to the first entry.
|
|
79
|
+
*/
|
|
80
|
+
readonly subRoutes?: readonly string[];
|
|
81
|
+
/**
|
|
82
|
+
* Keep this surface's **permanent tab pointing at the current selection**. Its siblings are facets of
|
|
83
|
+
* one choice rather than independent documents: pick a program on one tab and the others should show
|
|
84
|
+
* that program.
|
|
85
|
+
*
|
|
86
|
+
* The host knows the parameter values of the address it is on, because it knows which pattern matched.
|
|
87
|
+
* For a following tab it substitutes those values **by name** into this surface's pattern, and where a
|
|
88
|
+
* value is unknown it truncates the address before it:
|
|
89
|
+
*
|
|
90
|
+
* ```
|
|
91
|
+
* on cedents/US003950/programs/205470/pricing
|
|
92
|
+
* cedents/:cedentId/programs/:programId/treaties → cedents/US003950/programs/205470/treaties
|
|
93
|
+
* cedents/:cedentId/programs/:programId/:reportId → cedents/US003950/programs/205470
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* **Off by default**, because the opposite is right for a tab showing one specific document: nobody
|
|
97
|
+
* wants an open quote rewritten because a parameter changed elsewhere. A following surface is drawn
|
|
98
|
+
* as a **permanent facet tab** (labelled by {@link SurfaceBase.title}/`icon`, ordered by
|
|
99
|
+
* {@link SurfaceBase.order}) whenever its computed address leads somewhere — it does not open
|
|
100
|
+
* dynamic tabs. A dynamically opened tab keeps the address it was opened with,
|
|
101
|
+
* and a tab dragged out of the group that carries the browser address freezes where it is — which is
|
|
102
|
+
* what lets a user park one program beside another.
|
|
103
|
+
*
|
|
104
|
+
* Two following surfaces may use the same parameter name only when the pattern **before** it is
|
|
105
|
+
* identical; otherwise the name means two different things and the host would fill one surface's
|
|
106
|
+
* address with the other's value. A collision refuses that one registration with a message.
|
|
107
|
+
*/
|
|
108
|
+
readonly follows?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Own **everything below** {@link path}: the longest registered prefix wins, and whatever no more
|
|
111
|
+
* specific surface claims is handed to this one as **the rest** — verbatim, **including the query
|
|
112
|
+
* string**. Without it a deeper address matches no route at all and the navigation fails; with it
|
|
113
|
+
* `programs/US003950/pricing?t=886320` reaches the surface registered on `programs` and hands over
|
|
114
|
+
* `US003950/pricing?t=886320`.
|
|
115
|
+
*
|
|
116
|
+
* The prefix stays the **tab root**, so the whole subtree is one tab whose state survives every move
|
|
117
|
+
* within it. That is the trade the flag buys you: what you put *in the rest* changes without
|
|
118
|
+
* rebuilding the surface, what you put *in the pattern* is a parameter change and may rebuild it.
|
|
119
|
+
*
|
|
120
|
+
* How the rest reaches you depends on the rung. A **sandboxed** surface receives it over its channel
|
|
121
|
+
* (`state.rest`) and sets its own with the channel's `navigate` — both confined to this prefix. A
|
|
122
|
+
* **trusted** component reads it the ordinary Angular way (its child `ActivatedRoute`/the router) and
|
|
123
|
+
* navigates with the router.
|
|
124
|
+
*
|
|
125
|
+
* A prefix of **fewer than two segments** owns most of the address space, which is where the surface
|
|
126
|
+
* channel's "confined to your own territory" guarantee stops meaning anything — declaring it there
|
|
127
|
+
* additionally requires the `navigation` capability.
|
|
128
|
+
*/
|
|
129
|
+
readonly rest?: boolean;
|
|
130
|
+
}
|
|
131
|
+
/** The metadata every surface form shares, independent of its presentation. */
|
|
132
|
+
export interface SurfaceBase {
|
|
133
|
+
/** Stable id (ordering, active selection, override/removal, per-instance `VIEW_STATE` key). */
|
|
134
|
+
readonly id: string;
|
|
135
|
+
/** Transloco key (or literal) for the surface title (its tab label + panel header). */
|
|
136
|
+
readonly title: string;
|
|
137
|
+
/** Icon name — resolved by the host icon registry (a plain string). */
|
|
138
|
+
readonly icon?: string;
|
|
139
|
+
/** Lower renders first among sibling surfaces in a dock (default 0). */
|
|
140
|
+
readonly order?: number;
|
|
141
|
+
/** The surface's own header actions, shown in the pane header while active (ex `View.actions`). */
|
|
142
|
+
readonly actions?: readonly ViewAction[];
|
|
143
|
+
/**
|
|
144
|
+
* Declarative auth gating: the host hides/disables/placeholders the surface when the current
|
|
145
|
+
* session does not meet the requirement. Presentation only — real enforcement is server-side. Omit for a
|
|
146
|
+
* surface everyone sees.
|
|
147
|
+
*/
|
|
148
|
+
readonly access?: AccessRequirement;
|
|
149
|
+
/**
|
|
150
|
+
* Opt in to **named saved instances**: the host shows a switcher so the user can save,
|
|
151
|
+
* name, rename and delete several configurations of this surface, each with its own `VIEW_STATE` blob.
|
|
152
|
+
*/
|
|
153
|
+
readonly instanceable?: boolean;
|
|
154
|
+
/**
|
|
155
|
+
* The **routable** capability — provide to let this surface hold the URL pane. A surface
|
|
156
|
+
* with `routable` is reached by its `path`; one without is host-rendered workspace state only.
|
|
157
|
+
*/
|
|
158
|
+
readonly routable?: SurfaceRoutable;
|
|
159
|
+
/**
|
|
160
|
+
* Retention when the surface is **hidden** — rendered by no pane of this window: a tab switch, a
|
|
161
|
+
* minimised or closed pane, a collapsed sidebar, the closed compact drawer. The default is
|
|
162
|
+
* the distribution's retention default (`provideShell({ retention })`), which itself
|
|
163
|
+
* defaults to **destroy**: a hidden, clean surface is destroyed and rebuilt on return — state that
|
|
164
|
+
* must survive belongs in `VIEW_STATE`. Declare `'always'` to keep the instance alive while hidden
|
|
165
|
+
* (an expensive rebuild, a live connection); `'never'` to opt back into destruction when the
|
|
166
|
+
* distribution flipped the default. The declaration wins over the distribution default. A retained
|
|
167
|
+
* **`iframe` surface is hidden in place** rather than destroyed (no reload, no new Penpal
|
|
168
|
+
* handshake) but is still rebuilt whenever it would have to *move* — a split, a drag into another
|
|
169
|
+
* pane, a minimise — because moving an `<iframe>` element in the DOM reloads it. `container`
|
|
170
|
+
* surfaces are always rebuilt.
|
|
171
|
+
*/
|
|
172
|
+
readonly retain?: 'always' | 'never';
|
|
173
|
+
/**
|
|
174
|
+
* Auto-save on hiding: when an instance of this surface becomes hidden while its
|
|
175
|
+
* {@link DirtySurface.surfaceDirty} reports unsaved changes, the host calls its
|
|
176
|
+
* {@link DirtySurface.surfaceSave} fire-and-forget — the gesture stays instant. Safe by
|
|
177
|
+
* construction: while the save is in flight the instance is still dirty and therefore still
|
|
178
|
+
* alive; a failure keeps it dirty and surfaces as an error, never as silent loss. Only
|
|
179
|
+
* meaningful for a surface whose component implements {@link DirtySurface} with a save.
|
|
180
|
+
*/
|
|
181
|
+
readonly saveOn?: 'hide';
|
|
182
|
+
/**
|
|
183
|
+
* Whether a tab of this surface may be closed by the user — the × affordance, the `Delete` key and
|
|
184
|
+
* the close entries of the tab menu. Defaults to `true`; declare `false` for the overview screen a
|
|
185
|
+
* product wants to keep open while its other tabs come and go.
|
|
186
|
+
*
|
|
187
|
+
* It applies to **every** tab of this surface, so it fits a parameterless route like `dashboard`
|
|
188
|
+
* and is almost always wrong for `doc/:id`, where it would make no document closable at all. The
|
|
189
|
+
* user can still move such a tab, split it and drag it elsewhere; only closing is refused.
|
|
190
|
+
*/
|
|
191
|
+
readonly closable?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* Whether the host insets this surface from its pane edges. Defaults to `true` — comfortable for the
|
|
194
|
+
* prose, forms and lists most surfaces are. Declare `false` for a surface that **is** the content and
|
|
195
|
+
* owns its own edges: a viewer, a canvas, a map, an edge-to-edge table. It travels with the surface,
|
|
196
|
+
* so it holds wherever the user puts it — the URL pane, a split, a sidebar, a pop-out window.
|
|
197
|
+
*
|
|
198
|
+
* Only the inset is yours to switch off; how wide it is stays a styling question, so a product that
|
|
199
|
+
* wants a different amount everywhere writes plain unlayered CSS rather than asking for a token.
|
|
200
|
+
*/
|
|
201
|
+
readonly padded?: boolean;
|
|
202
|
+
/**
|
|
203
|
+
* Which docks (region ids, e.g. `'primary'`/`'secondary'`, or `'content'`) this surface may be hosted in
|
|
204
|
+
* — capabilities, not location: the *user* decides where a surface finally lands. The first
|
|
205
|
+
* entry is the surface's **home** dock (where a non-routable surface first appears). Omit only for a
|
|
206
|
+
* routable surface (its home is the content area); a non-routable surface **must** declare `docks` —
|
|
207
|
+
* the host fails fast at registration otherwise. A non-routable surface with an **empty** `docks: []`
|
|
208
|
+
* is a **container-only child**: it is never seeded into a panel and exists only to be
|
|
209
|
+
* mounted inside a container's nested pane tree by id.
|
|
210
|
+
*/
|
|
211
|
+
readonly docks?: readonly string[];
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* The **one author contract**: a plugin contributes a `Surface` and declares *what it can do*
|
|
215
|
+
* (routable · instanceable · which docks) rather than *where it lives* — the user decides placement.
|
|
216
|
+
* This is the convergence of the two older contracts, {@link View} (a component docked in a Panel region)
|
|
217
|
+
* and {@link ContentRoute} (a URL-addressed content view), which the host still uses internally as its
|
|
218
|
+
* storage shapes. Register it with `ctx.registerSurface`.
|
|
219
|
+
*/
|
|
220
|
+
export type Surface = SurfaceBase & SurfacePresentation;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface.js","sourceRoot":"","sources":["../../../../../../libs/core/plugin-sdk/src/lib/surface.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* An instance-scoped handle a mounted view uses to read and persist its **own** serialisable state — the
|
|
4
|
+
* chosen view + filters, scroll position, expanded nodes. The platform stays
|
|
5
|
+
* domain-pure: it stores an opaque blob and only this view interprets it.
|
|
6
|
+
*
|
|
7
|
+
* Since a hidden surface is destroyed as soon as it is clean, this is the survival path:
|
|
8
|
+
* anything that must outlive a tab switch, a collapsed sidebar or an F5 belongs here — the rule to author
|
|
9
|
+
* by is *evictable = reload-safe*.
|
|
10
|
+
*
|
|
11
|
+
* Reads are Signal-shaped (`() => T`) so a template re-reads reactively (the same convention as
|
|
12
|
+
* `PluginSession`); writes are auto-saved by the host (debounced) — the view never touches storage, and
|
|
13
|
+
* a fresh instance simply reads `undefined` and applies its own default.
|
|
14
|
+
*
|
|
15
|
+
* The host provides one handle per mounted **docked** surface instance. A **routable** surface has none:
|
|
16
|
+
* its shareable state belongs in the URL it already owns (route params, `subRoutes`), and unsaved work is
|
|
17
|
+
* carried by `DirtySurface` or a `retain` declaration. A **sandboxed** surface has none either — nothing
|
|
18
|
+
* of this shape crosses the RPC boundary; it declares `retain: 'always'` instead, and the host hides the
|
|
19
|
+
* iframe in place rather than destroying it, so the document keeps its own state.
|
|
20
|
+
*/
|
|
21
|
+
export interface ViewState<T = unknown> {
|
|
22
|
+
/** The instance's saved state, reactive; `undefined` for a fresh instance (apply your own default). */
|
|
23
|
+
readonly value: () => T | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Replace the state; the host auto-saves it to the active instance. Call it freely — writes are
|
|
26
|
+
* debounced. It replaces the **whole** blob, so spread the current value when you change one field.
|
|
27
|
+
*/
|
|
28
|
+
set(next: T): void;
|
|
29
|
+
/** The id of the instance this view is bound to. */
|
|
30
|
+
readonly instanceId: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* DI token for the mounted view's {@link ViewState}. A docked view injects it, typing the state to its
|
|
34
|
+
* own shape: `const vs = inject(VIEW_STATE) as ViewState<MyState>`. The host provides one per instance.
|
|
35
|
+
* Injecting it from a routable or sandboxed surface throws — see {@link ViewState} for what those do
|
|
36
|
+
* instead.
|
|
37
|
+
*/
|
|
38
|
+
export declare const VIEW_STATE: InjectionToken<ViewState<unknown>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* DI token for the mounted view's {@link ViewState}. A docked view injects it, typing the state to its
|
|
4
|
+
* own shape: `const vs = inject(VIEW_STATE) as ViewState<MyState>`. The host provides one per instance.
|
|
5
|
+
* Injecting it from a routable or sandboxed surface throws — see {@link ViewState} for what those do
|
|
6
|
+
* instead.
|
|
7
|
+
*/
|
|
8
|
+
export const VIEW_STATE = new InjectionToken('lw.view-state');
|
|
9
|
+
//# sourceMappingURL=view-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-state.js","sourceRoot":"","sources":["../../../../../../libs/core/plugin-sdk/src/lib/view-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAiC/C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,cAAc,CAAY,eAAe,CAAC,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Type } from '@angular/core';
|
|
2
|
+
import { AccessRequirement } from './auth.js';
|
|
3
|
+
/**
|
|
4
|
+
* A view's own header action (`header.actions`) — an independent function
|
|
5
|
+
* of that view (e.g. "new", "sort"), shown in the panel header while the view is
|
|
6
|
+
* active. Not a view switcher (that is the Rail). Mirrors Obsidian's view actions.
|
|
7
|
+
*/
|
|
8
|
+
export interface ViewAction {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
/** Icon name — resolved by the host icon registry (a plain string). */
|
|
11
|
+
readonly icon: string;
|
|
12
|
+
/** Transloco key (or literal) for the tooltip/label. */
|
|
13
|
+
readonly title: string;
|
|
14
|
+
/** Lower renders first (default 0). */
|
|
15
|
+
readonly order?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Id of a menu slot to open as this action's **context menu** on right-click — region-agnostic:
|
|
18
|
+
* the host wires the right-click uniformly and passes a serialisable context (`{ targetKind, id, region }`).
|
|
19
|
+
* Contribute items to the slot with `ctx.registerMenuItem({ menu, … })`. Omit for no context menu.
|
|
20
|
+
*/
|
|
21
|
+
readonly menu?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Id of a registered {@link Command} this action triggers. Provide this **or** {@link run}; when
|
|
24
|
+
* set, the host runs that command (so a keybinding/palette can share the same behaviour).
|
|
25
|
+
*/
|
|
26
|
+
readonly command?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Declarative auth gating: the host hides (default) or disables this action when the
|
|
29
|
+
* current session does not meet the requirement. Presentation only — real enforcement is
|
|
30
|
+
* server-side. Omit for an action everyone sees.
|
|
31
|
+
*/
|
|
32
|
+
readonly access?: AccessRequirement;
|
|
33
|
+
/**
|
|
34
|
+
* Inline behaviour, for an action that is not backed by a registered command. May be async; the
|
|
35
|
+
* host fires it fire-and-forget. Typed `() => void` so a one-expression arrow whose handler
|
|
36
|
+
* happens to return a value (e.g. `() => ctx.ui.openSettings()`) still assigns — the return is
|
|
37
|
+
* ignored either way.
|
|
38
|
+
*/
|
|
39
|
+
run?(): void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A view docked into a **Panel** region (chrome-local, auto-tabbed by the host) — the host's internal
|
|
43
|
+
* shape for a **non-routable** {@link Surface}. Authors do not build one directly: contribute a
|
|
44
|
+
* `Surface` via `ctx.registerSurface` and the host normalises it into this.
|
|
45
|
+
*/
|
|
46
|
+
export interface View {
|
|
47
|
+
/** Stable id (ordering, active-view selection, future removal). */
|
|
48
|
+
readonly id: string;
|
|
49
|
+
/** Target region id this view docks into. */
|
|
50
|
+
readonly region: string;
|
|
51
|
+
/** Transloco key (or literal) for the view title. */
|
|
52
|
+
readonly title: string;
|
|
53
|
+
/** Lower renders/launchers first within a region (default 0). */
|
|
54
|
+
readonly order?: number;
|
|
55
|
+
/** Icon name for this view's tab in the panel's tab bar. */
|
|
56
|
+
readonly icon?: string;
|
|
57
|
+
/** The view's own header actions, shown in the panel header while active. */
|
|
58
|
+
readonly actions?: readonly ViewAction[];
|
|
59
|
+
/**
|
|
60
|
+
* Declarative auth gating: the host **hides** the whole view (its tab and body) when
|
|
61
|
+
* the current session does not meet the requirement. A view is present or not, so `mode` is
|
|
62
|
+
* ignored here (unlike a button, a disabled tab is not a useful state). Presentation only — real
|
|
63
|
+
* enforcement is server-side. Omit for a view everyone sees.
|
|
64
|
+
*/
|
|
65
|
+
readonly access?: AccessRequirement;
|
|
66
|
+
/**
|
|
67
|
+
* Opt in to **named saved instances**: the host shows a switcher in the view
|
|
68
|
+
* header so the user can save, name, rename and delete several configurations of this view, each with
|
|
69
|
+
* its own `VIEW_STATE` blob (auto-saved). The non-deletable *default* instance carries the view's
|
|
70
|
+
* baseline state. Omit for a single implicit instance (the view's own `VIEW_STATE`).
|
|
71
|
+
*/
|
|
72
|
+
readonly instanceable?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Retention when the view is hidden — carried through from {@link Surface.retain}.
|
|
75
|
+
* `'always'` keeps the instance alive while hidden; `'never'` forces destruction; omitted falls back
|
|
76
|
+
* to the distribution's retention default (destroy).
|
|
77
|
+
*/
|
|
78
|
+
readonly retain?: 'always' | 'never';
|
|
79
|
+
/**
|
|
80
|
+
* Auto-save on hiding — carried through from {@link Surface.saveOn}: a hidden dirty
|
|
81
|
+
* instance's `surfaceSave` is called fire-and-forget.
|
|
82
|
+
*/
|
|
83
|
+
readonly saveOn?: 'hide';
|
|
84
|
+
/** Whether the user may close a tab of this view — carried through from {@link Surface.closable}. */
|
|
85
|
+
readonly closable?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Whether the host insets this surface from its pane edges (default `true`). Declare `false` for a
|
|
88
|
+
* surface that owns its own edges — a viewer, a canvas, a map, an edge-to-edge table. See
|
|
89
|
+
* `SurfaceBase.padded`.
|
|
90
|
+
*/
|
|
91
|
+
readonly padded?: boolean;
|
|
92
|
+
/** Component the host renders as the view body. */
|
|
93
|
+
readonly component?: Type<unknown>;
|
|
94
|
+
/** Deferred alternative to {@link component} — the host calls it the first time the view is shown. */
|
|
95
|
+
readonly loadComponent?: () => Promise<Type<unknown>>;
|
|
96
|
+
/**
|
|
97
|
+
* A URL the host mounts as an **isolated** `<iframe sandbox>` view body — the same presentation form a
|
|
98
|
+
* routable surface may take, now valid at a dock too. A docked surface has no address, so
|
|
99
|
+
* its channel's `navigate` is a no-op with a development warning and it is told no tab or sub-route;
|
|
100
|
+
* everything else it receives (locale, theme, tokens, text size, session, its instance id) is unchanged.
|
|
101
|
+
*/
|
|
102
|
+
readonly iframe?: string;
|
|
103
|
+
}
|
package/src/lib/view.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../../../../libs/core/plugin-sdk/src/lib/view.ts"],"names":[],"mappings":""}
|