nuxt-ui-tools 1.20.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "configKey": "nuxtUiTools",
6
6
  "docs": "https://ui.nuxt.com/docs/getting-started/installation/nuxt",
7
7
  "name": "nuxt-ui-tools",
8
- "version": "1.20.0",
8
+ "version": "1.21.0",
9
9
  "builder": {
10
10
  "@nuxt/module-builder": "1.0.3",
11
11
  "unbuild": "unknown"
@@ -23,6 +23,37 @@ const { runtime } = page.root;
23
23
  const pageUi = computed(() => formUi.ui.value.page?.ui);
24
24
  const titleId = useId();
25
25
  const dirty = computed(() => page.dirtyCheck.value && props.section.dirty);
26
+ const status = computed(() => {
27
+ if (!page.statusVisible.value) {
28
+ return void 0;
29
+ }
30
+ if (props.section.status === "optional") {
31
+ return { color: "neutral", icon: void 0, label: t("form.page.status.optional") };
32
+ }
33
+ if (props.section.status === "complete") {
34
+ return {
35
+ color: "success",
36
+ icon: "i-lucide-check",
37
+ label: t("form.page.status.complete")
38
+ };
39
+ }
40
+ if (props.section.status === "invalid") {
41
+ return {
42
+ color: "error",
43
+ icon: "i-lucide-circle-alert",
44
+ label: t("form.page.status.invalid")
45
+ };
46
+ }
47
+ const { missing, required } = props.section;
48
+ return {
49
+ color: "neutral",
50
+ icon: void 0,
51
+ label: t("form.page.progress", { filled: required - missing, required })
52
+ };
53
+ });
54
+ const spanClass = computed(
55
+ () => page.spanned.value ? "col-span-12 @3xl/form-sections:col-span-(--nut-form-page-section-span)" : ""
56
+ );
26
57
  const layout = computed(
27
58
  () => resolveFormLayoutConfig(runtime.currentLayout.value, props.entry.section.layout)
28
59
  );
@@ -47,18 +78,22 @@ onBeforeUnmount(() => unregister?.());
47
78
  :data-state="section.status"
48
79
  :data-dirty="dirty || void 0"
49
80
  :style="{
50
- scrollMarginTop: `calc(${page.stickyOffset.value}px + var(--nut-form-page-gap, 24px))`
81
+ scrollMarginTop: `calc(${page.stickyOffset.value}px + var(--nut-form-page-gap, 24px))`,
82
+ '--nut-form-page-section-span': page.spanned.value ? String(section.span) : void 0
51
83
  }"
52
84
  :class="
53
85
  mergeFormUiClass(
54
- `flex min-w-0 flex-col ${page.surfaceClasses.value.section}`,
86
+ `flex min-w-0 flex-col ${spanClass} ${page.surfaceClasses.value.section}`,
55
87
  pageUi?.section
56
88
  )
57
89
  "
58
90
  >
59
91
  <header
60
92
  :class="
61
- mergeFormUiClass('flex flex-wrap items-center gap-x-3 gap-y-1', pageUi?.sectionHeader)
93
+ mergeFormUiClass(
94
+ `flex flex-wrap items-center gap-x-3 gap-y-1 ${page.surfaceClasses.value.sectionHeader}`,
95
+ pageUi?.sectionHeader
96
+ )
62
97
  "
63
98
  >
64
99
  <span
@@ -99,7 +134,7 @@ onBeforeUnmount(() => unregister?.());
99
134
  {{ section.description }}
100
135
  </p>
101
136
  <UBadge
102
- v-if="section.status === 'optional'"
137
+ v-if="section.status === 'optional' && !status"
103
138
  color="neutral"
104
139
  variant="soft"
105
140
  :label="t('form.page.status.optional')"
@@ -107,9 +142,24 @@ onBeforeUnmount(() => unregister?.());
107
142
  data-form-page-optional
108
143
  />
109
144
  <div
110
- v-if="page.dirtyCheck.value || $slots.actions"
145
+ v-if="status || page.dirtyCheck.value || $slots.actions"
111
146
  :class="mergeFormUiClass('ms-auto -my-1.5 flex items-center gap-2', pageUi?.sectionActions)"
112
147
  >
