@xleddyl/443-components-vue 0.8.1 → 0.8.2

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 (147) hide show
  1. package/README.md +34 -1
  2. package/dist/chart/BarChart.vue +33 -22
  3. package/dist/chart/BarChart.vue.d.ts +4 -0
  4. package/dist/chart/chart.css +2 -2
  5. package/dist/chart/useChartColors.mjs +8 -8
  6. package/dist/components/core/Button.vue.d.ts +1 -1
  7. package/dist/components/core/Input.vue.d.ts +1 -1
  8. package/dist/components/core/Textarea.vue.d.ts +1 -1
  9. package/dist/components/core/types.d.ts +1 -1
  10. package/dist/components/data/Badge.vue.d.ts +1 -1
  11. package/dist/components/data/FilterPills.vue +43 -4
  12. package/dist/components/data/FilterPills.vue.d.ts +4 -1
  13. package/dist/components/data/Pagination.vue +55 -0
  14. package/dist/components/data/Pagination.vue.d.ts +10 -0
  15. package/dist/components/data/Tag.vue.d.ts +1 -1
  16. package/dist/components/data/Tree.vue.d.ts +1 -1
  17. package/dist/components/data/types.d.ts +1 -0
  18. package/dist/components/feedback/Meter.vue.d.ts +1 -1
  19. package/dist/components/feedback/Progress.vue.d.ts +1 -1
  20. package/dist/components/feedback/ProgressRing.vue.d.ts +1 -1
  21. package/dist/components/forms/Calendar.vue +31 -7
  22. package/dist/components/forms/Calendar.vue.d.ts +13 -2
  23. package/dist/components/forms/ColorInput.vue.d.ts +1 -1
  24. package/dist/components/forms/DateInput.vue.d.ts +2 -2
  25. package/dist/components/forms/DatePicker.vue.d.ts +1 -1
  26. package/dist/components/forms/FileInput.vue.d.ts +1 -1
  27. package/dist/components/forms/NumberInput.vue.d.ts +1 -1
  28. package/dist/components/forms/PasswordInput.vue.d.ts +1 -1
  29. package/dist/components/forms/PinInput.vue.d.ts +1 -1
  30. package/dist/components/forms/Select.vue.d.ts +1 -1
  31. package/dist/components/forms/Slider.vue.d.ts +1 -1
  32. package/dist/components/forms/Switch.vue.d.ts +1 -1
  33. package/dist/components/forms/TimeInput.vue.d.ts +1 -1
  34. package/dist/components/layout/AppShell.vue +4 -2
  35. package/dist/components/layout/AppShell.vue.d.ts +2 -0
  36. package/dist/components/layout/CopyButton.vue.d.ts +1 -1
  37. package/dist/components/layout/PageHeader.vue +15 -3
  38. package/dist/components/layout/PageHeader.vue.d.ts +5 -0
  39. package/dist/components/layout/Separator.vue +17 -4
  40. package/dist/components/layout/Separator.vue.d.ts +7 -1
  41. package/dist/components/layout/Tabs.vue +10 -0
  42. package/dist/components/layout/types.d.ts +3 -0
  43. package/dist/components/overlays/ConfirmDialog.vue.d.ts +6 -2
  44. package/dist/components/overlays/ConfirmHost.vue.d.ts +6 -2
  45. package/dist/components/overlays/ContextMenu.vue.d.ts +2 -0
  46. package/dist/components/overlays/DropdownMenu.vue +5 -1
  47. package/dist/components/overlays/DropdownMenu.vue.d.ts +6 -0
  48. package/dist/components/overlays/Modal.vue +9 -2
  49. package/dist/components/overlays/Modal.vue.d.ts +4 -0
  50. package/dist/components/templates/DashboardLayout.vue +2 -0
  51. package/dist/components/templates/DashboardLayout.vue.d.ts +2 -0
  52. package/dist/components/templates/SettingsModal.vue.d.ts +6 -2
  53. package/dist/components/templates/types.d.ts +1 -0
  54. package/dist/composables/useForm.d.ts +16 -1
  55. package/dist/composables/useForm.mjs +31 -6
  56. package/dist/editor/RichTextEditor.vue +13 -1
  57. package/dist/editor/RichTextEditor.vue.d.ts +1 -1
  58. package/dist/editor/rich-text-editor.css +10 -4
  59. package/dist/editor/types.d.ts +1 -1
  60. package/dist/grid/DataGrid.vue +60 -8
  61. package/dist/grid/DataGrid.vue.d.ts +9 -2
  62. package/dist/grid/cells/DateCell.vue +18 -3
  63. package/dist/grid/data-grid.css +1 -1
  64. package/dist/grid/index.d.ts +1 -1
  65. package/dist/grid/index.mjs +1 -1
  66. package/dist/grid/modules.d.ts +1 -0
  67. package/dist/grid/modules.mjs +9 -0
  68. package/dist/grid/theme.mjs +4 -4
  69. package/dist/grid/types.d.ts +1 -0
  70. package/dist/icons/builtin.d.ts +3 -0
  71. package/dist/icons/builtin.mjs +3 -0
  72. package/dist/index.d.ts +1 -1
  73. package/dist/index.mjs +1 -0
  74. package/dist/internal/core/intl.d.ts +2 -0
  75. package/dist/internal/core/intl.mjs +17 -0
  76. package/dist/internal/keys.d.ts +2 -1
  77. package/dist/internal/keys.mjs +1 -0
  78. package/dist/internal/overlays/MenuList.vue +4 -2
  79. package/dist/internal/overlays/MenuList.vue.d.ts +2 -0
  80. package/dist/internal/overlays/OverlayView.vue.d.ts +6 -2
  81. package/dist/locale/de.mjs +10 -2
  82. package/dist/locale/en.mjs +10 -2
  83. package/dist/locale/it.mjs +10 -2
  84. package/dist/locale/types.d.ts +8 -0
  85. package/dist/nuxt/runtime/layouts/dashboard.vue +1 -0
  86. package/dist/styles/base.css +2 -1
  87. package/dist/styles/core/button.css +42 -16
  88. package/dist/styles/core/form-field.css +1 -1
  89. package/dist/styles/core/input.css +2 -2
  90. package/dist/styles/core/kbd.css +1 -1
  91. package/dist/styles/data/avatar.css +1 -1
  92. package/dist/styles/data/badge.css +39 -23
  93. package/dist/styles/data/description-list.css +2 -2
  94. package/dist/styles/data/filter-pills.css +24 -3
  95. package/dist/styles/data/pagination.css +26 -3
  96. package/dist/styles/data/selection-bar.css +1 -1
  97. package/dist/styles/data/stat.css +4 -4
  98. package/dist/styles/data/table.css +4 -4
  99. package/dist/styles/data/tag.css +1 -1
  100. package/dist/styles/data/timeline.css +1 -1
  101. package/dist/styles/data/tree.css +2 -2
  102. package/dist/styles/feedback/empty-state.css +1 -1
  103. package/dist/styles/feedback/loading-host.css +1 -1
  104. package/dist/styles/feedback/loading-overlay.css +1 -1
  105. package/dist/styles/feedback/meter.css +1 -1
  106. package/dist/styles/feedback/progress.css +2 -2
  107. package/dist/styles/forced-colors.css +6 -1
  108. package/dist/styles/forms/calendar.css +30 -3
  109. package/dist/styles/forms/checkbox.css +1 -1
  110. package/dist/styles/forms/choice.css +1 -1
  111. package/dist/styles/forms/combobox.css +2 -2
  112. package/dist/styles/forms/file-input.css +1 -1
  113. package/dist/styles/forms/password-input.css +1 -1
  114. package/dist/styles/forms/pin-input.css +1 -1
  115. package/dist/styles/forms/radio.css +1 -1
  116. package/dist/styles/forms/segmented.css +2 -2
  117. package/dist/styles/forms/select.css +2 -2
  118. package/dist/styles/forms/slider.css +1 -1
  119. package/dist/styles/forms/switch.css +4 -4
  120. package/dist/styles/layout/accordion.css +2 -2
  121. package/dist/styles/layout/app-shell.css +18 -6
  122. package/dist/styles/layout/breadcrumbs.css +3 -3
  123. package/dist/styles/layout/card.css +1 -1
  124. package/dist/styles/layout/nav-link.css +1 -1
  125. package/dist/styles/layout/page-header.css +21 -1
  126. package/dist/styles/layout/separator.css +21 -1
  127. package/dist/styles/layout/sidebar.css +1 -1
  128. package/dist/styles/layout/tabs.css +30 -1
  129. package/dist/styles/layout/theme-switch.css +1 -1
  130. package/dist/styles/overlays/command.css +3 -3
  131. package/dist/styles/overlays/drawer.css +4 -3
  132. package/dist/styles/overlays/floating.css +2 -2
  133. package/dist/styles/overlays/menu.css +5 -1
  134. package/dist/styles/overlays/modal.css +12 -9
  135. package/dist/styles/overlays/toast.css +3 -3
  136. package/dist/styles/overlays/tooltip.css +26 -8
  137. package/dist/styles/shared.css +2 -2
  138. package/dist/styles/templates/account-menu.css +1 -1
  139. package/dist/styles/templates/auth-layout.css +4 -4
  140. package/dist/styles/templates/brand.css +2 -2
  141. package/dist/styles/templates/dashboard-page.css +1 -1
  142. package/dist/styles/templates/empty-page.css +3 -3
  143. package/dist/styles/templates/error-page.css +1 -1
  144. package/dist/styles/templates/save-bar.css +1 -1
  145. package/dist/styles/templates/settings-modal.css +6 -6
  146. package/dist/styles/utilities.css +3 -3
  147. package/package.json +1 -1
