@bagelink/vue 0.0.335 → 0.0.339

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.
@@ -11,6 +11,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
11
11
  required?: boolean | undefined;
12
12
  label?: string | undefined;
13
13
  fullWidth?: boolean | undefined;
14
+ multiselect?: boolean | undefined;
14
15
  }>, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
16
  "update:modelValue": (...args: any[]) => void;
16
17
  }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
@@ -22,6 +23,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<__
22
23
  required?: boolean | undefined;
23
24
  label?: string | undefined;
24
25
  fullWidth?: boolean | undefined;
26
+ multiselect?: boolean | undefined;
25
27
  }>>> & {
26
28
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
27
29
  }, {}, {}>, {
@@ -1 +1 @@
1
- {"version":3,"file":"SelectInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/form/inputs/SelectInput.vue"],"names":[],"mappings":"AA6BA;AAIA,OAAO,wBAAwB,CAAC;AAOhC,KAAK,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AA2UhG,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"SelectInput.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/form/inputs/SelectInput.vue"],"names":[],"mappings":"AA2BA;AAIA,OAAO,wBAAwB,CAAC;AAOhC,KAAK,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqXhG,wBAAwG;AACxG,KAAK,sBAAsB,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,GAAG,KAAK,GAAG,CAAC,CAAC;AACjE,KAAK,6BAA6B,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,OAAO,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE;CAAE,CAAC;AAC9M,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAAE,QAAO;QAClD,MAAM,EAAE,CAAC,CAAC;KACT,CAAA;CAAE,CAAC"}
package/dist/index.cjs CHANGED
@@ -27436,37 +27436,38 @@ const _sfc_main$g = /* @__PURE__ */ vue.defineComponent({
27436
27436
  searchable: { type: Boolean },
27437
27437
  required: { type: Boolean },
27438
27438
  label: {},
27439
- fullWidth: { type: Boolean }
27439
+ fullWidth: { type: Boolean },
27440
+ multiselect: { type: Boolean }
27440
27441
  },
27441
27442
  emits: ["update:modelValue"],
27442
27443
  setup(__props, { emit: __emit }) {
27443
27444
  let open = vue.ref(false);
27444
27445
  const searchInput = vue.ref(null);
27445
27446
  const props2 = __props;
27446
- let selectedItem = vue.ref();
27447
+ const selectedItems = vue.ref([]);
27447
27448
  let search = vue.ref("");
27449
+ const dropdown = vue.ref(null);
27448
27450
  const toggle = () => {
27451
+ var _a2;
27452
+ (_a2 = dropdown.value) == null ? void 0 : _a2.hide();
27449
27453
  open.value = !open.value;
27450
27454
  if (!open.value)
27451
27455
  search.value = "";
27452
27456
  if (open.value)
27453
27457
  setTimeout(() => {
27454
- var _a2, _b, _c;
27455
- return (_c = (_b = (_a2 = searchInput.value) == null ? void 0 : _a2.$el) == null ? void 0 : _b.querySelector("input")) == null ? void 0 : _c.focus();
27458
+ var _a3, _b, _c;
27459
+ return (_c = (_b = (_a3 = searchInput.value) == null ? void 0 : _a3.$el) == null ? void 0 : _b.querySelector("input")) == null ? void 0 : _c.focus();
27456
27460
  }, 100);
27457
27461
  };
27458
- const valueToLabel = (value) => {
27459
- if (!value)
27460
- return "";
27461
- const option2 = props2.options.find((option22) => {
27462
- if (typeof option22 === "string" || typeof option22 === "number")
27463
- return option22 === value;
27464
- return option22.value === value;
27465
- });
27466
- if (!option2)
27467
- return value;
27468
- return getLabel(option2);
27469
- };
27462
+ const selecteLabel = vue.computed(() => {
27463
+ if (selectedItems.value.length === 0)
27464
+ return props2.placeholder || "Select";
27465
+ if (selectedItems.value.length > 4) {
27466
+ const str = selectedItems.value.slice(0, 4).map((item) => getLabel(item)).join(", ");
27467
+ return `${str}... +${selectedItems.value.length - 4}`;
27468
+ }
27469
+ return selectedItems.value.map((item) => getLabel(item)).join(", ");
27470
+ });
27470
27471
  const emit2 = __emit;
27471
27472
  const getLabel = (option2) => {
27472
27473
  if (typeof option2 === "string")
@@ -27475,11 +27476,14 @@ const _sfc_main$g = /* @__PURE__ */ vue.defineComponent({
27475
27476
  return `${option2}`;
27476
27477
  return option2.label;
27477
27478
  };
27478
- const isSelected = (option2) => {
27479
- if (typeof option2 === "string" || typeof option2 === "number")
27480
- return option2 === selectedItem.value;
27481
- return option2.value === selectedItem.value;
27479
+ const getValue = (option2) => {
27480
+ if (typeof option2 === "string")
27481
+ return option2;
27482
+ if (typeof option2 === "number")
27483
+ return option2;
27484
+ return option2.value;
27482
27485
  };
27486
+ const isSelected = (option2) => selectedItems.value.includes(getValue(option2));
27483
27487
  const filteredOptions = vue.computed(() => props2.options.filter((option2) => {
27484
27488
  const searchTerm = new RegExp(search.value, "gi");
27485
27489
  if (typeof option2 === "string")
@@ -27489,21 +27493,53 @@ const _sfc_main$g = /* @__PURE__ */ vue.defineComponent({
27489
27493
  return option2.label.match(searchTerm);
27490
27494
  }));
27491
27495
  const select2 = (option2) => {
27492
- if (typeof option2 === "string")
27493
- selectedItem.value = option2;
27494
- else if (typeof option2 === "number")
27495
- selectedItem.value = option2;
27496
- else
27497
- selectedItem.value = option2.value;
27498
- emit2("update:modelValue", selectedItem.value);
27499
- open.value = false;
27496
+ const existingIndex = selectedItems.value.findIndex((item) => {
27497
+ if (typeof item === "string" || typeof item === "number")
27498
+ return item === option2;
27499
+ return item.value === option2;
27500
+ });
27501
+ if (existingIndex > -1)
27502
+ selectedItems.value.splice(existingIndex, 1);
27503
+ else if (props2.multiselect) {
27504
+ selectedItems.value.push(getValue(option2));
27505
+ } else {
27506
+ selectedItems.value.splice(0, selectedItems.value.length, getValue(option2));
27507
+ toggle();
27508
+ }
27509
+ emitUpdate();
27500
27510
  };
27501
- vue.watch(() => props2.modelValue, (value) => {
27502
- if (value !== selectedItem.value)
27503
- selectedItem.value = value;
27504
- }, { immediate: true });
27511
+ function emitUpdate() {
27512
+ if (props2.multiselect) {
27513
+ emit2("update:modelValue", selectedItems.value);
27514
+ } else {
27515
+ selectedItems.value.splice(1, selectedItems.value.length);
27516
+ emit2("update:modelValue", selectedItems.value[0]);
27517
+ }
27518
+ }
27519
+ function compareArrays(arr1, arr2) {
27520
+ const isSame = arr1.every((item) => arr2.map((a2) => getValue(a2)).includes(getValue(item)));
27521
+ return isSame;
27522
+ }
27523
+ vue.watch(
27524
+ () => props2.modelValue,
27525
+ (newVal) => {
27526
+ if (!newVal)
27527
+ return;
27528
+ if (!props2.multiselect) {
27529
+ if (!isSelected(newVal))
27530
+ selectedItems.value.splice(0, selectedItems.value.length, newVal);
27531
+ } else {
27532
+ const isSame = compareArrays([newVal].flat(), selectedItems.value);
27533
+ if (!isSame)
27534
+ selectedItems.value.splice(0, selectedItems.value.length, [newVal].flat());
27535
+ }
27536
+ },
27537
+ { immediate: true }
27538
+ );
27505
27539
  return (_ctx, _cache) => {
27506
27540
  return vue.openBlock(), vue.createBlock(vue.unref(kt$1), {
27541
+ ref_key: "dropdown",
27542
+ ref: dropdown,
27507
27543
  placement: "bottom-start",
27508
27544
  class: "bagel-input selectinput"
27509
27545
  }, {
@@ -27525,12 +27561,9 @@ const _sfc_main$g = /* @__PURE__ */ vue.defineComponent({
27525
27561
  }, null, 8, ["modelValue"])) : vue.createCommentVNode("", true),
27526
27562
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(filteredOptions.value, (option2, i2) => {
27527
27563
  return vue.openBlock(), vue.createElementBlock("div", {
27528
- class: vue.normalizeClass(["selectinput-option hover gap-1", { selected: option2 === vue.unref(selectedItem) }]),
27564
+ class: vue.normalizeClass(["selectinput-option hover gap-1", { selected: isSelected(option2) }]),
27529
27565
  key: `${option2}${i2}`,
27530
- onClick: () => {
27531
- select2(option2);
27532
- hide();
27533
- }
27566
+ onClick: ($event) => select2(option2)
27534
27567
  }, [
27535
27568
  isSelected(option2) ? (vue.openBlock(), vue.createBlock(vue.unref(_sfc_main$H), {
27536
27569
  key: 0,
@@ -27546,8 +27579,8 @@ const _sfc_main$g = /* @__PURE__ */ vue.defineComponent({
27546
27579
  }), 128)),
27547
27580
  vue.renderSlot(_ctx.$slots, "last", {}, void 0, true)
27548
27581
  ]),
27549
- _: 2
27550
- }, 1032, ["style"])
27582
+ _: 3
27583
+ }, 8, ["style"])
27551
27584
  ]),
27552
27585
  default: vue.withCtx(() => [
27553
27586
  vue.createElementVNode("label", null, [
@@ -27555,28 +27588,27 @@ const _sfc_main$g = /* @__PURE__ */ vue.defineComponent({
27555
27588
  vue.createElementVNode("button", {
27556
27589
  disabled: _ctx.disabled,
27557
27590
  type: "button",
27558
- class: "selectinput-btn",
27559
- onClick: toggle
27591
+ class: "selectinput-btn"
27560
27592
  }, [
27561
- vue.createTextVNode(vue.toDisplayString(valueToLabel(vue.unref(selectedItem)) || _ctx.placeholder || "Select") + " ", 1),
27593
+ vue.createTextVNode(vue.toDisplayString(selecteLabel.value) + " ", 1),
27562
27594
  vue.createVNode(vue.unref(_sfc_main$H), vue.normalizeProps(vue.guardReactiveProps({ "icon": vue.unref(open) ? "unfold_less" : "unfold_more" })), null, 16)
27563
27595
  ], 8, _hoisted_1$m),
27564
27596
  _ctx.required ? vue.withDirectives((vue.openBlock(), vue.createElementBlock("input", {
27565
27597
  key: 0,
27566
27598
  style: { "width": "0", "height": "0", "position": "absolute", "opacity": "0", "z-index": "-1" },
27567
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => vue.isRef(selectedItem) ? selectedItem.value = $event : selectedItem = $event),
27599
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => selectedItems.value = $event),
27568
27600
  required: ""
27569
27601
  }, null, 512)), [
27570
- [vue.vModelText, vue.unref(selectedItem)]
27602
+ [vue.vModelText, selectedItems.value]
27571
27603
  ]) : vue.createCommentVNode("", true)
27572
27604
  ])
27573
27605
  ]),
27574
27606
  _: 3
27575
- });
27607
+ }, 512);
27576
27608
  };
27577
27609
  }
27578
27610
  });
