@dragonmastery/zinia-forms-core 0.4.3 → 0.4.6

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.
package/dist/index.js CHANGED
@@ -8423,14 +8423,50 @@ var BooleanFilter = (props) => {
8423
8423
  );
8424
8424
  };
8425
8425
  var comboboxState = reactive({});
8426
+ var DROPDOWN_MAX_HEIGHT = 240;
8427
+ var MIN_SPACE_BELOW = 100;
8426
8428
  var ComboboxFilter = (props) => {
8427
8429
  if (!comboboxState[props.field]) {
8428
8430
  comboboxState[props.field] = {
8429
8431
  isOpen: false,
8430
- selectedIndex: -1
8432
+ selectedIndex: -1,
8433
+ position: { top: 0, left: 0, width: 0, openUpward: false }
8431
8434
  };
8432
8435
  }
8433
8436
  const state = comboboxState[props.field];
8437
+ const updateDropdownPosition = () => {
8438
+ const input = document.querySelector(`[data-combobox-input="${props.field}"]`);
8439
+ if (!input) return;
8440
+ const rect = input.getBoundingClientRect();
8441
+ const spaceBelow = window.innerHeight - rect.bottom;
8442
+ const spaceAbove = rect.top;
8443
+ const openUpward = spaceBelow < MIN_SPACE_BELOW && spaceAbove > spaceBelow;
8444
+ state.position = {
8445
+ top: openUpward ? rect.top - 4 : rect.bottom + 4,
8446
+ // 4px gap
8447
+ left: rect.left,
8448
+ width: rect.width,
8449
+ openUpward
8450
+ };
8451
+ };
8452
+ const handleScrollOrResize = () => {
8453
+ if (state.isOpen) {
8454
+ updateDropdownPosition();
8455
+ }
8456
+ };
8457
+ let cleanupFns = [];
8458
+ const setupEventListeners = () => {
8459
+ window.addEventListener("scroll", handleScrollOrResize, true);
8460
+ window.addEventListener("resize", handleScrollOrResize);
8461
+ cleanupFns.push(() => {
8462
+ window.removeEventListener("scroll", handleScrollOrResize, true);
8463
+ window.removeEventListener("resize", handleScrollOrResize);
8464
+ });
8465
+ };
8466
+ const cleanupEventListeners = () => {
8467
+ cleanupFns.forEach((fn) => fn());
8468
+ cleanupFns = [];
8469
+ };
8434
8470
  const searchQuery = computed(() => props.filterInputValues.value[props.field] || "");
8435
8471
  const selectedOption = computed(() => {
8436
8472
  if (!props.value) return "";
@@ -8465,10 +8501,7 @@ var ComboboxFilter = (props) => {
8465
8501
  props.filterInputValues.value[props.field] = value;
8466
8502
  state.isOpen = true;
8467
8503
  state.selectedIndex = -1;
8468
- const exactMatch = props.options.find((opt) => opt.label.toLowerCase() === value.toLowerCase().trim());
8469
- if (exactMatch) {
8470
- props.onFilterChange(props.field, exactMatch.value, "eq");
8471
- }
8504
+ updateDropdownPosition();
8472
8505
  };
8473
8506
  const handleSelectOption = (option) => {
8474
8507
  props.filterInputValues.value[props.field] = option.label;
@@ -8553,7 +8586,10 @@ var ComboboxFilter = (props) => {
8553
8586
  if (e.key === "ArrowDown") {
8554
8587
  e.preventDefault();
8555
8588
  e.stopPropagation();
8556
- state.isOpen = true;
8589
+ if (!state.isOpen) {
8590
+ state.isOpen = true;
8591
+ updateDropdownPosition();
8592
+ }
8557
8593
  const totalOptions = filteredOptions.value.length + (isNewValue.value && props.allowCreate ? 1 : 0);
8558
8594
  if (totalOptions > 0) {
8559
8595
  const currentIndex = state.selectedIndex;
@@ -8568,7 +8604,10 @@ var ComboboxFilter = (props) => {
8568
8604
  if (e.key === "ArrowUp") {
8569
8605
  e.preventDefault();
8570
8606
  e.stopPropagation();
8571
- state.isOpen = true;
8607
+ if (!state.isOpen) {
8608
+ state.isOpen = true;
8609
+ updateDropdownPosition();
8610
+ }
8572
8611
  const totalOptions = filteredOptions.value.length + (isNewValue.value && props.allowCreate ? 1 : 0);
8573
8612
  if (totalOptions > 0) {
8574
8613
  const currentIndex = state.selectedIndex;
@@ -8583,6 +8622,8 @@ var ComboboxFilter = (props) => {
8583
8622
  };
8584
8623
  const handleFocus = () => {
8585
8624
  state.isOpen = true;
8625
+ updateDropdownPosition();
8626
+ setupEventListeners();
8586
8627
  };
8587
8628
  const scrollToSelectedOption = (index) => {
8588
8629
  const container = document.querySelector(`[data-combobox-dropdown="${props.field}"]`);
@@ -8603,10 +8644,12 @@ var ComboboxFilter = (props) => {
8603
8644
  const handleBlur = (e) => {
8604
8645
  const relatedTarget = e.relatedTarget || document.activeElement;
8605
8646
  const container = document.querySelector(`[data-combobox-container="${props.field}"]`);
8606
- if (container && container.contains(relatedTarget)) {
8647
+ const dropdown = document.querySelector(`[data-combobox-dropdown="${props.field}"]`);
8648
+ if (container && container.contains(relatedTarget) || dropdown && dropdown.contains(relatedTarget)) {
8607
8649
  return;
8608
8650
  }
8609
8651
  state.isOpen = false;
8652
+ cleanupEventListeners();
8610
8653
  const currentQuery = searchQuery.value.trim();
8611
8654
  const currentValue = props.value;
8612
8655
  const currentLabel = selectedOption.value;
@@ -8643,6 +8686,18 @@ var ComboboxFilter = (props) => {
8643
8686
  }
8644
8687
  }
8645
8688
  };
8689
+ const dropdownStyle = computed(() => {
8690
+ const pos = state.position;
8691
+ return {
8692
+ position: "fixed",
8693
+ top: pos.openUpward ? "auto" : `${pos.top}px`,
8694
+ bottom: pos.openUpward ? `${window.innerHeight - pos.top}px` : "auto",
8695
+ left: `${pos.left}px`,
8696
+ width: `${pos.width}px`,
8697
+ maxHeight: `${DROPDOWN_MAX_HEIGHT}px`,
8698
+ zIndex: 9999
8699
+ };
8700
+ });
8646
8701
  return /* @__PURE__ */ jsxs("div", { class: "relative w-full", "data-combobox-container": props.field, children: [
8647
8702
  /* @__PURE__ */ jsx(
8648
8703
  "input",
@@ -8656,7 +8711,8 @@ var ComboboxFilter = (props) => {
8656
8711
  placeholder: props.isOptionsLoading ? "Loading options..." : `Search ${props.label}`,
8657
8712
  class: "input input-bordered input-sm w-full",
8658
8713
  disabled: props.isLoading || props.isOptionsLoading,
8659
- "data-testid": `datatable-filter-${props.field}-input`
8714
+ "data-testid": `datatable-filter-${props.field}-input`,
8715
+ "data-combobox-input": props.field
8660
8716
  }
8661
8717
  ),
8662
8718
  /* @__PURE__ */ jsx("div", { class: "absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none", children: /* @__PURE__ */ jsx(
@@ -8671,11 +8727,15 @@ var ComboboxFilter = (props) => {
8671
8727
  children: /* @__PURE__ */ jsx("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M8 9l4-4 4 4m0 6l-4 4-4-4" })
8672
8728
  }
8673
8729
  ) }),
8674
- state.isOpen && /* @__PURE__ */ jsx(
8730
+ state.isOpen && /* @__PURE__ */ jsx(Teleport, { to: "body", children: /* @__PURE__ */ jsx(
8675
8731
  "div",
8676
8732
  {
8677
8733
  "data-combobox-dropdown": props.field,
8678
- class: "absolute z-50 mt-1 bg-base-100 border border-base-300 rounded-box shadow-lg max-h-60 overflow-auto w-full",
8734
+ class: "bg-base-100 border border-base-300 rounded-box shadow-lg overflow-auto",
8735
+ style: dropdownStyle.value,
8736
+ onMousedown: (e) => {
8737
+ e.preventDefault();
8738
+ },
8679
8739
  children: /* @__PURE__ */ jsx("ul", { class: "menu w-full", role: "listbox", id: `combobox-listbox-${props.field}`, children: props.isOptionsLoading ? /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("span", { class: "text-sm text-base-content/70 p-2", children: "Loading options..." }) }) : filteredOptions.value.length === 0 && !isNewValue.value && !isInvalidValue.value ? /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("span", { class: "text-sm text-base-content/70 p-2", children: "No options available" }) }) : isInvalidValue.value ? /* @__PURE__ */ jsx("li", { class: "bg-error/10 border-l-4 border-error", children: /* @__PURE__ */ jsx("div", { class: "p-2", children: /* @__PURE__ */ jsxs("div", { class: "flex items-center gap-2", children: [
8680
8740
  /* @__PURE__ */ jsx(
8681
8741
  "svg",
@@ -8779,7 +8839,7 @@ var ComboboxFilter = (props) => {
8779
8839
  )
8780
8840
  ] }) })
8781
8841
  }
8782
- )
8842
+ ) })
8783
8843
  ] });
8784
8844
  };
8785
8845
  var FilterDrawer = (props) => {
@@ -9336,7 +9396,8 @@ var MobileCards = (props) => {
9336
9396
  if (!column) return null;
9337
9397
  const value = row[field];
9338
9398
  const formattedValue = formatCellValue(value, field, row, column);
9339
- if (!value && value !== 0 && value !== false) return null;
9399
+ const hasCustomSlot = !!props.slots[`cell-${field}`];
9400
+ if (!hasCustomSlot && !value && value !== 0 && value !== false) return null;
9340
9401
  return /* @__PURE__ */ jsxs("div", { class: "flex justify-between items-center", children: [
9341
9402
  /* @__PURE__ */ jsxs("span", { class: "text-sm font-medium text-base-content/70 min-w-0 flex-shrink-0 mr-2", children: [
9342
9403
  column.label,