148
+ <UBadge
149
+ v-if="status"
150
+ :color="status.color"
151
+ variant="soft"
152
+ :icon="status.icon"
153
+ :label="status.label"
154
+ :class="
155
+ mergeFormUiClass(
156
+ section.status === 'optional' ? pageUi?.sectionOptional : void 0,
157
+ pageUi?.sectionStatus
158
+ )
159
+ "
160
+ :data-form-page-status="section.status"
161
+ :data-form-page-optional="section.status === 'optional' ? '' : void 0"
162
+ />
113
163
  <slot name="actions" :section />
114
164
  <UButton
115
165
  v-if="page.dirtyCheck.value"
@@ -125,7 +175,12 @@ onBeforeUnmount(() => unregister?.());
125
175
  />
126
176
  </div>
127
177
  </header>
128
- <div :class="mergeFormUiClass('min-w-0', pageUi?.sectionBody)" :style="grid.style.value">
178
+ <div
179
+ :class="
180
+ mergeFormUiClass(`min-w-0 ${page.surfaceClasses.value.sectionBody}`, pageUi?.sectionBody)
181
+ "
182
+ :style="grid.style.value"
183
+ >
129
184
  <FormFieldRenderer
130
185
  v-for="field in entry.section.fields"
131
186
  :key="field.key"
@@ -1,9 +1,10 @@
1
1
  import type { FormPageSectionState } from '../../types/index.js';
2
2
  /**
3
3
  * Sections of a form page, one per visible section, each with its title, description, fields, and,
4
- * with `controls.dirtyCheck`, a mark and a reset button while it is modified. They are cards, or
5
- * plain blocks with the `page.surface` UI option. Skeletons stand in while the schema context
6
- * loads.
4
+ * with `controls.dirtyCheck`, a mark and a reset button while it is modified. They are cards,
5
+ * panels, or plain blocks with the `page.surface` UI option. Once a section sets a `span`, they lay
6
+ * out in a twelve-column grid, which is also the container their spans query. Skeletons stand in
7
+ * while the schema context loads.
7
8
  */
