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