directix 1.4.0 → 1.4.1

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * directix v1.4.0
2
+ * directix v1.4.1
3
3
  * A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3
4
4
  * (c) 2021-present saqqdy <https://github.com/saqqdy>
5
5
  * Released under the MIT License.
@@ -57,7 +57,7 @@ var __async = (__this, __arguments, generator) => {
57
57
  });
58
58
  };
59
59
  /*!
60
- * directix v1.4.0
60
+ * directix v1.4.1
61
61
  * A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3
62
62
  * (c) 2021-present saqqdy <https://github.com/saqqdy>
63
63
  * Released under the MIT License.
@@ -2803,15 +2803,15 @@ var __async = (__this, __arguments, generator) => {
2803
2803
  delete el[STATE_KEY$3];
2804
2804
  }
2805
2805
  });
2806
- let globalObserver = null;
2807
- function getGlobalObserver(preload) {
2808
- if (globalObserver) return globalObserver;
2809
- globalObserver = new IntersectionObserver(
2806
+ let globalObserver$1 = null;
2807
+ function getGlobalObserver$1(preload) {
2808
+ if (globalObserver$1) return globalObserver$1;
2809
+ globalObserver$1 = new IntersectionObserver(
2810
2810
  (entries) => {
2811
2811
  entries.forEach((entry) => {
2812
2812
  if (entry.isIntersecting) {
2813
2813
  load(entry.target);
2814
- globalObserver == null ? void 0 : globalObserver.unobserve(entry.target);
2814
+ globalObserver$1 == null ? void 0 : globalObserver$1.unobserve(entry.target);
2815
2815
  }
2816
2816
  });
2817
2817
  },
@@ -2819,9 +2819,9 @@ var __async = (__this, __arguments, generator) => {
2819
2819
  rootMargin: `${preload}px`
2820
2820
  }
2821
2821
  );
2822
- return globalObserver;
2822
+ return globalObserver$1;
2823
2823
  }
2824
- function setSrc(el, src) {
2824
+ function setSrc$1(el, src) {
2825
2825
  if (el.tagName === "IMG") {
2826
2826
  el.src = src;
2827
2827
  } else {
@@ -2846,7 +2846,7 @@ var __async = (__this, __arguments, generator) => {
2846
2846
  const img = new Image();
2847
2847
  img.onload = () => {
2848
2848
  var _a, _b;
2849
- setSrc(el, state.options.src);
2849
+ setSrc$1(el, state.options.src);
2850
2850
  setLazyState(el, "loaded");
2851
2851
  el.classList.remove("v-lazy--loading");
2852
2852
  el.classList.add("v-lazy--loaded");
@@ -2860,7 +2860,7 @@ var __async = (__this, __arguments, generator) => {
2860
2860
  return;
2861
2861
  }
2862
2862
  if (state.options.error) {
2863
- setSrc(el, state.options.error);
2863
+ setSrc$1(el, state.options.error);
2864
2864
  }
2865
2865
  setLazyState(el, "error");
2866
2866
  el.classList.add("v-lazy--error");
@@ -2879,7 +2879,7 @@ var __async = (__this, __arguments, generator) => {
2879
2879
  state.observer = state.options.observer;
2880
2880
  state.observer.observe(el);
2881
2881
  } else {
2882
- const observer = getGlobalObserver(state.options.preload || 0);
2882
+ const observer = getGlobalObserver$1(state.options.preload || 0);
2883
2883
  state.observer = observer;
2884
2884
  observer.observe(el);
2885
2885
  }
@@ -2889,8 +2889,8 @@ var __async = (__this, __arguments, generator) => {
2889
2889
  if (!state) return;
2890
2890
  if (state.observer) {
2891
2891
  state.observer.unobserve(el);
2892
- } else if (globalObserver) {
2893
- globalObserver.unobserve(el);
2892
+ } else if (globalObserver$1) {
2893
+ globalObserver$1.unobserve(el);
2894
2894
  }
2895
2895
  }
2896
2896
  function normalizeOptions$n(binding) {
@@ -2916,7 +2916,7 @@ var __async = (__this, __arguments, generator) => {
2916
2916
  }
2917
2917
  setLazyState(el, "pending");
2918
2918
  if (options.placeholder) {
2919
- setSrc(el, options.placeholder);
2919
+ setSrc$1(el, options.placeholder);
2920
2920
  }
2921
2921
  el.classList.add("v-lazy");
2922
2922
  const state = {
@@ -2941,7 +2941,7 @@ var __async = (__this, __arguments, generator) => {
2941
2941
  setLazyState(el, "pending");
2942
2942
  el.classList.remove("v-lazy--loaded", "v-lazy--error");
2943
2943
  if (newOptions.placeholder) {
2944
- setSrc(el, newOptions.placeholder);
2944
+ setSrc$1(el, newOptions.placeholder);
2945
2945
  }
2946
2946
  observe(el);
2947
2947
  }
@@ -2966,12 +2966,12 @@ var __async = (__this, __arguments, generator) => {
2966
2966
  disabled: false
2967
2967
  }, binding);
2968
2968
  }
2969
- const DEFAULT_SPINNER = `
2969
+ const DEFAULT_SPINNER$1 = `
2970
2970
  <svg class="v-loading__circular" viewBox="25 25 50 50">
2971
2971
  <circle class="v-loading__path" cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10"/>
2972
2972
  </svg>
2973
2973
  `;
2974
- function createLoadingOverlay(options) {
2974
+ function createLoadingOverlay$1(options) {
2975
2975
  const overlay = document.createElement("div");
2976
2976
  overlay.className = options.loadingClass || "v-loading";
2977
2977
  overlay.style.cssText = `
@@ -2987,7 +2987,7 @@ var __async = (__this, __arguments, generator) => {
2987
2987
  align-items: center;
2988
2988
  justify-content: center;
2989
2989
  `;
2990
- const spinnerHtml = options.spinner || DEFAULT_SPINNER;
2990
+ const spinnerHtml = options.spinner || DEFAULT_SPINNER$1;
2991
2991
  const spinnerContainer = document.createElement("div");
2992
2992
  spinnerContainer.className = options.spinnerClass || "v-loading__spinner";
2993
2993
  spinnerContainer.innerHTML = spinnerHtml;
@@ -3066,7 +3066,7 @@ var __async = (__this, __arguments, generator) => {
3066
3066
  });
3067
3067
  function showLoading(el, state) {
3068
3068
  if (state.loadingOverlay) return;
3069
- state.loadingOverlay = createLoadingOverlay(state.options);
3069
+ state.loadingOverlay = createLoadingOverlay$1(state.options);
3070
3070
  el.appendChild(state.loadingOverlay);
3071
3071
  if (state.options.lock) {
3072
3072
  el.style.overflow = "hidden";
@@ -3290,15 +3290,15 @@ var __async = (__this, __arguments, generator) => {
3290
3290
  }
3291
3291
  });
3292
3292
  const STATE_KEY$2 = "__mask";
3293
- const TOKEN_PATTERNS = {
3293
+ const TOKEN_PATTERNS$1 = {
3294
3294
  "#": /\d/,
3295
3295
  A: /[A-Za-z]/,
3296
3296
  N: /[A-Za-z0-9]/,
3297
3297
  X: /./
3298
3298
  };
3299
- function parseMask(mask, placeholder) {
3299
+ function parseMask$1(mask, placeholder) {
3300
3300
  return [...mask].map((char) => {
3301
- const pattern = TOKEN_PATTERNS[char];
3301
+ const pattern = TOKEN_PATTERNS$1[char];
3302
3302
  return pattern ? { pattern, placeholder, isLiteral: false } : { pattern: new RegExp(`\\${char}`), placeholder: char, isLiteral: true };
3303
3303
  });
3304
3304
  }
@@ -3370,7 +3370,7 @@ var __async = (__this, __arguments, generator) => {
3370
3370
  const options = normalizeOptions$j(binding.value);
3371
3371
  if (options.disabled || !isBrowser()) return;
3372
3372
  const placeholder = options.placeholder || "_";
3373
- const tokens = parseMask(options.mask, placeholder);
3373
+ const tokens = parseMask$1(options.mask, placeholder);
3374
3374
  const inputHandler = (e) => {
3375
3375
  var _a2, _b, _c;
3376
3376
  const target = e.target;
@@ -3410,7 +3410,7 @@ var __async = (__this, __arguments, generator) => {
3410
3410
  const state = el[STATE_KEY$2];
3411
3411
  if (!state) return;
3412
3412
  state.options = normalizeOptions$j(binding.value);
3413
- state.tokens = parseMask(state.options.mask, state.placeholder);
3413
+ state.tokens = parseMask$1(state.options.mask, state.placeholder);
3414
3414
  },
3415
3415
  unmounted(el) {
3416
3416
  const state = el[STATE_KEY$2];
@@ -3763,6 +3763,14 @@ var __async = (__this, __arguments, generator) => {
3763
3763
  }
3764
3764
  });
3765
3765
  const STATE_KEY$1 = "__permission";
3766
+ const WILDCARD$1 = "*";
3767
+ let globalConfig = null;
3768
+ function configurePermission(config) {
3769
+ globalConfig = config;
3770
+ }
3771
+ function getPermissionConfig() {
3772
+ return globalConfig;
3773
+ }
3766
3774
  function normalizeOptions$h(binding) {
3767
3775
  if (!binding) {
3768
3776
  throw new Error("[Directix] v-permission: permission value is required");
@@ -3775,14 +3783,39 @@ var __async = (__this, __arguments, generator) => {
3775
3783
  }
3776
3784
  return binding;
3777
3785
  }
3786
+ function hasPermission$1(required, permissions) {
3787
+ return permissions.includes(WILDCARD$1) || permissions.includes(required);
3788
+ }
3778
3789
  function verifyPermission(options) {
3790
+ var _a;
3779
3791
  if (options.check) {
3780
3792
  return options.check(options.value, options.mode || "some");
3781
3793
  }
3782
- {
3794
+ if (!globalConfig) {
3783
3795
  console.warn("[Directix] v-permission: No permission config provided");
3784
3796
  return true;
3785
3797
  }
3798
+ const permissions = globalConfig.getPermissions();
3799
+ const roles = ((_a = globalConfig.getRoles) == null ? void 0 : _a.call(globalConfig)) || [];
3800
+ const roleMap = globalConfig.roleMap || {};
3801
+ const required = Array.isArray(options.value) ? options.value : [options.value];
3802
+ const mode = options.mode || "some";
3803
+ function checkSingle(value) {
3804
+ if (value in roleMap) {
3805
+ return roles.includes(value);
3806
+ }
3807
+ if (hasPermission$1(value, permissions)) {
3808
+ return true;
3809
+ }
3810
+ for (const role of roles) {
3811
+ const rolePermissions = roleMap[role] || [];
3812
+ if (hasPermission$1(value, rolePermissions)) {
3813
+ return true;
3814
+ }
3815
+ }
3816
+ return false;
3817
+ }
3818
+ return mode === "every" ? required.every(checkSingle) : required.some(checkSingle);
3786
3819
  }
3787
3820
  function handleDenied(el, action, state) {
3788
3821
  var _a, _b;
@@ -4492,23 +4525,23 @@ var __async = (__this, __arguments, generator) => {
4492
4525
  delete el.__ripple;
4493
4526
  }
4494
4527
  });
4495
- const DEFAULT_ALLOWED_TAGS = ["b", "i", "u", "strong", "em", "br", "p", "span", "div"];
4496
- const DEFAULT_ALLOWED_ATTRIBUTES = ["title", "alt", "href", "src"];
4497
- const DANGEROUS_TAGS = ["script", "iframe", "object", "embed", "form", "input", "style", "link", "meta", "base"];
4498
- const DANGEROUS_ATTRIBUTES = ["onclick", "onerror", "onload", "onmouseover", "onfocus", "onblur", "onchange", "onsubmit"];
4528
+ const DEFAULT_ALLOWED_TAGS$1 = ["b", "i", "u", "strong", "em", "br", "p", "span", "div"];
4529
+ const DEFAULT_ALLOWED_ATTRIBUTES$1 = ["title", "alt", "href", "src"];
4530
+ const DANGEROUS_TAGS$1 = ["script", "iframe", "object", "embed", "form", "input", "style", "link", "meta", "base"];
4531
+ const DANGEROUS_ATTRIBUTES$1 = ["onclick", "onerror", "onload", "onmouseover", "onfocus", "onblur", "onchange", "onsubmit"];
4499
4532
  function normalizeOptions$c(binding) {
4500
4533
  if (binding === false) {
4501
4534
  return { disabled: true };
4502
4535
  }
4503
4536
  if (binding === true) {
4504
4537
  return {
4505
- allowedTags: DEFAULT_ALLOWED_TAGS,
4506
- allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES
4538
+ allowedTags: DEFAULT_ALLOWED_TAGS$1,
4539
+ allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES$1
4507
4540
  };
4508
4541
  }
4509
4542
  return __spreadValues({
4510
- allowedTags: DEFAULT_ALLOWED_TAGS,
4511
- allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES,
4543
+ allowedTags: DEFAULT_ALLOWED_TAGS$1,
4544
+ allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES$1,
4512
4545
  allowDataUrls: false,
4513
4546
  allowStyles: false,
4514
4547
  allowClass: false,
@@ -4524,7 +4557,7 @@ var __async = (__this, __arguments, generator) => {
4524
4557
  }
4525
4558
  const temp = document.createElement("div");
4526
4559
  temp.innerHTML = html;
4527
- for (const tag of DANGEROUS_TAGS) {
4560
+ for (const tag of DANGEROUS_TAGS$1) {
4528
4561
  const elements = temp.getElementsByTagName(tag);
4529
4562
  while (elements.length > 0) {
4530
4563
  (_a = elements[0].parentNode) == null ? void 0 : _a.removeChild(elements[0]);
@@ -4538,7 +4571,7 @@ var __async = (__this, __arguments, generator) => {
4538
4571
  (_a2 = el.parentNode) == null ? void 0 : _a2.replaceChild(text, el);
4539
4572
  return;
4540
4573
  }
4541
- for (const attr of DANGEROUS_ATTRIBUTES) {
4574
+ for (const attr of DANGEROUS_ATTRIBUTES$1) {
4542
4575
  el.removeAttribute(attr);
4543
4576
  }
4544
4577
  const href = el.getAttribute("href");
@@ -4576,8 +4609,8 @@ var __async = (__this, __arguments, generator) => {
4576
4609
  name: "sanitize",
4577
4610
  ssr: true,
4578
4611
  defaults: {
4579
- allowedTags: DEFAULT_ALLOWED_TAGS,
4580
- allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES,
4612
+ allowedTags: DEFAULT_ALLOWED_TAGS$1,
4613
+ allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES$1,
4581
4614
  allowDataUrls: false,
4582
4615
  allowStyles: false,
4583
4616
  allowClass: false,
@@ -7506,6 +7539,105 @@ var __async = (__this, __arguments, generator) => {
7506
7539
  bind
7507
7540
  };
7508
7541
  }
7542
+ function useInfiniteScroll(options) {
7543
+ const {
7544
+ onLoad,
7545
+ loading: externalLoading,
7546
+ finished: externalFinished,
7547
+ distance = 0,
7548
+ immediate = true,
7549
+ disabled = false
7550
+ } = options;
7551
+ const internalLoading = vue.ref(false);
7552
+ const internalFinished = vue.ref(false);
7553
+ const loading = externalLoading || internalLoading;
7554
+ const finished = externalFinished || internalFinished;
7555
+ let scrollContainer = null, scrollHandler = null, observer = null, sentinel = null;
7556
+ function load2() {
7557
+ return __async(this, null, function* () {
7558
+ if (vue.unref(loading) || vue.unref(finished) || vue.unref(disabled)) return;
7559
+ internalLoading.value = true;
7560
+ try {
7561
+ yield onLoad();
7562
+ } finally {
7563
+ internalLoading.value = false;
7564
+ }
7565
+ });
7566
+ }
7567
+ function checkScroll() {
7568
+ if (!scrollContainer || vue.unref(loading) || vue.unref(finished) || vue.unref(disabled)) return;
7569
+ const currentDistance = vue.unref(distance);
7570
+ let scrollBottom, containerHeight;
7571
+ if (scrollContainer === window) {
7572
+ scrollBottom = document.documentElement.scrollHeight - window.scrollY;
7573
+ containerHeight = window.innerHeight;
7574
+ } else {
7575
+ const el = scrollContainer;
7576
+ scrollBottom = el.scrollHeight - el.scrollTop;
7577
+ containerHeight = el.clientHeight;
7578
+ }
7579
+ if (scrollBottom <= containerHeight + currentDistance) {
7580
+ load2();
7581
+ }
7582
+ }
7583
+ function bind(element) {
7584
+ if (!isBrowser()) return () => {
7585
+ };
7586
+ stop();
7587
+ if (supportsIntersectionObserver()) {
7588
+ sentinel = document.createElement("div");
7589
+ sentinel.style.cssText = "height: 1px; width: 100%; visibility: hidden;";
7590
+ element.appendChild(sentinel);
7591
+ const parent = getScrollParent(element);
7592
+ const root = parent instanceof Window ? null : parent;
7593
+ observer = new IntersectionObserver(
7594
+ (entries) => {
7595
+ if (entries[0].isIntersecting) {
7596
+ load2();
7597
+ }
7598
+ },
7599
+ {
7600
+ root,
7601
+ rootMargin: `${vue.unref(distance)}px`
7602
+ }
7603
+ );
7604
+ observer.observe(sentinel);
7605
+ } else {
7606
+ scrollContainer = getScrollParent(element);
7607
+ scrollHandler = checkScroll;
7608
+ scrollContainer.addEventListener("scroll", scrollHandler);
7609
+ }
7610
+ if (immediate) {
7611
+ load2();
7612
+ }
7613
+ return stop;
7614
+ }
7615
+ function stop() {
7616
+ if (observer) {
7617
+ observer.disconnect();
7618
+ observer = null;
7619
+ }
7620
+ if (sentinel) {
7621
+ sentinel.remove();
7622
+ sentinel = null;
7623
+ }
7624
+ if (scrollContainer && scrollHandler) {
7625
+ scrollContainer.removeEventListener("scroll", scrollHandler);
7626
+ }
7627
+ scrollContainer = null;
7628
+ scrollHandler = null;
7629
+ }
7630
+ vue.onUnmounted(() => {
7631
+ stop();
7632
+ });
7633
+ return {
7634
+ loading: vue.readonly(loading),
7635
+ finished: vue.readonly(finished),
7636
+ load: load2,
7637
+ bind,
7638
+ stop
7639
+ };
7640
+ }
7509
7641
  function useIntersect(options = {}) {
7510
7642
  const {
7511
7643
  handler,
@@ -7577,6 +7709,269 @@ var __async = (__this, __arguments, generator) => {
7577
7709
  stop
7578
7710
  };
7579
7711
  }
7712
+ let globalObserver = null;
7713
+ function getGlobalObserver(preload) {
7714
+ if (globalObserver) return globalObserver;
7715
+ globalObserver = new IntersectionObserver(
7716
+ (entries) => {
7717
+ entries.forEach((entry) => {
7718
+ if (entry.isIntersecting) {
7719
+ const el = entry.target;
7720
+ const loadFn = el.__lazyLoad;
7721
+ if (loadFn) {
7722
+ loadFn();
7723
+ globalObserver == null ? void 0 : globalObserver.unobserve(el);
7724
+ }
7725
+ }
7726
+ });
7727
+ },
7728
+ {
7729
+ rootMargin: `${preload}px`
7730
+ }
7731
+ );
7732
+ return globalObserver;
7733
+ }
7734
+ function setSrc(el, src) {
7735
+ if (el.tagName === "IMG") {
7736
+ el.src = src;
7737
+ } else {
7738
+ el.style.backgroundImage = `url("${src}")`;
7739
+ }
7740
+ }
7741
+ function useLazy(options = {}) {
7742
+ const {
7743
+ src,
7744
+ placeholder,
7745
+ error,
7746
+ preload = 0,
7747
+ onLoad,
7748
+ onError,
7749
+ attempt = 1
7750
+ } = options;
7751
+ const state = vue.ref("pending");
7752
+ const isLoading = vue.ref(false);
7753
+ const isLoaded = vue.ref(false);
7754
+ const hasError = vue.ref(false);
7755
+ let currentElement = null, attemptCount = 0, observer = null;
7756
+ function loadImage() {
7757
+ const srcValue = vue.unref(src);
7758
+ if (!srcValue || !currentElement) return;
7759
+ if (state.value === "loading") return;
7760
+ state.value = "loading";
7761
+ isLoading.value = true;
7762
+ const img = new Image();
7763
+ img.onload = () => {
7764
+ setSrc(currentElement, srcValue);
7765
+ state.value = "loaded";
7766
+ isLoading.value = false;
7767
+ isLoaded.value = true;
7768
+ hasError.value = false;
7769
+ currentElement == null ? void 0 : currentElement.classList.remove("v-lazy--loading");
7770
+ currentElement == null ? void 0 : currentElement.classList.add("v-lazy--loaded");
7771
+ onLoad == null ? void 0 : onLoad(currentElement);
7772
+ };
7773
+ img.onerror = () => {
7774
+ currentElement == null ? void 0 : currentElement.classList.remove("v-lazy--loading");
7775
+ attemptCount++;
7776
+ if (attemptCount < attempt) {
7777
+ setTimeout(() => loadImage(), 1e3 * attemptCount);
7778
+ return;
7779
+ }
7780
+ if (error && currentElement) {
7781
+ setSrc(currentElement, error);
7782
+ }
7783
+ state.value = "error";
7784
+ isLoading.value = false;
7785
+ hasError.value = true;
7786
+ currentElement == null ? void 0 : currentElement.classList.add("v-lazy--error");
7787
+ onError == null ? void 0 : onError(currentElement, new Error("Failed to load image"));
7788
+ };
7789
+ currentElement.classList.add("v-lazy--loading");
7790
+ img.src = srcValue;
7791
+ }
7792
+ function bind(element) {
7793
+ if (!isBrowser()) return () => {
7794
+ };
7795
+ unbind();
7796
+ currentElement = element;
7797
+ attemptCount = 0;
7798
+ state.value = "pending";
7799
+ element.classList.add("v-lazy");
7800
+ if (placeholder) {
7801
+ setSrc(element, placeholder);
7802
+ }
7803
+ element.__lazyLoad = loadImage;
7804
+ if (!supportsIntersectionObserver()) {
7805
+ loadImage();
7806
+ return unbind;
7807
+ }
7808
+ observer = getGlobalObserver(preload);
7809
+ observer.observe(element);
7810
+ return unbind;
7811
+ }
7812
+ function unbind() {
7813
+ if (currentElement) {
7814
+ if (observer) {
7815
+ observer.unobserve(currentElement);
7816
+ }
7817
+ delete currentElement.__lazyLoad;
7818
+ currentElement.classList.remove("v-lazy", "v-lazy--loading", "v-lazy--loaded", "v-lazy--error");
7819
+ }
7820
+ currentElement = null;
7821
+ }
7822
+ function reset() {
7823
+ state.value = "pending";
7824
+ isLoading.value = false;
7825
+ isLoaded.value = false;
7826
+ hasError.value = false;
7827
+ attemptCount = 0;
7828
+ }
7829
+ vue.onUnmounted(() => {
7830
+ unbind();
7831
+ });
7832
+ return {
7833
+ state: vue.readonly(state),
7834
+ isLoading: vue.readonly(isLoading),
7835
+ isLoaded: vue.readonly(isLoaded),
7836
+ hasError: vue.readonly(hasError),
7837
+ bind,
7838
+ load: loadImage,
7839
+ reset
7840
+ };
7841
+ }
7842
+ const DEFAULT_SPINNER = `
7843
+ <svg class="v-loading__circular" viewBox="25 25 50 50">
7844
+ <circle class="v-loading__path" cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10"/>
7845
+ </svg>
7846
+ `;
7847
+ function createLoadingOverlay(options) {
7848
+ const overlay = document.createElement("div");
7849
+ overlay.className = options.loadingClass || "v-loading";
7850
+ overlay.style.cssText = `
7851
+ position: absolute;
7852
+ top: 0;
7853
+ left: 0;
7854
+ right: 0;
7855
+ bottom: 0;
7856
+ z-index: 1000;
7857
+ background: ${options.background || "rgba(255, 255, 255, 0.9)"};
7858
+ display: flex;
7859
+ flex-direction: column;
7860
+ align-items: center;
7861
+ justify-content: center;
7862
+ `;
7863
+ const spinnerHtml = options.spinner || DEFAULT_SPINNER;
7864
+ const spinnerContainer = document.createElement("div");
7865
+ spinnerContainer.className = options.spinnerClass || "v-loading__spinner";
7866
+ spinnerContainer.innerHTML = spinnerHtml;
7867
+ overlay.appendChild(spinnerContainer);
7868
+ if (options.text) {
7869
+ const textEl = document.createElement("div");
7870
+ textEl.className = options.textClass || "v-loading__text";
7871
+ textEl.textContent = options.text;
7872
+ overlay.appendChild(textEl);
7873
+ }
7874
+ return overlay;
7875
+ }
7876
+ function useLoading(options = {}) {
7877
+ const {
7878
+ initial = false,
7879
+ text,
7880
+ loadingClass = "v-loading",
7881
+ spinnerClass = "v-loading__spinner",
7882
+ textClass = "v-loading__text",
7883
+ spinner,
7884
+ background = "rgba(255, 255, 255, 0.9)",
7885
+ lock = false
7886
+ } = options;
7887
+ const loading = vue.ref(vue.unref(initial));
7888
+ let currentElement = null, loadingOverlay = null, originalPosition = "", originalOverflow = "";
7889
+ function showLoading2() {
7890
+ if (!currentElement || loadingOverlay) return;
7891
+ loadingOverlay = createLoadingOverlay({
7892
+ text: vue.unref(text),
7893
+ loadingClass,
7894
+ spinnerClass,
7895
+ textClass,
7896
+ spinner,
7897
+ background
7898
+ });
7899
+ currentElement.appendChild(loadingOverlay);
7900
+ if (lock) {
7901
+ currentElement.style.overflow = "hidden";
7902
+ }
7903
+ currentElement.classList.add("v-loading--active");
7904
+ }
7905
+ function hideLoading2() {
7906
+ if (!currentElement || !loadingOverlay) return;
7907
+ loadingOverlay.remove();
7908
+ loadingOverlay = null;
7909
+ if (lock) {
7910
+ currentElement.style.overflow = originalOverflow;
7911
+ }
7912
+ currentElement.classList.remove("v-loading--active");
7913
+ }
7914
+ function start() {
7915
+ loading.value = true;
7916
+ }
7917
+ function stop() {
7918
+ loading.value = false;
7919
+ }
7920
+ function toggle() {
7921
+ loading.value = !loading.value;
7922
+ }
7923
+ function bind(element) {
7924
+ if (!isBrowser()) return () => {
7925
+ };
7926
+ unbind();
7927
+ currentElement = element;
7928
+ originalPosition = element.style.position;
7929
+ originalOverflow = element.style.overflow;
7930
+ const computedStyle = getComputedStyle(element);
7931
+ if (computedStyle.position === "static") {
7932
+ element.style.position = "relative";
7933
+ }
7934
+ if (loading.value) {
7935
+ showLoading2();
7936
+ }
7937
+ return unbind;
7938
+ }
7939
+ function unbind() {
7940
+ hideLoading2();
7941
+ if (currentElement) {
7942
+ currentElement.style.position = originalPosition;
7943
+ currentElement.style.overflow = originalOverflow;
7944
+ }
7945
+ currentElement = null;
7946
+ }
7947
+ vue.watch(loading, (newValue) => {
7948
+ if (newValue) {
7949
+ showLoading2();
7950
+ } else {
7951
+ hideLoading2();
7952
+ }
7953
+ });
7954
+ if (typeof text === "object" && "value" in text) {
7955
+ vue.watch(text, (newText) => {
7956
+ if (loadingOverlay) {
7957
+ const textEl = loadingOverlay.querySelector(`.${textClass}`);
7958
+ if (textEl) {
7959
+ textEl.textContent = newText || "";
7960
+ }
7961
+ }
7962
+ });
7963
+ }
7964
+ vue.onUnmounted(() => {
7965
+ unbind();
7966
+ });
7967
+ return {
7968
+ loading,
7969
+ start,
7970
+ stop,
7971
+ toggle,
7972
+ bind
7973
+ };
7974
+ }
7580
7975
  function getEventPosition(e) {
7581
7976
  if ("touches" in e && e.touches.length > 0) {
7582
7977
  return {
@@ -7720,40 +8115,183 @@ var __async = (__this, __arguments, generator) => {
7720
8115
  function createLowercaser(first = false) {
7721
8116
  return (text) => lowercaseText(text, first);
7722
8117
  }
7723
- function formatMoney(value, options = {}) {
8118
+ const TOKEN_PATTERNS = {
8119
+ "#": /\d/,
8120
+ A: /[A-Za-z]/,
8121
+ N: /[A-Za-z0-9]/,
8122
+ X: /./
8123
+ };
8124
+ function parseMask(mask, placeholder) {
8125
+ return [...mask].map((char) => {
8126
+ const pattern = TOKEN_PATTERNS[char];
8127
+ return pattern ? { pattern, placeholder, isLiteral: false } : { pattern: new RegExp(`\\${char}`), placeholder: char, isLiteral: true };
8128
+ });
8129
+ }
8130
+ function useMask(options) {
7724
8131
  const {
7725
- precision = 2,
7726
- separator = ",",
7727
- decimal = ".",
7728
- symbol = "$",
7729
- symbolPosition = "before"
8132
+ mask,
8133
+ placeholder = "_",
8134
+ showPlaceholder = true,
8135
+ showMaskOnBlur = false,
8136
+ clearIncomplete = false,
8137
+ disabled: _disabled = false,
8138
+ onChange,
8139
+ onComplete
7730
8140
  } = options;
7731
- const fixed = value.toFixed(precision);
7732
- const [intPart, decPart] = fixed.split(".");
7733
- const formattedInt = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
7734
- let result = formattedInt;
7735
- if (precision > 0 && decPart) {
7736
- result += decimal + decPart;
8141
+ let currentElement = null, inputHandler = null, focusHandler = null, blurHandler = null;
8142
+ function getTokens() {
8143
+ return parseMask(vue.unref(mask), placeholder);
8144
+ }
8145
+ function formatValue2(value, tokens, show) {
8146
+ let result = "", valueIndex = 0;
8147
+ for (const token of tokens) {
8148
+ if (valueIndex >= value.length) {
8149
+ result += token.isLiteral ? token.placeholder : show ? placeholder : "";
8150
+ continue;
8151
+ }
8152
+ const inputChar = value[valueIndex];
8153
+ if (token.isLiteral) {
8154
+ if (inputChar === token.placeholder) valueIndex++;
8155
+ result += token.placeholder;
8156
+ } else if (token.pattern.test(inputChar)) {
8157
+ result += inputChar;
8158
+ valueIndex++;
8159
+ } else if (inputChar === placeholder) {
8160
+ result += show ? placeholder : "";
8161
+ valueIndex++;
8162
+ } else {
8163
+ valueIndex++;
8164
+ }
8165
+ }
8166
+ return result;
7737
8167
  }
7738
- return symbolPosition === "before" ? symbol + result : result + symbol;
7739
- }
7740
- function parseMoney(formatted, options = {}) {
7741
- const { decimal = ".", symbol = "$" } = options;
7742
- let cleaned = formatted.replace(new RegExp(`[${symbol}\\s]`, "g"), "");
7743
- if (decimal !== ".") {
7744
- cleaned = cleaned.replace(/,/g, "");
7745
- cleaned = cleaned.replace(new RegExp(`\\${decimal}`, "g"), ".");
7746
- } else {
7747
- cleaned = cleaned.replace(/,/g, "");
8168
+ function getRawValue2(value, tokens) {
8169
+ let raw = "";
8170
+ for (let i = 0; i < value.length && i < tokens.length; i++) {
8171
+ if (!tokens[i].isLiteral && value[i] !== placeholder) {
8172
+ raw += value[i];
8173
+ }
8174
+ }
8175
+ return raw;
7748
8176
  }
7749
- return parseFloat(cleaned) || 0;
7750
- }
7751
- function useMoney(options) {
7752
- const {
7753
- value,
7754
- symbol = "$",
7755
- symbolPosition = "before",
7756
- precision = 2,
8177
+ function checkComplete(value, tokens) {
8178
+ for (let i = 0; i < tokens.length; i++) {
8179
+ if (!tokens[i].isLiteral && (i >= value.length || value[i] === placeholder)) {
8180
+ return false;
8181
+ }
8182
+ }
8183
+ return true;
8184
+ }
8185
+ function getCursorPos2(tokens, rawCursorPos) {
8186
+ let pos = rawCursorPos;
8187
+ while (pos < tokens.length && tokens[pos].isLiteral) {
8188
+ pos++;
8189
+ }
8190
+ return Math.min(pos, tokens.length);
8191
+ }
8192
+ function handleInput(e) {
8193
+ const target = e.target;
8194
+ const tokens = getTokens();
8195
+ const rawValue = target.value;
8196
+ const cursorPos = target.selectionStart || 0;
8197
+ const formatted = formatValue2(rawValue, tokens, showPlaceholder);
8198
+ if (formatted !== rawValue) {
8199
+ target.value = formatted;
8200
+ target.setSelectionRange(getCursorPos2(tokens, cursorPos), getCursorPos2(tokens, cursorPos));
8201
+ target.dispatchEvent(new Event("input", { bubbles: true }));
8202
+ return;
8203
+ }
8204
+ onChange == null ? void 0 : onChange(formatted, getRawValue2(formatted, tokens));
8205
+ if (checkComplete(formatted, tokens)) {
8206
+ onComplete == null ? void 0 : onComplete(formatted);
8207
+ }
8208
+ }
8209
+ function handleFocus() {
8210
+ if (!currentElement) return;
8211
+ const tokens = getTokens();
8212
+ if (!currentElement.value && showPlaceholder) {
8213
+ currentElement.value = formatValue2("", tokens, true);
8214
+ }
8215
+ }
8216
+ function handleBlur() {
8217
+ if (!currentElement) return;
8218
+ const tokens = getTokens();
8219
+ if (!showMaskOnBlur && !checkComplete(currentElement.value, tokens) && clearIncomplete) {
8220
+ currentElement.value = "";
8221
+ }
8222
+ }
8223
+ function bind(element) {
8224
+ if (!isBrowser()) return () => {
8225
+ };
8226
+ unbind();
8227
+ currentElement = element;
8228
+ inputHandler = handleInput;
8229
+ focusHandler = handleFocus;
8230
+ blurHandler = handleBlur;
8231
+ element.addEventListener("input", inputHandler);
8232
+ element.addEventListener("focus", focusHandler);
8233
+ element.addEventListener("blur", blurHandler);
8234
+ if (element.value) {
8235
+ const tokens = getTokens();
8236
+ element.value = formatValue2(element.value, tokens, showPlaceholder);
8237
+ }
8238
+ return unbind;
8239
+ }
8240
+ function unbind() {
8241
+ if (currentElement) {
8242
+ if (inputHandler) currentElement.removeEventListener("input", inputHandler);
8243
+ if (focusHandler) currentElement.removeEventListener("focus", focusHandler);
8244
+ if (blurHandler) currentElement.removeEventListener("blur", blurHandler);
8245
+ }
8246
+ currentElement = null;
8247
+ inputHandler = null;
8248
+ focusHandler = null;
8249
+ blurHandler = null;
8250
+ }
8251
+ vue.onUnmounted(() => {
8252
+ unbind();
8253
+ });
8254
+ return {
8255
+ getFormattedValue: (value) => formatValue2(value, getTokens(), showPlaceholder),
8256
+ getRawValue: (value) => getRawValue2(value, getTokens()),
8257
+ isComplete: (value) => checkComplete(value, getTokens()),
8258
+ bind
8259
+ };
8260
+ }
8261
+ function formatMoney(value, options = {}) {
8262
+ const {
8263
+ precision = 2,
8264
+ separator = ",",
8265
+ decimal = ".",
8266
+ symbol = "$",
8267
+ symbolPosition = "before"
8268
+ } = options;
8269
+ const fixed = value.toFixed(precision);
8270
+ const [intPart, decPart] = fixed.split(".");
8271
+ const formattedInt = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
8272
+ let result = formattedInt;
8273
+ if (precision > 0 && decPart) {
8274
+ result += decimal + decPart;
8275
+ }
8276
+ return symbolPosition === "before" ? symbol + result : result + symbol;
8277
+ }
8278
+ function parseMoney(formatted, options = {}) {
8279
+ const { decimal = ".", symbol = "$" } = options;
8280
+ let cleaned = formatted.replace(new RegExp(`[${symbol}\\s]`, "g"), "");
8281
+ if (decimal !== ".") {
8282
+ cleaned = cleaned.replace(/,/g, "");
8283
+ cleaned = cleaned.replace(new RegExp(`\\${decimal}`, "g"), ".");
8284
+ } else {
8285
+ cleaned = cleaned.replace(/,/g, "");
8286
+ }
8287
+ return parseFloat(cleaned) || 0;
8288
+ }
8289
+ function useMoney(options) {
8290
+ const {
8291
+ value,
8292
+ symbol = "$",
8293
+ symbolPosition = "before",
8294
+ precision = 2,
7757
8295
  separator = ",",
7758
8296
  decimal = "."
7759
8297
  } = options;
@@ -7791,6 +8329,68 @@ var __async = (__this, __arguments, generator) => {
7791
8329
  function createMoneyFormatter(options = {}) {
7792
8330
  return (value) => formatMoney(value, options);
7793
8331
  }
8332
+ function useMutation(options) {
8333
+ const {
8334
+ handler,
8335
+ attributes = false,
8336
+ attributeFilter,
8337
+ childList = true,
8338
+ subtree = false,
8339
+ characterData = false,
8340
+ attributeOldValue = false,
8341
+ characterDataOldValue = false,
8342
+ disabled = false
8343
+ } = options;
8344
+ let currentElement = null, observer = null;
8345
+ function createObserver2() {
8346
+ if (!isBrowser() || !supportsMutationObserver()) {
8347
+ console.warn("[Directix] useMutation: MutationObserver not supported");
8348
+ return null;
8349
+ }
8350
+ return new MutationObserver((mutations, obs) => {
8351
+ if (vue.unref(disabled)) return;
8352
+ handler(mutations, obs);
8353
+ });
8354
+ }
8355
+ function start() {
8356
+ if (!currentElement || !observer || vue.unref(disabled)) return;
8357
+ observer.observe(currentElement, {
8358
+ attributes,
8359
+ attributeFilter,
8360
+ childList,
8361
+ subtree,
8362
+ characterData,
8363
+ attributeOldValue,
8364
+ characterDataOldValue
8365
+ });
8366
+ }
8367
+ function stop() {
8368
+ if (observer) {
8369
+ observer.disconnect();
8370
+ }
8371
+ }
8372
+ function bind(element) {
8373
+ if (!isBrowser()) return () => {
8374
+ };
8375
+ stop();
8376
+ currentElement = element;
8377
+ observer = createObserver2();
8378
+ if (observer && !vue.unref(disabled)) {
8379
+ start();
8380
+ }
8381
+ return stop;
8382
+ }
8383
+ vue.onUnmounted(() => {
8384
+ stop();
8385
+ observer = null;
8386
+ currentElement = null;
8387
+ });
8388
+ return {
8389
+ bind,
8390
+ stop,
8391
+ start
8392
+ };
8393
+ }
7794
8394
  function formatNumber(value, options = {}) {
7795
8395
  const {
7796
8396
  precision = 0,
@@ -8314,6 +8914,206 @@ var __async = (__this, __arguments, generator) => {
8314
8914
  stop
8315
8915
  };
8316
8916
  }
8917
+ function createRippleElement(x, y, el, color, duration, initialScale, finalScale) {
8918
+ const rect = el.getBoundingClientRect();
8919
+ const size = Math.max(rect.width, rect.height) * 2;
8920
+ const ripple = document.createElement("span");
8921
+ ripple.className = "v-ripple__wave";
8922
+ ripple.style.cssText = `
8923
+ position: absolute;
8924
+ border-radius: 50%;
8925
+ pointer-events: none;
8926
+ background-color: ${color};
8927
+ width: ${size}px;
8928
+ height: ${size}px;
8929
+ left: ${x - size / 2}px;
8930
+ top: ${y - size / 2}px;
8931
+ transform: scale(${initialScale});
8932
+ opacity: 0.3;
8933
+ z-index: 0;
8934
+ `;
8935
+ if (typeof ripple.animate === "function") {
8936
+ ripple.animate(
8937
+ [
8938
+ { transform: `scale(${initialScale})`, opacity: 0.3 },
8939
+ { transform: `scale(${finalScale})`, opacity: 0 }
8940
+ ],
8941
+ {
8942
+ duration,
8943
+ easing: "ease-out",
8944
+ fill: "forwards"
8945
+ }
8946
+ ).onfinish = () => {
8947
+ ripple.remove();
8948
+ };
8949
+ } else {
8950
+ ripple.style.transition = `transform ${duration}ms ease-out, opacity ${duration}ms ease-out`;
8951
+ String(ripple.offsetHeight);
8952
+ ripple.style.transform = `scale(${finalScale})`;
8953
+ ripple.style.opacity = "0";
8954
+ setTimeout(() => ripple.remove(), duration);
8955
+ }
8956
+ return ripple;
8957
+ }
8958
+ function useRipple(options = {}) {
8959
+ const {
8960
+ color = "currentColor",
8961
+ duration = 600,
8962
+ disabled = false,
8963
+ initialScale = 0,
8964
+ finalScale = 2
8965
+ } = options;
8966
+ let currentElement = null, clickHandler = null;
8967
+ function handleClick(event) {
8968
+ if (vue.unref(disabled)) return;
8969
+ const currentColor = vue.unref(color);
8970
+ const currentDuration = vue.unref(duration);
8971
+ const ripple = createRippleElement(
8972
+ event.clientX - currentElement.getBoundingClientRect().left,
8973
+ event.clientY - currentElement.getBoundingClientRect().top,
8974
+ currentElement,
8975
+ currentColor,
8976
+ currentDuration,
8977
+ initialScale,
8978
+ finalScale
8979
+ );
8980
+ currentElement.appendChild(ripple);
8981
+ }
8982
+ function trigger(event) {
8983
+ var _a, _b;
8984
+ if (!currentElement || vue.unref(disabled)) return;
8985
+ const rect = currentElement.getBoundingClientRect();
8986
+ const x = (_a = event == null ? void 0 : event.x) != null ? _a : rect.width / 2;
8987
+ const y = (_b = event == null ? void 0 : event.y) != null ? _b : rect.height / 2;
8988
+ const ripple = createRippleElement(
8989
+ x,
8990
+ y,
8991
+ currentElement,
8992
+ vue.unref(color),
8993
+ vue.unref(duration),
8994
+ initialScale,
8995
+ finalScale
8996
+ );
8997
+ currentElement.appendChild(ripple);
8998
+ }
8999
+ function bind(element) {
9000
+ if (!isBrowser()) return () => {
9001
+ };
9002
+ unbind();
9003
+ currentElement = element;
9004
+ const computedStyle = getComputedStyle(element);
9005
+ if (computedStyle.position === "static") {
9006
+ element.style.position = "relative";
9007
+ }
9008
+ if (computedStyle.overflow === "visible") {
9009
+ element.style.overflow = "hidden";
9010
+ }
9011
+ element.classList.add("v-ripple");
9012
+ clickHandler = handleClick;
9013
+ element.addEventListener("click", clickHandler);
9014
+ return unbind;
9015
+ }
9016
+ function unbind() {
9017
+ if (currentElement && clickHandler) {
9018
+ currentElement.removeEventListener("click", clickHandler);
9019
+ currentElement.classList.remove("v-ripple");
9020
+ }
9021
+ currentElement = null;
9022
+ clickHandler = null;
9023
+ }
9024
+ vue.onUnmounted(() => {
9025
+ unbind();
9026
+ });
9027
+ return {
9028
+ bind,
9029
+ trigger
9030
+ };
9031
+ }
9032
+ const DEFAULT_ALLOWED_TAGS = ["b", "i", "u", "strong", "em", "br", "p", "span", "div"];
9033
+ const DEFAULT_ALLOWED_ATTRIBUTES = ["title", "alt", "href", "src"];
9034
+ const DANGEROUS_TAGS = ["script", "iframe", "object", "embed", "form", "input", "style", "link", "meta", "base"];
9035
+ const DANGEROUS_ATTRIBUTES = ["onclick", "onerror", "onload", "onmouseover", "onfocus", "onblur", "onchange", "onsubmit"];
9036
+ function useSanitize(options = {}) {
9037
+ const {
9038
+ allowedTags = DEFAULT_ALLOWED_TAGS,
9039
+ allowedAttributes = DEFAULT_ALLOWED_ATTRIBUTES,
9040
+ allowDataUrls = false,
9041
+ allowStyles = false,
9042
+ allowClass = false,
9043
+ allowId = false,
9044
+ handler
9045
+ } = options;
9046
+ function sanitizeHtml2(html) {
9047
+ var _a;
9048
+ if (handler) {
9049
+ return handler(html);
9050
+ }
9051
+ if (!isBrowser()) return html;
9052
+ const temp = document.createElement("div");
9053
+ temp.innerHTML = html;
9054
+ for (const tag of DANGEROUS_TAGS) {
9055
+ const elements = temp.getElementsByTagName(tag);
9056
+ while (elements.length > 0) {
9057
+ (_a = elements[0].parentNode) == null ? void 0 : _a.removeChild(elements[0]);
9058
+ }
9059
+ }
9060
+ const processElement = (el) => {
9061
+ var _a2;
9062
+ const tagName = el.tagName.toLowerCase();
9063
+ if (!allowedTags.includes(tagName)) {
9064
+ const text = document.createTextNode(el.textContent || "");
9065
+ (_a2 = el.parentNode) == null ? void 0 : _a2.replaceChild(text, el);
9066
+ return;
9067
+ }
9068
+ for (const attr of DANGEROUS_ATTRIBUTES) {
9069
+ el.removeAttribute(attr);
9070
+ }
9071
+ const href = el.getAttribute("href");
9072
+ if (href && href.toLowerCase().startsWith("javascript:")) {
9073
+ el.removeAttribute("href");
9074
+ }
9075
+ if (!allowDataUrls) {
9076
+ const src = el.getAttribute("src");
9077
+ if (src && src.toLowerCase().startsWith("data:")) {
9078
+ el.removeAttribute("src");
9079
+ }
9080
+ }
9081
+ const attrs = Array.from(el.attributes);
9082
+ for (const attr of attrs) {
9083
+ const isAllowed = allowedAttributes.includes(attr.name.toLowerCase());
9084
+ const isClass = attr.name === "class" && allowClass;
9085
+ const isId = attr.name === "id" && allowId;
9086
+ const isStyle = attr.name === "style" && allowStyles;
9087
+ if (!isAllowed && !isClass && !isId && !isStyle) {
9088
+ el.removeAttribute(attr.name);
9089
+ }
9090
+ }
9091
+ for (const child of Array.from(el.children)) {
9092
+ processElement(child);
9093
+ }
9094
+ };
9095
+ for (const child of Array.from(temp.children)) {
9096
+ processElement(child);
9097
+ }
9098
+ return temp.innerHTML;
9099
+ }
9100
+ function bind(element) {
9101
+ if (!isBrowser()) return () => {
9102
+ };
9103
+ const content = element.innerHTML;
9104
+ if (content) {
9105
+ element.innerHTML = sanitizeHtml2(content);
9106
+ }
9107
+ return () => {
9108
+ };
9109
+ }
9110
+ vue.onUnmounted(() => {
9111
+ });
9112
+ return {
9113
+ sanitize: sanitizeHtml2,
9114
+ bind
9115
+ };
9116
+ }
8317
9117
  function getScrollInfoFromContainer(container, lastScrollLeft, lastScrollTop) {
8318
9118
  let scrollLeft = 0, scrollTop = 0, scrollLeftMax = 0, scrollTopMax = 0;
8319
9119
  if (container === window) {
@@ -8462,6 +9262,97 @@ var __async = (__this, __arguments, generator) => {
8462
9262
  scrollTo
8463
9263
  };
8464
9264
  }
9265
+ function useSticky(options = {}) {
9266
+ const {
9267
+ offsetTop = 0,
9268
+ onStick,
9269
+ disabled = false
9270
+ } = options;
9271
+ const isSticky = vue.ref(false);
9272
+ let currentElement = null, scrollContainer = null, scrollHandler = null, placeholder = null, originalStyles = null;
9273
+ function checkSticky2() {
9274
+ var _a;
9275
+ if (!currentElement || vue.unref(disabled)) return;
9276
+ const container = scrollContainer === window ? document.documentElement : scrollContainer;
9277
+ const containerRect = container.getBoundingClientRect();
9278
+ const elementRect = currentElement.getBoundingClientRect();
9279
+ const currentOffsetTop = vue.unref(offsetTop);
9280
+ const shouldBeSticky = elementRect.top <= currentOffsetTop && containerRect.top <= currentOffsetTop;
9281
+ if (shouldBeSticky !== isSticky.value) {
9282
+ isSticky.value = shouldBeSticky;
9283
+ if (shouldBeSticky) {
9284
+ if (!placeholder) {
9285
+ placeholder = document.createElement("div");
9286
+ placeholder.style.width = `${elementRect.width}px`;
9287
+ placeholder.style.height = `${elementRect.height}px`;
9288
+ (_a = currentElement.parentNode) == null ? void 0 : _a.insertBefore(placeholder, currentElement);
9289
+ }
9290
+ currentElement.style.position = "fixed";
9291
+ currentElement.style.top = `${currentOffsetTop}px`;
9292
+ currentElement.style.width = `${elementRect.width}px`;
9293
+ currentElement.classList.add("v-sticky--active");
9294
+ } else {
9295
+ if (placeholder) {
9296
+ placeholder.remove();
9297
+ placeholder = null;
9298
+ }
9299
+ if (originalStyles) {
9300
+ currentElement.style.position = originalStyles.position;
9301
+ currentElement.style.top = originalStyles.top;
9302
+ currentElement.style.width = originalStyles.width;
9303
+ }
9304
+ currentElement.classList.remove("v-sticky--active");
9305
+ }
9306
+ onStick == null ? void 0 : onStick(shouldBeSticky);
9307
+ }
9308
+ }
9309
+ function bind(element) {
9310
+ if (!isBrowser()) return () => {
9311
+ };
9312
+ stop();
9313
+ currentElement = element;
9314
+ originalStyles = {
9315
+ position: element.style.position,
9316
+ top: element.style.top,
9317
+ width: element.style.width
9318
+ };
9319
+ element.classList.add("v-sticky");
9320
+ scrollContainer = getScrollParent(element);
9321
+ scrollHandler = checkSticky2;
9322
+ scrollContainer.addEventListener("scroll", scrollHandler, { passive: true });
9323
+ checkSticky2();
9324
+ return stop;
9325
+ }
9326
+ function stop() {
9327
+ if (scrollContainer && scrollHandler) {
9328
+ scrollContainer.removeEventListener("scroll", scrollHandler);
9329
+ }
9330
+ if (currentElement) {
9331
+ if (originalStyles) {
9332
+ currentElement.style.position = originalStyles.position;
9333
+ currentElement.style.top = originalStyles.top;
9334
+ currentElement.style.width = originalStyles.width;
9335
+ }
9336
+ currentElement.classList.remove("v-sticky", "v-sticky--active");
9337
+ }
9338
+ if (placeholder) {
9339
+ placeholder.remove();
9340
+ placeholder = null;
9341
+ }
9342
+ scrollContainer = null;
9343
+ scrollHandler = null;
9344
+ currentElement = null;
9345
+ isSticky.value = false;
9346
+ }
9347
+ vue.onUnmounted(() => {
9348
+ stop();
9349
+ });
9350
+ return {
9351
+ isSticky: vue.readonly(isSticky),
9352
+ bind,
9353
+ stop
9354
+ };
9355
+ }
8465
9356
  const DEFAULT_DIRECTIONS = ["left", "right", "up", "down"];
8466
9357
  function getSwipeDirection(deltaX, deltaY, allowedDirections) {
8467
9358
  const absX = Math.abs(deltaX);
@@ -8662,6 +9553,167 @@ var __async = (__this, __arguments, generator) => {
8662
9553
  function throttleFn(fn, wait = 300, options) {
8663
9554
  return throttle(fn, wait, options);
8664
9555
  }
9556
+ function useTooltip(options = {}) {
9557
+ const {
9558
+ content,
9559
+ placement = "top",
9560
+ trigger = "hover",
9561
+ delay = 0,
9562
+ hideDelay = 0,
9563
+ arrow = true,
9564
+ class: customClass,
9565
+ onShow,
9566
+ onHide,
9567
+ disabled = false
9568
+ } = options;
9569
+ const isVisible = vue.ref(false);
9570
+ let currentElement = null, tooltipEl = null, showTimeout = null, hideTimeout = null;
9571
+ const eventHandlers = {};
9572
+ function createTooltip2() {
9573
+ const tooltip = document.createElement("div");
9574
+ tooltip.className = `v-tooltip v-tooltip--${placement}${customClass ? ` ${customClass}` : ""}${arrow ? " v-tooltip--arrow" : ""}`;
9575
+ tooltip.style.cssText = `
9576
+ position: absolute;
9577
+ z-index: 9999;
9578
+ opacity: 0;
9579
+ transition: opacity 0.2s;
9580
+ pointer-events: none;
9581
+ `;
9582
+ return tooltip;
9583
+ }
9584
+ function positionTooltip2() {
9585
+ if (!tooltipEl || !currentElement) return;
9586
+ const elementRect = currentElement.getBoundingClientRect();
9587
+ const tooltipRect = tooltipEl.getBoundingClientRect();
9588
+ let top = 0, left = 0;
9589
+ switch (placement) {
9590
+ case "top":
9591
+ top = elementRect.top - tooltipRect.height - 8;
9592
+ left = elementRect.left + (elementRect.width - tooltipRect.width) / 2;
9593
+ break;
9594
+ case "bottom":
9595
+ top = elementRect.bottom + 8;
9596
+ left = elementRect.left + (elementRect.width - tooltipRect.width) / 2;
9597
+ break;
9598
+ case "left":
9599
+ top = elementRect.top + (elementRect.height - tooltipRect.height) / 2;
9600
+ left = elementRect.left - tooltipRect.width - 8;
9601
+ break;
9602
+ case "right":
9603
+ top = elementRect.top + (elementRect.height - tooltipRect.height) / 2;
9604
+ left = elementRect.right + 8;
9605
+ break;
9606
+ }
9607
+ if (left < 0) left = 8;
9608
+ if (left + tooltipRect.width > window.innerWidth) left = window.innerWidth - tooltipRect.width - 8;
9609
+ if (top < 0) top = 8;
9610
+ if (top + tooltipRect.height > window.innerHeight) top = window.innerHeight - tooltipRect.height - 8;
9611
+ tooltipEl.style.top = `${top + window.scrollY}px`;
9612
+ tooltipEl.style.left = `${left + window.scrollX}px`;
9613
+ }
9614
+ function show() {
9615
+ if (vue.unref(disabled) || !content) return;
9616
+ if (hideTimeout) {
9617
+ clearTimeout(hideTimeout);
9618
+ hideTimeout = null;
9619
+ }
9620
+ if (delay > 0) {
9621
+ showTimeout = setTimeout(doShow, delay);
9622
+ } else {
9623
+ doShow();
9624
+ }
9625
+ }
9626
+ function doShow() {
9627
+ var _a;
9628
+ if (!currentElement) return;
9629
+ if (!tooltipEl) {
9630
+ tooltipEl = createTooltip2();
9631
+ document.body.appendChild(tooltipEl);
9632
+ }
9633
+ tooltipEl.textContent = (_a = vue.unref(content)) != null ? _a : null;
9634
+ positionTooltip2();
9635
+ tooltipEl.style.opacity = "1";
9636
+ isVisible.value = true;
9637
+ onShow == null ? void 0 : onShow();
9638
+ }
9639
+ function hide() {
9640
+ if (showTimeout) {
9641
+ clearTimeout(showTimeout);
9642
+ showTimeout = null;
9643
+ }
9644
+ if (hideDelay > 0) {
9645
+ hideTimeout = setTimeout(doHide, hideDelay);
9646
+ } else {
9647
+ doHide();
9648
+ }
9649
+ }
9650
+ function doHide() {
9651
+ if (tooltipEl) {
9652
+ tooltipEl.style.opacity = "0";
9653
+ }
9654
+ isVisible.value = false;
9655
+ onHide == null ? void 0 : onHide();
9656
+ }
9657
+ function toggle() {
9658
+ if (isVisible.value) {
9659
+ hide();
9660
+ } else {
9661
+ show();
9662
+ }
9663
+ }
9664
+ function bind(element) {
9665
+ if (!isBrowser()) return () => {
9666
+ };
9667
+ unbind();
9668
+ currentElement = element;
9669
+ if (trigger === "hover") {
9670
+ eventHandlers.mouseenter = show;
9671
+ eventHandlers.mouseleave = hide;
9672
+ element.addEventListener("mouseenter", eventHandlers.mouseenter);
9673
+ element.addEventListener("mouseleave", eventHandlers.mouseleave);
9674
+ } else if (trigger === "click") {
9675
+ eventHandlers.click = toggle;
9676
+ element.addEventListener("click", eventHandlers.click);
9677
+ } else if (trigger === "focus") {
9678
+ eventHandlers.focus = show;
9679
+ eventHandlers.blur = hide;
9680
+ element.addEventListener("focus", eventHandlers.focus);
9681
+ element.addEventListener("blur", eventHandlers.blur);
9682
+ }
9683
+ return unbind;
9684
+ }
9685
+ function unbind() {
9686
+ if (currentElement) {
9687
+ Object.entries(eventHandlers).forEach(([event, handler]) => {
9688
+ currentElement.removeEventListener(event, handler);
9689
+ });
9690
+ }
9691
+ if (tooltipEl) {
9692
+ tooltipEl.remove();
9693
+ tooltipEl = null;
9694
+ }
9695
+ if (showTimeout) {
9696
+ clearTimeout(showTimeout);
9697
+ showTimeout = null;
9698
+ }
9699
+ if (hideTimeout) {
9700
+ clearTimeout(hideTimeout);
9701
+ hideTimeout = null;
9702
+ }
9703
+ currentElement = null;
9704
+ isVisible.value = false;
9705
+ }
9706
+ vue.onUnmounted(() => {
9707
+ unbind();
9708
+ });
9709
+ return {
9710
+ isVisible: vue.readonly(isVisible),
9711
+ show,
9712
+ hide,
9713
+ toggle,
9714
+ bind
9715
+ };
9716
+ }
8665
9717
  function useTouch(options = {}) {
8666
9718
  const {
8667
9719
  onSwipe,
@@ -8841,6 +9893,7 @@ var __async = (__this, __arguments, generator) => {
8841
9893
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8842
9894
  }
8843
9895
  function trimText(text, position = "both", chars) {
9896
+ if (!text) return "";
8844
9897
  const charPattern = chars ? `[\\s${escapeRegex(chars)}]` : "\\s";
8845
9898
  switch (position) {
8846
9899
  case "start":
@@ -8883,6 +9936,74 @@ var __async = (__this, __arguments, generator) => {
8883
9936
  function createTrimmer(position = "both", chars) {
8884
9937
  return (text) => trimText(text, position, chars);
8885
9938
  }
9939
+ function truncateEnd(text, length, omission) {
9940
+ if (text.length <= length) return text;
9941
+ return text.slice(0, length - omission.length) + omission;
9942
+ }
9943
+ function truncateStart(text, length, omission) {
9944
+ if (text.length <= length) return text;
9945
+ return omission + text.slice(-(length - omission.length));
9946
+ }
9947
+ function truncateMiddle(text, length, omission) {
9948
+ if (text.length <= length) return text;
9949
+ const availableLength = length - omission.length;
9950
+ const startLength = Math.ceil(availableLength / 2);
9951
+ const endLength = Math.floor(availableLength / 2);
9952
+ return text.slice(0, startLength) + omission + text.slice(-endLength);
9953
+ }
9954
+ function useTruncate(options) {
9955
+ const {
9956
+ text,
9957
+ length = 100,
9958
+ position = "end",
9959
+ omission = "..."
9960
+ } = options;
9961
+ const truncated = vue.ref("");
9962
+ const isTruncated = vue.ref(false);
9963
+ const originalLength = vue.ref(0);
9964
+ function truncate(textValue, lengthValue, positionValue) {
9965
+ const maxLen = lengthValue != null ? lengthValue : vue.unref(length);
9966
+ const pos = positionValue != null ? positionValue : vue.unref(position);
9967
+ if (textValue.length <= maxLen) {
9968
+ return textValue;
9969
+ }
9970
+ switch (pos) {
9971
+ case "start":
9972
+ return truncateStart(textValue, maxLen, omission);
9973
+ case "middle":
9974
+ return truncateMiddle(textValue, maxLen, omission);
9975
+ case "end":
9976
+ default:
9977
+ return truncateEnd(textValue, maxLen, omission);
9978
+ }
9979
+ }
9980
+ function update() {
9981
+ const textValue = vue.unref(text);
9982
+ const lengthValue = vue.unref(length);
9983
+ originalLength.value = textValue.length;
9984
+ isTruncated.value = textValue.length > lengthValue;
9985
+ truncated.value = truncate(textValue);
9986
+ }
9987
+ vue.watch(
9988
+ () => vue.unref(text),
9989
+ update,
9990
+ { immediate: true }
9991
+ );
9992
+ vue.watch(
9993
+ () => vue.unref(length),
9994
+ update
9995
+ );
9996
+ vue.watch(
9997
+ () => vue.unref(position),
9998
+ update
9999
+ );
10000
+ return {
10001
+ truncated: vue.readonly(truncated),
10002
+ isTruncated: vue.readonly(isTruncated),
10003
+ originalLength: vue.readonly(originalLength),
10004
+ truncate
10005
+ };
10006
+ }
8886
10007
  function uppercaseText(text, firstOnly = false) {
8887
10008
  if (!text) return text;
8888
10009
  if (firstOnly) {
@@ -9381,6 +10502,7 @@ var __async = (__this, __arguments, generator) => {
9381
10502
  exports.calculateTime = calculateTime;
9382
10503
  exports.capitalizeText = capitalizeText;
9383
10504
  exports.capitalizeWord = capitalizeWord;
10505
+ exports.configurePermission = configurePermission;
9384
10506
  exports.createCapitalizer = createCapitalizer;
9385
10507
  exports.createDelayedClick = createDelayedClick;
9386
10508
  exports.createLowercaser = createLowercaser;
@@ -9402,6 +10524,7 @@ var __async = (__this, __arguments, generator) => {
9402
10524
  exports.formatTime = formatTime;
9403
10525
  exports.generateId = generateId;
9404
10526
  exports.get = get;
10527
+ exports.getPermissionConfig = getPermissionConfig;
9405
10528
  exports.getVueVersion = getVueVersion;
9406
10529
  exports.isArray = isArray;
9407
10530
  exports.isBoolean = isBoolean;
@@ -9446,20 +10569,30 @@ var __async = (__this, __arguments, generator) => {
9446
10569
  exports.useHotkey = useHotkey;
9447
10570
  exports.useHover = useHover;
9448
10571
  exports.useImagePreview = useImagePreview;
10572
+ exports.useInfiniteScroll = useInfiniteScroll;
9449
10573
  exports.useIntersect = useIntersect;
10574
+ exports.useLazy = useLazy;
10575
+ exports.useLoading = useLoading;
9450
10576
  exports.useLongPress = useLongPress;
9451
10577
  exports.useLowercase = useLowercase;
10578
+ exports.useMask = useMask;
9452
10579
  exports.useMoney = useMoney;
10580
+ exports.useMutation = useMutation;
9453
10581
  exports.useNumber = useNumber;
9454
10582
  exports.usePermission = usePermission;
9455
10583
  exports.usePrint = usePrint;
9456
10584
  exports.usePullRefresh = usePullRefresh;
9457
10585
  exports.useResize = useResize;
10586
+ exports.useRipple = useRipple;
10587
+ exports.useSanitize = useSanitize;
9458
10588
  exports.useScroll = useScroll;
10589
+ exports.useSticky = useSticky;
9459
10590
  exports.useSwipe = useSwipe;
9460
10591
  exports.useThrottle = useThrottle;
10592
+ exports.useTooltip = useTooltip;
9461
10593
  exports.useTouch = useTouch;
9462
10594
  exports.useTrim = useTrim;
10595
+ exports.useTruncate = useTruncate;
9463
10596
  exports.useUppercase = useUppercase;
9464
10597
  exports.useVirtualList = useVirtualList;
9465
10598
  exports.useVisible = useVisible;