@xpufx/paseo-top 0.4.3 → 0.4.5
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/OVERVIEW.md +17 -0
- package/client/host-ui.tsx +184 -0
- package/client/multi-host-view.tsx +57 -43
- package/client/multi-host.ts +36 -13
- package/client/pill-labels.ts +124 -7
- package/client/pill.tsx +724 -669
- package/client/resources-query.ts +1 -1
- package/client/settings-events.ts +33 -0
- package/client/settings-ui.tsx +86 -9
- package/client/surface.tsx +310 -274
- package/client/telemetry-copy.ts +8 -2
- package/client/telemetry.tsx +372 -321
- package/client/turn-panel.tsx +126 -104
- package/client/vendor/paseo-plugin-helper/{host.ts → core/host.ts} +21 -61
- package/client/vendor/paseo-plugin-helper/core/index.ts +76 -0
- package/client/vendor/paseo-plugin-helper/core/plugin-load-count.ts +89 -0
- package/client/vendor/paseo-plugin-helper/{query-refresh.ts → core/query-refresh.ts} +2 -2
- package/client/vendor/paseo-plugin-helper/{query.ts → core/query.ts} +2 -2
- package/client/vendor/paseo-plugin-helper/{settings.ts → core/settings.ts} +1 -1
- package/client/vendor/paseo-plugin-helper/{shared-settings.ts → core/shared-settings.ts} +2 -2
- package/client/vendor/paseo-plugin-helper/{utils → lifecycle}/clipboard.ts +2 -2
- package/client/vendor/paseo-plugin-helper/lifecycle/flair.ts +26 -0
- package/client/vendor/paseo-plugin-helper/{theme/color-utils.ts → lifecycle/host-color.ts} +95 -38
- package/client/vendor/paseo-plugin-helper/lifecycle/host-theme.tsx +109 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/index.ts +23 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/multi-host.ts +66 -0
- package/client/vendor/paseo-plugin-helper/{panel.tsx → lifecycle/panel.tsx} +7 -7
- package/client/vendor/paseo-plugin-helper/{pill.tsx → lifecycle/pill.tsx} +118 -338
- package/client/vendor/paseo-plugin-helper/lifecycle/providers.tsx +46 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/scroll-owner.ts +26 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/surface.tsx +140 -0
- package/client/vendor/paseo-plugin-helper/ui/color.ts +1 -0
- package/client/vendor/paseo-plugin-helper/ui/content.tsx +1326 -0
- package/client/vendor/paseo-plugin-helper/ui/controls.tsx +1018 -0
- package/client/vendor/paseo-plugin-helper/{components/DataTable.tsx → ui/data.tsx} +55 -47
- package/client/vendor/paseo-plugin-helper/ui/index.ts +44 -0
- package/client/vendor/paseo-plugin-helper/ui/layout.tsx +263 -0
- package/client/vendor/paseo-plugin-helper/ui/modal.tsx +111 -0
- package/client/vendor/paseo-plugin-helper/ui/plugin-reload-banner.tsx +119 -0
- package/client/vendor/paseo-plugin-helper/{settings-screen.tsx → ui/settings-screen.tsx} +3 -3
- package/client/vendor/paseo-plugin-helper/ui/settings.ts +36 -0
- package/client/vendor/paseo-plugin-helper/ui/text.tsx +821 -0
- package/client/vendor/paseo-plugin-helper/ui/theme.tsx +1 -0
- package/client/vendor/permission-audit/client.tsx +706 -0
- package/client/vendor/permission-audit/index.tsx +1 -0
- package/index.client.tsx +58 -37
- package/index.server.ts +256 -227
- package/package.json +14 -2
- package/paseo-plugin.json +2 -0
- package/screenshots/1-paseo-top-modal-system.jpg +0 -0
- package/screenshots/2-paseo-top-modal-workspace.jpg +0 -0
- package/screenshots/3-paseo-top-modal-settings.jpg +0 -0
- package/screenshots/4-paseo-top-modal-about.jpg +0 -0
- package/screenshots/paseo-top-dashboard.jpg +0 -0
- package/screenshots/paseo-top-general-view.jpg +0 -0
- package/server/resources.ts +98 -0
- package/server/vendor/paseo-plugin-helper/custom-pills.ts +70 -0
- package/server/vendor/paseo-plugin-helper/index.ts +4 -0
- package/server/vendor/paseo-plugin-helper/logger.ts +5 -16
- package/server/vendor/paseo-plugin-helper/mcp-injection.ts +20 -2
- package/server/vendor/paseo-plugin-helper/plugins.ts +184 -19
- package/server/vendor/paseo-plugin-helper/rpc-guard.ts +2 -2
- package/server/vendor/paseo-plugin-helper/storage-guard.ts +294 -0
- package/server/vendor/paseo-plugin-helper/storage.ts +36 -2
- package/server/vendor/paseo-plugin-helper/telemetry.ts +486 -0
- package/server/vendor/paseo-plugin-helper/tickets.ts +1232 -0
- package/server/vendor/permission-audit/index.ts +1 -0
- package/server/vendor/permission-audit/server.ts +839 -0
- package/shared/helper-version.ts +20 -0
- package/shared/multi-host.ts +156 -155
- package/shared/resources.ts +146 -1
- package/shared/vendor/paseo-plugin-helper/async.ts +14 -7
- package/shared/vendor/paseo-plugin-helper/features.ts +244 -0
- package/shared/vendor/paseo-plugin-helper/forge.ts +27 -0
- package/shared/vendor/paseo-plugin-helper/index.ts +2 -0
- package/shared/vendor/paseo-plugin-helper/tickets.ts +1104 -0
- package/shared/vendor/permission-audit/filter.ts +61 -0
- package/shared/vendor/permission-audit/index.ts +2 -0
- package/shared/vendor/permission-audit/shared.ts +119 -0
- package/shared/version.ts +1 -1
- package/client/vendor/paseo-plugin-helper/components/AboutSection.tsx +0 -493
- package/client/vendor/paseo-plugin-helper/components/AttentionBeacon.tsx +0 -250
- package/client/vendor/paseo-plugin-helper/components/Badge.tsx +0 -156
- package/client/vendor/paseo-plugin-helper/components/Button.tsx +0 -184
- package/client/vendor/paseo-plugin-helper/components/Card.tsx +0 -225
- package/client/vendor/paseo-plugin-helper/components/CodeBlock.tsx +0 -196
- package/client/vendor/paseo-plugin-helper/components/Collapsible.tsx +0 -277
- package/client/vendor/paseo-plugin-helper/components/CommandBox.tsx +0 -172
- package/client/vendor/paseo-plugin-helper/components/CopyButton.tsx +0 -180
- package/client/vendor/paseo-plugin-helper/components/EmptyState.tsx +0 -97
- package/client/vendor/paseo-plugin-helper/components/HighlightedText.tsx +0 -70
- package/client/vendor/paseo-plugin-helper/components/InlineButton.tsx +0 -75
- package/client/vendor/paseo-plugin-helper/components/KeyValue.tsx +0 -446
- package/client/vendor/paseo-plugin-helper/components/MetricGauge.tsx +0 -247
- package/client/vendor/paseo-plugin-helper/components/ProgressBar.tsx +0 -117
- package/client/vendor/paseo-plugin-helper/components/Responsive.tsx +0 -53
- package/client/vendor/paseo-plugin-helper/components/SearchInput.tsx +0 -118
- package/client/vendor/paseo-plugin-helper/components/SectionHeader.tsx +0 -80
- package/client/vendor/paseo-plugin-helper/components/Select.tsx +0 -215
- package/client/vendor/paseo-plugin-helper/components/StatusDot.tsx +0 -80
- package/client/vendor/paseo-plugin-helper/components/Tabs.tsx +0 -319
- package/client/vendor/paseo-plugin-helper/components/TextInput.tsx +0 -150
- package/client/vendor/paseo-plugin-helper/components/Toggle.tsx +0 -163
- package/client/vendor/paseo-plugin-helper/components/TruncatedText.tsx +0 -157
- package/client/vendor/paseo-plugin-helper/components/index.ts +0 -25
- package/client/vendor/paseo-plugin-helper/custom-pills.tsx +0 -224
- package/client/vendor/paseo-plugin-helper/forge-icon.tsx +0 -79
- package/client/vendor/paseo-plugin-helper/icon.tsx +0 -39
- package/client/vendor/paseo-plugin-helper/index.ts +0 -29
- package/client/vendor/paseo-plugin-helper/layout/ActionBar.tsx +0 -49
- package/client/vendor/paseo-plugin-helper/layout/FormRow.tsx +0 -103
- package/client/vendor/paseo-plugin-helper/layout/Grid.tsx +0 -65
- package/client/vendor/paseo-plugin-helper/layout/ModalBody.tsx +0 -378
- package/client/vendor/paseo-plugin-helper/layout/ModalContent.tsx +0 -51
- package/client/vendor/paseo-plugin-helper/layout/Row.tsx +0 -39
- package/client/vendor/paseo-plugin-helper/layout/Stack.tsx +0 -39
- package/client/vendor/paseo-plugin-helper/layout/index.ts +0 -7
- package/client/vendor/paseo-plugin-helper/styles/index.ts +0 -1
- package/client/vendor/paseo-plugin-helper/styles/recipes.ts +0 -550
- package/client/vendor/paseo-plugin-helper/surface.tsx +0 -80
- package/client/vendor/paseo-plugin-helper/theme/flair.ts +0 -76
- package/client/vendor/paseo-plugin-helper/theme/host-variables.ts +0 -121
- package/client/vendor/paseo-plugin-helper/theme/index.ts +0 -7
- package/client/vendor/paseo-plugin-helper/theme/provider.tsx +0 -178
- package/client/vendor/paseo-plugin-helper/theme/responsive.ts +0 -213
- package/client/vendor/paseo-plugin-helper/theme/tokens.ts +0 -200
- package/client/vendor/paseo-plugin-helper/theme/useResponsive.ts +0 -57
- /package/client/vendor/paseo-plugin-helper/{command-center.ts → core/command-center.ts} +0 -0
- /package/client/vendor/paseo-plugin-helper/{snapshot.ts → core/snapshot.ts} +0 -0
- /package/client/vendor/paseo-plugin-helper/{utils → lifecycle}/haptics.ts +0 -0
|
@@ -1,7 +1,63 @@
|
|
|
1
1
|
import type { StatusVariant, ThemeColors } from "../../../../shared/vendor/paseo-plugin-helper/types";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* The single host-color fallback owned by the helper.
|
|
5
|
+
*
|
|
6
|
+
* A host `theme` prop normally supplies every token, but a partial or older
|
|
7
|
+
* payload may omit some. Rather than each plugin inventing its own
|
|
8
|
+
* `colors.border || "#334155"` guard, the helper resolves a theme once, here,
|
|
9
|
+
* and every adapter reads the resolved token. Plugins may pass this palette to
|
|
10
|
+
* code that renders outside a provider (recipes, previews, tests); they must
|
|
11
|
+
* not define their own literal fallbacks.
|
|
12
|
+
*/
|
|
13
|
+
export const FALLBACK_COLORS: ThemeColors = {
|
|
14
|
+
surface0: "#18181b",
|
|
15
|
+
surface1: "#27272a",
|
|
16
|
+
surface2: "#3f3f46",
|
|
17
|
+
border: "#3f3f46",
|
|
18
|
+
foreground: "#fafafa",
|
|
19
|
+
foregroundMuted: "#a1a1aa",
|
|
20
|
+
accent: "#3b82f6",
|
|
21
|
+
accentForeground: "#ffffff",
|
|
22
|
+
statusSuccess: "#22c55e",
|
|
23
|
+
statusWarning: "#eab308",
|
|
24
|
+
statusDanger: "#ef4444",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The host theme carries no shadow token, so shadows use this documented
|
|
29
|
+
* overlay constant owned by the helper. It is not a `ThemeColors` token and is
|
|
30
|
+
* intentionally not part of the palette a render guard checks; it is the one
|
|
31
|
+
* allowed non-theme color.
|
|
32
|
+
*/
|
|
33
|
+
export const HOST_SHADOW_COLOR = "rgba(0, 0, 0, 0.4)";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Fills a possibly-partial host `theme.colors` from {@link FALLBACK_COLORS}.
|
|
37
|
+
* This is the one place a missing token becomes a literal, so surfaces never
|
|
38
|
+
* need a per-property `|| "#hex"` guard.
|
|
39
|
+
*/
|
|
40
|
+
export function resolveHostColors(colors?: Partial<ThemeColors> | null): ThemeColors {
|
|
41
|
+
return { ...FALLBACK_COLORS, ...(colors ?? {}) };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Paseo Plugin Helper — UI color tokens (`paseo-plugin-helper/ui`).
|
|
46
|
+
*
|
|
47
|
+
* Pure color math for the ui/ adapter layer. These helpers are deliberately
|
|
48
|
+
* self-contained: they never read the DOM, never scrape CSS variables, and
|
|
49
|
+
* never import the frozen `client/` theme system. Colors arrive from the host
|
|
50
|
+
* `theme` prop via {@link HostThemeProvider} and are combined here.
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Converts a hex color and opacity (0.0 to 1.0) into an 8-character hex or
|
|
55
|
+
* rgba string.
|
|
56
|
+
*
|
|
57
|
+
* - `#rgb` / `#rrggbb` / `#rrggbbaa` → `#rrggbbaa` (alpha channel replaced)
|
|
58
|
+
* - `rgb()` / `rgba()` → `rgba(r, g, b, opacity)`
|
|
59
|
+
* - anything else is returned unchanged (named colors, `transparent`, …)
|
|
60
|
+
* - empty/invalid color degrades to `rgba(0, 0, 0, opacity)`
|
|
5
61
|
*/
|
|
6
62
|
export function alpha(color: string, opacity: number): string {
|
|
7
63
|
if (!color) return `rgba(0, 0, 0, ${opacity})`;
|
|
@@ -39,42 +95,6 @@ export function alpha(color: string, opacity: number): string {
|
|
|
39
95
|
return color;
|
|
40
96
|
}
|
|
41
97
|
|
|
42
|
-
/**
|
|
43
|
-
* Calculates relative luminance (WCAG 2.0 formula) from a hex color.
|
|
44
|
-
*/
|
|
45
|
-
export function getLuminance(hexColor: string): number {
|
|
46
|
-
let hex = hexColor.replace("#", "");
|
|
47
|
-
if (hex.length === 3) {
|
|
48
|
-
hex = hex
|
|
49
|
-
.split("")
|
|
50
|
-
.map((c) => c + c)
|
|
51
|
-
.join("");
|
|
52
|
-
}
|
|
53
|
-
const r = parseInt(hex.slice(0, 2), 16) / 255;
|
|
54
|
-
const g = parseInt(hex.slice(2, 4), 16) / 255;
|
|
55
|
-
const b = parseInt(hex.slice(4, 6), 16) / 255;
|
|
56
|
-
|
|
57
|
-
const toLinear = (c: number) => (c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));
|
|
58
|
-
|
|
59
|
-
return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Returns either lightText or darkText depending on which has highest contrast against bgHex.
|
|
64
|
-
*/
|
|
65
|
-
export function getContrastColor(
|
|
66
|
-
bgHex: string,
|
|
67
|
-
lightText = "#ffffff",
|
|
68
|
-
darkText = "#0f172a",
|
|
69
|
-
): string {
|
|
70
|
-
try {
|
|
71
|
-
const lum = getLuminance(bgHex);
|
|
72
|
-
return lum > 0.45 ? darkText : lightText;
|
|
73
|
-
} catch {
|
|
74
|
-
return lightText;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
98
|
/**
|
|
79
99
|
* Resolves a StatusVariant to a corresponding theme color hex string.
|
|
80
100
|
*/
|
|
@@ -102,7 +122,8 @@ export function getStatusColor(
|
|
|
102
122
|
}
|
|
103
123
|
|
|
104
124
|
/**
|
|
105
|
-
* Returns background, text, and border styling colors for a given status
|
|
125
|
+
* Returns background, text, and border styling colors for a given status
|
|
126
|
+
* variant, derived from the host theme colors via {@link alpha}.
|
|
106
127
|
*/
|
|
107
128
|
export function getVariantPalette(
|
|
108
129
|
variant: StatusVariant,
|
|
@@ -116,3 +137,39 @@ export function getVariantPalette(
|
|
|
116
137
|
border: alpha(base, 0.3),
|
|
117
138
|
};
|
|
118
139
|
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Calculates relative luminance (WCAG 2.0 formula) from a hex color.
|
|
143
|
+
*/
|
|
144
|
+
export function getLuminance(hexColor: string): number {
|
|
145
|
+
let hex = hexColor.replace("#", "");
|
|
146
|
+
if (hex.length === 3) {
|
|
147
|
+
hex = hex
|
|
148
|
+
.split("")
|
|
149
|
+
.map((c) => c + c)
|
|
150
|
+
.join("");
|
|
151
|
+
}
|
|
152
|
+
const r = parseInt(hex.slice(0, 2), 16) / 255;
|
|
153
|
+
const g = parseInt(hex.slice(2, 4), 16) / 255;
|
|
154
|
+
const b = parseInt(hex.slice(4, 6), 16) / 255;
|
|
155
|
+
|
|
156
|
+
const toLinear = (c: number) => (c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));
|
|
157
|
+
|
|
158
|
+
return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Returns either lightText or darkText depending on which has highest contrast against bgHex.
|
|
163
|
+
*/
|
|
164
|
+
export function getContrastColor(
|
|
165
|
+
bgHex: string,
|
|
166
|
+
lightText = "#ffffff",
|
|
167
|
+
darkText = "#0f172a",
|
|
168
|
+
): string {
|
|
169
|
+
try {
|
|
170
|
+
const lum = getLuminance(bgHex);
|
|
171
|
+
return lum > 0.45 ? darkText : lightText;
|
|
172
|
+
} catch {
|
|
173
|
+
return lightText;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import React, { createContext, useContext, type ReactNode } from "react";
|
|
2
|
+
import type { PluginTheme, ResponsiveLayout, StatusVariant, ThemeColors } from "../../../../shared/vendor/paseo-plugin-helper/types";
|
|
3
|
+
import { alpha, getStatusColor, getVariantPalette, FALLBACK_COLORS, resolveHostColors } from "./host-color";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Paseo Plugin Helper — Host theme context (`paseo-plugin-helper/ui`).
|
|
7
|
+
*
|
|
8
|
+
* The ui/ adapter layer's ONLY source of color tokens. The host hands every
|
|
9
|
+
* surface a `theme` prop (`PluginTheme`); `HostThemeProvider` carries those
|
|
10
|
+
* colors to every ui/ adapter below it.
|
|
11
|
+
*
|
|
12
|
+
* Contract — what this context deliberately does NOT do:
|
|
13
|
+
* - No DOM CSS variable scraping. Colors come from the host `theme` prop only;
|
|
14
|
+
* the removed legacy theme provider's `getComputedStyle` scraper is gone.
|
|
15
|
+
* - No flair, density, typography, or padding machinery. The host owns the
|
|
16
|
+
* design language; ui/ only consumes its color tokens.
|
|
17
|
+
* - No scroll-ownership state machine. See `ui/modal.tsx`.
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <HostThemeProvider theme={props.theme}>
|
|
22
|
+
* <HostCard>…</HostCard>
|
|
23
|
+
* </HostThemeProvider>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
export interface HostTheme {
|
|
28
|
+
/** Host theme colors, straight from the host `theme` prop. */
|
|
29
|
+
colors: ThemeColors;
|
|
30
|
+
/** Color-token opacity helper bound to nothing but its arguments. */
|
|
31
|
+
alpha: (color: string, opacity: number) => string;
|
|
32
|
+
/** Status variant → host theme color. */
|
|
33
|
+
getStatusColor: (variant: StatusVariant) => string;
|
|
34
|
+
/** Status variant → { bg, text, border } palette derived via `alpha`. */
|
|
35
|
+
getVariantPalette: (variant: StatusVariant) => { bg: string; text: string; border: string };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Neutral fallback palette so ui/ adapters still render outside a provider
|
|
40
|
+
* (tests, previews, host surfaces that have not migrated yet). It is the single
|
|
41
|
+
* helper-owned fallback; see {@link FALLBACK_COLORS}. A supplied `theme` is
|
|
42
|
+
* merged over it, so a partial host payload never paints a raw literal.
|
|
43
|
+
*/
|
|
44
|
+
function createHostTheme(colors: ThemeColors): HostTheme {
|
|
45
|
+
return {
|
|
46
|
+
colors,
|
|
47
|
+
alpha,
|
|
48
|
+
getStatusColor: (variant) => getStatusColor(variant, colors),
|
|
49
|
+
getVariantPalette: (variant) => getVariantPalette(variant, colors),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const FALLBACK_HOST_THEME: HostTheme = createHostTheme(FALLBACK_COLORS);
|
|
54
|
+
|
|
55
|
+
const HostThemeContext = createContext<HostTheme>(FALLBACK_HOST_THEME);
|
|
56
|
+
|
|
57
|
+
export interface HostThemeProviderProps {
|
|
58
|
+
/** The host `theme` prop for this surface — the single source of colors. */
|
|
59
|
+
theme: PluginTheme;
|
|
60
|
+
children: ReactNode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Provides host theme colors to every ui/ adapter in the subtree. Same `theme`
|
|
65
|
+
* prop shape the removed legacy `PluginThemeProvider` took, but no scraped
|
|
66
|
+
* variables and no flair.
|
|
67
|
+
*/
|
|
68
|
+
export function HostThemeProvider({ theme, children }: HostThemeProviderProps) {
|
|
69
|
+
const value = createHostTheme(resolveHostColors(theme.colors));
|
|
70
|
+
return <HostThemeContext.Provider value={value}>{children}</HostThemeContext.Provider>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Reads the host theme provided by {@link HostThemeProvider}. Falls back to a
|
|
75
|
+
* static neutral palette when no provider is above — adapters never throw and
|
|
76
|
+
* never scrape.
|
|
77
|
+
*/
|
|
78
|
+
export function useHostTheme(): HostTheme {
|
|
79
|
+
return useContext(HostThemeContext);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// --- Host layout -----------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
const DEFAULT_LAYOUT: ResponsiveLayout = {
|
|
85
|
+
compact: false,
|
|
86
|
+
platform: "web",
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const HostLayoutContext = createContext<ResponsiveLayout>(DEFAULT_LAYOUT);
|
|
90
|
+
|
|
91
|
+
export interface HostLayoutProviderProps {
|
|
92
|
+
/** The host `layout` prop for this surface. */
|
|
93
|
+
layout: ResponsiveLayout;
|
|
94
|
+
children: ReactNode;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Provides the host layout descriptor (compact / platform / width) to ui/
|
|
99
|
+
* adapters that branch on it (e.g. `HostResponsive`). Optional: adapters
|
|
100
|
+
* fall back to a wide-web default when no provider is above.
|
|
101
|
+
*/
|
|
102
|
+
export function HostLayoutProvider({ layout, children }: HostLayoutProviderProps) {
|
|
103
|
+
return <HostLayoutContext.Provider value={layout}>{children}</HostLayoutContext.Provider>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Reads the host layout descriptor. */
|
|
107
|
+
export function useHostLayout(): ResponsiveLayout {
|
|
108
|
+
return useContext(HostLayoutContext);
|
|
109
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paseo Plugin Helper — Lifecycle (headless, client-safe, UI-free).
|
|
3
|
+
*
|
|
4
|
+
* Import from `paseo-plugin-helper/lifecycle` for the host-registration
|
|
5
|
+
* engines — composer pills, sidebar surfaces, workspace/agent panels — plus
|
|
6
|
+
* clipboard and haptics helpers. These are client-bundle safe (React Native,
|
|
7
|
+
* no `node:*`) but intentionally separate from `paseo-plugin-helper/core`,
|
|
8
|
+
* whose purity contract forbids `react-native`.
|
|
9
|
+
*
|
|
10
|
+
* The bespoke `client/` design system was removed (#938); this entry mounts
|
|
11
|
+
* the host theme itself and imports only the headless host seam from `core`.
|
|
12
|
+
*/
|
|
13
|
+
export * from "./pill";
|
|
14
|
+
export * from "./surface";
|
|
15
|
+
export * from "./panel";
|
|
16
|
+
export * from "./clipboard";
|
|
17
|
+
export * from "./haptics";
|
|
18
|
+
export * from "./scroll-owner";
|
|
19
|
+
export * from "./host-theme";
|
|
20
|
+
export * from "./host-color";
|
|
21
|
+
export * from "./flair";
|
|
22
|
+
export * from "./providers";
|
|
23
|
+
export * from "./multi-host";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as pluginClient from "@getpaseo/plugin/client";
|
|
2
|
+
import type { PluginHostSummary } from "@getpaseo/plugin/client";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The desktop host bundle supplies `useHosts`/`getPaseoClient`; the mobile
|
|
6
|
+
* bundle omits them, so a direct named call throws `useHosts is not a
|
|
7
|
+
* function` and takes the whole surface with it (#1043, #1057-G). These seams
|
|
8
|
+
* reach the primitives through a feature-detected namespace so a surface
|
|
9
|
+
* degrades to "no hosts" instead of crashing the plugin.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** The host summary shape `useHosts()` returns (the SDK's `PluginHostSummary`). */
|
|
13
|
+
export type OptionalHostSummary = PluginHostSummary;
|
|
14
|
+
|
|
15
|
+
/** The borrowed per-host client `getPaseoClient(serverId)` returns. */
|
|
16
|
+
export type OptionalPaseoClient = ReturnType<typeof pluginClient.getPaseoClient>;
|
|
17
|
+
|
|
18
|
+
interface MultiHostPrimitives {
|
|
19
|
+
useHosts?: () => readonly PluginHostSummary[];
|
|
20
|
+
getPaseoClient?: (serverId: string) => OptionalPaseoClient;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Read a function export without tripping a test runner's module-mock `get`
|
|
25
|
+
* trap. A partial mock throws when an unlisted export is read; `Object.keys`
|
|
26
|
+
* only asks for the keys the module has, so an absent primitive reads as
|
|
27
|
+
* `undefined` on mock and real host alike.
|
|
28
|
+
*/
|
|
29
|
+
function readFunction<T>(source: unknown, key: string): T | undefined {
|
|
30
|
+
if (source === null || typeof source !== "object") return undefined;
|
|
31
|
+
if (!Object.keys(source).includes(key)) return undefined;
|
|
32
|
+
const value = (source as Record<string, unknown>)[key];
|
|
33
|
+
return typeof value === "function" ? (value as T) : undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const hostPrimitives: MultiHostPrimitives = {
|
|
37
|
+
useHosts: readFunction(pluginClient, "useHosts"),
|
|
38
|
+
getPaseoClient: readFunction(pluginClient, "getPaseoClient"),
|
|
39
|
+
};
|
|
40
|
+
const EMPTY_HOSTS: readonly PluginHostSummary[] = [];
|
|
41
|
+
const noHosts = () => EMPTY_HOSTS;
|
|
42
|
+
|
|
43
|
+
// Hook identity is module-constant, so a given host calls the same function on
|
|
44
|
+
// every render and the hook order never changes.
|
|
45
|
+
const useHosts = hostPrimitives.useHosts ?? noHosts;
|
|
46
|
+
|
|
47
|
+
/** True when the running host supplies the multi-host primitives. */
|
|
48
|
+
export function isMultiHostSupported(): boolean {
|
|
49
|
+
return (
|
|
50
|
+
typeof hostPrimitives.useHosts === "function" &&
|
|
51
|
+
typeof hostPrimitives.getPaseoClient === "function"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* `useHosts()` when the host supplies it, otherwise an empty host list, so a
|
|
57
|
+
* surface that enumerates hosts degrades instead of crashing the bundle.
|
|
58
|
+
*/
|
|
59
|
+
export function useOptionalHosts(): readonly PluginHostSummary[] {
|
|
60
|
+
return useHosts();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Borrow an online host's API, or `undefined` when the host omits the seam. */
|
|
64
|
+
export function getOptionalPaseoClient(serverId: string): OptionalPaseoClient | undefined {
|
|
65
|
+
return hostPrimitives.getPaseoClient?.(serverId);
|
|
66
|
+
}
|
|
@@ -2,9 +2,9 @@ import React, { type ComponentType } from "react";
|
|
|
2
2
|
import type {
|
|
3
3
|
HostWorkspacePanelProps as PluginWorkspacePanelProps,
|
|
4
4
|
HostAgentPanelProps as PluginAgentPanelProps,
|
|
5
|
-
} from "
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
5
|
+
} from "../core/host";
|
|
6
|
+
import type { VisualFlair } from "./flair";
|
|
7
|
+
import { RegistrarThemeScope } from "./providers";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Structural registrar interface satisfied by both Paseo v0.7 PluginContext
|
|
@@ -43,9 +43,9 @@ export function registerWorkspacePanel(
|
|
|
43
43
|
const { id, title, icon, Component, flair, locations } = options;
|
|
44
44
|
|
|
45
45
|
const WrappedComponent: ComponentType<PluginWorkspacePanelProps> = (props) => (
|
|
46
|
-
<
|
|
46
|
+
<RegistrarThemeScope theme={props.theme} layout={props.layout} flair={flair}>
|
|
47
47
|
<Component {...props} />
|
|
48
|
-
</
|
|
48
|
+
</RegistrarThemeScope>
|
|
49
49
|
);
|
|
50
50
|
|
|
51
51
|
const registration = plugin.addWorkspacePanel({
|
|
@@ -74,9 +74,9 @@ export function registerAgentPanel(
|
|
|
74
74
|
const { id, title, icon, Component, flair } = options;
|
|
75
75
|
|
|
76
76
|
const WrappedComponent: ComponentType<PluginAgentPanelProps> = (props) => (
|
|
77
|
-
<
|
|
77
|
+
<RegistrarThemeScope theme={props.theme} layout={props.layout} flair={flair}>
|
|
78
78
|
<Component {...props} />
|
|
79
|
-
</
|
|
79
|
+
</RegistrarThemeScope>
|
|
80
80
|
);
|
|
81
81
|
|
|
82
82
|
plugin.addWorkspacePanel({
|