@gamesberry/karmyc-core
v1.0.0-beta22
Published
A flexible and powerful layout management system for React applications
Maintainers
Readme
Karmyc Core
Table of Contents
Overview
Karmyc Core is a React library that provides a flexible layout management system using Zustand for state management. It allows you to create dynamic, resizable workspace areas that can be arranged in rows and columns, with support for multiple screens, undo/redo functionality, and a plugin system.
Demo
A comprehensive demo is available here showcasing Karmyc Core's key features.
Quick Start
1. Installation
# Using yarn (recommended)
yarn add @gamesberry/karmyc-core
# Using npm
npm install @gamesberry/karmyc-coreDependencies
Karmyc Core requires the following peer dependencies:
react >= 19.0react-dom >= 19.0
2. Basic Setup
// App.tsx
import { KarmycCoreProvider, useKarmyc, Karmyc, Tools } from '@gamesberry/karmyc-core';
import { AreaInitializer } from './AreaInitializer';
const App = () => {
const karmycConfig = {
plugins: [],
validators: [],
initialAreas: [
{ id: 'area-1', type: 'my-area', state: { initialData: 'default value' }, role: 'SELF' },
],
keyboardShortcutsEnabled: true,
resizableAreas: true,
manageableAreas: true,
multiScreen: true,
allowStackMixedRoles: false,
previewDuringDrag: false,
builtInLayouts: [],
initialLayout: 'default',
};
const config = useKarmyc(karmycConfig);
return (
<KarmycCoreProvider options={config}>
<AreaInitializer />
<Tools areaType="apptitle">
<Tools areaType="app">
<Karmyc />
</Tools>
</Tools>
</KarmycCoreProvider>
);
};2b. Next.js / SSR usage
When using Next.js, wrap your app with KarmycNextWrapper to ensure safe client-side hydration:
// app/providers.tsx or pages/_app.tsx
import { KarmycNextWrapper, useKarmyc } from '@gamesberry/karmyc-core';
export default function Providers({ children }: { children: React.ReactNode }) {
const config = useKarmyc({ initialAreas: [] });
const isClient = typeof window !== 'undefined';
return (
<KarmycNextWrapper isClient={isClient} config={config}>
{children}
</KarmycNextWrapper>
);
}3. Area Initialization
// AreaInitializer.tsx
import { MyArea } from './areas/MyArea';
export const AreaInitializer = () => {
return (
<>
<MyArea />
</>
);
};4. Defining an Area Type
// areas/MyArea.tsx
import { useRegisterAreaType, AREA_ROLE } from '@gamesberry/karmyc-core';
import { MyAreaComponent } from './MyAreaComponent';
import { Icon } from 'lucide-react';
export const MyArea = () => {
useRegisterAreaType(
'my-area',
MyAreaComponent,
{ initialData: 'default value' },
{
displayName: 'My Area',
role: AREA_ROLE.LEAD,
icon: Icon
}
);
return null;
};5. Area Component
// MyAreaComponent.tsx
import { AreaComponentProps } from '@gamesberry/karmyc-core';
interface MyAreaState {
initialData: string;
}
export const MyAreaComponent: React.FC<AreaComponentProps<MyAreaState>> = ({
id,
state,
type,
viewport,
raised
}) => {
return (
<div style={{
width: viewport.width,
height: viewport.height,
left: viewport.left,
top: viewport.top
}}>
<h2>My Area: {state.initialData}</h2>
</div>
);
};Core Concepts
Screens, Spaces, Areas, and Layouts
- Screen: A top-level container (main window or detached window) that contains areas and layout
- Area: A rectangular region that renders a specific React component, organized within a screen
- Layout: Tree structure of nested rows and columns defining area arrangement within a screen
- Space: A logical workspace concept that can be associated with areas (especially LEAD areas) for shared state and history
Area Roles
const AREA_ROLE = {
LEAD: 'LEAD', // Primary workspace areas with shared state
FOLLOW: 'FOLLOW', // Secondary areas that follow LEAD areas
SELF: 'SELF' // Independent areas with local state only
} as const;Tools Slot System
The tools slot system allows injecting components into predefined UI positions. The Tools component (alias for ToolsSlot) can be configured with different props:
<Tools areaType="apptitle">
<Tools areaType="app">
<Karmyc />
</Tools>
</Tools>Tools Component Props
interface ToolsProps {
areaId?: string; // Specific area ID for targeted tools
areaType?: string; // Area type for type-specific tools (default: 'app')
areaState?: any; // Current area state
children: React.ReactNode; // Content to render
style?: React.CSSProperties; // Inline style for container
viewport?: Rect; // Viewport dimensions
nbOfLines?: number; // Number of toolbar lines (default: 1)
}API Reference
Core Hooks
useKarmyc(options, onError?)
Initializes the Karmyc system with configuration options.
interface IKarmycOptions {
plugins?: IActionPlugin[];
validators?: Array<{
actionType: string;
validator: (action: any) => { valid: boolean; message?: string };
}>;
initialAreas?: IArea[];
keyboardShortcutsEnabled?: boolean;
resizableAreas?: boolean;
manageableAreas?: boolean;
multiScreen?: boolean;
allowStackMixedRoles?: boolean;
previewDuringDrag?: boolean;
builtInLayouts?: LayoutPreset[];
initialLayout?: string;
t?: (key: string, fallback: string) => string;
spaces?: Record<string, ISpace>;
}useArea()
Provides functions to manipulate areas and access their state.
const {
createArea,
removeArea,
setActive,
update,
getActive,
getById,
getAll,
getErrors
} = useArea();useSpace()
Access state for spaces.
const { spaces, activeSpaceId, getSpaceById } = useSpace();useRegisterAreaType(type, component, initialState, options)
Register a new area type.
useRegisterAreaType(
'my-area',
MyComponent,
{ data: 'default' },
{ displayName: 'My Area', role: AREA_ROLE.LEAD }
);Additional Hooks
useAreaOptimized()
Optimized hook for area management with enhanced performance and extended functionality.
const { createArea, removeArea, splitArea, setRowSizes } = useAreaOptimized();Specialized Area Hooks
Granular hooks for optimal performance:
const area = useAreaById(areaId); // Get specific area
const activeArea = useActiveArea(); // Get active area
const allAreas = useAllAreas(); // Get all areas
const layout = useAreaLayoutById(areaId); // Get area layout
const actions = useAreaActions(); // Get area actionsuseAreaDragAndDrop(params?)
Provides drag and drop functionality for areas and placement overlay.
const { isDragging, handleDragStart, handleDragOver, handleDragEnd, handleDrop } =
useAreaDragAndDrop({ id: 'area-1', type: 'my-area', state: {} });useAreaKeyboardShortcuts(areaId)
Provides keyboard shortcuts for areas.
useAreaKeyboardShortcuts(areaId);useContextMenu()
Provides context menu functionality.
const { openContextMenu, closeContextMenu } = useContextMenu();useResizePreview()
Provides resize preview functionality.
const { showPreview, hidePreview, previewState } = useResizePreview();useScreenManagement()
Provides screen management functionality.
const { createScreen, removeScreen, switchScreen } = useScreenManagement();useAreaStack(areaId)
Provides area stacking functionality.
const { isChildOfStack, stackArea, unstackArea } = useAreaStack(areaId);useActiveSpaceHistory()
Enhanced history bound to the active space.
const history = useActiveSpaceHistory();useHistory(spaceId)
Provides enhanced history functionality with advanced features like action batching, diff tracking, and typed actions.
const {
// State
isActionInProgress,
currentActionId,
lastAction,
stats,
// Actions
startAction,
submitAction,
cancelAction,
undo,
redo,
// Utilities
createSimpleAction,
createSelectionAction,
createTransformAction,
// Checks
canUndo,
canRedo,
// Getters
getCurrentAction,
getHistoryLength,
getHistoryStats,
// Management
clearHistory,
updateSelectionState
} = useHistory(spaceId);useActiveSpaceHistory()
Provides enhanced history functionality for the currently active space.
const historyActions = useActiveSpaceHistory();useTypedHistoryActions(spaceId)
Provides typed history actions for common operations.
const {
create, update, delete, move, copy, paste,
select, deselect, selectAll, deselectAll,
group, ungroup, transform, rotate, scale, translate,
timelineUpdate, keyframeAdd, keyframeRemove, keyframeUpdate,
custom
} = useTypedHistoryActions(spaceId);usePluginSystem()
Provides plugin system functionality.
const { registerPlugin, unregisterPlugin, getPlugins } = usePluginSystem();Core Components
KarmycCoreProvider
Main provider that sets up the Karmyc environment.
<KarmycCoreProvider options={config}>
{children}
</KarmycCoreProvider>Karmyc
Primary component that renders layouts and areas.
<Karmyc />Tools
System for injecting components into predefined UI slots.
<Tools areaType="app">
<Karmyc />
</Tools>Additional Components
AreaErrorBoundary
Error boundary component for areas.
<AreaErrorBoundary
component={MyAreaComponent}
areaId="area-1"
areaState={{}}
type="my-area"
viewport={{ left: 0, top: 0, width: 300, height: 200 }}
/>AreaPreview
Preview component used during drag operations.
<AreaPreview areaToOpen={{ position: { x: 100, y: 50 }, area: { type: 'my-area', state: {} } }} dimensions={{ x: 320, y: 200 }} />AreaTabs
Tab component for stacked areas (internal usage via AreaStack).
ScreenSwitcher
Component for switching between screens.
<ScreenSwitcher />KeyboardShortcutsViewer
Component for displaying keyboard shortcuts.
<KeyboardShortcutsViewer />ContextMenu
Context menu component.
<ContextMenu />Configuration
Built-in Layouts
You can define built-in layouts that users can switch between:
const builtInLayouts = [
{
id: 'default',
name: 'Default Layout',
config: { /* layout configuration */ },
isBuiltIn: true
}
];Types and Interfaces
Core Types
// Area types
interface IArea<T = any> {
id: string;
type: AreaTypeValue;
state?: Record<string, any>;
spaceId?: string | null;
viewport?: Rect;
position?: Point;
size?: { width: number; height: number };
raised?: boolean;
role?: AreaRole;
isLocked?: boolean;
enableFullscreen?: boolean;
previousLayout?: { [key: string]: AreaLayout | AreaRowLayout };
previousRootId?: string | null;
}
// Layout types
interface LayoutNode {
id: string;
type: 'area' | 'area_row';
orientation?: 'horizontal' | 'vertical' | 'stack';
areas?: Array<{ id: string; size: number }>;
}
// Additional types
interface Rect {
top: number;
left: number;
width: number;
height: number;
}
interface Point {
x: number;
y: number;
}
interface AreaLayout {
// Layout configuration for areas
}
interface AreaRowLayout {
// Layout configuration for area rows
}
// Space types
interface ISpace {
id: string;
name: string;
sharedState: any;
history: EnhancedHistoryAction[];
}
// Plugin types
interface IActionPlugin {
id: string;
name: string;
onStoreChange?: (state: any, prevState: any) => void;
onStoreInit?: (store: StoreApi<any>) => void;
transformState?: (state: any) => Partial<any>;
actions?: Record<string, (...args: any[]) => void>;
}Enums and Constants
const AREA_ROLE = {
LEAD: 'LEAD',
FOLLOW: 'FOLLOW',
SELF: 'SELF'
} as const;
const TOOLBAR_HEIGHT = 30;Development
Available Scripts
yarn dev: Start development mode with watchyarn build: Build the libraryyarn bundle: Build the library (alias for build)yarn test: Run testsyarn test:watch: Run tests in watch modeyarn test:coverage: Run tests with coverageyarn demo:dev: Start the demo application in development modeyarn demo:build: Build the demo applicationyarn demo:ssr:dev: Start the SSR demo application in development modeyarn demo:ssr:build: Build the SSR demo applicationyarn demo:ssr:start: Start the SSR demo application
Project Structure
karmyc-core/
├── src/ # Source code
│ ├── components/ # React components
│ │ ├── menus/ # Context menus
│ │ └── handlers/ # Event handlers
│ ├── core/ # Core logic and state management
│ │ ├── plugins/ # Plugin system
│ │ ├── registries/ # Component registries
│ │ ├── slices/ # Zustand store slices
│ │ └── types/ # Core type definitions
│ ├── hooks/ # Custom React hooks
│ ├── types/ # TypeScript type definitions
│ ├── utils/ # Utility functions
│ └── index.ts # Main entry point
├── demo/ # Demo application
│ ├── config/ # Demo configuration
│ └── shared/ # Shared demo components
└── docs/ # DocumentationAcknowledgements
Karmyc core was extracted and derived from animation-editor by @alexharri - a web-based animation editor built with React, Redux, PIXI.js and HTML Canvas.
Karmyc Core is built upon several key libraries:
- Zustand & Immer for state management
- React DnD for drag-and-drop functionality
- Lucide React for icons
- @szhsin/react-menu for context menus
License
- MIT © Yann Loosli
- KARMYC Logo © Yann Loosli
