Skip to main content

Overview

The store module provides centralized state management using Zustand. It manages bins, grid configuration, view modes, selection state, drag interactions, and undo/redo history.

Import

import { useStore, type Bin, type ViewMode, type RenderMode } from '@/store/useStore';

Types

Bin

Represents a single Gridfinity bin with all its properties.
interface Bin {
  id: string;              // Unique identifier (UUID)
  x: number;               // Grid position X (0-based column)
  y: number;               // Grid position Y (0-based row)
  w: number;               // Width in grid units
  d: number;               // Depth in grid units
  h: number;               // Height in grid units
  cornerRadius: number;    // Corner radius in mm
  wallThickness: number;   // Wall thickness in mm
  bottomThickness: number; // Bottom thickness in mm
  stackingLip: boolean;    // Enable stacking lip feature
  labelShelf: boolean;     // Enable 45° label shelf
  labelWidth: number;      // Label shelf width in mm
  magnets: boolean;        // Enable magnet holes
  screws: boolean;         // Enable screw holes
  dividersX: number;       // Number of X-axis dividers
  dividersY: number;       // Number of Y-axis dividers
  color: string;           // Hex color code
  label: string;           // User-defined label
  group: string;           // Bin group/category ID
}
id
string
required
UUID generated automatically on creation
x
number
required
Grid column position (0-indexed)
y
number
required
Grid row position (0-indexed)
w
number
required
Width in grid units (1 unit = 42mm)
d
number
required
Depth in grid units (1 unit = 42mm)
h
number
required
Height in grid units (1 unit = 7mm)

ViewMode

type ViewMode = '2d' | '3d' | 'split';
Controls the viewport layout.

RenderMode

type RenderMode = 'standard' | 'technical' | 'blueprint';
Controls the 3D rendering style.

DragState

Tracks drag-and-drop interactions for placing and moving bins.
interface DragState {
  mode: 'idle' | 'placing' | 'dragging';
  binId: string | null;                      // ID of bin being dragged
  origin: { col: number; row: number } | null; // Drag start position
  ghost: { col: number; row: number } | null;  // Ghost preview position
  ghostValid: boolean;                         // Whether ghost position is valid
  placingConfig: Omit<Bin, 'id' | 'x' | 'y'> | null; // Config for new bin placement
}

State Properties

Grid Configuration

gridCols
number
default:"6"
Number of grid columns
gridRows
number
default:"6"
Number of grid rows

Bin Management

bins
Bin[]
default:"[]"
Array of all bins in the grid
selectedBinId
string | null
default:"null"
ID of the primary selected bin
selectedBinIds
string[]
default:"[]"
Array of all selected bin IDs (supports multi-select)

View Settings

viewMode
ViewMode
default:"'split'"
Current viewport layout mode
renderMode
RenderMode
default:"'standard'"
Current 3D rendering style
showBaseplate
boolean
default:"true"
Whether to render the baseplate
showDimensions
boolean
default:"false"
Whether to show dimension annotations
sectionView
boolean
default:"false"
Whether to enable section view (cut-through)

Interaction State

dragState
DragState
Current drag-and-drop state

History

history
Bin[][]
default:"[[]]"
Undo/redo history stack of bin states
historyIndex
number
default:"0"
Current position in history stack

Actions

addBin

Adds a new bin to the grid.
addBin(bin: Omit<Bin, 'id'>): void
bin
Omit<Bin, 'id'>
required
Bin configuration without ID (generated automatically)
Example:
const { addBin } = useStore();

addBin({
  x: 0,
  y: 0,
  w: 2,
  d: 2,
  h: 3,
  cornerRadius: 3.75,
  wallThickness: 1.2,
  bottomThickness: 0.8,
  stackingLip: true,
  labelShelf: false,
  labelWidth: 12,
  magnets: false,
  screws: false,
  dividersX: 0,
  dividersY: 0,
  color: '#00d4aa',
  label: 'Small Parts',
  group: 'parts',
});
Source: src/store/useStore.ts:112-121

removeBin

Removes a bin by ID.
removeBin(id: string): void
id
string
required
ID of the bin to remove
Source: src/store/useStore.ts:123-133

updateBin

Updates properties of an existing bin.
updateBin(id: string, updates: Partial<Bin>): void
id
string
required
ID of the bin to update
updates
Partial<Bin>
required
Properties to update (partial update)
Example:
const { updateBin } = useStore();

