GrDashboardPalette

  • dashboard
  • Дашборд
  • API · 5 props

Берут, когда набор виджетов выбирает пользователь.

import { GrDashboardPalette } from '@feugene/granularity-dashboard/components/GrDashboardPalette'

Обзор

Когда брать

  • набор виджетов выбирает пользователь — дашборд собирается из каталога, а не приходит готовым;
  • доступное зависит от роли или тарифа — список приходит пропом, и недоступное просто не попадает в него;
  • карточка каталога нестандартная — слот item рисует иконку, описание, превью;
  • добавлять пока нечего — слот empty объясняет почему, вместо пустого прямоугольника.

Когда взять другое

НужноБерите
Выбрать один вариант из спискаGrSelect
Найти команду или объект поискомGrCommandPalette
Показать список без добавленияGrList
Объяснить, что дашборд пустGrEmptyState
Сама сеткаGrDashboard

Несмотря на название, это не GrCommandPalette: там ищут команду по всему приложению вводом с клавиатуры, здесь выбирают виджет из короткого известного набора.

Примеры 2 у каждого — живое демо и его код

  • Доска, собранная из каталога

    Добавьте виджет кнопкой или перетащите плитку на сетку: droppable показывает, куда она встанет. Каталог лишь говорит, что добавить, — add для кнопки, item-drop у сетки с ячейкой и опциями, — а кладёт виджет страница через addItem. То, что уже на доске, остаётся в списке как «Added», а minW едет вместе с плиткой.

    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
  • Плитки с иконками и тарифами

    Слот item рисует свою плитку — иконку, описание, бейдж тарифа, — а transferProps вешается на её корень, без него плитку не перетащить. Кнопка «Add» остаётся в плитке: это клавиатурный путь, а перетаскивание — лишь усиление. Она зовёт add из слота, и каталог эмитит add и объявляет виджет, как со своей плиткой. ghost решает, что тянется за курсором.

    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 порождается из пакета · разойтись не может

Props

PropTypeпо умолчаниюОписание
draggableboolean | undefinedundefinedПлитку можно перетащить на сетку. Кнопка «Добавить» остаётся при любом значении: она и есть контракт и единственный клавиатурный путь. Сетка, слушающая `itemDrop`, положит брошенное — не слушающая покажет подложку и ничего не сделает.
size"lg" | "xs" | "sm" | "md" | undefinedundefinedСтупень размера: кегль плиток и кнопок добавления. По умолчанию `md`; берётся из `GrConfigProvider`.
disabledboolean | undefinedfalseКаталог недоступен: кнопки «Добавить» выключены, плитки не перетаскиваются.
ariaLabelstring | undefined—Имя списка плиток. Не задано — из локали («Widget catalog»).
itemsобязательныйGrDashboardPaletteItem[]—Каталог доступных виджетов.

Слоты

SlotTypeОписание
item
{ item: GrDashboardPaletteItem; dragging: boolean; transferP{ item: GrDashboardPaletteItem; dragging: boolean; transferProps: { onPointerdown: (event: PointerEvent) => void; }; add: () => void; }
Своя плитка. `transferProps` навешивается на её корень (`v-bind`) — без этого перетащить свою разметку нечем, а слот существует ровно ради неё.
ghost{ item: GrDashboardPaletteItem; }Что рисуется под курсором во время переноса.
emptyanyЧто показать, когда каталог пуст.

События

EventСигнатураОписание
add(event: "add", item: GrDashboardPaletteItem): void—

Типы

Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.

Импорт
import type { GrDashboardPaletteConfigurableProps, GrDashboardPaletteSize, GrDashboardPaletteItem } from '@feugene/granularity-dashboard/components/GrDashboardPalette'

Файлdist/types/components/GrDashboardPalette/config.d.ts

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

Файлdist/types/components/GrDashboardPalette/defaults.d.ts

GrDashboardPaletteConfigurablePropsinterface

Пропы GrDashboardPalette, настраиваемые глобально.

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

Файлdist/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;
}

Файлdist/types/components/GrDashboardPalette/safelist.d.ts

grDashboardPaletteSafelistconst
const grDashboardPaletteSafelist: string[];

Файлdist/types/components/GrDashboardPalette/GrDashboardPalette.vue.d.ts

GrDashboardPalettePropsinterface
interface GrDashboardPaletteProps {
    /** Каталог доступных виджетов. */
    items: GrDashboardPaletteItem[];
    /**
     * Ступень размера: кегль плиток и кнопок добавления. По умолчанию `md`; берётся из
     * `GrConfigProvider`.
     */
    size?: GrDashboardPaletteSize;
    /**
     * Плитку можно перетащить на сетку.
     *
     * Кнопка «Добавить» остаётся при любом значении: она и есть контракт и
     * единственный клавиатурный путь. Сетка, слушающая `itemDrop`, положит
     * брошенное — не слушающая покажет подложку и ничего не сделает.
     */
    draggable?: boolean;
    /** Каталог недоступен: кнопки «Добавить» выключены, плитки не перетаскиваются. */
    disabled?: boolean;
    /** Имя списка плиток. Не задано — из локали («Widget catalog»). */
    ariaLabel?: string;
}
GrDashboardPaletteEmitsinterface
interface GrDashboardPaletteEmits {
    /** Нажата кнопка «Добавить»: положить виджет в раскладку — дело приложения. */
    (e: 'add', item: GrDashboardPaletteItem): void;
}

Использование из прозы библиотеки

Куда встаёт добавленный виджет — решает приложение

Компонент излучает намерение с описанием виджета, а координаты назначает потребитель: он один знает, добавлять новый виджет вниз, в первое свободное место или на позицию, с которой пользователь начал. Класть его «куда-нибудь» означало бы портить раскладку, которую человек только что собрал.

Перетаскивание — усиление, а не контракт

Плитку можно перетащить на сетку (draggable, включено по умолчанию), но кнопка «Добавить» при этом остаётся и остаётся единственным клавиатурным путём. Сделай перетаскивание контрактом — и каталогом нельзя пользоваться с клавиатуры, а «доступность потом» здесь не наступает.

Куда бросили, сообщает сетка эмитом itemDrop, и кладёт по-прежнему приложение — ровно как по кнопке. Сетка, которая itemDrop не слушает, покажет подложку и по отпусканию не сделает ничего: либо обработайте событие, либо выключите draggable.

Нажатие на саму кнопку переносом не становится: иначе дрогнувшая на пять пикселей рука давала бы перенос вместо добавления.

Своя плитка — слот #item

Слот получает item, dragging, transferProps и add. transferProps навешивается на корень плитки — без него свою разметку не перетащить. add — тот же путь, что у встроенной кнопки: эмит add и объявление «добавлено» скринридеру, у выключенной плитки — ничего. Своя кнопка «Добавить» обязана звать именно его: она остаётся единственным клавиатурным путём.

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">
          Добавить
        </GrButton>
      </div>
    </template>
  </GrDashboardPalette>
</template>
Границы

Пальцем плитка не тащится. Перенос касанием требует touch-action: none на плитке, а каталог — вертикальный список, который на телефоне обязан прокручиваться. Отбирать у скроллера вертикальную ось ради жеста, у которого уже есть работающий эквивалент, — плохой обмен; на сенсорном вводе остаётся кнопка.