@xleddyl/443-components-vue 0.8.4 → 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,21 @@ 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-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) |
123
- | Calendar | `--k-calendar-day-radius`, `--k-calendar-unavailable-color`, `--k-calendar-unavailable-decoration` (line-through), `--k-calendar-unavailable-opacity` (0.6) |
124
- | Badge | `--k-badge-radius`, `--k-badge-font`, `--k-badge-font-size`, `--k-badge-font-weight`, `--k-badge-text-transform`, `--k-badge-letter-spacing` |
125
- | 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` |
126
- | Charts | `--k-chart-1` to `--k-chart-8` (series palette) |
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) |
127
128
 
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`).
129
130
 
@@ -251,6 +252,8 @@ Built-in messages follow the active language. `messages` overrides them for one
251
252
 
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.
253
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
+
254
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.
255
258
 
256
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.
@@ -325,12 +328,12 @@ Composables: `useTheme`, `usePreset`, `useForm`, `useField`, `useFieldControl`,
325
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.
326
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.
327
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.
328
- - `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).
329
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.
330
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.
331
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.
332
- - `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`.
333
- - `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; `--k-separator-heading-font-size` (0.9375rem) sizes the heading.
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.
334
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).
335
338
  - `Tabs` items take `dot: true` for a small indicator without a number (`dotTone`, default `danger`; `dotLabel` is the hidden text, default "Needs attention").
336
339
  - `DropdownMenu` takes `matchTriggerWidth` (the menu is at least as wide as its trigger) and `minWidth` (a CSS length).
