@xleddyl/443-components-vue 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CATALOG.md +45 -40
  2. package/README.md +62 -4
  3. package/dist/components/layout/Sidebar.vue +8 -3
  4. package/dist/components/layout/Sidebar.vue.d.ts +6 -1
  5. package/dist/components/layout/types.d.ts +1 -0
  6. package/dist/components/templates/DashboardLayout.vue +11 -1
  7. package/dist/components/templates/DashboardLayout.vue.d.ts +5 -2
  8. package/dist/components/templates/SettingsModal.vue +95 -4
  9. package/dist/components/templates/SettingsModal.vue.d.ts +6 -1
  10. package/dist/components/templates/types.d.ts +2 -0
  11. package/dist/composables/layout.d.ts +1 -0
  12. package/dist/composables/layout.mjs +1 -0
  13. package/dist/composables/useRouteState.d.ts +13 -0
  14. package/dist/composables/useRouteState.mjs +37 -0
  15. package/dist/grid/DataGrid.vue +7 -1
  16. package/dist/grid/DataGrid.vue.d.ts +8 -1
  17. package/dist/grid/GridToolbar.vue +57 -2
  18. package/dist/grid/GridToolbar.vue.d.ts +13 -2
  19. package/dist/grid/data-grid.css +33 -0
  20. package/dist/grid/types.d.ts +1 -0
  21. package/dist/icons/builtin.d.ts +2 -0
  22. package/dist/icons/builtin.mjs +2 -0
  23. package/dist/internal/layout/query.d.ts +6 -0
  24. package/dist/internal/layout/query.mjs +64 -0
  25. package/dist/internal/layout/route.d.ts +9 -2
  26. package/dist/locale/de.mjs +4 -0
  27. package/dist/locale/en.mjs +4 -0
  28. package/dist/locale/it.mjs +4 -0
  29. package/dist/locale/types.d.ts +4 -0
  30. package/dist/nuxt/runtime/layouts/dashboard.vue +1 -0
  31. package/dist/styles/layout/app-shell.css +12 -6
  32. package/dist/styles/layout/sidebar.css +11 -2
  33. package/dist/styles/templates/settings-modal.css +5 -1
  34. package/package.json +1 -1
package/CATALOG.md CHANGED
@@ -65,6 +65,8 @@ Playground paths in this file are relative to `playground/nuxt/app/pages/compone
65
65
  | Toast after saving in an open Drawer | `toast` (the stack moves beside the drawer or above its footer) |
66
66
  | Detail or edit panel from the side | `Drawer` (or `useDrawer().open`) |
67
67
  | Dialog with a form or content | `Modal` (or `useModal().open` to get the result as a promise) |
68
+ | Buttons in a Modal or Drawer header | `#actions` slot of `Modal` / `Drawer` (right side, before the close button) |
69
+ | Deep link to a drawer or modal (`?family=fam_1`, `?family=new`) | `useRouteState('family')` + `:open="!!familyId"`; settings: `route` on `SettingsModal`, `settingsRoute` on `DashboardLayout` |
68
70
  | Menu opened by a button | `DropdownMenu` |
69
71
  | Right click menu | `ContextMenu` |
70
72
  | Small floating panel with content or a form | `Popover` |
@@ -73,6 +75,7 @@ Playground paths in this file are relative to `playground/nuxt/app/pages/compone
73
75
  | Global search, command menu (Cmd+K) | `CommandPalette` (the `DashboardLayout` has it with `search`) |
74
76
  | Small table, simple sort | `Table` (+ `useTableSort` for client sort) |
75
77
  | Big table, many rows, editing, Excel-like | `DataGrid` (+ `spreadsheet` prop for Excel-like editing) |
78
+ | Filters for a grid (selects, dates in a modal from the toolbar) | `DataGrid` `#filters` slot with `filterCount` and `@filters-reset` |
76
79
  | Several tags or statuses in one grid cell | `BadgeCell` with an array value (`max` adds a `+N` badge) |
77
80
  | Whole list page: search, filters, table, pagination | `ListPage` |
78
81
  | Page numbers and page size | `Pagination` |
@@ -95,6 +98,7 @@ Playground paths in this file are relative to `playground/nuxt/app/pages/compone
95
98
  | Page title, description, breadcrumbs, actions | `PageHeader` (or a page template) |
96
99
  | Breadcrumbs only | `Breadcrumbs` |
97
100
  | Dashboard layout with sidebar, search, account and settings | `DashboardLayout` (or the Nuxt layout `k-dashboard`) |
101
+ | Actions in a settings section header ("Add user") | `#actions-<id>` on `SettingsModal`, `#settings-actions-<id>` on `DashboardLayout` (gets `page`, `openPage`, `back`) |
98
102
  | Page that fills the panel height (a full height grid) | `content="fill"` or `"centered"` on `DashboardLayout` / `AppShell`, `definePageMeta({ content: 'fill' })` |
99
103
  | Custom app frame with your own sidebar | `AppShell` + `Sidebar` + `SidebarNav` |
100
104
  | Login, sign up, reset password page | `AuthLayout` (or the Nuxt layout `k-auth`) |
