fds-vue-core 4.8.0 → 4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1015,7 +1015,7 @@ const _hoisted_10$3 = { class: "flex items-start justify-between gap-4" };
1015
1015
  const _hoisted_11$3 = { class: "flex items-center gap-3" };
1016
1016
  const _hoisted_12$2 = { class: "m-0 text-base font-main font-bold tracking-wide" };
1017
1017
  const _hoisted_13$2 = { class: "flex items-start gap-3" };
1018
- const _hoisted_14$1 = { class: "mb-0-last-child" };
1018
+ const _hoisted_14$2 = { class: "mb-0-last-child" };
1019
1019
  const smallIconSize = 24;
1020
1020
  const largeIconSize = 48;
1021
1021
  const _sfc_main$z = /* @__PURE__ */ vue.defineComponent({
@@ -1089,7 +1089,7 @@ const _sfc_main$z = /* @__PURE__ */ vue.defineComponent({
1089
1089
  ])
1090
1090
  ])
1091
1091
  ], 2)) : vue.createCommentVNode("", true),
1092
- vue.createElementVNode("div", _hoisted_14$1, [
1092
+ vue.createElementVNode("div", _hoisted_14$2, [
1093
1093
  vue.renderSlot(_ctx.$slots, "default")
1094
1094
  ])
1095
1095
  ]))
@@ -8928,7 +8928,7 @@ const _hoisted_13$1 = {
8928
8928
  key: 1,
8929
8929
  class: "max-h-72 overflow-auto border border-gray-200 rounded-md"
8930
8930
  };
8931
- const _hoisted_14 = { class: "w-full text-left text-xs border-collapse" };
8931
+ const _hoisted_14$1 = { class: "w-full text-left text-xs border-collapse" };
8932
8932
  const _hoisted_15 = ["onClick"];
8933
8933
  const _hoisted_16 = { class: "py-1.5 px-3 font-mono break-all" };
8934
8934
  const _hoisted_17 = { class: "py-1.5 px-3 font-mono whitespace-pre-wrap break-all" };