updateBin('bin-id', {
  h: 6,
  labelShelf: true,
  dividersX: 2,
});
Source: src/store/useStore.ts:135-139

moveBin

Moves a bin to a new grid position.
moveBin(id: string, x: number, y: number): void
id
string
required
ID of the bin to move
x
number
required
New X grid position
y
number
required
New Y grid position
Source: src/store/useStore.ts:141-145

selectBin

Selects a bin, with optional multi-select support.
selectBin(id: string | null, multi?: boolean): void
id
string | null
required
ID of bin to select, or null to clear selection
multi
boolean
default:"false"
Whether to add to selection (multi-select mode)
Behavior:
  • If id is null, clears all selections
  • If multi is false, replaces current selection
  • If multi is true, toggles the bin in the selection set
Source: src/store/useStore.ts:147-160

setGridSize

Updates the grid dimensions.
setGridSize(cols: number, rows: number): void
cols
number
required
Number of columns
rows
number
required
Number of rows
Source: src/store/useStore.ts:162

setViewMode

Changes the viewport layout.
setViewMode(mode: ViewMode): void
mode
ViewMode
required
New view mode: ‘2d’, ‘3d’, or ‘split’
Source: src/store/useStore.ts:164

setRenderMode

Changes the 3D rendering style.
setRenderMode(mode: RenderMode): void
mode
RenderMode
required
New render mode: ‘standard’, ‘technical’, or ‘blueprint’
Source: src/store/useStore.ts:166

setShowDimensions

Toggles dimension annotations.
setShowDimensions(on: boolean): void
on
boolean
required
Whether to show dimensions
Source: src/store/useStore.ts:168

setSectionView

Toggles section view (cut-through).
setSectionView(on: boolean): void
on
boolean
required
Whether to enable section view
Source: src/store/useStore.ts:170

clearAll

Removes all bins and clears selection.
clearAll(): void
Source: src/store/useStore.ts:172-175

setDragState

Updates the drag state (used internally by drag handlers).
setDragState(state: Partial<DragState>): void
state
Partial<DragState>
required
Partial drag state to merge
Source: src/store/useStore.ts:177-179

startPlacing

Enters bin placement mode with a configuration template.
startPlacing(config: Omit<Bin, 'id' | 'x' | 'y'>): void
config
Omit<Bin, 'id' | 'x' | 'y'>
required
Bin configuration for placement (position determined by user click)
Source: src/store/useStore.ts:181-190

cancelPlacing

Exits placement mode without creating a bin.
cancelPlacing(): void
Source: src/store/useStore.ts:192

undo

Reverts to the previous state in history.
undo(): void
Source: src/store/useStore.ts:194-201

redo

Reapplies the next state in history.
redo(): void
Source: src/store/useStore.ts:203-210

Usage Example

import { useStore } from '@/store/useStore';

function BinEditor() {
  const bins = useStore((state) => state.bins);
  const addBin = useStore((state) => state.addBin);
  const updateBin = useStore((state) => state.updateBin);
  const selectedBinId = useStore((state) => state.selectedBinId);

  const handleAddBin = () => {
    addBin({
      x: 0, y: 0, w: 1, d: 1, h: 3,
      cornerRadius: 3.75,
      wallThickness: 1.2,
      bottomThickness: 0.8,
      stackingLip: true,
      labelShelf: false,
      labelWidth: 12,
      magnets: false,
      screws: false,
      dividersX: 0,
      dividersY: 0,
      color: '#00d4aa',
      label: 'New Bin',
      group: '',
    });
  };

  const handleUpdateHeight = (id: string, newHeight: number) => {
    updateBin(id, { h: newHeight });
  };

  return (
    <div>
      <button onClick={handleAddBin}>Add Bin</button>
      {bins.map(bin => (
        <div key={bin.id}>
          {bin.label} - {bin.w}x{bin.d}x{bin.h}
        </div>
      ))}
    </div>
  );
}

History Management

The store automatically tracks bin changes for undo/redo:
  • Recorded operations: addBin, removeBin, updateBin, moveBin, clearAll
  • History stack: Maintains a snapshot of bins array after each operation
  • Max history: Limited only by browser memory
  • Implementation: Uses deep cloning via JSON.parse(JSON.stringify())
Source: src/store/useStore.ts:87-91

Build docs developers (and LLMs) love