gosling-designer-vec
v0.0.66
Published
[](https://www.npmjs.com/package/gosling-designer-vec)
Readme
Gosling Designer VEC
Gosling is equipped with visualization authoring interfaces, such as graphical template-base, shelf configuration, and natural language interfaces.
VEC (Visualization Editor Component) supports creating and customizing interactive genomics data visualization.
The repo is based on gosling-lang/blace.
Peer Dependencies
gosling-designer-vec externalizes @dnd-kit/core, react, and react-dom so that your application and VEC share the same module instances. Install them alongside VEC:
pnpm add gosling-designer-vec @dnd-kit/core react react-domIf you don't use @dnd-kit/core yourself, you still need it installed — VEC uses it internally for its drag-and-drop UI. No extra setup is required; VEC wraps itself in its own DndContext by default.
If you do use @dnd-kit/core and need VEC's droppables to participate in your DndContext, see External DnD Context below.
How to Use
Basic Usage
<GoslingDesignerVEC
visualization={Examples.visualizations[exIndex]} // `GDVis` or `undefined`
data={Examples.data} // `GDData[]` or `undefined`
isPublished={false} // Is this visualization published by a user?
isChatMode={true} // This will hide several panels on the right and show the chatbot interface
userMode="guest" // 'viewer' | 'editor' | 'admin' | 'guest'
onPublish={published => {
console.warn(`The current visualization has been ${published ? 'published' : 'unpublished'}`);
}}
onChange={vis => console.warn('The visualization spec has been changed', vis)}
hideDataPanel={false} // Should the VEC's data panel be hidden?
>
<div> ... </div> // a child element that will be shown right above the VEC's data panel
</GoslingDesignerVEC>External DnD Context
If you need to wrap GoslingDesignerVEC alongside your own draggable content in a shared DndContext (from @dnd-kit/core), use the externalDndContext prop together with the exported useGoslingDndHandlers hook and AppStateProvider.
When externalDndContext is set, VEC skips rendering its own DndContext and AppStateProvider, so you must provide both externally.
import {
GoslingDesignerVEC,
AppStateProvider,
useGoslingDndHandlers,
} from 'gosling-designer-vec';
import { DndContext } from '@dnd-kit/core';
function MyDndWrapper({ children, ...vecProps }) {
const { collisionDetection, onDragStart, onDragEnd, dragOverlay } =
useGoslingDndHandlers();
// Optionally customize the drop animation:
// useGoslingDndHandlers({ dropAnimation: null }) — disable animation
// useGoslingDndHandlers({ dropAnimation: { duration: 200, easing: 'ease' } }) — custom
return (
<DndContext
collisionDetection={collisionDetection}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
>
<GoslingDesignerVEC {...vecProps} externalDndContext />
{children}
{dragOverlay}
</DndContext>
);
}
// Wrap everything in AppStateProvider so VEC and your components share state
function App() {
return (
<AppStateProvider data={data} visualization={visualization} {...otherProps}>
<MyDndWrapper visualization={visualization} data={data}>
{/* your own draggable content */}
</MyDndWrapper>
</AppStateProvider>
);
}Custom Mode Widget
The bottom-center mode widget (undo/redo, export, publish, etc.) can be replaced or hidden via the ModeWidget prop. Pass a component to fully replace it, null to hide it entirely, or leave it undefined for the default.
A custom widget receives ModeWidgetProps (onJsonImport, onJsonExport, onPngExport, PublishMenu, className) and can read/write the same state as the default via the exported hooks:
import {
GoslingDesignerVEC,
ModeWidgetProps,
useVisualizationValue,
useUndo,
useRedo,
useCanUndo,
useCanRedo,
useModeStatus,
useToggleSetting,
} from 'gosling-designer-vec';
function MyModeWidget({ onJsonExport, onPngExport }: ModeWidgetProps) {
const vis = useVisualizationValue();
const undo = useUndo();
const redo = useRedo();
const canUndo = useCanUndo();
const canRedo = useCanRedo();
const isPresentMode = useModeStatus('isPresentMode');
const toggle = useToggleSetting();
return (
<div className="absolute bottom-4 right-4 flex gap-2 rounded-xl bg-white p-3 shadow-lg">
<button disabled={!canUndo} onClick={undo}>Undo</button>
<button disabled={!canRedo} onClick={redo}>Redo</button>
<button onClick={onJsonExport}>Export JSON</button>
<button onClick={onPngExport}>Export PNG</button>
<button onClick={() => toggle('isPresentMode')}>
{isPresentMode ? 'Edit' : 'Present'}
</button>
</div>
);
}
<GoslingDesignerVEC ModeWidget={MyModeWidget} />
// Or hide it entirely and render your own elsewhere:
<GoslingDesignerVEC ModeWidget={null} />The default ModeWidget is also exported, so you can wrap or extend it instead of rewriting.
Styling & Layout
Every slot in the layout accepts a Tailwind class override via classNames. Conflicting utilities (widths, backgrounds, etc.) cleanly replace the defaults. The root frame also accepts className and style directly; style is merged onto the root and overrides the default height: calc(100vh - 44px).
<GoslingDesignerVEC
style={{ height: '100%' }}
classNames={{
root: 'rounded-xl shadow-xl bg-white',
leftPanel: 'w-[320px] bg-slate-50',
rightPanel: 'w-[360px]',
bottomPanel: 'h-[320px]',
canvas: 'bg-white',
modeWidget: 'top-[16px] bottom-auto', // move the ModeWidget to the top
}}
/>Slots: root, leftPanel, rightPanel, bottomPanel, canvas, modeWidget. See FrameClassNames.
Exports
| Export | Type | Description |
|---|---|---|
| GoslingDesignerVEC | Component | Main editor component |
| Examples | Object | Example visualizations and data |
| ModeWidget | Component | Default mode widget — exported so you can wrap or extend it |
| useGoslingDndHandlers | Hook | DnD handlers for external DndContext integration. Accepts an optional { dropAnimation } to customize or disable (null) the drag overlay animation. |
| useVisualizationValue | Hook | Read the current visualization (same atom the default ModeWidget uses) |
| useUndo / useRedo | Hook | Trigger undo / redo |
| useCanUndo / useCanRedo | Hook | Boolean: whether undo / redo is available |
| useActiveStatusOfPanelsAndModesValue | Hook | Read the full mode status object |
| useModeStatus | Hook | Read a single field from the mode status (e.g. useModeStatus('isPresentMode')) |
| useToggleSetting | Hook | Toggle any field on the mode status (e.g. toggle('isPresentMode')) |
| useOnPublishValue | Hook | Read the onPublish callback supplied via props |
| useOnAddToWorkspaceValue | Hook | Read the onAddToWorkspace callback supplied via props |
| AppStateProvider | Component | Jotai/Bunshi state provider (needed with externalDndContext) |
| AppStateProviderProps | Type | Props for AppStateProvider |
| FrameProps | Type | Props for GoslingDesignerVEC |
| FrameClassNames | Type | Per-slot className overrides (root, leftPanel, rightPanel, bottomPanel, canvas, modeWidget) |
| ModeWidgetProps | Type | Props passed to a custom ModeWidget |
| ModeStatus | Type | Shape returned by useActiveStatusOfPanelsAndModesValue |
| GDData | Type | Data schema type |
| DataSchema | Namespace | Data schema definitions |
| VisSchema | Namespace | Visualization schema definitions |
Development
Prerequisite
Installing pnpm v10.
Run Demo
pnpm install
pnpm startThis will open the demo website (\demo). Any edits to packages will be updated to the demo page in your browser.
For other commands, refer to the scripts defined in package.json.
Initial Dataset
The initial list of data that needs to be loaded on the Goslign Designer interface can be changed below:
https://github.com/gosling-lang/gosling-designer/blob/fca3de067308e3d5dcaec1c679d1c71283bb5c66/src/views-data-explorer/DataExplorer.tsx#L9
Styling
For styling UI components, we use tailwindcss. This way, we do not create separate CSS files but, instead, add styles directly to className. Refer to its documentation.
