UNPKG

@gamesberry/karmyc-core

Version:

A flexible and powerful layout management system for React applications

632 lines (514 loc) β€’ 15.6 kB
# Karmyc Core <p align="center"> <img style="width:50%;" src="https://raw.githubusercontent.com/yannloosli/karmyc/refs/heads/main/demo/assets/brand/karmyc_logo.svg" alt="πŸ”—Karmyc" /> </p> <p align="center"><strong>CORE</strong></p> <p align="center"><em>A flexible and powerful layout management system for React applications</em></p> --- [![npm version](https://img.shields.io/npm/v/@gamesberry/karmyc-core.svg)](https://www.npmjs.com/package/@gamesberry/karmyc-core) [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/your-username/karmyc/blob/main/LICENSE) [![npm downloads](https://img.shields.io/npm/dm/@gamesberry/karmyc-core.svg)](https://www.npmjs.com/package/@gamesberry/karmyc-core) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue.svg)](https://www.typescriptlang.org/) [![React](https://img.shields.io/badge/React-19.0+-61DAFB.svg)](https://reactjs.org/) ## Table of Contents - [Overview](#overview) - [Quick Start](#quick-start) - [Core Concepts](#core-concepts) - [API Reference](#api-reference) - [Development](#development) - [Acknowledgements](#acknowledgements) - [License](#license) ## 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](https://yannloosli.github.io/karmyc) showcasing Karmyc Core's key features. ## Quick Start ### 1. Installation ```bash # Using yarn (recommended) yarn add @gamesberry/karmyc-core # Using npm npm install @gamesberry/karmyc-core ``` #### Dependencies Karmyc Core requires the following peer dependencies: - `react >= 19.0` - `react-dom >= 19.0` ### 2. Basic Setup ```tsx // 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: ```tsx // 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 ```tsx // AreaInitializer.tsx import { MyArea } from './areas/MyArea'; export const AreaInitializer = () => { return ( <> <MyArea /> </> ); }; ``` ### 4. Defining an Area Type ```tsx // 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 ```tsx // 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 ```typescript 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: ```tsx <Tools areaType="apptitle"> <Tools areaType="app"> <Karmyc /> </Tools> </Tools> ``` #### Tools Component Props ```typescript 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. ```typescript 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. ```typescript const { createArea, removeArea, setActive, update, getActive, getById, getAll, getErrors } = useArea(); ``` #### `useSpace()` Access state for spaces. ```typescript const { spaces, activeSpaceId, getSpaceById } = useSpace(); ``` #### `useRegisterAreaType(type, component, initialState, options)` Register a new area type. ```typescript 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. ```typescript const { createArea, removeArea, splitArea, setRowSizes } = useAreaOptimized(); ``` ##### Specialized Area Hooks Granular hooks for optimal performance: ```typescript 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 actions ``` ##### `useAreaDragAndDrop(params?)` Provides drag and drop functionality for areas and placement overlay. ```typescript const { isDragging, handleDragStart, handleDragOver, handleDragEnd, handleDrop } = useAreaDragAndDrop({ id: 'area-1', type: 'my-area', state: {} }); ``` ##### `useAreaKeyboardShortcuts(areaId)` Provides keyboard shortcuts for areas. ```typescript useAreaKeyboardShortcuts(areaId); ``` ##### `useContextMenu()` Provides context menu functionality. ```typescript const { openContextMenu, closeContextMenu } = useContextMenu(); ``` ##### `useResizePreview()` Provides resize preview functionality. ```typescript const { showPreview, hidePreview, previewState } = useResizePreview(); ``` ##### `useScreenManagement()` Provides screen management functionality. ```typescript const { createScreen, removeScreen, switchScreen } = useScreenManagement(); ``` ##### `useAreaStack(areaId)` Provides area stacking functionality. ```typescript const { isChildOfStack, stackArea, unstackArea } = useAreaStack(areaId); ``` ##### `useActiveSpaceHistory()` Enhanced history bound to the active space. ```typescript const history = useActiveSpaceHistory(); ``` ##### `useHistory(spaceId)` Provides enhanced history functionality with advanced features like action batching, diff tracking, and typed actions. ```typescript 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. ```typescript const historyActions = useActiveSpaceHistory(); ``` ##### `useTypedHistoryActions(spaceId)` Provides typed history actions for common operations. ```typescript 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. ```typescript const { registerPlugin, unregisterPlugin, getPlugins } = usePluginSystem(); ``` ### Core Components #### `KarmycCoreProvider` Main provider that sets up the Karmyc environment. ```tsx <KarmycCoreProvider options={config}> {children} </KarmycCoreProvider> ``` #### `Karmyc` Primary component that renders layouts and areas. ```tsx <Karmyc /> ``` #### `Tools` System for injecting components into predefined UI slots. ```tsx <Tools areaType="app"> <Karmyc /> </Tools> ``` #### Additional Components ##### `AreaErrorBoundary` Error boundary component for areas. ```tsx <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. ```tsx <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. ```tsx <ScreenSwitcher /> ``` ##### `KeyboardShortcutsViewer` Component for displaying keyboard shortcuts. ```tsx <KeyboardShortcutsViewer /> ``` ##### `ContextMenu` Context menu component. ```tsx <ContextMenu /> ``` ### Configuration #### Built-in Layouts You can define built-in layouts that users can switch between: ```typescript const builtInLayouts = [ { id: 'default', name: 'Default Layout', config: { /* layout configuration */ }, isBuiltIn: true } ]; ``` ### Types and Interfaces #### Core Types ```typescript // 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 ```typescript const AREA_ROLE = { LEAD: 'LEAD', FOLLOW: 'FOLLOW', SELF: 'SELF' } as const; const TOOLBAR_HEIGHT = 30; ``` ## Development ### Available Scripts - `yarn dev`: Start development mode with watch - `yarn build`: Build the library - `yarn bundle`: Build the library (alias for build) - `yarn test`: Run tests - `yarn test:watch`: Run tests in watch mode - `yarn test:coverage`: Run tests with coverage - `yarn demo:dev`: Start the demo application in development mode - `yarn demo:build`: Build the demo application - `yarn demo:ssr:dev`: Start the SSR demo application in development mode - `yarn demo:ssr:build`: Build the SSR demo application - `yarn 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/ # Documentation ``` ## Acknowledgements Karmyc core was extracted and derived from [animation-editor](https://github.com/alexharri/animation-editor) by [@alexharri](https://github.com/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](https://github.com/yannloosli) - KARMYC Logo Β© Yann Loosli