@@ -646,6 +649,7 @@ Accessibility related props and defaults:
646
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.
647
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.
648
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`.
649
653
  - `DataGrid` translates the AG Grid ARIA strings through the catalog (`grid.*`; your own `localeText` still wins) and announces row count changes.
650
654
 
651
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;
@@ -3,7 +3,12 @@
3
3
  class="k-separator"
4
4
  :class="[
5
5
  `k-separator-${orientation}`,
6
- { 'k-separator-heading': isHeading, 'has-label': hasContent, 'no-lines': !lines }
6
+ {
7
+ 'k-separator-heading': isHeading,
8
+ 'k-separator-center': isHeading && align === 'center',
9
+ 'has-label': hasContent,
10
+ 'no-lines': !lines
11
+ }
7
12
  ]"
8
13
  :role="plain ? 'none' : 'separator'"
9
14
  :aria-orientation="!plain && orientation === 'vertical' ? 'vertical' : void 0"
@@ -36,6 +41,7 @@ const props = defineProps({
36
41
  orientation: { type: String, required: false, default: "horizontal" },
37
42
  variant: { type: String, required: false, default: "label" },
38
43
  lines: { type: Boolean, required: false, default: true },
44
+ align: { type: String, required: false, default: "start" },
39
45
  level: { type: Number, required: false, default: 3 },
40
46
  label: { type: String, required: false },
41
47
  description: { type: String, required: false },
@@ -1,4 +1,4 @@
1
- import type { HeadingLevel, SeparatorVariant } from './types';
1
+ import type { HeadingLevel, SeparatorAlign, SeparatorVariant } from './types';
2
2
  declare var __VLS_13: {}, __VLS_21: {}, __VLS_23: {};
3
3
  type __VLS_Slots = {} & {
4
4
  default?: (props: typeof __VLS_13) => any;
@@ -11,6 +11,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
11
11
  orientation?: "horizontal" | "vertical";
12
12
  variant?: SeparatorVariant;
13
13
  lines?: boolean;
14
+ align?: SeparatorAlign;
14
15
  level?: HeadingLevel;
15
16
  label?: string;
16
17
  description?: string;
@@ -211,6 +212,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
211
212
  orientation?: "horizontal" | "vertical";
212
213
  variant?: SeparatorVariant;
213
214
  lines?: boolean;
215
+ align?: SeparatorAlign;
214
216
  level?: HeadingLevel;
215
217
  label?: string;
216
218
  description?: string;
@@ -410,6 +412,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
410
412
  }> & Readonly<{}>, {
411
413
  orientation: "horizontal" | "vertical";
412
414
  variant: SeparatorVariant;
415
+ align: SeparatorAlign;
413
416
  level: HeadingLevel;
414
417
  lines: boolean;
415
418
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -46,6 +46,7 @@ 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
48
  export type SeparatorVariant = 'label' | 'heading';
49
+ export type SeparatorAlign = 'start' | 'center';
49
50
  export interface AppShellContext {
50
51
  sidebarId: string;
51
52
  collapsed: Readonly<{
@@ -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;
@@ -185,6 +185,10 @@ export function useForm(options) {
185
185
  async function runValidator() {
186
186
  return evaluateValidator();
187
187
  }
188
+ function isFieldRequired(name) {
189
+ const required = schema.value[name]?.required;
190
+ return typeof required === "function" ? Boolean(required(target())) : Boolean(required);
191
+ }
188
192
  function evaluateRules(name) {
189
193
  const definition = schema.value[name];
190
194
  if (!definition) return void 0;
@@ -205,7 +209,7 @@ export function useForm(options) {
205
209
  maxLength: definition.maxLength
206
210
  };
207
211
  if (definition.isEmpty ? definition.isEmpty(value) : isEmptyValue(value)) {
208
- if (definition.required) return fieldMessages.required(context);
212
+ if (isFieldRequired(name)) return fieldMessages.required(context);
209
213
  } else {
210
214
  if (typeof value === "number") {
211
215
  if (definition.min !== void 0 && value < definition.min)
@@ -436,6 +440,13 @@ export function useForm(options) {
436
440
  },
437
441
  { deep: 2 }
438
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
+ );
439
450
  watch(
440
451
  () => toValue(options.validator),
441
452
  () => {
@@ -491,7 +502,7 @@ export function useForm(options) {
491
502
  setErrors,
492
503
  clearErrors,
493
504
  touch,
494
- isRequired: (name) => Boolean(schema.value[name]?.required),
505
+ isRequired: isFieldRequired,
495
506
  reset,
496
507
  submit
497
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;
@@ -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';
@@ -41,10 +42,13 @@ export interface DateCellParams {
41
42
  relative?: boolean | Intl.RelativeTimeFormatOptions;
42
43
  relativeWithin?: number;
43
44
  }
44
- export interface BadgeCellParams {
45
+ export interface BadgeCellParams<T = unknown> {
45
46
  tones?: Record<string, Tone>;
46
47
  labels?: Record<string, string>;
47
48
  defaultTone?: Tone;
49
+ variant?: BadgeVariant;
50
+ size?: BadgeSize;
51
+ badgeClass?: string | ((value: unknown, data: T | undefined) => string | undefined);
48
52
  }
49
53
  export type ImageCellFit = 'cover' | 'contain';
50
54
  export interface ImageCellParams<T = unknown> {
@@ -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
  }
@@ -174,6 +174,19 @@
174
174
  opacity: var(--k-calendar-unavailable-opacity, 0.6);
175
175
  }
176
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));
188
+ }
189
+
177
190
  .k-calendar.is-disabled {
178
191
  opacity: 0.6;
179
192
  pointer-events: none;
@@ -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;
@@ -96,7 +96,7 @@
96
96
  font-size: var(--k-separator-heading-font-size, 0.9375rem);
97
97
  font-weight: var(--k-font-weight-strong, 600);
98
98
  line-height: 1.3;
99
- color: var(--k-text);
99
+ color: var(--k-separator-heading-color, var(--k-text));
100
100
  white-space: normal;
101
101
  }
102
102
 
@@ -105,3 +105,12 @@
105
105
  font-size: 0.8125rem;
106
106
  line-height: 1.4;
107
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xleddyl/443-components-vue",
3
- "version": "0.8.4",
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)",