@auronui/vue 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/cjs/index.cjs +690 -423
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/components/autocomplete/Autocomplete.context.js.map +1 -1
  4. package/dist/components/autocomplete/Autocomplete.js.map +1 -1
  5. package/dist/components/autocomplete/Autocomplete.vue_vue_type_script_setup_true_lang.js +119 -14
  6. package/dist/components/autocomplete/Autocomplete.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/components/autocomplete/AutocompleteCreateItem.js +7 -0
  8. package/dist/components/autocomplete/AutocompleteCreateItem.js.map +1 -0
  9. package/dist/components/autocomplete/AutocompleteCreateItem.vue_vue_type_script_setup_true_lang.js +57 -0
  10. package/dist/components/autocomplete/AutocompleteCreateItem.vue_vue_type_script_setup_true_lang.js.map +1 -0
  11. package/dist/components/autocomplete/AutocompleteInput.js.map +1 -1
  12. package/dist/components/autocomplete/AutocompleteInput.vue_vue_type_script_setup_true_lang.js +40 -9
  13. package/dist/components/autocomplete/AutocompleteInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
  14. package/dist/components/autocomplete/AutocompleteItem.js.map +1 -1
  15. package/dist/components/autocomplete/AutocompleteItem.vue_vue_type_script_setup_true_lang.js +33 -5
  16. package/dist/components/autocomplete/AutocompleteItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  17. package/dist/components/autocomplete/AutocompleteOverflowChips.js +7 -0
  18. package/dist/components/autocomplete/AutocompleteOverflowChips.js.map +1 -0
  19. package/dist/components/autocomplete/AutocompleteOverflowChips.vue_vue_type_script_setup_true_lang.js +88 -0
  20. package/dist/components/autocomplete/AutocompleteOverflowChips.vue_vue_type_script_setup_true_lang.js.map +1 -0
  21. package/dist/components/form/Form.js.map +1 -1
  22. package/dist/components/form/Form.vue_vue_type_script_setup_true_lang.js +123 -8
  23. package/dist/components/form/Form.vue_vue_type_script_setup_true_lang.js.map +1 -1
  24. package/dist/components/form/FormField.js.map +1 -1
  25. package/dist/components/form/FormField.vue_vue_type_script_setup_true_lang.js +30 -2
  26. package/dist/components/form/FormField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  27. package/dist/components/form/form.context.js.map +1 -1
  28. package/dist/components/form/validation.js +23 -3
  29. package/dist/components/form/validation.js.map +1 -1
  30. package/dist/components/select/Select.context.js.map +1 -1
  31. package/dist/components/select/Select.js.map +1 -1
  32. package/dist/components/select/Select.vue_vue_type_script_setup_true_lang.js +12 -1
  33. package/dist/components/select/Select.vue_vue_type_script_setup_true_lang.js.map +1 -1
  34. package/dist/components/select/SelectOverflowChips.js +7 -0
  35. package/dist/components/select/SelectOverflowChips.js.map +1 -0
  36. package/dist/components/select/SelectOverflowChips.vue_vue_type_script_setup_true_lang.js +85 -0
  37. package/dist/components/select/SelectOverflowChips.vue_vue_type_script_setup_true_lang.js.map +1 -0
  38. package/dist/components/select/SelectValue.js.map +1 -1
  39. package/dist/components/select/SelectValue.vue_vue_type_script_setup_true_lang.js +6 -1
  40. package/dist/components/select/SelectValue.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/index.d.ts +397 -423
  42. package/dist/index.js +2 -7
  43. package/package.json +4 -4
  44. package/dist/components/tag/Tag.js +0 -7
  45. package/dist/components/tag/Tag.js.map +0 -1
  46. package/dist/components/tag/Tag.vue_vue_type_script_setup_true_lang.js +0 -69
  47. package/dist/components/tag/Tag.vue_vue_type_script_setup_true_lang.js.map +0 -1
  48. package/dist/components/tag/TagDelete.js +0 -7
  49. package/dist/components/tag/TagDelete.js.map +0 -1
  50. package/dist/components/tag/TagDelete.vue_vue_type_script_setup_true_lang.js +0 -49
  51. package/dist/components/tag/TagDelete.vue_vue_type_script_setup_true_lang.js.map +0 -1
  52. package/dist/components/tag/TagText.js +0 -7
  53. package/dist/components/tag/TagText.js.map +0 -1
  54. package/dist/components/tag/TagText.vue_vue_type_script_setup_true_lang.js +0 -18
  55. package/dist/components/tag/TagText.vue_vue_type_script_setup_true_lang.js.map +0 -1
  56. package/dist/components/tag-group/TagGroup.context.js +0 -7
  57. package/dist/components/tag-group/TagGroup.context.js.map +0 -1
  58. package/dist/components/tag-group/TagGroup.js +0 -7
  59. package/dist/components/tag-group/TagGroup.js.map +0 -1
  60. package/dist/components/tag-group/TagGroup.vue_vue_type_script_setup_true_lang.js +0 -142
  61. package/dist/components/tag-group/TagGroup.vue_vue_type_script_setup_true_lang.js.map +0 -1
  62. package/dist/components/tag-group/TagGroupInput.js +0 -7
  63. package/dist/components/tag-group/TagGroupInput.js.map +0 -1
  64. package/dist/components/tag-group/TagGroupInput.vue_vue_type_script_setup_true_lang.js +0 -37
  65. package/dist/components/tag-group/TagGroupInput.vue_vue_type_script_setup_true_lang.js.map +0 -1
@@ -1,6 +1,8 @@
1
1
  import Spinner_default from "../spinner/Spinner.js";
2
+ import Chip_default from "../chip/Chip.js";
2
3
  import { useAutocompleteInject } from "./Autocomplete.context.js";
3
- import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, renderSlot, toDisplayString, unref, useTemplateRef, withCtx } from "vue";
4
+ import AutocompleteOverflowChips_default from "./AutocompleteOverflowChips.js";
5
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, renderList, renderSlot, toDisplayString, unref, useTemplateRef, withCtx, withModifiers } from "vue";
4
6
  import { useFocusWithin } from "@vueuse/core";
5
7
  import { AutocompleteAnchor, AutocompleteCancel, AutocompleteInput, AutocompleteTrigger } from "reka-ui";
6
8
  //#region src/components/autocomplete/AutocompleteInput.vue?vue&type=script&setup=true&lang.ts
@@ -20,6 +22,8 @@ var AutocompleteInput_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
20
22
  const ctx = useAutocompleteInject();
21
23
  const { focused: isFocused } = useFocusWithin(useTemplateRef("anchor"));
22
24
  const showInsideLabel = computed(() => ctx.hasLabel.value && ctx.labelPlacement.value === "inside");
