nuxt-ui-tools 1.10.0 → 1.11.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.10.0",
8
+ "version": "1.11.0",
9
9
  "builder": {
10
10
  "@nuxt/module-builder": "1.0.3",
11
11
  "unbuild": "unknown"
@@ -14,7 +14,7 @@ import { getSchemaDirtyCheck } from "../../utils/controls";
14
14
  import { createFormFieldInstance } from "../../utils/field-instance";
15
15
  import { isFunction, isNumber, isString } from "../../utils/predicate";
16
16
  import { resolveRequired } from "../../utils/state";
17
- import { resolveFieldDescription, resolveFormText } from "../../utils/text";
17
+ import { resolveFieldDescription, resolveFieldText, resolveFormText } from "../../utils/text";
18
18
  import { mergeFormUiClass } from "../../utils/ui";
19
19
  const props = defineProps({
20
20
  field: { type: null, required: true },
@@ -25,12 +25,13 @@ const form = useFormRuntimeContext();
25
25
  const formUi = useFormUi();
26
26
  const bare = useFormFieldBare();
27
27
  const field = computed(() => createFormFieldInstance(props.field));
28
+ const params = computed(() => form.getFieldCallbackParams(props.path, props.field));
28
29
  const label = computed(
29
30
  () => field.value.capability.has("label") && "label" in props.field ? resolveFormText(props.field.label) : void 0
30
31
  );
31
32
  const { t } = useUiToolsLocale();
32
33
  const descriptionConfig = computed(
33
- () => field.value.capability.has("description") && "description" in props.field ? resolveFieldDescription(props.field.description) : void 0
34
+ () => field.value.capability.has("description") && "description" in props.field ? resolveFieldDescription(props.field.description, params.value) : void 0
34
35
  );
35
36
  const description = computed(
36
37
  () => descriptionConfig.value?.display === "inline" ? descriptionConfig.value.text : void 0
@@ -59,7 +60,7 @@ const shellStyle = computed(
59
60
  () => orientation.value === "horizontal" && labelWidth.value ? { "--nut-form-label-width": labelWidth.value } : void 0
60
61
  );
61
62
  const hint = computed(
62
- () => field.value.capability.has("hint") && "hint" in props.field ? resolveFormText(props.field.hint) : void 0
63
+ () => field.value.capability.has("hint") && "hint" in props.field ? resolveFieldText(props.field.hint, params.value) : void 0
63
64
  );
64
65
  const labelExtra = computed(() => {
65
66
  if (!field.value.capability.has("hint") || !("labelExtra" in props.field)) {
@@ -78,10 +79,10 @@ const required = computed(() => {
78
79
  if (!field.value.capability.has("validation")) {
79
80
  return false;
80
81
  }
81
- return resolveRequired(props.field, form.getFieldCallbackParams(props.path, props.field));
82
+ return resolveRequired(props.field, params.value);
82
83
  });
83
84
  const help = computed(
84
- () => field.value.capability.has("hint") && "help" in props.field ? resolveFormText(props.field.help) : void 0
85
+ () => field.value.capability.has("hint") && "help" in props.field ? resolveFieldText(props.field.help, params.value) : void 0
85
86
  );
86
87
  const shellHelp = computed(() => props.inlineLabel ? void 0 : help.value);
87
88
  const dirty = computed(
@@ -30,7 +30,7 @@ export declare function useFieldControl<TField extends FormField>(field: () => T
30
30
  activate: () => void;
31
31
  add: (option: FormValue) => import("../utils/options.js").ResolvedFormOption;
32
32
  creatable: import("vue").ComputedRef<boolean>;
33
- create: (label: string) => Promise<import("../utils/options.js").ResolvedFormOption | null>;
33
+ create: (label?: string) => Promise<import("../utils/options.js").ResolvedFormOption | null>;
34
34
  createLabel: import("vue").ComputedRef<string | undefined>;
35
35
  creating: import("vue").ComputedRef<boolean>;
36
36
  disableOnLoading: import("vue").ComputedRef<boolean>;
@@ -12,7 +12,7 @@ export declare function useFieldOptions(params: {
12
12
  activate: () => void;
13
13
  add: (option: FormValue) => ResolvedFormOption;
14
14
  creatable: ComputedRef<boolean>;
15
- create: (label: string) => Promise<ResolvedFormOption | null>;
15
+ create: (label?: string) => Promise<ResolvedFormOption | null>;
16
16
  createLabel: ComputedRef<string | undefined>;
17
17
  creating: ComputedRef<boolean>;
18
18
  disableOnLoading: ComputedRef<boolean>;
@@ -46,7 +46,10 @@ export function useFieldOptions(params) {
46
46
  }
47
47
  return resolveTrackedOptionSource(params.field(), params.callbackParams.value);
48
48
  });
49
- const resolvedSource = computed(() => trackedOptionSource.value.source);
49
+ const resolvedSource = computed(() => {
50
+ const { source } = trackedOptionSource.value;
51
+ return isRuntimeQueryOptions(source) && isDisabledQueryOptions(source) ? [] : source;
52
+ });
50
53
  const contextResources = computed(() => {
51
54
  const { ctx } = params.callbackParams.value;
52
55
  if (!isRecord(ctx)) {
@@ -260,8 +263,8 @@ export function useFieldOptions(params) {
260
263
  return normalized;
261
264
  }
262
265
  async function create(label) {
263
- const normalizedLabel = label.trim();
264
- if (!normalizedLabel || creating.value) {
266
+ const normalizedLabel = label?.trim() ?? "";
267
+ if (!isUndefined(label) && !normalizedLabel || creating.value) {
265
268
  return null;
266
269
  }
267
270
  const createOption = optionConfig.value?.create;
@@ -435,6 +438,9 @@ function trackContextAccess(ctx, contextKeys) {
435
438
  }
436
439
  });
437
440
  }
441
+ function isDisabledQueryOptions(source) {
442
+ return Object.getOwnPropertyDescriptor(source, "enabled")?.value === false;
443
+ }
438
444
  function isRuntimeQueryOptions(value) {
439
445
  if (!isRecord(value)) {
440
446
  return false;
@@ -77,7 +77,7 @@ async function handleCreate(label) {
77
77
  await options.create(label);
78
78
  }
79
79
  async function handleCreateAction() {
80
- await handleCreate(searchTerm.value);
80
+ await options.create(searchTerm.value.trim() || void 0);
81
81
  }
82
82
  async function handleNativeCreate(label) {
83
83
  const normalizedLabel = label.trim();
@@ -85,7 +85,7 @@ async function handleCreate(label) {
85
85
  await options.create(label);
86
86
  }
87
87
  async function handleCreateAction() {
88
- await handleCreate(searchTerm.value);
88
+ await options.create(searchTerm.value.trim() || void 0);
89
89
  }
90
90
  async function handleNativeCreate(label) {
91
91
  const normalizedLabel = label.trim();
@@ -27,8 +27,24 @@ const model = computed({
27
27
  });
28
28
  const maskOptions = computed(() => maskDirectiveOptions(fieldProps.value.mask));
29
29
  const vOptionalMaska = (element, binding, vnode, previousVnode) => {
30
- if (binding.value !== void 0 && typeof vMaska === "function") {
30
+ if (typeof vMaska !== "function") {
31
+ return;
32
+ }
33
+ if (binding.value !== void 0) {
31
34
  vMaska(element, binding, vnode, previousVnode);
35
+ } else if (binding.oldValue !== void 0) {
36
+ vMaska(
37
+ element,
38
+ {
39
+ dir: {},
40
+ instance: binding.instance,
41
+ modifiers: {},
42
+ oldValue: binding.oldValue,
43
+ value: { mask: null }
44
+ },
45
+ vnode,
46
+ previousVnode
47
+ );
32
48
  }
33
49
  };
34
50
  const prefix = computed(() => resolveFormText(fieldProps.value.prefix));
@@ -86,8 +86,11 @@ export interface FormFieldOptionsApi<TOption = FormValue> {
86
86
  error: () => FormValue | null;
87
87
  /** Refreshes the option source when it is async or query-backed. */
88
88
  refresh: () => Promise<void>;
89
- /** Creates a new option when the field configured an option creation handler. */
90
- create: (label: string) => Promise<TOption | null>;
89
+ /**
90
+ * Creates a new option when the field configured an option creation handler. A blank typed label
91
+ * creates nothing; calling it without a label runs the handler with an empty one.
92
+ */
93
+ create: (label?: string) => Promise<TOption | null>;
91
94
  /** Returns hydrated options for the current selection, including values outside loaded pages. */
92
95
  selected: () => readonly TOption[];
93
96
  /** True when the field loads options remotely. */
@@ -35,12 +35,12 @@ export interface FormStatefulFieldBase<TType extends FormFieldType, TValue, TCon
35
35
  }>;
36
36
  /** Label rendered by the field wrapper. */
37
37
  label?: FormText;
38
- /** Optional supporting copy rendered near the control, or a tooltip/modal variant. */
39
- description?: FormText | FormFieldDescription;
40
- /** Optional right-side hint rendered by the field wrapper. */
41
- hint?: FormText;
42
- /** Optional help text rendered under the control. */
43
- help?: FormText;
38
+ /** Optional supporting copy rendered near the control, or a tooltip/modal variant. Callbacks receive `{ ctx, deps, api }`. */
39
+ description?: FormText | FormFieldDescription | FormFieldCallback<FormText | FormFieldDescription, TContext, TDeps, TValue>;
40
+ /** Optional right-side hint rendered by the field wrapper. Callbacks receive `{ ctx, deps, api }`. */
41
+ hint?: FormText | FormFieldCallback<FormText, TContext, TDeps, TValue>;
42
+ /** Optional help text rendered under the control. Callbacks receive `{ ctx, deps, api }`. */
43
+ help?: FormText | FormFieldCallback<FormText, TContext, TDeps, TValue>;
44
44
  /** Optional rich content rendered beside the label. Takes precedence over `hint`. */
45
45
  labelExtra?: FormRenderable;
46
46
  /** Placeholder forwarded to controls that support placeholders. Callbacks receive `{ ctx, deps, api }`. */
@@ -49,5 +49,6 @@ export interface FormOptionRuntimeState {
49
49
  /** Loads the direct children of a remote tree option. */
50
50
  loadChildren: (option: ResolvedFormOption) => Promise<void>;
51
51
  add: (option: FormValue) => void;
52
- create: (label: string) => Promise<ResolvedFormOption | null>;
52
+ /** Creates an option; a blank typed label creates nothing, and no label runs the handler with an empty one. */
53
+ create: (label?: string) => Promise<ResolvedFormOption | null>;
53
54
  }
@@ -33,7 +33,10 @@ export type FormOptionsSource<TOption, TContext = NonNullable<unknown>, TDeps =
33
33
  * Option creation hook for fields that can create a missing option from user input.
34
34
  */
35
35
  export interface FormCreateOptionParams<TContext = NonNullable<unknown>, TDeps = FormDependencies, TValue = FormValue, TOption = FormValue> extends FormFieldCallbackParams<TContext, TDeps, TValue, TOption> {
36
- /** User-entered label that should be converted into a concrete option. */
36
+ /**
37
+ * User-entered label that should be converted into a concrete option. Empty when the explicit
38
+ * create action runs without a search term, such as a creator that opens its own form.
39
+ */
37
40
  label: string;
38
41
  }
39
42
  export interface FormCreateOption<TOption, TContext = NonNullable<unknown>, TDeps = FormDependencies, TValue = FormValue> {
@@ -1,9 +1,11 @@
1
- import type { FormFieldDescription, FormText, FormValue } from '../types/index.js';
1
+ import type { FormText, FormValue } from '../types/index.js';
2
2
  export declare function resolveFormText(text: FormText | undefined): string | undefined;
3
+ /** Resolves field copy that is static, lazy, or computed from the field callback parameters. */
4
+ export declare function resolveFieldText(text: FormValue, params: FormValue): string | undefined;
3
5
  export declare function resolveFormBoundaryText(value: FormValue): string | undefined;
4
6
  export interface ResolvedFieldDescription {
5
7
  text: string;
6
8
  display: 'inline' | 'tooltip' | 'modal';
7
9
  title?: string;
8
10
  }
9
- export declare function resolveFieldDescription(value: FormText | FormFieldDescription | undefined): ResolvedFieldDescription | undefined;
11
+ export declare function resolveFieldDescription(description: FormValue, params: FormValue): ResolvedFieldDescription | undefined;
@@ -9,6 +9,9 @@ export function resolveFormText(text) {
9
9
  }
10
10
  return text;
11
11
  }
12
+ export function resolveFieldText(text, params) {
13
+ return resolveFormBoundaryText(isFunction(text) ? invokeFormFunction(text, [params]) : text);
14
+ }
12
15
  export function resolveFormBoundaryText(value) {
13
16
  if (isString(value)) {
14
17
  return value;
@@ -21,20 +24,20 @@ export function resolveFormBoundaryText(value) {
21
24
  return isString(resolved) || isNumber(resolved) ? String(resolved) : void 0;
22
25
  }
23
26
  }
24
- export function resolveFieldDescription(value) {
25
- if (value === void 0) {
26
- return void 0;
27
- }
28
- if (isDescriptionConfig(value)) {
29
- const text2 = resolveFormText(value.text);
27
+ const DESCRIPTION_DISPLAYS = ["inline", "tooltip", "modal"];
28
+ export function resolveFieldDescription(description, params) {
29
+ const value = isFunction(description) ? invokeFormFunction(description, [params]) : description;
30
+ if (isRecord(value) && "text" in value) {
31
+ const text2 = resolveFormBoundaryText(value.text);
30
32
  if (!text2) {
31
33
  return void 0;
32
34
  }
33
- return { display: value.display ?? "inline", text: text2, title: resolveFormText(value.title) };
35
+ return {
36
+ display: DESCRIPTION_DISPLAYS.find((display) => display === value.display) ?? "inline",
37
+ text: text2,
38
+ title: resolveFormBoundaryText(value.title)
39
+ };
34
40
  }
35
- const text = resolveFormText(value);
41
+ const text = resolveFormBoundaryText(value);
36
42
  return text ? { display: "inline", text } : void 0;
37
43
  }
38
- function isDescriptionConfig(value) {
39
- return isRecord(value) && "text" in value;
40
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-ui-tools",
3
- "version": "1.10.0",
3
+ "version": "1.11.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",