@@ -172,20 +176,20 @@ All field components work inside `FormField` and take `invalid`, `disabled`, `re
172
176
 
173
177
  Mount `OverlayHost` once for the imperative hooks (see [Composables](#composables)).
174
178
 
175
- | Component | Purpose and when to use it | Main props, models, slots, events | Playground |
176
- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
177
- | `Modal` | Centered dialog for forms and content. Use `Drawer` for a side panel, `useConfirm` for a yes or no question. | Model: `v-model:open`. Props: `title`, `description`, `size` (sm to xl, full, fit, fullscreen), `width`, `minHeight`, `dismissible`, `hideClose`, `sheet`, `flush`, `loading`, `beforeClose(reason)`. Slots: default, `header`, `footer`, `title-trailing`. Events: `open`, `close`, `afterLeave`. | `overlays/modal.vue` |
178
- | `Drawer` | Panel from the side or bottom for details and edit forms. Use `Modal` for short focused dialogs. | Model: `v-model:open`. Props: `title`, `description`, `side` (left, right, bottom), `size` (sm to xl, full), `dismissible`, `hideClose`, `flush`, `loading`, `beforeClose(reason)`. Slots like `Modal`. Events: `open`, `close`, `afterLeave`. | `overlays/drawer.vue` |
179
- | `ConfirmDialog` | Declarative confirm dialog. Prefer `useConfirm()`. Use this one only when the dialog state lives in the template. | Model: `v-model:open`. Props: `title`, `description`, `confirmLabel`, `cancelLabel`, `tone`, `icon`, `hideCancel`, `onConfirm`. Events: `resolve(confirmed)`, `cancel`, `afterLeave`. | `overlays/confirm-dialog.vue` |
180
- | `ConfirmHost` | Renders the dialogs of `useConfirm`, `useAlert`, `usePrompt`. `OverlayHost` includes it. Do not mount it alone. | None. | - |
181
- | `OverlayHost` | One mount point for toasts, confirm dialogs, programmatic modals and loading indicators. | Props: `toaster` (true or options), `confirm`, `modals`, `loading` (true or `{ bar, delay, label }`). | `overlays/hooks.vue` |
182
- | `Toaster` | Renders toasts. `OverlayHost` includes it. Use it directly only for custom options. The stack moves out of the way of an open side Drawer (beside it, or above its footer). | Props: `position`, `max`, `duration`, `gap`, `expand`, `progress`, `hotkey`. | `overlays/toast.vue` |
183
- | `DropdownMenu` | Menu opened by its trigger. Items can have icons, shortcuts, checkboxes, radios, sub menus and links. | Model: `v-model:open`. Props: `items` (`label`, `icon`, `to`, `href`, `tone: danger`, `shortcut`, `disabled`, `children`, `onSelect`; also `type`: checkbox, radio, label, separator), `placement`, `offset`, `matchTriggerWidth`, `minWidth`. Slot: default (the trigger). Event: `select`. | `overlays/dropdown-menu.vue` |
184
- | `ContextMenu` | Menu on right click of the wrapped area. | Model: `v-model:open`. Props: `items` (same as `DropdownMenu`), `disabled`. Slot: default (the area). Event: `select`. | `overlays/context-menu.vue` |
185
- | `Popover` | Floating panel with any content (a form, filters) opened by its trigger. Use `DropdownMenu` for a list of actions. | Model: `v-model:open`. Props: `placement`, `offset`, `arrow`, `label`, `initialFocus`. Slots: default (the trigger), `content`. | `overlays/popover.vue` |
186
- | `HoverCard` | Rich preview on hover or focus (user card, link preview). Use `Tooltip` for plain text. | Model: `v-model:open`. Props: `placement`, `openDelay`, `closeDelay`, `arrow`, `disabled`. Slots: default (trigger), `content`. | `overlays/hover-card.vue` |
187
- | `Tooltip` | Short text on hover or focus. Optional shortcut. | Props: `text`, `placement`, `openDelay`, `closeDelay`, `arrow`, `shortcut`, `disabled`. Slots: default (trigger), `content`. | `overlays/tooltip.vue` |
188
- | `CommandPalette` | Search and command dialog (Cmd+K) with groups, recent items, async search and typed item data. | Models: `v-model:open`, `v-model:query`. Props: `groups` (items with `id`, `label`, `description`, `icon`, `shortcut`, `keywords`, `to`, `data`, `onSelect`), `search(query, signal)`, `shortcut`, `trigger`, `recentKey`, `emptyText`, `notice`. Slots: `item`, `empty`, `group-label`, `after-results`. Events: `select`, `open`, `close`. | `overlays/command-palette.vue` |
179
+ | Component | Purpose and when to use it | Main props, models, slots, events | Playground |
180
+ | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
181
+ | `Modal` | Centered dialog for forms and content. Use `Drawer` for a side panel, `useConfirm` for a yes or no question. | Model: `v-model:open`. Props: `title`, `description`, `size` (sm to xl, full, fit, fullscreen), `width`, `minHeight`, `dismissible`, `hideClose`, `sheet`, `flush`, `loading`, `beforeClose(reason)`. Slots: default, `header`, `actions` (header, before the close button), `footer`, `title-trailing`. Events: `open`, `close`, `afterLeave`. | `overlays/modal.vue` |
182
+ | `Drawer` | Panel from the side or bottom for details and edit forms. Use `Modal` for short focused dialogs. | Model: `v-model:open`. Props: `title`, `description`, `side` (left, right, bottom), `size` (sm to xl, full), `dismissible`, `hideClose`, `flush`, `loading`, `beforeClose(reason)`. Slots like `Modal`. Events: `open`, `close`, `afterLeave`. | `overlays/drawer.vue` |
183
+ | `ConfirmDialog` | Declarative confirm dialog. Prefer `useConfirm()`. Use this one only when the dialog state lives in the template. | Model: `v-model:open`. Props: `title`, `description`, `confirmLabel`, `cancelLabel`, `tone`, `icon`, `hideCancel`, `onConfirm`. Events: `resolve(confirmed)`, `cancel`, `afterLeave`. | `overlays/confirm-dialog.vue` |
184
+ | `ConfirmHost` | Renders the dialogs of `useConfirm`, `useAlert`, `usePrompt`. `OverlayHost` includes it. Do not mount it alone. | None. | - |
185
+ | `OverlayHost` | One mount point for toasts, confirm dialogs, programmatic modals and loading indicators. | Props: `toaster` (true or options), `confirm`, `modals`, `loading` (true or `{ bar, delay, label }`). | `overlays/hooks.vue` |
186
+ | `Toaster` | Renders toasts. `OverlayHost` includes it. Use it directly only for custom options. The stack moves out of the way of an open side Drawer (beside it, or above its footer). | Props: `position`, `max`, `duration`, `gap`, `expand`, `progress`, `hotkey`. | `overlays/toast.vue` |
187
+ | `DropdownMenu` | Menu opened by its trigger. Items can have icons, shortcuts, checkboxes, radios, sub menus and links. | Model: `v-model:open`. Props: `items` (`label`, `icon`, `to`, `href`, `tone: danger`, `shortcut`, `disabled`, `children`, `onSelect`; also `type`: checkbox, radio, label, separator), `placement`, `offset`, `matchTriggerWidth`, `minWidth`. Slot: default (the trigger). Event: `select`. | `overlays/dropdown-menu.vue` |
188
+ | `ContextMenu` | Menu on right click of the wrapped area. | Model: `v-model:open`. Props: `items` (same as `DropdownMenu`), `disabled`. Slot: default (the area). Event: `select`. | `overlays/context-menu.vue` |
189
+ | `Popover` | Floating panel with any content (a form, filters) opened by its trigger. Use `DropdownMenu` for a list of actions. | Model: `v-model:open`. Props: `placement`, `offset`, `arrow`, `label`, `initialFocus`. Slots: default (the trigger), `content`. | `overlays/popover.vue` |
190
+ | `HoverCard` | Rich preview on hover or focus (user card, link preview). Use `Tooltip` for plain text. | Model: `v-model:open`. Props: `placement`, `openDelay`, `closeDelay`, `arrow`, `disabled`. Slots: default (trigger), `content`. | `overlays/hover-card.vue` |
191
+ | `Tooltip` | Short text on hover or focus. Optional shortcut. | Props: `text`, `placement`, `openDelay`, `closeDelay`, `arrow`, `shortcut`, `disabled`. Slots: default (trigger), `content`. | `overlays/tooltip.vue` |
192
+ | `CommandPalette` | Search and command dialog (Cmd+K) with groups, recent items, async search and typed item data. | Models: `v-model:open`, `v-model:query`. Props: `groups` (items with `id`, `label`, `description`, `icon`, `shortcut`, `keywords`, `to`, `data`, `onSelect`), `search(query, signal)`, `shortcut`, `trigger`, `recentKey`, `emptyText`, `notice`. Slots: `item`, `empty`, `group-label`, `after-results`. Events: `select`, `open`, `close`. | `overlays/command-palette.vue` |
189
193
 
190
194
  ## Data
191
195
 
@@ -224,7 +228,7 @@ Mount `OverlayHost` once for the imperative hooks (see [Composables](#composable
224
228
  | `ThemeSwitch` | Light, dark and system switch. | Props: `variant` (segmented, icon), `size`, `showLabels`. | `layout/theme-switch.vue` |
225
229
  | `NavLink` | One navigation link with icon, badge and active state. | Props: `label`, `to`, `href`, `icon`, `badge`, `active`, `match` (exact, prefix), `external`, `disabled`. Slots: default, `icon`. | `layout/nav-link.vue` |
226
230
  | `AppShell` | App frame: sidebar, topbar, mobile menu, collapse, skip link. Use it for a custom frame. Use `DashboardLayout` for the ready one. | Models: `v-model:collapsed`, `v-model:open`. Props: `variant` (inset, sidebar, floating), `content` (`page`, `fill`, `centered`, `bleed`), `fluid`, `fill`, `topbar`, `storageKey`, `shortcut`. Slots: default, `sidebar`, `topbar`, `overlays`. | `layout/app-shell.vue` |
227
- | `Sidebar` | Sidebar content with header, collapse button and footer. Goes in the `sidebar` slot of `AppShell`. | Props: `label`, `collapsible`. Slots: default, `header`, `top`, `footer`. | `layout/app-shell.vue` |
231
+ | `Sidebar` | Sidebar content with header, collapse button and footer. Goes in the `sidebar` slot of `AppShell`. | Props: `label`, `collapsible`, `collapseLabel`, `brandAlign` (`start`, `center`). Icons `sidebar-collapse` and `sidebar-expand` for the collapse button. Slots: default, `header`, `top`, `footer`. | `layout/app-shell.vue` |
228
232
  | `SidebarNav` | Navigation list from data, with groups and children. | Props: `items` (`NavItem[]` or `NavSection[]`: `label`, `to`, `icon`, `badge`, `children`), `currentPath`. | `layout/app-shell.vue` |
229
233
  | `SidebarSection` | Labelled block inside a sidebar for hand written links. | Prop: `label`. Slot: default. | `layout/app-shell.vue` |
230
234
 
@@ -244,25 +248,25 @@ Mount `OverlayHost` once for the imperative hooks (see [Composables](#composable
244
248
 
245
249
  Templates combine core parts into whole pages and layouts. Start from them for new pages.
246
250
 
247
- | Component | Purpose and when to use it | Main props, models, slots, events | Playground |
248
- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------- |
249
- | `DashboardLayout` | Ready app frame: brand, navigation, command search, account menu, settings modal, breadcrumbs, theme switch. Put it in `layouts/default.vue`. | Models: `v-model:collapsed`, `v-model:open`, `v-model:settingsOpen`, `v-model:settingsSection`. Props: `navigation` (`NavItem[]` or `NavSection[]`), `account` (`name`, `email`, `avatar`, `role`, `menu`), `brandName`, `brandIcon`, `brandLogo`, `breadcrumbs`, `search` (true, groups or function), `settingsSections`, `variant`, `content` (`page`, `fill`, `centered`, `bleed`; per page with `definePageMeta({ content })` in `k-dashboard`), `fluid`, `fill`, `onSignOut`. Slots: default, `actions`, `brand`, `sidebar`, `sidebar-footer`, `account`, `topbar`, `search-item`, `settings-account-fields`. Event: `accountSelect`. | `templates/dashboard-layout.vue` |
250
- | `AuthLayout` | Login, sign up and reset password frame. Centered card or split with aside. | Props: `variant` (centered, split), `title`, `description`, `footer`, `brandName`, `brandIcon`, `brandLogo`, `asideTitle`, `asideDescription`, `themeSwitch`. Slots: default, `links`, `footer`, `brand`, `aside`, `corner`. | `templates/auth-layout.vue` |
251
- | `ListPage` | Whole list page: header, search, filters, table, pagination, bulk actions, loading, empty, no results and error states. Client or server mode (`total`). | Models: `page`, `pageSize`, `search`, `filter`, `sort`, `selected`. Props: `title`, `rows`, `columns`, `rowKey`, `rowTo`, `selectable`, `loading`, `error`, `total`, `paginate`, `searchable`, `searchKeys`, `filters`, `filterKey`, `filterMultiple`, `emptyTitle`. Slots: `actions`, `toolbar`, `toolbar-end`, `bulk`, `empty`, `empty-actions`, `no-results`, `error`, `cell-<key>`, `table`. Events: `retry`, `clear`, `rowClick`. | `templates/list-page.vue` |
252
- | `DetailPage` | Record page: back link, title, status, actions, tabs, main column and aside with description lists. | Model: `v-model:tab`. Props: `title`, `backTo`, `backLabel`, `status` (`label`, `tone`, `dot`), `tabs`, `sections` (`title`, `items`), `loading`, `error`. Slots: default, `actions`, `badge`, `meta`, `aside`, `aside-before`, `panel-<value>`. | `templates/detail-page.vue` |
253
- | `FormPage` | Form page: header, cards in a `Form`, sticky submit and cancel footer, dirty guard. | Props: `title`, `backTo`, `form` (from `useForm`), `dirty`, `saving`, `guard`, `requireDirty`, `submitLabel`, `cancelLabel`, `cancelTo`, `width`, `sticky`. Slots: default, `actions`, `footer`, `status`. Events: `submit`, `submitted`, `invalid`, `reset`, `cancel`. | `templates/form-page.vue` |
254
- | `DashboardPage` | Overview page: header, stat grid, content grid. | Props: `title`, `eyebrow`, `description`, `stats` (`PageStat[]`), `statsColumns`, `columns`, `loading`. Slots: default, `actions`, `stats`, `sparkline`, `before`, `after`, `eyebrow`. | `templates/dashboard-page.vue` |
255
- | `SettingsPage` | Settings as a page: section nav, panels, floating save bar when `dirty`. | Model: `v-model:section`. Props: `title`, `sections` (`value`, `label`, `icon`, `to`), `dirty`, `saving`, `saveBar`, `form`. Slots: `section-<value>`, `actions`, `nav-footer`. Events: `save`, `discard`. | `templates/settings-page.vue` |
256
- | `SettingsSection` | Card of one settings section with a save footer. | Props: `title`, `description`, `icon`, `hint`, `saveable`, `saving`, `saveDisabled`, `saveLabel`, `form`. Slots: default, `actions`, `footer`, `hint`. Event: `save`. | `templates/settings-page.vue` |
257
- | `SettingsGroup` | Block with label, description and actions inside a settings section. | Props: `label`, `description`, `level`, `row`. Slots: default, `label`, `description`, `actions`. | `templates/settings-modal.vue` |
258
- | `SettingsModal` | Settings dialog with nav, built-in account and appearance sections, your own sections and subpages. | Models: `v-model:open`, `v-model:section`, `v-model:pages`. Props: `sections` (`id`, `label`, `icon`, `group`, `badge`, `to`), `account`, `presets`, `title`, `onSignOut`, `hideSession`, `beforeClose`. Slots: `section-<id>`, `actions-<id>`, `account-fields`. | `templates/settings-modal.vue` |
259
- | `AppearanceSettings` | Theme (light, dark, system) and preset cards. Used by `SettingsModal`. Use alone in a settings page. | Props: `presets` (list or false), `themes`, `level`. | `presets.vue` (pages root) |
260
- | `SaveBar` | Floating bar with save and discard for unsaved changes. | Props: `visible`, `saving`, `message`, `saveLabel`, `discardLabel`, `form`. Slots: default, `actions`. Events: `save`, `discard`. | `templates/settings-page.vue` |
261
- | `EmptyPage` | First run screen with illustration, actions and onboarding steps. | Props: `title`, `description`, `icon`, `actionLabel`, `actionTo`, `onAction`, `secondaryLabel`, `steps` (`title`, `description`, `done`, `to`), `fill`. Slots: default, `illustration`, `title`, `description`, `actions`. | `templates/empty-page.vue` |
262
- | `ErrorPage` | Error screen. Reads a Nuxt `error`. Use it in `app/error.vue`. | Props: `error`, `statusCode`, `title`, `message`, `homeTo`, `homeLabel`, `retryLabel`, `brandName`, `fill`, `onHome`, `onRetry`. Slots: default, `title`, `message`, `actions`, `brand`. | `templates/error-page.vue` |
263
- | `NotFoundPage` | 404 screen. | Props: `title`, `message`, `homeTo`, `homeLabel`, `backLabel`, `brandName`, `fill`, `onHome`. Slots: default, `actions`, `brand`. | `templates/error-page.vue` |
264
- | `Brand` | Logo and name block (image URL, inline SVG or component). | Props: `name`, `subtitle`, `icon`, `logo`, `to`, `size`, `accent`, `hideText`, `showName`. Slots: default, `logo`, `mark`, `subtitle`. | `templates/dashboard-layout.vue` |
265
- | `AccountMenu` | Account button with avatar, name and a dropdown menu. Used by `DashboardLayout`. | Props: `name`, `email`, `avatar`, `menu` (menu items), `placement`, `icon`. Event: `select`. | `templates/dashboard-layout.vue` |
251
+ | Component | Purpose and when to use it | Main props, models, slots, events | Playground |
252
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------- |
253
+ | `DashboardLayout` | Ready app frame: brand, navigation, command search, account menu, settings modal, breadcrumbs, theme switch. Put it in `layouts/default.vue`. | Models: `v-model:collapsed`, `v-model:open`, `v-model:settingsOpen`, `v-model:settingsSection`. Props: `navigation` (`NavItem[]` or `NavSection[]`), `account` (`name`, `email`, `avatar`, `role`, `menu`), `brandName`, `brandIcon`, `brandLogo`, `breadcrumbs`, `search` (true, groups or function), `settingsSections`, `settingsRoute`, `settingsResolvePage`, `variant`, `content` (`page`, `fill`, `centered`, `bleed`; per page with `definePageMeta({ content })` in `k-dashboard`), `fluid`, `fill`, `onSignOut`. Slots: default, `actions`, `brand`, `sidebar`, `sidebar-footer`, `account`, `topbar`, `search-item`, `settings-account-fields`, `settings-section-<id>`, `settings-actions-<id>`. Event: `accountSelect`. | `templates/dashboard-layout.vue` |
254
+ | `AuthLayout` | Login, sign up and reset password frame. Centered card or split with aside. | Props: `variant` (centered, split), `title`, `description`, `footer`, `brandName`, `brandIcon`, `brandLogo`, `asideTitle`, `asideDescription`, `themeSwitch`. Slots: default, `links`, `footer`, `brand`, `aside`, `corner`. | `templates/auth-layout.vue` |
255
+ | `ListPage` | Whole list page: header, search, filters, table, pagination, bulk actions, loading, empty, no results and error states. Client or server mode (`total`). | Models: `page`, `pageSize`, `search`, `filter`, `sort`, `selected`. Props: `title`, `rows`, `columns`, `rowKey`, `rowTo`, `selectable`, `loading`, `error`, `total`, `paginate`, `searchable`, `searchKeys`, `filters`, `filterKey`, `filterMultiple`, `emptyTitle`. Slots: `actions`, `toolbar`, `toolbar-end`, `bulk`, `empty`, `empty-actions`, `no-results`, `error`, `cell-<key>`, `table`. Events: `retry`, `clear`, `rowClick`. | `templates/list-page.vue` |
256
+ | `DetailPage` | Record page: back link, title, status, actions, tabs, main column and aside with description lists. | Model: `v-model:tab`. Props: `title`, `backTo`, `backLabel`, `status` (`label`, `tone`, `dot`), `tabs`, `sections` (`title`, `items`), `loading`, `error`. Slots: default, `actions`, `badge`, `meta`, `aside`, `aside-before`, `panel-<value>`. | `templates/detail-page.vue` |
257
+ | `FormPage` | Form page: header, cards in a `Form`, sticky submit and cancel footer, dirty guard. | Props: `title`, `backTo`, `form` (from `useForm`), `dirty`, `saving`, `guard`, `requireDirty`, `submitLabel`, `cancelLabel`, `cancelTo`, `width`, `sticky`. Slots: default, `actions`, `footer`, `status`. Events: `submit`, `submitted`, `invalid`, `reset`, `cancel`. | `templates/form-page.vue` |
258
+ | `DashboardPage` | Overview page: header, stat grid, content grid. | Props: `title`, `eyebrow`, `description`, `stats` (`PageStat[]`), `statsColumns`, `columns`, `loading`. Slots: default, `actions`, `stats`, `sparkline`, `before`, `after`, `eyebrow`. | `templates/dashboard-page.vue` |
259
+ | `SettingsPage` | Settings as a page: section nav, panels, floating save bar when `dirty`. | Model: `v-model:section`. Props: `title`, `sections` (`value`, `label`, `icon`, `to`), `dirty`, `saving`, `saveBar`, `form`. Slots: `section-<value>`, `actions`, `nav-footer`. Events: `save`, `discard`. | `templates/settings-page.vue` |
260
+ | `SettingsSection` | Card of one settings section with a save footer. | Props: `title`, `description`, `icon`, `hint`, `saveable`, `saving`, `saveDisabled`, `saveLabel`, `form`. Slots: default, `actions`, `footer`, `hint`. Event: `save`. | `templates/settings-page.vue` |
261
+ | `SettingsGroup` | Block with label, description and actions inside a settings section. | Props: `label`, `description`, `level`, `row`. Slots: default, `label`, `description`, `actions`. | `templates/settings-modal.vue` |
262
+ | `SettingsModal` | Settings dialog with nav, built-in account and appearance sections, your own sections and subpages. | Models: `v-model:open`, `v-model:section`, `v-model:pages`. Props: `sections` (`id`, `label`, `icon`, `group`, `badge`, `to`), `account`, `presets`, `title`, `onSignOut`, `hideSession`, `beforeClose`, `route` (sync with `?settings=<section>/<page>`), `resolvePage(section, id, parents)`. Slots: `section-<id>`, `actions-<id>` (right of the header row, also on a subpage), `account-fields`. | `templates/settings-modal.vue` |
263
+ | `AppearanceSettings` | Theme (light, dark, system) and preset cards. Used by `SettingsModal`. Use alone in a settings page. | Props: `presets` (list or false), `themes`, `level`. | `presets.vue` (pages root) |
264
+ | `SaveBar` | Floating bar with save and discard for unsaved changes. | Props: `visible`, `saving`, `message`, `saveLabel`, `discardLabel`, `form`. Slots: default, `actions`. Events: `save`, `discard`. | `templates/settings-page.vue` |
265
+ | `EmptyPage` | First run screen with illustration, actions and onboarding steps. | Props: `title`, `description`, `icon`, `actionLabel`, `actionTo`, `onAction`, `secondaryLabel`, `steps` (`title`, `description`, `done`, `to`), `fill`. Slots: default, `illustration`, `title`, `description`, `actions`. | `templates/empty-page.vue` |
266
+ | `ErrorPage` | Error screen. Reads a Nuxt `error`. Use it in `app/error.vue`. | Props: `error`, `statusCode`, `title`, `message`, `homeTo`, `homeLabel`, `retryLabel`, `brandName`, `fill`, `onHome`, `onRetry`. Slots: default, `title`, `message`, `actions`, `brand`. | `templates/error-page.vue` |
267
+ | `NotFoundPage` | 404 screen. | Props: `title`, `message`, `homeTo`, `homeLabel`, `backLabel`, `brandName`, `fill`, `onHome`. Slots: default, `actions`, `brand`. | `templates/error-page.vue` |
268
+ | `Brand` | Logo and name block (image URL, inline SVG or component). | Props: `name`, `subtitle`, `icon`, `logo`, `to`, `size`, `accent`, `hideText`, `showName`. Slots: default, `logo`, `mark`, `subtitle`. | `templates/dashboard-layout.vue` |
269
+ | `AccountMenu` | Account button with avatar, name and a dropdown menu. Used by `DashboardLayout`. | Props: `name`, `email`, `avatar`, `menu` (menu items), `placement`, `icon`. Event: `select`. | `templates/dashboard-layout.vue` |
266
270
 
267
271
  Nuxt ready layouts: with `k: { layouts: true }` the module registers the layouts `k-dashboard` and `k-auth`. They read brand, navigation, account and settings from `app.config.ts` (`k` key). `useDashboard()` gives the runtime account, breadcrumbs and badges for `k-dashboard`. See README, section "Nuxt: ready layouts".
268
272
 
@@ -270,12 +274,12 @@ Nuxt ready layouts: with `k: { layouts: true }` the module registers the layouts
270
274
 
271
275
  Import from `@xleddyl/443-components-vue/grid`. It wraps AG Grid Community.
272
276
 
273
- | Component | Purpose and when to use it | Main props, models, slots, events | Playground |
274
- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------- |
275
- | `DataGrid` | Big table: virtual scroll, column menu, search, CSV export, selection, server sort and paging, inline editing. For small tables use `Table`. | Models: `v-model:query`, `v-model:page`, `v-model:pageSize`, `v-model:sort` (`{ column, direction }`). Props: `rows`, `columns` (AG Grid `ColDef`), `rowIdKey` or `getRowId`, `storageKey`, `density`, `selectable`, `loading`, `height`, `fill`, `autoHeight`, `toolbar`, `searchable`, `columnMenu`, `exportable`, `serverSort`, `pagination`, `serverPagination`, `total`, `filterable`, `editable`, `spreadsheet`, `gridOptions`, `messages`. Slot: `actions`. Events: `rowClick`, `selectionChange`, `sortChange`, `filterChange`, `cellsChange`, `cellsInvalid`, `dirtyChange`, `rangeChange`, `copy`. | `grid/data-grid.vue` |
276
- | `DataGrid` with `spreadsheet` | Excel-like editing: cell range selection, copy and paste (TSV), fill down and right, clear, undo and redo, dirty cell tracking. Set `rowIdKey` or `getRowId`. | Template ref methods (`GridSpreadsheetMethods`): `getRange`, `getSelectedCells`, `selectRange`, `selectAll`, `setRangeValue`, `copyRange`, `paste`, `fillDown`, `fillRight`, `clearCells`, `undo`, `redo`, `getDirtyCells`, `clearDirty`. The `actions` slot gets the same methods plus `range`, `selectedCellCount`, `dirtyCount`, `canUndo`, `canRedo`. Use `cellsChange` to save edits, `cellsInvalid` for rejected input. | `grid/spreadsheet.vue` |
277
- | `GridToolbar` | Toolbar of `DataGrid` (search, column menu, export). `DataGrid` already renders it. Use it alone only for a custom grid setup. | Props: `api`, `searchable`, `columnMenu`, `exportable`, `exportFileName`, `debounce`. Model: `v-model` (query). Event: `resetColumns`. | - |
278
- | Cell renderers | Use as `cellRenderer` in a column definition, with `cellRendererParams`. | `BadgeCell` (`tones`, `labels`, `defaultTone`, `variant`; array values render one badge each, `max` adds a `+N` badge, `wrap`), `BooleanCell` (`trueLabel`, `falseLabel`), `DateCell` (`locale`, `options`, `relative`), `EmptyCell` (placeholder for empty values), `ImageCell` (`alt`, `rounded`, `fit`, `size`), `LinkCell` (`href`, `label`, `target`). | `grid/data-grid.vue` |
277
+ | Component | Purpose and when to use it | Main props, models, slots, events | Playground |
278
+ | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
279
+ | `DataGrid` | Big table: virtual scroll, column menu, search, CSV export, selection, server sort and paging, inline editing. For small tables use `Table`. | Models: `v-model:query`, `v-model:page`, `v-model:pageSize`, `v-model:sort` (`{ column, direction }`). Props: `rows`, `columns` (AG Grid `ColDef`), `rowIdKey` or `getRowId`, `storageKey`, `density`, `selectable`, `loading`, `height`, `fill`, `autoHeight`, `toolbar`, `searchable`, `columnMenu`, `exportable`, `serverSort`, `pagination`, `serverPagination`, `total`, `filterable`, `editable`, `spreadsheet`, `gridOptions`, `messages`, `filterCount`. Slots: `actions`, `filters` (`{ close, count }`, hosted in a modal opened by a funnel button next to the search). Events: `filtersReset`, `rowClick`, `selectionChange`, `sortChange`, `filterChange`, `cellsChange`, `cellsInvalid`, `dirtyChange`, `rangeChange`, `copy`. | `grid/data-grid.vue` |
280
+ | `DataGrid` with `spreadsheet` | Excel-like editing: cell range selection, copy and paste (TSV), fill down and right, clear, undo and redo, dirty cell tracking. Set `rowIdKey` or `getRowId`. | Template ref methods (`GridSpreadsheetMethods`): `getRange`, `getSelectedCells`, `selectRange`, `selectAll`, `setRangeValue`, `copyRange`, `paste`, `fillDown`, `fillRight`, `clearCells`, `undo`, `redo`, `getDirtyCells`, `clearDirty`. The `actions` slot gets the same methods plus `range`, `selectedCellCount`, `dirtyCount`, `canUndo`, `canRedo`. Use `cellsChange` to save edits, `cellsInvalid` for rejected input. | `grid/spreadsheet.vue` |
281
+ | `GridToolbar` | Toolbar of `DataGrid` (search, column menu, export). `DataGrid` already renders it. Use it alone only for a custom grid setup. | Props: `api`, `searchable`, `columnMenu`, `exportable`, `exportFileName`, `debounce`, `filterCount`. Model: `v-model` (query). Slots: default (actions), `filters`. Events: `resetColumns`, `filtersReset`. | - |
282
+ | Cell renderers | Use as `cellRenderer` in a column definition, with `cellRendererParams`. | `BadgeCell` (`tones`, `labels`, `defaultTone`, `variant`; array values render one badge each, `max` adds a `+N` badge, `wrap`), `BooleanCell` (`trueLabel`, `falseLabel`), `DateCell` (`locale`, `options`, `relative`), `EmptyCell` (placeholder for empty values), `ImageCell` (`alt`, `rounded`, `fit`, `size`), `LinkCell` (`href`, `label`, `target`). | `grid/data-grid.vue` |
279
283
 
280
284
  Grid helpers: `registerGridModules`, `registerGridEditorModules`, `registerGridFilterModules`, `registerGridSpreadsheetModules` (register AG Grid modules by hand), `createGridTheme`, `parseTsv`, `formatTsv`.
281
285
 
@@ -325,6 +329,7 @@ All are exported from `@xleddyl/443-components-vue` and auto-imported in Nuxt.
325
329
  | `useTheme` | Read or set the theme preference (system, light, dark). | `const { preference, resolved, set } = useTheme()`. Nuxt module stores it in a cookie. | `layout/theme-switch.vue` |
326
330
  | `usePreset` | Read or set the visual preset. | `presetOptions` lists the presets. | `presets.vue` (pages root) |
327
331
  | `useAppShell` | Read the `AppShell` state (collapsed, open) from a child component. | Returns the shell context or `null` outside a shell. | `layout/app-shell.vue` |
332
+ | `useRouteState` | Bind a ref to a URL query parameter: deep links to drawers and modals, back button closes them, filters in the URL. | `useRouteState(key, { parse, serialize, default, history: 'push' \| 'replace' })`. Returns a ref; `undefined` or `''` removes the parameter. No-op without a router. | `overlays/drawer.vue` |
328
333
  | `useScrollLock` | Lock the page scroll while something is open. | `useScrollLock(activeRef)`. | - |
329
334
  | `useLocale` | Translate component texts and read the active locale (en, it, de). | `const { locale, t } = useLocale()`. `provideLocale` and `createLocale` set it. Nuxt follows `k.locale`. | `languages.vue` (pages root) |
330
335
  | `useIcons` helpers, `createIcons`, `provideIcons` | Register your own icons by name. | Nuxt: option `k.icons: { dir: '~/assets/icons' }`. | `components/core/icon.vue` |
package/README.md CHANGED
@@ -136,7 +136,7 @@ A few component tokens are unset by default and only exist to be overridden on a
136
136
  | Fields | `--k-field-padding-x` |
137
137
  | Overlays | `--k-modal-radius`, `--k-modal-shadow`, `--k-drawer-radius`, `--k-drawer-shadow`, `--k-popover-radius`, `--k-popover-shadow`, `--k-toast-radius`, `--k-toast-shadow`, `--k-scrim-blur` (3px) |
138
138
  | Tooltip | `--k-tooltip-background`, `--k-tooltip-text`, `--k-tooltip-border`, `--k-tooltip-radius`, `--k-tooltip-shadow`, `--k-tooltip-padding` |
139
- | Shell | `--k-sidebar-width` (15rem), `--k-sidebar-rail-width`, `--k-topbar-height` (3rem), `--k-shell-inset`, `--k-shell-padding`, `--k-shell-content` |
139
+ | Shell | `--k-sidebar-width` (16.5rem), `--k-sidebar-rail-width`, `--k-topbar-height` (3rem), `--k-shell-inset`, `--k-shell-padding`, `--k-shell-content` |
140
140
  | Switch | `--k-switch-track-width`, `--k-switch-track-height`, `--k-switch-thumb-size` (md size) |
141
141
  | Separator | `--k-separator-heading-font-size` (0.9375rem), `--k-separator-heading-color` (`--k-text`), `--k-separator-label-font-size` (0.75rem) |
142
142
  | Calendar | `--k-calendar-day-radius`, `--k-calendar-unavailable-color`, `--k-calendar-unavailable-decoration` (line-through), `--k-calendar-unavailable-opacity` (0.6), `--k-calendar-out-of-range-color`, `--k-calendar-out-of-range-decoration`, `--k-calendar-out-of-range-opacity` (each defaults to its unavailable token) |
@@ -358,7 +358,7 @@ Several controls in one `FormField`. Only the primary control takes the field id
358
358
  | editor | RichTextEditor |
359
359
  | chart | ChartPanel, ChartLegend, LineChart, BarChart, DoughnutChart |
360
360
 
361
- Composables: `useTheme`, `usePreset`, `useForm`, `useField`, `useFieldControl`, `useToast` (and `toast`), `useConfirm`, `useAlert`, `usePrompt`, `useModal`, `useDrawer`, `useOverlay`, `useModalContext`, `useLoading` (and `withLoading`), `useLoadingState`, `useHotkey`, `useCopy`, `useFileDrop` (with `readDroppedFiles`), `useSortable`, `usePasswordStrength`, `useTableSort`, `useAppShell`, `useScrollLock`, `useDirtyGuard`, `useIcons` helpers and `useLinkComponent`, `provideFieldBoundary`, `provideAuxiliaryControls`, `provideForm`, `useLocale`. With the Nuxt module also `useDashboard()` (runtime account, breadcrumbs and badges for the `k-dashboard` layout).
361
+ Composables: `useTheme`, `usePreset`, `useForm`, `useField`, `useFieldControl`, `useToast` (and `toast`), `useConfirm`, `useAlert`, `usePrompt`, `useModal`, `useDrawer`, `useOverlay`, `useModalContext`, `useLoading` (and `withLoading`), `useLoadingState`, `useHotkey`, `useCopy`, `useFileDrop` (with `readDroppedFiles`), `useSortable`, `usePasswordStrength`, `useTableSort`, `useAppShell`, `useRouteState`, `useScrollLock`, `useDirtyGuard`, `useIcons` helpers and `useLinkComponent`, `provideFieldBoundary`, `provideAuxiliaryControls`, `provideForm`, `useLocale`. With the Nuxt module also `useDashboard()` (runtime account, breadcrumbs and badges for the `k-dashboard` layout).
362
362
 
363
363
  ### Lists, trees and uploads
364
364
 
@@ -475,9 +475,47 @@ const confirmDiscard = () => !dirty.value || confirm({ title: 'Discard changes?'
475
475
  ```
