@xleddyl/443-components-vue 0.8.0 → 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 (150) hide show
  1. package/README.md +38 -2
  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 +62 -8
  61. package/dist/grid/DataGrid.vue.d.ts +10 -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 +7 -6
  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 +2 -2
  73. package/dist/index.mjs +2 -1
  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.d.ts +2 -0
  82. package/dist/locale/de.mjs +362 -0
  83. package/dist/locale/en.mjs +10 -2
  84. package/dist/locale/index.d.ts +2 -1
  85. package/dist/locale/index.mjs +3 -2
  86. package/dist/locale/it.mjs +10 -2
  87. package/dist/locale/types.d.ts +8 -0
  88. package/dist/nuxt/runtime/layouts/dashboard.vue +1 -0
  89. package/dist/styles/base.css +2 -1
  90. package/dist/styles/core/button.css +42 -16
  91. package/dist/styles/core/form-field.css +1 -1
  92. package/dist/styles/core/input.css +2 -2
  93. package/dist/styles/core/kbd.css +1 -1
  94. package/dist/styles/data/avatar.css +1 -1
  95. package/dist/styles/data/badge.css +40 -24
  96. package/dist/styles/data/description-list.css +2 -2
  97. package/dist/styles/data/filter-pills.css +24 -3
  98. package/dist/styles/data/pagination.css +26 -3
  99. package/dist/styles/data/selection-bar.css +1 -1
  100. package/dist/styles/data/stat.css +4 -4
  101. package/dist/styles/data/table.css +4 -4
  102. package/dist/styles/data/tag.css +1 -1
  103. package/dist/styles/data/timeline.css +1 -1
  104. package/dist/styles/data/tree.css +2 -2
  105. package/dist/styles/feedback/empty-state.css +1 -1
  106. package/dist/styles/feedback/loading-host.css +1 -1
  107. package/dist/styles/feedback/loading-overlay.css +1 -1
  108. package/dist/styles/feedback/meter.css +1 -1
  109. package/dist/styles/feedback/progress.css +2 -2
  110. package/dist/styles/forced-colors.css +6 -1
  111. package/dist/styles/forms/calendar.css +30 -3
  112. package/dist/styles/forms/checkbox.css +1 -1
  113. package/dist/styles/forms/choice.css +1 -1
  114. package/dist/styles/forms/combobox.css +2 -2
  115. package/dist/styles/forms/file-input.css +1 -1
  116. package/dist/styles/forms/password-input.css +1 -1
  117. package/dist/styles/forms/pin-input.css +1 -1
  118. package/dist/styles/forms/radio.css +1 -1
  119. package/dist/styles/forms/segmented.css +2 -2
  120. package/dist/styles/forms/select.css +2 -2
  121. package/dist/styles/forms/slider.css +1 -1
  122. package/dist/styles/forms/switch.css +4 -4
  123. package/dist/styles/layout/accordion.css +2 -2
  124. package/dist/styles/layout/app-shell.css +18 -6
  125. package/dist/styles/layout/breadcrumbs.css +3 -3
  126. package/dist/styles/layout/card.css +1 -1
  127. package/dist/styles/layout/nav-link.css +1 -1
  128. package/dist/styles/layout/page-header.css +21 -1
  129. package/dist/styles/layout/separator.css +21 -1
  130. package/dist/styles/layout/sidebar.css +1 -1
  131. package/dist/styles/layout/tabs.css +30 -1
  132. package/dist/styles/layout/theme-switch.css +1 -1
  133. package/dist/styles/overlays/command.css +3 -3
  134. package/dist/styles/overlays/drawer.css +4 -3
  135. package/dist/styles/overlays/floating.css +2 -2
  136. package/dist/styles/overlays/menu.css +5 -1
  137. package/dist/styles/overlays/modal.css +13 -10
  138. package/dist/styles/overlays/toast.css +3 -3
  139. package/dist/styles/overlays/tooltip.css +26 -8
  140. package/dist/styles/shared.css +2 -2
  141. package/dist/styles/templates/account-menu.css +1 -1
  142. package/dist/styles/templates/auth-layout.css +4 -4
  143. package/dist/styles/templates/brand.css +2 -2
  144. package/dist/styles/templates/dashboard-page.css +1 -1
  145. package/dist/styles/templates/empty-page.css +3 -3
  146. package/dist/styles/templates/error-page.css +1 -1
  147. package/dist/styles/templates/save-bar.css +1 -1
  148. package/dist/styles/templates/settings-modal.css +6 -6
  149. package/dist/styles/utilities.css +3 -3
  150. package/package.json +1 -1
@@ -4,6 +4,7 @@
4
4
  v-model:open="open"
5
5
  prefix="k-modal"
6
6
  :root-class="[`k-modal-${size}`, { 'is-sheet': sheet && size !== 'fullscreen' }]"
7
+ :style="sizeStyle"
7
8
  :title="title"
