-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'latest' into taefi/fix-signals-dx-issues
- Loading branch information
Showing
5 changed files
with
288 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import 'Frontend/demo/init'; // hidden-source-line | ||
import '@vaadin/grid'; | ||
import '@vaadin/grid/vaadin-grid-selection-column.js'; | ||
import { html, LitElement } from 'lit'; | ||
import { customElement, state } from 'lit/decorators.js'; | ||
import type { GridItemToggleEvent } from '@vaadin/grid'; | ||
import { getPeople } from 'Frontend/demo/domain/DataService'; | ||
import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; | ||
import { applyTheme } from 'Frontend/generated/theme'; | ||
|
||
// tag::snippet[] | ||
@customElement('grid-range-selection') | ||
export class Example extends LitElement { | ||
protected override createRenderRoot() { | ||
const root = super.createRenderRoot(); | ||
// Apply custom theme (only supported if your app uses one) | ||
applyTheme(root); | ||
return root; | ||
} | ||
|
||
@state() | ||
private items: Person[] = []; | ||
|
||
@state() | ||
private selectedItems: Person[] = []; | ||
|
||
private rangeStartItem?: Person; | ||
|
||
protected override async firstUpdated() { | ||
const { people } = await getPeople(); | ||
this.items = people; | ||
} | ||
|
||
handleItemToggle(event: GridItemToggleEvent<Person>) { | ||
const { item, selected, shiftKey } = event.detail; | ||
|
||
// If the anchor point isn't set, set it to the current item | ||
this.rangeStartItem ??= item; | ||
|
||
if (shiftKey) { | ||
// Calculcate the range of items between the anchor point and | ||
// the current item | ||
const [rangeStart, rangeEnd] = [this.rangeStartItem, item] | ||
.map((i) => this.items.indexOf(i)) | ||
.sort((a, b) => a - b); | ||
const rangeItems = this.items.slice(rangeStart, rangeEnd + 1); | ||
|
||
// Update the selection state of items within the range | ||
// based on the state of the current item | ||
const newSelectedItems = new Set(this.selectedItems); | ||
rangeItems.forEach((rangeItem) => { | ||
if (selected) { | ||
newSelectedItems.add(rangeItem); | ||
} else { | ||
newSelectedItems.delete(rangeItem); | ||
} | ||
}); | ||
this.selectedItems = [...newSelectedItems]; | ||
} | ||
|
||
// Update the anchor point to the current item | ||
this.rangeStartItem = item; | ||
} | ||
|
||
protected override render() { | ||
return html` | ||
<vaadin-grid | ||
.items="${this.items}" | ||
.selectedItems="${this.selectedItems}" | ||
@item-toggle="${this.handleItemToggle}" | ||
> | ||
<vaadin-grid-selection-column></vaadin-grid-selection-column> | ||
<vaadin-grid-column path="firstName"></vaadin-grid-column> | ||
<vaadin-grid-column path="lastName"></vaadin-grid-column> | ||
<vaadin-grid-column path="email"></vaadin-grid-column> | ||
</vaadin-grid> | ||
`; | ||
} | ||
} | ||
// end::snippet[] |
66 changes: 66 additions & 0 deletions
66
frontend/demo/component/grid/react/grid-range-selection.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { reactExample } from 'Frontend/demo/react-example'; // hidden-source-line | ||
import React, { useCallback, useEffect, useRef } from 'react'; | ||
import { useSignals } from '@preact/signals-react/runtime'; // hidden-source-line | ||
import { useSignal } from '@vaadin/hilla-react-signals'; | ||
import { Grid, GridItemToggleEvent } from '@vaadin/react-components/Grid.js'; | ||
import { GridColumn } from '@vaadin/react-components/GridColumn.js'; | ||
import { GridSelectionColumn } from '@vaadin/react-components/GridSelectionColumn.js'; | ||
import { getPeople } from 'Frontend/demo/domain/DataService'; | ||
import type Person from 'Frontend/generated/com/vaadin/demo/domain/Person'; | ||
|
||
function Example() { | ||
useSignals(); // hidden-source-line | ||
const items = useSignal<Person[]>([]); | ||
const selectedItems = useSignal<Person[]>([]); | ||
const rangeStartItem = useRef<Person>(); | ||
|
||
useEffect(() => { | ||
getPeople().then(({ people }) => { | ||
items.value = people; | ||
}); | ||
}, []); | ||
|
||
const handleItemToggle = (event: GridItemToggleEvent<Person>) => { | ||
const { item, selected, shiftKey } = event.detail; | ||
|
||
// If the anchor point isn't set, set it to the current item | ||
rangeStartItem.current ??= item; | ||
|
||
if (shiftKey) { | ||
// Calculcate the range of items between the anchor point and | ||
// the current item | ||
const [rangeStart, rangeEnd] = [rangeStartItem.current, item] | ||
.map((i) => items.value.indexOf(i)) | ||
.sort((a, b) => a - b); | ||
const rangeItems = items.value.slice(rangeStart, rangeEnd + 1); | ||
|
||
// Update the selection state of items within the range | ||
// based on the state of the current item | ||
const newSelectedItems = new Set(selectedItems.value); | ||
rangeItems.forEach((rangeItem) => { | ||
if (selected) { | ||
newSelectedItems.add(rangeItem); | ||
} else { | ||
newSelectedItems.delete(rangeItem); | ||
} | ||
}); | ||
selectedItems.value = [...newSelectedItems]; | ||
} | ||
|
||
// Update the anchor point to the current item | ||
rangeStartItem.current = item; | ||
}; | ||
|
||
return ( | ||
// tag::snippet[] | ||
<Grid items={items.value} selectedItems={selectedItems.value} onItemToggle={handleItemToggle}> | ||
<GridSelectionColumn /> | ||
<GridColumn path="firstName" /> | ||
<GridColumn path="lastName" /> | ||
<GridColumn path="email" /> | ||
</Grid> | ||
// end::snippet[] | ||
); | ||
} | ||
|
||
export default reactExample(Example); // hidden-source-line |
71 changes: 71 additions & 0 deletions
71
src/main/java/com/vaadin/demo/component/grid/GridRangeSelection.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package com.vaadin.demo.component.grid; | ||
|
||
import java.util.List; | ||
|
||
import com.vaadin.demo.domain.Person; | ||
import com.vaadin.flow.component.grid.Grid; | ||
import com.vaadin.flow.component.grid.GridMultiSelectionModel; | ||
import com.vaadin.flow.component.grid.dataview.GridListDataView; | ||
import com.vaadin.flow.component.html.Div; | ||
import com.vaadin.flow.router.Route; | ||
import com.vaadin.demo.DemoExporter; // hidden-source-line | ||
import com.vaadin.demo.domain.DataService; | ||
|
||
@Route("grid-range-selection") | ||
public class GridRangeSelection extends Div { | ||
|
||
private Person rangeStartItem; | ||
|
||
public GridRangeSelection() { | ||
// tag::snippet[] | ||
Grid<Person> grid = new Grid<>(Person.class, false); | ||
grid.addColumn(Person::getFirstName).setHeader("First name"); | ||
grid.addColumn(Person::getLastName).setHeader("Last name"); | ||
grid.addColumn(Person::getEmail).setHeader("Email"); | ||
|
||
List<Person> people = DataService.getPeople(); | ||
grid.setItems(people); | ||
|
||
GridMultiSelectionModel<Person> selectionModel = (GridMultiSelectionModel<Person>) grid | ||
.setSelectionMode(Grid.SelectionMode.MULTI); | ||
|
||
selectionModel.addClientItemToggleListener(event -> { | ||
Person item = event.getItem(); | ||
|
||
// If the anchor point isn't set, set it to the current item | ||
if (rangeStartItem == null) { | ||
rangeStartItem = item; | ||
} | ||
|
||
if (event.isShiftKey()) { | ||
// Calculcate the range of items between the anchor | ||
// point and the current item | ||
GridListDataView<Person> dataView = grid.getListDataView(); | ||
int rangeStart = dataView.getItemIndex(rangeStartItem).get(); | ||
int rangeEnd = dataView.getItemIndex(item).get(); | ||
Person[] rangeItems = dataView.getItems() | ||
.skip(Math.min(rangeStart, rangeEnd)) | ||
.limit(Math.abs(rangeStart - rangeEnd) + 1) | ||
.toArray(Person[]::new); | ||
|
||
// Update the selection state of items within the range | ||
// based on the state of the current item | ||
if (event.isSelected()) { | ||
selectionModel.selectItems(rangeItems); | ||
} else { | ||
selectionModel.deselectItems(rangeItems); | ||
} | ||
} | ||
|
||
// Update the anchor point to the current item | ||
rangeStartItem = item; | ||
}); | ||
// end::snippet[] | ||
|
||
add(grid); | ||
} | ||
|
||
public static class Exporter // hidden-source-line | ||
extends DemoExporter<GridRangeSelection> { // hidden-source-line | ||
} // hidden-source-line | ||
} |