25
+ const effectivePlaceholder = computed(() => ctx.multiple.value && ctx.selectedValues.value.length > 0 ? void 0 : props.placeholder);
26
+ const getLabel = (v) => ctx.selectedLabels.value.find((l) => l.value === v)?.label ?? v;
23
27
  return (_ctx, _cache) => {
24
28
  return openBlock(), createBlock(unref(AutocompleteAnchor), {
25
29
  ref: "anchor",
@@ -29,6 +33,7 @@ var AutocompleteInput_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
29
33
  "data-invalid": unref(ctx).isInvalid.value || void 0,
30
34
  "data-disabled": unref(ctx).isDisabled.value || void 0,
31
35
  "data-readonly": unref(ctx).isReadonly.value || void 0,
36
+ "data-multiple-overflow": unref(ctx).multiple.value ? unref(ctx).multipleOverflow.value : void 0,
32
37
  "data-slot": "trigger"
33
38
  }, {
34
39
  default: withCtx(() => [
@@ -42,15 +47,38 @@ var AutocompleteInput_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
42
47
  class: normalizeClass(unref(ctx).slots.value.startContent()),
43
48
  "data-slot": "start-content"
44
49
  }, [renderSlot(_ctx.$slots, "startContent")], 2)) : createCommentVNode("", true),
50
+ unref(ctx).multiple.value && unref(ctx).multipleOverflow.value === "collapse" && unref(ctx).selectedValues.value.length > 0 ? (openBlock(), createBlock(AutocompleteOverflowChips_default, {
51
+ key: 2,
52
+ values: unref(ctx).selectedValues.value,
53
+ "get-label": getLabel,
54
+ "remove-value": unref(ctx).removeValue
55
+ }, null, 8, ["values", "remove-value"])) : unref(ctx).multiple.value && unref(ctx).multipleOverflow.value === "wrap" ? (openBlock(true), createElementBlock(Fragment, { key: 3 }, renderList(unref(ctx).selectedLabels.value, (item) => {
56
+ return openBlock(), createBlock(Chip_default, {
57
+ key: item.value,
58
+ size: "sm",
59
+ "is-closable": "",
60
+ "close-aria-label": `Remove ${item.label}`,
61
+ "data-slot": "selected-chip",
62
+ onClose: withModifiers(($event) => unref(ctx).removeValue(item.value), ["stop"])
63
+ }, {
64
+ default: withCtx(() => [createTextVNode(toDisplayString(item.label), 1)]),
65
+ _: 2
66
+ }, 1032, ["close-aria-label", "onClose"]);
67
+ }), 128)) : createCommentVNode("", true),
45
68
  createVNode(unref(AutocompleteInput), {
46
69
  id: unref(ctx).inputId.value,
47
- placeholder: props.placeholder,
70
+ placeholder: effectivePlaceholder.value,
48
71
  disabled: unref(ctx).isDisabled.value,
49
72
  readonly: unref(ctx).isReadonly.value,
50
73
  required: unref(ctx).isRequired.value,
51
74
  "aria-invalid": unref(ctx).isInvalid.value || void 0,
52
75
  "aria-describedby": unref(ctx).ariaDescribedBy.value,
53
76
  class: normalizeClass(unref(ctx).slots.value.input()),
77
+ style: normalizeStyle(unref(ctx).multiple.value && unref(ctx).multipleOverflow.value === "collapse" && unref(ctx).selectedValues.value.length > 0 ? {
78
+ flex: "0 0 auto",
79
+ minWidth: "80px",
80
+ width: "auto"
81
+ } : void 0),
54
82
  "data-slot": "input",
55
83
  autocomplete: "off"
56
84
  }, null, 8, [
@@ -61,15 +89,17 @@ var AutocompleteInput_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
61
89
  "required",
62
90
  "aria-invalid",
63
91
  "aria-describedby",
64
- "class"
92
+ "class",
93
+ "style"
65
94
  ]),
66
95
  createVNode(unref(AutocompleteCancel), {
67
96
  class: normalizeClass(unref(ctx).slots.value.clearButton()),
68
97
  "data-empty": !unref(ctx).isFilled.value || unref(ctx).isReadonly.value || unref(ctx).isDisabled.value ? "true" : void 0,
69
98
  "data-slot": "clear-button",
70
- "aria-label": "Clear"
99
+ "aria-label": "Clear",
100
+ onClick: _cache[0] || (_cache[0] = ($event) => unref(ctx).multiple.value ? unref(ctx).clearAll() : void 0)
71
101
  }, {
72
- default: withCtx(() => [renderSlot(_ctx.$slots, "clearIcon", {}, () => [_cache[0] || (_cache[0] = createElementVNode("svg", {
102
+ default: withCtx(() => [renderSlot(_ctx.$slots, "clearIcon", {}, () => [_cache[1] || (_cache[1] = createElementVNode("svg", {
73
103
  xmlns: "http://www.w3.org/2000/svg",
74
104
  width: "10",
75
105
  height: "10",
@@ -95,19 +125,19 @@ var AutocompleteInput_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
95
125
  _: 3
96
126
  }, 8, ["class", "data-empty"]),
97
127
  unref(ctx).isLoading.value ? (openBlock(), createElementBlock("span", {
98
- key: 2,
128
+ key: 4,
99
129
  class: normalizeClass(unref(ctx).slots.value.indicator()),
100
130
  "data-slot": "autocomplete-loading-indicator",
101
131
  role: "status",
102
132
  "aria-live": "polite",
103
133
  "aria-label": "Loading suggestions"
104
134
  }, [createVNode(Spinner_default, { size: "sm" })], 2)) : (openBlock(), createBlock(unref(AutocompleteTrigger), {
105
- key: 3,
135
+ key: 5,
106
136
  class: normalizeClass(unref(ctx).slots.value.indicator()),
107
137
  "data-slot": "autocomplete-default-indicator",
108
138
  "aria-label": "Toggle suggestions"
109
139
  }, {
110
- default: withCtx(() => [renderSlot(_ctx.$slots, "triggerIcon", {}, () => [_cache[1] || (_cache[1] = createElementVNode("svg", {
140
+ default: withCtx(() => [renderSlot(_ctx.$slots, "triggerIcon", {}, () => [_cache[2] || (_cache[2] = createElementVNode("svg", {
111
141
  xmlns: "http://www.w3.org/2000/svg",
112
142
  width: "16",
113
143
  height: "16",
@@ -129,7 +159,8 @@ var AutocompleteInput_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
129
159
  "data-focused",
130
160
  "data-invalid",
131
161
  "data-disabled",
132
- "data-readonly"
162
+ "data-readonly",
163
+ "data-multiple-overflow"
133
164
  ]);
134
165
  };
135
166
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AutocompleteInput.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/autocomplete/AutocompleteInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, useTemplateRef } from 'vue'\nimport { useFocusWithin } from '@vueuse/core'\nimport { AutocompleteInput, AutocompleteTrigger, AutocompleteCancel, AutocompleteAnchor } from 'reka-ui'\nimport { useAutocompleteInject } from './Autocomplete.context'\nimport Spinner from '../spinner/Spinner.vue';\n\nconst props = withDefaults(defineProps<{\n placeholder?: string\n class?: string\n}>(), {\n placeholder: undefined,\n class: undefined,\n})\n\nconst ctx = useAutocompleteInject()\n\n// Track focused state via useFocusWithin (NOT manual @focus/@blur listeners) — the\n// inner Reka <AutocompleteInput> wraps the native <input>; useFocusWithin observes\n// the actual DOM subtree of the anchor, so isFocused flips reliably regardless of\n// how Reka forwards refs/attrs.\nconst anchorRef = useTemplateRef<HTMLElement>('anchor')\nconst { focused: isFocused } = useFocusWithin(anchorRef)\n\n// Render the inside-label only when (a) a label is set and (b) labelPlacement is 'inside'\nconst showInsideLabel = computed(\n () => ctx.hasLabel.value && ctx.labelPlacement.value === 'inside',\n)\n</script>\n\n<template>\n <AutocompleteAnchor\n ref=\"anchor\"\n :class=\"ctx.slots.value.trigger()\"\n :data-filled=\"ctx.hasLabel.value ? (ctx.isFilled.value || undefined) : undefined\"\n :data-focused=\"isFocused || undefined\"\n :data-invalid=\"ctx.isInvalid.value || undefined\"\n :data-disabled=\"ctx.isDisabled.value || undefined\"\n :data-readonly=\"ctx.isReadonly.value || undefined\"\n data-slot=\"trigger\"\n >\n <label\n v-if=\"showInsideLabel\"\n :for=\"ctx.inputId.value\"\n :class=\"ctx.slots.value.label()\"\n >{{ ctx.label.value }}<span\n v-if=\"ctx.isRequired.value\"\n aria-hidden=\"true\"\n > *</span></label>\n <span\n v-if=\"$slots.startContent\"\n :class=\"ctx.slots.value.startContent()\"\n data-slot=\"start-content\"\n >\n <slot name=\"startContent\" />\n </span>\n <AutocompleteInput\n :id=\"ctx.inputId.value\"\n :placeholder=\"props.placeholder\"\n :disabled=\"ctx.isDisabled.value\"\n :readonly=\"ctx.isReadonly.value\"\n :required=\"ctx.isRequired.value\"\n :aria-invalid=\"ctx.isInvalid.value || undefined\"\n :aria-describedby=\"ctx.ariaDescribedBy.value\"\n :class=\"ctx.slots.value.input()\"\n data-slot=\"input\"\n autocomplete=\"off\"\n />\n <!-- Clear button: only shown when filled and not in a readonly/disabled state.\n Reka's AutocompleteCancel does not set data-empty itself, so we drive it here. -->\n <AutocompleteCancel\n :class=\"ctx.slots.value.clearButton()\"\n :data-empty=\"(!ctx.isFilled.value || ctx.isReadonly.value || ctx.isDisabled.value) ? 'true' : undefined\"\n data-slot=\"clear-button\"\n aria-label=\"Clear\"\n >\n <slot name=\"clearIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"autocomplete-clear-button-icon\"\n aria-hidden=\"true\"\n >\n <line\n x1=\"18\"\n y1=\"6\"\n x2=\"6\"\n y2=\"18\"\n />\n <line\n x1=\"6\"\n y1=\"6\"\n x2=\"18\"\n y2=\"18\"\n />\n </svg>\n </slot>\n </AutocompleteCancel>\n <!-- Inline loading spinner: replaces the dropdown indicator while loadItems is pending -->\n <span\n v-if=\"ctx.isLoading.value\"\n :class=\"ctx.slots.value.indicator()\"\n data-slot=\"autocomplete-loading-indicator\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Loading suggestions\"\n >\n <Spinner size=\"sm\" />\n </span>\n <!-- Dropdown trigger indicator (hidden while loading) -->\n <AutocompleteTrigger\n v-else\n :class=\"ctx.slots.value.indicator()\"\n data-slot=\"autocomplete-default-indicator\"\n aria-label=\"Toggle suggestions\"\n >\n <slot name=\"triggerIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </slot>\n </AutocompleteTrigger>\n </AutocompleteAnchor>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"AutocompleteInput.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/autocomplete/AutocompleteInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, useTemplateRef } from 'vue'\nimport { useFocusWithin } from '@vueuse/core'\nimport { AutocompleteInput, AutocompleteTrigger, AutocompleteCancel, AutocompleteAnchor } from 'reka-ui'\nimport { useAutocompleteInject } from './Autocomplete.context'\nimport Chip from '../chip/Chip.vue'\nimport Spinner from '../spinner/Spinner.vue'\nimport AutocompleteOverflowChips from './AutocompleteOverflowChips.vue'\n\nconst props = withDefaults(defineProps<{\n placeholder?: string\n class?: string\n}>(), {\n placeholder: undefined,\n class: undefined,\n})\n\nconst ctx = useAutocompleteInject()\n\n// Track focused state via useFocusWithin (NOT manual @focus/@blur listeners) — the\n// inner Reka <AutocompleteInput> wraps the native <input>; useFocusWithin observes\n// the actual DOM subtree of the anchor, so isFocused flips reliably regardless of\n// how Reka forwards refs/attrs.\nconst anchorRef = useTemplateRef<HTMLElement>('anchor')\nconst { focused: isFocused } = useFocusWithin(anchorRef)\n\n// Render the inside-label only when (a) a label is set and (b) labelPlacement is 'inside'\nconst showInsideLabel = computed(\n () => ctx.hasLabel.value && ctx.labelPlacement.value === 'inside',\n)\n\n// In multiple mode, hide placeholder once chips are present\nconst effectivePlaceholder = computed(() =>\n ctx.multiple.value && ctx.selectedValues.value.length > 0 ? undefined : props.placeholder,\n)\n\nconst getLabel = (v: string) => ctx.selectedLabels.value.find(l => l.value === v)?.label ?? v\n</script>\n\n<template>\n <AutocompleteAnchor\n ref=\"anchor\"\n :class=\"ctx.slots.value.trigger()\"\n :data-filled=\"ctx.hasLabel.value ? (ctx.isFilled.value || undefined) : undefined\"\n :data-focused=\"isFocused || undefined\"\n :data-invalid=\"ctx.isInvalid.value || undefined\"\n :data-disabled=\"ctx.isDisabled.value || undefined\"\n :data-readonly=\"ctx.isReadonly.value || undefined\"\n :data-multiple-overflow=\"ctx.multiple.value ? ctx.multipleOverflow.value : undefined\"\n data-slot=\"trigger\"\n >\n <label\n v-if=\"showInsideLabel\"\n :for=\"ctx.inputId.value\"\n :class=\"ctx.slots.value.label()\"\n >{{ ctx.label.value }}<span\n v-if=\"ctx.isRequired.value\"\n aria-hidden=\"true\"\n > *</span></label>\n <span\n v-if=\"$slots.startContent\"\n :class=\"ctx.slots.value.startContent()\"\n data-slot=\"start-content\"\n >\n <slot name=\"startContent\" />\n </span>\n <!-- Multiple/collapse: overflow chip area with truncation -->\n <AutocompleteOverflowChips\n v-if=\"ctx.multiple.value && ctx.multipleOverflow.value === 'collapse' && ctx.selectedValues.value.length > 0\"\n :values=\"ctx.selectedValues.value\"\n :get-label=\"getLabel\"\n :remove-value=\"ctx.removeValue\"\n />\n <!-- Multiple/wrap: chips that wrap onto new lines -->\n <template v-else-if=\"ctx.multiple.value && ctx.multipleOverflow.value === 'wrap'\">\n <Chip\n v-for=\"item in ctx.selectedLabels.value\"\n :key=\"item.value\"\n size=\"sm\"\n is-closable\n :close-aria-label=\"`Remove ${item.label}`\"\n data-slot=\"selected-chip\"\n @close.stop=\"ctx.removeValue(item.value)\"\n >\n {{ item.label }}\n </Chip>\n </template>\n <AutocompleteInput\n :id=\"ctx.inputId.value\"\n :placeholder=\"effectivePlaceholder\"\n :disabled=\"ctx.isDisabled.value\"\n :readonly=\"ctx.isReadonly.value\"\n :required=\"ctx.isRequired.value\"\n :aria-invalid=\"ctx.isInvalid.value || undefined\"\n :aria-describedby=\"ctx.ariaDescribedBy.value\"\n :class=\"ctx.slots.value.input()\"\n :style=\"ctx.multiple.value && ctx.multipleOverflow.value === 'collapse' && ctx.selectedValues.value.length > 0\n ? { flex: '0 0 auto', minWidth: '80px', width: 'auto' }\n : undefined\"\n data-slot=\"input\"\n autocomplete=\"off\"\n />\n <!-- Clear button: only shown when filled and not in a readonly/disabled state.\n Reka's AutocompleteCancel does not set data-empty itself, so we drive it here.\n In multiple mode also clears selectedValues via ctx.clearAll(). -->\n <AutocompleteCancel\n :class=\"ctx.slots.value.clearButton()\"\n :data-empty=\"(!ctx.isFilled.value || ctx.isReadonly.value || ctx.isDisabled.value) ? 'true' : undefined\"\n data-slot=\"clear-button\"\n aria-label=\"Clear\"\n @click=\"ctx.multiple.value ? ctx.clearAll() : undefined\"\n >\n <slot name=\"clearIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"autocomplete-clear-button-icon\"\n aria-hidden=\"true\"\n >\n <line\n x1=\"18\"\n y1=\"6\"\n x2=\"6\"\n y2=\"18\"\n />\n <line\n x1=\"6\"\n y1=\"6\"\n x2=\"18\"\n y2=\"18\"\n />\n </svg>\n </slot>\n </AutocompleteCancel>\n <!-- Inline loading spinner: replaces the dropdown indicator while loadItems is pending -->\n <span\n v-if=\"ctx.isLoading.value\"\n :class=\"ctx.slots.value.indicator()\"\n data-slot=\"autocomplete-loading-indicator\"\n role=\"status\"\n aria-live=\"polite\"\n aria-label=\"Loading suggestions\"\n >\n <Spinner size=\"sm\" />\n </span>\n <!-- Dropdown trigger indicator (hidden while loading) -->\n <AutocompleteTrigger\n v-else\n :class=\"ctx.slots.value.indicator()\"\n data-slot=\"autocomplete-default-indicator\"\n aria-label=\"Toggle suggestions\"\n >\n <slot name=\"triggerIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </slot>\n </AutocompleteTrigger>\n </AutocompleteAnchor>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AutocompleteItem.js","names":[],"sources":["../../../src/components/autocomplete/AutocompleteItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, useSlots, type Slots, type VNode } from 'vue'\nimport { AutocompleteItem, ComboboxItemIndicator } from 'reka-ui'\nimport { useAutocompleteInject } from './Autocomplete.context'\n\nconst props = withDefaults(defineProps<{\n value: string\n isDisabled?: boolean\n class?: string\n}>(), {\n isDisabled: false,\n class: undefined,\n})\n\nconst slots: Slots = useSlots()\nconst ctx = useAutocompleteInject()\n\n// Extract plain text from default slot VNodes at render time.\nfunction extractText(nodes: VNode[]): string {\n return nodes.map(n => {\n if (typeof n.children === 'string') return n.children\n if (Array.isArray(n.children)) return extractText(n.children as VNode[])\n return ''\n }).join('')\n}\n\n// The display text Reka writes into the input when this item is selected.\n// Reads slot text content — no extra props needed.\nconst displayText = computed((): string => {\n const vnodes: VNode[] | undefined = (slots.default as (() => VNode[]) | undefined)?.()\n if (!vnodes) return props.value\n return extractText(vnodes).trim() || props.value\n})\n\n// Register this item's value→label mapping with the parent Autocomplete bridge\n// so valueFor() can translate the display label back to the real value.\nonMounted(() => {\n ctx.registerItem(props.value, displayText.value)\n})\n\nonUnmounted(() => {\n ctx.unregisterItem(props.value)\n})\n</script>\n\n<template>\n <AutocompleteItem\n :value=\"displayText\"\n :text-value=\"displayText\"\n :disabled=\"props.isDisabled\"\n :data-item-value=\"props.value\"\n class=\"list-box-item list-box-item--default\"\n data-slot=\"list-box-item\"\n >\n <slot name=\"startContent\" />\n <span\n class=\"autocomplete-item__text\"\n data-slot=\"item-text\"\n ><slot /></span>\n <ComboboxItemIndicator\n class=\"list-box-item__indicator\"\n data-slot=\"list-box-item-indicator\"\n >\n <slot name=\"selectedIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"list-box-item-indicator--checkmark\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </slot>\n </ComboboxItemIndicator>\n <slot name=\"endContent\" />\n </AutocompleteItem>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"AutocompleteItem.js","names":[],"sources":["../../../src/components/autocomplete/AutocompleteItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, useSlots, type Slots, type VNode } from 'vue'\nimport { AutocompleteItem, ComboboxItemIndicator } from 'reka-ui'\nimport { useAutocompleteInject } from './Autocomplete.context'\n\nconst props = withDefaults(defineProps<{\n value: string\n isDisabled?: boolean\n class?: string\n}>(), {\n isDisabled: false,\n class: undefined,\n})\n\nconst slots: Slots = useSlots()\nconst ctx = useAutocompleteInject()\n\nfunction extractText(nodes: VNode[]): string {\n return nodes.map(n => {\n if (typeof n.children === 'string') return n.children\n if (Array.isArray(n.children)) return extractText(n.children as VNode[])\n return ''\n }).join('')\n}\n\nconst displayText = computed((): string => {\n const vnodes: VNode[] | undefined = (slots.default as (() => VNode[]) | undefined)?.()\n if (!vnodes) return props.value\n return extractText(vnodes).trim() || props.value\n})\n\n// In multiple mode, track whether this item is in the selected array\nconst isChecked = computed(() => ctx.multiple.value && ctx.isSelected(props.value))\n\nonMounted(() => {\n ctx.registerItem(props.value, displayText.value)\n})\n\nonUnmounted(() => {\n ctx.unregisterItem(props.value)\n})\n\nfunction handleSelect(event: Event) {\n if (ctx.multiple.value) {\n // Prevent Reka from overwriting the combobox value with the selected item's text.\n // Without this, Reka's internal handler fires after ours and sets searchTerm = displayText.\n event.preventDefault()\n ctx.onMultipleSelect(props.value)\n }\n}\n</script>\n\n<template>\n <AutocompleteItem\n :value=\"displayText\"\n :text-value=\"displayText\"\n :disabled=\"props.isDisabled\"\n :data-item-value=\"props.value\"\n :data-selected=\"isChecked || undefined\"\n class=\"list-box-item list-box-item--default\"\n data-slot=\"list-box-item\"\n @select=\"handleSelect\"\n >\n <slot name=\"startContent\" />\n <span\n class=\"autocomplete-item__text\"\n data-slot=\"item-text\"\n ><slot /></span>\n <!-- Single mode: Reka's ComboboxItemIndicator handles the checkmark natively -->\n <ComboboxItemIndicator\n v-if=\"!ctx.multiple.value\"\n class=\"list-box-item__indicator\"\n data-slot=\"list-box-item-indicator\"\n >\n <slot name=\"selectedIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"list-box-item-indicator--checkmark\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </slot>\n </ComboboxItemIndicator>\n <!-- Multiple mode: check against our selectedValues array instead -->\n <span\n v-else-if=\"isChecked\"\n class=\"list-box-item__indicator\"\n data-slot=\"list-box-item-indicator\"\n >\n <slot name=\"selectedIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"list-box-item-indicator--checkmark\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </slot>\n </span>\n <slot name=\"endContent\" />\n </AutocompleteItem>\n</template>\n"],"mappings":""}
@@ -1,11 +1,16 @@
1
1
  import { useAutocompleteInject } from "./Autocomplete.context.js";
2
- import { computed, createBlock, createElementVNode, createVNode, defineComponent, onMounted, onUnmounted, openBlock, renderSlot, unref, useSlots, withCtx } from "vue";
2
+ import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, onMounted, onUnmounted, openBlock, renderSlot, unref, useSlots, withCtx } from "vue";
3
3
  import { AutocompleteItem, ComboboxItemIndicator } from "reka-ui";
4
4
  //#region src/components/autocomplete/AutocompleteItem.vue?vue&type=script&setup=true&lang.ts
5
5
  var _hoisted_1 = {
6
6
  class: "autocomplete-item__text",
7
7
  "data-slot": "item-text"
8
8
  };
9
+ var _hoisted_2 = {
10
+ key: 1,
11
+ class: "list-box-item__indicator",
12
+ "data-slot": "list-box-item-indicator"
13
+ };
9
14
  var AutocompleteItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
10
15
  __name: "AutocompleteItem",
11
16
  props: {
@@ -32,25 +37,35 @@ var AutocompleteItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
32
37
  if (!vnodes) return props.value;
33
38
  return extractText(vnodes).trim() || props.value;
34
39
  });
40
+ const isChecked = computed(() => ctx.multiple.value && ctx.isSelected(props.value));
35
41
  onMounted(() => {
36
42
  ctx.registerItem(props.value, displayText.value);
37
43
  });
38
44
  onUnmounted(() => {
39
45
  ctx.unregisterItem(props.value);
40
46
  });
47
+ function handleSelect(event) {
48
+ if (ctx.multiple.value) {
49
+ event.preventDefault();
50
+ ctx.onMultipleSelect(props.value);
51
+ }
52
+ }
41
53
  return (_ctx, _cache) => {
42
54
  return openBlock(), createBlock(unref(AutocompleteItem), {
43
55
  value: displayText.value,
44
56
  "text-value": displayText.value,
45
57
  disabled: props.isDisabled,
46
58
  "data-item-value": props.value,
59
+ "data-selected": isChecked.value || void 0,
47
60
  class: "list-box-item list-box-item--default",
48
- "data-slot": "list-box-item"
61
+ "data-slot": "list-box-item",
62
+ onSelect: handleSelect
49
63
  }, {
50
64
  default: withCtx(() => [
51
65
  renderSlot(_ctx.$slots, "startContent"),
52
66
  createElementVNode("span", _hoisted_1, [renderSlot(_ctx.$slots, "default")]),
53
- createVNode(unref(ComboboxItemIndicator), {
67
+ !unref(ctx).multiple.value ? (openBlock(), createBlock(unref(ComboboxItemIndicator), {
68
+ key: 0,
54
69
  class: "list-box-item__indicator",
55
70
  "data-slot": "list-box-item-indicator"
56
71
  }, {
@@ -68,7 +83,19 @@ var AutocompleteItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
68
83
  "aria-hidden": "true"
69
84
  }, [createElementVNode("polyline", { points: "20 6 9 17 4 12" })], -1))])]),
70
85
  _: 3
71
- }),
86
+ })) : isChecked.value ? (openBlock(), createElementBlock("span", _hoisted_2, [renderSlot(_ctx.$slots, "selectedIcon", {}, () => [_cache[1] || (_cache[1] = createElementVNode("svg", {
87
+ xmlns: "http://www.w3.org/2000/svg",
88
+ width: "12",
89
+ height: "12",
90
+ viewBox: "0 0 24 24",
91
+ fill: "none",
92
+ stroke: "currentColor",
93
+ "stroke-width": "3",
94
+ "stroke-linecap": "round",
95
+ "stroke-linejoin": "round",
96
+ "data-slot": "list-box-item-indicator--checkmark",
97
+ "aria-hidden": "true"
98
+ }, [createElementVNode("polyline", { points: "20 6 9 17 4 12" })], -1))])])) : createCommentVNode("", true),
72
99
  renderSlot(_ctx.$slots, "endContent")
73
100
  ]),
74
101
  _: 3
@@ -76,7 +103,8 @@ var AutocompleteItem_vue_vue_type_script_setup_true_lang_default = /* @__PURE__
76
103
  "value",
77
104
  "text-value",
78
105
  "disabled",
79
- "data-item-value"
106
+ "data-item-value",
107
+ "data-selected"
80
108
  ]);
81
109
  };
82
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AutocompleteItem.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/autocomplete/AutocompleteItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, useSlots, type Slots, type VNode } from 'vue'\nimport { AutocompleteItem, ComboboxItemIndicator } from 'reka-ui'\nimport { useAutocompleteInject } from './Autocomplete.context'\n\nconst props = withDefaults(defineProps<{\n value: string\n isDisabled?: boolean\n class?: string\n}>(), {\n isDisabled: false,\n class: undefined,\n})\n\nconst slots: Slots = useSlots()\nconst ctx = useAutocompleteInject()\n\n// Extract plain text from default slot VNodes at render time.\nfunction extractText(nodes: VNode[]): string {\n return nodes.map(n => {\n if (typeof n.children === 'string') return n.children\n if (Array.isArray(n.children)) return extractText(n.children as VNode[])\n return ''\n }).join('')\n}\n\n// The display text Reka writes into the input when this item is selected.\n// Reads slot text content — no extra props needed.\nconst displayText = computed((): string => {\n const vnodes: VNode[] | undefined = (slots.default as (() => VNode[]) | undefined)?.()\n if (!vnodes) return props.value\n return extractText(vnodes).trim() || props.value\n})\n\n// Register this item's value→label mapping with the parent Autocomplete bridge\n// so valueFor() can translate the display label back to the real value.\nonMounted(() => {\n ctx.registerItem(props.value, displayText.value)\n})\n\nonUnmounted(() => {\n ctx.unregisterItem(props.value)\n})\n</script>\n\n<template>\n <AutocompleteItem\n :value=\"displayText\"\n :text-value=\"displayText\"\n :disabled=\"props.isDisabled\"\n :data-item-value=\"props.value\"\n class=\"list-box-item list-box-item--default\"\n data-slot=\"list-box-item\"\n >\n <slot name=\"startContent\" />\n <span\n class=\"autocomplete-item__text\"\n data-slot=\"item-text\"\n ><slot /></span>\n <ComboboxItemIndicator\n class=\"list-box-item__indicator\"\n data-slot=\"list-box-item-indicator\"\n >\n <slot name=\"selectedIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"list-box-item-indicator--checkmark\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </slot>\n </ComboboxItemIndicator>\n <slot name=\"endContent\" />\n </AutocompleteItem>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;EAKA,MAAM,QAAQ;EASd,MAAM,QAAe,UAAS;EAC9B,MAAM,MAAM,uBAAsB;EAGlC,SAAS,YAAY,OAAwB;AAC3C,UAAO,MAAM,KAAI,MAAK;AACpB,QAAI,OAAO,EAAE,aAAa,SAAU,QAAO,EAAE;AAC7C,QAAI,MAAM,QAAQ,EAAE,SAAS,CAAE,QAAO,YAAY,EAAE,SAAmB;AACvE,WAAO;KACP,CAAC,KAAK,GAAE;;EAKZ,MAAM,cAAc,eAAuB;GACzC,MAAM,SAA+B,MAAM,WAA0C;AACrF,OAAI,CAAC,OAAQ,QAAO,MAAM;AAC1B,UAAO,YAAY,OAAO,CAAC,MAAM,IAAI,MAAM;IAC5C;AAID,kBAAgB;AACd,OAAI,aAAa,MAAM,OAAO,YAAY,MAAK;IAChD;AAED,oBAAkB;AAChB,OAAI,eAAe,MAAM,MAAK;IAC/B;;uBAIC,YAoCmB,MAAA,iBAAA,EAAA;IAnChB,OAAO,YAAA;IACP,cAAY,YAAA;IACZ,UAAU,MAAM;IAChB,mBAAiB,MAAM;IACxB,OAAM;IACN,aAAU;;2BAEkB;KAA5B,WAA4B,KAAA,QAAA,eAAA;KAC5B,mBAGgB,QAHhB,YAGgB,CAAf,WAAQ,KAAA,QAAA,UAAA,CAAA,CAAA;KACT,YAqBwB,MAAA,sBAAA,EAAA;MApBtB,OAAM;MACN,aAAU;;6BAkBH,CAhBP,WAgBO,KAAA,QAAA,gBAAA,EAAA,QAAA,CAAA,OAAA,OAAA,OAAA,KAfL,mBAcM,OAAA;OAbJ,OAAM;OACN,OAAM;OACN,QAAO;OACP,SAAQ;OACR,MAAK;OACL,QAAO;OACP,gBAAa;OACb,kBAAe;OACf,mBAAgB;OAChB,aAAU;OACV,eAAY;UAEZ,mBAAoC,YAAA,EAA1B,QAAO,kBAAgB,CAAA,CAAA,EAAA,GAAA,EAAA,CAAA,CAAA,CAAA;;;KAIvC,WAA0B,KAAA,QAAA,aAAA"}
1
+ {"version":3,"file":"AutocompleteItem.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/autocomplete/AutocompleteItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onMounted, onUnmounted, useSlots, type Slots, type VNode } from 'vue'\nimport { AutocompleteItem, ComboboxItemIndicator } from 'reka-ui'\nimport { useAutocompleteInject } from './Autocomplete.context'\n\nconst props = withDefaults(defineProps<{\n value: string\n isDisabled?: boolean\n class?: string\n}>(), {\n isDisabled: false,\n class: undefined,\n})\n\nconst slots: Slots = useSlots()\nconst ctx = useAutocompleteInject()\n\nfunction extractText(nodes: VNode[]): string {\n return nodes.map(n => {\n if (typeof n.children === 'string') return n.children\n if (Array.isArray(n.children)) return extractText(n.children as VNode[])\n return ''\n }).join('')\n}\n\nconst displayText = computed((): string => {\n const vnodes: VNode[] | undefined = (slots.default as (() => VNode[]) | undefined)?.()\n if (!vnodes) return props.value\n return extractText(vnodes).trim() || props.value\n})\n\n// In multiple mode, track whether this item is in the selected array\nconst isChecked = computed(() => ctx.multiple.value && ctx.isSelected(props.value))\n\nonMounted(() => {\n ctx.registerItem(props.value, displayText.value)\n})\n\nonUnmounted(() => {\n ctx.unregisterItem(props.value)\n})\n\nfunction handleSelect(event: Event) {\n if (ctx.multiple.value) {\n // Prevent Reka from overwriting the combobox value with the selected item's text.\n // Without this, Reka's internal handler fires after ours and sets searchTerm = displayText.\n event.preventDefault()\n ctx.onMultipleSelect(props.value)\n }\n}\n</script>\n\n<template>\n <AutocompleteItem\n :value=\"displayText\"\n :text-value=\"displayText\"\n :disabled=\"props.isDisabled\"\n :data-item-value=\"props.value\"\n :data-selected=\"isChecked || undefined\"\n class=\"list-box-item list-box-item--default\"\n data-slot=\"list-box-item\"\n @select=\"handleSelect\"\n >\n <slot name=\"startContent\" />\n <span\n class=\"autocomplete-item__text\"\n data-slot=\"item-text\"\n ><slot /></span>\n <!-- Single mode: Reka's ComboboxItemIndicator handles the checkmark natively -->\n <ComboboxItemIndicator\n v-if=\"!ctx.multiple.value\"\n class=\"list-box-item__indicator\"\n data-slot=\"list-box-item-indicator\"\n >\n <slot name=\"selectedIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"list-box-item-indicator--checkmark\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </slot>\n </ComboboxItemIndicator>\n <!-- Multiple mode: check against our selectedValues array instead -->\n <span\n v-else-if=\"isChecked\"\n class=\"list-box-item__indicator\"\n data-slot=\"list-box-item-indicator\"\n >\n <slot name=\"selectedIcon\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n data-slot=\"list-box-item-indicator--checkmark\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n </slot>\n </span>\n <slot name=\"endContent\" />\n </AutocompleteItem>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;EAKA,MAAM,QAAQ;EASd,MAAM,QAAe,UAAS;EAC9B,MAAM,MAAM,uBAAsB;EAElC,SAAS,YAAY,OAAwB;AAC3C,UAAO,MAAM,KAAI,MAAK;AACpB,QAAI,OAAO,EAAE,aAAa,SAAU,QAAO,EAAE;AAC7C,QAAI,MAAM,QAAQ,EAAE,SAAS,CAAE,QAAO,YAAY,EAAE,SAAmB;AACvE,WAAO;KACP,CAAC,KAAK,GAAE;;EAGZ,MAAM,cAAc,eAAuB;GACzC,MAAM,SAA+B,MAAM,WAA0C;AACrF,OAAI,CAAC,OAAQ,QAAO,MAAM;AAC1B,UAAO,YAAY,OAAO,CAAC,MAAM,IAAI,MAAM;IAC5C;EAGD,MAAM,YAAY,eAAe,IAAI,SAAS,SAAS,IAAI,WAAW,MAAM,MAAM,CAAA;AAElF,kBAAgB;AACd,OAAI,aAAa,MAAM,OAAO,YAAY,MAAK;IAChD;AAED,oBAAkB;AAChB,OAAI,eAAe,MAAM,MAAK;IAC/B;EAED,SAAS,aAAa,OAAc;AAClC,OAAI,IAAI,SAAS,OAAO;AAGtB,UAAM,gBAAe;AACrB,QAAI,iBAAiB,MAAM,MAAK;;;;uBAMlC,YAgEmB,MAAA,iBAAA,EAAA;IA/DhB,OAAO,YAAA;IACP,cAAY,YAAA;IACZ,UAAU,MAAM;IAChB,mBAAiB,MAAM;IACvB,iBAAe,UAAA,SAAa,KAAA;IAC7B,OAAM;IACN,aAAU;IACT,UAAQ;;2BAEmB;KAA5B,WAA4B,KAAA,QAAA,eAAA;KAC5B,mBAGgB,QAHhB,YAGgB,CAAf,WAAQ,KAAA,QAAA,UAAA,CAAA,CAAA;MAGA,MAAA,IAAG,CAAC,SAAS,SAAA,WAAA,EADtB,YAsBwB,MAAA,sBAAA,EAAA;;MApBtB,OAAM;MACN,aAAU;;6BAkBH,CAhBP,WAgBO,KAAA,QAAA,gBAAA,EAAA,QAAA,CAAA,OAAA,OAAA,OAAA,KAfL,mBAcM,OAAA;OAbJ,OAAM;OACN,OAAM;OACN,QAAO;OACP,SAAQ;OACR,MAAK;OACL,QAAO;OACP,gBAAa;OACb,kBAAe;OACf,mBAAgB;OAChB,aAAU;OACV,eAAY;UAEZ,mBAAoC,YAAA,EAA1B,QAAO,kBAAgB,CAAA,CAAA,EAAA,GAAA,EAAA,CAAA,CAAA,CAAA;;WAM1B,UAAA,SAAA,WAAA,EADb,mBAsBO,QAtBP,YAsBO,CAjBL,WAgBO,KAAA,QAAA,gBAAA,EAAA,QAAA,CAAA,OAAA,OAAA,OAAA,KAfL,mBAcM,OAAA;MAbJ,OAAM;MACN,OAAM;MACN,QAAO;MACP,SAAQ;MACR,MAAK;MACL,QAAO;MACP,gBAAa;MACb,kBAAe;MACf,mBAAgB;MAChB,aAAU;MACV,eAAY;SAEZ,mBAAoC,YAAA,EAA1B,QAAO,kBAAgB,CAAA,CAAA,EAAA,GAAA,EAAA,CAAA,CAAA,CAAA,IAAA,mBAAA,IAAA,KAAA;KAIvC,WAA0B,KAAA,QAAA,aAAA"}
@@ -0,0 +1,7 @@
1
+ import AutocompleteOverflowChips_vue_vue_type_script_setup_true_lang_default from "./AutocompleteOverflowChips.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/components/autocomplete/AutocompleteOverflowChips.vue
3
+ var AutocompleteOverflowChips_default = AutocompleteOverflowChips_vue_vue_type_script_setup_true_lang_default;
4
+ //#endregion
5
+ export { AutocompleteOverflowChips_default as default };
6
+
7
+ //# sourceMappingURL=AutocompleteOverflowChips.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AutocompleteOverflowChips.js","names":[],"sources":["../../../src/components/autocomplete/AutocompleteOverflowChips.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, nextTick, useTemplateRef, onMounted, watch } from 'vue'\nimport { useResizeObserver } from '@vueuse/core'\nimport Chip from '../chip/Chip.vue'\n\nconst props = defineProps<{\n values: string[]\n getLabel: (value: string) => string\n removeValue: (value: string) => void\n}>()\n\nconst containerEl = useTemplateRef<HTMLElement>('container')\nconst visibleCount = ref(props.values.length)\nconst overflowCount = computed(() => Math.max(0, props.values.length - visibleCount.value))\n\n// Prevents re-entrant reflows while we are in the async measurement phase.\nlet measuring = false\n\nasync function reflow() {\n if (measuring) return\n measuring = true\n\n try {\n const el = containerEl.value\n if (!el) return\n\n // Phase 1: show all chips to measure their natural widths\n visibleCount.value = props.values.length\n await nextTick()\n\n const chips = [...el.querySelectorAll<HTMLElement>('[data-chip-item]')]\n if (!chips.length) return\n\n const containerW = el.offsetWidth\n if (!containerW) return\n\n // BADGE_W = estimated chip width (68px) + CSS gap before it (4px).\n const BADGE_W = 76\n\n let usedW = 0\n let n = 0\n\n for (let i = 0; i < chips.length; i++) {\n const gap = i > 0 ? 4 : 0\n const chipW = chips[i].offsetWidth\n const isLast = i === chips.length - 1\n const budget = isLast ? containerW : containerW - BADGE_W\n\n if (usedW + gap + chipW > budget) break\n usedW += gap + chipW\n n++\n }\n\n visibleCount.value = Math.max(1, n)\n } finally {\n measuring = false\n }\n}\n\nonMounted(reflow)\nuseResizeObserver(containerEl, reflow)\nwatch(\n () => props.values.join('\\x00'),\n () => reflow(),\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n ref=\"container\"\n style=\"display: flex; flex-wrap: nowrap; align-items: center; gap: 4px; overflow: hidden; flex: 1; min-width: 0;\"\n >\n <Chip\n v-for=\"(val, i) in values\"\n :key=\"val\"\n data-chip-item\n size=\"sm\"\n is-closable\n :style=\"i >= visibleCount ? 'display: none' : undefined\"\n @close.stop=\"removeValue(val)\"\n >\n {{ getLabel(val) }}\n </Chip>\n <Chip\n v-if=\"overflowCount > 0\"\n size=\"sm\"\n color=\"default\"\n >\n +{{ overflowCount }} more\n </Chip>\n </div>\n</template>\n"],"mappings":""}
@@ -0,0 +1,88 @@
1
+ import Chip_default from "../chip/Chip.js";
2
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, defineComponent, nextTick, normalizeStyle, onMounted, openBlock, ref, renderList, toDisplayString, useTemplateRef, watch, withCtx, withModifiers } from "vue";
3
+ import { useResizeObserver } from "@vueuse/core";
4
+ //#region src/components/autocomplete/AutocompleteOverflowChips.vue?vue&type=script&setup=true&lang.ts
5
+ var _hoisted_1 = {
6
+ ref: "container",
7
+ style: {
8
+ "display": "flex",
9
+ "flex-wrap": "nowrap",
10
+ "align-items": "center",
11
+ "gap": "4px",
12
+ "overflow": "hidden",
13
+ "flex": "1",
14
+ "min-width": "0"
15
+ }
16
+ };
17
+ var AutocompleteOverflowChips_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
18
+ __name: "AutocompleteOverflowChips",
19
+ props: {
20
+ values: {},
21
+ getLabel: { type: Function },
22
+ removeValue: { type: Function }
23
+ },
24
+ setup(__props) {
25
+ const props = __props;
26
+ const containerEl = useTemplateRef("container");
27
+ const visibleCount = ref(props.values.length);
28
+ const overflowCount = computed(() => Math.max(0, props.values.length - visibleCount.value));
29
+ let measuring = false;
30
+ async function reflow() {
31
+ if (measuring) return;
32
+ measuring = true;
33
+ try {
34
+ const el = containerEl.value;
35
+ if (!el) return;
36
+ visibleCount.value = props.values.length;
37
+ await nextTick();
38
+ const chips = [...el.querySelectorAll("[data-chip-item]")];
39
+ if (!chips.length) return;
40
+ const containerW = el.offsetWidth;
41
+ if (!containerW) return;
42
+ const BADGE_W = 76;
43
+ let usedW = 0;
44
+ let n = 0;
45
+ for (let i = 0; i < chips.length; i++) {
46
+ const gap = i > 0 ? 4 : 0;
47
+ const chipW = chips[i].offsetWidth;
48
+ const budget = i === chips.length - 1 ? containerW : containerW - BADGE_W;
49
+ if (usedW + gap + chipW > budget) break;
50
+ usedW += gap + chipW;
51
+ n++;
52
+ }
53
+ visibleCount.value = Math.max(1, n);
54
+ } finally {
55
+ measuring = false;
56
+ }
57
+ }
58
+ onMounted(reflow);
59
+ useResizeObserver(containerEl, reflow);
60
+ watch(() => props.values.join("\0"), () => reflow(), { flush: "post" });
61
+ return (_ctx, _cache) => {
62
+ return openBlock(), createElementBlock("div", _hoisted_1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.values, (val, i) => {
63
+ return openBlock(), createBlock(Chip_default, {
64
+ key: val,
65
+ "data-chip-item": "",
66
+ size: "sm",
67
+ "is-closable": "",
68
+ style: normalizeStyle(i >= visibleCount.value ? "display: none" : void 0),
69
+ onClose: withModifiers(($event) => __props.removeValue(val), ["stop"])
70
+ }, {
71
+ default: withCtx(() => [createTextVNode(toDisplayString(__props.getLabel(val)), 1)]),
72
+ _: 2
73
+ }, 1032, ["style", "onClose"]);
74
+ }), 128)), overflowCount.value > 0 ? (openBlock(), createBlock(Chip_default, {
75
+ key: 0,
76
+ size: "sm",
77
+ color: "default"
78
+ }, {
79
+ default: withCtx(() => [createTextVNode(" +" + toDisplayString(overflowCount.value) + " more ", 1)]),
80
+ _: 1
81
+ })) : createCommentVNode("", true)], 512);
82
+ };
83
+ }
84
+ });
85
+ //#endregion
86
+ export { AutocompleteOverflowChips_vue_vue_type_script_setup_true_lang_default as default };
87
+
88
+ //# sourceMappingURL=AutocompleteOverflowChips.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AutocompleteOverflowChips.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/autocomplete/AutocompleteOverflowChips.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, nextTick, useTemplateRef, onMounted, watch } from 'vue'\nimport { useResizeObserver } from '@vueuse/core'\nimport Chip from '../chip/Chip.vue'\n\nconst props = defineProps<{\n values: string[]\n getLabel: (value: string) => string\n removeValue: (value: string) => void\n}>()\n\nconst containerEl = useTemplateRef<HTMLElement>('container')\nconst visibleCount = ref(props.values.length)\nconst overflowCount = computed(() => Math.max(0, props.values.length - visibleCount.value))\n\n// Prevents re-entrant reflows while we are in the async measurement phase.\nlet measuring = false\n\nasync function reflow() {\n if (measuring) return\n measuring = true\n\n try {\n const el = containerEl.value\n if (!el) return\n\n // Phase 1: show all chips to measure their natural widths\n visibleCount.value = props.values.length\n await nextTick()\n\n const chips = [...el.querySelectorAll<HTMLElement>('[data-chip-item]')]\n if (!chips.length) return\n\n const containerW = el.offsetWidth\n if (!containerW) return\n\n // BADGE_W = estimated chip width (68px) + CSS gap before it (4px).\n const BADGE_W = 76\n\n let usedW = 0\n let n = 0\n\n for (let i = 0; i < chips.length; i++) {\n const gap = i > 0 ? 4 : 0\n const chipW = chips[i].offsetWidth\n const isLast = i === chips.length - 1\n const budget = isLast ? containerW : containerW - BADGE_W\n\n if (usedW + gap + chipW > budget) break\n usedW += gap + chipW\n n++\n }\n\n visibleCount.value = Math.max(1, n)\n } finally {\n measuring = false\n }\n}\n\nonMounted(reflow)\nuseResizeObserver(containerEl, reflow)\nwatch(\n () => props.values.join('\\x00'),\n () => reflow(),\n { flush: 'post' },\n)\n</script>\n\n<template>\n <div\n ref=\"container\"\n style=\"display: flex; flex-wrap: nowrap; align-items: center; gap: 4px; overflow: hidden; flex: 1; min-width: 0;\"\n >\n <Chip\n v-for=\"(val, i) in values\"\n :key=\"val\"\n data-chip-item\n size=\"sm\"\n is-closable\n :style=\"i >= visibleCount ? 'display: none' : undefined\"\n @close.stop=\"removeValue(val)\"\n >\n {{ getLabel(val) }}\n </Chip>\n <Chip\n v-if=\"overflowCount > 0\"\n size=\"sm\"\n color=\"default\"\n >\n +{{ overflowCount }} more\n </Chip>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;EAKA,MAAM,QAAQ;EAMd,MAAM,cAAc,eAA4B,YAAW;EAC3D,MAAM,eAAe,IAAI,MAAM,OAAO,OAAM;EAC5C,MAAM,gBAAgB,eAAe,KAAK,IAAI,GAAG,MAAM,OAAO,SAAS,aAAa,MAAM,CAAA;EAG1F,IAAI,YAAY;EAEhB,eAAe,SAAS;AACtB,OAAI,UAAW;AACf,eAAY;AAEZ,OAAI;IACF,MAAM,KAAK,YAAY;AACvB,QAAI,CAAC,GAAI;AAGT,iBAAa,QAAQ,MAAM,OAAO;AAClC,UAAM,UAAS;IAEf,MAAM,QAAQ,CAAC,GAAG,GAAG,iBAA8B,mBAAmB,CAAA;AACtE,QAAI,CAAC,MAAM,OAAQ;IAEnB,MAAM,aAAa,GAAG;AACtB,QAAI,CAAC,WAAY;IAGjB,MAAM,UAAU;IAEhB,IAAI,QAAQ;IACZ,IAAI,IAAI;AAER,SAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;KACrC,MAAM,MAAM,IAAI,IAAI,IAAI;KACxB,MAAM,QAAQ,MAAM,GAAG;KAEvB,MAAM,SADS,MAAM,MAAM,SAAS,IACZ,aAAa,aAAa;AAElD,SAAI,QAAQ,MAAM,QAAQ,OAAQ;AAClC,cAAS,MAAM;AACf;;AAGF,iBAAa,QAAQ,KAAK,IAAI,GAAG,EAAC;aAC1B;AACR,gBAAY;;;AAIhB,YAAU,OAAM;AAChB,oBAAkB,aAAa,OAAM;AACrC,cACQ,MAAM,OAAO,KAAK,KAAO,QACzB,QAAQ,EACd,EAAE,OAAO,QAAQ,CACnB;;uBAIE,mBAsBM,OAtBN,YAsBM,EAAA,UAAA,KAAA,EAlBJ,mBAUO,UAAA,MAAA,WATc,QAAA,SAAX,KAAK,MAAC;wBADhB,YAUO,cAAA;KARJ,KAAK;KACN,kBAAA;KACA,MAAK;KACL,eAAA;KACC,OAAK,eAAE,KAAK,aAAA,QAAY,kBAAqB,KAAA,EAAS;KACtD,SAAK,eAAA,WAAO,QAAA,YAAY,IAAG,EAAA,CAAA,OAAA,CAAA;;4BAET,CAAA,gBAAA,gBAAhB,QAAA,SAAS,IAAG,CAAA,EAAA,EAAA,CAAA,CAAA;;;cAGT,cAAA,QAAa,KAAA,WAAA,EADrB,YAMO,cAAA;;IAJL,MAAK;IACL,OAAM;;2BAEL,CAAA,gBADF,OACE,gBAAG,cAAA,MAAa,GAAG,UACtB,EAAA,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Form.js","names":[],"sources":["../../../src/components/form/Form.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, provide } from 'vue'\nimport { formContextKey } from './form.context'\nimport { runValidation } from './validation'\nimport type { ValidationMode, FieldRegistration, FormContext } from './form.context'\n\nconst props = withDefaults(\n defineProps<{\n validationMode?: ValidationMode\n isDisabled?: boolean\n class?: string\n }>(),\n {\n validationMode: 'on-submit',\n isDisabled: false,\n class: undefined,\n },\n)\n\nconst emit = defineEmits<{\n submit: [payload: { values: Record<string, unknown>; setErrors: (e: Record<string, string>) => void }]\n invalid: [errors: Record<string, string>]\n}>()\n\nconst errors = ref<Record<string, string>>({})\nconst isSubmitting = ref(false)\nconst fields = new Map<string, FieldRegistration>()\n\nfunction registerField(reg: FieldRegistration): void {\n fields.set(reg.name, reg)\n}\n\nfunction unregisterField(name: string): void {\n fields.delete(name)\n const next = { ...errors.value }\n delete next[name]\n errors.value = next\n}\n\nasync function triggerFieldValidation(name: string): Promise<void> {\n const field = fields.get(name)\n if (!field) return\n const error = await runValidation(field.getValue(), field.rules, field.validate)\n const next = { ...errors.value }\n if (error) {\n next[name] = error\n } else {\n delete next[name]\n }\n errors.value = next\n}\n\nfunction setErrors(newErrors: Record<string, string>): void {\n errors.value = { ...errors.value, ...newErrors }\n isSubmitting.value = false\n}\n\nasync function handleSubmit(): Promise<void> {\n isSubmitting.value = true\n\n const results = await Promise.all(\n [...fields.entries()].map(async ([name, field]) => {\n const error = await runValidation(field.getValue(), field.rules, field.validate)\n return { name, error }\n }),\n )\n\n const nextErrors: Record<string, string> = {}\n for (const { name, error } of results) {\n if (error) nextErrors[name] = error\n }\n\n if (Object.keys(nextErrors).length > 0) {\n errors.value = nextErrors\n isSubmitting.value = false\n emit('invalid', nextErrors)\n return\n }\n\n errors.value = {}\n\n const values: Record<string, unknown> = {}\n for (const [name, field] of fields.entries()) {\n values[name] = field.getValue()\n }\n\n emit('submit', { values, setErrors })\n}\n\nconst ctx: FormContext = {\n errors,\n isSubmitting,\n isDisabled: computed(() => props.isDisabled),\n validationMode: computed(() => props.validationMode),\n registerField,\n unregisterField,\n triggerFieldValidation,\n setErrors,\n}\n\nprovide(formContextKey, ctx)\n</script>\n\n<template>\n <form\n :class=\"props.class\"\n novalidate\n @submit.prevent=\"handleSubmit\"\n >\n <slot\n :is-submitting=\"isSubmitting\"\n :is-disabled=\"props.isDisabled\"\n :errors=\"errors\"\n />\n </form>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"Form.js","names":[],"sources":["../../../src/components/form/Form.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, provide } from 'vue'\nimport { formContextKey } from './form.context'\nimport { runValidation } from './validation'\nimport type { ValidationMode, FieldRegistration, FormContext } from './form.context'\n\nconst props = withDefaults(\n defineProps<{\n validationMode?: ValidationMode\n isDisabled?: boolean\n class?: string\n }>(),\n {\n validationMode: 'on-submit',\n isDisabled: false,\n class: undefined,\n },\n)\n\nconst emit = defineEmits<{\n submit: [payload: { values: Record<string, unknown>; setErrors: (e: Record<string, string>) => void }]\n invalid: [errors: Record<string, string>]\n reset: []\n}>()\n\nconst errors = ref<Record<string, string>>({})\nconst isSubmitting = ref(false)\nconst isSubmitted = ref(false)\nconst submitCount = ref(0)\nconst fields = new Map<string, FieldRegistration>()\n\n// Reactive field count so computed properties re-evaluate when fields register/unregister\nconst fieldCount = ref(0)\n\nfunction registerField(reg: FieldRegistration): void {\n fields.set(reg.name, reg)\n fieldCount.value++\n}\n\nfunction unregisterField(name: string): void {\n fields.delete(name)\n fieldCount.value--\n const next = { ...errors.value }\n delete next[name]\n errors.value = next\n}\n\n// ── Computed state ──────────────────────────────────────────────────────────\n\nconst isValid = computed(() => {\n void fieldCount.value // track reactivity\n return Object.keys(errors.value).length === 0\n})\n\nconst isDirty = computed(() => {\n void fieldCount.value\n for (const field of fields.values()) {\n if (field.dirty.value) return true\n }\n return false\n})\n\nconst isTouched = computed(() => {\n void fieldCount.value\n for (const field of fields.values()) {\n if (field.touched.value) return true\n }\n return false\n})\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nfunction getAllValues(): Record<string, unknown> {\n const values: Record<string, unknown> = {}\n for (const [name, field] of fields.entries()) {\n values[name] = field.getValue()\n }\n return values\n}\n\n// ── Validation ───────────────────────────────────────────────────────────────\n\nasync function triggerFieldValidation(name: string): Promise<void> {\n const field = fields.get(name)\n if (!field) return\n const error = await runValidation(\n field.getValue(),\n field.rules,\n field.validate,\n { values: getAllValues() },\n )\n const next = { ...errors.value }\n if (error) {\n next[name] = error\n } else {\n delete next[name]\n }\n errors.value = next\n}\n\nasync function trigger(name?: string): Promise<boolean> {\n if (name) {\n await triggerFieldValidation(name)\n return !errors.value[name]\n }\n\n const results = await Promise.all(\n [...fields.entries()].map(async ([fieldName, field]) => {\n const error = await runValidation(\n field.getValue(),\n field.rules,\n field.validate,\n { values: getAllValues() },\n )\n return { name: fieldName, error }\n }),\n )\n\n const next: Record<string, string> = {}\n for (const { name: fieldName, error } of results) {\n if (error) next[fieldName] = error\n }\n errors.value = next\n return Object.keys(next).length === 0\n}\n\n// ── Error management ─────────────────────────────────────────────────────────\n\nfunction setErrors(newErrors: Record<string, string>): void {\n errors.value = { ...errors.value, ...newErrors }\n isSubmitting.value = false\n}\n\nfunction setError(name: string, message: string): void {\n errors.value = { ...errors.value, [name]: message }\n}\n\nfunction clearErrors(name?: string): void {\n if (name) {\n const next = { ...errors.value }\n delete next[name]\n errors.value = next\n } else {\n errors.value = {}\n }\n}\n\n// ── Values ───────────────────────────────────────────────────────────────────\n\nfunction getValues(): Record<string, unknown> {\n return getAllValues()\n}\n\nfunction setValue(name: string, value: unknown): void {\n const field = fields.get(name)\n if (field) field.setValue(value)\n}\n\n// ── Reset ────────────────────────────────────────────────────────────────────\n\nfunction reset(): void {\n for (const field of fields.values()) {\n field.reset()\n }\n errors.value = {}\n isSubmitting.value = false\n isSubmitted.value = false\n submitCount.value = 0\n emit('reset')\n}\n\n// ── Submit ───────────────────────────────────────────────────────────────────\n\nasync function handleSubmit(): Promise<void> {\n isSubmitting.value = true\n submitCount.value++\n\n const values = getAllValues()\n const context = { values }\n\n const results = await Promise.all(\n [...fields.entries()].map(async ([name, field]) => {\n const error = await runValidation(field.getValue(), field.rules, field.validate, context)\n return { name, error }\n }),\n )\n\n const nextErrors: Record<string, string> = {}\n for (const { name, error } of results) {\n if (error) nextErrors[name] = error\n }\n\n if (Object.keys(nextErrors).length > 0) {\n errors.value = nextErrors\n isSubmitting.value = false\n isSubmitted.value = true\n emit('invalid', nextErrors)\n return\n }\n\n errors.value = {}\n isSubmitted.value = true\n isSubmitting.value = false\n emit('submit', { values, setErrors })\n}\n\n// ── Context ──────────────────────────────────────────────────────────────────\n\nconst ctx: FormContext = {\n errors,\n isSubmitting,\n isSubmitted,\n submitCount,\n isDisabled: computed(() => props.isDisabled),\n isValid,\n isDirty,\n isTouched,\n validationMode: computed(() => props.validationMode),\n registerField,\n unregisterField,\n triggerFieldValidation,\n setErrors,\n setError,\n clearErrors,\n getValues,\n setValue,\n trigger,\n reset,\n}\n\nprovide(formContextKey, ctx)\n\ndefineExpose({\n errors,\n isSubmitting,\n isSubmitted,\n submitCount,\n isValid,\n isDirty,\n isTouched,\n getValues,\n setValue,\n setErrors,\n setError,\n clearErrors,\n trigger,\n reset,\n})\n</script>\n\n<template>\n <form\n :class=\"props.class\"\n novalidate\n @submit.prevent=\"handleSubmit\"\n >\n <slot\n :is-submitting=\"isSubmitting\"\n :is-submitted=\"isSubmitted\"\n :submit-count=\"submitCount\"\n :is-disabled=\"props.isDisabled\"\n :is-valid=\"isValid\"\n :is-dirty=\"isDirty\"\n :is-touched=\"isTouched\"\n :errors=\"errors\"\n :get-values=\"getValues\"\n :set-value=\"setValue\"\n :set-errors=\"setErrors\"\n :set-error=\"setError\"\n :clear-errors=\"clearErrors\"\n :trigger=\"trigger\"\n :reset=\"reset\"\n />\n </form>\n</template>\n"],"mappings":""}