8
9
  :description="description"
9
10
  :label="label"
@@ -26,7 +27,7 @@
26
27
  <script setup>
27
28
  import { computed, useTemplateRef } from "vue";
28
29
  import DialogFrame from "../../internal/overlays/DialogFrame.vue";
29
- defineProps({
30
+ const props = defineProps({
30
31
  title: { type: String, required: false },
31
32
  description: { type: String, required: false },
32
33
  label: { type: String, required: false },
@@ -37,8 +38,14 @@ defineProps({
37
38
  sheet: { type: Boolean, required: false, default: true },
38
39
  flush: { type: Boolean, required: false },
39
40
  loading: { type: Boolean, required: false },
40
- beforeClose: { type: Function, required: false }
41
+ beforeClose: { type: Function, required: false },
42
+ width: { type: String, required: false },
43
+ minHeight: { type: String, required: false }
41
44
  });
45
+ const sizeStyle = computed(() => ({
46
+ "--k-modal-custom-width": props.width,
47
+ "--k-modal-min-height": props.minHeight
48
+ }));
42
49
  const slots = defineSlots();
43
50
  const slotNames = computed(() => Object.keys(slots));
44
51
  const emit = defineEmits(["open", "close", "afterLeave"]);
@@ -13,6 +13,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
13
13
  flush?: boolean;
14
14
  loading?: boolean;
15
15
  beforeClose?: DialogBeforeClose;
16
+ width?: string;
17
+ minHeight?: string;
16
18
  open?: boolean | undefined;
17
19
  key?: PropertyKey | undefined;
18
20
  prefix?: "k-modal" | "k-drawer" | undefined;
@@ -234,6 +236,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
234
236
  flush?: boolean;
235
237
  loading?: boolean;
236
238
  beforeClose?: DialogBeforeClose;
239
+ width?: string;
240
+ minHeight?: string;
237
241
  open?: boolean | undefined;
238
242
  key?: PropertyKey | undefined;
239
243
  prefix?: "k-modal" | "k-drawer" | undefined;
@@ -10,6 +10,7 @@
10
10
  :close-label="closeLabel"
11
11
  :skip-label="skipLabel"
12
12
  :fluid="fluid"
13
+ :fill="fill"
13
14
  :topbar="hasDesktopTopbar"
14
15
  :storage-key="storageKey || void 0"
15
16
  :shortcut="shortcut"
@@ -193,6 +194,7 @@ const props = defineProps({
193
194
  storageKey: { type: [String, Boolean], required: false, default: "k-sidebar-collapsed" },
194
195
  shortcut: { type: [String, Boolean], required: false, default: "mod+b" },
195
196
  fluid: { type: Boolean, required: false },
197
+ fill: { type: Boolean, required: false },
196
198
  viewTransition: { type: Boolean, required: false, default: true },
197
199
  navLabel: { type: String, required: false },
198
200
  sidebarLabel: { type: String, required: false },
@@ -34,6 +34,7 @@ declare const __VLS_export: <T = unknown>(__VLS_props: NonNullable<Awaited<typeo
34
34
  storageKey?: string | false;
35
35
  shortcut?: string | false;
36
36
  fluid?: boolean;
37
+ fill?: boolean;
37
38
  viewTransition?: boolean;
38
39
  navLabel?: string;
39
40
  sidebarLabel?: string;
@@ -61,6 +62,7 @@ declare const __VLS_export: <T = unknown>(__VLS_props: NonNullable<Awaited<typeo
61
62
  readonly closeLabel?: string | undefined;
62
63
  readonly skipLabel?: string | undefined;
63
64
  readonly fluid?: boolean | undefined;
65
+ readonly fill?: boolean | undefined;
64
66
  readonly topbar?: boolean | undefined;
65
67
  readonly storageKey?: string | false | undefined;
66
68
  readonly shortcut?: string | false | undefined;
@@ -36,12 +36,12 @@ declare const __VLS_base: import("vue").DefineComponent<{
36
36
  key?: PropertyKey | undefined;
37
37
  loading?: boolean;
38
38
  prefix?: "k-modal" | "k-drawer" | undefined;
39
+ size?: import("../overlays/types").ModalSize;
39
40
  label?: string;
40
41
  style?: import("vue").StyleValue;
41
42
  results?: (string | number) | undefined;
42
43
  placeholder?: string | undefined;
43
44
  description?: string;
44
- size?: import("../overlays/types").ModalSize;
45
45
  dir?: string | undefined;
46
46
  class?: import("vue").ClassValue;
47
47
  role?: string | undefined;
@@ -145,6 +145,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
145
145
  color?: string | undefined;
146
146
  id?: string | undefined;
147
147
  lang?: string | undefined;
148
+ width?: string;
148
149
  tabindex?: (string | number) | undefined;
149
150
  'aria-activedescendant'?: string | undefined;
150
151
  'aria-atomic'?: (boolean | "true" | "false") | undefined;
@@ -241,6 +242,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
241
242
  rootClass?: unknown;
242
243
  hideClose?: boolean;
243
244
  closedby?: import("../../index.ts").DialogClosedBy;
245
+ minHeight?: string;
244
246
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
245
247
  close: () => any;
246
248
  open: () => any;
@@ -273,12 +275,12 @@ declare const __VLS_base: import("vue").DefineComponent<{
273
275
  key?: PropertyKey | undefined;
274
276
  loading?: boolean;
275
277
  prefix?: "k-modal" | "k-drawer" | undefined;
278
+ size?: import("../overlays/types").ModalSize;
276
279
  label?: string;
277
280
  style?: import("vue").StyleValue;
278
281
  results?: (string | number) | undefined;
279
282
  placeholder?: string | undefined;
280
283
  description?: string;
281
- size?: import("../overlays/types").ModalSize;
282
284
  dir?: string | undefined;
283
285
  class?: import("vue").ClassValue;
284
286
  role?: string | undefined;
@@ -382,6 +384,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
382
384
  color?: string | undefined;
383
385
  id?: string | undefined;
384
386
  lang?: string | undefined;
387
+ width?: string;
385
388
  tabindex?: (string | number) | undefined;
386
389
  'aria-activedescendant'?: string | undefined;
387
390
  'aria-atomic'?: (boolean | "true" | "false") | undefined;
@@ -478,6 +481,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
478
481
  rootClass?: unknown;
479
482
  hideClose?: boolean;
480
483
  closedby?: import("../../index.ts").DialogClosedBy;
484
+ minHeight?: string;
481
485
  }> & Readonly<{
482
486
  onClose?: (() => any) | undefined;
483
487
  onOpen?: (() => any) | undefined;
@@ -129,6 +129,7 @@ export interface KAppConfig {
129
129
  collapsible?: boolean;
130
130
  storageKey?: string | false;
131
131
  fluid?: boolean;
132
+ fill?: boolean;
132
133
  breadcrumbs?: boolean;
133
134
  };
134
135
  auth?: {
@@ -1,4 +1,4 @@
1
- import type { ComputedRef, MaybeRefOrGetter, Ref, UnwrapRef } from 'vue';
1
+ import type { App, ComputedRef, MaybeRefOrGetter, Ref, UnwrapRef } from 'vue';
2
2
  import type { IssueKeyResolver, StandardSchemaIssue, StandardSchemaV1 } from '../internal/forms/standard-schema';
3
3
  export type { IssuePath as FormIssuePath, StandardSchemaIssue, StandardSchemaResult, StandardSchemaV1, } from '../internal/forms/standard-schema';
4
4
  export type FieldValidationResult = string | undefined | null | boolean;
@@ -36,6 +36,16 @@ export interface FormMessages {
36
36
  pattern: (context: FormMessageContext) => string;
37
37
  invalid: (context: FormMessageContext) => string;
38
38
  }
39
+ export interface FormTranslateContext {
40
+ name?: string;
41
+ label?: string;
42
+ kind: 'error' | 'warning';
43
+ }
44
+ export type FormTranslateMessage = (message: string, context: FormTranslateContext) => string;
45
+ export interface FormConfig {
46
+ messages?: Partial<FormMessages>;
47
+ translateMessage?: FormTranslateMessage;
48
+ }
39
49
  export type FormValidationTrigger = 'submit' | 'blur' | 'input';
40
50
  export type FormIssueKey = IssueKeyResolver;
41
51
  export type FormMessageMap = Record<string, string | undefined>;
@@ -50,6 +60,7 @@ export interface UseFormOptions<S extends FormSchema = FormSchema, V extends obj
50
60
  warnings?: FormWarnings<V>;
51
61
  issueKey?: FormIssueKey;
52
62
  messages?: Partial<FormMessages>;
63
+ translateMessage?: FormTranslateMessage;
53
64
  validateOn?: FormValidationTrigger;
54
65
  onSubmit?: (values: V) => unknown;
55
66
  onInvalid?: (errors: FormErrors<S>) => unknown;
@@ -94,4 +105,8 @@ export interface UseFormReturn<S extends FormSchema = FormSchema, V extends obje
94
105
  export declare function isEmptyValue(value: unknown): boolean;
95
106
  export declare function useForm<S extends FormSchema = FormSchema, V extends object = FormValues<S>>(options: UseFormOptions<S, V>): UseFormReturn<S, V>;
96
107
  export declare function useFormContext(): FormContext | null;
108
+ export declare function provideFormConfig(config: FormConfig): FormConfig;
109
+ export declare function createFormConfig(config: FormConfig): {
110
+ install(app: App): void;
111
+ };
97
112
  export declare function provideForm(form: FormContext): FormContext;
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  computed,
3
+ hasInjectionContext,
3
4
  inject,
4
5
  isRef,
5
6
  provide,
@@ -18,7 +19,7 @@ import {
18
19
  keyPath,
19
20
  schemaIssues
20
21
  } from "../internal/forms/standard-schema.mjs";
21
- import { FORM_KEY } from "../internal/keys.mjs";
22
+ import { FORM_CONFIG_KEY, FORM_KEY } from "../internal/keys.mjs";
22
23
  import { useLocale } from "./useLocale.mjs";
23
24
  function localeFormMessages(t) {
24
25
  return {
@@ -101,7 +102,19 @@ export function useForm(options) {
101
102
  const schemaNames = Object.keys(schema);
102
103
  const external = options.values !== void 0;
103
104
  const { t } = useLocale();
104
- const messages = computed(() => ({ ...localeFormMessages(t), ...options.messages }));
105
+ const config = hasInjectionContext() && inject(FORM_CONFIG_KEY, null) || null;
106
+ const messages = computed(() => ({
107
+ ...localeFormMessages(t),
108
+ ...config?.messages,
109
+ ...options.messages
110
+ }));
111
+ const translator = options.translateMessage ?? config?.translateMessage;
112
+ const translate = (message, context) => translator && message ? translator(message, context) : message;
113
+ const translateIssues = (issues, kind) => issues.map((issue) => {
114
+ const name = issue.path.map(String).join(".") || void 0;
115
+ const label = name ? schema[name]?.label : void 0;
116
+ return { ...issue, message: translate(issue.message, { name, label, kind }) };
117
+ });
105
118
  const validateOn = options.validateOn ?? "submit";
106
119
  const issueKey = options.issueKey ?? defaultIssueKey;
107
120
  const initialValues = () => Object.fromEntries(schemaNames.map((name) => [name, resolveInitial(schema[name])]));
@@ -153,7 +166,7 @@ export function useForm(options) {
153
166
  if (!validator) return groupIssues([]);
154
167
  return chain(
155
168
  validator["~standard"].validate(cloneValue(target())),
156
- (result) => groupIssues(schemaIssues(result.issues ?? []), issueKey)
169
+ (result) => groupIssues(translateIssues(schemaIssues(result.issues ?? []), "error"), issueKey)
157
170
  );
158
171
  }
159
172
  async function runValidator() {
@@ -164,6 +177,7 @@ export function useForm(options) {
164
177
  if (!definition) return void 0;
165
178
  const value = readValue(name);
166
179
  const fieldMessages = { ...messages.value, ...definition.messages };
180
+ const own = (message) => translate(message, { name, label: definition.label, kind: "error" });
167
181
  const context = {
168
182
  label: definition.label,
169
183
  value,
@@ -197,12 +211,12 @@ export function useForm(options) {
197
211
  if (!definition.schema) return void 0;
198
212
  return chain(definition.schema["~standard"].validate(value), (result) => {
199
213
  const issues = result.issues ?? [];
200
- return issues.length ? issues[0].message || fieldMessages.invalid(context) : void 0;
214
+ return issues.length ? issues[0].message && own(issues[0].message) || fieldMessages.invalid(context) : void 0;
201
215
  });
202
216
  };
203
217
  if (!definition.validate) return runSchema();
204
218
  return chain(definition.validate(value, target()), (result) => {
205
- if (typeof result === "string" && result) return result;
219
+ if (typeof result === "string" && result) return own(result);
206
220
  if (result === false) return fieldMessages.invalid(context);
207
221
  return runSchema();
208
222
  });
@@ -373,7 +387,7 @@ export function useForm(options) {
373
387
  let warningRun = 0;
374
388
  const applyWarnings = (result) => {
375
389
  const list = Array.isArray(result) ? schemaIssues(result) : Object.entries(result ?? {}).filter((entry) => Boolean(entry[1])).map(([key, message]) => ({ message, path: keyPath(key) }));
376
- const grouped = groupIssues(list, issueKey);
390
+ const grouped = groupIssues(translateIssues(list, "warning"), issueKey);
377
391
  replaceEntries(warnings, grouped.fields);
378
392
  rootWarnings.value = grouped.root;
379
393
  };
@@ -423,6 +437,17 @@ export function useForm(options) {
423
437
  export function useFormContext() {
424
438
  return inject(FORM_KEY, null);
425
439
  }
440
+ export function provideFormConfig(config) {
441
+ provide(FORM_CONFIG_KEY, config);
442
+ return config;
443
+ }
444
+ export function createFormConfig(config) {
445
+ return {
446
+ install(app) {
447
+ app.provide(FORM_CONFIG_KEY, config);
448
+ }
449
+ };
450
+ }
426
451
  export function provideForm(form) {
427
452
  provide(FORM_KEY, form);
428
453
  return form;
@@ -338,6 +338,16 @@ const defaultToolbar = computed(() => [
338
338
  }
339
339
  ]
340
340
  ]);
341
+ const optionalItems = computed(() => [
342
+ mark(
343
+ "underline",
344
+ text.value.underline,
345
+ "U",
346
+ "is-underline",
347
+ "underline",
348
+ () => editor.value?.chain().focus().toggleUnderline().run()
349
+ )
350
+ ]);
341
351
  function isToolbarGroups(toolbar) {
342
352
  return toolbar.some((entry) => Array.isArray(entry));
343
353
  }
@@ -352,7 +362,9 @@ function splitToolbar(toolbar) {
352
362
  }
353
363
  const groups = computed(() => {
354
364
  if (!props.toolbar) return defaultToolbar.value.filter((group) => group.length);
355
- const byId = new Map(defaultToolbar.value.flat().map((item) => [item.id, item]));
365
+ const byId = new Map(
366
+ [...defaultToolbar.value.flat(), ...optionalItems.value].map((item) => [item.id, item])
367
+ );
356
368
  const headingItems = defaultToolbar.value[1] ?? [];
357
369
  return splitToolbar(props.toolbar).map(
358
370
  (group) => group.flatMap((entry) => {
@@ -429,8 +429,8 @@ declare const __VLS_export: import("vue").DefineComponent<{
429
429
  }>, {
430
430
  invalid: boolean;
431
431
  format: EditorFormat;
432
- headings: EditorHeadingLevel[];
433
432
  minHeight: string;
433
+ headings: EditorHeadingLevel[];
434
434
  headingLabel: EditorHeadingLabel;
435
435
  extensions: Extensions;
436
436
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -90,7 +90,13 @@
90
90
 
91
91
  .k-editor-glyph-text.is-strike {
92
92
  text-decoration: line-through;
93
- font-weight: 600;
93
+ font-weight: var(--k-font-weight-strong, 600);
94
+ }
95
+
96
+ .k-editor-glyph-text.is-underline {
97
+ text-decoration: underline;
98
+ text-underline-offset: 2px;
99
+ font-weight: var(--k-font-weight-strong, 600);
94
100
  }
95
101
 
96
102
  .k-editor-glyph-text.is-mono {
@@ -100,7 +106,7 @@
100
106
 
101
107
  .k-editor-glyph-text.is-tabular {
102
108
  font-variant-numeric: tabular-nums;
103
- font-weight: 600;
109
+ font-weight: var(--k-font-weight-strong, 600);
104
110
  }
105
111
 
106
112
  .k-editor-glyph-text.is-quote {
@@ -161,7 +167,7 @@
161
167
  .k-editor-prose h3,
162
168
  .k-editor-prose h4 {
163
169
  margin: 1.25em 0 0.5em;
164
- font-weight: 600;
170
+ font-weight: var(--k-font-weight-strong, 600);
165
171
  line-height: 1.25;
166
172
  letter-spacing: -0.015em;
167
173
  color: var(--k-text);
@@ -180,7 +186,7 @@
180
186
  }
181
187
 
182
188
  .k-editor-prose strong {
183
- font-weight: 600;
189
+ font-weight: var(--k-font-weight-strong, 600);
184
190
  color: var(--k-text);
185
191
  }
186
192
 
@@ -5,5 +5,5 @@ export type EditorValue = string | JSONContent | null;
5
5
  export type EditorMessages = KMessages['editor'];
6
6
  export type EditorHeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
7
7
  export type EditorHeadingLabel = 'level' | 'relative';
8
- export type EditorToolbarItem = 'undo' | 'redo' | 'headings' | `h${EditorHeadingLevel}` | 'bold' | 'italic' | 'strike' | 'code' | 'bulletList' | 'orderedList' | 'blockquote' | 'link' | '|';
8
+ export type EditorToolbarItem = 'undo' | 'redo' | 'headings' | `h${EditorHeadingLevel}` | 'bold' | 'italic' | 'underline' | 'strike' | 'code' | 'bulletList' | 'orderedList' | 'blockquote' | 'link' | '|';
9
9
  export type EditorToolbar = EditorToolbarItem[] | EditorToolbarItem[][];
@@ -27,10 +27,11 @@
27
27
  >
28
28
  <AgGridVue
29
29
  v-if="mounted"
30
+ v-bind="gridOptions"
30
31
  class="k-data-grid-ag"
31
32
  :theme="theme"
32
33
  :row-data="rows"
33
- :column-defs="columns"
34
+ :column-defs="columnDefs"
34
35
  :default-col-def="defaultColDef"
35
36
  :get-row-id="props.rowIdKey ? getRowId : void 0"
36
37
  :loading="loading"
@@ -46,6 +47,8 @@
46
47
  :suppress-pagination-panel="true"
47
48
  :auto-size-strategy="autoSizeStrategy"
48
49
  :dom-layout="autoHeight ? 'autoHeight' : 'normal'"
50
+ :row-height="rowHeight ?? gridOptions?.rowHeight"
51
+ :header-height="headerHeight ?? gridOptions?.headerHeight"
49
52
  :tooltip-show-delay="600"
50
53
  :suppress-cell-focus="false"
51
54
  v-on="gridEvents"
@@ -90,7 +93,7 @@
90
93
 
91
94
  <script setup>
92
95
  import { AgGridVue } from "ag-grid-vue3";
93
- import { computed, onMounted, ref, shallowRef, watch } from "vue";
96
+ import { computed, nextTick, onMounted, ref, shallowRef, watch } from "vue";
94
97
  import Pagination from "../components/data/Pagination.vue";
95
98
  import Spinner from "../components/core/Spinner.vue";
96
99
  import { useCopy } from "../composables/useCopy";
@@ -101,7 +104,7 @@ import { useLiveMessage } from "../internal/core/live";
101
104
  import { readStorageJson, removeStorage, writeStorageJson } from "../internal/core/storage";
102
105
  import GridToolbar from "./GridToolbar.vue";
103
106
  import { escapeHtml } from "../internal/core/text";
104
- import { registerGridModules } from "./modules";
107
+ import { registerGridFilterModules, registerGridModules } from "./modules";
105
108
  import { getGridTheme } from "./theme";
106
109
  registerGridModules();
107
110
  const props = defineProps({
@@ -127,12 +130,28 @@ const props = defineProps({
127
130
  total: { type: Number, required: false, default: 0 },
128
131
  pageSizes: { type: Array, required: false, default: () => [10, 25, 50, 100] },
129
132
  messages: { type: Object, required: false },
130
- localeText: { type: Object, required: false }
133
+ localeText: { type: Object, required: false },
134
+ gridOptions: { type: Object, required: false },
135
+ rowHeight: { type: Number, required: false },
136
+ headerHeight: { type: Number, required: false },
137
+ headerText: { type: Function, required: false },
138
+ filterable: { type: Boolean, required: false }
131
139
  });
132
- const emit = defineEmits(["rowClick", "selectionChange", "sortChange", "copy"]);
140
+ const emit = defineEmits(["rowClick", "selectionChange", "sortChange", "filterChange", "copy"]);
133
141
  const query = defineModel("query", { type: String, ...{ default: "" } });
134
142
  const page = defineModel("page", { type: Number, ...{ default: 1 } });
135
143
  const pageSize = defineModel("pageSize", { type: Number, ...{ default: 25 } });
144
+ const sort = defineModel("sort", { type: null, ...{ default: void 0 } });
145
+ if (props.filterable) registerGridFilterModules();
146
+ const columnDefs = computed(() => {
147
+ const headerText = props.headerText;
148
+ if (!headerText) return props.columns;
149
+ return props.columns.map((column) => {
150
+ if (column.headerName !== void 0 || !column.field) return column;
151
+ const headerName = headerText(String(column.field), column);
152
+ return headerName === void 0 ? column : { ...column, headerName };
153
+ });
154
+ });
136
155
  const { locale, t } = useLocale();
137
156
  const text = computed(() => ({
138
157
  ...locale.value.messages.grid,
@@ -195,6 +214,7 @@ const rowSelection = computed(() => {
195
214
  const defaultColDef = computed(() => ({
196
215
  sortable: true,
197
216
  resizable: true,
217
+ filter: props.filterable || void 0,
198
218
  minWidth: 80,
199
219
  comparator: props.serverSort ? () => 0 : void 0,
200
220
  valueFormatter: (params) => isEmpty(params.value) ? "-" : String(params.value),
@@ -245,8 +265,28 @@ function onGridReady(event) {
245
265
  api.value = event.api;
246
266
  const stored = readStoredState();
247
267
  if (stored?.length) event.api.applyColumnState({ state: stored, applyOrder: true });
268
+ applySort();
248
269
  syncPagination();
249
270
  }
271
+ function sameSort(a, b) {
272
+ return (a?.column ?? null) === (b?.column ?? null) && (a?.direction ?? null) === (b?.direction ?? null);
273
+ }
274
+ function readSort(current) {
275
+ const sorted = current.getColumnState().filter((column) => column.sort).sort((a, b) => (a.sortIndex ?? 0) - (b.sortIndex ?? 0))[0];
276
+ return sorted?.sort ? { column: sorted.colId, direction: sorted.sort } : null;
277
+ }
278
+ function applySort() {
279
+ const current = api.value;
280
+ if (!current || sort.value === void 0) return;
281
+ if (sameSort(readSort(current), sort.value)) return;
282
+ const target = sort.value;
283
+ current.applyColumnState({
284
+ state: target ? [{ colId: target.column, sort: target.direction }] : [],
285
+ defaultState: { sort: null }
286
+ });
287
+ }
288
+ watch(sort, applySort);
289
+ watch(columnDefs, () => nextTick(applySort));
250
290
  function syncPagination() {
251
291
  const current = api.value;
252
292
  if (!current || props.serverPagination) return;
@@ -279,9 +319,22 @@ function onSelectionChanged(event) {
279
319
  emit("selectionChange", rows);
280
320
  }
281
321
  function onSortChanged(event) {
282
- if (!props.serverSort) return;
283
- const sorted = event.api.getColumnState().find((column) => column.sort);
284
- emit("sortChange", sorted?.sort ? { column: sorted.colId, direction: sorted.sort } : null);
322
+ const change = readSort(event.api);
323
+ if (!sameSort(change, sort.value)) sort.value = change;
324
+ if (props.serverSort) emit("sortChange", change);
325
+ }
326
+ const columnFilterModules = [
327
+ "TextFilterModule",
328
+ "NumberFilterModule",
329
+ "DateFilterModule",
330
+ "BigIntFilterModule",
331
+ "CustomFilterModule",
332
+ "SetFilterModule",
333
+ "MultiFilterModule"
334
+ ];
335
+ function onFilterChanged(event) {
336
+ if (!columnFilterModules.some((name) => event.api.isModuleRegistered(name))) return;
337
+ emit("filterChange", event.api.getFilterModel(), event);
285
338
  }
286
339
  async function onCellContextMenu(event) {
287
340
  if (!event.node || !event.column) return;
@@ -299,6 +352,7 @@ const gridEvents = {
299
352
  rowClicked: (event) => emit("rowClick", event),
300
353
  selectionChanged: onSelectionChanged,
301
354
  sortChanged: onSortChanged,
355
+ filterChanged: onFilterChanged,
302
356
  cellContextMenu: onCellContextMenu,
303
357
  paginationChanged: syncPagination,
304
358
  modelUpdated: onModelUpdated,
@@ -1,4 +1,4 @@
1
- import type { ColDef, GridApi, RowClickedEvent } from 'ag-grid-community';
1
+ import type { FilterChangedEvent, FilterModel, ColDef, GridApi, GridOptions, RowClickedEvent } from 'ag-grid-community';
2
2
  import type { GridDensity, GridMessages, GridSelection, GridSortChange } from './types';
3
3
  declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
4
4
  props: import("vue").PublicProps & __VLS_PrettifyLocal<({
@@ -25,18 +25,26 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
25
25
  pageSizes?: number[];
26
26
  messages?: Partial<GridMessages>;
27
27
  localeText?: Record<string, string>;
28
+ gridOptions?: GridOptions<T>;
29
+ rowHeight?: number;
30
+ headerHeight?: number;
31
+ headerText?: (field: string, column: ColDef<T>) => string | undefined;
32
+ filterable?: boolean;
28
33
  } & {
29
34
  query?: string;
30
35
  page?: number;
31
36
  pageSize?: number;
37
+ sort?: GridSortChange | null | undefined;
32
38
  }) & {
33
39
  onCopy?: ((text: string) => any) | undefined;
34
40
  "onUpdate:page"?: ((value: number) => any) | undefined;
35
41
  "onUpdate:pageSize"?: ((value: number) => any) | undefined;
36
42
  onRowClick?: ((event: RowClickedEvent<T, any>) => any) | undefined;
43
+ "onUpdate:sort"?: ((value: GridSortChange | null | undefined) => any) | undefined;
37
44
  "onUpdate:query"?: ((value: string) => any) | undefined;
38
45
  onSelectionChange?: ((rows: T[]) => any) | undefined;
39
46
  onSortChange?: ((change: GridSortChange | null) => any) | undefined;
47
+ onFilterChange?: ((model: FilterModel, event: FilterChangedEvent<T, any>) => any) | undefined;
40
48
  } & Partial<import("vue").HTMLAttributes & import("vue").ReservedProps>> & (typeof globalThis extends {
41
49
  __VLS_PROPS_FALLBACK: infer P;
42
50
  } ? P : {});
@@ -52,7 +60,7 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
52
60
  api: GridApi<T> | null;
53
61
  }) => any;
54
62
  };
55
- emit: (((evt: "copy", text: string) => void) & ((evt: "rowClick", event: RowClickedEvent<T, any>) => void) & ((evt: "selectionChange", rows: T[]) => void) & ((evt: "sortChange", change: GridSortChange | null) => void)) & (((event: "update:page", value: number) => void) & ((event: "update:pageSize", value: number) => void) & ((event: "update:query", value: string) => void));
63
+ emit: (((evt: "copy", text: string) => void) & ((evt: "rowClick", event: RowClickedEvent<T, any>) => void) & ((evt: "selectionChange", rows: T[]) => void) & ((evt: "sortChange", change: GridSortChange | null) => void) & ((evt: "filterChange", model: FilterModel, event: FilterChangedEvent<T, any>) => void)) & (((event: "update:page", value: number) => void) & ((event: "update:pageSize", value: number) => void) & ((event: "update:sort", value: GridSortChange | null | undefined) => void) & ((event: "update:query", value: string) => void));
56
64
  }>) => import("vue").VNode & {
57
65
  __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
58
66
  };
@@ -1,12 +1,18 @@
1
1
  <template>
2
- <time v-if="formatted" class="k-data-grid-date k-tabular" :datetime="iso">{{ formatted }}</time>
2
+ <time
3
+ v-if="formatted"
4
+ class="k-data-grid-date k-tabular"
5
+ :datetime="iso"
6
+ :title="params.relative ? absolute : void 0"
7
+ >{{ formatted }}</time
8
+ >
3
9
  <EmptyCell v-else :context="cellContext" />
4
10
  </template>
5
11
 
6
12
  <script setup>
7
13
  import { computed } from "vue";
8
14
  import EmptyCell from "./EmptyCell.vue";
9
- import { dateTimeFormat } from "../../internal/core/intl";
15
+ import { dateTimeFormat, formatRelativeTime } from "../../internal/core/intl";
10
16
  const props = defineProps({
11
17
  params: { type: Object, required: true }
12
18
  });
@@ -19,11 +25,20 @@ const date = computed(() => {
19
25
  const locale = computed(
20
26
  () => props.params.locale ?? props.params.context?.locale
21
27
  );
22
- const formatted = computed(
28
+ const absolute = computed(
23
29
  () => date.value ? dateTimeFormat(locale.value, props.params.options ?? { dateStyle: "medium" }).format(
24
30
  date.value
25
31
  ) : ""
26
32
  );
33
+ const formatted = computed(() => {
34
+ const relative = props.params.relative;
35
+ if (!date.value || !relative) return absolute.value;
36
+ return formatRelativeTime(
37
+ date.value,
38
+ locale.value,
39
+ relative === true ? { numeric: "auto" } : relative
40
+ );
41
+ });
27
42
  const iso = computed(() => date.value?.toISOString());
28
43
  const cellContext = computed(() => props.params.context);
29
44
  </script>
@@ -144,7 +144,7 @@
144
144
  align-items: center;
145
145
  padding: 0.125rem 0.5rem;
146
146
  font-size: 0.75rem;
147
- font-weight: 500;
147
+ font-weight: var(--k-font-weight-medium, 500);
148
148
  line-height: 1.2;
149
149
  color: var(--k-badge-tone);
150
150
  background: color-mix(in oklab, var(--k-badge-tone) 12%, transparent);
@@ -5,6 +5,6 @@ export { default as DateCell } from './cells/DateCell.vue';
5
5
  export { default as BadgeCell } from './cells/BadgeCell.vue';
6
6
  export { default as ImageCell } from './cells/ImageCell.vue';
7
7
  export { default as LinkCell } from './cells/LinkCell.vue';
8
- export { registerGridModules } from './modules';
8
+ export { registerGridFilterModules, registerGridModules } from './modules';
9
9
  export { createGridTheme } from './theme';
10
10
  export type * from './types';
@@ -5,5 +5,5 @@ export { default as DateCell } from "./cells/DateCell.vue";
5
5
  export { default as BadgeCell } from "./cells/BadgeCell.vue";
6
6
  export { default as ImageCell } from "./cells/ImageCell.vue";
7
7
  export { default as LinkCell } from "./cells/LinkCell.vue";
8
- export { registerGridModules } from "./modules.mjs";
8
+ export { registerGridFilterModules, registerGridModules } from "./modules.mjs";
9
9
  export { createGridTheme } from "./theme.mjs";
@@ -1 +1,2 @@
1
1
  export declare function registerGridModules(): void;
2
+ export declare function registerGridFilterModules(): void;
@@ -6,16 +6,19 @@ import {
6
6
  ColumnApiModule,
7
7
  ColumnAutoSizeModule,
8
8
  CsvExportModule,
9
+ DateFilterModule,
9
10
  DragAndDropModule,
10
11
  EventApiModule,
11
12
  LocaleModule,
12
13
  ModuleRegistry,
14
+ NumberFilterModule,
13
15
  PaginationModule,
14
16
  QuickFilterModule,
15
17
  RenderApiModule,
16
18
  RowApiModule,
17
19
  RowAutoHeightModule,
18
20
  RowSelectionModule,
21
+ TextFilterModule,
19
22
  TooltipModule
20
23
  } from "ag-grid-community";
21
24
  let registered = false;
@@ -42,3 +45,9 @@ export function registerGridModules() {
42
45
  TooltipModule
43
46
  ]);
44
47
  }
48
+ let filtersRegistered = false;
49
+ export function registerGridFilterModules() {
50
+ if (filtersRegistered) return;
51
+ filtersRegistered = true;
52
+ ModuleRegistry.registerModules([TextFilterModule, NumberFilterModule, DateFilterModule]);
53
+ }