@ulu/frontend-vue 0.2.0-beta.12 → 0.2.0-beta.14

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.
@@ -5,9 +5,11 @@ type __VLS_WithTemplateSlots<T, S> = T & (new () => {
5
5
  });
6
6
  declare const __VLS_component: import('vue').DefineComponent<{}, {
7
7
  vertical: boolean;
8
+ modifiers?: string | unknown[] | undefined;
8
9
  defaultIndex?: number | undefined;
9
10
  $props: {
10
11
  readonly vertical?: boolean | undefined;
12
+ readonly modifiers?: string | unknown[] | undefined;
11
13
  readonly defaultIndex?: number | undefined;
12
14
  };
13
15
  }, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
@@ -1 +1 @@
1
- {"version":3,"file":"UluTabGroup.vue.d.ts","sourceRoot":"","sources":["../../../lib/components/collapsible/UluTabGroup.vue"],"names":[],"mappings":"AAYA;wBAwHqB,uBAAuB,CAAC,OAAO,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;;6BAEtE,CAAC,EAAE,CAAC;;;AAVjC;;;;;;;2OAOG"}
1
+ {"version":3,"file":"UluTabGroup.vue.d.ts","sourceRoot":"","sources":["../../../lib/components/collapsible/UluTabGroup.vue"],"names":[],"mappings":"AAoBA;wBAmJqB,uBAAuB,CAAC,OAAO,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;;6BAEtE,CAAC,EAAE,CAAC;;;AAVjC;;;;;;;;;2OAOG"}
@@ -1,6 +1,7 @@
1
- import { createBlock as r, openBlock as l, unref as o, withCtx as n, createElementVNode as c, normalizeClass as i, renderSlot as s, normalizeProps as u, guardReactiveProps as d } from "vue";
2
- import { TabGroup as f } from "@headlessui/vue";
3
- const b = /* @__PURE__ */ Object.assign({
1
+ import { createBlock as l, openBlock as i, unref as t, withCtx as n, createElementVNode as d, mergeProps as c, renderSlot as u, normalizeProps as f, guardReactiveProps as m } from "vue";
2
+ import { TabGroup as p } from "@headlessui/vue";
3
+ import { useModifiers as v } from "../../composables/useModifiers.js";
4
+ const h = /* @__PURE__ */ Object.assign({
4
5
  inheritAttrs: !1
5
6
  }, {
6
7
  __name: "UluTabGroup",
@@ -12,26 +13,34 @@ const b = /* @__PURE__ */ Object.assign({
12
13
  /**
13
14
  * Whether or not to use vertical layout
14
15
  */
15
- vertical: Boolean
16
+ vertical: Boolean,
17
+ /**
18
+ * Class modifiers (ie. 'transparent', 'secondary', etc)
19
+ */
20
+ modifiers: [String, Array]
16
21
  },
17
22
  setup(e) {
18
- return (t, m) => (l(), r(o(f), {
23
+ const a = e, { resolvedModifiers: s } = v({ props: a, baseClass: "tabs" });
24
+ return (r, b) => (i(), l(t(p), {
19
25
  defaultIndex: e.defaultIndex,
20
26
  vertical: e.vertical
21
27
  }, {
22
- default: n((a) => [
23
- c("div", {
24
- class: i(["tabs", {
25
- "tabs--vertical": e.vertical
26
- }])
27
- }, [
28
- s(t.$slots, "default", u(d(a)))
29
- ], 2)
28
+ default: n((o) => [
29
+ d("div", c(r.$attrs, {
30
+ class: ["tabs", [
31
+ t(s),
32
+ {
33
+ "tabs--vertical": e.vertical
34
+ }
35
+ ]]
36
+ }), [
37
+ u(r.$slots, "default", f(m(o)))
38
+ ], 16)
30
39
  ]),
31
40
  _: 3
32
41
  }, 8, ["defaultIndex", "vertical"]));
33
42
  }
34
43
  });
35
44
  export {
36
- b as default
45
+ h as default
37
46
  };
@@ -14,6 +14,7 @@
14
14
  * @param {Object} [options.urlSync] - Optional configuration to sync state with URL.
15
15
  * @param {import('vue-router').Router} [options.urlSync.router] - The Vue Router instance.
16
16
  * @param {import('vue-router').RouteLocationNormalizedLoaded} [options.urlSync.route] - The current route instance.
17
+ * @param {Function} [options.isPinned] - A function that receives an item and returns true if it should be pinned to the top of the results.
17
18
  */
18
19
  export function useFacets(allItems: import('vue').Ref<Array<Object>>, options?: {
19
20
  initialFacets?: any[] | undefined;
@@ -29,6 +30,7 @@ export function useFacets(allItems: import('vue').Ref<Array<Object>>, options?:
29
30
  router?: import('vue-router').Router | undefined;
30
31
  route?: import('vue-router').RouteLocationNormalizedLoadedGeneric | undefined;
31
32
  } | undefined;
33
+ isPinned?: Function | undefined;
32
34
  }): {
33
35
  facets: import('vue').Ref<never[], never[]>;
34
36
  searchValue: import('vue').Ref<string, string>;
@@ -51,6 +53,7 @@ export function useFacets(allItems: import('vue').Ref<Array<Object>>, options?:
51
53
  } | undefined;
52
54
  }>;
53
55
  displayItems: import('vue').ComputedRef<any>;
56
+ pinnedItems: import('vue').ComputedRef<any[] | never[]>;
54
57
  selectedFacets: import('vue').ComputedRef<any[]>;
55
58
  clearFilters: () => void;
56
59
  handleFacetChange: ({ groupUid, facetUid, selected }: {
@@ -1 +1 @@
1
- {"version":3,"file":"useFacets.d.ts","sourceRoot":"","sources":["../../../../lib/components/systems/facets/useFacets.js"],"names":[],"mappings":"AA+GA;;;;;;;;;;;;;;;;GAgBG;AACH,oCAfW,OAAO,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,YAExC;IAAwB,aAAa;IACb,WAAW;IACV,kBAAkB;IAClB,eAAe;IACd,cAAc;IACf,cAAc;IACd,aAAa;IACX,YAAY;IACd,SAAS;IACT,OAAO;;;;CAGlC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkWA"}
1
+ {"version":3,"file":"useFacets.d.ts","sourceRoot":"","sources":["../../../../lib/components/systems/facets/useFacets.js"],"names":[],"mappings":"AAiHA;;;;;;;;;;;;;;;;;GAiBG;AACH,oCAhBW,OAAO,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,YAExC;IAAwB,aAAa;IACb,WAAW;IACV,kBAAkB;IAClB,eAAe;IACd,cAAc;IACf,cAAc;IACd,aAAa;IACX,YAAY;IACd,SAAS;IACT,OAAO;;;;IAGL,QAAQ;CACrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+WA"}
@@ -1,18 +1,19 @@
1
- import { ref as T, computed as F, watch as $, watchPostEffect as G } from "vue";
2
- import H from "fuse.js";
3
- function K(u) {
1
+ import { ref as T, computed as E, watch as $, watchPostEffect as X } from "vue";
2
+ import Y from "fuse.js";
3
+ const Z = (u) => typeof u == "function";
4
+ function ee(u) {
4
5
  const h = /* @__PURE__ */ new Set();
5
6
  for (const d of u)
6
- for (const c of d)
7
- h.add(c);
7
+ for (const a of d)
8
+ h.add(a);
8
9
  return h;
9
10
  }
10
11
  function k(u) {
11
12
  if (!u || u.length === 0) return /* @__PURE__ */ new Set();
12
- const h = u.sort((c, S) => c.size - S.size), d = new Set(h[0]);
13
- for (let c = 1; c < h.length; c++) {
13
+ const h = u.sort((a, S) => a.size - S.size), d = new Set(h[0]);
14
+ for (let a = 1; a < h.length; a++) {
14
15
  for (const S of d)
15
- h[c].has(S) || d.delete(S);
16
+ h[a].has(S) || d.delete(S);
16
17
  if (d.size === 0) break;
17
18
  }
18
19
  return d;
@@ -20,207 +21,218 @@ function k(u) {
20
21
  function O(u, h, d) {
21
22
  if (!u || u.length === 0)
22
23
  return d;
23
- const c = u.map((S) => {
24
- const z = S.children.map((b) => {
25
- const v = `${S.uid}:${b.uid}`;
24
+ const a = u.map((S) => {
25
+ const z = S.children.map((V) => {
26
+ const v = `${S.uid}:${V.uid}`;
26
27
  return h.get(v) || /* @__PURE__ */ new Set();
27
28
  });
28
- return S.match === "all" ? k(z) : K(z);
29
+ return S.match === "all" ? k(z) : ee(z);
29
30
  });
30
- return k(c);
31
+ return k(a);
31
32
  }
32
- function Q(u, h) {
33
+ function te(u, h) {
33
34
  return !h || !Array.isArray(h) ? [] : h.map((d) => {
34
- const c = /* @__PURE__ */ new Set(), S = d.getValue || ((v) => v[d.uid]);
35
+ const a = /* @__PURE__ */ new Set(), S = d.getValue || ((v) => v[d.uid]);
35
36
  u.forEach((v) => {
36
- const E = S(v);
37
- Array.isArray(E) ? E.forEach((I) => I && c.add(I)) : E && c.add(E);
37
+ const F = S(v);
38
+ Array.isArray(F) ? F.forEach((A) => A && a.add(A)) : F && a.add(F);
38
39
  });
39
- const z = d.getLabel || ((v) => v), b = [...c].map((v) => ({
40
+ const z = d.getLabel || ((v) => v), V = [...a].map((v) => ({
40
41
  uid: v,
41
42
  label: z(v),
42
43
  selected: !1
43
44
  }));
44
- return b.sort((v, E) => String(v.label).localeCompare(String(E.label))), {
45
+ return V.sort((v, F) => String(v.label).localeCompare(String(F.label))), {
45
46
  ...d,
46
- children: b
47
+ children: V
47
48
  };
48
49
  });
49
50
  }
50
- function ee(u, h = {}) {
51
+ function re(u, h = {}) {
51
52
  const {
52
53
  initialFacets: d,
53
- facetFields: c,
54
+ facetFields: a,
54
55
  initialSearchValue: S = "",
55
56
  initialSortType: z = "az",
56
- noDefaultSorts: b = !1,
57
+ noDefaultSorts: V = !1,
57
58
  extraSortTypes: v = {},
58
- searchOptions: E = {},
59
- getSortValue: I = (e) => e.title || e.label || "",
59
+ searchOptions: F = {},
60
+ getSortValue: A = (e) => e.title || e.label || "",
60
61
  countMode: q = "none",
61
62
  // 'none', 'simple', 'intuitive'
62
- urlSync: U
63
- } = h, B = (e) => e.sort((t, a) => {
64
- const n = I(t), s = I(a);
63
+ urlSync: U,
64
+ isPinned: B
65
+ } = h, _ = (e) => e.sort((t, r) => {
66
+ const n = A(t), s = A(r);
65
67
  return n && s ? String(n).localeCompare(String(s)) : n ? -1 : s ? 1 : 0;
66
- }), N = {
67
- az: { text: "A-Z", sort: B },
68
- za: { text: "Z-A", sort: (e) => B(e).reverse() }
68
+ }), j = {
69
+ az: { text: "A-Z", sort: _ },
70
+ za: { text: "Z-A", sort: (e) => _(e).reverse() }
69
71
  };
70
- function Z(e) {
72
+ function D(e) {
71
73
  return (e || []).map((t) => ({
72
74
  ...t,
73
75
  open: t.open || !1,
74
- children: t.children.map((a) => ({
75
- ...a,
76
- selected: a.selected || !1
76
+ children: t.children.map((r) => ({
77
+ ...r,
78
+ selected: r.selected || !1
77
79
  })),
78
80
  selectedCount: 0
79
81
  }));
80
82
  }
81
- const f = T([]), x = T(S), V = T(z), j = F(() => !c || !u.value?.length ? null : Q(u.value, c)), _ = F(() => ({
82
- ...b ? {} : N,
83
+ const f = T([]), x = T(S), I = T(z), G = E(() => !a || !u.value?.length ? null : te(u.value, a)), J = E(() => ({
84
+ ...V ? {} : j,
83
85
  ...v
84
- })), M = F(() => {
86
+ })), M = E(() => {
85
87
  const e = /* @__PURE__ */ new Map(), t = y.value;
86
- if (!t || !c) return e;
87
- const a = new Map(c.map((n) => {
88
+ if (!t || !a) return e;
89
+ const r = new Map(a.map((n) => {
88
90
  const s = n.getValue || ((o) => o[n.uid]);
89
91
  return [n.uid, s];
90
92
  }));
91
93
  for (let n = 0; n < t.length; n++) {
92
94
  const s = t[n];
93
- for (const o of c) {
94
- const r = a.get(o.uid)(s), i = Array.isArray(r) ? r : r ? [r] : [];
95
- for (const m of i) {
95
+ for (const o of a) {
96
+ const l = r.get(o.uid)(s), c = Array.isArray(l) ? l : l ? [l] : [];
97
+ for (const m of c) {
96
98
  const p = `${o.uid}:${m}`;
97
99
  e.has(p) || e.set(p, /* @__PURE__ */ new Set()), e.get(p).add(n);
98
100
  }
99
101
  }
100
102
  }
101
103
  return e;
102
- }), D = F(() => ({
104
+ }), R = E(() => ({
103
105
  shouldSort: !0,
104
106
  keys: ["title", "label", "description", "author"],
105
- ...E
106
- })), y = F(() => x.value?.length ? new H(u.value, D.value).search(x.value).map((t) => t.item) : u.value), A = F(() => {
107
+ ...F
108
+ })), y = E(() => x.value?.length ? new Y(u.value, R.value).search(x.value).map((t) => t.item) : u.value), b = E(() => {
107
109
  const e = [];
108
110
  return f.value.forEach((t) => {
109
- const a = t.children.filter((n) => n.selected);
110
- a.length > 0 && e.push({ ...t, children: a });
111
+ const r = t.children.filter((n) => n.selected);
112
+ r.length > 0 && e.push({ ...t, children: r });
111
113
  }), e;
112
- }), J = F(() => {
113
- if (!A.value.length)
114
+ }), L = E(() => {
115
+ if (!b.value.length)
114
116
  return y.value;
115
117
  const e = M.value;
116
- if (e.size === 0 && y.value.length > 0 && c?.length > 0)
118
+ if (e.size === 0 && y.value.length > 0 && a?.length > 0)
117
119
  return [];
118
- const t = new Set(y.value.map((s, o) => o)), a = O(A.value, e, t), n = [];
119
- for (const s of a)
120
+ const t = new Set(y.value.map((s, o) => o)), r = O(b.value, e, t), n = [];
121
+ for (const s of r)
120
122
  n.push(y.value[s]);
121
123
  return n;
122
- }), P = F(() => {
123
- const e = _.value[V.value]?.sort;
124
- return typeof e != "function" ? J.value : e([...J.value]);
125
- });
126
- function R() {
124
+ }), N = E(() => {
125
+ const e = J.value[I.value]?.sort;
126
+ let t = Z(e) ? e([...L.value]) : [...L.value];
127
+ if (Z(B)) {
128
+ const r = [], n = [];
129
+ return t.forEach((s) => B(s) ? r.push(s) : n.push(s)), { pinned: r, unpinned: n, all: [...r, ...n] };
130
+ }
131
+ return { pinned: [], unpinned: t, all: t };
132
+ }), W = E(() => N.value.all), H = E(() => N.value.pinned);
133
+ function K() {
127
134
  f.value.forEach((e) => {
128
135
  e.children && e.children.forEach((t) => t.selected = !1), e.selectedCount = 0;
129
136
  });
130
137
  }
131
- function L({ groupUid: e, facetUid: t, selected: a }) {
138
+ function P({ groupUid: e, facetUid: t, selected: r }) {
132
139
  const n = f.value.find((s) => s.uid === e);
133
140
  if (n) {
134
- !n.multiple && a && n.children.forEach((o) => {
141
+ !n.multiple && r && n.children.forEach((o) => {
135
142
  o.uid !== t && (o.selected = !1);
136
143
  });
137
144
  const s = n.children.find((o) => o.uid === t);
138
- s && (s.selected = a), n.selectedCount = n.children.filter((o) => o.selected).length;
145
+ s && (s.selected = r), n.selectedCount = n.children.filter((o) => o.selected).length;
139
146
  }
140
147
  }
141
- if ($(j, (e) => {
142
- const t = Z(d || e);
143
- t.forEach((a) => {
144
- a.selectedCount = a.children.filter((n) => n.selected).length;
148
+ if ($(G, (e) => {
149
+ const t = D(d || e);
150
+ t.forEach((r) => {
151
+ r.selectedCount = r.children.filter((n) => n.selected).length;
145
152
  }), f.value = t;
146
- }, { immediate: !0 }), $([A, y], ([e, t], [a, n]) => {
147
- if (!(q === "none" || !f.value.length) && !(e === a && t === n)) {
153
+ }, { immediate: !0 }), $([b, y], ([e, t], [r, n]) => {
154
+ if (!(q === "none" || !f.value.length) && !(e === r && t === n)) {
148
155
  if (q === "simple") {
149
156
  const s = M.value;
150
- if (s.size === 0 && y.value.length > 0 && c?.length > 0)
157
+ if (s.size === 0 && y.value.length > 0 && a?.length > 0)
151
158
  return;
152
- const o = new Set(y.value.map((l, r) => r));
153
- f.value.forEach((l) => {
154
- const r = e.filter((m) => m.uid !== l.uid), i = O(r, s, o);
155
- l.children.forEach((m) => {
156
- const p = `${l.uid}:${m.uid}`, g = s.get(p) || /* @__PURE__ */ new Set(), w = k([i, g]);
159
+ const o = new Set(y.value.map((i, l) => l));
160
+ f.value.forEach((i) => {
161
+ const l = e.filter((m) => m.uid !== i.uid), c = O(l, s, o);
162
+ i.children.forEach((m) => {
163
+ const p = `${i.uid}:${m.uid}`, g = s.get(p) || /* @__PURE__ */ new Set(), w = k([c, g]);
157
164
  m.count = w.size;
158
165
  });
159
166
  });
160
167
  } else if (q === "intuitive") {
161
168
  const s = M.value;
162
- if (s.size === 0 && y.value.length > 0 && c?.length > 0)
169
+ if (s.size === 0 && y.value.length > 0 && a?.length > 0)
163
170
  return;
164
- const o = new Set(y.value.map((r, i) => i)), l = O(e, s, o);
165
- f.value.forEach((r) => {
166
- r.children.forEach((i) => {
167
- const m = `${r.uid}:${i.uid}`, p = s.get(m) || /* @__PURE__ */ new Set();
168
- if (i.selected)
169
- if (r.multiple) {
170
- const g = k([l, p]);
171
- i.count = g.size;
171
+ const o = new Set(y.value.map((l, c) => c)), i = O(e, s, o);
172
+ f.value.forEach((l) => {
173
+ l.children.forEach((c) => {
174
+ const m = `${l.uid}:${c.uid}`, p = s.get(m) || /* @__PURE__ */ new Set();
175
+ if (c.selected)
176
+ if (l.multiple) {
177
+ const g = k([i, p]);
178
+ c.count = g.size;
172
179
  } else
173
- i.count = l.size;
180
+ c.count = i.size;
174
181
  else {
175
182
  const g = [];
176
183
  for (const C of e)
177
184
  g.push({ ...C, children: [...C.children] });
178
- let w = g.find((C) => C.uid === r.uid);
179
- w || (w = { ...r, children: [] }, g.push(w)), r.multiple ? w.children.push(i) : w.children = [i];
180
- const W = O(g, s, o);
181
- i.count = W.size;
185
+ let w = g.find((C) => C.uid === l.uid);
186
+ w || (w = { ...l, children: [] }, g.push(w)), l.multiple ? w.children.push(c) : w.children = [c];
187
+ const Q = O(g, s, o);
188
+ c.count = Q.size;
182
189
  }
183
190
  });
184
191
  });
185
192
  }
186
193
  }
187
194
  }, { deep: !0, immediate: !0 }), U?.router && U?.route) {
188
- const { router: e, route: t } = U, a = () => f.value && f.value.length > 0, n = () => {
189
- if (!a()) return;
190
- const l = { ...t.query };
191
- delete l.sort, delete l.search, f.value.forEach((r) => delete l[r.uid]), V.value && V.value !== z && (l.sort = V.value), x.value && (l.search = x.value), A.value.forEach((r) => {
192
- r.children.length > 0 && (l[r.uid] = r.children.map((i) => i.uid).join(","));
193
- }), JSON.stringify(l) !== JSON.stringify(t.query) && e.push({ query: l });
195
+ const { router: e, route: t } = U, r = () => f.value && f.value.length > 0, n = () => {
196
+ if (!r()) return;
197
+ const i = { ...t.query };
198
+ delete i.sort, delete i.search, f.value.forEach((l) => delete i[l.uid]), I.value && I.value !== z && (i.sort = I.value), x.value && (i.search = x.value), b.value.forEach((l) => {
199
+ l.children.length > 0 && (i[l.uid] = l.children.map((c) => c.uid).join(","));
200
+ }), JSON.stringify(i) !== JSON.stringify(t.query) && e.push({ query: i });
194
201
  }, s = () => {
195
- const l = t.query;
196
- l.sort && (V.value = l.sort), l.search && (x.value = l.search);
197
- const r = /* @__PURE__ */ new Map();
198
- f.value.forEach((i) => {
199
- const m = l[i.uid] ? l[i.uid].split(",") : [];
200
- r.set(i.uid, new Set(m));
201
- }), f.value.forEach((i) => {
202
- const m = r.get(i.uid) || /* @__PURE__ */ new Set();
203
- i.children.forEach((p) => {
202
+ const i = t.query;
203
+ i.sort && (I.value = i.sort), i.search && (x.value = i.search);
204
+ const l = /* @__PURE__ */ new Map();
205
+ f.value.forEach((c) => {
206
+ const m = i[c.uid] ? i[c.uid].split(",") : [];
207
+ l.set(c.uid, new Set(m));
208
+ }), f.value.forEach((c) => {
209
+ const m = l.get(c.uid) || /* @__PURE__ */ new Set();
210
+ c.children.forEach((p) => {
204
211
  const g = p.selected, w = m.has(p.uid);
205
- g !== w && L({ groupUid: i.uid, facetUid: p.uid, selected: w });
212
+ g !== w && P({ groupUid: c.uid, facetUid: p.uid, selected: w });
206
213
  });
207
214
  });
208
- }, o = G(() => {
215
+ }, o = X(() => {
209
216
  f.value && f.value.length > 0 && (s(), o());
210
217
  });
211
- $([V, x, A], n, { deep: !0 }), $(() => t.query, s);
218
+ $(
219
+ [I, x, b],
220
+ n,
221
+ { deep: !0 }
222
+ ), $(() => t.query, s);
212
223
  }
213
224
  return {
214
225
  facets: f,
215
226
  searchValue: x,
216
- selectedSort: V,
217
- sortTypes: _,
218
- displayItems: P,
219
- selectedFacets: A,
220
- clearFilters: R,
221
- handleFacetChange: L
227
+ selectedSort: I,
228
+ sortTypes: J,
229
+ displayItems: W,
230
+ pinnedItems: H,
231
+ selectedFacets: b,
232
+ clearFilters: K,
233
+ handleFacetChange: P
222
234
  };
223
235
  }
224
236
  export {
225
- ee as useFacets
237
+ re as useFacets
226
238
  };
@@ -1,10 +1,18 @@
1
1
  <template>
2
- <TabGroup v-slot="slotProps" :defaultIndex="defaultIndex" :vertical="vertical">
2
+ <TabGroup
3
+ v-slot="slotProps"
4
+ :defaultIndex="defaultIndex"
5
+ :vertical="vertical"
6
+ >
3
7
  <div
8
+ v-bind="$attrs"
4
9
  class="tabs"
5
- :class="{
6
- 'tabs--vertical' : vertical
7
- }"
10
+ :class="[
11
+ resolvedModifiers,
12
+ {
13
+ 'tabs--vertical' : vertical
14
+ }
15
+ ]"
8
16
  >
9
17
  <slot v-bind="slotProps"/>
10
18
  </div>
@@ -13,12 +21,13 @@
13
21
 
14
22
  <script setup>
15
23
  import { TabGroup } from "@headlessui/vue";
24
+ import { useModifiers } from "../../composables/useModifiers.js";
16
25
 
17
26
  defineOptions({
18
27
  inheritAttrs: false
19
28
  });
20
29
 
21
- defineProps({
30
+ const props = defineProps({
22
31
  /**
23
32
  * Active tab index by default
24
33
  */
@@ -26,6 +35,12 @@
26
35
  /**
27
36
  * Whether or not to use vertical layout
28
37
  */
29
- vertical: Boolean
38
+ vertical: Boolean,
39
+ /**
40
+ * Class modifiers (ie. 'transparent', 'secondary', etc)
41
+ */
42
+ modifiers: [String, Array]
30
43
  });
44
+
45
+ const { resolvedModifiers } = useModifiers({ props, baseClass: "tabs" });
31
46
  </script>
@@ -1,5 +1,7 @@
1
- import { ref, computed, watch, nextTick, watchPostEffect } from 'vue';
2
- import Fuse from 'fuse.js';
1
+ import { ref, computed, watch, watchPostEffect } from "vue";
2
+ import Fuse from "fuse.js";
3
+
4
+ const isFunction = v => typeof v === "function";
3
5
 
4
6
  /**
5
7
  * Helper function to create a union of multiple Sets.
@@ -58,7 +60,7 @@ function getFilteredSetFromIndex(selected, index, allItemsSet) {
58
60
  });
59
61
 
60
62
  // For 'all' (AND), intersect the sets within the group.
61
- if (group.match === 'all') {
63
+ if (group.match === "all") {
62
64
  return intersectSets(childSets);
63
65
  }
64
66
  // For 'some' (OR), union the sets within the group.
@@ -125,19 +127,21 @@ function generateInitialFacets(allItems, facetFields) {
125
127
  * @param {Object} [options.urlSync] - Optional configuration to sync state with URL.
126
128
  * @param {import('vue-router').Router} [options.urlSync.router] - The Vue Router instance.
127
129
  * @param {import('vue-router').RouteLocationNormalizedLoaded} [options.urlSync.route] - The current route instance.
130
+ * @param {Function} [options.isPinned] - A function that receives an item and returns true if it should be pinned to the top of the results.
128
131
  */
129
132
  export function useFacets(allItems, options = {}) {
130
133
  const {
131
134
  initialFacets,
132
135
  facetFields,
133
- initialSearchValue = '',
134
- initialSortType = 'az',
136
+ initialSearchValue = "",
137
+ initialSortType = "az",
135
138
  noDefaultSorts = false,
136
139
  extraSortTypes = {},
137
140
  searchOptions: initialSearchOptions = {},
138
141
  getSortValue = item => (item.title || item.label || ""),
139
- countMode = 'none', // 'none', 'simple', 'intuitive'
140
- urlSync: urlSyncOptions
142
+ countMode = "none", // 'none', 'simple', 'intuitive'
143
+ urlSync: urlSyncOptions,
144
+ isPinned
141
145
  } = options;
142
146
 
143
147
  const sortAlpha = items => {
@@ -261,14 +265,22 @@ export function useFacets(allItems, options = {}) {
261
265
  return result;
262
266
  });
263
267
 
264
- const displayItems = computed(() => {
268
+ const displayItemsGrouped = computed(() => {
265
269
  const sortFn = sortTypes.value[selectedSort.value]?.sort;
266
- if (typeof sortFn !== 'function') {
267
- return filteredItems.value;
270
+ let sorted = isFunction(sortFn) ? sortFn([...filteredItems.value]) : [...filteredItems.value];
271
+
272
+ if (isFunction(isPinned)) {
273
+ const pinned = [];
274
+ const unpinned = [];
275
+ sorted.forEach(item => isPinned(item) ? pinned.push(item) : unpinned.push(item));
276
+ return { pinned, unpinned, all: [...pinned, ...unpinned] };
268
277
  }
269
- return sortFn([...filteredItems.value]);
278
+ return { pinned: [], unpinned: sorted, all: sorted };
270
279
  });
271
280
 
281
+ const displayItems = computed(() => displayItemsGrouped.value.all);
282
+ const pinnedItems = computed(() => displayItemsGrouped.value.pinned);
283
+
272
284
  // --- Methods ---
273
285
  function clearFilters() {
274
286
  facets.value.forEach(group => {
@@ -309,12 +321,12 @@ export function useFacets(allItems, options = {}) {
309
321
  }, { immediate: true });
310
322
 
311
323
  watch([selectedFacets, searchedItems], ([currentSelected, currentSearchedItems], [prevSelected, prevSearchedItems]) => {
312
- if (countMode === 'none' || !facets.value.length) return;
324
+ if (countMode === "none" || !facets.value.length) return;
313
325
 
314
326
  // A simple optimization to prevent re-calculating counts if the actual data hasn't changed.
315
327
  if (currentSelected === prevSelected && currentSearchedItems === prevSearchedItems) return;
316
328
 
317
- if (countMode === 'simple') {
329
+ if (countMode === "simple") {
318
330
  const index = facetIndex.value;
319
331
  if (index.size === 0 && searchedItems.value.length > 0 && facetFields?.length > 0) {
320
332
  return; // Index not ready
@@ -337,7 +349,7 @@ export function useFacets(allItems, options = {}) {
337
349
  child.count = intersection.size;
338
350
  });
339
351
  });
340
- } else if (countMode === 'intuitive') {
352
+ } else if (countMode === "intuitive") {
341
353
  const index = facetIndex.value;
342
354
  if (index.size === 0 && searchedItems.value.length > 0 && facetFields?.length > 0) {
343
355
  // Index might not be ready yet.
@@ -348,7 +360,7 @@ export function useFacets(allItems, options = {}) {
348
360
 
349
361
  facets.value.forEach(group => {
350
362
  group.children.forEach(child => {
351
- const key = `${group.uid}:${child.uid}`;
363
+ const key = `${ group.uid }:${ child.uid }`;
352
364
  const childSet = index.get(key) || new Set();
353
365
 
354
366
  if (child.selected) {
@@ -438,7 +450,7 @@ export function useFacets(allItems, options = {}) {
438
450
 
439
451
  const selectionsFromUrl = new Map();
440
452
  facets.value.forEach(group => {
441
- const selectedUids = query[group.uid] ? query[group.uid].split(',') : [];
453
+ const selectedUids = query[group.uid] ? query[group.uid].split(",") : [];
442
454
  selectionsFromUrl.set(group.uid, new Set(selectedUids));
443
455
  });
444
456
 
@@ -463,7 +475,10 @@ export function useFacets(allItems, options = {}) {
463
475
  });
464
476
 
465
477
  // Sync state changes TO the URL
466
- watch([selectedSort, searchValue, selectedFacets], updateUrlFromState, { deep: true });
478
+ watch(
479
+ [selectedSort, searchValue, selectedFacets], updateUrlFromState,
480
+ { deep: true }
481
+ );
467
482
 
468
483
  // Sync URL changes TO the state
469
484
  watch(() => route.query, updateStateFromUrl);
@@ -475,6 +490,7 @@ export function useFacets(allItems, options = {}) {
475
490
  selectedSort,
476
491
  sortTypes,
477
492
  displayItems,
493
+ pinnedItems,
478
494
  selectedFacets,
479
495
  clearFilters,
480
496
  handleFacetChange
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ulu/frontend-vue",
3
- "version": "0.2.0-beta.12",
3
+ "version": "0.2.0-beta.14",
4
4
  "description": "A modular and tree-shakeable Vue 3 component library for the Ulu frontend",
5
5
  "type": "module",
6
6
  "files": [