npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@gravity-ui/dashkit

v8.20.0

Published

Library for rendering dashboard grid layout

Downloads

3,450

Readme

@gravity-ui/dashkit · npm package CI storybook

DashKit

A dashboard grid rendering library.

Installation

npm i @gravity-ui/dashkit @gravity-ui/uikit

Description

The library is used to line up widgets in a grid, resize them, add new ones, and delete them. The widget is a react component. For example, text, graphics, and images.

New widgets are added via a plugin system.

Plugins

Plugins are required to create custom widgets.

Props

type ItemManipulationCallback = (eventData: {
    layout: Layouts;
    oldItem: Layout;
    newItem: Layout;
    placeholder: Layout;
    e: MouseEvent;
    element: HTMLElement;
}) => void;

interface DashKitProps {
  config: Config;
  editMode: boolean;
  onItemEdit: ({id}: {id: string}) => void;
  onChange: (data: {config: Config; itemsStateAndParams: ItemsStateAndParams}) => void;
  onDrop: (dropProps: ItemDropProps) => void;
  onItemMountChange: (item: ConfigItem, state: {isAsync: boolead; isMounted: boolean}) => void;
  onItemRender: (item: ConfigItem) => void;

  onDragStart?: ItemManipulationCallback;
  onDrag?: ItemManipulationCallback;
  onDragStop?: ItemManipulationCallback;
  onResizeStart?: ItemManipulationCallback;
  onResize?: ItemManipulationCallback;
  onResizeStop?: ItemManipulationCallback;

