Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/itchy-moments-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"sit-onyx": minor
---

Implemented basic expandable row feature for DataGrid
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script setup lang="ts">
import { h } from "vue";
import { OnyxDataGrid, OnyxHeadline, type ColumnConfig } from "../../../index.js";
import { useExpandableRows } from "../features/all.js";

type TEntry = {
id: number;
name: string;
age: number;
};

const data: TEntry[] = [
{ id: 1, name: "Alice", age: 30 },
{ id: 2, name: "Charlie", age: 35 },
{ id: 3, name: "Bob", age: 25 },
{ id: 4, name: "Robin", age: 28 },
{ id: 5, name: "John", age: 42 },
];

const columns: ColumnConfig<TEntry>[] = [
{ key: "name", label: "Name" },
{ key: "age", label: "Age", type: "number" },
];

const features = [
useExpandableRows<TEntry>({
detailsComponent: (row) => h(OnyxHeadline, { is: "h3" }, () => `Details for ${row.name}`),
}),
];
</script>

<template>
<OnyxDataGrid headline="Example headline" :columns :data :features />
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export const Editing: Story = {
...createAdvancedStoryExample("OnyxDataGrid", "EditingExample"),
};

export const ExpandableRow: Story = {
...createAdvancedStoryExample("OnyxDataGrid", "ExpandableRowExample"),
};

export const LazyLoading: Story = {
...createAdvancedStoryExample("OnyxDataGrid", "LazyLoadingExample"),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./expandableRows/types.js";
export * from "./filtering/types.js";
export * from "./hideColumns/types.js";
export * from "./pagination/types.js";
Expand All @@ -7,6 +8,7 @@ export * from "./sorting/types.js";
export * from "./stickyColumns/types.js";

export { useEditing } from "./editing/editing.js";
export { useExpandableRows } from "./expandableRows/expandableRows.js";
export { useFiltering } from "./filtering/filtering.js";
export { useHideColumns } from "./hideColumns/hideColumns.js";
export { usePagination } from "./pagination/pagination.js";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { iconChevronDown, iconChevronUp } from "@sit-onyx/icons";
import { h, ref } from "vue";
import { DataGridFeatures } from "../../../../index.js";
import OnyxSystemButton from "../../../OnyxSystemButton/OnyxSystemButton.vue";
import { DataGridRowOptionsSymbol, type DataGridEntry } from "../../types.js";
import { createFeature, type DataGridFeature, type InternalColumnConfig } from "../index.js";
import type { UseExpandableRowsOptions } from "./types.js";

const EXPANDABLE_ROWS_FEATURE = Symbol("ExpandableRowsFeature");
const EXPAND_BUTTON_COLUMN = Symbol("ExpandButtonColumn");
const EXPAND_BUTTON_RENDERER = Symbol("ExpandButtonRenderer");
const DETAILS_COLUMN = Symbol("DetailsColumn");
const DETAILS_RENDERER = Symbol("DetailsRenderer");

export const useExpandableRows = <TEntry extends DataGridEntry>(
options: UseExpandableRowsOptions<TEntry>,
) =>
createFeature(() => {
const columnConfig = ref<Readonly<InternalColumnConfig<TEntry>[]>>([]);

const expandedRows = ref<Set<PropertyKey>>(new Set());
const toggleExpanded = (id: PropertyKey) => {
if (expandedRows.value.has(id)) {
expandedRows.value.delete(id);
} else {
expandedRows.value.add(id);
}
};

/**
* Adds the detail row for expandedd columns
*/
const mapRow = (row: TEntry) => {
if (!expandedRows.value.has(row.id))
return [
// don't change anything
{
...row,
[DataGridRowOptionsSymbol]: {
columns: columnConfig.value,
},
},
];
else
return [
{
...row,
[DataGridRowOptionsSymbol]: {
columns: columnConfig.value,
},
},
// add hidden row to keep striped pattern
{
[DataGridRowOptionsSymbol]: {
trAttributes: {
style: { display: "none" },
},
},
},
// add row for details
{
...row,
id: row.id,
[DataGridRowOptionsSymbol]: {
columns: [{ key: DETAILS_COLUMN, type: { name: DETAILS_RENDERER } }],
},
},
];
};

return {
name: EXPANDABLE_ROWS_FEATURE,
watch: [expandedRows, columnConfig],
modifyColumns: {
func: (cols) => {
const config = [
{
key: EXPAND_BUTTON_COLUMN,
label: "",
type: { name: EXPAND_BUTTON_RENDERER },
width: "min-content",
},
...cols,
] as InternalColumnConfig<TEntry>[];

// Store the column configuration with column for expand button for later reference
columnConfig.value = config;
return config;
},
},
mutation: {
func: (rows) => {
return rows.flatMap(mapRow);
},
},

typeRenderer: {
[EXPAND_BUTTON_RENDERER]: DataGridFeatures.createTypeRenderer<object, TEntry>({
cell: {
component: ({ row }) =>
h(OnyxSystemButton, {
icon: expandedRows.value.has(row.id) ? iconChevronUp : iconChevronDown,
label: "",
onClick: () => {
toggleExpanded(row.id);
},
}),
},
}),
[DETAILS_RENDERER]: DataGridFeatures.createTypeRenderer<object, TEntry>({
cell: {
tdAttributes: {
colspan: 99,
},
component: ({ row }) => options.detailsComponent(row),
},
}),
},
};
}) as DataGridFeature<TEntry>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { Component } from "vue";

/**
* Options for rendering detail content for expanded rows.
*/
export type UseExpandableRowsOptions<TEntry> = {
/**
* Function to render the detail content.
*/
detailsComponent: (row: TEntry) => Component;
};
Loading