import type { ColumnFilterConfig, ColumnRegular, ColumnTypes } from '@revolist/revogrid';
import NumberColumnType from '@revolist/revogrid-column-numeral';
import {
AdvanceFilterPlugin,
ColumnDropdown,
ColumnStretchPlugin,
RowOddPlugin,
columnTypeRenderer,
} from '@revolist/revogrid-pro';
type FilterSelectionFruit = {
name: string;
emoji: string;
family: string;
color: string;
availability: AvailabilityValue;
};
type AvailabilityValue = 'In stock' | 'Backorder' | 'Seasonal';
export type FilterSelectionRow = {
id: number;
name: string;
fruitFamily: string;
fruitColor: string;
availability: AvailabilityValue;
price: number;
};
export const filterSelectionPlugins = [
AdvanceFilterPlugin,
ColumnStretchPlugin,
RowOddPlugin,
];
export const filterSelectionColumnTypes: ColumnTypes = {
currency: new NumberColumnType('$0,0.00'),
dropdown: ColumnDropdown,
};
const FRUITS: FilterSelectionFruit[] = [
{ name: 'Apple', emoji: '🍎', family: 'Tree fruit', color: 'Red', availability: 'In stock' },
{ name: 'Pear', emoji: '🍐', family: 'Tree fruit', color: 'Green', availability: 'In stock' },
{ name: 'Peach', emoji: '🍑', family: 'Stone fruit', color: 'Orange', availability: 'Seasonal' },
{ name: 'Cherry', emoji: '🍒', family: 'Stone fruit', color: 'Red', availability: 'Seasonal' },
{ name: 'Orange', emoji: '🍊', family: 'Citrus', color: 'Orange', availability: 'In stock' },
{ name: 'Lemon', emoji: '🍋', family: 'Citrus', color: 'Yellow', availability: 'Backorder' },
{ name: 'Mango', emoji: '🥭', family: 'Tropical', color: 'Orange', availability: 'Backorder' },
{ name: 'Banana', emoji: '🍌', family: 'Tropical', color: 'Yellow', availability: 'In stock' },
{ name: 'Strawberry', emoji: '🍓', family: 'Berries', color: 'Red', availability: 'Seasonal' },
{ name: 'Grapes', emoji: '🍇', family: 'Berries', color: 'Purple', availability: 'Backorder' },
];
const AVAILABILITY_OPTIONS = [
{ value: 'In stock', label: 'In stock', tone: 'stock' },
{ value: 'Backorder', label: 'Backorder', tone: 'backorder' },
{ value: 'Seasonal', label: 'Seasonal', tone: 'seasonal' },
];
function normalizeFruitValue(fruit: FilterSelectionFruit) {
return `${fruit.name} ${fruit.emoji}`.toLowerCase();
}
function availabilityTone(value: unknown) {
const option = AVAILABILITY_OPTIONS.find((item) => item.value === value || item.label === value);
return option?.tone ?? 'stock';
}
export function renderAvailabilityBadge(h: any, value: unknown) {
const label = String(value || 'In stock');
return h(
'span',
{
class: `filter-selection-availability-badge filter-selection-availability-badge--${availabilityTone(label)}`,
},
label,
);
}
function renderFruitLabel(h: any, label: string) {
const [name, emoji = ''] = label.split(' ');
return h('span', { class: 'filter-selection-fruit-option' }, [
h('span', { class: 'filter-selection-fruit-option__emoji' }, emoji),
h('span', { class: 'filter-selection-fruit-option__label' }, name),
]);
}
export function createFilterSelectionRows(count = 80): FilterSelectionRow[] {
return Array.from({ length: count }, (_, index) => {
const fruit = FRUITS[index % FRUITS.length];
return {
id: index + 1,
name: `${fruit.name} ${fruit.emoji}`,
fruitFamily: fruit.family,
fruitColor: fruit.color,
availability: fruit.availability,
price: 5 + ((index * 7) % 24),
};
});
}
export function createFilterSelectionColumns(): ColumnRegular[] {
return [
{
name: 'Fruit',
prop: 'name',
size: 220,
filter: ['string', 'selection'],
columnType: 'string',
columnTemplate: columnTypeRenderer,
},
{
name: 'Availability',
prop: 'availability',
size: 180,
filter: ['selection'],
columnType: 'dropdown',
columnTemplate: columnTypeRenderer,
cellTemplate: ColumnDropdown.cellTemplate,
cellProperties: ColumnDropdown.cellProperties,
readonly: true,
dropdown: {
source: AVAILABILITY_OPTIONS,
renderSelectedValue: (h, selectedOptions, children) =>
h('span', null, [
renderAvailabilityBadge(h, selectedOptions[0]?.label ?? selectedOptions[0]?.value),
children,
]),
renderOption: (h, option) => renderAvailabilityBadge(h, option.label),
},
},
{
name: 'Price',
prop: 'price',
size: 110,
filter: 'number',
columnType: 'currency',
columnTemplate: columnTypeRenderer,
},
];
}
export function createFilterSelectionFilter(): {
multiFilterItems: any;
expressions: ColumnFilterConfig['expressions'];
localization: {
captions: Record<string, string>;
};
selection: {
sortDirection: 'asc';
grouping: Record<string, { props: string[]; expandedAll: boolean }>;
getItems: Record<string, () => any[]>;
itemTemplate: Record<string, (h: any, props: any) => any>;
};
} {
return {
multiFilterItems: {
name: [
{
id: 0,
type: 'selection',
value: new Set([
normalizeFruitValue(FRUITS[7]),
normalizeFruitValue(FRUITS[5]),
]),
relation: 'and',
hidden: true,
},
],
},
expressions: {
enabled: true,
buttonLabel: 'Expression',
placeholder: [
'in ("Apple 🍎", "Orange 🍊")',
'not in ("Banana 🍌", "Lemon 🍋")',
'contains "berry" OR contains "citrus"',
].join('\n'),
},
localization: {
captions: {
expressionButton: 'Expression',
expressionTitle: 'Filter expression',
expressionPlaceholder: 'Type a filter expression',
expressionApply: 'Apply expression',
expressionInvalid: 'Fix the expression before applying.',
},
},
selection: {
sortDirection: 'asc',
grouping: {
name: {
props: ['fruitFamily', 'fruitColor'],
expandedAll: true,
},
},
getItems: {
name: () =>
FRUITS.map((fruit) => ({
value: normalizeFruitValue(fruit),
label: `${fruit.name} ${fruit.emoji}`,
fruitFamily: fruit.family,
fruitColor: fruit.color,
})),
availability: () => AVAILABILITY_OPTIONS,
},
itemTemplate: {
name: (h, { label }) => renderFruitLabel(h, label),
availability: (h, { label }) => renderAvailabilityBadge(h, label),
},
},
};
}