27579
- const SelectInput = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-8845266b"]]);
27611
+ const SelectInput = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-fa186094"]]);
27580
27612
  const _hoisted_1$l = ["title"];
27581
27613
  const _hoisted_2$h = { key: 0 };
27582
27614
  const _hoisted_3$e = ["value", "placeholder"];
package/dist/index.mjs CHANGED
@@ -27434,37 +27434,38 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
27434
27434
  searchable: { type: Boolean },
27435
27435
  required: { type: Boolean },
27436
27436
  label: {},
27437
- fullWidth: { type: Boolean }
27437
+ fullWidth: { type: Boolean },
27438
+ multiselect: { type: Boolean }
27438
27439
  },
27439
27440
  emits: ["update:modelValue"],
27440
27441
  setup(__props, { emit: __emit }) {
27441
27442
  let open = ref(false);
27442
27443
  const searchInput = ref(null);
27443
27444
  const props2 = __props;
27444
- let selectedItem = ref();
27445
+ const selectedItems = ref([]);
27445
27446
  let search = ref("");
27447
+ const dropdown = ref(null);
27446
27448
  const toggle = () => {
27449
+ var _a2;
27450
+ (_a2 = dropdown.value) == null ? void 0 : _a2.hide();
27447
27451
  open.value = !open.value;
27448
27452
  if (!open.value)
27449
27453
  search.value = "";
27450
27454
  if (open.value)
27451
27455
  setTimeout(() => {
27452
- var _a2, _b, _c;
27453
- return (_c = (_b = (_a2 = searchInput.value) == null ? void 0 : _a2.$el) == null ? void 0 : _b.querySelector("input")) == null ? void 0 : _c.focus();
27456
+ var _a3, _b, _c;
27457
+ return (_c = (_b = (_a3 = searchInput.value) == null ? void 0 : _a3.$el) == null ? void 0 : _b.querySelector("input")) == null ? void 0 : _c.focus();
27454
27458
  }, 100);
27455
27459
  };
27456
- const valueToLabel = (value) => {
27457
- if (!value)
27458
- return "";
27459
- const option2 = props2.options.find((option22) => {
27460
- if (typeof option22 === "string" || typeof option22 === "number")
27461
- return option22 === value;
27462
- return option22.value === value;
27463
- });
27464
- if (!option2)
27465
- return value;
27466
- return getLabel(option2);
27467
- };
27460
+ const selecteLabel = computed(() => {
27461
+ if (selectedItems.value.length === 0)
27462
+ return props2.placeholder || "Select";
27463
+ if (selectedItems.value.length > 4) {
27464
+ const str = selectedItems.value.slice(0, 4).map((item) => getLabel(item)).join(", ");
27465
+ return `${str}... +${selectedItems.value.length - 4}`;
27466
+ }
27467
+ return selectedItems.value.map((item) => getLabel(item)).join(", ");
27468
+ });
27468
27469
  const emit2 = __emit;
27469
27470
  const getLabel = (option2) => {
27470
27471
  if (typeof option2 === "string")
@@ -27473,11 +27474,14 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
27473
27474
  return `${option2}`;
27474
27475
  return option2.label;
27475
27476
  };
27476
- const isSelected = (option2) => {
27477
- if (typeof option2 === "string" || typeof option2 === "number")
27478
- return option2 === selectedItem.value;
27479
- return option2.value === selectedItem.value;
27477
+ const getValue = (option2) => {
27478
+ if (typeof option2 === "string")
27479
+ return option2;
27480
+ if (typeof option2 === "number")
27481
+ return option2;
27482
+ return option2.value;
27480
27483
  };
27484
+ const isSelected = (option2) => selectedItems.value.includes(getValue(option2));
27481
27485
  const filteredOptions = computed(() => props2.options.filter((option2) => {
27482
27486
  const searchTerm = new RegExp(search.value, "gi");
27483
27487
  if (typeof option2 === "string")
@@ -27487,21 +27491,53 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
27487
27491
  return option2.label.match(searchTerm);
27488
27492
  }));
27489
27493
  const select2 = (option2) => {
27490
- if (typeof option2 === "string")
27491
- selectedItem.value = option2;
27492
- else if (typeof option2 === "number")
27493
- selectedItem.value = option2;
27494
- else
27495
- selectedItem.value = option2.value;
27496
- emit2("update:modelValue", selectedItem.value);
27497
- open.value = false;
27494
+ const existingIndex = selectedItems.value.findIndex((item) => {
27495
+ if (typeof item === "string" || typeof item === "number")
27496
+ return item === option2;
27497
+ return item.value === option2;
27498
+ });
27499
+ if (existingIndex > -1)
27500
+ selectedItems.value.splice(existingIndex, 1);
27501
+ else if (props2.multiselect) {
27502
+ selectedItems.value.push(getValue(option2));
27503
+ } else {
27504
+ selectedItems.value.splice(0, selectedItems.value.length, getValue(option2));
27505
+ toggle();
27506
+ }
27507
+ emitUpdate();
27498
27508
  };
27499
- watch(() => props2.modelValue, (value) => {
27500
- if (value !== selectedItem.value)
27501
- selectedItem.value = value;
27502
- }, { immediate: true });
27509
+ function emitUpdate() {
27510
+ if (props2.multiselect) {
27511
+ emit2("update:modelValue", selectedItems.value);
27512
+ } else {
27513
+ selectedItems.value.splice(1, selectedItems.value.length);
27514
+ emit2("update:modelValue", selectedItems.value[0]);
27515
+ }
27516
+ }
27517
+ function compareArrays(arr1, arr2) {
27518
+ const isSame = arr1.every((item) => arr2.map((a2) => getValue(a2)).includes(getValue(item)));
27519
+ return isSame;
27520
+ }
27521
+ watch(
27522
+ () => props2.modelValue,
27523
+ (newVal) => {
27524
+ if (!newVal)
27525
+ return;
27526
+ if (!props2.multiselect) {
27527
+ if (!isSelected(newVal))
27528
+ selectedItems.value.splice(0, selectedItems.value.length, newVal);
27529
+ } else {
27530
+ const isSame = compareArrays([newVal].flat(), selectedItems.value);
27531
+ if (!isSame)
27532
+ selectedItems.value.splice(0, selectedItems.value.length, [newVal].flat());
27533
+ }
27534
+ },
27535
+ { immediate: true }
27536
+ );
27503
27537
  return (_ctx, _cache) => {
27504
27538
  return openBlock(), createBlock(unref(kt$1), {
27539
+ ref_key: "dropdown",
27540
+ ref: dropdown,
27505
27541
  placement: "bottom-start",
27506
27542
  class: "bagel-input selectinput"
27507
27543
  }, {
@@ -27523,12 +27559,9 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
27523
27559
  }, null, 8, ["modelValue"])) : createCommentVNode("", true),
27524
27560
  (openBlock(true), createElementBlock(Fragment$1, null, renderList(filteredOptions.value, (option2, i2) => {
27525
27561
  return openBlock(), createElementBlock("div", {
27526
- class: normalizeClass(["selectinput-option hover gap-1", { selected: option2 === unref(selectedItem) }]),
27562
+ class: normalizeClass(["selectinput-option hover gap-1", { selected: isSelected(option2) }]),
27527
27563
  key: `${option2}${i2}`,
27528
- onClick: () => {
27529
- select2(option2);
27530
- hide();
27531
- }
27564
+ onClick: ($event) => select2(option2)
27532
27565
  }, [
27533
27566
  isSelected(option2) ? (openBlock(), createBlock(unref(_sfc_main$H), {
27534
27567
  key: 0,
@@ -27544,8 +27577,8 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
27544
27577
  }), 128)),
27545
27578
  renderSlot(_ctx.$slots, "last", {}, void 0, true)
27546
27579
  ]),
27547
- _: 2
27548
- }, 1032, ["style"])
27580
+ _: 3
27581
+ }, 8, ["style"])
27549
27582
  ]),
