admins-components 9.0.76 → 9.0.78

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 (57) hide show
  1. package/dist/admins-components100.js.map +1 -1
  2. package/dist/admins-components102.js.map +1 -1
  3. package/dist/admins-components103.js.map +1 -1
  4. package/dist/admins-components105.js.map +1 -1
  5. package/dist/admins-components109.js.map +1 -1
  6. package/dist/admins-components11.js.map +1 -1
  7. package/dist/admins-components112.js.map +1 -1
  8. package/dist/admins-components12.js +44 -29
  9. package/dist/admins-components12.js.map +1 -1
  10. package/dist/admins-components13.js.map +1 -1
  11. package/dist/admins-components14.js.map +1 -1
  12. package/dist/admins-components169.js.map +1 -1
  13. package/dist/admins-components173.js +2 -2
  14. package/dist/admins-components173.js.map +1 -1
  15. package/dist/admins-components174.js.map +1 -1
  16. package/dist/admins-components179.js.map +1 -1
  17. package/dist/admins-components21.js.map +1 -1
  18. package/dist/admins-components22.js.map +1 -1
  19. package/dist/admins-components26.js +88 -82
  20. package/dist/admins-components26.js.map +1 -1
  21. package/dist/admins-components28.js.map +1 -1
  22. package/dist/admins-components31.js.map +1 -1
  23. package/dist/admins-components35.js +25 -23
  24. package/dist/admins-components35.js.map +1 -1
  25. package/dist/admins-components37.js.map +1 -1
  26. package/dist/admins-components46.js.map +1 -1
  27. package/dist/admins-components48.js.map +1 -1
  28. package/dist/admins-components54.js.map +1 -1
  29. package/dist/admins-components56.js.map +1 -1
  30. package/dist/admins-components65.js.map +1 -1
  31. package/dist/admins-components68.js.map +1 -1
  32. package/dist/admins-components70.js.map +1 -1
  33. package/dist/admins-components75.js.map +1 -1
  34. package/dist/admins-components77.js.map +1 -1
  35. package/dist/admins-components79.js.map +1 -1
  36. package/dist/admins-components8.js.map +1 -1
  37. package/dist/admins-components80.js.map +1 -1
  38. package/dist/admins-components82.js.map +1 -1
  39. package/dist/admins-components83.js.map +1 -1
  40. package/dist/admins-components85.js.map +1 -1
  41. package/dist/admins-components86.js.map +1 -1
  42. package/dist/admins-components87.js.map +1 -1
  43. package/dist/admins-components91.js.map +1 -1
  44. package/dist/admins-components93.js.map +1 -1
  45. package/dist/main.css +1 -1
  46. package/dist/main.css.map +1 -1
  47. package/dist/src/components/HeaderComponent.vue.d.ts +3 -0
  48. package/dist/src/composables/useDropdownAnchor.d.ts +2 -0
  49. package/dist/src/composables/useSwipeToClose.d.ts +0 -31
  50. package/dist/src/utils/dataFilters.d.ts +0 -8
  51. package/dist/src/utils/dataListConverters.d.ts +0 -10
  52. package/dist/src/utils/url.d.ts +0 -11
  53. package/dist/styles/components/dropdown-select.scss_vue_type_style_index_0_src_true_lang.css +1 -1
  54. package/dist/styles/components/header.scss_vue_type_style_index_0_src_true_lang.css +1 -1
  55. package/dist/vueformelements/ArticlePickerElement.vue_vue_type_style_index_0_scoped_54217a66_lang.css +1 -0
  56. package/package.json +1 -1
  57. package/dist/vueformelements/ArticlePickerElement.vue_vue_type_style_index_0_scoped_43c54caa_lang.css +0 -1
@@ -1,27 +1,27 @@
1
1
  import e from "./admins-components6.js";
2
2
  import { useDropdownAnchor as t } from "./admins-components12.js";
3
3
  import n from "./admins-components25.js";
4
- import { Fragment as r, Teleport as i, computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, createVNode as ee, defineComponent as u, nextTick as d, normalizeClass as f, normalizeStyle as te, openBlock as p, ref as m, renderList as h, toDisplayString as g, unref as _, watch as v, withModifiers as y } from "vue";
4
+ import { Fragment as r, Teleport as i, computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, createVNode as u, defineComponent as d, nextTick as f, normalizeClass as p, normalizeStyle as ee, openBlock as m, ref as h, renderList as te, toDisplayString as g, unref as _, watch as v, withModifiers as y } from "vue";
5
5
  //#region src/components/DropdownSelect.vue?vue&type=script&setup=true&lang.ts
