Skip to content
Merged
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@
"@inertiajs/vite": "^3.0.3",
"@inertiajs/vue3": "^3.0.3",
"@simplewebauthn/browser": "catalog:",
"@tanstack/table-core": "^8.21.3",
"@tanstack/vue-table": "^8.21.3",
"@tanstack/table-core": "^9.2.4",
"@tanstack/vue-table": "^9.2.4",
"@uppy/aws-s3": "^6.1.0",
"@uppy/core": "^6.0.1",
"@uppy/drop-target": "^5.0.0",
Expand Down
34 changes: 21 additions & 13 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 25 additions & 20 deletions resources/js/common/components/DataTable.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<script setup lang="ts">
<script setup lang="ts" generic="TData extends Record<string, any>">
import {
type Column,
FlexRender,
type Row,
type Table,
} from '@tanstack/vue-table';
import type {CraftTableFeatures} from '@/modules/admin-table/craftTable';
import {t} from '@craftcms/ui';
import type CraftSpinner from '@craftcms/ui/components/spinner/spinner';
import {
Expand All @@ -23,7 +24,7 @@
import DropIndicator from '@/common/components/DropIndicator.vue';
const props = withDefaults(
defineProps<{
table: Table<any>;
table: Table<CraftTableFeatures, TData>;
title?: string;
reorderable?: boolean;
/**
Expand All @@ -33,7 +34,7 @@
interactionsDisabled?: boolean;
readOnly?: boolean;
leadingColumnTracks?: string[];
rowAttributes?: (row: Row<any>) => HTMLAttributes;
rowAttributes?: (row: Row<CraftTableFeatures, TData>) => HTMLAttributes;
loading?: boolean;
layout?: 'auto' | 'fixed';
spacing?: TableSpacingValue;
Expand All @@ -53,9 +54,13 @@

const emit = defineEmits<{
reorder: [startIndex: number, finishIndex: number];
rowClick: [row: Row<any>, event: MouseEvent];
rowKeydown: [row: Row<any>, index: number, event: KeyboardEvent];
rowRef: [element: Element | null, row: Row<any>];
rowClick: [row: Row<CraftTableFeatures, TData>, event: MouseEvent];
rowKeydown: [
row: Row<CraftTableFeatures, TData>,
index: number,
event: KeyboardEvent,
];
rowRef: [element: Element | null, row: Row<CraftTableFeatures, TData>];
}>();

const loadingRef = useTemplateRef<CraftSpinner>('loading-ref');
Expand Down Expand Up @@ -134,7 +139,7 @@
);

function getAriaSortAttribute(
column: Column<any>
column: Column<CraftTableFeatures, TData>
): 'ascending' | 'descending' | 'none' | undefined {
if (column.getCanSort()) {
if (column.getIsSorted()) {
Expand All @@ -146,8 +151,8 @@

const visibleColumnCount = computed(() => {
const columns = props.table.getAllColumns();
const visibleColumns = columns.filter((column: Column<any>) =>
column.getIsVisible()
const visibleColumns = columns.filter(
(column: Column<CraftTableFeatures, TData>) => column.getIsVisible()
);
let columnCount = visibleColumns.length;

Expand All @@ -160,14 +165,14 @@

const tableStyles = computed(() => {
const columns = props.table.getAllColumns();
const visibleColumns = columns.filter((column: Column<any>) =>
column.getIsVisible()
const visibleColumns = columns.filter(
(column: Column<CraftTableFeatures, TData>) => column.getIsVisible()
);

const columnCount = visibleColumnCount.value;

const gridDef = visibleColumns.reduce(
(acc: Array<string>, column: Column<any>) => {
(acc: Array<string>, column: Column<CraftTableFeatures, TData>) => {
acc.push(column.columnDef.meta?.trackSize ?? `minmax(0, 1fr)`);
return acc;
},
Expand Down Expand Up @@ -212,7 +217,11 @@
rows?.[index]?.focus();
}

function onRowKeydown(row: Row<any>, index: number, event: KeyboardEvent) {
function onRowKeydown(
row: Row<CraftTableFeatures, TData>,
index: number,
event: KeyboardEvent
) {
emit('rowKeydown', row, index, event);

if (event.defaultPrevented || !(event.currentTarget instanceof HTMLElement))
Expand Down Expand Up @@ -288,7 +297,7 @@
:aria-sort="getAriaSortAttribute(header.column)"
>
<div
class="flex gap-1 items-center [.text-center>&]:justify-center"
class="flex gap-sm items-center [.text-center>&]:justify-center"
:class="{'sr-only': header.column.columnDef.meta?.headerSrOnly}"
>
<ColumnHeaderTitle
Expand All @@ -299,8 +308,7 @@
>
<FlexRender
v-if="!header.isPlaceholder"
:render="header.column.columnDef.header"
:props="header.getContext()"
:header="header"
/><template v-if="header.column.getCanSort()">&nbsp;</template
><craft-icon
v-if="
Expand Down Expand Up @@ -393,10 +401,7 @@
]"
>
<slot name="cell" :cell="cell" :row="row" :index="cellIdx">
<FlexRender
:render="cell.column.columnDef.cell"
:props="cell.getContext()"
/>
<FlexRender :cell="cell" />
</slot>
</component>
</tr>
Expand Down
6 changes: 3 additions & 3 deletions resources/js/common/components/PaginationControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
:params="{from: from ?? 0, to: to ?? 0, total: total ?? 0}"
/>
</div>
<div class="flex gap-1">
<div class="flex gap-sm">
<template v-if="showPagination">
<craft-button
type="button"
Expand All @@ -71,7 +71,7 @@
:label="t('Previous page')"
></craft-icon>
</craft-button>
<div class="flex items-center gap-1 mx-2">
<div class="flex items-center gap-sm mx-md">
{{ t('Page') }}
<craft-input
type="text"
Expand All @@ -98,7 +98,7 @@
</craft-button>
</template>
</div>
<div class="flex gap-2 items-center">
<div class="flex gap-md items-center">
<template v-if="enableAdjustPageSize">
<span aria-hidden="true">{{ pageSizeLabel }}</span>
<Select
Expand Down
4 changes: 2 additions & 2 deletions resources/js/common/form/IconPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
slot="header"
role="search"
@submit.prevent="loadIcons()"
class="sticky top-0 pt-4 px-4 pb-2 bg-white"
class="sticky top-0 pt-lg px-lg pb-md bg-white"
>
<CraftInput :label="t('Search')" v-model="query">
<div slot="suffix" class="flex self-center w-[1em] h-[1em]">
Expand All @@ -190,7 +190,7 @@
<div>
<!-- This only shows on the initial load -->
<template v-if="http.processing && icons === null">
<div class="flex justify-center p-4">
<div class="flex justify-center p-lg">
<craft-spinner></craft-spinner>
</div>
</template>
Expand Down
16 changes: 0 additions & 16 deletions resources/js/common/types/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,6 @@ interface LegacyModalInstance {
destroy?(): void;
}

declare module '@tanstack/vue-table' {
interface ColumnMeta {
wrap?: boolean;
// Applies classes to the cell
cellClass?: string | Record<string, boolean>;
cellTag?: 'td' | 'th';
headerTip?: string;
headerSrOnly?: boolean;
// Applies classes to the header
headerClass?: string | Record<string, boolean>;
// Applies classes to both the header and cell at once
columnClass?: string | Record<string, boolean>;
trackSize?: string;
}
}

// Set up interfaces and types
interface ProgressBarInterface {
// oxlint-disable-next-line @typescript-eslint/no-misused-new
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import {createSampleTable} from '@/modules/elements/fixtures/elements';

const meta = {
title: 'Elements/AdminTable',
component: AdminTable,
// The component is generic over its row type, which `Meta<typeof …>` can't
// instantiate. Every story drives it through `render`, so the only thing the
// cast costs is arg typing that nothing here uses.
component: AdminTable as Meta['component'],
parameters: {
docs: {
description: {
Expand All @@ -13,7 +16,7 @@ const meta = {
},
},
},
} satisfies Meta<typeof AdminTable>;
} satisfies Meta;

export default meta;
type Story = StoryObj<{title?: string}>;
Expand Down
13 changes: 3 additions & 10 deletions resources/js/modules/admin-table/components/AdminTable.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {createApp, h} from 'vue';
import {afterEach, beforeEach, expect, it, vi} from 'vite-plus/test';
import {createTable, getCoreRowModel} from '@tanstack/vue-table';
import {useCraftTable} from '@/modules/admin-table/craftTable';
import AdminTable from './AdminTable.vue';

vi.mock('@inertiajs/vue3', () => ({
Expand All @@ -21,27 +21,20 @@ afterEach(() => {

it('renders settings rows and drives caller pagination without an element payload', () => {
const onPaginationChange = vi.fn();
const table = createTable({
const table = useCraftTable({
data: [{id: 1, name: 'Settings record'}],
columns: [
{accessorKey: 'name', header: 'Name', cell: ({getValue}) => getValue()},
],
state: {pagination: {pageIndex: 0, pageSize: 50}},
manualPagination: true,
rowCount: 151,
getCoreRowModel: getCoreRowModel(),
onStateChange: () => {},
onPaginationChange,
renderFallbackValue: null,
});
table.setOptions((options) => ({
...options,
state: {...table.initialState, pagination: {pageIndex: 0, pageSize: 50}},
}));
const host = document.createElement('div');
document.body.append(host);
const app = createApp({
render: () => h(AdminTable, {table, from: 1, to: 50, total: 151}),
render: () => h(AdminTable, {table, from: 1, to: 50, total: 151} as never),
});
app.config.compilerOptions.isCustomElement = (tag) => tag.includes('-');
app.mount(host);
Expand Down
11 changes: 6 additions & 5 deletions resources/js/modules/admin-table/components/AdminTable.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
<script setup lang="ts" generic="TData extends Record<string, any>">
import type {Table} from '@tanstack/vue-table';
import type {CraftTableFeatures} from '@/modules/admin-table/craftTable';
import DataTable from '@/common/components/DataTable.vue';
import PaginationControls from '@/common/components/PaginationControls.vue';
import {usePage} from '@inertiajs/vue3';
Expand All @@ -8,7 +9,7 @@

const props = withDefaults(
defineProps<{
table: Table<any>;
table: Table<CraftTableFeatures, TData>;
title?: string;
reorderable?: boolean;
readOnly?: boolean;
Expand Down Expand Up @@ -68,13 +69,13 @@
</div>
<div class="admin-table__footer" v-if="showFooter">
<PaginationControls
:page-index="table.getState().pagination.pageIndex"
:page-size="table.getState().pagination.pageSize"
:page-index="table.atoms.pagination.get().pageIndex"
:page-size="table.atoms.pagination.get().pageSize"
:page-count="table.getPageCount()"
:paginated="
Boolean(
table.options.manualPagination ||
table.options.getPaginationRowModel
'paginatedRowModel' in table.options.features
)
"
:from="from"
Expand Down
Loading
Loading