@xleddyl/443-components-vue 0.8.3 → 0.8.5

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 CHANGED
@@ -110,20 +110,23 @@ Input tokens, declared only on the outermost root so nested roots inherit them:
110
110
 
111
111
  A few component tokens are unset by default and only exist to be overridden on a root (or any ancestor). Unset, every one keeps the library look. The full list with defaults is in [CONVENTIONS.md](./CONVENTIONS.md#tokens):
112
112
 
113
- | Area | Tokens |
114
- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115
- | Type | `--k-font-weight` (400), `--k-font-weight-medium` (500), `--k-font-weight-strong` (600), `--k-font-weight-display` (650) |
116
- | Buttons | `--k-btn-highlight`, `--k-btn-shadow` (`0 0 #0000` for a flat button), `--k-btn-border`, `--k-btn-padding-x`, `--k-btn-font-size`, `--k-btn-icon-size`, `--k-press-scale` (0.97) |
117
- | Fields | `--k-field-padding-x` |
118
- | Overlays | `--k-modal-radius`, `--k-modal-shadow`, `--k-drawer-radius`, `--k-drawer-shadow`, `--k-popover-radius`, `--k-popover-shadow`, `--k-toast-radius`, `--k-toast-shadow`, `--k-scrim-blur` (3px) |
119
- | Tooltip | `--k-tooltip-background`, `--k-tooltip-text`, `--k-tooltip-border`, `--k-tooltip-radius`, `--k-tooltip-shadow`, `--k-tooltip-padding` |
120
- | Shell | `--k-sidebar-width` (15rem), `--k-sidebar-rail-width`, `--k-topbar-height` (3rem), `--k-shell-inset`, `--k-shell-padding`, `--k-shell-content` |
121
- | Switch | `--k-switch-track-width`, `--k-switch-track-height`, `--k-switch-thumb-size` (md size) |
122
- | Badge | `--k-badge-radius`, `--k-badge-font`, `--k-badge-font-size`, `--k-badge-font-weight`, `--k-badge-text-transform`, `--k-badge-letter-spacing` |
123
- | DataGrid | `--k-grid-header-background`, `--k-grid-header-text`, `--k-grid-header-font`, `--k-grid-header-font-weight`, `--k-grid-header-font-size` (12px), `--k-grid-font-size` (13px), `--k-grid-radius`, `--k-grid-selected-background` |
124
- | Charts | `--k-chart-1` to `--k-chart-8` (series palette) |
125
-
126
- Some tokens are meant for one element: set `--k-btn-tone`, `--k-btn-on-tone` and `--k-btn-tone-text` on a button for a brand tone outside `Tone` (a lime fill with green text), and `--k-badge-background`, `--k-badge-color` and `--k-badge-border-color` on a badge for a custom pill color. `variant="subtle"` is a borderless tinted fill (`--k-fill` for the neutral tone).
113
+ | Area | Tokens |
114
+ | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115
+ | Type | `--k-font-weight` (400), `--k-font-weight-medium` (500), `--k-font-weight-strong` (600), `--k-font-weight-display` (650) |
116
+ | Buttons | `--k-btn-highlight`, `--k-btn-shadow` (`0 0 #0000` for a flat button), `--k-btn-border`, `--k-btn-hover-background`, `--k-btn-active-background`, `--k-btn-padding-x`, `--k-btn-font-size`, `--k-btn-icon-size`, `--k-press-scale` (0.97) |
117
+ | Fields | `--k-field-padding-x` |
118
+ | Overlays | `--k-modal-radius`, `--k-modal-shadow`, `--k-drawer-radius`, `--k-drawer-shadow`, `--k-popover-radius`, `--k-popover-shadow`, `--k-toast-radius`, `--k-toast-shadow`, `--k-scrim-blur` (3px) |
119
+ | Tooltip | `--k-tooltip-background`, `--k-tooltip-text`, `--k-tooltip-border`, `--k-tooltip-radius`, `--k-tooltip-shadow`, `--k-tooltip-padding` |
120
+ | Shell | `--k-sidebar-width` (15rem), `--k-sidebar-rail-width`, `--k-topbar-height` (3rem), `--k-shell-inset`, `--k-shell-padding`, `--k-shell-content` |
121
+ | Switch | `--k-switch-track-width`, `--k-switch-track-height`, `--k-switch-thumb-size` (md size) |
122
+ | Separator | `--k-separator-heading-font-size` (0.9375rem), `--k-separator-heading-color` (`--k-text`), `--k-separator-label-font-size` (0.75rem) |
123
+ | Calendar | `--k-calendar-day-radius`, `--k-calendar-unavailable-color`, `--k-calendar-unavailable-decoration` (line-through), `--k-calendar-unavailable-opacity` (0.6), `--k-calendar-out-of-range-color`, `--k-calendar-out-of-range-decoration`, `--k-calendar-out-of-range-opacity` (each defaults to its unavailable token) |
124
+ | Checkbox group | `--k-checkbox-group-background`, `--k-checkbox-group-padding` (0.75rem), `--k-checkbox-group-radius`, `--k-checkbox-group-border` (`variant="filled"`) |
125
+ | Badge | `--k-badge-radius`, `--k-badge-font`, `--k-badge-font-size`, `--k-badge-font-weight`, `--k-badge-text-transform`, `--k-badge-letter-spacing` |
126
+ | DataGrid | `--k-grid-header-background`, `--k-grid-header-text`, `--k-grid-header-font`, `--k-grid-header-font-weight`, `--k-grid-header-font-size` (12px), `--k-grid-font-size` (13px), `--k-grid-radius`, `--k-grid-selected-background` |
127
+ | Charts | `--k-chart-1` to `--k-chart-8` (series palette) |
128
+
129
+ Some tokens are meant for one element: set `--k-btn-tone`, `--k-btn-on-tone` and `--k-btn-tone-text` on a button for a brand tone outside `Tone` (a lime fill with green text), and `--k-badge-background`, `--k-badge-color` and `--k-badge-border-color` on a badge for a custom pill color. `variant="subtle"` is a borderless tinted fill (`--k-fill` for the neutral tone). For solid buttons without hover darkening, declare the fill tokens on the button so `var(--k-btn-tone)` resolves per tone: `.k-btn-solid { --k-btn-hover-background: var(--k-btn-tone); --k-btn-active-background: var(--k-btn-tone) }` (the neutral solid button rests on `--k-text`).
127
130
 
128
131
  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.
129
132
 
@@ -247,6 +250,10 @@ Issues are keyed by their first path segment and by their full dotted path (`blo
247
250
 
248
251
  Built-in messages follow the active language. `messages` overrides them for one form.
249
252
 
253
+ `schema` also accepts a ref or getter (`MaybeRefOrGetter<FormSchema>`), for one form component reused with different fields, labels or rules per open, mode or language: `schema: () => (mode.value === 'edit' ? editSchema : createSchema)`. Field definitions, labels, `required` and rules follow the source (after the first submit the form validates again when they change). A field that appears starts from its `initial` and is clean; a field that disappears loses its value, error and touched state. With `values` the host owns the values, so only rules and labels change. `form.schema` always returns the current definitions.
254
+
255
+ `required` is a boolean or a function of the current values (`FieldRequired`, `boolean | ((values) => boolean)`) for conditional fields: `required: (values) => values.delivery === 'ship'`. The `FormField` required marker, `aria-required` and `form.isRequired(name)` follow the current result, and after the first submit the form validates again when it changes.
256
+
250
257
  `required` treats `null`, `undefined`, blank strings, empty arrays, `NaN` and plain objects whose values are all empty (a per-language map like `{ it: '', en: '' }`) as empty. A field with another idea of empty passes `isEmpty: (value) => boolean`, which replaces the check for that field. `isEmptyValue(value)` is the default check, exported for reuse.
251
258
 
252
259
  A `validate` function returns a message, `false` (the built-in invalid message), nothing (valid), or `{ message, params }` when the message needs values: `validate: (value) => value.length > 80 ? { message: 'errors.maxLength', params: { max: 80 } } : undefined`. The params reach `translateMessage` as `context.params`; without a translator they fill the `{name}` placeholders of the message.
@@ -321,12 +328,12 @@ Composables: `useTheme`, `usePreset`, `useForm`, `useField`, `useFieldControl`,
321
328
  - `Input` and `Textarea` take `counter`: with a `maxlength` attribute they show `length / maxlength` inside the field, describe the control with "12 of 40 characters" (`form.characterCount`) and announce "Character limit reached" when it is hit.
322
329
  - `Input` takes `transform: (value: string) => string`, applied to the typed text before it reaches the model (the caret keeps its place; IME composition is transformed when it ends). `:transform="(value) => value.toUpperCase()"` enforces uppercase codes. Values set from outside are not transformed.
323
330
  - `FormField` takes `optional`, a muted localized "Optional" marker in the label row (`form.optional`, `optionalText` overrides it), the counterpart of the required asterisk. It is hidden when the field is required.
324
- - `CheckboxGroup` takes `columns` (a number): the options are laid out in a grid with that many equal columns. Unset keeps the `orientation` layout.
331
+ - `CheckboxGroup` takes `columns` (a number): the options are laid out in a grid with that many equal columns. Unset keeps the `orientation` layout. `variant="filled"` (`CheckboxGroupVariant`, `'default' | 'filled'`, default `'default'`) puts the options in a subtle filled panel, styled by `--k-checkbox-group-background` (`--k-subtle`), `--k-checkbox-group-padding` (0.75rem), `--k-checkbox-group-radius` (`--k-radius-md`) and `--k-checkbox-group-border` (none).
325
332
  - `Combobox` with `multiple` takes `hideTags`: the selected values are not rendered as tags inside the control (the host shows them elsewhere), the placeholder stays visible and Backspace no longer removes the last value. Selection is still announced through the options.
326
333
  - `Pagination` takes `showEdges` (first and last page buttons, `firstLabel`, `lastLabel`) and `showJump` (a typed page number, `jumpLabel`). Both are off by default. `page` is clamped to the page count only when `total` is known: while `total` is `0` or `loading` is set (it also sets `aria-busy`), the page is kept, so a server reload does not reset it.
327
334
  - `FilterPills` can list active filters: options with `removable: true` render as active pills with a remove button (`removeLabel`, a `'Remove {label}'` template). Clicking the pill emits `select(value)`, the button emits `remove(value)` (and drops the value from the model when it is selected); focus moves to the next pill when the removed one disappears.
328
- - `Calendar` takes `dayText: (iso) => string | undefined`, a short line under each day number that is also added to the day's accessible name (availability, prices). The `#day` slot (`{ date, number, text, selected, unavailable, inMonth }`) replaces the cell content; it is decorative, so announced text still comes from `dayText`.
329
- - `Separator` takes `description` (or `#description`) under its label, and an `#actions` slot rendered next to them (a small add or edit button).
335
+ - `Calendar` takes `dayText: (iso) => string | undefined`, a short line under each day number that is also added to the day's accessible name (availability, prices). The `#day` slot (`{ date, number, text, selected, unavailable, outOfRange, inMonth }`) replaces the cell content; it is decorative, so announced text still comes from `dayText`. Days before `min` or after `max` get the `is-out-of-range` class (and `is-unavailable`, like days rejected by `isDateDisabled`), so the `--k-calendar-out-of-range-*` tokens style them apart from disabled days.
336
+ - `Separator` takes `description` (or `#description`) under its label, and an `#actions` slot rendered next to them (a small add or edit button). `variant="heading"` (`SeparatorVariant`, `'label' | 'heading'`, default `'label'`) shows the label as a section title on its own (an `h3`, `level` changes it) with the description below and the actions at the end, under one line above instead of the small muted label between two lines. `:lines="false"` (default `true`) hides the lines of either variant. `align` (`SeparatorAlign`, `'start' | 'center'`, default `'start'`) centers the heading title and description. `--k-separator-heading-font-size` (0.9375rem) sizes the heading, `--k-separator-heading-color` (default `--k-text`) colors it, and `--k-separator-label-font-size` (0.75rem) sizes the small label of `variant="label"`, with or without lines.
330
337
  - `Modal` takes `width` (any CSS length, overrides `size`) and `minHeight` (keeps the height steady while tabs or steps change). The size widths are tokens: `--k-modal-width-sm` (26rem), `--k-modal-width-md` (32rem), `--k-modal-width-lg` (50rem), `--k-modal-width-xl` (64rem).
331
338
  - `Tabs` items take `dot: true` for a small indicator without a number (`dotTone`, default `danger`; `dotLabel` is the hidden text, default "Needs attention").
332
339
  - `DropdownMenu` takes `matchTriggerWidth` (the menu is at least as wide as its trigger) and `minWidth` (a CSS length).
@@ -635,13 +642,14 @@ Accessibility related props and defaults:
635
642
  - `DataGrid` sort is a model: `v-model:sort` (`{ column, direction } | null`) sets the sorted column from outside (server side sort, a sort restored from the URL) and follows header clicks. Leave it unset for an uncontrolled grid. `sortChange` still fires with `serverSort`.
636
643
  - `DataGrid` takes `rowHeight` and `headerHeight` (pixels) for an exact row size on top of `density`, and `headerText: (field, column) => string | undefined` to name every column that has a `field` and no `headerName` (from your i18n).
637
644
  - `DataGrid` `filterable` registers the AG Grid text, number and date filters (`registerGridFilterModules()` does it without the prop) and turns `filter` on for every column. `filterChange(model, event)` fires with `api.getFilterModel()` whenever a column filter changes, also when the filters come from `gridOptions` or your own registered modules.
638
- - `DateCell` takes `relative: true` (or `Intl.RelativeTimeFormatOptions`) in `cellRendererParams` for "3 days ago"; the absolute date stays in the `title`.
645
+ - `DateCell` takes `relative: true` (or `Intl.RelativeTimeFormatOptions`) in `cellRendererParams` for "3 days ago"; the absolute date stays in the `title`. `relativeWithin` (milliseconds, default unset: always relative) shows the absolute date instead once the value is further than that from now, in the past or the future (`relativeWithin: 7 * 86_400_000` keeps "3 days ago" and prints older dates in full).
639
646
  - `DataGrid` takes `gridOptions` for any AG Grid option it does not wrap (`rowHeight`, `onCellEditingStopped`, `onFilterChanged`, ...). A prop of `DataGrid` wins only when it is set: `getRowId`, `rowSelection` (when `selectable` is off), `autoSizeStrategy` (also `undefined` to turn it off), `tooltipShowDelay`, `overlayNoRowsTemplate` and `overlayLoadingTemplate` from `gridOptions` are used otherwise; `defaultColDef` and `localeText` are merged over the component defaults, and `context` is merged under the cell context. Handlers from both run.
640
647
  - `DataGrid` row ids: `getRowId: (params) => string` (wins), `rowIdKey` (a field of the row), or `gridOptions.getRowId`.
641
648
  - `DataGrid` `fill` makes the grid, with its toolbar and footer, fill its parent (a flex or grid item with `flex: 1; min-height: 0`, or `height: 100%` in a block with a height) instead of the fixed `height`. Ignored with `autoHeight`.
642
649
  - `DataGrid` `showEdges` and `showJump` reach the footer pager (first and last page buttons, page number input). `loading` also keeps the pager from resetting the page while a server total is unknown.
643
650
  - `DataGrid` registers the AG Grid cell editors (text, large text, number, date, checkbox, select, custom and undo/redo) when `editable` is set or when a column or `gridOptions.defaultColDef` has `editable` at mount. `registerGridEditorModules()` from `/grid` does it by hand, before the first grid mounts, for columns that become editable later.
644
651
  - `ImageCell` takes `fit` (`'cover'` default, or `'contain'` for logos) and `size` (any CSS length, default `1.75rem`) in `cellRendererParams`. `EmptyCell` (the hidden "Empty" dash) is exported from `/grid` for custom renderers.
652
+ - `BadgeCell` takes `variant` (`BadgeVariant`, `'soft' | 'solid' | 'outline'`) in `cellRendererParams`: set, the cell renders a `KBadge` with that variant and the resolved tone (`size`, `BadgeSize`, default `'sm'`); unset keeps the compact grid pill. `badgeClass` (`string | ((value, data) => string | undefined)`) adds host classes to the badge, to set the per instance badge tokens (`--k-badge-background`, `--k-badge-color`, `--k-badge-border-color`, which the grid pill also reads) for values outside `Tone`. `BadgeCellParams<T>` types the row of `data`.
645
653
  - `DataGrid` translates the AG Grid ARIA strings through the catalog (`grid.*`; your own `localeText` still wins) and announces row count changes.
646
654
 
647
655
  ## Browser support
@@ -66,6 +66,7 @@
66
66
  'is-today': day.iso === today,
67
67
  'is-selected': day.selected,
68
68
  'is-unavailable': day.unavailable,
69
+ 'is-out-of-range': day.outOfRange,
69
70
  'is-range-start': day.rangeStart,
70
71
  'is-range-end': day.rangeEnd,
71
72
  'is-in-range': day.inRange,
@@ -90,6 +91,7 @@
90
91
  :text="day.text"
91
92
  :selected="day.selected"
92
93
  :unavailable="day.unavailable"
94
+ :out-of-range="day.outOfRange"
93
95
  :in-month="day.inMonth"
94
96
  >
95
97
  {{ day.number }}
@@ -185,10 +187,11 @@ const previewEnd = computed(() => {
185
187
  if (!props.range || !start || end) return null;
186
188
  return hoverDate.value ?? null;
187
189
  });
190
+ function isOutOfRange(iso) {
191
+ return Boolean(props.min && iso < props.min || props.max && iso > props.max);
192
+ }
188
193
  function isUnavailable(iso) {
189
- if (props.min && iso < props.min) return true;
190
- if (props.max && iso > props.max) return true;
191
- return Boolean(props.isDateDisabled?.(iso));
194
+ return isOutOfRange(iso) || Boolean(props.isDateDisabled?.(iso));
192
195
  }
193
196
  function dayLabel(iso, start, end) {
194
197
  const label = formatIso(iso, resolvedLocale.value, {
@@ -211,6 +214,7 @@ const weeks = computed(() => {
211
214
  const [previewFrom, previewTo] = start && preview ? preview < start ? [preview, start] : [start, preview] : [null, null];
212
215
  const days = monthGrid(firstOfMonth(focusedDate.value), weekStart.value).map((iso) => {
213
216
  const inMonth = monthKey(iso) === currentMonth;
217
+ const outOfRange = isOutOfRange(iso);
214
218
  const selected = Boolean(
215
219
  start && (props.range ? iso === start || iso === end : iso === start)
216
220
  );
@@ -220,7 +224,8 @@ const weeks = computed(() => {
220
224
  number: Number(iso.slice(8)),
221
225
  text: props.dayText?.(iso),
222
226
  label: dayLabel(iso, start, end),
223
- unavailable: isUnavailable(iso),
227
+ outOfRange,
228
+ unavailable: outOfRange || Boolean(props.isDateDisabled?.(iso)),
224
229
  selected: selected || Boolean(props.range && start && end && iso > start && iso < end),
225
230
  rangeStart: Boolean(props.range && start && end && iso === start && start !== end),
226
231
  rangeEnd: Boolean(props.range && start && end && iso === end && start !== end),
@@ -5,6 +5,7 @@ declare var __VLS_25: {
5
5
  text: string | undefined;
6
6
  selected: boolean;
7
7
  unavailable: boolean;
8
+ outOfRange: boolean;
8
9
  inMonth: boolean;
9
10
  }, __VLS_27: {};
10
11
  type __VLS_Slots = {} & {
@@ -9,6 +9,7 @@
9
9
  class="k-choice-group k-checkbox-group"
10
10
  :class="[
11
11
  `k-choice-group-${orientation}`,
12
+ `k-checkbox-group-${variant}`,
12
13
  {
13
14
  'is-invalid': control.invalid.value,
14
15
  'is-disabled': control.disabled.value,
@@ -48,6 +49,7 @@ const props = defineProps({
48
49
  label: { type: String, required: false },
49
50
  legend: { type: String, required: false },
50
51
  orientation: { type: String, required: false, default: "vertical" },
52
+ variant: { type: String, required: false, default: "default" },
51
53
  columns: { type: Number, required: false },
52
54
  size: { type: String, required: false, default: "md" },
53
55
  name: { type: String, required: false },
@@ -1,11 +1,12 @@
1
1
  import type { FieldSize } from '../core/types';
2
- import type { ChoiceOption, ChoiceOrientation, ChoiceValue } from './types';
2
+ import type { CheckboxGroupVariant, ChoiceOption, ChoiceOrientation, ChoiceValue } from './types';
3
3
  declare const __VLS_export: <T extends ChoiceValue>(__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<({
5
5
  options?: ChoiceOption<T>[];
6
6
  label?: string;
7
7
  legend?: string;
8
8
  orientation?: ChoiceOrientation;
9
+ variant?: CheckboxGroupVariant;
9
10
  columns?: number;
10
11
  size?: FieldSize;
11
12
  name?: string;
@@ -58,6 +58,7 @@ export type FileInputDirectory = boolean | 'drop';
58
58
  export type FileInputAcceptMode = 'filter' | 'hint';
59
59
  export type PinInputMode = 'numeric' | 'alphanumeric' | 'alphabetic';
60
60
  export type RadioGroupVariant = 'default' | 'card';
61
+ export type CheckboxGroupVariant = 'default' | 'filled';
61
62
  export type SliderBubble = boolean | 'always';
62
63
  export type ColorSwatch = string | {
63
64
  value: string;
@@ -1,18 +1,34 @@
1
1
  <template>
2
2
  <div
3
3
  class="k-separator"
4
- :class="[`k-separator-${orientation}`, { 'has-label': hasContent }]"
4
+ :class="[
5
+ `k-separator-${orientation}`,
6
+ {
7
+ 'k-separator-heading': isHeading,
8
+ 'k-separator-center': isHeading && align === 'center',
9
+ 'has-label': hasContent,
10
+ 'no-lines': !lines
11
+ }
12
+ ]"
5
13
  :role="plain ? 'none' : 'separator'"
6
14
  :aria-orientation="!plain && orientation === 'vertical' ? 'vertical' : void 0"
7
15
  >
8
- <span v-if="hasText" class="k-separator-text">
9
- <span v-if="label || $slots.default" class="k-separator-label">
16
+ <component :is="isHeading ? 'div' : 'span'" v-if="hasText" class="k-separator-text">
17
+ <component
18
+ :is="isHeading ? `h${level}` : 'span'"
19
+ v-if="label || $slots.default"
20
+ class="k-separator-label"
21
+ >
10
22
  <slot>{{ label }}</slot>
11
- </span>
12
- <span v-if="description || $slots.description" class="k-separator-description">
23
+ </component>
24
+ <component
25
+ :is="isHeading ? 'p' : 'span'"
26
+ v-if="description || $slots.description"
27
+ class="k-separator-description"
28
+ >
13
29
  <slot name="description">{{ description }}</slot>
14
- </span>
15
- </span>
30
+ </component>
31
+ </component>
16
32
  <span v-if="$slots.actions" class="k-separator-actions">
17
33
  <slot name="actions" />
18
34
  </span>
@@ -23,6 +39,10 @@
23
39
  import { computed, useSlots } from "vue";
24
40
  const props = defineProps({
25
41
  orientation: { type: String, required: false, default: "horizontal" },
42
+ variant: { type: String, required: false, default: "label" },
43
+ lines: { type: Boolean, required: false, default: true },
44
+ align: { type: String, required: false, default: "start" },
45
+ level: { type: Number, required: false, default: 3 },
26
46
  label: { type: String, required: false },
27
47
  description: { type: String, required: false },
28
48
  decorative: { type: Boolean, required: false }
@@ -32,5 +52,6 @@ const hasText = computed(
32
52
  () => Boolean(props.label || slots.default || props.description || slots.description)
33
53
  );
34
54
  const hasContent = computed(() => Boolean(hasText.value || slots.actions));
55
+ const isHeading = computed(() => props.variant === "heading" && props.orientation === "horizontal");
35
56
  const plain = computed(() => props.decorative || hasContent.value);
36
57
  </script>
@@ -1,13 +1,18 @@
1
- declare var __VLS_1: {}, __VLS_3: {}, __VLS_5: {};
1
+ import type { HeadingLevel, SeparatorAlign, SeparatorVariant } from './types';
2
+ declare var __VLS_13: {}, __VLS_21: {}, __VLS_23: {};
2
3
  type __VLS_Slots = {} & {
3
- default?: (props: typeof __VLS_1) => any;
4
+ default?: (props: typeof __VLS_13) => any;
4
5
  } & {
5
- description?: (props: typeof __VLS_3) => any;
6
+ description?: (props: typeof __VLS_21) => any;
6
7
  } & {
7
- actions?: (props: typeof __VLS_5) => any;
8
+ actions?: (props: typeof __VLS_23) => any;
8
9
  };
9
10
  declare const __VLS_base: import("vue").DefineComponent<{
10
11
  orientation?: "horizontal" | "vertical";
12
+ variant?: SeparatorVariant;
13
+ lines?: boolean;
14
+ align?: SeparatorAlign;
15
+ level?: HeadingLevel;
11
16
  label?: string;
12
17
  description?: string;
13
18
  decorative?: boolean;
@@ -205,6 +210,10 @@ declare const __VLS_base: import("vue").DefineComponent<{
205
210
  ref_key?: string | undefined | undefined;
206
211
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
207
212
  orientation?: "horizontal" | "vertical";
213
+ variant?: SeparatorVariant;
214
+ lines?: boolean;
215
+ align?: SeparatorAlign;
216
+ level?: HeadingLevel;
208
217
  label?: string;
209
218
  description?: string;
210
219
  decorative?: boolean;
@@ -402,6 +411,10 @@ declare const __VLS_base: import("vue").DefineComponent<{
402
411
  ref_key?: string | undefined | undefined;
403
412
  }> & Readonly<{}>, {
404
413
  orientation: "horizontal" | "vertical";
414
+ variant: SeparatorVariant;
415
+ align: SeparatorAlign;
416
+ level: HeadingLevel;
417
+ lines: boolean;
405
418
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
406
419
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
407
420
  declare const _default: typeof __VLS_export;
@@ -45,6 +45,8 @@ export interface AccordionItem {
45
45
  export type AccordionVariant = 'separated' | 'plain' | 'card' | 'outline';
46
46
  export type AccordionContentVariant = 'text' | 'neutral';
47
47
  export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
48
+ export type SeparatorVariant = 'label' | 'heading';
49
+ export type SeparatorAlign = 'start' | 'center';
48
50
  export interface AppShellContext {
49
51
  sidebarId: string;
50
52
  collapsed: Readonly<{
@@ -26,6 +26,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
26
26
  style?: import("vue").StyleValue;
27
27
  results?: (string | number) | undefined;
28
28
  placeholder?: string | undefined;
29
+ flush?: boolean;
29
30
  dir?: string | undefined;
30
31
  class?: import("vue").ClassValue;
31
32
  role?: string | undefined;
@@ -220,7 +221,6 @@ declare const __VLS_base: import("vue").DefineComponent<{
220
221
  onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
221
222
  onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
222
223
  onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
223
- flush?: boolean;
224
224
  sheet?: boolean;
225
225
  onClose?: (() => any) | undefined;
226
226
  onOpen?: (() => any) | undefined;
@@ -256,6 +256,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
256
256
  style?: import("vue").StyleValue;
257
257
  results?: (string | number) | undefined;
258
258
  placeholder?: string | undefined;
259
+ flush?: boolean;
259
260
  dir?: string | undefined;
260
261
  class?: import("vue").ClassValue;
261
262
  role?: string | undefined;
@@ -450,7 +451,6 @@ declare const __VLS_base: import("vue").DefineComponent<{
450
451
  onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
451
452
  onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
452
453
  onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
453
- flush?: boolean;
454
454
  sheet?: boolean;
455
455
  onClose?: (() => any) | undefined;
456
456
  onOpen?: (() => any) | undefined;
@@ -16,6 +16,7 @@ declare const __VLS_export: import("vue").DefineComponent<Partial<NonNullable<{
16
16
  readonly style?: import("vue").StyleValue;
17
17
  readonly results?: (string | number) | undefined;
18
18
  readonly placeholder?: string | undefined | undefined;
19
+ readonly flush?: boolean | undefined;
19
20
  readonly dir?: string | undefined | undefined;
20
21
  readonly class?: import("vue").ClassValue;
21
22
  readonly role?: string | undefined | undefined;
@@ -210,7 +211,6 @@ declare const __VLS_export: import("vue").DefineComponent<Partial<NonNullable<{
210
211
  readonly onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
211
212
  readonly onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
212
213
  readonly onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
213
- readonly flush?: boolean | undefined;
214
214
  readonly sheet?: boolean | undefined;
215
215
  readonly onClose?: (() => any) | undefined;
216
216
  readonly onOpen?: (() => any) | undefined;
@@ -242,6 +242,7 @@ declare const __VLS_export: import("vue").DefineComponent<Partial<NonNullable<{
242
242
  readonly style?: import("vue").StyleValue;
243
243
  readonly results?: (string | number) | undefined;
244
244
  readonly placeholder?: string | undefined | undefined;
245
+ readonly flush?: boolean | undefined;
245
246
  readonly dir?: string | undefined | undefined;
246
247
  readonly class?: import("vue").ClassValue;
247
248
  readonly role?: string | undefined | undefined;
@@ -436,7 +437,6 @@ declare const __VLS_export: import("vue").DefineComponent<Partial<NonNullable<{
436
437
  readonly onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
437
438
  readonly onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
438
439
  readonly onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
439
- readonly flush?: boolean | undefined;
440
440
  readonly sheet?: boolean | undefined;
441
441
  readonly onClose?: (() => any) | undefined;
442
442
  readonly onOpen?: (() => any) | undefined;
@@ -42,6 +42,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
42
42
  results?: (string | number) | undefined;
43
43
  placeholder?: string | undefined;
44
44
  description?: string;
45
+ flush?: boolean;
45
46
  dir?: string | undefined;
46
47
  class?: import("vue").ClassValue;
47
48
  role?: string | undefined;
@@ -236,7 +237,6 @@ declare const __VLS_base: import("vue").DefineComponent<{
236
237
  onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
237
238
  onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
238
239
  onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
239
- flush?: boolean;
240
240
  sheet?: boolean;
241
241
  onCancel?: ((payload: Event) => void) | undefined;
242
242
  rootClass?: unknown;
@@ -281,6 +281,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
281
281
  results?: (string | number) | undefined;
282
282
  placeholder?: string | undefined;
283
283
  description?: string;
284
+ flush?: boolean;
284
285
  dir?: string | undefined;
285
286
  class?: import("vue").ClassValue;
286
287
  role?: string | undefined;
@@ -475,7 +476,6 @@ declare const __VLS_base: import("vue").DefineComponent<{
475
476
  onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
476
477
  onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
477
478
  onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
478
- flush?: boolean;
479
479
  sheet?: boolean;
480
480
  onCancel?: ((payload: Event) => void) | undefined;
481
481
  rootClass?: unknown;
@@ -7,10 +7,11 @@ export interface FieldValidationMessage {
7
7
  params?: MessageParams;
8
8
  }
9
9
  export type FieldValidationResult = string | FieldValidationMessage | undefined | null | boolean;
10
+ export type FieldRequired = boolean | ((values: Record<string, unknown>) => boolean);
10
11
  export interface FieldDefinition<T = unknown> {
11
12
  initial?: T | (() => T);
12
13
  label?: string;
13
- required?: boolean;
14
+ required?: FieldRequired;
14
15
  min?: number;
15
16
  max?: number;
16
17
  minLength?: number;
@@ -61,7 +62,7 @@ export type FormWarningsFunction<V> = (values: V) => FormWarningsResult | Promis
61
62
  export type FormWarnings<V> = StandardSchemaV1 | Readonly<Ref<StandardSchemaV1 | undefined>> | FormWarningsFunction<V>;
62
63
  export type FormPath<V> = (keyof V & string) | (string & {});
63
64
  export interface UseFormOptions<S extends FormSchema = FormSchema, V extends object = FormValues<S>> {
64
- schema?: S;
65
+ schema?: MaybeRefOrGetter<S>;
65
66
  values?: MaybeRefOrGetter<V>;
66
67
  validator?: MaybeRefOrGetter<StandardSchemaV1 | undefined>;
67
68
  warnings?: FormWarnings<V>;
@@ -105,8 +105,8 @@ function replaceEntries(target, next, inScope = () => true) {
105
105
  }
106
106
  }
107
107
  export function useForm(options) {
108
- const schema = options.schema ?? {};
109
- const schemaNames = Object.keys(schema);
108
+ const schema = computed(() => toValue(options.schema) ?? {});
109
+ const schemaNames = computed(() => Object.keys(schema.value));
110
110
  const external = options.values !== void 0;
111
111
  const { t, locale } = useLocale();
112
112
  const config = hasInjectionContext() && inject(FORM_CONFIG_KEY, null) || null;
@@ -123,19 +123,21 @@ export function useForm(options) {
123
123
  };
124
124
  const translateIssues = (issues, kind) => issues.map((issue) => {
125
125
  const name = issue.path.map(String).join(".") || void 0;
126
- const label = name ? schema[name]?.label : void 0;
126
+ const label = name ? schema.value[name]?.label : void 0;
127
127
  return { ...issue, message: translate(issue.message, { name, label, kind }) };
128
128
  });
129
129
  const validateOn = options.validateOn ?? "submit";
130
130
  const issueKey = options.issueKey ?? defaultIssueKey;
131
- const initialValues = () => Object.fromEntries(schemaNames.map((name) => [name, resolveInitial(schema[name])]));
131
+ const initialValues = () => Object.fromEntries(
132
+ schemaNames.value.map((name) => [name, resolveInitial(schema.value[name])])
133
+ );
132
134
  const internalValues = external ? void 0 : reactive(initialValues());
133
135
  const target = () => external ? toValue(options.values) : internalValues;
134
136
  let baseline = cloneValue(target());
135
137
  const baselineVersion = ref(0);
136
138
  const names = computed(() => {
137
- if (!external) return schemaNames;
138
- return [.../* @__PURE__ */ new Set([...schemaNames, ...Object.keys(target())])];
139
+ if (!external) return schemaNames.value;
140
+ return [.../* @__PURE__ */ new Set([...schemaNames.value, ...Object.keys(target())])];
139
141
  });
140
142
  const errors = reactive({});
141
143
  const warnings = reactive({});
@@ -183,8 +185,12 @@ export function useForm(options) {
183
185
  async function runValidator() {
184
186
  return evaluateValidator();
185
187
  }
188
+ function isFieldRequired(name) {
189
+ const required = schema.value[name]?.required;
190
+ return typeof required === "function" ? Boolean(required(target())) : Boolean(required);
191
+ }
186
192
  function evaluateRules(name) {
187
- const definition = schema[name];
193
+ const definition = schema.value[name];
188
194
  if (!definition) return void 0;
189
195
  const value = readValue(name);
190
196
  const fieldMessages = { ...messages.value, ...definition.messages };
@@ -203,7 +209,7 @@ export function useForm(options) {
203
209
  maxLength: definition.maxLength
204
210
  };
205
211
  if (definition.isEmpty ? definition.isEmpty(value) : isEmptyValue(value)) {
206
- if (definition.required) return fieldMessages.required(context);
212
+ if (isFieldRequired(name)) return fieldMessages.required(context);
207
213
  } else {
208
214
  if (typeof value === "number") {
209
215
  if (definition.min !== void 0 && value < definition.min)
@@ -394,6 +400,53 @@ export function useForm(options) {
394
400
  },
395
401
  { deep: true }
396
402
  );
403
+ function dropErrorsWithin(name) {
404
+ for (const source of [ruleErrors, manualErrors, issueErrors, touched]) {
405
+ for (const key of Object.keys(source)) {
406
+ if (isWithin(key, name)) delete source[key];
407
+ }
408
+ }
409
+ }
410
+ watch(
411
+ schemaNames,
412
+ (next, previous) => {
413
+ const added = next.filter((name) => !previous.includes(name));
414
+ const removed = previous.filter((name) => !next.includes(name));
415
+ if (!added.length && !removed.length) return;
416
+ if (internalValues) {
417
+ for (const name of removed) delete internalValues[name];
418
+ for (const name of added) internalValues[name] = resolveInitial(schema.value[name]);
419
+ }
420
+ for (const name of removed) {
421
+ if (names.value.includes(name)) continue;
422
+ if (!external) delete baseline[name];
423
+ snapshots.delete(name);
424
+ fieldRuns.delete(name);
425
+ dropErrorsWithin(name);
426
+ }
427
+ for (const name of added) {
428
+ if (!external) baseline[name] = cloneValue(readValue(name));
429
+ snapshots.set(name, cloneValue(readValue(name)));
430
+ }
431
+ baselineVersion.value++;
432
+ syncErrors();
433
+ },
434
+ { flush: "sync" }
435
+ );
436
+ watch(
437
+ schema,
438
+ () => {
439
+ if (submitCount.value > 0) void validate();
440
+ },
441
+ { deep: 2 }
442
+ );
443
+ watch(
444
+ () => names.value.map((name) => isFieldRequired(name)),
445
+ (next, previous) => {
446
+ if (submitCount.value > 0 && next.some((required, index) => required !== previous[index]))
447
+ void validate();
448
+ }
449
+ );
397
450
  watch(
398
451
  () => toValue(options.validator),
399
452
  () => {
@@ -425,7 +478,9 @@ export function useForm(options) {
425
478
  });
426
479
  }
427
480
  return {
428
- schema,
481
+ get schema() {
482
+ return schema.value;
483
+ },
429
484
  get values() {
430
485
  return target();
431
486
  },
@@ -447,7 +502,7 @@ export function useForm(options) {
447
502
  setErrors,
448
503
  clearErrors,
449
504
  touch,
450
- isRequired: (name) => Boolean(schema[name]?.required),
505
+ isRequired: isFieldRequired,
451
506
  reset,
452
507
  submit
453
508
  };
@@ -1,12 +1,18 @@
1
1
  <template>
2
- <span v-if="text" class="k-data-grid-badge" :class="`k-data-grid-badge-${tone}`">{{
3
- text
4
- }}</span>
2
+ <template v-if="text">
3
+ <Badge v-if="params.variant" :class="badgeClass" :tone :variant="params.variant" :size>{{
4
+ text
5
+ }}</Badge>
6
+ <span v-else class="k-data-grid-badge" :class="[`k-data-grid-badge-${tone}`, badgeClass]">{{
7
+ text
8
+ }}</span>
9
+ </template>
5
10
  <EmptyCell v-else :context="cellContext" />
6
11
  </template>
7
12
 
8
13
  <script setup>
9
14
  import { computed } from "vue";
15
+ import Badge from "../../components/data/Badge.vue";
10
16
  import EmptyCell from "./EmptyCell.vue";
11
17
  const props = defineProps({
12
18
  params: { type: Object, required: true }
@@ -19,5 +25,10 @@ const text = computed(() => key.value ? props.params.labels?.[key.value] ?? key.
19
25
  const tone = computed(
20
26
  () => props.params.tones?.[key.value] ?? props.params.defaultTone ?? "neutral"
21
27
  );
28
+ const size = computed(() => props.params.size ?? "sm");
29
+ const badgeClass = computed(() => {
30
+ const source = props.params.badgeClass;
31
+ return typeof source === "function" ? source(props.params.value, props.params.data) : source;
32
+ });
22
33
  const cellContext = computed(() => props.params.context);
23
34
  </script>
@@ -1,6 +1,13 @@
1
1
  import type { BadgeCellParams, GridCellContext } from '../types';
2
2
  declare const __VLS_export: import("vue").DefineComponent<{
3
- params: import("ag-grid-community").ICellRendererParams<any, any, any> & BadgeCellParams;
3
+ params: import("ag-grid-community").ICellRendererParams<any, any, any> & BadgeCellParams<unknown>;
4
+ label?: string | number;
5
+ tone?: import("../../index.ts").Tone;
6
+ variant?: import("../../index.ts").BadgeVariant;
7
+ size?: import("../../index.ts").BadgeSize;
8
+ dot?: boolean;
9
+ pulse?: boolean;
10
+ icon?: import("../../index.ts").IconName;
4
11
  innerHTML?: string | undefined | undefined;
5
12
  class?: import("vue").ClassValue;
6
13
  style?: import("vue").StyleValue;
@@ -193,15 +200,22 @@ declare const __VLS_export: import("vue").DefineComponent<{
193
200
  ref?: import("vue").VNodeRef | undefined;
194
201
  ref_for?: boolean | undefined | undefined;
195
202
  ref_key?: string | undefined | undefined;
196
- context?: GridCellContext;
197
203
  onVnodeBeforeMount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
198
204
  onVnodeMounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
199
205
  onVnodeBeforeUpdate?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
200
206
  onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
201
207
  onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
202
208
  onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
209
+ context?: GridCellContext;
203
210
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{
204
- params: import("ag-grid-community").ICellRendererParams<any, any, any> & BadgeCellParams;
211
+ params: import("ag-grid-community").ICellRendererParams<any, any, any> & BadgeCellParams<unknown>;
212
+ label?: string | number;
213
+ tone?: import("../../index.ts").Tone;
214
+ variant?: import("../../index.ts").BadgeVariant;
215
+ size?: import("../../index.ts").BadgeSize;
216
+ dot?: boolean;
217
+ pulse?: boolean;
218
+ icon?: import("../../index.ts").IconName;
205
219
  innerHTML?: string | undefined | undefined;
206
220
  class?: import("vue").ClassValue;
207
221
  style?: import("vue").StyleValue;
@@ -394,13 +408,13 @@ declare const __VLS_export: import("vue").DefineComponent<{
394
408
  ref?: import("vue").VNodeRef | undefined;
395
409
  ref_for?: boolean | undefined | undefined;
396
410
  ref_key?: string | undefined | undefined;
397
- context?: GridCellContext;
398
411
  onVnodeBeforeMount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
399
412
  onVnodeMounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
400
413
  onVnodeBeforeUpdate?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
401
414
  onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
402
415
  onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
403
416
  onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
417
+ context?: GridCellContext;
404
418
  }> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
405
419
  declare const _default: typeof __VLS_export;
406
420
  export default _default;
@@ -3,7 +3,7 @@
3
3
  v-if="formatted"
4
4
  class="k-data-grid-date k-tabular"
5
5
  :datetime="iso"
6
- :title="params.relative ? absolute : void 0"
6
+ :title="isRelative ? absolute : void 0"
7
7
  >{{ formatted }}</time
8
8
  >
9
9
  <EmptyCell v-else :context="cellContext" />
@@ -30,9 +30,14 @@ const absolute = computed(
30
30
  date.value
31
31
  ) : ""
32
32
  );
33
+ const isRelative = computed(() => {
34
+ if (!date.value || !props.params.relative) return false;
35
+ const within = props.params.relativeWithin;
36
+ return within === void 0 || Math.abs(Date.now() - date.value.getTime()) <= within;
37
+ });
33
38
  const formatted = computed(() => {
34
39
  const relative = props.params.relative;
35
- if (!date.value || !relative) return absolute.value;
40
+ if (!date.value || !relative || !isRelative.value) return absolute.value;
36
41
  return formatRelativeTime(
37
42
  date.value,
38
43
  locale.value,
@@ -156,8 +156,9 @@
156
156
  font-size: 0.75rem;
157
157
  font-weight: var(--k-font-weight-medium, 500);
158
158
  line-height: 1.2;
159
- color: var(--k-badge-tone);
160
- background: color-mix(in oklab, var(--k-badge-tone) 12%, transparent);
159
+ color: var(--k-badge-color, var(--k-badge-tone));
160
+ background: var(--k-badge-background, color-mix(in oklab, var(--k-badge-tone) 12%, transparent));
161
+ box-shadow: inset 0 0 0 1px var(--k-badge-border-color, transparent);
161
162
  border-radius: var(--k-radius-full);
162
163
  white-space: nowrap;
163
164
  }
@@ -1,5 +1,6 @@
1
1
  import type { ColDef, GridApi, ICellRendererParams } from 'ag-grid-community';
2
2
  import type { Tone } from '../components/core/types';
3
+ import type { BadgeSize, BadgeVariant } from '../components/data/types';
3
4
  import type { KMessages } from '../locale/types';
4
5
  export type GridDensity = 'compact' | 'normal' | 'comfortable';
5
6
  export type GridSelection = boolean | 'single' | 'multiple';
@@ -39,11 +40,15 @@ export interface DateCellParams {
39
40
  locale?: string;
40
41
  options?: Intl.DateTimeFormatOptions;
41
42
  relative?: boolean | Intl.RelativeTimeFormatOptions;
43
+ relativeWithin?: number;
42
44
  }
43
- export interface BadgeCellParams {
45
+ export interface BadgeCellParams<T = unknown> {
44
46
  tones?: Record<string, Tone>;
45
47
  labels?: Record<string, string>;
46
48
  defaultTone?: Tone;
49
+ variant?: BadgeVariant;
50
+ size?: BadgeSize;
51
+ badgeClass?: string | ((value: unknown, data: T | undefined) => string | undefined);
47
52
  }
48
53
  export type ImageCellFit = 'cover' | 'contain';
49
54
  export interface ImageCellParams<T = unknown> {
@@ -11,6 +11,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
11
11
  results?: (string | number) | undefined;
12
12
  placeholder?: string | undefined;
13
13
  description?: string;
14
+ flush?: boolean;
14
15
  dir?: string | undefined;
15
16
  class?: import("vue").ClassValue;
16
17
  role?: string | undefined;
@@ -207,7 +208,6 @@ declare const __VLS_export: import("vue").DefineComponent<{
207
208
  onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
208
209
  onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
209
210
  onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
210
- flush?: boolean;
211
211
  sheet?: boolean;
212
212
  onCancel?: ((payload: Event) => void) | undefined;
213
213
  side?: import("../../index.ts").DrawerSide;
@@ -234,6 +234,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
234
234
  results?: (string | number) | undefined;
235
235
  placeholder?: string | undefined;
236
236
  description?: string;
237
+ flush?: boolean;
237
238
  dir?: string | undefined;
238
239
  class?: import("vue").ClassValue;
239
240
  role?: string | undefined;
@@ -430,7 +431,6 @@ declare const __VLS_export: import("vue").DefineComponent<{
430
431
  onVnodeUpdated?: (((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void) | ((vnode: import("vue").VNode, oldVNode: import("vue").VNode) => void)[]) | undefined;
431
432
  onVnodeBeforeUnmount?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
432
433
  onVnodeUnmounted?: (((vnode: import("vue").VNode) => void) | ((vnode: import("vue").VNode) => void)[]) | undefined;
433
- flush?: boolean;
434
434
  sheet?: boolean;
435
435
  onCancel?: ((payload: Event) => void) | undefined;
436
436
  side?: import("../../index.ts").DrawerSide;
@@ -141,22 +141,22 @@
141
141
  }
142
142
 
143
143
  .k-btn-solid:hover:not(:disabled, [aria-disabled='true']) {
144
- background: color-mix(in oklab, var(--k-btn-tone) 90%, black);
144
+ background: var(--k-btn-hover-background, color-mix(in oklab, var(--k-btn-tone) 90%, black));
145
145
  box-shadow:
146
146
  inset 0 1px 0 var(--k-btn-highlight, rgb(255 255 255 / 0.22)),
147
147
  var(--k-btn-shadow, 0 2px 8px -2px color-mix(in oklab, var(--k-btn-tone) 60%, transparent));
148
148
  }
149
149
 
150
150
  .k-btn-solid:active:not(:disabled, [aria-disabled='true']) {
151
- background: color-mix(in oklab, var(--k-btn-tone) 82%, black);
151
+ background: var(--k-btn-active-background, color-mix(in oklab, var(--k-btn-tone) 82%, black));
152
152
  }
153
153
 
154
154
  .k-btn-accent.k-btn-solid:hover:not(:disabled, [aria-disabled='true']) {
155
- background: var(--k-accent-hover);
155
+ background: var(--k-btn-hover-background, var(--k-accent-hover));
156
156
  }
157
157
 
158
158
  .k-btn-accent.k-btn-solid:active:not(:disabled, [aria-disabled='true']) {
159
- background: var(--k-accent-press);
159
+ background: var(--k-btn-active-background, var(--k-accent-press));
160
160
  }
161
161
 
162
162
  .k-btn-neutral.k-btn-solid {
@@ -167,12 +167,18 @@
167
167
  }
168
168
 
169
169
  .k-btn-neutral.k-btn-solid:hover:not(:disabled, [aria-disabled='true']) {
170
- background: color-mix(in oklab, var(--k-text) 86%, var(--k-surface));
170
+ background: var(
171
+ --k-btn-hover-background,
172
+ color-mix(in oklab, var(--k-text) 86%, var(--k-surface))
173
+ );
171
174
  box-shadow: inset 0 1px 0 var(--k-btn-highlight, rgb(255 255 255 / 0.14));
172
175
  }
173
176
 
174
177
  .k-btn-neutral.k-btn-solid:active:not(:disabled, [aria-disabled='true']) {
175
- background: color-mix(in oklab, var(--k-text) 80%, var(--k-surface));
178
+ background: var(
179
+ --k-btn-active-background,
180
+ color-mix(in oklab, var(--k-text) 80%, var(--k-surface))
181
+ );
176
182
  }
177
183
 
178
184
  .k-btn-soft {
@@ -192,6 +192,10 @@
192
192
  background: none;
193
193
  }
194
194
 
195
+ .k-checkbox-group-filled > .k-choice-group-items {
196
+ border: 1px solid CanvasText;
197
+ }
198
+
195
199
  :is(.k-btn-solid, .k-btn-soft, .k-btn-subtle, .k-btn-ghost, .k-badge) {
196
200
  border: 1px solid ButtonText;
197
201
  }
@@ -61,7 +61,7 @@
61
61
  place-items: center;
62
62
  width: 100%;
63
63
  height: 100%;
64
- border-radius: var(--k-radius-md);
64
+ border-radius: var(--k-calendar-day-radius, var(--k-radius-md));
65
65
  color: var(--k-text-toned);
66
66
  font-variant-numeric: tabular-nums;
67
67
  transition:
@@ -134,14 +134,14 @@
134
134
 
135
135
  .k-calendar-day.is-in-range:first-child::before,
136
136
  .k-calendar-day.is-in-preview:first-child::before {
137
- border-top-left-radius: var(--k-radius-md);
138
- border-bottom-left-radius: var(--k-radius-md);
137
+ border-top-left-radius: var(--k-calendar-day-radius, var(--k-radius-md));
138
+ border-bottom-left-radius: var(--k-calendar-day-radius, var(--k-radius-md));
139
139
  }
140
140
 
141
141
  .k-calendar-day.is-in-range:last-child::before,
142
142
  .k-calendar-day.is-in-preview:last-child::before {
143
- border-top-right-radius: var(--k-radius-md);
144
- border-bottom-right-radius: var(--k-radius-md);
143
+ border-top-right-radius: var(--k-calendar-day-radius, var(--k-radius-md));
144
+ border-bottom-right-radius: var(--k-calendar-day-radius, var(--k-radius-md));
145
145
  }
146
146
 
147
147
  .k-calendar-day.is-selected .k-calendar-day-number,
@@ -169,9 +169,22 @@
169
169
  .k-calendar-day.is-unavailable .k-calendar-day-number,
170
170
  .k-calendar-day.is-unavailable:hover .k-calendar-day-number {
171
171
  background: transparent;
172
- color: var(--k-text-dimmed);
173
- text-decoration: line-through;
174
- opacity: 0.6;
172
+ color: var(--k-calendar-unavailable-color, var(--k-text-dimmed));
173
+ text-decoration: var(--k-calendar-unavailable-decoration, line-through);
174
+ opacity: var(--k-calendar-unavailable-opacity, 0.6);
175
+ }
176
+
177
+ .k-calendar-day.is-out-of-range .k-calendar-day-number,
178
+ .k-calendar-day.is-out-of-range:hover .k-calendar-day-number {
179
+ color: var(
180
+ --k-calendar-out-of-range-color,
181
+ var(--k-calendar-unavailable-color, var(--k-text-dimmed))
182
+ );
183
+ text-decoration: var(
184
+ --k-calendar-out-of-range-decoration,
185
+ var(--k-calendar-unavailable-decoration, line-through)
186
+ );
187
+ opacity: var(--k-calendar-out-of-range-opacity, var(--k-calendar-unavailable-opacity, 0.6));
175
188
  }
176
189
 
177
190
  .k-calendar.is-disabled {
@@ -31,6 +31,13 @@
31
31
  gap: 0.625rem 1.25rem;
32
32
  }
33
33
 
34
+ .k-checkbox-group-filled > .k-choice-group-items {
35
+ padding: var(--k-checkbox-group-padding, 0.75rem);
36
+ border: var(--k-checkbox-group-border, 0 solid transparent);
37
+ border-radius: var(--k-checkbox-group-radius, var(--k-radius-md));
38
+ background: var(--k-checkbox-group-background, var(--k-subtle));
39
+ }
40
+
34
41
  .k-radio-group-card > .k-choice-group-items {
35
42
  gap: 0.5rem;
36
43
  }
@@ -31,7 +31,7 @@
31
31
  }
32
32
 
33
33
  .k-separator-label {
34
- font-size: 0.75rem;
34
+ font-size: var(--k-separator-label-font-size, 0.75rem);
35
35
  font-weight: var(--k-font-weight-medium, 500);
36
36
  color: var(--k-text-muted);
37
37
  white-space: nowrap;
@@ -56,3 +56,61 @@
56
56
  font-size: 0.75rem;
57
57
  color: var(--k-text-muted);
58
58
  }
59
+
60
+ .k-separator.no-lines {
61
+ background: none;
62
+ }
63
+
64
+ .k-separator.has-label.no-lines {
65
+ justify-content: center;
66
+ }
67
+
68
+ .k-separator.has-label.no-lines::before,
69
+ .k-separator.has-label.no-lines::after,
70
+ .k-separator-heading.has-label::before,
71
+ .k-separator-heading.has-label::after {
72
+ display: none;
73
+ }
74
+
75
+ .k-separator-heading.has-label {
76
+ justify-content: flex-start;
77
+ padding-top: 0.75rem;
78
+ border-top: 1px solid var(--k-line);
79
+ }
80
+
81
+ .k-separator-heading.has-label.no-lines {
82
+ padding-top: 0;
83
+ border-top: 0;
84
+ }
85
+
86
+ .k-separator-heading .k-separator-text {
87
+ display: flex;
88
+ flex: 1;
89
+ align-items: flex-start;
90
+ gap: 0.25rem;
91
+ text-align: start;
92
+ }
93
+
94
+ .k-separator-heading .k-separator-label {
95
+ margin: 0;
96
+ font-size: var(--k-separator-heading-font-size, 0.9375rem);
97
+ font-weight: var(--k-font-weight-strong, 600);
98
+ line-height: 1.3;
99
+ color: var(--k-separator-heading-color, var(--k-text));
100
+ white-space: normal;
101
+ }
102
+
103
+ .k-separator-heading .k-separator-description {
104
+ margin: 0;
105
+ font-size: 0.8125rem;
106
+ line-height: 1.4;
107
+ }
108
+
109
+ .k-separator-heading.k-separator-center.has-label {
110
+ justify-content: center;
111
+ }
112
+
113
+ .k-separator-heading.k-separator-center .k-separator-text {
114
+ align-items: center;
115
+ text-align: center;
116
+ }
@@ -126,7 +126,8 @@
126
126
  .k-error-code,
127
127
  .k-error-title,
128
128
  .k-stat-value,
129
- .k-settings-modal-title
129
+ .k-settings-modal-title,
130
+ .k-separator-heading .k-separator-label
130
131
  ) {
131
132
  font-family: var(--k-font-display, var(--k-font-sans));
132
133
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xleddyl/443-components-vue",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "Compact, scoped dashboard components for Vue and Nuxt",
5
5
  "license": "MIT",
6
6
  "author": "Edoardo Alberti (https://github.com/xleddyl)",