27550
27583
  default: withCtx(() => [
27551
27584
  createElementVNode("label", null, [
@@ -27553,28 +27586,27 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
27553
27586
  createElementVNode("button", {
27554
27587
  disabled: _ctx.disabled,
27555
27588
  type: "button",
27556
- class: "selectinput-btn",
27557
- onClick: toggle
27589
+ class: "selectinput-btn"
27558
27590
  }, [
27559
- createTextVNode(toDisplayString(valueToLabel(unref(selectedItem)) || _ctx.placeholder || "Select") + " ", 1),
27591
+ createTextVNode(toDisplayString(selecteLabel.value) + " ", 1),
27560
27592
  createVNode(unref(_sfc_main$H), normalizeProps(guardReactiveProps({ "icon": unref(open) ? "unfold_less" : "unfold_more" })), null, 16)
27561
27593
  ], 8, _hoisted_1$m),
27562
27594
  _ctx.required ? withDirectives((openBlock(), createElementBlock("input", {
27563
27595
  key: 0,
27564
27596
  style: { "width": "0", "height": "0", "position": "absolute", "opacity": "0", "z-index": "-1" },
27565
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(selectedItem) ? selectedItem.value = $event : selectedItem = $event),
27597
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => selectedItems.value = $event),
27566
27598
  required: ""
27567
27599
  }, null, 512)), [
27568
- [vModelText, unref(selectedItem)]
27600
+ [vModelText, selectedItems.value]
27569
27601
  ]) : createCommentVNode("", true)
27570
27602
  ])
