|
| 1 | +import { Canvas, Meta, Controls } from "@storybook/addon-docs/blocks" |
| 2 | + |
| 3 | +import * as GridStackStories from "./GridStackReact.stories" |
| 4 | + |
| 5 | +<Meta of={GridStackStories} /> |
| 6 | + |
| 7 | +# GridStack |
| 8 | + |
| 9 | +## Introduction |
| 10 | + |
| 11 | +### Definition |
| 12 | + |
| 13 | +F0GridStack is a React wrapper for the GridStack library that enables the |
| 14 | +creation of resizable and draggable grid layouts. It provides a flexible, |
| 15 | +interactive grid system where widgets can be dynamically arranged, resized, and |
| 16 | +repositioned by users or programmatically through ref methods. |
| 17 | + |
| 18 | +### Purpose |
| 19 | + |
| 20 | +The purpose of F0GridStack in our design system is as follows: |
| 21 | + |
| 22 | +- **Interactive Layouts**: Enables users to customize their dashboard or |
| 23 | + workspace layouts by dragging and resizing widgets |
| 24 | +- **Dynamic Content Management**: Allows programmatic addition and removal of |
| 25 | + widgets at runtime |
| 26 | +- **Responsive Grid System**: Provides a flexible grid that adapts to different |
| 27 | + screen sizes and widget configurations |
| 28 | +- **Layout Persistence**: Supports saving and restoring widget positions and |
| 29 | + sizes through the onChange callback |
| 30 | +- **Nested Grids**: Supports sub-grids for complex, hierarchical layouts |
| 31 | + |
| 32 | +## Basic Usage |
| 33 | + |
| 34 | +The default GridStack configuration demonstrates a simple grid layout with |
| 35 | +multiple widgets that can be dragged and resized. |
| 36 | + |
| 37 | +<Canvas of={GridStackStories.Default} /> |
| 38 | +<Controls of={GridStackStories.Default} /> |
| 39 | + |
| 40 | +## Programmatic Control with Ref Methods |
| 41 | + |
| 42 | +F0GridStack exposes several methods through a ref that allow you to |
| 43 | +programmatically control the grid layout. This is useful for dynamic widget |
| 44 | +management, such as adding or removing widgets based on user actions or |
| 45 | +application state. |
| 46 | + |
| 47 | +### Accessing Ref Methods |
| 48 | + |
| 49 | +To use the ref methods, create a ref using `useRef<F0GridStackRef>(null)` and |
| 50 | +attach it to the `F0GridStack` component: |
| 51 | + |
| 52 | +```tsx |
| 53 | +import { useRef } from "react" |
| 54 | +import { F0GridStack, type F0GridStackRef } from "@/components/Utilities/F0GridStack" |
| 55 | + |
| 56 | +const gridRef = useRef<F0GridStackRef>(null) |
| 57 | + |
| 58 | +<F0GridStack ref={gridRef} options={{ column: 12 }} widgets={[]} /> |
| 59 | +``` |
| 60 | + |
| 61 | +### Available Methods |
| 62 | + |
| 63 | +#### `addWidget` |
| 64 | + |
| 65 | +Adds a new widget to the grid programmatically. |
| 66 | + |
| 67 | +**Parameters:** |
| 68 | + |
| 69 | +- `widget`: A `GridStackReactWidget` object with the following properties: |
| 70 | + - `id`: Unique identifier for the widget (required) |
| 71 | + - `w`: Width in grid columns |
| 72 | + - `h`: Height in grid rows |
| 73 | + - `x`: X position in grid columns (optional, will auto-place if not provided) |
| 74 | + - `y`: Y position in grid rows (optional, will auto-place if not provided) |
| 75 | + - `renderFn`: Function that returns the React element to render |
| 76 | + - `meta`: Optional metadata object associated with the widget |
| 77 | + - `allowedSizes`: Optional array of allowed size combinations |
| 78 | + - `allowResize`: Whether the widget can be resized (default: true) |
| 79 | + - `allowMove`: Whether the widget can be moved (default: true) |
| 80 | + |
| 81 | +**Example:** |
| 82 | + |
| 83 | +```tsx |
| 84 | +gridRef.current?.addWidget({ |
| 85 | + id: "new-widget-1", |
| 86 | + w: 2, |
| 87 | + h: 2, |
| 88 | + meta: { |
| 89 | + title: "New Widget", |
| 90 | + type: "chart", |
| 91 | + }, |
| 92 | + renderFn: () => ( |
| 93 | + <div className="h-full rounded-md bg-f1-background-secondary p-4"> |
| 94 | + New Widget Content |
| 95 | + </div> |
| 96 | + ), |
| 97 | +}) |
| 98 | +``` |
| 99 | + |
| 100 | +#### `removeWidget` |
| 101 | + |
| 102 | +Removes a widget from the grid by its ID. |
| 103 | + |
| 104 | +**Parameters:** |
| 105 | + |
| 106 | +- `id`: The unique identifier of the widget to remove (string) |
| 107 | + |
| 108 | +**Example:** |
| 109 | + |
| 110 | +```tsx |
| 111 | +gridRef.current?.removeWidget("widget-1") |
| 112 | +``` |
| 113 | + |
| 114 | +#### `addSubGrid` |
| 115 | + |
| 116 | +Adds a nested grid (sub-grid) to the main grid. This is useful for creating |
| 117 | +hierarchical layouts where widgets can be grouped within a parent widget. |
| 118 | + |
| 119 | +**Parameters:** |
| 120 | + |
| 121 | +- `subGrid`: A `GridStackReactWidget` with additional `subGridOpts` property |
| 122 | + containing: |
| 123 | + - `children`: Array of widgets that will be placed inside the sub-grid |
| 124 | + |
| 125 | +**Example:** |
| 126 | + |
| 127 | +```tsx |
| 128 | +gridRef.current?.addSubGrid({ |
| 129 | + id: "subgrid-1", |
| 130 | + w: 4, |
| 131 | + h: 4, |
| 132 | + subGridOpts: { |
| 133 | + column: 6, |
| 134 | + children: [ |
| 135 | + { |
| 136 | + id: "nested-widget-1", |
| 137 | + w: 2, |
| 138 | + h: 2, |
| 139 | + renderFn: () => <div>Nested Widget 1</div>, |
| 140 | + }, |
| 141 | + { |
| 142 | + id: "nested-widget-2", |
| 143 | + w: 2, |
| 144 | + h: 2, |
| 145 | + renderFn: () => <div>Nested Widget 2</div>, |
| 146 | + }, |
| 147 | + ], |
| 148 | + }, |
| 149 | + renderFn: () => <div>Sub-grid Container</div>, |
| 150 | +}) |
| 151 | +``` |
| 152 | + |
| 153 | +#### `removeAll` |
| 154 | + |
| 155 | +Removes all widgets from the grid at once. |
| 156 | + |
| 157 | +**Example:** |
| 158 | + |
| 159 | +```tsx |
| 160 | +gridRef.current?.removeAll() |
| 161 | +``` |
| 162 | + |
| 163 | +### Complete Example |
| 164 | + |
| 165 | +The following example demonstrates all ref methods in action: |
| 166 | + |
| 167 | +<Canvas of={GridStackStories.WithRefMethods} /> |
| 168 | + |
| 169 | +This example shows: |
| 170 | + |
| 171 | +- **Add Widget**: Dynamically adds new widgets to the grid |
| 172 | +- **Remove Last Widget**: Removes the most recently added widget |
| 173 | +- **Remove All**: Clears all widgets from the grid |
| 174 | + |
| 175 | +## Best Practices |
| 176 | + |
| 177 | +1. **Widget IDs**: Always use unique, stable IDs for widgets to ensure proper |
| 178 | + tracking and removal |
| 179 | +2. **Layout Persistence**: Use the `onChange` callback to save widget positions |
| 180 | + and restore them on component mount |
| 181 | +3. **Performance**: For large numbers of widgets, consider debouncing the |
| 182 | + `onChange` callback |
| 183 | +4. **Responsive Design**: Configure appropriate column counts for different |
| 184 | + screen sizes using the `options.column` property |
| 185 | +5. **Widget Constraints**: Use `allowedSizes` to restrict widget dimensions to |
| 186 | + specific size combinations |
| 187 | +6. **Metadata**: Store widget-specific data in the `meta` property for easy |
| 188 | + retrieval and persistence |
| 189 | + |
| 190 | +## Props |
| 191 | + |
| 192 | +### `options` |
| 193 | + |
| 194 | +Configuration object for the grid layout. |
| 195 | + |
| 196 | +- `column`: Number of columns in the grid (default: 12) |
| 197 | +- `row`: Number of rows in the grid (optional) |
| 198 | +- `margin`: Margin between widgets in pixels (optional) |
| 199 | +- `draggable`: Whether widgets can be dragged (default: true) |
| 200 | +- `acceptWidgets`: Whether the grid can accept widgets from other grids |
| 201 | + (default: false) |
| 202 | + |
| 203 | +### `widgets` |
| 204 | + |
| 205 | +Array of initial widgets to render in the grid. Each widget follows the |
| 206 | +`GridStackReactWidget` interface. |
| 207 | + |
| 208 | +### `onChange` |
| 209 | + |
| 210 | +Callback function that is called whenever the layout changes (widget moved, |
| 211 | +resized, added, or removed). Receives an array of `GridStackWidgetPosition` |
| 212 | +objects containing the current state of all widgets. |
0 commit comments