directix 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/index.cjs +1790 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +829 -0
- package/dist/index.iife.js +1962 -198
- package/dist/index.iife.js.map +1 -1
- package/dist/index.iife.min.js +2 -2
- package/dist/index.mjs +1791 -27
- package/dist/index.mjs.map +1 -1
- package/dist/nuxt/index.cjs +1 -1
- package/dist/nuxt/index.d.ts +1 -1
- package/dist/nuxt/index.mjs +1 -1
- package/dist/nuxt/runtime/plugin.mjs +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* directix v1.
|
|
2
|
+
* directix v1.10.0
|
|
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.
|
|
@@ -79,7 +79,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
79
79
|
});
|
|
80
80
|
};
|
|
81
81
|
/*!
|
|
82
|
-
* directix v1.
|
|
82
|
+
* directix v1.10.0
|
|
83
83
|
* A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3
|
|
84
84
|
* (c) 2021-present saqqdy <https://github.com/saqqdy>
|
|
85
85
|
* Released under the MIT License.
|
|
@@ -7193,23 +7193,23 @@ function handleEnd(e, state2, el) {
|
|
|
7193
7193
|
state2.initialAngle = 0;
|
|
7194
7194
|
state2.currentAngle = 0;
|
|
7195
7195
|
}
|
|
7196
|
-
const DEFAULT_ALLOWED_TAGS$
|
|
7197
|
-
const DEFAULT_ALLOWED_ATTRIBUTES$
|
|
7198
|
-
const DANGEROUS_TAGS$
|
|
7199
|
-
const DANGEROUS_ATTRIBUTES$
|
|
7196
|
+
const DEFAULT_ALLOWED_TAGS$2 = ["b", "i", "u", "strong", "em", "br", "p", "span", "div"];
|
|
7197
|
+
const DEFAULT_ALLOWED_ATTRIBUTES$2 = ["title", "alt", "href", "src"];
|
|
7198
|
+
const DANGEROUS_TAGS$2 = ["script", "iframe", "object", "embed", "form", "input", "style", "link", "meta", "base"];
|
|
7199
|
+
const DANGEROUS_ATTRIBUTES$2 = ["onclick", "onerror", "onload", "onmouseover", "onfocus", "onblur", "onchange", "onsubmit"];
|
|
7200
7200
|
function normalizeOptions$e(binding) {
|
|
7201
7201
|
if (binding === false) {
|
|
7202
7202
|
return { disabled: true };
|
|
7203
7203
|
}
|
|
7204
7204
|
if (binding === true) {
|
|
7205
7205
|
return {
|
|
7206
|
-
allowedTags: DEFAULT_ALLOWED_TAGS$
|
|
7207
|
-
allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES$
|
|
7206
|
+
allowedTags: DEFAULT_ALLOWED_TAGS$2,
|
|
7207
|
+
allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES$2
|
|
7208
7208
|
};
|
|
7209
7209
|
}
|
|
7210
7210
|
return __spreadValues({
|
|
7211
|
-
allowedTags: DEFAULT_ALLOWED_TAGS$
|
|
7212
|
-
allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES$
|
|
7211
|
+
allowedTags: DEFAULT_ALLOWED_TAGS$2,
|
|
7212
|
+
allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES$2,
|
|
7213
7213
|
allowDataUrls: false,
|
|
7214
7214
|
allowStyles: false,
|
|
7215
7215
|
allowClass: false,
|
|
@@ -7218,14 +7218,14 @@ function normalizeOptions$e(binding) {
|
|
|
7218
7218
|
sanitizeOnUpdate: true
|
|
7219
7219
|
}, binding);
|
|
7220
7220
|
}
|
|
7221
|
-
function sanitizeHtml(html, options) {
|
|
7221
|
+
function sanitizeHtml$1(html, options) {
|
|
7222
7222
|
var _a2;
|
|
7223
7223
|
if (options.handler) {
|
|
7224
7224
|
return options.handler(html);
|
|
7225
7225
|
}
|
|
7226
7226
|
const temp = document.createElement("div");
|
|
7227
7227
|
temp.innerHTML = html;
|
|
7228
|
-
for (const tag of DANGEROUS_TAGS$
|
|
7228
|
+
for (const tag of DANGEROUS_TAGS$2) {
|
|
7229
7229
|
const elements = temp.getElementsByTagName(tag);
|
|
7230
7230
|
while (elements.length > 0) {
|
|
7231
7231
|
(_a2 = elements[0].parentNode) == null ? void 0 : _a2.removeChild(elements[0]);
|
|
@@ -7239,7 +7239,7 @@ function sanitizeHtml(html, options) {
|
|
|
7239
7239
|
(_a3 = el.parentNode) == null ? void 0 : _a3.replaceChild(text, el);
|
|
7240
7240
|
return;
|
|
7241
7241
|
}
|
|
7242
|
-
for (const attr of DANGEROUS_ATTRIBUTES$
|
|
7242
|
+
for (const attr of DANGEROUS_ATTRIBUTES$2) {
|
|
7243
7243
|
el.removeAttribute(attr);
|
|
7244
7244
|
}
|
|
7245
7245
|
const href = el.getAttribute("href");
|
|
@@ -7277,8 +7277,8 @@ const vSanitize = defineDirective({
|
|
|
7277
7277
|
name: "sanitize",
|
|
7278
7278
|
ssr: true,
|
|
7279
7279
|
defaults: {
|
|
7280
|
-
allowedTags: DEFAULT_ALLOWED_TAGS$
|
|
7281
|
-
allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES$
|
|
7280
|
+
allowedTags: DEFAULT_ALLOWED_TAGS$2,
|
|
7281
|
+
allowedAttributes: DEFAULT_ALLOWED_ATTRIBUTES$2,
|
|
7282
7282
|
allowDataUrls: false,
|
|
7283
7283
|
allowStyles: false,
|
|
7284
7284
|
allowClass: false,
|
|
@@ -7293,7 +7293,7 @@ const vSanitize = defineDirective({
|
|
|
7293
7293
|
if (options.disabled) return;
|
|
7294
7294
|
const content = el.innerHTML;
|
|
7295
7295
|
if (content) {
|
|
7296
|
-
el.innerHTML = sanitizeHtml(content, options);
|
|
7296
|
+
el.innerHTML = sanitizeHtml$1(content, options);
|
|
7297
7297
|
}
|
|
7298
7298
|
},
|
|
7299
7299
|
updated(el, binding) {
|
|
@@ -7305,14 +7305,14 @@ const vSanitize = defineDirective({
|
|
|
7305
7305
|
if (prevDisabled && !state2.options.disabled) {
|
|
7306
7306
|
const content2 = el.innerHTML;
|
|
7307
7307
|
if (content2) {
|
|
7308
|
-
el.innerHTML = sanitizeHtml(content2, state2.options);
|
|
7308
|
+
el.innerHTML = sanitizeHtml$1(content2, state2.options);
|
|
7309
7309
|
}
|
|
7310
7310
|
}
|
|
7311
7311
|
return;
|
|
7312
7312
|
}
|
|
7313
7313
|
const content = el.innerHTML;
|
|
7314
7314
|
if (content) {
|
|
7315
|
-
el.innerHTML = sanitizeHtml(content, state2.options);
|
|
7315
|
+
el.innerHTML = sanitizeHtml$1(content, state2.options);
|
|
7316
7316
|
}
|
|
7317
7317
|
},
|
|
7318
7318
|
unmounted(el) {
|
|
@@ -13720,14 +13720,14 @@ function useRotateGesture(options = {}) {
|
|
|
13720
13720
|
bind
|
|
13721
13721
|
};
|
|
13722
13722
|
}
|
|
13723
|
-
const DEFAULT_ALLOWED_TAGS = ["b", "i", "u", "strong", "em", "br", "p", "span", "div"];
|
|
13724
|
-
const DEFAULT_ALLOWED_ATTRIBUTES = ["title", "alt", "href", "src"];
|
|
13725
|
-
const DANGEROUS_TAGS = ["script", "iframe", "object", "embed", "form", "input", "style", "link", "meta", "base"];
|
|
13726
|
-
const DANGEROUS_ATTRIBUTES = ["onclick", "onerror", "onload", "onmouseover", "onfocus", "onblur", "onchange", "onsubmit"];
|
|
13723
|
+
const DEFAULT_ALLOWED_TAGS$1 = ["b", "i", "u", "strong", "em", "br", "p", "span", "div"];
|
|
13724
|
+
const DEFAULT_ALLOWED_ATTRIBUTES$1 = ["title", "alt", "href", "src"];
|
|
13725
|
+
const DANGEROUS_TAGS$1 = ["script", "iframe", "object", "embed", "form", "input", "style", "link", "meta", "base"];
|
|
13726
|
+
const DANGEROUS_ATTRIBUTES$1 = ["onclick", "onerror", "onload", "onmouseover", "onfocus", "onblur", "onchange", "onsubmit"];
|
|
13727
13727
|
function useSanitize(options = {}) {
|
|
13728
13728
|
const {
|
|
13729
|
-
allowedTags = DEFAULT_ALLOWED_TAGS,
|
|
13730
|
-
allowedAttributes = DEFAULT_ALLOWED_ATTRIBUTES,
|
|
13729
|
+
allowedTags = DEFAULT_ALLOWED_TAGS$1,
|
|
13730
|
+
allowedAttributes = DEFAULT_ALLOWED_ATTRIBUTES$1,
|
|
13731
13731
|
allowDataUrls = false,
|
|
13732
13732
|
allowStyles = false,
|
|
13733
13733
|
allowClass = false,
|
|
@@ -13742,7 +13742,7 @@ function useSanitize(options = {}) {
|
|
|
13742
13742
|
if (!isBrowser()) return html;
|
|
13743
13743
|
const temp = document.createElement("div");
|
|
13744
13744
|
temp.innerHTML = html;
|
|
13745
|
-
for (const tag of DANGEROUS_TAGS) {
|
|
13745
|
+
for (const tag of DANGEROUS_TAGS$1) {
|
|
13746
13746
|
const elements = temp.getElementsByTagName(tag);
|
|
13747
13747
|
while (elements.length > 0) {
|
|
13748
13748
|
(_a2 = elements[0].parentNode) == null ? void 0 : _a2.removeChild(elements[0]);
|
|
@@ -13756,7 +13756,7 @@ function useSanitize(options = {}) {
|
|
|
13756
13756
|
(_a3 = el.parentNode) == null ? void 0 : _a3.replaceChild(text, el);
|
|
13757
13757
|
return;
|
|
13758
13758
|
}
|
|
13759
|
-
for (const attr of DANGEROUS_ATTRIBUTES) {
|
|
13759
|
+
for (const attr of DANGEROUS_ATTRIBUTES$1) {
|
|
13760
13760
|
el.removeAttribute(attr);
|
|
13761
13761
|
}
|
|
13762
13762
|
const href = el.getAttribute("href");
|
|
@@ -15792,6 +15792,1734 @@ function createStyleDirective(options) {
|
|
|
15792
15792
|
}
|
|
15793
15793
|
});
|
|
15794
15794
|
}
|
|
15795
|
+
function applyAriaAttributes(el, config) {
|
|
15796
|
+
clearAriaAttributes(el);
|
|
15797
|
+
if (config.role) {
|
|
15798
|
+
el.setAttribute("role", config.role);
|
|
15799
|
+
}
|
|
15800
|
+
if (config.ariaExpanded !== void 0) {
|
|
15801
|
+
el.setAttribute("aria-expanded", String(config.ariaExpanded));
|
|
15802
|
+
}
|
|
15803
|
+
if (config.ariaSelected !== void 0) {
|
|
15804
|
+
el.setAttribute("aria-selected", String(config.ariaSelected));
|
|
15805
|
+
}
|
|
15806
|
+
if (config.ariaChecked !== void 0) {
|
|
15807
|
+
el.setAttribute("aria-checked", String(config.ariaChecked));
|
|
15808
|
+
}
|
|
15809
|
+
if (config.ariaDisabled !== void 0) {
|
|
15810
|
+
el.setAttribute("aria-disabled", String(config.ariaDisabled));
|
|
15811
|
+
if (config.ariaDisabled) {
|
|
15812
|
+
el.setAttribute("tabindex", "-1");
|
|
15813
|
+
}
|
|
15814
|
+
}
|
|
15815
|
+
if (config.ariaHidden !== void 0) {
|
|
15816
|
+
el.setAttribute("aria-hidden", String(config.ariaHidden));
|
|
15817
|
+
}
|
|
15818
|
+
if (config.ariaBusy !== void 0) {
|
|
15819
|
+
el.setAttribute("aria-busy", String(config.ariaBusy));
|
|
15820
|
+
}
|
|
15821
|
+
if (config.ariaPressed !== void 0) {
|
|
15822
|
+
el.setAttribute("aria-pressed", String(config.ariaPressed));
|
|
15823
|
+
}
|
|
15824
|
+
if (config.ariaCurrent !== void 0) {
|
|
15825
|
+
el.setAttribute("aria-current", typeof config.ariaCurrent === "boolean" ? String(config.ariaCurrent) : config.ariaCurrent);
|
|
15826
|
+
}
|
|
15827
|
+
if (config.ariaLabel) {
|
|
15828
|
+
el.setAttribute("aria-label", config.ariaLabel);
|
|
15829
|
+
}
|
|
15830
|
+
if (config.ariaLabelledBy) {
|
|
15831
|
+
el.setAttribute("aria-labelledby", config.ariaLabelledBy);
|
|
15832
|
+
}
|
|
15833
|
+
if (config.ariaDescribedBy) {
|
|
15834
|
+
el.setAttribute("aria-describedby", config.ariaDescribedBy);
|
|
15835
|
+
}
|
|
15836
|
+
if (config.ariaControls) {
|
|
15837
|
+
el.setAttribute("aria-controls", config.ariaControls);
|
|
15838
|
+
}
|
|
15839
|
+
if (config.ariaOwns) {
|
|
15840
|
+
el.setAttribute("aria-owns", config.ariaOwns);
|
|
15841
|
+
}
|
|
15842
|
+
if (config.ariaHasPopup !== void 0) {
|
|
15843
|
+
const value = typeof config.ariaHasPopup === "boolean" ? "true" : config.ariaHasPopup;
|
|
15844
|
+
el.setAttribute("aria-haspopup", value);
|
|
15845
|
+
}
|
|
15846
|
+
if (config.ariaAutoComplete) {
|
|
15847
|
+
el.setAttribute("aria-autocomplete", config.ariaAutoComplete);
|
|
15848
|
+
}
|
|
15849
|
+
if (config.ariaLive) {
|
|
15850
|
+
el.setAttribute("aria-live", config.ariaLive);
|
|
15851
|
+
}
|
|
15852
|
+
if (config.ariaAtomic !== void 0) {
|
|
15853
|
+
el.setAttribute("aria-atomic", String(config.ariaAtomic));
|
|
15854
|
+
}
|
|
15855
|
+
if (config.ariaRelevant) {
|
|
15856
|
+
el.setAttribute("aria-relevant", config.ariaRelevant);
|
|
15857
|
+
}
|
|
15858
|
+
if (config.ariaValueNow !== void 0) {
|
|
15859
|
+
el.setAttribute("aria-valuenow", String(config.ariaValueNow));
|
|
15860
|
+
}
|
|
15861
|
+
if (config.ariaValueMin !== void 0) {
|
|
15862
|
+
el.setAttribute("aria-valuemin", String(config.ariaValueMin));
|
|
15863
|
+
}
|
|
15864
|
+
if (config.ariaValueMax !== void 0) {
|
|
15865
|
+
el.setAttribute("aria-valuemax", String(config.ariaValueMax));
|
|
15866
|
+
}
|
|
15867
|
+
if (config.ariaValueText) {
|
|
15868
|
+
el.setAttribute("aria-valuetext", config.ariaValueText);
|
|
15869
|
+
}
|
|
15870
|
+
if (config.ariaPlaceholder) {
|
|
15871
|
+
el.setAttribute("aria-placeholder", config.ariaPlaceholder);
|
|
15872
|
+
}
|
|
15873
|
+
if (config.ariaRequired !== void 0) {
|
|
15874
|
+
el.setAttribute("aria-required", String(config.ariaRequired));
|
|
15875
|
+
}
|
|
15876
|
+
if (config.ariaReadonly !== void 0) {
|
|
15877
|
+
el.setAttribute("aria-readonly", String(config.ariaReadonly));
|
|
15878
|
+
}
|
|
15879
|
+
if (config.ariaModal !== void 0) {
|
|
15880
|
+
el.setAttribute("aria-modal", String(config.ariaModal));
|
|
15881
|
+
}
|
|
15882
|
+
if (config.tabIndex !== void 0) {
|
|
15883
|
+
el.setAttribute("tabindex", String(config.tabIndex));
|
|
15884
|
+
}
|
|
15885
|
+
}
|
|
15886
|
+
function clearAriaAttributes(el) {
|
|
15887
|
+
const ariaAttrs = Array.from(el.attributes).filter((attr) => attr.name.startsWith("aria-") || attr.name === "role");
|
|
15888
|
+
ariaAttrs.forEach((attr) => el.removeAttribute(attr.name));
|
|
15889
|
+
}
|
|
15890
|
+
function generateAriaId(prefix = "directix-aria") {
|
|
15891
|
+
return `${prefix}-${Math.random().toString(36).substring(2, 10)}`;
|
|
15892
|
+
}
|
|
15893
|
+
let announcerElement = null, announcerId = null;
|
|
15894
|
+
function ensureAnnouncer() {
|
|
15895
|
+
if (announcerElement && document.getElementById(announcerId || "")) {
|
|
15896
|
+
return announcerElement;
|
|
15897
|
+
}
|
|
15898
|
+
announcerId = "directix-sr-announcer";
|
|
15899
|
+
announcerElement = document.createElement("div");
|
|
15900
|
+
announcerElement.id = announcerId;
|
|
15901
|
+
announcerElement.setAttribute("aria-live", "polite");
|
|
15902
|
+
announcerElement.setAttribute("aria-atomic", "true");
|
|
15903
|
+
announcerElement.setAttribute(
|
|
15904
|
+
"style",
|
|
15905
|
+
"position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;"
|
|
15906
|
+
);
|
|
15907
|
+
document.body.appendChild(announcerElement);
|
|
15908
|
+
return announcerElement;
|
|
15909
|
+
}
|
|
15910
|
+
function announce(message, options = {}) {
|
|
15911
|
+
if (!isBrowser()) return;
|
|
15912
|
+
const { priority = "polite", timeout = 1e3, clear = true } = options;
|
|
15913
|
+
const announcer = ensureAnnouncer();
|
|
15914
|
+
announcer.setAttribute("aria-live", priority);
|
|
15915
|
+
announcer.textContent = "";
|
|
15916
|
+
requestAnimationFrame(() => {
|
|
15917
|
+
announcer.textContent = message;
|
|
15918
|
+
if (clear) {
|
|
15919
|
+
setTimeout(() => {
|
|
15920
|
+
if (announcer.textContent === message) {
|
|
15921
|
+
announcer.textContent = "";
|
|
15922
|
+
}
|
|
15923
|
+
}, timeout);
|
|
15924
|
+
}
|
|
15925
|
+
});
|
|
15926
|
+
}
|
|
15927
|
+
function clearAnnouncer() {
|
|
15928
|
+
if (announcerElement) {
|
|
15929
|
+
announcerElement.textContent = "";
|
|
15930
|
+
}
|
|
15931
|
+
}
|
|
15932
|
+
const DEFAULT_NEXT_KEYS = ["ArrowDown", "ArrowRight"];
|
|
15933
|
+
const DEFAULT_PREV_KEYS = ["ArrowUp", "ArrowLeft"];
|
|
15934
|
+
const DEFAULT_SELECT_KEYS = ["Enter", " "];
|
|
15935
|
+
const DEFAULT_CLOSE_KEYS = ["Escape"];
|
|
15936
|
+
const DEFAULT_HOME_KEYS = ["Home"];
|
|
15937
|
+
const DEFAULT_END_KEYS = ["End"];
|
|
15938
|
+
function useKeyboardNavigation(options = {}) {
|
|
15939
|
+
const {
|
|
15940
|
+
nextKeys = DEFAULT_NEXT_KEYS,
|
|
15941
|
+
prevKeys = DEFAULT_PREV_KEYS,
|
|
15942
|
+
selectKeys = DEFAULT_SELECT_KEYS,
|
|
15943
|
+
closeKeys = DEFAULT_CLOSE_KEYS,
|
|
15944
|
+
homeKeys = DEFAULT_HOME_KEYS,
|
|
15945
|
+
endKeys = DEFAULT_END_KEYS,
|
|
15946
|
+
focusTrap = false,
|
|
15947
|
+
returnFocus = true,
|
|
15948
|
+
mode: _mode = "linear",
|
|
15949
|
+
loop = true,
|
|
15950
|
+
rovingTabindex = false
|
|
15951
|
+
} = options;
|
|
15952
|
+
const focusedIndex = vue.ref(0);
|
|
15953
|
+
let items = [], triggerElement = null, cleanup2 = null;
|
|
15954
|
+
function getFocusables() {
|
|
15955
|
+
return items.filter((item) => !item.hasAttribute("disabled") && item.getAttribute("aria-disabled") !== "true");
|
|
15956
|
+
}
|
|
15957
|
+
function focusIndex(index) {
|
|
15958
|
+
const focusables = getFocusables();
|
|
15959
|
+
if (focusables.length === 0) return;
|
|
15960
|
+
let newIndex = index;
|
|
15961
|
+
if (newIndex < 0) {
|
|
15962
|
+
newIndex = loop ? focusables.length - 1 : 0;
|
|
15963
|
+
} else if (newIndex >= focusables.length) {
|
|
15964
|
+
newIndex = loop ? 0 : focusables.length - 1;
|
|
15965
|
+
}
|
|
15966
|
+
const target = focusables[newIndex];
|
|
15967
|
+
if (target) {
|
|
15968
|
+
target.focus();
|
|
15969
|
+
if (rovingTabindex) {
|
|
15970
|
+
focusables.forEach((item, i) => {
|
|
15971
|
+
item.setAttribute("tabindex", i === newIndex ? "0" : "-1");
|
|
15972
|
+
});
|
|
15973
|
+
}
|
|
15974
|
+
focusedIndex.value = newIndex;
|
|
15975
|
+
}
|
|
15976
|
+
}
|
|
15977
|
+
function focusNext() {
|
|
15978
|
+
focusIndex(focusedIndex.value + 1);
|
|
15979
|
+
}
|
|
15980
|
+
function focusPrev() {
|
|
15981
|
+
focusIndex(focusedIndex.value - 1);
|
|
15982
|
+
}
|
|
15983
|
+
function focusFirst() {
|
|
15984
|
+
focusIndex(0);
|
|
15985
|
+
}
|
|
15986
|
+
function focusLast() {
|
|
15987
|
+
focusIndex(getFocusables().length - 1);
|
|
15988
|
+
}
|
|
15989
|
+
function handleKeyDown(e) {
|
|
15990
|
+
var _a2;
|
|
15991
|
+
const isModified = e.altKey || e.ctrlKey || e.metaKey;
|
|
15992
|
+
if (isModified) return;
|
|
15993
|
+
if (focusTrap && e.key === "Tab") {
|
|
15994
|
+
const focusables = getFocusables();
|
|
15995
|
+
if (focusables.length === 0) return;
|
|
15996
|
+
e.preventDefault();
|
|
15997
|
+
if (e.shiftKey) {
|
|
15998
|
+
focusPrev();
|
|
15999
|
+
} else {
|
|
16000
|
+
focusNext();
|
|
16001
|
+
}
|
|
16002
|
+
return;
|
|
16003
|
+
}
|
|
16004
|
+
if (nextKeys.includes(e.key)) {
|
|
16005
|
+
e.preventDefault();
|
|
16006
|
+
focusNext();
|
|
16007
|
+
} else if (prevKeys.includes(e.key)) {
|
|
16008
|
+
e.preventDefault();
|
|
16009
|
+
focusPrev();
|
|
16010
|
+
} else if (homeKeys.includes(e.key)) {
|
|
16011
|
+
e.preventDefault();
|
|
16012
|
+
focusFirst();
|
|
16013
|
+
} else if (endKeys.includes(e.key)) {
|
|
16014
|
+
e.preventDefault();
|
|
16015
|
+
focusLast();
|
|
16016
|
+
} else if (selectKeys.includes(e.key)) {
|
|
16017
|
+
e.preventDefault();
|
|
16018
|
+
(_a2 = items[focusedIndex.value]) == null ? void 0 : _a2.click();
|
|
16019
|
+
} else if (closeKeys.includes(e.key)) {
|
|
16020
|
+
e.preventDefault();
|
|
16021
|
+
if (returnFocus && triggerElement) {
|
|
16022
|
+
triggerElement.focus();
|
|
16023
|
+
}
|
|
16024
|
+
}
|
|
16025
|
+
}
|
|
16026
|
+
function bind(el, itemElements) {
|
|
16027
|
+
cleanup2 == null ? void 0 : cleanup2();
|
|
16028
|
+
items = itemElements;
|
|
16029
|
+
triggerElement = document.activeElement;
|
|
16030
|
+
el.addEventListener("keydown", handleKeyDown);
|
|
16031
|
+
if (rovingTabindex && items.length > 0) {
|
|
16032
|
+
items.forEach((item, i) => {
|
|
16033
|
+
item.setAttribute("tabindex", i === 0 ? "0" : "-1");
|
|
16034
|
+
});
|
|
16035
|
+
}
|
|
16036
|
+
if (items.length > 0) {
|
|
16037
|
+
focusIndex(0);
|
|
16038
|
+
}
|
|
16039
|
+
cleanup2 = () => {
|
|
16040
|
+
el.removeEventListener("keydown", handleKeyDown);
|
|
16041
|
+
items = [];
|
|
16042
|
+
};
|
|
16043
|
+
return cleanup2;
|
|
16044
|
+
}
|
|
16045
|
+
vue.onUnmounted(() => {
|
|
16046
|
+
cleanup2 == null ? void 0 : cleanup2();
|
|
16047
|
+
});
|
|
16048
|
+
return {
|
|
16049
|
+
focusedIndex: vue.readonly(focusedIndex),
|
|
16050
|
+
bind,
|
|
16051
|
+
focusIndex,
|
|
16052
|
+
focusNext,
|
|
16053
|
+
focusPrev,
|
|
16054
|
+
focusFirst,
|
|
16055
|
+
focusLast
|
|
16056
|
+
};
|
|
16057
|
+
}
|
|
16058
|
+
function useFocusTrap(container, options = {}) {
|
|
16059
|
+
const {
|
|
16060
|
+
initialFocus,
|
|
16061
|
+
allowOutsideClick = false,
|
|
16062
|
+
escapeDeactivates = true,
|
|
16063
|
+
onActivate,
|
|
16064
|
+
onDeactivate
|
|
16065
|
+
} = options;
|
|
16066
|
+
const isActive = vue.ref(false);
|
|
16067
|
+
let lastFocusedElement = null;
|
|
16068
|
+
function getFocusableElements() {
|
|
16069
|
+
const el = container.value;
|
|
16070
|
+
if (!el) return [];
|
|
16071
|
+
const selector = [
|
|
16072
|
+
"a[href]",
|
|
16073
|
+
"button:not([disabled])",
|
|
16074
|
+
"textarea:not([disabled])",
|
|
16075
|
+
"input:not([disabled])",
|
|
16076
|
+
"select:not([disabled])",
|
|
16077
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
16078
|
+
].join(", ");
|
|
16079
|
+
return Array.from(el.querySelectorAll(selector)).filter((item) => !item.hasAttribute("aria-hidden"));
|
|
16080
|
+
}
|
|
16081
|
+
function handleKeyDown(e) {
|
|
16082
|
+
if (!isActive.value) return;
|
|
16083
|
+
if (escapeDeactivates && e.key === "Escape") {
|
|
16084
|
+
e.preventDefault();
|
|
16085
|
+
deactivate();
|
|
16086
|
+
return;
|
|
16087
|
+
}
|
|
16088
|
+
if (e.key !== "Tab") return;
|
|
16089
|
+
const el = container.value;
|
|
16090
|
+
if (!el) return;
|
|
16091
|
+
const focusables = getFocusableElements();
|
|
16092
|
+
if (focusables.length === 0) return;
|
|
16093
|
+
const firstFocusable = focusables[0];
|
|
16094
|
+
const lastFocusable = focusables[focusables.length - 1];
|
|
16095
|
+
const currentElement = document.activeElement;
|
|
16096
|
+
if (e.shiftKey) {
|
|
16097
|
+
if (currentElement === firstFocusable || !el.contains(currentElement)) {
|
|
16098
|
+
e.preventDefault();
|
|
16099
|
+
lastFocusable.focus();
|
|
16100
|
+
}
|
|
16101
|
+
} else {
|
|
16102
|
+
if (currentElement === lastFocusable || !el.contains(currentElement)) {
|
|
16103
|
+
e.preventDefault();
|
|
16104
|
+
firstFocusable.focus();
|
|
16105
|
+
}
|
|
16106
|
+
}
|
|
16107
|
+
}
|
|
16108
|
+
function handleOutsideClick(event) {
|
|
16109
|
+
if (!isActive.value) return;
|
|
16110
|
+
if (!container.value) return;
|
|
16111
|
+
if (typeof allowOutsideClick === "boolean" && !allowOutsideClick) {
|
|
16112
|
+
event.preventDefault();
|
|
16113
|
+
return;
|
|
16114
|
+
}
|
|
16115
|
+
if (typeof allowOutsideClick === "function" && !allowOutsideClick(event)) {
|
|
16116
|
+
event.preventDefault();
|
|
16117
|
+
}
|
|
16118
|
+
}
|
|
16119
|
+
function activate() {
|
|
16120
|
+
var _a2;
|
|
16121
|
+
if (isActive.value) return;
|
|
16122
|
+
lastFocusedElement = document.activeElement;
|
|
16123
|
+
if (initialFocus) {
|
|
16124
|
+
let initialEl = null;
|
|
16125
|
+
if (typeof initialFocus === "function") {
|
|
16126
|
+
initialEl = initialFocus();
|
|
16127
|
+
} else if (typeof initialFocus === "string") {
|
|
16128
|
+
initialEl = ((_a2 = container.value) == null ? void 0 : _a2.querySelector(initialFocus)) || null;
|
|
16129
|
+
} else {
|
|
16130
|
+
initialEl = initialFocus;
|
|
16131
|
+
}
|
|
16132
|
+
initialEl == null ? void 0 : initialEl.focus();
|
|
16133
|
+
} else {
|
|
16134
|
+
const focusables = getFocusableElements();
|
|
16135
|
+
if (focusables.length > 0) {
|
|
16136
|
+
focusables[0].focus();
|
|
16137
|
+
}
|
|
16138
|
+
}
|
|
16139
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
16140
|
+
document.addEventListener("mousedown", handleOutsideClick);
|
|
16141
|
+
document.addEventListener("touchstart", handleOutsideClick);
|
|
16142
|
+
isActive.value = true;
|
|
16143
|
+
onActivate == null ? void 0 : onActivate();
|
|
16144
|
+
}
|
|
16145
|
+
function deactivate() {
|
|
16146
|
+
if (!isActive.value) return;
|
|
16147
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
16148
|
+
document.removeEventListener("mousedown", handleOutsideClick);
|
|
16149
|
+
document.removeEventListener("touchstart", handleOutsideClick);
|
|
16150
|
+
if (lastFocusedElement && lastFocusedElement.focus) {
|
|
16151
|
+
lastFocusedElement.focus();
|
|
16152
|
+
}
|
|
16153
|
+
isActive.value = false;
|
|
16154
|
+
onDeactivate == null ? void 0 : onDeactivate();
|
|
16155
|
+
}
|
|
16156
|
+
vue.onUnmounted(() => {
|
|
16157
|
+
deactivate();
|
|
16158
|
+
});
|
|
16159
|
+
return {
|
|
16160
|
+
activate,
|
|
16161
|
+
deactivate,
|
|
16162
|
+
isActive: vue.readonly(isActive)
|
|
16163
|
+
};
|
|
16164
|
+
}
|
|
16165
|
+
function getAutoAriaConfig(options) {
|
|
16166
|
+
const { type, label, expanded, disabled, relatedId } = options;
|
|
16167
|
+
const configs = {
|
|
16168
|
+
tooltip: {
|
|
16169
|
+
role: "tooltip",
|
|
16170
|
+
ariaHidden: expanded === void 0 ? true : !expanded
|
|
16171
|
+
},
|
|
16172
|
+
menu: {
|
|
16173
|
+
role: "menu",
|
|
16174
|
+
ariaLabel: label,
|
|
16175
|
+
ariaExpanded: expanded,
|
|
16176
|
+
ariaDisabled: disabled
|
|
16177
|
+
},
|
|
16178
|
+
dialog: {
|
|
16179
|
+
role: "dialog",
|
|
16180
|
+
ariaLabel: label,
|
|
16181
|
+
ariaModal: true
|
|
16182
|
+
},
|
|
16183
|
+
popover: {
|
|
16184
|
+
role: "region",
|
|
16185
|
+
ariaLabel: label,
|
|
16186
|
+
ariaExpanded: expanded
|
|
16187
|
+
},
|
|
16188
|
+
dropdown: {
|
|
16189
|
+
role: "listbox",
|
|
16190
|
+
ariaLabel: label,
|
|
16191
|
+
ariaExpanded: expanded
|
|
16192
|
+
},
|
|
16193
|
+
modal: {
|
|
16194
|
+
role: "dialog",
|
|
16195
|
+
ariaModal: true,
|
|
16196
|
+
ariaLabel: label
|
|
16197
|
+
},
|
|
16198
|
+
alert: {
|
|
16199
|
+
role: "alert",
|
|
16200
|
+
ariaLive: "assertive",
|
|
16201
|
+
ariaAtomic: true
|
|
16202
|
+
},
|
|
16203
|
+
region: {
|
|
16204
|
+
role: "region",
|
|
16205
|
+
ariaLabel: label
|
|
16206
|
+
}
|
|
16207
|
+
};
|
|
16208
|
+
const config = __spreadValues({}, configs[type] || {});
|
|
16209
|
+
if (relatedId) {
|
|
16210
|
+
if (type === "tooltip") {
|
|
16211
|
+
config.ariaDescribedBy = relatedId;
|
|
16212
|
+
} else {
|
|
16213
|
+
config.ariaControls = relatedId;
|
|
16214
|
+
}
|
|
16215
|
+
}
|
|
16216
|
+
return config;
|
|
16217
|
+
}
|
|
16218
|
+
const DEFAULT_THRESHOLDS = {
|
|
16219
|
+
tap: 10,
|
|
16220
|
+
longPress: 500,
|
|
16221
|
+
swipe: 30,
|
|
16222
|
+
pinch: 0.1,
|
|
16223
|
+
rotate: 5,
|
|
16224
|
+
doubleTap: 300,
|
|
16225
|
+
swipeVelocity: 0.3
|
|
16226
|
+
};
|
|
16227
|
+
function triggerHaptic(type = "light") {
|
|
16228
|
+
if (!isBrowser()) return;
|
|
16229
|
+
const nav = navigator;
|
|
16230
|
+
if (nav.vibrate) {
|
|
16231
|
+
const patterns = {
|
|
16232
|
+
light: 10,
|
|
16233
|
+
medium: 20,
|
|
16234
|
+
heavy: 30,
|
|
16235
|
+
selection: [10, 50, 10]
|
|
16236
|
+
};
|
|
16237
|
+
nav.vibrate(patterns[type]);
|
|
16238
|
+
}
|
|
16239
|
+
}
|
|
16240
|
+
function applyVisualFeedback(element, options = {}) {
|
|
16241
|
+
const {
|
|
16242
|
+
visualClass = "directix-touch-active",
|
|
16243
|
+
visualDuration = 150
|
|
16244
|
+
} = options;
|
|
16245
|
+
element.classList.add(visualClass);
|
|
16246
|
+
const timer = setTimeout(() => {
|
|
16247
|
+
element.classList.remove(visualClass);
|
|
16248
|
+
}, visualDuration);
|
|
16249
|
+
return () => {
|
|
16250
|
+
clearTimeout(timer);
|
|
16251
|
+
element.classList.remove(visualClass);
|
|
16252
|
+
};
|
|
16253
|
+
}
|
|
16254
|
+
function calculateVelocity(startX, startY, endX, endY, duration) {
|
|
16255
|
+
if (duration === 0) return 0;
|
|
16256
|
+
const distance = Math.sqrt(__pow(endX - startX, 2) + __pow(endY - startY, 2));
|
|
16257
|
+
return distance / duration;
|
|
16258
|
+
}
|
|
16259
|
+
function isEdgePoint(x, y, edgeSize = 20) {
|
|
16260
|
+
if (!isBrowser()) return { isEdge: false };
|
|
16261
|
+
const width = window.innerWidth;
|
|
16262
|
+
const height = window.innerHeight;
|
|
16263
|
+
if (x <= edgeSize) return { isEdge: true, edge: "left" };
|
|
16264
|
+
if (x >= width - edgeSize) return { isEdge: true, edge: "right" };
|
|
16265
|
+
if (y <= edgeSize) return { isEdge: true, edge: "top" };
|
|
16266
|
+
if (y >= height - edgeSize) return { isEdge: true, edge: "bottom" };
|
|
16267
|
+
return { isEdge: false };
|
|
16268
|
+
}
|
|
16269
|
+
function useEnhancedTouch(options = {}) {
|
|
16270
|
+
const {
|
|
16271
|
+
thresholds: userThresholds = {},
|
|
16272
|
+
feedback = {},
|
|
16273
|
+
debounce: debounce2 = 0,
|
|
16274
|
+
throttle: throttle2 = 16,
|
|
16275
|
+
passive = true,
|
|
16276
|
+
disabled = false,
|
|
16277
|
+
onTap,
|
|
16278
|
+
onDoubleTap,
|
|
16279
|
+
onLongPress,
|
|
16280
|
+
onSwipe,
|
|
16281
|
+
onSwipeLeft,
|
|
16282
|
+
onSwipeRight,
|
|
16283
|
+
onSwipeUp,
|
|
16284
|
+
onSwipeDown,
|
|
16285
|
+
onPan,
|
|
16286
|
+
onPinch,
|
|
16287
|
+
onPinchIn,
|
|
16288
|
+
onPinchOut,
|
|
16289
|
+
onRotate,
|
|
16290
|
+
onTwoFingerTap,
|
|
16291
|
+
onEdgeSwipe
|
|
16292
|
+
} = options;
|
|
16293
|
+
const thresholds = __spreadValues(__spreadValues({}, DEFAULT_THRESHOLDS), userThresholds);
|
|
16294
|
+
const activeGesture = vue.ref(null);
|
|
16295
|
+
const isTouching = vue.ref(false);
|
|
16296
|
+
let currentElement = null, startX = 0, startY = 0, startTime = 0, lastTapTime = 0, lastPanTime = 0, longPressTimer = null, initialPinchDistance = 0, initialAngle = 0, removeVisualFeedback = null, lastGestureTime = 0;
|
|
16297
|
+
function getTouchCenter(touches) {
|
|
16298
|
+
let x = 0, y = 0;
|
|
16299
|
+
for (let i = 0; i < touches.length; i++) {
|
|
16300
|
+
x += touches[i].clientX;
|
|
16301
|
+
y += touches[i].clientY;
|
|
16302
|
+
}
|
|
16303
|
+
return { x: x / touches.length, y: y / touches.length };
|
|
16304
|
+
}
|
|
16305
|
+
function getDistance2(t1, t2) {
|
|
16306
|
+
return Math.sqrt(__pow(t1.clientX - t2.clientX, 2) + __pow(t1.clientY - t2.clientY, 2));
|
|
16307
|
+
}
|
|
16308
|
+
function getAngle2(t1, t2) {
|
|
16309
|
+
return Math.atan2(t2.clientY - t1.clientY, t2.clientX - t1.clientX) * (180 / Math.PI);
|
|
16310
|
+
}
|
|
16311
|
+
function shouldProcessGesture() {
|
|
16312
|
+
if (typeof disabled === "boolean" ? disabled : disabled.value) return false;
|
|
16313
|
+
if (debounce2 > 0 && Date.now() - lastGestureTime < debounce2) return false;
|
|
16314
|
+
return true;
|
|
16315
|
+
}
|
|
16316
|
+
function handleTouchStart(e) {
|
|
16317
|
+
if (!shouldProcessGesture()) return;
|
|
16318
|
+
isTouching.value = true;
|
|
16319
|
+
startTime = Date.now();
|
|
16320
|
+
activeGesture.value = null;
|
|
16321
|
+
if (feedback.haptic) {
|
|
16322
|
+
triggerHaptic("light");
|
|
16323
|
+
}
|
|
16324
|
+
if (e.touches.length === 1) {
|
|
16325
|
+
startX = e.touches[0].clientX;
|
|
16326
|
+
startY = e.touches[0].clientY;
|
|
16327
|
+
if (onLongPress) {
|
|
16328
|
+
longPressTimer = setTimeout(() => {
|
|
16329
|
+
if (!activeGesture.value) {
|
|
16330
|
+
activeGesture.value = "longPress";
|
|
16331
|
+
lastGestureTime = Date.now();
|
|
16332
|
+
onLongPress({
|
|
16333
|
+
type: "longPress",
|
|
16334
|
+
center: { x: startX, y: startY },
|
|
16335
|
+
event: e,
|
|
16336
|
+
duration: Date.now() - startTime
|
|
16337
|
+
});
|
|
16338
|
+
if (feedback.haptic) triggerHaptic("medium");
|
|
16339
|
+
}
|
|
16340
|
+
}, thresholds.longPress);
|
|
16341
|
+
}
|
|
16342
|
+
} else if (e.touches.length === 2) {
|
|
16343
|
+
if (longPressTimer) {
|
|
16344
|
+
clearTimeout(longPressTimer);
|
|
16345
|
+
longPressTimer = null;
|
|
16346
|
+
}
|
|
16347
|
+
initialPinchDistance = getDistance2(e.touches[0], e.touches[1]);
|
|
16348
|
+
initialAngle = getAngle2(e.touches[0], e.touches[1]);
|
|
16349
|
+
}
|
|
16350
|
+
}
|
|
16351
|
+
function handleTouchMove(e) {
|
|
16352
|
+
if (!shouldProcessGesture()) return;
|
|
16353
|
+
if (longPressTimer) {
|
|
16354
|
+
clearTimeout(longPressTimer);
|
|
16355
|
+
longPressTimer = null;
|
|
16356
|
+
}
|
|
16357
|
+
if (e.touches.length === 1) {
|
|
16358
|
+
const currentX = e.touches[0].clientX;
|
|
16359
|
+
const currentY = e.touches[0].clientY;
|
|
16360
|
+
if (onPan) {
|
|
16361
|
+
const now = Date.now();
|
|
16362
|
+
if (now - lastPanTime >= throttle2) {
|
|
16363
|
+
lastPanTime = now;
|
|
16364
|
+
const deltaX = currentX - startX;
|
|
16365
|
+
const deltaY = currentY - startY;
|
|
16366
|
+
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
16367
|
+
if (distance > thresholds.tap) {
|
|
16368
|
+
activeGesture.value = "pan";
|
|
16369
|
+
onPan({
|
|
16370
|
+
type: "pan",
|
|
16371
|
+
distance,
|
|
16372
|
+
angle: Math.atan2(deltaY, deltaX) * (180 / Math.PI),
|
|
16373
|
+
center: { x: currentX, y: currentY },
|
|
16374
|
+
event: e
|
|
16375
|
+
});
|
|
16376
|
+
}
|
|
16377
|
+
}
|
|
16378
|
+
}
|
|
16379
|
+
} else if (e.touches.length === 2) {
|
|
16380
|
+
const currentDistance = getDistance2(e.touches[0], e.touches[1]);
|
|
16381
|
+
const currentAngle = getAngle2(e.touches[0], e.touches[1]);
|
|
16382
|
+
if (onPinch && initialPinchDistance > 0) {
|
|
16383
|
+
const scale = currentDistance / initialPinchDistance;
|
|
16384
|
+
const deltaScale = Math.abs(scale - 1);
|
|
16385
|
+
if (deltaScale > thresholds.pinch) {
|
|
16386
|
+
activeGesture.value = "pinch";
|
|
16387
|
+
onPinch({
|
|
16388
|
+
type: "pinch",
|
|
16389
|
+
scale,
|
|
16390
|
+
center: getTouchCenter(e.touches),
|
|
16391
|
+
event: e
|
|
16392
|
+
});
|
|
16393
|
+
if (scale < 1 && onPinchIn) {
|
|
16394
|
+
onPinchIn({
|
|
16395
|
+
type: "pinchIn",
|
|
16396
|
+
scale,
|
|
16397
|
+
center: getTouchCenter(e.touches),
|
|
16398
|
+
event: e
|
|
16399
|
+
});
|
|
16400
|
+
} else if (scale > 1 && onPinchOut) {
|
|
16401
|
+
onPinchOut({
|
|
16402
|
+
type: "pinchOut",
|
|
16403
|
+
scale,
|
|
16404
|
+
center: getTouchCenter(e.touches),
|
|
16405
|
+
event: e
|
|
16406
|
+
});
|
|
16407
|
+
}
|
|
16408
|
+
}
|
|
16409
|
+
}
|
|
16410
|
+
if (onRotate) {
|
|
16411
|
+
const rotation = currentAngle - initialAngle;
|
|
16412
|
+
if (Math.abs(rotation) > thresholds.rotate) {
|
|
16413
|
+
activeGesture.value = "rotate";
|
|
16414
|
+
onRotate({
|
|
16415
|
+
type: "rotate",
|
|
16416
|
+
rotation,
|
|
16417
|
+
center: getTouchCenter(e.touches),
|
|
16418
|
+
event: e
|
|
16419
|
+
});
|
|
16420
|
+
}
|
|
16421
|
+
}
|
|
16422
|
+
}
|
|
16423
|
+
}
|
|
16424
|
+
function handleTouchEnd(e) {
|
|
16425
|
+
var _a2, _b, _c, _d;
|
|
16426
|
+
if (!shouldProcessGesture()) return;
|
|
16427
|
+
isTouching.value = false;
|
|
16428
|
+
if (longPressTimer) {
|
|
16429
|
+
clearTimeout(longPressTimer);
|
|
16430
|
+
longPressTimer = null;
|
|
16431
|
+
}
|
|
16432
|
+
const duration = Date.now() - startTime;
|
|
16433
|
+
const endX = (_b = (_a2 = e.changedTouches[0]) == null ? void 0 : _a2.clientX) != null ? _b : startX;
|
|
16434
|
+
const endY = (_d = (_c = e.changedTouches[0]) == null ? void 0 : _c.clientY) != null ? _d : startY;
|
|
16435
|
+
const deltaX = endX - startX;
|
|
16436
|
+
const deltaY = endY - startY;
|
|
16437
|
+
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
16438
|
+
const velocity = calculateVelocity(startX, startY, endX, endY, duration);
|
|
16439
|
+
if (e.touches.length === 0 && e.changedTouches.length === 2 && onTwoFingerTap) {
|
|
16440
|
+
const twoFingerDistance = getDistance2(e.changedTouches[0], e.changedTouches[1]);
|
|
16441
|
+
if (twoFingerDistance < 50) {
|
|
16442
|
+
activeGesture.value = "twoFingerTap";
|
|
16443
|
+
onTwoFingerTap({
|
|
16444
|
+
type: "twoFingerTap",
|
|
16445
|
+
center: getTouchCenter(e.changedTouches),
|
|
16446
|
+
event: e
|
|
16447
|
+
});
|
|
16448
|
+
}
|
|
16449
|
+
}
|
|
16450
|
+
if (e.changedTouches.length === 1) {
|
|
16451
|
+
if (distance >= thresholds.swipe) {
|
|
16452
|
+
let direction;
|
|
16453
|
+
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
|
16454
|
+
direction = deltaX > 0 ? "right" : "left";
|
|
16455
|
+
} else {
|
|
16456
|
+
direction = deltaY > 0 ? "down" : "up";
|
|
16457
|
+
}
|
|
16458
|
+
const edge = isEdgePoint(startX, startY);
|
|
16459
|
+
if (edge.isEdge && onEdgeSwipe) {
|
|
16460
|
+
activeGesture.value = "edgeSwipe";
|
|
16461
|
+
onEdgeSwipe({
|
|
16462
|
+
type: "edgeSwipe",
|
|
16463
|
+
direction,
|
|
16464
|
+
distance,
|
|
16465
|
+
velocity,
|
|
16466
|
+
center: { x: endX, y: endY },
|
|
16467
|
+
event: e
|
|
16468
|
+
});
|
|
16469
|
+
}
|
|
16470
|
+
if (!activeGesture.value) {
|
|
16471
|
+
activeGesture.value = "swipe";
|
|
16472
|
+
const swipeEvent = {
|
|
16473
|
+
type: "swipe",
|
|
16474
|
+
direction,
|
|
16475
|
+
distance,
|
|
16476
|
+
velocity,
|
|
16477
|
+
angle: Math.atan2(deltaY, deltaX) * (180 / Math.PI),
|
|
16478
|
+
center: { x: endX, y: endY },
|
|
16479
|
+
event: e,
|
|
16480
|
+
duration
|
|
16481
|
+
};
|
|
16482
|
+
onSwipe == null ? void 0 : onSwipe(swipeEvent);
|
|
16483
|
+
if (direction === "left") onSwipeLeft == null ? void 0 : onSwipeLeft(swipeEvent);
|
|
16484
|
+
if (direction === "right") onSwipeRight == null ? void 0 : onSwipeRight(swipeEvent);
|
|
16485
|
+
if (direction === "up") onSwipeUp == null ? void 0 : onSwipeUp(swipeEvent);
|
|
16486
|
+
if (direction === "down") onSwipeDown == null ? void 0 : onSwipeDown(swipeEvent);
|
|
16487
|
+
if (feedback.haptic) triggerHaptic("light");
|
|
16488
|
+
}
|
|
16489
|
+
} else if (distance < thresholds.tap && duration < 300) {
|
|
16490
|
+
const now = Date.now();
|
|
16491
|
+
const timeSinceLastTap = now - lastTapTime;
|
|
16492
|
+
if (timeSinceLastTap < thresholds.doubleTap && onDoubleTap) {
|
|
16493
|
+
activeGesture.value = "doubleTap";
|
|
16494
|
+
onDoubleTap({
|
|
16495
|
+
type: "doubleTap",
|
|
16496
|
+
center: { x: endX, y: endY },
|
|
16497
|
+
event: e,
|
|
16498
|
+
duration
|
|
16499
|
+
});
|
|
16500
|
+
if (feedback.haptic) triggerHaptic("medium");
|
|
16501
|
+
lastTapTime = 0;
|
|
16502
|
+
} else if (onTap) {
|
|
16503
|
+
if (onDoubleTap) {
|
|
16504
|
+
setTimeout(() => {
|
|
16505
|
+
if (activeGesture.value !== "doubleTap") {
|
|
16506
|
+
activeGesture.value = "tap";
|
|
16507
|
+
onTap({
|
|
16508
|
+
type: "tap",
|
|
16509
|
+
center: { x: endX, y: endY },
|
|
16510
|
+
event: e,
|
|
16511
|
+
duration
|
|
16512
|
+
});
|
|
16513
|
+
if (feedback.haptic) triggerHaptic("light");
|
|
16514
|
+
}
|
|
16515
|
+
}, thresholds.doubleTap);
|
|
16516
|
+
} else {
|
|
16517
|
+
activeGesture.value = "tap";
|
|
16518
|
+
onTap({
|
|
16519
|
+
type: "tap",
|
|
16520
|
+
center: { x: endX, y: endY },
|
|
16521
|
+
event: e,
|
|
16522
|
+
duration
|
|
16523
|
+
});
|
|
16524
|
+
if (feedback.haptic) triggerHaptic("light");
|
|
16525
|
+
}
|
|
16526
|
+
lastTapTime = now;
|
|
16527
|
+
}
|
|
16528
|
+
}
|
|
16529
|
+
}
|
|
16530
|
+
if (removeVisualFeedback) {
|
|
16531
|
+
removeVisualFeedback();
|
|
16532
|
+
removeVisualFeedback = null;
|
|
16533
|
+
}
|
|
16534
|
+
lastGestureTime = Date.now();
|
|
16535
|
+
setTimeout(() => {
|
|
16536
|
+
activeGesture.value = null;
|
|
16537
|
+
}, 100);
|
|
16538
|
+
}
|
|
16539
|
+
function bind(element) {
|
|
16540
|
+
if (!isBrowser()) return () => {
|
|
16541
|
+
};
|
|
16542
|
+
unbind();
|
|
16543
|
+
currentElement = element;
|
|
16544
|
+
const touchOptions = passive ? { passive: true } : void 0;
|
|
16545
|
+
element.addEventListener("touchstart", handleTouchStart, touchOptions);
|
|
16546
|
+
element.addEventListener("touchmove", handleTouchMove, { passive: false });
|
|
16547
|
+
element.addEventListener("touchend", handleTouchEnd);
|
|
16548
|
+
element.addEventListener("touchcancel", handleTouchEnd);
|
|
16549
|
+
if (feedback.visual) {
|
|
16550
|
+
element.addEventListener("touchstart", () => {
|
|
16551
|
+
removeVisualFeedback = applyVisualFeedback(element, feedback);
|
|
16552
|
+
});
|
|
16553
|
+
}
|
|
16554
|
+
return unbind;
|
|
16555
|
+
}
|
|
16556
|
+
function unbind() {
|
|
16557
|
+
if (currentElement) {
|
|
16558
|
+
currentElement.removeEventListener("touchstart", handleTouchStart);
|
|
16559
|
+
currentElement.removeEventListener("touchmove", handleTouchMove);
|
|
16560
|
+
currentElement.removeEventListener("touchend", handleTouchEnd);
|
|
16561
|
+
currentElement.removeEventListener("touchcancel", handleTouchEnd);
|
|
16562
|
+
}
|
|
16563
|
+
if (longPressTimer) {
|
|
16564
|
+
clearTimeout(longPressTimer);
|
|
16565
|
+
longPressTimer = null;
|
|
16566
|
+
}
|
|
16567
|
+
if (removeVisualFeedback) {
|
|
16568
|
+
removeVisualFeedback();
|
|
16569
|
+
removeVisualFeedback = null;
|
|
16570
|
+
}
|
|
16571
|
+
currentElement = null;
|
|
16572
|
+
activeGesture.value = null;
|
|
16573
|
+
isTouching.value = false;
|
|
16574
|
+
}
|
|
16575
|
+
vue.onUnmounted(unbind);
|
|
16576
|
+
return {
|
|
16577
|
+
activeGesture: vue.readonly(activeGesture),
|
|
16578
|
+
bind,
|
|
16579
|
+
isTouching: vue.readonly(isTouching)
|
|
16580
|
+
};
|
|
16581
|
+
}
|
|
16582
|
+
function addPassiveListener(element, event, handler, options) {
|
|
16583
|
+
element.addEventListener(event, handler, __spreadValues({ passive: true }, options));
|
|
16584
|
+
return () => element.removeEventListener(event, handler);
|
|
16585
|
+
}
|
|
16586
|
+
function addNonPassiveListener(element, event, handler, options) {
|
|
16587
|
+
element.addEventListener(event, handler, __spreadValues({ passive: false }, options));
|
|
16588
|
+
return () => element.removeEventListener(event, handler);
|
|
16589
|
+
}
|
|
16590
|
+
function isTouchDevice() {
|
|
16591
|
+
if (!isBrowser()) return false;
|
|
16592
|
+
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
16593
|
+
}
|
|
16594
|
+
function isMobileDevice() {
|
|
16595
|
+
if (!isBrowser()) return false;
|
|
16596
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
16597
|
+
}
|
|
16598
|
+
function getDevicePixelRatio() {
|
|
16599
|
+
if (!isBrowser()) return 1;
|
|
16600
|
+
return window.devicePixelRatio || 1;
|
|
16601
|
+
}
|
|
16602
|
+
function usePWA(config = {}) {
|
|
16603
|
+
const {
|
|
16604
|
+
serviceWorker: swConfig = {}
|
|
16605
|
+
} = config;
|
|
16606
|
+
const isOnline = vue.ref(isBrowser() ? navigator.onLine : true);
|
|
16607
|
+
const isRegistered = vue.ref(false);
|
|
16608
|
+
const needsUpdate = vue.ref(false);
|
|
16609
|
+
let registration = null;
|
|
16610
|
+
function handleOnline() {
|
|
16611
|
+
isOnline.value = true;
|
|
16612
|
+
}
|
|
16613
|
+
function handleOffline() {
|
|
16614
|
+
isOnline.value = false;
|
|
16615
|
+
}
|
|
16616
|
+
function register() {
|
|
16617
|
+
return __async(this, null, function* () {
|
|
16618
|
+
if (!isBrowser() || !("serviceWorker" in navigator)) return;
|
|
16619
|
+
if (!swConfig.enabled) return;
|
|
16620
|
+
try {
|
|
16621
|
+
registration = yield navigator.serviceWorker.register(
|
|
16622
|
+
swConfig.path || "/sw.js",
|
|
16623
|
+
{ scope: swConfig.scope || "/" }
|
|
16624
|
+
);
|
|
16625
|
+
isRegistered.value = true;
|
|
16626
|
+
registration.addEventListener("updatefound", () => {
|
|
16627
|
+
const newWorker = registration == null ? void 0 : registration.installing;
|
|
16628
|
+
if (newWorker) {
|
|
16629
|
+
newWorker.addEventListener("statechange", () => {
|
|
16630
|
+
if (newWorker.state === "installed" && navigator.serviceWorker.controller) {
|
|
16631
|
+
needsUpdate.value = true;
|
|
16632
|
+
}
|
|
16633
|
+
});
|
|
16634
|
+
}
|
|
16635
|
+
});
|
|
16636
|
+
} catch (error2) {
|
|
16637
|
+
console.warn("[Directix] Service Worker registration failed:", error2);
|
|
16638
|
+
}
|
|
16639
|
+
});
|
|
16640
|
+
}
|
|
16641
|
+
function update() {
|
|
16642
|
+
return __async(this, null, function* () {
|
|
16643
|
+
if (!registration) return;
|
|
16644
|
+
try {
|
|
16645
|
+
yield registration.update();
|
|
16646
|
+
if (registration.waiting) {
|
|
16647
|
+
registration.waiting.postMessage({ type: "SKIP_WAITING" });
|
|
16648
|
+
}
|
|
16649
|
+
} catch (error2) {
|
|
16650
|
+
console.warn("[Directix] Service Worker update failed:", error2);
|
|
16651
|
+
}
|
|
16652
|
+
});
|
|
16653
|
+
}
|
|
16654
|
+
function unregister() {
|
|
16655
|
+
return __async(this, null, function* () {
|
|
16656
|
+
if (!registration) return;
|
|
16657
|
+
try {
|
|
16658
|
+
yield registration.unregister();
|
|
16659
|
+
isRegistered.value = false;
|
|
16660
|
+
registration = null;
|
|
16661
|
+
} catch (error2) {
|
|
16662
|
+
console.warn("[Directix] Service Worker unregistration failed:", error2);
|
|
16663
|
+
}
|
|
16664
|
+
});
|
|
16665
|
+
}
|
|
16666
|
+
function init() {
|
|
16667
|
+
if (!isBrowser()) return () => {
|
|
16668
|
+
};
|
|
16669
|
+
window.addEventListener("online", handleOnline);
|
|
16670
|
+
window.addEventListener("offline", handleOffline);
|
|
16671
|
+
register();
|
|
16672
|
+
return () => {
|
|
16673
|
+
window.removeEventListener("online", handleOnline);
|
|
16674
|
+
window.removeEventListener("offline", handleOffline);
|
|
16675
|
+
};
|
|
16676
|
+
}
|
|
16677
|
+
vue.onUnmounted(() => {
|
|
16678
|
+
unregister();
|
|
16679
|
+
});
|
|
16680
|
+
return {
|
|
16681
|
+
isOnline: vue.readonly(isOnline),
|
|
16682
|
+
isRegistered: vue.readonly(isRegistered),
|
|
16683
|
+
needsUpdate: vue.readonly(needsUpdate),
|
|
16684
|
+
register,
|
|
16685
|
+
update,
|
|
16686
|
+
unregister,
|
|
16687
|
+
init
|
|
16688
|
+
};
|
|
16689
|
+
}
|
|
16690
|
+
class ObjectPool {
|
|
16691
|
+
constructor(factory, reset, maxSize = 100) {
|
|
16692
|
+
__publicField(this, "pool", []);
|
|
16693
|
+
__publicField(this, "factory");
|
|
16694
|
+
__publicField(this, "reset");
|
|
16695
|
+
__publicField(this, "maxSize");
|
|
16696
|
+
this.factory = factory;
|
|
16697
|
+
this.reset = reset;
|
|
16698
|
+
this.maxSize = maxSize;
|
|
16699
|
+
}
|
|
16700
|
+
acquire() {
|
|
16701
|
+
if (this.pool.length > 0) {
|
|
16702
|
+
return this.pool.pop();
|
|
16703
|
+
}
|
|
16704
|
+
return this.factory();
|
|
16705
|
+
}
|
|
16706
|
+
release(item) {
|
|
16707
|
+
if (this.pool.length < this.maxSize) {
|
|
16708
|
+
this.reset(item);
|
|
16709
|
+
this.pool.push(item);
|
|
16710
|
+
}
|
|
16711
|
+
}
|
|
16712
|
+
get size() {
|
|
16713
|
+
return this.pool.length;
|
|
16714
|
+
}
|
|
16715
|
+
clear() {
|
|
16716
|
+
this.pool.length = 0;
|
|
16717
|
+
}
|
|
16718
|
+
}
|
|
16719
|
+
const DEFAULT_ALLOWED_TAGS = [
|
|
16720
|
+
"b",
|
|
16721
|
+
"i",
|
|
16722
|
+
"u",
|
|
16723
|
+
"strong",
|
|
16724
|
+
"em",
|
|
16725
|
+
"br",
|
|
16726
|
+
"p",
|
|
16727
|
+
"span",
|
|
16728
|
+
"div",
|
|
16729
|
+
"h1",
|
|
16730
|
+
"h2",
|
|
16731
|
+
"h3",
|
|
16732
|
+
"h4",
|
|
16733
|
+
"h5",
|
|
16734
|
+
"h6",
|
|
16735
|
+
"ul",
|
|
16736
|
+
"ol",
|
|
16737
|
+
"li",
|
|
16738
|
+
"blockquote",
|
|
16739
|
+
"pre",
|
|
16740
|
+
"code",
|
|
16741
|
+
"a",
|
|
16742
|
+
"img",
|
|
16743
|
+
"table",
|
|
16744
|
+
"thead",
|
|
16745
|
+
"tbody",
|
|
16746
|
+
"tr",
|
|
16747
|
+
"td",
|
|
16748
|
+
"th"
|
|
16749
|
+
];
|
|
16750
|
+
const DEFAULT_ALLOWED_ATTRIBUTES = {
|
|
16751
|
+
"*": ["title", "alt", "class", "id"],
|
|
16752
|
+
a: ["href", "target", "rel", "title"],
|
|
16753
|
+
img: ["src", "alt", "title", "width", "height"]
|
|
16754
|
+
};
|
|
16755
|
+
const DEFAULT_ALLOWED_PROTOCOLS = ["http", "https", "mailto", "tel"];
|
|
16756
|
+
const DANGEROUS_TAGS = [
|
|
16757
|
+
"script",
|
|
16758
|
+
"iframe",
|
|
16759
|
+
"object",
|
|
16760
|
+
"embed",
|
|
16761
|
+
"applet",
|
|
16762
|
+
"form",
|
|
16763
|
+
"input",
|
|
16764
|
+
"button",
|
|
16765
|
+
"select",
|
|
16766
|
+
"textarea",
|
|
16767
|
+
"style",
|
|
16768
|
+
"link",
|
|
16769
|
+
"meta",
|
|
16770
|
+
"base",
|
|
16771
|
+
"frame",
|
|
16772
|
+
"frameset",
|
|
16773
|
+
"svg",
|
|
16774
|
+
"math",
|
|
16775
|
+
"template"
|
|
16776
|
+
];
|
|
16777
|
+
const DANGEROUS_ATTRIBUTES = [
|
|
16778
|
+
"onclick",
|
|
16779
|
+
"onerror",
|
|
16780
|
+
"onload",
|
|
16781
|
+
"onmouseover",
|
|
16782
|
+
"onmouseout",
|
|
16783
|
+
"onmousedown",
|
|
16784
|
+
"onmouseup",
|
|
16785
|
+
"onmousemove",
|
|
16786
|
+
"onfocus",
|
|
16787
|
+
"onblur",
|
|
16788
|
+
"onchange",
|
|
16789
|
+
"onsubmit",
|
|
16790
|
+
"onreset",
|
|
16791
|
+
"onkeydown",
|
|
16792
|
+
"onkeyup",
|
|
16793
|
+
"onkeypress",
|
|
16794
|
+
"oninput",
|
|
16795
|
+
"onscroll",
|
|
16796
|
+
"onresize",
|
|
16797
|
+
"onunload",
|
|
16798
|
+
"onbeforeunload",
|
|
16799
|
+
"onabort",
|
|
16800
|
+
"oncanplay",
|
|
16801
|
+
"oncanplaythrough",
|
|
16802
|
+
"ondurationchange",
|
|
16803
|
+
"onemptied",
|
|
16804
|
+
"onended",
|
|
16805
|
+
"onloadeddata",
|
|
16806
|
+
"onloadedmetadata",
|
|
16807
|
+
"onloadstart",
|
|
16808
|
+
"onpause",
|
|
16809
|
+
"onplay",
|
|
16810
|
+
"onplaying",
|
|
16811
|
+
"onprogress",
|
|
16812
|
+
"onratechange",
|
|
16813
|
+
"onseeked",
|
|
16814
|
+
"onseeking",
|
|
16815
|
+
"onstalled",
|
|
16816
|
+
"onsuspend",
|
|
16817
|
+
"ontimeupdate",
|
|
16818
|
+
"onvolumechange",
|
|
16819
|
+
"onwaiting",
|
|
16820
|
+
"onafterprint",
|
|
16821
|
+
"onbeforeprint",
|
|
16822
|
+
"oncontextmenu",
|
|
16823
|
+
"oncopy",
|
|
16824
|
+
"oncut",
|
|
16825
|
+
"onpaste",
|
|
16826
|
+
"ondblclick",
|
|
16827
|
+
"ondrag",
|
|
16828
|
+
"ondragend",
|
|
16829
|
+
"ondragenter",
|
|
16830
|
+
"ondragleave",
|
|
16831
|
+
"ondragover",
|
|
16832
|
+
"ondragstart",
|
|
16833
|
+
"ondrop",
|
|
16834
|
+
// Form-related
|
|
16835
|
+
"formaction",
|
|
16836
|
+
"action",
|
|
16837
|
+
"method",
|
|
16838
|
+
"enctype"
|
|
16839
|
+
];
|
|
16840
|
+
const DANGEROUS_URL_PATTERNS = [
|
|
16841
|
+
/^javascript:/i,
|
|
16842
|
+
/^data:/i,
|
|
16843
|
+
/^vbscript:/i,
|
|
16844
|
+
/^file:/i
|
|
16845
|
+
];
|
|
16846
|
+
function isUrlSafe(url, allowedProtocols = DEFAULT_ALLOWED_PROTOCOLS) {
|
|
16847
|
+
if (!url) return true;
|
|
16848
|
+
const trimmed = url.trim();
|
|
16849
|
+
for (const pattern of DANGEROUS_URL_PATTERNS) {
|
|
16850
|
+
if (pattern.test(trimmed)) {
|
|
16851
|
+
return false;
|
|
16852
|
+
}
|
|
16853
|
+
}
|
|
16854
|
+
const protocolMatch = trimmed.match(/^([a-zA-Z][a-zA-Z0-9+.-]*):/);
|
|
16855
|
+
if (protocolMatch) {
|
|
16856
|
+
return allowedProtocols.includes(protocolMatch[1].toLowerCase());
|
|
16857
|
+
}
|
|
16858
|
+
return true;
|
|
16859
|
+
}
|
|
16860
|
+
function sanitizeUrl(url, allowedProtocols = DEFAULT_ALLOWED_PROTOCOLS) {
|
|
16861
|
+
if (!url) return "";
|
|
16862
|
+
const trimmed = url.trim();
|
|
16863
|
+
if (!isUrlSafe(trimmed, allowedProtocols)) {
|
|
16864
|
+
return "";
|
|
16865
|
+
}
|
|
16866
|
+
return trimmed;
|
|
16867
|
+
}
|
|
16868
|
+
function escapeHtml(str) {
|
|
16869
|
+
const escapeMap = {
|
|
16870
|
+
"&": "&",
|
|
16871
|
+
"<": "<",
|
|
16872
|
+
">": ">",
|
|
16873
|
+
'"': """,
|
|
16874
|
+
"'": "'",
|
|
16875
|
+
"/": "/",
|
|
16876
|
+
"`": "`",
|
|
16877
|
+
"=": "="
|
|
16878
|
+
};
|
|
16879
|
+
return str.replace(/[&<>"'`=/]/g, (char) => escapeMap[char] || char);
|
|
16880
|
+
}
|
|
16881
|
+
function unescapeHtml(str) {
|
|
16882
|
+
const unescapeMap = {
|
|
16883
|
+
"&": "&",
|
|
16884
|
+
"<": "<",
|
|
16885
|
+
">": ">",
|
|
16886
|
+
""": '"',
|
|
16887
|
+
"'": "'",
|
|
16888
|
+
"/": "/",
|
|
16889
|
+
"`": "`",
|
|
16890
|
+
"=": "=",
|
|
16891
|
+
"'": "'"
|
|
16892
|
+
};
|
|
16893
|
+
return str.replace(/&[^;]+;/g, (entity) => unescapeMap[entity] || entity).replace(/&#(\d+);/g, (_, code) => String.fromCharCode(parseInt(code, 10)));
|
|
16894
|
+
}
|
|
16895
|
+
function stripHtml(html) {
|
|
16896
|
+
return html.replace(/<[^>]*>/g, "");
|
|
16897
|
+
}
|
|
16898
|
+
function sanitizeHtml(html, config = {}) {
|
|
16899
|
+
var _a2;
|
|
16900
|
+
if (!html) return "";
|
|
16901
|
+
if (!isBrowser()) return html;
|
|
16902
|
+
const {
|
|
16903
|
+
allowedTags = DEFAULT_ALLOWED_TAGS,
|
|
16904
|
+
allowedAttributes = DEFAULT_ALLOWED_ATTRIBUTES,
|
|
16905
|
+
allowedProtocols = DEFAULT_ALLOWED_PROTOCOLS,
|
|
16906
|
+
allowDataUrls = false,
|
|
16907
|
+
allowInlineStyles = false,
|
|
16908
|
+
allowClass = true,
|
|
16909
|
+
allowId = false,
|
|
16910
|
+
detectDangerousPatterns = true,
|
|
16911
|
+
customFilters = []
|
|
16912
|
+
} = config;
|
|
16913
|
+
let result = html;
|
|
16914
|
+
for (const filter of customFilters) {
|
|
16915
|
+
result = filter(result);
|
|
16916
|
+
}
|
|
16917
|
+
if (detectDangerousPatterns) {
|
|
16918
|
+
const dangerousPatterns = [
|
|
16919
|
+
/<script[\s\S]*?>[\s\S]*?<\/script>/gi,
|
|
16920
|
+
/javascript:/gi,
|
|
16921
|
+
/on\w+\s*=/gi,
|
|
16922
|
+
/data:\s*text\/html/gi,
|
|
16923
|
+
/vbscript:/gi,
|
|
16924
|
+
/expression\s*\(/gi,
|
|
16925
|
+
/url\s*\(\s*["']?javascript:/gi
|
|
16926
|
+
];
|
|
16927
|
+
for (const pattern of dangerousPatterns) {
|
|
16928
|
+
if (pattern.test(result)) {
|
|
16929
|
+
result = result.replace(pattern, "");
|
|
16930
|
+
}
|
|
16931
|
+
}
|
|
16932
|
+
}
|
|
16933
|
+
const temp = document.createElement("div");
|
|
16934
|
+
temp.innerHTML = result;
|
|
16935
|
+
for (const tag of DANGEROUS_TAGS) {
|
|
16936
|
+
const elements = temp.getElementsByTagName(tag);
|
|
16937
|
+
while (elements.length > 0) {
|
|
16938
|
+
(_a2 = elements[0].parentNode) == null ? void 0 : _a2.removeChild(elements[0]);
|
|
16939
|
+
}
|
|
16940
|
+
}
|
|
16941
|
+
function processElement(el) {
|
|
16942
|
+
var _a3;
|
|
16943
|
+
const tagName = el.tagName.toLowerCase();
|
|
16944
|
+
if (!allowedTags.includes(tagName)) {
|
|
16945
|
+
const text = document.createTextNode(el.textContent || "");
|
|
16946
|
+
(_a3 = el.parentNode) == null ? void 0 : _a3.replaceChild(text, el);
|
|
16947
|
+
return;
|
|
16948
|
+
}
|
|
16949
|
+
for (const attr of DANGEROUS_ATTRIBUTES) {
|
|
16950
|
+
el.removeAttribute(attr);
|
|
16951
|
+
}
|
|
16952
|
+
const attrs = Array.from(el.attributes);
|
|
16953
|
+
for (const attr of attrs) {
|
|
16954
|
+
const attrName = attr.name.toLowerCase();
|
|
16955
|
+
if (attrName.startsWith("on")) {
|
|
16956
|
+
el.removeAttribute(attr.name);
|
|
16957
|
+
continue;
|
|
16958
|
+
}
|
|
16959
|
+
let isAllowed2 = false;
|
|
16960
|
+
if (Array.isArray(allowedAttributes)) {
|
|
16961
|
+
isAllowed2 = allowedAttributes.includes(attrName);
|
|
16962
|
+
} else {
|
|
16963
|
+
const globalAttrs = allowedAttributes["*"] || [];
|
|
16964
|
+
const tagAttrs = allowedAttributes[tagName] || [];
|
|
16965
|
+
isAllowed2 = globalAttrs.includes(attrName) || tagAttrs.includes(attrName);
|
|
16966
|
+
}
|
|
16967
|
+
if (attrName === "class" && !allowClass) {
|
|
16968
|
+
el.removeAttribute(attr.name);
|
|
16969
|
+
continue;
|
|
16970
|
+
}
|
|
16971
|
+
if (attrName === "id" && !allowId) {
|
|
16972
|
+
el.removeAttribute(attr.name);
|
|
16973
|
+
continue;
|
|
16974
|
+
}
|
|
16975
|
+
if (attrName === "style" && !allowInlineStyles) {
|
|
16976
|
+
el.removeAttribute(attr.name);
|
|
16977
|
+
continue;
|
|
16978
|
+
}
|
|
16979
|
+
if (attrName === "href" || attrName === "src") {
|
|
16980
|
+
const url = attr.value;
|
|
16981
|
+
if (!isUrlSafe(url, allowDataUrls ? [...allowedProtocols, "data"] : allowedProtocols)) {
|
|
16982
|
+
el.removeAttribute(attr.name);
|
|
16983
|
+
continue;
|
|
16984
|
+
}
|
|
16985
|
+
}
|
|
16986
|
+
if (!isAllowed2 && attrName !== "class" && attrName !== "id" && attrName !== "style") {
|
|
16987
|
+
el.removeAttribute(attr.name);
|
|
16988
|
+
}
|
|
16989
|
+
}
|
|
16990
|
+
for (const child of Array.from(el.children)) {
|
|
16991
|
+
processElement(child);
|
|
16992
|
+
}
|
|
16993
|
+
}
|
|
16994
|
+
for (const child of Array.from(temp.children)) {
|
|
16995
|
+
processElement(child);
|
|
16996
|
+
}
|
|
16997
|
+
return temp.innerHTML;
|
|
16998
|
+
}
|
|
16999
|
+
function getCSPNonce() {
|
|
17000
|
+
if (!isBrowser()) return null;
|
|
17001
|
+
const meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
|
|
17002
|
+
if (meta) {
|
|
17003
|
+
const content = meta.content;
|
|
17004
|
+
const match = content.match(/nonce-([a-zA-Z0-9+/=]+)/);
|
|
17005
|
+
if (match) {
|
|
17006
|
+
return match[1];
|
|
17007
|
+
}
|
|
17008
|
+
}
|
|
17009
|
+
const scripts = document.querySelectorAll("script[nonce]");
|
|
17010
|
+
if (scripts.length > 0) {
|
|
17011
|
+
return scripts[0].nonce || null;
|
|
17012
|
+
}
|
|
17013
|
+
return null;
|
|
17014
|
+
}
|
|
17015
|
+
function injectStylesCSP(css, options = {}) {
|
|
17016
|
+
if (!isBrowser()) return null;
|
|
17017
|
+
const { nonce } = options;
|
|
17018
|
+
if (nonce || getCSPNonce()) {
|
|
17019
|
+
const style2 = document.createElement("style");
|
|
17020
|
+
style2.setAttribute("nonce", nonce || getCSPNonce() || "");
|
|
17021
|
+
style2.textContent = css;
|
|
17022
|
+
document.head.appendChild(style2);
|
|
17023
|
+
return style2;
|
|
17024
|
+
}
|
|
17025
|
+
const style = document.createElement("style");
|
|
17026
|
+
style.textContent = css;
|
|
17027
|
+
document.head.appendChild(style);
|
|
17028
|
+
return style;
|
|
17029
|
+
}
|
|
17030
|
+
function injectScriptCSP(src, options = {}) {
|
|
17031
|
+
if (!isBrowser()) return null;
|
|
17032
|
+
const { nonce } = options;
|
|
17033
|
+
const script = document.createElement("script");
|
|
17034
|
+
script.src = src;
|
|
17035
|
+
if (nonce || getCSPNonce()) {
|
|
17036
|
+
script.setAttribute("nonce", nonce || getCSPNonce() || "");
|
|
17037
|
+
}
|
|
17038
|
+
document.head.appendChild(script);
|
|
17039
|
+
return script;
|
|
17040
|
+
}
|
|
17041
|
+
const SecurityAudit = {
|
|
17042
|
+
/**
|
|
17043
|
+
* Scan for potential security issues in HTML
|
|
17044
|
+
*/
|
|
17045
|
+
scanHtml(html) {
|
|
17046
|
+
const issues = [];
|
|
17047
|
+
if (/<script[\s\S]*?>[\s\S]*?<\/script>/gi.test(html)) {
|
|
17048
|
+
issues.push({
|
|
17049
|
+
type: "script-injection",
|
|
17050
|
+
severity: "critical",
|
|
17051
|
+
description: "HTML contains script tags which could lead to XSS attacks",
|
|
17052
|
+
remediation: "Remove script tags or use a sanitization library"
|
|
17053
|
+
});
|
|
17054
|
+
}
|
|
17055
|
+
const eventHandlerMatch = html.match(/on\w+\s*=/gi);
|
|
17056
|
+
if (eventHandlerMatch) {
|
|
17057
|
+
issues.push({
|
|
17058
|
+
type: "event-handler",
|
|
17059
|
+
severity: "high",
|
|
17060
|
+
description: `Found ${eventHandlerMatch.length} event handler(s) which could be exploited`,
|
|
17061
|
+
remediation: "Remove inline event handlers and use addEventListener instead"
|
|
17062
|
+
});
|
|
17063
|
+
}
|
|
17064
|
+
if (/javascript:/gi.test(html)) {
|
|
17065
|
+
issues.push({
|
|
17066
|
+
type: "javascript-url",
|
|
17067
|
+
severity: "high",
|
|
17068
|
+
description: "HTML contains javascript: URLs which could lead to XSS attacks",
|
|
17069
|
+
remediation: "Remove javascript: URLs or validate/sanitize them"
|
|
17070
|
+
});
|
|
17071
|
+
}
|
|
17072
|
+
if (/data:\s*text\/html/gi.test(html)) {
|
|
17073
|
+
issues.push({
|
|
17074
|
+
type: "data-url",
|
|
17075
|
+
severity: "high",
|
|
17076
|
+
description: "HTML contains data:text/html URLs which could execute scripts",
|
|
17077
|
+
remediation: "Remove or sanitize data: URLs"
|
|
17078
|
+
});
|
|
17079
|
+
}
|
|
17080
|
+
if (/<iframe[\s\S]*?srcdoc=/gi.test(html)) {
|
|
17081
|
+
issues.push({
|
|
17082
|
+
type: "iframe-srcdoc",
|
|
17083
|
+
severity: "high",
|
|
17084
|
+
description: "HTML contains iframe with srcdoc attribute",
|
|
17085
|
+
remediation: "Avoid using srcdoc or sanitize its content"
|
|
17086
|
+
});
|
|
17087
|
+
}
|
|
17088
|
+
if (/<form[\s\S]*?action\s*=/gi.test(html)) {
|
|
17089
|
+
issues.push({
|
|
17090
|
+
type: "form-action",
|
|
17091
|
+
severity: "medium",
|
|
17092
|
+
description: "HTML contains form with action attribute",
|
|
17093
|
+
remediation: "Validate form actions or use CSRF protection"
|
|
17094
|
+
});
|
|
17095
|
+
}
|
|
17096
|
+
return issues;
|
|
17097
|
+
},
|
|
17098
|
+
/**
|
|
17099
|
+
* Check CSP configuration
|
|
17100
|
+
*/
|
|
17101
|
+
checkCSP() {
|
|
17102
|
+
var _a2, _b;
|
|
17103
|
+
const result = {
|
|
17104
|
+
policies: {},
|
|
17105
|
+
warnings: [],
|
|
17106
|
+
recommendations: []
|
|
17107
|
+
};
|
|
17108
|
+
if (!isBrowser()) {
|
|
17109
|
+
result.warnings.push("CSP check requires browser environment");
|
|
17110
|
+
return result;
|
|
17111
|
+
}
|
|
17112
|
+
const meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
|
|
17113
|
+
if (meta) {
|
|
17114
|
+
const content = meta.content;
|
|
17115
|
+
const directives = content.split(";").map((d) => d.trim());
|
|
17116
|
+
for (const directive of directives) {
|
|
17117
|
+
const [name, ...values] = directive.split(/\s+/);
|
|
17118
|
+
if (name) {
|
|
17119
|
+
result.policies[name.toLowerCase()] = values;
|
|
17120
|
+
}
|
|
17121
|
+
}
|
|
17122
|
+
if ((_a2 = result.policies["script-src"]) == null ? void 0 : _a2.includes("'unsafe-inline'")) {
|
|
17123
|
+
result.warnings.push("CSP allows unsafe-inline scripts - this reduces XSS protection");
|
|
17124
|
+
}
|
|
17125
|
+
if ((_b = result.policies["script-src"]) == null ? void 0 : _b.includes("'unsafe-eval'")) {
|
|
17126
|
+
result.warnings.push("CSP allows unsafe-eval - this reduces XSS protection");
|
|
17127
|
+
}
|
|
17128
|
+
const recommendedDirectives = ["default-src", "script-src", "style-src", "img-src", "connect-src"];
|
|
17129
|
+
for (const directive of recommendedDirectives) {
|
|
17130
|
+
if (!result.policies[directive]) {
|
|
17131
|
+
result.recommendations.push(`Consider adding ${directive} directive to CSP`);
|
|
17132
|
+
}
|
|
17133
|
+
}
|
|
17134
|
+
} else {
|
|
17135
|
+
result.warnings.push("No CSP meta tag found - consider adding Content Security Policy");
|
|
17136
|
+
result.recommendations.push("Add a Content-Security-Policy meta tag or header");
|
|
17137
|
+
}
|
|
17138
|
+
return result;
|
|
17139
|
+
},
|
|
17140
|
+
/**
|
|
17141
|
+
* Check for known dependency vulnerabilities (Node.js environment only)
|
|
17142
|
+
* Note: This is a client-side check that uses npm audit API when available.
|
|
17143
|
+
* For production use, run `npm audit` or `pnpm audit` in CI/CD.
|
|
17144
|
+
*/
|
|
17145
|
+
checkDependencies() {
|
|
17146
|
+
return __async(this, null, function* () {
|
|
17147
|
+
var _a2, _b, _c, _d, _e;
|
|
17148
|
+
const vulnerabilities = [];
|
|
17149
|
+
if (typeof process === "undefined" || !((_a2 = process.versions) == null ? void 0 : _a2.node)) {
|
|
17150
|
+
console.warn("[Directix] checkDependencies() is only available in Node.js environment");
|
|
17151
|
+
return vulnerabilities;
|
|
17152
|
+
}
|
|
17153
|
+
try {
|
|
17154
|
+
const { execSync } = yield import("node:child_process");
|
|
17155
|
+
try {
|
|
17156
|
+
const result = execSync("npm audit --json", {
|
|
17157
|
+
encoding: "utf-8",
|
|
17158
|
+
timeout: 3e4
|
|
17159
|
+
});
|
|
17160
|
+
const audit = JSON.parse(result);
|
|
17161
|
+
if (audit.vulnerabilities) {
|
|
17162
|
+
for (const [name, info2] of Object.entries(audit.vulnerabilities)) {
|
|
17163
|
+
if (info2.via && Array.isArray(info2.via)) {
|
|
17164
|
+
for (const via of info2.via) {
|
|
17165
|
+
if (typeof via === "object" && via.title) {
|
|
17166
|
+
vulnerabilities.push({
|
|
17167
|
+
name,
|
|
17168
|
+
id: (_c = (_b = via.url) == null ? void 0 : _b.match(/(CVE-\d+-\d+|GHSA-[a-zA-Z0-9-]+)/)) == null ? void 0 : _c[0],
|
|
17169
|
+
version: info2.version || "unknown",
|
|
17170
|
+
severity: via.severity || info2.severity || "medium",
|
|
17171
|
+
title: via.title,
|
|
17172
|
+
url: via.url,
|
|
17173
|
+
patchedVersions: info2.fixAvailable ? "Available" : void 0
|
|
17174
|
+
});
|
|
17175
|
+
}
|
|
17176
|
+
}
|
|
17177
|
+
}
|
|
17178
|
+
}
|
|
17179
|
+
}
|
|
17180
|
+
} catch (execError) {
|
|
17181
|
+
if (execError.stdout) {
|
|
17182
|
+
try {
|
|
17183
|
+
const audit = JSON.parse(execError.stdout);
|
|
17184
|
+
if (audit.vulnerabilities) {
|
|
17185
|
+
for (const [name, info2] of Object.entries(audit.vulnerabilities)) {
|
|
17186
|
+
if (info2.via && Array.isArray(info2.via)) {
|
|
17187
|
+
for (const via of info2.via) {
|
|
17188
|
+
if (typeof via === "object" && via.title) {
|
|
17189
|
+
vulnerabilities.push({
|
|
17190
|
+
name,
|
|
17191
|
+
id: (_e = (_d = via.url) == null ? void 0 : _d.match(/(CVE-\d+-\d+|GHSA-[a-zA-Z0-9-]+)/)) == null ? void 0 : _e[0],
|
|
17192
|
+
version: info2.version || "unknown",
|
|
17193
|
+
severity: via.severity || info2.severity || "medium",
|
|
17194
|
+
title: via.title,
|
|
17195
|
+
url: via.url,
|
|
17196
|
+
patchedVersions: info2.fixAvailable ? "Available" : void 0
|
|
17197
|
+
});
|
|
17198
|
+
}
|
|
17199
|
+
}
|
|
17200
|
+
}
|
|
17201
|
+
}
|
|
17202
|
+
}
|
|
17203
|
+
} catch (e) {
|
|
17204
|
+
}
|
|
17205
|
+
}
|
|
17206
|
+
}
|
|
17207
|
+
} catch (error2) {
|
|
17208
|
+
console.warn("[Directix] Failed to check dependencies:", error2);
|
|
17209
|
+
}
|
|
17210
|
+
return vulnerabilities;
|
|
17211
|
+
});
|
|
17212
|
+
},
|
|
17213
|
+
/**
|
|
17214
|
+
* Generate security report
|
|
17215
|
+
*/
|
|
17216
|
+
generateReport(html) {
|
|
17217
|
+
const report = {
|
|
17218
|
+
vulnerabilities: [],
|
|
17219
|
+
warnings: [],
|
|
17220
|
+
recommendations: [],
|
|
17221
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
17222
|
+
};
|
|
17223
|
+
if (html) {
|
|
17224
|
+
report.vulnerabilities = this.scanHtml(html);
|
|
17225
|
+
}
|
|
17226
|
+
const cspResult = this.checkCSP();
|
|
17227
|
+
for (const warning of cspResult.warnings) {
|
|
17228
|
+
report.warnings.push({
|
|
17229
|
+
type: "csp-warning",
|
|
17230
|
+
severity: "medium",
|
|
17231
|
+
description: warning
|
|
17232
|
+
});
|
|
17233
|
+
}
|
|
17234
|
+
report.recommendations.push(...cspResult.recommendations);
|
|
17235
|
+
return report;
|
|
17236
|
+
},
|
|
17237
|
+
/**
|
|
17238
|
+
* Format security report
|
|
17239
|
+
*/
|
|
17240
|
+
formatReport(report, format = "text") {
|
|
17241
|
+
if (format === "json") {
|
|
17242
|
+
return JSON.stringify(report, null, 2);
|
|
17243
|
+
}
|
|
17244
|
+
if (format === "html") {
|
|
17245
|
+
let html = '<div class="security-report">';
|
|
17246
|
+
html += `<h2>Security Report</h2>`;
|
|
17247
|
+
html += `<p>Generated: ${report.timestamp.toISOString()}</p>`;
|
|
17248
|
+
if (report.vulnerabilities.length > 0) {
|
|
17249
|
+
html += "<h3>Vulnerabilities</h3><ul>";
|
|
17250
|
+
for (const vuln of report.vulnerabilities) {
|
|
17251
|
+
html += `<li class="severity-${vuln.severity}"><strong>${vuln.type}</strong>: ${vuln.description}</li>`;
|
|
17252
|
+
}
|
|
17253
|
+
html += "</ul>";
|
|
17254
|
+
}
|
|
17255
|
+
if (report.warnings.length > 0) {
|
|
17256
|
+
html += "<h3>Warnings</h3><ul>";
|
|
17257
|
+
for (const warning of report.warnings) {
|
|
17258
|
+
html += `<li class="severity-${warning.severity}"><strong>${warning.type}</strong>: ${warning.description}</li>`;
|
|
17259
|
+
}
|
|
17260
|
+
html += "</ul>";
|
|
17261
|
+
}
|
|
17262
|
+
if (report.recommendations.length > 0) {
|
|
17263
|
+
html += "<h3>Recommendations</h3><ul>";
|
|
17264
|
+
for (const rec of report.recommendations) {
|
|
17265
|
+
html += `<li>${rec}</li>`;
|
|
17266
|
+
}
|
|
17267
|
+
html += "</ul>";
|
|
17268
|
+
}
|
|
17269
|
+
html += "</div>";
|
|
17270
|
+
return html;
|
|
17271
|
+
}
|
|
17272
|
+
let text = "Security Report\n";
|
|
17273
|
+
text += `Generated: ${report.timestamp.toISOString()}
|
|
17274
|
+
|
|
17275
|
+
`;
|
|
17276
|
+
if (report.vulnerabilities.length > 0) {
|
|
17277
|
+
text += "Vulnerabilities:\n";
|
|
17278
|
+
for (const vuln of report.vulnerabilities) {
|
|
17279
|
+
text += ` [${vuln.severity.toUpperCase()}] ${vuln.type}: ${vuln.description}
|
|
17280
|
+
`;
|
|
17281
|
+
}
|
|
17282
|
+
text += "\n";
|
|
17283
|
+
}
|
|
17284
|
+
if (report.warnings.length > 0) {
|
|
17285
|
+
text += "Warnings:\n";
|
|
17286
|
+
for (const warning of report.warnings) {
|
|
17287
|
+
text += ` [${warning.severity.toUpperCase()}] ${warning.type}: ${warning.description}
|
|
17288
|
+
`;
|
|
17289
|
+
}
|
|
17290
|
+
text += "\n";
|
|
17291
|
+
}
|
|
17292
|
+
if (report.recommendations.length > 0) {
|
|
17293
|
+
text += "Recommendations:\n";
|
|
17294
|
+
for (const rec of report.recommendations) {
|
|
17295
|
+
text += ` - ${rec}
|
|
17296
|
+
`;
|
|
17297
|
+
}
|
|
17298
|
+
}
|
|
17299
|
+
return text;
|
|
17300
|
+
}
|
|
17301
|
+
};
|
|
17302
|
+
class SafeContentHandler {
|
|
17303
|
+
constructor(config = {}) {
|
|
17304
|
+
__publicField(this, "config");
|
|
17305
|
+
this.config = config;
|
|
17306
|
+
}
|
|
17307
|
+
/**
|
|
17308
|
+
* Sanitize and set HTML content
|
|
17309
|
+
*/
|
|
17310
|
+
setHtml(element, content) {
|
|
17311
|
+
element.innerHTML = sanitizeHtml(content, this.config);
|
|
17312
|
+
}
|
|
17313
|
+
/**
|
|
17314
|
+
* Sanitize and set text content
|
|
17315
|
+
*/
|
|
17316
|
+
setText(element, content) {
|
|
17317
|
+
element.textContent = content;
|
|
17318
|
+
}
|
|
17319
|
+
/**
|
|
17320
|
+
* Set attribute with URL validation
|
|
17321
|
+
*/
|
|
17322
|
+
setAttribute(element, name, value) {
|
|
17323
|
+
if (name.toLowerCase().startsWith("on")) {
|
|
17324
|
+
return;
|
|
17325
|
+
}
|
|
17326
|
+
if (name.toLowerCase() === "href" || name.toLowerCase() === "src") {
|
|
17327
|
+
value = sanitizeUrl(value, this.config.allowedProtocols);
|
|
17328
|
+
}
|
|
17329
|
+
element.setAttribute(name, value);
|
|
17330
|
+
}
|
|
17331
|
+
/**
|
|
17332
|
+
* Get sanitized HTML
|
|
17333
|
+
*/
|
|
17334
|
+
getSanitizedHtml(content) {
|
|
17335
|
+
return sanitizeHtml(content, this.config);
|
|
17336
|
+
}
|
|
17337
|
+
}
|
|
17338
|
+
function createSafeContentHandler(config) {
|
|
17339
|
+
return new SafeContentHandler(config);
|
|
17340
|
+
}
|
|
17341
|
+
function useLazyOptimized(options = {}) {
|
|
17342
|
+
const {
|
|
17343
|
+
threshold = 0,
|
|
17344
|
+
rootMargin = "0px",
|
|
17345
|
+
once = true,
|
|
17346
|
+
onLoad
|
|
17347
|
+
} = options;
|
|
17348
|
+
const state2 = vue.shallowRef({
|
|
17349
|
+
loading: false,
|
|
17350
|
+
loaded: false,
|
|
17351
|
+
error: null,
|
|
17352
|
+
isVisible: false
|
|
17353
|
+
});
|
|
17354
|
+
let observer = null;
|
|
17355
|
+
function disconnect() {
|
|
17356
|
+
if (observer) {
|
|
17357
|
+
observer.disconnect();
|
|
17358
|
+
observer = null;
|
|
17359
|
+
}
|
|
17360
|
+
}
|
|
17361
|
+
function observe2(el) {
|
|
17362
|
+
disconnect();
|
|
17363
|
+
observer = new IntersectionObserver(
|
|
17364
|
+
(entries) => {
|
|
17365
|
+
const entry = entries[0];
|
|
17366
|
+
if (entry == null ? void 0 : entry.isIntersecting) {
|
|
17367
|
+
state2.value = __spreadProps(__spreadValues({}, state2.value), { isVisible: true });
|
|
17368
|
+
load2();
|
|
17369
|
+
if (once) {
|
|
17370
|
+
disconnect();
|
|
17371
|
+
}
|
|
17372
|
+
}
|
|
17373
|
+
},
|
|
17374
|
+
{ threshold, rootMargin }
|
|
17375
|
+
);
|
|
17376
|
+
observer.observe(el);
|
|
17377
|
+
}
|
|
17378
|
+
function load2() {
|
|
17379
|
+
if (state2.value.loading || state2.value.loaded) return;
|
|
17380
|
+
state2.value = __spreadProps(__spreadValues({}, state2.value), { loading: true, error: null });
|
|
17381
|
+
try {
|
|
17382
|
+
onLoad == null ? void 0 : onLoad({});
|
|
17383
|
+
state2.value = __spreadProps(__spreadValues({}, state2.value), { loading: false, loaded: true });
|
|
17384
|
+
} catch (e) {
|
|
17385
|
+
state2.value = __spreadProps(__spreadValues({}, state2.value), { loading: false, error: e });
|
|
17386
|
+
}
|
|
17387
|
+
}
|
|
17388
|
+
return {
|
|
17389
|
+
state: vue.readonly(state2),
|
|
17390
|
+
observe: observe2,
|
|
17391
|
+
disconnect,
|
|
17392
|
+
load: load2
|
|
17393
|
+
};
|
|
17394
|
+
}
|
|
17395
|
+
function useDirectiveInstance(options = {}) {
|
|
17396
|
+
const { initialState = {}, shallow = false } = options;
|
|
17397
|
+
let element = null;
|
|
17398
|
+
const state2 = shallow ? vue.reactive(initialState) : vue.reactive(initialState);
|
|
17399
|
+
function setElement(el) {
|
|
17400
|
+
element = vue.markRaw(el);
|
|
17401
|
+
}
|
|
17402
|
+
function setState2(updater) {
|
|
17403
|
+
const newState = updater(vue.toRaw(state2));
|
|
17404
|
+
Object.assign(state2, newState);
|
|
17405
|
+
}
|
|
17406
|
+
function reset() {
|
|
17407
|
+
Object.assign(state2, initialState);
|
|
17408
|
+
}
|
|
17409
|
+
return {
|
|
17410
|
+
get element() {
|
|
17411
|
+
return element;
|
|
17412
|
+
},
|
|
17413
|
+
set element(el) {
|
|
17414
|
+
if (el) setElement(el);
|
|
17415
|
+
},
|
|
17416
|
+
state: vue.readonly(state2),
|
|
17417
|
+
setElement,
|
|
17418
|
+
setState: setState2,
|
|
17419
|
+
reset
|
|
17420
|
+
};
|
|
17421
|
+
}
|
|
17422
|
+
function computedWithCleanup(options) {
|
|
17423
|
+
const { get: get2, cleanup: cleanup2 } = options;
|
|
17424
|
+
let oldValue;
|
|
17425
|
+
return vue.computed({
|
|
17426
|
+
get() {
|
|
17427
|
+
const newValue = get2();
|
|
17428
|
+
if (oldValue !== void 0 && oldValue !== newValue) {
|
|
17429
|
+
cleanup2 == null ? void 0 : cleanup2(oldValue);
|
|
17430
|
+
}
|
|
17431
|
+
oldValue = newValue;
|
|
17432
|
+
return newValue;
|
|
17433
|
+
},
|
|
17434
|
+
set() {
|
|
17435
|
+
}
|
|
17436
|
+
});
|
|
17437
|
+
}
|
|
17438
|
+
function watchEffectBinding(options) {
|
|
17439
|
+
const { binding, effect } = options;
|
|
17440
|
+
let cleanupFn = null, cleanup2 = (fn) => {
|
|
17441
|
+
cleanupFn = fn;
|
|
17442
|
+
};
|
|
17443
|
+
const stop = vue.watchEffect((onCleanup) => {
|
|
17444
|
+
cleanup2 = onCleanup;
|
|
17445
|
+
if (cleanupFn) {
|
|
17446
|
+
cleanupFn();
|
|
17447
|
+
cleanupFn = null;
|
|
17448
|
+
}
|
|
17449
|
+
if (vue.isRef(binding)) {
|
|
17450
|
+
effect(binding.value, void 0, cleanup2);
|
|
17451
|
+
} else {
|
|
17452
|
+
effect(binding, void 0, cleanup2);
|
|
17453
|
+
}
|
|
17454
|
+
});
|
|
17455
|
+
return () => {
|
|
17456
|
+
if (cleanupFn) {
|
|
17457
|
+
cleanupFn();
|
|
17458
|
+
}
|
|
17459
|
+
stop();
|
|
17460
|
+
};
|
|
17461
|
+
}
|
|
17462
|
+
function useSuspenseDirective(options) {
|
|
17463
|
+
const { loader, onSuccess, onError } = options;
|
|
17464
|
+
const state2 = vue.shallowRef({
|
|
17465
|
+
loading: false,
|
|
17466
|
+
error: null,
|
|
17467
|
+
data: null
|
|
17468
|
+
});
|
|
17469
|
+
function load2() {
|
|
17470
|
+
return __async(this, null, function* () {
|
|
17471
|
+
if (state2.value.loading) return;
|
|
17472
|
+
state2.value = __spreadProps(__spreadValues({}, state2.value), { loading: true, error: null });
|
|
17473
|
+
try {
|
|
17474
|
+
const data = yield loader();
|
|
17475
|
+
state2.value = { loading: false, error: null, data };
|
|
17476
|
+
onSuccess == null ? void 0 : onSuccess(data);
|
|
17477
|
+
} catch (error2) {
|
|
17478
|
+
state2.value = __spreadProps(__spreadValues({}, state2.value), { loading: false, error: error2 });
|
|
17479
|
+
onError == null ? void 0 : onError(error2);
|
|
17480
|
+
}
|
|
17481
|
+
});
|
|
17482
|
+
}
|
|
17483
|
+
function retry() {
|
|
17484
|
+
return __async(this, null, function* () {
|
|
17485
|
+
state2.value = __spreadProps(__spreadValues({}, state2.value), { error: null });
|
|
17486
|
+
yield load2();
|
|
17487
|
+
});
|
|
17488
|
+
}
|
|
17489
|
+
return {
|
|
17490
|
+
state: vue.readonly(state2),
|
|
17491
|
+
load: load2,
|
|
17492
|
+
retry
|
|
17493
|
+
};
|
|
17494
|
+
}
|
|
17495
|
+
function ensureTeleportTarget(target) {
|
|
17496
|
+
if (typeof document === "undefined") return null;
|
|
17497
|
+
let el = document.querySelector(target);
|
|
17498
|
+
if (!el) {
|
|
17499
|
+
el = document.createElement("div");
|
|
17500
|
+
el.id = target.replace("#", "");
|
|
17501
|
+
document.body.appendChild(el);
|
|
17502
|
+
}
|
|
17503
|
+
return el;
|
|
17504
|
+
}
|
|
17505
|
+
function teleportContent(content, options) {
|
|
17506
|
+
const { to, disabled = false } = options;
|
|
17507
|
+
if (disabled || typeof document === "undefined") {
|
|
17508
|
+
return () => {
|
|
17509
|
+
};
|
|
17510
|
+
}
|
|
17511
|
+
const targetEl = typeof to === "string" ? ensureTeleportTarget(to) : to;
|
|
17512
|
+
if (!targetEl) return () => {
|
|
17513
|
+
};
|
|
17514
|
+
const parent = content.parentNode;
|
|
17515
|
+
const nextSibling = content.nextSibling;
|
|
17516
|
+
targetEl.appendChild(content);
|
|
17517
|
+
return () => {
|
|
17518
|
+
if (parent && content.parentNode === targetEl) {
|
|
17519
|
+
parent.insertBefore(content, nextSibling);
|
|
17520
|
+
}
|
|
17521
|
+
};
|
|
17522
|
+
}
|
|
15795
17523
|
const zhCN = {
|
|
15796
17524
|
directives: {
|
|
15797
17525
|
debounce: {
|
|
@@ -17873,10 +19601,17 @@ const Directix = {
|
|
|
17873
19601
|
install
|
|
17874
19602
|
};
|
|
17875
19603
|
exports.Directix = Directix;
|
|
19604
|
+
exports.ObjectPool = ObjectPool;
|
|
17876
19605
|
exports.PluginManager = PluginManager;
|
|
17877
19606
|
exports.PluginRegistry = PluginRegistry;
|
|
19607
|
+
exports.SafeContentHandler = SafeContentHandler;
|
|
19608
|
+
exports.SecurityAudit = SecurityAudit;
|
|
17878
19609
|
exports.addCleanupVue2 = addCleanup$1;
|
|
17879
19610
|
exports.addCleanupVue3 = addCleanup;
|
|
19611
|
+
exports.addNonPassiveListener = addNonPassiveListener;
|
|
19612
|
+
exports.addPassiveListener = addPassiveListener;
|
|
19613
|
+
exports.announce = announce;
|
|
19614
|
+
exports.applyAriaAttributes = applyAriaAttributes;
|
|
17880
19615
|
exports.assert = assert;
|
|
17881
19616
|
exports.assertPositive = assertPositive;
|
|
17882
19617
|
exports.assertRange = assertRange;
|
|
@@ -17885,8 +19620,11 @@ exports.calculateStats = calculateStats;
|
|
|
17885
19620
|
exports.calculateTime = calculateTime;
|
|
17886
19621
|
exports.capitalizeText = capitalizeText;
|
|
17887
19622
|
exports.capitalizeWord = capitalizeWord;
|
|
19623
|
+
exports.clearAnnouncer = clearAnnouncer;
|
|
19624
|
+
exports.clearAriaAttributes = clearAriaAttributes;
|
|
17888
19625
|
exports.clearDevtoolsState = clearDevtoolsState;
|
|
17889
19626
|
exports.clearPerformanceMetrics = clearPerformanceMetrics;
|
|
19627
|
+
exports.computedWithCleanup = computedWithCleanup;
|
|
17890
19628
|
exports.configurePerformance = configurePerformance;
|
|
17891
19629
|
exports.configurePermission = configurePermission;
|
|
17892
19630
|
exports.createCapitalizer = createCapitalizer;
|
|
@@ -17898,6 +19636,7 @@ exports.createLowercaser = createLowercaser;
|
|
|
17898
19636
|
exports.createMoneyFormatter = createMoneyFormatter;
|
|
17899
19637
|
exports.createNumberFormatter = createNumberFormatter;
|
|
17900
19638
|
exports.createPermissionChecker = createPermissionChecker;
|
|
19639
|
+
exports.createSafeContentHandler = createSafeContentHandler;
|
|
17901
19640
|
exports.createStyleDirective = createStyleDirective;
|
|
17902
19641
|
exports.createTrimmer = createTrimmer;
|
|
17903
19642
|
exports.createUppercaser = createUppercaser;
|
|
@@ -17920,7 +19659,9 @@ exports.enUS = enUS;
|
|
|
17920
19659
|
exports.enableDevtools = enableDevtools;
|
|
17921
19660
|
exports.enablePerformance = enablePerformance;
|
|
17922
19661
|
exports.endMeasure = endMeasure;
|
|
19662
|
+
exports.ensureTeleportTarget = ensureTeleportTarget;
|
|
17923
19663
|
exports.error = error;
|
|
19664
|
+
exports.escapeHtml = escapeHtml;
|
|
17924
19665
|
exports.exportPerformanceData = exportPerformanceData;
|
|
17925
19666
|
exports.formatCurrencyLocale = formatCurrencyLocale;
|
|
17926
19667
|
exports.formatDateLocale = formatDateLocale;
|
|
@@ -17928,9 +19669,13 @@ exports.formatMoney = formatMoney;
|
|
|
17928
19669
|
exports.formatNumber = formatNumber;
|
|
17929
19670
|
exports.formatNumberLocale = formatNumberLocale;
|
|
17930
19671
|
exports.formatTime = formatTime;
|
|
19672
|
+
exports.generateAriaId = generateAriaId;
|
|
17931
19673
|
exports.generateId = generateId;
|
|
17932
19674
|
exports.get = get;
|
|
19675
|
+
exports.getAutoAriaConfig = getAutoAriaConfig;
|
|
19676
|
+
exports.getCSPNonce = getCSPNonce;
|
|
17933
19677
|
exports.getDateFormat = getDateFormat;
|
|
19678
|
+
exports.getDevicePixelRatio = getDevicePixelRatio;
|
|
17934
19679
|
exports.getDevtoolsState = getDevtoolsState;
|
|
17935
19680
|
exports.getDirectiveMetrics = getDirectiveMetrics;
|
|
17936
19681
|
exports.getLocale = getLocale;
|
|
@@ -17947,18 +19692,23 @@ exports.getSupportedRegions = getSupportedRegions;
|
|
|
17947
19692
|
exports.getTimezoneInfo = getTimezoneInfo;
|
|
17948
19693
|
exports.getVueVersion = getVueVersion;
|
|
17949
19694
|
exports.info = info;
|
|
19695
|
+
exports.injectScriptCSP = injectScriptCSP;
|
|
19696
|
+
exports.injectStylesCSP = injectStylesCSP;
|
|
17950
19697
|
exports.isArray = isArray;
|
|
17951
19698
|
exports.isBoolean = isBoolean;
|
|
17952
19699
|
exports.isBrowser = isBrowser;
|
|
17953
19700
|
exports.isDevtoolsAvailable = isDevtoolsAvailable;
|
|
17954
19701
|
exports.isEmpty = isEmpty;
|
|
17955
19702
|
exports.isFunction = isFunction;
|
|
19703
|
+
exports.isMobileDevice = isMobileDevice;
|
|
17956
19704
|
exports.isNumber = isNumber;
|
|
17957
19705
|
exports.isObject = isObject;
|
|
17958
19706
|
exports.isPerformanceEnabled = isPerformanceEnabled;
|
|
17959
19707
|
exports.isPromise = isPromise;
|
|
17960
19708
|
exports.isSSR = isSSR;
|
|
17961
19709
|
exports.isString = isString;
|
|
19710
|
+
exports.isTouchDevice = isTouchDevice;
|
|
19711
|
+
exports.isUrlSafe = isUrlSafe;
|
|
17962
19712
|
exports.isVue2 = isVue2;
|
|
17963
19713
|
exports.isVue27 = isVue27;
|
|
17964
19714
|
exports.isVue3 = isVue3;
|
|
@@ -17975,6 +19725,8 @@ exports.quickPrint = quickPrint;
|
|
|
17975
19725
|
exports.resetPluginManager = resetPluginManager;
|
|
17976
19726
|
exports.resetPluginRegistry = resetPluginRegistry;
|
|
17977
19727
|
exports.resetVueVersion = resetVueVersion;
|
|
19728
|
+
exports.sanitizeHtml = sanitizeHtml;
|
|
19729
|
+
exports.sanitizeUrl = sanitizeUrl;
|
|
17978
19730
|
exports.set = set;
|
|
17979
19731
|
exports.setLocale = setLocale;
|
|
17980
19732
|
exports.setVueVersion = setVueVersion;
|
|
@@ -17982,17 +19734,21 @@ exports.setWarningDevMode = setWarningDevMode;
|
|
|
17982
19734
|
exports.setWarningI18n = setWarningI18n;
|
|
17983
19735
|
exports.setWarningLevel = setWarningLevel;
|
|
17984
19736
|
exports.startMeasure = startMeasure;
|
|
19737
|
+
exports.stripHtml = stripHtml;
|
|
17985
19738
|
exports.supportsClipboard = supportsClipboard;
|
|
17986
19739
|
exports.supportsIntersectionObserver = supportsIntersectionObserver;
|
|
17987
19740
|
exports.supportsMutationObserver = supportsMutationObserver;
|
|
17988
19741
|
exports.supportsPassive = supportsPassive;
|
|
17989
19742
|
exports.supportsResizeObserver = supportsResizeObserver;
|
|
17990
19743
|
exports.t = t;
|
|
19744
|
+
exports.teleportContent = teleportContent;
|
|
17991
19745
|
exports.throttleFn = throttleFn;
|
|
17992
19746
|
exports.trackDirective = trackDirective;
|
|
17993
19747
|
exports.trackPlugin = trackPlugin;
|
|
19748
|
+
exports.triggerHaptic = triggerHaptic;
|
|
17994
19749
|
exports.trimText = trimText;
|
|
17995
19750
|
exports.truncateText = truncateText;
|
|
19751
|
+
exports.unescapeHtml = unescapeHtml;
|
|
17996
19752
|
exports.untrackDirective = untrackDirective;
|
|
17997
19753
|
exports.untrackPlugin = untrackPlugin;
|
|
17998
19754
|
exports.uppercaseText = uppercaseText;
|
|
@@ -18006,12 +19762,15 @@ exports.useCopy = useCopy;
|
|
|
18006
19762
|
exports.useCountdown = useCountdown;
|
|
18007
19763
|
exports.useCounter = useCounter;
|
|
18008
19764
|
exports.useDebounce = useDebounce;
|
|
19765
|
+
exports.useDirectiveInstance = useDirectiveInstance;
|
|
18009
19766
|
exports.useDraggable = useDraggable;
|
|
18010
19767
|
exports.useEllipsis = useEllipsis;
|
|
18011
19768
|
exports.useEmoji = useEmoji;
|
|
19769
|
+
exports.useEnhancedTouch = useEnhancedTouch;
|
|
18012
19770
|
exports.useExport = useExport;
|
|
18013
19771
|
exports.useFade = useFade;
|
|
18014
19772
|
exports.useFocus = useFocus;
|
|
19773
|
+
exports.useFocusTrap = useFocusTrap;
|
|
18015
19774
|
exports.useFullscreen = useFullscreen;
|
|
18016
19775
|
exports.useHighlight = useHighlight;
|
|
18017
19776
|
exports.useHotkey = useHotkey;
|
|
@@ -18019,7 +19778,9 @@ exports.useHover = useHover;
|
|
|
18019
19778
|
exports.useImagePreview = useImagePreview;
|
|
18020
19779
|
exports.useInfiniteScroll = useInfiniteScroll;
|
|
18021
19780
|
exports.useIntersect = useIntersect;
|
|
19781
|
+
exports.useKeyboardNavigation = useKeyboardNavigation;
|
|
18022
19782
|
exports.useLazy = useLazy;
|
|
19783
|
+
exports.useLazyOptimized = useLazyOptimized;
|
|
18023
19784
|
exports.useLoading = useLoading;
|
|
18024
19785
|
exports.useLongPress = useLongPress;
|
|
18025
19786
|
exports.useLottie = useLottie;
|
|
@@ -18028,6 +19789,7 @@ exports.useMask = useMask;
|
|
|
18028
19789
|
exports.useMoney = useMoney;
|
|
18029
19790
|
exports.useMutation = useMutation;
|
|
18030
19791
|
exports.useNumber = useNumber;
|
|
19792
|
+
exports.usePWA = usePWA;
|
|
18031
19793
|
exports.usePan = usePan;
|
|
18032
19794
|
exports.useParallax = useParallax;
|
|
18033
19795
|
exports.usePermission = usePermission;
|
|
@@ -18042,6 +19804,7 @@ exports.useSanitize = useSanitize;
|
|
|
18042
19804
|
exports.useScroll = useScroll;
|
|
18043
19805
|
exports.useSkeleton = useSkeleton;
|
|
18044
19806
|
exports.useSticky = useSticky;
|
|
19807
|
+
exports.useSuspenseDirective = useSuspenseDirective;
|
|
18045
19808
|
exports.useSwipe = useSwipe;
|
|
18046
19809
|
exports.useThrottle = useThrottle;
|
|
18047
19810
|
exports.useTooltip = useTooltip;
|
|
@@ -18116,6 +19879,7 @@ exports.warnInvalidParam = warnInvalidParam;
|
|
|
18116
19879
|
exports.warnMissingParam = warnMissingParam;
|
|
18117
19880
|
exports.warnNotSupported = warnNotSupported;
|
|
18118
19881
|
exports.warnSSRNotSupported = warnSSRNotSupported;
|
|
19882
|
+
exports.watchEffectBinding = watchEffectBinding;
|
|
18119
19883
|
exports.withPerformanceMonitoring = withPerformanceMonitoring;
|
|
18120
19884
|
exports.wouldTextTruncate = wouldTextTruncate;
|
|
18121
19885
|
exports.zhCN = zhCN;
|