@@ -9270,7 +9270,7 @@ const _sfc_main$m = /* @__PURE__ */ vue.defineComponent({
9270
9270
  }, {
9271
9271
  default: vue.withCtx(() => [
9272
9272
  !sessionStorageEntries.value.length ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_12$1, "Inga värden i sessionStorage.")) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_13$1, [
9273
- vue.createElementVNode("table", _hoisted_14, [
9273
+ vue.createElementVNode("table", _hoisted_14$1, [
9274
9274
  _cache[15] || (_cache[15] = vue.createElementVNode("thead", { class: "bg-gray-50" }, [
9275
9275
  vue.createElementVNode("tr", null, [
9276
9276
  vue.createElementVNode("th", { class: "py-2 px-3 font-semibold" }, "Nyckel"),
@@ -10454,7 +10454,6 @@ const useSearchSelectProItems = ({
10454
10454
  });
10455
10455
  };
10456
10456
  const matchesSearchTerm = (item) => {
10457
- if (isDividerItem(item) && searchTerm.value) return false;
10458
10457
  if (!searchTerm.value) return true;
10459
10458
  const searchValue = isPid.value ? searchTerm.value.replace(/\D/g, "") : searchTerm.value;
10460
10459
  const searchLower = searchValue.toLowerCase();
@@ -10469,6 +10468,53 @@ const useSearchSelectProItems = ({
10469
10468
  return valueLower.includes(searchLower) || unmaskedValue.length > 0 && unmaskedValue.includes(searchValue);
10470
10469
  });
10471
10470
  };
10471
+ const matchesDividerSearchTerm = (item) => {
10472
+ if (!isDividerItem(item) || !searchTerm.value) return false;
10473
+ const searchValue = isPid.value ? searchTerm.value.replace(/\D/g, "") : searchTerm.value;
10474
+ const searchLower = searchValue.toLowerCase();
10475
+ const dividerSearchFields = [...searchFields.value, "label", "name"];
10476
+ return dividerSearchFields.some((field) => {
10477
+ const value = item[field];
10478
+ if (!value) return false;
10479
+ return String(value).toLowerCase().includes(searchLower);
10480
+ });
10481
+ };
10482
+ const filterWithDividerGroups = (sourceData) => {
10483
+ if (!searchTerm.value) return sourceData;
10484
+ const matched = [];
10485
+ let currentDivider = null;
10486
+ let currentChildren = [];
10487
+ const flushCurrentGroup = () => {
10488
+ if (!currentDivider) {
10489
+ matched.push(...currentChildren.filter((item) => matchesSearchTerm(item)));
10490
+ } else {
10491
+ const dividerMatched = matchesDividerSearchTerm(currentDivider);
10492
+ const matchedChildren = currentChildren.filter((item) => matchesSearchTerm(item));
10493
+ if (!dividerMatched && matchedChildren.length === 0) {
10494
+ return;
10495
+ }
10496
+ if (dividerMatched || props.showOutOfBoundsDivider !== false) {
10497
+ matched.push(currentDivider);
10498
+ }
10499
+ if (dividerMatched) {
10500
+ matched.push(...currentChildren);
10501
+ } else {
10502
+ matched.push(...matchedChildren);
10503
+ }
10504
+ }
10505
+ };
10506
+ sourceData.forEach((item) => {
10507
+ if (isDividerItem(item)) {
10508
+ flushCurrentGroup();
10509
+ currentDivider = item;
10510
+ currentChildren = [];
10511
+ return;
10512
+ }
10513
+ currentChildren.push(item);
10514
+ });
10515
+ flushCurrentGroup();
10516
+ return matched;
10517
+ };
10472
10518
  const filterAndPaginate = (onTotal) => {
10473
10519
  if (!sourceItems.value.length) {
10474
10520
  matchingItems.value = [];
@@ -10480,7 +10526,7 @@ const useSearchSelectProItems = ({
10480
10526
  if (props.preserveOrder && sourceData.length) {
10481
10527
  sourceData = sortResponse(sourceData);
10482
10528
  }
10483
- const matchedArray = sourceData.filter((item) => matchesSearchTerm(item));
10529
+ const matchedArray = hasDividerMode.value ? filterWithDividerGroups(sourceData) : sourceData.filter((item) => matchesSearchTerm(item));
10484
10530
  matchingItems.value = matchedArray;
10485
10531
  const shouldLimitItems = props.maxItems !== void 0 && props.maxItems > 0;
10486
10532
  const effectiveLimit = shouldLimitItems ? visibleItemsLimit.value ?? props.maxItems : null;
@@ -10501,7 +10547,11 @@ const useSearchSelectProItems = ({
10501
10547
  selectedItems.value = selectedItems.value.filter((item) => currentIds.has(getItemIdentifier(item)));
10502
10548
  };
10503
10549
  const hasInternalMoreItems = vue.computed(() => matchingItems.value.length > displayedItems.value.length);
10504
- const shouldShowLoadMore = vue.computed(() => props.showLoadMore || hasInternalMoreItems.value);
10550
+ const shouldShowLoadMore = vue.computed(() => {
10551
+ if (hasInternalMoreItems.value) return true;
10552
+ if (props.maxItems && props.maxItems > 0) return false;
10553
+ return props.showLoadMore;
10554
+ });
10505
10555
  const handleInternalLoadMore = () => {
10506
10556
  if (props.maxItems && props.maxItems > 0 && hasInternalMoreItems.value) {
10507
10557
  visibleItemsLimit.value = (visibleItemsLimit.value ?? props.maxItems) + props.maxItems;
@@ -10536,18 +10586,19 @@ const _hoisted_5$5 = {
10536
10586
  };
10537
10587
  const _hoisted_6$3 = ["checked"];
10538
10588
  const _hoisted_7$3 = ["id", "role", "onMouseup"];
10539
- const _hoisted_8$2 = ["type", "id", "name", "checked", "onChange", "onKeydown"];
10540
- const _hoisted_9$2 = ["innerHTML"];
10541
- const _hoisted_10 = {
10589
+ const _hoisted_8$2 = ["innerHTML"];
10590
+ const _hoisted_9$2 = ["type", "id", "name", "checked", "onChange", "onKeydown"];
10591
+ const _hoisted_10 = ["innerHTML"];
10592
+ const _hoisted_11 = {
10542
10593
  key: 0,
10543
10594
  class: "border-b border-blue_t-200 p-3"
10544
10595
  };
10545
- const _hoisted_11 = ["aria-disabled"];
10546
- const _hoisted_12 = {
10596
+ const _hoisted_12 = ["aria-disabled"];
10597
+ const _hoisted_13 = {
10547
10598
  key: 2,
10548
10599
  class: "block m-0 list-none p-0"
10549
10600
  };
10550
- const _hoisted_13 = { class: "p-3" };
10601
+ const _hoisted_14 = { class: "p-3" };
10551
10602
  const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
10552
10603
  __name: "FdsSearchSelectPro",
10553
10604
  props: {
@@ -10564,6 +10615,10 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
10564
10615
  selectedToggleLabel: { default: "Dina val" },
10565
10616
  showLoadMore: { type: Boolean, default: false },
10566
10617
  loadingMore: { type: Boolean, default: false },
10618
+ autoLoadOnScroll: { type: Boolean, default: false },
10619
+ autoLoadThreshold: { default: 24 },
10620
+ highlightDividerMatch: { type: Boolean, default: true },
10621
+ showOutOfBoundsDivider: { type: Boolean, default: true },
10567
10622
  maxItems: { default: void 0 },
10568
10623
  page: { default: void 0 },
10569
10624
  totalPages: { default: void 0 },
@@ -10572,6 +10627,7 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
10572
10627
  searchFields: { default: () => [] },
10573
10628
  preserveOrder: { type: Boolean, default: false },
10574
10629
  initialValue: { default: "" },
10630
+ displayValue: { default: "" },
10575
10631
  disabled: { type: Boolean, default: false },
10576
10632
  dropdownAbsolute: { type: Boolean, default: false },
10577
10633
  labelLeft: { type: Boolean, default: false },
@@ -10697,6 +10753,9 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
10697
10753
  const resolvedLoadMoreLabel = vue.computed(() => props.locale === "en" ? "Show more" : "Visa fler");
10698
10754
  const resolvedLoadingMoreLabel = vue.computed(() => props.locale === "en" ? "Loading more..." : "Hämtar fler...");
10699
10755
  const displayInputValue = vue.computed(() => {
10756
+ if (!inputHasFocus.value && !hasSelection.value && !searchTerm.value.length && props.displayValue) {
10757
+ return props.displayValue;
10758
+ }
10700
10759
  if (isMultiple.value && !inputHasFocus.value && selectedItems.value.length > 0) {
10701
10760
  return `${selectedItems.value.length} val`;
10702
10761
  }
@@ -10841,24 +10900,39 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
10841
10900
  const handleMatchingString = (item) => {
10842
10901
  if (isDividerItem(item)) {
10843
10902
  const dividerLabel = searchFields.value.map((key) => String(item[key] ?? "").trim()).find((value) => value.length > 0) ?? String(item.label ?? item.name ?? "");
10903
+ if (props.highlightDividerMatch && searchTerm.value) {
10904
+ const formattedTerm = formatPidWithDash(searchTerm.value);
10905
+ const escaped = formattedTerm.replace(/[()]/g, "\\$&");
10906
+ if (new RegExp(escaped, "i").test(dividerLabel)) {
10907
+ return boldQuery(dividerLabel);
10908
+ }
10909
+ }
10844
10910
  return dividerLabel;
10845
10911
  }
10846
- const values = searchFields.value.map((key) => String(item[key] || ""));
10912
+ const values = searchFields.value.map((key) => String(item[key] ?? "").trim()).filter((value) => value.length > 0);
10847
10913
  let result = "";
10914
+ if (values.length === 0) {
10915
+ return "";
10916
+ }
10848
10917
  if (values.length === 1) {
10849
- result = values[0] || "";
10918
+ result = values[0] ?? "";
10850
10919
  } else {
10851
10920
  if (values[1]?.length === 12 && parseInt(values[1])) {
10852
10921
  values[1] = formatPidWithDash(values[1]);
10853
10922
  }
10854
10923
  if (props.preserveOrder) {
10855
- const combined = `${values[0]} (${values[1]})`;
10924
+ const primaryValue = values[0] ?? "";
10925
+ const secondaryValue = values[1];
10926
+ const combined = secondaryValue ? `${primaryValue} (${secondaryValue})` : primaryValue;
10856
10927
  const rest = values.slice(2).join("<br>");
10857
10928
  result = rest ? `${combined}<br>${rest}` : combined;
10858
10929
  } else {
10859
- result = values[0] || "";
10930
+ result = values[0] ?? "";
10860
10931
  for (let i = 1; i < values.length; i++) {
10861
- result += ` (${values[i]})`;
10932
+ const value = values[i];
10933
+ if (value) {
10934
+ result += ` (${value})`;
10935
+ }
10862
10936
  }
10863
10937
  }
10864
10938
  }
@@ -10962,6 +11036,16 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
10962
11036
  }
10963
11037
  emit("loadMore");
10964
11038
  };
11039
+ const handleDropdownScroll = (event) => {
11040
+ if (!props.autoLoadOnScroll || props.loadingMore || !shouldShowLoadMore.value) return;
11041
+ const target = event.target;
11042
+ if (!target) return;
11043
+ const threshold = Math.max(0, props.autoLoadThreshold ?? 24);
11044
+ const remaining = target.scrollHeight - (target.scrollTop + target.clientHeight);
11045
+ if (remaining <= threshold) {
11046
+ handleLoadMore();
11047
+ }
11048
+ };
10965
11049
  const handleInputFocus = () => {
10966
11050
  inputHasFocus.value = true;
10967
11051
  if ((isMultiple.value || !selectedItem.value) && displayedItems.value.length > 0) {
@@ -11099,7 +11183,8 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
11099
11183
  ref_key: "dropdownRef",
11100
11184
  ref: dropdownRef,
11101
11185
  class: vue.normalizeClass(listWrapperClasses.value),
11102
- style: vue.normalizeStyle(listWrapperStyle.value)
11186
+ style: vue.normalizeStyle(listWrapperStyle.value),
11187
+ onScrollPassive: handleDropdownScroll
11103
11188
  }, [
11104
11189
  __props.loading ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4$5, [
11105
11190
  vue.createVNode(_sfc_main$x, {
@@ -11141,8 +11226,9 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
11141
11226
  labelClasses.value,
11142
11227
  "font-normal text-gray-700 border-b border-gray-100 cursor-default pointer-events-none"
11143
11228
  ]),
11144
- style: vue.normalizeStyle(vue.unref(optionPaddingStyle)(item))
11145
- }, vue.toDisplayString(handleMatchingString(item).replace(/<[^>]*>/g, "")), 7)) : (vue.openBlock(), vue.createElementBlock("label", {
11229
+ style: vue.normalizeStyle(vue.unref(optionPaddingStyle)(item)),
11230
+ innerHTML: handleMatchingString(item)
11231
+ }, null, 14, _hoisted_8$2)) : (vue.openBlock(), vue.createElementBlock("label", {
11146
11232
  key: 1,
11147
11233
  class: vue.normalizeClass([labelClasses.value, listItemClasses.value, "flex items-start gap-2"]),
11148
11234
  style: vue.normalizeStyle(vue.unref(optionPaddingStyle)(item))
@@ -11158,15 +11244,15 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
11158
11244
  vue.withKeys((e) => !__props.multiple && handleClick(e, item), ["enter"]),
11159
11245
  vue.withKeys(vue.withModifiers((e) => !__props.multiple && handleClick(e, item), ["prevent"]), ["space"])
11160
11246
  ]
11161
- }, null, 42, _hoisted_8$2),
11247
+ }, null, 42, _hoisted_9$2),
11162
11248
  vue.createElementVNode("span", {
11163
11249
  class: "min-w-0 flex-1",
11164
11250
  innerHTML: handleMatchingString(item)
11165
- }, null, 8, _hoisted_9$2)
11251
+ }, null, 8, _hoisted_10)
11166
11252
  ], 6))
11167
11253
  ], 42, _hoisted_7$3);
11168
11254
  }), 128)),
11169
- vue.unref(shouldShowLoadMore) ? (vue.openBlock(), vue.createElementBlock("li", _hoisted_10, [
11255
+ vue.unref(shouldShowLoadMore) ? (vue.openBlock(), vue.createElementBlock("li", _hoisted_11, [
11170
11256
  vue.createElementVNode("div", {
11171
11257
  class: vue.normalizeClass(["flex items-center gap-2 text-blue-600", { "cursor-pointer": !__props.loadingMore, "cursor-not-allowed opacity-70": __props.loadingMore }]),
11172
11258
  role: "button",
@@ -11186,7 +11272,7 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
11186
11272
  class: "w-6 h-6 pointer-events-none"
11187
11273
  }, null, 8, ["loading", "aria-label"]),
11188
11274
  vue.createElementVNode("span", null, vue.toDisplayString(__props.loadingMore ? resolvedLoadingMoreLabel.value : resolvedLoadMoreLabel.value), 1)
11189
- ], 42, _hoisted_11)
11275
+ ], 42, _hoisted_12)
11190
11276
  ])) : vue.createCommentVNode("", true)
11191
11277
  ], 32),
11192
11278
  __props.page !== void 0 && totalPages.value !== null && totalPages.value > 1 ? (vue.openBlock(), vue.createBlock(_sfc_main$k, {
@@ -11196,10 +11282,10 @@ const _sfc_main$i = /* @__PURE__ */ vue.defineComponent({
11196
11282
  onPaginate: handlePagination,
11197
11283
  class: "my-4! px-2"
11198
11284
  }, null, 8, ["current", "max"])) : vue.createCommentVNode("", true)
11199
- ], 64)) : !__props.loading ? (vue.openBlock(), vue.createElementBlock("ul", _hoisted_12, [
11200
- vue.createElementVNode("li", _hoisted_13, vue.toDisplayString(__props.noResultPrompt), 1)
11285
+ ], 64)) : !__props.loading ? (vue.openBlock(), vue.createElementBlock("ul", _hoisted_13, [
11286
+ vue.createElementVNode("li", _hoisted_14, vue.toDisplayString(__props.noResultPrompt), 1)
11201
11287
  ])) : vue.createCommentVNode("", true)
11202
- ], 6)) : vue.createCommentVNode("", true)
11288
+ ], 38)) : vue.createCommentVNode("", true)
11203
11289
  ])
11204
11290
  ], 16);
11205
11291
  };