package/README.md CHANGED
@@ -108,7 +108,22 @@ Tokens live on `.k-root`, never on `:root`. Override them on a root element: Roo
108
108
 
109
109
  Input tokens, declared only on the outermost root so nested roots inherit them: `--k-accent`, `--k-accent-contrast`, `--k-font-sans`, `--k-font-mono`, `--k-font-size`, `--k-font-features`, `--k-line-height`, `--k-radius-scale`. Every other token (surfaces, text, lines, accent shades, status colors, radii, shadows, motion) is derived per root, so a nested root with its own `theme` or `accent` re-themes a region. The full list is in [CONVENTIONS.md](./CONVENTIONS.md#tokens).
110
110
 
111
- A few component tokens are unset by default and only exist to be overridden on a root: `--k-scrim-blur` (backdrop blur of Modal and Drawer, `3px`), `--k-badge-radius` (Badge corners, `--k-radius-full`), `--k-grid-header-background`, `--k-grid-header-text` and `--k-grid-header-font` (DataGrid header, `--k-subtle`, `--k-text-muted` and `--k-font-sans`).
111
+ A few component tokens are unset by default and only exist to be overridden on a root (or any ancestor). Unset, every one keeps the library look. The full list with defaults is in [CONVENTIONS.md](./CONVENTIONS.md#tokens):
112
+
113
+ | Area | Tokens |
114
+ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115
+ | Type | `--k-font-weight` (400), `--k-font-weight-medium` (500), `--k-font-weight-strong` (600), `--k-font-weight-display` (650) |
116
+ | Buttons | `--k-btn-highlight`, `--k-btn-shadow` (`0 0 #0000` for a flat button), `--k-btn-border`, `--k-btn-padding-x`, `--k-btn-font-size`, `--k-btn-icon-size`, `--k-press-scale` (0.97) |
117
+ | Fields | `--k-field-padding-x` |
118
+ | 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) |
119
+ | Tooltip | `--k-tooltip-background`, `--k-tooltip-text`, `--k-tooltip-border`, `--k-tooltip-radius`, `--k-tooltip-shadow`, `--k-tooltip-padding` |
120
+ | Shell | `--k-sidebar-width` (15rem), `--k-sidebar-rail-width`, `--k-topbar-height` (3rem), `--k-shell-inset`, `--k-shell-padding`, `--k-shell-content` |
121
+ | Switch | `--k-switch-track-width`, `--k-switch-track-height`, `--k-switch-thumb-size` (md size) |
122
+ | Badge | `--k-badge-radius`, `--k-badge-font`, `--k-badge-font-size`, `--k-badge-font-weight`, `--k-badge-text-transform`, `--k-badge-letter-spacing` |
123
+ | DataGrid | `--k-grid-header-background`, `--k-grid-header-text`, `--k-grid-header-font`, `--k-grid-header-font-weight`, `--k-grid-font-size` (13px), `--k-grid-radius`, `--k-grid-selected-background` |
124
+ | Charts | `--k-chart-1` to `--k-chart-8` (series palette) |
125
+
126
+ Some tokens are meant for one element: set `--k-btn-tone`, `--k-btn-on-tone` and `--k-btn-tone-text` on a button for a brand tone outside `Tone` (a lime fill with green text), and `--k-badge-background`, `--k-badge-color` and `--k-badge-border-color` on a badge for a custom pill color. `variant="subtle"` is a borderless tinted fill (`--k-fill` for the neutral tone).
112
127
 
113
128
  Contrast is part of the tokens: `--k-text-muted` is the lightest text color (4.5:1), `--k-text-dimmed` is for icons and decoration (3:1), `--k-ring` is an opaque focus color (3:1 on every surface), and `--k-danger-text`, `--k-success-text`, `--k-warning-text`, `--k-info-text` color status text (4.5:1, also on soft tints). Every preset sets them for light and dark; keep the same ratios when you override them.
114
129
 
@@ -232,6 +247,8 @@ Issues are keyed by their first path segment and by their full dotted path (`blo
232
247
 
233
248
  Built-in messages follow the active language. `messages` overrides them for one form.
234
249
 
250
+ Rules that return message keys instead of text (an existing validator library, server side codes) go through `translateMessage(message, { name, label, kind })`: it receives every string returned by a `validate` function, a field `schema`, the form `validator` and `warnings` (`kind` is `'error'` or `'warning'`), and returns the text to show. Built-in messages are not passed to it. Set `translateMessage` and `messages` once for the whole app with `app.use(createFormConfig({ translateMessage: (key) => i18n.t(key), messages: { required: () => i18n.t('form.required') } }))`, or `provideFormConfig()` in a component; the options of one `useForm` still win.
251
+
235
252
  Forms can also drive values they do not own. Pass `values` (a reactive object, ref or getter) and the form reads, validates, tracks dirty state and submits it. The schema becomes optional and only adds rules, labels and `required`; its `initial` values are not used. `reset()` restores the clean snapshot, `reset(next)` replaces the values and makes them the new clean state (`form.reset(record.value)` after a save). `validator` accepts a ref or getter, so it can change with the record type:
236
253
 
237
254
  ```ts
@@ -296,6 +313,17 @@ Composables: `useTheme`, `usePreset`, `useForm`, `useField`, `useFieldControl`,
296
313
  ### Lists, trees and uploads
297
314
 
298
315
  - `Tree` takes `size="sm"` for dense rows, `checkmark`, `descriptionVariant` (`mono`, the default for paths and slugs, or `text`; a node can override it with its own `descriptionVariant`), `emptyText` (or `#empty`) and works inside a `FormField` (labelled and described by the field). With `reorderable` rows get a drag handle and Alt with the up and down arrows moves them; `nestable` also lets rows change level (drop in the middle of a row, Alt with left and right). The `move` event carries `{ node, target, position, from: { parent, index }, to: { parent, index } }`, `to.index` being the final index, and `applyTreeMove(nodes, move)` returns the updated tree. `canDrop(move)` vetoes a move. Moves are announced to screen readers.
316
+ - `Select` takes string, number or boolean option values (`{ value: true, label: 'Yes' }`); the model gets the option value back with its type.
317
+ - `Pagination` takes `showEdges` (first and last page buttons, `firstLabel`, `lastLabel`) and `showJump` (a typed page number, `jumpLabel`). Both are off by default.
318
+ - `FilterPills` can list active filters: options with `removable: true` render as active pills with a remove button (`removeLabel`, a `'Remove {label}'` template). Clicking the pill emits `select(value)`, the button emits `remove(value)` (and drops the value from the model when it is selected); focus moves to the next pill when the removed one disappears.
319
+ - `Calendar` takes `dayText: (iso) => string | undefined`, a short line under each day number that is also added to the day's accessible name (availability, prices). The `#day` slot (`{ date, number, text, selected, unavailable, inMonth }`) replaces the cell content; it is decorative, so announced text still comes from `dayText`.
320
+ - `Separator` takes `description` (or `#description`) under its label, and an `#actions` slot rendered next to them (a small add or edit button).
321
+ - `Modal` takes `width` (any CSS length, overrides `size`) and `minHeight` (keeps the height steady while tabs or steps change). The size widths are tokens: `--k-modal-width-sm` (26rem), `--k-modal-width-md` (32rem), `--k-modal-width-lg` (50rem), `--k-modal-width-xl` (64rem).
322
+ - `Tabs` items take `dot: true` for a small indicator without a number (`dotTone`, default `danger`; `dotLabel` is the hidden text, default "Needs attention").
323
+ - `DropdownMenu` takes `matchTriggerWidth` (the menu is at least as wide as its trigger) and `minWidth` (a CSS length).
324
+ - `PageHeader` takes `align` (`'end'` by default, `'start'` or `'center'`) for the title block and the actions, and `truncate` to keep the title on one line with an ellipsis (the full title is in its `title` attribute).
325
+ - `RichTextEditor` accepts `'underline'` in `toolbar` (not in the default toolbar).
326
+ - `BarChart` takes `colorByPoint` (every bar of a series takes the next palette color, or one from `colors: string[]`; the legend lists and toggles the categories). The palette comes from `--k-chart-1` to `--k-chart-8`.
299
327
  - `SelectionBar` shows a plural aware selected count (announced in a live region), select all (`total` plus `@select-all`) and clear (`@clear`) actions, an `#actions` slot and `placement` `inline`, `sticky` or `floating`. With `count` 0 it renders no box (only its live region), so it can sit in a flex toolbar without adding a gap; the first count after mount is announced too. `ListPage` renders it for `#bulk`.
300
328
  - `FilterPills` is generic: the value type comes from the options, `multiple` makes the model an array and `required` drops `null` from it (like `SegmentedControl`). Options take `menu` items (a dropdown trigger showing `valueLabel`) or `panel: true`, which opens a popover with the `#panel-<value>` slot (`{ option, active, toggle, close }`, `panelLabel` names it). The `#pill` slot renders any trigger and its scope has `defaultPill`, a component that renders the built-in pill for that option, so one custom pill does not mean rewriting the others: `<component :is="defaultPill" v-else />`. `FilterPill` is exported so custom triggers match the other pills.
301
329
  - `SegmentedControl` with `required` narrows `v-model` to a non null value. Options take `title` (tooltip and description) and `muted`, and the `#option` slot replaces the content of each option.
@@ -412,6 +440,7 @@ Ready defaults to start a dashboard project: an app frame, an auth frame and pag
412
440
  | `shortcut` | `'mod+b'` | Toggles the rail on desktop and the drawer on mobile. `searchShortcut` defaults to `mod+k`. |
413
441
  | `v-model:open` | `false` | Mobile drawer (below 768px of shell width): scrim, focus moves into the drawer, the content is `inert`, Escape and the scrim close it and focus returns to the burger. |
414
442
  | `fluid`, `viewTransition` | `false`, `true` | Full width content; `view-transition-name` on sidebar and panel so page transitions keep the frame still. |
443
+ | `fill` | `false` | Full height, full bleed content: no padding, gap or max width, and the content fills the panel (a page that is one DataGrid with `height="100%"`). Also on `AppShell`; in the `k-dashboard` layout per page with `definePageMeta({ fill: true })` or for every page with `dashboard.fill`. |
415
444
 
416
445
  Slots: `brand`, `search`, `sidebar` (replaces the navigation), `sidebar-footer`, `account`, `topbar-brand`, `topbar`, `actions`, default, plus `settings-section-<id>`, `settings-actions-<id>` and `settings-account-fields`, forwarded to the SettingsModal. The exposed `openSettings(id?)` opens it on a section. Landmarks: skip link, `aside` and `nav` with labels, `main` with an id, `aria-current="page"` on the active link. `SidebarNav` (layout group) renders the same navigation data inside your own `Sidebar`.
417
446
 
@@ -593,6 +622,10 @@ Accessibility related props and defaults:
593
622
  - Copy props that contain a value are templates: `removeLabel` (`'Remove {label}'`) on `Tag`, `Combobox` and `FileInput`, `moreLabel` (`'{count} more'`) on `AvatarGroup`, `pageLabel` (`'Page {page}'`) on `Pagination`. `ListPage` takes `resultsText: (count) => string` for the announced result count, `ColorInput` takes `invalidText`.
594
623
  - `ColorInput` `swatches` accept `{ value, label }` objects (a radio group named by `label` or the hex). `PasswordInput` picks `autocomplete="new-password"` with `generate` or `strength`, `current-password` otherwise.
595
624
  - `Tree` with `reorderable` shows small move buttons (up, down, indent, outdent) on the hovered or focused row, as a single pointer alternative to dragging. Set `patterns` on `LineChart` and `BarChart` to tell series apart without color (dash and point style per line, a fill pattern per bar series, mirrored in the legend); it is off by default.
625
+ - `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`.
626
+ - `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).
627
+ - `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.
628
+ - `DateCell` takes `relative: true` (or `Intl.RelativeTimeFormatOptions`) in `cellRendererParams` for "3 days ago"; the absolute date stays in the `title`.
596
629
  - `DataGrid` takes `gridOptions` for any AG Grid option it does not wrap (`rowHeight`, `onCellEditingStopped`, `onFilterChanged`, ...). They are applied before the props of `DataGrid`, so its own props win, and handlers from both run.
597
630
  - `DataGrid` translates the AG Grid ARIA strings through the catalog (`grid.*`; your own `localeText` still wins) and announces row count changes.
598
631
 
@@ -35,40 +35,51 @@ const props = defineProps({
35
35
  horizontal: { type: Boolean, required: false },
36
36
  patterns: { type: Boolean, required: false },
37
37
  formatValue: { type: Function, required: false },
38
- options: { type: null, required: false }
38
+ options: { type: null, required: false },
39
+ colorByPoint: { type: Boolean, required: false },
40
+ colors: { type: Array, required: false }
39
41
  });
40
42
  const { colors, reducedMotion, ready, colorAt, isHidden, toggle } = useChartSurface(
41
43
  useTemplateRef("root"),
42
44
  {
43
- color: (index) => props.series[index]?.color,
44
- key: (index) => props.series[index]?.label
45
+ color: (index) => props.colorByPoint ? props.colors?.[index] : props.series[index]?.color,
46
+ key: (index) => props.colorByPoint ? props.labels[index] : props.series[index]?.label
45
47
  }
46
48
  );
47
49
  const legendItems = computed(
48
- () => props.series.map((entry, index) => ({
49
- label: entry.label,
50
- color: colorAt(index),
51
- hidden: isHidden(index),
52
- pattern: props.patterns ? seriesPattern(index) : void 0
53
- }))
50
+ () => (props.colorByPoint ? props.labels : props.series.map((entry) => entry.label)).map(
51
+ (label, index) => ({
52
+ label,
53
+ color: colorAt(index),
54
+ hidden: isHidden(index),
55
+ pattern: props.patterns ? seriesPattern(index) : void 0
56
+ })
57
+ )
58
+ );
59
+ const visibleIndexes = computed(
60
+ () => props.labels.map((_, index) => index).filter((index) => !props.colorByPoint || !isHidden(index))
54
61
  );
55
62
  function fillAt(index) {
56
63
  const color = colorAt(index);
57
64
  return props.patterns ? barFill(color, seriesPattern(index), colors.value.surface) : color;
58
65
  }
59
- const chartData = computed(() => ({
60
- labels: props.labels,
61
- datasets: props.series.map((entry, index) => ({
62
- label: entry.label,
63
- data: entry.data,
64
- hidden: isHidden(index),
65
- backgroundColor: fillAt(index),
66
- hoverBackgroundColor: fillAt(index),
67
- borderRadius: 4,
68
- borderSkipped: false,
69
- maxBarThickness: 36
70
- }))
71
- }));
66
+ const chartData = computed(() => {
67
+ const indexes = visibleIndexes.value;
68
+ const pointFills = props.colorByPoint ? indexes.map(fillAt) : void 0;
69
+ return {
70
+ labels: props.colorByPoint ? indexes.map((index) => props.labels[index] ?? "") : props.labels,
71
+ datasets: props.series.map((entry, index) => ({
72
+ label: entry.label,
73
+ data: props.colorByPoint ? indexes.map((point) => entry.data[point] ?? null) : entry.data,
74
+ hidden: props.colorByPoint ? false : isHidden(index),
75
+ backgroundColor: pointFills ?? fillAt(index),
76
+ hoverBackgroundColor: pointFills ?? fillAt(index),
77
+ borderRadius: 4,
78
+ borderSkipped: false,
79
+ maxBarThickness: 36
80
+ }))
81
+ };
82
+ });
72
83
  const chartOptions = computed(
73
84
  () => buildCartesianOptions(
74
85
  {
@@ -12,6 +12,8 @@ declare const __VLS_export: import("vue").DefineComponent<{
12
12
  patterns?: boolean;
13
13
  formatValue?: ChartValueFormatter;
14
14
  options?: ChartOptions<"bar">;
15
+ colorByPoint?: boolean;
16
+ colors?: string[];
15
17
  innerHTML?: string | undefined | undefined;
16
18
  class?: import("vue").ClassValue;
17
19
  style?: import("vue").StyleValue;
@@ -216,6 +218,8 @@ declare const __VLS_export: import("vue").DefineComponent<{
216
218
  patterns?: boolean;
217
219
  formatValue?: ChartValueFormatter;
218
220
  options?: ChartOptions<"bar">;
221
+ colorByPoint?: boolean;
222
+ colors?: string[];
219
223
  innerHTML?: string | undefined | undefined;
220
224
  class?: import("vue").ClassValue;
221
225
  style?: import("vue").StyleValue;
@@ -24,7 +24,7 @@
24
24
  .k-chart-panel-title {
25
25
  margin: 0;
26
26
  font-size: 0.9375rem;
27
- font-weight: 600;
27
+ font-weight: var(--k-font-weight-strong, 600);
28
28
  letter-spacing: -0.015em;
29
29
  color: var(--k-text);
30
30
  }
@@ -156,7 +156,7 @@
156
156
  }
157
157
 
158
158
  .k-chart-legend-item:active {
159
- scale: 0.97;
159
+ scale: var(--k-press-scale, 0.97);
160
160
  }
161
161
 
162
162
  .k-chart-legend-item.is-hidden {
@@ -23,14 +23,14 @@ const fallbackColors = {
23
23
  fontFamily: "ui-sans-serif, system-ui, sans-serif"
24
24
  };
25
25
  const seriesExpressions = [
26
- "var(--k-accent)",
27
- "var(--k-info)",
28
- "var(--k-success)",
29
- "var(--k-warning)",
30
- "var(--k-danger)",
31
- "color-mix(in oklab, var(--k-accent) 55%, var(--k-danger))",
32
- "color-mix(in oklab, var(--k-info) 55%, var(--k-success))",
33
- "color-mix(in oklab, var(--k-warning) 50%, var(--k-success))"
26
+ "var(--k-chart-1, var(--k-accent))",
27
+ "var(--k-chart-2, var(--k-info))",
28
+ "var(--k-chart-3, var(--k-success))",
29
+ "var(--k-chart-4, var(--k-warning))",
30
+ "var(--k-chart-5, var(--k-danger))",
31
+ "var(--k-chart-6, color-mix(in oklab, var(--k-accent) 55%, var(--k-danger)))",
32
+ "var(--k-chart-7, color-mix(in oklab, var(--k-info) 55%, var(--k-success)))",
33
+ "var(--k-chart-8, color-mix(in oklab, var(--k-warning) 50%, var(--k-success)))"
34
34
  ];
35
35
  let normalizeContext;
36
36
  function normalize(color) {
@@ -459,8 +459,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
459
459
  popovertarget?: string | undefined;
460
460
  popovertargetaction?: import("../../index.ts").PopoverTargetAction | undefined;
461
461
  }> & Readonly<{}>, {
462
- tone: Tone;
463
462
  size: ButtonSize;
463
+ tone: Tone;
464
464
  type: "submit" | "button" | "reset";
465
465
  variant: ButtonVariant;
466
466
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -489,8 +489,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
489
489
  onClear?: (() => any) | undefined;
490
490
  "onUpdate:modelValue"?: ((value: string | number | null | undefined) => any) | undefined;
491
491
  }>, {
492
- invalid: boolean;
493
492
  size: FieldSize;
493
+ invalid: boolean;
494
494
  type: string;
495
495
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
496
496
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -439,8 +439,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
439
439
  }> & Readonly<{
440
440
  "onUpdate:modelValue"?: ((value: string | null | undefined) => any) | undefined;
441
441
  }>, {
442
- invalid: boolean;
443
442
  size: FieldSize;
443
+ invalid: boolean;
444
444
  rows: number;
445
445
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
446
446
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -1,5 +1,5 @@
1
1
  export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
2
2
  export type Tone = 'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger';
3
- export type ButtonVariant = 'solid' | 'soft' | 'outline' | 'ghost' | 'link';
3
+ export type ButtonVariant = 'solid' | 'soft' | 'subtle' | 'outline' | 'ghost' | 'link';
4
4
  export type FieldSize = 'sm' | 'md' | 'lg';
5
5
  export type LinkTarget = string | Record<string, unknown>;
@@ -406,8 +406,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
406
406
  ref_for?: boolean | undefined | undefined;
407
407
  ref_key?: string | undefined | undefined;
408
408
  }> & Readonly<{}>, {
409
- tone: Tone;
410
409
  size: BadgeSize;
410
+ tone: Tone;
411
411
  variant: BadgeVariant;
412
412
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
413
413
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -34,6 +34,7 @@
34
34
  <script setup>
35
35
  import { computed, h, nextTick, ref, useTemplateRef, watch } from "vue";
36
36
  import { useLocale } from "../../composables/useLocale";
37
+ import { translateOr } from "../../locale";
37
38
  import { hasFocusWithin } from "../../internal/core/focus";
38
39
  import Button from "../core/Button.vue";
39
40
  import DropdownMenu from "../overlays/DropdownMenu.vue";
@@ -46,10 +47,12 @@ const props = defineProps({
46
47
  size: { type: String, required: false, default: "md" },
47
48
  clearable: { type: Boolean, required: false },
48
49
  clearLabel: { type: String, required: false },
50
+ removeLabel: { type: String, required: false },
49
51
  disabled: { type: Boolean, required: false },
50
52
  required: { type: null, required: false }
51
53
  });
52
- const { t } = useLocale();
54
+ const emit = defineEmits(["select", "remove"]);
55
+ const { t, locale } = useLocale();
53
56
  const groupLabel = computed(() => props.label ?? t("filterPills.label"));
54
57
  const clearText = computed(() => props.clearLabel ?? t("common.clear"));
55
58
  const slots = defineSlots();
@@ -82,10 +85,10 @@ function toggle(value) {
82
85
  setModel(active ? null : value);
83
86
  }
84
87
  const root = useTemplateRef("root");
85
- async function clear() {
88
+ async function keepFocus(change) {
86
89
  const group = root.value;
87
90
  const hadFocus = hasFocusWithin(group);
88
- setModel(props.multiple ? [] : null);
91
+ change();
89
92
  if (!hadFocus || !group) return;
90
93
  await nextTick();
91
94
  if (hasFocusWithin(group)) return;
@@ -98,6 +101,35 @@ async function clear() {
98
101
  group.focus({ preventScroll: true });
99
102
  }
100
103
  }
104
+ function clear() {
105
+ return keepFocus(() => setModel(props.multiple ? [] : null));
106
+ }
107
+ function remove(value) {
108
+ return keepFocus(() => {
109
+ const rest = activeValues.value.filter((item) => item !== value);
110
+ if (isActive(value) && !(props.required && rest.length === 0))
111
+ setModel(props.multiple ? rest : null);
112
+ emit("remove", value);
113
+ });
114
+ }
115
+ function removable(pill, option, disabled) {
116
+ return h("span", { class: "k-filter-pill-group" }, [
117
+ pill,
118
+ h(Button, {
119
+ class: "k-filter-pill-remove",
120
+ variant: "ghost",
121
+ tone: "neutral",
122
+ size: "xs",
123
+ icon: "x-mark",
124
+ square: true,
125
+ disabled,
126
+ "aria-label": translateOr(locale.value, props.removeLabel, "filterPills.remove", {
127
+ label: option.valueLabel ? `${option.label} ${option.valueLabel}` : option.label
128
+ }),
129
+ onClick: () => remove(option.value)
130
+ })
131
+ ]);
132
+ }
101
133
  function setPanel(value, open) {
102
134
  if (open) openPanel.value = value;
103
135
  else if (openPanel.value === value) openPanel.value = null;
@@ -113,7 +145,12 @@ function renderPill(value) {
113
145
  size: props.size,
114
146
  disabled: Boolean(props.disabled || option.disabled)
115
147
  };
116
- const active = option.active ?? isActive(value);
148
+ const active = option.active ?? (option.removable ? true : isActive(value));
149
+ const pill = renderTrigger(option, base, active);
150
+ return option.removable ? removable(pill, option, base.disabled) : pill;
151
+ }
152
+ function renderTrigger(option, base, active) {
153
+ const value = option.value;
117
154
  if (option.menu)
118
155
  return h(
119
156
  DropdownMenu,
@@ -140,6 +177,8 @@ function renderPill(value) {
140
177
  }
141
178
  );
142
179
  }
180
+ if (option.removable)
181
+ return h(FilterPill, { ...base, active, onClick: () => emit("select", value) });
143
182
  return h(FilterPill, { ...base, pressed: isActive(value), onClick: () => toggle(value) });
144
183
  }
145
184
  const defaultPills = /* @__PURE__ */ new Map();
@@ -8,11 +8,14 @@ declare const __VLS_export: <T extends FilterPillValue, M extends boolean = fals
8
8
  size?: "sm" | "md";
9
9
  clearable?: boolean;
10
10
  clearLabel?: string;
11
+ removeLabel?: string;
11
12
  disabled?: boolean;
12
13
  required?: R;
13
14
  } & {
14
15
  modelValue?: M extends true ? T[] : R extends true ? T : T | null;
15
16
  }) & {
17
+ onRemove?: ((value: T) => any) | undefined;
18
+ onSelect?: ((value: T) => any) | undefined;
16
19
  "onUpdate:modelValue"?: ((value: M extends true ? T[] : R extends true ? T : T | null) => any) | undefined;
17
20
  } & Partial<import("vue").HTMLAttributes & import("vue").ReservedProps>> & (typeof globalThis extends {
18
21
  __VLS_PROPS_FALLBACK: infer P;
@@ -36,7 +39,7 @@ declare const __VLS_export: <T extends FilterPillValue, M extends boolean = fals
36
39
  close: () => void;
37
40
  }) => unknown) | undefined;
38
41
  };
39
- emit: (event: "update:modelValue", value: M extends true ? T[] : R extends true ? T : T | null) => void;
42
+ emit: (((evt: "remove", value: T) => void) & ((evt: "select", value: T) => void)) & ((event: "update:modelValue", value: M extends true ? T[] : R extends true ? T : T | null) => void);
40
43
  }>) => import("vue").VNode & {
41
44
  __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
42
45
  };
@@ -28,6 +28,18 @@
28
28
  </span>
29
29
  </div>
30
30
  <nav class="k-pagination-nav" :aria-label="navLabel">
31
+ <button
32
+ v-if="showEdges"
33
+ type="button"
34
+ class="k-btn k-btn-neutral k-btn-ghost is-icon"
35
+ :class="`k-btn-${buttonSize}`"
36
+ :disabled="disabled"
37
+ :aria-disabled="!disabled && page <= 1 ? 'true' : void 0"
38
+ :aria-label="firstText"
39
+ @click="go(1)"
40
+ >
41
+ <Icon name="chevron-double-left" />
42
+ </button>
31
43
  <button
32
44
  type="button"
33
45
  class="k-btn k-btn-neutral k-btn-ghost is-icon"
@@ -73,7 +85,35 @@
73
85
  >
74
86
  <Icon name="chevron-right" />
75
87
  </button>
88
+ <button
89
+ v-if="showEdges"
90
+ type="button"
91
+ class="k-btn k-btn-neutral k-btn-ghost is-icon"
92
+ :class="`k-btn-${buttonSize}`"
93
+ :disabled="disabled"
94
+ :aria-disabled="!disabled && page >= pageCount ? 'true' : void 0"
95
+ :aria-label="lastText"
96
+ @click="go(pageCount)"
97
+ >
98
+ <Icon name="chevron-double-right" />
99
+ </button>
76
100
  </nav>
101
+ <div v-if="showJump" class="k-pagination-jump">
102
+ <label :for="jumpId" class="k-pagination-size-label">{{ jumpText }}</label>
103
+ <input
104
+ :id="jumpId"
105
+ class="k-field k-field-sm k-pagination-jump-input"
106
+ type="number"
107
+ inputmode="numeric"
108
+ min="1"
109
+ :max="pageCount"
110
+ :value="page"
111
+ :disabled="disabled"
112
+ @change="onJump"
113
+ @keydown.enter.prevent="onJump"
114
+ />
115
+ <span class="k-pagination-jump-total" aria-hidden="true">/ {{ pageCount }}</span>
116
+ </div>
77
117
  </div>
78
118
  </template>
79
119
 
@@ -91,10 +131,15 @@ const props = defineProps({
91
131
  compact: { type: Boolean, required: false },
92
132
  disabled: { type: Boolean, required: false },
93
133
  showSummary: { type: Boolean, required: false, default: true },
134
+ showEdges: { type: Boolean, required: false },
135
+ showJump: { type: Boolean, required: false },
94
136
  label: { type: String, required: false },
95
137
  pageLabel: { type: String, required: false },
96
138
  previousLabel: { type: String, required: false },
97
139
  nextLabel: { type: String, required: false },
140
+ firstLabel: { type: String, required: false },
141
+ lastLabel: { type: String, required: false },
142
+ jumpLabel: { type: String, required: false },
98
143
  pageSizeLabel: { type: String, required: false },
99
144
  ofText: { type: String, required: false },
100
145
  emptyText: { type: String, required: false }
@@ -106,12 +151,16 @@ function pageText(value) {
106
151
  }
107
152
  const previousText = computed(() => props.previousLabel ?? t("pagination.previous"));
108
153
  const nextText = computed(() => props.nextLabel ?? t("pagination.next"));
154
+ const firstText = computed(() => props.firstLabel ?? t("pagination.first"));
155
+ const lastText = computed(() => props.lastLabel ?? t("pagination.last"));
156
+ const jumpText = computed(() => props.jumpLabel ?? t("pagination.jump"));
109
157
  const pageSizeText = computed(() => props.pageSizeLabel ?? t("pagination.pageSize"));
110
158
  const ofLabel = computed(() => props.ofText ?? t("pagination.of"));
111
159
  const emptyLabel = computed(() => props.emptyText ?? t("common.noResults"));
112
160
  const page = defineModel("page", { type: Number, ...{ default: 1 } });
113
161
  const pageSize = defineModel("pageSize", { type: Number, ...{ default: 20 } });
114
162
  const sizeId = useId();
163
+ const jumpId = useId();
115
164
  const buttonSize = computed(() => props.size === "sm" ? "xs" : "sm");
116
165
  const pageCount = computed(() => Math.max(1, Math.ceil(props.total / pageSize.value)));
117
166
  const items = computed(() => paginationItems(page.value, pageCount.value, props.siblings));
@@ -126,6 +175,12 @@ function go(target) {
126
175
  const next = Math.min(Math.max(target, 1), pageCount.value);
127
176
  if (next !== page.value) page.value = next;
128
177
  }
178
+ function onJump(event) {
179
+ const input = event.target;
180
+ const target = Math.trunc(Number(input.value));
181
+ if (Number.isFinite(target) && input.value !== "") go(target);
182
+ input.value = String(page.value);
183
+ }
129
184
  function onSizeChange(event) {
130
185
  const firstItem = (page.value - 1) * pageSize.value;
131
186
  pageSize.value = Number(event.target.value);
@@ -14,10 +14,15 @@ declare const __VLS_base: import("vue").DefineComponent<{
14
14
  compact?: boolean;
15
15
  disabled?: boolean;
16
16
  showSummary?: boolean;
17
+ showEdges?: boolean;
18
+ showJump?: boolean;
17
19
  label?: string;
18
20
  pageLabel?: string;
19
21
  previousLabel?: string;
20
22
  nextLabel?: string;
23
+ firstLabel?: string;
24
+ lastLabel?: string;
25
+ jumpLabel?: string;
21
26
  pageSizeLabel?: string;
22
27
  ofText?: string;
23
28
  emptyText?: string;
@@ -226,10 +231,15 @@ declare const __VLS_base: import("vue").DefineComponent<{
226
231
  compact?: boolean;
227
232
  disabled?: boolean;
228
233
  showSummary?: boolean;
234
+ showEdges?: boolean;
235
+ showJump?: boolean;
229
236
  label?: string;
230
237
  pageLabel?: string;
231
238
  previousLabel?: string;
232
239
  nextLabel?: string;
240
+ firstLabel?: string;
241
+ lastLabel?: string;
242
+ jumpLabel?: string;
233
243
  pageSizeLabel?: string;
234
244
  ofText?: string;
235
245
  emptyText?: string;
@@ -410,8 +410,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
410
410
  }> & Readonly<{
411
411
  onRemove?: (() => any) | undefined;
412
412
  }>, {
413
- tone: Tone;
414
413
  size: BadgeSize;
414
+ tone: Tone;
415
415
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
416
416
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
417
417
  declare const _default: typeof __VLS_export;
@@ -441,8 +441,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
441
441
  "onUpdate:selected"?: ((value: TreeNodeId | null) => any) | undefined;
442
442
  "onUpdate:expanded"?: ((value: TreeNodeId[]) => any) | undefined;
443
443
  }>, {
444
- invalid: boolean;
445
444
  size: TreeSize;
445
+ invalid: boolean;
446
446
  selectable: boolean;
447
447
  bordered: boolean;
448
448
  descriptionVariant: TreeDescriptionVariant;
@@ -91,5 +91,6 @@ export interface FilterPillOption<T extends FilterPillValue = FilterPillValue> {
91
91
  panel?: boolean;
92
92
  panelLabel?: string;
93
93
  active?: boolean;
94
+ removable?: boolean;
94
95
  }
95
96
  export type SelectionBarPlacement = 'inline' | 'sticky' | 'floating';
@@ -407,9 +407,9 @@ declare const __VLS_export: import("vue").DefineComponent<{
407
407
  ref_for?: boolean | undefined | undefined;
408
408
  ref_key?: string | undefined | undefined;
409
409
  }> & Readonly<{}>, {
410
+ size: "sm" | "md";
410
411
  min: number;
411
412
  max: number;
412
- size: "sm" | "md";
413
413
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
414
414
  declare const _default: typeof __VLS_export;
415
415
  export default _default;
@@ -408,9 +408,9 @@ declare const __VLS_base: import("vue").DefineComponent<{
408
408
  ref_key?: string | undefined | undefined;
409
409
  }> & Readonly<{}>, {
410
410
  value: number | null;
411
+ size: ProgressSize;
411
412
  tone: Tone;
412
413
  max: number;
413
- size: ProgressSize;
414
414
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
415
415
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
416
416
  declare const _default: typeof __VLS_export;
@@ -410,9 +410,9 @@ declare const __VLS_base: import("vue").DefineComponent<{
410
410
  ref_key?: string | undefined | undefined;
411
411
  }> & Readonly<{}>, {
412
412
  value: number | null;
413
+ size: number | "sm" | "md" | "lg";
413
414
  tone: Tone;
414
415
  max: number;
415
- size: number | "sm" | "md" | "lg";
416
416
  thickness: number;
417
417
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
418
418
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;