476
476
 
477
477
  - `#title-trailing` puts badges or a status next to the title without replacing `#header`.
478
+ - `#actions` (`{ close }`) puts buttons in the header, on the right before the close button (an edit or a more menu), without replacing `#header`.
478
479
  - `size="fullscreen"` on a Modal fills the viewport edge to edge (no radius, no outer padding, safe area insets inside the panel) and never turns into a bottom sheet.
479
480
  - Overlays reset the field context: controls inside a Modal, Drawer, CommandPalette, menu, Popover or HoverCard panel do not inherit the id, description or invalid state of a `FormField` that contains the trigger. Call `provideFieldBoundary()` in your own overlay components to do the same.
480
481
 
482
+ ### Deep links
483
+
484
+ `useRouteState(key, options?)` binds a ref to one query parameter of the current URL, so any Drawer or Modal can be opened from a link, survives a reload and closes with the browser back button. It reads the router through `$router` (vue-router or Nuxt, no import of either); without a router it is a plain ref.
485
+
486
+ ```ts
487
+ const familyId = useRouteState('family')
488
+ ```
489
+
490
+ ```vue
491
+ <KButton icon="plus" @click="familyId = 'new'">New family</KButton>
492
+ <KDrawer
493
+ :open="!!familyId"
494
+ :title="familyId === 'new' ? 'New family' : family?.name"
495
+ @update:open="familyId = undefined"
496
+ >
497
+ <FamilyForm :id="familyId === 'new' ? undefined : familyId" />
498
+ </KDrawer>
499
+ ```
500
+
501
+ - Reading: the initial value comes from the URL (on the server too, so SSR renders the same state), and the ref follows every later route change (back, forward, links).
502
+ - Writing: setting the ref navigates with `router.push` (default) or `router.replace` (`history: 'replace'`, for filters or tabs that should not add history entries). The path and the other query parameters stay. `undefined`, `null` and `''` remove the parameter. Several refs changed in the same tick make one navigation. A push that returns to the previous history entry goes back instead (`router.back()`), so opening then closing a drawer leaves the history as it was, and the browser back button and the in-app close button agree.
503
+ - Types: `parse(value)` and `serialize(value)` convert the string (`parse` returning `undefined` means no value). `default` gives the value when the parameter is missing, and setting the default removes the parameter:
504
+
505
+ ```ts
506
+ const page = useRouteState('page', { parse: Number, default: 1, history: 'replace' })
507
+ const archived = useRouteState('archived', {
508
+ parse: (value) => value === '1',
509
+ serialize: (value) => (value ? '1' : undefined),
510
+ default: false,
511
+ })
512
+ ```
513
+
514
+ - Create forms: use a reserved value (`?family=new`) and branch on it, like above.
515
+ - Nested views inside one overlay: keep the path in one parameter (`?settings=users/usr_123`, `?family=fam_1/variants`) and split it on `/` in a computed. One parameter keeps every step in one history entry and avoids two refs racing. Encode ids that may contain `/` with `encodeURIComponent` per segment.
516
+ - Pages that set `definePageMeta({ key: (route) => route.fullPath })` remount on every query change; keep the default page key for pages with deep links.
517
+ - To leave the page from inside an overlay, navigate (a link or `router.push`): the new route has no parameter, so the overlay closes. Do not set the ref to `undefined` and navigate in the same tick: the later navigation cancels the earlier one.
518
+
481
519
  `CommandPalette`: items take typed `data` (`CommandItem<T>`, `CommandGroup<T>`), which reaches the `#item` slot and the `select` event typed; `emptyText` also takes `(query) => string`. Groups take a `description` (shown after the label), the `#group-label` slot (`{ group, label, description, recent }`) replaces the label, and `notice` or the `#after-results` slot (`{ query, count }`) adds a line under the results, for example "Showing the first results".
