From a05102fab352342ea257c078430502c97ca6f1c1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:07:08 +0200 Subject: [PATCH 1/9] chore(deps): update dependency reka-ui to v2.3.2 (v3) (#4439) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- pnpm-lock.yaml | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index d4536f39..122ccb29 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,7 @@ "mlly": "^1.7.4", "ohash": "^2.0.11", "pathe": "^2.0.3", - "reka-ui": "2.3.1", + "reka-ui": "2.3.2", "scule": "^1.3.0", "tailwind-variants": "^1.0.0", "tailwindcss": "^4.1.11", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d637fb3c..a7b163d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -119,8 +119,8 @@ importers: specifier: ^2.0.3 version: 2.0.3 reka-ui: - specifier: 2.3.1 - version: 2.3.1(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)) + specifier: 2.3.2 + version: 2.3.2(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)) scule: specifier: ^1.3.0 version: 1.3.0 @@ -153,7 +153,7 @@ importers: version: 1.1.0(typescript@5.8.3) vaul-vue: specifier: 0.4.1 - version: 0.4.1(reka-ui@2.3.1(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)))(vue@3.5.17(typescript@5.8.3)) + version: 0.4.1(reka-ui@2.3.2(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)))(vue@3.5.17(typescript@5.8.3)) vue-component-type-helpers: specifier: ^2.2.10 version: 2.2.10 @@ -6322,8 +6322,8 @@ packages: rehype-sort-attributes@5.0.1: resolution: {integrity: sha512-Bxo+AKUIELcnnAZwJDt5zUDDRpt4uzhfz9d0PVGhcxYWsbFj5Cv35xuWxu5r1LeYNFNhgGqsr9Q2QiIOM/Qctg==} - reka-ui@2.3.1: - resolution: {integrity: sha512-2SjGeybd7jvD8EQUkzjgg7GdOQdf4cTwdVMq/lDNTMqneUFNnryGO43dg8WaM/jaG9QpSCZBvstfBFWlDdb2Zg==} + reka-ui@2.3.2: + resolution: {integrity: sha512-lCysSCILH2uqShEnt93/qzlXnB7ySvK7scR0Q5C+a2iXwFVzHhvZQsMaSnbQYueoCihx6yyUZTYECepnmKrbRA==} peerDependencies: vue: '>= 3.2.0' @@ -14699,7 +14699,7 @@ snapshots: '@types/hast': 3.0.4 unist-util-visit: 5.0.0 - reka-ui@2.3.1(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)): + reka-ui@2.3.2(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)): dependencies: '@floating-ui/dom': 1.7.2 '@floating-ui/vue': 1.1.7(vue@3.5.17(typescript@5.8.3)) @@ -15822,10 +15822,10 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vaul-vue@0.4.1(reka-ui@2.3.1(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)))(vue@3.5.17(typescript@5.8.3)): + vaul-vue@0.4.1(reka-ui@2.3.2(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)))(vue@3.5.17(typescript@5.8.3)): dependencies: '@vueuse/core': 10.11.1(vue@3.5.17(typescript@5.8.3)) - reka-ui: 2.3.1(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)) + reka-ui: 2.3.2(typescript@5.8.3)(vue@3.5.17(typescript@5.8.3)) vue: 3.5.17(typescript@5.8.3) transitivePeerDependencies: - '@vue/composition-api' From 09c1ed8bf4d6df2e90bca9f8578a41816823e83e Mon Sep 17 00:00:00 2001 From: Benjamin Canac Date: Wed, 2 Jul 2025 11:20:57 +0200 Subject: [PATCH 2/9] chore(renovate): group `vue-tsc` & `vue-component-type-helpers` --- renovate.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/renovate.json b/renovate.json index d9086b48..0b9ad389 100644 --- a/renovate.json +++ b/renovate.json @@ -22,6 +22,12 @@ "reka-ui", "vaul-vue" ] + }, { + "groupName": "vue-tsc", + "matchPackageNames": [ + "vue-tsc", + "vue-component-type-helpers" + ] }, { "matchDepTypes": ["peerDependencies"], "enabled": false From 127e06ae83c1ec145dadffcab357907b7b06bc98 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:39:23 +0200 Subject: [PATCH 3/9] chore(deps): update all non-major dependencies (v3) (#4443) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Benjamin Canac --- cli/templates.mjs | 3 +- .../examples/form/FormExampleSuperstruct.vue | 3 +- .../content/examples/form/FormExampleYup.vue | 3 +- .../table/TableGroupedRowsExample.vue | 3 +- docs/package.json | 6 +- package.json | 14 +- playground-vue/package.json | 2 +- playground/package.json | 2 +- pnpm-lock.yaml | 805 ++++++------------ src/plugins/nuxt-environment.ts | 3 +- src/plugins/plugins.ts | 3 +- src/runtime/components/Button.vue | 3 +- src/runtime/components/ContextMenuContent.vue | 1 - .../components/DropdownMenuContent.vue | 1 - src/runtime/components/FormField.vue | 3 +- src/runtime/components/OverlayProvider.vue | 3 +- src/runtime/composables/useAvatarGroup.ts | 3 +- src/runtime/composables/useComponentIcons.ts | 3 +- src/runtime/composables/useFormField.ts | 6 +- src/runtime/composables/usePortal.ts | 3 +- src/runtime/types/form.ts | 18 +- src/runtime/types/tv.ts | 4 +- src/runtime/types/utils.ts | 12 +- src/runtime/utils/tv.ts | 3 +- test/components/Accordion.spec.ts | 3 +- test/components/Alert.spec.ts | 3 +- test/components/Avatar.spec.ts | 3 +- test/components/AvatarGroup.spec.ts | 3 +- test/components/Badge.spec.ts | 3 +- test/components/Breadcrumb.spec.ts | 3 +- test/components/Button.spec.ts | 3 +- test/components/ButtonGroup.spec.ts | 3 +- test/components/Calendar.spec.ts | 3 +- test/components/Card.spec.ts | 3 +- test/components/Carousel.spec.ts | 3 +- test/components/Checkbox.spec.ts | 3 +- test/components/CheckboxGroup.spec.ts | 3 +- test/components/Chip.spec.ts | 3 +- test/components/Collapsible.spec.ts | 3 +- test/components/ColorPicker.spec.ts | 3 +- test/components/CommandPalette.spec.ts | 3 +- test/components/Container.spec.ts | 3 +- test/components/ContextMenu.spec.ts | 3 +- test/components/Drawer.spec.ts | 3 +- test/components/DropdownMenu.spec.ts | 3 +- test/components/Input.spec.ts | 3 +- test/components/InputMenu.spec.ts | 3 +- test/components/InputNumber.spec.ts | 3 +- test/components/InputTags.spec.ts | 3 +- test/components/Kbd.spec.ts | 3 +- test/components/Modal.spec.ts | 3 +- test/components/NavigationMenu.spec.ts | 3 +- test/components/Pagination.spec.ts | 3 +- test/components/PinInput.spec.ts | 3 +- test/components/Popover.spec.ts | 3 +- test/components/Progress.spec.ts | 3 +- test/components/RadioGroup.spec.ts | 3 +- test/components/Select.spec.ts | 3 +- test/components/SelectMenu.spec.ts | 3 +- test/components/Separator.spec.ts | 3 +- test/components/Skeleton.spec.ts | 3 +- test/components/Slideover.spec.ts | 3 +- test/components/Slider.spec.ts | 3 +- test/components/Stepper.spec.ts | 3 +- test/components/Switch.spec.ts | 3 +- test/components/Table.spec.ts | 3 +- test/components/Tabs.spec.ts | 3 +- test/components/Textarea.spec.ts | 3 +- test/components/Timeline.spec.ts | 3 +- test/components/Toast.spec.ts | 3 +- test/components/Tooltip.spec.ts | 3 +- test/components/Tree.spec.ts | 3 +- 72 files changed, 439 insertions(+), 615 deletions(-) diff --git a/cli/templates.mjs b/cli/templates.mjs index a37ddc3f..d2ff1221 100644 --- a/cli/templates.mjs +++ b/cli/templates.mjs @@ -147,7 +147,8 @@ const test = ({ name, prose, content }) => { ? undefined : ` import { describe, it, expect } from 'vitest' -import ${upperName}, { type ${upperName}Props, type ${upperName}Slots } from '../../${content ? '../' : ''}src/runtime/components/${content ? 'content/' : ''}${upperName}.vue' +import ${upperName} from '../../${content ? '../' : ''}src/runtime/components/${content ? 'content/' : ''}${upperName}.vue' +import type { ${upperName}Props, ${upperName}Slots } from '../../${content ? '../' : ''}src/runtime/components/${content ? 'content/' : ''}${upperName}.vue' import ComponentRender from '../${content ? '../' : ''}component-render' describe('${upperName}', () => { diff --git a/docs/app/components/content/examples/form/FormExampleSuperstruct.vue b/docs/app/components/content/examples/form/FormExampleSuperstruct.vue index fca03d5c..7c6ef064 100644 --- a/docs/app/components/content/examples/form/FormExampleSuperstruct.vue +++ b/docs/app/components/content/examples/form/FormExampleSuperstruct.vue @@ -1,5 +1,6 @@ + + diff --git a/docs/content/3.components/table.md b/docs/content/3.components/table.md index eb2a9cff..d2bb5659 100644 --- a/docs/content/3.components/table.md +++ b/docs/content/3.components/table.md @@ -77,6 +77,7 @@ Use the `columns` prop as an array of [ColumnDef](https://tanstack.com/table/lat - `accessorKey`: [The key of the row object to use when extracting the value for the column.]{class="text-muted"} - `header`: [The header to display for the column. If a string is passed, it can be used as a default for the column ID. If a function is passed, it will be passed a props object for the header and should return the rendered header value (the exact type depends on the adapter being used).]{class="text-muted"} +- `footer`: [The footer to display for the column. Works exactly like header, but is displayed under the table.]{class="text-muted"} - `cell`: [The cell to display each row for the column. If a function is passed, it will be passed a props object for the cell and should return the rendered cell value (the exact type depends on the adapter being used).]{class="text-muted"} - `meta`: [Extra properties for the column.]{class="text-muted"} - `class`: @@ -161,7 +162,7 @@ props: ### Sticky -Use the `sticky` prop to make the header sticky. +Use the `sticky` prop to make the header or footer sticky. ::component-code --- @@ -172,6 +173,10 @@ ignore: - class external: - data +items: + sticky: + - true + - false props: sticky: true data: @@ -372,6 +377,22 @@ class: '!p-0' This example is similar as the Popover [with following cursor example](/components/popover#with-following-cursor) and uses a [`refDebounced`](https://vueuse.org/shared/refDebounced/#refdebounced) to prevent the Popover from opening and closing too quickly when moving the cursor from one row to another. :: +### With column footer :badge{label="Soon" class="align-text-top"} + +You can add a `footer` property to the column definition to render a footer for the column. + +::component-example +--- +prettier: true +collapse: true +name: 'table-column-footer-example' +highlights: + - 94 + - 108 +class: '!p-0' +--- +:: + ### With column sorting You can update a column `header` to render a [Button](/components/button) component inside the `header` to toggle the sorting state using the TanStack Table [Sorting APIs](https://tanstack.com/table/latest/docs/api/features/sorting). diff --git a/playground/app/pages/components/table.vue b/playground/app/pages/components/table.vue index 03c71a08..6cd02722 100644 --- a/playground/app/pages/components/table.vue +++ b/playground/app/pages/components/table.vue @@ -242,6 +242,16 @@ const columns: TableColumn[] = [{ }, { accessorKey: 'amount', header: () => h('div', { class: 'text-right' }, 'Amount'), + footer: ({ column }) => { + const total = column.getFacetedRowModel().rows.reduce((acc: number, row: TableRow) => acc + Number.parseFloat(row.getValue('amount')), 0) + + const formatted = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'EUR' + }).format(total) + + return h('div', { class: 'text-right font-medium' }, `Total: ${formatted}`) + }, cell: ({ row }) => { const amount = Number.parseFloat(row.getValue('amount')) diff --git a/src/runtime/components/Table.vue b/src/runtime/components/Table.vue index 00b67008..88871cb1 100644 --- a/src/runtime/components/Table.vue +++ b/src/runtime/components/Table.vue @@ -83,10 +83,10 @@ export interface TableProps extends TableOption */ empty?: string /** - * Whether the table should have a sticky header. + * Whether the table should have a sticky header or footer. True for both, 'header' for header only, 'footer' for footer only. * @defaultValue false */ - sticky?: boolean + sticky?: boolean | 'header' | 'footer' /** Whether the table should be in loading state. */ loading?: boolean /** @@ -172,6 +172,7 @@ export interface TableProps extends TableOption } type DynamicHeaderSlots = Record) => any> & Record<`${K extends string ? K : never}-header`, (props: HeaderContext) => any> +type DynamicFooterSlots = Record) => any> & Record<`${K extends string ? K : never}-footer`, (props: HeaderContext) => any> type DynamicCellSlots = Record) => any> & Record<`${K extends string ? K : never}-cell`, (props: CellContext) => any> export type TableSlots = { @@ -181,7 +182,7 @@ export type TableSlots = { 'caption': (props?: {}) => any 'body-top': (props?: {}) => any 'body-bottom': (props?: {}) => any -} & DynamicHeaderSlots & DynamicCellSlots +} & DynamicHeaderSlots & DynamicFooterSlots & DynamicCellSlots @@ -216,6 +217,22 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.table || {}) loadingAnimation: props.loadingAnimation })) +const hasFooter = computed(() => { + function hasFooterRecursive(columns: TableColumn[]): boolean { + for (const column of columns) { + if ('footer' in column) { + return true + } + if ('columns' in column && hasFooterRecursive(column.columns as TableColumn[])) { + return true + } + } + return false + } + + return hasFooterRecursive(columns.value) +}) + const globalFilterState = defineModel('globalFilter', { default: undefined }) const columnFiltersState = defineModel('columnFilters', { default: [] }) const columnOrderState = defineModel('columnOrder', { default: [] }) @@ -461,6 +478,30 @@ defineExpose({ + + + + + + + + + + + + diff --git a/src/theme/table.ts b/src/theme/table.ts index 11985e09..643e8cc5 100644 --- a/src/theme/table.ts +++ b/src/theme/table.ts @@ -7,6 +7,7 @@ export default (options: Required) => ({ caption: 'sr-only', thead: 'relative', tbody: 'divide-y divide-default [&>tr]:data-[selectable=true]:hover:bg-elevated/50 [&>tr]:data-[selectable=true]:focus-visible:outline-primary', + tfoot: 'relative', 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', @@ -23,7 +24,14 @@ export default (options: Required) => ({ }, sticky: { true: { + thead: 'sticky top-0 inset-x-0 bg-default/75 z-[1] backdrop-blur', + tfoot: 'sticky bottom-0 inset-x-0 bg-default/75 z-[1] backdrop-blur' + }, + header: { thead: 'sticky top-0 inset-x-0 bg-default/75 z-[1] backdrop-blur' + }, + footer: { + tfoot: 'sticky bottom-0 inset-x-0 bg-default/75 z-[1] backdrop-blur' } }, loading: { diff --git a/test/components/Table.spec.ts b/test/components/Table.spec.ts index 0b1d183d..a0590c76 100644 --- a/test/components/Table.spec.ts +++ b/test/components/Table.spec.ts @@ -4,7 +4,7 @@ import { flushPromises } from '@vue/test-utils' import { mountSuspended } from '@nuxt/test-utils/runtime' import { UCheckbox, UButton, UBadge, UDropdownMenu } from '#components' import Table from '../../src/runtime/components/Table.vue' -import type { TableProps, TableSlots, TableColumn } from '../../src/runtime/components/Table.vue' +import type { TableProps, TableSlots, TableColumn, TableRow } from '../../src/runtime/components/Table.vue' import ComponentRender from '../component-render' import theme from '#build/ui/table' @@ -99,6 +99,16 @@ describe('Table', () => { }, { accessorKey: 'amount', header: () => h('div', { class: 'text-right' }, 'Amount'), + footer: ({ column }) => { + const total = column.getFacetedRowModel().rows.reduce((acc: number, row: TableRow) => acc + Number.parseFloat(row.getValue('amount')), 0) + + const formatted = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'EUR' + }).format(total) + + return h('div', { class: 'text-right font-medium' }, `Total: ${formatted}`) + }, cell: ({ row }) => { const amount = Number.parseFloat(row.getValue('amount')) diff --git a/test/components/__snapshots__/Table-vue.spec.ts.snap b/test/components/__snapshots__/Table-vue.spec.ts.snap index b28ae606..cbff99fa 100644 --- a/test/components/__snapshots__/Table-vue.spec.ts.snap +++ b/test/components/__snapshots__/Table-vue.spec.ts.snap @@ -50,6 +50,7 @@ exports[`Table > renders with as correctly 1`] = ` + " `; @@ -104,6 +105,7 @@ exports[`Table > renders with body-bottom slot correctly 1`] = ` Body bottom slot + " `; @@ -157,6 +159,7 @@ exports[`Table > renders with body-top slot correctly 1`] = ` + " `; @@ -211,6 +214,7 @@ exports[`Table > renders with caption correctly 1`] = ` + " `; @@ -265,6 +269,7 @@ exports[`Table > renders with caption slot correctly 1`] = ` + " `; @@ -319,6 +324,7 @@ exports[`Table > renders with cell slot correctly 1`] = ` + " `; @@ -373,6 +379,7 @@ exports[`Table > renders with class correctly 1`] = ` + " `; @@ -564,6 +571,32 @@ exports[`Table > renders with columns correctly 1`] = ` + + + + + + + + + + + + + + + + + + + +
Total: €2,990.00
+ + + + + + " `; @@ -618,6 +651,7 @@ exports[`Table > renders with data correctly 1`] = ` + " `; @@ -635,6 +669,7 @@ exports[`Table > renders with empty correctly 1`] = ` There is no data + " `; @@ -674,6 +709,32 @@ exports[`Table > renders with empty slot correctly 1`] = ` Empty slot + + + + + + + + + + + + + + + + + + + +
Total: €0.00
+ + + + + + " `; @@ -728,6 +789,7 @@ exports[`Table > renders with expanded slot correctly 1`] = ` + " `; @@ -782,6 +844,7 @@ exports[`Table > renders with header slot correctly 1`] = ` + " `; @@ -836,6 +899,7 @@ exports[`Table > renders with loading animation carousel correctly 1`] = ` + " `; @@ -890,6 +954,7 @@ exports[`Table > renders with loading animation carousel-inverse correctly 1`] = + " `; @@ -944,6 +1009,7 @@ exports[`Table > renders with loading animation elastic correctly 1`] = ` + " `; @@ -998,6 +1064,7 @@ exports[`Table > renders with loading animation swing correctly 1`] = ` + " `; @@ -1052,6 +1119,7 @@ exports[`Table > renders with loading color error correctly 1`] = ` + " `; @@ -1106,6 +1174,7 @@ exports[`Table > renders with loading color info correctly 1`] = ` + " `; @@ -1160,6 +1229,7 @@ exports[`Table > renders with loading color neutral correctly 1`] = ` + " `; @@ -1214,6 +1284,7 @@ exports[`Table > renders with loading color primary correctly 1`] = ` + " `; @@ -1268,6 +1339,7 @@ exports[`Table > renders with loading color secondary correctly 1`] = ` + " `; @@ -1322,6 +1394,7 @@ exports[`Table > renders with loading color success correctly 1`] = ` + " `; @@ -1376,6 +1449,7 @@ exports[`Table > renders with loading color warning correctly 1`] = ` + " `; @@ -1430,6 +1504,7 @@ exports[`Table > renders with loading correctly 1`] = ` + " `; @@ -1469,6 +1544,32 @@ exports[`Table > renders with loading slot correctly 1`] = ` Loading slot + + + + + + + + + + + + + + + + + + + +
Total: €0.00
+ + + + + + " `; @@ -1523,6 +1624,7 @@ exports[`Table > renders with sticky correctly 1`] = ` + " `; @@ -1577,6 +1679,7 @@ exports[`Table > renders with ui correctly 1`] = ` + " `; @@ -1594,6 +1697,7 @@ exports[`Table > renders without data correctly 1`] = ` No data + " `; diff --git a/test/components/__snapshots__/Table.spec.ts.snap b/test/components/__snapshots__/Table.spec.ts.snap index 8d1b9fe8..ee61ab7a 100644 --- a/test/components/__snapshots__/Table.spec.ts.snap +++ b/test/components/__snapshots__/Table.spec.ts.snap @@ -50,6 +50,7 @@ exports[`Table > renders with as correctly 1`] = ` + " `; @@ -104,6 +105,7 @@ exports[`Table > renders with body-bottom slot correctly 1`] = ` Body bottom slot + " `; @@ -157,6 +159,7 @@ exports[`Table > renders with body-top slot correctly 1`] = ` + " `; @@ -211,6 +214,7 @@ exports[`Table > renders with caption correctly 1`] = ` + " `; @@ -265,6 +269,7 @@ exports[`Table > renders with caption slot correctly 1`] = ` + " `; @@ -319,6 +324,7 @@ exports[`Table > renders with cell slot correctly 1`] = ` + " `; @@ -373,6 +379,7 @@ exports[`Table > renders with class correctly 1`] = ` + " `; @@ -564,6 +571,32 @@ exports[`Table > renders with columns correctly 1`] = ` + + + + + + + + + + + + + + + + + + + +
Total: €2,990.00
+ + + + + + " `; @@ -618,6 +651,7 @@ exports[`Table > renders with data correctly 1`] = ` + " `; @@ -635,6 +669,7 @@ exports[`Table > renders with empty correctly 1`] = ` There is no data + " `; @@ -674,6 +709,32 @@ exports[`Table > renders with empty slot correctly 1`] = ` Empty slot + + + + + + + + + + + + + + + + + + + +
Total: €0.00
+ + + + + + " `; @@ -728,6 +789,7 @@ exports[`Table > renders with expanded slot correctly 1`] = ` + " `; @@ -782,6 +844,7 @@ exports[`Table > renders with header slot correctly 1`] = ` + " `; @@ -836,6 +899,7 @@ exports[`Table > renders with loading animation carousel correctly 1`] = ` + " `; @@ -890,6 +954,7 @@ exports[`Table > renders with loading animation carousel-inverse correctly 1`] = + " `; @@ -944,6 +1009,7 @@ exports[`Table > renders with loading animation elastic correctly 1`] = ` + " `; @@ -998,6 +1064,7 @@ exports[`Table > renders with loading animation swing correctly 1`] = ` + " `; @@ -1052,6 +1119,7 @@ exports[`Table > renders with loading color error correctly 1`] = ` + " `; @@ -1106,6 +1174,7 @@ exports[`Table > renders with loading color info correctly 1`] = ` + " `; @@ -1160,6 +1229,7 @@ exports[`Table > renders with loading color neutral correctly 1`] = ` + " `; @@ -1214,6 +1284,7 @@ exports[`Table > renders with loading color primary correctly 1`] = ` + " `; @@ -1268,6 +1339,7 @@ exports[`Table > renders with loading color secondary correctly 1`] = ` + " `; @@ -1322,6 +1394,7 @@ exports[`Table > renders with loading color success correctly 1`] = ` + " `; @@ -1376,6 +1449,7 @@ exports[`Table > renders with loading color warning correctly 1`] = ` + " `; @@ -1430,6 +1504,7 @@ exports[`Table > renders with loading correctly 1`] = ` + " `; @@ -1469,6 +1544,32 @@ exports[`Table > renders with loading slot correctly 1`] = ` Loading slot + + + + + + + + + + + + + + + + + + + +
Total: €0.00
+ + + + + + " `; @@ -1523,6 +1624,7 @@ exports[`Table > renders with sticky correctly 1`] = ` + " `; @@ -1577,6 +1679,7 @@ exports[`Table > renders with ui correctly 1`] = ` + " `; @@ -1594,6 +1697,7 @@ exports[`Table > renders without data correctly 1`] = ` No data + " `; From 8922c7388efb8eca3937bb2407a43203d4dbb888 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 17:31:53 +0200 Subject: [PATCH 6/9] chore(deps): update all non-major dependencies (v3) (#4448) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Benjamin Canac --- docs/package.json | 6 +++--- package.json | 3 +-- pnpm-lock.yaml | 36 +++++++++++++++++------------------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/docs/package.json b/docs/package.json index 1f62f0f4..325c2914 100644 --- a/docs/package.json +++ b/docs/package.json @@ -14,7 +14,7 @@ "@iconify-json/lucide": "^1.2.54", "@iconify-json/simple-icons": "^1.2.41", "@iconify-json/vscode-icons": "^1.2.23", - "@nuxt/content": "^3.6.1", + "@nuxt/content": "^3.6.2", "@nuxt/image": "^1.10.0", "@nuxt/ui": "workspace:*", "@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@22fdc5e", @@ -28,10 +28,10 @@ "better-sqlite3": "^12.2.0", "capture-website": "^4.2.0", "joi": "^17.13.3", - "maska": "^3.1.1", + "maska": "^3.2.0", "motion-v": "^1.4.0", "nuxt": "^3.17.6", - "nuxt-component-meta": "^0.12.0", + "nuxt-component-meta": "^0.12.1", "nuxt-llms": "^0.1.3", "nuxt-og-image": "^5.1.8", "prettier": "^3.6.2", diff --git a/package.json b/package.json index dccc7d92..17db36a5 100644 --- a/package.json +++ b/package.json @@ -208,8 +208,7 @@ "debug": "4.3.7", "rollup": "4.34.9", "unimport": "4.1.1", - "unplugin": "^2.3.5", - "nuxt-component-meta": "https://pkg.pr.new/nuxt-component-meta@a844f93" + "unplugin": "^2.3.5" }, "pnpm": { "onlyBuiltDependencies": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ea8acf67..e3fb325e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,7 +11,6 @@ overrides: rollup: 4.34.9 unimport: 4.1.1 unplugin: ^2.3.5 - nuxt-component-meta: https://pkg.pr.new/nuxt-component-meta@a844f93 importers: @@ -241,8 +240,8 @@ importers: specifier: ^1.2.23 version: 1.2.23 '@nuxt/content': - specifier: ^3.6.1 - version: 3.6.1(better-sqlite3@12.2.0)(magicast@0.3.5)(vue-component-type-helpers@3.0.0) + specifier: ^3.6.2 + version: 3.6.2(better-sqlite3@12.2.0)(magicast@0.3.5)(vue-component-type-helpers@3.0.0) '@nuxt/image': specifier: ^1.10.0 version: 1.10.0(db0@0.3.2(better-sqlite3@12.2.0))(ioredis@5.6.1)(magicast@0.3.5) @@ -283,8 +282,8 @@ importers: specifier: ^17.13.3 version: 17.13.3 maska: - specifier: ^3.1.1 - version: 3.1.1 + specifier: ^3.2.0 + version: 3.2.0 motion-v: specifier: ^1.4.0 version: 1.4.0(react@19.1.0)(vue@3.5.17(typescript@5.8.3)) @@ -292,8 +291,8 @@ importers: specifier: ^3.17.6 version: 3.17.6(@parcel/watcher@2.5.1)(@types/node@24.0.7)(@vue/compiler-sfc@3.5.17)(better-sqlite3@12.2.0)(db0@0.3.2(better-sqlite3@12.2.0))(eslint@9.30.1(jiti@2.4.2))(ioredis@5.6.1)(lightningcss@1.30.1)(magicast@0.3.5)(meow@13.2.0)(optionator@0.9.4)(rollup@4.34.9)(terser@5.43.1)(typescript@5.8.3)(vite@6.3.5(@types/node@24.0.7)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.0))(vue-tsc@2.2.12(typescript@5.8.3))(yaml@2.8.0) nuxt-component-meta: - specifier: https://pkg.pr.new/nuxt-component-meta@a844f93 - version: https://pkg.pr.new/nuxt-component-meta@a844f93(magicast@0.3.5)(vue-component-type-helpers@3.0.0) + specifier: ^0.12.1 + version: 0.12.1(magicast@0.3.5)(vue-component-type-helpers@3.0.0) nuxt-llms: specifier: ^0.1.3 version: 0.1.3(magicast@0.3.5) @@ -1470,12 +1469,12 @@ packages: engines: {node: ^16.10.0 || >=18.0.0} hasBin: true - '@nuxt/content@3.6.1': - resolution: {integrity: sha512-uW0XBvlofPYhgBJajWvlsZpIUig4RfA8h5zaqcMbZdMYBtM+0NXyn/PDWuxMkdHd13vX6FPDobT3gC7mYq9bbQ==} + '@nuxt/content@3.6.2': + resolution: {integrity: sha512-i9UG6Y0+HROaodeqBT3VXFSBsiNBIDu8rKgbq1Bk4nbwAys/s861hZC/b+vLvwMAkNRuOG7vsxnaa33re48TJg==} peerDependencies: '@electric-sql/pglite': '*' '@libsql/client': '*' - better-sqlite3: 11.10.0 + better-sqlite3: 12.0.0 sqlite3: '*' peerDependenciesMeta: '@electric-sql/pglite': @@ -5117,8 +5116,8 @@ packages: marky@1.3.0: resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} - maska@3.1.1: - resolution: {integrity: sha512-68ZJfZ6/YANwv7CufbQmcCNoHdJnIRxuQgZtSFZe5ltlmZ15ZdA01siUGLh9EfaUX65DN0l/A7g+o2xjTICeGQ==} + maska@3.2.0: + resolution: {integrity: sha512-zSmSgs5/q9vMSmrdZT3rKOv9uLznNWR/niuuAdBZDTvB3SMKOX9vhMtDijFyExz+B4UClu2rvksylUh/ea1bLA==} math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} @@ -5564,9 +5563,8 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nuxt-component-meta@https://pkg.pr.new/nuxt-component-meta@a844f93: - resolution: {tarball: https://pkg.pr.new/nuxt-component-meta@a844f93} - version: 0.12.0 + nuxt-component-meta@0.12.1: + resolution: {integrity: sha512-w0ZgRCE9wGZLbmAnCUV2F4/Gjwy1J6L9FejrpTHSHM8Igrf2THwe809QOXbdV8g4+Elkz2MeC/34ZFyt05tKCg==} hasBin: true nuxt-llms@0.1.3: @@ -8682,7 +8680,7 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/content@3.6.1(better-sqlite3@12.2.0)(magicast@0.3.5)(vue-component-type-helpers@3.0.0)': + '@nuxt/content@3.6.2(better-sqlite3@12.2.0)(magicast@0.3.5)(vue-component-type-helpers@3.0.0)': dependencies: '@nuxt/kit': 3.17.6(magicast@0.3.5) '@nuxtjs/mdc': 0.17.0(magicast@0.3.5) @@ -8710,7 +8708,7 @@ snapshots: micromatch: 4.0.8 minimark: 0.2.0 minimatch: 10.0.3 - nuxt-component-meta: https://pkg.pr.new/nuxt-component-meta@a844f93(magicast@0.3.5)(vue-component-type-helpers@3.0.0) + nuxt-component-meta: 0.12.1(magicast@0.3.5)(vue-component-type-helpers@3.0.0) nypm: 0.6.0 ohash: 2.0.11 pathe: 2.0.3 @@ -12969,7 +12967,7 @@ snapshots: marky@1.3.0: {} - maska@3.1.1: {} + maska@3.2.0: {} math-intrinsics@1.1.0: {} @@ -13653,7 +13651,7 @@ snapshots: dependencies: boolbase: 1.0.0 - nuxt-component-meta@https://pkg.pr.new/nuxt-component-meta@a844f93(magicast@0.3.5)(vue-component-type-helpers@3.0.0): + nuxt-component-meta@0.12.1(magicast@0.3.5)(vue-component-type-helpers@3.0.0): dependencies: '@nuxt/kit': 3.17.6(magicast@0.3.5) citty: 0.1.6 From d7aefa53b28f788accf3b2113f53a1a42fa00af5 Mon Sep 17 00:00:00 2001 From: Teages Date: Thu, 3 Jul 2025 16:45:19 +0800 Subject: [PATCH 7/9] fix(useOverlay): support infering close argument from complex emits (#4414) Co-authored-by: Eugen Istoc --- src/runtime/composables/useOverlay.ts | 31 ++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/runtime/composables/useOverlay.ts b/src/runtime/composables/useOverlay.ts index 2a22b451..9e81ed31 100644 --- a/src/runtime/composables/useOverlay.ts +++ b/src/runtime/composables/useOverlay.ts @@ -3,9 +3,34 @@ import { reactive, markRaw, shallowReactive } from 'vue' import { createSharedComposable } from '@vueuse/core' import type { ComponentProps, ComponentEmit } from 'vue-component-type-helpers' -// Extracts the first argument of the close event -type CloseEventArgType = T extends (event: 'close', args_0: infer R) => void ? R : never - +/** + * This is a workaround for a design limitation in TypeScript. + * + * Conditional types only match the last function overload, not a union of all possible + * parameter types. This workaround forces TypeScript to properly extract the 'close' + * event argument type from component emits with multiple event signatures. + * + * @see https://github.com/microsoft/TypeScript/issues/32164 + */ +type CloseEventArgType = T extends { + (event: 'close', arg_0: infer Arg, ...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void + (...args: any[]): void +} ? Arg : never export type OverlayOptions> = { defaultOpen?: boolean props?: OverlayAttrs From 772631cde9ac6bfdfa8aaaecff34a784ef80fb49 Mon Sep 17 00:00:00 2001 From: Sylvain Marroufin Date: Thu, 3 Jul 2025 15:51:50 +0200 Subject: [PATCH 8/9] fix(defineShortcuts): allow extra keys to be combined with `shift` (#4456) --- src/runtime/composables/defineShortcuts.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/runtime/composables/defineShortcuts.ts b/src/runtime/composables/defineShortcuts.ts index 57e53d27..75655fd0 100644 --- a/src/runtime/composables/defineShortcuts.ts +++ b/src/runtime/composables/defineShortcuts.ts @@ -36,6 +36,8 @@ interface Shortcut { const chainedShortcutRegex = /^[^-]+.*-.*[^-]+$/ const combinedShortcutRegex = /^[^_]+.*_.*[^_]+$/ +// keyboard keys which can be combined with Shift modifier (in addition to alphabet keys) +const shiftableKeys = ['arrowleft', 'arrowright', 'arrowup', 'arrowright', 'tab', 'escape', 'enter', 'backspace'] export function extractShortcuts(items: any[] | any[][]) { const shortcuts: Record = {} @@ -76,7 +78,8 @@ export function defineShortcuts(config: MaybeRef, options: Shor return } - const alphabeticalKey = /^[a-z]{1}$/i.test(e.key) + const alphabetKey = /^[a-z]{1}$/i.test(e.key) + const shiftableKey = shiftableKeys.includes(e.key.toLowerCase()) let chainedKey chainedInputs.value.push(e.key) @@ -109,9 +112,9 @@ export function defineShortcuts(config: MaybeRef, options: Shor if (e.ctrlKey !== shortcut.ctrlKey) { continue } - // shift modifier is only checked in combination with alphabetical keys - // (shift with non-alphabetical keys would change the key) - if (alphabeticalKey && e.shiftKey !== shortcut.shiftKey) { + // shift modifier is only checked in combination with alphabet keys and some extra keys + // (shift with special characters would change the key) + if ((alphabetKey || shiftableKey) && e.shiftKey !== shortcut.shiftKey) { continue } // alt modifier changes the combined key anyways From 9debce737cc779229713cd19b03e6167dfd3ea8e Mon Sep 17 00:00:00 2001 From: TonyWeb Date: Thu, 3 Jul 2025 16:18:27 +0200 Subject: [PATCH 9/9] fix(Button/Link): merge `active-class` / `inactive-class` with app config (#4446) Co-authored-by: Benjamin Canac --- src/runtime/components/Button.vue | 12 ++++-------- src/runtime/components/Link.vue | 11 +++++------ src/runtime/utils/index.ts | 11 +++++++++++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/runtime/components/Button.vue b/src/runtime/components/Button.vue index 93f69ca0..d797bbc3 100644 --- a/src/runtime/components/Button.vue +++ b/src/runtime/components/Button.vue @@ -50,7 +50,7 @@ import { useAppConfig } from '#imports' import { useComponentIcons } from '../composables/useComponentIcons' import { useButtonGroup } from '../composables/useButtonGroup' import { formLoadingInjectionKey } from '../composables/useFormField' -import { omit } from '../utils' +import { omit, mergeClasses } from '../utils' import { tv } from '../utils/tv' import { pickLinkProps } from '../utils/link' import UIcon from './Icon.vue' @@ -58,11 +58,7 @@ import UAvatar from './Avatar.vue' import ULink from './Link.vue' import ULinkBase from './LinkBase.vue' -const props = withDefaults(defineProps(), { - active: undefined, - activeClass: '', - inactiveClass: '' -}) +const props = defineProps() const slots = defineSlots() const appConfig = useAppConfig() as Button['AppConfig'] @@ -97,10 +93,10 @@ const ui = computed(() => tv({ variants: { active: { true: { - base: props.activeClass + base: mergeClasses(appConfig.ui?.button?.variants?.active?.true?.base, props.activeClass) }, false: { - base: props.inactiveClass + base: mergeClasses(appConfig.ui?.button?.variants?.active?.false?.base, props.inactiveClass) } } } diff --git a/src/runtime/components/Link.vue b/src/runtime/components/Link.vue index 4dcaa994..a177d33e 100644 --- a/src/runtime/components/Link.vue +++ b/src/runtime/components/Link.vue @@ -88,11 +88,12 @@ export interface LinkSlots {