GrDashboardPalette

  • dashboard
  • dashboard
  • API · 5 props
import { GrDashboardPalette } from '@feugene/granularity-dashboard/components/GrDashboardPalette'

Overview

When to take it

  • the set of widgets is chosen by the user — the dashboard is assembled from a catalogue rather than arriving ready;
  • what is available depends on the role or on the plan — the list arrives as a prop, and what is unavailable simply does not enter it;
  • the card of the catalogue is non-standard — the item slot draws an icon, a description, a preview;
  • there is nothing to add yet — the empty slot explains why, instead of an empty rectangle.

When to take something else

NeedTake
Choose one option from a listGrSelect
Find a command or an object by searchingGrCommandPalette
Show a list without addingGrList
Explain that the dashboard is emptyGrEmptyState
The grid itselfGrDashboard

Despite the name, this is not GrCommandPalette: there a command is searched for across the whole application by typing, here a widget is chosen from a short known set.

Examples 2 each with a live demo and its code

  • Building a board from the catalogue

    Add a widget with its button, or drag a tile onto the grid: droppable previews where it will land. The palette only says what to add — add for the button, item-drop on the grid with the cell and the options — and the page places it with addItem. What is already on the board stays in the list as «Added», and minW travels with the tile.

    Widgets
    • Sales today3×2Orders and revenue so far
    • Average basket3×2Compared with last week
    • Returns3×2Open and processed
    • Low stock6×3Needs at least half the width
    My store board
    Sales today
    €4,812 · 63 orders
  • Tiles with icons and plans

    The item slot draws a tile of its own — icon, description, a plan badge — and transferProps goes on its root, without which the tile could not be dragged. The «Add» button stays in the tile: it is the keyboard path, and dragging is only an enhancement. It calls the slot’s add, so the palette emits add and announces the widget, as with its own tile. ghost decides what follows the pointer.

    Add widgetsTeam plan
    • MRR Recurring revenue and its change
    • Overdue invoices Who owes what, oldest first
    • Cash forecast BusinessNext 90 days from open invoices

API generated from the package · cannot drift

Props

PropTypedefaultDescription
draggableboolean | undefinedundefinedThe tile can be dragged onto the grid. The "Add" button stays at any value: it is the contract and the only keyboard path. A grid listening to `itemDrop` will place what is dropped — one that does not will show the backdrop and do nothing.
size"lg" | "xs" | "sm" | "md" | undefinedundefinedThe size step: the type size of the tiles and the add buttons. `md` by default; taken from `GrConfigProvider`.
disabledboolean | undefinedfalseThe catalogue is unavailable: the "Add" buttons are disabled, the tiles cannot be dragged.
ariaLabelstring | undefined—The name of the tile list. Not set — from the locale ("Widget catalog").
itemsrequiredGrDashboardPaletteItem[]—Catalog of available widgets.

Slots

SlotTypeDescription
item
{ item: GrDashboardPaletteItem; dragging: boolean; transferP{ item: GrDashboardPaletteItem; dragging: boolean; transferProps: { onPointerdown: (event: PointerEvent) => void; }; add: () => void; }
A custom tile. `transferProps` is bound to its root (`v-bind`) — without it there is nothing to drag custom markup by, and the slot exists precisely for that markup.
ghost{ item: GrDashboardPaletteItem; }What is drawn under the cursor during a drag.
emptyanyWhat to show when the catalogue is empty.

Events

EventSignatureDescription
add(event: "add", item: GrDashboardPaletteItem): void—

Types

Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.

Import
import type { GrDashboardPaletteConfigurableProps, GrDashboardPaletteSize, GrDashboardPaletteItem } from '@feugene/granularity-dashboard/components/GrDashboardPalette'

Filedist/types/components/GrDashboardPalette/config.d.ts

grDashboardPaletteConfigconst
const grDashboardPaletteConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrDashboardPalette">;

Filedist/types/components/GrDashboardPalette/defaults.d.ts

GrDashboardPaletteConfigurablePropsinterface
interface GrDashboardPaletteConfigurableProps {
    size: GrDashboardPaletteSize;
    draggable: boolean;
}

Filedist/types/components/GrDashboardPalette/grDashboardPaletteStyles.d.ts

GrDashboardPaletteSizetype
type GrDashboardPaletteSize = GrComponentSize;
GrDashboardPaletteIteminterface
interface GrDashboardPaletteItem {
    id: string;
    title: string;
    description?: string;
    defaultSize?: {
        w: number;
        h: number;
    };
    minW?: number;
    minH?: number;
    maxW?: number;
    maxH?: number;
    disabled?: boolean;
}

Filedist/types/components/GrDashboardPalette/safelist.d.ts

grDashboardPaletteSafelistconst
const grDashboardPaletteSafelist: string[];

Filedist/types/components/GrDashboardPalette/GrDashboardPalette.vue.d.ts

GrDashboardPalettePropsinterface
interface GrDashboardPaletteProps {
    items: GrDashboardPaletteItem[];
    size?: GrDashboardPaletteSize;
    draggable?: boolean;
    disabled?: boolean;
    ariaLabel?: string;
}
GrDashboardPaletteEmitsinterface
interface GrDashboardPaletteEmits {
    (e: 'add', item: GrDashboardPaletteItem): void;
}

Usage from the library prose

Where an added widget goes is decided by the application

The component emits an intent with a description of the widget, and the coordinates are assigned by the consumer: only they know whether to add a new widget at the bottom, in the first free place or at the position the user started from. Putting it “somewhere” would mean spoiling the layout the person has just assembled.

Dragging is a reinforcement rather than a contract

A tile can be dragged onto the grid (draggable, on by default), but the “Add” button stays and remains the only keyboard path. Make dragging the contract and the catalogue cannot be used from the keyboard, and “accessibility later” never comes here.

Where it was dropped is reported by the grid with an itemDrop emit, and the putting is still done by the application — exactly as with the button. A grid that does not listen to itemDrop will show the underlay and will do nothing on release: either handle the event or switch draggable off.

A press on the button itself does not become a drag: otherwise a hand that wavered by five pixels would give a drag instead of an addition.

A tile of your own — the #item slot

The slot receives item, dragging, transferProps and add. transferProps is bound to the root of the tile — without it your own markup cannot be dragged. add is the same path as the built-in button’s: an add emit and an “added” announcement to the screen reader, and nothing at all for a disabled tile. Your own “Add” button is obliged to call exactly it: it remains the only keyboard path.

vue
<template>
  <GrDashboardPalette :items="catalog" @add="place">
    <template #item="{ item, transferProps, add }">
      <div v-bind="transferProps" class="flex items-center justify-between gap-2">
        <span>{{ item.title }}</span>
        <GrButton size="sm" :disabled="item.disabled" @click="add">
          Add
        </GrButton>
      </div>
    </template>
  </GrDashboardPalette>
</template>
Limits

A tile is not dragged with a finger. Moving by touch requires a touch-action: none on the tile, and the catalogue is a vertical list, which on a phone is obliged to scroll. Taking the vertical axis away from a scroller for the sake of a gesture that already has a working equivalent is a bad trade; on touch input the button remains.