482
520
 
483
521
  - `Brand`: `logo` takes an image URL, trusted inline SVG markup (`'<svg ...>'`) or a component; the `#logo` slot replaces the boxed mark; `show-name` keeps the name visible next to a logo.
@@ -510,9 +548,10 @@ Ready defaults to start a dashboard project: an app frame, an auth frame and pag
510
548
  | `variant` | `'inset'` | `inset` (canvas sidebar, inset content panel), `sidebar` (bordered sidebar, full bleed content), `floating` (raised sidebar card on the canvas). |
511
549
  | `navigation` | | `NavItem[]` or `NavSection[]` (`{ label?, items }`). Items: `label`, `to`/`href`, `icon`, `badge`, `exact`, `active`, `external`, `disabled`, `children`. |
512
550
  | `currentPath` | router path | Active state is computed from the router (`$route`) with prefix matching (`/` and `exact` items match exactly). |
513
- | `brandName`, `brandSubtitle`, `brandIcon`, `brandLogo`, `brandShowName`, `brandTo` | `brandTo: '/'` | `brandLogo` takes an image URL, inline SVG markup or a component; the name is hidden next to a logo unless `brandShowName`. Or the `#brand` slot. |
551
+ | `brandName`, `brandSubtitle`, `brandIcon`, `brandLogo`, `brandShowName`, `brandTo` | `brandTo: '/'` | `brandLogo` takes an image URL, inline SVG markup or a component; the name is hidden next to a logo unless `brandShowName`. Or the `#brand` slot. `brandAlign` (`'start'` or `'center'`) centers the brand in the expanded sidebar, with the collapse button on the right. The collapse button uses the icons `sidebar-collapse` and `sidebar-expand` (chevrons by default), so `k.icons.aliases: { 'sidebar-collapse': 'lucide:panel-left-close', 'sidebar-expand': 'lucide:panel-left-open' }` changes only that button. |
514
552
  | `account` | | `{ name, email?, avatar?, role?, menu? }`. Shown as a row (avatar, name, email, chevron) at the bottom of the sidebar. |
