diff --git a/package.json b/package.json index e3ffd33..bee2975 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "docs:preview": "vitepress preview packages" }, "dependencies": { + "@tanstack/table-core": "^8.21.3", + "@tanstack/vue-table": "^8.21.3", "@vueuse/core": "^13.1.0", "@vueuse/integrations": "^13.1.0", "@vueuse/shared": "^13.1.0", diff --git a/packages/.playground/package.json b/packages/.playground/package.json index 71b49c3..79ef1f7 100644 --- a/packages/.playground/package.json +++ b/packages/.playground/package.json @@ -8,8 +8,11 @@ "preview": "vite preview" }, "dependencies": { + "@tanstack/table-core": "^8.21.3", + "@tanstack/vue-table": "^8.21.3", "@vueuse/integrations": "^13.1.0", "fuse.js": "^7.1.0", + "scule": "^1.3.0", "tailwindcss": "^4.1.4", "vue": "^3.5.13", "vue-router": "^4.5.0" diff --git a/packages/.playground/src/pages/components/table.vue b/packages/.playground/src/pages/components/table.vue new file mode 100644 index 0000000..3879f24 --- /dev/null +++ b/packages/.playground/src/pages/components/table.vue @@ -0,0 +1,53 @@ + + + diff --git a/packages/.playground/src/styles/keyframes.css b/packages/.playground/src/styles/keyframes.css index 3d89193..7943886 100644 --- a/packages/.playground/src/styles/keyframes.css +++ b/packages/.playground/src/styles/keyframes.css @@ -1,44 +1,26 @@ -@keyframes fade-in { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@keyframes fade-out { +@keyframes accordion-up { from { - opacity: 1; + height: var(--reka-accordion-content-height); } to { - opacity: 0; + height: 0; } } -@keyframes scale-in { +@keyframes accordion-down { from { - transform: scale(0.98); - } - to { - transform: scale(1); + height: 0; } -} -@keyframes scale-out { - from { - transform: scale(1); - } to { - transform: scale(0.98); + height: var(--reka-accordion-content-height); } } -@keyframes accordion-up { +@keyframes collapsible-up { from { - height: var(--reka-accordion-content-height); + height: var(--reka-collapsible-content-height); } to { @@ -46,17 +28,16 @@ } } -@keyframes accordion-down { +@keyframes collapsible-down { from { height: 0; } to { - height: var(--reka-accordion-content-height); + height: var(--reka-collapsible-content-height); } } - @keyframes toast-collapsed-closed { from { transform: var(--transform); @@ -97,23 +78,47 @@ } } -@keyframes toast-slide-up { +@keyframes fade-in { from { - transform: translateY(100%); + opacity: 0; } to { - transform: translateY(0); + opacity: 1; } } -@keyframes toast-slide-down { +@keyframes fade-out { from { - transform: translateY(-100%); + opacity: 1; } to { - transform: translateY(0); + opacity: 0; + } +} + +@keyframes scale-in { + from { + opacity: 0; + transform: scale(0.95); + } + + to { + opacity: 1; + transform: scale(1); + } +} + +@keyframes scale-out { + from { + opacity: 1; + transform: scale(1); + } + + to { + opacity: 0; + transform: scale(0.95); } } @@ -195,4 +200,309 @@ to { transform: translateX(-100%); } -} \ No newline at end of file +} + +@keyframes slide-in-from-top-and-fade { + from { + opacity: 0; + transform: translateY(-4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slide-out-to-top-and-fade { + from { + opacity: 1; + transform: translateY(0); + } + + to { + opacity: 0; + transform: translateY(-4px); + } +} + +@keyframes slide-in-from-right-and-fade { + from { + opacity: 0; + transform: translateX(4px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes slide-out-to-right-and-fade { + from { + opacity: 1; + transform: translateX(0); + } + + to { + opacity: 0; + transform: translateX(4px); + } +} + +@keyframes slide-in-from-bottom-and-fade { + from { + opacity: 0; + transform: translateY(4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slide-out-to-bottom-and-fade { + from { + opacity: 1; + transform: translateY(0); + } + + to { + opacity: 0; + transform: translateY(4px); + } +} + +@keyframes slide-in-from-left-and-fade { + from { + opacity: 0; + transform: translateX(-4px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes slide-out-to-left-and-fade { + from { + opacity: 1; + transform: translateX(0); + } + + to { + opacity: 0; + transform: translateX(-4px); + } +} + +@keyframes enter-from-right { + from { + opacity: 0; + transform: translateX(200px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes enter-from-left { + from { + opacity: 0; + transform: translateX(-200px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes exit-to-right { + from { + opacity: 1; + transform: translateX(0); + } + + to { + opacity: 0; + transform: translateX(200px); + } +} + +@keyframes exit-to-left { + from { + opacity: 1; + transform: translateX(0); + } + + to { + opacity: 0; + transform: translateX(-200px); + } +} + +@keyframes carousel { + + 0%, + 100% { + width: 50% + } + + 0% { + transform: translateX(-100%) + } + + 100% { + transform: translateX(200%) + } +} + + +@keyframes carousel-rtl { + + 0%, + 100% { + width: 50% + } + + 0% { + transform: translateX(100%) + } + + 100% { + transform: translateX(-200%) + } +} + + +@keyframes carousel-vertical { + + 0%, + 100% { + height: 50% + } + + 0% { + transform: translateY(-100%) + } + + 100% { + transform: translateY(200%) + } +} + +@keyframes carousel-inverse { + + 0%, + 100% { + width: 50% + } + + 0% { + transform: translateX(200%) + } + + 100% { + transform: translateX(-100%) + } +} + +@keyframes carousel-inverse-rtl { + + 0%, + 100% { + width: 50% + } + + 0% { + transform: translateX(-200%) + } + + 100% { + transform: translateX(100%) + } +} + +@keyframes carousel-inverse-vertical { + + 0%, + 100% { + height: 50% + } + + 0% { + transform: translateY(200%) + } + + 100% { + transform: translateY(-100%) + } +} + +@keyframes swing { + + 0%, + 100% { + width: 50% + } + + 0%, + 100% { + transform: translateX(-25%) + } + + 50% { + transform: translateX(125%) + } +} + +@keyframes swing-vertical { + + 0%, + 100% { + height: 50% + } + + 0%, + 100% { + transform: translateY(-25%) + } + + 50% { + transform: translateY(125%) + } +} + +@keyframes elastic { + + /* Firefox doesn't do "margin: 0 auto", we have to play with margin-left */ + 0%, + 100% { + width: 50%; + margin-left: 25%; + } + + 50% { + width: 90%; + margin-left: 5%; + } +} + +@keyframes elastic-vertical { + + 0%, + 100% { + height: 50%; + margin-top: 25%; + } + + 50% { + height: 90%; + margin-top: 5%; + } +} diff --git a/packages/.playground/tsconfig.app.json b/packages/.playground/tsconfig.app.json index 6b98676..0336390 100644 --- a/packages/.playground/tsconfig.app.json +++ b/packages/.playground/tsconfig.app.json @@ -13,8 +13,12 @@ /* Bundler mode */ "moduleResolution": "bundler", "paths": { - "@/ui/*": ["../base-components/components/*", "../base-components/composables/*", "../base-components/*"], - "@/app/*": ["./base-components/*"] + "@/ui/*": [ + "../base-components/*" + ], + "@/app/*": [ + "./src/*" + ] }, "allowImportingTsExtensions": true, @@ -28,5 +32,9 @@ "skipLibCheck": true, "noUncheckedSideEffectImports": true }, - "include": ["base-components/**/*.ts", "base-components/**/*.tsx", "base-components/**/*.vue", "./typed-router.d.ts"] + "include": [ + "./src/**/*.ts", + "./src/**/*.vue", + "./typed-router.d.ts" + ] } diff --git a/packages/.playground/typed-router.d.ts b/packages/.playground/typed-router.d.ts index 13e9a43..5f1c48e 100644 --- a/packages/.playground/typed-router.d.ts +++ b/packages/.playground/typed-router.d.ts @@ -53,6 +53,7 @@ declare module 'vue-router/auto-routes' { '/components/slideover': RouteRecordInfo<'/components/slideover', '/components/slideover', Record, Record>, '/components/stepper': RouteRecordInfo<'/components/stepper', '/components/stepper', Record, Record>, '/components/switch': RouteRecordInfo<'/components/switch', '/components/switch', Record, Record>, + '/components/table': RouteRecordInfo<'/components/table', '/components/table', Record, Record>, '/components/tabs': RouteRecordInfo<'/components/tabs', '/components/tabs', Record, Record>, '/components/textarea': RouteRecordInfo<'/components/textarea', '/components/textarea', Record, Record>, '/components/toast': RouteRecordInfo<'/components/toast', '/components/toast', Record, Record>, diff --git a/packages/.vitepress/config.mts b/packages/.vitepress/config.mts index c513f2d..d475395 100644 --- a/packages/.vitepress/config.mts +++ b/packages/.vitepress/config.mts @@ -164,9 +164,11 @@ export default defineConfig({ include: [ 'defu', 'ohash', + 'scule', '@vueuse/shared', 'tailwind-variants', 'reka-ui/namespaced', + '@tanstack/vue-table', ], }, plugins: [ diff --git a/packages/.vitepress/theme/assets/css/keyframes.css b/packages/.vitepress/theme/assets/css/keyframes.css index c471cca..7943886 100644 --- a/packages/.vitepress/theme/assets/css/keyframes.css +++ b/packages/.vitepress/theme/assets/css/keyframes.css @@ -1,44 +1,26 @@ -@keyframes fade-in { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@keyframes fade-out { +@keyframes accordion-up { from { - opacity: 1; + height: var(--reka-accordion-content-height); } to { - opacity: 0; + height: 0; } } -@keyframes scale-in { +@keyframes accordion-down { from { - transform: scale(0.98); - } - to { - transform: scale(1); + height: 0; } -} -@keyframes scale-out { - from { - transform: scale(1); - } to { - transform: scale(0.98); + height: var(--reka-accordion-content-height); } } -@keyframes accordion-up { +@keyframes collapsible-up { from { - height: var(--reka-accordion-content-height); + height: var(--reka-collapsible-content-height); } to { @@ -46,17 +28,16 @@ } } -@keyframes accordion-down { +@keyframes collapsible-down { from { height: 0; } to { - height: var(--reka-accordion-content-height); + height: var(--reka-collapsible-content-height); } } - @keyframes toast-collapsed-closed { from { transform: var(--transform); @@ -97,23 +78,47 @@ } } -@keyframes toast-slide-up { +@keyframes fade-in { from { - transform: translateY(100%); + opacity: 0; } to { - transform: translateY(0); + opacity: 1; } } -@keyframes toast-slide-down { +@keyframes fade-out { from { - transform: translateY(-100%); + opacity: 1; } to { - transform: translateY(0); + opacity: 0; + } +} + +@keyframes scale-in { + from { + opacity: 0; + transform: scale(0.95); + } + + to { + opacity: 1; + transform: scale(1); + } +} + +@keyframes scale-out { + from { + opacity: 1; + transform: scale(1); + } + + to { + opacity: 0; + transform: scale(0.95); } } @@ -196,3 +201,308 @@ transform: translateX(-100%); } } + +@keyframes slide-in-from-top-and-fade { + from { + opacity: 0; + transform: translateY(-4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slide-out-to-top-and-fade { + from { + opacity: 1; + transform: translateY(0); + } + + to { + opacity: 0; + transform: translateY(-4px); + } +} + +@keyframes slide-in-from-right-and-fade { + from { + opacity: 0; + transform: translateX(4px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes slide-out-to-right-and-fade { + from { + opacity: 1; + transform: translateX(0); + } + + to { + opacity: 0; + transform: translateX(4px); + } +} + +@keyframes slide-in-from-bottom-and-fade { + from { + opacity: 0; + transform: translateY(4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slide-out-to-bottom-and-fade { + from { + opacity: 1; + transform: translateY(0); + } + + to { + opacity: 0; + transform: translateY(4px); + } +} + +@keyframes slide-in-from-left-and-fade { + from { + opacity: 0; + transform: translateX(-4px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes slide-out-to-left-and-fade { + from { + opacity: 1; + transform: translateX(0); + } + + to { + opacity: 0; + transform: translateX(-4px); + } +} + +@keyframes enter-from-right { + from { + opacity: 0; + transform: translateX(200px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes enter-from-left { + from { + opacity: 0; + transform: translateX(-200px); + } + + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes exit-to-right { + from { + opacity: 1; + transform: translateX(0); + } + + to { + opacity: 0; + transform: translateX(200px); + } +} + +@keyframes exit-to-left { + from { + opacity: 1; + transform: translateX(0); + } + + to { + opacity: 0; + transform: translateX(-200px); + } +} + +@keyframes carousel { + + 0%, + 100% { + width: 50% + } + + 0% { + transform: translateX(-100%) + } + + 100% { + transform: translateX(200%) + } +} + + +@keyframes carousel-rtl { + + 0%, + 100% { + width: 50% + } + + 0% { + transform: translateX(100%) + } + + 100% { + transform: translateX(-200%) + } +} + + +@keyframes carousel-vertical { + + 0%, + 100% { + height: 50% + } + + 0% { + transform: translateY(-100%) + } + + 100% { + transform: translateY(200%) + } +} + +@keyframes carousel-inverse { + + 0%, + 100% { + width: 50% + } + + 0% { + transform: translateX(200%) + } + + 100% { + transform: translateX(-100%) + } +} + +@keyframes carousel-inverse-rtl { + + 0%, + 100% { + width: 50% + } + + 0% { + transform: translateX(-200%) + } + + 100% { + transform: translateX(100%) + } +} + +@keyframes carousel-inverse-vertical { + + 0%, + 100% { + height: 50% + } + + 0% { + transform: translateY(200%) + } + + 100% { + transform: translateY(-100%) + } +} + +@keyframes swing { + + 0%, + 100% { + width: 50% + } + + 0%, + 100% { + transform: translateX(-25%) + } + + 50% { + transform: translateX(125%) + } +} + +@keyframes swing-vertical { + + 0%, + 100% { + height: 50% + } + + 0%, + 100% { + transform: translateY(-25%) + } + + 50% { + transform: translateY(125%) + } +} + +@keyframes elastic { + + /* Firefox doesn't do "margin: 0 auto", we have to play with margin-left */ + 0%, + 100% { + width: 50%; + margin-left: 25%; + } + + 50% { + width: 90%; + margin-left: 5%; + } +} + +@keyframes elastic-vertical { + + 0%, + 100% { + height: 50%; + margin-top: 25%; + } + + 50% { + height: 90%; + margin-top: 5%; + } +} diff --git a/packages/base-components/components/Table/Table.test.ts b/packages/base-components/components/Table/Table.test.ts new file mode 100644 index 0000000..312f21d --- /dev/null +++ b/packages/base-components/components/Table/Table.test.ts @@ -0,0 +1,175 @@ +import type { TableColumn } from '@/ui/components/Table/Table.vue' +import type { RenderOptions } from '@testing-library/vue' +import Badge from '@/ui/components/Badge/Badge.vue' +import Button from '@/ui/components/Button/Button.vue' +import Checkbox from '@/ui/components/Checkbox/Checkbox.vue' +import DropdownMenu from '@/ui/components/DropdownMenu/DropdownMenu.vue' +import Table from '@/ui/components/Table/Table.vue' +import theme from '@/ui/theme/table' +import { render } from '@testing-library/vue' +import { describe, expect, it } from 'vitest' +import { h } from 'vue' + +describe('table', () => { + const loadingColors = Object.keys(theme.variants.loadingColor) as any + const loadingAnimations = Object.keys(theme.variants.loadingAnimation) as any + + const data = [{ + id: 'm5gr84i9', + amount: 316, + status: 'success', + email: 'ken99@yahoo.com', + }, { + id: '3u1reuv4', + amount: 242, + status: 'success', + email: 'Abe45@gmail.com', + }, { + id: 'derv1ws0', + amount: 837, + status: 'processing', + email: 'Monserrat44@gmail.com', + }, { + id: '5kma53ae', + amount: 874, + status: 'success', + email: 'Silas22@gmail.com', + }, { + id: 'bhqecj4p', + amount: 721, + status: 'failed', + email: 'carmella@hotmail.com', + }] + + const columns: TableColumn[] = [{ + id: 'select', + header: ({ table }) => h(Checkbox, { + 'modelValue': table.getIsSomePageRowsSelected() ? 'indeterminate' : table.getIsAllPageRowsSelected(), + 'onUpdate:modelValue': (value: boolean | 'indeterminate' | undefined) => table.toggleAllPageRowsSelected(!!value), + 'ariaLabel': 'Select all', + }), + cell: ({ row }) => h(Checkbox, { + 'modelValue': row.getIsSelected(), + 'onUpdate:modelValue': (value: boolean | 'indeterminate' | undefined) => row.toggleSelected(!!value), + 'ariaLabel': 'Select row', + }), + enableSorting: false, + enableHiding: false, + }, { + accessorKey: 'id', + header: '#', + cell: ({ row }) => `#${row.getValue('id')}`, + }, { + accessorKey: 'date', + header: 'Date', + cell: ({ row }) => { + return new Date(row.getValue('date')).toLocaleString('en-US', { + day: 'numeric', + month: 'short', + hour: '2-digit', + minute: '2-digit', + hour12: false, + }) + }, + }, { + accessorKey: 'status', + header: 'Status', + cell: ({ row }) => { + const color = ({ + paid: 'success' as const, + failed: 'error' as const, + refunded: 'neutral' as const, + })[row.getValue('status') as string] + + return h(Badge, { class: 'capitalize', variant: 'subtle', color }, () => row.getValue('status')) + }, + }, { + accessorKey: 'email', + header: ({ column }) => { + const isSorted = column.getIsSorted() + + return h(Button, { + color: 'neutral', + variant: 'ghost', + label: 'Email', + icon: isSorted ? (isSorted === 'asc' ? 'i-lucide-arrow-up-narrow-wide' : 'i-lucide-arrow-down-wide-narrow') : 'i-lucide-arrow-up-down', + class: '-mx-2.5', + onClick: () => column.toggleSorting(column.getIsSorted() === 'asc'), + }) + }, + cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email')), + }, { + accessorKey: 'amount', + header: () => h('div', { class: 'text-right' }, 'Amount'), + cell: ({ row }) => { + const amount = Number.parseFloat(row.getValue('amount')) + + const formatted = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'EUR', + }).format(amount) + + return h('div', { class: 'text-right font-medium' }, formatted) + }, + }, { + id: 'actions', + enableHiding: false, + cell: ({ row }) => { + const items = [{ + type: 'label', + label: 'Actions', + }, { + label: 'Copy payment ID', + }, { + label: row.getIsExpanded() ? 'Collapse' : 'Expand', + }, { + type: 'separator', + }, { + label: 'View customer', + }, { + label: 'View payment details', + }] + + return h('div', { class: 'text-right' }, h(DropdownMenu, { + content: { + align: 'end', + }, + items, + }, () => h(Button, { + icon: 'i-lucide-ellipsis-vertical', + color: 'neutral', + variant: 'ghost', + class: 'ml-auto', + }))) + }, + }] + + const props = { data } + + it.each<[string, RenderOptions]>([ + // Props + ['with data', { props }], + ['without data', {}], + ['with empty', { props: { empty: 'There is no data' } }], + ['with caption', { props: { ...props, caption: 'Table caption' } }], + ['with columns', { props: { ...props, columns } }], + ['with sticky', { props: { ...props, sticky: true } }], + ['with loading', { props: { ...props, loading: true } }], + ...loadingColors.map((loadingColor: string) => [`with loading color ${loadingColor}`, { props: { ...props, loading: true, loadingColor } }]), + ...loadingAnimations.map((loadingAnimation: string) => [`with loading animation ${loadingAnimation}`, { props: { ...props, loading: true, loadingAnimation } }]), + ['with as', { props: { ...props, as: 'section' } }], + ['with class', { props: { ...props, class: 'absolute' } }], + ['with ui', { props: { ...props, ui: { base: 'table-auto' } } }], + // Slots + ['with header slot', { props, slots: { 'id-header': () => 'ID Header slot' } }], + ['with cell slot', { props, slots: { 'id-cell': () => 'ID Cell slot' } }], + ['with expanded slot', { props, slots: { expanded: () => 'Expanded slot' } }], + ['with empty slot', { props: { columns }, slots: { empty: () => 'Empty slot' } }], + ['with loading slot', { props: { columns, loading: true }, slots: { loading: () => 'Loading slot' } }], + ['with caption slot', { props, slots: { caption: () => 'Caption slot' } }], + ])('renders %s correctly', (name, options) => { + const { html } = render(Table, options) + + expect(html()).toMatchSnapshot() + }) +}) diff --git a/packages/base-components/components/Table/Table.vue b/packages/base-components/components/Table/Table.vue new file mode 100644 index 0000000..9eb5403 --- /dev/null +++ b/packages/base-components/components/Table/Table.vue @@ -0,0 +1,375 @@ + + + + + + diff --git a/packages/base-components/components/Table/__snapshots__/Table.test.ts.snap b/packages/base-components/components/Table/__snapshots__/Table.test.ts.snap new file mode 100644 index 0000000..70c5be7 --- /dev/null +++ b/packages/base-components/components/Table/__snapshots__/Table.test.ts.snap @@ -0,0 +1,1452 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`table > renders with as correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with caption correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table caption
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with caption slot correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Caption slot
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with cell slot correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
ID Cell slot316successken99@yahoo.com
ID Cell slot242successAbe45@gmail.com
ID Cell slot837processingMonserrat44@gmail.com
ID Cell slot874successSilas22@gmail.com
ID Cell slot721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with class correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with columns correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#DateStatus +
Amount
+
+ +
#m5gr84i9Invalid Datesuccess +
ken99@yahoo.com
+
+
€316.00
+
+
+ + +
+
#3u1reuv4Invalid Datesuccess +
Abe45@gmail.com
+
+
€242.00
+
+
+ + +
+
#derv1ws0Invalid Dateprocessing +
Monserrat44@gmail.com
+
+
€837.00
+
+
+ + +
+
#5kma53aeInvalid Datesuccess +
Silas22@gmail.com
+
+
€874.00
+
+
+ + +
+
#bhqecj4pInvalid Datefailed +
carmella@hotmail.com
+
+
€721.00
+
+
+ + +
+
+
" +`; + +exports[`table > renders with data correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with empty correctly 1`] = ` +"
+ + + + + + + + + + +
There is no data
+
" +`; + +exports[`table > renders with empty slot correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + +
#DateStatus +
Amount
+
+ +
Empty slot
+
" +`; + +exports[`table > renders with expanded slot correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with header slot correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID Header slotAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading animation carousel correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading animation carousel-inverse correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading animation elastic correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading animation swing correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading color error correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading color info correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading color neutral correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading color primary correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading color secondary correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading color success correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading color warning correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with loading slot correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + +
#DateStatus +
Amount
+
+ +
Loading slot
+
" +`; + +exports[`table > renders with sticky correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders with ui correctly 1`] = ` +"
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IdAmountStatusEmail
m5gr84i9316successken99@yahoo.com
3u1reuv4242successAbe45@gmail.com
derv1ws0837processingMonserrat44@gmail.com
5kma53ae874successSilas22@gmail.com
bhqecj4p721failedcarmella@hotmail.com
+
" +`; + +exports[`table > renders without data correctly 1`] = ` +"
+ + + + + + + + + + +
No data
+
" +`; diff --git a/packages/base-components/components/Table/demo.vue b/packages/base-components/components/Table/demo.vue new file mode 100644 index 0000000..83a1b9e --- /dev/null +++ b/packages/base-components/components/Table/demo.vue @@ -0,0 +1,46 @@ + + + diff --git a/packages/base-components/components/Table/index.md b/packages/base-components/components/Table/index.md new file mode 100644 index 0000000..c7886f6 --- /dev/null +++ b/packages/base-components/components/Table/index.md @@ -0,0 +1,3 @@ +# Table + +A responsive table element to display data in rows and columns. diff --git a/packages/base-components/package.json b/packages/base-components/package.json index 47b6be7..cfcc822 100644 --- a/packages/base-components/package.json +++ b/packages/base-components/package.json @@ -6,6 +6,8 @@ "test": "vitest" }, "dependencies": { + "@tanstack/table-core": "^8.21.3", + "@tanstack/vue-table": "^8.21.3", "@vueuse/core": "^13.1.0", "@vueuse/integrations": "^13.1.0", "@vueuse/shared": "^13.1.0", @@ -22,6 +24,7 @@ "fuse.js": "^7.1.0", "ohash": "^2.0.11", "reka-ui": "^2.2.0", + "scule": "^1.3.0", "tailwind-variants": "^1.0.0", "tailwindcss": "^4.1.5", "vue": "^3.5.13", diff --git a/packages/base-components/theme/table.md b/packages/base-components/theme/table.md new file mode 100644 index 0000000..9a6a0fc --- /dev/null +++ b/packages/base-components/theme/table.md @@ -0,0 +1 @@ +# table diff --git a/packages/base-components/theme/table.ts b/packages/base-components/theme/table.ts new file mode 100644 index 0000000..cfe875f --- /dev/null +++ b/packages/base-components/theme/table.ts @@ -0,0 +1,130 @@ +export default { + slots: { + root: 'relative overflow-auto', + base: 'min-w-full overflow-clip', + caption: 'sr-only', + thead: 'relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-(--ui-border-accented)', + tbody: 'divide-y divide-default [&>tr]:data-[selectable=true]:hover:bg-elevated/50 [&>tr]:data-[selectable=true]:focus-visible:outline-primary', + tr: 'data-[selected=true]:bg-elevated/50', + th: 'px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0', + td: 'p-4 text-sm text-muted whitespace-nowrap [&:has([role=checkbox])]:pe-0', + empty: 'py-6 text-center text-sm text-muted', + loading: 'py-6 text-center', + }, + variants: { + pinned: { + true: { + th: 'sticky bg-default/75 data-[pinned=left]:left-0 data-[pinned=right]:right-0', + td: 'sticky bg-default/75 data-[pinned=left]:left-0 data-[pinned=right]:right-0', + }, + }, + sticky: { + true: { + thead: 'sticky top-0 inset-x-0 bg-default/75 z-[1] backdrop-blur', + }, + }, + loading: { + true: { + thead: 'after:absolute after:bottom-0 after:inset-x-0 after:h-px', + }, + }, + loadingAnimation: { + 'carousel': '', + 'carousel-inverse': '', + 'swing': '', + 'elastic': '', + }, + loadingColor: { + primary: '', + secondary: '', + success: '', + info: '', + warning: '', + error: '', + neutral: '', + }, + }, + compoundVariants: [ + { + loading: true, + loadingColor: 'primary', + class: { + thead: 'after:bg-primary', + }, + } as const, + { + loading: true, + loadingColor: 'secondary', + class: { + thead: 'after:bg-secondary', + }, + } as const, + { + loading: true, + loadingColor: 'success', + class: { + thead: 'after:bg-success', + }, + } as const, + { + loading: true, + loadingColor: 'info', + class: { + thead: 'after:bg-info', + }, + } as const, + { + loading: true, + loadingColor: 'warning', + class: { + thead: 'after:bg-warning', + }, + } as const, + { + loading: true, + loadingColor: 'error', + class: { + thead: 'after:bg-error', + }, + } as const, + { + loading: true, + loadingColor: 'neutral', + class: { + thead: 'after:bg-inverted', + }, + } as const, + { + loading: true, + loadingAnimation: 'carousel', + class: { + thead: 'after:animate-[carousel_2s_ease-in-out_infinite] rtl:after:animate-[carousel-rtl_2s_ease-in-out_infinite]', + }, + } as const, + { + loading: true, + loadingAnimation: 'carousel-inverse', + class: { + thead: 'after:animate-[carousel-inverse_2s_ease-in-out_infinite] rtl:after:animate-[carousel-inverse-rtl_2s_ease-in-out_infinite]', + }, + } as const, + { + loading: true, + loadingAnimation: 'swing', + class: { + thead: 'after:animate-[swing_2s_ease-in-out_infinite]', + }, + } as const, + { + loading: true, + loadingAnimation: 'elastic', + class: { + thead: 'after:animate-[elastic_2s_ease-in-out_infinite]', + }, + } as const, + ], + defaultVariants: { + loadingColor: 'primary', + loadingAnimation: 'carousel', + } as const, +} diff --git a/packages/base-components/tsconfig.test.json b/packages/base-components/tsconfig.test.json index 42d847f..a5c29b6 100644 --- a/packages/base-components/tsconfig.test.json +++ b/packages/base-components/tsconfig.test.json @@ -5,11 +5,11 @@ "baseUrl": "./", "paths": { "@/ui/*": [ - "src/*" + "./*" ] } }, "include": [ - "src/**/*.test.ts" + "./**/*.test.ts" ] } diff --git a/packages/usage/nuxt-integration-guide.md b/packages/usage/nuxt-integration-guide.md index be61a4f..539b771 100644 --- a/packages/usage/nuxt-integration-guide.md +++ b/packages/usage/nuxt-integration-guide.md @@ -9,7 +9,27 @@ npm create nuxt@latest Before going further, you need to install the required dependencies. ```bash [pnpm] -pnpm add reka-ui tailwind-variants @vueuse/core @vueuse/shared @vueuse/integrations colortranslator defu fuse.js ohash embla-carousel embla-carousel-auto-height embla-carousel-auto-scroll embla-carousel-autoplay embla-carousel-class-names embla-carousel-fade embla-carousel-vue embla-carousel-wheel-gestures vue-component-type-helpers +pnpm add scule \ + defu \ + ohash \ + fuse.js \ + reka-ui \ + colortranslator \ + tailwind-variants \ + @vueuse/core \ + @vueuse/shared \ + @vueuse/integrations \ + @tanstack/table-core \ + @tanstack/vue-table \ + embla-carousel \ + embla-carousel-fade \ + embla-carousel-vue \ + embla-carousel-autoplay \ + embla-carousel-auto-scroll \ + embla-carousel-auto-height \ + embla-carousel-class-names \ + embla-carousel-wheel-gestures \ + vue-component-type-helpers ``` ## Configuring Nuxt @@ -60,7 +80,14 @@ export default defineNuxtConfig({ tailwindcss(), ], optimizeDeps: { - include: ['reka-ui', 'tailwind-variants', '@vueuse/shared', '@vueuse/core'] + include: [ + 'scule', + 'reka-ui', + '@vueuse/core', + '@vueuse/shared', + 'tailwind-variants', + '@tanstack/vue-table', + ] }, resolve: { alias: { diff --git a/packages/usage/vite-integration-guide.md b/packages/usage/vite-integration-guide.md index 88f5d63..b540311 100644 --- a/packages/usage/vite-integration-guide.md +++ b/packages/usage/vite-integration-guide.md @@ -9,7 +9,27 @@ npm create vite@latest my-vue-app --template vue-ts Before going further, you need to install the required dependencies. ```bash [pnpm] -pnpm add reka-ui tailwind-variants @vueuse/core @vueuse/shared @vueuse/integrations colortranslator defu fuse.js ohash embla-carousel embla-carousel-auto-height embla-carousel-auto-scroll embla-carousel-autoplay embla-carousel-class-names embla-carousel-fade embla-carousel-vue embla-carousel-wheel-gestures vue-component-type-helpers +pnpm add scule \ + defu \ + ohash \ + fuse.js \ + reka-ui \ + colortranslator \ + tailwind-variants \ + @vueuse/core \ + @vueuse/shared \ + @vueuse/integrations \ + @tanstack/table-core \ + @tanstack/vue-table \ + embla-carousel \ + embla-carousel-fade \ + embla-carousel-vue \ + embla-carousel-autoplay \ + embla-carousel-auto-scroll \ + embla-carousel-auto-height \ + embla-carousel-class-names \ + embla-carousel-wheel-gestures \ + vue-component-type-helpers ``` ## Configuring Vite @@ -25,7 +45,14 @@ import { defineConfig } from 'vite' export default defineConfig({ optimizeDeps: { - include: ['reka-ui', 'tailwind-variants', '@vueuse/shared', '@vueuse/core'], + include: [ + 'scule', + 'reka-ui', + '@vueuse/core', + '@vueuse/shared', + 'tailwind-variants', + '@tanstack/vue-table', + ], }, }) ``` diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed5141e..eda683a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,6 +13,12 @@ importers: .: dependencies: + '@tanstack/table-core': + specifier: ^8.21.3 + version: 8.21.3 + '@tanstack/vue-table': + specifier: ^8.21.3 + version: 8.21.3(vue@3.5.13(typescript@5.8.3)) '@vueuse/core': specifier: ^13.1.0 version: 13.1.0(vue@3.5.13(typescript@5.8.3)) @@ -140,15 +146,24 @@ importers: packages/.playground: dependencies: + '@tanstack/table-core': + specifier: ^8.21.3 + version: 8.21.3 + '@tanstack/vue-table': + specifier: ^8.21.3 + version: 8.21.3(vue@3.5.13(typescript@5.8.3)) '@vueuse/integrations': specifier: ^13.1.0 version: 13.1.0(focus-trap@7.6.4)(fuse.js@7.1.0)(vue@3.5.13(typescript@5.8.3)) fuse.js: specifier: ^7.1.0 version: 7.1.0 + scule: + specifier: ^1.3.0 + version: 1.3.0 tailwindcss: specifier: ^4.1.4 - version: 4.1.4 + version: 4.1.5 vue: specifier: ^3.5.13 version: 3.5.13(typescript@5.8.3) @@ -158,19 +173,19 @@ importers: devDependencies: '@egoist/tailwindcss-icons': specifier: ^1.9.0 - version: 1.9.0(tailwindcss@4.1.4) + version: 1.9.0(tailwindcss@4.1.5) '@iconify-json/lucide': specifier: ^1.2.38 version: 1.2.39 '@tailwindcss/vite': specifier: ^4.1.4 - version: 4.1.4(vite@6.3.4(@types/node@22.14.1)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0)) + version: 4.1.5(vite@6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0)) '@types/node': specifier: ^22.14.1 - version: 22.14.1 + version: 22.15.3 '@vitejs/plugin-vue': specifier: ^5.2.3 - version: 5.2.3(vite@6.3.4(@types/node@22.14.1)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.3)) + version: 5.2.3(vite@6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.3)) typescript: specifier: ~5.8.3 version: 5.8.3 @@ -179,13 +194,19 @@ importers: version: 0.12.0(vue-router@4.5.1(vue@3.5.13(typescript@5.8.3)))(vue@3.5.13(typescript@5.8.3)) vite: specifier: ^6.3.2 - version: 6.3.4(@types/node@22.14.1)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0) + version: 6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0) vue-tsc: specifier: ^2.2.10 version: 2.2.10(typescript@5.8.3) packages/base-components: dependencies: + '@tanstack/table-core': + specifier: ^8.21.3 + version: 8.21.3 + '@tanstack/vue-table': + specifier: ^8.21.3 + version: 8.21.3(vue@3.5.13(typescript@5.8.3)) '@vueuse/core': specifier: ^13.1.0 version: 13.1.0(vue@3.5.13(typescript@5.8.3)) @@ -234,6 +255,9 @@ importers: reka-ui: specifier: ^2.2.0 version: 2.2.0(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3)) + scule: + specifier: ^1.3.0 + version: 1.3.0 tailwind-variants: specifier: ^1.0.0 version: 1.0.0(tailwindcss@4.1.5) @@ -1120,132 +1144,63 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@tailwindcss/node@4.1.4': - resolution: {integrity: sha512-MT5118zaiO6x6hNA04OWInuAiP1YISXql8Z+/Y8iisV5nuhM8VXlyhRuqc2PEviPszcXI66W44bCIk500Oolhw==} - '@tailwindcss/node@4.1.5': resolution: {integrity: sha512-CBhSWo0vLnWhXIvpD0qsPephiaUYfHUX3U9anwDaHZAeuGpTiB3XmsxPAN6qX7bFhipyGBqOa1QYQVVhkOUGxg==} - '@tailwindcss/oxide-android-arm64@4.1.4': - resolution: {integrity: sha512-xMMAe/SaCN/vHfQYui3fqaBDEXMu22BVwQ33veLc8ep+DNy7CWN52L+TTG9y1K397w9nkzv+Mw+mZWISiqhmlA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - '@tailwindcss/oxide-android-arm64@4.1.5': resolution: {integrity: sha512-LVvM0GirXHED02j7hSECm8l9GGJ1RfgpWCW+DRn5TvSaxVsv28gRtoL4aWKGnXqwvI3zu1GABeDNDVZeDPOQrw==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.4': - resolution: {integrity: sha512-JGRj0SYFuDuAGilWFBlshcexev2hOKfNkoX+0QTksKYq2zgF9VY/vVMq9m8IObYnLna0Xlg+ytCi2FN2rOL0Sg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - '@tailwindcss/oxide-darwin-arm64@4.1.5': resolution: {integrity: sha512-//TfCA3pNrgnw4rRJOqavW7XUk8gsg9ddi8cwcsWXp99tzdBAZW0WXrD8wDyNbqjW316Pk2hiN/NJx/KWHl8oA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.4': - resolution: {integrity: sha512-sdDeLNvs3cYeWsEJ4H1DvjOzaGios4QbBTNLVLVs0XQ0V95bffT3+scptzYGPMjm7xv4+qMhCDrkHwhnUySEzA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.5': resolution: {integrity: sha512-XQorp3Q6/WzRd9OalgHgaqgEbjP3qjHrlSUb5k1EuS1Z9NE9+BbzSORraO+ecW432cbCN7RVGGL/lSnHxcd+7Q==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.4': - resolution: {integrity: sha512-VHxAqxqdghM83HslPhRsNhHo91McsxRJaEnShJOMu8mHmEj9Ig7ToHJtDukkuLWLzLboh2XSjq/0zO6wgvykNA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - '@tailwindcss/oxide-freebsd-x64@4.1.5': resolution: {integrity: sha512-bPrLWbxo8gAo97ZmrCbOdtlz/Dkuy8NK97aFbVpkJ2nJ2Jo/rsCbu0TlGx8joCuA3q6vMWTSn01JY46iwG+clg==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.4': - resolution: {integrity: sha512-OTU/m/eV4gQKxy9r5acuesqaymyeSCnsx1cFto/I1WhPmi5HDxX1nkzb8KYBiwkHIGg7CTfo/AcGzoXAJBxLfg==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.5': resolution: {integrity: sha512-1gtQJY9JzMAhgAfvd/ZaVOjh/Ju/nCoAsvOVJenWZfs05wb8zq+GOTnZALWGqKIYEtyNpCzvMk+ocGpxwdvaVg==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.4': - resolution: {integrity: sha512-hKlLNvbmUC6z5g/J4H+Zx7f7w15whSVImokLPmP6ff1QqTVE+TxUM9PGuNsjHvkvlHUtGTdDnOvGNSEUiXI1Ww==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.5': resolution: {integrity: sha512-dtlaHU2v7MtdxBXoqhxwsWjav7oim7Whc6S9wq/i/uUMTWAzq/gijq1InSgn2yTnh43kR+SFvcSyEF0GCNu1PQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.4': - resolution: {integrity: sha512-X3As2xhtgPTY/m5edUtddmZ8rCruvBvtxYLMw9OsZdH01L2gS2icsHRwxdU0dMItNfVmrBezueXZCHxVeeb7Aw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.5': resolution: {integrity: sha512-fg0F6nAeYcJ3CriqDT1iVrqALMwD37+sLzXs8Rjy8Z1ZHshJoYceodfyUwGJEsQoTyWbliFNRs2wMQNXtT7MVA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.4': - resolution: {integrity: sha512-2VG4DqhGaDSmYIu6C4ua2vSLXnJsb/C9liej7TuSO04NK+JJJgJucDUgmX6sn7Gw3Cs5ZJ9ZLrnI0QRDOjLfNQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.5': resolution: {integrity: sha512-SO+F2YEIAHa1AITwc8oPwMOWhgorPzzcbhWEb+4oLi953h45FklDmM8dPSZ7hNHpIk9p/SCZKUYn35t5fjGtHA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.4': - resolution: {integrity: sha512-v+mxVgH2kmur/X5Mdrz9m7TsoVjbdYQT0b4Z+dr+I4RvreCNXyCFELZL/DO0M1RsidZTrm6O1eMnV6zlgEzTMQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.5': resolution: {integrity: sha512-6UbBBplywkk/R+PqqioskUeXfKcBht3KU7juTi1UszJLx0KPXUo10v2Ok04iBJIaDPkIFkUOVboXms5Yxvaz+g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.4': - resolution: {integrity: sha512-2TLe9ir+9esCf6Wm+lLWTMbgklIjiF0pbmDnwmhR9MksVOq+e8aP3TSsXySnBDDvTTVd/vKu1aNttEGj3P6l8Q==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - '@tailwindcss/oxide-wasm32-wasi@4.1.5': resolution: {integrity: sha512-hwALf2K9FHuiXTPqmo1KeOb83fTRNbe9r/Ixv9ZNQ/R24yw8Ge1HOWDDgTdtzntIaIUJG5dfXCf4g9AD4RiyhQ==} engines: {node: '>=14.0.0'} @@ -1258,51 +1213,40 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.4': - resolution: {integrity: sha512-VlnhfilPlO0ltxW9/BgfLI5547PYzqBMPIzRrk4W7uupgCt8z6Trw/tAj6QUtF2om+1MH281Pg+HHUJoLesmng==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - '@tailwindcss/oxide-win32-arm64-msvc@4.1.5': resolution: {integrity: sha512-oDKncffWzaovJbkuR7/OTNFRJQVdiw/n8HnzaCItrNQUeQgjy7oUiYpsm9HUBgpmvmDpSSbGaCa2Evzvk3eFmA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.4': - resolution: {integrity: sha512-+7S63t5zhYjslUGb8NcgLpFXD+Kq1F/zt5Xv5qTv7HaFTG/DHyHD9GA6ieNAxhgyA4IcKa/zy7Xx4Oad2/wuhw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.5': resolution: {integrity: sha512-WiR4dtyrFdbb+ov0LK+7XsFOsG+0xs0PKZKkt41KDn9jYpO7baE3bXiudPVkTqUEwNfiglCygQHl2jklvSBi7Q==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.4': - resolution: {integrity: sha512-p5wOpXyOJx7mKh5MXh5oKk+kqcz8T+bA3z/5VWWeQwFrmuBItGwz8Y2CHk/sJ+dNb9B0nYFfn0rj/cKHZyjahQ==} - engines: {node: '>= 10'} - '@tailwindcss/oxide@4.1.5': resolution: {integrity: sha512-1n4br1znquEvyW/QuqMKQZlBen+jxAbvyduU87RS8R3tUSvByAkcaMTkJepNIrTlYhD+U25K4iiCIxE6BGdRYA==} engines: {node: '>= 10'} - '@tailwindcss/vite@4.1.4': - resolution: {integrity: sha512-4UQeMrONbvrsXKXXp/uxmdEN5JIJ9RkH7YVzs6AMxC/KC1+Np7WZBaNIco7TEjlkthqxZbt8pU/ipD+hKjm80A==} - peerDependencies: - vite: ^5.2.0 || ^6 - '@tailwindcss/vite@4.1.5': resolution: {integrity: sha512-FE1stRoqdHSb7RxesMfCXE8icwI1W6zGE/512ae3ZDrpkQYTTYeSyUJPRCjZd8CwVAhpDUbi1YR8pcZioFJQ/w==} peerDependencies: vite: ^5.2.0 || ^6 + '@tanstack/table-core@8.21.3': + resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} + engines: {node: '>=12'} + '@tanstack/virtual-core@3.13.0': resolution: {integrity: sha512-NBKJP3OIdmZY3COJdWkSonr50FMVIi+aj5ZJ7hI/DTpEKg2RMfo/KvP8A3B/zOSpMgIe52B5E2yn7rryULzA6g==} + '@tanstack/vue-table@8.21.3': + resolution: {integrity: sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw==} + engines: {node: '>=12'} + peerDependencies: + vue: '>=3.2' + '@tanstack/vue-virtual@3.13.0': resolution: {integrity: sha512-EPgcTc41KGJAK2N2Ux2PeUnG3cPpdkldTib05nwq+0zdS2Ihpbq8BsWXz/eXPyNc5noDBh1GBgAe36yMYiW6WA==} peerDependencies: @@ -1367,9 +1311,6 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@22.14.1': - resolution: {integrity: sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==} - '@types/node@22.15.3': resolution: {integrity: sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==} @@ -3776,9 +3717,6 @@ packages: peerDependencies: tailwindcss: '*' - tailwindcss@4.1.4: - resolution: {integrity: sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==} - tailwindcss@4.1.5: resolution: {integrity: sha512-nYtSPfWGDiWgCkwQG/m+aX83XCwf62sBgg3bIlNiiOcggnS1x3uVRDAuyelBFL+vJdOPPCGElxv9DjHJjRHiVA==} @@ -4502,13 +4440,6 @@ snapshots: transitivePeerDependencies: - '@algolia/client-search' - '@egoist/tailwindcss-icons@1.9.0(tailwindcss@4.1.4)': - dependencies: - '@iconify/utils': 2.3.0 - tailwindcss: 4.1.4 - transitivePeerDependencies: - - supports-color - '@egoist/tailwindcss-icons@1.9.0(tailwindcss@4.1.5)': dependencies: '@iconify/utils': 2.3.0 @@ -5024,13 +4955,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@tailwindcss/node@4.1.4': - dependencies: - enhanced-resolve: 5.18.1 - jiti: 2.4.2 - lightningcss: 1.29.2 - tailwindcss: 4.1.4 - '@tailwindcss/node@4.1.5': dependencies: enhanced-resolve: 5.18.1 @@ -5038,93 +4962,42 @@ snapshots: lightningcss: 1.29.2 tailwindcss: 4.1.5 - '@tailwindcss/oxide-android-arm64@4.1.4': - optional: true - '@tailwindcss/oxide-android-arm64@4.1.5': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.4': - optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.5': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.4': - optional: true - '@tailwindcss/oxide-darwin-x64@4.1.5': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.4': - optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.5': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.4': - optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.5': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.4': - optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.5': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.4': - optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.5': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.4': - optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.5': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.4': - optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.5': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.4': - optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.5': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.4': - optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.5': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.4': - optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.5': optional: true - '@tailwindcss/oxide@4.1.4': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.4 - '@tailwindcss/oxide-darwin-arm64': 4.1.4 - '@tailwindcss/oxide-darwin-x64': 4.1.4 - '@tailwindcss/oxide-freebsd-x64': 4.1.4 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.4 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.4 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.4 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.4 - '@tailwindcss/oxide-linux-x64-musl': 4.1.4 - '@tailwindcss/oxide-wasm32-wasi': 4.1.4 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.4 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.4 - '@tailwindcss/oxide@4.1.5': optionalDependencies: '@tailwindcss/oxide-android-arm64': 4.1.5 @@ -5140,13 +5013,6 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.5 '@tailwindcss/oxide-win32-x64-msvc': 4.1.5 - '@tailwindcss/vite@4.1.4(vite@6.3.4(@types/node@22.14.1)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0))': - dependencies: - '@tailwindcss/node': 4.1.4 - '@tailwindcss/oxide': 4.1.4 - tailwindcss: 4.1.4 - vite: 6.3.4(@types/node@22.14.1)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0) - '@tailwindcss/vite@4.1.5(vite@5.4.11(@types/node@22.15.3)(lightningcss@1.29.2))': dependencies: '@tailwindcss/node': 4.1.5 @@ -5161,8 +5027,15 @@ snapshots: tailwindcss: 4.1.5 vite: 6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0) + '@tanstack/table-core@8.21.3': {} + '@tanstack/virtual-core@3.13.0': {} + '@tanstack/vue-table@8.21.3(vue@3.5.13(typescript@5.8.3))': + dependencies: + '@tanstack/table-core': 8.21.3 + vue: 3.5.13(typescript@5.8.3) + '@tanstack/vue-virtual@3.13.0(vue@3.5.13(typescript@5.8.3))': dependencies: '@tanstack/virtual-core': 3.13.0 @@ -5233,10 +5106,6 @@ snapshots: '@types/ms@0.7.34': {} - '@types/node@22.14.1': - dependencies: - undici-types: 6.21.0 - '@types/node@22.15.3': dependencies: undici-types: 6.21.0 @@ -5420,11 +5289,6 @@ snapshots: vite: 5.4.11(@types/node@22.15.3)(lightningcss@1.29.2) vue: 3.5.13(typescript@5.8.3) - '@vitejs/plugin-vue@5.2.3(vite@6.3.4(@types/node@22.14.1)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.3))': - dependencies: - vite: 6.3.4(@types/node@22.14.1)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0) - vue: 3.5.13(typescript@5.8.3) - '@vitejs/plugin-vue@5.2.3(vite@6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.3))': dependencies: vite: 6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0) @@ -8015,8 +7879,6 @@ snapshots: tailwind-merge: 3.0.2 tailwindcss: 4.1.5 - tailwindcss@4.1.4: {} - tailwindcss@4.1.5: {} tapable@2.2.1: {} @@ -8274,21 +8136,6 @@ snapshots: fsevents: 2.3.3 lightningcss: 1.29.2 - vite@6.3.4(@types/node@22.14.1)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0): - dependencies: - esbuild: 0.25.3 - fdir: 6.4.4(picomatch@4.0.2) - picomatch: 4.0.2 - postcss: 8.5.3 - rollup: 4.40.0 - tinyglobby: 0.2.13 - optionalDependencies: - '@types/node': 22.14.1 - fsevents: 2.3.3 - jiti: 2.4.2 - lightningcss: 1.29.2 - yaml: 2.7.0 - vite@6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.2)(yaml@2.7.0): dependencies: esbuild: 0.25.3