Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support drag-reordering of dashboard items #7738

Merged
merged 13 commits into from
Sep 5, 2024
16 changes: 15 additions & 1 deletion dev/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,24 @@
</vaadin-dashboard-widget>
`;
};

dashboard.addEventListener('dashboard-item-reorder-start', (e) => {
console.log('dashboard-item-reorder-start');
});

dashboard.addEventListener('dashboard-item-drag-reorder', (e) => {
console.log('dashboard-item-drag-reorder', e.detail);
// e.preventDefault();
});

dashboard.addEventListener('dashboard-item-reorder-end', (e) => {
console.log('dashboard-item-reorder-end');
console.log('items after reorder', e.target.items);
});
</script>
</head>

<body>
<vaadin-dashboard></vaadin-dashboard>
<vaadin-dashboard editable></vaadin-dashboard>
</body>
</html>
95 changes: 52 additions & 43 deletions packages/dashboard/src/vaadin-dashboard-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
import { css } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import { TitleController } from './title-controller.js';
import { dashboardWidgetAndSectionStyles, hasWidgetWrappers } from './vaadin-dashboard-styles.js';

/**
* A section component for use with the Dashboard component
Expand All @@ -30,48 +31,54 @@ class DashboardSection extends ControllerMixin(ElementMixin(PolylitMixin(LitElem
}

static get styles() {
return css`
:host {
display: grid;
grid-template-columns: subgrid;
--_vaadin-dashboard-section-column: 1 / calc(var(--_vaadin-dashboard-effective-col-count) + 1);
grid-column: var(--_vaadin-dashboard-section-column) !important;
gap: var(--vaadin-dashboard-gap, 1rem);
/* Dashbaord section header height */
--_vaadin-dashboard-section-header-height: minmax(0, auto);
grid-template-rows: var(--_vaadin-dashboard-section-header-height) repeat(
auto-fill,
var(--_vaadin-dashboard-row-height)
);
grid-auto-rows: var(--_vaadin-dashboard-row-height);
}

:host([hidden]) {
display: none !important;
}

::slotted(*) {
--_vaadin-dashboard-title-level: 3;
--_vaadin-dashboard-item-column: span
min(
var(--vaadin-dashboard-item-colspan, 1),
var(--_vaadin-dashboard-effective-col-count, var(--_vaadin-dashboard-col-count))
);

grid-column: var(--_vaadin-dashboard-item-column);
}

::slotted(vaadin-dashboard-widget-wrapper) {
display: contents;
}

header {
display: flex;
grid-column: var(--_vaadin-dashboard-section-column);
justify-content: space-between;
align-items: center;
}
`;
return [
css`
:host {
display: grid;
position: relative;
grid-template-columns: subgrid;
--_vaadin-dashboard-section-column: 1 / calc(var(--_vaadin-dashboard-effective-col-count) + 1);
grid-column: var(--_vaadin-dashboard-section-column) !important;
gap: var(--vaadin-dashboard-gap, 1rem);
/* Dashbaord section header height */
--_vaadin-dashboard-section-header-height: minmax(0, auto);
grid-template-rows: var(--_vaadin-dashboard-section-header-height) repeat(
auto-fill,
var(--_vaadin-dashboard-row-height)
);
grid-auto-rows: var(--_vaadin-dashboard-row-height);
}

:host([hidden]) {
display: none !important;
}

:host([highlight]) {
background-color: #f5f5f5;
}

::slotted(*) {
--_vaadin-dashboard-title-level: 3;
--_vaadin-dashboard-item-column: span
min(
var(--vaadin-dashboard-item-colspan, 1),
var(--_vaadin-dashboard-effective-col-count, var(--_vaadin-dashboard-col-count))
);

grid-column: var(--_vaadin-dashboard-item-column);
}

header {
grid-column: var(--_vaadin-dashboard-section-column);
}

:host::before {
z-index: 2 !important;
}
`,
hasWidgetWrappers,
dashboardWidgetAndSectionStyles,
];
}

static get properties() {
Expand All @@ -92,7 +99,9 @@ class DashboardSection extends ControllerMixin(ElementMixin(PolylitMixin(LitElem
return html`
<header>
<slot name="title" @slotchange="${this.__onTitleSlotChange}"></slot>
<div id="header-actions"></div>
<div id="header-actions">
<span id="drag-handle" draggable="true" class="drag-handle"></span>
</div>
</header>

<slot></slot>
Expand Down
37 changes: 37 additions & 0 deletions packages/dashboard/src/vaadin-dashboard-styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { css } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';