515
553
  | `accountAction` | `'settings'` | `settings`: the row opens a `SettingsModal` (`settingsSections`, `settingsPresets`, `v-model:settings-open`, `v-model:settings-section`, `@sign-out`). `menu`: a DropdownMenu with `account.menu`, selections emit `account-select`. Or replace it with the `#account` slot. |
554
+ | `settingsRoute`, `settingsResolvePage` | `false` | Sync the settings modal with the URL (`?settings=users/usr_123`): `true` uses the key `settings`, a string sets the key. `settingsResolvePage(section, id, parents)` gives the label of a subpage restored from the URL. See SettingsModal. |
516
555
  | `breadcrumbs` | | Rendered in the desktop topbar. `#topbar` replaces them, `#actions` adds buttons on the right. |
517
556
  | `search` | `false` | `true` adds a CommandPalette with every navigation item, an array adds your own command groups, an async function `(query, signal) => CommandGroup<T>[]` searches on your server (item `data` reaches `#search-item` typed) (matching navigation items come first unless `searchNavigation` is `false`). `#search` replaces it. |
518
557
  | `searchProps` | | Options for the built-in CommandPalette: `minQueryLength`, `debounce`, `placeholder`, `label`, `emptyText` (a string or `(query) => string`), `minQueryText`, `errorText`, `loadingText`, `resultsText`, `notice`, `recentKey`, footer labels. Slots `#search-item`, `#search-empty`, `#search-group-label` and `#search-after-results` reach the palette. |