  defaultGlobalParams: GlobalParams;
  globalParams: GlobalParams;
  itemsStateAndParams: ItemsStateAndParams;
  settings: SettingsProps;
  context: ContextProps;
  overlayControls?: Record<string, OverlayControlItem[]> | null;
  overlayMenuItems?: MenuItems[] | null;
  noOverlay?: boolean;
  focusable?: boolean;
  draggableHandleClassName?: string;
  getPreparedCopyItemOptions?: (options: PreparedCopyItemOptions) => PreparedCopyItemOptions;
  onCopyFulfill?: (error: null | Error, data?: PreparedCopyItemOptions) => void;
}
  • config: сonfig.
  • editMode: Whether edit mode is enabled.
  • onItemEdit: Called when you click to edit a widget.
  • onChange: Called when config or itemsStateAndParams are changed.
  • onDrop: Called when item dropped from ActionPanel using (#DashKitDnDWrapper)
  • onItemMountChange: Called when item mount state changed
  • onItemRender: Called when item render complete
  • defaultGlobalParams, globalParams: Parameters that affect all widgets. In DataLens, defaultGlobalParams are global parameters set in the dashboard settings. globalParams are globals parameters that can be set in the url.
  • itemsStateAndParams: itemsStateAndParams.
  • settings: DashKit settings.
  • context: Object that will be propped up on all widgets.
  • overlayControls: Object that overrides widget controls at the time of editing. If not transmitted, basic controls will be displayed. If null passed only close button or custom menu will be displayed.
  • overlayMenuItems: Custom dropdown menu items
  • noOverlay: If true, overlay and controls are not displayed while editing.
  • focusable: If true, grid items will be focusable.
  • draggableHandleClassName : СSS class name of the element that makes the widget draggable.
  • onDragStart: ReactGridLayout called when item drag started
  • onDrag: ReactGridLayout called while item drag
  • onDragStop: ReactGridLayout called when item drag stopped
  • onResizeStart: ReactGridLayout called when item resize started
  • onResize: ReactGridLayout called while item resizing
  • onResizeStop: ReactGridLayout called when item resize stoped
  • getPreparedCopyItemOptions: Called for converting copied item to serializable object before saving it to localstorage. It should be used instead of deprecated context.getPreparedCopyItemOptions prop
  • onCopyFulfill: Called when item copy finished with error=null and defined data on successful operation done and with error: Error without data otherwise

Usage

DashKit configuration

Before using DashKit as a react component, it must be configured.

  • set language

    import {configure, Lang} from '@gravity-ui/uikit';
    
    configure({lang: Lang.En});
  • DashKit.setSettings

    Used for global DashKit settings (such as margins between widgets, default widget sizes and widget overlay menu)

    import {DashKit} from '@gravity-ui/dashkit';
    
    DashKit.setSettings({
      gridLayout: {margin: [8, 8]},
      isMobile: true,
      // menu: [] as Array<MenuItem>,
    });
  • DashKit.registerPlugins

    Registering and configuring plugins

    import {DashKit} from '@gravity-ui/dashkit';
    import {pluginTitle, pluginText} from '@gravity-ui/dashkit';
    
    DashKit.registerPlugins(
      pluginTitle,
      pluginText.setSettings({
        apiHandler({text}) {
          return api.getMarkdown(text);
        },
      }),
    );
    
    DashKit.registerPlugins({
      type: 'custom',
      defaultLayout: {
        w: 10,
        h: 8,
      },
      renderer: function CustomPlugin() {
        return <div>Custom widget with custom controls</div>;
      },
    });

Config

export interface Config {
  salt: string; // to form a unique id
  counter: number; // to form a unique id, only increases
  items: ConfigItem[]; //  initial widget states
  layout: ConfigLayout[]; // widget position on the grid https://github.com/react-grid-layout
  aliases: ConfigAliases; // aliases for parameters see #Params
  connections: ConfigConnection[]; // links between widgets see #Params
}

Config example:

import {DashKitProps} from '@gravity-ui/dashkit';

const config: DashKitProps['config'] = {
  salt: '0.46703554571365613',
  counter: 4,
  items: [
    {
      id: 'tT',
      data: {
        size: 'm',
        text: 'Caption',
        showInTOC: true,
      },
      type: 'title',
      namespace: 'default',
      orderId: 1,
    },
    {
      id: 'Ea',
      data: {
        text: 'mode _editActive',
        _editActive: true,
      },
      type: 'text',
      namespace: 'default',
    },
    {
      id: 'zR',
      data: {
        text: '### Text',
      },
      type: 'text',
      namespace: 'default',
      orderId: 0,
    },
    {
      id: 'Dk',
      data: {
        foo: 'bar',
      },
      type: 'custom',
      namespace: 'default',
      orderId: 5,
    },
  ],
  layout: [
    {
      h: 2,
      i: 'tT',
      w: 36,
      x: 0,
      y: 0,
    },
    {
      h: 6,
      i: 'Ea',
      w: 12,
      x: 0,
      y: 2,
    },
    {
      h: 6,
      i: 'zR',
      w: 12,
      x: 12,
      y: 2,
    },
    {
      h: 4,
      i: 'Dk',
      w: 8,
      x: 0,
      y: 8,
    },
  ],
  aliases: {},
  connections: [],
};

Add a new item to the config:

const newLayout = updateLayout: [
  {
    h: 6,
    i: 'Ea',
    w: 12,
    x: 0,
    y: 6,
  },
  {
    h: 4,
    i: 'Dk',
    w: 8,
    x: 0,
    y: 12,
  },
];

const newConfig = DashKit.setItem({
  item: {
    data: {
      text: `Some text`,
    },
    namespace: 'default',
    type: 'text',
    // Optional. If new item needed to be inserted in current layout with predefined dimensions
    layout: { // Current item inseterted before 'Ea'
      h: 6,
      w: 12,
      x: 0,
      y: 2,
    },,
  },
  config: config,
  options: {
    // Optional. New layout values for existing items when new element is dropped from ActionPanel
    updateLayout: newLayout,
  },
});

Change an existing item in the config:

const newConfig = DashKit.setItem({
  item: {
    id: 'tT', // item.id
    data: {
      size: 'm',
      text: `New caption`,
    },
    namespace: 'default',
    type: 'title',
  },
  config: config,
});

Delete an item from the config:

import {DashKitProps} from '@gravity-ui/dashkit';

const oldItemsStateAndParams: DashKitProps['itemsStateAndParams'] = {};

const {config: newConfig, itemsStateAndParams} = DashKit.removeItem({
  id: 'tT', // item.id
  config: config,
  itemsStateAndParams: this.state.itemsStateAndParams,
});

Params

type Params = Record<string, string | string[]>;

DashKit generates parameters according to the default parameters for widgets, links, and aliases. These parameters are required for the ChartKit library.

Generation order:

  1. defaultGlobalParams
  2. Default widget parameters item.default
  3. globalParams
  4. Parameters from itemsStateAndParams according to the queue.

itemsStateAndParams

Object that stores widget parameters and states as well as a parameter change queue. It has a __meta__ field for storing queue and meta information.

interface StateAndParamsMeta = {
    __meta__: {
        queue: {id: string}[]; // queue
        version: number; // current version itemsStateAndParams
    };
}

And also widget states and parameters:

interface ItemsStateAndParamsBase {
  [itemId: string]: {
    state?: Record<string, any>;
    params?: Params;
  };
}
type ItemsStateAndParams = StateAndParamsMeta & ItemsStateAndParamsBase;

Menu

You can specify custom DashKit widget overlay menu in edit mode

type MenuItem = {
  id: string; // uniq id
  title?: string; // string title
  icon?: ReactNode; // node of icon
  iconSize?: number | string; // icon size in px as number or as string with units
  handler?: (item: ConfigItem) => void; // custom item action handler
  visible?: (item: ConfigItem) => boolean; // optional visibility handler for filtering menu items
  className?: string; // custom class property
};

// use array of menu items in settings
<Dashkit overlayMenuItems={[] as Array<MenuItem> | null} />

[deprecated]
// overlayMenuItems property has greater priority over setSettings menu
DashKit.setSettings({menu: [] as Array<MenuItem>});

Draggable items from ActionPanel

DashKitDnDWrapper

type DraggedOverItem = {
  h: number;
  w: number;
  type: string;
  parent: string;
  i?: number;
};

interface DashKitDnDWrapperProps {
  dragImageSrc?: string;
  onDragStart?: (dragProps: ItemDragProps) => void;
  onDragEnd?: () => void;
  onDropDragOver?: (draggedItem: DraggedOverItem, sharedItem: DraggedOverItem | null) => void | boolean;
}
  • dragImageSrc: Drag image preview, by default used transparent 1px png base64
  • onDragStart: Callback called when element is dragged from ActionPanel
  • onDragEnd: Callback called when element dropped or drag canceled
type ItemDragProps = {
    type: string; // Plugin type
    layout?: { // Optional. Layout item size for preview and init
        w?: number;
        h?: number;
    };
    extra?: any; // Custom user context
};
type ItemDropProps = {
    commit: () => void; // Callback should be called after all config operations are made
    dragProps: ItemDragProps; // Item drag props
    itemLayout: ConfigLayout; // Calculated item layout dimensions
    newLayout: ConfigLayout[]; // New layout after element is dropped
};

Example:

const overlayMenuItems = [
  {
    id: 'chart',
    icon: <Icon data={ChartColumn} />,
    title: 'Chart',
    qa: 'chart',
    dragProps: { // ItemDragProps
        type: 'custom', // Registered plugin type
    },
  }
]

const onDrop = (dropProps: ItemDropProps) => {
  // ... add element to your config
  dropProps.commit();
}

<DashKitDnDWrapper>
  <DashKit editMode={true} config={config} onChange={onChange} onDrop={onDrop} />
  <ActionPanel items={overlayMenuItems} />
</DashKitDnDWrapper>

CSS API

| Name | Description | | :--------------------------------------------- | :-------------------- | | Action panel variables | | | --dashkit-action-panel-color | Background color | | --dashkit-action-panel-border-color | Border color | | --dashkit-action-panel-border-radius | Border radius | | Action panel item variables | | | --dashkit-action-panel-item-color | Backgroud color | | --dashkit-action-panel-item-text-color | Text color | | --dashkit-action-panel-item-color-hover | Hover backgroud color | | --dashkit-action-panel-item-text-color-hover | Hover text color | | Overlay variables | | | --dashkit-overlay-border-color | Border color | | --dashkit-overlay-color | Background color | | --dashkit-overlay-opacity | Opacity | | Grid item variables | | | --dashkit-grid-item-edit-opacity | Opacity | | --dashkit-grid-item-border-radius | Border radius | | Placeholder variables | | | --dashkit-placeholder-color | Background color | | --dashkit-placeholder-opacity | Opacity |

Usage example

.custom-theme-wrapper {
  --dashkit-grid-item-edit-opacit: 1;
  --dashkit-overlay-color: var(--g-color-base-float);
  --dashkit-overlay-border-color: var(--g-color-base-float);
  --dashkit-overlay-opacity: 0.5;

  --dashkit-action-panel-border-color: var(--g-color-line-info);
  --dashkit-action-panel-color: var(--g-color-base-float-accent);
  --dashkit-action-panel-border-radius: var(--g-border-radius-xxl);
}
// ....

const CustomThemeWrapper = (props: {
  dashkitProps: DashkitProps;
  actionPanelProps: ActionPanelProps;
}) => {
  return (
    <div className="custom-theme-wrapper">
      <Dashkit {...props.dashkitProps} />
      <ActionPanel {...props.actionPanelProps} />
    </div>
  );
};

Development

Build & watch

  • Build dependencies npm ci
  • Build a project npm run build
  • Build storybook npm run start

By default, storybook runs on http://localhost:7120/. New changes from a project aren't always picked up when storybook is running, so it's better to rebuild a project manually and restart storybook.

Example of an nginx config for development on a dev machine

server {
    server_name dashkit.username.ru;

    include common/ssl;

    access_log /home/username/logs/common.access.log;
    error_log /home/username/logs/common.error.log;

    root /home/username/projects/dashkit;

    location / {
        try_files $uri @node;
    }

    location @node {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:7120;
        proxy_redirect off;
    }
}