@vue-interface/searchable-select-field 2.0.3 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
- import { openBlock as d, createElementBlock as v, createElementVNode as S, defineComponent as Z, useModel as _, computed as b, watchEffect as ee, ref as C, useTemplateRef as B, watch as $, nextTick as le, createVNode as x, unref as c, mergeProps as I, withKeys as k, withModifiers as m, createSlots as te, withCtx as R, renderSlot as z, normalizeProps as oe, guardReactiveProps as ne, createBlock as ae, createCommentVNode as O, normalizeClass as T, Fragment as ie, renderList as ue, toDisplayString as re, mergeModels as j } from "vue";
2
- import { ActivityIndicator as se, Pulse as de } from "@vue-interface/activity-indicator";
3
- import { useFormControl as ce } from "@vue-interface/form-control";
4
- import { InputField as ve } from "@vue-interface/input-field";
5
- import fe from "fuse.js";
6
- function me(e, w) {
7
- return d(), v("svg", {
1
+ import { openBlock as d, createElementBlock as c, createElementVNode as S, defineComponent as Y, useModel as Z, computed as b, watchEffect as _, ref as C, useTemplateRef as B, watch as $, nextTick as ee, createVNode as x, unref as f, mergeProps as I, withKeys as k, withModifiers as m, createSlots as le, withCtx as R, renderSlot as z, normalizeProps as te, guardReactiveProps as oe, createBlock as ne, createCommentVNode as O, normalizeClass as T, Fragment as ae, renderList as ie, toDisplayString as ue, mergeModels as j } from "vue";
2
+ import { ActivityIndicator as re, Pulse as se } from "@vue-interface/activity-indicator";
3
+ import { useFormControl as de } from "@vue-interface/form-control";
4
+ import { InputField as ce } from "@vue-interface/input-field";
5
+ import ve from "fuse.js";
6
+ function fe(e, w) {
7
+ return d(), c("svg", {
8
8
  xmlns: "http://www.w3.org/2000/svg",
9
9
  fill: "none",
10
10
  viewBox: "0 0 24 24",
@@ -20,8 +20,8 @@ function me(e, w) {
20
20
  })
21
21
  ]);
22
22
  }
23
- function ye(e, w) {
24
- return d(), v("svg", {
23
+ function me(e, w) {
24
+ return d(), c("svg", {
25
25
  xmlns: "http://www.w3.org/2000/svg",
26
26
  fill: "none",
27
27
  viewBox: "0 0 24 24",
@@ -37,7 +37,7 @@ function ye(e, w) {
37
37
  })
38
38
  ]);
39
39
  }
40
- const pe = { class: "relative [&_.form-control]:pr-8" }, be = ["title", "onClick"], ke = { class: "truncate" }, $e = /* @__PURE__ */ Z({
40
+ const ye = { class: "relative [&_.form-control]:pr-8" }, pe = ["title", "onClick"], be = { class: "truncate" }, Be = /* @__PURE__ */ Y({
41
41
  __name: "SearchableSelectField",
42
42
  props: /* @__PURE__ */ j({
43
43
  activity: { type: Boolean },
@@ -72,24 +72,23 @@ const pe = { class: "relative [&_.form-control]:pr-8" }, be = ["title", "onClick
72
72
  }),
73
73
  emits: /* @__PURE__ */ j(["blur", "focus", "focusin", "focusout", "click", "doubleclick", "contextmenu", "mousedown", "mouseup", "mouseover", "mouseout", "mouseenter", "mouseleave", "mousemove", "keydown", "keyup", "keypress", "select", "selectionchange", "invalid", "submit", "reset", "scroll", "wheel", "copy", "cut", "paste", "touchstart", "touchend", "touchmove", "touchcancel", "change", "input", "beforeinput"], ["update:modelValue"]),
74
74
  setup(e, { emit: w }) {
75
- const t = e, u = _(e, "modelValue"), s = b(() => !t.disabled && !t.readonly), P = w, {
76
- controlAttributes: A,
75
+ const t = e, u = Z(e, "modelValue"), s = b(() => !t.disabled && !t.readonly), P = w, {
77
76
  formGroupClasses: N,
78
77
  listeners: D
79
- } = ce({ model: u, props: t, emit: P });
80
- ee(() => {
78
+ } = de({ model: u, props: t, emit: P });
79
+ _(() => {
81
80
  t.value !== void 0 && (u.value = t.value);
82
81
  });
83
82
  const i = C(), V = B("field"), a = C(!1), n = C(), p = B("buttons"), h = B("optionsEl"), G = b(() => typeof t.options == "object" && t.options?.[0] ? Object.keys(t.options?.[0]) : ["$"]);
84
83
  let K = F();
85
84
  function F() {
86
- return new fe(t.options ?? [], t.fuseOptions ?? {
85
+ return new ve(t.options ?? [], t.fuseOptions ?? {
87
86
  includeScore: !0,
88
87
  threshold: 0.45,
89
88
  keys: G.value
90
89
  });
91
90
  }
92
- const f = b(() => {
91
+ const v = b(() => {
93
92
  if (!i.value)
94
93
  return t.options ?? [];
95
94
  const l = K.search(i.value).map(({ item: o }) => o);
@@ -114,51 +113,51 @@ const pe = { class: "relative [&_.form-control]:pr-8" }, be = ["title", "onClick
114
113
  inline: "nearest"
115
114
  });
116
115
  }), $(h, (l) => {
117
- !l || n.value === void 0 || le(() => {
116
+ !l || n.value === void 0 || ee(() => {
118
117
  q(p.value?.[n.value]);
119
118
  });
120
119
  });
121
120
  function y(l) {
122
121
  u.value = l, n.value = l && t.options.includes(l) ? t.options.indexOf(l) : void 0, i.value = void 0, a.value = !1;
123
122
  }
124
- function L(l) {
123
+ function A(l) {
125
124
  s.value && (a.value = !0, n.value = void 0, i.value = l.target?.value, !i.value && !t.allowCustom && (u.value = void 0), t.allowCustom && (u.value = i.value));
126
125
  }
127
- function U() {
126
+ function L() {
128
127
  if (s.value) {
129
128
  if (!a.value) {
130
129
  a.value = !0;
131
130
  return;
132
131
  }
133
- t.allowCustom && n.value === void 0 ? y(i.value ?? u.value) : n.value === void 0 ? y(f.value[0]) : f.value[n.value] ? y(f.value[n.value]) : y(void 0);
132
+ t.allowCustom && n.value === void 0 ? y(i.value ?? u.value) : n.value === void 0 ? y(v.value[0]) : v.value[n.value] ? y(v.value[n.value]) : y(void 0);
134
133
  }
135
134
  }
135
+ function U() {
136
+ s.value && (a.value = !0, n.value ? n.value-- : n.value = v.value.length - 1);
137
+ }
136
138
  function H() {
137
- s.value && (a.value = !0, n.value ? n.value-- : n.value = f.value.length - 1);
139
+ s.value && (a.value = !0, n.value === void 0 || n.value === v.value.length - 1 ? n.value = 0 : n.value++);
138
140
  }
139
141
  function J() {
140
- s.value && (a.value = !0, n.value === void 0 || n.value === f.value.length - 1 ? n.value = 0 : n.value++);
141
- }
142
- function Q() {
143
142
  a.value = !1, i.value = void 0;
144
143
  }
145
- function W(l) {
144
+ function Q(l) {
146
145
  s.value && y(l);
147
146
  }
148
- function X() {
147
+ function W() {
149
148
  s.value && (i.value = void 0, u.value = void 0);
150
149
  }
151
- function Y() {
150
+ function X() {
152
151
  s.value && (a.value ? a.value = !1 : (a.value = !0, V.value?.$el?.querySelector("input")?.focus()));
153
152
  }
154
153
  const M = b(() => t.clearable && (!!i.value || !!u.value) && s.value);
155
- return (l, o) => (d(), v("div", pe, [
156
- x(c(ve), I({
154
+ return (l, o) => (d(), c("div", ye, [
155
+ x(f(ce), I({
157
156
  ref_key: "field",
158
157
  ref: V,
159
- class: ["searchable-select-field-input", { "has-clear-button": M.value, formGroupClasses: c(N) }],
158
+ class: ["searchable-select-field-input", { "has-clear-button": M.value, formGroupClasses: f(N) }],
160
159
  size: e.size
161
- }, { ...l.$attrs, controlAttributes: c(A), listeners: c(D) }, {
160
+ }, { ...l.$attrs, ...f(D) }, {
162
161
  name: e.name,
163
162
  label: e.label,
164
163
  "model-value": i.value ?? (u.value && t?.display ? t?.display?.(u.value) : u.value),
@@ -172,34 +171,34 @@ const pe = { class: "relative [&_.form-control]:pr-8" }, be = ["title", "onClick
172
171
  invalid: e.invalid,
173
172
  onClick: o[0] || (o[0] = (r) => s.value && (a.value = !0)),
174
173
  onFocus: o[1] || (o[1] = (r) => s.value && (a.value = !0)),
175
- onBlur: Q,
176
- onKeypress: k(m(U, ["prevent"]), ["enter"]),
174
+ onBlur: J,
175
+ onKeypress: k(m(L, ["prevent"]), ["enter"]),
177
176
  onKeydown: [
178
- k(m(H, ["prevent"]), ["up"]),
179
- k(m(J, ["prevent"]), ["down"])
177
+ k(m(U, ["prevent"]), ["up"]),
178
+ k(m(H, ["prevent"]), ["down"])
180
179
  ],
181
180
  onKeyup: o[2] || (o[2] = k((r) => a.value = !1, ["escape"])),
182
- onInput: L
183
- }), te({
181
+ onInput: A
182
+ }), le({
184
183
  activity: R(() => [
185
- z(l.$slots, "activity", oe(ne({ disabled: e.disabled, options: e.options, invalid: e.invalid, valid: e.valid })), () => [
186
- !e.disabled && !e.options ? (d(), ae(c(se), {
184
+ z(l.$slots, "activity", te(oe({ disabled: e.disabled, options: e.options, invalid: e.invalid, valid: e.valid })), () => [
185
+ !e.disabled && !e.options ? (d(), ne(f(re), {
187
186
  key: 0,
188
- type: c(de),
187
+ type: f(se),
189
188
  size: "activity-indicator-sm"
190
- }, null, 8, ["type"])) : M.value ? (d(), v("button", {
189
+ }, null, 8, ["type"])) : M.value ? (d(), c("button", {
191
190
  key: 1,
192
191
  type: "button",
193
192
  class: "searchable-select-field-clear-button",
194
- onClick: m(X, ["stop"])
193
+ onClick: m(W, ["stop"])
195
194
  }, [
196
- x(c(ye), { class: "size-[1.25em]" })
197
- ])) : !e.invalid && !e.valid ? (d(), v("button", {
195
+ x(f(me), { class: "size-[1.25em]" })
196
+ ])) : !e.invalid && !e.valid ? (d(), c("button", {
198
197
  key: 2,
199
198
  type: "button",
200
- onClick: m(Y, ["stop"])
199
+ onClick: m(X, ["stop"])
201
200
  }, [
202
- x(c(me), { class: "size-[1em]" })
201
+ x(f(fe), { class: "size-[1em]" })
203
202
  ])) : O("", !0)
204
203
  ])
205
204
  ]),
@@ -213,7 +212,7 @@ const pe = { class: "relative [&_.form-control]:pr-8" }, be = ["title", "onClick
213
212
  key: "0"
214
213
  } : void 0
215
214
  ]), 1040, ["class", "size", "name", "label", "model-value", "disabled", "readonly", "color", "error", "errors", "feedback", "valid", "invalid", "onKeypress", "onKeydown"]),
216
- a.value && f.value.length ? (d(), v("div", {
215
+ a.value && v.value.length ? (d(), c("div", {
217
216
  key: 0,
218
217
  ref_key: "optionsEl",
219
218
  ref: h,
@@ -222,7 +221,7 @@ const pe = { class: "relative [&_.form-control]:pr-8" }, be = ["title", "onClick
222
221
  onMousedown: o[4] || (o[4] = m(() => {
223
222
  }, ["prevent", "stop"]))
224
223
  }, [
225
- (d(!0), v(ie, null, ue(f.value, (r, g) => (d(), v("button", {
224
+ (d(!0), c(ae, null, ie(v.value, (r, g) => (d(), c("button", {
226
225
  ref_for: !0,
227
226
  ref_key: "buttons",
228
227
  ref: p,
@@ -235,17 +234,17 @@ const pe = { class: "relative [&_.form-control]:pr-8" }, be = ["title", "onClick
235
234
  }),
236
235
  onMousedown: o[3] || (o[3] = m(() => {
237
236
  }, ["prevent"])),
238
- onClick: (E) => W(r)
237
+ onClick: (E) => Q(r)
239
238
  }, [
240
239
  z(l.$slots, "default", I({ ref_for: !0 }, { option: r, display: e.display }), () => [
241
- S("div", ke, re(e.display?.(r) ?? r), 1)
240
+ S("div", be, ue(e.display?.(r) ?? r), 1)
242
241
  ])
243
- ], 42, be))), 128))
242
+ ], 42, pe))), 128))
244
243
  ], 34)) : O("", !0)
245
244
  ]));
246
245
  }
247
246
  });
248
247
  export {
249
- $e as SearchableSelectField
248
+ Be as SearchableSelectField
250
249
  };
251
250
  //# sourceMappingURL=searchable-select-field.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"searchable-select-field.js","sources":["../../../node_modules/.pnpm/@heroicons+vue@2.2.0_vue@3.5.26_typescript@5.9.3_/node_modules/@heroicons/vue/24/outline/esm/ChevronDownIcon.js","../../../node_modules/.pnpm/@heroicons+vue@2.2.0_vue@3.5.26_typescript@5.9.3_/node_modules/@heroicons/vue/24/outline/esm/XMarkIcon.js","../src/SearchableSelectField.vue"],"sourcesContent":["import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport default function render(_ctx, _cache) {\n return (_openBlock(), _createElementBlock(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n fill: \"none\",\n viewBox: \"0 0 24 24\",\n \"stroke-width\": \"1.5\",\n stroke: \"currentColor\",\n \"aria-hidden\": \"true\",\n \"data-slot\": \"icon\"\n }, [\n _createElementVNode(\"path\", {\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n d: \"m19.5 8.25-7.5 7.5-7.5-7.5\"\n })\n ]))\n}","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport default function render(_ctx, _cache) {\n return (_openBlock(), _createElementBlock(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n fill: \"none\",\n viewBox: \"0 0 24 24\",\n \"stroke-width\": \"1.5\",\n stroke: \"currentColor\",\n \"aria-hidden\": \"true\",\n \"data-slot\": \"icon\"\n }, [\n _createElementVNode(\"path\", {\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n d: \"M6 18 18 6M6 6l12 12\"\n })\n ]))\n}","<script setup lang=\"ts\" generic=\"T, Value\">\nimport { ChevronDownIcon, XMarkIcon } from '@heroicons/vue/24/outline';\nimport { ActivityIndicator, Pulse } from '@vue-interface/activity-indicator';\nimport type { FormControlEvents, FormControlProps, FormControlSlots } from '@vue-interface/form-control';\nimport { useFormControl } from '@vue-interface/form-control';\nimport { InputField } from '@vue-interface/input-field';\nimport Fuse, { IFuseOptions } from 'fuse.js';\nimport { InputHTMLAttributes, computed, nextTick, ref, useTemplateRef, watch, watchEffect } from 'vue';\n\nconst props = withDefaults(defineProps<SearchableSelectFieldProps<T,Value>>(), {\n formControlClass: 'form-control',\n labelClass: 'form-label',\n size: 'form-control-md',\n clearable: true,\n options: () => []\n});\n\nconst model = defineModel<T>();\nconst isInteractive = computed(() => !props.disabled && !props.readonly);\n\ndefineSlots<FormControlSlots<SearchableSelectFieldSizePrefix,T> & {\n default(props: { option: T; display?: (option: T) => string }): any;\n}>();\n\nconst emit = defineEmits<FormControlEvents>();\n\nconst {\n controlAttributes,\n formGroupClasses,\n listeners\n} = useFormControl<InputHTMLAttributes, SearchableSelectFieldSizePrefix, T|undefined, T>({ model, props, emit });\n\nwatchEffect(() => {\n if(props.value !== undefined) {\n model.value = props.value;\n }\n});\n\nconst input = ref<string>();\nconst field = useTemplateRef<any>('field');\nconst showOptions = ref(false);\nconst active = ref<number>();\nconst buttons = useTemplateRef<HTMLButtonElement[]>('buttons');\nconst optionsEl = useTemplateRef<HTMLDivElement>('optionsEl');\n\nconst keys = computed(() => {\n return typeof props.options === 'object' && props.options?.[0]\n ? Object.keys(props.options?.[0])\n : ['$'];\n});\n\nlet fuse: Fuse<T> = createFuse();\n\nfunction createFuse() {\n return new Fuse(props.options ?? [], props.fuseOptions ?? {\n includeScore: true,\n threshold: .45,\n keys: keys.value\n });\n}\n\nconst filtered = computed<T[]>(() => {\n if(!input.value) {\n return props.options ?? [];\n }\n\n const matches = fuse.search(input.value).map(({ item }) => item);\n\n if(props.allowCustom && !matches.length) {\n return props.options;\n }\n\n return matches;\n});\n\nwatch(() => props.options, () => {\n fuse = createFuse();\n});\n\nfunction scrollIntoView(child?: HTMLElement) {\n const parent = optionsEl.value;\n\n if(!parent || !child) {\n return;\n }\n\n const parentRect = parent.getBoundingClientRect();\n const childRect = child.getBoundingClientRect();\n\n const childTop = childRect.top - parentRect.top + parent.scrollTop;\n\n parent.scrollTop = childTop;\n};\n\nwatch([input, active], ([input, active]) => {\n if(input) {\n buttons.value?.[0]?.scrollIntoView({\n block: 'nearest',\n inline: 'nearest'\n });\n }\n else if(active !== undefined) {\n buttons.value?.[active]?.scrollIntoView({\n block: 'nearest',\n inline: 'nearest'\n });\n }\n});\n\nwatch(optionsEl, (value) => {\n if(!value || active.value === undefined) {\n return;\n }\n\n nextTick(() => {\n scrollIntoView(buttons.value?.[active.value as number]);\n });\n});\n\nfunction select(option?: T) {\n model.value = option;\n active.value = option && props.options.includes(option)\n ? props.options.indexOf(option)\n : undefined;\n input.value = undefined;\n showOptions.value = false;\n}\n\nfunction onInput(e: Event) {\n if (!isInteractive.value) return;\n\n showOptions.value = true;\n active.value = undefined;\n input.value = (e.target as HTMLInputElement)?.value;\n\n if(!input.value && !props.allowCustom) {\n model.value = undefined;\n }\n\n if(props.allowCustom) {\n model.value = input.value as T;\n }\n}\n\nfunction onKeypressEnter() {\n if (!isInteractive.value) return;\n\n if(!showOptions.value) {\n showOptions.value = true;\n return;\n }\n\n if(props.allowCustom && active.value === undefined) {\n select(input.value as T ?? model.value);\n }\n else if(active.value === undefined) {\n select(filtered.value[0]);\n }\n else if(filtered.value[active.value]) {\n select(filtered.value[active.value]);\n }\n else {\n select(undefined);\n }\n}\n\nfunction onKeydownUp() {\n if (!isInteractive.value) return;\n \n showOptions.value = true;\n\n if(!active.value) {\n active.value = filtered.value.length - 1;\n }\n else {\n active.value--;\n }\n}\n\nfunction onKeydownDown() {\n if (!isInteractive.value) return;\n\n showOptions.value = true;\n\n if(active.value === undefined || active.value === filtered.value.length - 1) {\n active.value = 0;\n }\n else {\n active.value++;\n }\n}\n\nfunction onBlur() {\n showOptions.value = false;\n input.value = undefined;\n}\n\nfunction onClickOption(option: T) {\n if (!isInteractive.value) return;\n select(option);\n}\n\nfunction clear() {\n if (!isInteractive.value) return;\n input.value = undefined;\n model.value = undefined;\n}\n\nfunction toggle() {\n if (!isInteractive.value) return;\n \n if(showOptions.value ) {\n showOptions.value = false;\n }\n else {\n showOptions.value = true;\n field.value?.$el?.querySelector('input')?.focus();\n }\n}\n\nconst canClear = computed(() => {\n return props.clearable && (!!input.value || !!model.value) && isInteractive.value;\n});\n</script>\n<script lang=\"ts\">\nexport type SearchableSelectFieldSizePrefix = 'form-control';\n\nexport type SearchableSelectFieldProps<ModelValue, Value> = FormControlProps<\n InputHTMLAttributes, \n SearchableSelectFieldSizePrefix, \n ModelValue, \n Value\n> & {\n options?: ModelValue[];\n fuseOptions?: IFuseOptions<ModelValue>;\n display?: (option: ModelValue) => string;\n allowCustom?: boolean;\n clearable?: boolean;\n};\n</script>\n\n\n<template>\n <div class=\"relative [&_.form-control]:pr-8\">\n <InputField\n ref=\"field\"\n class=\"searchable-select-field-input\"\n :class=\"{ 'has-clear-button': canClear, formGroupClasses }\"\n :size=\"size\"\n v-bind=\"{ ...$attrs, controlAttributes, listeners }\"\n :name=\"name\"\n :label=\"label\"\n :model-value=\"input ?? (model && props?.display ? props?.display?.(model) : model)\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :color=\"color\"\n :error=\"error\"\n :errors=\"errors\"\n :feedback=\"feedback\"\n :valid=\"valid\"\n :invalid=\"invalid\"\n @click=\"isInteractive && (showOptions = true)\"\n @focus=\"isInteractive && (showOptions = true)\"\n @blur=\"onBlur\"\n @keypress.enter.prevent=\"onKeypressEnter\"\n @keydown.up.prevent=\"onKeydownUp\"\n @keydown.down.prevent=\"onKeydownDown\"\n @keyup.escape=\"showOptions = false\"\n @input=\"onInput\">\n <template #icon v-if=\"$slots.icon\">\n <slot name=\"icon\" />\n </template>\n <template #activity>\n <slot\n name=\"activity\"\n v-bind=\"{ disabled, options, invalid, valid }\">\n <ActivityIndicator\n v-if=\"!disabled && !options\"\n :type=\"Pulse\"\n size=\"activity-indicator-sm\" />\n <button\n v-else-if=\"canClear\"\n type=\"button\"\n class=\"searchable-select-field-clear-button\"\n @click.stop=\"clear\">\n <XMarkIcon class=\"size-[1.25em]\" />\n </button>\n <button\n v-else-if=\"!invalid && !valid\"\n type=\"button\"\n @click.stop=\"toggle\">\n <ChevronDownIcon class=\"size-[1em]\" />\n </button>\n </slot>\n </template>\n </InputField>\n <div\n v-if=\"showOptions && filtered.length\"\n ref=\"optionsEl\"\n tabindex=\"-1\"\n class=\"searchable-select-field-dropdown\"\n :class=\"size\"\n @mousedown.prevent.stop>\n <button\n v-for=\"(option, i) in filtered\"\n ref=\"buttons\"\n :key=\"i\"\n type=\"button\"\n tabindex=\"-1\"\n :title=\"display?.(option) ?? String(option)\"\n :class=\"{\n ['bg-neutral-200 dark:bg-neutral-700']: active === i\n }\"\n @mousedown.prevent\n @click=\"onClickOption(option)\">\n <slot v-bind=\"{ option, display }\">\n <div class=\"truncate\">\n {{ display?.(option) ?? option }}\n </div>\n </slot>\n </button>\n </div>\n </div>\n</template>"],"names":["render","_ctx","_cache","_openBlock","_createElementBlock","_createElementVNode","props","__props","model","_useModel","isInteractive","computed","emit","__emit","controlAttributes","formGroupClasses","listeners","useFormControl","watchEffect","input","ref","field","useTemplateRef","showOptions","active","buttons","optionsEl","keys","fuse","createFuse","Fuse","filtered","matches","item","watch","scrollIntoView","child","parent","parentRect","childTop","value","nextTick","select","option","onInput","e","onKeypressEnter","onKeydownUp","onKeydownDown","onBlur","onClickOption","clear","toggle","canClear","_hoisted_1","_createVNode","_unref","_mergeProps","$attrs","$event","_renderSlot","_normalizeProps","_guardReactiveProps","_createBlock","ActivityIndicator","Pulse","XMarkIcon","ChevronDownIcon","$slots","_normalizeClass","_Fragment","_renderList","i","_hoisted_3","_toDisplayString"],"mappings":"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","x_google_ignoreList":[0,1]}
1
+ {"version":3,"file":"searchable-select-field.js","sources":["../../../node_modules/.pnpm/@heroicons+vue@2.2.0_vue@3.5.27_typescript@5.9.3_/node_modules/@heroicons/vue/24/outline/esm/ChevronDownIcon.js","../../../node_modules/.pnpm/@heroicons+vue@2.2.0_vue@3.5.27_typescript@5.9.3_/node_modules/@heroicons/vue/24/outline/esm/XMarkIcon.js","../src/SearchableSelectField.vue"],"sourcesContent":["import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport default function render(_ctx, _cache) {\n return (_openBlock(), _createElementBlock(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n fill: \"none\",\n viewBox: \"0 0 24 24\",\n \"stroke-width\": \"1.5\",\n stroke: \"currentColor\",\n \"aria-hidden\": \"true\",\n \"data-slot\": \"icon\"\n }, [\n _createElementVNode(\"path\", {\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n d: \"m19.5 8.25-7.5 7.5-7.5-7.5\"\n })\n ]))\n}","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport default function render(_ctx, _cache) {\n return (_openBlock(), _createElementBlock(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n fill: \"none\",\n viewBox: \"0 0 24 24\",\n \"stroke-width\": \"1.5\",\n stroke: \"currentColor\",\n \"aria-hidden\": \"true\",\n \"data-slot\": \"icon\"\n }, [\n _createElementVNode(\"path\", {\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n d: \"M6 18 18 6M6 6l12 12\"\n })\n ]))\n}","<script setup lang=\"ts\" generic=\"ModelValue, Value extends ModelValue\">\nimport { ChevronDownIcon, XMarkIcon } from '@heroicons/vue/24/outline';\nimport { ActivityIndicator, Pulse } from '@vue-interface/activity-indicator';\nimport type { FormControlEvents, FormControlProps, FormControlSlots } from '@vue-interface/form-control';\nimport { useFormControl } from '@vue-interface/form-control';\nimport { InputField } from '@vue-interface/input-field';\nimport Fuse, { IFuseOptions } from 'fuse.js';\nimport { type HTMLAttributes, computed, nextTick, ref, useTemplateRef, watch, watchEffect } from 'vue';\n\nconst props = withDefaults(defineProps<SearchableSelectFieldProps<ModelValue,Value>>(), {\n formControlClass: 'form-control',\n labelClass: 'form-label',\n size: 'form-control-md',\n clearable: true,\n options: () => []\n});\n\nconst model = defineModel<ModelValue>();\nconst isInteractive = computed(() => !props.disabled && !props.readonly);\n\ndefineSlots<FormControlSlots<SearchableSelectFieldSizePrefix,ModelValue> & {\n default(props: { option: ModelValue; display?: (option: ModelValue) => string }): any;\n}>();\n\nconst emit = defineEmits<FormControlEvents>();\n\nconst {\n formGroupClasses,\n listeners\n} = useFormControl<HTMLAttributes, SearchableSelectFieldSizePrefix, ModelValue|undefined, ModelValue>({ model, props, emit });\n\nwatchEffect(() => {\n if(props.value !== undefined) {\n model.value = props.value;\n }\n});\n\nconst input = ref<string>();\nconst field = useTemplateRef<any>('field');\nconst showOptions = ref(false);\nconst active = ref<number>();\nconst buttons = useTemplateRef<HTMLButtonElement[]>('buttons');\nconst optionsEl = useTemplateRef<HTMLDivElement>('optionsEl');\n\nconst keys = computed(() => {\n return typeof props.options === 'object' && props.options?.[0]\n ? Object.keys(props.options?.[0])\n : ['$'];\n});\n\nlet fuse: Fuse<ModelValue> = createFuse();\n\nfunction createFuse() {\n return new Fuse(props.options ?? [], props.fuseOptions ?? {\n includeScore: true,\n threshold: .45,\n keys: keys.value\n });\n}\n\nconst filtered = computed<ModelValue[]>(() => {\n if(!input.value) {\n return props.options ?? [];\n }\n\n const matches = fuse.search(input.value).map(({ item }) => item);\n\n if(props.allowCustom && !matches.length) {\n return props.options;\n }\n\n return matches;\n});\n\nwatch(() => props.options, () => {\n fuse = createFuse();\n});\n\nfunction scrollIntoView(child?: HTMLElement) {\n const parent = optionsEl.value;\n\n if(!parent || !child) {\n return;\n }\n\n const parentRect = parent.getBoundingClientRect();\n const childRect = child.getBoundingClientRect();\n\n const childTop = childRect.top - parentRect.top + parent.scrollTop;\n\n parent.scrollTop = childTop;\n};\n\nwatch([input, active], ([input, active]) => {\n if(input) {\n buttons.value?.[0]?.scrollIntoView({\n block: 'nearest',\n inline: 'nearest'\n });\n }\n else if(active !== undefined) {\n buttons.value?.[active]?.scrollIntoView({\n block: 'nearest',\n inline: 'nearest'\n });\n }\n});\n\nwatch(optionsEl, (value) => {\n if(!value || active.value === undefined) {\n return;\n }\n\n nextTick(() => {\n scrollIntoView(buttons.value?.[active.value as number]);\n });\n});\n\nfunction select(option?: ModelValue) {\n model.value = option;\n active.value = option && props.options.includes(option)\n ? props.options.indexOf(option)\n : undefined;\n input.value = undefined;\n showOptions.value = false;\n}\n\nfunction onInput(e: Event) {\n if (!isInteractive.value) return;\n\n showOptions.value = true;\n active.value = undefined;\n input.value = (e.target as HTMLInputElement)?.value;\n\n if(!input.value && !props.allowCustom) {\n model.value = undefined;\n }\n\n if(props.allowCustom) {\n model.value = input.value as ModelValue;\n }\n}\n\nfunction onKeypressEnter() {\n if (!isInteractive.value) return;\n\n if(!showOptions.value) {\n showOptions.value = true;\n return;\n }\n\n if(props.allowCustom && active.value === undefined) {\n select(input.value as ModelValue ?? model.value);\n }\n else if(active.value === undefined) {\n select(filtered.value[0]);\n }\n else if(filtered.value[active.value]) {\n select(filtered.value[active.value]);\n }\n else {\n select(undefined);\n }\n}\n\nfunction onKeydownUp() {\n if (!isInteractive.value) return;\n \n showOptions.value = true;\n\n if(!active.value) {\n active.value = filtered.value.length - 1;\n }\n else {\n active.value--;\n }\n}\n\nfunction onKeydownDown() {\n if (!isInteractive.value) return;\n\n showOptions.value = true;\n\n if(active.value === undefined || active.value === filtered.value.length - 1) {\n active.value = 0;\n }\n else {\n active.value++;\n }\n}\n\nfunction onBlur() {\n showOptions.value = false;\n input.value = undefined;\n}\n\nfunction onClickOption(option: ModelValue) {\n if (!isInteractive.value) return;\n select(option);\n}\n\nfunction clear() {\n if (!isInteractive.value) return;\n input.value = undefined;\n model.value = undefined;\n}\n\nfunction toggle() {\n if (!isInteractive.value) return;\n \n if(showOptions.value ) {\n showOptions.value = false;\n }\n else {\n showOptions.value = true;\n field.value?.$el?.querySelector('input')?.focus();\n }\n}\n\nconst canClear = computed(() => {\n return props.clearable && (!!input.value || !!model.value) && isInteractive.value;\n});\n</script>\n<script lang=\"ts\">\nexport type SearchableSelectFieldSizePrefix = 'form-control';\n\nexport type SearchableSelectFieldProps<ModelValue, Value> = FormControlProps<\n HTMLAttributes, \n SearchableSelectFieldSizePrefix, \n ModelValue, \n Value\n> & {\n options?: ModelValue[];\n fuseOptions?: IFuseOptions<ModelValue>;\n display?: (option: ModelValue) => string;\n allowCustom?: boolean;\n clearable?: boolean;\n};\n</script>\n\n\n<template>\n <div class=\"relative [&_.form-control]:pr-8\">\n <InputField\n ref=\"field\"\n class=\"searchable-select-field-input\"\n :class=\"{ 'has-clear-button': canClear, formGroupClasses }\"\n :size=\"size\"\n v-bind=\"{ ...$attrs, ...listeners }\"\n :name=\"name\"\n :label=\"label\"\n :model-value=\"input ?? (model && props?.display ? props?.display?.(model) : model)\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :color=\"color\"\n :error=\"error\"\n :errors=\"errors\"\n :feedback=\"feedback\"\n :valid=\"valid\"\n :invalid=\"invalid\"\n @click=\"isInteractive && (showOptions = true)\"\n @focus=\"isInteractive && (showOptions = true)\"\n @blur=\"onBlur\"\n @keypress.enter.prevent=\"onKeypressEnter\"\n @keydown.up.prevent=\"onKeydownUp\"\n @keydown.down.prevent=\"onKeydownDown\"\n @keyup.escape=\"showOptions = false\"\n @input=\"onInput\">\n <template #icon v-if=\"$slots.icon\">\n <slot name=\"icon\" />\n </template>\n <template #activity>\n <slot\n name=\"activity\"\n v-bind=\"{ disabled, options, invalid, valid }\">\n <ActivityIndicator\n v-if=\"!disabled && !options\"\n :type=\"Pulse\"\n size=\"activity-indicator-sm\" />\n <button\n v-else-if=\"canClear\"\n type=\"button\"\n class=\"searchable-select-field-clear-button\"\n @click.stop=\"clear\">\n <XMarkIcon class=\"size-[1.25em]\" />\n </button>\n <button\n v-else-if=\"!invalid && !valid\"\n type=\"button\"\n @click.stop=\"toggle\">\n <ChevronDownIcon class=\"size-[1em]\" />\n </button>\n </slot>\n </template>\n </InputField>\n <div\n v-if=\"showOptions && filtered.length\"\n ref=\"optionsEl\"\n tabindex=\"-1\"\n class=\"searchable-select-field-dropdown\"\n :class=\"size\"\n @mousedown.prevent.stop>\n <button\n v-for=\"(option, i) in filtered\"\n ref=\"buttons\"\n :key=\"i\"\n type=\"button\"\n tabindex=\"-1\"\n :title=\"display?.(option) ?? String(option)\"\n :class=\"{\n ['bg-neutral-200 dark:bg-neutral-700']: active === i\n }\"\n @mousedown.prevent\n @click=\"onClickOption(option)\">\n <slot v-bind=\"{ option, display }\">\n <div class=\"truncate\">\n {{ display?.(option) ?? option }}\n </div>\n </slot>\n </button>\n </div>\n </div>\n</template>"],"names":["render","_ctx","_cache","_openBlock","_createElementBlock","_createElementVNode","props","__props","model","_useModel","isInteractive","computed","emit","__emit","formGroupClasses","listeners","useFormControl","watchEffect","input","ref","field","useTemplateRef","showOptions","active","buttons","optionsEl","keys","fuse","createFuse","Fuse","filtered","matches","item","watch","scrollIntoView","child","parent","parentRect","childTop","value","nextTick","select","option","onInput","e","onKeypressEnter","onKeydownUp","onKeydownDown","onBlur","onClickOption","clear","toggle","canClear","_hoisted_1","_createVNode","_unref","_mergeProps","$attrs","$event","_renderSlot","_normalizeProps","_guardReactiveProps","_createBlock","ActivityIndicator","Pulse","XMarkIcon","ChevronDownIcon","$slots","_normalizeClass","_Fragment","_renderList","i","_hoisted_3","_toDisplayString"],"mappings":"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","x_google_ignoreList":[0,1]}
@@ -1,2 +1,2 @@
1
- (function(s,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue"),require("@vue-interface/activity-indicator"),require("@vue-interface/form-control"),require("@vue-interface/input-field"),require("fuse.js")):typeof define=="function"&&define.amd?define(["exports","vue","@vue-interface/activity-indicator","@vue-interface/form-control","@vue-interface/input-field","fuse.js"],e):(s=typeof globalThis<"u"?globalThis:s||self,e(s.SearchableSelectField={},s.Vue,s.VueInterfaceActivityIndicator,s.VueInterfaceFormControl,s.VueInterfaceInputField,s.FuseJs))})(this,(function(s,e,w,V,S,E){"use strict";function M(t,p){return e.openBlock(),e.createElementBlock("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor","aria-hidden":"true","data-slot":"icon"},[e.createElementVNode("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"m19.5 8.25-7.5 7.5-7.5-7.5"})])}function x(t,p){return e.openBlock(),e.createElementBlock("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor","aria-hidden":"true","data-slot":"icon"},[e.createElementVNode("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M6 18 18 6M6 6l12 12"})])}const z={class:"relative [&_.form-control]:pr-8"},K=["title","onClick"],$={class:"truncate"},F=e.defineComponent({__name:"SearchableSelectField",props:e.mergeModels({activity:{type:Boolean},disabled:{type:Boolean},error:{},errors:{},feedback:{},formControlClass:{default:"form-control"},helpText:{},id:{},indicator:{},indicatorSize:{},invalid:{type:Boolean},label:{},labelClass:{default:"form-label"},modelValue:{},name:{},plaintext:{type:Boolean},size:{default:"form-control-md"},color:{},readonly:{type:Boolean},valid:{type:Boolean},value:{},options:{default:()=>[]},fuseOptions:{},display:{},allowCustom:{type:Boolean},clearable:{type:Boolean,default:!0}},{modelValue:{},modelModifiers:{}}),emits:e.mergeModels(["blur","focus","focusin","focusout","click","doubleclick","contextmenu","mousedown","mouseup","mouseover","mouseout","mouseenter","mouseleave","mousemove","keydown","keyup","keypress","select","selectionchange","invalid","submit","reset","scroll","wheel","copy","cut","paste","touchstart","touchend","touchmove","touchcancel","change","input","beforeinput"],["update:modelValue"]),setup(t,{emit:p}){const o=t,c=e.useModel(t,"modelValue"),d=e.computed(()=>!o.disabled&&!o.readonly),I=p,{controlAttributes:T,formGroupClasses:R,listeners:j}=V.useFormControl({model:c,props:o,emit:I});e.watchEffect(()=>{o.value!==void 0&&(c.value=o.value)});const r=e.ref(),h=e.useTemplateRef("field"),a=e.ref(!1),i=e.ref(),v=e.useTemplateRef("buttons"),y=e.useTemplateRef("optionsEl"),N=e.computed(()=>typeof o.options=="object"&&o.options?.[0]?Object.keys(o.options?.[0]):["$"]);let b=B();function B(){return new E(o.options??[],o.fuseOptions??{includeScore:!0,threshold:.45,keys:N.value})}const f=e.computed(()=>{if(!r.value)return o.options??[];const l=b.search(r.value).map(({item:n})=>n);return o.allowCustom&&!l.length?o.options:l});e.watch(()=>o.options,()=>{b=B()});function O(l){const n=y.value;if(!n||!l)return;const u=n.getBoundingClientRect(),g=l.getBoundingClientRect().top-u.top+n.scrollTop;n.scrollTop=g}e.watch([r,i],([l,n])=>{l?v.value?.[0]?.scrollIntoView({block:"nearest",inline:"nearest"}):n!==void 0&&v.value?.[n]?.scrollIntoView({block:"nearest",inline:"nearest"})}),e.watch(y,l=>{!l||i.value===void 0||e.nextTick(()=>{O(v.value?.[i.value])})});function m(l){c.value=l,i.value=l&&o.options.includes(l)?o.options.indexOf(l):void 0,r.value=void 0,a.value=!1}function q(l){d.value&&(a.value=!0,i.value=void 0,r.value=l.target?.value,!r.value&&!o.allowCustom&&(c.value=void 0),o.allowCustom&&(c.value=r.value))}function P(){if(d.value){if(!a.value){a.value=!0;return}o.allowCustom&&i.value===void 0?m(r.value??c.value):i.value===void 0?m(f.value[0]):f.value[i.value]?m(f.value[i.value]):m(void 0)}}function A(){d.value&&(a.value=!0,i.value?i.value--:i.value=f.value.length-1)}function D(){d.value&&(a.value=!0,i.value===void 0||i.value===f.value.length-1?i.value=0:i.value++)}function G(){a.value=!1,r.value=void 0}function J(l){d.value&&m(l)}function L(){d.value&&(r.value=void 0,c.value=void 0)}function U(){d.value&&(a.value?a.value=!1:(a.value=!0,h.value?.$el?.querySelector("input")?.focus()))}const C=e.computed(()=>o.clearable&&(!!r.value||!!c.value)&&d.value);return(l,n)=>(e.openBlock(),e.createElementBlock("div",z,[e.createVNode(e.unref(S.InputField),e.mergeProps({ref_key:"field",ref:h,class:["searchable-select-field-input",{"has-clear-button":C.value,formGroupClasses:e.unref(R)}],size:t.size},{...l.$attrs,controlAttributes:e.unref(T),listeners:e.unref(j)},{name:t.name,label:t.label,"model-value":r.value??(c.value&&o?.display?o?.display?.(c.value):c.value),disabled:t.disabled,readonly:t.readonly,color:t.color,error:t.error,errors:t.errors,feedback:t.feedback,valid:t.valid,invalid:t.invalid,onClick:n[0]||(n[0]=u=>d.value&&(a.value=!0)),onFocus:n[1]||(n[1]=u=>d.value&&(a.value=!0)),onBlur:G,onKeypress:e.withKeys(e.withModifiers(P,["prevent"]),["enter"]),onKeydown:[e.withKeys(e.withModifiers(A,["prevent"]),["up"]),e.withKeys(e.withModifiers(D,["prevent"]),["down"])],onKeyup:n[2]||(n[2]=e.withKeys(u=>a.value=!1,["escape"])),onInput:q}),e.createSlots({activity:e.withCtx(()=>[e.renderSlot(l.$slots,"activity",e.normalizeProps(e.guardReactiveProps({disabled:t.disabled,options:t.options,invalid:t.invalid,valid:t.valid})),()=>[!t.disabled&&!t.options?(e.openBlock(),e.createBlock(e.unref(w.ActivityIndicator),{key:0,type:e.unref(w.Pulse),size:"activity-indicator-sm"},null,8,["type"])):C.value?(e.openBlock(),e.createElementBlock("button",{key:1,type:"button",class:"searchable-select-field-clear-button",onClick:e.withModifiers(L,["stop"])},[e.createVNode(e.unref(x),{class:"size-[1.25em]"})])):!t.invalid&&!t.valid?(e.openBlock(),e.createElementBlock("button",{key:2,type:"button",onClick:e.withModifiers(U,["stop"])},[e.createVNode(e.unref(M),{class:"size-[1em]"})])):e.createCommentVNode("",!0)])]),_:2},[l.$slots.icon?{name:"icon",fn:e.withCtx(()=>[e.renderSlot(l.$slots,"icon")]),key:"0"}:void 0]),1040,["class","size","name","label","model-value","disabled","readonly","color","error","errors","feedback","valid","invalid","onKeypress","onKeydown"]),a.value&&f.value.length?(e.openBlock(),e.createElementBlock("div",{key:0,ref_key:"optionsEl",ref:y,tabindex:"-1",class:e.normalizeClass(["searchable-select-field-dropdown",t.size]),onMousedown:n[4]||(n[4]=e.withModifiers(()=>{},["prevent","stop"]))},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(f.value,(u,k)=>(e.openBlock(),e.createElementBlock("button",{ref_for:!0,ref_key:"buttons",ref:v,key:k,type:"button",tabindex:"-1",title:t.display?.(u)??String(u),class:e.normalizeClass({"bg-neutral-200 dark:bg-neutral-700":i.value===k}),onMousedown:n[3]||(n[3]=e.withModifiers(()=>{},["prevent"])),onClick:g=>J(u)},[e.renderSlot(l.$slots,"default",e.mergeProps({ref_for:!0},{option:u,display:t.display}),()=>[e.createElementVNode("div",$,e.toDisplayString(t.display?.(u)??u),1)])],42,K))),128))],34)):e.createCommentVNode("",!0)]))}});s.SearchableSelectField=F,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(s,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue"),require("@vue-interface/activity-indicator"),require("@vue-interface/form-control"),require("@vue-interface/input-field"),require("fuse.js")):typeof define=="function"&&define.amd?define(["exports","vue","@vue-interface/activity-indicator","@vue-interface/form-control","@vue-interface/input-field","fuse.js"],e):(s=typeof globalThis<"u"?globalThis:s||self,e(s.SearchableSelectField={},s.Vue,s.VueInterfaceActivityIndicator,s.VueInterfaceFormControl,s.VueInterfaceInputField,s.FuseJs))})(this,(function(s,e,w,V,S,E){"use strict";function M(t,p){return e.openBlock(),e.createElementBlock("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor","aria-hidden":"true","data-slot":"icon"},[e.createElementVNode("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"m19.5 8.25-7.5 7.5-7.5-7.5"})])}function x(t,p){return e.openBlock(),e.createElementBlock("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor","aria-hidden":"true","data-slot":"icon"},[e.createElementVNode("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M6 18 18 6M6 6l12 12"})])}const z={class:"relative [&_.form-control]:pr-8"},K=["title","onClick"],$={class:"truncate"},F=e.defineComponent({__name:"SearchableSelectField",props:e.mergeModels({activity:{type:Boolean},disabled:{type:Boolean},error:{},errors:{},feedback:{},formControlClass:{default:"form-control"},helpText:{},id:{},indicator:{},indicatorSize:{},invalid:{type:Boolean},label:{},labelClass:{default:"form-label"},modelValue:{},name:{},plaintext:{type:Boolean},size:{default:"form-control-md"},color:{},readonly:{type:Boolean},valid:{type:Boolean},value:{},options:{default:()=>[]},fuseOptions:{},display:{},allowCustom:{type:Boolean},clearable:{type:Boolean,default:!0}},{modelValue:{},modelModifiers:{}}),emits:e.mergeModels(["blur","focus","focusin","focusout","click","doubleclick","contextmenu","mousedown","mouseup","mouseover","mouseout","mouseenter","mouseleave","mousemove","keydown","keyup","keypress","select","selectionchange","invalid","submit","reset","scroll","wheel","copy","cut","paste","touchstart","touchend","touchmove","touchcancel","change","input","beforeinput"],["update:modelValue"]),setup(t,{emit:p}){const o=t,c=e.useModel(t,"modelValue"),d=e.computed(()=>!o.disabled&&!o.readonly),I=p,{formGroupClasses:T,listeners:R}=V.useFormControl({model:c,props:o,emit:I});e.watchEffect(()=>{o.value!==void 0&&(c.value=o.value)});const r=e.ref(),h=e.useTemplateRef("field"),a=e.ref(!1),i=e.ref(),v=e.useTemplateRef("buttons"),y=e.useTemplateRef("optionsEl"),j=e.computed(()=>typeof o.options=="object"&&o.options?.[0]?Object.keys(o.options?.[0]):["$"]);let b=B();function B(){return new E(o.options??[],o.fuseOptions??{includeScore:!0,threshold:.45,keys:j.value})}const f=e.computed(()=>{if(!r.value)return o.options??[];const l=b.search(r.value).map(({item:n})=>n);return o.allowCustom&&!l.length?o.options:l});e.watch(()=>o.options,()=>{b=B()});function N(l){const n=y.value;if(!n||!l)return;const u=n.getBoundingClientRect(),g=l.getBoundingClientRect().top-u.top+n.scrollTop;n.scrollTop=g}e.watch([r,i],([l,n])=>{l?v.value?.[0]?.scrollIntoView({block:"nearest",inline:"nearest"}):n!==void 0&&v.value?.[n]?.scrollIntoView({block:"nearest",inline:"nearest"})}),e.watch(y,l=>{!l||i.value===void 0||e.nextTick(()=>{N(v.value?.[i.value])})});function m(l){c.value=l,i.value=l&&o.options.includes(l)?o.options.indexOf(l):void 0,r.value=void 0,a.value=!1}function O(l){d.value&&(a.value=!0,i.value=void 0,r.value=l.target?.value,!r.value&&!o.allowCustom&&(c.value=void 0),o.allowCustom&&(c.value=r.value))}function q(){if(d.value){if(!a.value){a.value=!0;return}o.allowCustom&&i.value===void 0?m(r.value??c.value):i.value===void 0?m(f.value[0]):f.value[i.value]?m(f.value[i.value]):m(void 0)}}function P(){d.value&&(a.value=!0,i.value?i.value--:i.value=f.value.length-1)}function A(){d.value&&(a.value=!0,i.value===void 0||i.value===f.value.length-1?i.value=0:i.value++)}function D(){a.value=!1,r.value=void 0}function G(l){d.value&&m(l)}function J(){d.value&&(r.value=void 0,c.value=void 0)}function L(){d.value&&(a.value?a.value=!1:(a.value=!0,h.value?.$el?.querySelector("input")?.focus()))}const C=e.computed(()=>o.clearable&&(!!r.value||!!c.value)&&d.value);return(l,n)=>(e.openBlock(),e.createElementBlock("div",z,[e.createVNode(e.unref(S.InputField),e.mergeProps({ref_key:"field",ref:h,class:["searchable-select-field-input",{"has-clear-button":C.value,formGroupClasses:e.unref(T)}],size:t.size},{...l.$attrs,...e.unref(R)},{name:t.name,label:t.label,"model-value":r.value??(c.value&&o?.display?o?.display?.(c.value):c.value),disabled:t.disabled,readonly:t.readonly,color:t.color,error:t.error,errors:t.errors,feedback:t.feedback,valid:t.valid,invalid:t.invalid,onClick:n[0]||(n[0]=u=>d.value&&(a.value=!0)),onFocus:n[1]||(n[1]=u=>d.value&&(a.value=!0)),onBlur:D,onKeypress:e.withKeys(e.withModifiers(q,["prevent"]),["enter"]),onKeydown:[e.withKeys(e.withModifiers(P,["prevent"]),["up"]),e.withKeys(e.withModifiers(A,["prevent"]),["down"])],onKeyup:n[2]||(n[2]=e.withKeys(u=>a.value=!1,["escape"])),onInput:O}),e.createSlots({activity:e.withCtx(()=>[e.renderSlot(l.$slots,"activity",e.normalizeProps(e.guardReactiveProps({disabled:t.disabled,options:t.options,invalid:t.invalid,valid:t.valid})),()=>[!t.disabled&&!t.options?(e.openBlock(),e.createBlock(e.unref(w.ActivityIndicator),{key:0,type:e.unref(w.Pulse),size:"activity-indicator-sm"},null,8,["type"])):C.value?(e.openBlock(),e.createElementBlock("button",{key:1,type:"button",class:"searchable-select-field-clear-button",onClick:e.withModifiers(J,["stop"])},[e.createVNode(e.unref(x),{class:"size-[1.25em]"})])):!t.invalid&&!t.valid?(e.openBlock(),e.createElementBlock("button",{key:2,type:"button",onClick:e.withModifiers(L,["stop"])},[e.createVNode(e.unref(M),{class:"size-[1em]"})])):e.createCommentVNode("",!0)])]),_:2},[l.$slots.icon?{name:"icon",fn:e.withCtx(()=>[e.renderSlot(l.$slots,"icon")]),key:"0"}:void 0]),1040,["class","size","name","label","model-value","disabled","readonly","color","error","errors","feedback","valid","invalid","onKeypress","onKeydown"]),a.value&&f.value.length?(e.openBlock(),e.createElementBlock("div",{key:0,ref_key:"optionsEl",ref:y,tabindex:"-1",class:e.normalizeClass(["searchable-select-field-dropdown",t.size]),onMousedown:n[4]||(n[4]=e.withModifiers(()=>{},["prevent","stop"]))},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(f.value,(u,k)=>(e.openBlock(),e.createElementBlock("button",{ref_for:!0,ref_key:"buttons",ref:v,key:k,type:"button",tabindex:"-1",title:t.display?.(u)??String(u),class:e.normalizeClass({"bg-neutral-200 dark:bg-neutral-700":i.value===k}),onMousedown:n[3]||(n[3]=e.withModifiers(()=>{},["prevent"])),onClick:g=>G(u)},[e.renderSlot(l.$slots,"default",e.mergeProps({ref_for:!0},{option:u,display:t.display}),()=>[e.createElementVNode("div",$,e.toDisplayString(t.display?.(u)??u),1)])],42,K))),128))],34)):e.createCommentVNode("",!0)]))}});s.SearchableSelectField=F,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})}));
2
2
  //# sourceMappingURL=searchable-select-field.umd.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"searchable-select-field.umd.cjs","sources":["../../../node_modules/.pnpm/@heroicons+vue@2.2.0_vue@3.5.26_typescript@5.9.3_/node_modules/@heroicons/vue/24/outline/esm/ChevronDownIcon.js","../../../node_modules/.pnpm/@heroicons+vue@2.2.0_vue@3.5.26_typescript@5.9.3_/node_modules/@heroicons/vue/24/outline/esm/XMarkIcon.js","../src/SearchableSelectField.vue"],"sourcesContent":["import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport default function render(_ctx, _cache) {\n return (_openBlock(), _createElementBlock(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n fill: \"none\",\n viewBox: \"0 0 24 24\",\n \"stroke-width\": \"1.5\",\n stroke: \"currentColor\",\n \"aria-hidden\": \"true\",\n \"data-slot\": \"icon\"\n }, [\n _createElementVNode(\"path\", {\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n d: \"m19.5 8.25-7.5 7.5-7.5-7.5\"\n })\n ]))\n}","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport default function render(_ctx, _cache) {\n return (_openBlock(), _createElementBlock(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n fill: \"none\",\n viewBox: \"0 0 24 24\",\n \"stroke-width\": \"1.5\",\n stroke: \"currentColor\",\n \"aria-hidden\": \"true\",\n \"data-slot\": \"icon\"\n }, [\n _createElementVNode(\"path\", {\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n d: \"M6 18 18 6M6 6l12 12\"\n })\n ]))\n}","<script setup lang=\"ts\" generic=\"T, Value\">\nimport { ChevronDownIcon, XMarkIcon } from '@heroicons/vue/24/outline';\nimport { ActivityIndicator, Pulse } from '@vue-interface/activity-indicator';\nimport type { FormControlEvents, FormControlProps, FormControlSlots } from '@vue-interface/form-control';\nimport { useFormControl } from '@vue-interface/form-control';\nimport { InputField } from '@vue-interface/input-field';\nimport Fuse, { IFuseOptions } from 'fuse.js';\nimport { InputHTMLAttributes, computed, nextTick, ref, useTemplateRef, watch, watchEffect } from 'vue';\n\nconst props = withDefaults(defineProps<SearchableSelectFieldProps<T,Value>>(), {\n formControlClass: 'form-control',\n labelClass: 'form-label',\n size: 'form-control-md',\n clearable: true,\n options: () => []\n});\n\nconst model = defineModel<T>();\nconst isInteractive = computed(() => !props.disabled && !props.readonly);\n\ndefineSlots<FormControlSlots<SearchableSelectFieldSizePrefix,T> & {\n default(props: { option: T; display?: (option: T) => string }): any;\n}>();\n\nconst emit = defineEmits<FormControlEvents>();\n\nconst {\n controlAttributes,\n formGroupClasses,\n listeners\n} = useFormControl<InputHTMLAttributes, SearchableSelectFieldSizePrefix, T|undefined, T>({ model, props, emit });\n\nwatchEffect(() => {\n if(props.value !== undefined) {\n model.value = props.value;\n }\n});\n\nconst input = ref<string>();\nconst field = useTemplateRef<any>('field');\nconst showOptions = ref(false);\nconst active = ref<number>();\nconst buttons = useTemplateRef<HTMLButtonElement[]>('buttons');\nconst optionsEl = useTemplateRef<HTMLDivElement>('optionsEl');\n\nconst keys = computed(() => {\n return typeof props.options === 'object' && props.options?.[0]\n ? Object.keys(props.options?.[0])\n : ['$'];\n});\n\nlet fuse: Fuse<T> = createFuse();\n\nfunction createFuse() {\n return new Fuse(props.options ?? [], props.fuseOptions ?? {\n includeScore: true,\n threshold: .45,\n keys: keys.value\n });\n}\n\nconst filtered = computed<T[]>(() => {\n if(!input.value) {\n return props.options ?? [];\n }\n\n const matches = fuse.search(input.value).map(({ item }) => item);\n\n if(props.allowCustom && !matches.length) {\n return props.options;\n }\n\n return matches;\n});\n\nwatch(() => props.options, () => {\n fuse = createFuse();\n});\n\nfunction scrollIntoView(child?: HTMLElement) {\n const parent = optionsEl.value;\n\n if(!parent || !child) {\n return;\n }\n\n const parentRect = parent.getBoundingClientRect();\n const childRect = child.getBoundingClientRect();\n\n const childTop = childRect.top - parentRect.top + parent.scrollTop;\n\n parent.scrollTop = childTop;\n};\n\nwatch([input, active], ([input, active]) => {\n if(input) {\n buttons.value?.[0]?.scrollIntoView({\n block: 'nearest',\n inline: 'nearest'\n });\n }\n else if(active !== undefined) {\n buttons.value?.[active]?.scrollIntoView({\n block: 'nearest',\n inline: 'nearest'\n });\n }\n});\n\nwatch(optionsEl, (value) => {\n if(!value || active.value === undefined) {\n return;\n }\n\n nextTick(() => {\n scrollIntoView(buttons.value?.[active.value as number]);\n });\n});\n\nfunction select(option?: T) {\n model.value = option;\n active.value = option && props.options.includes(option)\n ? props.options.indexOf(option)\n : undefined;\n input.value = undefined;\n showOptions.value = false;\n}\n\nfunction onInput(e: Event) {\n if (!isInteractive.value) return;\n\n showOptions.value = true;\n active.value = undefined;\n input.value = (e.target as HTMLInputElement)?.value;\n\n if(!input.value && !props.allowCustom) {\n model.value = undefined;\n }\n\n if(props.allowCustom) {\n model.value = input.value as T;\n }\n}\n\nfunction onKeypressEnter() {\n if (!isInteractive.value) return;\n\n if(!showOptions.value) {\n showOptions.value = true;\n return;\n }\n\n if(props.allowCustom && active.value === undefined) {\n select(input.value as T ?? model.value);\n }\n else if(active.value === undefined) {\n select(filtered.value[0]);\n }\n else if(filtered.value[active.value]) {\n select(filtered.value[active.value]);\n }\n else {\n select(undefined);\n }\n}\n\nfunction onKeydownUp() {\n if (!isInteractive.value) return;\n \n showOptions.value = true;\n\n if(!active.value) {\n active.value = filtered.value.length - 1;\n }\n else {\n active.value--;\n }\n}\n\nfunction onKeydownDown() {\n if (!isInteractive.value) return;\n\n showOptions.value = true;\n\n if(active.value === undefined || active.value === filtered.value.length - 1) {\n active.value = 0;\n }\n else {\n active.value++;\n }\n}\n\nfunction onBlur() {\n showOptions.value = false;\n input.value = undefined;\n}\n\nfunction onClickOption(option: T) {\n if (!isInteractive.value) return;\n select(option);\n}\n\nfunction clear() {\n if (!isInteractive.value) return;\n input.value = undefined;\n model.value = undefined;\n}\n\nfunction toggle() {\n if (!isInteractive.value) return;\n \n if(showOptions.value ) {\n showOptions.value = false;\n }\n else {\n showOptions.value = true;\n field.value?.$el?.querySelector('input')?.focus();\n }\n}\n\nconst canClear = computed(() => {\n return props.clearable && (!!input.value || !!model.value) && isInteractive.value;\n});\n</script>\n<script lang=\"ts\">\nexport type SearchableSelectFieldSizePrefix = 'form-control';\n\nexport type SearchableSelectFieldProps<ModelValue, Value> = FormControlProps<\n InputHTMLAttributes, \n SearchableSelectFieldSizePrefix, \n ModelValue, \n Value\n> & {\n options?: ModelValue[];\n fuseOptions?: IFuseOptions<ModelValue>;\n display?: (option: ModelValue) => string;\n allowCustom?: boolean;\n clearable?: boolean;\n};\n</script>\n\n\n<template>\n <div class=\"relative [&_.form-control]:pr-8\">\n <InputField\n ref=\"field\"\n class=\"searchable-select-field-input\"\n :class=\"{ 'has-clear-button': canClear, formGroupClasses }\"\n :size=\"size\"\n v-bind=\"{ ...$attrs, controlAttributes, listeners }\"\n :name=\"name\"\n :label=\"label\"\n :model-value=\"input ?? (model && props?.display ? props?.display?.(model) : model)\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :color=\"color\"\n :error=\"error\"\n :errors=\"errors\"\n :feedback=\"feedback\"\n :valid=\"valid\"\n :invalid=\"invalid\"\n @click=\"isInteractive && (showOptions = true)\"\n @focus=\"isInteractive && (showOptions = true)\"\n @blur=\"onBlur\"\n @keypress.enter.prevent=\"onKeypressEnter\"\n @keydown.up.prevent=\"onKeydownUp\"\n @keydown.down.prevent=\"onKeydownDown\"\n @keyup.escape=\"showOptions = false\"\n @input=\"onInput\">\n <template #icon v-if=\"$slots.icon\">\n <slot name=\"icon\" />\n </template>\n <template #activity>\n <slot\n name=\"activity\"\n v-bind=\"{ disabled, options, invalid, valid }\">\n <ActivityIndicator\n v-if=\"!disabled && !options\"\n :type=\"Pulse\"\n size=\"activity-indicator-sm\" />\n <button\n v-else-if=\"canClear\"\n type=\"button\"\n class=\"searchable-select-field-clear-button\"\n @click.stop=\"clear\">\n <XMarkIcon class=\"size-[1.25em]\" />\n </button>\n <button\n v-else-if=\"!invalid && !valid\"\n type=\"button\"\n @click.stop=\"toggle\">\n <ChevronDownIcon class=\"size-[1em]\" />\n </button>\n </slot>\n </template>\n </InputField>\n <div\n v-if=\"showOptions && filtered.length\"\n ref=\"optionsEl\"\n tabindex=\"-1\"\n class=\"searchable-select-field-dropdown\"\n :class=\"size\"\n @mousedown.prevent.stop>\n <button\n v-for=\"(option, i) in filtered\"\n ref=\"buttons\"\n :key=\"i\"\n type=\"button\"\n tabindex=\"-1\"\n :title=\"display?.(option) ?? String(option)\"\n :class=\"{\n ['bg-neutral-200 dark:bg-neutral-700']: active === i\n }\"\n @mousedown.prevent\n @click=\"onClickOption(option)\">\n <slot v-bind=\"{ option, display }\">\n <div class=\"truncate\">\n {{ display?.(option) ?? option }}\n </div>\n </slot>\n </button>\n </div>\n </div>\n</template>"],"names":["render","_ctx","_cache","_openBlock","_createElementBlock","_createElementVNode","props","__props","model","_useModel","isInteractive","computed","emit","__emit","controlAttributes","formGroupClasses","listeners","useFormControl","watchEffect","input","ref","field","useTemplateRef","showOptions","active","buttons","optionsEl","keys","fuse","createFuse","Fuse","filtered","matches","item","watch","scrollIntoView","child","parent","parentRect","childTop","value","nextTick","select","option","onInput","e","onKeypressEnter","onKeydownUp","onKeydownDown","onBlur","onClickOption","clear","toggle","canClear","_hoisted_1","_createVNode","_unref","_mergeProps","$attrs","$event","_renderSlot","_normalizeProps","_guardReactiveProps","_createBlock","ActivityIndicator","Pulse","XMarkIcon","ChevronDownIcon","$slots","_normalizeClass","_Fragment","_renderList","i","_hoisted_3","_toDisplayString"],"mappings":"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","x_google_ignoreList":[0,1]}
1
+ {"version":3,"file":"searchable-select-field.umd.cjs","sources":["../../../node_modules/.pnpm/@heroicons+vue@2.2.0_vue@3.5.27_typescript@5.9.3_/node_modules/@heroicons/vue/24/outline/esm/ChevronDownIcon.js","../../../node_modules/.pnpm/@heroicons+vue@2.2.0_vue@3.5.27_typescript@5.9.3_/node_modules/@heroicons/vue/24/outline/esm/XMarkIcon.js","../src/SearchableSelectField.vue"],"sourcesContent":["import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport default function render(_ctx, _cache) {\n return (_openBlock(), _createElementBlock(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n fill: \"none\",\n viewBox: \"0 0 24 24\",\n \"stroke-width\": \"1.5\",\n stroke: \"currentColor\",\n \"aria-hidden\": \"true\",\n \"data-slot\": \"icon\"\n }, [\n _createElementVNode(\"path\", {\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n d: \"m19.5 8.25-7.5 7.5-7.5-7.5\"\n })\n ]))\n}","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport default function render(_ctx, _cache) {\n return (_openBlock(), _createElementBlock(\"svg\", {\n xmlns: \"http://www.w3.org/2000/svg\",\n fill: \"none\",\n viewBox: \"0 0 24 24\",\n \"stroke-width\": \"1.5\",\n stroke: \"currentColor\",\n \"aria-hidden\": \"true\",\n \"data-slot\": \"icon\"\n }, [\n _createElementVNode(\"path\", {\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n d: \"M6 18 18 6M6 6l12 12\"\n })\n ]))\n}","<script setup lang=\"ts\" generic=\"ModelValue, Value extends ModelValue\">\nimport { ChevronDownIcon, XMarkIcon } from '@heroicons/vue/24/outline';\nimport { ActivityIndicator, Pulse } from '@vue-interface/activity-indicator';\nimport type { FormControlEvents, FormControlProps, FormControlSlots } from '@vue-interface/form-control';\nimport { useFormControl } from '@vue-interface/form-control';\nimport { InputField } from '@vue-interface/input-field';\nimport Fuse, { IFuseOptions } from 'fuse.js';\nimport { type HTMLAttributes, computed, nextTick, ref, useTemplateRef, watch, watchEffect } from 'vue';\n\nconst props = withDefaults(defineProps<SearchableSelectFieldProps<ModelValue,Value>>(), {\n formControlClass: 'form-control',\n labelClass: 'form-label',\n size: 'form-control-md',\n clearable: true,\n options: () => []\n});\n\nconst model = defineModel<ModelValue>();\nconst isInteractive = computed(() => !props.disabled && !props.readonly);\n\ndefineSlots<FormControlSlots<SearchableSelectFieldSizePrefix,ModelValue> & {\n default(props: { option: ModelValue; display?: (option: ModelValue) => string }): any;\n}>();\n\nconst emit = defineEmits<FormControlEvents>();\n\nconst {\n formGroupClasses,\n listeners\n} = useFormControl<HTMLAttributes, SearchableSelectFieldSizePrefix, ModelValue|undefined, ModelValue>({ model, props, emit });\n\nwatchEffect(() => {\n if(props.value !== undefined) {\n model.value = props.value;\n }\n});\n\nconst input = ref<string>();\nconst field = useTemplateRef<any>('field');\nconst showOptions = ref(false);\nconst active = ref<number>();\nconst buttons = useTemplateRef<HTMLButtonElement[]>('buttons');\nconst optionsEl = useTemplateRef<HTMLDivElement>('optionsEl');\n\nconst keys = computed(() => {\n return typeof props.options === 'object' && props.options?.[0]\n ? Object.keys(props.options?.[0])\n : ['$'];\n});\n\nlet fuse: Fuse<ModelValue> = createFuse();\n\nfunction createFuse() {\n return new Fuse(props.options ?? [], props.fuseOptions ?? {\n includeScore: true,\n threshold: .45,\n keys: keys.value\n });\n}\n\nconst filtered = computed<ModelValue[]>(() => {\n if(!input.value) {\n return props.options ?? [];\n }\n\n const matches = fuse.search(input.value).map(({ item }) => item);\n\n if(props.allowCustom && !matches.length) {\n return props.options;\n }\n\n return matches;\n});\n\nwatch(() => props.options, () => {\n fuse = createFuse();\n});\n\nfunction scrollIntoView(child?: HTMLElement) {\n const parent = optionsEl.value;\n\n if(!parent || !child) {\n return;\n }\n\n const parentRect = parent.getBoundingClientRect();\n const childRect = child.getBoundingClientRect();\n\n const childTop = childRect.top - parentRect.top + parent.scrollTop;\n\n parent.scrollTop = childTop;\n};\n\nwatch([input, active], ([input, active]) => {\n if(input) {\n buttons.value?.[0]?.scrollIntoView({\n block: 'nearest',\n inline: 'nearest'\n });\n }\n else if(active !== undefined) {\n buttons.value?.[active]?.scrollIntoView({\n block: 'nearest',\n inline: 'nearest'\n });\n }\n});\n\nwatch(optionsEl, (value) => {\n if(!value || active.value === undefined) {\n return;\n }\n\n nextTick(() => {\n scrollIntoView(buttons.value?.[active.value as number]);\n });\n});\n\nfunction select(option?: ModelValue) {\n model.value = option;\n active.value = option && props.options.includes(option)\n ? props.options.indexOf(option)\n : undefined;\n input.value = undefined;\n showOptions.value = false;\n}\n\nfunction onInput(e: Event) {\n if (!isInteractive.value) return;\n\n showOptions.value = true;\n active.value = undefined;\n input.value = (e.target as HTMLInputElement)?.value;\n\n if(!input.value && !props.allowCustom) {\n model.value = undefined;\n }\n\n if(props.allowCustom) {\n model.value = input.value as ModelValue;\n }\n}\n\nfunction onKeypressEnter() {\n if (!isInteractive.value) return;\n\n if(!showOptions.value) {\n showOptions.value = true;\n return;\n }\n\n if(props.allowCustom && active.value === undefined) {\n select(input.value as ModelValue ?? model.value);\n }\n else if(active.value === undefined) {\n select(filtered.value[0]);\n }\n else if(filtered.value[active.value]) {\n select(filtered.value[active.value]);\n }\n else {\n select(undefined);\n }\n}\n\nfunction onKeydownUp() {\n if (!isInteractive.value) return;\n \n showOptions.value = true;\n\n if(!active.value) {\n active.value = filtered.value.length - 1;\n }\n else {\n active.value--;\n }\n}\n\nfunction onKeydownDown() {\n if (!isInteractive.value) return;\n\n showOptions.value = true;\n\n if(active.value === undefined || active.value === filtered.value.length - 1) {\n active.value = 0;\n }\n else {\n active.value++;\n }\n}\n\nfunction onBlur() {\n showOptions.value = false;\n input.value = undefined;\n}\n\nfunction onClickOption(option: ModelValue) {\n if (!isInteractive.value) return;\n select(option);\n}\n\nfunction clear() {\n if (!isInteractive.value) return;\n input.value = undefined;\n model.value = undefined;\n}\n\nfunction toggle() {\n if (!isInteractive.value) return;\n \n if(showOptions.value ) {\n showOptions.value = false;\n }\n else {\n showOptions.value = true;\n field.value?.$el?.querySelector('input')?.focus();\n }\n}\n\nconst canClear = computed(() => {\n return props.clearable && (!!input.value || !!model.value) && isInteractive.value;\n});\n</script>\n<script lang=\"ts\">\nexport type SearchableSelectFieldSizePrefix = 'form-control';\n\nexport type SearchableSelectFieldProps<ModelValue, Value> = FormControlProps<\n HTMLAttributes, \n SearchableSelectFieldSizePrefix, \n ModelValue, \n Value\n> & {\n options?: ModelValue[];\n fuseOptions?: IFuseOptions<ModelValue>;\n display?: (option: ModelValue) => string;\n allowCustom?: boolean;\n clearable?: boolean;\n};\n</script>\n\n\n<template>\n <div class=\"relative [&_.form-control]:pr-8\">\n <InputField\n ref=\"field\"\n class=\"searchable-select-field-input\"\n :class=\"{ 'has-clear-button': canClear, formGroupClasses }\"\n :size=\"size\"\n v-bind=\"{ ...$attrs, ...listeners }\"\n :name=\"name\"\n :label=\"label\"\n :model-value=\"input ?? (model && props?.display ? props?.display?.(model) : model)\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :color=\"color\"\n :error=\"error\"\n :errors=\"errors\"\n :feedback=\"feedback\"\n :valid=\"valid\"\n :invalid=\"invalid\"\n @click=\"isInteractive && (showOptions = true)\"\n @focus=\"isInteractive && (showOptions = true)\"\n @blur=\"onBlur\"\n @keypress.enter.prevent=\"onKeypressEnter\"\n @keydown.up.prevent=\"onKeydownUp\"\n @keydown.down.prevent=\"onKeydownDown\"\n @keyup.escape=\"showOptions = false\"\n @input=\"onInput\">\n <template #icon v-if=\"$slots.icon\">\n <slot name=\"icon\" />\n </template>\n <template #activity>\n <slot\n name=\"activity\"\n v-bind=\"{ disabled, options, invalid, valid }\">\n <ActivityIndicator\n v-if=\"!disabled && !options\"\n :type=\"Pulse\"\n size=\"activity-indicator-sm\" />\n <button\n v-else-if=\"canClear\"\n type=\"button\"\n class=\"searchable-select-field-clear-button\"\n @click.stop=\"clear\">\n <XMarkIcon class=\"size-[1.25em]\" />\n </button>\n <button\n v-else-if=\"!invalid && !valid\"\n type=\"button\"\n @click.stop=\"toggle\">\n <ChevronDownIcon class=\"size-[1em]\" />\n </button>\n </slot>\n </template>\n </InputField>\n <div\n v-if=\"showOptions && filtered.length\"\n ref=\"optionsEl\"\n tabindex=\"-1\"\n class=\"searchable-select-field-dropdown\"\n :class=\"size\"\n @mousedown.prevent.stop>\n <button\n v-for=\"(option, i) in filtered\"\n ref=\"buttons\"\n :key=\"i\"\n type=\"button\"\n tabindex=\"-1\"\n :title=\"display?.(option) ?? String(option)\"\n :class=\"{\n ['bg-neutral-200 dark:bg-neutral-700']: active === i\n }\"\n @mousedown.prevent\n @click=\"onClickOption(option)\">\n <slot v-bind=\"{ option, display }\">\n <div class=\"truncate\">\n {{ display?.(option) ?? option }}\n </div>\n </slot>\n </button>\n </div>\n </div>\n</template>"],"names":["render","_ctx","_cache","_openBlock","_createElementBlock","_createElementVNode","props","__props","model","_useModel","isInteractive","computed","emit","__emit","formGroupClasses","listeners","useFormControl","watchEffect","input","ref","field","useTemplateRef","showOptions","active","buttons","optionsEl","keys","fuse","createFuse","Fuse","filtered","matches","item","watch","scrollIntoView","child","parent","parentRect","childTop","value","nextTick","select","option","onInput","e","onKeypressEnter","onKeydownUp","onKeydownDown","onBlur","onClickOption","clear","toggle","canClear","_hoisted_1","_createVNode","_unref","_mergeProps","$attrs","$event","_renderSlot","_normalizeProps","_guardReactiveProps","_createBlock","ActivityIndicator","Pulse","XMarkIcon","ChevronDownIcon","$slots","_normalizeClass","_Fragment","_renderList","i","_hoisted_3","_toDisplayString"],"mappings":"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","x_google_ignoreList":[0,1]}
@@ -1,15 +1,15 @@
1
1
  import { FormControlProps, FormControlSlots } from '@vue-interface/form-control';
2
2
  import { IFuseOptions } from 'fuse.js';
3
- import { InputHTMLAttributes } from 'vue';
3
+ import { HTMLAttributes } from 'vue';
4
4
  export type SearchableSelectFieldSizePrefix = 'form-control';
5
- export type SearchableSelectFieldProps<ModelValue, Value> = FormControlProps<InputHTMLAttributes, SearchableSelectFieldSizePrefix, ModelValue, Value> & {
5
+ export type SearchableSelectFieldProps<ModelValue, Value> = FormControlProps<HTMLAttributes, SearchableSelectFieldSizePrefix, ModelValue, Value> & {
6
6
  options?: ModelValue[];
7
7
  fuseOptions?: IFuseOptions<ModelValue>;
8
8
  display?: (option: ModelValue) => string;
9
9
  allowCustom?: boolean;
10
10
  clearable?: boolean;
11
11
  };
12
- declare const _default: <T, Value>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
12
+ declare const _default: <ModelValue, Value extends ModelValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
13
13
  props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{
14
14
  readonly onInput?: ((event: Event) => any) | undefined;
15
15
  readonly onSelect?: ((event: Event) => any) | undefined;
@@ -45,9 +45,9 @@ declare const _default: <T, Value>(__VLS_props: NonNullable<Awaited<typeof __VLS
45
45
  readonly onTouchcancel?: ((event: TouchEvent) => any) | undefined;
46
46
  readonly onChange?: ((event: Event) => any) | undefined;
47
47
  readonly onBeforeinput?: ((event: Event) => any) | undefined;
48
- readonly "onUpdate:modelValue"?: ((value: T) => any) | undefined;
48
+ readonly "onUpdate:modelValue"?: ((value: ModelValue) => any) | undefined;
49
49
  } & import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, never>, "onCopy" | "onCut" | "onPaste" | "onFocus" | "onFocusin" | "onFocusout" | "onBlur" | "onChange" | "onBeforeinput" | "onInput" | "onReset" | "onSubmit" | "onInvalid" | "onKeydown" | "onKeypress" | "onKeyup" | "onMousedown" | "onMouseenter" | "onMouseleave" | "onMousemove" | "onMouseout" | "onMouseover" | "onMouseup" | "onSelect" | "onScroll" | "onTouchcancel" | "onTouchend" | "onTouchmove" | "onTouchstart" | "onClick" | "onContextmenu" | "onWheel" | "onDoubleclick" | "onSelectionchange" | "onUpdate:modelValue"> & ({
50
- modelValue?: T;
50
+ modelValue?: ModelValue;
51
51
  } & {
52
52
  activity?: boolean;
53
53
  disabled?: boolean;
@@ -62,7 +62,7 @@ declare const _default: <T, Value>(__VLS_props: NonNullable<Awaited<typeof __VLS
62
62
  invalid?: boolean;
63
63
  label?: string;
64
64
  labelClass?: string;
65
- modelValue?: T | undefined;
65
+ modelValue?: ModelValue | undefined;
66
66
  name?: string;
67
67
  plaintext?: boolean;
68
68
  size?: import('@vue-interface/form-control').FormControlSize<"form-control"> | undefined;
@@ -70,27 +70,27 @@ declare const _default: <T, Value>(__VLS_props: NonNullable<Awaited<typeof __VLS
70
70
  readonly?: boolean;
71
71
  valid?: boolean;
72
72
  value?: Value | undefined;
73
- } & Omit<InputHTMLAttributes, "size"> & {
74
- options?: T[] | undefined;
75
- fuseOptions?: IFuseOptions<T> | undefined;
76
- display?: ((option: T) => string) | undefined;
73
+ } & Omit<HTMLAttributes, "size"> & {
74
+ options?: ModelValue[] | undefined;
75
+ fuseOptions?: IFuseOptions<ModelValue> | undefined;
76
+ display?: ((option: ModelValue) => string) | undefined;
77
77
  allowCustom?: boolean;
78
78
  clearable?: boolean;
79
79
  }) & Partial<{}>> & import('vue').PublicProps;
80
80
  expose(exposed: import('vue').ShallowUnwrapRef<{}>): void;
81
81
  attrs: any;
82
- slots: Readonly<FormControlSlots<"form-control", T> & {
82
+ slots: Readonly<FormControlSlots<"form-control", ModelValue> & {
83
83
  default(props: {
84
- option: T;
85
- display?: (option: T) => string;
84
+ option: ModelValue;
85
+ display?: (option: ModelValue) => string;
86
86
  }): any;
87
- }> & FormControlSlots<"form-control", T> & {
87
+ }> & FormControlSlots<"form-control", ModelValue> & {
88
88
  default(props: {
89
- option: T;
90
- display?: (option: T) => string;
89
+ option: ModelValue;
90
+ display?: (option: ModelValue) => string;
91
91
  }): any;
92
92
  };
93
- emit: (((evt: "input", event: Event) => void) & ((evt: "select", event: Event) => void) & ((evt: "blur", event: FocusEvent) => void) & ((evt: "focus", event: FocusEvent) => void) & ((evt: "focusin", event: FocusEvent) => void) & ((evt: "focusout", event: FocusEvent) => void) & ((evt: "click", event: MouseEvent) => void) & ((evt: "doubleclick", event: MouseEvent) => void) & ((evt: "contextmenu", event: MouseEvent) => void) & ((evt: "mousedown", event: MouseEvent) => void) & ((evt: "mouseup", event: MouseEvent) => void) & ((evt: "mouseover", event: MouseEvent) => void) & ((evt: "mouseout", event: MouseEvent) => void) & ((evt: "mouseenter", event: MouseEvent) => void) & ((evt: "mouseleave", event: MouseEvent) => void) & ((evt: "mousemove", event: MouseEvent) => void) & ((evt: "keydown", event: KeyboardEvent) => void) & ((evt: "keyup", event: KeyboardEvent) => void) & ((evt: "keypress", event: KeyboardEvent) => void) & ((evt: "selectionchange", event: Event) => void) & ((evt: "invalid", event: Event) => void) & ((evt: "submit", event: Event) => void) & ((evt: "reset", event: Event) => void) & ((evt: "scroll", event: Event) => void) & ((evt: "wheel", event: WheelEvent) => void) & ((evt: "copy", event: ClipboardEvent) => void) & ((evt: "cut", event: ClipboardEvent) => void) & ((evt: "paste", event: ClipboardEvent) => void) & ((evt: "touchstart", event: TouchEvent) => void) & ((evt: "touchend", event: TouchEvent) => void) & ((evt: "touchmove", event: TouchEvent) => void) & ((evt: "touchcancel", event: TouchEvent) => void) & ((evt: "change", event: Event) => void) & ((evt: "beforeinput", event: Event) => void)) & ((evt: "update:modelValue", value: T) => void);
93
+ emit: (((evt: "input", event: Event) => void) & ((evt: "select", event: Event) => void) & ((evt: "blur", event: FocusEvent) => void) & ((evt: "focus", event: FocusEvent) => void) & ((evt: "focusin", event: FocusEvent) => void) & ((evt: "focusout", event: FocusEvent) => void) & ((evt: "click", event: MouseEvent) => void) & ((evt: "doubleclick", event: MouseEvent) => void) & ((evt: "contextmenu", event: MouseEvent) => void) & ((evt: "mousedown", event: MouseEvent) => void) & ((evt: "mouseup", event: MouseEvent) => void) & ((evt: "mouseover", event: MouseEvent) => void) & ((evt: "mouseout", event: MouseEvent) => void) & ((evt: "mouseenter", event: MouseEvent) => void) & ((evt: "mouseleave", event: MouseEvent) => void) & ((evt: "mousemove", event: MouseEvent) => void) & ((evt: "keydown", event: KeyboardEvent) => void) & ((evt: "keyup", event: KeyboardEvent) => void) & ((evt: "keypress", event: KeyboardEvent) => void) & ((evt: "selectionchange", event: Event) => void) & ((evt: "invalid", event: Event) => void) & ((evt: "submit", event: Event) => void) & ((evt: "reset", event: Event) => void) & ((evt: "scroll", event: Event) => void) & ((evt: "wheel", event: WheelEvent) => void) & ((evt: "copy", event: ClipboardEvent) => void) & ((evt: "cut", event: ClipboardEvent) => void) & ((evt: "paste", event: ClipboardEvent) => void) & ((evt: "touchstart", event: TouchEvent) => void) & ((evt: "touchend", event: TouchEvent) => void) & ((evt: "touchmove", event: TouchEvent) => void) & ((evt: "touchcancel", event: TouchEvent) => void) & ((evt: "change", event: Event) => void) & ((evt: "beforeinput", event: Event) => void)) & ((evt: "update:modelValue", value: ModelValue) => void);
94
94
  }>) => import('vue').VNode & {
95
95
  __ctx?: Awaited<typeof __VLS_setup>;
96
96
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vue-interface/searchable-select-field",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "A Vue searchable select field component.",
5
5
  "type": "module",
6
6
  "main": "./dist/searchable-select-field.umd.cjs",
@@ -48,9 +48,9 @@
48
48
  "fuse.js": "^7.1.0",
49
49
  "vue": "^3.3.4",
50
50
  "@vue-interface/activity-indicator": "3.0.8",
51
- "@vue-interface/form-control": "2.0.22",
52
- "@vue-interface/input-field": "3.0.3",
53
- "@vue-interface/sizeable": "2.0.0"
51
+ "@vue-interface/input-field": "3.0.4",
52
+ "@vue-interface/sizeable": "2.0.0",
53
+ "@vue-interface/form-control": "2.0.23"
54
54
  },
55
55
  "scripts": {
56
56
  "dev": "vite",
@@ -1,13 +1,13 @@
1
- <script setup lang="ts" generic="T, Value">
1
+ <script setup lang="ts" generic="ModelValue, Value extends ModelValue">
2
2
  import { ChevronDownIcon, XMarkIcon } from '@heroicons/vue/24/outline';
3
3
  import { ActivityIndicator, Pulse } from '@vue-interface/activity-indicator';
4
4
  import type { FormControlEvents, FormControlProps, FormControlSlots } from '@vue-interface/form-control';
5
5
  import { useFormControl } from '@vue-interface/form-control';
6
6
  import { InputField } from '@vue-interface/input-field';
7
7
  import Fuse, { IFuseOptions } from 'fuse.js';
8
- import { InputHTMLAttributes, computed, nextTick, ref, useTemplateRef, watch, watchEffect } from 'vue';
8
+ import { type HTMLAttributes, computed, nextTick, ref, useTemplateRef, watch, watchEffect } from 'vue';
9
9
 
10
- const props = withDefaults(defineProps<SearchableSelectFieldProps<T,Value>>(), {
10
+ const props = withDefaults(defineProps<SearchableSelectFieldProps<ModelValue,Value>>(), {
11
11
  formControlClass: 'form-control',
12
12
  labelClass: 'form-label',
13
13
  size: 'form-control-md',
@@ -15,20 +15,19 @@ const props = withDefaults(defineProps<SearchableSelectFieldProps<T,Value>>(), {
15
15
  options: () => []
16
16
  });
17
17
 
18
- const model = defineModel<T>();
18
+ const model = defineModel<ModelValue>();
19
19
  const isInteractive = computed(() => !props.disabled && !props.readonly);
20
20
 
21
- defineSlots<FormControlSlots<SearchableSelectFieldSizePrefix,T> & {
22
- default(props: { option: T; display?: (option: T) => string }): any;
21
+ defineSlots<FormControlSlots<SearchableSelectFieldSizePrefix,ModelValue> & {
22
+ default(props: { option: ModelValue; display?: (option: ModelValue) => string }): any;
23
23
  }>();
24
24
 
25
25
  const emit = defineEmits<FormControlEvents>();
26
26
 
27
27
  const {
28
- controlAttributes,
29
28
  formGroupClasses,
30
29
  listeners
31
- } = useFormControl<InputHTMLAttributes, SearchableSelectFieldSizePrefix, T|undefined, T>({ model, props, emit });
30
+ } = useFormControl<HTMLAttributes, SearchableSelectFieldSizePrefix, ModelValue|undefined, ModelValue>({ model, props, emit });
32
31
 
33
32
  watchEffect(() => {
34
33
  if(props.value !== undefined) {
@@ -49,7 +48,7 @@ const keys = computed(() => {
49
48
  : ['$'];
50
49
  });
51
50
 
52
- let fuse: Fuse<T> = createFuse();
51
+ let fuse: Fuse<ModelValue> = createFuse();
53
52
 
54
53
  function createFuse() {
55
54
  return new Fuse(props.options ?? [], props.fuseOptions ?? {
@@ -59,7 +58,7 @@ function createFuse() {
59
58
  });
60
59
  }
61
60
 
62
- const filtered = computed<T[]>(() => {
61
+ const filtered = computed<ModelValue[]>(() => {
63
62
  if(!input.value) {
64
63
  return props.options ?? [];
65
64
  }
@@ -117,7 +116,7 @@ watch(optionsEl, (value) => {
117
116
  });
118
117
  });
119
118
 
120
- function select(option?: T) {
119
+ function select(option?: ModelValue) {
121
120
  model.value = option;
122
121
  active.value = option && props.options.includes(option)
123
122
  ? props.options.indexOf(option)
@@ -138,7 +137,7 @@ function onInput(e: Event) {
138
137
  }
139
138
 
140
139
  if(props.allowCustom) {
141
- model.value = input.value as T;
140
+ model.value = input.value as ModelValue;
142
141
  }
143
142
  }
144
143
 
@@ -151,7 +150,7 @@ function onKeypressEnter() {
151
150
  }
152
151
 
153
152
  if(props.allowCustom && active.value === undefined) {
154
- select(input.value as T ?? model.value);
153
+ select(input.value as ModelValue ?? model.value);
155
154
  }
156
155
  else if(active.value === undefined) {
157
156
  select(filtered.value[0]);
@@ -195,7 +194,7 @@ function onBlur() {
195
194
  input.value = undefined;
196
195
  }
197
196
 
198
- function onClickOption(option: T) {
197
+ function onClickOption(option: ModelValue) {
199
198
  if (!isInteractive.value) return;
200
199
  select(option);
201
200
  }
@@ -226,7 +225,7 @@ const canClear = computed(() => {
226
225
  export type SearchableSelectFieldSizePrefix = 'form-control';
227
226
 
228
227
  export type SearchableSelectFieldProps<ModelValue, Value> = FormControlProps<
229
- InputHTMLAttributes,
228
+ HTMLAttributes,
230
229
  SearchableSelectFieldSizePrefix,
231
230
  ModelValue,
232
231
  Value
@@ -247,7 +246,7 @@ export type SearchableSelectFieldProps<ModelValue, Value> = FormControlProps<
247
246
  class="searchable-select-field-input"
248
247
  :class="{ 'has-clear-button': canClear, formGroupClasses }"
249
248
  :size="size"
250
- v-bind="{ ...$attrs, controlAttributes, listeners }"
249
+ v-bind="{ ...$attrs, ...listeners }"
251
250
  :name="name"
252
251
  :label="label"
253
252
  :model-value="input ?? (model && props?.display ? props?.display?.(model) : model)"