8
9
  type __VLS_Slots = {
9
10
  /** Extra buttons in a section header, before its reset button. */
@@ -14,20 +14,22 @@ const formUi = useFormUi();
14
14
  const { t } = useUiToolsLocale();
15
15
  const pageUi = computed(() => formUi.ui.value.page?.ui);
16
16
  const { contextError, contextLoading, contextPending, refreshContext } = page.root;
17
+ const flow = computed(
18
+ () => page.spanned.value ? "@container/form-sections grid grid-cols-12 items-stretch" : "flex flex-col"
19
+ );
20
+ const fullRow = computed(() => page.spanned.value ? "col-span-12" : "");
17
21
  </script>
18
22
 
19
23
  <template>
20
24
  <div
21
25
  :class="
22
- mergeFormUiClass(
23
- `flex min-w-0 flex-col ${page.surfaceClasses.value.sections}`,
24
- pageUi?.sections
25
- )
26
+ mergeFormUiClass(`${flow} min-w-0 ${page.surfaceClasses.value.sections}`, pageUi?.sections)
26
27
  "
27
28
  data-form-page-sections
28
29
  >
29
30
  <UAlert
30
31
  v-if="contextError"
32
+ :class="fullRow"
31
33
  color="error"
32
34
  variant="soft"
33
35
  icon="i-lucide-circle-alert"
@@ -53,7 +55,7 @@ const { contextError, contextLoading, contextPending, refreshContext } = page.ro
53
55
  :key="section.key"
54
56
  :class="
55
57
  mergeFormUiClass(
56
- `grid gap-4 ${page.surfaceClasses.value.sectionSkeleton}`,
58
+ `grid gap-4 ${fullRow} ${page.surfaceClasses.value.sectionSkeleton}`,
57
59
  pageUi?.sectionSkeleton
58
60
  )
59
61
  "
@@ -1,9 +1,10 @@
1
1
  import type { FormPageSectionState } from '../../types/index.js';
2
2
  /**
3
3
  * Sections of a form page, one per visible section, each with its title, description, fields, and,
4
- * with `controls.dirtyCheck`, a mark and a reset button while it is modified. They are cards, or
5
- * plain blocks with the `page.surface` UI option. Skeletons stand in while the schema context
6
- * loads.
4
+ * with `controls.dirtyCheck`, a mark and a reset button while it is modified. They are cards,
5
+ * panels, or plain blocks with the `page.surface` UI option. Once a section sets a `span`, they lay
6
+ * out in a twelve-column grid, which is also the container their spans query. Skeletons stand in
7
+ * while the schema context loads.
7
8
  */
8
9
  type __VLS_Slots = {
9
10
  /** Extra buttons in a section header, before its reset button. */
@@ -43,6 +43,8 @@ export declare function useFormPage(params: {
43
43
  };
44
44
  scrollTo: (key: string, options?: import("../types/index.js").FormPageScrollOptions) => boolean;
45
45
  sections: import("vue").ComputedRef<readonly FormPageSectionState[]>;
46
+ spanned: import("vue").ComputedRef<boolean>;
47
+ statusVisible: import("vue").ComputedRef<boolean>;
46
48
  stickyOffset: import("vue").Ref<number, number>;
47
49
  surface: import("vue").ComputedRef<import("../types/index.js").FormPageSurface>;
48
50
  surfaceClasses: import("vue").ComputedRef<import("../utils/page-surface.js").FormPageSurfaceClasses>;
@@ -80,6 +82,8 @@ export declare function provideFormPage(page: ReturnType<typeof useFormPage>): {
80
82
  };
81
83
  scrollTo: (key: string, options?: import("../types/index.js").FormPageScrollOptions) => boolean;
82
84
  sections: import("vue").ComputedRef<readonly FormPageSectionState[]>;
85
+ spanned: import("vue").ComputedRef<boolean>;
86
+ statusVisible: import("vue").ComputedRef<boolean>;
83
87
  stickyOffset: import("vue").Ref<number, number>;
84
88
  surface: import("vue").ComputedRef<import("../types/index.js").FormPageSurface>;
85
89
  surfaceClasses: import("vue").ComputedRef<import("../utils/page-surface.js").FormPageSurfaceClasses>;
@@ -118,6 +122,8 @@ export declare function useFormPageContext(): {
118
122
  };
119
123
  scrollTo: (key: string, options?: import("../types/index.js").FormPageScrollOptions) => boolean;
120
124
  sections: import("vue").ComputedRef<readonly FormPageSectionState[]>;
125
+ spanned: import("vue").ComputedRef<boolean>;
126
+ statusVisible: import("vue").ComputedRef<boolean>;
121
127
  stickyOffset: import("vue").Ref<number, number>;
122
128
  surface: import("vue").ComputedRef<import("../types/index.js").FormPageSurface>;
123
129
  surfaceClasses: import("vue").ComputedRef<import("../utils/page-surface.js").FormPageSurfaceClasses>;
@@ -43,6 +43,8 @@ export function useFormPage(params) {
43
43
  const navigationVisible = computed(() => sections.value.length >= navigationMinSections.value);
44
44
  const surface = computed(() => resolveFormPageSurface(root.formUi.ui.value.page?.surface));
45
45
  const surfaceClasses = computed(() => getFormPageSurfaceClasses(surface.value));
46
+ const statusVisible = computed(() => root.formUi.ui.value.page?.status === true);
47
+ const spanned = computed(() => sections.value.some((section) => section.span < 12));
46
48
  const remaining = computed(() => sections.value.filter(isFormPageSectionBlocking).length);
47
49
  const modified = computed(() => sections.value.filter((section) => section.dirty).length);
48
50
  const stickyOffset = ref(0);
@@ -72,6 +74,8 @@ export function useFormPage(params) {
72
74
  root,
73
75
  scrollTo: scroll.scrollTo,
74
76
  sections,
77
+ spanned,
78
+ statusVisible,
75
79
  stickyOffset,
76
80
  surface,
77
81
  surfaceClasses
@@ -10,6 +10,7 @@ import FormOptionSuffix from "../../components/utils/form-option-suffix.vue";
10
10
  import FormOptionValueOverlay from "../../components/utils/form-option-value-overlay.vue";
11
11
  import { useFieldControl } from "../../composables/use-field-control";
12
12
  import { useOptionMenu } from "../../composables/use-option-menu";
13
+ import { leadingVisualPadding } from "../../utils/options";
13
14
  import { isBoolean, isNumber, isString } from "../../utils/predicate";
14
15
  import { mergeFormUiClass } from "../../utils/ui";
15
16
  const props = defineProps({
@@ -61,6 +62,7 @@ const controlUi = computed(() => ({
61
62
  ...controlProps.value.ui,
62
63
  base: mergeFormUiClass(
63
64
  controlProps.value.ui?.base,
65
+ menu.leadingOption.value ? leadingVisualPadding(controlProps.value.size) : void 0,
64
66
  overlayActive.value ? "text-transparent" : void 0
65
67
  ),
66
68
  content: mergeFormUiClass(controlProps.value.ui?.content, interactionOwnerClass.value),
@@ -11,6 +11,7 @@ import FormOptionMenuFooter from "../../components/utils/form-option-menu-footer
11
11
  import FormOptionSuffix from "../../components/utils/form-option-suffix.vue";
12
12
  import { useFieldControl } from "../../composables/use-field-control";
13
13
  import { useOptionMenu } from "../../composables/use-option-menu";
14
+ import { leadingVisualPadding } from "../../utils/options";
14
15
  import { isBoolean, isNumber, isString } from "../../utils/predicate";
15
16
  import { mergeFormUiClass } from "../../utils/ui";
16
17
  const props = defineProps({
@@ -65,6 +66,10 @@ const menu = useOptionMenu({
65
66
  });
66
67
  const controlUi = computed(() => ({
67
68
  ...controlProps.value.ui,
69
+ base: mergeFormUiClass(
70
+ controlProps.value.ui?.base,
71
+ menu.leadingOption.value ? leadingVisualPadding(controlProps.value.size) : void 0
72
+ ),
68
73
  content: mergeFormUiClass(controlProps.value.ui?.content, interactionOwnerClass.value),
69
74
  itemDescription: mergeFormUiClass(
70
75
  menu.renderOption.value ? "hidden" : "text-[12.5px]",
@@ -54,6 +54,13 @@ export interface FormPageSection<TContext = NonNullable<unknown>, TFields extend
54
54
  optional?: boolean;
55
55
  /** Grid of the section's fields, merged over the schema `layout`. */
56
56
  layout?: FormLayoutConfig;
57
+ /**
58
+ * Columns, out of twelve, the section takes once the sections area is at least 48rem wide, so
59
+ * short sections sit side by side: `span: 4` next to `span: 8`. Sections fill the rows in order
60
+ * and the ones sharing a row stretch to the same height. Below that width, or without a `span`,
61
+ * the section takes the whole row.
62
+ */
63
+ span?: number;
57
64
  /** Raw dependency paths read before evaluating `condition`. */
58
65
  dependencies?: readonly (string | readonly [string, string])[];
59
66
  /** Hides the section, its navigation entry, and its fields while it returns `false`. */
@@ -186,6 +193,10 @@ export interface FormPageSectionState {
186
193
  optional: boolean;
187
194
  /** Number of required fields without a value, the fields of array items included. */
188
195
  missing: number;
196
+ /** Number of required fields, the fields of array items included. */
197
+ required: number;
198
+ /** Columns, out of twelve, the section takes on a wide sections area: 12 without a `span`. */
199
+ span: number;
189
200
  /** Where the section stands, see `FormPageSectionStatus`. */
190
201
  status: FormPageSectionStatus;
191
202
  /** True when a value of the section differs from the form's baseline. */
@@ -197,10 +197,11 @@ export interface FormOverlayUi {
197
197
  * How the sections of a form page are drawn:
198
198
  *
199
199
  * - `card`: each section is a bordered card on the gray canvas of the page (default)
200
+ * - `panel`: a card whose heading sits in a bar across its top, above the fields
200
201
  * - `plain`: no box. A section is its heading, description, and fields on the page itself,
201
202
  * separated from the next by spacing and a hairline
202
203
  */
203
- export type FormPageSurface = 'card' | 'plain';
204
+ export type FormPageSurface = 'card' | 'panel' | 'plain';
204
205
  /**
205
206
  * The `page` part of the form UI config: the surface of the sections and the `ui` slots of the
206
207
  * page parts. Both follow the usual layering: app config, then schema `ui`, then the `ui` prop.
@@ -208,6 +209,13 @@ export type FormPageSurface = 'card' | 'plain';
208
209
  export interface FormPageUiConfig extends FormUiPartConfig<FormPageUi> {
209
210
  /** Defaults to `card`. */
210
211
  surface?: FormPageSurface;
212
+ /**
213
+ * Shows where each section stands at the end of its heading: the required fields filled out of
214
+ * the total while some are missing ("2 sur 3"), "Complété" once nothing is, "À corriger" while a
215
+ * field shows an error, and "Facultatif" for an optional section with nothing entered, which
216
+ * then carries its tag there instead of after the title. Off by default.
217
+ */
218
+ status?: boolean;
211
219
  }
212
220
  /**
213
221
  * Slots of a form page and its parts. Data attributes carry the live state, so a slot can
@@ -274,6 +282,8 @@ export interface FormPageUi {
274
282
  sectionDescription?: FormUiClass;
275
283
  /** The "Optional" badge of an optional section with nothing entered. */
276
284
  sectionOptional?: FormUiClass;
285
+ /** Badge of where the section stands, with `page.status`. Carries `data-form-page-status`. */
286
+ sectionStatus?: FormUiClass;
277
287
  sectionActions?: FormUiClass;
278
288
  sectionReset?: FormUiClass;
279
289
  sectionBody?: FormUiClass;
@@ -12,6 +12,12 @@ export interface FormOptionKeys {
12
12
  export type { ResolvedFormOption } from '../types/index.js';
13
13
  /** The one visual an option draws before its label: its icon, else its avatar, else its chip. */
14
14
  export type OptionLeading = 'icon' | 'avatar' | 'chip';
15
+ /**
16
+ * Start padding of a select or auto-complete that draws the chosen option's visual in its leading
17
+ * slot. Nuxt UI decides that padding from the slot once, so a visual that appears after mount (a
18
+ * value picked later) would otherwise draw over the text.
19
+ */
20
+ export declare function leadingVisualPadding(size: unknown): "ps-10" | "ps-9" | "ps-8" | "ps-11" | "ps-7";
15
21
  export declare function resolveOptionLeading(option: ResolvedFormOption): OptionLeading | undefined;
16
22
  export declare function resolveOptionDescriptionIndent(option: ResolvedFormOption): string | undefined;
17
23
  export declare function normalizeOptionItem(option: FormValue, keys?: FormOptionKeys): ResolvedFormOption;
@@ -12,6 +12,13 @@ const CHIP_COLORS = [
12
12
  "error",
13
13
  "neutral"
14
14
  ];
15
+ const LEADING_PADDING = { lg: "ps-10", md: "ps-9", sm: "ps-8", xl: "ps-11", xs: "ps-7" };
16
+ export function leadingVisualPadding(size) {
17
+ return LEADING_PADDING[isLeadingSize(size) ? size : "md"];
18
+ }
19
+ function isLeadingSize(size) {
20
+ return isString(size) && Object.hasOwn(LEADING_PADDING, size);
21
+ }
15
22
  export function resolveOptionLeading(option) {
16
23
  if (option.icon) return "icon";
17
24
  if (option.avatar) return "avatar";
@@ -10,6 +10,10 @@ export interface FormPageSurfaceClasses {
10
10
  sections: string;
11
11
  /** The box of a card, or the spacing, hairline, and modified marker of a plain section. */
12
12
  section: string;
13
+ /** The bar of a panel heading. */
14
+ sectionHeader: string;
15
+ /** Padding of the fields under a panel bar. */
16
+ sectionBody: string;
13
17
  /** Where the description sits against the title. */
14
18
  sectionDescription: string;
15
19
  /** Placeholder shown while the schema context loads. */
@@ -5,14 +5,27 @@ const FORM_PAGE_SURFACES = {
5
5
  card: {
6
6
  root: "bg-muted",
7
7
  section: "gap-[18px] rounded-xl border border-default bg-default px-5 pt-5 pb-6 transition-[border-color,box-shadow] duration-200 @3xl/form-page:px-6 @3xl/form-page:pt-[22px] data-[dirty]:border-primary data-[dirty]:ring-4 data-[dirty]:ring-primary/20 data-[dirty]:ring-inset",
8
+ sectionBody: "",
8
9
  sectionDescription: "order-last basis-full @3xl/form-page:order-none @3xl/form-page:basis-auto",
10
+ sectionHeader: "",
9
11
  sectionSkeleton: "rounded-xl border border-default bg-default px-6 pt-[22px] pb-6",
10
12
  sections: "gap-[18px]"
11
13
  },
14
+ panel: {
15
+ root: "bg-muted",
16
+ section: "overflow-hidden rounded-xl border border-default bg-default transition-[border-color,box-shadow] duration-200 focus-within:border-accented data-[dirty]:border-primary data-[dirty]:ring-4 data-[dirty]:ring-primary/20 data-[dirty]:ring-inset",
17
+ sectionBody: "px-5 pt-5 pb-6 @3xl/form-page:px-6",
18
+ sectionDescription: "order-last basis-full",
19
+ sectionHeader: "min-h-13 border-b border-default bg-elevated/60 px-4 py-2.5 @3xl/form-page:px-5",
20
+ sectionSkeleton: "rounded-xl border border-default bg-default px-6 pt-[22px] pb-6",
21
+ sections: "gap-4"
22
+ },
12
23
  plain: {
13
24
  root: "bg-default",
14
25
  section: "relative gap-[18px] border-t border-default py-8 first:border-t-0 first:pt-0 last:pb-0 before:pointer-events-none before:absolute before:inset-y-8 before:-start-3 before:w-0.5 before:rounded-full before:transition-colors first:before:top-0 last:before:bottom-0 data-[dirty]:before:bg-primary",
26
+ sectionBody: "",
15
27
  sectionDescription: "order-last basis-full",
28
+ sectionHeader: "",
16
29
  sectionSkeleton: "border-t border-default py-8 first:border-t-0 first:pt-0",
17
30
  sections: "gap-0"
18
31
  }
@@ -38,3 +38,5 @@ export declare function resolveFormPageSectionState(params: {
38
38
  /** False when the validation mode does not enforce required fields. */
39
39
  requiredEnforced: boolean;
40
40
  }): FormPageSectionState;
41
+ /** Columns a section takes out of twelve: a whole number from 1 to 12, the full row otherwise. */
42
+ export declare function resolveFormPageSectionSpan(value: FormValue): number;
@@ -76,9 +76,14 @@ export function resolveFormPageSectionState(params) {
76
76
  label: resolveFormText(entry.section.label) ?? entry.section.key,
77
77
  missing,
78
78
  optional,
79
+ required: required.length,
80
+ span: resolveFormPageSectionSpan(entry.section.span),
79
81
  status: resolveFormPageSectionStatus({ invalid, missing, optional, provided })
80
82
  };
81
83
  }
84
+ export function resolveFormPageSectionSpan(value) {
85
+ return isNumber(value) && value >= 1 ? Math.min(12, Math.trunc(value)) : 12;
86
+ }
82
87
  function collectVisibleLeaves(fields, parentPath, runtime, item = false) {
83
88
  return fields.flatMap((field) => {
84
89
  if (field.ignore === true) {
@@ -206,6 +206,7 @@ export default defineUiToolsLocale({
206
206
  },
207
207
  page: {
208
208
  complete: "Everything is ready.",
209
+ progress: "{filled} of {required}",
209
210
  modifiedOne: "{count} modified.",
210
211
  modifiedOther: "{count} modified.",
211
212
  navigation: "Form sections",
@@ -206,6 +206,7 @@ export default defineUiToolsLocale({
206
206
  },
207
207
  page: {
208
208
  complete: "Tout est pr\xEAt.",
209
+ progress: "{filled} sur {required}",
209
210
  modifiedOne: "{count} modifi\xE9e.",
210
211
  modifiedOther: "{count} modifi\xE9es.",
211
212
  navigation: "Sections du formulaire",
@@ -464,6 +464,8 @@ export interface UiToolsFormMessages {
464
464
  remaining: string;
465
465
  /** Navigation summary once every required section is complete. */
466
466
  complete: string;
467
+ /** Status of a section with required fields left, with `page.status`: "{filled} of {required}". */
468
+ progress: string;
467
469
  /** Navigation summary of a form with dirty checking: "{count} modified." */
468
470
  modifiedOne: string;
469
471
  modifiedOther: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-ui-tools",
3
- "version": "1.20.0",
3
+ "version": "1.21.0",
4
4
  "description": "Nuxt module and runtime toolkit for UI-heavy Nuxt applications",
5
5
  "homepage": "https://github.com/ChronicStone/nuxt-ui-tools#readme",
6
6
  "bugs": "https://github.com/ChronicStone/nuxt-ui-tools/issues",