27571
27603
  ]),
27572
27604
  _: 3
27573
- });
27605
+ }, 512);
27574
27606
  };
27575
27607
  }
27576
27608
  });
27577
- const SelectInput = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-8845266b"]]);
27609
+ const SelectInput = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-fa186094"]]);
27578
27610
  const _hoisted_1$l = ["title"];
27579
27611
  const _hoisted_2$h = { key: 0 };
27580
27612
  const _hoisted_3$e = ["value", "placeholder"];
package/dist/style.css CHANGED
@@ -1196,59 +1196,59 @@ display: block;
1196
1196
  }
1197
1197
  .resize-observer[data-v-b329ee4c]{position:absolute;top:0;left:0;z-index:-1;width:100%;height:100%;border:none;background-color:transparent;pointer-events:none;display:block;overflow:hidden;opacity:0}.resize-observer[data-v-b329ee4c] object{display:block;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:-1}.v-popper__popper{z-index:10000;top:0;left:0;outline:none}.v-popper__popper.v-popper__popper--hidden{visibility:hidden;opacity:0;transition:opacity .15s,visibility .15s;pointer-events:none}.v-popper__popper.v-popper__popper--shown{visibility:visible;opacity:1;transition:opacity .15s}.v-popper__popper.v-popper__popper--skip-transition,.v-popper__popper.v-popper__popper--skip-transition>.v-popper__wrapper{transition:none!important}.v-popper__backdrop{position:absolute;top:0;left:0;width:100%;height:100%;display:none}.v-popper__inner{position:relative;box-sizing:border-box;overflow-y:auto}.v-popper__inner>div{position:relative;z-index:1;max-width:inherit;max-height:inherit}.v-popper__arrow-container{position:absolute;width:10px;height:10px}.v-popper__popper--arrow-overflow .v-popper__arrow-container,.v-popper__popper--no-positioning .v-popper__arrow-container{display:none}.v-popper__arrow-inner,.v-popper__arrow-outer{border-style:solid;position:absolute;top:0;left:0;width:0;height:0}.v-popper__arrow-inner{visibility:hidden;border-width:7px}.v-popper__arrow-outer{border-width:6px}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-inner{left:-2px}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-outer,.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-outer{left:-1px}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-outer{border-bottom-width:0;border-left-color:transparent!important;border-right-color:transparent!important;border-bottom-color:transparent!important}.v-popper__popper[data-popper-placement^=top] .v-popper__arrow-inner{top:-2px}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-container{top:0}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-outer{border-top-width:0;border-left-color:transparent!important;border-right-color:transparent!important;border-top-color:transparent!important}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-inner{top:-4px}.v-popper__popper[data-popper-placement^=bottom] .v-popper__arrow-outer{top:-6px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-inner{top:-2px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-outer,.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-outer{top:-1px}.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-outer{border-left-width:0;border-left-color:transparent!important;border-top-color:transparent!important;border-bottom-color:transparent!important}.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-inner{left:-4px}.v-popper__popper[data-popper-placement^=right] .v-popper__arrow-outer{left:-6px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-container{right:-10px}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-inner,.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-outer{border-right-width:0;border-top-color:transparent!important;border-right-color:transparent!important;border-bottom-color:transparent!important}.v-popper__popper[data-popper-placement^=left] .v-popper__arrow-inner{left:-2px}.v-popper--theme-tooltip .v-popper__inner{background:rgba(0,0,0,.8);color:#fff;border-radius:6px;padding:7px 12px 6px}.v-popper--theme-tooltip .v-popper__arrow-outer{border-color:#000c}.v-popper--theme-dropdown .v-popper__inner{background:#fff;color:#000;border-radius:6px;border:1px solid #ddd;box-shadow:0 6px 30px #0000001a}.v-popper--theme-dropdown .v-popper__arrow-inner{visibility:visible;border-color:#fff}.v-popper--theme-dropdown .v-popper__arrow-outer{border-color:#ddd}
1198
1198
 
1199
- .selectinput[data-v-8845266b] {
1200
- width: 100%;
1199
+ .selectinput[data-v-fa186094] {
1200
+ width: 100%;
1201
1201
  }
1202
- .selectinput-option[data-v-8845266b] {
1203
- padding: 6px 12px;
1204
- cursor: pointer;
1205
- border-radius: 5px;
1206
- transition: all 0.2s;
1207
- display: grid;
1208
- grid-template-columns: 10px 1fr;
1209
- justify-content: space-between;
1210
- width: 100%;
1211
- font-size: var(--input-font-size);
1202
+ .selectinput-option[data-v-fa186094] {
1203
+ padding: 6px 12px;
1204
+ cursor: pointer;
1205
+ border-radius: 5px;
1206
+ transition: all 0.2s;
1207
+ display: grid;
1208
+ grid-template-columns: 10px 1fr;
1209
+ justify-content: space-between;
1210
+ width: 100%;
1211
+ font-size: var(--input-font-size);
1212
1212
  }
1213
- .selectinput-options[data-v-8845266b] {
1214
- max-height: 300px;
1215
- overflow-y: auto;
1213
+ .selectinput-options[data-v-fa186094] {
1214
+ max-height: 300px;
1215
+ overflow-y: auto;
1216
1216
  }
1217
- .selectinput-option[data-v-8845266b]:hover {
1218
- background: var(--bgl-gray-20);
1217
+ .selectinput-option[data-v-fa186094]:hover {
1218
+ background: var(--bgl-gray-20);
1219
1219
  }
1220
1220
 
1221
1221
  .bagel-input label {
1222
- font-size: var(--label-font-size);
1222
+ font-size: var(--label-font-size);
1223
1223
  }
1224
1224
  .selectinput-btn {
1225
- display: flex;
1226
- justify-content: space-between;
1227
- align-items: center;
1228
- height: var(--input-height);
1229
- border-radius: var(--input-border-radius);
1230
- border: none;
1231
- background: var(--input-bg);
1232
- padding: 0.7rem;
1233
- color: var(--input-color);
1234
- width: 100%;
1235
- font-family: inherit;
1225
+ display: flex;
1226
+ justify-content: space-between;
1227
+ align-items: center;
1228
+ height: var(--input-height);
1229
+ border-radius: var(--input-border-radius);
1230
+ border: none;
1231
+ background: var(--input-bg);
1232
+ padding: 0.7rem;
1233
+ color: var(--input-color);
1234
+ width: 100%;
1235
+ font-family: inherit;
1236
1236
  }
1237
1237
  .selectinput-btn:disabled {
1238
- background: var(--input-disabled-bg);
1239
- color: var(--input-disabled-color);
1238
+ background: var(--input-disabled-bg);
1239
+ color: var(--input-disabled-color);
1240
1240
  }
1241
1241
  .selectinput-btn:focus {
1242
- outline: none;
1243
- box-shadow: inset 0 0 10px #00000012;
1242
+ outline: none;
1243
+ box-shadow: inset 0 0 10px #00000012;
1244
1244
  }
1245
1245
  .v-popper__arrow-container {
1246
- display: none;
1246
+ display: none;
1247
1247
  }
1248
1248
  .v-popper--theme-dropdown .v-popper__inner {
1249
- border: none;
1250
- background: transparent;
1251
- border-radius: var(--card-border-radius);
1249
+ border: none;
1250
+ background: transparent;
1251
+ border-radius: var(--card-border-radius);
1252
1252
  }
1253
1253
 
1254
1254
  .bagel-input[data-v-69a60381] {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/vue",
3
3
  "type": "module",
4
- "version": "0.0.335",
4
+ "version": "0.0.339",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Neveh Allon",
@@ -1,31 +1,29 @@
1
1
  <template>
2
- <Dropdown placement="bottom-start" class="bagel-input selectinput">
3
- <label>
4
- {{ label }}
5
- <button :disabled="disabled" type="button" class="selectinput-btn" @click="toggle">
6
- {{ valueToLabel(selectedItem) || placeholder || 'Select' }}
7
- <MaterialIcon v-bind="{ 'icon': open ? 'unfold_less' : 'unfold_more' }" />
8
- </button>
9
- <input style="width: 0; height: 0; position: absolute; opacity: 0; z-index: -1;" v-if="required"
10
- v-model="selectedItem" required>
11
- </label>
12
- <template #popper="{ hide }">
13
- <Card class="selectinput-options p-05" :style="{ width: fullWidth ? '100%' : 'auto' }">
14
- <TextInput v-if="searchable" ref="searchInput" dense :placeholder="'Search'" icon="search" v-model="search" />
15
- <div class="selectinput-option hover gap-1" v-for="(option, i) in filteredOptions" :key="`${option}${i}`"
16
- @click="() => {
17
- select(option); hide();
18
- }" :class="{ selected: option === selectedItem }">
19
- <Icon v-if="isSelected(option)" icon="check" />
20
- <Icon class="opacity-3" v-if="!isSelected(option)" icon="fiber_manual_record" />
21
- <span>
22
- {{ getLabel(option) }}
23
- </span>
24
- </div>
25
- <slot name="last" />
26
- </Card>
27
- </template>
28
- </Dropdown>
2
+ <Dropdown ref="dropdown" placement="bottom-start" class="bagel-input selectinput">
3
+ <label>
4
+ {{ label }}
5
+ <button :disabled="disabled" type="button" class="selectinput-btn">
6
+ {{ selecteLabel }}
7
+ <MaterialIcon v-bind="{ 'icon': open ? 'unfold_less' : 'unfold_more' }" />
8
+ </button>
9
+ <input style="width: 0; height: 0; position: absolute; opacity: 0; z-index: -1;" v-if="required"
10
+ v-model="selectedItems" required>
11
+ </label>
12
+ <template #popper="{ hide }">
13
+ <Card class="selectinput-options p-05" :style="{ width: fullWidth ? '100%' : 'auto' }">
14
+ <TextInput v-if="searchable" ref="searchInput" dense :placeholder="'Search'" icon="search" v-model="search" />
15
+ <div class="selectinput-option hover gap-1" v-for="(option, i) in filteredOptions" :key="`${option}${i}`"
16
+ @click="select(option)" :class="{ selected: isSelected(option) }">
17
+ <Icon v-if="isSelected(option)" icon="check" />
18
+ <Icon class="opacity-3" v-if="!isSelected(option)" icon="fiber_manual_record" />
19
+ <span>
20
+ {{ getLabel(option) }}
21
+ </span>
22
+ </div>
23
+ <slot name="last" />
24
+ </Card>
25
+ </template>
26
+ </Dropdown>
29
27
  </template>
30
28
 
31
29
  <script lang="ts" setup>
@@ -33,7 +31,7 @@ import { watch } from 'vue';
33
31
  import { Dropdown } from 'floating-vue';
34
32
  import 'floating-vue/style.css';
35
33
  import {
36
- TextInput, Card, Icon, MaterialIcon,
34
+ TextInput, Card, Icon, MaterialIcon,
37
35
  } from '@bagelink/vue';
38
36
 
39
37
  type Option = string | number | Record<string, any> | { label: string, value: string | number };
@@ -42,130 +40,167 @@ let open = $ref(false);
42
40
  const searchInput = $ref<HTMLInputElement | null>(null);
43
41
 
44
42
  const props = defineProps<{
45
- options: Option[];
46
- placeholder?: string;
47
- disabled?: boolean;
48
- modelValue?: Option;
49
- searchable?: boolean;
50
- required?: boolean;
51
- label?: string;
52
- fullWidth?: boolean;
43
+ options: Option[];
44
+ placeholder?: string;
45
+ disabled?: boolean;
46
+ modelValue?: Option;
47
+ searchable?: boolean;
48
+ required?: boolean;
49
+ label?: string;
50
+ fullWidth?: boolean;
51
+ multiselect?: boolean;
53
52
  }>();
54
- let selectedItem = $ref<Option>();
53
+ const selectedItems = $ref<Option[]>([]);
55
54
  let search = $ref('');
56
55
 
56
+ const dropdown = $ref<InstanceType<typeof Dropdown> | null>(null);
57
+
57
58
  const toggle = () => {
58
- open = !open;
59
- if (!open) search = '';
60
- if (open) setTimeout(() => (searchInput as any)?.$el?.querySelector('input')?.focus(), 100);
59
+ dropdown?.hide();
60
+ open = !open;
61
+ if (!open) search = '';
62
+ if (open) setTimeout(() => (searchInput as any)?.$el?.querySelector('input')?.focus(), 100);
61
63
  };
62
64
 
63
- const valueToLabel = (value?: Option) => {
64
- if (!value) return '';
65
- const option = props.options.find((option) => {
66
- if (typeof option === 'string' || typeof option === 'number') return option === value;
67
- return option.value === value;
68
- });
69
- if (!option) return value;
70
- return getLabel(option);
71
- };
65
+ const selecteLabel = $computed(() => {
66
+ if (selectedItems.length === 0) return props.placeholder || 'Select';
67
+ if (selectedItems.length > 4) {
68
+ const str = selectedItems.slice(0, 4).map((item) => getLabel(item)).join(', ');
69
+ return `${str}... +${selectedItems.length - 4}`;
70
+ }
71
+ return selectedItems.map((item) => getLabel(item)).join(', ');
72
+ });
72
73
 
73
74
  const emit = defineEmits(['update:modelValue']);
74
75
 
75
76
  const getLabel = (option: Option) => {
76
- if (typeof option === 'string') return option;
77
- if (typeof option === 'number') return `${option}`;
78
- return option.label;
77
+ if (typeof option === 'string') return option;
78
+ if (typeof option === 'number') return `${option}`;
79
+ return option.label;
79
80
  };
80
81
 
81
- const isSelected = (option: Option) => {
82
- if (typeof option === 'string' || typeof option === 'number') return option === selectedItem;
83
- return option.value === selectedItem;
82
+ const getValue = (option: Option) => {
83
+ if (typeof option === 'string') return option;
84
+ if (typeof option === 'number') return option;
85
+ return option.value;
84
86
  };
85
87
 
88
+ const isSelected = (option: Option) => selectedItems.includes(getValue(option));
89
+
86
90
  const filteredOptions = $computed(() => props.options.filter((option) => {
87
- const searchTerm = new RegExp(search, 'gi');
88
- if (typeof option === 'string') return option.match(searchTerm);
89
- if (typeof option === 'number') return `${option}`.match(searchTerm);
90
- return option.label.match(searchTerm);
91
+ const searchTerm = new RegExp(search, 'gi');
92
+ if (typeof option === 'string') return option.match(searchTerm);
93
+ if (typeof option === 'number') return `${option}`.match(searchTerm);
94
+ return option.label.match(searchTerm);
91
95
  }));
92
96
 
93
97
  const select = (option: Option) => {
94
- if (typeof option === 'string') selectedItem = option;
95
- else if (typeof option === 'number') selectedItem = option;
96
- else selectedItem = option.value;
97
- emit('update:modelValue', selectedItem);
98
- open = false;
98
+ const existingIndex = selectedItems.findIndex((item) => {
99
+ if (typeof item === 'string' || typeof item === 'number') return item === option;
100
+ return item.value === option;
101
+ });
102
+ if (existingIndex > -1) selectedItems.splice(existingIndex, 1);
103
+ else if (props.multiselect) {
104
+ selectedItems.push(getValue(option));
105
+ } else {
106
+ selectedItems.splice(0, selectedItems.length, getValue(option));
107
+ toggle();
108
+ }
109
+ emitUpdate();
99
110
  };
100
111
 
101
- watch(() => props.modelValue, (value) => {
102
- if (value !== selectedItem) selectedItem = value;
103
- }, { immediate: true });
112
+ function emitUpdate() {
113
+ if (props.multiselect) {
114
+ emit('update:modelValue', selectedItems);
115
+ } else {
116
+ selectedItems.splice(1, selectedItems.length);
117
+ emit('update:modelValue', selectedItems[0]);
118
+ }
119
+ }
120
+
121
+ function compareArrays(arr1: Option[], arr2: Option[]) {
122
+ const isSame = arr1.every((item: Option) => arr2.map((a) => getValue(a)).includes(getValue(item)));
123
+ return isSame;
124
+ }
125
+
126
+ watch(
127
+ () => props.modelValue,
128
+ (newVal: Option | Option[]) => {
129
+ if (!newVal) return;
130
+ if (!props.multiselect) {
131
+ if (!isSelected(newVal)) selectedItems.splice(0, selectedItems.length, newVal);
132
+ } else {
133
+ const isSame = compareArrays([newVal].flat(), selectedItems);
134
+ if (!isSame) selectedItems.splice(0, selectedItems.length, [newVal].flat());
135
+ }
136
+ },
137
+ { immediate: true },
138
+ );
104
139
  </script>
105
140
 
106
141
  <style scoped>
107
142
  .selectinput {
108
- width: 100%;
143
+ width: 100%;
109
144
  }
110
145
 
111
146
  .selectinput-option {
112
- padding: 6px 12px;
113
- cursor: pointer;
114
- border-radius: 5px;
115
- transition: all 0.2s;
116
- display: grid;
117
- grid-template-columns: 10px 1fr;
118
- justify-content: space-between;
119
- width: 100%;
120
- font-size: var(--input-font-size);
147
+ padding: 6px 12px;
148
+ cursor: pointer;
149
+ border-radius: 5px;
150
+ transition: all 0.2s;
151
+ display: grid;
152
+ grid-template-columns: 10px 1fr;
153
+ justify-content: space-between;
154
+ width: 100%;
155
+ font-size: var(--input-font-size);
121
156
  }
122
157
 
123
158
  .selectinput-options {
124
- max-height: 300px;
125
- overflow-y: auto;
159
+ max-height: 300px;
160
+ overflow-y: auto;
126
161
  }
127
162
 
128
163
  .selectinput-option:hover {
129
- background: var(--bgl-gray-20);
164
+ background: var(--bgl-gray-20);
130
165
  }
131
166
  </style>
132
167
 
133
168
  <style>
134
169
  .bagel-input label {
135
- font-size: var(--label-font-size);
170
+ font-size: var(--label-font-size);
136
171
  }
137
172
 
138
173
  .selectinput-btn {
139
- display: flex;
140
- justify-content: space-between;
141
- align-items: center;
142
- height: var(--input-height);
143
- border-radius: var(--input-border-radius);
144
- border: none;
145
- background: var(--input-bg);
146
- padding: 0.7rem;
147
- color: var(--input-color);
148
- width: 100%;
149
- font-family: inherit;
174
+ display: flex;
175
+ justify-content: space-between;
176
+ align-items: center;
177
+ height: var(--input-height);
178
+ border-radius: var(--input-border-radius);
179
+ border: none;
180
+ background: var(--input-bg);
181
+ padding: 0.7rem;
182
+ color: var(--input-color);
183
+ width: 100%;
184
+ font-family: inherit;
150
185
  }
151
186
 
152
187
  .selectinput-btn:disabled {
153
- background: var(--input-disabled-bg);
154
- color: var(--input-disabled-color);
188
+ background: var(--input-disabled-bg);
189
+ color: var(--input-disabled-color);
155
190
  }
156
191
 
157
192
  .selectinput-btn:focus {
158
- outline: none;
159
- box-shadow: inset 0 0 10px #00000012;
193
+ outline: none;
194
+ box-shadow: inset 0 0 10px #00000012;
160
195
  }
161
196
 
162
197
  .v-popper__arrow-container {
163
- display: none;
198
+ display: none;
164
199
  }
165
200
 
166
201
  .v-popper--theme-dropdown .v-popper__inner {
167
- border: none;
168
- background: transparent;
169
- border-radius: var(--card-border-radius);
202
+ border: none;
203
+ background: transparent;
204
+ border-radius: var(--card-border-radius);
170
205
  }
171
206
  </style>