@xleddyl/443-components-vue 0.4.0 → 0.6.0
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.
- package/README.md +25 -6
- package/dist/chart/BarChart.vue +11 -4
- package/dist/chart/BarChart.vue.d.ts +2 -0
- package/dist/chart/ChartLegend.vue +43 -4
- package/dist/chart/ChartLegend.vue.d.ts +4 -2
- package/dist/chart/ChartPanel.vue +10 -10
- package/dist/chart/ChartPanel.vue.d.ts +11 -8
- package/dist/chart/ChartSummary.vue +8 -3
- package/dist/chart/ChartSummary.vue.d.ts +3 -1
- package/dist/chart/DoughnutChart.vue +11 -4
- package/dist/chart/LineChart.vue +8 -2
- package/dist/chart/LineChart.vue.d.ts +2 -0
- package/dist/chart/chart.css +19 -0
- package/dist/chart/patterns.d.ts +6 -0
- package/dist/chart/patterns.mjs +79 -0
- package/dist/chart/types.d.ts +5 -0
- package/dist/chart/useChartColors.mjs +1 -1
- package/dist/components/core/Button.vue +11 -1
- package/dist/components/core/Button.vue.d.ts +1 -1
- package/dist/components/core/FieldMessage.vue +6 -0
- package/dist/components/core/FieldMessage.vue.d.ts +1 -1
- package/dist/components/core/Form.vue +18 -1
- package/dist/components/core/FormAlerts.vue +41 -3
- package/dist/components/core/FormField.vue +43 -24
- package/dist/components/core/Input.vue.d.ts +6 -6
- package/dist/components/core/Root.vue +6 -1
- package/dist/components/core/Root.vue.d.ts +2 -2
- package/dist/components/core/Spinner.vue +6 -11
- package/dist/components/core/Spinner.vue.d.ts +2 -2
- package/dist/components/core/Textarea.vue.d.ts +2 -2
- package/dist/components/core/VisuallyHidden.vue.d.ts +2 -2
- package/dist/components/data/Avatar.vue +8 -5
- package/dist/components/data/AvatarGroup.vue +6 -3
- package/dist/components/data/Badge.vue.d.ts +1 -1
- package/dist/components/data/FilterPills.vue +18 -2
- package/dist/components/data/Pagination.vue +24 -18
- package/dist/components/data/Pagination.vue.d.ts +2 -2
- package/dist/components/data/SelectionBar.vue +32 -3
- package/dist/components/data/Stat.vue +7 -1
- package/dist/components/data/Stat.vue.d.ts +2 -2
- package/dist/components/data/Table.vue +62 -14
- package/dist/components/data/Tag.vue +24 -4
- package/dist/components/data/Tag.vue.d.ts +3 -3
- package/dist/components/data/Timeline.vue +12 -1
- package/dist/components/data/Tree.vue +137 -36
- package/dist/components/data/Tree.vue.d.ts +13 -14
- package/dist/components/data/types.d.ts +2 -1
- package/dist/components/feedback/Alert.vue +18 -9
- package/dist/components/feedback/Alert.vue.d.ts +2 -2
- package/dist/components/feedback/LoadingOverlay.vue +35 -3
- package/dist/components/feedback/Meter.vue +28 -3
- package/dist/components/feedback/Progress.vue +2 -7
- package/dist/components/feedback/Progress.vue.d.ts +1 -1
- package/dist/components/feedback/ProgressRing.vue +2 -6
- package/dist/components/feedback/ProgressRing.vue.d.ts +1 -1
- package/dist/components/forms/Calendar.vue +49 -26
- package/dist/components/forms/Calendar.vue.d.ts +9 -5
- package/dist/components/forms/CheckboxGroup.vue +14 -4
- package/dist/components/forms/CheckboxGroup.vue.d.ts +1 -0
- package/dist/components/forms/ColorInput.vue +68 -15
- package/dist/components/forms/ColorInput.vue.d.ts +16 -13
- package/dist/components/forms/Combobox.vue +18 -4
- package/dist/components/forms/DateInput.vue.d.ts +6 -6
- package/dist/components/forms/DatePicker.vue +23 -7
- package/dist/components/forms/DatePicker.vue.d.ts +4 -2
- package/dist/components/forms/FileInput.vue +31 -13
- package/dist/components/forms/FileInput.vue.d.ts +2 -2
- package/dist/components/forms/InputAddon.vue +18 -2
- package/dist/components/forms/InputGroup.vue +27 -0
- package/dist/components/forms/InputGroup.vue.d.ts +2 -0
- package/dist/components/forms/NumberInput.vue +6 -7
- package/dist/components/forms/NumberInput.vue.d.ts +6 -6
- package/dist/components/forms/PasswordInput.vue +12 -6
- package/dist/components/forms/PasswordInput.vue.d.ts +6 -7
- package/dist/components/forms/PinInput.vue +11 -1
- package/dist/components/forms/PinInput.vue.d.ts +8 -6
- package/dist/components/forms/RadioGroup.vue +15 -5
- package/dist/components/forms/RadioGroup.vue.d.ts +1 -0
- package/dist/components/forms/SegmentedControl.vue +15 -10
- package/dist/components/forms/SegmentedControl.vue.d.ts +1 -0
- package/dist/components/forms/Slider.vue +9 -0
- package/dist/components/forms/Slider.vue.d.ts +8 -6
- package/dist/components/forms/Switch.vue +7 -0
- package/dist/components/forms/Switch.vue.d.ts +2 -2
- package/dist/components/forms/TimeInput.vue.d.ts +6 -6
- package/dist/components/forms/types.d.ts +4 -0
- package/dist/components/layout/Accordion.vue.d.ts +2 -2
- package/dist/components/layout/AppShell.vue +40 -18
- package/dist/components/layout/AppShell.vue.d.ts +11 -9
- package/dist/components/layout/Card.vue +50 -16
- package/dist/components/layout/Card.vue.d.ts +13 -11
- package/dist/components/layout/CopyButton.vue +13 -5
- package/dist/components/layout/CopyButton.vue.d.ts +3 -3
- package/dist/components/layout/NavLink.vue +10 -1
- package/dist/components/layout/NavLink.vue.d.ts +2 -2
- package/dist/components/layout/PageHeader.vue +2 -2
- package/dist/components/layout/Separator.vue +6 -3
- package/dist/components/layout/Sidebar.vue +14 -7
- package/dist/components/layout/Sidebar.vue.d.ts +0 -2
- package/dist/components/layout/SidebarNav.vue +16 -44
- package/dist/components/layout/Stack.vue.d.ts +2 -2
- package/dist/components/layout/Tabs.vue +10 -18
- package/dist/components/layout/Tabs.vue.d.ts +2 -2
- package/dist/components/layout/Toolbar.vue +10 -4
- package/dist/components/layout/Toolbar.vue.d.ts +1 -0
- package/dist/components/layout/types.d.ts +1 -0
- package/dist/components/overlays/CommandPalette.vue +8 -4
- package/dist/components/overlays/CommandPalette.vue.d.ts +3 -8
- package/dist/components/overlays/ConfirmDialog.vue +7 -5
- package/dist/components/overlays/ConfirmDialog.vue.d.ts +12 -8
- package/dist/components/overlays/ConfirmHost.vue +22 -19
- package/dist/components/overlays/ConfirmHost.vue.d.ts +8 -6
- package/dist/components/overlays/ContextMenu.vue +9 -11
- package/dist/components/overlays/ContextMenu.vue.d.ts +2 -2
- package/dist/components/overlays/Drawer.vue +2 -0
- package/dist/components/overlays/Drawer.vue.d.ts +4 -2
- package/dist/components/overlays/DropdownMenu.vue +13 -21
- package/dist/components/overlays/DropdownMenu.vue.d.ts +2 -2
- package/dist/components/overlays/HoverCard.vue +8 -2
- package/dist/components/overlays/HoverCard.vue.d.ts +2 -2
- package/dist/components/overlays/Modal.vue +2 -0
- package/dist/components/overlays/Modal.vue.d.ts +4 -2
- package/dist/components/overlays/Popover.vue +19 -4
- package/dist/components/overlays/Popover.vue.d.ts +2 -2
- package/dist/components/overlays/Toaster.vue +71 -8
- package/dist/components/overlays/Toaster.vue.d.ts +3 -0
- package/dist/components/overlays/Tooltip.vue +39 -14
- package/dist/components/overlays/types.d.ts +7 -0
- package/dist/components/templates/AccountMenu.vue.d.ts +2 -2
- package/dist/components/templates/AppearanceSettings.vue +83 -77
- package/dist/components/templates/AppearanceSettings.vue.d.ts +2 -2
- package/dist/components/templates/AuthLayout.vue +2 -2
- package/dist/components/templates/Brand.vue.d.ts +2 -2
- package/dist/components/templates/DashboardLayout.vue +3 -7
- package/dist/components/templates/DashboardLayout.vue.d.ts +8 -18
- package/dist/components/templates/DetailPage.vue +3 -1
- package/dist/components/templates/DetailPage.vue.d.ts +2 -2
- package/dist/components/templates/ErrorPage.vue +11 -5
- package/dist/components/templates/ErrorPage.vue.d.ts +10 -6
- package/dist/components/templates/FormPage.vue +16 -3
- package/dist/components/templates/ListPage.vue +19 -6
- package/dist/components/templates/ListPage.vue.d.ts +1 -0
- package/dist/components/templates/NotFoundPage.vue +2 -0
- package/dist/components/templates/NotFoundPage.vue.d.ts +4 -0
- package/dist/components/templates/SaveBar.vue +18 -3
- package/dist/components/templates/SaveBar.vue.d.ts +5 -5
- package/dist/components/templates/SettingsGroup.vue +1 -1
- package/dist/components/templates/SettingsGroup.vue.d.ts +3 -1
- package/dist/components/templates/SettingsModal.vue +73 -46
- package/dist/components/templates/SettingsModal.vue.d.ts +9 -11
- package/dist/components/templates/SettingsPage.vue.d.ts +2 -2
- package/dist/components/templates/SettingsSection.vue.d.ts +4 -2
- package/dist/components/templates/types.d.ts +4 -0
- package/dist/composables/useAlert.mjs +5 -10
- package/dist/composables/useConfirm.mjs +5 -5
- package/dist/composables/useField.d.ts +4 -0
- package/dist/composables/useField.mjs +16 -5
- package/dist/composables/useFileDrop.mjs +2 -1
- package/dist/composables/useOverlay.mjs +2 -1
- package/dist/composables/usePreset.mjs +4 -10
- package/dist/composables/usePrompt.mjs +6 -13
- package/dist/composables/useScrollLock.mjs +4 -3
- package/dist/composables/useTheme.mjs +3 -11
- package/dist/composables/useToast.mjs +2 -1
- package/dist/editor/RichTextEditor.vue +31 -6
- package/dist/editor/RichTextEditor.vue.d.ts +2 -2
- package/dist/editor/rich-text-editor.css +9 -4
- package/dist/grid/DataGrid.vue +72 -12
- package/dist/grid/GridToolbar.vue +1 -1
- package/dist/grid/GridToolbar.vue.d.ts +2 -2
- package/dist/grid/cells/BadgeCell.vue +3 -1
- package/dist/grid/cells/BadgeCell.vue.d.ts +17 -3
- package/dist/grid/cells/DateCell.vue +3 -1
- package/dist/grid/cells/DateCell.vue.d.ts +17 -3
- package/dist/grid/cells/EmptyCell.vue +15 -0
- package/dist/grid/cells/EmptyCell.vue.d.ts +392 -0
- package/dist/grid/cells/LinkCell.vue +9 -2
- package/dist/grid/cells/LinkCell.vue.d.ts +17 -3
- package/dist/grid/data-grid.css +5 -5
- package/dist/grid/types.d.ts +2 -0
- package/dist/internal/core/ButtonContent.vue +3 -0
- package/dist/internal/core/LiveRegion.vue +26 -0
- package/dist/internal/core/LiveRegion.vue.d.ts +393 -0
- package/dist/internal/core/copy.d.ts +6 -0
- package/dist/internal/core/copy.mjs +14 -0
- package/dist/internal/core/focus.d.ts +6 -0
- package/dist/internal/core/focus.mjs +46 -0
- package/dist/internal/core/intl.d.ts +4 -2
- package/dist/internal/core/intl.mjs +23 -22
- package/dist/internal/core/live.d.ts +6 -0
- package/dist/internal/core/live.mjs +22 -0
- package/dist/internal/core/preset.d.ts +0 -1
- package/dist/internal/core/preset.mjs +4 -14
- package/dist/internal/core/resize.d.ts +1 -0
- package/dist/internal/core/resize.mjs +11 -0
- package/dist/internal/core/roving.d.ts +7 -0
- package/dist/internal/core/roving.mjs +19 -1
- package/dist/internal/core/scroll-edges.d.ts +5 -0
- package/dist/internal/core/scroll-edges.mjs +63 -0
- package/dist/internal/core/storage.d.ts +2 -0
- package/dist/internal/core/storage.mjs +8 -0
- package/dist/internal/core/theme.d.ts +0 -1
- package/dist/internal/core/theme.mjs +4 -13
- package/dist/internal/core/tone.d.ts +1 -0
- package/dist/internal/core/tone.mjs +4 -0
- package/dist/internal/core/transition.d.ts +1 -0
- package/dist/internal/core/transition.mjs +20 -0
- package/dist/internal/data/rows.mjs +6 -5
- package/dist/internal/data/tree.d.ts +2 -3
- package/dist/internal/feedback/LoadingHost.vue +16 -6
- package/dist/internal/feedback/loading.mjs +2 -1
- package/dist/internal/feedback/progress.d.ts +12 -0
- package/dist/internal/feedback/progress.mjs +13 -0
- package/dist/internal/floating/layer.d.ts +1 -1
- package/dist/internal/floating/layer.mjs +17 -10
- package/dist/internal/forms/keys.d.ts +4 -0
- package/dist/internal/forms/keys.mjs +1 -0
- package/dist/internal/forms/name.d.ts +2 -0
- package/dist/internal/forms/name.mjs +12 -0
- package/dist/internal/forms/standard-schema.d.ts +0 -2
- package/dist/internal/forms/standard-schema.mjs +0 -18
- package/dist/internal/layout/NavGroup.vue +104 -0
- package/dist/internal/layout/NavGroup.vue.d.ts +412 -0
- package/dist/internal/layout/route.mjs +1 -1
- package/dist/internal/overlays/DialogFrame.vue +53 -6
- package/dist/internal/overlays/DialogFrame.vue.d.ts +5 -2
- package/dist/internal/overlays/MenuList.vue +4 -11
- package/dist/internal/overlays/MenuList.vue.d.ts +6 -6
- package/dist/internal/overlays/OverlayView.vue +2 -0
- package/dist/internal/overlays/OverlayView.vue.d.ts +8 -6
- package/dist/internal/overlays/confirm.d.ts +6 -1
- package/dist/internal/overlays/confirm.mjs +5 -2
- package/dist/internal/overlays/dialog.d.ts +1 -0
- package/dist/internal/overlays/dialog.mjs +9 -9
- package/dist/internal/overlays/hover.d.ts +1 -0
- package/dist/internal/overlays/hover.mjs +20 -3
- package/dist/internal/overlays/menu.d.ts +9 -0
- package/dist/internal/overlays/menu.mjs +15 -0
- package/dist/internal/overlays/stack.d.ts +1 -0
- package/dist/locale/en.mjs +72 -19
- package/dist/locale/index.d.ts +1 -1
- package/dist/locale/index.mjs +5 -11
- package/dist/locale/it.mjs +72 -19
- package/dist/locale/types.d.ts +55 -2
- package/dist/nuxt/module.mjs +1 -1
- package/dist/nuxt/runtime/RouteAnnouncer.vue +21 -0
- package/dist/nuxt/runtime/RouteAnnouncer.vue.d.ts +3 -0
- package/dist/nuxt/runtime/layout-head.d.ts +2 -0
- package/dist/nuxt/runtime/layout-head.mjs +13 -0
- package/dist/nuxt/runtime/layouts/auth.vue +4 -0
- package/dist/nuxt/runtime/layouts/auth.vue.d.ts +2 -2
- package/dist/nuxt/runtime/layouts/dashboard.vue +4 -0
- package/dist/nuxt/runtime/layouts/dashboard.vue.d.ts +2 -2
- package/dist/nuxt/runtime/locale.mjs +8 -1
- package/dist/nuxt/runtime/theme.mjs +17 -12
- package/dist/styles/base.css +0 -13
- package/dist/styles/core/button.css +8 -8
- package/dist/styles/core/field-message.css +2 -2
- package/dist/styles/core/form-field.css +13 -4
- package/dist/styles/core/input.css +4 -7
- package/dist/styles/core/kbd.css +0 -1
- package/dist/styles/data/badge.css +8 -4
- package/dist/styles/data/description-list.css +7 -5
- package/dist/styles/data/filter-pills.css +5 -8
- package/dist/styles/data/pagination.css +2 -2
- package/dist/styles/data/stat.css +3 -3
- package/dist/styles/data/table.css +3 -2
- package/dist/styles/data/tag.css +1 -2
- package/dist/styles/data/timeline.css +2 -1
- package/dist/styles/data/tree.css +31 -10
- package/dist/styles/feedback/alert.css +1 -3
- package/dist/styles/feedback/empty-state.css +6 -4
- package/dist/styles/feedback/loading-host.css +4 -0
- package/dist/styles/feedback/loading-overlay.css +4 -0
- package/dist/styles/forced-colors.css +215 -0
- package/dist/styles/forms/calendar.css +2 -2
- package/dist/styles/forms/choice.css +2 -2
- package/dist/styles/forms/color-input.css +1 -1
- package/dist/styles/forms/combobox.css +2 -24
- package/dist/styles/forms/date-input.css +2 -2
- package/dist/styles/forms/date-picker.css +3 -7
- package/dist/styles/forms/file-input.css +4 -3
- package/dist/styles/forms/input-group.css +6 -0
- package/dist/styles/forms/number-input.css +2 -2
- package/dist/styles/forms/password-input.css +5 -2
- package/dist/styles/forms/pin-input.css +4 -2
- package/dist/styles/forms/segmented.css +2 -2
- package/dist/styles/forms/select.css +6 -6
- package/dist/styles/forms/slider.css +5 -4
- package/dist/styles/forms/switch.css +5 -1
- package/dist/styles/index.css +1 -0
- package/dist/styles/layout/accordion.css +1 -1
- package/dist/styles/layout/app-shell.css +15 -3
- package/dist/styles/layout/card.css +12 -2
- package/dist/styles/layout/copy-button.css +1 -1
- package/dist/styles/layout/nav-link.css +1 -33
- package/dist/styles/layout/page-header.css +2 -1
- package/dist/styles/layout/separator.css +1 -1
- package/dist/styles/layout/sidebar-nav.css +15 -4
- package/dist/styles/layout/sidebar.css +20 -6
- package/dist/styles/layout/tabs.css +9 -4
- package/dist/styles/layout/theme-switch.css +0 -6
- package/dist/styles/overlays/command.css +9 -15
- package/dist/styles/overlays/confirm.css +1 -1
- package/dist/styles/overlays/drawer.css +23 -3
- package/dist/styles/overlays/menu.css +2 -17
- package/dist/styles/overlays/modal.css +33 -9
- package/dist/styles/overlays/toast.css +1 -2
- package/dist/styles/presets.css +4 -4
- package/dist/styles/shared.css +96 -3
- package/dist/styles/templates/account-menu.css +3 -3
- package/dist/styles/templates/auth-layout.css +5 -1
- package/dist/styles/templates/brand.css +3 -3
- package/dist/styles/templates/empty-page.css +5 -1
- package/dist/styles/templates/error-page.css +4 -0
- package/dist/styles/templates/form-page.css +10 -0
- package/dist/styles/templates/save-bar.css +10 -0
- package/dist/styles/templates/settings-modal.css +46 -45
- package/dist/styles/templates/settings-page.css +3 -3
- package/dist/styles/tokens.css +12 -2
- package/package.json +1 -1
- package/dist/internal/overlays/focus.d.ts +0 -1
- package/dist/internal/overlays/focus.mjs +0 -24
package/README.md
CHANGED
|
@@ -108,6 +108,8 @@ 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
|
+
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.
|
|
112
|
+
|
|
111
113
|
Themes: `data-theme="light"` or `"dark"` forces the scheme, `system` (or no attribute) follows the OS. `useTheme()` returns `preference`, `set()` and `cycle()`; `KThemeSwitch` is a ready control.
|
|
112
114
|
|
|
113
115
|
Titles (headings, `k-title`, `k-display`, PageHeader, Card, Modal and Drawer titles, Brand, Stat values, auth and error titles) use `--k-font-display`, which falls back to `--k-font-sans`. Set it (or the `fontDisplay` prop of `Root`) for a separate display face.
|
|
@@ -209,6 +211,7 @@ k: { locale: 'it', messages: { it: { common: { cancel: 'Indietro' } } } }
|
|
|
209
211
|
- With `@nuxtjs/i18n` the module follows the current i18n locale (a `de-CH` locale uses `de` overrides, then English).
|
|
210
212
|
- A new language is a full `messages[code]` object, or `defineLocale({ code: 'de', messages: {...} })` passed to `createLocale()` / `provideLocale()` in plain Vue.
|
|
211
213
|
- `useLocale()` returns `{ locale, t }` for your own components (`t('common.cancel')`).
|
|
214
|
+
- The outermost `Root` sets `lang` and `dir` from the provided locale, and the Nuxt module sets them on `<html>` unless `@nuxtjs/i18n` manages the document language.
|
|
212
215
|
- The `*Label` and `*Text` props of each component still override a single instance.
|
|
213
216
|
|
|
214
217
|
## Forms
|
|
@@ -260,7 +263,7 @@ Nested forms. Overlays stay in the DOM, so a `Form` inside a Modal opened from a
|
|
|
260
263
|
</KForm>
|
|
261
264
|
```
|
|
262
265
|
|
|
263
|
-
Several controls in one `FormField`. Only the primary control takes the field id, name, description and invalid state. Wrap secondary controls (a search input above a Tree) in `<KFieldBoundary auxiliary>`, or call `useFieldControl({ role: 'auxiliary' })` in your own control: they keep their own id and only follow `disabled`. `<KFieldBoundary>` without `auxiliary` cuts the field context completely, like the overlays do. A primary control that is not labelable (a tree, a group, a contenteditable editor) passes `useFieldControl({ labelable: false })`; `FormField` then drops `for` from its label and the control uses `aria-labelledby` with `field.
|
|
266
|
+
Several controls in one `FormField`. Only the primary control takes the field id, name, description and invalid state. Wrap secondary controls (a search input above a Tree) in `<KFieldBoundary auxiliary>`, or call `useFieldControl({ role: 'auxiliary' })` in your own control: they keep their own id and only follow `disabled`. `<KFieldBoundary>` without `auxiliary` cuts the field context completely, like the overlays do. A primary control that is not labelable (a tree, a group, a contenteditable editor) passes `useFieldControl({ labelable: false })`; `FormField` then drops `for` from its label and the control uses `aria-labelledby` with `control.labelledBy` (the label id, or `undefined` when the field has no label). A control that cannot carry `required` itself (a button trigger, a fieldset) passes `requiredHint: true`: `FormField` then adds a visually hidden "(required)" to its label. Errors and warnings render inside a polite live region, prefixed with a hidden "Error:" or "Warning:". `Tree`, `CheckboxGroup`, `RadioGroup`, `SegmentedControl` and `RichTextEditor` already do.
|
|
264
267
|
|
|
265
268
|
```vue
|
|
266
269
|
<KFormField label="Folder">
|
|
@@ -546,7 +549,7 @@ export default defineAppConfig({
|
|
|
546
549
|
|
|
547
550
|
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.
|
|
548
551
|
|
|
549
|
-
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). 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.
|
|
552
|
+
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.
|
|
550
553
|
|
|
551
554
|
### Starter
|
|
552
555
|
|
|
@@ -567,13 +570,29 @@ Components are typed for `strictTemplates`: native attributes and listeners of t
|
|
|
567
570
|
|
|
568
571
|
## Accessibility
|
|
569
572
|
|
|
573
|
+
The components target WCAG 2.2 AA in every preset and both themes.
|
|
574
|
+
|
|
570
575
|
- Native elements first (`button`, `a`, `input`, `select`, `dialog`, `table`), full ARIA patterns where none fits (combobox, listbox, menu, tabs, tree, radio group, grid calendar).
|
|
571
|
-
- Labels, descriptions and errors are wired through `FormField` (`for`/`id`, `aria-describedby`, `aria-invalid`, required state). Every form control works inside it.
|
|
572
|
-
-
|
|
573
|
-
-
|
|
574
|
-
-
|
|
576
|
+
- Labels, descriptions and errors are wired through `FormField` (`for`/`id`, `aria-describedby`, `aria-invalid`, required state, hidden "(required)" for controls that cannot carry it). Every form control works inside it, and errors are announced when they appear.
|
|
577
|
+
- Every control has an accessible name: components that can end up unnamed take a `label` prop (falling back to the FormField label) and warn in development. Icon-only buttons need an `aria-label` (Button warns in development). Decorative icons are hidden from assistive technology.
|
|
578
|
+
- Keyboard: arrows inside composite widgets, Escape closes overlays, focus moves into overlays on open and returns to the trigger on close, modals trap focus natively. Tag supports Delete and Backspace on its remove button. Busy buttons (`loading`, or a submitting form) keep focus: they use `aria-disabled` and ignore clicks instead of becoming disabled.
|
|
579
|
+
- Focus is a 2px opaque ring at 3:1 or more; text is 4.5:1 or more, icons and control boundaries 3:1 or more.
|
|
580
|
+
- Windows forced colors (high contrast) keep focus rings, checked, selected and current states, switch thumbs, progress and meter fills, and overlay borders.
|
|
581
|
+
- Pointer targets are at least 24px.
|
|
582
|
+
- Status changes (loading, results, copy, uploads, sorting, toasts) are announced through persistent live regions. While a modal dialog is open the toast stack and the live regions move inside that dialog, so they stay reachable and announced (the rest of the page is inert).
|
|
575
583
|
- `prefers-reduced-motion` disables animations inside every root. Colors are never the only signal.
|
|
576
584
|
|
|
585
|
+
Accessibility related props and defaults:
|
|
586
|
+
|
|
587
|
+
- Accessible names: `label` on `RadioGroup` and `CheckboxGroup` (alias of `legend`), `SegmentedControl`, `Slider`, `PinInput`, `InputGroup`, `Tabs`, `Toolbar`, `Modal`, `Drawer` and `useModal`/`useDrawer` options (when there is no `title`), `Card` (stretched link without a title), `ChartLegend`. `AppShell` takes `closeLabel` for the close button of the mobile navigation, which opens as a named modal dialog. `Sidebar`'s collapse button keeps one label (`collapseLabel`) and exposes the state with `aria-expanded`.
|
|
588
|
+
- Heading levels: `level` on `Calendar`, `DatePicker`, `ChartPanel`, `ErrorPage` and `NotFoundPage`; page templates pass `level + 1` to their sections and empty states.
|
|
589
|
+
- Live roles are opt in on `Alert`: pass `role="alert"` or `role="status"` for messages that appear at runtime; static banners get none. Without a title the tone is spoken from a hidden prefix.
|
|
590
|
+
- `Toolbar` uses roving focus by default (`:roving="false"` renders a plain named group).
|
|
591
|
+
- 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`.
|
|
592
|
+
- `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.
|
|
593
|
+
- `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.
|
|
594
|
+
- `DataGrid` translates the AG Grid ARIA strings through the catalog (`grid.*`; your own `localeText` still wins) and announces row count changes.
|
|
595
|
+
|
|
577
596
|
## Browser support
|
|
578
597
|
|
|
579
598
|
- Required: native `popover`, `<dialog>`, `:where()`, cascade layers, `color-mix()`, `light-dark()` (Chrome and Edge 123, Firefox 128, Safari 17.5).
|
package/dist/chart/BarChart.vue
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
:position="legendPosition"
|
|
11
11
|
@toggle="toggle"
|
|
12
12
|
/>
|
|
13
|
-
<ChartSummary :caption="label" :labels="labels" :rows="series" />
|
|
13
|
+
<ChartSummary :caption="label" :labels="labels" :rows="series" :format-value="formatValue" />
|
|
14
14
|
</div>
|
|
15
15
|
</template>
|
|
16
16
|
|
|
@@ -22,6 +22,7 @@ import ChartSummary from "./ChartSummary.vue";
|
|
|
22
22
|
import { buildCartesianOptions } from "./options";
|
|
23
23
|
import { registerChartModules } from "./register";
|
|
24
24
|
import { useChartSurface } from "./useChartSurface";
|
|
25
|
+
import { barFill, seriesPattern } from "./patterns";
|
|
25
26
|
registerChartModules();
|
|
26
27
|
const props = defineProps({
|
|
27
28
|
labels: { type: Array, required: true },
|
|
@@ -32,6 +33,7 @@ const props = defineProps({
|
|
|
32
33
|
legendPosition: { type: String, required: false, default: "bottom" },
|
|
33
34
|
stacked: { type: Boolean, required: false },
|
|
34
35
|
horizontal: { type: Boolean, required: false },
|
|
36
|
+
patterns: { type: Boolean, required: false },
|
|
35
37
|
formatValue: { type: Function, required: false },
|
|
36
38
|
options: { type: null, required: false }
|
|
37
39
|
});
|
|
@@ -46,17 +48,22 @@ const legendItems = computed(
|
|
|
46
48
|
() => props.series.map((entry, index) => ({
|
|
47
49
|
label: entry.label,
|
|
48
50
|
color: colorAt(index),
|
|
49
|
-
hidden: isHidden(index)
|
|
51
|
+
hidden: isHidden(index),
|
|
52
|
+
pattern: props.patterns ? seriesPattern(index) : void 0
|
|
50
53
|
}))
|
|
51
54
|
);
|
|
55
|
+
function fillAt(index) {
|
|
56
|
+
const color = colorAt(index);
|
|
57
|
+
return props.patterns ? barFill(color, seriesPattern(index), colors.value.surface) : color;
|
|
58
|
+
}
|
|
52
59
|
const chartData = computed(() => ({
|
|
53
60
|
labels: props.labels,
|
|
54
61
|
datasets: props.series.map((entry, index) => ({
|
|
55
62
|
label: entry.label,
|
|
56
63
|
data: entry.data,
|
|
57
64
|
hidden: isHidden(index),
|
|
58
|
-
backgroundColor:
|
|
59
|
-
hoverBackgroundColor:
|
|
65
|
+
backgroundColor: fillAt(index),
|
|
66
|
+
hoverBackgroundColor: fillAt(index),
|
|
60
67
|
borderRadius: 4,
|
|
61
68
|
borderSkipped: false,
|
|
62
69
|
maxBarThickness: 36
|
|
@@ -9,6 +9,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
9
9
|
legendPosition?: ChartLegendPosition;
|
|
10
10
|
stacked?: boolean;
|
|
11
11
|
horizontal?: boolean;
|
|
12
|
+
patterns?: boolean;
|
|
12
13
|
formatValue?: ChartValueFormatter;
|
|
13
14
|
options?: ChartOptions<"bar">;
|
|
14
15
|
innerHTML?: string | undefined | undefined;
|
|
@@ -212,6 +213,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
212
213
|
legendPosition?: ChartLegendPosition;
|
|
213
214
|
stacked?: boolean;
|
|
214
215
|
horizontal?: boolean;
|
|
216
|
+
patterns?: boolean;
|
|
215
217
|
formatValue?: ChartValueFormatter;
|
|
216
218
|
options?: ChartOptions<"bar">;
|
|
217
219
|
innerHTML?: string | undefined | undefined;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<ul class="k-chart-legend" :class="`is-${position}`">
|
|
2
|
+
<ul class="k-chart-legend" :class="`is-${position}`" role="list" :aria-label="legendLabel">
|
|
3
3
|
<li v-for="(item, index) in items" :key="item.label">
|
|
4
4
|
<button
|
|
5
5
|
type="button"
|
|
@@ -8,7 +8,37 @@
|
|
|
8
8
|
:aria-pressed="!item.hidden"
|
|
9
9
|
@click="emit('toggle', index)"
|
|
10
10
|
>
|
|
11
|
-
<
|
|
11
|
+
<svg
|
|
12
|
+
v-if="item.dash"
|
|
13
|
+
class="k-chart-legend-line"
|
|
14
|
+
viewBox="0 0 18 10"
|
|
15
|
+
aria-hidden="true"
|
|
16
|
+
:stroke="item.color"
|
|
17
|
+
>
|
|
18
|
+
<line
|
|
19
|
+
x1="1"
|
|
20
|
+
y1="5"
|
|
21
|
+
x2="17"
|
|
22
|
+
y2="5"
|
|
23
|
+
stroke-width="2"
|
|
24
|
+
:stroke-dasharray="dashArray(item.dash)"
|
|
25
|
+
/>
|
|
26
|
+
<circle v-if="item.point === 'circle'" cx="9" cy="5" r="2.5" />
|
|
27
|
+
<rect v-else-if="item.point === 'rect'" x="6.5" y="2.5" width="5" height="5" />
|
|
28
|
+
<polygon v-else-if="item.point === 'triangle'" points="9,2 12,7.5 6,7.5" />
|
|
29
|
+
<polygon v-else-if="item.point === 'rectRot'" points="9,1.5 12.5,5 9,8.5 5.5,5" />
|
|
30
|
+
<polygon
|
|
31
|
+
v-else-if="item.point === 'star'"
|
|
32
|
+
points="9,1.5 10,4 12.5,4 10.5,5.75 11.25,8.5 9,7 6.75,8.5 7.5,5.75 5.5,4 8,4"
|
|
33
|
+
/>
|
|
34
|
+
<path v-else-if="item.point === 'crossRot'" d="M6.5 2.5l5 5m0-5l-5 5" />
|
|
35
|
+
</svg>
|
|
36
|
+
<span
|
|
37
|
+
v-else
|
|
38
|
+
class="k-chart-legend-swatch"
|
|
39
|
+
aria-hidden="true"
|
|
40
|
+
:style="{ background: patternBackground(item.color, item.pattern) }"
|
|
41
|
+
/>
|
|
12
42
|
<span class="k-chart-legend-label">{{ item.label }}</span>
|
|
13
43
|
<span v-if="item.value" class="k-chart-legend-value k-tabular">{{ item.value }}</span>
|
|
14
44
|
</button>
|
|
@@ -17,9 +47,18 @@
|
|
|
17
47
|
</template>
|
|
18
48
|
|
|
19
49
|
<script setup>
|
|
20
|
-
|
|
50
|
+
import { computed } from "vue";
|
|
51
|
+
import { useLocale } from "../composables/useLocale";
|
|
52
|
+
import { patternBackground } from "./patterns";
|
|
53
|
+
const props = defineProps({
|
|
21
54
|
items: { type: Array, required: true },
|
|
22
|
-
position: { type: String, required: false, default: "bottom" }
|
|
55
|
+
position: { type: String, required: false, default: "bottom" },
|
|
56
|
+
label: { type: String, required: false }
|
|
23
57
|
});
|
|
24
58
|
const emit = defineEmits(["toggle"]);
|
|
59
|
+
const { t } = useLocale();
|
|
60
|
+
const legendLabel = computed(() => props.label ?? t("chart.legend"));
|
|
61
|
+
function dashArray(dash) {
|
|
62
|
+
return dash.length ? dash.map((value) => value * 0.5).join(" ") : void 0;
|
|
63
|
+
}
|
|
25
64
|
</script>
|
|
@@ -2,12 +2,14 @@ import type { ChartLegendItem, ChartLegendPosition } from './types';
|
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<{
|
|
3
3
|
items: ChartLegendItem[];
|
|
4
4
|
position?: ChartLegendPosition;
|
|
5
|
+
label?: string;
|
|
5
6
|
key?: PropertyKey | undefined;
|
|
6
7
|
prefix?: string | undefined | undefined;
|
|
7
8
|
title?: string | undefined | undefined;
|
|
8
9
|
style?: import("vue").StyleValue;
|
|
9
10
|
results?: (string | number) | undefined;
|
|
10
11
|
placeholder?: string | undefined | undefined;
|
|
12
|
+
dir?: string | undefined | undefined;
|
|
11
13
|
class?: import("vue").ClassValue;
|
|
12
14
|
role?: string | undefined | undefined;
|
|
13
15
|
'aria-label'?: string | undefined | undefined;
|
|
@@ -162,7 +164,6 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
162
164
|
accesskey?: string | undefined | undefined;
|
|
163
165
|
contenteditable?: (boolean | "true" | "false") | "inherit" | "plaintext-only" | undefined;
|
|
164
166
|
contextmenu?: string | undefined | undefined;
|
|
165
|
-
dir?: string | undefined | undefined;
|
|
166
167
|
draggable?: (boolean | "true" | "false") | undefined;
|
|
167
168
|
enterkeyhint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
|
|
168
169
|
enterKeyHint?: "search" | "done" | "previous" | "next" | "enter" | "go" | "send" | undefined;
|
|
@@ -198,12 +199,14 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
198
199
|
}, string, import("vue").PublicProps, Readonly<{
|
|
199
200
|
items: ChartLegendItem[];
|
|
200
201
|
position?: ChartLegendPosition;
|
|
202
|
+
label?: string;
|
|
201
203
|
key?: PropertyKey | undefined;
|
|
202
204
|
prefix?: string | undefined | undefined;
|
|
203
205
|
title?: string | undefined | undefined;
|
|
204
206
|
style?: import("vue").StyleValue;
|
|
205
207
|
results?: (string | number) | undefined;
|
|
206
208
|
placeholder?: string | undefined | undefined;
|
|
209
|
+
dir?: string | undefined | undefined;
|
|
207
210
|
class?: import("vue").ClassValue;
|
|
208
211
|
role?: string | undefined | undefined;
|
|
209
212
|
'aria-label'?: string | undefined | undefined;
|
|
@@ -358,7 +361,6 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
358
361
|
accesskey?: string | undefined | undefined;
|
|
359
362
|
contenteditable?: (boolean | "true" | "false") | "inherit" | "plaintext-only" | undefined;
|
|
360
363
|
contextmenu?: string | undefined | undefined;
|
|
361
|
-
dir?: string | undefined | undefined;
|
|
362
364
|
draggable?: (boolean | "true" | "false") | undefined;
|
|
363
365
|
enterkeyhint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
|
|
364
366
|
enterKeyHint?: "search" | "done" | "previous" | "next" | "enter" | "go" | "send" | undefined;
|
|
@@ -2,24 +2,20 @@
|
|
|
2
2
|
<section
|
|
3
3
|
class="k-chart-panel"
|
|
4
4
|
:aria-busy="loading ? 'true' : void 0"
|
|
5
|
-
:aria-labelledby="titleId"
|
|
5
|
+
:aria-labelledby="title ? titleId : void 0"
|
|
6
6
|
>
|
|
7
7
|
<header v-if="title || $slots.actions || $slots.legend" class="k-chart-panel-header">
|
|
8
8
|
<div class="k-chart-panel-heading">
|
|
9
|
-
<
|
|
9
|
+
<component :is="headingTag" v-if="title" :id="titleId" class="k-chart-panel-title">{{
|
|
10
|
+
title
|
|
11
|
+
}}</component>
|
|
10
12
|
<p v-if="description" class="k-chart-panel-description">{{ description }}</p>
|
|
11
13
|
</div>
|
|
12
14
|
<div v-if="$slots.legend" class="k-chart-panel-legend"><slot name="legend" /></div>
|
|
13
15
|
<div v-if="$slots.actions" class="k-chart-panel-actions"><slot name="actions" /></div>
|
|
14
16
|
</header>
|
|
15
17
|
<div class="k-chart-panel-body">
|
|
16
|
-
<div
|
|
17
|
-
v-if="loading"
|
|
18
|
-
class="k-chart-skeleton"
|
|
19
|
-
:style="{ height }"
|
|
20
|
-
role="status"
|
|
21
|
-
:aria-label="loadingLabel"
|
|
22
|
-
>
|
|
18
|
+
<div v-if="loading" class="k-chart-skeleton" :style="{ height }" aria-hidden="true">
|
|
23
19
|
<span v-for="bar in skeletonBars" :key="bar" :style="{ height: `${bar}%` }" />
|
|
24
20
|
</div>
|
|
25
21
|
<div v-else-if="empty" class="k-chart-empty" :style="{ height }">
|
|
@@ -28,12 +24,14 @@
|
|
|
28
24
|
<slot v-else />
|
|
29
25
|
</div>
|
|
30
26
|
<footer v-if="$slots.footer" class="k-chart-panel-footer"><slot name="footer" /></footer>
|
|
27
|
+
<LiveRegion :message="loading ? loadingLabel : ''" />
|
|
31
28
|
</section>
|
|
32
29
|
</template>
|
|
33
30
|
|
|
34
31
|
<script setup>
|
|
35
32
|
import { computed, useId } from "vue";
|
|
36
33
|
import { useLocale } from "../composables/useLocale";
|
|
34
|
+
import LiveRegion from "../internal/core/LiveRegion.vue";
|
|
37
35
|
const props = defineProps({
|
|
38
36
|
title: { type: String, required: false },
|
|
39
37
|
description: { type: String, required: false },
|
|
@@ -41,11 +39,13 @@ const props = defineProps({
|
|
|
41
39
|
empty: { type: Boolean, required: false },
|
|
42
40
|
emptyText: { type: String, required: false },
|
|
43
41
|
loadingText: { type: String, required: false },
|
|
44
|
-
height: { type: String, required: false, default: "16rem" }
|
|
42
|
+
height: { type: String, required: false, default: "16rem" },
|
|
43
|
+
level: { type: Number, required: false, default: 3 }
|
|
45
44
|
});
|
|
46
45
|
const { t } = useLocale();
|
|
47
46
|
const emptyLabel = computed(() => props.emptyText ?? t("chart.empty"));
|
|
48
47
|
const loadingLabel = computed(() => props.loadingText ?? t("chart.loading"));
|
|
49
48
|
const titleId = useId();
|
|
49
|
+
const headingTag = computed(() => `h${props.level}`);
|
|
50
50
|
const skeletonBars = [42, 68, 54, 86, 62, 74, 48, 92, 58, 70, 52, 80];
|
|
51
51
|
</script>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
declare var
|
|
1
|
+
declare var __VLS_7: {}, __VLS_9: {}, __VLS_12: {}, __VLS_14: {}, __VLS_16: {};
|
|
2
2
|
type __VLS_Slots = {} & {
|
|
3
|
-
legend?: (props: typeof
|
|
3
|
+
legend?: (props: typeof __VLS_7) => any;
|
|
4
4
|
} & {
|
|
5
|
-
actions?: (props: typeof
|
|
5
|
+
actions?: (props: typeof __VLS_9) => any;
|
|
6
6
|
} & {
|
|
7
|
-
empty?: (props: typeof
|
|
7
|
+
empty?: (props: typeof __VLS_12) => any;
|
|
8
8
|
} & {
|
|
9
|
-
default?: (props: typeof
|
|
9
|
+
default?: (props: typeof __VLS_14) => any;
|
|
10
10
|
} & {
|
|
11
|
-
footer?: (props: typeof
|
|
11
|
+
footer?: (props: typeof __VLS_16) => any;
|
|
12
12
|
};
|
|
13
13
|
declare const __VLS_base: import("vue").DefineComponent<{
|
|
14
14
|
title?: string | undefined;
|
|
@@ -18,6 +18,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
|
|
|
18
18
|
emptyText?: string;
|
|
19
19
|
loadingText?: string;
|
|
20
20
|
height?: string;
|
|
21
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
21
22
|
innerHTML?: string | undefined | undefined;
|
|
22
23
|
class?: import("vue").ClassValue;
|
|
23
24
|
style?: import("vue").StyleValue;
|
|
@@ -62,7 +63,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
|
|
|
62
63
|
is?: string | undefined | undefined;
|
|
63
64
|
exportparts?: string | undefined;
|
|
64
65
|
part?: string | undefined;
|
|
65
|
-
popover?: (import("
|
|
66
|
+
popover?: (import("../index.ts").PopoverMode | "" | boolean) | undefined;
|
|
66
67
|
'aria-activedescendant'?: string | undefined | undefined;
|
|
67
68
|
'aria-atomic'?: (boolean | "true" | "false") | undefined;
|
|
68
69
|
'aria-autocomplete'?: "none" | "inline" | "list" | "both" | undefined | undefined;
|
|
@@ -217,6 +218,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
|
|
|
217
218
|
emptyText?: string;
|
|
218
219
|
loadingText?: string;
|
|
219
220
|
height?: string;
|
|
221
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
220
222
|
innerHTML?: string | undefined | undefined;
|
|
221
223
|
class?: import("vue").ClassValue;
|
|
222
224
|
style?: import("vue").StyleValue;
|
|
@@ -261,7 +263,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
|
|
|
261
263
|
is?: string | undefined | undefined;
|
|
262
264
|
exportparts?: string | undefined;
|
|
263
265
|
part?: string | undefined;
|
|
264
|
-
popover?: (import("
|
|
266
|
+
popover?: (import("../index.ts").PopoverMode | "" | boolean) | undefined;
|
|
265
267
|
'aria-activedescendant'?: string | undefined | undefined;
|
|
266
268
|
'aria-atomic'?: (boolean | "true" | "false") | undefined;
|
|
267
269
|
'aria-autocomplete'?: "none" | "inline" | "list" | "both" | undefined | undefined;
|
|
@@ -410,6 +412,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
|
|
|
410
412
|
ref_key?: string | undefined | undefined;
|
|
411
413
|
}> & Readonly<{}>, {
|
|
412
414
|
height: string;
|
|
415
|
+
level: 1 | 2 | 4 | 3 | 5 | 6;
|
|
413
416
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
414
417
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
415
418
|
declare const _default: typeof __VLS_export;
|
|
@@ -14,16 +14,21 @@
|
|
|
14
14
|
<tbody>
|
|
15
15
|
<tr v-for="(label, index) in labels" :key="label">
|
|
16
16
|
<th scope="row">{{ label }}</th>
|
|
17
|
-
<td v-for="series in rows" :key="series.label">{{ series.data[index]
|
|
17
|
+
<td v-for="series in rows" :key="series.label">{{ cellText(series.data[index]) }}</td>
|
|
18
18
|
</tr>
|
|
19
19
|
</tbody>
|
|
20
20
|
</table>
|
|
21
21
|
</template>
|
|
22
22
|
|
|
23
23
|
<script setup>
|
|
24
|
-
defineProps({
|
|
24
|
+
const props = defineProps({
|
|
25
25
|
caption: { type: String, required: true },
|
|
26
26
|
labels: { type: Array, required: true },
|
|
27
|
-
rows: { type: Array, required: true }
|
|
27
|
+
rows: { type: Array, required: true },
|
|
28
|
+
formatValue: { type: Function, required: false }
|
|
28
29
|
});
|
|
30
|
+
function cellText(value) {
|
|
31
|
+
if (value === null || value === void 0) return "";
|
|
32
|
+
return props.formatValue ? props.formatValue(value) : String(value);
|
|
33
|
+
}
|
|
29
34
|
</script>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { ChartSeries } from './types';
|
|
1
|
+
import type { ChartSeries, ChartValueFormatter } from './types';
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<{
|
|
3
3
|
caption: string;
|
|
4
4
|
labels: string[];
|
|
5
5
|
rows: ChartSeries[];
|
|
6
|
+
formatValue?: ChartValueFormatter;
|
|
6
7
|
cellpadding?: (string | number) | undefined;
|
|
7
8
|
cellspacing?: (string | number) | undefined;
|
|
8
9
|
summary?: string | undefined | undefined;
|
|
@@ -203,6 +204,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
203
204
|
caption: string;
|
|
204
205
|
labels: string[];
|
|
205
206
|
rows: ChartSeries[];
|
|
207
|
+
formatValue?: ChartValueFormatter;
|
|
206
208
|
cellpadding?: (string | number) | undefined;
|
|
207
209
|
cellspacing?: (string | number) | undefined;
|
|
208
210
|
summary?: string | undefined | undefined;
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ref="root" class="k-chart k-chart-doughnut" :class="`k-chart-legend-${legendPosition}`">
|
|
3
|
-
<div class="k-chart-canvas" :style="{ height }"
|
|
4
|
-
<
|
|
5
|
-
|
|
3
|
+
<div class="k-chart-canvas" :style="{ height }">
|
|
4
|
+
<div class="k-chart-figure" role="img" :aria-label="label">
|
|
5
|
+
<Doughnut v-if="ready" :data="chartData" :options="chartOptions" />
|
|
6
|
+
<div v-else class="k-chart-placeholder is-round" aria-hidden="true" />
|
|
7
|
+
</div>
|
|
6
8
|
<div v-if="$slots.default" class="k-chart-center">
|
|
7
9
|
<slot />
|
|
8
10
|
</div>
|
|
9
11
|
</div>
|
|
10
12
|
<ChartLegend v-if="legend" :items="legendItems" :position="legendPosition" @toggle="toggle" />
|
|
11
|
-
<ChartSummary
|
|
13
|
+
<ChartSummary
|
|
14
|
+
:caption="label"
|
|
15
|
+
:labels="labels"
|
|
16
|
+
:rows="[{ label, data: values }]"
|
|
17
|
+
:format-value="formatValue"
|
|
18
|
+
/>
|
|
12
19
|
</div>
|
|
13
20
|
</template>
|
|
14
21
|
|
package/dist/chart/LineChart.vue
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
:position="legendPosition"
|
|
11
11
|
@toggle="toggle"
|
|
12
12
|
/>
|
|
13
|
-
<ChartSummary :caption="label" :labels="labels" :rows="series" />
|
|
13
|
+
<ChartSummary :caption="label" :labels="labels" :rows="series" :format-value="formatValue" />
|
|
14
14
|
</div>
|
|
15
15
|
</template>
|
|
16
16
|
|
|
@@ -22,6 +22,7 @@ import ChartSummary from "./ChartSummary.vue";
|
|
|
22
22
|
import { buildCartesianOptions } from "./options";
|
|
23
23
|
import { registerChartModules } from "./register";
|
|
24
24
|
import { useChartSurface } from "./useChartSurface";
|
|
25
|
+
import { seriesDash, seriesPoint } from "./patterns";
|
|
25
26
|
import { withAlpha } from "./useChartColors";
|
|
26
27
|
registerChartModules();
|
|
27
28
|
const props = defineProps({
|
|
@@ -34,6 +35,7 @@ const props = defineProps({
|
|
|
34
35
|
smooth: { type: Boolean, required: false, default: true },
|
|
35
36
|
fill: { type: Boolean, required: false },
|
|
36
37
|
points: { type: Boolean, required: false },
|
|
38
|
+
patterns: { type: Boolean, required: false },
|
|
37
39
|
stacked: { type: Boolean, required: false },
|
|
38
40
|
formatValue: { type: Function, required: false },
|
|
39
41
|
options: { type: null, required: false }
|
|
@@ -49,7 +51,9 @@ const legendItems = computed(
|
|
|
49
51
|
() => props.series.map((entry, index) => ({
|
|
50
52
|
label: entry.label,
|
|
51
53
|
color: colorAt(index),
|
|
52
|
-
hidden: isHidden(index)
|
|
54
|
+
hidden: isHidden(index),
|
|
55
|
+
dash: props.patterns ? seriesDash(index) : void 0,
|
|
56
|
+
point: props.patterns && props.points ? seriesPoint(index) : void 0
|
|
53
57
|
}))
|
|
54
58
|
);
|
|
55
59
|
const chartData = computed(() => ({
|
|
@@ -63,6 +67,8 @@ const chartData = computed(() => ({
|
|
|
63
67
|
borderColor: color,
|
|
64
68
|
backgroundColor: withAlpha(color, props.fill ? 0.14 : 1),
|
|
65
69
|
borderWidth: 2,
|
|
70
|
+
borderDash: props.patterns ? seriesDash(index) : [],
|
|
71
|
+
pointStyle: props.patterns ? seriesPoint(index) : "circle",
|
|
66
72
|
tension: props.smooth ? 0.35 : 0,
|
|
67
73
|
fill: props.fill ? "origin" : false,
|
|
68
74
|
pointRadius: props.points ? 3 : 0,
|
|
@@ -10,6 +10,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
10
10
|
smooth?: boolean;
|
|
11
11
|
fill?: boolean;
|
|
12
12
|
points?: boolean;
|
|
13
|
+
patterns?: boolean;
|
|
13
14
|
stacked?: boolean;
|
|
14
15
|
formatValue?: ChartValueFormatter;
|
|
15
16
|
options?: ChartOptions<"line">;
|
|
@@ -215,6 +216,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
|
|
|
215
216
|
smooth?: boolean;
|
|
216
217
|
fill?: boolean;
|
|
217
218
|
points?: boolean;
|
|
219
|
+
patterns?: boolean;
|
|
218
220
|
stacked?: boolean;
|
|
219
221
|
formatValue?: ChartValueFormatter;
|
|
220
222
|
options?: ChartOptions<"line">;
|
package/dist/chart/chart.css
CHANGED
|
@@ -97,6 +97,12 @@
|
|
|
97
97
|
border-radius: var(--k-radius-full);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
.k-chart-figure {
|
|
101
|
+
position: relative;
|
|
102
|
+
width: 100%;
|
|
103
|
+
height: 100%;
|
|
104
|
+
}
|
|
105
|
+
|
|
100
106
|
.k-chart-center {
|
|
101
107
|
position: absolute;
|
|
102
108
|
inset: 0;
|
|
@@ -168,6 +174,19 @@
|
|
|
168
174
|
border-radius: 3px;
|
|
169
175
|
}
|
|
170
176
|
|
|
177
|
+
.k-chart-legend-line {
|
|
178
|
+
flex: none;
|
|
179
|
+
width: 1.125rem;
|
|
180
|
+
height: 0.625rem;
|
|
181
|
+
overflow: visible;
|
|
182
|
+
fill: var(--k-surface);
|
|
183
|
+
stroke-width: 1.5;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.k-chart-legend-line > line {
|
|
187
|
+
stroke-width: 2;
|
|
188
|
+
}
|
|
189
|
+
|
|
171
190
|
.k-chart-legend-label {
|
|
172
191
|
flex: 1;
|
|
173
192
|
min-width: 0;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ChartBarPattern, ChartPointStyle } from './types';
|
|
2
|
+
export declare function seriesDash(index: number): number[];
|
|
3
|
+
export declare function seriesPoint(index: number): ChartPointStyle;
|
|
4
|
+
export declare function seriesPattern(index: number): ChartBarPattern;
|
|
5
|
+
export declare function barFill(color: string, pattern: ChartBarPattern, surface: string): string | CanvasPattern;
|
|
6
|
+
export declare function patternBackground(color: string, pattern: ChartBarPattern | undefined): string;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { isClient } from "../internal/core/env.mjs";
|
|
2
|
+
const dashes = [[], [6, 4], [2, 3], [10, 3, 2, 3], [14, 5], [4, 2, 1, 2]];
|
|
3
|
+
const points = ["circle", "rect", "triangle", "rectRot", "star", "crossRot"];
|
|
4
|
+
const patterns = ["solid", "diagonal", "dots", "horizontal", "reverse", "cross"];
|
|
5
|
+
export function seriesDash(index) {
|
|
6
|
+
return dashes[index % dashes.length];
|
|
7
|
+
}
|
|
8
|
+
export function seriesPoint(index) {
|
|
9
|
+
return points[index % points.length];
|
|
10
|
+
}
|
|
11
|
+
export function seriesPattern(index) {
|
|
12
|
+
return patterns[index % patterns.length];
|
|
13
|
+
}
|
|
14
|
+
const TILE = 8;
|
|
15
|
+
const cache = /* @__PURE__ */ new Map();
|
|
16
|
+
function strokeLine(context, x1, y1, x2, y2) {
|
|
17
|
+
context.beginPath();
|
|
18
|
+
context.moveTo(x1, y1);
|
|
19
|
+
context.lineTo(x2, y2);
|
|
20
|
+
context.stroke();
|
|
21
|
+
}
|
|
22
|
+
function drawMarks(context, pattern) {
|
|
23
|
+
if (pattern === "diagonal" || pattern === "cross") {
|
|
24
|
+
strokeLine(context, -1, TILE + 1, TILE + 1, -1);
|
|
25
|
+
strokeLine(context, -1, 1, 1, -1);
|
|
26
|
+
strokeLine(context, TILE - 1, TILE + 1, TILE + 1, TILE - 1);
|
|
27
|
+
}
|
|
28
|
+
if (pattern === "reverse" || pattern === "cross") {
|
|
29
|
+
strokeLine(context, -1, -1, TILE + 1, TILE + 1);
|
|
30
|
+
strokeLine(context, TILE - 1, -1, TILE + 1, 1);
|
|
31
|
+
strokeLine(context, -1, TILE - 1, 1, TILE + 1);
|
|
32
|
+
}
|
|
33
|
+
if (pattern === "horizontal") strokeLine(context, 0, TILE / 2, TILE, TILE / 2);
|
|
34
|
+
if (pattern === "dots") {
|
|
35
|
+
context.beginPath();
|
|
36
|
+
context.arc(TILE / 2, TILE / 2, 1.5, 0, Math.PI * 2);
|
|
37
|
+
context.fill();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function barFill(color, pattern, surface) {
|
|
41
|
+
if (pattern === "solid" || !isClient()) return color;
|
|
42
|
+
const key = `${color}|${pattern}|${surface}`;
|
|
43
|
+
const cached = cache.get(key);
|
|
44
|
+
if (cached) return cached;
|
|
45
|
+
const canvas = document.createElement("canvas");
|
|
46
|
+
canvas.width = TILE;
|
|
47
|
+
canvas.height = TILE;
|
|
48
|
+
const context = canvas.getContext("2d");
|
|
49
|
+
if (!context) return color;
|
|
50
|
+
context.fillStyle = color;
|
|
51
|
+
context.fillRect(0, 0, TILE, TILE);
|
|
52
|
+
context.globalAlpha = 0.6;
|
|
53
|
+
context.strokeStyle = surface;
|
|
54
|
+
context.fillStyle = surface;
|
|
55
|
+
context.lineWidth = 1.5;
|
|
56
|
+
drawMarks(context, pattern);
|
|
57
|
+
const result = context.createPattern(canvas, "repeat") ?? color;
|
|
58
|
+
if (cache.size > 200) cache.clear();
|
|
59
|
+
cache.set(key, result);
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
export function patternBackground(color, pattern) {
|
|
63
|
+
const mark = `color-mix(in oklab, var(--k-surface) 60%, ${color})`;
|
|
64
|
+
const stripes = (angle) => `repeating-linear-gradient(${angle}, ${color} 0 2.5px, ${mark} 2.5px 4px)`;
|
|
65
|
+
switch (pattern) {
|
|
66
|
+
case "diagonal":
|
|
67
|
+
return stripes("-45deg");
|
|
68
|
+
case "reverse":
|
|
69
|
+
return stripes("45deg");
|
|
70
|
+
case "horizontal":
|
|
71
|
+
return stripes("0deg");
|
|
72
|
+
case "cross":
|
|
73
|
+
return `repeating-linear-gradient(45deg, transparent 0 2.5px, ${mark} 2.5px 4px), ${stripes("-45deg")}`;
|
|
74
|
+
case "dots":
|
|
75
|
+
return `radial-gradient(circle, ${mark} 0 1px, transparent 1.25px) 0 0 / 4px 4px, ${color}`;
|
|
76
|
+
default:
|
|
77
|
+
return color;
|
|
78
|
+
}
|
|
79
|
+
}
|