Skip to content

Aysnine/gridstack-react

Repository files navigation

GridStack React

Online demo: https://gridstack-react.pages.dev/

The code in this repository will be manually copied to the react folder of the gridstack.js main repository.

TODO

  • Add Widgets
  • Add Sub Grid
  • Nested Sub Grid
  • Remove Widget
  • Copy(Duplicate) Widget
  • Custom handle
  • Drag between two grid stacks

Welcome to give any suggestions and ideas, you can submit an issue or contact me by email. :)

Usage

Simple

Render item with widget id selector.

function App() {
  const [uncontrolledInitialOptions] = useState<GridStackOptions>({
    // ...
    children: [
      { id: "item1", h: 2, w: 2, x: 0, y: 0 },
      { id: "item2", h: 2, w: 2, x: 2, y: 0 },
    ],
  });

  return (
    <GridStackProvider initialOptions={uncontrolledInitialOptions}>
      <Toolbar />

      <GridStackRender>
        <GridStackItem id="item1">
          <div>hello</div>
        </GridStackItem>

        <GridStackItem id="item2">
          <div>grid</div>
        </GridStackItem>
      </GridStackRender>
    </GridStackProvider>
  );
}

Advanced

Render item with widget map component info.

ComponentInfoMap is just an example, you can use any way you want to store and retrieve component information.

function App() {
  const [uncontrolledInitialOptions] = useState<GridStackOptions>({
    // ...
    children: [
      { id: "item1", h: 2, w: 2, x: 0, y: 0 },
      { id: "item2", h: 2, w: 2, x: 2, y: 0 },
    ],
  });

  const [initialComponentInfoMap] = useState<Record<string, ComponentInfo>>(
    () => ({
      item1: { component: "Text", serializableProps: { content: "Text" } },
      item2: {
        component: "ComplexCard",
        serializableProps: { title: "Complex Card", color: "red" },
      },
    })
  );

  return (
    <ComponentInfoMapProvider initialComponentInfoMap={initialComponentInfoMap}>
      <GridStackProvider initialOptions={uncontrolledInitialOptions}>
        <Toolbar />

        <GridStackRender>
          <DynamicGridStackItems />
        </GridStackRender>
      </GridStackProvider>
    </ComponentInfoMapProvider>
  );
}

export function DynamicGridStackItems() {
  const { componentInfoMap } = useComponentInfoMap();

  return (
    <>
      {Array.from(componentInfoMap.entries()).map(
        ([widgetId, componentInfo]) => {
          const Component = COMPONENT_MAP[componentInfo.component];
          if (!Component) {
            throw new Error(`Component ${componentInfo.component} not found`);
          }

          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          const props = componentInfo.serializableProps as any;

          if (componentInfo.component === "ComplexCard") {
            return (
              <GridStackItem key={widgetId} id={widgetId}>
                <ComplexCardEditableWrapper
                  key={`complex-card-editable-wrapper-${widgetId}`}
                  serializableProps={componentInfo.serializableProps}
                >
                  <Component {...props} key={`component-${widgetId}`} />
                </ComplexCardEditableWrapper>
              </GridStackItem>
            );
          }

          return (
            <GridStackItem key={widgetId} id={widgetId}>
              <Component {...props} key={`component-${widgetId}`} />
            </GridStackItem>
          );
        }
      )}
    </>
  );
}

Experimental

Render item with custom handle.

<GridStackItem id="xxx">
  <GridStackHandleReInitializer>
    <button className={CUSTOM_DRAGGABLE_HANDLE_CLASSNAME}>
      Handle ONLY HERE
    </button>
  </GridStackHandleReInitializer>
</GridStackItem>

API Reference

Components

GridStackProvider

Top-level component that provides GridStack context.

type GridStackProviderProps = {
  initialOptions: GridStackOptions; // GridStack initialization options
  children: React.ReactNode;
};

GridStackRender

Render GridStack root container component.

type GridStackRenderProps = {
  children: React.ReactNode;
};

GridStackItem

Component representing a single grid item.

type GridStackItemProps = {
  id: string; // Grid item unique identifier
  children: React.ReactNode;
};

GridStackHandleReInitializer

Experimental component for reinitializing the drag handle of a grid item.

type GridStackHandleReInitializerProps = {
  children: React.ReactNode;
};

Contexts

GridStackContext

Provide GridStack core functionality context.

interface GridStackContextType {
  initialOptions: GridStackOptions;
  addWidget: (widget: GridStackWidget) => void;
  removeWidget: (el: GridStackElement) => void;
  saveOptions: () => ReturnType<GridStack["save"]> | undefined;

  _gridStack: {
    value: GridStack | null;
    set: React.Dispatch<React.SetStateAction<GridStack | null>>;
  };
}

GridStackItemContext

Provide single grid item functionality context.

type GridStackItemContextType = {
  id: string;
  remove: () => void;
  getBounds: () => {
    current: { x?: number; y?: number; w?: number; h?: number };
    original: { x?: number; y?: number; w?: number; h?: number };
  } | null;
  setSize: (size: { w: number; h: number }) => void;
};

GridStackRenderContext

Provide rendering related functionality context.

type GridStackRenderContextType = {
  getWidgetContainer: (widgetId: string) => HTMLElement | null;
};

Hooks

useGridStackContext

Get GridStack context.

function useGridStackContext(): GridStackContextType;

useGridStackItemContext

Get grid item context.

function useGridStackItemContext(): GridStackItemContextType;

useGridStackRenderContext

Get rendering context.

function useGridStackRenderContext(): GridStackRenderContextType;

Type Exports

export type {
  GridStackContextType,
  GridStackProviderProps,
  GridStackRenderContextType,
  GridStackRenderProps,
  GridStackItemProps,
  GridStackItemContextType,
  GridStackHandleReInitializerProps,
};