@@ -559,7 +598,9 @@ A large dialog (60rem) with a section nav on the left and the content on the rig
559
598
  - Built-in sections, used when no `#section-<id>` slot fills them: `account` (profile card, your `#account-fields`, a sign out button) and `appearance` (`AppearanceSettings`: theme cards light, dark, system and preset cards; `presets` limits or hides them).
560
599
  - `@sign-out` adds a Sign out item at the bottom of the nav and in the account section.
561
600
  - Labels: `title` (accessible name of the dialog, default `Settings`), `closeLabel`, `navLabel`, `signOutLabel`, `accountLabel`, `accountText`, `appearanceLabel`, `appearanceText`, `sessionLabel`, `sessionText`, `themeLabel`, `themeText`, `presetLabel`, `presetText`.
601
+ - Header actions: `#actions-<id>` renders buttons on the right of the section header row (an "Add user" button), next to the title instead of on a row of its own in the body. It stays there when a subpage is open, so render different actions per page from its `page` prop. When the content is too narrow, the actions wrap under the title. On `DashboardLayout` the slot is `#settings-actions-<id>`.
562
602
  - Subpages: `#section-<id>` and `#actions-<id>` get `page`, `pages`, `openPage({ id, label })` and `back()`. With a page open, the header title becomes the path (`Members > Grace Hopper`, same size, only the last part in the text color, earlier parts are buttons that go back to them), the section description stays, and a Back button (`backLabel`, default `common.back`) shows on the right before `#actions-<id>`. `v-model:pages` binds the stack (it also works unbound). Changing section clears it. Render the detail when `page` is set, the list otherwise.