6
- var ne = { class: "ac-component" }, b = ["aria-disabled"], x = {
6
+ var b = { class: "ac-component" }, x = ["aria-disabled"], ne = {
7
7
  key: 0,
8
8
  class: "c-truncate ds-value"
9
- }, S = {
9
+ }, re = {
10
10
  key: 1,
11
11
  class: "c-placeholder"
12
- }, re = { class: "ac-component" }, ie = {
12
+ }, ie = { class: "ac-component" }, ae = {
13
13
  key: 0,
14
14
  class: "ds-filter"
15
- }, ae = ["title"], C = ["value", "placeholder"], w = { class: "ds-options c-scroll" }, T = {
15
+ }, S = ["title"], C = ["value", "placeholder"], w = { class: "ds-options c-scroll" }, oe = {
16
16
  key: 0,
17
17
  class: "ds-option ds-option--loading"
18
- }, oe = ["onClick", "onKeydown"], E = ["innerHTML"], D = {
18
+ }, se = ["onClick", "onKeydown"], T = ["innerHTML"], E = {
19
19
  key: 0,
20
20
  class: "ds-option ds-option--empty"
21
- }, O = {
21
+ }, D = {
22
22
  key: 1,
23
23
  class: "c-footer"
24
- }, k = {
24
+ }, O = {
25
25
  placeholder: "Válassz...",
26
26
  filterable: !0,
27
27
  filterPlaceholder: "Kezdj el gépelni...",
@@ -33,48 +33,51 @@ var ne = { class: "ac-component" }, b = ["aria-disabled"], x = {
33
33
  size: "normal",
34
34
  highlight: !0,
35
35
  disabled: !1
36
- }, A = /*@__PURE__*/ u({
36
+ }, k = /*@__PURE__*/ d({
37
37
  __name: "DropdownSelect",
38
38
  props: {
39
39
  modelValue: { default: null },
40
40
  options: {},
41
- config: { default: () => ({ ...k }) }
41
+ config: { default: () => ({ ...O }) }
42
42
  },
43
43
  emits: ["update:modelValue", "filter-input"],
44
- setup(u, { expose: A, emit: se }) {
45
- let j = u, M = a(() => ({
46
- ...k,
44
+ setup(d, { expose: k, emit: A }) {
45
+ let j = d, M = a(() => ({
46
+ ...O,
47
47
  ...j.config
48
- })), N = se, P = m(""), F = m(null), I = m(null), L = m(null), R = m([]), z = m(H(j.modelValue, j.options)), { isOpen: B, dropdownStyle: V } = t(F, I, { extraStyle: (e) => ({
49
- minWidth: `${e.width}px`,
50
- maxWidth: `${e.width * 1.5}px`
51
- }) });
52
- function H(e, t) {
48
+ })), N = A, P = h(""), F = h(null), I = h(null), L = h(null), R = h([]), z = h(U(j.modelValue, j.options)), { isOpen: B, dropdownStyle: V, placement: H } = t(F, I, {
49
+ extraStyle: (e) => ({
50
+ minWidth: `${e.width}px`,
51
+ maxWidth: `${e.width}px`
52
+ }),
53
+ maxHeight: "17rem"
54
+ });
55
+ function U(e, t) {
53
56
  return e == null ? [] : (Array.isArray(e) ? e : [e]).map((e) => e == null ? null : typeof e == "object" && "label" in e ? e : typeof e == "string" ? t.find((t) => t.value === e) ?? {
54
57
  value: e,
55
58
  label: e
56
59
  } : null).filter((e) => e !== null);
57
60
  }
58
61
  v(() => [j.modelValue, j.options], ([e]) => {
59
- z.value = H(e, j.options);
62
+ z.value = U(e, j.options);
60
63
  }), v(B, (e) => {
61
- e && (P.value = "", M.value.filterable && d(() => L.value?.focus()), M.value.lazy && (R.value = [...z.value]));
64
+ e && (P.value = "", M.value.filterable && f(() => L.value?.focus()), M.value.lazy && (R.value = [...z.value]));
62
65
  });
63
- function U(e) {
66
+ function W(e) {
64
67
  P.value = e, N("filter-input", e);
65
68
  }
66
- let W = a(() => {
69
+ let G = a(() => {
67
70
  if (z.value.length === 0) return null;
68
71
  if (!M.value.multiple) {
69
72
  let e = z.value[0];
70
73
  return j.options.find((t) => t.value === e?.value)?.label ?? e?.label ?? null;
71
74
  }
72
75
  return z.value.length > 2 ? `${z.value.length} kiválasztva` : z.value.map((e) => j.options.find((t) => t.value === e.value)?.label ?? e.label ?? e.value).join(", ");
73
- }), G = a(() => {
76
+ }), K = a(() => {
74
77
  let e = P.value.toLowerCase();
75
78
  return e ? j.options.filter((t) => t.label.toLowerCase().includes(e)) : j.options;
76
79
  });
77
- function K(e) {
80
+ function q(e) {
78
81
  return e.replace(/[&<>"']/g, (e) => ({
79
82
  "&": "&amp;",
80
83
  "<": "&lt;",
@@ -85,21 +88,21 @@ var ne = { class: "ac-component" }, b = ["aria-disabled"], x = {
85
88
  }
86
89
  function ce(e) {
87
90
  let t = P.value.trim();
88
- if (!t || !M.value.highlight) return K(e);
89
- let n = K(e), r = K(t), i = new RegExp(r.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "ig");
91
+ if (!t || !M.value.highlight) return q(e);
92
+ let n = q(e), r = q(t), i = new RegExp(r.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "ig");
90
93
  return n.replace(i, (e) => `<mark class="ds-option__highlight">${e}</mark>`);
91
94
  }
92
- let q = a(() => G.value.filter((e) => e.value)), J = a(() => {
93
- if (q.value.length === 0) return !1;
95
+ let J = a(() => K.value.filter((e) => e.value)), Y = a(() => {
96
+ if (J.value.length === 0) return !1;
94
97
  let e = M.value.lazy && B.value ? R.value : z.value;
95
- return q.value.every((t) => t.value && e.some((e) => e.value === t.value));
98
+ return J.value.every((t) => t.value && e.some((e) => e.value === t.value));
96
99
  });
97
- function Y(e) {
100
+ function X(e) {
98
101
  return (M.value.lazy && B.value ? R : z).value.some((t) => t.value === e);
99
102
  }
100
103
  function le() {
101
- let e = M.value.lazy && B.value ? R : z, t = q.value.filter((e) => e.value);
102
- if (J.value) {
104
+ let e = M.value.lazy && B.value ? R : z, t = J.value.filter((e) => e.value);
105
+ if (Y.value) {
103
106
  let n = new Set(t.map((e) => e.value));
104
107
  e.value = e.value.filter((e) => !n.has(e.value ?? ""));
105
108
  } else {
@@ -108,74 +111,78 @@ var ne = { class: "ac-component" }, b = ["aria-disabled"], x = {
108
111
  }
109
112
  M.value.lazy || N("update:modelValue", z.value.length > 0 ? [...z.value] : null);
110
113
  }
111
- function X(e, t) {
114
+ function Z(e, t) {
112
115
  let n = e.findIndex((e) => e.value === t.value);
113
116
  return n >= 0 ? e.filter((e, t) => t !== n) : [...e, t];
114
117
  }
115
- function Z(e) {
118
+ function Q(e) {
116
119
  if (e.callback) {
117
120
  e.callback(), B.value = !1;
118
121
  return;
119
122
  }
120
- e.value && (M.value.multiple ? M.value.lazy ? R.value = X(R.value, e) : (z.value = X(z.value, e), N("update:modelValue", z.value.length > 0 ? [...z.value] : null)) : (z.value = [e], N("update:modelValue", e), B.value = !1));
123
+ e.value && (M.value.multiple ? M.value.lazy ? R.value = Z(R.value, e) : (z.value = Z(z.value, e), N("update:modelValue", z.value.length > 0 ? [...z.value] : null)) : (z.value = [e], N("update:modelValue", e), B.value = !1));
121
124
  }
122
- function Q() {
125
+ function $() {
123
126
  M.value.lazy && (z.value = [...R.value], N("update:modelValue", R.value.length > 0 ? [...R.value] : null)), B.value = !1;
124
127
  }
125
- function $() {
128
+ function ue() {
126
129
  M.value.lazy ? R.value = [] : (z.value = [], N("update:modelValue", null));
127
130
  }
128
- function ue(e, t) {
129
- e.key === " " ? (e.preventDefault(), Z(t)) : e.key === "Enter" && (e.preventDefault(), Q());
130
- }
131
- function de() {
132
- M.value.disabled || (B.value = !B.value, B.value && M.value.filterable && (P.value = "", N("filter-input", "")));
131
+ function de(e, t) {
132
+ e.key === " " ? (e.preventDefault(), Q(t)) : e.key === "Enter" && (e.preventDefault(), $());
133
133
  }
134
134
  function fe() {
135
- M.value.disabled || (z.value = [], N("update:modelValue", null), B.value = !1);
135
+ M.value.disabled || (B.value = !B.value, B.value && M.value.filterable && (P.value = "", N("filter-input", "")));
136
136
  }
137
137
  function pe() {
138
- M.value.disabled || (B.value = !0, M.value.filterable && d(() => L.value?.focus()));
138
+ M.value.disabled || (z.value = [], N("update:modelValue", null), B.value = !1);
139
139
  }
140
140
  function me() {
141
+ M.value.disabled || (B.value = !0, M.value.filterable && f(() => L.value?.focus()));
142
+ }
143
+ function he() {
141
144
  P.value = "", N("filter-input", "");
142
145
  }
143
- return A({ focusAndOpen: pe }), (t, a) => (p(), c("div", ne, [l("div", {
146
+ return k({ focusAndOpen: me }), (t, a) => (m(), c("div", b, [l("div", {
144
147
  ref_key: "wrapperRef",
145
148
  ref: F,
146
149
  class: "c-wrapper ds-wrapper"
147
150
  }, [l("div", {
148
- class: f(["c-input-row pointer", {
151
+ class: p(["c-input-row pointer", {
149
152
  "c-input-row--sm": M.value.size === "small",
150
153
  "c-input-row--lg": M.value.size === "large",
151
- "c-input-row--disabled": M.value.disabled
154
+ "c-input-row--disabled": M.value.disabled,
155
+ "c-input-row--open": _(B)
152
156
  }]),
153
157
  "aria-disabled": M.value.disabled || void 0,
154
- onClick: a[1] ||= (e) => de()
158
+ onClick: a[1] ||= (e) => fe()
155
159
  }, [
156
- W.value ? (p(), c("span", x, g(W.value), 1)) : (p(), c("span", S, g(M.value.placeholder), 1)),
157
- M.value.clearable && z.value.length > 0 ? (p(), c("button", {
160
+ G.value ? (m(), c("span", ne, g(G.value), 1)) : (m(), c("span", re, g(M.value.placeholder), 1)),
161
+ M.value.clearable && z.value.length > 0 ? (m(), c("button", {
158
162
  key: 2,
159
163
  type: "button",
160
164
  class: "c-icon-btn c-icon-btn--clear ds-clear-btn",
161
- onClick: a[0] ||= y((e) => fe(), ["stop"]),
165
+ onClick: a[0] ||= y((e) => pe(), ["stop"]),
162
166
  "aria-label": "Törlés"
163
167
  }, [...a[6] ||= [l("i", { class: "fa-solid fa-fw fa-xmark" }, null, -1)]])) : s("", !0),
164
- l("span", { class: f(["c-icon-btn c-icon-btn--chevron mr-2", { "c-icon-btn--chevron-open": _(B) }]) }, [...a[7] ||= [l("i", { class: "fa-solid fa-fw fa-chevron-down" }, null, -1)]], 2)
165
- ], 10, b)], 512), (p(), o(i, { to: "body" }, [l("div", re, [_(B) ? (p(), c("div", {
168
+ l("span", { class: p(["c-icon-btn c-icon-btn--chevron mr-2", { "c-icon-btn--chevron-open": _(B) }]) }, [...a[7] ||= [l("i", { class: "fa-solid fa-fw fa-chevron-down" }, null, -1)]], 2)
169
+ ], 10, x)], 512), (m(), o(i, { to: "body" }, [l("div", ie, [_(B) ? (m(), c("div", {
166
170
  key: 0,
167
171
  ref_key: "dropdownRef",
168
172
  ref: I,
169
- class: f(["c-dropdown ds-dropdown ds-wrapper", { "ds-dropdown--multiple": M.value.multiple }]),
170
- style: te(_(V))
173
+ class: p(["c-dropdown ds-dropdown ds-wrapper", {
174
+ "ds-dropdown--multiple": M.value.multiple,
175
+ "ds-dropdown--up": _(H) === "up"
176
+ }]),
177
+ style: ee(_(V))
171
178
  }, [
172
- M.value.filterable ? (p(), c("div", ie, [
173
- M.value.multiple ? (p(), c("span", {
179
+ M.value.filterable ? (m(), c("div", ae, [
180
+ M.value.multiple ? (m(), c("span", {
174
181
  key: 0,
175
- class: f(["c-checkbox ds-select-all-checkbox", { "c-checkbox--checked": J.value }]),
182
+ class: p(["c-checkbox ds-select-all-checkbox", { "c-checkbox--checked": Y.value }]),
176
183
  onClick: a[2] ||= y((e) => le(), ["stop"]),
177
- title: J.value ? "Összes kijelölés törlése" : "Összes kijelölése"
178
- }, null, 10, ae)) : s("", !0),
184
+ title: Y.value ? "Összes kijelölés törlése" : "Összes kijelölése"
185
+ }, null, 10, S)) : s("", !0),
179
186
  l("input", {
180
187
  ref_key: "filterInputRef",
181
188
  ref: L,
@@ -183,56 +190,55 @@ var ne = { class: "ac-component" }, b = ["aria-disabled"], x = {
183
190
  id: "ds-filter-input",
184
191
  class: "c-focus ds-filter-input",
185
192
  value: P.value,
186
- onInput: a[3] ||= (e) => U(e.target.value),
193
+ onInput: a[3] ||= (e) => W(e.target.value),
187
194
  autocomplete: "off",
188
195
  placeholder: M.value.filterPlaceholder,
189
196
  onClick: a[4] ||= y(() => {}, ["stop"])
190
197
  }, null, 40, C),
191
- P.value ? (p(), c("button", {
198
+ P.value ? (m(), c("button", {
192
199
  key: 1,
193
200
  type: "button",
194
201
  class: "c-icon-btn c-icon-btn--clear ds-filter-clear",
195
- onClick: a[5] ||= y((e) => me(), ["stop"]),
202
+ onClick: a[5] ||= y((e) => he(), ["stop"]),
196
203
  "aria-label": "Szűrők törlése"
197
204
  }, [...a[8] ||= [l("i", { class: "fa-solid fa-xmark" }, null, -1)]])) : s("", !0)
198
205
  ])) : s("", !0),
199
- l("ul", w, [M.value.loading ? (p(), c("li", T, [ee(n, {
206
+ l("ul", w, [M.value.loading ? (m(), c("li", oe, [u(n, {
200
207
  size: "2rem",
201
208
  color: "var(--neutral-300)",
202
209
  class: "m-auto p-3"
203
- })])) : (p(), c(r, { key: 1 }, [(p(!0), c(r, null, h(G.value, (e, t) => (p(), c("li", {
210
+ })])) : (m(), c(r, { key: 1 }, [(m(!0), c(r, null, te(K.value, (e, t) => (m(), c("li", {
204
211
  key: e.value ?? `cb-${t}`,
205
- class: f(["d-option ds-option", { "ds-option--selected": e.value && Y(e.value) }]),
212
+ class: p(["d-option ds-option", { "ds-option--selected": e.value && X(e.value) }]),
206
213
  tabindex: "0",
207
- onClick: (t) => Z(e),
208
- onKeydown: (t) => ue(t, e)
214
+ onClick: (t) => Q(e),
215
+ onKeydown: (t) => de(t, e)
209
216
  }, [
210
- M.value.multiple && e.value ? (p(), c("span", {
217
+ M.value.multiple && e.value ? (m(), c("span", {
211
218
  key: 0,
212
- class: f(["c-checkbox", { "c-checkbox--checked": Y(e.value) }])
219
+ class: p(["c-checkbox", { "c-checkbox--checked": X(e.value) }])
213
220
  }, null, 2)) : s("", !0),
214
- e.icon ? (p(), c("i", {
221
+ e.icon ? (m(), c("i", {
215
222
  key: 1,
216
- class: f(["fa-fw", e.icon])
223
+ class: p(["fa-fw", e.icon])
217
224
  }, null, 2)) : s("", !0),
218
225
  l("span", {
219
- class: f(["d-option__label", { "c-truncate": M.value.textEllipsis }]),
226
+ class: p(["d-option__label", { "c-truncate": M.value.textEllipsis }]),
220
227
  innerHTML: ce(e.label)
221
- }, null, 10, E)
222
- ], 42, oe))), 128)), G.value.length === 0 ? (p(), c("li", D, " Nincs találat ")) : s("", !0)], 64))]),
223
- M.value.multiple || M.value.clearable && z.value.length > 0 ? (p(), c("div", O, [M.value.clearable ? (p(), o(e, {
228
+ }, null, 10, T)
229
+ ], 42, se))), 128)), K.value.length === 0 ? (m(), c("li", E, " Nincs találat ")) : s("", !0)], 64))]),
230
+ M.value.multiple ? (m(), c("div", D, [M.value.clearable && z.value.length > 0 ? (m(), o(e, {
224
231
  key: 0,
225
232
  label: "Törlés",
226
233
  outline: "",
227
- onClick: $
228
- })) : s("", !0), M.value.multiple ? (p(), o(e, {
229
- key: 1,
234
+ onClick: ue
235
+ })) : s("", !0), u(e, {
230
236
  label: "OK",
231
237
  type: "success",
232
- onClick: Q
233
- })) : s("", !0)])) : s("", !0)
238
+ onClick: $
239
+ })])) : s("", !0)
234
240
  ], 6)) : s("", !0)])]))]));
235
241
  }
236
242
  });
237
243
  //#endregion
238
- export { A as default, k as dropdownSelectConfigDefaults };
244
+ export { k as default, O as dropdownSelectConfigDefaults };
@@ -1 +1 @@
1
- {"version":3,"file":"admins-components26.js","names":[],"sources":["../src/components/DropdownSelect.vue"],"sourcesContent":["<script lang=\"ts\">\nexport interface DropdownSelectConfig {\n placeholder?: string\n filterable?: boolean\n filterPlaceholder?: string\n clearable?: boolean\n textEllipsis?: boolean\n multiple?: boolean\n lazy?: boolean\n size?: ControlSize\n loading?: boolean\n highlight?: boolean\n disabled?: boolean\n}\n\nexport const dropdownSelectConfigDefaults: DropdownSelectConfig = {\n placeholder: 'Válassz...',\n filterable: true,\n filterPlaceholder: 'Kezdj el gépelni...',\n clearable: true,\n textEllipsis: true,\n multiple: false,\n lazy: false,\n loading: false,\n size: 'normal' as ControlSize,\n highlight: true,\n disabled: false,\n}\n\nexport interface DropdownOption {\n icon?: string\n value?: string\n label: string\n callback?: () => void\n}\n\nexport interface DropdownSelectProps {\n modelValue?: DropdownOption | DropdownOption[] | string | string[] | null\n options: DropdownOption[]\n config?: DropdownSelectConfig\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick } from 'vue'\nimport Button from '@/components/Button.vue'\nimport type { ControlSize } from '@/types/types'\nimport Loader from '@/components/Loader.vue'\nimport { useDropdownAnchor } from '@/composables/useDropdownAnchor'\n\nconst props = withDefaults(defineProps<DropdownSelectProps>(), {\n modelValue: null,\n config: () => ({ ...dropdownSelectConfigDefaults }),\n})\n\nconst cfg = computed(() => ({ ...dropdownSelectConfigDefaults, ...props.config }))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: DropdownOption | DropdownOption[] | null]\n 'filter-input': [filterText: string]\n}>()\n\nconst filterText = ref('')\nconst wrapperRef = ref<HTMLElement | null>(null)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst filterInputRef = ref<HTMLInputElement | null>(null)\nconst buffer = ref<DropdownOption[]>([])\nconst selection = ref<DropdownOption[]>(normalizeToOptions(props.modelValue, props.options))\n\nconst { isOpen, dropdownStyle } = useDropdownAnchor(wrapperRef, dropdownRef, {\n extraStyle: (rect) => ({\n minWidth: `${rect.width}px`,\n maxWidth: `${rect.width * 1.5}px`,\n }),\n})\n\n\nfunction normalizeToOptions(\n val: DropdownOption | DropdownOption[] | string | string[] | null | undefined,\n options: DropdownOption[],\n): DropdownOption[] {\n if (val == null) return []\n const arr = Array.isArray(val) ? val : [val]\n return arr\n .map((entry): DropdownOption | null => {\n if (entry == null) return null\n if (typeof entry === 'object' && 'label' in entry) {\n return entry as DropdownOption\n }\n if (typeof entry === 'string') {\n const found = options.find((o) => o.value === entry)\n return found ?? { value: entry, label: entry }\n }\n return null\n })\n .filter((o): o is DropdownOption => o !== null)\n}\n\nwatch(\n () => [props.modelValue, props.options],\n ([v]) => {\n selection.value = normalizeToOptions(v as typeof props.modelValue, props.options)\n },\n)\n\nwatch(isOpen, (open) => {\n if (open) {\n filterText.value = ''\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n if (cfg.value.lazy) buffer.value = [...selection.value]\n }\n})\n\nfunction onFilterInput(text: string) {\n filterText.value = text\n emit('filter-input', text)\n //debouncedEmit(text)\n}\n\n/* const debouncedEmit = debounce((raw: string) => {\n emit('filter-input', raw)\n}) */\n\n// Display\nconst selectedLabel = computed(() => {\n if (selection.value.length === 0) return null\n if (!cfg.value.multiple) {\n const sel = selection.value[0]\n // Prefer the label from the live options list, fall back to the stored label\n return props.options.find((o) => o.value === sel?.value)?.label ?? sel?.label ?? null\n }\n if (selection.value.length > 2) return `${selection.value.length} kiválasztva`\n return selection.value\n .map((sel) => props.options.find((o) => o.value === sel.value)?.label ?? sel.label ?? sel.value)\n .join(', ')\n})\n\nconst filteredOptions = computed(() => {\n const q = filterText.value.toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nfunction escapeHtml(str: string) {\n return str.replace(\n /[&<>\"']/g,\n (m) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[m]!,\n )\n}\n\nfunction highlight(label: string) {\n const q = filterText.value.trim()\n if (!q || !cfg.value.highlight) return escapeHtml(label)\n\n const safeLabel = escapeHtml(label)\n const safeQ = escapeHtml(q)\n\n const re = new RegExp(safeQ.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'ig')\n return safeLabel.replace(re, (m) => `<mark class=\"ds-option__highlight\">${m}</mark>`)\n}\n\nconst selectableOptions = computed(() => {\n return filteredOptions.value.filter((o) => o.value)\n})\n\nconst allOptionsSelected = computed(() => {\n if (selectableOptions.value.length === 0) return false\n const currentList = cfg.value.lazy && isOpen.value ? buffer.value : selection.value\n return selectableOptions.value.every((o) => o.value && currentList.some((s) => s.value === o.value))\n})\n\nfunction isSelected(value: string): boolean {\n const list = cfg.value.lazy && isOpen.value ? buffer : selection\n return list.value.some((s) => s.value === value)\n}\n\nfunction toggleAllOptions() {\n const currentList = cfg.value.lazy && isOpen.value ? buffer : selection\n const selectableOpts = selectableOptions.value.filter((o) => o.value)\n\n if (allOptionsSelected.value) {\n const selectableValues = new Set(selectableOpts.map((o) => o.value as string))\n currentList.value = currentList.value.filter((s) => !selectableValues.has(s.value ?? ''))\n } else {\n const existingValues = new Set(currentList.value.map((s) => s.value))\n const toAdd = selectableOpts.filter((o) => !existingValues.has(o.value as string))\n currentList.value = [...currentList.value, ...toAdd]\n }\n\n if (!cfg.value.lazy) {\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n}\n\n// Actions\nfunction toggleList(list: DropdownOption[], opt: DropdownOption): DropdownOption[] {\n const idx = list.findIndex((s) => s.value === opt.value)\n return idx >= 0 ? list.filter((_, i) => i !== idx) : [...list, opt]\n}\n\nfunction selectOption(opt: DropdownOption) {\n if (opt.callback) {\n opt.callback()\n isOpen.value = false\n return\n }\n\n const value = opt.value\n if (!value) return\n\n if (cfg.value.multiple) {\n if (cfg.value.lazy) {\n buffer.value = toggleList(buffer.value, opt)\n } else {\n selection.value = toggleList(selection.value, opt)\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n } else {\n selection.value = [opt]\n emit('update:modelValue', opt)\n isOpen.value = false\n }\n}\n\nfunction confirm() {\n if (cfg.value.lazy) {\n selection.value = [...buffer.value]\n emit('update:modelValue', buffer.value.length > 0 ? [...buffer.value] : null)\n }\n isOpen.value = false\n}\n\nfunction clear() {\n if (cfg.value.lazy) {\n buffer.value = []\n } else {\n selection.value = []\n emit('update:modelValue', null)\n }\n}\n\nfunction onOptionKeydown(e: KeyboardEvent, opt: DropdownOption) {\n if (e.key === ' ') {\n e.preventDefault()\n selectOption(opt)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n confirm()\n }\n}\n\nfunction toggleOpen() {\n if (cfg.value.disabled) return\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n if (cfg.value.filterable) {\n filterText.value = ''\n emit('filter-input', '')\n }\n }\n}\n\nfunction clearInput() {\n if (cfg.value.disabled) return\n selection.value = []\n emit('update:modelValue', null)\n isOpen.value = false\n}\n\nfunction focusAndOpen() {\n if (cfg.value.disabled) return\n isOpen.value = true\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n}\n\nfunction handleFilterClear() {\n filterText.value = ''\n emit('filter-input', '')\n}\n\ndefineExpose({ focusAndOpen })\n</script>\n\n<template>\n <div class=\"ac-component\">\n <div ref=\"wrapperRef\" class=\"c-wrapper ds-wrapper\">\n <div\n class=\"c-input-row pointer\"\n :class=\"{\n 'c-input-row--sm': cfg.size === 'small',\n 'c-input-row--lg': cfg.size === 'large',\n 'c-input-row--disabled': cfg.disabled,\n }\"\n :aria-disabled=\"cfg.disabled || undefined\"\n @click=\"toggleOpen()\"\n >\n <span v-if=\"selectedLabel\" class=\"c-truncate ds-value\">{{ selectedLabel }}</span>\n <span v-else class=\"c-placeholder\">{{ cfg.placeholder }}</span>\n <button\n v-if=\"cfg.clearable && selection.length > 0\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-clear-btn\"\n @click.stop=\"clearInput()\"\n aria-label=\"Törlés\"\n >\n <i class=\"fa-solid fa-fw fa-xmark\"></i>\n </button>\n <span\n class=\"c-icon-btn c-icon-btn--chevron mr-2\"\n :class=\"{ 'c-icon-btn--chevron-open': isOpen }\"\n >\n <i class=\"fa-solid fa-fw fa-chevron-down\"></i>\n </span>\n </div>\n </div>\n <Teleport to=\"body\">\n <div class=\"ac-component\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdownRef\"\n class=\"c-dropdown ds-dropdown ds-wrapper\"\n :class=\"{ 'ds-dropdown--multiple': cfg.multiple }\"\n :style=\"dropdownStyle\"\n >\n <div v-if=\"cfg.filterable\" class=\"ds-filter\">\n <span\n v-if=\"cfg.multiple\"\n class=\"c-checkbox ds-select-all-checkbox\"\n :class=\"{ 'c-checkbox--checked': allOptionsSelected }\"\n @click.stop=\"toggleAllOptions()\"\n :title=\"allOptionsSelected ? 'Összes kijelölés törlése' : 'Összes kijelölése'\"\n ></span>\n <input\n ref=\"filterInputRef\"\n type=\"text\"\n id=\"ds-filter-input\"\n class=\"c-focus ds-filter-input\"\n :value=\"filterText\"\n @input=\"onFilterInput(($event.target as HTMLInputElement).value)\"\n autocomplete=\"off\"\n :placeholder=\"cfg.filterPlaceholder\"\n @click.stop\n />\n <button\n v-if=\"filterText\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-filter-clear\"\n @click.stop=\"handleFilterClear()\"\n aria-label=\"Szűrők törlése\"\n >\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <ul class=\"ds-options c-scroll\">\n <li v-if=\"cfg.loading\" class=\"ds-option ds-option--loading\">\n <Loader size=\"2rem\" color=\"var(--neutral-300)\" class=\"m-auto p-3\" />\n </li>\n <template v-else>\n <li\n v-for=\"(opt, idx) in filteredOptions\"\n :key=\"opt.value ?? `cb-${idx}`\"\n class=\"d-option ds-option\"\n :class=\"{ 'ds-option--selected': opt.value && isSelected(opt.value) }\"\n tabindex=\"0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt)\"\n >\n <span\n v-if=\"cfg.multiple && opt.value\"\n class=\"c-checkbox\"\n :class=\"{ 'c-checkbox--checked': isSelected(opt.value) }\"\n ></span>\n <i v-if=\"opt.icon\" class=\"fa-fw\" :class=\"opt.icon\"></i>\n <span\n class=\"d-option__label\"\n :class=\"{ 'c-truncate': cfg.textEllipsis }\"\n v-html=\"highlight(opt.label)\"\n ></span>\n </li>\n <li v-if=\"filteredOptions.length === 0\" class=\"ds-option ds-option--empty\">\n Nincs találat\n </li>\n </template>\n </ul>\n\n <div v-if=\"cfg.multiple || (cfg.clearable && selection.length > 0)\" class=\"c-footer\">\n <Button v-if=\"cfg.clearable\" label=\"Törlés\" outline @click=\"clear\" />\n <Button v-if=\"cfg.multiple\" label=\"OK\" type=\"success\" @click=\"confirm\" />\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style lang=\"scss\" src=\"@/styles/components/dropdown-select.scss\"></style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"admins-components26.js","names":[],"sources":["../src/components/DropdownSelect.vue"],"sourcesContent":["<script lang=\"ts\">\nexport interface DropdownSelectConfig {\n placeholder?: string\n filterable?: boolean\n filterPlaceholder?: string\n clearable?: boolean\n textEllipsis?: boolean\n multiple?: boolean\n lazy?: boolean\n size?: ControlSize\n loading?: boolean\n highlight?: boolean\n disabled?: boolean\n}\n\nexport const dropdownSelectConfigDefaults: DropdownSelectConfig = {\n placeholder: 'Válassz...',\n filterable: true,\n filterPlaceholder: 'Kezdj el gépelni...',\n clearable: true,\n textEllipsis: true,\n multiple: false,\n lazy: false,\n loading: false,\n size: 'normal' as ControlSize,\n highlight: true,\n disabled: false,\n}\n\nexport interface DropdownOption {\n icon?: string\n value?: string\n label: string\n callback?: () => void\n}\n\nexport interface DropdownSelectProps {\n modelValue?: DropdownOption | DropdownOption[] | string | string[] | null\n options: DropdownOption[]\n config?: DropdownSelectConfig\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick } from 'vue'\nimport Button from '@/components/Button.vue'\nimport type { ControlSize } from '@/types/types'\nimport Loader from '@/components/Loader.vue'\nimport { useDropdownAnchor } from '@/composables/useDropdownAnchor'\n\nconst props = withDefaults(defineProps<DropdownSelectProps>(), {\n modelValue: null,\n config: () => ({ ...dropdownSelectConfigDefaults }),\n})\n\nconst cfg = computed(() => ({ ...dropdownSelectConfigDefaults, ...props.config }))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: DropdownOption | DropdownOption[] | null]\n 'filter-input': [filterText: string]\n}>()\n\nconst filterText = ref('')\nconst wrapperRef = ref<HTMLElement | null>(null)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst filterInputRef = ref<HTMLInputElement | null>(null)\nconst buffer = ref<DropdownOption[]>([])\nconst selection = ref<DropdownOption[]>(normalizeToOptions(props.modelValue, props.options))\n\nconst { isOpen, dropdownStyle, placement } = useDropdownAnchor(wrapperRef, dropdownRef, {\n extraStyle: (rect) => ({\n minWidth: `${rect.width}px`,\n maxWidth: `${rect.width}px`,\n }),\n maxHeight: '17rem',\n})\n\n\nfunction normalizeToOptions(\n val: DropdownOption | DropdownOption[] | string | string[] | null | undefined,\n options: DropdownOption[],\n): DropdownOption[] {\n if (val == null) return []\n const arr = Array.isArray(val) ? val : [val]\n return arr\n .map((entry): DropdownOption | null => {\n if (entry == null) return null\n if (typeof entry === 'object' && 'label' in entry) {\n return entry as DropdownOption\n }\n if (typeof entry === 'string') {\n const found = options.find((o) => o.value === entry)\n return found ?? { value: entry, label: entry }\n }\n return null\n })\n .filter((o): o is DropdownOption => o !== null)\n}\n\nwatch(\n () => [props.modelValue, props.options],\n ([v]) => {\n selection.value = normalizeToOptions(v as typeof props.modelValue, props.options)\n },\n)\n\nwatch(isOpen, (open) => {\n if (open) {\n filterText.value = ''\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n if (cfg.value.lazy) buffer.value = [...selection.value]\n }\n})\n\nfunction onFilterInput(text: string) {\n filterText.value = text\n emit('filter-input', text)\n}\n\nconst selectedLabel = computed(() => {\n if (selection.value.length === 0) return null\n if (!cfg.value.multiple) {\n const sel = selection.value[0]\n\n return props.options.find((o) => o.value === sel?.value)?.label ?? sel?.label ?? null\n }\n if (selection.value.length > 2) return `${selection.value.length} kiválasztva`\n return selection.value\n .map((sel) => props.options.find((o) => o.value === sel.value)?.label ?? sel.label ?? sel.value)\n .join(', ')\n})\n\nconst filteredOptions = computed(() => {\n const q = filterText.value.toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nfunction escapeHtml(str: string) {\n return str.replace(\n /[&<>\"']/g,\n (m) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[m]!,\n )\n}\n\nfunction highlight(label: string) {\n const q = filterText.value.trim()\n if (!q || !cfg.value.highlight) return escapeHtml(label)\n\n const safeLabel = escapeHtml(label)\n const safeQ = escapeHtml(q)\n\n const re = new RegExp(safeQ.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'ig')\n return safeLabel.replace(re, (m) => `<mark class=\"ds-option__highlight\">${m}</mark>`)\n}\n\nconst selectableOptions = computed(() => {\n return filteredOptions.value.filter((o) => o.value)\n})\n\nconst allOptionsSelected = computed(() => {\n if (selectableOptions.value.length === 0) return false\n const currentList = cfg.value.lazy && isOpen.value ? buffer.value : selection.value\n return selectableOptions.value.every((o) => o.value && currentList.some((s) => s.value === o.value))\n})\n\nfunction isSelected(value: string): boolean {\n const list = cfg.value.lazy && isOpen.value ? buffer : selection\n return list.value.some((s) => s.value === value)\n}\n\nfunction toggleAllOptions() {\n const currentList = cfg.value.lazy && isOpen.value ? buffer : selection\n const selectableOpts = selectableOptions.value.filter((o) => o.value)\n\n if (allOptionsSelected.value) {\n const selectableValues = new Set(selectableOpts.map((o) => o.value as string))\n currentList.value = currentList.value.filter((s) => !selectableValues.has(s.value ?? ''))\n } else {\n const existingValues = new Set(currentList.value.map((s) => s.value))\n const toAdd = selectableOpts.filter((o) => !existingValues.has(o.value as string))\n currentList.value = [...currentList.value, ...toAdd]\n }\n\n if (!cfg.value.lazy) {\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n}\n\nfunction toggleList(list: DropdownOption[], opt: DropdownOption): DropdownOption[] {\n const idx = list.findIndex((s) => s.value === opt.value)\n return idx >= 0 ? list.filter((_, i) => i !== idx) : [...list, opt]\n}\n\nfunction selectOption(opt: DropdownOption) {\n if (opt.callback) {\n opt.callback()\n isOpen.value = false\n return\n }\n\n const value = opt.value\n if (!value) return\n\n if (cfg.value.multiple) {\n if (cfg.value.lazy) {\n buffer.value = toggleList(buffer.value, opt)\n } else {\n selection.value = toggleList(selection.value, opt)\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n } else {\n selection.value = [opt]\n emit('update:modelValue', opt)\n isOpen.value = false\n }\n}\n\nfunction confirm() {\n if (cfg.value.lazy) {\n selection.value = [...buffer.value]\n emit('update:modelValue', buffer.value.length > 0 ? [...buffer.value] : null)\n }\n isOpen.value = false\n}\n\nfunction clear() {\n if (cfg.value.lazy) {\n buffer.value = []\n } else {\n selection.value = []\n emit('update:modelValue', null)\n }\n}\n\nfunction onOptionKeydown(e: KeyboardEvent, opt: DropdownOption) {\n if (e.key === ' ') {\n e.preventDefault()\n selectOption(opt)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n confirm()\n }\n}\n\nfunction toggleOpen() {\n if (cfg.value.disabled) return\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n if (cfg.value.filterable) {\n filterText.value = ''\n emit('filter-input', '')\n }\n }\n}\n\nfunction clearInput() {\n if (cfg.value.disabled) return\n selection.value = []\n emit('update:modelValue', null)\n isOpen.value = false\n}\n\nfunction focusAndOpen() {\n if (cfg.value.disabled) return\n isOpen.value = true\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n}\n\nfunction handleFilterClear() {\n filterText.value = ''\n emit('filter-input', '')\n}\n\ndefineExpose({ focusAndOpen })\n</script>\n\n<template>\n <div class=\"ac-component\">\n <div ref=\"wrapperRef\" class=\"c-wrapper ds-wrapper\">\n <div\n class=\"c-input-row pointer\"\n :class=\"{\n 'c-input-row--sm': cfg.size === 'small',\n 'c-input-row--lg': cfg.size === 'large',\n 'c-input-row--disabled': cfg.disabled,\n 'c-input-row--open': isOpen,\n }\"\n :aria-disabled=\"cfg.disabled || undefined\"\n @click=\"toggleOpen()\"\n >\n <span v-if=\"selectedLabel\" class=\"c-truncate ds-value\">{{ selectedLabel }}</span>\n <span v-else class=\"c-placeholder\">{{ cfg.placeholder }}</span>\n <button\n v-if=\"cfg.clearable && selection.length > 0\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-clear-btn\"\n @click.stop=\"clearInput()\"\n aria-label=\"Törlés\"\n >\n <i class=\"fa-solid fa-fw fa-xmark\"></i>\n </button>\n <span\n class=\"c-icon-btn c-icon-btn--chevron mr-2\"\n :class=\"{ 'c-icon-btn--chevron-open': isOpen }\"\n >\n <i class=\"fa-solid fa-fw fa-chevron-down\"></i>\n </span>\n </div>\n </div>\n <Teleport to=\"body\">\n <div class=\"ac-component\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdownRef\"\n class=\"c-dropdown ds-dropdown ds-wrapper\"\n :class=\"{ 'ds-dropdown--multiple': cfg.multiple, 'ds-dropdown--up': placement === 'up' }\"\n :style=\"dropdownStyle\"\n >\n <div v-if=\"cfg.filterable\" class=\"ds-filter\">\n <span\n v-if=\"cfg.multiple\"\n class=\"c-checkbox ds-select-all-checkbox\"\n :class=\"{ 'c-checkbox--checked': allOptionsSelected }\"\n @click.stop=\"toggleAllOptions()\"\n :title=\"allOptionsSelected ? 'Összes kijelölés törlése' : 'Összes kijelölése'\"\n ></span>\n <input\n ref=\"filterInputRef\"\n type=\"text\"\n id=\"ds-filter-input\"\n class=\"c-focus ds-filter-input\"\n :value=\"filterText\"\n @input=\"onFilterInput(($event.target as HTMLInputElement).value)\"\n autocomplete=\"off\"\n :placeholder=\"cfg.filterPlaceholder\"\n @click.stop\n />\n <button\n v-if=\"filterText\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-filter-clear\"\n @click.stop=\"handleFilterClear()\"\n aria-label=\"Szűrők törlése\"\n >\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <ul class=\"ds-options c-scroll\">\n <li v-if=\"cfg.loading\" class=\"ds-option ds-option--loading\">\n <Loader size=\"2rem\" color=\"var(--neutral-300)\" class=\"m-auto p-3\" />\n </li>\n <template v-else>\n <li\n v-for=\"(opt, idx) in filteredOptions\"\n :key=\"opt.value ?? `cb-${idx}`\"\n class=\"d-option ds-option\"\n :class=\"{ 'ds-option--selected': opt.value && isSelected(opt.value) }\"\n tabindex=\"0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt)\"\n >\n <span\n v-if=\"cfg.multiple && opt.value\"\n class=\"c-checkbox\"\n :class=\"{ 'c-checkbox--checked': isSelected(opt.value) }\"\n ></span>\n <i v-if=\"opt.icon\" class=\"fa-fw\" :class=\"opt.icon\"></i>\n <span\n class=\"d-option__label\"\n :class=\"{ 'c-truncate': cfg.textEllipsis }\"\n v-html=\"highlight(opt.label)\"\n ></span>\n </li>\n <li v-if=\"filteredOptions.length === 0\" class=\"ds-option ds-option--empty\">\n Nincs találat\n </li>\n </template>\n </ul>\n <div v-if=\"cfg.multiple\" class=\"c-footer\">\n <Button v-if=\"cfg.clearable && selection.length > 0\" label=\"Törlés\" outline @click=\"clear\" />\n <Button label=\"OK\" type=\"success\" @click=\"confirm\" />\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style lang=\"scss\" src=\"@/styles/components/dropdown-select.scss\"></style>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"admins-components28.js","names":[],"sources":["../src/components/DropdownSelect.vue"],"sourcesContent":["<script lang=\"ts\">\nexport interface DropdownSelectConfig {\n placeholder?: string\n filterable?: boolean\n filterPlaceholder?: string\n clearable?: boolean\n textEllipsis?: boolean\n multiple?: boolean\n lazy?: boolean\n size?: ControlSize\n loading?: boolean\n highlight?: boolean\n disabled?: boolean\n}\n\nexport const dropdownSelectConfigDefaults: DropdownSelectConfig = {\n placeholder: 'Válassz...',\n filterable: true,\n filterPlaceholder: 'Kezdj el gépelni...',\n clearable: true,\n textEllipsis: true,\n multiple: false,\n lazy: false,\n loading: false,\n size: 'normal' as ControlSize,\n highlight: true,\n disabled: false,\n}\n\nexport interface DropdownOption {\n icon?: string\n value?: string\n label: string\n callback?: () => void\n}\n\nexport interface DropdownSelectProps {\n modelValue?: DropdownOption | DropdownOption[] | string | string[] | null\n options: DropdownOption[]\n config?: DropdownSelectConfig\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick } from 'vue'\nimport Button from '@/components/Button.vue'\nimport type { ControlSize } from '@/types/types'\nimport Loader from '@/components/Loader.vue'\nimport { useDropdownAnchor } from '@/composables/useDropdownAnchor'\n\nconst props = withDefaults(defineProps<DropdownSelectProps>(), {\n modelValue: null,\n config: () => ({ ...dropdownSelectConfigDefaults }),\n})\n\nconst cfg = computed(() => ({ ...dropdownSelectConfigDefaults, ...props.config }))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: DropdownOption | DropdownOption[] | null]\n 'filter-input': [filterText: string]\n}>()\n\nconst filterText = ref('')\nconst wrapperRef = ref<HTMLElement | null>(null)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst filterInputRef = ref<HTMLInputElement | null>(null)\nconst buffer = ref<DropdownOption[]>([])\nconst selection = ref<DropdownOption[]>(normalizeToOptions(props.modelValue, props.options))\n\nconst { isOpen, dropdownStyle } = useDropdownAnchor(wrapperRef, dropdownRef, {\n extraStyle: (rect) => ({\n minWidth: `${rect.width}px`,\n maxWidth: `${rect.width * 1.5}px`,\n }),\n})\n\n\nfunction normalizeToOptions(\n val: DropdownOption | DropdownOption[] | string | string[] | null | undefined,\n options: DropdownOption[],\n): DropdownOption[] {\n if (val == null) return []\n const arr = Array.isArray(val) ? val : [val]\n return arr\n .map((entry): DropdownOption | null => {\n if (entry == null) return null\n if (typeof entry === 'object' && 'label' in entry) {\n return entry as DropdownOption\n }\n if (typeof entry === 'string') {\n const found = options.find((o) => o.value === entry)\n return found ?? { value: entry, label: entry }\n }\n return null\n })\n .filter((o): o is DropdownOption => o !== null)\n}\n\nwatch(\n () => [props.modelValue, props.options],\n ([v]) => {\n selection.value = normalizeToOptions(v as typeof props.modelValue, props.options)\n },\n)\n\nwatch(isOpen, (open) => {\n if (open) {\n filterText.value = ''\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n if (cfg.value.lazy) buffer.value = [...selection.value]\n }\n})\n\nfunction onFilterInput(text: string) {\n filterText.value = text\n emit('filter-input', text)\n //debouncedEmit(text)\n}\n\n/* const debouncedEmit = debounce((raw: string) => {\n emit('filter-input', raw)\n}) */\n\n// Display\nconst selectedLabel = computed(() => {\n if (selection.value.length === 0) return null\n if (!cfg.value.multiple) {\n const sel = selection.value[0]\n // Prefer the label from the live options list, fall back to the stored label\n return props.options.find((o) => o.value === sel?.value)?.label ?? sel?.label ?? null\n }\n if (selection.value.length > 2) return `${selection.value.length} kiválasztva`\n return selection.value\n .map((sel) => props.options.find((o) => o.value === sel.value)?.label ?? sel.label ?? sel.value)\n .join(', ')\n})\n\nconst filteredOptions = computed(() => {\n const q = filterText.value.toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nfunction escapeHtml(str: string) {\n return str.replace(\n /[&<>\"']/g,\n (m) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[m]!,\n )\n}\n\nfunction highlight(label: string) {\n const q = filterText.value.trim()\n if (!q || !cfg.value.highlight) return escapeHtml(label)\n\n const safeLabel = escapeHtml(label)\n const safeQ = escapeHtml(q)\n\n const re = new RegExp(safeQ.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'ig')\n return safeLabel.replace(re, (m) => `<mark class=\"ds-option__highlight\">${m}</mark>`)\n}\n\nconst selectableOptions = computed(() => {\n return filteredOptions.value.filter((o) => o.value)\n})\n\nconst allOptionsSelected = computed(() => {\n if (selectableOptions.value.length === 0) return false\n const currentList = cfg.value.lazy && isOpen.value ? buffer.value : selection.value\n return selectableOptions.value.every((o) => o.value && currentList.some((s) => s.value === o.value))\n})\n\nfunction isSelected(value: string): boolean {\n const list = cfg.value.lazy && isOpen.value ? buffer : selection\n return list.value.some((s) => s.value === value)\n}\n\nfunction toggleAllOptions() {\n const currentList = cfg.value.lazy && isOpen.value ? buffer : selection\n const selectableOpts = selectableOptions.value.filter((o) => o.value)\n\n if (allOptionsSelected.value) {\n const selectableValues = new Set(selectableOpts.map((o) => o.value as string))\n currentList.value = currentList.value.filter((s) => !selectableValues.has(s.value ?? ''))\n } else {\n const existingValues = new Set(currentList.value.map((s) => s.value))\n const toAdd = selectableOpts.filter((o) => !existingValues.has(o.value as string))\n currentList.value = [...currentList.value, ...toAdd]\n }\n\n if (!cfg.value.lazy) {\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n}\n\n// Actions\nfunction toggleList(list: DropdownOption[], opt: DropdownOption): DropdownOption[] {\n const idx = list.findIndex((s) => s.value === opt.value)\n return idx >= 0 ? list.filter((_, i) => i !== idx) : [...list, opt]\n}\n\nfunction selectOption(opt: DropdownOption) {\n if (opt.callback) {\n opt.callback()\n isOpen.value = false\n return\n }\n\n const value = opt.value\n if (!value) return\n\n if (cfg.value.multiple) {\n if (cfg.value.lazy) {\n buffer.value = toggleList(buffer.value, opt)\n } else {\n selection.value = toggleList(selection.value, opt)\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n } else {\n selection.value = [opt]\n emit('update:modelValue', opt)\n isOpen.value = false\n }\n}\n\nfunction confirm() {\n if (cfg.value.lazy) {\n selection.value = [...buffer.value]\n emit('update:modelValue', buffer.value.length > 0 ? [...buffer.value] : null)\n }\n isOpen.value = false\n}\n\nfunction clear() {\n if (cfg.value.lazy) {\n buffer.value = []\n } else {\n selection.value = []\n emit('update:modelValue', null)\n }\n}\n\nfunction onOptionKeydown(e: KeyboardEvent, opt: DropdownOption) {\n if (e.key === ' ') {\n e.preventDefault()\n selectOption(opt)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n confirm()\n }\n}\n\nfunction toggleOpen() {\n if (cfg.value.disabled) return\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n if (cfg.value.filterable) {\n filterText.value = ''\n emit('filter-input', '')\n }\n }\n}\n\nfunction clearInput() {\n if (cfg.value.disabled) return\n selection.value = []\n emit('update:modelValue', null)\n isOpen.value = false\n}\n\nfunction focusAndOpen() {\n if (cfg.value.disabled) return\n isOpen.value = true\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n}\n\nfunction handleFilterClear() {\n filterText.value = ''\n emit('filter-input', '')\n}\n\ndefineExpose({ focusAndOpen })\n</script>\n\n<template>\n <div class=\"ac-component\">\n <div ref=\"wrapperRef\" class=\"c-wrapper ds-wrapper\">\n <div\n class=\"c-input-row pointer\"\n :class=\"{\n 'c-input-row--sm': cfg.size === 'small',\n 'c-input-row--lg': cfg.size === 'large',\n 'c-input-row--disabled': cfg.disabled,\n }\"\n :aria-disabled=\"cfg.disabled || undefined\"\n @click=\"toggleOpen()\"\n >\n <span v-if=\"selectedLabel\" class=\"c-truncate ds-value\">{{ selectedLabel }}</span>\n <span v-else class=\"c-placeholder\">{{ cfg.placeholder }}</span>\n <button\n v-if=\"cfg.clearable && selection.length > 0\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-clear-btn\"\n @click.stop=\"clearInput()\"\n aria-label=\"Törlés\"\n >\n <i class=\"fa-solid fa-fw fa-xmark\"></i>\n </button>\n <span\n class=\"c-icon-btn c-icon-btn--chevron mr-2\"\n :class=\"{ 'c-icon-btn--chevron-open': isOpen }\"\n >\n <i class=\"fa-solid fa-fw fa-chevron-down\"></i>\n </span>\n </div>\n </div>\n <Teleport to=\"body\">\n <div class=\"ac-component\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdownRef\"\n class=\"c-dropdown ds-dropdown ds-wrapper\"\n :class=\"{ 'ds-dropdown--multiple': cfg.multiple }\"\n :style=\"dropdownStyle\"\n >\n <div v-if=\"cfg.filterable\" class=\"ds-filter\">\n <span\n v-if=\"cfg.multiple\"\n class=\"c-checkbox ds-select-all-checkbox\"\n :class=\"{ 'c-checkbox--checked': allOptionsSelected }\"\n @click.stop=\"toggleAllOptions()\"\n :title=\"allOptionsSelected ? 'Összes kijelölés törlése' : 'Összes kijelölése'\"\n ></span>\n <input\n ref=\"filterInputRef\"\n type=\"text\"\n id=\"ds-filter-input\"\n class=\"c-focus ds-filter-input\"\n :value=\"filterText\"\n @input=\"onFilterInput(($event.target as HTMLInputElement).value)\"\n autocomplete=\"off\"\n :placeholder=\"cfg.filterPlaceholder\"\n @click.stop\n />\n <button\n v-if=\"filterText\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-filter-clear\"\n @click.stop=\"handleFilterClear()\"\n aria-label=\"Szűrők törlése\"\n >\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <ul class=\"ds-options c-scroll\">\n <li v-if=\"cfg.loading\" class=\"ds-option ds-option--loading\">\n <Loader size=\"2rem\" color=\"var(--neutral-300)\" class=\"m-auto p-3\" />\n </li>\n <template v-else>\n <li\n v-for=\"(opt, idx) in filteredOptions\"\n :key=\"opt.value ?? `cb-${idx}`\"\n class=\"d-option ds-option\"\n :class=\"{ 'ds-option--selected': opt.value && isSelected(opt.value) }\"\n tabindex=\"0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt)\"\n >\n <span\n v-if=\"cfg.multiple && opt.value\"\n class=\"c-checkbox\"\n :class=\"{ 'c-checkbox--checked': isSelected(opt.value) }\"\n ></span>\n <i v-if=\"opt.icon\" class=\"fa-fw\" :class=\"opt.icon\"></i>\n <span\n class=\"d-option__label\"\n :class=\"{ 'c-truncate': cfg.textEllipsis }\"\n v-html=\"highlight(opt.label)\"\n ></span>\n </li>\n <li v-if=\"filteredOptions.length === 0\" class=\"ds-option ds-option--empty\">\n Nincs találat\n </li>\n </template>\n </ul>\n\n <div v-if=\"cfg.multiple || (cfg.clearable && selection.length > 0)\" class=\"c-footer\">\n <Button v-if=\"cfg.clearable\" label=\"Törlés\" outline @click=\"clear\" />\n <Button v-if=\"cfg.multiple\" label=\"OK\" type=\"success\" @click=\"confirm\" />\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style lang=\"scss\" src=\"@/styles/components/dropdown-select.scss\"></style>\n"],"mappings":""}
1
+ {"version":3,"file":"admins-components28.js","names":[],"sources":["../src/components/DropdownSelect.vue"],"sourcesContent":["<script lang=\"ts\">\nexport interface DropdownSelectConfig {\n placeholder?: string\n filterable?: boolean\n filterPlaceholder?: string\n clearable?: boolean\n textEllipsis?: boolean\n multiple?: boolean\n lazy?: boolean\n size?: ControlSize\n loading?: boolean\n highlight?: boolean\n disabled?: boolean\n}\n\nexport const dropdownSelectConfigDefaults: DropdownSelectConfig = {\n placeholder: 'Válassz...',\n filterable: true,\n filterPlaceholder: 'Kezdj el gépelni...',\n clearable: true,\n textEllipsis: true,\n multiple: false,\n lazy: false,\n loading: false,\n size: 'normal' as ControlSize,\n highlight: true,\n disabled: false,\n}\n\nexport interface DropdownOption {\n icon?: string\n value?: string\n label: string\n callback?: () => void\n}\n\nexport interface DropdownSelectProps {\n modelValue?: DropdownOption | DropdownOption[] | string | string[] | null\n options: DropdownOption[]\n config?: DropdownSelectConfig\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick } from 'vue'\nimport Button from '@/components/Button.vue'\nimport type { ControlSize } from '@/types/types'\nimport Loader from '@/components/Loader.vue'\nimport { useDropdownAnchor } from '@/composables/useDropdownAnchor'\n\nconst props = withDefaults(defineProps<DropdownSelectProps>(), {\n modelValue: null,\n config: () => ({ ...dropdownSelectConfigDefaults }),\n})\n\nconst cfg = computed(() => ({ ...dropdownSelectConfigDefaults, ...props.config }))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: DropdownOption | DropdownOption[] | null]\n 'filter-input': [filterText: string]\n}>()\n\nconst filterText = ref('')\nconst wrapperRef = ref<HTMLElement | null>(null)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst filterInputRef = ref<HTMLInputElement | null>(null)\nconst buffer = ref<DropdownOption[]>([])\nconst selection = ref<DropdownOption[]>(normalizeToOptions(props.modelValue, props.options))\n\nconst { isOpen, dropdownStyle, placement } = useDropdownAnchor(wrapperRef, dropdownRef, {\n extraStyle: (rect) => ({\n minWidth: `${rect.width}px`,\n maxWidth: `${rect.width}px`,\n }),\n maxHeight: '17rem',\n})\n\n\nfunction normalizeToOptions(\n val: DropdownOption | DropdownOption[] | string | string[] | null | undefined,\n options: DropdownOption[],\n): DropdownOption[] {\n if (val == null) return []\n const arr = Array.isArray(val) ? val : [val]\n return arr\n .map((entry): DropdownOption | null => {\n if (entry == null) return null\n if (typeof entry === 'object' && 'label' in entry) {\n return entry as DropdownOption\n }\n if (typeof entry === 'string') {\n const found = options.find((o) => o.value === entry)\n return found ?? { value: entry, label: entry }\n }\n return null\n })\n .filter((o): o is DropdownOption => o !== null)\n}\n\nwatch(\n () => [props.modelValue, props.options],\n ([v]) => {\n selection.value = normalizeToOptions(v as typeof props.modelValue, props.options)\n },\n)\n\nwatch(isOpen, (open) => {\n if (open) {\n filterText.value = ''\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n if (cfg.value.lazy) buffer.value = [...selection.value]\n }\n})\n\nfunction onFilterInput(text: string) {\n filterText.value = text\n emit('filter-input', text)\n}\n\nconst selectedLabel = computed(() => {\n if (selection.value.length === 0) return null\n if (!cfg.value.multiple) {\n const sel = selection.value[0]\n\n return props.options.find((o) => o.value === sel?.value)?.label ?? sel?.label ?? null\n }\n if (selection.value.length > 2) return `${selection.value.length} kiválasztva`\n return selection.value\n .map((sel) => props.options.find((o) => o.value === sel.value)?.label ?? sel.label ?? sel.value)\n .join(', ')\n})\n\nconst filteredOptions = computed(() => {\n const q = filterText.value.toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nfunction escapeHtml(str: string) {\n return str.replace(\n /[&<>\"']/g,\n (m) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' })[m]!,\n )\n}\n\nfunction highlight(label: string) {\n const q = filterText.value.trim()\n if (!q || !cfg.value.highlight) return escapeHtml(label)\n\n const safeLabel = escapeHtml(label)\n const safeQ = escapeHtml(q)\n\n const re = new RegExp(safeQ.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'ig')\n return safeLabel.replace(re, (m) => `<mark class=\"ds-option__highlight\">${m}</mark>`)\n}\n\nconst selectableOptions = computed(() => {\n return filteredOptions.value.filter((o) => o.value)\n})\n\nconst allOptionsSelected = computed(() => {\n if (selectableOptions.value.length === 0) return false\n const currentList = cfg.value.lazy && isOpen.value ? buffer.value : selection.value\n return selectableOptions.value.every((o) => o.value && currentList.some((s) => s.value === o.value))\n})\n\nfunction isSelected(value: string): boolean {\n const list = cfg.value.lazy && isOpen.value ? buffer : selection\n return list.value.some((s) => s.value === value)\n}\n\nfunction toggleAllOptions() {\n const currentList = cfg.value.lazy && isOpen.value ? buffer : selection\n const selectableOpts = selectableOptions.value.filter((o) => o.value)\n\n if (allOptionsSelected.value) {\n const selectableValues = new Set(selectableOpts.map((o) => o.value as string))\n currentList.value = currentList.value.filter((s) => !selectableValues.has(s.value ?? ''))\n } else {\n const existingValues = new Set(currentList.value.map((s) => s.value))\n const toAdd = selectableOpts.filter((o) => !existingValues.has(o.value as string))\n currentList.value = [...currentList.value, ...toAdd]\n }\n\n if (!cfg.value.lazy) {\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n}\n\nfunction toggleList(list: DropdownOption[], opt: DropdownOption): DropdownOption[] {\n const idx = list.findIndex((s) => s.value === opt.value)\n return idx >= 0 ? list.filter((_, i) => i !== idx) : [...list, opt]\n}\n\nfunction selectOption(opt: DropdownOption) {\n if (opt.callback) {\n opt.callback()\n isOpen.value = false\n return\n }\n\n const value = opt.value\n if (!value) return\n\n if (cfg.value.multiple) {\n if (cfg.value.lazy) {\n buffer.value = toggleList(buffer.value, opt)\n } else {\n selection.value = toggleList(selection.value, opt)\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n } else {\n selection.value = [opt]\n emit('update:modelValue', opt)\n isOpen.value = false\n }\n}\n\nfunction confirm() {\n if (cfg.value.lazy) {\n selection.value = [...buffer.value]\n emit('update:modelValue', buffer.value.length > 0 ? [...buffer.value] : null)\n }\n isOpen.value = false\n}\n\nfunction clear() {\n if (cfg.value.lazy) {\n buffer.value = []\n } else {\n selection.value = []\n emit('update:modelValue', null)\n }\n}\n\nfunction onOptionKeydown(e: KeyboardEvent, opt: DropdownOption) {\n if (e.key === ' ') {\n e.preventDefault()\n selectOption(opt)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n confirm()\n }\n}\n\nfunction toggleOpen() {\n if (cfg.value.disabled) return\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n if (cfg.value.filterable) {\n filterText.value = ''\n emit('filter-input', '')\n }\n }\n}\n\nfunction clearInput() {\n if (cfg.value.disabled) return\n selection.value = []\n emit('update:modelValue', null)\n isOpen.value = false\n}\n\nfunction focusAndOpen() {\n if (cfg.value.disabled) return\n isOpen.value = true\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n}\n\nfunction handleFilterClear() {\n filterText.value = ''\n emit('filter-input', '')\n}\n\ndefineExpose({ focusAndOpen })\n</script>\n\n<template>\n <div class=\"ac-component\">\n <div ref=\"wrapperRef\" class=\"c-wrapper ds-wrapper\">\n <div\n class=\"c-input-row pointer\"\n :class=\"{\n 'c-input-row--sm': cfg.size === 'small',\n 'c-input-row--lg': cfg.size === 'large',\n 'c-input-row--disabled': cfg.disabled,\n 'c-input-row--open': isOpen,\n }\"\n :aria-disabled=\"cfg.disabled || undefined\"\n @click=\"toggleOpen()\"\n >\n <span v-if=\"selectedLabel\" class=\"c-truncate ds-value\">{{ selectedLabel }}</span>\n <span v-else class=\"c-placeholder\">{{ cfg.placeholder }}</span>\n <button\n v-if=\"cfg.clearable && selection.length > 0\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-clear-btn\"\n @click.stop=\"clearInput()\"\n aria-label=\"Törlés\"\n >\n <i class=\"fa-solid fa-fw fa-xmark\"></i>\n </button>\n <span\n class=\"c-icon-btn c-icon-btn--chevron mr-2\"\n :class=\"{ 'c-icon-btn--chevron-open': isOpen }\"\n >\n <i class=\"fa-solid fa-fw fa-chevron-down\"></i>\n </span>\n </div>\n </div>\n <Teleport to=\"body\">\n <div class=\"ac-component\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdownRef\"\n class=\"c-dropdown ds-dropdown ds-wrapper\"\n :class=\"{ 'ds-dropdown--multiple': cfg.multiple, 'ds-dropdown--up': placement === 'up' }\"\n :style=\"dropdownStyle\"\n >\n <div v-if=\"cfg.filterable\" class=\"ds-filter\">\n <span\n v-if=\"cfg.multiple\"\n class=\"c-checkbox ds-select-all-checkbox\"\n :class=\"{ 'c-checkbox--checked': allOptionsSelected }\"\n @click.stop=\"toggleAllOptions()\"\n :title=\"allOptionsSelected ? 'Összes kijelölés törlése' : 'Összes kijelölése'\"\n ></span>\n <input\n ref=\"filterInputRef\"\n type=\"text\"\n id=\"ds-filter-input\"\n class=\"c-focus ds-filter-input\"\n :value=\"filterText\"\n @input=\"onFilterInput(($event.target as HTMLInputElement).value)\"\n autocomplete=\"off\"\n :placeholder=\"cfg.filterPlaceholder\"\n @click.stop\n />\n <button\n v-if=\"filterText\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-filter-clear\"\n @click.stop=\"handleFilterClear()\"\n aria-label=\"Szűrők törlése\"\n >\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <ul class=\"ds-options c-scroll\">\n <li v-if=\"cfg.loading\" class=\"ds-option ds-option--loading\">\n <Loader size=\"2rem\" color=\"var(--neutral-300)\" class=\"m-auto p-3\" />\n </li>\n <template v-else>\n <li\n v-for=\"(opt, idx) in filteredOptions\"\n :key=\"opt.value ?? `cb-${idx}`\"\n class=\"d-option ds-option\"\n :class=\"{ 'ds-option--selected': opt.value && isSelected(opt.value) }\"\n tabindex=\"0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt)\"\n >\n <span\n v-if=\"cfg.multiple && opt.value\"\n class=\"c-checkbox\"\n :class=\"{ 'c-checkbox--checked': isSelected(opt.value) }\"\n ></span>\n <i v-if=\"opt.icon\" class=\"fa-fw\" :class=\"opt.icon\"></i>\n <span\n class=\"d-option__label\"\n :class=\"{ 'c-truncate': cfg.textEllipsis }\"\n v-html=\"highlight(opt.label)\"\n ></span>\n </li>\n <li v-if=\"filteredOptions.length === 0\" class=\"ds-option ds-option--empty\">\n Nincs találat\n </li>\n </template>\n </ul>\n <div v-if=\"cfg.multiple\" class=\"c-footer\">\n <Button v-if=\"cfg.clearable && selection.length > 0\" label=\"Törlés\" outline @click=\"clear\" />\n <Button label=\"OK\" type=\"success\" @click=\"confirm\" />\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style lang=\"scss\" src=\"@/styles/components/dropdown-select.scss\"></style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"admins-components31.js","names":[],"sources":["../src/composables/useSwipeToClose.ts"],"sourcesContent":["import { computed, onBeforeUnmount, onMounted, ref } from 'vue'\nimport type { Ref } from 'vue'\n\nexport interface UseSwipeToCloseOptions {\n /**\n * The panel's anchor position. The composable only attempts to close on\n * horizontal positions ('left' / 'right').\n */\n position: Ref<'left' | 'right' | 'top' | 'bottom'>\n /** Called when the user completes a qualifying swipe-to-close gesture. */\n onClose: () => void\n /**\n * Fraction of the panel width that must be covered by the swipe to trigger\n * a close. Defaults to 0.35 (35%).\n */\n distanceThreshold?: number\n /**\n * Horizontal velocity (px/ms) above which a shorter swipe still closes.\n * Defaults to 0.4.\n */\n velocityThreshold?: number\n /**\n * Vertical-movement ratio above which the gesture is treated as a scroll\n * and ignored. Defaults to 0.7 (vertical must be ≤ 70% of horizontal).\n */\n verticalRatio?: number\n /**\n * Which swipe directions count as a close gesture.\n *\n * - `'away'` (default): only swipes toward the anchored edge close the\n * panel (left-positioned panel closes on left swipe, right-positioned\n * on right swipe).\n * - `'both'`: swipes in either horizontal direction close the panel.\n *\n * Swipes against the anchored edge are visually constrained so the panel\n * doesn't get pushed past its anchor.\n */\n closeDirections?: 'away' | 'both'\n}\n\nexport interface UseSwipeToCloseReturn {\n /** Whether a swipe is currently in progress. */\n isDragging: Ref<boolean>\n /** Inline style to apply to the panel element (transform + transition). */\n panelStyle: Ref<Record<string, string> | undefined>\n /** Handlers to bind to the panel element's touch events. */\n touchHandlers: {\n onTouchstart: (e: TouchEvent) => void\n onTouchend: (e: TouchEvent) => void\n onTouchcancel: () => void\n }\n}\n\nexport function useSwipeToClose(\n panelRef: Ref<HTMLElement | null>,\n options: UseSwipeToCloseOptions,\n): UseSwipeToCloseReturn {\n const {\n position,\n onClose,\n distanceThreshold = 0.35,\n velocityThreshold = 0.4,\n verticalRatio = 0.7,\n closeDirections = 'away',\n } = options\n\n const isDragging = ref(false)\n const dragOffset = ref(0)\n\n let startX = 0\n let startY = 0\n let startTime = 0\n let trackingPointer: number | null = null\n let panelWidth = 0\n\n const isHorizontal = computed(\n () => position.value === 'left' || position.value === 'right',\n )\n\n function onTouchStart(e: TouchEvent) {\n if (!isHorizontal.value || e.touches.length !== 1) return\n const touch = e.touches[0]\n if (!touch) return\n const panel = panelRef.value\n if (!panel) return\n\n startX = touch.clientX\n startY = touch.clientY\n startTime = performance.now()\n panelWidth = panel.offsetWidth\n isDragging.value = true\n dragOffset.value = 0\n trackingPointer = touch.identifier\n }\n\n function onTouchMove(e: TouchEvent) {\n if (!isDragging.value || trackingPointer === null) return\n const touch = Array.from(e.touches).find((t) => t.identifier === trackingPointer)\n if (!touch) return\n\n const dx = touch.clientX - startX\n const dy = touch.clientY - startY\n\n // Vertical-dominant gesture: let the browser scroll the panel content.\n if (Math.abs(dy) > Math.abs(dx) * verticalRatio && Math.abs(dy) > 10) {\n isDragging.value = false\n dragOffset.value = 0\n return\n }\n\n // The panel can't be dragged past its anchor: the edge closest to the\n // panel's position acts as a wall. When closeDirections === 'away' the\n // inward direction (away from the anchor) is also clamped at 0 so the\n // gesture mirrors a \"dismiss\" only toward the screen edge.\n if (position.value === 'left') {\n dragOffset.value = closeDirections === 'both' ? dx : Math.min(0, dx)\n } else {\n dragOffset.value = closeDirections === 'both' ? dx : Math.max(0, dx)\n }\n\n if (e.cancelable) e.preventDefault()\n }\n\n function onTouchEnd(e: TouchEvent) {\n if (!isDragging.value) return\n\n const touch =\n Array.from(e.changedTouches).find((t) => t.identifier === trackingPointer) ??\n e.changedTouches[0]\n\n const dx = touch ? touch.clientX - startX : 0\n const dt = Math.max(1, performance.now() - startTime)\n const velocity = Math.abs(dx) / dt\n const distanceRatio = Math.abs(dx) / Math.max(panelWidth, 1)\n\n const shouldClose =\n distanceRatio >= distanceThreshold || velocity >= velocityThreshold\n const swipedTowardEdge =\n (position.value === 'left' && dx < 0) || (position.value === 'right' && dx > 0)\n\n if (shouldClose && (closeDirections === 'both' || swipedTowardEdge)) {\n onClose()\n }\n\n isDragging.value = false\n trackingPointer = null\n dragOffset.value = 0\n }\n\n function onTouchCancel() {\n isDragging.value = false\n trackingPointer = null\n dragOffset.value = 0\n }\n\n const panelStyle = computed<Record<string, string> | undefined>(() => {\n if (!isDragging.value || dragOffset.value === 0) return undefined\n return {\n transform: `translateX(${dragOffset.value}px)`,\n transition: 'none',\n }\n })\n\n onMounted(() => {\n // Non-passive so we can preventDefault and stop the page from scrolling\n // horizontally while the panel is being dragged.\n document.addEventListener('touchmove', onTouchMove, { passive: false })\n })\n\n onBeforeUnmount(() => {\n document.removeEventListener('touchmove', onTouchMove)\n })\n\n return {\n isDragging,\n panelStyle,\n touchHandlers: {\n onTouchstart: onTouchStart,\n onTouchend: onTouchEnd,\n onTouchcancel: onTouchCancel,\n },\n }\n}\n"],"mappings":";;AAqDA,SAAgB,EACd,GACA,GACuB;CACvB,IAAM,EACJ,aACA,YACA,uBAAoB,KACpB,uBAAoB,IACpB,mBAAgB,IAChB,qBAAkB,WAChB,GAEE,IAAa,EAAI,EAAK,GACtB,IAAa,EAAI,CAAC,GAEpB,IAAS,GACT,IAAS,GACT,IAAY,GACZ,IAAiC,MACjC,IAAa,GAEX,IAAe,QACb,EAAS,UAAU,UAAU,EAAS,UAAU,OACxD;CAEA,SAAS,EAAa,GAAe;EACnC,IAAI,CAAC,EAAa,SAAS,EAAE,QAAQ,WAAW,GAAG;EACnD,IAAM,IAAQ,EAAE,QAAQ;EACxB,IAAI,CAAC,GAAO;EACZ,IAAM,IAAQ,EAAS;EAClB,MAEL,IAAS,EAAM,SACf,IAAS,EAAM,SACf,IAAY,YAAY,IAAI,GAC5B,IAAa,EAAM,aACnB,EAAW,QAAQ,IACnB,EAAW,QAAQ,GACnB,IAAkB,EAAM;CAC1B;CAEA,SAAS,EAAY,GAAe;EAClC,IAAI,CAAC,EAAW,SAAS,MAAoB,MAAM;EACnD,IAAM,IAAQ,MAAM,KAAK,EAAE,OAAO,CAAC,CAAC,MAAM,MAAM,EAAE,eAAe,CAAe;EAChF,IAAI,CAAC,GAAO;EAEZ,IAAM,IAAK,EAAM,UAAU,GACrB,IAAK,EAAM,UAAU;EAG3B,IAAI,KAAK,IAAI,CAAE,IAAI,KAAK,IAAI,CAAE,IAAI,KAAiB,KAAK,IAAI,CAAE,IAAI,IAAI;GAEpE,AADA,EAAW,QAAQ,IACnB,EAAW,QAAQ;GACnB;EACF;EAYA,AANI,EAAS,UAAU,SACrB,EAAW,QAAQ,MAAoB,SAAS,IAAK,KAAK,IAAI,GAAG,CAAE,IAEnE,EAAW,QAAQ,MAAoB,SAAS,IAAK,KAAK,IAAI,GAAG,CAAE,GAGjE,EAAE,cAAY,EAAE,eAAe;CACrC;CAEA,SAAS,EAAW,GAAe;EACjC,IAAI,CAAC,EAAW,OAAO;EAEvB,IAAM,IACJ,MAAM,KAAK,EAAE,cAAc,CAAC,CAAC,MAAM,MAAM,EAAE,eAAe,CAAe,KACzE,EAAE,eAAe,IAEb,IAAK,IAAQ,EAAM,UAAU,IAAS,GACtC,IAAK,KAAK,IAAI,GAAG,YAAY,IAAI,IAAI,CAAS,GAC9C,IAAW,KAAK,IAAI,CAAE,IAAI,GAG1B,IAFgB,KAAK,IAAI,CAAE,IAAI,KAAK,IAAI,GAAY,CAAC,KAGxC,KAAqB,KAAY,GAC9C,IACH,EAAS,UAAU,UAAU,IAAK,KAAO,EAAS,UAAU,WAAW,IAAK;EAQ/E,AANI,MAAgB,MAAoB,UAAU,MAChD,EAAQ,GAGV,EAAW,QAAQ,IACnB,IAAkB,MAClB,EAAW,QAAQ;CACrB;CAEA,SAAS,IAAgB;EAGvB,AAFA,EAAW,QAAQ,IACnB,IAAkB,MAClB,EAAW,QAAQ;CACrB;CAEA,IAAM,IAAa,QAAmD;EAChE,OAAC,EAAW,SAAS,EAAW,UAAU,IAC9C,OAAO;GACL,WAAW,cAAc,EAAW,MAAM;GAC1C,YAAY;EACd;CACF,CAAC;CAYD,OAVA,QAAgB;EAGd,SAAS,iBAAiB,aAAa,GAAa,EAAE,SAAS,GAAM,CAAC;CACxE,CAAC,GAED,QAAsB;EACpB,SAAS,oBAAoB,aAAa,CAAW;CACvD,CAAC,GAEM;EACL;EACA;EACA,eAAe;GACb,cAAc;GACd,YAAY;GACZ,eAAe;EACjB;CACF;AACF"}
1
+ {"version":3,"file":"admins-components31.js","names":[],"sources":["../src/composables/useSwipeToClose.ts"],"sourcesContent":["import { computed, onBeforeUnmount, onMounted, ref } from 'vue'\nimport type { Ref } from 'vue'\n\nexport interface UseSwipeToCloseOptions {\n position: Ref<'left' | 'right' | 'top' | 'bottom'>\n onClose: () => void\n distanceThreshold?: number\n velocityThreshold?: number\n verticalRatio?: number\n closeDirections?: 'away' | 'both'\n}\n\nexport interface UseSwipeToCloseReturn {\n isDragging: Ref<boolean>\n panelStyle: Ref<Record<string, string> | undefined>\n touchHandlers: {\n onTouchstart: (e: TouchEvent) => void\n onTouchend: (e: TouchEvent) => void\n onTouchcancel: () => void\n }\n}\n\nexport function useSwipeToClose(\n panelRef: Ref<HTMLElement | null>,\n options: UseSwipeToCloseOptions,\n): UseSwipeToCloseReturn {\n const {\n position,\n onClose,\n distanceThreshold = 0.35,\n velocityThreshold = 0.4,\n verticalRatio = 0.7,\n closeDirections = 'away',\n } = options\n\n const isDragging = ref(false)\n const dragOffset = ref(0)\n\n let startX = 0\n let startY = 0\n let startTime = 0\n let trackingPointer: number | null = null\n let panelWidth = 0\n\n const isHorizontal = computed(() => position.value === 'left' || position.value === 'right')\n\n function onTouchStart(e: TouchEvent) {\n if (!isHorizontal.value || e.touches.length !== 1) return\n const touch = e.touches[0]\n if (!touch) return\n const panel = panelRef.value\n if (!panel) return\n\n startX = touch.clientX\n startY = touch.clientY\n startTime = performance.now()\n panelWidth = panel.offsetWidth\n isDragging.value = true\n dragOffset.value = 0\n trackingPointer = touch.identifier\n }\n\n function onTouchMove(e: TouchEvent) {\n if (!isDragging.value || trackingPointer === null) return\n const touch = Array.from(e.touches).find((t) => t.identifier === trackingPointer)\n if (!touch) return\n\n const dx = touch.clientX - startX\n const dy = touch.clientY - startY\n\n if (Math.abs(dy) > Math.abs(dx) * verticalRatio && Math.abs(dy) > 10) {\n isDragging.value = false\n dragOffset.value = 0\n return\n }\n\n if (position.value === 'left') {\n dragOffset.value = closeDirections === 'both' ? dx : Math.min(0, dx)\n } else {\n dragOffset.value = closeDirections === 'both' ? dx : Math.max(0, dx)\n }\n\n if (e.cancelable) e.preventDefault()\n }\n\n function onTouchEnd(e: TouchEvent) {\n if (!isDragging.value) return\n\n const touch =\n Array.from(e.changedTouches).find((t) => t.identifier === trackingPointer) ??\n e.changedTouches[0]\n\n const dx = touch ? touch.clientX - startX : 0\n const dt = Math.max(1, performance.now() - startTime)\n const velocity = Math.abs(dx) / dt\n const distanceRatio = Math.abs(dx) / Math.max(panelWidth, 1)\n\n const shouldClose = distanceRatio >= distanceThreshold || velocity >= velocityThreshold\n const swipedTowardEdge =\n (position.value === 'left' && dx < 0) || (position.value === 'right' && dx > 0)\n\n if (shouldClose && (closeDirections === 'both' || swipedTowardEdge)) {\n onClose()\n }\n\n isDragging.value = false\n trackingPointer = null\n dragOffset.value = 0\n }\n\n function onTouchCancel() {\n isDragging.value = false\n trackingPointer = null\n dragOffset.value = 0\n }\n\n const panelStyle = computed<Record<string, string> | undefined>(() => {\n if (!isDragging.value || dragOffset.value === 0) return undefined\n return {\n transform: `translateX(${dragOffset.value}px)`,\n transition: 'none',\n }\n })\n\n onMounted(() => {\n document.addEventListener('touchmove', onTouchMove, { passive: false })\n })\n\n onBeforeUnmount(() => {\n document.removeEventListener('touchmove', onTouchMove)\n })\n\n return {\n isDragging,\n panelStyle,\n touchHandlers: {\n onTouchstart: onTouchStart,\n onTouchend: onTouchEnd,\n onTouchcancel: onTouchCancel,\n },\n }\n}\n"],"mappings":";;AAsBA,SAAgB,EACd,GACA,GACuB;CACvB,IAAM,EACJ,aACA,YACA,uBAAoB,KACpB,uBAAoB,IACpB,mBAAgB,IAChB,qBAAkB,WAChB,GAEE,IAAa,EAAI,EAAK,GACtB,IAAa,EAAI,CAAC,GAEpB,IAAS,GACT,IAAS,GACT,IAAY,GACZ,IAAiC,MACjC,IAAa,GAEX,IAAe,QAAe,EAAS,UAAU,UAAU,EAAS,UAAU,OAAO;CAE3F,SAAS,EAAa,GAAe;EACnC,IAAI,CAAC,EAAa,SAAS,EAAE,QAAQ,WAAW,GAAG;EACnD,IAAM,IAAQ,EAAE,QAAQ;EACxB,IAAI,CAAC,GAAO;EACZ,IAAM,IAAQ,EAAS;EAClB,MAEL,IAAS,EAAM,SACf,IAAS,EAAM,SACf,IAAY,YAAY,IAAI,GAC5B,IAAa,EAAM,aACnB,EAAW,QAAQ,IACnB,EAAW,QAAQ,GACnB,IAAkB,EAAM;CAC1B;CAEA,SAAS,EAAY,GAAe;EAClC,IAAI,CAAC,EAAW,SAAS,MAAoB,MAAM;EACnD,IAAM,IAAQ,MAAM,KAAK,EAAE,OAAO,CAAC,CAAC,MAAM,MAAM,EAAE,eAAe,CAAe;EAChF,IAAI,CAAC,GAAO;EAEZ,IAAM,IAAK,EAAM,UAAU,GACrB,IAAK,EAAM,UAAU;EAE3B,IAAI,KAAK,IAAI,CAAE,IAAI,KAAK,IAAI,CAAE,IAAI,KAAiB,KAAK,IAAI,CAAE,IAAI,IAAI;GAEpE,AADA,EAAW,QAAQ,IACnB,EAAW,QAAQ;GACnB;EACF;EAQA,AANI,EAAS,UAAU,SACrB,EAAW,QAAQ,MAAoB,SAAS,IAAK,KAAK,IAAI,GAAG,CAAE,IAEnE,EAAW,QAAQ,MAAoB,SAAS,IAAK,KAAK,IAAI,GAAG,CAAE,GAGjE,EAAE,cAAY,EAAE,eAAe;CACrC;CAEA,SAAS,EAAW,GAAe;EACjC,IAAI,CAAC,EAAW,OAAO;EAEvB,IAAM,IACJ,MAAM,KAAK,EAAE,cAAc,CAAC,CAAC,MAAM,MAAM,EAAE,eAAe,CAAe,KACzE,EAAE,eAAe,IAEb,IAAK,IAAQ,EAAM,UAAU,IAAS,GACtC,IAAK,KAAK,IAAI,GAAG,YAAY,IAAI,IAAI,CAAS,GAC9C,IAAW,KAAK,IAAI,CAAE,IAAI,GAG1B,IAFgB,KAAK,IAAI,CAAE,IAAI,KAAK,IAAI,GAAY,CAAC,KAEtB,KAAqB,KAAY,GAChE,IACH,EAAS,UAAU,UAAU,IAAK,KAAO,EAAS,UAAU,WAAW,IAAK;EAQ/E,AANI,MAAgB,MAAoB,UAAU,MAChD,EAAQ,GAGV,EAAW,QAAQ,IACnB,IAAkB,MAClB,EAAW,QAAQ;CACrB;CAEA,SAAS,IAAgB;EAGvB,AAFA,EAAW,QAAQ,IACnB,IAAkB,MAClB,EAAW,QAAQ;CACrB;CAEA,IAAM,IAAa,QAAmD;EAChE,OAAC,EAAW,SAAS,EAAW,UAAU,IAC9C,OAAO;GACL,WAAW,cAAc,EAAW,MAAM;GAC1C,YAAY;EACd;CACF,CAAC;CAUD,OARA,QAAgB;EACd,SAAS,iBAAiB,aAAa,GAAa,EAAE,SAAS,GAAM,CAAC;CACxE,CAAC,GAED,QAAsB;EACpB,SAAS,oBAAoB,aAAa,CAAW;CACvD,CAAC,GAEM;EACL;EACA;EACA,eAAe;GACb,cAAc;GACd,YAAY;GACZ,eAAe;EACjB;CACF;AACF"}