export const hasWidgetWrappers = css`
::slotted(vaadin-dashboard-widget-wrapper) {
display: contents;
}
`;

export const dashboardWidgetAndSectionStyles = css`
/* Placeholder shown while the widget or section is dragged */
:host::before {
content: '';
z-index: 1;
position: absolute;
display: var(--_vaadin-dashboard-item-placeholder-display, none);
inset: 0;
border: 3px dashed black;
border-radius: 5px;
background-color: #fff;
}

header {
display: flex;
justify-content: space-between;
align-items: center;
}

#header-actions {
display: var(--_vaadin-dashboard-widget-actions-display, none);
}

#drag-handle::before {
font-size: 30px;
content: '☰';
cursor: grab;
}
`;
45 changes: 23 additions & 22 deletions packages/dashboard/src/vaadin-dashboard-widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
import { css } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import { TitleController } from './title-controller.js';
import { dashboardWidgetAndSectionStyles } from './vaadin-dashboard-styles.js';

/**
* A Widget component for use with the Dashboard component
Expand All @@ -30,27 +31,25 @@ class DashboardWidget extends ControllerMixin(ElementMixin(PolylitMixin(LitEleme
}

static get styles() {
return css`
:host {
display: flex;
flex-direction: column;
grid-column: var(--_vaadin-dashboard-item-column);
}

:host([hidden]) {
display: none !important;
}

header {
display: flex;
justify-content: space-between;
align-items: center;
}

#content {
flex: 1;
}
`;
return [
css`
:host {
display: flex;
flex-direction: column;
grid-column: var(--_vaadin-dashboard-item-column);
position: relative;
}

:host([hidden]) {
display: none !important;
}

#content {
flex: 1;
}
`,
dashboardWidgetAndSectionStyles,
];
}

static get properties() {
Expand All @@ -72,7 +71,9 @@ class DashboardWidget extends ControllerMixin(ElementMixin(PolylitMixin(LitEleme
<header>
<slot name="title" @slotchange="${this.__onTitleSlotChange}"></slot>
<slot name="header"></slot>
<div id="header-actions"></div>
<div id="header-actions">
<span id="drag-handle" draggable="true" class="drag-handle"></span>
</div>
</header>

<div id="content">
Expand Down
47 changes: 46 additions & 1 deletion packages/dashboard/src/vaadin-dashboard.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export interface DashboardSectionItem<TItem extends DashboardItem> {
/**
* The title of the section
*/
title: string | null | undefined;
title?: string | null;

/**
* The items of the section
Expand All @@ -42,6 +42,34 @@ export type DashboardRenderer<TItem extends DashboardItem> = (
model: DashboardItemModel<TItem>,
) => void;

/**
* Fired when item reordering starts
*/
export type DashboardItemReorderStartEvent = CustomEvent;

/**
* Fired when item reordering ends
*/
export type DashboardItemReorderEndEvent = CustomEvent;

/**
* Fired when an items will be reordered by dragging
*/
export type DashboardItemDragReorderEvent<TItem extends DashboardItem> = CustomEvent<{
item: TItem | DashboardSectionItem<TItem>;
targetIndex: number;
}>;

export interface DashboardCustomEventMap<TItem extends DashboardItem> {
'dashboard-item-reorder-start': DashboardItemReorderStartEvent;

'dashboard-item-reorder-end': DashboardItemReorderEndEvent;

'dashboard-item-drag-reorder': DashboardItemDragReorderEvent<TItem>;
}

export type DashboardEventMap<TItem extends DashboardItem> = DashboardCustomEventMap<TItem> & HTMLElementEventMap;

/**
* A responsive, grid-based dashboard layout component
*/
Expand All @@ -65,6 +93,23 @@ declare class Dashboard<TItem extends DashboardItem = DashboardItem> extends Das
* - `model.item` The item.
*/
renderer: DashboardRenderer<TItem> | null | undefined;

/**
* Whether the dashboard is editable.
*/
editable: boolean;

addEventListener<K extends keyof DashboardEventMap<TItem>>(
type: K,
listener: (this: Dashboard, ev: DashboardEventMap<TItem>[K]) => void,
options?: AddEventListenerOptions | boolean,
): void;

removeEventListener<K extends keyof DashboardEventMap<TItem>>(
type: K,
listener: (this: Dashboard, ev: DashboardEventMap<TItem>[K]) => void,
options?: EventListenerOptions | boolean,
): void;
}

declare global {
Expand Down
Loading
Loading