603
+ - Deep links: `route` (`true` for the key `settings`, or your own query key, default `false`) syncs the open state, the section and the subpage stack with the URL: `?settings=users` for a section, `?settings=users/usr_123` for a subpage, deeper pages add segments. Opening, switching section, opening a subpage, Back and the crumbs push history entries, so the browser back button steps back through them and finally closes the dialog; closing removes the parameter. Loading a URL with the parameter opens the dialog at that section and subpage after mount. A section id that is not selectable falls back to the first section and the URL is corrected with `replace`. The URL holds only page ids, so `resolvePage(section, id, parents)` returns the label of a page restored from the URL: a string, `undefined` (the page and the ones after it are dropped, the URL is corrected) or a promise of either (the page opens at once with an empty label, then the label fills in). Without `resolvePage` the label is the id. Pages opened with `openPage` keep their own label. Link sections (`to`) do not close the dialog themselves when the route is synced: the navigation drops the parameter and closes it. On `DashboardLayout` the props are `settingsRoute` and `settingsResolvePage`; in the `k-dashboard` layout `settings.route` in `app.config`.
563
604
  - `hide-session` hides the Session group (sign out) in the account section; the Sign out item in the nav stays. `beforeClose` works as on Modal.
564
605
  - Accessibility: native modal `<dialog>` (focus trap, Escape, focus returns to the trigger), the nav is a labelled `nav` of buttons with `aria-current` and `aria-controls`, the content is a `section` labelled by its heading.
565
606
 
@@ -661,7 +702,7 @@ export default defineAppConfig({
661
702
  })
662
703
  ```
663
704
 
664
- The account row opens the SettingsModal (`account.action: 'menu'` with `account.menu` for a dropdown instead). Sections from `app.config` can be built-ins or links (`to`); `settings.presets` limits the preset cards, `settings.signOutTo` adds Sign out.
705
+ The account row opens the SettingsModal (`account.action: 'menu'` with `account.menu` for a dropdown instead). Sections from `app.config` can be built-ins or links (`to`); `settings.presets` limits the preset cards, `settings.signOutTo` adds Sign out, `settings.route` (`true` or a query key) syncs the modal with the URL (see SettingsModal, deep links).
665
706
 
666
707
  Pages pick them with `definePageMeta({ layout: 'k-dashboard', title: 'Items' })` or `layout: 'k-auth'` (the auth card shows `title` and `description` from the page meta). Both layouts set the document title from `meta.title` and the brand name (`Items · Acme`; a page's own `useHead({ title })` wins) and announce route changes through a polite live region, unless the app already renders `<NuxtRouteAnnouncer />`. Breadcrumbs come from `meta.breadcrumbs`, otherwise from the matching navigation item (plus `meta.title` on deeper pages). At runtime `useDashboard().value = { account, breadcrumbs, badges: { '/items': 12 } }` overrides the account, the breadcrumbs and the badges. Set it in route middleware (`definePageMeta({ middleware })`) or a plugin, not in the page `setup`: the layout renders the sidebar and breadcrumbs before the page, so a value set during the page render would differ between the server HTML and hydration.
667
708
 
@@ -708,6 +749,23 @@ Accessibility related props and defaults:
708
749
  - `DataGrid` sort is a model: `v-model:sort` (`{ column, direction } | null`) sets the sorted column from outside (server side sort, a sort restored from the URL) and follows header clicks. Leave it unset for an uncontrolled grid. `sortChange` still fires with `serverSort`.
709
750
  - `DataGrid` takes `rowHeight` and `headerHeight` (pixels) for an exact row size on top of `density`, and `headerText: (field, column) => string | undefined` to name every column that has a `field` and no `headerName` (from your i18n).
710
751
  - `DataGrid` `filterable` registers the AG Grid text, number and date filters (`registerGridFilterModules()` does it without the prop) and turns `filter` on for every column. `filterChange(model, event)` fires with `api.getFilterModel()` whenever a column filter changes, also when the filters come from `gridOptions` or your own registered modules.
752
+ - `DataGrid` `#filters` slot: put your own filter controls (Select, Combobox, DateInput bound with `v-model`) in it and the toolbar shows a square funnel button right after the search input (at the start with `:searchable="false"`), before the `actions`. The button opens a `Modal` titled "Filters" that hosts the slot, so the filters still apply live; its footer has "Reset filters" (emits `filtersReset`, disabled while `filterCount` is 0) and "Show results" (closes it). `filterCount` shows the number of active filters as a badge on the button and in its accessible name ("Filters, 2 active", `grid.filtersActive`). Slot props: `{ close, count }`. Focus returns to the button on close, and the modal becomes a bottom sheet on small screens. `GridToolbar` takes the same slot, prop and event.
753
+
754
+ ```vue
755
+ <KDataGrid
756
+ :rows="rows"
757
+ :columns="columns"
758
+ toolbar
759
+ :filter-count="[status, owner].filter(Boolean).length"
760
+ @filters-reset="status = owner = null"
761
+ >
762
+ <template #filters>
763
+ <KFormField label="Status"><KSelect v-model="status" :options="statuses" /></KFormField>
764
+ <KFormField label="Owner"><KSelect v-model="owner" :options="owners" /></KFormField>
765
+ </template>
766
+ </KDataGrid>
767
+ ```
768
+
711
769
  - `DateCell` takes `relative: true` (or `Intl.RelativeTimeFormatOptions`) in `cellRendererParams` for "3 days ago"; the absolute date stays in the `title`. `relativeWithin` (milliseconds, default unset: always relative) shows the absolute date instead once the value is further than that from now, in the past or the future (`relativeWithin: 7 * 86_400_000` keeps "3 days ago" and prints older dates in full).
