@bitovi/vybit 0.8.2 → 0.9.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/overlay/dist/overlay.js +540 -211
- package/package.json +9 -2
- package/panel/dist/assets/DesignMode-D6tjMRjM.js +511 -0
- package/panel/dist/assets/index-BdUOBofL.css +1 -0
- package/panel/dist/assets/index-D5VCKvC6.js +62 -0
- package/panel/dist/index.html +2 -2
- package/server/app.ts +88 -1
- package/server/ghost-cache.ts +154 -0
- package/server/index.ts +5 -1
- package/server/mcp-tools.ts +120 -14
- package/server/queue.ts +4 -0
- package/server/storybook.ts +110 -0
- package/server/websocket.ts +12 -0
- package/shared/types.ts +92 -3
- package/storybook-addon/index.js +1 -0
- package/storybook-addon/manager.tsx +33 -0
- package/storybook-addon/package.json +10 -0
- package/storybook-addon/preset.js +10 -0
- package/storybook-addon/preview.ts +29 -0
- package/panel/dist/assets/DesignMode-DHfdZ_OH.js +0 -510
- package/panel/dist/assets/index-Bk7q5Yfb.css +0 -1
- package/panel/dist/assets/index-DwDMVGkn.js +0 -49
package/shared/types.ts
CHANGED
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
// Shared types for the PATCH protocol.
|
|
2
2
|
// Imported by overlay (esbuild), panel (Vite), and server (tsx).
|
|
3
3
|
|
|
4
|
+
/** Cached ghost HTML + host styles for instant component preview placeholders. */
|
|
5
|
+
export interface GhostCacheEntry {
|
|
6
|
+
storyId: string;
|
|
7
|
+
argsHash: string;
|
|
8
|
+
ghostHtml: string;
|
|
9
|
+
hostStyles: Record<string, string>;
|
|
10
|
+
storyBackground?: string;
|
|
11
|
+
componentName: string;
|
|
12
|
+
componentPath?: string;
|
|
13
|
+
extractedAt: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
4
16
|
export type ContainerName = 'modal' | 'popover' | 'sidebar' | 'popup';
|
|
5
17
|
|
|
6
|
-
|
|
18
|
+
/** A component placed on the Fabric.js design canvas */
|
|
19
|
+
export interface CanvasComponent {
|
|
20
|
+
componentName: string;
|
|
21
|
+
componentPath?: string; // e.g. './src/components/Button.tsx'
|
|
22
|
+
storyId?: string;
|
|
23
|
+
args?: Record<string, unknown>;
|
|
24
|
+
// Position/size on the canvas (px, relative to canvas top-left)
|
|
25
|
+
x: number;
|
|
26
|
+
y: number;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type PatchKind = 'class-change' | 'message' | 'design' | 'component-drop';
|
|
7
32
|
|
|
8
33
|
export type PatchStatus = 'staged' | 'committed' | 'implementing' | 'implemented' | 'error';
|
|
9
34
|
|
|
@@ -30,6 +55,15 @@ export interface Patch {
|
|
|
30
55
|
insertMode?: string; // before | after | first-child | last-child
|
|
31
56
|
canvasWidth?: number;
|
|
32
57
|
canvasHeight?: number;
|
|
58
|
+
canvasComponents?: CanvasComponent[]; // Components placed on the design canvas
|
|
59
|
+
// Component-drop fields (used when kind === 'component-drop'):
|
|
60
|
+
ghostHtml?: string; // HTML of the dropped component (overlay preview only — stripped from MCP response)
|
|
61
|
+
componentStoryId?: string; // Storybook story ID
|
|
62
|
+
componentPath?: string; // Source file of the component, e.g. './src/components/Button.tsx'
|
|
63
|
+
componentArgs?: Record<string, unknown>; // Props the user configured before dropping
|
|
64
|
+
parentComponent?: { name: string }; // React component that contains the drop target
|
|
65
|
+
targetPatchId?: string; // If target is a ghost from an earlier drop, references that patch
|
|
66
|
+
targetComponentName?: string; // Name of the ghost component being referenced
|
|
33
67
|
// Commit reference:
|
|
34
68
|
commitId?: string; // Set when committed into a Commit
|
|
35
69
|
}
|
|
@@ -57,6 +91,12 @@ export interface PatchSummary {
|
|
|
57
91
|
errorMessage?: string;
|
|
58
92
|
message?: string;
|
|
59
93
|
image?: string;
|
|
94
|
+
canvasComponents?: CanvasComponent[];
|
|
95
|
+
// Component-drop display fields:
|
|
96
|
+
insertMode?: string;
|
|
97
|
+
parentComponent?: { name: string };
|
|
98
|
+
targetComponentName?: string;
|
|
99
|
+
targetPatchId?: string;
|
|
60
100
|
}
|
|
61
101
|
|
|
62
102
|
export interface CommitSummary {
|
|
@@ -270,6 +310,7 @@ export interface DesignSubmitMessage {
|
|
|
270
310
|
insertMode: InsertMode;
|
|
271
311
|
canvasWidth: number;
|
|
272
312
|
canvasHeight: number;
|
|
313
|
+
canvasComponents?: CanvasComponent[];
|
|
273
314
|
}
|
|
274
315
|
|
|
275
316
|
/** Design iframe → Overlay: close the canvas wrapper */
|
|
@@ -282,6 +323,44 @@ export interface ClosePanelMessage {
|
|
|
282
323
|
type: 'CLOSE_PANEL';
|
|
283
324
|
}
|
|
284
325
|
|
|
326
|
+
/** Overlay → Server: story changed in Storybook, clear panel selection */
|
|
327
|
+
export interface ResetSelectionMessage {
|
|
328
|
+
type: 'RESET_SELECTION';
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
// Component arm-and-place messages
|
|
333
|
+
// ---------------------------------------------------------------------------
|
|
334
|
+
|
|
335
|
+
/** Panel → Overlay: user armed a component for placement from the Draw tab */
|
|
336
|
+
export interface ComponentArmMessage {
|
|
337
|
+
type: 'COMPONENT_ARM';
|
|
338
|
+
to: 'overlay';
|
|
339
|
+
componentName: string;
|
|
340
|
+
storyId: string;
|
|
341
|
+
ghostHtml: string;
|
|
342
|
+
componentPath?: string; // Source file path from Storybook index, e.g. './src/components/Button.tsx'
|
|
343
|
+
args?: Record<string, unknown>; // Current prop values from ArgsForm
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** Panel → Overlay: user cancelled the armed state (panel click or escape) */
|
|
347
|
+
export interface ComponentDisarmMessage {
|
|
348
|
+
type: 'COMPONENT_DISARM';
|
|
349
|
+
to: 'overlay';
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Overlay → Panel: overlay has disarmed (user placed or pressed Escape in app) */
|
|
353
|
+
export interface ComponentDisarmedMessage {
|
|
354
|
+
type: 'COMPONENT_DISARMED';
|
|
355
|
+
to: 'panel';
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Overlay → Server: component was placed, stage a patch */
|
|
359
|
+
export interface ComponentDroppedMessage {
|
|
360
|
+
type: 'COMPONENT_DROPPED';
|
|
361
|
+
patch: Patch;
|
|
362
|
+
}
|
|
363
|
+
|
|
285
364
|
// ---------------------------------------------------------------------------
|
|
286
365
|
// Union types
|
|
287
366
|
// ---------------------------------------------------------------------------
|
|
@@ -296,8 +375,10 @@ export type PanelToOverlay =
|
|
|
296
375
|
| SwitchContainerMessage
|
|
297
376
|
| InsertDesignCanvasMessage
|
|
298
377
|
| CaptureScreenshotMessage
|
|
299
|
-
| ClosePanelMessage
|
|
300
|
-
|
|
378
|
+
| ClosePanelMessage
|
|
379
|
+
| ComponentArmMessage
|
|
380
|
+
| ComponentDisarmMessage;
|
|
381
|
+
export type OverlayToServer = PatchStagedMessage | ComponentDroppedMessage | ResetSelectionMessage;
|
|
301
382
|
export type PanelToServer = PatchCommitMessage | MessageStageMessage;
|
|
302
383
|
export type ClientToServer =
|
|
303
384
|
| RegisterMessage
|
|
@@ -306,10 +387,13 @@ export type ClientToServer =
|
|
|
306
387
|
| MessageStageMessage
|
|
307
388
|
| DesignSubmitMessage
|
|
308
389
|
| DesignCloseMessage
|
|
390
|
+
| ComponentDroppedMessage
|
|
391
|
+
| ResetSelectionMessage
|
|
309
392
|
| PingMessage;
|
|
310
393
|
export type ServerToClient =
|
|
311
394
|
| PongMessage
|
|
312
395
|
| QueueUpdateMessage
|
|
396
|
+
| ResetSelectionMessage
|
|
313
397
|
| PatchUpdateMessage
|
|
314
398
|
| PatchImplementingMessage
|
|
315
399
|
| PatchImplementedMessage
|
|
@@ -336,5 +420,10 @@ export type AnyMessage =
|
|
|
336
420
|
| DesignSubmitMessage
|
|
337
421
|
| DesignCloseMessage
|
|
338
422
|
| ClosePanelMessage
|
|
423
|
+
| ComponentArmMessage
|
|
424
|
+
| ComponentDisarmMessage
|
|
425
|
+
| ComponentDisarmedMessage
|
|
426
|
+
| ComponentDroppedMessage
|
|
427
|
+
| ResetSelectionMessage
|
|
339
428
|
| PingMessage
|
|
340
429
|
| PongMessage;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require('./preset');
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { addons, types } from '@storybook/manager-api';
|
|
3
|
+
import { AddonPanel } from '@storybook/components';
|
|
4
|
+
|
|
5
|
+
const ADDON_ID = 'vybit';
|
|
6
|
+
const PANEL_ID = `${ADDON_ID}/panel`;
|
|
7
|
+
|
|
8
|
+
addons.register(ADDON_ID, (api) => {
|
|
9
|
+
addons.add(PANEL_ID, {
|
|
10
|
+
type: types.PANEL,
|
|
11
|
+
title: 'Vybit',
|
|
12
|
+
paramKey: 'vybit',
|
|
13
|
+
render: ({ active }) => {
|
|
14
|
+
const serverUrl =
|
|
15
|
+
api.getCurrentParameter<{ serverUrl?: string }>('vybit')?.serverUrl
|
|
16
|
+
?? 'http://localhost:3333';
|
|
17
|
+
|
|
18
|
+
if (active) {
|
|
19
|
+
api.togglePanelPosition('right');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<AddonPanel active={active ?? false}>
|
|
24
|
+
<iframe
|
|
25
|
+
src={`${serverUrl}/panel/`}
|
|
26
|
+
style={{ width: '100%', height: '100%', border: 'none' }}
|
|
27
|
+
title="Vybit Panel"
|
|
28
|
+
/>
|
|
29
|
+
</AddonPanel>
|
|
30
|
+
);
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { addons } from '@storybook/preview-api';
|
|
2
|
+
|
|
3
|
+
let injected = false;
|
|
4
|
+
|
|
5
|
+
export const decorators = [
|
|
6
|
+
(StoryFn: any, context: any) => {
|
|
7
|
+
const serverUrl =
|
|
8
|
+
context.parameters?.vybit?.serverUrl ?? 'http://localhost:3333';
|
|
9
|
+
|
|
10
|
+
if (!injected) {
|
|
11
|
+
const script = document.createElement('script');
|
|
12
|
+
script.src = `${serverUrl}/overlay.js`;
|
|
13
|
+
document.head.appendChild(script);
|
|
14
|
+
injected = true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return StoryFn();
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const channel = addons.getChannel();
|
|
22
|
+
let lastStoryId: string | undefined;
|
|
23
|
+
|
|
24
|
+
channel.on('storyRendered', (storyId?: string) => {
|
|
25
|
+
// Only reset selection on actual story navigation, not HMR updates
|
|
26
|
+
if (storyId && storyId === lastStoryId) return;
|
|
27
|
+
lastStoryId = storyId;
|
|
28
|
+
window.postMessage({ type: 'STORYBOOK_STORY_RENDERED' }, '*');
|
|
29
|
+
});
|