Grid Layout Plus

repository·main·Indexed 20 days ago

https://github.com/qmhc/grid-layout-plus

A Vue 3-based grid layout system for creating draggable and resizable widget interfaces. A successor to Vue Grid Layout, it features serialization, responsiveness, RTL support, and a headless Core API in its v2 beta. Key capabilities include item overlap, auto-height for dynamic content, cross-grid dragging, and a useGridLayout composable for custom rendering logic.

Tokens
43.6K
Snippets
116
Records
166
Agent score
69%

What's inside grid-layout-plus

  1. Overview of Grid Layout Plus

    main

    Grid Layout Plus is a draggable and resizable grid layout system designed for Vue 3. It is a migration of the original Vue Grid Layout and is built using <script setup> and normalized TypeScript.

    Key Features

    • Draggable & Resizable widgets: Easily manipulate widget positions and sizes.
    • Static widgets: Support for non-moving elements within the grid.
    • Bounds checking: Prevents dragging and resizing outside of defined grid boundaries.
    • Dynamic updates: Add or remove widgets without rebuilding the entire grid.
    • Serialization: The layout can be serialized and restored (useful for saving user configurations).
    • RTL Support: Automatic support for Right-to-Left languages.
    • Responsive: Adapts to different screen sizes.
  2. Handle LayoutTransactionReceipt statuses

    main

    When calling a method on GridLayout, it returns a LayoutTransactionReceipt. You should check the status to determine if your programmatic change was accepted or rejected.

    StatusMeaning
    pendingThe proposal was emitted through update:layout and is waiting for prop confirmation.
    unchangedThe command is valid, but its result is semantically equal to the committed Layout.
    rejectedValidation or layout rules rejected the command; the committed Layout did not change.

    Important Notes:

    • If using v-model:layout, Vue typically writes the pending proposal back automatically. If the parent fails to confirm it, the component rolls back and emits operation-rejected with reason: 'external-not-committed'.
    • Layer methods (bringToFront, sendToBack) only work when collision-mode="overlap". Otherwise, they return a rejected receipt with reason: 'disabled'.
    • To react to a successful commit, use the layout-updated event.
    function moveSummary() {
      const receipt = grid.value?.moveItem('summary', 2, 0)
      if (!receipt) return
    
      if (receipt.status === 'pending') {
        console.log('Proposed revision', receipt.revision)
      } else if (receipt.status === 'rejected') {
        console.warn('Move rejected:', receipt.reason)
      }
    }
  3. Configure the drag threshold

    main
    The drag-threshold property defines the distance a pointer must move before a drag operation is initiated. This is useful for preventing accidental drags when items contain clickable elements (like buttons or links) that might be triggered by a slight movement. Increasing this value ensures that a user must intentionally move the pointer a certain distance before the item becomes 'draggable'.
  4. Configure Responsive Layouts and Breakpoints

    main

    The grid supports responsive layouts using breakpoints. The default breakpoints are 'xxs', 'xs', 'sm', 'md', and 'lg'.

    • Breakpoints: A mapping of breakpoint names to column counts.
    • ResponsiveValue: A utility type that allows you to provide either a single value (applied to all breakpoints) or a breakpoint-specific map.
    • ResponsiveLayoutsInput: The partial breakpoint map you pass to GridLayout to define different layouts for different screen sizes.
    type DefaultBreakpoint = 'xxs' | 'xs' | 'sm' | 'md' | 'lg';
    // Example of a ResponsiveValue for gap
    const gap: ResponsiveValue<DefaultBreakpoint, readonly [number, number]> = {
      sm: [10, 10],
      md: [20, 20]
    };
  5. Use Compactors to manage item placement

    main

    A Compactor is an object used to define how items should be moved to fill gaps in the grid. The Compactor interface is:

    interface Compactor {
      readonly type?: 'vertical' | 'horizontal'
      compact(layout: ReadonlyLayout, cols: number): Layout
    }

    Available Compactors

    • verticalCompactor: Compacts items upward (the default).
    • horizontalCompactor: Compacts items left and wraps when a row is full.
    • noCompactor: Preserves placement after validation.
    • fastVerticalCompactor: Same as verticalCompactor but uses indexed candidate lookup for performance.
    • fastHorizontalCompactor: Same as horizontalCompactor but uses indexed candidate lookup for performance.

    Note: withOverlap(compactor) is deprecated. Use collisionMode: 'overlap' in your normalization options instead.

  6. Configure compaction direction with horizontalCompactor and verticalCompactor

    main

    The compactor property determines the direction in which items move to fill gaps in the layout.

    • Use horizontalCompactor to move items toward earlier columns (leftward).
    • Use verticalCompactor to move items toward earlier rows (upward).

    When an item is dragged away from its position, the remaining items will automatically shift along the chosen axis to fill the resulting empty space.

    // Example of setting the compaction direction
    // Note: The specific implementation depends on the component props
    <GridLayout
      :compactor="horizontalCompactor"
    />
  7. Disable layout compaction with noCompactor

    main

    By default, the grid layout engine attempts to compact the layout by moving items into empty spaces. To prevent this behavior and leave gaps where they are, use the noCompactor property. When noCompactor is enabled, an item's coordinates will only change if that specific item is manually moved or resized; other items will not shift to fill empty spaces created by moving or removing items.

    // Example usage concept
    <GridLayout
      :layout="layout"
      :no-compactor="true"
    >
      <!-- Items will stay in their original positions even if gaps are created -->
    </GridLayout>
  8. Configure grid behavior and capabilities

    main

    Grid Layout Plus provides several configurable behaviors for managing how items interact within the grid:

    • Responsive layouts: Change the number of columns and item positions based on specific breakpoints.
    • Collision control: Manage how items interact when they overlap. You can choose to push items aside, reject collisions, or allow items to overlap.
    • Drag and drop: Support moving existing items within the grid or dragging new items from outside into the grid.
    • Position strategy: Choose between transform-based positioning or absolute positioning depending on your rendering requirements.
    • Styling hooks: Customize the appearance of grid lines, placeholders, backgrounds, and various item states.
    • Composable API: For advanced use cases, you can use the underlying layout engine via its Composable API without using the built-in Vue component markup.
  9. Understand InteractionTerminalPayload states

    main

    When an interaction finishes (via interaction-end or useGridLayout.onInteractionEnd), it results in one of three terminal states:

    • committed: The final candidate was successfully applied (reason: 'applied').
    • unchanged: The interaction ended without changing the original Layout.
    • cancelled: The interaction was interrupted. You should inspect the typed reason to understand why.

    The payload includes metadata such as previousLayout, the final layout, oldItem, the final item, the revision, and the last nativeEvent if available.

  10. Understand and use position-strategy

    main

    The position-strategy property determines how logical grid coordinates are converted into actual CSS positions. Changing the strategy affects the visual rendering and CSS positioning method but does not change the underlying layout data (the grid coordinates themselves).

    Built-in strategies include:

    • Transform-based positioning: Uses CSS transform for positioning.
    • Absolute positioning: Uses standard CSS top/left absolute positioning.
    • Pointer-coordinate correction: Adjusts positioning for containers that have been scaled.

    Use different strategies to optimize for performance or to handle scaled containers without losing coordinate accuracy.

  11. Use configuration grouping for grid settings

    main

    To improve readability in layouts with many settings, grid-layout-plus allows you to group related options into specific configuration objects: grid-config, drag-config, resize-config, and drop-config. These groups collect related properties while maintaining reactivity, making them easier to manage than a flat list of individual props.

    // Example of the grouping concept
    const layoutConfig = {
      gridConfig: { /* grid related options */ },
      dragConfig: { /* drag related options */ },
      resizeConfig: { /* resize related options */ },
      dropConfig: { /* drop related options */ }
    };
  12. Implement responsive layouts

    main

    To make the grid responsive to container width changes, set the responsive prop to true. You must then provide configuration for different breakpoints.

    • breakpoints: Defines the width thresholds (e.g., { lg: 1200, md: 996, ... }).
    • cols: Defines the number of columns for each breakpoint (e.g., { lg: 12, md: 10, ... }).
    • responsive-layouts: An object mapping breakpoint names to their specific layouts (e.g., { lg: [item1, item2], md: [item1] }).

    Important for Controlled Mode: When using v-model in responsive mode, you must bind both v-model:layout and v-model:responsive-layouts. Updates to the current layout and the breakpoint map share one revision and must be written back in the same Vue update cycle.

    <GridLayout
      v-model:layout="currentLayout"
      v-model:responsive-layouts="responsiveLayoutMap"
      :responsive="true"
      :breakpoints="{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }"
      :cols="{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }"
    >
    </GridLayout>