712
770
  - `DataGrid` takes `gridOptions` for any AG Grid option it does not wrap (`rowHeight`, `onCellEditingStopped`, `onFilterChanged`, ...). A prop of `DataGrid` wins only when it is set: `getRowId`, `rowSelection` (when `selectable` is off), `autoSizeStrategy` (also `undefined` to turn it off), `tooltipShowDelay`, `overlayNoRowsTemplate` and `overlayLoadingTemplate` from `gridOptions` are used otherwise; `defaultColDef` and `localeText` are merged over the component defaults, and `context` is merged under the cell context. Handlers from both run.
713
771
  - `DataGrid` row ids: `getRowId: (params) => string` (wins), `rowIdKey` (a field of the row), or `gridOptions.getRowId`.
@@ -1,6 +1,10 @@
1
1
  <template>
2
2
  <div class="k-sidebar">
3
- <div v-if="$slots.header || collapsible" class="k-sidebar-header">
3
+ <div
4
+ v-if="$slots.header || collapsible"
5
+ class="k-sidebar-header"
6
+ :class="{ 'is-brand-center': brandAlign === 'center' && !isCollapsed }"
7
+ >
4
8
  <div class="k-sidebar-brand">
5
9
  <slot name="header" :collapsed="isCollapsed" />
6
10
  </div>
@@ -10,7 +14,7 @@
10
14
  variant="ghost"
11
15
  tone="neutral"
12
16
  size="xs"
13
- icon="chevron-left"
17
+ :icon="isCollapsed ? 'sidebar-expand' : 'sidebar-collapse'"
14
18
  :aria-label="collapseText"
15
19
  :aria-expanded="isCollapsed ? 'false' : 'true'"
16
20
  :aria-controls="shell.sidebarId"
@@ -43,7 +47,8 @@ import Button from "../core/Button.vue";
43
47
  const props = defineProps({
44
48
  label: { type: String, required: false },
45
49
  collapsible: { type: Boolean, required: false },
46
- collapseLabel: { type: String, required: false }
50
+ collapseLabel: { type: String, required: false },
51
+ brandAlign: { type: String, required: false, default: "start" }
47
52
  });
48
53
  const { t } = useLocale();
49
54
  const navText = computed(() => props.label ?? t("shell.main"));
@@ -1,3 +1,4 @@
1
+ import type { SidebarBrandAlign } from './types';
1
2
  declare var __VLS_1: {
2
3
  collapsed: boolean;
3
4
  }, __VLS_10: {
@@ -20,6 +21,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
20
21
  label?: string;
21
22
  collapsible?: boolean;
22
23
  collapseLabel?: string;
24
+ brandAlign?: SidebarBrandAlign;
23
25
  innerHTML?: string | undefined | undefined;
24
26
  class?: import("vue").ClassValue;
25
27
  style?: import("vue").StyleValue;
@@ -216,6 +218,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
216
218
  label?: string;
217
219
  collapsible?: boolean;
218
220
  collapseLabel?: string;
221
+ brandAlign?: SidebarBrandAlign;
219
222
  innerHTML?: string | undefined | undefined;
220
223
  class?: import("vue").ClassValue;
221
224
  style?: import("vue").StyleValue;
@@ -408,7 +411,9 @@ declare const __VLS_base: import("vue").DefineComponent<{
408
411
  ref?: import("vue").VNodeRef | undefined;
409
412
  ref_for?: boolean | undefined | undefined;
410
413
  ref_key?: string | undefined | undefined;
411
- }> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
414
+ }> & Readonly<{}>, {
415
+ brandAlign: SidebarBrandAlign;
416
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
412
417
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
413
418
  declare const _default: typeof __VLS_export;
414
419
  export default _default;
@@ -3,6 +3,7 @@ import type { LinkTarget, Tone } from '../core/types';
3
3
  export type LayoutGap = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
4
4
  export type LayoutAlign = 'start' | 'center' | 'end' | 'stretch' | 'baseline';
5
5
  export type LayoutJustify = 'start' | 'center' | 'end' | 'between' | 'around';
6
+ export type SidebarBrandAlign = 'start' | 'center';
6
7
  export interface GridColumns {
7
8
  base?: number;
8
9
  sm?: number;
@@ -18,7 +18,12 @@
18
18
  :view-transition="viewTransition"
19
19
  >
20
20
  <template #sidebar="{ collapsed: isCollapsed }">
21
- <Sidebar :label="navLabel" :collapsible="collapsible" :collapse-label="collapseLabel">
21
+ <Sidebar
22
+ :label="navLabel"
23
+ :collapsible="collapsible"
24
+ :collapse-label="collapseLabel"
25
+ :brand-align="brandAlign"
26
+ >
22
27
  <template #header>
23
28
  <slot name="brand" :collapsed="isCollapsed">
24
29
  <Brand
@@ -140,6 +145,8 @@
140
145
  :presets="settingsPresets"
141
146
  :title="settingsTitleText"
142
147
  :on-sign-out="onSignOut"
148
+ :route="settingsRoute"
149
+ :resolve-page="settingsResolvePage"
143
150
  >
144
151
  <template v-if="$slots['settings-account-fields']" #account-fields="scope">
145
152
  <slot name="settings-account-fields" v-bind="scope" />
@@ -176,11 +183,14 @@ const props = defineProps({
176
183
  brandLogo: { type: null, required: false },
177
184
  brandShowName: { type: Boolean, required: false },
178
185
  brandTo: { type: [String, Object], required: false, default: "/" },
186
+ brandAlign: { type: String, required: false },
179
187
  account: { type: Object, required: false },
180
188
  accountAction: { type: String, required: false, default: "settings" },
181
189
  settingsSections: { type: Array, required: false, default: void 0 },
182
190
  settingsPresets: { type: [Array, Boolean], required: false, default: void 0 },
183
191
  settingsTitle: { type: String, required: false },
192
+ settingsRoute: { type: [String, Boolean], required: false, default: false },
193
+ settingsResolvePage: { type: Function, required: false },
184
194
  onSignOut: { type: Function, required: false },
185
195
  breadcrumbs: { type: Array, required: false },
186
196
  search: { type: [Boolean, Array, Function], required: false },
@@ -1,9 +1,9 @@
1
1
  import type { IconName } from '../../composables/useIcons';
2
- import type { BreadcrumbItem, ShellContent } from '../layout/types';
2
+ import type { BreadcrumbItem, ShellContent, SidebarBrandAlign } from '../layout/types';
3
3
  import type { CommandGroupLabelSlotProps, CommandItem, MenuItem } from '../overlays/types';
4
4
  import type { ThemePreset } from '../../composables/usePreset';
5
5
  import type { LinkTarget } from '../core/types';
6
- import type { AccountAction, BrandLogo, DashboardAccount, DashboardNavigation, DashboardSearch, DashboardSearchProps, DashboardVariant, SettingsModalAccount, SettingsModalSection, SettingsSectionSlotProps, ThemeSwitchPlacement } from './types';
6
+ import type { AccountAction, BrandLogo, DashboardAccount, DashboardNavigation, DashboardSearch, DashboardSearchProps, DashboardVariant, SettingsModalAccount, SettingsModalSection, SettingsPageResolver, SettingsSectionSlotProps, ThemeSwitchPlacement } from './types';
7
7
  declare const __VLS_export: <T = unknown>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
8
8
  props: import("vue").PublicProps & __VLS_PrettifyLocal<({
9
9
  variant?: DashboardVariant;
@@ -15,11 +15,14 @@ declare const __VLS_export: <T = unknown>(__VLS_props: NonNullable<Awaited<typeo
15
15
  brandLogo?: BrandLogo;
16
16
  brandShowName?: boolean;
17
17
  brandTo?: LinkTarget;
18
+ brandAlign?: SidebarBrandAlign;
18
19
  account?: DashboardAccount;
19
20
  accountAction?: AccountAction;
20
21
  settingsSections?: SettingsModalSection[];
21
22
  settingsPresets?: readonly ThemePreset[] | false;
22
23
  settingsTitle?: string;
24
+ settingsRoute?: string | boolean;
25
+ settingsResolvePage?: SettingsPageResolver;
23
26
  onSignOut?: () => void;
24
27
  breadcrumbs?: BreadcrumbItem[];
25
28
  search?: DashboardSearch<T>;